From patchwork Fri Mar 7 12:47:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darren.Ye" X-Patchwork-Id: 14006473 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2C098C282DE for ; Fri, 7 Mar 2025 13:13:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=eIzA5blZjnn1Za4hHHyhXXOBaYZDr85xHWv+EF326Ts=; b=f9vjVxc1a8tCYR1iC7HoT1MIZv n2q1Mbq5rZ3FDg4WrKt62fHsATT2xSmadYkJ5myb4ofB+QPoXsZOe5aBEm3tFQpDMEpAWYgILN4OC bEVN40NUIR6PwpgyRBF2bJiqdO+4FePAC1lESqv2FatS46MmdqytU8u9tDjcxDA/t2Ijaiy7i8MHt UZLBaQM2XmYeqhKnGINU7Yu2hmYJCcf6TxZ5obNeq5q9mR66q35JnapcO0/390edbyXIR/Cwduwxp 4vgNUi4RFatxLx7n33r6ouU1mI1/ifJJeJ6pPaOGHWOpLh8oflu21eT6erNtdADosCti/t8vX6NBx OW+kSE7w==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tqXVW-0000000EHcT-2aop; Fri, 07 Mar 2025 13:12:54 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqXNC-0000000EG5Y-2SfI for linux-arm-kernel@lists.infradead.org; Fri, 07 Mar 2025 13:04:19 +0000 X-UUID: 84f92504fb5211efa1e849db4cc18d44-20250307 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=eIzA5blZjnn1Za4hHHyhXXOBaYZDr85xHWv+EF326Ts=; b=sTSfmRdN4nj8Ckl9jqIQbzsCX8rnOLq7ZV4WW1Y0yHkBPWloj5brN9tUE10z0s5XpHesGKZsf4Up6T1CnABzT7LS8mmQSZsWqxR4JpzBEOSxAyNf405tHgHHwK1cqlHshbPZuC1IAdEYisNiETmZgd3PWabp7ghlSkM0htcTmvU=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:093522e7-964f-4e56-8f77-805d72db3bbc,IP:0,UR L:0,TC:0,Content:0,EDM:-25,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION :release,TS:-25 X-CID-META: VersionHash:0ef645f,CLOUDID:abca0dc6-16da-468a-87f7-8ca8d6b3b9f7,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:1, IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV: 0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 84f92504fb5211efa1e849db4cc18d44-20250307 Received: from mtkmbs14n1.mediatek.inc [(172.21.101.75)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1108031026; Fri, 07 Mar 2025 05:48:50 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS09N2.mediatek.inc (172.21.101.94) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 7 Mar 2025 20:48:47 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 7 Mar 2025 20:48:47 +0800 From: Darren.Ye To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Jaroslav Kysela , Takashi Iwai , Linus Walleij , Bartosz Golaszewski CC: , , , , , , Darren Ye Subject: [PATCH 01/14] ASoC: mediatek: common: modify mtk afe common driver for mt8196 Date: Fri, 7 Mar 2025 20:47:27 +0800 Message-ID: <20250307124841.23777-2-darren.ye@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250307124841.23777-1-darren.ye@mediatek.com> References: <20250307124841.23777-1-darren.ye@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250307_050418_664863_E45A8999 X-CRM114-Status: GOOD ( 18.22 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Darren Ye Export register read and write interface, add sample reate interface, and update the mtk_memif_set_channel interface for the mt8196 platform. Signed-off-by: Darren Ye --- sound/soc/mediatek/common/mtk-afe-fe-dai.c | 30 ++++++++++++++-------- sound/soc/mediatek/common/mtk-afe-fe-dai.h | 6 +++++ sound/soc/mediatek/common/mtk-base-afe.h | 13 ++++++++++ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c index 3809068f5620..c36dae520f04 100644 --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c @@ -18,7 +18,7 @@ #define AFE_BASE_END_OFFSET 8 -static int mtk_regmap_update_bits(struct regmap *map, int reg, +int mtk_regmap_update_bits(struct regmap *map, int reg, unsigned int mask, unsigned int val, int shift) { @@ -26,13 +26,16 @@ static int mtk_regmap_update_bits(struct regmap *map, int reg, return 0; return regmap_update_bits(map, reg, mask << shift, val << shift); } +EXPORT_SYMBOL(mtk_regmap_update_bits); + +int mtk_regmap_write(struct regmap *map, int reg, unsigned int val) -static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val) { if (reg < 0) return 0; return regmap_write(map, reg, val); } +EXPORT_SYMBOL(mtk_regmap_write); int mtk_afe_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) @@ -459,8 +462,12 @@ int mtk_memif_set_channel(struct mtk_base_afe *afe, struct mtk_base_afe_memif *memif = &afe->memif[id]; unsigned int mono; - if (memif->data->mono_shift < 0) - return 0; + dev_info(afe->dev, "%s(), id: %d, channel: %d\n", __func__, id, channel); + mono = memif->data->mono_invert ^ (channel == 1); + + if (memif->data->mono_shift > 0) + mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg, + 0x1, mono, memif->data->mono_shift); if (memif->data->quad_ch_mask) { unsigned int quad_ch = (channel == 4) ? 1 : 0; @@ -470,11 +477,6 @@ int mtk_memif_set_channel(struct mtk_base_afe *afe, quad_ch, memif->data->quad_ch_shift); } - if (memif->data->mono_invert) - mono = (channel == 1) ? 0 : 1; - else - mono = (channel == 1) ? 1 : 0; - /* for specific configuration of memif mono mode */ if (memif->data->int_odd_flag_reg) mtk_regmap_update_bits(afe->regmap, @@ -482,8 +484,14 @@ int mtk_memif_set_channel(struct mtk_base_afe *afe, 1, mono, memif->data->int_odd_flag_shift); - return mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg, - 1, mono, memif->data->mono_shift); + if (memif->data->ch_num_maskbit) { + dev_info(afe->dev, "%s(), set ch num id: %d, channel: %d\n", __func__, id, channel); + mtk_regmap_update_bits(afe->regmap, memif->data->ch_num_reg, + memif->data->ch_num_maskbit, + channel, memif->data->ch_num_shift); + } + + return 0; } EXPORT_SYMBOL_GPL(mtk_memif_set_channel); diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.h b/sound/soc/mediatek/common/mtk-afe-fe-dai.h index b6d0f2b27e86..64b10ccba291 100644 --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.h +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.h @@ -12,7 +12,13 @@ struct snd_soc_dai_ops; struct mtk_base_afe; struct mtk_base_afe_memif; +struct mtk_base_irq_data; +int mtk_regmap_update_bits(struct regmap *map, int reg, + unsigned int mask, unsigned int val, + int shift); +int mtk_regmap_write(struct regmap *map, int reg, + unsigned int val); int mtk_afe_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream, diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h index f51578b6c50a..01c27fe92e2f 100644 --- a/sound/soc/mediatek/common/mtk-base-afe.h +++ b/sound/soc/mediatek/common/mtk-base-afe.h @@ -53,9 +53,11 @@ struct mtk_base_memif_data { int enable_reg; int enable_shift; int hd_reg; + int hd_mask; int hd_shift; int hd_align_reg; int hd_align_mshift; + int hd_msb_shift; int msb_reg; int msb_shift; int msb_end_reg; @@ -65,6 +67,10 @@ struct mtk_base_memif_data { int ch_num_reg; int ch_num_shift; int ch_num_maskbit; + /* VUL 24~26 only for CM2 */ + int out_on_use_reg; + int out_on_use_mask; + int out_on_use_shift; /* playback memif only */ int pbuf_reg; int pbuf_mask; @@ -72,6 +78,9 @@ struct mtk_base_memif_data { int minlen_reg; int minlen_mask; int minlen_shift; + int maxlen_reg; + int maxlen_mask; + int maxlen_shift; }; struct mtk_base_irq_data { @@ -87,6 +96,10 @@ struct mtk_base_irq_data { int irq_clr_reg; int irq_clr_shift; int irq_status_shift; + int irq_ap_en_reg; + int irq_ap_en_shift; + int irq_scp_en_reg; + int irq_scp_en_shift; }; struct device; From patchwork Fri Mar 7 12:47:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darren.Ye" X-Patchwork-Id: 14006474 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 897DAC19F32 for ; Fri, 7 Mar 2025 13:13:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=skVloWfjYX0Udap1CoSYzWq4P8c37FUFZ0XtJToyWgY=; b=dlxIr/+L99hplgbxB5n/QOpz9d s0phgMhxdexRXnQj7vsXy+e3zpSWeKDBdTkKZkA0j6K6tTLzJp9/R/Fnyihvft83+pVJ5hcdd6EBE Zu+OSXAqFH89TQSaG//KT6VvS5+tMjq2jBR1LIQWRiHFMxIBSMe8h2cxUyUu7vG3nwcJok5Va8E6q Da47H8e+YBBqLoW/QHSWy1uf/qB5WaWaS78fGTfmI1iOweWjTwmWDTbAAnDntqttqMxMx1cyTwPNj wVGYQHLLxFsxqtlwecUWi/Kje/MovIqcgotAGF9Bd6vE+44mJdiUeKFfb4mHnCWk53qdDnKyy5Zlc Xt8Mps7g==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tqXVW-0000000EHbx-0Fnr; Fri, 07 Mar 2025 13:12:54 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqXN5-0000000EG4T-3vrI; Fri, 07 Mar 2025 13:04:13 +0000 X-UUID: 86566740fb5211ef83f2a1c9db70dae0-20250307 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=skVloWfjYX0Udap1CoSYzWq4P8c37FUFZ0XtJToyWgY=; b=bh8Wr3+rqZIHuPzwFMKs8tSX6XCy6L0ksqKEP44Dh2x+DQrW0RSG9c2gDBYE5aQfAH2b7LiwLYGnDQ2Nh4qvCIqH4vKJCU3fMWSd38iLGx2JpYyj/2edNnzE9sFE39kbcatEUgz4owR7vB6WZvZyaLFP1qZea8EjBP++9Z628v0=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:5fee789a-fa7c-4499-b273-0e012c042c35,IP:0,UR L:0,TC:0,Content:0,EDM:-25,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION :release,TS:-25 X-CID-META: VersionHash:0ef645f,CLOUDID:d24827ce-23b9-4c94-add0-e827a7999e28,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:1, IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV: 0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 86566740fb5211ef83f2a1c9db70dae0-20250307 Received: from mtkmbs13n1.mediatek.inc [(172.21.101.193)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1885396598; Fri, 07 Mar 2025 05:48:53 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 7 Mar 2025 20:48:50 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 7 Mar 2025 20:48:49 +0800 From: Darren.Ye To: Liam Girdwood , Mark Brown , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Matthias Brugger , AngeloGioacchino Del Regno , Jaroslav Kysela , Takashi Iwai , "Linus Walleij" , Bartosz Golaszewski CC: , , , , , , Darren Ye Subject: [PATCH 02/14] ASoC: mediatek: common: modify mtk afe platform driver for mt8196 Date: Fri, 7 Mar 2025 20:47:28 +0800 Message-ID: <20250307124841.23777-3-darren.ye@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250307124841.23777-1-darren.ye@mediatek.com> References: <20250307124841.23777-1-darren.ye@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250307_050411_974775_1911E1DC X-CRM114-Status: GOOD ( 17.37 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Darren Ye Mofify the pcm pointer interface to support 64-bit address access. Signed-off-by: Darren Ye --- .../mediatek/common/mtk-afe-platform-driver.c | 63 ++++++++++++++----- .../mediatek/common/mtk-afe-platform-driver.h | 5 ++ 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c index 6b6330583941..5d8f4421e665 100644 --- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c +++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c @@ -77,6 +77,16 @@ int mtk_afe_add_sub_dai_control(struct snd_soc_component *component) } EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control); +int mtk_afe_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + /* set the wait_for_avail to 2 sec*/ + substream->wait_time = msecs_to_jiffies(2 * 1000); + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_afe_pcm_open); + snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -86,29 +96,44 @@ snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component, const struct mtk_base_memif_data *memif_data = memif->data; struct regmap *regmap = afe->regmap; struct device *dev = afe->dev; - int reg_ofs_base = memif_data->reg_ofs_base; - int reg_ofs_cur = memif_data->reg_ofs_cur; - unsigned int hw_ptr = 0, hw_base = 0; - int ret, pcm_ptr_bytes; - - ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr); - if (ret || hw_ptr == 0) { - dev_err(dev, "%s hw_ptr err\n", __func__); - pcm_ptr_bytes = 0; + unsigned int hw_ptr_lower32 = 0, hw_ptr_upper32 = 0; + unsigned int hw_base_lower32 = 0, hw_base_upper32 = 0; + unsigned long long hw_ptr = 0, hw_base = 0; + int ret; + unsigned long long pcm_ptr_bytes = 0; + + ret = regmap_read(regmap, memif_data->reg_ofs_cur, &hw_ptr_lower32); + if (ret || hw_ptr_lower32 == 0) { + dev_err(dev, "%s hw_ptr_lower32 err\n", __func__); goto POINTER_RETURN_FRAMES; } - ret = regmap_read(regmap, reg_ofs_base, &hw_base); - if (ret || hw_base == 0) { - dev_err(dev, "%s hw_ptr err\n", __func__); - pcm_ptr_bytes = 0; - goto POINTER_RETURN_FRAMES; + if (memif_data->reg_ofs_cur_msb) { + ret = regmap_read(regmap, memif_data->reg_ofs_cur_msb, &hw_ptr_upper32); + if (ret) { + dev_err(dev, "%s hw_ptr_upper32 err\n", __func__); + goto POINTER_RETURN_FRAMES; + } } - pcm_ptr_bytes = hw_ptr - hw_base; + ret = regmap_read(regmap, memif_data->reg_ofs_base, &hw_base_lower32); + if (ret || hw_base_lower32 == 0) { + dev_err(dev, "%s hw_base_lower32 err\n", __func__); + goto POINTER_RETURN_FRAMES; + } + if (memif_data->reg_ofs_base_msb) { + ret = regmap_read(regmap, memif_data->reg_ofs_base_msb, &hw_base_upper32); + if (ret) { + dev_err(dev, "%s hw_base_upper32 err\n", __func__); + goto POINTER_RETURN_FRAMES; + } + } + hw_ptr = ((unsigned long long)hw_ptr_upper32 << 32) + hw_ptr_lower32; + hw_base = ((unsigned long long)hw_base_upper32 << 32) + hw_base_lower32; POINTER_RETURN_FRAMES: - return bytes_to_frames(substream->runtime, pcm_ptr_bytes); + pcm_ptr_bytes = MTK_WORD_SIZE_ALIGN(hw_ptr - hw_base); + return bytes_to_frames(substream->runtime, (ssize_t)pcm_ptr_bytes); } EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer); @@ -143,6 +168,12 @@ static int mtk_afe_component_probe(struct snd_soc_component *component) return 0; } +void mtk_afe_pcm_free(struct snd_soc_component *component, struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_free_for_all(pcm); +} +EXPORT_SYMBOL_GPL(mtk_afe_pcm_free); + const struct snd_soc_component_driver mtk_afe_pcm_platform = { .name = AFE_PCM_NAME, .pointer = mtk_afe_pcm_pointer, diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.h b/sound/soc/mediatek/common/mtk-afe-platform-driver.h index fcc923b88f12..948998968a45 100644 --- a/sound/soc/mediatek/common/mtk-afe-platform-driver.h +++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.h @@ -12,15 +12,20 @@ #define AFE_PCM_NAME "mtk-afe-pcm" extern const struct snd_soc_component_driver mtk_afe_pcm_platform; +#define MTK_WORD_SIZE_ALIGN(x) ((x) & (0xfffffffff0)) + struct mtk_base_afe; struct snd_pcm; struct snd_soc_component; struct snd_soc_pcm_runtime; +int mtk_afe_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream); snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream); int mtk_afe_pcm_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd); +void mtk_afe_pcm_free(struct snd_soc_component *component, struct snd_pcm *pcm); int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe); int mtk_afe_add_sub_dai_control(struct snd_soc_component *component); From patchwork Fri Mar 7 12:47:30 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darren.Ye" X-Patchwork-Id: 14006445 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 46139C19F32 for ; Fri, 7 Mar 2025 12:54:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=3YKZgSoMuTXktamYFQTdo3ZV/YxOMNDKsaOxZk019Kc=; b=hrqASlFmRuAfLXRLLe+WwdHI4f f8khTYMkgVeRpVNfaeQeC3nIMRf8oSOINq6Zc4mLOPOAaPFCHvdbKzHxUzJjS2qI7B7DIjll5Qh9x u0z15DcdhZmCab+L4DTVv/VY6E+bi7pptpu6bJpiVcnngoW7mmIfqVVwqTFR6bvXrPM8pxG8qBYij nN4J+ryeAzDbgI1l81jfwQl5mHuAz/CN/n/95LjxxEPperY0OZnQLW1uda5lQZA40zT2PYiHVXVTR Ew8z13Sh28Touh+0WZgMhOVBLlChLIkwQCfsGIl0KstKTmN07iRrC7PCSJzn3nZeNpo5zqTndfYNX 4+7+cv3w==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tqXDa-0000000EEn9-2wyx; Fri, 07 Mar 2025 12:54:22 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqX8P-0000000EDlK-2Tmk; Fri, 07 Mar 2025 12:49:02 +0000 X-UUID: 8968e9b2fb5211efa1e849db4cc18d44-20250307 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=3YKZgSoMuTXktamYFQTdo3ZV/YxOMNDKsaOxZk019Kc=; b=ZECAXa767BcFHiJMBToLMtyuqrBSeeXcyRVCVfJRCpiTsRWbMsq0JnHx9yI7Okg46OPTkfnsjxhmmzcHwOyknDpV8FqMBZdyt6sunjMp7RZ3QQjV/Gtf3tyDidpzJLcBk56FbbKTtgYWpMqoaiUS7rhYRU1+wY9sow/XU5sJQ6k=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:9dbd4278-e8bb-49f6-b37a-70f87c3327b9,IP:0,UR L:0,TC:0,Content:0,EDM:-25,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION :release,TS:-25 X-CID-META: VersionHash:0ef645f,CLOUDID:7613d249-a527-43d8-8af6-bc8b32d9f5e9,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:1, IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV: 0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 8968e9b2fb5211efa1e849db4cc18d44-20250307 Received: from mtkmbs14n2.mediatek.inc [(172.21.101.76)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1219185272; Fri, 07 Mar 2025 05:48:58 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n1.mediatek.inc (172.21.101.193) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 7 Mar 2025 20:48:55 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 7 Mar 2025 20:48:54 +0800 From: Darren.Ye To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Jaroslav Kysela , Takashi Iwai , Linus Walleij , Bartosz Golaszewski CC: , , , , , , Darren Ye Subject: [PATCH 04/14] ASoC: mediatek: mt8196: add common interface for mt8196 DAI driver Date: Fri, 7 Mar 2025 20:47:30 +0800 Message-ID: <20250307124841.23777-5-darren.ye@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250307124841.23777-1-darren.ye@mediatek.com> References: <20250307124841.23777-1-darren.ye@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250307_044901_639667_C89D0C04 X-CRM114-Status: GOOD ( 15.38 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Darren Ye Implement sample rate conversion and set private data for mt8196. Signed-off-by: Darren Ye --- .../soc/mediatek/mt8196/mt8196-afe-control.c | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-control.c diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-control.c b/sound/soc/mediatek/mt8196/mt8196-afe-control.c new file mode 100644 index 000000000000..bb85f4ad8585 --- /dev/null +++ b/sound/soc/mediatek/mt8196/mt8196-afe-control.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek ALSA SoC Audio Control + * + * Copyright (c) 2024 MediaTek Inc. + * Author: Darren Ye + */ + +#include "mt8196-afe-common.h" +#include + +unsigned int mt8196_general_rate_transform(struct device *dev, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_IPM2P0_RATE_8K; + case 11025: + return MTK_AFE_IPM2P0_RATE_11K; + case 12000: + return MTK_AFE_IPM2P0_RATE_12K; + case 16000: + return MTK_AFE_IPM2P0_RATE_16K; + case 22050: + return MTK_AFE_IPM2P0_RATE_22K; + case 24000: + return MTK_AFE_IPM2P0_RATE_24K; + case 32000: + return MTK_AFE_IPM2P0_RATE_32K; + case 44100: + return MTK_AFE_IPM2P0_RATE_44K; + case 48000: + return MTK_AFE_IPM2P0_RATE_48K; + case 88200: + return MTK_AFE_IPM2P0_RATE_88K; + case 96000: + return MTK_AFE_IPM2P0_RATE_96K; + case 176400: + return MTK_AFE_IPM2P0_RATE_176K; + case 192000: + return MTK_AFE_IPM2P0_RATE_192K; + /* not support 260K */ + case 352800: + return MTK_AFE_IPM2P0_RATE_352K; + case 384000: + return MTK_AFE_IPM2P0_RATE_384K; + default: + dev_info(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, + rate, MTK_AFE_IPM2P0_RATE_48K); + return MTK_AFE_IPM2P0_RATE_48K; + } +} + +static unsigned int pcm_rate_transform(struct device *dev, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_PCM_RATE_8K; + case 16000: + return MTK_AFE_PCM_RATE_16K; + case 32000: + return MTK_AFE_PCM_RATE_32K; + case 48000: + return MTK_AFE_PCM_RATE_48K; + default: + dev_info(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, + rate, MTK_AFE_PCM_RATE_32K); + return MTK_AFE_PCM_RATE_32K; + } +} + +unsigned int mt8196_rate_transform(struct device *dev, + unsigned int rate, int aud_blk) +{ + switch (aud_blk) { + case MT8196_DAI_PCM_0: + case MT8196_DAI_PCM_1: + return pcm_rate_transform(dev, rate); + default: + return mt8196_general_rate_transform(dev, rate); + } +} + +int mt8196_dai_set_priv(struct mtk_base_afe *afe, int id, + int priv_size, const void *priv_data) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + void *temp_data; + + temp_data = devm_kzalloc(afe->dev, + priv_size, + GFP_KERNEL); + if (!temp_data) + return -ENOMEM; + + if (priv_data) + memcpy(temp_data, priv_data, priv_size); + + if (id >= MT8196_DAI_NUM || id < 0) + return -EINVAL; + + afe_priv->dai_priv[id] = temp_data; + + return 0; +} + From patchwork Fri Mar 7 12:47:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darren.Ye" X-Patchwork-Id: 14006454 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id BB82DC19F32 for ; Fri, 7 Mar 2025 12:57:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=GVVvuFqlzvu5sPz8ho1aRl4B81EpOIBwcWCUoVpBuVM=; b=Q8+vHMe8N0F1Vwbo9clOT1OStQ rmACaCARXTIU4CIezclvgyBh+QfDLJGTpTvSyGTxWFb9+so6xP13FwRA/MePTCrF6VL4rJIMt5RzE FKVMRGgfxTvFBZGlpQnM0y9UtHXDFyIX99yVMJedzELzYDaZ6UqYj3ZByLH6sO9UvjMR3Hly87XcP 2iqdg556Wdenu012wGtig2Y4hNugkjENVvyHLx+cmt1GcCW1aYpVzUialesTiReQHkf4uqESNXClx XkfKnH6iuu063RkP4CGhyKgj6bsWByfwaxjoj8llr3iNIu4UsFE7bGyZgFDnwvAh4GBo3o7M8UjJ2 c8qfI3Kw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tqXGm-0000000EFCM-3R9O; Fri, 07 Mar 2025 12:57:40 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqX8T-0000000EDmH-1Qrg; Fri, 07 Mar 2025 12:49:06 +0000 X-UUID: 8a020d0efb5211efa1e849db4cc18d44-20250307 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=GVVvuFqlzvu5sPz8ho1aRl4B81EpOIBwcWCUoVpBuVM=; b=SGYXn9V3AGkBmu5P1AdIubJeBdVz2jlm2OArYJcCz/J6kfwFFwS0QPhOuWx/I1F3+5NK5TLPzuLZmEG2CSgZwbbDck+/z5eZGXyVghxqBLfdhTaYnRxvQZE2HThisGAoKA7o4mdgPnpx4vc18WSsQzLufYxtue88UIQy9AkPIo0=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:86e9ce1b-b707-4b1b-be7e-5c2bf1c937c3,IP:0,UR L:0,TC:0,Content:0,EDM:-25,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION :release,TS:-25 X-CID-META: VersionHash:0ef645f,CLOUDID:fcca0dc6-16da-468a-87f7-8ca8d6b3b9f7,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:1, IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV: 0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 8a020d0efb5211efa1e849db4cc18d44-20250307 Received: from mtkmbs14n2.mediatek.inc [(172.21.101.76)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 877317264; Fri, 07 Mar 2025 05:48:59 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n1.mediatek.inc (172.21.101.193) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 7 Mar 2025 20:48:57 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 7 Mar 2025 20:48:56 +0800 From: Darren.Ye To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Jaroslav Kysela , Takashi Iwai , Linus Walleij , Bartosz Golaszewski CC: , , , , , , Darren Ye Subject: [PATCH 05/14] ASoC: mediatek: mt8196: support audio clock control Date: Fri, 7 Mar 2025 20:47:31 +0800 Message-ID: <20250307124841.23777-6-darren.ye@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250307124841.23777-1-darren.ye@mediatek.com> References: <20250307124841.23777-1-darren.ye@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250307_044905_405468_04C1791F X-CRM114-Status: GOOD ( 17.37 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Darren Ye Add audio clock wrapper and audio tuner control. Signed-off-by: Darren Ye --- sound/soc/mediatek/mt8196/mt8196-afe-clk.c | 698 +++++++++++++++++++++ sound/soc/mediatek/mt8196/mt8196-afe-clk.h | 313 +++++++++ 2 files changed, 1011 insertions(+) create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.c create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.h diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.c b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c new file mode 100644 index 000000000000..d1407d7bf775 --- /dev/null +++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c @@ -0,0 +1,698 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mt8196-afe-clk.c -- Mediatek 8196 afe clock ctrl + * + * Copyright (c) 2024 MediaTek Inc. + * Author: Darren Ye + */ + +#include +#include +#include +#include "mt8196-afe-common.h" +#include "mt8196-afe-clk.h" + +static DEFINE_MUTEX(mutex_request_dram); + +static const char *aud_clks[CLK_NUM] = { + [CLK_HOPPING] = "aud_hopping_clk", + [CLK_F26M] = "aud_f26m_clk", + [CLK_UL0_ADC_CLK] = "aud_ul0_adc_clk", + [CLK_UL0_ADC_HIRES_CLK] = "aud_ul0_adc_hires_clk", + [CLK_UL1_ADC_CLK] = "aud_ul1_adc_clk", + [CLK_UL1_ADC_HIRES_CLK] = "aud_ul1_adc_hires_clk", + [CLK_APLL1] = "aud_apll1_clk", + [CLK_APLL2] = "aud_apll2_clk", + [CLK_APLL1_TUNER] = "aud_apll_tuner1_clk", + [CLK_APLL2_TUNER] = "aud_apll_tuner2_clk", + [CLK_VLP_MUX_AUDIOINTBUS] = "vlp_mux_audio_int", + [CLK_VLP_MUX_AUD_ENG1] = "vlp_mux_aud_eng1", + [CLK_VLP_MUX_AUD_ENG2] = "vlp_mux_aud_eng2", + [CLK_VLP_MUX_AUDIO_H] = "vlp_mux_audio_h", + [CLK_VLP_CLK26M] = "vlp_clk26m_clk", + [CLK_CK_MAINPLL_D4_D4] = "ck_mainpll_d4_d4", + [CLK_CK_MUX_AUD_1] = "ck_mux_aud_1", + [CLK_CK_APLL1_CK] = "ck_apll1_ck", + [CLK_CK_MUX_AUD_2] = "ck_mux_aud_2", + [CLK_CK_APLL2_CK] = "ck_apll2_ck", + [CLK_CK_APLL1_D4] = "ck_apll1_d4", + [CLK_CK_APLL2_D4] = "ck_apll2_d4", + [CLK_CK_I2SIN0_M_SEL] = "ck_i2sin0_m_sel", + [CLK_CK_I2SIN1_M_SEL] = "ck_i2sin1_m_sel", + [CLK_CK_FMI2S_M_SEL] = "ck_fmi2s_m_sel", + [CLK_CK_TDMOUT_M_SEL] = "ck_tdmout_m_sel", + [CLK_CK_APLL12_DIV_I2SIN0] = "ck_apll12_div_i2sin0", + [CLK_CK_APLL12_DIV_I2SIN1] = "ck_apll12_div_i2sin1", + [CLK_CK_APLL12_DIV_FMI2S] = "ck_apll12_div_fmi2s", + [CLK_CK_APLL12_DIV_TDMOUT_M] = "ck_apll12_div_tdmout_m", + [CLK_CK_APLL12_DIV_TDMOUT_B] = "ck_apll12_div_tdmout_b", + [CLK_CK_ADSP_SEL] = "ck_adsp_sel", + [CLK_CLK26M] = "ck_clk26m_clk", +}; + +int mt8196_set_audio_int_bus_parent(struct mtk_base_afe *afe, + int clk_id, bool int_bus) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + struct clk *clk; + int ret; + + if (clk_id >= CLK_NUM || clk_id < 0) + return -EINVAL; + + clk = int_bus ? afe_priv->clk[CLK_VLP_MUX_AUDIOINTBUS] : + afe_priv->clk[CLK_VLP_MUX_AUDIO_H]; + ret = clk_set_parent(clk, afe_priv->clk[clk_id]); + if (ret) + dev_err(afe->dev, "%s() clk_set_parent %s fail %d, int_bus %d\n", + __func__, aud_clks[clk_id], ret, int_bus); + + return ret; +} + +static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int ret = 0; + + dev_dbg(afe->dev, "%s(), enable: %d\n", __func__, enable); + + if (enable) { + ret = clk_prepare_enable(afe_priv->clk[CLK_CK_MUX_AUD_1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_CK_MUX_AUD_1], ret); + goto EXIT; + } + ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_1], + afe_priv->clk[CLK_CK_APLL1_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_CK_MUX_AUD_1], + aud_clks[CLK_CK_APLL1_CK], ret); + goto EXIT; + } + + /* 180.6336 / 4 = 45.1584MHz */ + ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUD_ENG1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_VLP_MUX_AUD_ENG1], ret); + goto EXIT; + } + ret = clk_set_parent(afe_priv->clk[CLK_VLP_MUX_AUD_ENG1], + afe_priv->clk[CLK_CK_APLL1_D4]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_VLP_MUX_AUD_ENG1], + aud_clks[CLK_CK_APLL1_D4], ret); + goto EXIT; + } + ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_VLP_MUX_AUDIO_H], ret); + goto EXIT; + } + + mt8196_set_audio_int_bus_parent(afe, CLK_CK_APLL1_CK, false); + } else { + ret = clk_set_parent(afe_priv->clk[CLK_VLP_MUX_AUD_ENG1], + afe_priv->clk[CLK_VLP_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_VLP_MUX_AUD_ENG1], + aud_clks[CLK_VLP_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUD_ENG1]); + + ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_1], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_CK_MUX_AUD_1], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_CK_MUX_AUD_1]); + + mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, false); + clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]); + } + +EXIT: + return 0; +} + +static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int ret = 0; + + dev_dbg(afe->dev, "%s(), enable: %d\n", __func__, enable); + + if (enable) { + ret = clk_prepare_enable(afe_priv->clk[CLK_CK_MUX_AUD_2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_CK_MUX_AUD_2], ret); + goto EXIT; + } + ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_2], + afe_priv->clk[CLK_CK_APLL2_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_CK_MUX_AUD_2], + aud_clks[CLK_CK_APLL2_CK], ret); + goto EXIT; + } + + /* 196.608 / 4 = 49.152MHz */ + ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUD_ENG2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_VLP_MUX_AUD_ENG2], ret); + goto EXIT; + } + ret = clk_set_parent(afe_priv->clk[CLK_VLP_MUX_AUD_ENG2], + afe_priv->clk[CLK_CK_APLL2_D4]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_VLP_MUX_AUD_ENG2], + aud_clks[CLK_CK_APLL2_D4], ret); + goto EXIT; + } + ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_VLP_MUX_AUDIO_H], ret); + goto EXIT; + } + + mt8196_set_audio_int_bus_parent(afe, CLK_CK_APLL2_CK, false); + } else { + ret = clk_set_parent(afe_priv->clk[CLK_VLP_MUX_AUD_ENG2], + afe_priv->clk[CLK_VLP_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_VLP_MUX_AUD_ENG2], + aud_clks[CLK_VLP_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUD_ENG2]); + + ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_2], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_CK_MUX_AUD_2], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_CK_MUX_AUD_2]); + + mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, false); + clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]); + } +EXIT: + return 0; +} + +int mt8196_afe_disable_apll(struct mtk_base_afe *afe) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int ret = 0; + + dev_dbg(afe->dev, "%s() successfully start\n", __func__); + + ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_VLP_MUX_AUDIO_H], ret); + goto EXIT; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_CK_MUX_AUD_1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_CK_MUX_AUD_1], ret); + goto EXIT; + } + + ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_1], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_CK_MUX_AUD_1], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + ret = clk_prepare_enable(afe_priv->clk[CLK_CK_MUX_AUD_2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_CK_MUX_AUD_2], ret); + goto EXIT; + } + + ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_2], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_CK_MUX_AUD_2], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + + clk_disable_unprepare(afe_priv->clk[CLK_CK_MUX_AUD_1]); + clk_disable_unprepare(afe_priv->clk[CLK_CK_MUX_AUD_2]); + mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, false); + clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]); + + return 0; +EXIT: + return ret; +} + +static int mt8196_afe_apll_init(struct mtk_base_afe *afe) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + /* VLP_APLL1_CON0 = 0x6f28bd4c + * VLP_APLL2_CON2 = 0x78FD5264 + * VLP_APLL1_TUNER_CON0 = 0x6f28bd4d + * VLP_APLL2_TUNER_CON0 = 0x78fd5265 + */ + if (afe_priv->vlp_ck) { + regmap_write(afe_priv->vlp_ck, VLP_APLL1_TUNER_CON0, 0x6f28bd4d); + regmap_write(afe_priv->vlp_ck, VLP_APLL2_TUNER_CON0, 0x78fd5265); + } else { + dev_warn(afe->dev, "%s vlp_ck regmap is null ptr\n", __func__); + } + return 0; +} + +int mt8196_afe_enable_clock(struct mtk_base_afe *afe) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int ret = 0; + + ret = clk_prepare_enable(afe_priv->clk[CLK_CK_ADSP_SEL]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_CK_ADSP_SEL], ret); + goto CLK_CK_ADSP_SEL_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUDIOINTBUS]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_VLP_MUX_AUDIOINTBUS], ret); + goto CLK_MUX_AUDIO_INTBUS_ERR; + } + ret = mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_VLP_MUX_AUDIO_H], ret); + goto CLK_AUDIO_H_ERR; + } + mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, false); + + /* IPM2.0: USE HOPPING & 26M */ + ret = clk_prepare_enable(afe_priv->clk[CLK_HOPPING]); + if (ret) { + dev_err(afe->dev, "%s() clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_HOPPING], ret); + goto CLK_AFE_ERR; + } + ret = clk_prepare_enable(afe_priv->clk[CLK_F26M]); + if (ret) { + dev_err(afe->dev, "%s() clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_F26M], ret); + goto CLK_AFE_ERR; + } + + return 0; + +CLK_AFE_ERR: + /* IPM2.0: Use HOPPING & 26M */ + clk_disable_unprepare(afe_priv->clk[CLK_HOPPING]); + clk_disable_unprepare(afe_priv->clk[CLK_F26M]); +CLK_AUDIO_H_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]); +CLK_MUX_AUDIO_INTBUS_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIOINTBUS]); +CLK_CK_ADSP_SEL_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_CK_ADSP_SEL]); + return ret; +} + +void mt8196_afe_disable_clock(struct mtk_base_afe *afe) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + dev_dbg(afe->dev, "%s() successfully start\n", __func__); + + /* IPM2.0: Use HOPPING & 26M */ + clk_disable_unprepare(afe_priv->clk[CLK_HOPPING]); + clk_disable_unprepare(afe_priv->clk[CLK_F26M]); + mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, false); + clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]); + mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, true); + clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIOINTBUS]); + clk_disable_unprepare(afe_priv->clk[CLK_CK_ADSP_SEL]); +} + +int mt8196_afe_dram_request(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + dev_dbg(dev, "%s(), dram_resource_counter %d\n", + __func__, afe_priv->dram_resource_counter); + + mutex_lock(&mutex_request_dram); + + afe_priv->dram_resource_counter++; + mutex_unlock(&mutex_request_dram); + + return 0; +} + +int mt8196_afe_dram_release(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + dev_dbg(dev, "%s(), dram_resource_counter %d\n", + __func__, afe_priv->dram_resource_counter); + + mutex_lock(&mutex_request_dram); + afe_priv->dram_resource_counter--; + + if (afe_priv->dram_resource_counter < 0) { + dev_warn(dev, "%s(), dram_resource_counter %d\n", + __func__, afe_priv->dram_resource_counter); + afe_priv->dram_resource_counter = 0; + } + mutex_unlock(&mutex_request_dram); + return 0; +} + +int mt8196_apll1_enable(struct mtk_base_afe *afe) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* setting for APLL */ + apll1_mux_setting(afe, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL1], ret); + goto ERR_CLK_APLL1; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1_TUNER]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL1_TUNER], ret); + goto ERR_CLK_APLL1_TUNER; + } + + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, + 0x0000FFF7, 0x00000372); + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1); + + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, + AUDIO_APLL1_EN_ON_MASK_SFT, + 0x1 << AUDIO_APLL1_EN_ON_SFT); + return 0; + +ERR_CLK_APLL1_TUNER: + clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]); +ERR_CLK_APLL1: + clk_disable_unprepare(afe_priv->clk[CLK_APLL1]); + + return ret; +} + +void mt8196_apll1_disable(struct mtk_base_afe *afe) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, + AUDIO_APLL1_EN_ON_MASK_SFT, + 0x0 << AUDIO_APLL1_EN_ON_SFT); + + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x0); + + clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]); + clk_disable_unprepare(afe_priv->clk[CLK_APLL1]); + + apll1_mux_setting(afe, false); +} + +int mt8196_apll2_enable(struct mtk_base_afe *afe) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* setting for APLL */ + apll2_mux_setting(afe, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL2], ret); + goto ERR_CLK_APLL2; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2_TUNER]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL2_TUNER], ret); + goto ERR_CLK_APLL2_TUNER; + } + + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, + 0x0000FFF7, 0x00000374); + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1); + + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, + AUDIO_APLL2_EN_ON_MASK_SFT, + 0x1 << AUDIO_APLL2_EN_ON_SFT); + + return 0; + +ERR_CLK_APLL2_TUNER: + clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]); +ERR_CLK_APLL2: + clk_disable_unprepare(afe_priv->clk[CLK_APLL2]); + + return ret; + + return 0; +} + +void mt8196_apll2_disable(struct mtk_base_afe *afe) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, + AUDIO_APLL2_EN_ON_MASK_SFT, + 0x0 << AUDIO_APLL2_EN_ON_SFT); + + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x0); + + clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]); + clk_disable_unprepare(afe_priv->clk[CLK_APLL2]); + + apll2_mux_setting(afe, false); +} + +int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll) +{ + return (apll == MT8196_APLL1) ? 180633600 : 196608000; +} + +int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate) +{ + return ((rate % 8000) == 0) ? MT8196_APLL2 : MT8196_APLL1; +} + +int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name) +{ + if (strcmp(name, APLL1_W_NAME) == 0) + return MT8196_APLL1; + else + return MT8196_APLL2; +} + +/* mck */ +struct mt8196_mck_div { + int m_sel_id; + int div_clk_id; +}; + +static const struct mt8196_mck_div mck_div[MT8196_MCK_NUM] = { + [MT8196_I2SIN0_MCK] = { + .m_sel_id = CLK_CK_I2SIN0_M_SEL, + .div_clk_id = CLK_CK_APLL12_DIV_I2SIN0, + }, + [MT8196_I2SIN1_MCK] = { + .m_sel_id = CLK_CK_I2SIN1_M_SEL, + .div_clk_id = CLK_CK_APLL12_DIV_I2SIN1, + }, + [MT8196_FMI2S_MCK] = { + .m_sel_id = CLK_CK_FMI2S_M_SEL, + .div_clk_id = CLK_CK_APLL12_DIV_FMI2S, + }, + [MT8196_TDMOUT_MCK] = { + .m_sel_id = CLK_CK_TDMOUT_M_SEL, + .div_clk_id = CLK_CK_APLL12_DIV_TDMOUT_M, + }, + [MT8196_TDMOUT_BCK] = { + .m_sel_id = -1, + .div_clk_id = CLK_CK_APLL12_DIV_TDMOUT_B, + }, +}; + +int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int apll = mt8196_get_apll_by_rate(afe, rate); + int apll_clk_id = apll == MT8196_APLL1 ? + CLK_CK_MUX_AUD_1 : CLK_CK_MUX_AUD_2; + int m_sel_id = 0; + int div_clk_id = 0; + int ret = 0; + + dev_dbg(afe->dev, "%s(), mck_id: %d\n", __func__, mck_id); + + if (mck_id >= MT8196_MCK_NUM || mck_id < 0) + return -EINVAL; + + m_sel_id = mck_div[mck_id].m_sel_id; + div_clk_id = mck_div[mck_id].div_clk_id; + + /* select apll */ + if (m_sel_id >= 0) { + ret = clk_prepare_enable(afe_priv->clk[m_sel_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[m_sel_id], ret); + return ret; + } + ret = clk_set_parent(afe_priv->clk[m_sel_id], + afe_priv->clk[apll_clk_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[m_sel_id], + aud_clks[apll_clk_id], ret); + return ret; + } + } + + /* enable div, set rate */ + if (div_clk_id < 0) { + dev_err(afe->dev, "%s(), invalid div_clk_id %d\n", __func__, div_clk_id); + return -EINVAL; + } + if (div_clk_id == CLK_CK_APLL12_DIV_TDMOUT_B) + rate = rate * 16; + ret = clk_prepare_enable(afe_priv->clk[div_clk_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[div_clk_id], ret); + return ret; + } + ret = clk_set_rate(afe_priv->clk[div_clk_id], rate); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n", + __func__, aud_clks[div_clk_id], + rate, ret); + return ret; + } + return 0; +} + +int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int m_sel_id = 0; + int div_clk_id = 0; + + dev_dbg(afe->dev, "%s(), mck_id: %d.\n", __func__, mck_id); + + if (mck_id < 0) { + dev_err(afe->dev, "%s(), mck_id = %d < 0\n", + __func__, mck_id); + return -EINVAL; + } + + m_sel_id = mck_div[mck_id].m_sel_id; + div_clk_id = mck_div[mck_id].div_clk_id; + + if (div_clk_id < 0) { + dev_err(afe->dev, "%s(), div_clk_id = %d < 0\n", + __func__, div_clk_id); + return -EINVAL; + } + clk_disable_unprepare(afe_priv->clk[div_clk_id]); + + if (m_sel_id >= 0) + clk_disable_unprepare(afe_priv->clk[m_sel_id]); + + return 0; +} + +int mt8196_init_clock(struct mtk_base_afe *afe) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int i = 0; + + afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk), + GFP_KERNEL); + if (!afe_priv->clk) + return -ENOMEM; + + for (i = 0; i < CLK_NUM; i++) { + if (!aud_clks[i]) { + dev_err(afe->dev, "%s(), clk id %d not define!!!\n", + __func__, i); + } + + afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]); + if (IS_ERR(afe_priv->clk[i])) { + dev_err(afe->dev, "%s devm_clk_get %s fail, ret %ld\n", + __func__, + aud_clks[i], PTR_ERR(afe_priv->clk[i])); + afe_priv->clk[i] = NULL; + } + } + + afe_priv->vlp_ck = syscon_regmap_lookup_by_phandle(afe->dev->of_node, + "vlpcksys"); + if (IS_ERR(afe_priv->vlp_ck)) { + dev_err(afe->dev, "%s() Cannot find vlpcksys: %ld\n", + __func__, PTR_ERR(afe_priv->vlp_ck)); + afe_priv->vlp_ck = NULL; + } + + afe_priv->cksys_ck = syscon_regmap_lookup_by_phandle(afe->dev->of_node, + "cksys"); + if (IS_ERR(afe_priv->cksys_ck)) { + dev_err(afe->dev, "%s() Cannot find cksys controller: %ld\n", + __func__, PTR_ERR(afe_priv->cksys_ck)); + afe_priv->cksys_ck = NULL; + } + + mt8196_afe_apll_init(afe); + mt8196_afe_disable_apll(afe); + + return 0; +} diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.h b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h new file mode 100644 index 000000000000..0094aebc8bba --- /dev/null +++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h @@ -0,0 +1,313 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8196-afe-clk.h -- Mediatek 8196 afe clock ctrl definition + * + * Copyright (c) 2024 MediaTek Inc. + * Author: Darren Ye + */ + +#ifndef _MT8196_AFE_CLOCK_CTRL_H_ +#define _MT8196_AFE_CLOCK_CTRL_H_ + +// vlp_cksys_clk: 0x1c016000 +#define VLP_AP_PLL_CON3 0x0264 +#define VLP_APLL1_CON0 0x0274 +#define VLP_APLL1_CON1 0x0278 +#define VLP_APLL1_CON2 0x027c +#define VLP_APLL1_CON4 0x0284 +#define VLP_APLL1_TUNER_CON0 0x02a4 + +#define VLP_APLL2_CON0 0x028c +#define VLP_APLL2_CON1 0x0290 +#define VLP_APLL2_CON2 0x0294 +#define VLP_APLL2_CON4 0x029c +#define VLP_APLL2_TUNER_CON0 0x02a8 +#define VLP_CLK_CFG_UPDATE1 0x0008 + +// cksys_clk: 0x10000000 +#define CLK_CFG_13 0x00e0 +#define CLK_CFG_UPDATE1 0x0008 + +#define CLK_AUDDIV_0 0x020c +#define CLK_AUDDIV_2 0x0214 +#define CLK_AUDDIV_5 0x0228 + +#define CKSYS_AUD_TOP_CFG 0x0218 + +/* CLK_AUDDIV_0 */ +#define APLL12_DIV_I2SIN0_PDN_SFT 0 +#define APLL12_DIV_I2SIN0_PDN_MASK 0x1 +#define APLL12_DIV_I2SIN0_PDN_MASK_SFT (0x1 << 0) +#define APLL12_DIV_I2SIN1_PDN_SFT 1 +#define APLL12_DIV_I2SIN1_PDN_MASK 0x1 +#define APLL12_DIV_I2SIN1_PDN_MASK_SFT (0x1 << 1) +#define APLL12_DIV_I2SIN2_PDN_SFT 2 +#define APLL12_DIV_I2SIN2_PDN_MASK 0x1 +#define APLL12_DIV_I2SIN2_PDN_MASK_SFT (0x1 << 2) +#define APLL12_DIV_I2SIN3_PDN_SFT 3 +#define APLL12_DIV_I2SIN3_PDN_MASK 0x1 +#define APLL12_DIV_I2SIN3_PDN_MASK_SFT (0x1 << 3) +#define APLL12_DIV_I2SIN4_PDN_SFT 4 +#define APLL12_DIV_I2SIN4_PDN_MASK 0x1 +#define APLL12_DIV_I2SIN4_PDN_MASK_SFT (0x1 << 4) +#define APLL12_DIV_I2SIN6_PDN_SFT 5 +#define APLL12_DIV_I2SIN6_PDN_MASK 0x1 +#define APLL12_DIV_I2SIN6_PDN_MASK_SFT (0x1 << 5) +#define APLL12_DIV_I2SOUT0_PDN_SFT 6 +#define APLL12_DIV_I2SOUT0_PDN_MASK 0x1 +#define APLL12_DIV_I2SOUT0_PDN_MASK_SFT (0x1 << 6) +#define APLL12_DIV_I2SOUT1_PDN_SFT 7 +#define APLL12_DIV_I2SOUT1_PDN_MASK 0x1 +#define APLL12_DIV_I2SOUT1_PDN_MASK_SFT (0x1 << 7) +#define APLL12_DIV_I2SOUT2_PDN_SFT 8 +#define APLL12_DIV_I2SOUT2_PDN_MASK 0x1 +#define APLL12_DIV_I2SOUT2_PDN_MASK_SFT (0x1 << 8) +#define APLL12_DIV_I2SOUT3_PDN_SFT 9 +#define APLL12_DIV_I2SOUT3_PDN_MASK 0x1 +#define APLL12_DIV_I2SOUT3_PDN_MASK_SFT (0x1 << 9) +#define APLL12_DIV_I2SOUT4_PDN_SFT 10 +#define APLL12_DIV_I2SOUT4_PDN_MASK 0x1 +#define APLL12_DIV_I2SOUT4_PDN_MASK_SFT (0x1 << 10) +#define APLL12_DIV_I2SOUT6_PDN_SFT 11 +#define APLL12_DIV_I2SOUT6_PDN_MASK 0x1 +#define APLL12_DIV_I2SOUT6_PDN_MASK_SFT (0x1 << 11) +#define APLL12_DIV_FMI2S_PDN_SFT 12 +#define APLL12_DIV_FMI2S_PDN_MASK 0x1 +#define APLL12_DIV_FMI2S_PDN_MASK_SFT (0x1 << 12) +#define APLL12_DIV_TDMOUT_M_PDN_SFT 13 +#define APLL12_DIV_TDMOUT_M_PDN_MASK 0x1 +#define APLL12_DIV_TDMOUT_M_PDN_MASK_SFT (0x1 << 13) +#define APLL12_DIV_TDMOUT_B_PDN_SFT 14 +#define APLL12_DIV_TDMOUT_B_PDN_MASK 0x1 +#define APLL12_DIV_TDMOUT_B_PDN_MASK_SFT (0x1 << 14) +#define APLL_I2SIN0_MCK_SEL_SFT 16 +#define APLL_I2SIN0_MCK_SEL_MASK 0x1 +#define APLL_I2SIN0_MCK_SEL_MASK_SFT (0x1 << 16) +#define APLL_I2SIN1_MCK_SEL_SFT 17 +#define APLL_I2SIN1_MCK_SEL_MASK 0x1 +#define APLL_I2SIN1_MCK_SEL_MASK_SFT (0x1 << 17) +#define APLL_I2SIN2_MCK_SEL_SFT 18 +#define APLL_I2SIN2_MCK_SEL_MASK 0x1 +#define APLL_I2SIN2_MCK_SEL_MASK_SFT (0x1 << 18) +#define APLL_I2SIN3_MCK_SEL_SFT 19 +#define APLL_I2SIN3_MCK_SEL_MASK 0x1 +#define APLL_I2SIN3_MCK_SEL_MASK_SFT (0x1 << 19) +#define APLL_I2SIN4_MCK_SEL_SFT 20 +#define APLL_I2SIN4_MCK_SEL_MASK 0x1 +#define APLL_I2SIN4_MCK_SEL_MASK_SFT (0x1 << 20) +#define APLL_I2SIN6_MCK_SEL_SFT 21 +#define APLL_I2SIN6_MCK_SEL_MASK 0x1 +#define APLL_I2SIN6_MCK_SEL_MASK_SFT (0x1 << 21) +#define APLL_I2SOUT0_MCK_SEL_SFT 22 +#define APLL_I2SOUT0_MCK_SEL_MASK 0x1 +#define APLL_I2SOUT0_MCK_SEL_MASK_SFT (0x1 << 22) +#define APLL_I2SOUT1_MCK_SEL_SFT 23 +#define APLL_I2SOUT1_MCK_SEL_MASK 0x1 +#define APLL_I2SOUT1_MCK_SEL_MASK_SFT (0x1 << 23) +#define APLL_I2SOUT2_MCK_SEL_SFT 24 +#define APLL_I2SOUT2_MCK_SEL_MASK 0x1 +#define APLL_I2SOUT2_MCK_SEL_MASK_SFT (0x1 << 24) +#define APLL_I2SOUT3_MCK_SEL_SFT 25 +#define APLL_I2SOUT3_MCK_SEL_MASK 0x1 +#define APLL_I2SOUT3_MCK_SEL_MASK_SFT (0x1 << 25) +#define APLL_I2SOUT4_MCK_SEL_SFT 26 +#define APLL_I2SOUT4_MCK_SEL_MASK 0x1 +#define APLL_I2SOUT4_MCK_SEL_MASK_SFT (0x1 << 26) +#define APLL_I2SOUT6_MCK_SEL_SFT 27 +#define APLL_I2SOUT6_MCK_SEL_MASK 0x1 +#define APLL_I2SOUT6_MCK_SEL_MASK_SFT (0x1 << 27) +#define APLL_FMI2S_MCK_SEL_SFT 28 +#define APLL_FMI2S_MCK_SEL_MASK 0x1 +#define APLL_FMI2S_MCK_SEL_MASK_SFT (0x1 << 28) +#define APLL_TDMOUT_MCK_SEL_SFT 29 +#define APLL_TDMOUT_MCK_SEL_MASK 0x1 +#define APLL_TDMOUT_MCK_SEL_MASK_SFT (0x1 << 29) + +/* CLK_AUDDIV_1 */ +#define APLL12_DIV_I2SIN0_INV_SFT 0 +#define APLL12_DIV_I2SIN0_INV_MASK 0x1 +#define APLL12_DIV_I2SIN0_INV_MASK_SFT (0x1 << 0) +#define APLL12_DIV_I2SIN1_INV_SFT 1 +#define APLL12_DIV_I2SIN1_INV_MASK 0x1 +#define APLL12_DIV_I2SIN1_INV_MASK_SFT (0x1 << 1) +#define APLL12_DIV_I2SIN2_INV_SFT 2 +#define APLL12_DIV_I2SIN2_INV_MASK 0x1 +#define APLL12_DIV_I2SIN2_INV_MASK_SFT (0x1 << 2) +#define APLL12_DIV_I2SIN3_INV_SFT 3 +#define APLL12_DIV_I2SIN3_INV_MASK 0x1 +#define APLL12_DIV_I2SIN3_INV_MASK_SFT (0x1 << 3) +#define APLL12_DIV_I2SIN4_INV_SFT 4 +#define APLL12_DIV_I2SIN4_INV_MASK 0x1 +#define APLL12_DIV_I2SIN4_INV_MASK_SFT (0x1 << 4) +#define APLL12_DIV_I2SIN6_INV_SFT 5 +#define APLL12_DIV_I2SIN6_INV_MASK 0x1 +#define APLL12_DIV_I2SIN6_INV_MASK_SFT (0x1 << 5) +#define APLL12_DIV_I2SOUT0_INV_SFT 6 +#define APLL12_DIV_I2SOUT0_INV_MASK 0x1 +#define APLL12_DIV_I2SOUT0_INV_MASK_SFT (0x1 << 6) +#define APLL12_DIV_I2SOUT1_INV_SFT 7 +#define APLL12_DIV_I2SOUT1_INV_MASK 0x1 +#define APLL12_DIV_I2SOUT1_INV_MASK_SFT (0x1 << 7) +#define APLL12_DIV_I2SOUT2_INV_SFT 8 +#define APLL12_DIV_I2SOUT2_INV_MASK 0x1 +#define APLL12_DIV_I2SOUT2_INV_MASK_SFT (0x1 << 8) +#define APLL12_DIV_I2SOUT3_INV_SFT 9 +#define APLL12_DIV_I2SOUT3_INV_MASK 0x1 +#define APLL12_DIV_I2SOUT3_INV_MASK_SFT (0x1 << 9) +#define APLL12_DIV_I2SOUT4_INV_SFT 10 +#define APLL12_DIV_I2SOUT4_INV_MASK 0x1 +#define APLL12_DIV_I2SOUT4_INV_MASK_SFT (0x1 << 10) +#define APLL12_DIV_I2SOUT6_INV_SFT 11 +#define APLL12_DIV_I2SOUT6_INV_MASK 0x1 +#define APLL12_DIV_I2SOUT6_INV_MASK_SFT (0x1 << 11) +#define APLL12_DIV_FMI2S_INV_SFT 12 +#define APLL12_DIV_FMI2S_INV_MASK 0x1 +#define APLL12_DIV_FMI2S_INV_MASK_SFT (0x1 << 12) +#define APLL12_DIV_TDMOUT_M_INV_SFT 13 +#define APLL12_DIV_TDMOUT_M_INV_MASK 0x1 +#define APLL12_DIV_TDMOUT_M_INV_MASK_SFT (0x1 << 13) +#define APLL12_DIV_TDMOUT_B_INV_SFT 14 +#define APLL12_DIV_TDMOUT_B_INV_MASK 0x1 +#define APLL12_DIV_TDMOUT_B_INV_MASK_SFT (0x1 << 14) + +/* CLK_AUDDIV_2 */ +#define APLL12_CK_DIV_I2SIN0_SFT 0 +#define APLL12_CK_DIV_I2SIN0_MASK 0xff +#define APLL12_CK_DIV_I2SIN0_MASK_SFT (0xff << 0) +#define APLL12_CK_DIV_I2SIN1_SFT 8 +#define APLL12_CK_DIV_I2SIN1_MASK 0xff +#define APLL12_CK_DIV_I2SIN1_MASK_SFT (0xff << 8) +#define APLL12_CK_DIV_I2SIN2_SFT 16 +#define APLL12_CK_DIV_I2SIN2_MASK 0xff +#define APLL12_CK_DIV_I2SIN2_MASK_SFT (0xff << 16) +#define APLL12_CK_DIV_I2SIN3_SFT 24 +#define APLL12_CK_DIV_I2SIN3_MASK 0xff +#define APLL12_CK_DIV_I2SIN3_MASK_SFT (0xff << 24) + +/* AUD_TOP_CFG */ +#define AUD_TOP_CFG_SFT 0 +#define AUD_TOP_CFG_MASK 0xffffffff +#define AUD_TOP_CFG_MASK_SFT (0xffffffff << 0) + +/* AUD_TOP_MON */ +#define AUD_TOP_MON_SFT 0 +#define AUD_TOP_MON_MASK 0xffffffff +#define AUD_TOP_MON_MASK_SFT (0xffffffff << 0) + +/* CLK_AUDDIV_3 */ +#define APLL12_CK_DIV_I2SIN4_SFT 0 +#define APLL12_CK_DIV_I2SIN4_MASK 0xff +#define APLL12_CK_DIV_I2SIN4_MASK_SFT (0xff << 0) +#define APLL12_CK_DIV_I2SIN6_SFT 8 +#define APLL12_CK_DIV_I2SIN6_MASK 0xff +#define APLL12_CK_DIV_I2SIN6_MASK_SFT (0xff << 8) +#define APLL12_CK_DIV_I2SOUT0_SFT 16 +#define APLL12_CK_DIV_I2SOUT0_MASK 0xff +#define APLL12_CK_DIV_I2SOUT0_MASK_SFT (0xff << 16) +#define APLL12_CK_DIV_I2SOUT1_SFT 24 +#define APLL12_CK_DIV_I2SOUT1_MASK 0xff +#define APLL12_CK_DIV_I2SOUT1_MASK_SFT (0xff << 24) + +/* CLK_AUDDIV_4 */ +#define APLL12_CK_DIV_I2SOUT2_SFT 0 +#define APLL12_CK_DIV_I2SOUT2_MASK 0xff +#define APLL12_CK_DIV_I2SOUT2_MASK_SFT (0xff << 0) +#define APLL12_CK_DIV_I2SOUT3_SFT 8 +#define APLL12_CK_DIV_I2SOUT3_MASK 0xff +#define APLL12_CK_DIV_I2SOUT3_MASK_SFT (0xff << 8) +#define APLL12_CK_DIV_I2SOUT4_SFT 16 +#define APLL12_CK_DIV_I2SOUT4_MASK 0xff +#define APLL12_CK_DIV_I2SOUT4_MASK_SFT (0xff << 16) +#define APLL12_CK_DIV_I2SOUT6_SFT 24 +#define APLL12_CK_DIV_I2SOUT6_MASK 0xff +#define APLL12_CK_DIV_I2SOUT6_MASK_SFT (0xff << 24) + +/* CLK_AUDDIV_5 */ +#define APLL12_CK_DIV_FMI2S_SFT 0 +#define APLL12_CK_DIV_FMI2S_MASK 0xff +#define APLL12_CK_DIV_FMI2S_MASK_SFT (0xff << 0) +#define APLL12_CK_DIV_TDMOUT_M_SFT 8 +#define APLL12_CK_DIV_TDMOUT_M_MASK 0xff +#define APLL12_CK_DIV_TDMOUT_M_MASK_SFT (0xff << 8) +#define APLL12_CK_DIV_TDMOUT_B_SFT 16 +#define APLL12_CK_DIV_TDMOUT_B_MASK 0xff +#define APLL12_CK_DIV_TDMOUT_B_MASK_SFT (0xff << 16) + +/* APLL */ +#define APLL1_W_NAME "APLL1" +#define APLL2_W_NAME "APLL2" +enum { + MT8196_APLL1 = 0, + MT8196_APLL2, +}; + +enum { + /* afe clk */ + CLK_HOPPING = 0, + CLK_F26M, + CLK_UL0_ADC_CLK, + CLK_UL0_ADC_HIRES_CLK, + CLK_UL1_ADC_CLK, + CLK_UL1_ADC_HIRES_CLK, + CLK_APLL1, + CLK_APLL2, + CLK_APLL1_TUNER, + CLK_APLL2_TUNER, + /* vlp clk */ + CLK_VLP_MUX_AUDIOINTBUS, + CLK_VLP_MUX_AUD_ENG1, + CLK_VLP_MUX_AUD_ENG2, + CLK_VLP_MUX_AUDIO_H, + CLK_VLP_CLK26M, + /* ck clk */ + CLK_CK_MAINPLL_D4_D4, + CLK_CK_MUX_AUD_1, + CLK_CK_APLL1_CK, + CLK_CK_MUX_AUD_2, + CLK_CK_APLL2_CK, + CLK_CK_APLL1_D4, + CLK_CK_APLL2_D4, + CLK_CK_I2SIN0_M_SEL, + CLK_CK_I2SIN1_M_SEL, + CLK_CK_FMI2S_M_SEL, + CLK_CK_TDMOUT_M_SEL, + CLK_CK_APLL12_DIV_I2SIN0, + CLK_CK_APLL12_DIV_I2SIN1, + CLK_CK_APLL12_DIV_FMI2S, + CLK_CK_APLL12_DIV_TDMOUT_M, + CLK_CK_APLL12_DIV_TDMOUT_B, + CLK_CK_ADSP_SEL, + CLK_CLK26M, + CLK_NUM +}; + +struct mtk_base_afe; + +int mt8196_init_clock(struct mtk_base_afe *afe); +int mt8196_afe_enable_clock(struct mtk_base_afe *afe); +void mt8196_afe_disable_clock(struct mtk_base_afe *afe); +int mt8196_afe_disable_apll(struct mtk_base_afe *afe); + +int mt8196_afe_dram_request(struct device *dev); +int mt8196_afe_dram_release(struct device *dev); + +int mt8196_apll1_enable(struct mtk_base_afe *afe); +void mt8196_apll1_disable(struct mtk_base_afe *afe); + +int mt8196_apll2_enable(struct mtk_base_afe *afe); +void mt8196_apll2_disable(struct mtk_base_afe *afe); + +int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll); +int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate); +int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name); + +void aud_intbus_mux_sel(unsigned int aud_idx); + +/* these will be replaced by using CCF */ +int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate); +int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id); + +int mt8196_set_audio_int_bus_parent(struct mtk_base_afe *afe, + int clk_id, bool int_bus); + +#endif From patchwork Fri Mar 7 12:47:32 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darren.Ye" X-Patchwork-Id: 14006446 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1D58CC19F32 for ; Fri, 7 Mar 2025 12:56:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=579JrFWpi95wWUZ2IKof6bunu2c/sHpygySN/3e4uJg=; b=E8jB7buHGPD7crcNSqfgRe9yok 1hym6NtWfzwQpxqCnL/w/wieusgRjPWNCPdkX32bjS/MWrbhvrhf+/9MQm3tez/kIbVS+Xhfkbuzq 3Of/Fogaum/KxaQ8poxaprgQZijnieNUo1xT0W6IRUQ2wgfgqyKlW/Viny2/0LaTo18fxRb+4Rc6R hLIzxl6sKbVPOe0//OoRCZEt1G1sc+c+MWFCh6EIb1rYH5/hd1tx63lKXzOfJyihkGNl7o/vISGJU 46g8NCo4fYNoGIz7TVRfeF89SUOApzkFwwcBfQFs+DLjpbiIejFwvStaJKUPChswe7ocdtIxpH0M9 DJj0mF4g==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tqXFC-0000000EF2X-38dk; Fri, 07 Mar 2025 12:56:02 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqX8S-0000000EDlx-1mc5; Fri, 07 Mar 2025 12:49:05 +0000 X-UUID: 8c1d6386fb5211ef83f2a1c9db70dae0-20250307 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=579JrFWpi95wWUZ2IKof6bunu2c/sHpygySN/3e4uJg=; b=bpZcIkwpq+XpBw2w7/kBl/rU3C6icF+bEk81ugnV3Mk5pe/LoqVEYnICI1Jc2DWhVbcr+w5NaFEgNjL5hJIAjuPlCYUntZMvlEzf9O7BpKxGVb3mXXq8+rckJ5N+i5y8GJNYy4dXodYmssHt/uXdR8wtduQF2W47MC1CxGZek+E=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:d1ce64f9-2aa2-43ad-897d-41aad2595022,IP:0,UR L:0,TC:0,Content:0,EDM:-25,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION :release,TS:-25 X-CID-META: VersionHash:0ef645f,CLOUDID:0c4927ce-23b9-4c94-add0-e827a7999e28,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:1, IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV: 0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 8c1d6386fb5211ef83f2a1c9db70dae0-20250307 Received: from mtkmbs11n1.mediatek.inc [(172.21.101.185)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1888745673; Fri, 07 Mar 2025 05:49:02 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs11n2.mediatek.inc (172.21.101.187) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 7 Mar 2025 20:48:59 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 7 Mar 2025 20:48:59 +0800 From: Darren.Ye To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Jaroslav Kysela , Takashi Iwai , Linus Walleij , Bartosz Golaszewski CC: , , , , , , Darren Ye Subject: [PATCH 06/14] ASoC: mediatek: mt8196: support audio GPIO control Date: Fri, 7 Mar 2025 20:47:32 +0800 Message-ID: <20250307124841.23777-7-darren.ye@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250307124841.23777-1-darren.ye@mediatek.com> References: <20250307124841.23777-1-darren.ye@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250307_044904_472926_1B330AC3 X-CRM114-Status: GOOD ( 19.15 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Darren Ye Implement mode switching for audio GPIO. Signed-off-by: Darren Ye --- sound/soc/mediatek/mt8196/mt8196-afe-gpio.c | 239 ++++++++++++++++++++ sound/soc/mediatek/mt8196/mt8196-afe-gpio.h | 58 +++++ 2 files changed, 297 insertions(+) create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-gpio.c create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-gpio.h diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-gpio.c b/sound/soc/mediatek/mt8196/mt8196-afe-gpio.c new file mode 100644 index 000000000000..17ba409af7c4 --- /dev/null +++ b/sound/soc/mediatek/mt8196/mt8196-afe-gpio.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mt8196-afe-gpio.c -- Mediatek 8196 afe gpio ctrl + * + * Copyright (c) 2024 MediaTek Inc. + * Author: Darren Ye + */ + +#include +#include + +#include "mt8196-afe-common.h" +#include "mt8196-afe-gpio.h" + +struct pinctrl *aud_pinctrl; +struct audio_gpio_attr { + const char *name; + bool gpio_prepare; + struct pinctrl_state *gpioctrl; +}; + +static struct audio_gpio_attr aud_gpios[MT8196_AFE_GPIO_GPIO_NUM] = { + [MT8196_AFE_GPIO_DAT_MISO0_OFF] = {"aud-dat-miso0-off", false, NULL}, + [MT8196_AFE_GPIO_DAT_MISO0_ON] = {"aud-dat-miso0-on", false, NULL}, + [MT8196_AFE_GPIO_DAT_MISO1_OFF] = {"aud-dat-miso1-off", false, NULL}, + [MT8196_AFE_GPIO_DAT_MISO1_ON] = {"aud-dat-miso1-on", false, NULL}, + [MT8196_AFE_GPIO_DAT_MOSI_OFF] = {"aud-dat-mosi-off", false, NULL}, + [MT8196_AFE_GPIO_DAT_MOSI_ON] = {"aud-dat-mosi-on", false, NULL}, + [MT8196_AFE_GPIO_I2SOUT0_OFF] = {"aud-gpio-i2sout0-off", false, NULL}, + [MT8196_AFE_GPIO_I2SOUT0_ON] = {"aud-gpio-i2sout0-on", false, NULL}, + [MT8196_AFE_GPIO_I2SIN0_OFF] = {"aud-gpio-i2sin0-off", false, NULL}, + [MT8196_AFE_GPIO_I2SIN0_ON] = {"aud-gpio-i2sin0-on", false, NULL}, + [MT8196_AFE_GPIO_I2SOUT1_OFF] = {"aud-gpio-i2sout1-off", false, NULL}, + [MT8196_AFE_GPIO_I2SOUT1_ON] = {"aud-gpio-i2sout1-on", false, NULL}, + [MT8196_AFE_GPIO_I2SIN1_OFF] = {"aud-gpio-i2sin1-off", false, NULL}, + [MT8196_AFE_GPIO_I2SIN1_ON] = {"aud-gpio-i2sin1-on", false, NULL}, + [MT8196_AFE_GPIO_I2SOUT4_OFF] = {"aud-gpio-i2sout4-off", false, NULL}, + [MT8196_AFE_GPIO_I2SOUT4_ON] = {"aud-gpio-i2sout4-on", false, NULL}, + [MT8196_AFE_GPIO_I2SIN4_OFF] = {"aud-gpio-i2sin4-off", false, NULL}, + [MT8196_AFE_GPIO_I2SIN4_ON] = {"aud-gpio-i2sin4-on", false, NULL}, + [MT8196_AFE_GPIO_I2SOUT6_OFF] = {"aud-gpio-i2sout6-off", false, NULL}, + [MT8196_AFE_GPIO_I2SOUT6_ON] = {"aud-gpio-i2sout6-on", false, NULL}, + [MT8196_AFE_GPIO_I2SIN6_OFF] = {"aud-gpio-i2sin6-off", false, NULL}, + [MT8196_AFE_GPIO_I2SIN6_ON] = {"aud-gpio-i2sin6-on", false, NULL}, + [MT8196_AFE_GPIO_AP_DMIC_OFF] = {"aud-gpio-ap-dmic-off", false, NULL}, + [MT8196_AFE_GPIO_AP_DMIC_ON] = {"aud-gpio-ap-dmic-on", false, NULL}, + [MT8196_AFE_GPIO_AP_DMIC1_OFF] = {"aud-gpio-ap-dmic1-off", false, NULL}, + [MT8196_AFE_GPIO_AP_DMIC1_ON] = {"aud-gpio-ap-dmic1-on", false, NULL}, + [MT8196_AFE_GPIO_DAT_MOSI_CH34_OFF] = {"aud-dat-mosi-ch34-off", false, NULL}, + [MT8196_AFE_GPIO_DAT_MOSI_CH34_ON] = {"aud-dat-mosi-ch34-on", false, NULL}, + [MT8196_AFE_GPIO_DAT_MISO_ONLY_OFF] = {"aud-dat-miso-only-off", false, NULL}, + [MT8196_AFE_GPIO_DAT_MISO_ONLY_ON] = {"aud-dat-miso-only-on", false, NULL}, + [MT8196_AFE_GPIO_I2SOUT3_OFF] = {"aud-gpio-i2sout3-off", false, NULL}, + [MT8196_AFE_GPIO_I2SOUT3_ON] = {"aud-gpio-i2sout3-on", false, NULL}, + [MT8196_AFE_GPIO_I2SIN3_OFF] = {"aud-gpio-i2sin3-off", false, NULL}, + [MT8196_AFE_GPIO_I2SIN3_ON] = {"aud-gpio-i2sin3-on", false, NULL}, +}; + +static DEFINE_MUTEX(gpio_request_mutex); + +int mt8196_afe_gpio_init(struct mtk_base_afe *afe) +{ + int ret; + int i = 0; + + aud_pinctrl = devm_pinctrl_get(afe->dev); + if (IS_ERR(aud_pinctrl)) { + ret = PTR_ERR(aud_pinctrl); + dev_info(afe->dev, "%s(), ret %d, cannot get aud_pinctrl!\n", + __func__, ret); + return -ENODEV; + } + + for (i = 0; i < MT8196_AFE_GPIO_GPIO_NUM; i++) { + if (!aud_gpios[i].name) { + dev_info(afe->dev, "%s(), gpio id %d not define!!!\n", + __func__, i); + } + } + + for (i = 0; i < ARRAY_SIZE(aud_gpios); i++) { + aud_gpios[i].gpioctrl = pinctrl_lookup_state(aud_pinctrl, + aud_gpios[i].name); + if (IS_ERR(aud_gpios[i].gpioctrl)) { + ret = PTR_ERR(aud_gpios[i].gpioctrl); + dev_info(afe->dev, "%s(), pinctrl_lookup_state %s fail, ret %d\n", + __func__, aud_gpios[i].name, ret); + } else { + aud_gpios[i].gpio_prepare = true; + } + } + + /* gpio status init */ + mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA, 0); + mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA, 1); + + return 0; +} + +static int mt8196_afe_gpio_select(struct mtk_base_afe *afe, + enum mt8196_afe_gpio type) +{ + int ret = 0; + + dev_dbg(afe->dev, "%s(), type: %d.\n", __func__, type); + + if (type >= MT8196_AFE_GPIO_GPIO_NUM) { + dev_info(afe->dev, "%s(), error, invalid gpio type %d\n", + __func__, type); + return -EINVAL; + } + + if (!aud_gpios[type].gpio_prepare) { + dev_info(afe->dev, "%s(), error, gpio type %d not prepared\n", + __func__, type); + return -EIO; + } + + ret = pinctrl_select_state(aud_pinctrl, + aud_gpios[type].gpioctrl); + if (ret) + dev_info(afe->dev, "%s(), error, can not set gpio type %d\n", + __func__, type); + + return ret; +} + +int mt8196_afe_gpio_request(struct mtk_base_afe *afe, bool enable, + int dai, int uplink) +{ + dev_dbg(afe->dev, "%s(), enable: %d, dai: %d, uplink: %d.\n", __func__, + enable, dai, uplink); + + mutex_lock(&gpio_request_mutex); + switch (dai) { + case MT8196_DAI_ADDA: + break; + case MT8196_DAI_ADDA_CH34: + break; + case MT8196_DAI_ADDA_CH56: + break; + case MT8196_DAI_I2S_IN0: + case MT8196_DAI_I2S_OUT0: + if (enable) { + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN0_ON); + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT0_ON); + } else { + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN0_OFF); + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT0_OFF); + } + break; + case MT8196_DAI_I2S_IN1: + case MT8196_DAI_I2S_OUT1: + if (enable) { + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN1_ON); + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT1_ON); + } else { + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN1_OFF); + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT1_OFF); + } + break; + case MT8196_DAI_I2S_IN3: + case MT8196_DAI_I2S_OUT3: + if (enable) { + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN3_ON); + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT3_ON); + } else { + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN3_OFF); + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT3_OFF); + } + break; + case MT8196_DAI_I2S_IN4: + case MT8196_DAI_I2S_OUT4: + if (enable) { + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN4_ON); + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT4_ON); + } else { + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN4_OFF); + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT4_OFF); + } + break; + case MT8196_DAI_I2S_IN6: + case MT8196_DAI_I2S_OUT6: + if (enable) { + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN6_ON); + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT6_ON); + } else { + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN6_OFF); + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT6_OFF); + } + break; + case MT8196_DAI_VOW: + break; + case MT8196_DAI_VOW_SCP_DMIC: + break; + case MT8196_DAI_MTKAIF: + if (enable) { + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_DAT_MISO1_ON); + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_DAT_MISO0_ON); + } else { + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_DAT_MISO1_OFF); + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_DAT_MISO0_OFF); + } + break; + case MT8196_DAI_MISO_ONLY: + if (enable) + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_DAT_MISO_ONLY_ON); + else + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_DAT_MISO_ONLY_OFF); + break; + case MT8196_DAI_AP_DMIC: + if (enable) + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_AP_DMIC_ON); + else + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_AP_DMIC_OFF); + break; + case MT8196_DAI_AP_DMIC_CH34: + if (enable) + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_AP_DMIC1_ON); + else + mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_AP_DMIC1_OFF); + break; + default: + mutex_unlock(&gpio_request_mutex); + dev_info(afe->dev, "%s(), invalid dai %d\n", __func__, dai); + return -EINVAL; + } + mutex_unlock(&gpio_request_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(mt8196_afe_gpio_request); + +bool mt8196_afe_gpio_is_prepared(enum mt8196_afe_gpio type) +{ + return aud_gpios[type].gpio_prepare; +} +EXPORT_SYMBOL(mt8196_afe_gpio_is_prepared); + diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-gpio.h b/sound/soc/mediatek/mt8196/mt8196-afe-gpio.h new file mode 100644 index 000000000000..b36a8201d649 --- /dev/null +++ b/sound/soc/mediatek/mt8196/mt8196-afe-gpio.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8196-afe-gpio.h -- Mediatek 8196 afe gpio ctrl definition + * + * Copyright (c) 2023 MediaTek Inc. + * Author: Darren Ye + */ + +#ifndef _MT8196_AFE_GPIO_H_ +#define _MT8196_AFE_GPIO_H_ +#include "mt8196-afe-common.h" + +enum mt8196_afe_gpio { + MT8196_AFE_GPIO_DAT_MISO0_OFF, + MT8196_AFE_GPIO_DAT_MISO0_ON, + MT8196_AFE_GPIO_DAT_MISO1_OFF, + MT8196_AFE_GPIO_DAT_MISO1_ON, + MT8196_AFE_GPIO_DAT_MOSI_OFF, + MT8196_AFE_GPIO_DAT_MOSI_ON, + MT8196_AFE_GPIO_DAT_MOSI_CH34_OFF, + MT8196_AFE_GPIO_DAT_MOSI_CH34_ON, + MT8196_AFE_GPIO_DAT_MISO_ONLY_OFF, + MT8196_AFE_GPIO_DAT_MISO_ONLY_ON, + MT8196_AFE_GPIO_I2SIN0_OFF, + MT8196_AFE_GPIO_I2SIN0_ON, + MT8196_AFE_GPIO_I2SOUT0_OFF, + MT8196_AFE_GPIO_I2SOUT0_ON, + MT8196_AFE_GPIO_I2SIN1_OFF, + MT8196_AFE_GPIO_I2SIN1_ON, + MT8196_AFE_GPIO_I2SOUT1_OFF, + MT8196_AFE_GPIO_I2SOUT1_ON, + MT8196_AFE_GPIO_I2SIN4_OFF, + MT8196_AFE_GPIO_I2SIN4_ON, + MT8196_AFE_GPIO_I2SOUT4_OFF, + MT8196_AFE_GPIO_I2SOUT4_ON, + MT8196_AFE_GPIO_I2SIN6_OFF, + MT8196_AFE_GPIO_I2SIN6_ON, + MT8196_AFE_GPIO_I2SOUT6_OFF, + MT8196_AFE_GPIO_I2SOUT6_ON, + MT8196_AFE_GPIO_AP_DMIC_OFF, + MT8196_AFE_GPIO_AP_DMIC_ON, + MT8196_AFE_GPIO_AP_DMIC1_OFF, + MT8196_AFE_GPIO_AP_DMIC1_ON, + MT8196_AFE_GPIO_I2SIN3_OFF, + MT8196_AFE_GPIO_I2SIN3_ON, + MT8196_AFE_GPIO_I2SOUT3_OFF, + MT8196_AFE_GPIO_I2SOUT3_ON, + MT8196_AFE_GPIO_GPIO_NUM +}; + +struct mtk_base_afe; + +int mt8196_afe_gpio_init(struct mtk_base_afe *afe); +int mt8196_afe_gpio_request(struct mtk_base_afe *afe, bool enable, + int dai, int uplink); +bool mt8196_afe_gpio_is_prepared(enum mt8196_afe_gpio type); + +#endif From patchwork Fri Mar 7 12:47:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darren.Ye" X-Patchwork-Id: 14006455 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 274FAC282DE for ; Fri, 7 Mar 2025 12:59:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=fJb5aL4ksRTiRJS5Gy5faBvYep6KIuem35TZVPDQn1k=; b=FbKYjc3gbusZYIZU7tbH3f9CjK MjK7Y0Jga8Hr7KgfskN7CrVUROTumoAieyU8lo5TmucNHehEDma8GZSXH5yaXaN393tTJ33n3p0xE IwW+Y3RDy/B5Wav07eBfeBQhIDFDr6JSoccrQXgqTYD0ZsSEdNYzxoz0OoHRqGb597F5srzMiiNoV 559F91Y0IKYsv85gpfElSWCnE0oGHprj9ZJGzskxAS9IkZoG/zbt/IhD+5lANuXT0baivNCbiqZZq c0PVLc/E/C+Jaj+0X33gWgmlY6Xb6abR9h6cvPtHryTQ9Dqsq1FEqyMGlgJScWyptm9q97Vy/dSzr sw+BEITA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tqXIN-0000000EFRv-1bIO; Fri, 07 Mar 2025 12:59:19 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqX8W-0000000EDnW-1Rv5; Fri, 07 Mar 2025 12:49:10 +0000 X-UUID: 8d81cff0fb5211ef83f2a1c9db70dae0-20250307 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=fJb5aL4ksRTiRJS5Gy5faBvYep6KIuem35TZVPDQn1k=; b=nXwbSH3VJ71Y+KZn4q508WHALknkktr2XLKiDt2pFaItU/qUSVGTuf0y1pXIMy38PlatnY07Sac0Z8DRyilKPpaSkbzrfi6eLqg/8VJ7S9HLyW2VsdpEYuFcN7/WMQL6gAeGoai5IRFuuu2cuaopLe8thhMhQQ3JIC6O5Yj66FM=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:25b78b05-b7b3-4e75-a16e-efef041720d0,IP:0,UR L:0,TC:0,Content:0,EDM:-25,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION :release,TS:-25 X-CID-META: VersionHash:0ef645f,CLOUDID:5a53168c-f5b8-47d5-8cf3-b68fe7530c9a,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:1, IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:1,OSI:0,OSA:0,AV: 0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 2,OSH X-CID-BAS: 2,OSH,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 8d81cff0fb5211ef83f2a1c9db70dae0-20250307 Received: from mtkmbs09n2.mediatek.inc [(172.21.101.94)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1438816549; Fri, 07 Mar 2025 05:49:05 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS09N2.mediatek.inc (172.21.101.94) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 7 Mar 2025 20:49:02 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 7 Mar 2025 20:49:01 +0800 From: Darren.Ye To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Jaroslav Kysela , Takashi Iwai , Linus Walleij , Bartosz Golaszewski CC: , , , , , , Darren Ye Subject: [PATCH 07/14] ASoC: mediatek: mt8196: support ADDA in platform driver Date: Fri, 7 Mar 2025 20:47:33 +0800 Message-ID: <20250307124841.23777-8-darren.ye@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250307124841.23777-1-darren.ye@mediatek.com> References: <20250307124841.23777-1-darren.ye@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250307_044908_428228_A788D3C4 X-CRM114-Status: GOOD ( 17.02 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Darren Ye Add mt8196 ADDA DAI driver support. Signed-off-by: Darren Ye --- sound/soc/mediatek/mt8196/mt8196-dai-adda.c | 2207 +++++++++++++++++++ 1 file changed, 2207 insertions(+) create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-adda.c diff --git a/sound/soc/mediatek/mt8196/mt8196-dai-adda.c b/sound/soc/mediatek/mt8196/mt8196-dai-adda.c new file mode 100644 index 000000000000..2934b3ba9d71 --- /dev/null +++ b/sound/soc/mediatek/mt8196/mt8196-dai-adda.c @@ -0,0 +1,2207 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek ALSA SoC Audio DAI ADDA Control + * + * Copyright (c) 2024 MediaTek Inc. + * Author: Darren Ye + */ + +#include +#include +#include "mt8196-afe-clk.h" +#include "mt8196-afe-common.h" +#include "mt8196-afe-gpio.h" +#include "mt8196-interconnection.h" + +#define MTKAIF4 //for mt6338 +/* mt6363 vs1 voter */ +#define RG_BUCK_VS1_VOTER_EN_LO 0x189a +#define RG_BUCK_VS1_VOTER_EN_LO_SET 0x189b +#define RG_BUCK_VS1_VOTER_EN_LO_CLR 0x189c + +#define VS1_MT6338_MSK (0x1 << 0) + +enum { + UL_IIR_SW = 0, + UL_IIR_5HZ, + UL_IIR_10HZ, + UL_IIR_25HZ, + UL_IIR_50HZ, + UL_IIR_75HZ, +}; + +enum { + AUDIO_SDM_LEVEL_MUTE = 0, + AUDIO_SDM_LEVEL_NORMAL = 0x1d, + /* if you change level normal */ + /* you need to change formula of hp impedance and dc trim too */ +}; + +enum { + AUDIO_SDM_2ND = 0, + AUDIO_SDM_3RD, +}; + +enum { + DELAY_DATA_MISO1 = 0, + DELAY_DATA_MISO2, +}; + +enum { + MTK_AFE_ADDA_DL_RATE_8K = 0, + MTK_AFE_ADDA_DL_RATE_11K = 1, + MTK_AFE_ADDA_DL_RATE_12K = 2, + MTK_AFE_ADDA_DL_RATE_16K = 4, + MTK_AFE_ADDA_DL_RATE_22K = 5, + MTK_AFE_ADDA_DL_RATE_24K = 6, + MTK_AFE_ADDA_DL_RATE_32K = 8, + MTK_AFE_ADDA_DL_RATE_44K = 9, + MTK_AFE_ADDA_DL_RATE_48K = 10, + MTK_AFE_ADDA_DL_RATE_88K = 13, + MTK_AFE_ADDA_DL_RATE_96K = 14, + MTK_AFE_ADDA_DL_RATE_176K = 17, + MTK_AFE_ADDA_DL_RATE_192K = 18, + MTK_AFE_ADDA_DL_RATE_352K = 21, + MTK_AFE_ADDA_DL_RATE_384K = 22, +}; + +enum { + MTK_AFE_ADDA_UL_RATE_8K = 0, + MTK_AFE_ADDA_UL_RATE_16K = 1, + MTK_AFE_ADDA_UL_RATE_32K = 2, + MTK_AFE_ADDA_UL_RATE_48K = 3, + MTK_AFE_ADDA_UL_RATE_96K = 4, + MTK_AFE_ADDA_UL_RATE_192K = 5, + MTK_AFE_ADDA_UL_RATE_48K_HD = 6, +}; + +#ifdef MTKAIF4 +enum { + MTK_AFE_MTKAIF_RATE_8K = 0x0, + MTK_AFE_MTKAIF_RATE_12K = 0x1, + MTK_AFE_MTKAIF_RATE_16K = 0x2, + MTK_AFE_MTKAIF_RATE_24K = 0x3, + MTK_AFE_MTKAIF_RATE_32K = 0x4, + MTK_AFE_MTKAIF_RATE_48K = 0x5, + MTK_AFE_MTKAIF_RATE_64K = 0x6, + MTK_AFE_MTKAIF_RATE_96K = 0x7, + MTK_AFE_MTKAIF_RATE_128K = 0x8, + MTK_AFE_MTKAIF_RATE_192K = 0x9, + MTK_AFE_MTKAIF_RATE_256K = 0xa, + MTK_AFE_MTKAIF_RATE_384K = 0xb, + MTK_AFE_MTKAIF_RATE_11K = 0x10, + MTK_AFE_MTKAIF_RATE_22K = 0x11, + MTK_AFE_MTKAIF_RATE_44K = 0x12, + MTK_AFE_MTKAIF_RATE_88K = 0x13, + MTK_AFE_MTKAIF_RATE_176K = 0x14, + MTK_AFE_MTKAIF_RATE_352K = 0x15, +}; +#endif + +#define SDM_AUTO_RESET_THRESHOLD 0x190000 + +struct mtk_afe_adda_priv { + int dl_rate; + int ul_rate; +}; + +static struct mtk_afe_adda_priv *get_adda_priv_by_name(struct mtk_base_afe *afe, + const char *name) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int dai_id; + + if (strncmp(name, "aud_dl0_dac_hires_clk", 21) == 0 || + strncmp(name, "aud_ul0_adc_hires_clk", 21) == 0) + dai_id = MT8196_DAI_ADDA; + else if (strncmp(name, "aud_dl1_dac_hires_clk", 21) == 0 || + strncmp(name, "aud_ul1_adc_hires_clk", 21) == 0) + dai_id = MT8196_DAI_ADDA_CH34; + else + return NULL; + + return afe_priv->dai_priv[dai_id]; +} + +static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_ADDA_UL_RATE_8K; + case 16000: + return MTK_AFE_ADDA_UL_RATE_16K; + case 32000: + return MTK_AFE_ADDA_UL_RATE_32K; + case 48000: + return MTK_AFE_ADDA_UL_RATE_48K; + case 96000: + return MTK_AFE_ADDA_UL_RATE_96K; + case 192000: + return MTK_AFE_ADDA_UL_RATE_192K; + default: + dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", + __func__, rate); + return MTK_AFE_ADDA_UL_RATE_48K; + } +} + +#ifdef MTKAIF4 +static unsigned int mtkaif_rate_transform(struct mtk_base_afe *afe, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_MTKAIF_RATE_8K; + case 11025: + return MTK_AFE_MTKAIF_RATE_11K; + case 12000: + return MTK_AFE_MTKAIF_RATE_12K; + case 16000: + return MTK_AFE_MTKAIF_RATE_16K; + case 22050: + return MTK_AFE_MTKAIF_RATE_22K; + case 24000: + return MTK_AFE_MTKAIF_RATE_24K; + case 32000: + return MTK_AFE_MTKAIF_RATE_32K; + case 44100: + return MTK_AFE_MTKAIF_RATE_44K; + case 48000: + return MTK_AFE_MTKAIF_RATE_48K; + case 96000: + return MTK_AFE_MTKAIF_RATE_96K; + case 192000: + return MTK_AFE_MTKAIF_RATE_192K; + default: + dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", + __func__, rate); + return MTK_AFE_MTKAIF_RATE_48K; + } +} +#endif + +/* dai component */ +static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN014_1, I_DL0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN014_1, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN014_1, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN014_1, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN014_1, I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN014_1, I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN014_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN014_1, I_DL7_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN014_1, I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN014_1, I_DL_24CH_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH1", AFE_CONN014_2, I_DL24_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN014_0, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN014_0, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN014_0, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN014_0, + I_GAIN0_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN014_4, + I_PCM_0_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN014_4, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN014_6, + I_SRC_0_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN014_6, + I_SRC_1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN014_6, + I_SRC_2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN015_1, I_DL0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN015_1, I_DL0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN015_1, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN015_1, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN015_1, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN015_1, I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN015_1, I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN015_1, I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN015_1, I_DL7_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN015_1, I_DL8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN015_1, I_DL_24CH_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH2", AFE_CONN015_2, I_DL24_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN015_0, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN015_0, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN015_0, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN015_0, + I_GAIN0_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN015_4, + I_PCM_0_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN015_4, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN015_4, + I_PCM_0_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN015_4, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN015_6, + I_SRC_0_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN015_6, + I_SRC_1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN015_6, + I_SRC_2_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_adda_dl_ch3_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN016_1, I_DL0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN016_1, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN016_1, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN016_1, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN016_1, I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN016_1, I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN016_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN016_1, I_DL7_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN016_1, I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN016_1, I_DL_24CH_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH3", AFE_CONN016_1, I_DL_24CH_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN016_0, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN016_0, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN016_0, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN016_0, + I_GAIN0_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN016_4, + I_PCM_0_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN016_4, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN016_6, + I_SRC_0_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN016_6, + I_SRC_1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN016_6, + I_SRC_2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_adda_dl_ch4_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN017_1, I_DL0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN017_1, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN017_1, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN017_1, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN017_1, I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN017_1, I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN017_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN017_1, I_DL7_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN017_1, I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN017_1, I_DL_24CH_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH4", AFE_CONN017_1, I_DL_24CH_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN017_0, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN017_0, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN017_0, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN017_0, + I_GAIN0_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN017_4, + I_PCM_0_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN017_4, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN017_4, + I_PCM_0_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN017_4, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN017_6, + I_SRC_0_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN017_6, + I_SRC_1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN017_6, + I_SRC_2_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_stf_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN012_0, + I_ADDA_UL_CH1, 1, 0), +}; + +// Luke: dummy BE for codec fail +static const char * const adda_mux_map[] = { + "Normal", "Dummy_Widget", +}; + +static int adda_mux_map_value[] = { + 0, 1, +}; + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(adda_mux_map_enum, + SND_SOC_NOPM, + 0, + 1, + adda_mux_map, + adda_mux_map_value); +static const struct snd_kcontrol_new adda_out_mux_control = + SOC_DAPM_ENUM("ADDA Out Select", adda_mux_map_enum); +static const struct snd_kcontrol_new adda_in_mux_control = + SOC_DAPM_ENUM("ADDA In Select", adda_mux_map_enum); +// Luke: dummy BE for codec fail + +enum { + SUPPLY_SEQ_ADDA_AFE_ON, + SUPPLY_SEQ_ADDA_DL_ON, + SUPPLY_SEQ_ADDA_AUD_PAD_TOP, + SUPPLY_SEQ_ADDA_MTKAIF_CFG, + SUPPLY_SEQ_ADDA6_MTKAIF_CFG, + SUPPLY_SEQ_ADDA_FIFO, + SUPPLY_SEQ_ADDA_AP_DMIC, + SUPPLY_SEQ_ADDA_UL_ON, +}; + +static int mtk_adda_ul_src_dmic_phase_sync(struct mtk_base_afe *afe) +{ + dev_dbg(afe->dev, "%s() set dmic phase sync\n", __func__); + // ul0~1 + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1, + UL0_PHASE_SYNC_HCLK_SET_MASK_SFT, + 0x1 << UL0_PHASE_SYNC_HCLK_SET_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1, + UL0_PHASE_SYNC_FCLK_SET_MASK_SFT, + 0x1 << UL0_PHASE_SYNC_FCLK_SET_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1, + UL1_PHASE_SYNC_HCLK_SET_MASK_SFT, + 0x1 << UL1_PHASE_SYNC_HCLK_SET_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1, + UL1_PHASE_SYNC_FCLK_SET_MASK_SFT, + 0x1 << UL1_PHASE_SYNC_FCLK_SET_SFT); + // dmic 0 + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1, + DMIC0_PHASE_SYNC_FCLK_SET_MASK_SFT, + 0x1 << DMIC0_PHASE_SYNC_FCLK_SET_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1, + DMIC0_PHASE_SYNC_HCLK_SET_MASK_SFT, + 0x1 << DMIC0_PHASE_SYNC_HCLK_SET_SFT); + // dmic 1 + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1, + DMIC1_PHASE_SYNC_FCLK_SET_MASK_SFT, + 0x1 << DMIC1_PHASE_SYNC_FCLK_SET_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1, + DMIC1_PHASE_SYNC_HCLK_SET_MASK_SFT, + 0x1 << DMIC1_PHASE_SYNC_HCLK_SET_SFT); + // ul0~1 phase sync clock + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0, + DMIC1_PHASE_HCLK_SEL_MASK_SFT, + 0x1 << DMIC1_PHASE_HCLK_SEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0, + DMIC1_PHASE_FCLK_SEL_MASK_SFT, + 0x1 << DMIC1_PHASE_FCLK_SEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0, + DMIC0_PHASE_HCLK_SEL_MASK_SFT, + 0x1 << DMIC0_PHASE_HCLK_SEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0, + DMIC0_PHASE_FCLK_SEL_MASK_SFT, + 0x1 << DMIC0_PHASE_FCLK_SEL_SFT); + // dmic 0 + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0, + UL1_PHASE_HCLK_SEL_MASK_SFT, + 0x2 << UL1_PHASE_HCLK_SEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0, + UL1_PHASE_FCLK_SEL_MASK_SFT, + 0x2 << UL1_PHASE_FCLK_SEL_SFT); + // dmic 1 + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0, + UL0_PHASE_HCLK_SEL_MASK_SFT, + 0x2 << UL0_PHASE_HCLK_SEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0, + UL0_PHASE_FCLK_SEL_MASK_SFT, + 0x2 << UL0_PHASE_FCLK_SEL_SFT); + + return 0; +} + +static int mtk_adda_ul_src_dmic_phase_sync_clock(struct mtk_base_afe *afe) +{ + dev_dbg(afe->dev, "%s(), dmic turn on phase sync clk\n", __func__); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0, + UL_PHASE_SYNC_HCLK_1_ON_MASK_SFT, + 0x1 << UL_PHASE_SYNC_HCLK_1_ON_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0, + UL_PHASE_SYNC_HCLK_0_ON_MASK_SFT, + 0x1 << UL_PHASE_SYNC_HCLK_0_ON_SFT); + + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0, + UL_PHASE_SYNC_FCLK_1_ON_MASK_SFT, + 0x1 << UL_PHASE_SYNC_FCLK_1_ON_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0, + UL_PHASE_SYNC_FCLK_0_ON_MASK_SFT, + 0x1 << UL_PHASE_SYNC_FCLK_0_ON_SFT); + + return 0; +} + +static int mtk_adda_ul_src_dmic(struct mtk_base_afe *afe, int id) +{ + unsigned int reg_con0 = 0, reg_con1 = 0; + + dev_dbg(afe->dev, "%s(), id: %d\n", __func__, id); + + switch (id) { + case MT8196_DAI_ADDA: + case MT8196_DAI_AP_DMIC: + reg_con0 = AFE_ADDA_UL0_SRC_CON0; + reg_con1 = AFE_ADDA_UL0_SRC_CON1; + break; + case MT8196_DAI_ADDA_CH34: + case MT8196_DAI_AP_DMIC_CH34: + reg_con0 = AFE_ADDA_UL1_SRC_CON0; + reg_con1 = AFE_ADDA_UL1_SRC_CON1; + break; + default: + return -EINVAL; + } + + switch (id) { + case MT8196_DAI_AP_DMIC: + dev_dbg(afe->dev, "%s(), clear mtkaifv4 ul ch1ch2 mux\n", __func__); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT, + 0x0 << MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT); + break; + case MT8196_DAI_AP_DMIC_CH34: + dev_dbg(afe->dev, "%s(), clear mtkaifv4 ul ch3ch4 mux\n", __func__); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT, + 0x0 << MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT); + break; + default: + return -EINVAL; + } + + /* choose Phase */ + regmap_update_bits(afe->regmap, reg_con0, + UL_DMIC_PHASE_SEL_CH1_MASK_SFT, + 0x0 << UL_DMIC_PHASE_SEL_CH1_SFT); + regmap_update_bits(afe->regmap, reg_con0, + UL_DMIC_PHASE_SEL_CH2_MASK_SFT, + 0x4 << UL_DMIC_PHASE_SEL_CH2_SFT); + + /* dmic mode, 3.25M*/ + regmap_update_bits(afe->regmap, reg_con0, + DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT, + 0x0); + regmap_update_bits(afe->regmap, reg_con0, + DMIC_LOW_POWER_MODE_CTL_MASK_SFT, + 0x0); + + /* turn on dmic, ch1, ch2 */ + regmap_update_bits(afe->regmap, reg_con0, + UL_SDM_3_LEVEL_CTL_MASK_SFT, + 0x1 << UL_SDM_3_LEVEL_CTL_SFT); + regmap_update_bits(afe->regmap, reg_con0, + UL_MODE_3P25M_CH1_CTL_MASK_SFT, + 0x1 << UL_MODE_3P25M_CH1_CTL_SFT); + regmap_update_bits(afe->regmap, reg_con0, + UL_MODE_3P25M_CH2_CTL_MASK_SFT, + 0x1 << UL_MODE_3P25M_CH2_CTL_SFT); + + /* ul gain: gain = 0x7fff/positive_gain = 0x0/gain_mode = 0x10 */ + regmap_update_bits(afe->regmap, reg_con1, + ADDA_UL_GAIN_VALUE_MASK_SFT, + 0x7fff << ADDA_UL_GAIN_VALUE_SFT); + regmap_update_bits(afe->regmap, reg_con1, + ADDA_UL_POSTIVEGAIN_MASK_SFT, + 0x0 << ADDA_UL_POSTIVEGAIN_SFT); + /* gain_mode = 0x10: Add 0.5 gain at CIC output */ + regmap_update_bits(afe->regmap, reg_con1, + GAIN_MODE_MASK_SFT, + 0x02 << GAIN_MODE_SFT); + return 0; +} + +static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int mtkaif_dmic = afe_priv->mtkaif_dmic; + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n", + __func__, w->name, event, mtkaif_dmic); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA, 1); + + /* update setting to dmic */ + if (mtkaif_dmic) { + /* mtkaif_rxif_data_mode = 1, dmic */ + regmap_update_bits(afe->regmap, AFE_MTKAIF0_RX_CFG0, + 0x1, 0x1); + + /* dmic mode, 3.25M*/ + regmap_update_bits(afe->regmap, AFE_MTKAIF0_RX_CFG0, + RG_MTKAIF0_RXIF_VOICE_MODE_MASK_SFT, + 0x0); + mtk_adda_ul_src_dmic(afe, MT8196_DAI_ADDA); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(120, 130); + mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA, 1); + + /* reset dmic */ + afe_priv->mtkaif_dmic = 0; + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_ch34_ul_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int mtkaif_dmic = afe_priv->mtkaif_dmic_ch34; + int mtkaif_adda6_only = afe_priv->mtkaif_adda6_only; + + dev_dbg(afe->dev, + "%s(), name %s, event 0x%x, mtkaif_dmic %d, mtkaif_adda6_only %d\n", + __func__, w->name, event, mtkaif_dmic, mtkaif_adda6_only); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA_CH34, 1); + + /* update setting to dmic */ + if (mtkaif_dmic) { + /* mtkaif_rxif_data_mode = 1, dmic */ + regmap_update_bits(afe->regmap, + AFE_MTKAIF1_RX_CFG0, + 0x1, 0x1); + + /* dmic mode, 3.25M*/ + regmap_update_bits(afe->regmap, + AFE_MTKAIF1_RX_CFG0, + RG_MTKAIF1_RXIF_VOICE_MODE_MASK_SFT, + 0x0); + mtk_adda_ul_src_dmic(afe, MT8196_DAI_ADDA_CH34); + } + + /* when using adda6 without adda enabled, + * RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_SFT need to be set or + * data cannot be received. + */ + if (mtkaif_adda6_only) { + regmap_update_bits(afe->regmap, + AFE_MTKAIF1_RX_CFG2, + RG_MTKAIF1_RXIF_SYNC_WORD1_DISABLE_MASK_SFT, + 0x1); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(120, 130); + mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA_CH34, 1); + + /* reset dmic */ + afe_priv->mtkaif_dmic_ch34 = 0; + + if (mtkaif_adda6_only) { + regmap_update_bits(afe->regmap, + AFE_MTKAIF1_RX_CFG2, + RG_MTKAIF1_RXIF_SYNC_WORD1_DISABLE_MASK_SFT, + 0x0); + } + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_ch56_ul_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int mtkaif_dmic = afe_priv->mtkaif_dmic; + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n", + __func__, w->name, event, mtkaif_dmic); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA_CH56, 1); + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(120, 130); + mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA_CH56, 1); + + /* reset dmic */ + afe_priv->mtkaif_dmic = 0; + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_ul_ap_dmic_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA, 1); + //mtk_adda_ul_src_dmic(afe, MT8196_DAI_AP_DMIC); + mt8196_afe_gpio_request(afe, true, MT8196_DAI_AP_DMIC, 1); + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(120, 130); + mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA, 1); + mt8196_afe_gpio_request(afe, false, MT8196_DAI_AP_DMIC, 1); + + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_ch34_ul_ap_dmic_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int mtkaif_adda6_only = afe_priv->mtkaif_adda6_only; + + dev_dbg(afe->dev, + "%s(), name %s, event 0x%x, mtkaif_adda6_only %d\n", + __func__, w->name, event, mtkaif_adda6_only); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA_CH34, 1); + mt8196_afe_gpio_request(afe, true, MT8196_DAI_AP_DMIC_CH34, 1); + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(120, 130); + mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA_CH34, 1); + mt8196_afe_gpio_request(afe, false, MT8196_DAI_AP_DMIC_CH34, 1); + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) + regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB8); + else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) + regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0); + else + regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0); + break; + default: + break; + } + + return 0; +} + +static bool is_adda_mtkaif_need_phase_delay(struct mt8196_afe_private *afe_priv) +{ + if (mt8196_afe_gpio_is_prepared(MT8196_AFE_GPIO_DAT_MISO0_ON) && + afe_priv->mtkaif_chosen_phase[0] < 0) { + return false; + } + + if (mt8196_afe_gpio_is_prepared(MT8196_AFE_GPIO_DAT_MISO1_ON) && + afe_priv->mtkaif_chosen_phase[1] < 0) { + return false; + } + + return true; +} + +static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int delay_data; + int delay_cycle; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: +#ifdef MTKAIF4 + /* mtkaif_rxif_clkinv_adc inverse for calibration */ + regmap_update_bits(afe->regmap, AFE_MTKAIF0_CFG0, + RG_MTKAIF0_RXIF_CLKINV_MASK_SFT, + 0x1 << RG_MTKAIF0_RXIF_CLKINV_SFT); + regmap_update_bits(afe->regmap, AFE_MTKAIF1_CFG0, + RG_MTKAIF1_RXIF_CLKINV_ADC_MASK_SFT, + 0x1 << RG_MTKAIF1_RXIF_CLKINV_ADC_SFT); +#endif + + if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) { + /* set protocol 2 */ + regmap_write(afe->regmap, AFE_MTKAIF0_CFG0, + 0x00010000); + regmap_write(afe->regmap, AFE_MTKAIF1_CFG0, + 0x00010000); + + /* mtkaif_rxif_clkinv_adc inverse for calibration */ + regmap_update_bits(afe->regmap, AFE_MTKAIF0_CFG0, + RG_MTKAIF0_RXIF_CLKINV_MASK_SFT, + 0x1 << RG_MTKAIF0_RXIF_CLKINV_SFT); + regmap_update_bits(afe->regmap, AFE_MTKAIF1_CFG0, + RG_MTKAIF1_RXIF_CLKINV_ADC_MASK_SFT, + 0x1 << RG_MTKAIF1_RXIF_CLKINV_ADC_SFT); + + /* This event align the phase of every miso pin */ + /* If only 1 miso is used, there is no need to do phase delay. */ + if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0 && + !is_adda_mtkaif_need_phase_delay(afe_priv)) { + dev_dbg(afe->dev, + "%s(), check adda mtkaif_chosen_phase[0/1]:%d/%d\n", + __func__, + afe_priv->mtkaif_chosen_phase[0], + afe_priv->mtkaif_chosen_phase[1]); + break; + } + + /* set delay for ch12 to align phase of miso0 and miso1 */ + if (afe_priv->mtkaif_phase_cycle[0] >= + afe_priv->mtkaif_phase_cycle[1]) { + delay_data = DELAY_DATA_MISO1; + delay_cycle = afe_priv->mtkaif_phase_cycle[0] - + afe_priv->mtkaif_phase_cycle[1]; + } else { + delay_data = DELAY_DATA_MISO2; + delay_cycle = afe_priv->mtkaif_phase_cycle[1] - + afe_priv->mtkaif_phase_cycle[0]; + } + + regmap_update_bits(afe->regmap, + AFE_MTKAIF0_RX_CFG2, + RG_MTKAIF0_RXIF_DELAY_DATA_MASK_SFT, + delay_data << + RG_MTKAIF0_RXIF_DELAY_DATA_SFT); + + regmap_update_bits(afe->regmap, + AFE_MTKAIF0_RX_CFG2, + RG_MTKAIF0_RXIF_DELAY_CYCLE_MASK_SFT, + delay_cycle << + RG_MTKAIF0_RXIF_DELAY_CYCLE_SFT); + + /* set delay between ch3 and ch2 */ + if (afe_priv->mtkaif_phase_cycle[2] >= + afe_priv->mtkaif_phase_cycle[1]) { + delay_data = DELAY_DATA_MISO1; /* ch3 */ + delay_cycle = afe_priv->mtkaif_phase_cycle[2] - + afe_priv->mtkaif_phase_cycle[1]; + } else { + delay_data = DELAY_DATA_MISO2; /* ch2 */ + delay_cycle = afe_priv->mtkaif_phase_cycle[1] - + afe_priv->mtkaif_phase_cycle[2]; + } + + regmap_update_bits(afe->regmap, + AFE_MTKAIF1_RX_CFG2, + RG_MTKAIF1_RXIF_DELAY_DATA_MASK_SFT, + delay_data << + RG_MTKAIF1_RXIF_DELAY_DATA_SFT); + regmap_update_bits(afe->regmap, + AFE_MTKAIF1_RX_CFG2, + RG_MTKAIF1_RXIF_DELAY_CYCLE_MASK_SFT, + delay_cycle << + RG_MTKAIF1_RXIF_DELAY_CYCLE_SFT); + } else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) { + regmap_write(afe->regmap, AFE_MTKAIF0_CFG0, + 0x00010000); + regmap_write(afe->regmap, AFE_MTKAIF1_CFG0, + 0x00010000); + } else { + regmap_write(afe->regmap, AFE_MTKAIF0_CFG0, 0x0); + regmap_write(afe->regmap, AFE_MTKAIF1_CFG0, 0x0); + } + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA, 0); + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(120, 130); + mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA, 0); + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_ch34_dl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA_CH34, 0); + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(120, 130); + mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA_CH34, 0); + break; + default: + break; + } + + return 0; +} + +static void mt6363_vs1_vote(struct mtk_base_afe *afe) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + bool pre_enable = afe_priv->is_mt6363_vote; + bool enable = false; + + if (!afe_priv->pmic_regmap) + return; + enable = (afe_priv->is_adda_dl_on && afe_priv->is_adda_dl_max_vol) || + afe_priv->is_adda_ul_on || + afe_priv->is_vow_enable; + if (enable == pre_enable) { + dev_dbg(afe->dev, "%s() enable == pre_enable = %d\n", + __func__, enable); + return; + } + afe_priv->is_mt6363_vote = enable; + dev_dbg(afe->dev, "%s() enable = %d\n", + __func__, enable); + if (enable) { + regmap_update_bits(afe_priv->pmic_regmap, RG_BUCK_VS1_VOTER_EN_LO_SET, + VS1_MT6338_MSK, VS1_MT6338_MSK); + } else { + regmap_update_bits(afe_priv->pmic_regmap, RG_BUCK_VS1_VOTER_EN_LO_CLR, + VS1_MT6338_MSK, VS1_MT6338_MSK); + } +} + +static int mt_vs1_voter_dl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + dev_dbg(afe->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + afe_priv->is_adda_dl_on = true; + mt6363_vs1_vote(afe); + break; + case SND_SOC_DAPM_POST_PMD: + afe_priv->is_adda_dl_on = false; + mt6363_vs1_vote(afe); + break; + default: + break; + } + + return 0; +} + +static int mt_vs1_voter_ul_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + dev_dbg(afe->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + afe_priv->is_adda_ul_on = true; + mt6363_vs1_vote(afe); + break; + case SND_SOC_DAPM_POST_PMD: + afe_priv->is_adda_ul_on = false; + mt6363_vs1_vote(afe); + break; + default: + break; + } + + return 0; +} + +/* stf */ +static int stf_positive_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->stf_positive_gain_db; + return 0; +} + +static int stf_positive_gain_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int gain_db = ucontrol->value.integer.value[0]; + + afe_priv->stf_positive_gain_db = gain_db; + + if (gain_db >= 0 && gain_db <= 24) { + regmap_update_bits(afe->regmap, + AFE_STF_GAIN, + SIDE_TONE_POSITIVE_GAIN_MASK_SFT, + (gain_db / 6) << SIDE_TONE_POSITIVE_GAIN_SFT); + } else { + dev_info(afe->dev, "%s(), gain_db %d invalid\n", + __func__, gain_db); + } + return 0; +} + +/* mtkaif dmic */ +static const char *const mt8196_adda_off_on_str[] = { + "Off", "On" +}; + +static const struct soc_enum mt8196_adda_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8196_adda_off_on_str), + mt8196_adda_off_on_str), +}; + +static int mt8196_adda_ap_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->ap_dmic; + return 0; +} + +static int mt8196_adda_ap_dmic_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int ap_dmic_on; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + ap_dmic_on = ucontrol->value.integer.value[0]; + + dev_dbg(afe->dev, "%s(), kcontrol name %s, ap_dmic_on %d\n", + __func__, kcontrol->id.name, ap_dmic_on); + + afe_priv->ap_dmic = ap_dmic_on; + return 0; +} + +static int mt8196_adda_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic; + return 0; +} + +static int mt8196_adda_dmic_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int dmic_on; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + dmic_on = ucontrol->value.integer.value[0]; + + dev_dbg(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n", + __func__, kcontrol->id.name, dmic_on); + + afe_priv->mtkaif_dmic = dmic_on; + afe_priv->mtkaif_dmic_ch34 = dmic_on; + return 0; +} + +static int mt8196_adda6_only_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->mtkaif_adda6_only; + return 0; +} + +static int mt8196_adda6_only_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int mtkaif_adda6_only; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + mtkaif_adda6_only = ucontrol->value.integer.value[0]; + + dev_dbg(afe->dev, "%s(), kcontrol name %s, mtkaif_adda6_only %d\n", + __func__, kcontrol->id.name, mtkaif_adda6_only); + + afe_priv->mtkaif_adda6_only = mtkaif_adda6_only; + return 0; +} + +static int mt8196_adda_dl_max_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->is_adda_dl_max_vol; + + return 0; +} + +static int mt8196_adda_dl_max_vol_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + bool is_adda_dl_max_vol = ucontrol->value.integer.value[0]; + + afe_priv->is_adda_dl_max_vol = is_adda_dl_max_vol; + mt6363_vs1_vote(afe); + + return 0; +} + +static int mt8196_vow_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->is_vow_enable; + + return 0; +} + +static int mt8196_vow_enable_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + bool is_vow_enable = ucontrol->value.integer.value[0]; + + afe_priv->is_vow_enable = is_vow_enable; + mt6363_vs1_vote(afe); + + return 0; +} + +static const struct snd_kcontrol_new mtk_adda_controls[] = { + SOC_SINGLE("Sidetone_Gain", AFE_STF_GAIN, + SIDE_TONE_GAIN_SFT, SIDE_TONE_GAIN_MASK, 0), + SOC_SINGLE_EXT("Sidetone_Positive_Gain_dB", SND_SOC_NOPM, 0, 100, 0, + stf_positive_gain_get, stf_positive_gain_set), + SOC_ENUM_EXT("MTKAIF_DMIC", mt8196_adda_enum[0], + mt8196_adda_dmic_get, mt8196_adda_dmic_set), + SOC_ENUM_EXT("MTKAIF_ADDA6_ONLY", mt8196_adda_enum[0], + mt8196_adda6_only_get, mt8196_adda6_only_set), + SOC_SINGLE_EXT("ADDA_DL_MAX_VOL", + SND_SOC_NOPM, 0, 0x1, 0, + mt8196_adda_dl_max_vol_get, + mt8196_adda_dl_max_vol_set), + SOC_SINGLE_EXT("VOW_ENABLE", + SND_SOC_NOPM, 0, 0x1, 0, + mt8196_vow_enable_get, + mt8196_vow_enable_set), + SOC_ENUM_EXT("AP DMIC Used", mt8196_adda_enum[0], + mt8196_adda_ap_dmic_get, mt8196_adda_ap_dmic_set), +}; + +static const struct snd_kcontrol_new stf_ctl = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const u16 stf_coeff_table_16k[] = { + 0x049C, 0x09E8, 0x09E0, 0x089C, + 0xFF54, 0xF488, 0xEAFC, 0xEBAC, + 0xfA40, 0x17AC, 0x3D1C, 0x6028, + 0x7538 +}; + +static const u16 stf_coeff_table_32k[] = { + 0xFE52, 0x0042, 0x00C5, 0x0194, + 0x029A, 0x03B7, 0x04BF, 0x057D, + 0x05BE, 0x0555, 0x0426, 0x0230, + 0xFF92, 0xFC89, 0xF973, 0xF6C6, + 0xF500, 0xF49D, 0xF603, 0xF970, + 0xFEF3, 0x065F, 0x0F4F, 0x1928, + 0x2329, 0x2C80, 0x345E, 0x3A0D, + 0x3D08 +}; + +static const u16 stf_coeff_table_48k[] = { + 0x0401, 0xFFB0, 0xFF5A, 0xFECE, + 0xFE10, 0xFD28, 0xFC21, 0xFB08, + 0xF9EF, 0xF8E8, 0xF80A, 0xF76C, + 0xF724, 0xF746, 0xF7E6, 0xF90F, + 0xFACC, 0xFD1E, 0xFFFF, 0x0364, + 0x0737, 0x0B62, 0x0FC1, 0x1431, + 0x188A, 0x1CA4, 0x2056, 0x237D, + 0x25F9, 0x27B0, 0x2890 +}; + +static int mtk_stf_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + size_t half_tap_num; + const u16 *stf_coeff_table; + unsigned int ul_rate; + + u32 reg_value; + size_t coef_addr; + + regmap_read(afe->regmap, AFE_ADDA_UL0_SRC_CON0, &ul_rate); + ul_rate = ul_rate >> UL_VOICE_MODE_CH1_CH2_CTL_SFT; + ul_rate = ul_rate & UL_VOICE_MODE_CH1_CH2_CTL_MASK; + + if (ul_rate == MTK_AFE_ADDA_UL_RATE_48K) { + half_tap_num = ARRAY_SIZE(stf_coeff_table_48k); + stf_coeff_table = stf_coeff_table_48k; + } else if (ul_rate == MTK_AFE_ADDA_UL_RATE_32K) { + half_tap_num = ARRAY_SIZE(stf_coeff_table_32k); + stf_coeff_table = stf_coeff_table_32k; + } else { + half_tap_num = ARRAY_SIZE(stf_coeff_table_16k); + stf_coeff_table = stf_coeff_table_16k; + } + + regmap_read(afe->regmap, AFE_STF_CON0, ®_value); + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x, ul_rate 0x%x, AFE_STF_CON0 0x%x\n", + __func__, w->name, event, ul_rate, reg_value); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* set side tone gain = 0 */ + regmap_update_bits(afe->regmap, + AFE_STF_GAIN, + SIDE_TONE_GAIN_MASK_SFT, + 0); + regmap_update_bits(afe->regmap, + AFE_STF_GAIN, + SIDE_TONE_POSITIVE_GAIN_MASK_SFT, + 0); + /* set stf half tap num */ + regmap_update_bits(afe->regmap, + AFE_STF_CON0, + SIDE_TONE_HALF_TAP_NUM_MASK_SFT, + half_tap_num << SIDE_TONE_HALF_TAP_NUM_SFT); + + /* set side tone coefficient */ + regmap_read(afe->regmap, AFE_STF_MON, ®_value); + for (coef_addr = 0; coef_addr < half_tap_num; coef_addr++) { + bool old_w_ready = (reg_value >> SIDE_TONE_W_RDY_SFT) & 0x1; + bool new_w_ready = 0; + int try_cnt = 0; + + regmap_update_bits(afe->regmap, + AFE_STF_COEFF, + 0x11FFFFF, + (1 << SIDE_TONE_COEFFICIENT_R_W_SEL_SFT) | + (coef_addr << + SIDE_TONE_COEFFICIENT_ADDR_SFT) | + stf_coeff_table[coef_addr]); + + /* wait until flag write_ready changed */ + for (try_cnt = 0; try_cnt < 10; try_cnt++) { + regmap_read(afe->regmap, + AFE_STF_MON, ®_value); + new_w_ready = (reg_value >> SIDE_TONE_W_RDY_SFT) & 0x1; + + /* flip => ok */ + if (new_w_ready == old_w_ready) { + usleep_range(1, 5); + if (try_cnt == 9) { + dev_info(afe->dev, + "%s(), write coeff not ready", + __func__); + } + } else { + break; + } + } + + /* need write -> read -> write to write next coeff */ + regmap_update_bits(afe->regmap, + AFE_STF_COEFF, + SIDE_TONE_COEFFICIENT_R_W_SEL_SFT, + 0x0); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* set side tone gain = 0 */ + regmap_update_bits(afe->regmap, + AFE_STF_GAIN, + SIDE_TONE_GAIN_MASK_SFT, + 0); + regmap_update_bits(afe->regmap, + AFE_STF_GAIN, + SIDE_TONE_POSITIVE_GAIN_MASK_SFT, + 0); + break; + default: + break; + } + + return 0; +} + +/* ADDA UL MUX */ +#define ADDA_UL_MUX_MASK 0x3 +enum { + ADDA_UL_MUX_MTKAIF = 0, + ADDA_UL_MUX_AP_DMIC, + ADDA_UL_MUX_AP_DMIC_MULTICH, +}; + +static const char *const adda_ul_mux_map[] = { + "MTKAIF", "AP_DMIC", "AP_DMIC_MULTI_CH", +}; + +static int adda_ul_map_value[] = { + ADDA_UL_MUX_MTKAIF, + ADDA_UL_MUX_AP_DMIC, + ADDA_UL_MUX_AP_DMIC_MULTICH, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum, + SND_SOC_NOPM, + 0, + ADDA_UL_MUX_MASK, + adda_ul_mux_map, + adda_ul_map_value); + +static const struct snd_kcontrol_new adda_ul_mux_control = + SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum); + +static const struct snd_kcontrol_new adda_ch34_ul_mux_control = + SOC_DAPM_ENUM("ADDA_CH34_UL_MUX Select", adda_ul_mux_map_enum); + +static const struct snd_kcontrol_new adda_ch56_ul_mux_control = + SOC_DAPM_ENUM("ADDA_CH56_UL_MUX Select", adda_ul_mux_map_enum); + +static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch1_mix, + ARRAY_SIZE(mtk_adda_dl_ch1_mix)), + SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch2_mix, + ARRAY_SIZE(mtk_adda_dl_ch2_mix)), + + SND_SOC_DAPM_MIXER("ADDA_DL_CH3", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch3_mix, + ARRAY_SIZE(mtk_adda_dl_ch3_mix)), + SND_SOC_DAPM_MIXER("ADDA_DL_CH4", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch4_mix, + ARRAY_SIZE(mtk_adda_dl_ch4_mix)), + + SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON, + AUDIO_ENGEN_CON0, AUDIO_F3P25M_EN_ON_SFT, 0, + NULL, 0), + + /*AFE_ADDA_MTKAIFV4_TX_CFG0 control by PAD_CLK*/ + SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON, + SND_SOC_NOPM, + 0, 0, + mtk_adda_dl_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ADDA CH34 Playback Enable", + SUPPLY_SEQ_ADDA_DL_ON, + AFE_ADDA6_MTKAIFV4_TX_CFG0, + ADDA6_MTKAIFV4_TXIF_AFE_ON_SFT, 0, + mtk_adda_ch34_dl_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON, + AFE_ADDA_UL0_SRC_CON0, + UL_SRC_ON_TMP_CTL_SFT, 0, + mtk_adda_ul_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ADDA CH34 Capture Enable", SUPPLY_SEQ_ADDA_UL_ON, + AFE_ADDA_UL1_SRC_CON0, + UL_SRC_ON_TMP_CTL_SFT, 0, + mtk_adda_ch34_ul_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ADDA CH56 Capture Enable", SUPPLY_SEQ_ADDA_UL_ON, + AFE_ADDA_UL1_SRC_CON0, + UL_SRC_ON_TMP_CTL_SFT, 0, + mtk_adda_ch56_ul_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP, + AFE_AUD_PAD_TOP_CFG0, + RG_RX_FIFO_ON_SFT, 0, + mtk_adda_pad_top_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("AUD_PAD_CLK", SUPPLY_SEQ_ADDA_AUD_PAD_TOP, + AFE_ADDA_MTKAIFV4_TX_CFG0, + MTKAIFV4_TXIF_AFE_ON_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIFV4_RX", SUPPLY_SEQ_ADDA_MTKAIF_CFG, + AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_RXIF_AFE_ON_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADDA6_MTKAIFV4_RX", SUPPLY_SEQ_ADDA6_MTKAIF_CFG, + AFE_ADDA6_MTKAIFV4_RX_CFG0, + ADDA6_MTKAIFV4_RXIF_AFE_ON_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG, + SND_SOC_NOPM, 0, 0, + mtk_adda_mtkaif_cfg_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("ADDA6_MTKAIF_CFG", SUPPLY_SEQ_ADDA6_MTKAIF_CFG, + SND_SOC_NOPM, 0, 0, + mtk_adda_mtkaif_cfg_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("ADDA7_MTKAIF_CFG", SUPPLY_SEQ_ADDA6_MTKAIF_CFG, + SND_SOC_NOPM, 0, 0, + mtk_adda_mtkaif_cfg_event, + SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC, + AFE_ADDA_UL0_SRC_CON0, + UL_AP_DMIC_ON_SFT, 0, + mtk_adda_ul_ap_dmic_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("AP_DMIC_CH34_EN", SUPPLY_SEQ_ADDA_AP_DMIC, + AFE_ADDA_UL1_SRC_CON0, + UL_AP_DMIC_ON_SFT, 0, + mtk_adda_ch34_ul_ap_dmic_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO, + AFE_ADDA_UL0_SRC_CON1, + FIFO_SOFT_RST_SFT, 1, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADDA_CH34_FIFO", SUPPLY_SEQ_ADDA_FIFO, + AFE_ADDA_UL1_SRC_CON1, + FIFO_SOFT_RST_SFT, 1, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("VS1_VOTER_DL", SUPPLY_SEQ_ADDA_AFE_ON, + SND_SOC_NOPM, 0, 0, + mt_vs1_voter_dl_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VS1_VOTER_UL", SUPPLY_SEQ_ADDA_AFE_ON, + SND_SOC_NOPM, 0, 0, + mt_vs1_voter_ul_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0, + &adda_ul_mux_control), + SND_SOC_DAPM_MUX("ADDA_CH34_UL_Mux", SND_SOC_NOPM, 0, 0, + &adda_ch34_ul_mux_control), + SND_SOC_DAPM_MUX("ADDA_CH56_UL_Mux", SND_SOC_NOPM, 0, 0, + &adda_ch56_ul_mux_control), + + SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"), + SND_SOC_DAPM_INPUT("AP_DMIC_CH34_INPUT"), + + /* stf */ + SND_SOC_DAPM_SWITCH_E("Sidetone Filter", + AFE_STF_CON0, SIDE_TONE_ON_SFT, 0, + &stf_ctl, + mtk_stf_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER("STF_CH1", SND_SOC_NOPM, 0, 0, + mtk_stf_ch1_mix, + ARRAY_SIZE(mtk_stf_ch1_mix)), + SND_SOC_DAPM_OUTPUT("STF_OUTPUT"), + + /* allow i2s on without codec on */ + SND_SOC_DAPM_OUTPUT("ADDA_DUMMY_OUT"), + SND_SOC_DAPM_MUX("ADDA_Out_Mux", + SND_SOC_NOPM, 0, 0, &adda_out_mux_control), + SND_SOC_DAPM_INPUT("ADDA_DUMMY_IN"), + SND_SOC_DAPM_MUX("ADDA_In_Mux", + SND_SOC_NOPM, 0, 0, &adda_in_mux_control), + + /* clock */ + SND_SOC_DAPM_CLOCK_SUPPLY("vlp_mux_audio_h"), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_ul0_adc_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_ul0_adc_hires_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_ul1_adc_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_ul1_adc_hires_clk"), +}; + +#define HIRES_THRESHOLD 48000 +static int mtk_afe_adc_hires_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = source; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_adda_priv *adda_priv; + + adda_priv = get_adda_priv_by_name(afe, w->name); + + if (!adda_priv) { + AUDIO_AEE("adda_priv == NULL"); + return 0; + } + + return (adda_priv->ul_rate > HIRES_THRESHOLD) ? 1 : 0; +} + +static int mtk_afe_record_miso1(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = source; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + return (afe_priv->audio_r_miso1_enable) ? 1 : 0; +} + +static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = { + /* playback */ + {"ADDA_DL_CH1", "DL0_CH1", "DL0"}, + {"ADDA_DL_CH2", "DL0_CH1", "DL0"}, + {"ADDA_DL_CH2", "DL0_CH2", "DL0"}, + + {"ADDA_DL_CH1", "DL1_CH1", "DL1"}, + {"ADDA_DL_CH2", "DL1_CH2", "DL1"}, + + {"ADDA_DL_CH1", "DL2_CH1", "DL2"}, + {"ADDA_DL_CH2", "DL2_CH2", "DL2"}, + + {"ADDA_DL_CH1", "DL3_CH1", "DL3"}, + {"ADDA_DL_CH2", "DL3_CH2", "DL3"}, + + {"ADDA_DL_CH1", "DL4_CH1", "DL4"}, + {"ADDA_DL_CH2", "DL4_CH2", "DL4"}, + + {"ADDA_DL_CH1", "DL5_CH1", "DL5"}, + {"ADDA_DL_CH2", "DL5_CH2", "DL5"}, + + {"ADDA_DL_CH1", "DL6_CH1", "DL6"}, + {"ADDA_DL_CH2", "DL6_CH2", "DL6"}, + + {"ADDA_DL_CH1", "DL7_CH1", "DL7"}, + {"ADDA_DL_CH2", "DL7_CH2", "DL7"}, + + {"ADDA_DL_CH1", "DL8_CH1", "DL8"}, + {"ADDA_DL_CH2", "DL8_CH2", "DL8"}, + + {"ADDA_DL_CH1", "DL_24CH_CH1", "DL_24CH"}, + {"ADDA_DL_CH2", "DL_24CH_CH2", "DL_24CH"}, + + {"ADDA_DL_CH1", "DL24_CH1", "DL24"}, + {"ADDA_DL_CH2", "DL24_CH2", "DL24"}, + + {"ADDA Playback", NULL, "ADDA_DL_CH1"}, + {"ADDA Playback", NULL, "ADDA_DL_CH2"}, + + {"ADDA Playback", NULL, "ADDA Enable"}, + {"ADDA Playback", NULL, "ADDA Playback Enable"}, + {"ADDA Playback", NULL, "AUD_PAD_CLK"}, + {"ADDA Playback", NULL, "AUD_PAD_TOP"}, + {"ADDA Playback", NULL, "VS1_VOTER_DL"}, + + {"ADDA_DL_CH3", "DL0_CH1", "DL0"}, + {"ADDA_DL_CH4", "DL0_CH2", "DL0"}, + + {"ADDA_DL_CH3", "DL1_CH1", "DL1"}, + {"ADDA_DL_CH4", "DL1_CH2", "DL1"}, + + {"ADDA_DL_CH3", "DL2_CH1", "DL2"}, + {"ADDA_DL_CH4", "DL2_CH2", "DL2"}, + + {"ADDA_DL_CH3", "DL3_CH1", "DL3"}, + {"ADDA_DL_CH4", "DL3_CH2", "DL3"}, + + {"ADDA_DL_CH3", "DL4_CH1", "DL4"}, + {"ADDA_DL_CH4", "DL4_CH2", "DL4"}, + + {"ADDA_DL_CH3", "DL5_CH1", "DL5"}, + {"ADDA_DL_CH4", "DL5_CH2", "DL5"}, + + {"ADDA_DL_CH3", "DL6_CH1", "DL6"}, + {"ADDA_DL_CH4", "DL6_CH2", "DL6"}, + + {"ADDA_DL_CH3", "DL7_CH1", "DL7"}, + {"ADDA_DL_CH4", "DL7_CH2", "DL7"}, + + {"ADDA_DL_CH3", "DL8_CH1", "DL8"}, + {"ADDA_DL_CH4", "DL8_CH2", "DL8"}, + + {"ADDA_DL_CH3", "DL_24CH_CH1", "DL_24CH"}, + {"ADDA_DL_CH4", "DL_24CH_CH2", "DL_24CH"}, + {"ADDA_DL_CH3", "DL_24CH_CH3", "DL_24CH"}, + {"ADDA_DL_CH4", "DL_24CH_CH4", "DL_24CH"}, + + {"ADDA CH34 Playback", NULL, "ADDA_DL_CH3"}, + {"ADDA CH34 Playback", NULL, "ADDA_DL_CH4"}, + + {"ADDA CH34 Playback", NULL, "ADDA Enable"}, + {"ADDA CH34 Playback", NULL, "ADDA CH34 Playback Enable"}, + {"ADDA CH34 Playback", NULL, "AUD_PAD_CLK"}, + {"ADDA CH34 Playback", NULL, "AUD_PAD_TOP"}, + {"ADDA CH34 Playback", NULL, "VS1_VOTER_DL"}, + + /* capture */ + {"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"}, + {"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"}, + {"ADDA_UL_Mux", "AP_DMIC_MULTI_CH", "AP DMIC MULTICH Capture"}, + + {"ADDA_CH34_UL_Mux", "MTKAIF", "ADDA CH34 Capture"}, + {"ADDA_CH34_UL_Mux", "AP_DMIC", "AP DMIC CH34 Capture"}, + {"ADDA_CH34_UL_Mux", "AP_DMIC_MULTI_CH", "AP DMIC MULTICH Capture"}, + + {"ADDA_CH56_UL_Mux", "MTKAIF", "ADDA CH56 Capture"}, + + {"ADDA Capture", NULL, "ADDA Enable"}, + {"ADDA Capture", NULL, "ADDA Capture Enable"}, + {"ADDA Capture", NULL, "AUD_PAD_CLK"}, + {"ADDA Capture", NULL, "AUD_PAD_TOP"}, + {"ADDA Capture", NULL, "ADDA_MTKAIFV4_RX"}, + {"ADDA Capture", NULL, "ADDA6_MTKAIFV4_RX", mtk_afe_record_miso1}, + {"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"}, + {"ADDA Capture", NULL, "VS1_VOTER_UL"}, + + {"AP DMIC Capture", NULL, "ADDA Enable"}, + {"AP DMIC Capture", NULL, "ADDA Capture Enable"}, + {"AP DMIC Capture", NULL, "ADDA_FIFO"}, + {"AP DMIC Capture", NULL, "AP_DMIC_EN"}, + + {"ADDA CH34 Capture", NULL, "ADDA Enable"}, + {"ADDA CH34 Capture", NULL, "ADDA CH34 Capture Enable"}, + {"ADDA CH34 Capture", NULL, "AUD_PAD_CLK"}, + {"ADDA CH34 Capture", NULL, "AUD_PAD_TOP"}, + {"ADDA CH34 Capture", NULL, "ADDA_MTKAIFV4_RX"}, + {"ADDA CH34 Capture", NULL, "ADDA6_MTKAIFV4_RX", mtk_afe_record_miso1}, + {"ADDA CH34 Capture", NULL, "ADDA6_MTKAIF_CFG"}, + {"ADDA CH34 Capture", NULL, "VS1_VOTER_UL"}, + + {"AP DMIC CH34 Capture", NULL, "ADDA Enable"}, + {"AP DMIC CH34 Capture", NULL, "ADDA CH34 Capture Enable"}, + {"AP DMIC CH34 Capture", NULL, "ADDA_CH34_FIFO"}, + {"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_EN"}, + + {"AP DMIC MULTICH Capture", NULL, "ADDA Enable"}, + {"AP DMIC MULTICH Capture", NULL, "ADDA Capture Enable"}, + {"AP DMIC MULTICH Capture", NULL, "ADDA CH34 Capture Enable"}, + {"AP DMIC MULTICH Capture", NULL, "ADDA_FIFO"}, + {"AP DMIC MULTICH Capture", NULL, "ADDA_CH34_FIFO"}, + {"AP DMIC MULTICH Capture", NULL, "AP_DMIC_EN"}, + {"AP DMIC MULTICH Capture", NULL, "AP_DMIC_CH34_EN"}, + + {"ADDA CH56 Capture", NULL, "ADDA Enable"}, + {"ADDA CH56 Capture", NULL, "ADDA CH56 Capture Enable"}, + {"ADDA CH56 Capture", NULL, "AUD_PAD_CLK"}, + {"ADDA CH56 Capture", NULL, "AUD_PAD_TOP"}, + {"ADDA CH56 Capture", NULL, "ADDA6_MTKAIFV4_RX"}, + {"ADDA CH56 Capture", NULL, "ADDA7_MTKAIF_CFG"}, + {"ADDA CH56 Capture", NULL, "VS1_VOTER_UL"}, + + {"AP DMIC Capture", NULL, "AP_DMIC_INPUT"}, + {"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_INPUT"}, + {"AP DMIC MULTICH Capture", NULL, "AP_DMIC_INPUT"}, + + /* sidetone filter */ + {"Sidetone Filter", "Switch", "STF_CH1"}, + + {"STF_OUTPUT", NULL, "Sidetone Filter"}, + {"ADDA Playback", NULL, "Sidetone Filter"}, + {"ADDA CH34 Playback", NULL, "Sidetone Filter"}, + + /* allow i2s on without codec on */ + {"ADDA Capture", NULL, "ADDA_In_Mux"}, + {"ADDA_In_Mux", "Dummy_Widget", "ADDA_DUMMY_IN"}, + {"ADDA_Out_Mux", "Dummy_Widget", "ADDA Playback"}, + {"ADDA_DUMMY_OUT", NULL, "ADDA_Out_Mux"}, + + /* clk */ + {"ADDA Capture Enable", NULL, "aud_ul0_adc_clk"}, + {"ADDA Capture Enable", NULL, "aud_ul0_adc_hires_clk", + mtk_afe_adc_hires_connect}, + {"ADDA CH34 Capture Enable", NULL, "aud_ul1_adc_clk"}, + {"ADDA CH34 Capture Enable", NULL, "aud_ul1_adc_hires_clk", + mtk_afe_adc_hires_connect}, + + {"aud_ul0_adc_hires_clk", NULL, "vlp_mux_audio_h"}, + {"aud_ul1_adc_hires_clk", NULL, "vlp_mux_audio_h"}, +}; + +/* dai ops */ +static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + unsigned int rate = params_rate(params); +#ifdef MTKAIF4 + unsigned int mtkaif_rate = 0; +#endif + int id = dai->id; + struct mtk_afe_adda_priv *adda_priv; + + if (id >= MT8196_DAI_NUM || id < 0) + return -EINVAL; + + adda_priv = afe_priv->dai_priv[id]; + + dev_info(afe->dev, "%s(), id %d, stream %d, rate %d\n", + __func__, + id, + substream->stream, + rate); + + if (!adda_priv) { + AUDIO_AEE("adda_priv == NULL"); + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + adda_priv->dl_rate = rate; + +#ifdef MTKAIF4 + /* get mtkaif dl rate */ + mtkaif_rate = + mtkaif_rate_transform(afe, adda_priv->dl_rate); +#endif + if (id == MT8196_DAI_ADDA) { +#ifdef MTKAIF4 + /* MTKAIF sample rate config */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0, + MTKAIFV4_TXIF_INPUT_MODE_MASK_SFT, + mtkaif_rate << MTKAIFV4_TXIF_INPUT_MODE_SFT); + /* AFE_ADDA_MTKAIFV4_TX_CFG0 */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0, + MTKAIFV4_TXIF_FOUR_CHANNEL_MASK_SFT, + 0x0 << MTKAIFV4_TXIF_FOUR_CHANNEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0, + MTKAIFV4_ADDA_OUT_EN_SEL_MASK_SFT, + 0x1 << MTKAIFV4_ADDA_OUT_EN_SEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0, + MTKAIFV4_ADDA6_OUT_EN_SEL_MASK_SFT, + 0x1 << MTKAIFV4_ADDA6_OUT_EN_SEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0, + MTKAIFV4_TXIF_V4_MASK_SFT, + 0x1 << MTKAIFV4_TXIF_V4_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0, + MTKAIFV4_TXIF_EN_SEL_MASK_SFT, + 0x0 << MTKAIFV4_TXIF_EN_SEL_SFT); +#endif + /* clean predistortion */ + } else { +#ifdef MTKAIF4 + /* MTKAIF sample rate config */ + regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_TX_CFG0, + ADDA6_MTKAIFV4_TXIF_INPUT_MODE_MASK_SFT, + mtkaif_rate << ADDA6_MTKAIFV4_TXIF_INPUT_MODE_SFT); + /* AFE_ADDA6_MTKAIFV4_TX_CFG0 */ + regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_TX_CFG0, + ADDA6_MTKAIFV4_TXIF_FOUR_CHANNEL_MASK_SFT, + 0x0 << ADDA6_MTKAIFV4_TXIF_FOUR_CHANNEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_TX_CFG0, + ADDA6_MTKAIFV4_TXIF_EN_SEL_MASK_SFT, + 0x1 << ADDA6_MTKAIFV4_TXIF_EN_SEL_SFT); +#endif + } + } else { + unsigned int voice_mode = 0; + unsigned int ul_src_con0 = 0; /* default value */ + + adda_priv->ul_rate = rate; + +#ifdef MTKAIF4 + /* get mtkaif dl rate */ + mtkaif_rate = + mtkaif_rate_transform(afe, adda_priv->ul_rate); +#endif + + voice_mode = adda_ul_rate_transform(afe, rate); + + ul_src_con0 |= (voice_mode << 17) & (0x7 << 17); + + /* enable iir */ + ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) & + UL_IIR_ON_TMP_CTL_MASK_SFT; + ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) & + UL_IIRMODE_CTL_MASK_SFT; + + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT, + mtkaif_rate << MTKAIFV4_RXIF_INPUT_MODE_SFT); + + regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0, + ADDA6_MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT, + mtkaif_rate << ADDA6_MTKAIFV4_RXIF_INPUT_MODE_SFT); + + switch (id) { + case MT8196_DAI_ADDA: + case MT8196_DAI_AP_DMIC: + case MT8196_DAI_AP_DMIC_MULTICH: +#ifdef MTKAIF4 + if (afe_priv->audio_r_miso1_enable == 1) { + /* AFE_ADDA_MTKAIFV4_RX_CFG0 */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT, + 0x0 << MTKAIFV4_RXIF_FOUR_CHANNEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_RXIF_EN_SEL_MASK_SFT, + 0x1 << MTKAIFV4_RXIF_EN_SEL_SFT); + + /* AFE_ADDA6_MTKAIFV4_RX_CFG0 */ + regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0, + ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT, + 0x1 << ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0, + ADDA6_MTKAIFV4_RXIF_EN_SEL_MASK_SFT, + 0x1 << ADDA6_MTKAIFV4_RXIF_EN_SEL_SFT); + } else { + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT, + mtkaif_rate << MTKAIFV4_RXIF_INPUT_MODE_SFT); + /* AFE_ADDA_MTKAIFV4_RX_CFG0 */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT, + 0x1 << MTKAIFV4_RXIF_FOUR_CHANNEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_RXIF_EN_SEL_MASK_SFT, + 0x0 << MTKAIFV4_RXIF_EN_SEL_SFT); + /* [28] loopback mode + * 0: loopback adda tx to adda rx + * 1: loopback adda6 tx to adda rx + */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_TXIF_EN_SEL_MASK_SFT, + 0x0 << MTKAIFV4_TXIF_EN_SEL_SFT); + } + + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT, + 0x1 << MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT, + 0x1 << MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT); +#endif + /* 35Hz @ 48k */ + regmap_write(afe->regmap, + AFE_ADDA_UL1_IIR_COEF_02_01, 0x00000000); + regmap_write(afe->regmap, + AFE_ADDA_UL1_IIR_COEF_04_03, 0x00003FB8); + regmap_write(afe->regmap, + AFE_ADDA_UL1_IIR_COEF_06_05, 0x3FB80000); + regmap_write(afe->regmap, + AFE_ADDA_UL1_IIR_COEF_08_07, 0x3FB80000); + regmap_write(afe->regmap, + AFE_ADDA_UL1_IIR_COEF_10_09, 0x0000C048); + + regmap_write(afe->regmap, + AFE_ADDA_UL1_SRC_CON0, ul_src_con0); + + /* mtkaif_rxif_data_mode = 0, amic */ + regmap_update_bits(afe->regmap, + AFE_MTKAIF1_RX_CFG0, + 0x1 << 0, + 0x0 << 0); + + /* 35Hz @ 48k */ + regmap_write(afe->regmap, + AFE_ADDA_UL0_IIR_COEF_02_01, 0x00000000); + regmap_write(afe->regmap, + AFE_ADDA_UL0_IIR_COEF_04_03, 0x00003FB8); + regmap_write(afe->regmap, + AFE_ADDA_UL0_IIR_COEF_06_05, 0x3FB80000); + regmap_write(afe->regmap, + AFE_ADDA_UL0_IIR_COEF_08_07, 0x3FB80000); + regmap_write(afe->regmap, + AFE_ADDA_UL0_IIR_COEF_10_09, 0x0000C048); + + regmap_write(afe->regmap, + AFE_ADDA_UL0_SRC_CON0, ul_src_con0); + + /* mtkaif_rxif_data_mode = 0, amic */ + regmap_update_bits(afe->regmap, + AFE_MTKAIF0_RX_CFG0, + 0x1 << 0, + 0x0 << 0); + break; + case MT8196_DAI_ADDA_CH34: + case MT8196_DAI_AP_DMIC_CH34: +#ifdef MTKAIF4 + if (afe_priv->audio_r_miso1_enable == 0) { + /* AFE_ADDA_MTKAIFV4_RX_CFG0 */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT, + 0x1 << MTKAIFV4_RXIF_FOUR_CHANNEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_RXIF_EN_SEL_MASK_SFT, + 0x0 << MTKAIFV4_RXIF_EN_SEL_SFT); + } + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT, + 0x1 << MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT, + 0x1 << MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT); + +#endif + /* 35Hz @ 48k */ + regmap_write(afe->regmap, + AFE_ADDA_UL1_IIR_COEF_02_01, 0x00000000); + regmap_write(afe->regmap, + AFE_ADDA_UL1_IIR_COEF_04_03, 0x00003FB8); + regmap_write(afe->regmap, + AFE_ADDA_UL1_IIR_COEF_06_05, 0x3FB80000); + regmap_write(afe->regmap, + AFE_ADDA_UL1_IIR_COEF_08_07, 0x3FB80000); + regmap_write(afe->regmap, + AFE_ADDA_UL1_IIR_COEF_10_09, 0x0000C048); + + regmap_write(afe->regmap, + AFE_ADDA_UL1_SRC_CON0, ul_src_con0); + + /* mtkaif_rxif_data_mode = 0, amic */ + regmap_update_bits(afe->regmap, + AFE_MTKAIF1_RX_CFG0, + 0x1 << 0, + 0x0 << 0); + + break; + case MT8196_DAI_ADDA_CH56: + if (afe_priv->audio_r_miso1_enable == 1) { + /* AFE_ADDA_MTKAIFV4_RX_CFG0 */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT, + 0x1 << MTKAIFV4_RXIF_FOUR_CHANNEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_RXIF_EN_SEL_MASK_SFT, + 0x0 << MTKAIFV4_RXIF_EN_SEL_SFT); + /* [28] loopback mode + * 0: loopback adda tx to adda rx + * 1: loopback adda6 tx to adda rx + */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_TXIF_EN_SEL_MASK_SFT, + 0x0 << MTKAIFV4_TXIF_EN_SEL_SFT); + } + regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0, + ADDA6_MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT, + mtkaif_rate << ADDA6_MTKAIFV4_RXIF_INPUT_MODE_SFT); + /* AFE_ADDA6_MTKAIFV4_RX_CFG0 */ + regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0, + ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT, + 0x1 << ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0, + MTKAIFV4_UL_CH5CH6_IN_EN_SEL_MASK_SFT, + 0x1 << MTKAIFV4_UL_CH5CH6_IN_EN_SEL_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0, + ADDA6_MTKAIFV4_RXIF_EN_SEL_MASK_SFT, + 0x1 << ADDA6_MTKAIFV4_RXIF_EN_SEL_SFT); + break; + default: + break; + } + + /* ap dmic */ + switch (id) { + case MT8196_DAI_AP_DMIC: + case MT8196_DAI_AP_DMIC_CH34: + mtk_adda_ul_src_dmic(afe, id); + break; + case MT8196_DAI_AP_DMIC_MULTICH: + regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1, + DMIC_CLK_PHASE_SYNC_SET_MASK_SFT, + 0x1 << DMIC_CLK_PHASE_SYNC_SET_SFT); + mtk_adda_ul_src_dmic_phase_sync(afe); + mtk_adda_ul_src_dmic(afe, MT8196_DAI_AP_DMIC); + mtk_adda_ul_src_dmic(afe, MT8196_DAI_AP_DMIC_CH34); + mtk_adda_ul_src_dmic_phase_sync_clock(afe); + break; + default: + break; + } + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_adda_ops = { + .hw_params = mtk_dai_adda_hw_params, +}; + +/* dai driver */ +#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_adda_driver[] = { + { + .name = "ADDA", + .id = MT8196_DAI_ADDA, + .playback = { + .stream_name = "ADDA Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_PLAYBACK_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .capture = { + .stream_name = "ADDA Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, + { + .name = "ADDA_CH34", + .id = MT8196_DAI_ADDA_CH34, + .playback = { + .stream_name = "ADDA CH34 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_PLAYBACK_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .capture = { + .stream_name = "ADDA CH34 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, + { + .name = "ADDA_CH56", + .id = MT8196_DAI_ADDA_CH56, + .capture = { + .stream_name = "ADDA CH56 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, + { + .name = "AP_DMIC", + .id = MT8196_DAI_AP_DMIC, + .capture = { + .stream_name = "AP DMIC Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, + { + .name = "AP_DMIC_CH34", + .id = MT8196_DAI_AP_DMIC_CH34, + .capture = { + .stream_name = "AP DMIC CH34 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, + { + .name = "AP_DMIC_MULTICH", + .id = MT8196_DAI_AP_DMIC_MULTICH, + .capture = { + .stream_name = "AP DMIC MULTICH Capture", + .channels_min = 1, + .channels_max = 4, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, +}; + +int mt8196_dai_adda_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int ret; + + dev_dbg(afe->dev, "%s() successfully start\n", __func__); + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_adda_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver); + + dai->controls = mtk_adda_controls; + dai->num_controls = ARRAY_SIZE(mtk_adda_controls); + dai->dapm_widgets = mtk_dai_adda_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets); + dai->dapm_routes = mtk_dai_adda_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes); + + /* set dai priv */ + ret = mt8196_dai_set_priv(afe, MT8196_DAI_ADDA, + sizeof(struct mtk_afe_adda_priv), NULL); + if (ret) + return ret; + + ret = mt8196_dai_set_priv(afe, MT8196_DAI_ADDA_CH34, + sizeof(struct mtk_afe_adda_priv), NULL); + if (ret) + return ret; + + ret = mt8196_dai_set_priv(afe, MT8196_DAI_ADDA_CH56, + sizeof(struct mtk_afe_adda_priv), NULL); + if (ret) + return ret; + + ret = mt8196_dai_set_priv(afe, MT8196_DAI_AP_DMIC_MULTICH, + sizeof(struct mtk_afe_adda_priv), NULL); + if (ret) + return ret; + + /* get ap mic type */ + ret = of_property_read_u32(afe->dev->of_node, "mediatek,ap-dmic", + &afe_priv->ap_dmic); + if (ret) + afe_priv->ap_dmic = 0; + + /* ap dmic priv share with adda */ + afe_priv->dai_priv[MT8196_DAI_AP_DMIC] = + afe_priv->dai_priv[MT8196_DAI_ADDA]; + afe_priv->dai_priv[MT8196_DAI_AP_DMIC_CH34] = + afe_priv->dai_priv[MT8196_DAI_ADDA_CH34]; + + return 0; +} + From patchwork Fri Mar 7 12:47:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darren.Ye" X-Patchwork-Id: 14006461 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3C2F0C19F32 for ; Fri, 7 Mar 2025 13:04:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=YHoPVUyk90tSk86Bv+iQ8zjOOea1918t2LmuhpaCEhU=; b=uVljeQQWQjWm+0FRMreQZwHZ4V dSIbjhBo//RSN9mpYp8AWBXS57R3O4pByNg6t0Yc7SB5Fa9SdnqP3QVcGF8ZHmMIQCWS/BSr3j0wS DymAF3qMUQtHSPsaXYkgTUow6Q/RtjLdFQVpQ0iGdN6VFYDfZ8+KCplUBUj/z7SgKQlAbjLyzdxab IkLjGWKWfD4KGUo6FcojY85dd8bd3s+NFAne7RoxB2702jgCBOrJpfUed9dQPVH1/Q5OIG0KEJa+0 Emmf0bRZ13gJjfyb0zD/cLrF/q8RubuXNCsQidmwW9QoBxG8oc/RroJvQqflqVYRM0BGS8Eos3AwB u8fgcLCA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tqXNM-0000000EG7b-1Xb0; Fri, 07 Mar 2025 13:04:28 +0000 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqX8i-0000000EDqg-0cNe; Fri, 07 Mar 2025 12:49:20 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Type:Content-Transfer-Encoding :MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From: Sender:Reply-To:Content-ID:Content-Description; bh=YHoPVUyk90tSk86Bv+iQ8zjOOea1918t2LmuhpaCEhU=; b=E4dB7uJgbiq4+QoVQ8QQudBGiq sr2C6ZNDTtZCVruyz1gG1j3is6UO5ToCq6l8xrPgkd+b5TO6cMRBPOjUwqcvLEfL/1k+67nfILCfs YaVino2hawIIWVTHS2qLSClN1Ei0dLxksGjKcMA7vdEOowOdp6xPNVOwLWIegqE2dVRiNDYRlj7zi Yk+aA5OUOZmcpSzuE2KtiY5rDDFXBn3OX0tEBFK7L8KhWxr2Ql8Hm+r1noR7YFV2ukkIRaWr25Zmf C7I50KJpQUGDp/lmws0Twk7M2CuAZKo9/jZ2ova5Aq7U5o10roA1QPK8ri8bkwCPATInXfbydvRds iuTrgsHA==; Received: from mailgw01.mediatek.com ([216.200.240.184]) by desiato.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqX8e-00000001KdQ-3ezu; Fri, 07 Mar 2025 12:49:19 +0000 X-UUID: 8ff81f82fb5211ef83f2a1c9db70dae0-20250307 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=YHoPVUyk90tSk86Bv+iQ8zjOOea1918t2LmuhpaCEhU=; b=DGbInvqXhs71YGOaaePS74I6tUydQvmZFm+jMJltozQlpSto+iux0kQuiy4q4iQoA6PxfJGskiLvzIq33rwKvIZSf+wL2UDDUU2k7t3X6jQ3hjyrcAUweh2Iz+VlU9wgWaqcyGA8sa0oFpb5u6sGAGYupqBA4hfqs0Dm8tEBCZI=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:867c3b2e-316a-492f-9535-977ff908986b,IP:0,UR L:0,TC:0,Content:0,EDM:-25,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION :release,TS:-25 X-CID-META: VersionHash:0ef645f,CLOUDID:8853168c-f5b8-47d5-8cf3-b68fe7530c9a,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:1, IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV: 0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 8ff81f82fb5211ef83f2a1c9db70dae0-20250307 Received: from mtkmbs14n2.mediatek.inc [(172.21.101.76)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1662436529; Fri, 07 Mar 2025 05:49:09 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n1.mediatek.inc (172.21.101.193) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 7 Mar 2025 20:49:06 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 7 Mar 2025 20:49:05 +0800 From: Darren.Ye To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Jaroslav Kysela , Takashi Iwai , Linus Walleij , Bartosz Golaszewski CC: , , , , , , Darren Ye Subject: [PATCH 09/14] ASoC: mediatek: mt8196: support TDM in platform driver Date: Fri, 7 Mar 2025 20:47:35 +0800 Message-ID: <20250307124841.23777-10-darren.ye@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250307124841.23777-1-darren.ye@mediatek.com> References: <20250307124841.23777-1-darren.ye@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250307_124917_352982_AB60426F X-CRM114-Status: GOOD ( 17.18 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Darren Ye Add mt8196 TDM DAI driver support. Signed-off-by: Darren Ye --- sound/soc/mediatek/mt8196/mt8196-dai-tdm.c | 837 +++++++++++++++++++++ 1 file changed, 837 insertions(+) create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-tdm.c diff --git a/sound/soc/mediatek/mt8196/mt8196-dai-tdm.c b/sound/soc/mediatek/mt8196/mt8196-dai-tdm.c new file mode 100644 index 000000000000..465134b234bd --- /dev/null +++ b/sound/soc/mediatek/mt8196/mt8196-dai-tdm.c @@ -0,0 +1,837 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek ALSA SoC Audio DAI TDM Control + * + * Copyright (c) 2024 MediaTek Inc. + * Author: Darren Ye + */ + +#include +#include +#include "mt8196-afe-clk.h" +#include "mt8196-afe-common.h" +#include "mt8196-interconnection.h" + +struct mtk_afe_tdm_priv { + int bck_id; + int bck_rate; + + int mclk_id; + int mclk_multiple; /* according to sample rate */ + int mclk_rate; + int mclk_apll; +}; + +enum { + TDM_WLEN_16_BIT = 1, + TDM_WLEN_32_BIT = 2, +}; + +enum { + TDM_CHANNEL_BCK_16 = 0, + TDM_CHANNEL_BCK_24 = 1, + TDM_CHANNEL_BCK_32 = 2, +}; + +enum { + TDM_CHANNEL_NUM_2 = 0, + TDM_CHANNEL_NUM_4 = 1, + TDM_CHANNEL_NUM_8 = 2, +}; + +enum { + TDM_CH_START_O30_O31 = 0, + TDM_CH_START_O32_O33, + TDM_CH_START_O34_O35, + TDM_CH_START_O36_O37, + TDM_CH_ZERO, +}; + +enum { + DPTX_CHANNEL_2, + DPTX_CHANNEL_8, +}; + +enum { + DPTX_WLEN_24_BIT, + DPTX_WLEN_16_BIT, +}; + +enum { + DPTX_CH_EN_MASK_2CH = 0x3, + DPTX_CH_EN_MASK_4CH = 0xf, + DPTX_CH_EN_MASK_6CH = 0x3f, + DPTX_CH_EN_MASK_8CH = 0xff, +}; + +static unsigned int get_tdm_wlen(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + TDM_WLEN_16_BIT : TDM_WLEN_32_BIT; +} + +static unsigned int get_tdm_channel_bck(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32; +} + +static unsigned int get_tdm_lrck_width(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) - 1; +} + +static unsigned int get_tdm_ch(unsigned int ch) +{ + switch (ch) { + case 1: + case 2: + return TDM_CHANNEL_NUM_2; + case 3: + case 4: + return TDM_CHANNEL_NUM_4; + case 5: + case 6: + case 7: + case 8: + default: + return TDM_CHANNEL_NUM_8; + } +} + +static unsigned int get_dptx_ch_enable_mask(unsigned int ch) +{ + switch (ch) { + case 1: + case 2: + return DPTX_CH_EN_MASK_2CH; + case 3: + case 4: + return DPTX_CH_EN_MASK_4CH; + case 5: + case 6: + return DPTX_CH_EN_MASK_6CH; + case 7: + case 8: + return DPTX_CH_EN_MASK_8CH; + default: + pr_info("%s(), invalid channel num, default use 2ch\n", + __func__); + return DPTX_CH_EN_MASK_2CH; + } +} + +static unsigned int get_dptx_ch(unsigned int ch) +{ + if (ch == 2) + return DPTX_CHANNEL_2; + else + return DPTX_CHANNEL_8; +} + +static unsigned int get_dptx_wlen(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + DPTX_WLEN_16_BIT : DPTX_WLEN_24_BIT; +} + +/* interconnection */ +enum { + HDMI_CONN_CH0 = 0, + HDMI_CONN_CH1, + HDMI_CONN_CH2, + HDMI_CONN_CH3, + HDMI_CONN_CH4, + HDMI_CONN_CH5, + HDMI_CONN_CH6, + HDMI_CONN_CH7, +}; + +static const char *const hdmi_conn_mux_map[] = { + "CH0", "CH1", "CH2", "CH3", + "CH4", "CH5", "CH6", "CH7", +}; + +static int hdmi_conn_mux_map_value[] = { + HDMI_CONN_CH0, + HDMI_CONN_CH1, + HDMI_CONN_CH2, + HDMI_CONN_CH3, + HDMI_CONN_CH4, + HDMI_CONN_CH5, + HDMI_CONN_CH6, + HDMI_CONN_CH7, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_0_SFT, + HDMI_O_0_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch0_mux_control = + SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_1_SFT, + HDMI_O_1_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch1_mux_control = + SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_2_SFT, + HDMI_O_2_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch2_mux_control = + SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_3_SFT, + HDMI_O_3_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch3_mux_control = + SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_4_SFT, + HDMI_O_4_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch4_mux_control = + SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_5_SFT, + HDMI_O_5_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch5_mux_control = + SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_6_SFT, + HDMI_O_6_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch6_mux_control = + SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_7_SFT, + HDMI_O_7_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch7_mux_control = + SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum); + +static const char *const tdm_out_mux_map[] = { + "Disconnect", "Connect", +}; + +static int tdm_out_mux_map_value[] = { + 0, 1, +}; + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(hdmi_out_mux_map_enum, + SND_SOC_NOPM, + 0, + 1, + tdm_out_mux_map, + tdm_out_mux_map_value); +static const struct snd_kcontrol_new hdmi_out_mux_control = + SOC_DAPM_ENUM("HDMI_OUT_MUX", hdmi_out_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(dptx_out_mux_map_enum, + SND_SOC_NOPM, + 0, + 1, + tdm_out_mux_map, + tdm_out_mux_map_value); +static const struct snd_kcontrol_new dptx_out_mux_control = + SOC_DAPM_ENUM("DPTX_OUT_MUX", dptx_out_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(dptx_virtual_out_mux_map_enum, + SND_SOC_NOPM, + 0, + 1, + tdm_out_mux_map, + tdm_out_mux_map_value); + +static const struct snd_kcontrol_new dptx_virtual_out_mux_control = + SOC_DAPM_ENUM("DPTX_VIRTUAL_OUT_MUX", dptx_virtual_out_mux_map_enum); + +enum { + SUPPLY_SEQ_APLL, + SUPPLY_SEQ_TDM_MCK_EN, + SUPPLY_SEQ_TDM_BCK_EN, + SUPPLY_SEQ_TDM_DPTX_MCK_EN, + SUPPLY_SEQ_TDM_DPTX_BCK_EN, +}; + +static int get_tdm_id_by_name(const char *name) +{ + if (strstr(name, "DPTX")) + return MT8196_DAI_TDM_DPTX; + else + return MT8196_DAI_TDM; +} + +static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n", + __func__, w->name, event, dai_id); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8196_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate); + break; + case SND_SOC_DAPM_POST_PMD: + mt8196_mck_disable(afe, tdm_priv->bck_id); + break; + default: + break; + } + + return 0; +} + +static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n", + __func__, w->name, event, dai_id); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8196_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate); + break; + case SND_SOC_DAPM_POST_PMD: + tdm_priv->mclk_rate = 0; + mt8196_mck_disable(afe, tdm_priv->mclk_id); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = { + SND_SOC_DAPM_MUX("HDMI_CH0_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch0_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH1_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch1_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH2_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch2_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH3_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch3_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH4_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch4_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH5_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch5_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH6_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch6_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch7_mux_control), + SND_SOC_DAPM_MUX("HDMI_OUT_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_out_mux_control), + SND_SOC_DAPM_MUX("DPTX_OUT_MUX", SND_SOC_NOPM, 0, 0, + &dptx_out_mux_control), + + SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN, + SND_SOC_NOPM, 0, 0, + mtk_tdm_bck_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN, + SND_SOC_NOPM, 0, 0, + mtk_tdm_mck_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TDM_DPTX_BCK", SUPPLY_SEQ_TDM_DPTX_BCK_EN, + SND_SOC_NOPM, 0, 0, + mtk_tdm_bck_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TDM_DPTX_MCK", SUPPLY_SEQ_TDM_DPTX_MCK_EN, + SND_SOC_NOPM, 0, 0, + mtk_tdm_mck_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("DPTX_VIRTUAL_OUT_MUX", + SND_SOC_NOPM, 0, 0, &dptx_virtual_out_mux_control), + SND_SOC_DAPM_OUTPUT("DPTX_VIRTUAL_OUT"), +}; + +static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + int cur_apll; + + /* which apll */ + cur_apll = mt8196_get_apll_by_name(afe, source->name); + + return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0; +} + +static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = { + {"HDMI_CH0_MUX", "CH0", "HDMI"}, + {"HDMI_CH0_MUX", "CH1", "HDMI"}, + {"HDMI_CH0_MUX", "CH2", "HDMI"}, + {"HDMI_CH0_MUX", "CH3", "HDMI"}, + {"HDMI_CH0_MUX", "CH4", "HDMI"}, + {"HDMI_CH0_MUX", "CH5", "HDMI"}, + {"HDMI_CH0_MUX", "CH6", "HDMI"}, + {"HDMI_CH0_MUX", "CH7", "HDMI"}, + + {"HDMI_CH1_MUX", "CH0", "HDMI"}, + {"HDMI_CH1_MUX", "CH1", "HDMI"}, + {"HDMI_CH1_MUX", "CH2", "HDMI"}, + {"HDMI_CH1_MUX", "CH3", "HDMI"}, + {"HDMI_CH1_MUX", "CH4", "HDMI"}, + {"HDMI_CH1_MUX", "CH5", "HDMI"}, + {"HDMI_CH1_MUX", "CH6", "HDMI"}, + {"HDMI_CH1_MUX", "CH7", "HDMI"}, + + {"HDMI_CH2_MUX", "CH0", "HDMI"}, + {"HDMI_CH2_MUX", "CH1", "HDMI"}, + {"HDMI_CH2_MUX", "CH2", "HDMI"}, + {"HDMI_CH2_MUX", "CH3", "HDMI"}, + {"HDMI_CH2_MUX", "CH4", "HDMI"}, + {"HDMI_CH2_MUX", "CH5", "HDMI"}, + {"HDMI_CH2_MUX", "CH6", "HDMI"}, + {"HDMI_CH2_MUX", "CH7", "HDMI"}, + + {"HDMI_CH3_MUX", "CH0", "HDMI"}, + {"HDMI_CH3_MUX", "CH1", "HDMI"}, + {"HDMI_CH3_MUX", "CH2", "HDMI"}, + {"HDMI_CH3_MUX", "CH3", "HDMI"}, + {"HDMI_CH3_MUX", "CH4", "HDMI"}, + {"HDMI_CH3_MUX", "CH5", "HDMI"}, + {"HDMI_CH3_MUX", "CH6", "HDMI"}, + {"HDMI_CH3_MUX", "CH7", "HDMI"}, + + {"HDMI_CH4_MUX", "CH0", "HDMI"}, + {"HDMI_CH4_MUX", "CH1", "HDMI"}, + {"HDMI_CH4_MUX", "CH2", "HDMI"}, + {"HDMI_CH4_MUX", "CH3", "HDMI"}, + {"HDMI_CH4_MUX", "CH4", "HDMI"}, + {"HDMI_CH4_MUX", "CH5", "HDMI"}, + {"HDMI_CH4_MUX", "CH6", "HDMI"}, + {"HDMI_CH4_MUX", "CH7", "HDMI"}, + + {"HDMI_CH5_MUX", "CH0", "HDMI"}, + {"HDMI_CH5_MUX", "CH1", "HDMI"}, + {"HDMI_CH5_MUX", "CH2", "HDMI"}, + {"HDMI_CH5_MUX", "CH3", "HDMI"}, + {"HDMI_CH5_MUX", "CH4", "HDMI"}, + {"HDMI_CH5_MUX", "CH5", "HDMI"}, + {"HDMI_CH5_MUX", "CH6", "HDMI"}, + {"HDMI_CH5_MUX", "CH7", "HDMI"}, + + {"HDMI_CH6_MUX", "CH0", "HDMI"}, + {"HDMI_CH6_MUX", "CH1", "HDMI"}, + {"HDMI_CH6_MUX", "CH2", "HDMI"}, + {"HDMI_CH6_MUX", "CH3", "HDMI"}, + {"HDMI_CH6_MUX", "CH4", "HDMI"}, + {"HDMI_CH6_MUX", "CH5", "HDMI"}, + {"HDMI_CH6_MUX", "CH6", "HDMI"}, + {"HDMI_CH6_MUX", "CH7", "HDMI"}, + + {"HDMI_CH7_MUX", "CH0", "HDMI"}, + {"HDMI_CH7_MUX", "CH1", "HDMI"}, + {"HDMI_CH7_MUX", "CH2", "HDMI"}, + {"HDMI_CH7_MUX", "CH3", "HDMI"}, + {"HDMI_CH7_MUX", "CH4", "HDMI"}, + {"HDMI_CH7_MUX", "CH5", "HDMI"}, + {"HDMI_CH7_MUX", "CH6", "HDMI"}, + {"HDMI_CH7_MUX", "CH7", "HDMI"}, + + {"HDMI_OUT_MUX", "Connect", "HDMI_CH0_MUX"}, + {"HDMI_OUT_MUX", "Connect", "HDMI_CH1_MUX"}, + {"HDMI_OUT_MUX", "Connect", "HDMI_CH2_MUX"}, + {"HDMI_OUT_MUX", "Connect", "HDMI_CH3_MUX"}, + {"HDMI_OUT_MUX", "Connect", "HDMI_CH4_MUX"}, + {"HDMI_OUT_MUX", "Connect", "HDMI_CH5_MUX"}, + {"HDMI_OUT_MUX", "Connect", "HDMI_CH6_MUX"}, + {"HDMI_OUT_MUX", "Connect", "HDMI_CH7_MUX"}, + + {"DPTX_OUT_MUX", "Connect", "HDMI_CH0_MUX"}, + {"DPTX_OUT_MUX", "Connect", "HDMI_CH1_MUX"}, + {"DPTX_OUT_MUX", "Connect", "HDMI_CH2_MUX"}, + {"DPTX_OUT_MUX", "Connect", "HDMI_CH3_MUX"}, + {"DPTX_OUT_MUX", "Connect", "HDMI_CH4_MUX"}, + {"DPTX_OUT_MUX", "Connect", "HDMI_CH5_MUX"}, + {"DPTX_OUT_MUX", "Connect", "HDMI_CH6_MUX"}, + {"DPTX_OUT_MUX", "Connect", "HDMI_CH7_MUX"}, + + {"TDM", NULL, "HDMI_OUT_MUX"}, + {"TDM", NULL, "TDM_BCK"}, + + {"TDM_DPTX", NULL, "DPTX_OUT_MUX"}, + {"TDM_DPTX", NULL, "TDM_DPTX_BCK"}, + + {"TDM_BCK", NULL, "TDM_MCK"}, + {"TDM_DPTX_BCK", NULL, "TDM_DPTX_MCK"}, + {"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect}, + {"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect}, + {"TDM_DPTX_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect}, + {"TDM_DPTX_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect}, + + {"DPTX_VIRTUAL_OUT_MUX", "Connect", "TDM_DPTX"}, + {"DPTX_VIRTUAL_OUT", NULL, "DPTX_VIRTUAL_OUT_MUX"}, +}; + +/* dai ops */ +static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe, + struct mtk_afe_tdm_priv *tdm_priv, + int freq) +{ + int apll; + int apll_rate; + + apll = mt8196_get_apll_by_rate(afe, freq); + apll_rate = mt8196_get_apll_rate(afe, apll); + + if (freq > apll_rate) { + AUDIO_AEE("freq > apll rate"); + return -EINVAL; + } + + if (apll_rate % freq != 0) { + AUDIO_AEE("APLL cannot generate freq Hz"); + return -EINVAL; + } + + tdm_priv->mclk_rate = freq; + tdm_priv->mclk_apll = apll; + + return 0; +} + +static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + int tdm_id = dai->id; + struct mtk_afe_tdm_priv *tdm_priv; + unsigned int rate = params_rate(params); + unsigned int channels = params_channels(params); + snd_pcm_format_t format = params_format(params); + unsigned int tdm_con = 0; + + if (tdm_id >= MT8196_DAI_NUM || tdm_id < 0) + return -EINVAL; + + tdm_priv = afe_priv->dai_priv[tdm_id]; + + /* calculate mclk_rate, if not set explicitly */ + if (!tdm_priv->mclk_rate) { + tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple; + mtk_dai_tdm_cal_mclk(afe, + tdm_priv, + tdm_priv->mclk_rate); + } + + /* calculate bck */ + tdm_priv->bck_rate = rate * + channels * + snd_pcm_format_physical_width(format); + + if (tdm_priv->bck_rate > tdm_priv->mclk_rate) + AUDIO_AEE("bck_rate > mclk_rate rate"); + + if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0) + AUDIO_AEE("bck cannot generate"); + + dev_info(afe->dev, "%s(), id %d, rate %d, channels %d, format %d, mclk_rate %d, bck_rate %d\n", + __func__, + tdm_id, rate, channels, format, + tdm_priv->mclk_rate, tdm_priv->bck_rate); + + /* set tdm */ + tdm_con = 0 << BCK_INVERSE_SFT; + tdm_con |= 0 << LRCK_INVERSE_SFT; + tdm_con |= 0 << DELAY_DATA_SFT; + tdm_con |= 1 << LEFT_ALIGN_SFT; + tdm_con |= get_tdm_wlen(format) << WLEN_SFT; + tdm_con |= get_tdm_ch(channels) << CHANNEL_NUM_SFT; + tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT; + tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT; + regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con); + + /* set dptx */ + if (tdm_id == MT8196_DAI_TDM_DPTX) { + regmap_update_bits(afe->regmap, AFE_DPTX_CON, + DPTX_CHANNEL_ENABLE_MASK_SFT, + get_dptx_ch_enable_mask(channels) << + DPTX_CHANNEL_ENABLE_SFT); + regmap_update_bits(afe->regmap, AFE_DPTX_CON, + DPTX_CHANNEL_NUMBER_MASK_SFT, + get_dptx_ch(channels) << + DPTX_CHANNEL_NUMBER_SFT); + regmap_update_bits(afe->regmap, AFE_DPTX_CON, + DPTX_16BIT_MASK_SFT, + get_dptx_wlen(format) << DPTX_16BIT_SFT); + } + switch (channels) { + case 1: + case 2: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 3: + case 4: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 5: + case 6: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 7: + case 8: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT; + break; + default: + tdm_con = 0; + } + regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con); + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, + HDMI_CH_NUM_MASK_SFT, + channels << HDMI_CH_NUM_SFT); + + return 0; +} + +static int mtk_dai_tdm_trigger(struct snd_pcm_substream *substream, + int cmd, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + int tdm_id = dai->id; + + dev_dbg(afe->dev, "%s(), cmd %d, tdm_id %d\n", __func__, cmd, tdm_id); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + /* enable Out control */ + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, + HDMI_OUT_ON_MASK_SFT, + 0x1 << HDMI_OUT_ON_SFT); + + /* enable dptx */ + if (tdm_id == MT8196_DAI_TDM_DPTX) { + regmap_update_bits(afe->regmap, AFE_DPTX_CON, + DPTX_ON_MASK_SFT, 0x1 << + DPTX_ON_SFT); + } + + /* enable tdm */ + regmap_update_bits(afe->regmap, AFE_TDM_CON1, + TDM_EN_MASK_SFT, 0x1 << TDM_EN_SFT); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + /* disable tdm */ + regmap_update_bits(afe->regmap, AFE_TDM_CON1, + TDM_EN_MASK_SFT, 0); + + /* disable dptx */ + if (tdm_id == MT8196_DAI_TDM_DPTX) { + regmap_update_bits(afe->regmap, AFE_DPTX_CON, + DPTX_ON_MASK_SFT, 0); + } + + /* disable Out control */ + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, + HDMI_OUT_ON_MASK_SFT, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8196_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv; + + if (dai->id >= MT8196_DAI_NUM || dai->id < 0) + return -EINVAL; + + tdm_priv = afe_priv->dai_priv[dai->id]; + + if (!tdm_priv) { + AUDIO_AEE("tdm_priv == NULL"); + return -EINVAL; + } + + if (dir != SND_SOC_CLOCK_OUT) { + AUDIO_AEE("dir != SND_SOC_CLOCK_OUT"); + return -EINVAL; + } + + dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq); + + return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq); +} + +static const struct snd_soc_dai_ops mtk_dai_tdm_ops = { + .hw_params = mtk_dai_tdm_hw_params, + .trigger = mtk_dai_tdm_trigger, + .set_sysclk = mtk_dai_tdm_set_sysclk, +}; + +/* dai driver */ +#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = { + { + .name = "TDM", + .id = MT8196_DAI_TDM, + .playback = { + .stream_name = "TDM", + .channels_min = 2, + .channels_max = 8, + .rates = MTK_TDM_RATES, + .formats = MTK_TDM_FORMATS, + }, + .ops = &mtk_dai_tdm_ops, + }, + { + .name = "TDM_DPTX", + .id = MT8196_DAI_TDM_DPTX, + .playback = { + .stream_name = "TDM_DPTX", + .channels_min = 2, + .channels_max = 8, + .rates = MTK_TDM_RATES, + .formats = MTK_TDM_FORMATS, + }, + .ops = &mtk_dai_tdm_ops, + }, +}; + +static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe, + int id) +{ + struct mtk_afe_tdm_priv *tdm_priv; + + tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv), + GFP_KERNEL); + if (!tdm_priv) + return NULL; + + if (id == MT8196_DAI_TDM_DPTX) + tdm_priv->mclk_multiple = 256; + else + tdm_priv->mclk_multiple = 128; + + tdm_priv->bck_id = MT8196_TDMOUT_BCK; + tdm_priv->mclk_id = MT8196_TDMOUT_MCK; + + return tdm_priv; +} + +int mt8196_dai_tdm_register(struct mtk_base_afe *afe) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv, *tdm_dptx_priv; + struct mtk_base_afe_dai *dai; + + dev_dbg(afe->dev, "%s() successfully start\n", __func__); + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_tdm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver); + + dai->dapm_widgets = mtk_dai_tdm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets); + dai->dapm_routes = mtk_dai_tdm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes); + + tdm_priv = init_tdm_priv_data(afe, MT8196_DAI_TDM); + if (!tdm_priv) + return -ENOMEM; + + tdm_dptx_priv = init_tdm_priv_data(afe, MT8196_DAI_TDM_DPTX); + if (!tdm_dptx_priv) + return -ENOMEM; + + afe_priv->dai_priv[MT8196_DAI_TDM] = tdm_priv; + afe_priv->dai_priv[MT8196_DAI_TDM_DPTX] = tdm_dptx_priv; + + return 0; +} + From patchwork Fri Mar 7 12:47:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darren.Ye" X-Patchwork-Id: 14006460 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EF533C282DE for ; Fri, 7 Mar 2025 13:02:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=46TuSHd10UP8OUoJJnde8lojq/wh9uzhaE+3oLPotOE=; b=iQ0Y2vsL3N9m6z5CGQSZmPoPVy qxG1df3rBFA06mzDqWFo+twVdkiKBJV1LzHr6xe5qhsk0ZJVRhu47OZ1LXyCHDuNUUxjlHL65riv0 aVl6c6eJEj0z/Fzm42z2dCKV9UcyCMSNiPNQaPWhkKi49MRKZwaZupUcB3ZEqx43O3gaRt2YORlM9 B1Wd/eg/74nmrI+jzU+oianPA6pmzcGhE4lefU1Niyn095smTvEOzaE3PGEsUdykP3M5yCFSQ8vg0 oMaSQ6Jp4jtcxWuCQ3MtSN+L0E+omBovbPKIAuMOoF4RzTG7Ve5EcqyWuTm1lcTmIfzHmday1Ylno RKdQpIrQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tqXLl-0000000EFoq-1ffL; Fri, 07 Mar 2025 13:02:49 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqX8c-0000000EDpR-1mc1; Fri, 07 Mar 2025 12:49:15 +0000 X-UUID: 9143e1befb5211ef83f2a1c9db70dae0-20250307 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=46TuSHd10UP8OUoJJnde8lojq/wh9uzhaE+3oLPotOE=; b=D8E1kDCG3lez9XLOa7ME45S4aqW5M1vAdwFaj9tCzIeCPgEYFq8JhTltP/ag6ZbZA4Xpmlue/U0I7bQ7E1dFHtrUqSjUFu47wYFQLE5AamgT70rwxbNKIGn0CvQ60pQHfVdEEG34bfQ5I5X6WQFcI1KwWLDUcE1z1NSOlVR/t+M=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:b625178d-d6e8-4c30-a47d-3956963fc1e2,IP:0,UR L:0,TC:0,Content:0,EDM:-25,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION :release,TS:-25 X-CID-META: VersionHash:0ef645f,CLOUDID:dc13d249-a527-43d8-8af6-bc8b32d9f5e9,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:1, IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV: 0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 9143e1befb5211ef83f2a1c9db70dae0-20250307 Received: from mtkmbs10n2.mediatek.inc [(172.21.101.183)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1874811707; Fri, 07 Mar 2025 05:49:11 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 7 Mar 2025 20:49:08 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 7 Mar 2025 20:49:07 +0800 From: Darren.Ye To: Liam Girdwood , Mark Brown , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Matthias Brugger , AngeloGioacchino Del Regno , Jaroslav Kysela , Takashi Iwai , "Linus Walleij" , Bartosz Golaszewski CC: , , , , , , Darren Ye Subject: [PATCH 10/14] ASoC: mediatek: mt8196: support CM in platform driver Date: Fri, 7 Mar 2025 20:47:36 +0800 Message-ID: <20250307124841.23777-11-darren.ye@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250307124841.23777-1-darren.ye@mediatek.com> References: <20250307124841.23777-1-darren.ye@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250307_044914_469503_66CCA950 X-CRM114-Status: GOOD ( 15.92 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Darren Ye Add mt8196 CM driver support for ADDA multi-channel. Signed-off-by: Darren Ye --- sound/soc/mediatek/mt8196/mt8196-afe-cm.c | 94 +++++++++++++++++++++++ sound/soc/mediatek/mt8196/mt8196-afe-cm.h | 23 ++++++ 2 files changed, 117 insertions(+) create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-cm.c create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-cm.h diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-cm.c b/sound/soc/mediatek/mt8196/mt8196-afe-cm.c new file mode 100644 index 000000000000..b923844a76f8 --- /dev/null +++ b/sound/soc/mediatek/mt8196/mt8196-afe-cm.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 MediaTek Inc. + * Author: Darren Ye + */ + +#include +#include +#include +#include + +#include "mtk-afe-fe-dai.h" +#include "mtk-base-afe.h" + +#include "mt8196-afe-cm.h" +#include "mt8196-afe-common.h" + +void mt8196_set_cm_rate(struct mtk_base_afe *afe, int id, unsigned int rate) +{ + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + afe_priv->cm_rate[id] = rate; +} +EXPORT_SYMBOL_GPL(mt8196_set_cm_rate); + +static int mt8196_convert_cm_ch(unsigned int ch) +{ + return ch - 1; +} + +static unsigned int calculate_cm_update(int rate, int ch) +{ + unsigned int update_val; + + update_val = 26000000 / rate / (ch / 2); + update_val = update_val * 10 / 7; + if (update_val > 100) + update_val = 100; + if (update_val < 7) + update_val = 7; + + return update_val; +} + +int mt8196_set_cm(struct mtk_base_afe *afe, int id, + bool update, bool swap, unsigned int ch) +{ + unsigned int rate = 0; + unsigned int update_val = 0; + int reg; + struct mt8196_afe_private *afe_priv = afe->platform_priv; + + dev_dbg(afe->dev, "%s()-0, CM%d, rate %d, update %d, swap %d, ch %d\n", + __func__, id, rate, update, swap, ch); + + rate = afe_priv->cm_rate[id]; + update_val = update ? calculate_cm_update(rate, (int)ch) : 0x64; + + reg = AFE_CM0_CON0 + 0x10 * id; + /* update cnt */ + mtk_regmap_update_bits(afe->regmap, reg, AFE_CM_UPDATE_CNT_MASK, + update_val, AFE_CM_UPDATE_CNT_SFT); + + /* rate */ + mtk_regmap_update_bits(afe->regmap, reg, AFE_CM_1X_EN_SEL_FS_MASK, + rate, AFE_CM_1X_EN_SEL_FS_SFT); + + /* ch num */ + ch = mt8196_convert_cm_ch(ch); + mtk_regmap_update_bits(afe->regmap, reg, AFE_CM_CH_NUM_MASK, + ch, AFE_CM_CH_NUM_SFT); + + /* swap */ + mtk_regmap_update_bits(afe->regmap, reg, AFE_CM_BYTE_SWAP_MASK, + swap, AFE_CM_BYTE_SWAP_SFT); + + return 0; +} +EXPORT_SYMBOL_GPL(mt8196_set_cm); + +int mt8196_enable_cm_bypass(struct mtk_base_afe *afe, int id, bool en) +{ + int reg = AFE_CM0_CON0 + 0x10 * id; + + mtk_regmap_update_bits(afe->regmap, reg, AFE_CM_BYPASS_MODE_MASK, + en, AFE_CM_BYPASS_MODE_SFT); + + return 0; +} +EXPORT_SYMBOL_GPL(mt8196_enable_cm_bypass); + +MODULE_DESCRIPTION("Mediatek afe cm"); +MODULE_AUTHOR("darren ye "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-cm.h b/sound/soc/mediatek/mt8196/mt8196-afe-cm.h new file mode 100644 index 000000000000..18115ec8fa70 --- /dev/null +++ b/sound/soc/mediatek/mt8196/mt8196-afe-cm.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 MediaTek Inc. + * Author: Darren Ye + */ + +#ifndef MTK_AFE_CM_H_ +#define MTK_AFE_CM_H_ +enum { + CM0, + CM1, + CM2, + CM_NUM, +}; + +void mt8196_set_cm_rate(struct mtk_base_afe *afe, int id, unsigned int rate); + +int mt8196_set_cm(struct mtk_base_afe *afe, int id, bool update, + bool swap, unsigned int ch); +int mt8196_enable_cm_bypass(struct mtk_base_afe *afe, int id, bool en); + +#endif /* MTK_AFE_CM_H_ */ + From patchwork Fri Mar 7 12:47:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darren.Ye" X-Patchwork-Id: 14006462 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B5B4EC28B23 for ; Fri, 7 Mar 2025 13:06:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=EmVWGVqGAI4TJUrJeI78GsI2NoWqQfInVXjGf3G+b4I=; b=lgXeLrYOLcXG1Lotm8SlB4LarU +N9ia9+0/Bv9UkELWsdaA6/PBqoi1N1U26yESWUw3I3j78pe+83U2SPZsowFcvysaCkc5ShRvYYNV XaufiTL9fxqP+3zJUPVlYJHWHZsy6OCkNERHXNg/XICnqauqNlH+s5JEvIgN2vtv5LaiL/wU84Ly1 Alc4XwZj0hzyoeW3PPajgwnd4WhtQLjBl45+Tsc5QcATsHJ9JWjc0iIehnbU0eyQZ8Kj+BH8xERwW DwtlqDdqs/nEEP5XkJ2pERLnrL3prl6ifimfR3SmSD1+GBOoz3iOd1Opto/YjnW19V2nvEAnlffOm sVMdHqBg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tqXOx-0000000EGLe-0M34; Fri, 07 Mar 2025 13:06:07 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqX8i-0000000EDqy-1PEh; Fri, 07 Mar 2025 12:49:21 +0000 X-UUID: 93ec8a6afb5211efa1e849db4cc18d44-20250307 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=EmVWGVqGAI4TJUrJeI78GsI2NoWqQfInVXjGf3G+b4I=; b=dxTsgkpSKvefllj9izOFuDNCb+INt1pwVEugG2lOhorqAPdhRZN0zzGENcB68Hz36WjXeTUzShHbQ63ktcR/eKHM0F6u7P1SUk19J0BcIKuRmSoB4hH2xSXpKqZqQnGLhe3Mo3UpbM49TcQn89fzz6MdA5AyO2G2hgMrUEPGONA=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:906d525d-1116-441f-a096-01afc871c1cd,IP:0,UR L:25,TC:0,Content:0,EDM:-25,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:0 X-CID-META: VersionHash:0ef645f,CLOUDID:624927ce-23b9-4c94-add0-e827a7999e28,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:1| 19,IP:nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA :0,AV:0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 93ec8a6afb5211efa1e849db4cc18d44-20250307 Received: from mtkmbs14n1.mediatek.inc [(172.21.101.75)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1943136985; Fri, 07 Mar 2025 05:49:15 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 7 Mar 2025 20:49:12 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 7 Mar 2025 20:49:12 +0800 From: Darren.Ye To: Liam Girdwood , Mark Brown , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Matthias Brugger , AngeloGioacchino Del Regno , Jaroslav Kysela , Takashi Iwai , "Linus Walleij" , Bartosz Golaszewski CC: , , , , , , Darren Ye Subject: [PATCH 12/14] dt-bindings: mediatek: mt8196: add audio AFE document Date: Fri, 7 Mar 2025 20:47:38 +0800 Message-ID: <20250307124841.23777-13-darren.ye@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250307124841.23777-1-darren.ye@mediatek.com> References: <20250307124841.23777-1-darren.ye@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250307_044920_383034_BEDAD069 X-CRM114-Status: GOOD ( 14.20 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Darren Ye Add mt8196 audio AFE document. Signed-off-by: Darren Ye --- .../bindings/sound/mediatek,mt8196-afe.yaml | 259 ++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml new file mode 100644 index 000000000000..59f8fdf3167c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml @@ -0,0 +1,259 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mediatek,mt8196-afe.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Audio Front End PCM controller for MT8196 + +maintainers: + - Darren Ye + +properties: + compatible: + const: mediatek,mt8196-afe-pcm + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + + clocks: + items: + - description: audio hopping clock + - description: audio f26m clock + - description: audio ul0 adc clock + - description: audio ul0 adc hires clock + - description: audio ul1 adc clock + - description: audio ul1 adc hires clock + - description: audio apll1 clock + - description: audio apll2 clock + - description: audio apll tuner1 clock + - description: audio apll tuner2 clock + - description: vlp mux audio int + - description: vlp mux aud engen1 + - description: vlp mux aud engen2 + - description: vlp mux audio h + - description: vlp clock 26m + - description: ck mainpll d4 d4 + - description: ck mux aud 1 + - description: ck apll1 + - description: ck mux aud 2 + - description: ck apll2 + - description: ck apll1 d4 + - description: ck apll2 d4 + - description: ck i2sin0 m sel + - description: ck i2sin1 m sel + - description: ck fmi2s m sel + - description: ck tdmout m sel + - description: ck apll12 div i2sin0 + - description: ck apll12 div i2sin1 + - description: ck apll12 div fmi2s + - description: ck apll12 div tdmout m + - description: ck apll12 div tdmout b + - description: ck adsp sel + - description: ck clock 26m + + clock-names: + items: + - const: aud_hopping_clk + - const: aud_f26m_clk + - const: aud_ul0_adc_clk + - const: aud_ul0_adc_hires_clk + - const: aud_ul1_adc_clk + - const: aud_ul1_adc_hires_clk + - const: aud_apll1_clk + - const: aud_apll2_clk + - const: aud_apll_tuner1_clk + - const: aud_apll_tuner2_clk + - const: vlp_mux_audio_int + - const: vlp_mux_aud_eng1 + - const: vlp_mux_aud_eng2 + - const: vlp_mux_audio_h + - const: vlp_clk26m_clk + - const: ck_mainpll_d4_d4 + - const: ck_mux_aud_1 + - const: ck_apll1_ck + - const: ck_mux_aud_2 + - const: ck_apll2_ck + - const: ck_apll1_d4 + - const: ck_apll2_d4 + - const: ck_i2sin0_m_sel + - const: ck_i2sin1_m_sel + - const: ck_fmi2s_m_sel + - const: ck_tdmout_m_sel + - const: ck_apll12_div_i2sin0 + - const: ck_apll12_div_i2sin1 + - const: ck_apll12_div_fmi2s + - const: ck_apll12_div_tdmout_m + - const: ck_apll12_div_tdmout_b + - const: ck_adsp_sel + - const: ck_clk26m_clk + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + + cksys: + $ref: /schemas/types.yaml#/definitions/phandle + description: Phandle to the cksys clock controller. + + vlpcksys: + $ref: /schemas/types.yaml#/definitions/phandle + description: Phandle to the vlpcksys clock controller. + + memory-region: + $ref: /schemas/types.yaml#/definitions/phandle + description: Phandle to the reserved memory region for AFE DMA. + + pinctrl-names: + items: + - const: default + + pinctrl-0: + $ref: /schemas/types.yaml#/definitions/phandle + description: Phandle to the pin control group for default state. + + mediatek,etdm-out-ch: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Number of ETDM output channels. + enum: [2] + + mediatek,etdm-in-ch: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Number of ETDM input channels. + enum: [2] + + mediatek,etdm-out-sync: + $ref: /schemas/types.yaml#/definitions/uint32 + description: ETDM output synchronization. + enum: [0, 1] + + mediatek,etdm-in-sync: + $ref: /schemas/types.yaml#/definitions/uint32 + description: ETDM input synchronization. + enum: [0, 1] + + mediatek,etdm-ip-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + description: ETDM IP mode. + enum: [0, 1] + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - power-domains + - cksys + - vlpcksys + - memory-region + - pinctrl-names + - pinctrl-0 + - mediatek,etdm-out-ch + - mediatek,etdm-in-ch + - mediatek,etdm-out-sync + - mediatek,etdm-in-sync + - mediatek,etdm-ip-mode + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + afe: mt8196-afe-pcm@1a110000 { + compatible = "mediatek,mt8196-afe-pcm"; + reg = <0 0x1a110000 0 0x9000>; + interrupts = ; + cksys = <&cksys_clk>; + vlpcksys = <&vlp_cksys_clk>; + power-domains = <&scpsys MT8196_POWER_DOMAIN_AUDIO>; + memory-region = <&afe_dma_mem_reserved>; + pinctrl-names = "default"; + pinctrl-0 = <&aud_pins_default>; + /* Only for ETDM in/out 4 */ + mediatek,etdm-out-ch = <2>; + mediatek,etdm-in-ch = <2>; + mediatek,etdm-out-sync = <0>; + mediatek,etdm-in-sync = <1>; + mediatek,etdm-ip-mode = <0>; + clocks = <&afe_clk CLK_AFE_AUDIO_HOPPING_AFE>, + <&afe_clk CLK_AFE_AUDIO_F26M_AFE>, + <&afe_clk CLK_AFE_UL0_ADC_AFE>, + <&afe_clk CLK_AFE_UL0_ADC_HIRES_AFE>, + <&afe_clk CLK_AFE_UL1_ADC_AFE>, + <&afe_clk CLK_AFE_UL1_ADC_HIRES_AFE>, + <&afe_clk CLK_AFE_APLL1_AFE>, + <&afe_clk CLK_AFE_APLL2_AFE>, + <&afe_clk CLK_AFE_APLL_TUNER1_AFE>, + <&afe_clk CLK_AFE_APLL_TUNER2_AFE>, + <&vlp_cksys_clk CLK_VLP_CK_AUD_INTBUS_SEL>, + <&vlp_cksys_clk CLK_VLP_CK_AUD_ENGEN1_SEL>, + <&vlp_cksys_clk CLK_VLP_CK_AUD_ENGEN2_SEL>, + <&vlp_cksys_clk CLK_VLP_CK_AUDIO_H_SEL>, + <&vlp_cksys_clk CLK_VLP_CK_CLKSQ>, + <&cksys_clk CLK_CK_MAINPLL_D4_D4>, + <&cksys_clk CLK_CK_AUD_1_SEL>, + <&cksys_clk CLK_CK_APLL1>, + <&cksys_clk CLK_CK_AUD_2_SEL>, + <&cksys_clk CLK_CK_APLL2>, + <&cksys_clk CLK_CK_APLL1_D4>, + <&cksys_clk CLK_CK_APLL2_D4>, + <&cksys_clk CLK_CK_APLL_I2SIN0_MCK_SEL>, + <&cksys_clk CLK_CK_APLL_I2SIN1_MCK_SEL>, + <&cksys_clk CLK_CK_APLL_FMI2S_MCK_SEL>, + <&cksys_clk CLK_CK_APLL_TDMOUT_MCK_SEL>, + <&cksys_clk CLK_CK_APLL12_CK_DIV_I2SIN0>, + <&cksys_clk CLK_CK_APLL12_CK_DIV_I2SIN1>, + <&cksys_clk CLK_CK_APLL12_CK_DIV_FMI2S>, + <&cksys_clk CLK_CK_APLL12_CK_DIV_TDMOUT_M>, + <&cksys_clk CLK_CK_APLL12_CK_DIV_TDMOUT_B>, + <&cksys_clk CLK_CK_ADSP_SEL>, + <&cksys_clk CLK_CK_TCK_26M_MX9>; + clock-names = "aud_hopping_clk", + "aud_f26m_clk", + "aud_ul0_adc_clk", + "aud_ul0_adc_hires_clk", + "aud_ul1_adc_clk", + "aud_ul1_adc_hires_clk", + "aud_apll1_clk", + "aud_apll2_clk", + "aud_apll_tuner1_clk", + "aud_apll_tuner2_clk", + "vlp_mux_audio_int", + "vlp_mux_aud_eng1", + "vlp_mux_aud_eng2", + "vlp_mux_audio_h", + "vlp_clk26m_clk", + "ck_mainpll_d4_d4", + "ck_mux_aud_1", + "ck_apll1_ck", + "ck_mux_aud_2", + "ck_apll2_ck", + "ck_apll1_d4", + "ck_apll2_d4", + "ck_i2sin0_m_sel", + "ck_i2sin1_m_sel", + "ck_fmi2s_m_sel", + "ck_tdmout_m_sel", + "ck_apll12_div_i2sin0", + "ck_apll12_div_i2sin1", + "ck_apll12_div_fmi2s", + "ck_apll12_div_tdmout_m", + "ck_apll12_div_tdmout_b", + "ck_adsp_sel", + "ck_clk26m_clk"; + }; + }; From patchwork Fri Mar 7 12:47:39 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darren.Ye" X-Patchwork-Id: 14006468 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 734D8C19F32 for ; Fri, 7 Mar 2025 13:09:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=IKJLoTOS/9L5k0LfbbiwTKRSonZ7cAag56j5vWI5EP0=; b=3ub5/KZ7A8kIoSWyfaji8fF3d3 WzGXu2rDpFS/5jH0EHyxtAT+pxljalDwpuoUIVDvJNLr3AV76qkuikkCRK4f3/5HbCc+l57o8qlk0 E9guuzLob7TMCS2MP/O7i5ggDaCmLlxkDagAH5DVDREGGisoOMU6GKYQLE0hV5agslgnRtCx1ISjG H6qN3psENkxqxacoAelfeIFMIMyW0ptGqH10S0rXbuWi1+p3eshfEDh59IQwN8ogugIyCRq1KEzt8 ydg0jVzt1kagJ1RPPmU7lsEmjgrRtQkAemMR0JcPpVN5Y/OOS54TS0fNbQqT8I/rBmaroZ8KM+8dt zGNEs8Xg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tqXS8-0000000EGkj-2mgC; Fri, 07 Mar 2025 13:09:24 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqX8l-0000000EDru-1R9K; Fri, 07 Mar 2025 12:49:24 +0000 X-UUID: 95202694fb5211efa1e849db4cc18d44-20250307 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=IKJLoTOS/9L5k0LfbbiwTKRSonZ7cAag56j5vWI5EP0=; b=fUs+Kjc/ZGfT9Ml8ha/A7CppfhaVoj4k6IRlu3zc5K5PsljEVw/l1gHM+qFDenVrbbuXZhohmkBT/qcq6QO2JITsdq1mi5TZoG0z7hCBtBkRkl2Y2rSgo3o+Zg33rD4tfOb0JbFkm4W7NJC/3zYQ9rGuidQSJga/r2rOUr7Qmm0=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:3578ceec-5568-401e-8e85-642f263c5a3b,IP:0,UR L:0,TC:0,Content:-5,EDM:-25,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-30 X-CID-META: VersionHash:0ef645f,CLOUDID:1214d249-a527-43d8-8af6-bc8b32d9f5e9,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:1, IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV: 0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 95202694fb5211efa1e849db4cc18d44-20250307 Received: from mtkmbs11n2.mediatek.inc [(172.21.101.187)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 980371074; Fri, 07 Mar 2025 05:49:17 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs13n1.mediatek.inc (172.21.101.193) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 7 Mar 2025 20:49:15 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 7 Mar 2025 20:49:14 +0800 From: Darren.Ye To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Jaroslav Kysela , Takashi Iwai , Linus Walleij , Bartosz Golaszewski CC: , , , , , , Darren Ye Subject: [PATCH 13/14] ASoC: mediatek: mt8196: add machine driver with mt6681 Date: Fri, 7 Mar 2025 20:47:39 +0800 Message-ID: <20250307124841.23777-14-darren.ye@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250307124841.23777-1-darren.ye@mediatek.com> References: <20250307124841.23777-1-darren.ye@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250307_044923_410738_4B0F3DEB X-CRM114-Status: GOOD ( 20.96 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Darren Ye Add support for mt8196 board with mt6681. Signed-off-by: Darren Ye --- sound/soc/mediatek/Kconfig | 20 + sound/soc/mediatek/mt8196/Makefile | 2 + sound/soc/mediatek/mt8196/mt8196-mt6681.c | 879 ++++++++++++++++++++++ 3 files changed, 901 insertions(+) create mode 100644 sound/soc/mediatek/mt8196/mt8196-mt6681.c diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 606f221e238c..55f9397fce91 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -214,6 +214,26 @@ config SND_SOC_MT8196 Select Y if you have such device. If unsure select "N". +config SND_SOC_MT8196_MT6681 + tristate "ASoc Audio driver for MT8196 with I2S codec" + depends on SND_SOC_MT8196 + depends on I2C + select SND_SOC_HDMI_CODEC + select SND_SOC_DMIC + select SND_SOC_NAU8315 + select SND_SOC_NAU8825 + select SND_SOC_RT5645 + select SND_SOC_RT5682_I2C + select SND_SOC_RT5682S + select SND_SOC_TAS2781_COMLIB + select SND_SOC_TAS2781_FMWLIB + select SND_SOC_TAS2781_I2C + help + This adds support for ASoC machine driver for MediaTek MT8196 + boards with the other I2S audio codecs. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MTK_BTCVSD tristate "ALSA BT SCO CVSD/MSBC Driver" help diff --git a/sound/soc/mediatek/mt8196/Makefile b/sound/soc/mediatek/mt8196/Makefile index 312cdfb5205b..ba5922736a59 100644 --- a/sound/soc/mediatek/mt8196/Makefile +++ b/sound/soc/mediatek/mt8196/Makefile @@ -15,3 +15,5 @@ snd-soc-mt8196-afe-objs += \ mt8196-dai-tdm.o \ mt8196-afe-cm.o +# machine driver +obj-$(CONFIG_SND_SOC_MT8196_MT6681) += mt8196-mt6681.o diff --git a/sound/soc/mediatek/mt8196/mt8196-mt6681.c b/sound/soc/mediatek/mt8196/mt8196-mt6681.c new file mode 100644 index 000000000000..9053e96fd193 --- /dev/null +++ b/sound/soc/mediatek/mt8196/mt8196-mt6681.c @@ -0,0 +1,879 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mt8196-mt6681.c -- mt8196 mt6681 ALSA SoC machine driver + * + * Copyright (c) 2023 MediaTek Inc. + * Author: Darren Ye + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtk-afe-platform-driver.h" +#include "mt8196-afe-common.h" +#include "mt8196-afe-clk.h" +#include "mt8196-afe-gpio.h" + +#include "../../codecs/nau8825.h" +#include "../../codecs/rt5682s.h" + +#include "../common/mtk-afe-platform-driver.h" +#include "../common/mtk-soundcard-driver.h" +#include "../common/mtk-dsp-sof-common.h" +#include "../common/mtk-soc-card.h" + +#define NAU8825_HS_PRESENT BIT(0) +#define RT5682S_HS_PRESENT BIT(1) +#define RT5650_HS_PRESENT BIT(2) + +/* + * Nau88l25 + */ +#define NAU8825_CODEC_DAI "nau8825-hifi" + +/* + * Rt5682s + */ +#define RT5682S_CODEC_DAI "rt5682s-aif1" + +/* + * Rt5650 + */ +#define RT5650_CODEC_DAI "rt5645-aif1" + +#define SOF_DMA_DL1 "SOF_DMA_DL1" +#define SOF_DMA_DL_24CH "SOF_DMA_DL_24CH" +#define SOF_DMA_UL0 "SOF_DMA_UL0" +#define SOF_DMA_UL1 "SOF_DMA_UL1" +#define SOF_DMA_UL2 "SOF_DMA_UL2" + +enum mt8196_jacks { + MT8196_JACK_HEADSET, + MT8196_JACK_DP, + MT8196_JACK_HDMI, + MT8196_JACK_MAX, +}; + +static struct snd_soc_jack_pin mt8196_dp_jack_pins[] = { + { + .pin = "DP", + .mask = SND_JACK_LINEOUT, + }, +}; + +static struct snd_soc_jack_pin mt8196_hdmi_jack_pins[] = { + { + .pin = "HDMI", + .mask = SND_JACK_LINEOUT, + }, +}; + +static struct snd_soc_jack_pin nau8825_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new mt8196_dumb_spk_controls[] = { + SOC_DAPM_PIN_SWITCH("Ext Spk"), +}; + +static const struct snd_soc_dapm_widget mt8196_dumb_spk_widgets[] = { + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + +static const struct snd_soc_dapm_widget mt8196_nau8825_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SINK("DP"), +}; + +static const struct snd_kcontrol_new mt8196_nau8825_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +/* + * if need additional control for the ext spk amp that is connected + * after Lineout Buffer / HP Buffer on the codec, put the control in + * mt8196_mt6681_spk_amp_event() + */ +#define EXT_SPK_AMP_W_NAME "Ext_Speaker_Amp" + +static struct snd_soc_card mt8196_mt6681_soc_card; + +static const struct snd_soc_dapm_widget mt8196_mt6681_widgets[] = { +}; + +static const struct snd_soc_dapm_route mt8196_mt6681_routes[] = { +}; + +static const struct snd_kcontrol_new mt8196_mt6681_controls[] = { + SOC_DAPM_PIN_SWITCH(EXT_SPK_AMP_W_NAME), +}; + +/* + * define mtk_spk_i2s_mck node in dts when need mclk, + * BE i2s need assign snd_soc_ops = mt8196_mt6681_i2s_ops + */ +static int mt8196_mt6681_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + unsigned int rate = params_rate(params); + unsigned int mclk_fs_ratio = 128; + unsigned int mclk_fs = rate * mclk_fs_ratio; + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + + return snd_soc_dai_set_sysclk(cpu_dai, + 0, mclk_fs, SND_SOC_CLOCK_OUT); +} + +static const struct snd_soc_ops mt8196_mt6681_i2s_ops = { + .hw_params = mt8196_mt6681_i2s_hw_params, +}; + +static int mt8196_dptx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + unsigned int rate = params_rate(params); + unsigned int mclk_fs_ratio = 256; + unsigned int mclk_fs = rate * mclk_fs_ratio; + struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0); + + return snd_soc_dai_set_sysclk(dai, 0, mclk_fs, SND_SOC_CLOCK_OUT); +} + +static const struct snd_soc_ops mt8196_dptx_ops = { + .hw_params = mt8196_dptx_hw_params, +}; + +static int mt8196_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + dev_info(rtd->dev, "%s(), fix format to 32bit\n", __func__); + + /* fix BE i2s format to 32bit, clean param mask first */ + snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), + 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); + + params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); + + return 0; +} + +static int mt8196_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + dev_info(rtd->dev, "%s(), fix format to 32bit\n", __func__); + + /* fix BE i2s format to 32bit, clean param mask first */ + snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), + 0, SNDRV_PCM_FORMAT_LAST); + + params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); + return 0; +} + +static int mt8196_sof_be_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_component *cmpnt_afe = NULL; + struct snd_soc_pcm_runtime *runtime; + + /* find afe component */ + for_each_card_rtds(rtd->card, runtime) { + cmpnt_afe = snd_soc_rtdcom_lookup(runtime, AFE_PCM_NAME); + if (cmpnt_afe) { + dev_info(rtd->dev, "component->name: %s\n", cmpnt_afe->name); + break; + } + } + + if (cmpnt_afe && !pm_runtime_active(cmpnt_afe->dev)) { + dev_err(rtd->dev, "afe pm runtime is not active!!\n"); + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_ops mt8196_sof_be_ops = { + .hw_params = mt8196_sof_be_hw_params, +}; + +static const struct sof_conn_stream g_sof_conn_streams[] = { + { + .sof_link = "AFE_SOF_DL1", + .sof_dma = SOF_DMA_DL1, + .stream_dir = SNDRV_PCM_STREAM_PLAYBACK + }, + { + .sof_link = "AFE_SOF_DL_24CH", + .sof_dma = SOF_DMA_DL_24CH, + .stream_dir = SNDRV_PCM_STREAM_PLAYBACK + }, + { + .sof_link = "AFE_SOF_UL0", + .sof_dma = SOF_DMA_UL0, + .stream_dir = SNDRV_PCM_STREAM_CAPTURE + }, + { + .sof_link = "AFE_SOF_UL1", + .sof_dma = SOF_DMA_UL1, + .stream_dir = SNDRV_PCM_STREAM_CAPTURE + }, + { + .sof_link = "AFE_SOF_UL2", + .sof_dma = SOF_DMA_UL2, + .stream_dir = SNDRV_PCM_STREAM_CAPTURE + }, +}; + +/* FE */ +SND_SOC_DAILINK_DEFS(playback1, + DAILINK_COMP_ARRAY(COMP_CPU("DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(playback_24ch, + DAILINK_COMP_ARRAY(COMP_CPU("DL_24CH")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(capture0, + DAILINK_COMP_ARRAY(COMP_CPU("UL0")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(capture1, + DAILINK_COMP_ARRAY(COMP_CPU("UL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(capture2, + DAILINK_COMP_ARRAY(COMP_CPU("UL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(playback_hdmi, + DAILINK_COMP_ARRAY(COMP_CPU("HDMI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(playback2, + DAILINK_COMP_ARRAY(COMP_CPU("DL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(capture_cm0, + DAILINK_COMP_ARRAY(COMP_CPU("UL_CM0")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +/* BE */ +SND_SOC_DAILINK_DEFS(ap_dmic, + DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(ap_dmic_ch34, + DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_CH34")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(ap_dmic_multich, + DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_MULTICH")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2sin6, + DAILINK_COMP_ARRAY(COMP_CPU("I2SIN6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2sout3, + DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT3")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2sout4, + DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT4")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2sout6, + DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(tdm_dptx, + DAILINK_COMP_ARRAY(COMP_CPU("TDM_DPTX")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_DL_24CH, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL_24CH")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_DL1, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_UL0, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL0")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_UL1, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_UL2, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link mt8196_mt6681_dai_links[] = { + /* + * The SOF topology expects PCM streams 0~4 to be available + * for the SOF PCM streams. Put the SOF BE definitions here + * so that the PCM device numbers are skipped over. + * (BE dailinks do not have PCM devices created.) + */ + { + .name = "AFE_SOF_DL_24CH", + .no_pcm = 1, + .playback_only = 1, + .ops = &mt8196_sof_be_ops, + SND_SOC_DAILINK_REG(AFE_SOF_DL_24CH), + }, + { + .name = "AFE_SOF_DL1", + .no_pcm = 1, + .playback_only = 1, + .ops = &mt8196_sof_be_ops, + SND_SOC_DAILINK_REG(AFE_SOF_DL1), + }, + { + .name = "AFE_SOF_UL0", + .no_pcm = 1, + .capture_only = 1, + .ops = &mt8196_sof_be_ops, + SND_SOC_DAILINK_REG(AFE_SOF_UL0), + }, + { + .name = "AFE_SOF_UL1", + .no_pcm = 1, + .capture_only = 1, + .ops = &mt8196_sof_be_ops, + SND_SOC_DAILINK_REG(AFE_SOF_UL1), + }, + { + .name = "AFE_SOF_UL2", + .no_pcm = 1, + .capture_only = 1, + .ops = &mt8196_sof_be_ops, + SND_SOC_DAILINK_REG(AFE_SOF_UL2), + }, + /* Front End DAI links */ + { + .name = "HDMI_FE", + .stream_name = "HDMI Playback", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .playback_only = 1, + SND_SOC_DAILINK_REG(playback_hdmi), + }, + { + .name = "DL2_FE", + .stream_name = "DL2 Playback", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .playback_only = 1, + SND_SOC_DAILINK_REG(playback2), + }, + { + .name = "UL_CM0_FE", + .stream_name = "UL_CM0 Capture", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .capture_only = 1, + SND_SOC_DAILINK_REG(capture_cm0), + }, + { + .name = "DL_24CH_FE", + .stream_name = "DL_24CH Playback", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .playback_only = 1, + SND_SOC_DAILINK_REG(playback_24ch), + }, + { + .name = "DL1_FE", + .stream_name = "DL1 Playback", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .playback_only = 1, + SND_SOC_DAILINK_REG(playback1), + }, + { + .name = "UL0_FE", + .stream_name = "UL0 Capture", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .capture_only = 1, + SND_SOC_DAILINK_REG(capture0), + }, + { + .name = "UL1_FE", + .stream_name = "UL1 Capture", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .capture_only = 1, + SND_SOC_DAILINK_REG(capture1), + }, + { + .name = "UL2_FE", + .stream_name = "UL2 Capture", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .capture_only = 1, + SND_SOC_DAILINK_REG(capture2), + }, + /* Back End DAI links */ + { + .name = "I2SIN6_BE", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + | SND_SOC_DAIFMT_GATED, + .ops = &mt8196_mt6681_i2s_ops, + .no_pcm = 1, + .capture_only = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8196_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2sin6), + }, + { + .name = "I2SOUT4_BE", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + | SND_SOC_DAIFMT_GATED, + .ops = &mt8196_mt6681_i2s_ops, + .no_pcm = 1, + .playback_only = 1, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = mt8196_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2sout4), + }, + { + .name = "I2SOUT6_BE", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + | SND_SOC_DAIFMT_GATED, + .ops = &mt8196_mt6681_i2s_ops, + .no_pcm = 1, + .playback_only = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8196_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2sout6), + }, + { + .name = "AP_DMIC_BE", + .no_pcm = 1, + .capture_only = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(ap_dmic), + }, + { + .name = "AP_DMIC_CH34_BE", + .no_pcm = 1, + .capture_only = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(ap_dmic_ch34), + }, + { + .name = "AP_DMIC_MULTICH_BE", + .no_pcm = 1, + .capture_only = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(ap_dmic_multich), + }, + { + .name = "TDM_DPTX_BE", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + | SND_SOC_DAIFMT_GATED, + .ops = &mt8196_dptx_ops, + .be_hw_params_fixup = mt8196_dptx_hw_params_fixup, + .no_pcm = 1, + .playback_only = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tdm_dptx), + }, + { + .name = "I2SOUT3_BE", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + | SND_SOC_DAIFMT_GATED, + .ops = &mt8196_mt6681_i2s_ops, + .no_pcm = 1, + .playback_only = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(i2sout3), + }, +}; + +static int mt8196_dumb_amp_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret = 0; + + ret = snd_soc_dapm_new_controls(&card->dapm, mt8196_dumb_spk_widgets, + ARRAY_SIZE(mt8196_dumb_spk_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add Dumb Speaker dapm, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, mt8196_dumb_spk_controls, + ARRAY_SIZE(mt8196_dumb_spk_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add Dumb card controls, ret %d\n", ret); + return ret; + } + + return 0; +} + +static int mt8196_dptx_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8196_JACK_DP]; + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; + int ret = 0; + + ret = snd_soc_card_jack_new_pins(rtd->card, "DP Jack", SND_JACK_LINEOUT, + jack, mt8196_dp_jack_pins, + ARRAY_SIZE(mt8196_dp_jack_pins)); + if (ret) { + dev_err(rtd->dev, "%s, new jack failed: %d\n", __func__, ret); + return ret; + } + + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) { + dev_err(rtd->dev, "%s, set jack failed on %s (ret=%d)\n", + __func__, component->name, ret); + return ret; + } + + return 0; +} + +static int mt8196_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8196_JACK_HDMI]; + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; + int ret = 0; + + ret = snd_soc_card_jack_new_pins(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, + jack, mt8196_hdmi_jack_pins, + ARRAY_SIZE(mt8196_hdmi_jack_pins)); + if (ret) { + dev_err(rtd->dev, "%s, new jack failed: %d\n", __func__, ret); + return ret; + } + + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) { + dev_err(rtd->dev, "%s, set jack failed on %s (ret=%d)\n", + __func__, component->name, ret); + return ret; + } + + return 0; +} + +static int mt8196_headset_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); + struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8196_JACK_HEADSET]; + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; + int ret; + int type; + + ret = snd_soc_dapm_new_controls(&card->dapm, mt8196_nau8825_widgets, + ARRAY_SIZE(mt8196_nau8825_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add nau8825 card widget, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, mt8196_nau8825_controls, + ARRAY_SIZE(mt8196_nau8825_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add nau8825 card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + jack, + nau8825_jack_pins, + ARRAY_SIZE(nau8825_jack_pins)); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3; + ret = snd_soc_component_set_jack(component, jack, (void *)&type); + + if (ret) { + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + + return 0; +}; + +static void mt8196_headset_codec_exit(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; + + snd_soc_component_set_jack(component, NULL, NULL); +} + +static int mt8196_nau8825_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + unsigned int rate = params_rate(params); + unsigned int bit_width = params_width(params); + int clk_freq, ret; + + clk_freq = rate * 2 * bit_width; + + /* Configure clock for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret); + return ret; + } + + /* Configure pll for codec */ + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq, + params_rate(params) * 256); + if (ret < 0) { + dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct snd_soc_ops mt8196_nau8825_ops = { + .hw_params = mt8196_nau8825_hw_params, +}; + +static int mt8196_rt5682s_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + unsigned int rate = params_rate(params); + int bitwidth; + int ret; + + bitwidth = snd_pcm_format_width(params_format(params)); + if (bitwidth < 0) { + dev_err(card->dev, "invalid bit width: %d\n", bitwidth); + return bitwidth; + } + + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth); + if (ret) { + dev_err(card->dev, "failed to set tdm slot\n"); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL1, RT5682S_PLL_S_BCLK1, + rate * 32, rate * 512); + if (ret) { + dev_err(card->dev, "failed to set pll\n"); + return ret; + } + + dev_info(card->dev, "%s set mclk rate: %d\n", __func__, rate * 512); + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_MCLK, + rate * 512, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(card->dev, "failed to set sysclk\n"); + return ret; + } + + return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 512, + SND_SOC_CLOCK_OUT); +} + +static const struct snd_soc_ops mt8196_rt5682s_i2s_ops = { + .hw_params = mt8196_rt5682s_i2s_hw_params, +}; + +static int mt8196_mt6681_soc_card_probe(struct mtk_soc_card_data *soc_card_data, bool legacy) +{ + struct snd_soc_card *card = soc_card_data->card_data->card; + struct snd_soc_dai_link *dai_link; + bool init_nau8825 = false; + bool init_rt5682s = false; + bool init_rt5650 = false; + bool init_dumb = false; + int i; + + dev_info(card->dev, "%s(), legacy: %d\n", __func__, legacy); + + for_each_card_prelinks(card, i, dai_link) { + if (strcmp(dai_link->name, "TDM_DPTX_BE") == 0) { + if (dai_link->num_codecs && + strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) + dai_link->init = mt8196_dptx_codec_init; + } else if (strcmp(dai_link->name, "I2SOUT3_BE") == 0) { + if (dai_link->num_codecs && + strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) + dai_link->init = mt8196_hdmi_codec_init; + } else if (strcmp(dai_link->name, "I2SOUT6_BE") == 0 || + strcmp(dai_link->name, "I2SIN6_BE") == 0) { + if (!strcmp(dai_link->codecs->dai_name, NAU8825_CODEC_DAI)) { + dai_link->ops = &mt8196_nau8825_ops; + if (!init_nau8825) { + dai_link->init = mt8196_headset_codec_init; + dai_link->exit = mt8196_headset_codec_exit; + init_nau8825 = true; + } + } else if (!strcmp(dai_link->codecs->dai_name, RT5682S_CODEC_DAI)) { + dai_link->ops = &mt8196_rt5682s_i2s_ops; + if (!init_rt5682s) { + dai_link->init = mt8196_headset_codec_init; + dai_link->exit = mt8196_headset_codec_exit; + init_rt5682s = true; + } + } else if (!strcmp(dai_link->codecs->dai_name, RT5650_CODEC_DAI)) { + dai_link->ops = &mt8196_rt5682s_i2s_ops; + if (!init_rt5650) { + dai_link->init = mt8196_headset_codec_init; + dai_link->exit = mt8196_headset_codec_exit; + init_rt5650 = true; + } + } else { + if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) { + if (!init_dumb) { + dai_link->init = mt8196_dumb_amp_init; + init_dumb = true; + } + } + } + } + } + + return 0; +} + +static const struct mtk_sof_priv mt8196_sof_priv = { + .conn_streams = g_sof_conn_streams, + .num_streams = ARRAY_SIZE(g_sof_conn_streams), +}; + +static struct snd_soc_card mt8196_mt6681_soc_card = { + .owner = THIS_MODULE, + .dai_link = mt8196_mt6681_dai_links, + .num_links = ARRAY_SIZE(mt8196_mt6681_dai_links), + .dapm_widgets = mt8196_mt6681_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8196_mt6681_widgets), + .dapm_routes = mt8196_mt6681_routes, + .num_dapm_routes = ARRAY_SIZE(mt8196_mt6681_routes), + .controls = mt8196_mt6681_controls, + .num_controls = ARRAY_SIZE(mt8196_mt6681_controls), +}; + +static const struct mtk_soundcard_pdata mt8196_evb_card = { + .card_name = "mt8196_mt6681", + .card_data = &(struct mtk_platform_card_data) { + .card = &mt8196_mt6681_soc_card, + .num_jacks = MT8196_JACK_MAX, + }, + .sof_priv = &mt8196_sof_priv, + .soc_probe = mt8196_mt6681_soc_card_probe, +}; + +static const struct mtk_soundcard_pdata mt8196_nau8825_card = { + .card_name = "mt8196_nau8825", + .card_data = &(struct mtk_platform_card_data) { + .card = &mt8196_mt6681_soc_card, + .num_jacks = MT8196_JACK_MAX, + .flags = NAU8825_HS_PRESENT + }, + .sof_priv = &mt8196_sof_priv, + .soc_probe = mt8196_mt6681_soc_card_probe, +}; + +static const struct mtk_soundcard_pdata mt8196_rt5682s_card = { + .card_name = "mt8196_rt5682s", + .card_data = &(struct mtk_platform_card_data) { + .card = &mt8196_mt6681_soc_card, + .num_jacks = MT8196_JACK_MAX, + .flags = RT5682S_HS_PRESENT + }, + .sof_priv = &mt8196_sof_priv, + .soc_probe = mt8196_mt6681_soc_card_probe, +}; + +static const struct mtk_soundcard_pdata mt8196_rt5650_card = { + .card_name = "mt8196_rt5650", + .card_data = &(struct mtk_platform_card_data) { + .card = &mt8196_mt6681_soc_card, + .num_jacks = MT8196_JACK_MAX, + .flags = RT5650_HS_PRESENT + }, + .sof_priv = &mt8196_sof_priv, + .soc_probe = mt8196_mt6681_soc_card_probe, +}; + +static const struct of_device_id mt8196_mt6681_dt_match[] = { + {.compatible = "mediatek,mt8196-mt6681-sound", .data = &mt8196_evb_card,}, + {.compatible = "mediatek,mt8196-nau8825-sound", .data = &mt8196_nau8825_card,}, + {.compatible = "mediatek,mt8196-rt5682s-sound", .data = &mt8196_rt5682s_card,}, + {.compatible = "mediatek,mt8196-rt5650-sound", .data = &mt8196_rt5650_card,}, + {} +}; +MODULE_DEVICE_TABLE(of, mt8196_mt6681_dt_match); + +static struct platform_driver mt8196_mt6681_driver = { + .driver = { + .name = "mt8196-mt6681", + .of_match_table = mt8196_mt6681_dt_match, + .pm = &snd_soc_pm_ops, + }, + .probe = mtk_soundcard_common_probe, +}; +module_platform_driver(mt8196_mt6681_driver); + +/* Module information */ +MODULE_DESCRIPTION("MT8196 mt6681 ALSA SoC machine driver"); +MODULE_AUTHOR("Darren Ye "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("mt8196 mt6681 soc card"); + From patchwork Fri Mar 7 12:47:40 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darren.Ye" X-Patchwork-Id: 14006467 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7CD08C19F32 for ; Fri, 7 Mar 2025 13:07:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=jnSsP+cBtx5bZbxvhgEu2Uhcf/WLPgXZHCzJojwqhQE=; b=bQTSv2EmpXGHyHxU7iBSWgr7sW vwxNaubqOPKLskzOFT0ftNKL9FoxbsuctqJlw1CdFicjxzQgauv7lA3/KE+vb8FDrfKPlXPzzKl3g CDm+1n+fu9f5Yq9o3bGIoTV9oghefyJyyX3dgEwnAZwlYrWrsCC7zyfQQezEc8FZ751syp4cGQocK UuvmlJceXZ73g4JRgUnJdUBYIfRwwPAe0ZV7l8kDYaTQLEugOKAnm17W5Nxs3uPmx7JE38Ihp38vp Tknzgp0vg0EZ/Y8f3a/nlJa7wn61TuA6zjRAFahegxmcPbWxJh2+hnVtEEsSRL6xte5hNsFDkzC2f on526D9A==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tqXQX-0000000EGZE-3LYO; Fri, 07 Mar 2025 13:07:45 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqX8l-0000000EDrv-1T1l; Fri, 07 Mar 2025 12:49:24 +0000 X-UUID: 966ff34efb5211ef83f2a1c9db70dae0-20250307 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=jnSsP+cBtx5bZbxvhgEu2Uhcf/WLPgXZHCzJojwqhQE=; b=p7lRiWb8ip/zxQbbwnOn3KEEFfwU+46eopJMODimPmXATcRsjls2OrcvwqUq9EMmW1RyHj1h9ew2NR+Wl8l5PoXW3NkEog8dLeuili8FRfLdmDzVkIn2LDWHvvLqMh+8SfQ8u3b9FgtMDh3G5YFr4IR4Rt5cNEeiJ078FFF8heA=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:71610885-4580-48eb-bdad-88db994b4e8b,IP:0,UR L:25,TC:0,Content:0,EDM:-25,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:0 X-CID-META: VersionHash:0ef645f,CLOUDID:864927ce-23b9-4c94-add0-e827a7999e28,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:1| 19,IP:nil,URL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA :0,AV:0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 966ff34efb5211ef83f2a1c9db70dae0-20250307 Received: from mtkmbs10n2.mediatek.inc [(172.21.101.183)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1685500000; Fri, 07 Mar 2025 05:49:20 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 7 Mar 2025 20:49:17 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 7 Mar 2025 20:49:16 +0800 From: Darren.Ye To: Liam Girdwood , Mark Brown , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Matthias Brugger , AngeloGioacchino Del Regno , Jaroslav Kysela , Takashi Iwai , "Linus Walleij" , Bartosz Golaszewski CC: , , , , , , Darren Ye Subject: [PATCH 14/14] dt-bindings: mediatek: mt8196: add mt8196-mt6681 document Date: Fri, 7 Mar 2025 20:47:40 +0800 Message-ID: <20250307124841.23777-15-darren.ye@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250307124841.23777-1-darren.ye@mediatek.com> References: <20250307124841.23777-1-darren.ye@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250307_044923_399960_95F4BA5A X-CRM114-Status: GOOD ( 14.25 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Darren Ye Add document for mt8196 board with mt6681. Signed-off-by: Darren Ye --- .../sound/mediatek,mt8196-mt6681.yaml | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml new file mode 100644 index 000000000000..b144ba748c23 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml @@ -0,0 +1,122 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mediatek,mt8196-mt6681.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT8196 ASoC sound card + +maintainers: + - Darren Ye + +allOf: + - $ref: sound-card-common.yaml# + +properties: + compatible: + oneOf: + - enum: + - mediatek,mt8196-mt6681-sound + - mediatek,mt8196-nau8825-sound + - mediatek,mt8196-rt5682s-sound + - mediatek,mt8196-rt5650-sound + - items: + - const: mediatek,mt8196-mt6681-sound + - const: mediatek,mt8196-nau8825-sound + + audio-routing: + description: + Valid names could be the input or output widgets of audio components, + power supplies, MicBias of codec and the software switch. + + mediatek,platform: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of MT8188 ASoC platform. + + mediatek,adsp: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The phandle of the MT8188 ADSP platform, which is the optional Audio DSP + hardware that provides additional audio functionalities if present. + The AFE will link to ADSP when the phandle is provided. + +patternProperties: + "^dai-link-[0-9]+$": + type: object + description: + Container for dai-link level properties and CODEC sub-nodes. + + properties: + link-name: + description: + This property corresponds to the name of the BE dai-link to which + we are going to update parameters in this node. + items: + enum: + - TDM_DPTX_BE + - I2SOUT6_BE + - I2SIN6_BE + - I2SOUT4_BE + - I2SOUT3_BE + + codec: + description: Holds subnode which indicates codec dai. + type: object + additionalProperties: false + properties: + sound-dai: + minItems: 1 + maxItems: 2 + required: + - sound-dai + + dai-format: + description: audio format. + items: + enum: + - i2s + - right_j + - left_j + - dsp_a + - dsp_b + + mediatek,clk-provider: + $ref: /schemas/types.yaml#/definitions/string + description: Indicates dai-link clock master. + items: + enum: + - cpu + - codec + + additionalProperties: false + + required: + - link-name + +unevaluatedProperties: false + +required: + - compatible + - mediatek,platform + +examples: + - | + sound { + compatible = "mediatek,mt8196-mt6681-sound"; + model = "mt8196-mt6681"; + mediatek,platform = <&afe>; + audio-routing = "I2SOUT4", "I2SIN4_GPIO", + "I2SOUT4", "I2OUT4_GPIO", + "I2SOUT6", "I2SIN6_GPIO", + "I2SOUT6", "I2SOUT6_GPIO"; + + dai-link-0 { + link-name = "I2SOUT6_BE"; + dai-format = "i2s"; + mediatek,clk-provider = "cpu"; + codec { + sound-dai = <&nau8825>; + }; + }; + }; +