linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC
@ 2022-10-21  8:27 Trevor Wu
  2022-10-21  8:27 ` [PATCH v2 01/12] ASoC: mediatek: common: add SMC ops and SMC CMD Trevor Wu
                   ` (10 more replies)
  0 siblings, 11 replies; 27+ messages in thread
From: Trevor Wu @ 2022-10-21  8:27 UTC (permalink / raw)
  To: broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: trevor.wu, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

This series of patches adds support for Mediatek AFE of MT8188 SoC.
Patches are based on broonie tree "for-next" branch.

Changes since v1:
  - remove bus protection functions in case of unmerged dependency problem
  - replace some bit operation macro with FIELD_PREP
  - simplify register control by regmap_set_bits and regmap_clear_bits
  - fix dt-binding errors
  - rename compatible string for recognition

Trevor Wu (12):
  ASoC: mediatek: common: add SMC ops and SMC CMD
  ASoC: mediatek: mt8188: add common header
  ASoC: mediatek: mt8188: support audsys clock
  ASoC: mediatek: mt8188: support adda in platform driver
  ASoC: mediatek: mt8188: support etdm in platform driver
  ASoC: mediatek: mt8188: support pcmif in platform driver
  ASoC: mediatek: mt8188: support audio clock control
  ASoC: mediatek: mt8188: add platform driver
  ASoC: mediatek: mt8188: add control for timing select
  dt-bindings: mediatek: mt8188: add audio afe document
  ASoC: mediatek: mt8188: add machine driver with mt6359
  dt-bindings: mediatek: mt8188: add mt8188-mt6359 document

 .../bindings/sound/mt8188-afe-pcm.yaml        |  187 +
 .../bindings/sound/mt8188-mt6359.yaml         |   64 +
 sound/soc/mediatek/Kconfig                    |   23 +
 sound/soc/mediatek/Makefile                   |    1 +
 sound/soc/mediatek/common/mtk-base-afe.h      |   19 +
 sound/soc/mediatek/mt8188/Makefile            |   15 +
 sound/soc/mediatek/mt8188/mt8188-afe-clk.c    |  656 ++++
 sound/soc/mediatek/mt8188/mt8188-afe-clk.h    |  114 +
 sound/soc/mediatek/mt8188/mt8188-afe-common.h |  151 +
 sound/soc/mediatek/mt8188/mt8188-afe-pcm.c    | 3359 +++++++++++++++++
 sound/soc/mediatek/mt8188/mt8188-audsys-clk.c |  206 +
 sound/soc/mediatek/mt8188/mt8188-audsys-clk.h |   15 +
 .../soc/mediatek/mt8188/mt8188-audsys-clkid.h |   83 +
 sound/soc/mediatek/mt8188/mt8188-dai-adda.c   |  631 ++++
 sound/soc/mediatek/mt8188/mt8188-dai-etdm.c   | 2596 +++++++++++++
 sound/soc/mediatek/mt8188/mt8188-dai-pcm.c    |  366 ++
 sound/soc/mediatek/mt8188/mt8188-mt6359.c     |  808 ++++
 sound/soc/mediatek/mt8188/mt8188-reg.h        | 3180 ++++++++++++++++
 18 files changed, 12474 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
 create mode 100644 sound/soc/mediatek/mt8188/Makefile
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-clk.c
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-clk.h
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-common.h
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-adda.c
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-pcm.c
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-mt6359.c
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-reg.h

-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v2 01/12] ASoC: mediatek: common: add SMC ops and SMC CMD
  2022-10-21  8:27 [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC Trevor Wu
@ 2022-10-21  8:27 ` Trevor Wu
  2022-10-21  8:27 ` [PATCH v2 03/12] ASoC: mediatek: mt8188: support audsys clock Trevor Wu
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Trevor Wu @ 2022-10-21  8:27 UTC (permalink / raw)
  To: broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: trevor.wu, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

SMC call is required to communicate with ATF for some secure operations,
so we add SMC ops IDs and SMC CMD ID to common header.

Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
---
 sound/soc/mediatek/common/mtk-base-afe.h | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h
index ef83e78c22a8..f51578b6c50a 100644
--- a/sound/soc/mediatek/common/mtk-base-afe.h
+++ b/sound/soc/mediatek/common/mtk-base-afe.h
@@ -9,7 +9,26 @@
 #ifndef _MTK_BASE_AFE_H_
 #define _MTK_BASE_AFE_H_
 
+#include <linux/soc/mediatek/mtk_sip_svc.h>
+
 #define MTK_STREAM_NUM (SNDRV_PCM_STREAM_LAST + 1)
+#define MTK_SIP_AUDIO_CONTROL MTK_SIP_SMC_CMD(0x517)
+
+/* SMC CALL Operations */
+enum mtk_audio_smc_call_op {
+	MTK_AUDIO_SMC_OP_INIT = 0,
+	MTK_AUDIO_SMC_OP_DRAM_REQUEST,
+	MTK_AUDIO_SMC_OP_DRAM_RELEASE,
+	MTK_AUDIO_SMC_OP_SRAM_REQUEST,
+	MTK_AUDIO_SMC_OP_SRAM_RELEASE,
+	MTK_AUDIO_SMC_OP_ADSP_REQUEST,
+	MTK_AUDIO_SMC_OP_ADSP_RELEASE,
+	MTK_AUDIO_SMC_OP_DOMAIN_SIDEBANDS,
+	MTK_AUDIO_SMC_OP_BTCVSD_WRITE,
+	MTK_AUDIO_SMC_OP_BTCVSD_UPDATE_CTRL_CLEAR,
+	MTK_AUDIO_SMC_OP_BTCVSD_UPDATE_CTRL_UNDERFLOW,
+	MTK_AUDIO_SMC_OP_NUM
+};
 
 struct mtk_base_memif_data {
 	int id;
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 03/12] ASoC: mediatek: mt8188: support audsys clock
  2022-10-21  8:27 [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC Trevor Wu
  2022-10-21  8:27 ` [PATCH v2 01/12] ASoC: mediatek: common: add SMC ops and SMC CMD Trevor Wu
@ 2022-10-21  8:27 ` Trevor Wu
  2022-10-21  8:41   ` AngeloGioacchino Del Regno
  2022-10-21  8:27 ` [PATCH v2 04/12] ASoC: mediatek: mt8188: support adda in platform driver Trevor Wu
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Trevor Wu @ 2022-10-21  8:27 UTC (permalink / raw)
  To: broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: trevor.wu, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Add mt8188 audio cg clock control. Audio clock gates are registered to CCF
for reference count and clock parent management.

Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
---
 sound/soc/mediatek/mt8188/mt8188-audsys-clk.c | 206 ++++++++++++++++++
 sound/soc/mediatek/mt8188/mt8188-audsys-clk.h |  15 ++
 .../soc/mediatek/mt8188/mt8188-audsys-clkid.h |  83 +++++++
 3 files changed, 304 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h

diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
new file mode 100644
index 000000000000..1f294231d4c2
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8188-audsys-clk.c  --  MediaTek 8188 audsys clock control
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include "mt8188-afe-common.h"
+#include "mt8188-audsys-clk.h"
+#include "mt8188-audsys-clkid.h"
+#include "mt8188-reg.h"
+
+struct afe_gate {
+	int id;
+	const char *name;
+	const char *parent_name;
+	int reg;
+	u8 bit;
+	const struct clk_ops *ops;
+	unsigned long flags;
+	u8 cg_flags;
+};
+
+#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, _flags, _cgflags) {\
+		.id = _id,					\
+		.name = _name,					\
+		.parent_name = _parent,				\
+		.reg = _reg,					\
+		.bit = _bit,					\
+		.flags = _flags,				\
+		.cg_flags = _cgflags,				\
+	}
+
+#define GATE_AFE(_id, _name, _parent, _reg, _bit)		\
+	GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,		\
+		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE)
+
+#define GATE_AUD0(_id, _name, _parent, _bit)			\
+	GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON0, _bit)
+
+#define GATE_AUD1(_id, _name, _parent, _bit)			\
+	GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON1, _bit)
+
+#define GATE_AUD3(_id, _name, _parent, _bit)			\
+	GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON3, _bit)
+
+#define GATE_AUD4(_id, _name, _parent, _bit)			\
+	GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON4, _bit)
+
+#define GATE_AUD5(_id, _name, _parent, _bit)			\
+	GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON5, _bit)
+
+#define GATE_AUD6(_id, _name, _parent, _bit)			\
+	GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON6, _bit)
+
+static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
+	/* AUD0 */
+	GATE_AUD0(CLK_AUD_AFE, "aud_afe", "top_a1sys_hp", 2),
+	GATE_AUD0(CLK_AUD_LRCK_CNT, "aud_lrck_cnt", "top_a1sys_hp", 4),
+	GATE_AUD0(CLK_AUD_SPDIFIN_TUNER_APLL, "aud_spdifin_tuner_apll", "top_apll4", 10),
+	GATE_AUD0(CLK_AUD_SPDIFIN_TUNER_DBG, "aud_spdifin_tuner_dbg", "top_apll4", 11),
+	GATE_AUD0(CLK_AUD_UL_TML, "aud_ul_tml", "top_a1sys_hp", 18),
+	GATE_AUD0(CLK_AUD_APLL1_TUNER, "aud_apll1_tuner", "top_apll1", 19),
+	GATE_AUD0(CLK_AUD_APLL2_TUNER, "aud_apll2_tuner", "top_apll2", 20),
+	GATE_AUD0(CLK_AUD_TOP0_SPDF, "aud_top0_spdf", "top_aud_iec_clk", 21),
+	GATE_AUD0(CLK_AUD_APLL, "aud_apll", "top_apll1", 23),
+	GATE_AUD0(CLK_AUD_APLL2, "aud_apll2", "top_apll2", 24),
+	GATE_AUD0(CLK_AUD_DAC, "aud_dac", "top_a1sys_hp", 25),
+	GATE_AUD0(CLK_AUD_DAC_PREDIS, "aud_dac_predis", "top_a1sys_hp", 26),
+	GATE_AUD0(CLK_AUD_TML, "aud_tml", "top_a1sys_hp", 27),
+	GATE_AUD0(CLK_AUD_ADC, "aud_adc", "top_a1sys_hp", 28),
+	GATE_AUD0(CLK_AUD_DAC_HIRES, "aud_dac_hires", "top_audio_h", 31),
+
+	/* AUD1 */
+	GATE_AUD1(CLK_AUD_A1SYS_HP, "aud_a1sys_hp", "top_a1sys_hp", 2),
+	GATE_AUD1(CLK_AUD_AFE_DMIC1, "aud_afe_dmic1", "top_a1sys_hp", 10),
+	GATE_AUD1(CLK_AUD_AFE_DMIC2, "aud_afe_dmic2", "top_a1sys_hp", 11),
+	GATE_AUD1(CLK_AUD_AFE_DMIC3, "aud_afe_dmic3", "top_a1sys_hp", 12),
+	GATE_AUD1(CLK_AUD_AFE_DMIC4, "aud_afe_dmic4", "top_a1sys_hp", 13),
+	GATE_AUD1(CLK_AUD_AFE_26M_DMIC_TM, "aud_afe_26m_dmic_tm", "top_a1sys_hp", 14),
+	GATE_AUD1(CLK_AUD_UL_TML_HIRES, "aud_ul_tml_hires", "top_audio_h", 16),
+	GATE_AUD1(CLK_AUD_ADC_HIRES, "aud_adc_hires", "top_audio_h", 17),
+
+	/* AUD3 */
+	GATE_AUD3(CLK_AUD_LINEIN_TUNER, "aud_linein_tuner", "top_apll5", 5),
+	GATE_AUD3(CLK_AUD_EARC_TUNER, "aud_earc_tuner", "top_apll3", 7),
+
+	/* AUD4 */
+	GATE_AUD4(CLK_AUD_I2SIN, "aud_i2sin", "top_a1sys_hp", 0),
+	GATE_AUD4(CLK_AUD_TDM_IN, "aud_tdm_in", "top_a1sys_hp", 1),
+	GATE_AUD4(CLK_AUD_I2S_OUT, "aud_i2s_out", "top_a1sys_hp", 6),
+	GATE_AUD4(CLK_AUD_TDM_OUT, "aud_tdm_out", "top_a1sys_hp", 7),
+	GATE_AUD4(CLK_AUD_HDMI_OUT, "aud_hdmi_out", "top_a1sys_hp", 8),
+	GATE_AUD4(CLK_AUD_ASRC11, "aud_asrc11", "top_a1sys_hp", 16),
+	GATE_AUD4(CLK_AUD_ASRC12, "aud_asrc12", "top_a1sys_hp", 17),
+	GATE_AUD4(CLK_AUD_MULTI_IN, "aud_multi_in", "mphone_slave_b", 19),
+	GATE_AUD4(CLK_AUD_INTDIR, "aud_intdir", "top_intdir", 20),
+	GATE_AUD4(CLK_AUD_A1SYS, "aud_a1sys", "top_a1sys_hp", 21),
+	GATE_AUD4(CLK_AUD_A2SYS, "aud_a2sys", "top_a2sys", 22),
+	GATE_AUD4(CLK_AUD_PCMIF, "aud_pcmif", "top_a1sys_hp", 24),
+	GATE_AUD4(CLK_AUD_A3SYS, "aud_a3sys", "top_a3sys", 30),
+	GATE_AUD4(CLK_AUD_A4SYS, "aud_a4sys", "top_a4sys", 31),
+
+	/* AUD5 */
+	GATE_AUD5(CLK_AUD_MEMIF_UL1, "aud_memif_ul1", "top_a1sys_hp", 0),
+	GATE_AUD5(CLK_AUD_MEMIF_UL2, "aud_memif_ul2", "top_a1sys_hp", 1),
+	GATE_AUD5(CLK_AUD_MEMIF_UL3, "aud_memif_ul3", "top_a1sys_hp", 2),
+	GATE_AUD5(CLK_AUD_MEMIF_UL4, "aud_memif_ul4", "top_a1sys_hp", 3),
+	GATE_AUD5(CLK_AUD_MEMIF_UL5, "aud_memif_ul5", "top_a1sys_hp", 4),
+	GATE_AUD5(CLK_AUD_MEMIF_UL6, "aud_memif_ul6", "top_a1sys_hp", 5),
+	GATE_AUD5(CLK_AUD_MEMIF_UL8, "aud_memif_ul8", "top_a1sys_hp", 7),
+	GATE_AUD5(CLK_AUD_MEMIF_UL9, "aud_memif_ul9", "top_a1sys_hp", 8),
+	GATE_AUD5(CLK_AUD_MEMIF_UL10, "aud_memif_ul10", "top_a1sys_hp", 9),
+	GATE_AUD5(CLK_AUD_MEMIF_DL2, "aud_memif_dl2", "top_a1sys_hp", 18),
+	GATE_AUD5(CLK_AUD_MEMIF_DL3, "aud_memif_dl3", "top_a1sys_hp", 19),
+	GATE_AUD5(CLK_AUD_MEMIF_DL6, "aud_memif_dl6", "top_a1sys_hp", 22),
+	GATE_AUD5(CLK_AUD_MEMIF_DL7, "aud_memif_dl7", "top_a1sys_hp", 23),
+	GATE_AUD5(CLK_AUD_MEMIF_DL8, "aud_memif_dl8", "top_a1sys_hp", 24),
+	GATE_AUD5(CLK_AUD_MEMIF_DL10, "aud_memif_dl10", "top_a1sys_hp", 26),
+	GATE_AUD5(CLK_AUD_MEMIF_DL11, "aud_memif_dl11", "top_a1sys_hp", 27),
+
+	/* AUD6 */
+	GATE_AUD6(CLK_AUD_GASRC0, "aud_gasrc0", "top_asm_h", 0),
+	GATE_AUD6(CLK_AUD_GASRC1, "aud_gasrc1", "top_asm_h", 1),
+	GATE_AUD6(CLK_AUD_GASRC2, "aud_gasrc2", "top_asm_h", 2),
+	GATE_AUD6(CLK_AUD_GASRC3, "aud_gasrc3", "top_asm_h", 3),
+	GATE_AUD6(CLK_AUD_GASRC4, "aud_gasrc4", "top_asm_h", 4),
+	GATE_AUD6(CLK_AUD_GASRC5, "aud_gasrc5", "top_asm_h", 5),
+	GATE_AUD6(CLK_AUD_GASRC6, "aud_gasrc6", "top_asm_h", 6),
+	GATE_AUD6(CLK_AUD_GASRC7, "aud_gasrc7", "top_asm_h", 7),
+	GATE_AUD6(CLK_AUD_GASRC8, "aud_gasrc8", "top_asm_h", 8),
+	GATE_AUD6(CLK_AUD_GASRC9, "aud_gasrc9", "top_asm_h", 9),
+	GATE_AUD6(CLK_AUD_GASRC10, "aud_gasrc10", "top_asm_h", 10),
+	GATE_AUD6(CLK_AUD_GASRC11, "aud_gasrc11", "top_asm_h", 11),
+};
+
+int mt8188_audsys_clk_register(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct clk *clk;
+	struct clk_lookup *cl;
+	int i;
+
+	afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AUD_NR_CLK,
+					sizeof(*afe_priv->lookup),
+					GFP_KERNEL);
+
+	if (!afe_priv->lookup)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
+		const struct afe_gate *gate = &aud_clks[i];
+
+		clk = clk_register_gate(afe->dev, gate->name, gate->parent_name,
+					gate->flags, afe->base_addr + gate->reg,
+					gate->bit, gate->cg_flags, NULL);
+
+		if (IS_ERR(clk)) {
+			dev_err(afe->dev, "Failed to register clk %s: %ld\n",
+				gate->name, PTR_ERR(clk));
+			continue;
+		}
+
+		/* add clk_lookup for devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */
+		cl = kzalloc(sizeof(*cl), GFP_KERNEL);
+		if (!cl)
+			return -ENOMEM;
+
+		cl->clk = clk;
+		cl->con_id = gate->name;
+		cl->dev_id = dev_name(afe->dev);
+		cl->clk_hw = NULL;
+		clkdev_add(cl);
+
+		afe_priv->lookup[i] = cl;
+	}
+
+	return 0;
+}
+
+void mt8188_audsys_clk_unregister(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct clk *clk;
+	struct clk_lookup *cl;
+	int i;
+
+	if (!afe_priv)
+		return;
+
+	for (i = 0; i < CLK_AUD_NR_CLK; i++) {
+		cl = afe_priv->lookup[i];
+		if (!cl)
+			continue;
+
+		clk = cl->clk;
+		clk_unregister_gate(clk);
+
+		clkdev_drop(cl);
+	}
+}
+
diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
new file mode 100644
index 000000000000..6c5f463ad7e4
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8188-audsys-clk.h  --  MediaTek 8188 audsys clock definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
+ */
+
+#ifndef _MT8188_AUDSYS_CLK_H_
+#define _MT8188_AUDSYS_CLK_H_
+
+int mt8188_audsys_clk_register(struct mtk_base_afe *afe);
+void mt8188_audsys_clk_unregister(struct mtk_base_afe *afe);
+
+#endif
diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h b/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h
new file mode 100644
index 000000000000..6f34ffc760e0
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8188-audsys-clkid.h  --  MediaTek 8188 audsys clock id definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
+ */
+
+#ifndef _MT8188_AUDSYS_CLKID_H_
+#define _MT8188_AUDSYS_CLKID_H_
+
+enum{
+	CLK_AUD_AFE,
+	CLK_AUD_LRCK_CNT,
+	CLK_AUD_SPDIFIN_TUNER_APLL,
+	CLK_AUD_SPDIFIN_TUNER_DBG,
+	CLK_AUD_UL_TML,
+	CLK_AUD_APLL1_TUNER,
+	CLK_AUD_APLL2_TUNER,
+	CLK_AUD_TOP0_SPDF,
+	CLK_AUD_APLL,
+	CLK_AUD_APLL2,
+	CLK_AUD_DAC,
+	CLK_AUD_DAC_PREDIS,
+	CLK_AUD_TML,
+	CLK_AUD_ADC,
+	CLK_AUD_DAC_HIRES,
+	CLK_AUD_A1SYS_HP,
+	CLK_AUD_AFE_DMIC1,
+	CLK_AUD_AFE_DMIC2,
+	CLK_AUD_AFE_DMIC3,
+	CLK_AUD_AFE_DMIC4,
+	CLK_AUD_AFE_26M_DMIC_TM,
+	CLK_AUD_UL_TML_HIRES,
+	CLK_AUD_ADC_HIRES,
+	CLK_AUD_LINEIN_TUNER,
+	CLK_AUD_EARC_TUNER,
+	CLK_AUD_I2SIN,
+	CLK_AUD_TDM_IN,
+	CLK_AUD_I2S_OUT,
+	CLK_AUD_TDM_OUT,
+	CLK_AUD_HDMI_OUT,
+	CLK_AUD_ASRC11,
+	CLK_AUD_ASRC12,
+	CLK_AUD_MULTI_IN,
+	CLK_AUD_INTDIR,
+	CLK_AUD_A1SYS,
+	CLK_AUD_A2SYS,
+	CLK_AUD_PCMIF,
+	CLK_AUD_A3SYS,
+	CLK_AUD_A4SYS,
+	CLK_AUD_MEMIF_UL1,
+	CLK_AUD_MEMIF_UL2,
+	CLK_AUD_MEMIF_UL3,
+	CLK_AUD_MEMIF_UL4,
+	CLK_AUD_MEMIF_UL5,
+	CLK_AUD_MEMIF_UL6,
+	CLK_AUD_MEMIF_UL8,
+	CLK_AUD_MEMIF_UL9,
+	CLK_AUD_MEMIF_UL10,
+	CLK_AUD_MEMIF_DL2,
+	CLK_AUD_MEMIF_DL3,
+	CLK_AUD_MEMIF_DL6,
+	CLK_AUD_MEMIF_DL7,
+	CLK_AUD_MEMIF_DL8,
+	CLK_AUD_MEMIF_DL10,
+	CLK_AUD_MEMIF_DL11,
+	CLK_AUD_GASRC0,
+	CLK_AUD_GASRC1,
+	CLK_AUD_GASRC2,
+	CLK_AUD_GASRC3,
+	CLK_AUD_GASRC4,
+	CLK_AUD_GASRC5,
+	CLK_AUD_GASRC6,
+	CLK_AUD_GASRC7,
+	CLK_AUD_GASRC8,
+	CLK_AUD_GASRC9,
+	CLK_AUD_GASRC10,
+	CLK_AUD_GASRC11,
+	CLK_AUD_NR_CLK,
+};
+
+#endif
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 04/12] ASoC: mediatek: mt8188: support adda in platform driver
  2022-10-21  8:27 [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC Trevor Wu
  2022-10-21  8:27 ` [PATCH v2 01/12] ASoC: mediatek: common: add SMC ops and SMC CMD Trevor Wu
  2022-10-21  8:27 ` [PATCH v2 03/12] ASoC: mediatek: mt8188: support audsys clock Trevor Wu
@ 2022-10-21  8:27 ` Trevor Wu
  2022-10-21  8:41   ` AngeloGioacchino Del Regno
  2022-10-21  8:27 ` [PATCH v2 05/12] ASoC: mediatek: mt8188: support etdm " Trevor Wu
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Trevor Wu @ 2022-10-21  8:27 UTC (permalink / raw)
  To: broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: trevor.wu, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Add mt8188 adda dai driver support.

Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
---
 sound/soc/mediatek/mt8188/mt8188-dai-adda.c | 631 ++++++++++++++++++++
 1 file changed, 631 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-adda.c

diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-adda.c b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c
new file mode 100644
index 000000000000..3c61abe2f9d2
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c
@@ -0,0 +1,631 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI ADDA Control
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Bicycle Tsai <bicycle.tsai@mediatek.com>
+ *         Trevor Wu <trevor.wu@mediatek.com>
+ *         Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include "mt8188-afe-clk.h"
+#include "mt8188-afe-common.h"
+#include "mt8188-reg.h"
+
+#define ADDA_HIRES_THRES 48000
+
+enum {
+	SUPPLY_SEQ_CLOCK_SEL,
+	SUPPLY_SEQ_ADDA_DL_ON,
+	SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+	SUPPLY_SEQ_ADDA_UL_ON,
+	SUPPLY_SEQ_ADDA_AFE_ON,
+};
+
+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 = 3,
+	MTK_AFE_ADDA_DL_RATE_22K = 4,
+	MTK_AFE_ADDA_DL_RATE_24K = 5,
+	MTK_AFE_ADDA_DL_RATE_32K = 6,
+	MTK_AFE_ADDA_DL_RATE_44K = 7,
+	MTK_AFE_ADDA_DL_RATE_48K = 8,
+	MTK_AFE_ADDA_DL_RATE_96K = 9,
+	MTK_AFE_ADDA_DL_RATE_192K = 10,
+};
+
+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,
+};
+
+enum {
+	DELAY_DATA_MISO1 = 0,
+	DELAY_DATA_MISO0 = 1,
+};
+
+struct mtk_dai_adda_priv {
+	unsigned int dl_rate;
+	unsigned int ul_rate;
+};
+
+static unsigned int afe_adda_dl_rate_transform(struct mtk_base_afe *afe,
+					       unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return MTK_AFE_ADDA_DL_RATE_8K;
+	case 11025:
+		return MTK_AFE_ADDA_DL_RATE_11K;
+	case 12000:
+		return MTK_AFE_ADDA_DL_RATE_12K;
+	case 16000:
+		return MTK_AFE_ADDA_DL_RATE_16K;
+	case 22050:
+		return MTK_AFE_ADDA_DL_RATE_22K;
+	case 24000:
+		return MTK_AFE_ADDA_DL_RATE_24K;
+	case 32000:
+		return MTK_AFE_ADDA_DL_RATE_32K;
+	case 44100:
+		return MTK_AFE_ADDA_DL_RATE_44K;
+	case 48000:
+		return MTK_AFE_ADDA_DL_RATE_48K;
+	case 96000:
+		return MTK_AFE_ADDA_DL_RATE_96K;
+	case 192000:
+		return MTK_AFE_ADDA_DL_RATE_192K;
+	default:
+		dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+			 __func__, rate);
+		return MTK_AFE_ADDA_DL_RATE_48K;
+	}
+}
+
+static unsigned int afe_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;
+	}
+}
+
+static int mt8188_adda_mtkaif_init(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtkaif_param *param = &afe_priv->mtkaif_params;
+	int delay_data;
+	int delay_cycle;
+	unsigned int mask = 0;
+	unsigned int val = 0;
+
+	/* set rx protocol 2 & mtkaif_rxif_clkinv_adc inverse */
+	regmap_set_bits(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
+			MTKAIF_RXIF_CLKINV_ADC | MTKAIF_RXIF_PROTOCOL2);
+
+	regmap_set_bits(afe->regmap, AFE_AUD_PAD_TOP, RG_RX_PROTOCOL2);
+
+	if (!param->mtkaif_calibration_ok) {
+		dev_info(afe->dev, "%s(), calibration fail\n",  __func__);
+		return 0;
+	}
+
+	/* set delay for ch1, ch2 */
+	if (param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_0] >=
+	    param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_1]) {
+		delay_data = DELAY_DATA_MISO1;
+		delay_cycle =
+			param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_0] -
+			param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_1];
+	} else {
+		delay_data = DELAY_DATA_MISO0;
+		delay_cycle =
+			param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_1] -
+			param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_0];
+	}
+
+	val = 0;
+	mask = (MTKAIF_RXIF_DELAY_DATA | MTKAIF_RXIF_DELAY_CYCLE_MASK);
+	val |= FIELD_PREP(MTKAIF_RXIF_DELAY_CYCLE_MASK, delay_cycle);
+	val |= FIELD_PREP(MTKAIF_RXIF_DELAY_DATA, delay_data);
+	regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG2, mask, val);
+
+	return 0;
+}
+
+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);
+
+	dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+		__func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8188_adda_mtkaif_init(afe);
+		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_POST_PMD:
+		/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+		usleep_range(125, 135);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void mtk_adda_ul_mictype(struct mtk_base_afe *afe, bool dmic)
+{
+	unsigned int reg = AFE_ADDA_UL_SRC_CON0;
+	unsigned int val;
+
+	val = (UL_SDM3_LEVEL_CTL | UL_MODE_3P25M_CH1_CTL |
+	       UL_MODE_3P25M_CH2_CTL);
+
+	/* turn on dmic, ch1, ch2 */
+	if (dmic)
+		regmap_set_bits(afe->regmap, reg, val);
+	else
+		regmap_clear_bits(afe->regmap, reg, val);
+}
+
+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 mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtkaif_param *param = &afe_priv->mtkaif_params;
+
+	dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+		__func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mtk_adda_ul_mictype(afe, param->mtkaif_dmic_on);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+		usleep_range(125, 135);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_audio_hires_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 mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct clk *clk = afe_priv->clk[MT8188_CLK_TOP_AUDIO_H_SEL];
+	struct clk *clk_parent;
+
+	dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+		__func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		clk_parent = afe_priv->clk[MT8188_CLK_TOP_APLL1];
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		clk_parent = afe_priv->clk[MT8188_CLK_XTAL_26M];
+		break;
+	default:
+		return 0;
+	}
+	mt8188_afe_set_clk_parent(afe, clk, clk_parent);
+
+	return 0;
+}
+
+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 mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_adda_priv *adda_priv;
+
+	adda_priv = afe_priv->dai_priv[MT8188_AFE_IO_ADDA];
+
+	if (!adda_priv) {
+		dev_err(afe->dev, "%s adda_priv == NULL", __func__);
+		return 0;
+	}
+
+	return !!(adda_priv->ul_rate > ADDA_HIRES_THRES);
+}
+
+static int mtk_afe_dac_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 mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_adda_priv *adda_priv;
+
+	adda_priv = afe_priv->dai_priv[MT8188_AFE_IO_ADDA];
+
+	if (!adda_priv) {
+		dev_err(afe->dev, "%s adda_priv == NULL", __func__);
+		return 0;
+	}
+
+	return !!(adda_priv->dl_rate > ADDA_HIRES_THRES);
+}
+
+static const struct snd_kcontrol_new mtk_dai_adda_o176_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN176, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I002 Switch", AFE_CONN176, 2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN176, 20, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN176, 22, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN176_2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_adda_o177_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN177, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I003 Switch", AFE_CONN177, 3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN177, 21, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN177, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN177_2, 7, 1, 0),
+};
+
+static const char * const adda_dlgain_mux_map[] = {
+	"Bypass", "Connect",
+};
+
+static SOC_ENUM_SINGLE_DECL(adda_dlgain_mux_map_enum,
+			    SND_SOC_NOPM, 0,
+			    adda_dlgain_mux_map);
+
+static const struct snd_kcontrol_new adda_dlgain_mux_control =
+	SOC_DAPM_ENUM("DL_GAIN_MUX", adda_dlgain_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+	SND_SOC_DAPM_MIXER("I168", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I169", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("O176", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_adda_o176_mix,
+			   ARRAY_SIZE(mtk_dai_adda_o176_mix)),
+	SND_SOC_DAPM_MIXER("O177", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_adda_o177_mix,
+			   ARRAY_SIZE(mtk_dai_adda_o177_mix)),
+
+	SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
+			      AFE_ADDA_UL_DL_CON0,
+			      ADDA_AFE_ON_SHIFT, 0,
+			      NULL,
+			      0),
+
+	SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON,
+			      AFE_ADDA_DL_SRC2_CON0,
+			      DL_2_SRC_ON_TMP_CTRL_PRE_SHIFT, 0,
+			      mtk_adda_dl_event,
+			      SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+			      AFE_ADDA_UL_SRC_CON0,
+			      UL_SRC_ON_TMP_CTL_SHIFT, 0,
+			      mtk_adda_ul_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("AUDIO_HIRES", SUPPLY_SEQ_CLOCK_SEL,
+			      SND_SOC_NOPM,
+			      0, 0,
+			      mtk_audio_hires_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	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_MUX("DL_GAIN_MUX", SND_SOC_NOPM, 0, 0,
+			 &adda_dlgain_mux_control),
+
+	SND_SOC_DAPM_PGA("DL_GAIN", AFE_ADDA_DL_SRC2_CON0,
+			 DL_2_GAIN_ON_CTL_PRE_SHIFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_INPUT("ADDA_INPUT"),
+	SND_SOC_DAPM_OUTPUT("ADDA_OUTPUT"),
+
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac"),
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc"),
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_hires"),
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_hires"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+	{"ADDA Capture", NULL, "ADDA Enable"},
+	{"ADDA Capture", NULL, "ADDA Capture Enable"},
+	{"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"},
+	{"ADDA Capture", NULL, "aud_adc"},
+	{"ADDA Capture", NULL, "aud_adc_hires", mtk_afe_adc_hires_connect},
+	{"aud_adc_hires", NULL, "AUDIO_HIRES"},
+
+	{"I168", NULL, "ADDA Capture"},
+	{"I169", NULL, "ADDA Capture"},
+
+	{"ADDA Playback", NULL, "ADDA Enable"},
+	{"ADDA Playback", NULL, "ADDA Playback Enable"},
+	{"ADDA Playback", NULL, "aud_dac"},
+	{"ADDA Playback", NULL, "aud_dac_hires", mtk_afe_dac_hires_connect},
+	{"aud_dac_hires", NULL, "AUDIO_HIRES"},
+
+	{"DL_GAIN", NULL, "O176"},
+	{"DL_GAIN", NULL, "O177"},
+
+	{"DL_GAIN_MUX", "Bypass", "O176"},
+	{"DL_GAIN_MUX", "Bypass", "O177"},
+	{"DL_GAIN_MUX", "Connect", "DL_GAIN"},
+
+	{"ADDA Playback", NULL, "DL_GAIN_MUX"},
+
+	{"O176", "I000 Switch", "I000"},
+	{"O177", "I001 Switch", "I001"},
+
+	{"O176", "I002 Switch", "I002"},
+	{"O177", "I003 Switch", "I003"},
+
+	{"O176", "I020 Switch", "I020"},
+	{"O177", "I021 Switch", "I021"},
+
+	{"O176", "I022 Switch", "I022"},
+	{"O177", "I023 Switch", "I023"},
+
+	{"O176", "I070 Switch", "I070"},
+	{"O177", "I071 Switch", "I071"},
+
+	{"ADDA Capture", NULL, "ADDA_INPUT"},
+	{"ADDA_OUTPUT", NULL, "ADDA Playback"},
+};
+
+static int mt8188_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 mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtkaif_param *param = &afe_priv->mtkaif_params;
+
+	ucontrol->value.integer.value[0] = param->mtkaif_dmic_on;
+	return 0;
+}
+
+static int mt8188_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 mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtkaif_param *param = &afe_priv->mtkaif_params;
+	int dmic_on;
+
+	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);
+
+	if (param->mtkaif_dmic_on == dmic_on)
+		return 0;
+
+	param->mtkaif_dmic_on = dmic_on;
+	return 1;
+}
+
+static const struct snd_kcontrol_new mtk_dai_adda_controls[] = {
+	SOC_SINGLE("ADDA_DL_GAIN", AFE_ADDA_DL_SRC2_CON1,
+		   DL_2_GAIN_CTL_PRE_SHIFT, 65535, 0),
+	SOC_SINGLE_BOOL_EXT("MTKAIF_DMIC Switch", 0,
+			    mt8188_adda_dmic_get, mt8188_adda_dmic_set),
+};
+
+static int mtk_dai_da_configure(struct mtk_base_afe *afe,
+				unsigned int rate, int id)
+{
+	unsigned int val = 0;
+	unsigned int mask = 0;
+
+	/* set sampling rate */
+	mask |= DL_2_INPUT_MODE_CTL_MASK;
+	val |= FIELD_PREP(DL_2_INPUT_MODE_CTL_MASK,
+			  afe_adda_dl_rate_transform(afe, rate));
+
+	/* turn off saturation */
+	mask |= DL_2_CH1_SATURATION_EN_CTL;
+	mask |= DL_2_CH2_SATURATION_EN_CTL;
+
+	/* turn off mute function */
+	mask |= DL_2_MUTE_CH1_OFF_CTL_PRE;
+	mask |= DL_2_MUTE_CH2_OFF_CTL_PRE;
+	val |= DL_2_MUTE_CH1_OFF_CTL_PRE;
+	val |= DL_2_MUTE_CH2_OFF_CTL_PRE;
+
+	/* set voice input data if input sample rate is 8k or 16k */
+	mask |= DL_2_VOICE_MODE_CTL_PRE;
+	if (rate == 8000 || rate == 16000)
+		val |= DL_2_VOICE_MODE_CTL_PRE;
+
+	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, mask, val);
+
+	/* new 2nd sdm */
+	regmap_set_bits(afe->regmap, AFE_ADDA_DL_SDM_DCCOMP_CON,
+			DL_USE_NEW_2ND_SDM);
+
+	return 0;
+}
+
+static int mtk_dai_ad_configure(struct mtk_base_afe *afe,
+				unsigned int rate, int id)
+{
+	unsigned int val;
+	unsigned int mask;
+
+	mask = UL_VOICE_MODE_CTL_MASK;
+	val = FIELD_PREP(UL_VOICE_MODE_CTL_MASK,
+			 afe_adda_ul_rate_transform(afe, rate));
+
+	regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,
+			   mask, val);
+	return 0;
+}
+
+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 mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_adda_priv *adda_priv = afe_priv->dai_priv[dai->id];
+	unsigned int rate = params_rate(params);
+	int id = dai->id;
+	int ret = 0;
+
+	dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+		__func__, id, substream->stream, rate);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		adda_priv->dl_rate = rate;
+		ret = mtk_dai_da_configure(afe, rate, id);
+	} else {
+		adda_priv->ul_rate = rate;
+		ret = mtk_dai_ad_configure(afe, rate, id);
+	}
+
+	return ret;
+}
+
+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 = MT8188_AFE_IO_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,
+	},
+};
+
+static int init_adda_priv_data(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_adda_priv *adda_priv;
+
+	adda_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_adda_priv),
+				 GFP_KERNEL);
+	if (!adda_priv)
+		return -ENOMEM;
+
+	afe_priv->dai_priv[MT8188_AFE_IO_ADDA] = adda_priv;
+
+	return 0;
+}
+
+int mt8188_dai_adda_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+
+	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->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);
+	dai->controls = mtk_dai_adda_controls;
+	dai->num_controls = ARRAY_SIZE(mtk_dai_adda_controls);
+
+	return init_adda_priv_data(afe);
+}
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 05/12] ASoC: mediatek: mt8188: support etdm in platform driver
  2022-10-21  8:27 [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC Trevor Wu
                   ` (2 preceding siblings ...)
  2022-10-21  8:27 ` [PATCH v2 04/12] ASoC: mediatek: mt8188: support adda in platform driver Trevor Wu
@ 2022-10-21  8:27 ` Trevor Wu
  2022-10-21  8:41   ` AngeloGioacchino Del Regno
  2022-10-21  8:27 ` [PATCH v2 06/12] ASoC: mediatek: mt8188: support pcmif " Trevor Wu
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Trevor Wu @ 2022-10-21  8:27 UTC (permalink / raw)
  To: broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: trevor.wu, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Add mt8188 etdm dai driver support.

Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
---
 sound/soc/mediatek/mt8188/mt8188-dai-etdm.c | 2596 +++++++++++++++++++
 1 file changed, 2596 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-etdm.c

diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
new file mode 100644
index 000000000000..24ea6ceb587c
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
@@ -0,0 +1,2596 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI eTDM Control
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Bicycle Tsai <bicycle.tsai@mediatek.com>
+ *         Trevor Wu <trevor.wu@mediatek.com>
+ *         Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8188-afe-clk.h"
+#include "mt8188-afe-common.h"
+#include "mt8188-reg.h"
+
+#define MT8188_ETDM_MAX_CHANNELS 16
+#define MT8188_ETDM_NORMAL_MAX_BCK_RATE 24576000
+#define ETDM_TO_DAI_ID(x) ((x) + MT8188_AFE_IO_ETDM_START)
+#define ENUM_TO_STR(x)	#x
+
+enum {
+	MTK_DAI_ETDM_FORMAT_I2S = 0,
+	MTK_DAI_ETDM_FORMAT_LJ,
+	MTK_DAI_ETDM_FORMAT_RJ,
+	MTK_DAI_ETDM_FORMAT_EIAJ,
+	MTK_DAI_ETDM_FORMAT_DSPA,
+	MTK_DAI_ETDM_FORMAT_DSPB,
+};
+
+enum {
+	MTK_DAI_ETDM_DATA_ONE_PIN = 0,
+	MTK_DAI_ETDM_DATA_MULTI_PIN,
+};
+
+enum {
+	ETDM_IN,
+	ETDM_OUT,
+};
+
+enum {
+	COWORK_ETDM_NONE = 0,
+	COWORK_ETDM_IN1_M = 2,
+	COWORK_ETDM_IN1_S = 3,
+	COWORK_ETDM_IN2_M = 4,
+	COWORK_ETDM_IN2_S = 5,
+	COWORK_ETDM_OUT1_M = 10,
+	COWORK_ETDM_OUT1_S = 11,
+	COWORK_ETDM_OUT2_M = 12,
+	COWORK_ETDM_OUT2_S = 13,
+	COWORK_ETDM_OUT3_M = 14,
+	COWORK_ETDM_OUT3_S = 15,
+};
+
+enum {
+	ETDM_RELATCH_TIMING_A1A2SYS,
+	ETDM_RELATCH_TIMING_A3SYS,
+	ETDM_RELATCH_TIMING_A4SYS,
+};
+
+enum {
+	ETDM_SYNC_NONE,
+	ETDM_SYNC_FROM_IN1 = 2,
+	ETDM_SYNC_FROM_IN2 = 4,
+	ETDM_SYNC_FROM_OUT1 = 10,
+	ETDM_SYNC_FROM_OUT2 = 12,
+	ETDM_SYNC_FROM_OUT3 = 14,
+};
+
+struct etdm_con_reg {
+	unsigned int con0;
+	unsigned int con1;
+	unsigned int con2;
+	unsigned int con3;
+	unsigned int con4;
+	unsigned int con5;
+};
+
+struct mtk_dai_etdm_rate {
+	unsigned int rate;
+	unsigned int reg_value;
+};
+
+struct mtk_dai_etdm_priv {
+	unsigned int clock_mode;
+	unsigned int data_mode;
+	bool slave_mode;
+	bool lrck_inv;
+	bool bck_inv;
+	unsigned int format;
+	unsigned int slots;
+	unsigned int lrck_width;
+	unsigned int mclk_freq;
+	unsigned int mclk_fixed_apll;
+	unsigned int mclk_apll;
+	unsigned int mclk_dir;
+	int cowork_source_id; //dai id
+	unsigned int cowork_slv_count;
+	int cowork_slv_id[MT8188_AFE_IO_ETDM_NUM - 1]; //dai_id
+	bool in_disable_ch[MT8188_ETDM_MAX_CHANNELS];
+	unsigned int en_ref_cnt;
+	bool is_prepared;
+};
+
+static const struct mtk_dai_etdm_rate mt8188_etdm_rates[] = {
+	{ .rate = 8000, .reg_value = 0, },
+	{ .rate = 12000, .reg_value = 1, },
+	{ .rate = 16000, .reg_value = 2, },
+	{ .rate = 24000, .reg_value = 3, },
+	{ .rate = 32000, .reg_value = 4, },
+	{ .rate = 48000, .reg_value = 5, },
+	{ .rate = 96000, .reg_value = 7, },
+	{ .rate = 192000, .reg_value = 9, },
+	{ .rate = 384000, .reg_value = 11, },
+	{ .rate = 11025, .reg_value = 16, },
+	{ .rate = 22050, .reg_value = 17, },
+	{ .rate = 44100, .reg_value = 18, },
+	{ .rate = 88200, .reg_value = 19, },
+	{ .rate = 176400, .reg_value = 20, },
+	{ .rate = 352800, .reg_value = 21, },
+};
+
+static int get_etdm_fs_timing(unsigned int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mt8188_etdm_rates); i++)
+		if (mt8188_etdm_rates[i].rate == rate)
+			return mt8188_etdm_rates[i].reg_value;
+
+	return -EINVAL;
+}
+
+static unsigned int get_etdm_ch_fixup(unsigned int channels)
+{
+	if (channels > 16)
+		return 24;
+	else if (channels > 8)
+		return 16;
+	else if (channels > 4)
+		return 8;
+	else if (channels > 2)
+		return 4;
+	else
+		return 2;
+}
+
+static int get_etdm_reg(unsigned int dai_id, struct etdm_con_reg *etdm_reg)
+{
+	switch (dai_id) {
+	case MT8188_AFE_IO_ETDM1_IN:
+		etdm_reg->con0 = ETDM_IN1_CON0;
+		etdm_reg->con1 = ETDM_IN1_CON1;
+		etdm_reg->con2 = ETDM_IN1_CON2;
+		etdm_reg->con3 = ETDM_IN1_CON3;
+		etdm_reg->con4 = ETDM_IN1_CON4;
+		etdm_reg->con5 = ETDM_IN1_CON5;
+		break;
+	case MT8188_AFE_IO_ETDM2_IN:
+		etdm_reg->con0 = ETDM_IN2_CON0;
+		etdm_reg->con1 = ETDM_IN2_CON1;
+		etdm_reg->con2 = ETDM_IN2_CON2;
+		etdm_reg->con3 = ETDM_IN2_CON3;
+		etdm_reg->con4 = ETDM_IN2_CON4;
+		etdm_reg->con5 = ETDM_IN2_CON5;
+		break;
+	case MT8188_AFE_IO_ETDM1_OUT:
+		etdm_reg->con0 = ETDM_OUT1_CON0;
+		etdm_reg->con1 = ETDM_OUT1_CON1;
+		etdm_reg->con2 = ETDM_OUT1_CON2;
+		etdm_reg->con3 = ETDM_OUT1_CON3;
+		etdm_reg->con4 = ETDM_OUT1_CON4;
+		etdm_reg->con5 = ETDM_OUT1_CON5;
+		break;
+	case MT8188_AFE_IO_ETDM2_OUT:
+		etdm_reg->con0 = ETDM_OUT2_CON0;
+		etdm_reg->con1 = ETDM_OUT2_CON1;
+		etdm_reg->con2 = ETDM_OUT2_CON2;
+		etdm_reg->con3 = ETDM_OUT2_CON3;
+		etdm_reg->con4 = ETDM_OUT2_CON4;
+		etdm_reg->con5 = ETDM_OUT2_CON5;
+		break;
+	case MT8188_AFE_IO_ETDM3_OUT:
+	case MT8188_AFE_IO_DPTX:
+		etdm_reg->con0 = ETDM_OUT3_CON0;
+		etdm_reg->con1 = ETDM_OUT3_CON1;
+		etdm_reg->con2 = ETDM_OUT3_CON2;
+		etdm_reg->con3 = ETDM_OUT3_CON3;
+		etdm_reg->con4 = ETDM_OUT3_CON4;
+		etdm_reg->con5 = ETDM_OUT3_CON5;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int get_etdm_dir(unsigned int dai_id)
+{
+	switch (dai_id) {
+	case MT8188_AFE_IO_ETDM1_IN:
+	case MT8188_AFE_IO_ETDM2_IN:
+		return ETDM_IN;
+	case MT8188_AFE_IO_ETDM1_OUT:
+	case MT8188_AFE_IO_ETDM2_OUT:
+	case MT8188_AFE_IO_ETDM3_OUT:
+		return ETDM_OUT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int get_etdm_wlen(unsigned int bitwidth)
+{
+	return bitwidth <= 16 ? 16 : 32;
+}
+
+static bool is_valid_etdm_dai(int dai_id)
+{
+	if (dai_id < MT8188_AFE_IO_ETDM_START || dai_id >= MT8188_AFE_IO_ETDM_END)
+		return false;
+	else
+		return true;
+}
+
+static int is_cowork_mode(struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+
+	if (!is_valid_etdm_dai(dai->id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai->id];
+
+	return (etdm_data->cowork_slv_count > 0 ||
+		etdm_data->cowork_source_id != COWORK_ETDM_NONE);
+}
+
+static int sync_to_dai_id(int source_sel)
+{
+	switch (source_sel) {
+	case ETDM_SYNC_FROM_IN1:
+		return MT8188_AFE_IO_ETDM1_IN;
+	case ETDM_SYNC_FROM_IN2:
+		return MT8188_AFE_IO_ETDM2_IN;
+	case ETDM_SYNC_FROM_OUT1:
+		return MT8188_AFE_IO_ETDM1_OUT;
+	case ETDM_SYNC_FROM_OUT2:
+		return MT8188_AFE_IO_ETDM2_OUT;
+	case ETDM_SYNC_FROM_OUT3:
+		return MT8188_AFE_IO_ETDM3_OUT;
+	default:
+		return 0;
+	}
+}
+
+static int get_etdm_cowork_master_id(struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+	int dai_id;
+
+	if (!is_valid_etdm_dai(dai->id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai->id];
+	dai_id = etdm_data->cowork_source_id;
+
+	if (dai_id == COWORK_ETDM_NONE)
+		dai_id = dai->id;
+
+	return dai_id;
+}
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o048_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN48, 20, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN48, 22, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I046 Switch", AFE_CONN48_1, 14, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN48_2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o049_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN49, 21, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN49, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I047 Switch", AFE_CONN49_1, 15, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN49_2, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o050_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I024 Switch", AFE_CONN50, 24, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I048 Switch", AFE_CONN50_1, 16, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o051_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I025 Switch", AFE_CONN51, 25, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I049 Switch", AFE_CONN51_1, 17, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o052_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I026 Switch", AFE_CONN52, 26, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I050 Switch", AFE_CONN52_1, 18, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o053_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I027 Switch", AFE_CONN53, 27, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I051 Switch", AFE_CONN53_1, 19, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o054_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I028 Switch", AFE_CONN54, 28, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I052 Switch", AFE_CONN54_1, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o055_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I029 Switch", AFE_CONN55, 29, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I053 Switch", AFE_CONN55_1, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o056_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I030 Switch", AFE_CONN56, 30, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I054 Switch", AFE_CONN56_1, 22, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o057_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I031 Switch", AFE_CONN57, 31, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I055 Switch", AFE_CONN57_1, 23, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o058_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I032 Switch", AFE_CONN58_1, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I056 Switch", AFE_CONN58_1, 24, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o059_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I033 Switch", AFE_CONN59_1, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I057 Switch", AFE_CONN59_1, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o060_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I034 Switch", AFE_CONN60_1, 2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I058 Switch", AFE_CONN60_1, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o061_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I035 Switch", AFE_CONN61_1, 3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I059 Switch", AFE_CONN61_1, 27, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o062_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I036 Switch", AFE_CONN62_1, 4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I060 Switch", AFE_CONN62_1, 28, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o063_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I037 Switch", AFE_CONN63_1, 5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I061 Switch", AFE_CONN63_1, 29, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o072_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN72, 20, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN72, 22, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I046 Switch", AFE_CONN72_1, 14, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN72_2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o073_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN73, 21, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN73, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I047 Switch", AFE_CONN73_1, 15, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN73_2, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o074_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I024 Switch", AFE_CONN74, 24, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I048 Switch", AFE_CONN74_1, 16, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o075_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I025 Switch", AFE_CONN75, 25, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I049 Switch", AFE_CONN75_1, 17, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o076_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I026 Switch", AFE_CONN76, 26, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I050 Switch", AFE_CONN76_1, 18, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o077_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I027 Switch", AFE_CONN77, 27, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I051 Switch", AFE_CONN77_1, 19, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o078_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I028 Switch", AFE_CONN78, 28, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I052 Switch", AFE_CONN78_1, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o079_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I029 Switch", AFE_CONN79, 29, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I053 Switch", AFE_CONN79_1, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o080_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I030 Switch", AFE_CONN80, 30, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I054 Switch", AFE_CONN80_1, 22, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o081_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I031 Switch", AFE_CONN81, 31, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I055 Switch", AFE_CONN81_1, 23, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o082_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I032 Switch", AFE_CONN82_1, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I056 Switch", AFE_CONN82_1, 24, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o083_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I033 Switch", AFE_CONN83_1, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I057 Switch", AFE_CONN83_1, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o084_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I034 Switch", AFE_CONN84_1, 2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I058 Switch", AFE_CONN84_1, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o085_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I035 Switch", AFE_CONN85_1, 3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I059 Switch", AFE_CONN85_1, 27, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o086_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I036 Switch", AFE_CONN86_1, 4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I060 Switch", AFE_CONN86_1, 28, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o087_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I037 Switch", AFE_CONN87_1, 5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I061 Switch", AFE_CONN87_1, 29, 1, 0),
+};
+
+static const char * const mt8188_etdm_clk_src_sel_text[] = {
+	"26m",
+	"a1sys_a2sys",
+	"a3sys",
+	"a4sys",
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(etdmout_clk_src_enum,
+	mt8188_etdm_clk_src_sel_text);
+
+static const char * const hdmitx_dptx_mux_map[] = {
+	"Disconnect", "Connect",
+};
+
+static int hdmitx_dptx_mux_map_value[] = {
+	0, 1,
+};
+
+/* HDMI_OUT_MUX */
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(hdmi_out_mux_map_enum,
+				SND_SOC_NOPM,
+				0,
+				1,
+				hdmitx_dptx_mux_map,
+				hdmitx_dptx_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_out_mux_control =
+	SOC_DAPM_ENUM("HDMI_OUT_MUX", hdmi_out_mux_map_enum);
+
+/* DPTX_OUT_MUX */
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(dptx_out_mux_map_enum,
+				SND_SOC_NOPM,
+				0,
+				1,
+				hdmitx_dptx_mux_map,
+				hdmitx_dptx_mux_map_value);
+
+static const struct snd_kcontrol_new dptx_out_mux_control =
+	SOC_DAPM_ENUM("DPTX_OUT_MUX", dptx_out_mux_map_enum);
+
+/* HDMI_CH0_MUX ~ HDMI_CH7_MUX */
+static const char *const afe_conn_hdmi_mux_map[] = {
+	"CH0", "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7",
+};
+
+static int afe_conn_hdmi_mux_map_value[] = {
+	0, 1, 2, 3, 4, 5, 6, 7,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum,
+				AFE_TDMOUT_CONN0,
+				0,
+				0xf,
+				afe_conn_hdmi_mux_map,
+				afe_conn_hdmi_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_TDMOUT_CONN0,
+				4,
+				0xf,
+				afe_conn_hdmi_mux_map,
+				afe_conn_hdmi_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_TDMOUT_CONN0,
+				8,
+				0xf,
+				afe_conn_hdmi_mux_map,
+				afe_conn_hdmi_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_TDMOUT_CONN0,
+				12,
+				0xf,
+				afe_conn_hdmi_mux_map,
+				afe_conn_hdmi_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_TDMOUT_CONN0,
+				16,
+				0xf,
+				afe_conn_hdmi_mux_map,
+				afe_conn_hdmi_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_TDMOUT_CONN0,
+				20,
+				0xf,
+				afe_conn_hdmi_mux_map,
+				afe_conn_hdmi_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_TDMOUT_CONN0,
+				24,
+				0xf,
+				afe_conn_hdmi_mux_map,
+				afe_conn_hdmi_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_TDMOUT_CONN0,
+				28,
+				0xf,
+				afe_conn_hdmi_mux_map,
+				afe_conn_hdmi_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 int mt8188_etdm_clk_src_sel_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	unsigned int source = ucontrol->value.enumerated.item[0];
+	unsigned int val;
+	unsigned int old_val;
+	unsigned int mask;
+	unsigned int reg;
+	unsigned int shift;
+
+	if (source >= e->items)
+		return -EINVAL;
+
+	reg = 0;
+	if (!strcmp(kcontrol->id.name, "ETDM_OUT1_Clock_Source")) {
+		reg = ETDM_OUT1_CON4;
+		mask = ETDM_OUT_CON4_CLOCK_MASK;
+		shift = ETDM_OUT_CON4_CLOCK_SHIFT;
+		val = FIELD_PREP(ETDM_OUT_CON4_CLOCK_MASK, source);
+	} else if (!strcmp(kcontrol->id.name, "ETDM_OUT2_Clock_Source")) {
+		reg = ETDM_OUT2_CON4;
+		mask = ETDM_OUT_CON4_CLOCK_MASK;
+		shift = ETDM_OUT_CON4_CLOCK_SHIFT;
+		val = FIELD_PREP(ETDM_OUT_CON4_CLOCK_MASK, source);
+	} else if (!strcmp(kcontrol->id.name, "ETDM_OUT3_Clock_Source")) {
+		reg = ETDM_OUT3_CON4;
+		mask = ETDM_OUT_CON4_CLOCK_MASK;
+		shift = ETDM_OUT_CON4_CLOCK_SHIFT;
+		val = FIELD_PREP(ETDM_OUT_CON4_CLOCK_MASK, source);
+	} else if (!strcmp(kcontrol->id.name, "ETDM_IN1_Clock_Source")) {
+		reg = ETDM_IN1_CON2;
+		mask = ETDM_IN_CON2_CLOCK_MASK;
+		shift = ETDM_IN_CON2_CLOCK_SHIFT;
+		val = FIELD_PREP(ETDM_IN_CON2_CLOCK_MASK, source);
+	} else if (!strcmp(kcontrol->id.name, "ETDM_IN2_Clock_Source")) {
+		reg = ETDM_IN2_CON2;
+		mask = ETDM_IN_CON2_CLOCK_MASK;
+		shift = ETDM_IN_CON2_CLOCK_SHIFT;
+		val = FIELD_PREP(ETDM_IN_CON2_CLOCK_MASK, source);
+	}
+
+	if (reg) {
+		regmap_read(afe->regmap, reg, &old_val);
+		old_val &= mask;
+		old_val >>= shift;
+
+		if (old_val == val)
+			return 0;
+
+		regmap_update_bits(afe->regmap, reg, mask, val);
+	}
+
+	return 1;
+}
+
+static int mt8188_etdm_clk_src_sel_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	unsigned int value = 0;
+	unsigned int reg = 0;
+	unsigned int mask = 0;
+	unsigned int shift = 0;
+
+	if (!strcmp(kcontrol->id.name, "ETDM_OUT1_Clock_Source")) {
+		reg = ETDM_OUT1_CON4;
+		mask = ETDM_OUT_CON4_CLOCK_MASK;
+		shift = ETDM_OUT_CON4_CLOCK_SHIFT;
+	} else if (!strcmp(kcontrol->id.name, "ETDM_OUT2_Clock_Source")) {
+		reg = ETDM_OUT2_CON4;
+		mask = ETDM_OUT_CON4_CLOCK_MASK;
+		shift = ETDM_OUT_CON4_CLOCK_SHIFT;
+	} else if (!strcmp(kcontrol->id.name, "ETDM_OUT3_Clock_Source")) {
+		reg = ETDM_OUT3_CON4;
+		mask = ETDM_OUT_CON4_CLOCK_MASK;
+		shift = ETDM_OUT_CON4_CLOCK_SHIFT;
+	} else if (!strcmp(kcontrol->id.name, "ETDM_IN1_Clock_Source")) {
+		reg = ETDM_IN1_CON2;
+		mask = ETDM_IN_CON2_CLOCK_MASK;
+		shift = ETDM_IN_CON2_CLOCK_SHIFT;
+	} else if (!strcmp(kcontrol->id.name, "ETDM_IN2_Clock_Source")) {
+		reg = ETDM_IN2_CON2;
+		mask = ETDM_IN_CON2_CLOCK_MASK;
+		shift = ETDM_IN_CON2_CLOCK_SHIFT;
+	}
+
+	if (reg)
+		regmap_read(afe->regmap, reg, &value);
+
+	value &= mask;
+	value >>= shift;
+	ucontrol->value.enumerated.item[0] = value;
+	return 0;
+}
+
+static const struct snd_kcontrol_new mtk_dai_etdm_controls[] = {
+	SOC_ENUM_EXT("ETDM_OUT1_Clock_Source", etdmout_clk_src_enum,
+		     mt8188_etdm_clk_src_sel_get,
+		     mt8188_etdm_clk_src_sel_put),
+	SOC_ENUM_EXT("ETDM_OUT2_Clock_Source", etdmout_clk_src_enum,
+		     mt8188_etdm_clk_src_sel_get,
+		     mt8188_etdm_clk_src_sel_put),
+	SOC_ENUM_EXT("ETDM_OUT3_Clock_Source", etdmout_clk_src_enum,
+		     mt8188_etdm_clk_src_sel_get,
+		     mt8188_etdm_clk_src_sel_put),
+	SOC_ENUM_EXT("ETDM_IN1_Clock_Source", etdmout_clk_src_enum,
+		     mt8188_etdm_clk_src_sel_get,
+		     mt8188_etdm_clk_src_sel_put),
+	SOC_ENUM_EXT("ETDM_IN2_Clock_Source", etdmout_clk_src_enum,
+		     mt8188_etdm_clk_src_sel_get,
+		     mt8188_etdm_clk_src_sel_put),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = {
+	/* eTDM_IN2 */
+	SND_SOC_DAPM_MIXER("I012", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I013", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I014", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I015", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I016", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I017", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I018", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I019", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I188", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I189", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I190", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I191", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I192", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I193", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I194", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I195", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* eTDM_IN1 */
+	SND_SOC_DAPM_MIXER("I072", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I073", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I074", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I075", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I076", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I077", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I078", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I079", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I080", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I081", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I082", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I083", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I084", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I085", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I086", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I087", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* eTDM_OUT2 */
+	SND_SOC_DAPM_MIXER("O048", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o048_mix, ARRAY_SIZE(mtk_dai_etdm_o048_mix)),
+	SND_SOC_DAPM_MIXER("O049", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o049_mix, ARRAY_SIZE(mtk_dai_etdm_o049_mix)),
+	SND_SOC_DAPM_MIXER("O050", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o050_mix, ARRAY_SIZE(mtk_dai_etdm_o050_mix)),
+	SND_SOC_DAPM_MIXER("O051", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o051_mix, ARRAY_SIZE(mtk_dai_etdm_o051_mix)),
+	SND_SOC_DAPM_MIXER("O052", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o052_mix, ARRAY_SIZE(mtk_dai_etdm_o052_mix)),
+	SND_SOC_DAPM_MIXER("O053", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o053_mix, ARRAY_SIZE(mtk_dai_etdm_o053_mix)),
+	SND_SOC_DAPM_MIXER("O054", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o054_mix, ARRAY_SIZE(mtk_dai_etdm_o054_mix)),
+	SND_SOC_DAPM_MIXER("O055", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o055_mix, ARRAY_SIZE(mtk_dai_etdm_o055_mix)),
+	SND_SOC_DAPM_MIXER("O056", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o056_mix, ARRAY_SIZE(mtk_dai_etdm_o056_mix)),
+	SND_SOC_DAPM_MIXER("O057", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o057_mix, ARRAY_SIZE(mtk_dai_etdm_o057_mix)),
+	SND_SOC_DAPM_MIXER("O058", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o058_mix, ARRAY_SIZE(mtk_dai_etdm_o058_mix)),
+	SND_SOC_DAPM_MIXER("O059", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o059_mix, ARRAY_SIZE(mtk_dai_etdm_o059_mix)),
+	SND_SOC_DAPM_MIXER("O060", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o060_mix, ARRAY_SIZE(mtk_dai_etdm_o060_mix)),
+	SND_SOC_DAPM_MIXER("O061", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o061_mix, ARRAY_SIZE(mtk_dai_etdm_o061_mix)),
+	SND_SOC_DAPM_MIXER("O062", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o062_mix, ARRAY_SIZE(mtk_dai_etdm_o062_mix)),
+	SND_SOC_DAPM_MIXER("O063", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o063_mix, ARRAY_SIZE(mtk_dai_etdm_o063_mix)),
+
+	/* eTDM_OUT1 */
+	SND_SOC_DAPM_MIXER("O072", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o072_mix, ARRAY_SIZE(mtk_dai_etdm_o072_mix)),
+	SND_SOC_DAPM_MIXER("O073", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o073_mix, ARRAY_SIZE(mtk_dai_etdm_o073_mix)),
+	SND_SOC_DAPM_MIXER("O074", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o074_mix, ARRAY_SIZE(mtk_dai_etdm_o074_mix)),
+	SND_SOC_DAPM_MIXER("O075", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o075_mix, ARRAY_SIZE(mtk_dai_etdm_o075_mix)),
+	SND_SOC_DAPM_MIXER("O076", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o076_mix, ARRAY_SIZE(mtk_dai_etdm_o076_mix)),
+	SND_SOC_DAPM_MIXER("O077", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o077_mix, ARRAY_SIZE(mtk_dai_etdm_o077_mix)),
+	SND_SOC_DAPM_MIXER("O078", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o078_mix, ARRAY_SIZE(mtk_dai_etdm_o078_mix)),
+	SND_SOC_DAPM_MIXER("O079", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o079_mix, ARRAY_SIZE(mtk_dai_etdm_o079_mix)),
+	SND_SOC_DAPM_MIXER("O080", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o080_mix, ARRAY_SIZE(mtk_dai_etdm_o080_mix)),
+	SND_SOC_DAPM_MIXER("O081", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o081_mix, ARRAY_SIZE(mtk_dai_etdm_o081_mix)),
+	SND_SOC_DAPM_MIXER("O082", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o082_mix, ARRAY_SIZE(mtk_dai_etdm_o082_mix)),
+	SND_SOC_DAPM_MIXER("O083", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o083_mix, ARRAY_SIZE(mtk_dai_etdm_o083_mix)),
+	SND_SOC_DAPM_MIXER("O084", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o084_mix, ARRAY_SIZE(mtk_dai_etdm_o084_mix)),
+	SND_SOC_DAPM_MIXER("O085", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o085_mix, ARRAY_SIZE(mtk_dai_etdm_o085_mix)),
+	SND_SOC_DAPM_MIXER("O086", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o086_mix, ARRAY_SIZE(mtk_dai_etdm_o086_mix)),
+	SND_SOC_DAPM_MIXER("O087", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_etdm_o087_mix, ARRAY_SIZE(mtk_dai_etdm_o087_mix)),
+
+	/* eTDM_OUT3 */
+	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_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_INPUT("ETDM_INPUT"),
+	SND_SOC_DAPM_OUTPUT("ETDM_OUTPUT"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = {
+	{"I012", NULL, "ETDM2 Capture"},
+	{"I013", NULL, "ETDM2 Capture"},
+	{"I014", NULL, "ETDM2 Capture"},
+	{"I015", NULL, "ETDM2 Capture"},
+	{"I016", NULL, "ETDM2 Capture"},
+	{"I017", NULL, "ETDM2 Capture"},
+	{"I018", NULL, "ETDM2 Capture"},
+	{"I019", NULL, "ETDM2 Capture"},
+	{"I188", NULL, "ETDM2 Capture"},
+	{"I189", NULL, "ETDM2 Capture"},
+	{"I190", NULL, "ETDM2 Capture"},
+	{"I191", NULL, "ETDM2 Capture"},
+	{"I192", NULL, "ETDM2 Capture"},
+	{"I193", NULL, "ETDM2 Capture"},
+	{"I194", NULL, "ETDM2 Capture"},
+	{"I195", NULL, "ETDM2 Capture"},
+
+	{"I072", NULL, "ETDM1 Capture"},
+	{"I073", NULL, "ETDM1 Capture"},
+	{"I074", NULL, "ETDM1 Capture"},
+	{"I075", NULL, "ETDM1 Capture"},
+	{"I076", NULL, "ETDM1 Capture"},
+	{"I077", NULL, "ETDM1 Capture"},
+	{"I078", NULL, "ETDM1 Capture"},
+	{"I079", NULL, "ETDM1 Capture"},
+	{"I080", NULL, "ETDM1 Capture"},
+	{"I081", NULL, "ETDM1 Capture"},
+	{"I082", NULL, "ETDM1 Capture"},
+	{"I083", NULL, "ETDM1 Capture"},
+	{"I084", NULL, "ETDM1 Capture"},
+	{"I085", NULL, "ETDM1 Capture"},
+	{"I086", NULL, "ETDM1 Capture"},
+	{"I087", NULL, "ETDM1 Capture"},
+
+	{"UL8", NULL, "ETDM1 Capture"},
+	{"UL3", NULL, "ETDM2 Capture"},
+
+	{"ETDM2 Playback", NULL, "O048"},
+	{"ETDM2 Playback", NULL, "O049"},
+	{"ETDM2 Playback", NULL, "O050"},
+	{"ETDM2 Playback", NULL, "O051"},
+	{"ETDM2 Playback", NULL, "O052"},
+	{"ETDM2 Playback", NULL, "O053"},
+	{"ETDM2 Playback", NULL, "O054"},
+	{"ETDM2 Playback", NULL, "O055"},
+	{"ETDM2 Playback", NULL, "O056"},
+	{"ETDM2 Playback", NULL, "O057"},
+	{"ETDM2 Playback", NULL, "O058"},
+	{"ETDM2 Playback", NULL, "O059"},
+	{"ETDM2 Playback", NULL, "O060"},
+	{"ETDM2 Playback", NULL, "O061"},
+	{"ETDM2 Playback", NULL, "O062"},
+	{"ETDM2 Playback", NULL, "O063"},
+
+	{"ETDM1 Playback", NULL, "O072"},
+	{"ETDM1 Playback", NULL, "O073"},
+	{"ETDM1 Playback", NULL, "O074"},
+	{"ETDM1 Playback", NULL, "O075"},
+	{"ETDM1 Playback", NULL, "O076"},
+	{"ETDM1 Playback", NULL, "O077"},
+	{"ETDM1 Playback", NULL, "O078"},
+	{"ETDM1 Playback", NULL, "O079"},
+	{"ETDM1 Playback", NULL, "O080"},
+	{"ETDM1 Playback", NULL, "O081"},
+	{"ETDM1 Playback", NULL, "O082"},
+	{"ETDM1 Playback", NULL, "O083"},
+	{"ETDM1 Playback", NULL, "O084"},
+	{"ETDM1 Playback", NULL, "O085"},
+	{"ETDM1 Playback", NULL, "O086"},
+	{"ETDM1 Playback", NULL, "O087"},
+
+	{"O048", "I020 Switch", "I020"},
+	{"O049", "I021 Switch", "I021"},
+
+	{"O048", "I022 Switch", "I022"},
+	{"O049", "I023 Switch", "I023"},
+	{"O050", "I024 Switch", "I024"},
+	{"O051", "I025 Switch", "I025"},
+	{"O052", "I026 Switch", "I026"},
+	{"O053", "I027 Switch", "I027"},
+	{"O054", "I028 Switch", "I028"},
+	{"O055", "I029 Switch", "I029"},
+	{"O056", "I030 Switch", "I030"},
+	{"O057", "I031 Switch", "I031"},
+	{"O058", "I032 Switch", "I032"},
+	{"O059", "I033 Switch", "I033"},
+	{"O060", "I034 Switch", "I034"},
+	{"O061", "I035 Switch", "I035"},
+	{"O062", "I036 Switch", "I036"},
+	{"O063", "I037 Switch", "I037"},
+
+	{"O048", "I046 Switch", "I046"},
+	{"O049", "I047 Switch", "I047"},
+	{"O050", "I048 Switch", "I048"},
+	{"O051", "I049 Switch", "I049"},
+	{"O052", "I050 Switch", "I050"},
+	{"O053", "I051 Switch", "I051"},
+	{"O054", "I052 Switch", "I052"},
+	{"O055", "I053 Switch", "I053"},
+	{"O056", "I054 Switch", "I054"},
+	{"O057", "I055 Switch", "I055"},
+	{"O058", "I056 Switch", "I056"},
+	{"O059", "I057 Switch", "I057"},
+	{"O060", "I058 Switch", "I058"},
+	{"O061", "I059 Switch", "I059"},
+	{"O062", "I060 Switch", "I060"},
+	{"O063", "I061 Switch", "I061"},
+
+	{"O048", "I070 Switch", "I070"},
+	{"O049", "I071 Switch", "I071"},
+
+	{"O072", "I020 Switch", "I020"},
+	{"O073", "I021 Switch", "I021"},
+
+	{"O072", "I022 Switch", "I022"},
+	{"O073", "I023 Switch", "I023"},
+	{"O074", "I024 Switch", "I024"},
+	{"O075", "I025 Switch", "I025"},
+	{"O076", "I026 Switch", "I026"},
+	{"O077", "I027 Switch", "I027"},
+	{"O078", "I028 Switch", "I028"},
+	{"O079", "I029 Switch", "I029"},
+	{"O080", "I030 Switch", "I030"},
+	{"O081", "I031 Switch", "I031"},
+	{"O082", "I032 Switch", "I032"},
+	{"O083", "I033 Switch", "I033"},
+	{"O084", "I034 Switch", "I034"},
+	{"O085", "I035 Switch", "I035"},
+	{"O086", "I036 Switch", "I036"},
+	{"O087", "I037 Switch", "I037"},
+
+	{"O072", "I046 Switch", "I046"},
+	{"O073", "I047 Switch", "I047"},
+	{"O074", "I048 Switch", "I048"},
+	{"O075", "I049 Switch", "I049"},
+	{"O076", "I050 Switch", "I050"},
+	{"O077", "I051 Switch", "I051"},
+	{"O078", "I052 Switch", "I052"},
+	{"O079", "I053 Switch", "I053"},
+	{"O080", "I054 Switch", "I054"},
+	{"O081", "I055 Switch", "I055"},
+	{"O082", "I056 Switch", "I056"},
+	{"O083", "I057 Switch", "I057"},
+	{"O084", "I058 Switch", "I058"},
+	{"O085", "I059 Switch", "I059"},
+	{"O086", "I060 Switch", "I060"},
+	{"O087", "I061 Switch", "I061"},
+
+	{"O072", "I070 Switch", "I070"},
+	{"O073", "I071 Switch", "I071"},
+
+	{"HDMI_CH0_MUX", "CH0", "DL10"},
+	{"HDMI_CH0_MUX", "CH1", "DL10"},
+	{"HDMI_CH0_MUX", "CH2", "DL10"},
+	{"HDMI_CH0_MUX", "CH3", "DL10"},
+	{"HDMI_CH0_MUX", "CH4", "DL10"},
+	{"HDMI_CH0_MUX", "CH5", "DL10"},
+	{"HDMI_CH0_MUX", "CH6", "DL10"},
+	{"HDMI_CH0_MUX", "CH7", "DL10"},
+
+	{"HDMI_CH1_MUX", "CH0", "DL10"},
+	{"HDMI_CH1_MUX", "CH1", "DL10"},
+	{"HDMI_CH1_MUX", "CH2", "DL10"},
+	{"HDMI_CH1_MUX", "CH3", "DL10"},
+	{"HDMI_CH1_MUX", "CH4", "DL10"},
+	{"HDMI_CH1_MUX", "CH5", "DL10"},
+	{"HDMI_CH1_MUX", "CH6", "DL10"},
+	{"HDMI_CH1_MUX", "CH7", "DL10"},
+
+	{"HDMI_CH2_MUX", "CH0", "DL10"},
+	{"HDMI_CH2_MUX", "CH1", "DL10"},
+	{"HDMI_CH2_MUX", "CH2", "DL10"},
+	{"HDMI_CH2_MUX", "CH3", "DL10"},
+	{"HDMI_CH2_MUX", "CH4", "DL10"},
+	{"HDMI_CH2_MUX", "CH5", "DL10"},
+	{"HDMI_CH2_MUX", "CH6", "DL10"},
+	{"HDMI_CH2_MUX", "CH7", "DL10"},
+
+	{"HDMI_CH3_MUX", "CH0", "DL10"},
+	{"HDMI_CH3_MUX", "CH1", "DL10"},
+	{"HDMI_CH3_MUX", "CH2", "DL10"},
+	{"HDMI_CH3_MUX", "CH3", "DL10"},
+	{"HDMI_CH3_MUX", "CH4", "DL10"},
+	{"HDMI_CH3_MUX", "CH5", "DL10"},
+	{"HDMI_CH3_MUX", "CH6", "DL10"},
+	{"HDMI_CH3_MUX", "CH7", "DL10"},
+
+	{"HDMI_CH4_MUX", "CH0", "DL10"},
+	{"HDMI_CH4_MUX", "CH1", "DL10"},
+	{"HDMI_CH4_MUX", "CH2", "DL10"},
+	{"HDMI_CH4_MUX", "CH3", "DL10"},
+	{"HDMI_CH4_MUX", "CH4", "DL10"},
+	{"HDMI_CH4_MUX", "CH5", "DL10"},
+	{"HDMI_CH4_MUX", "CH6", "DL10"},
+	{"HDMI_CH4_MUX", "CH7", "DL10"},
+
+	{"HDMI_CH5_MUX", "CH0", "DL10"},
+	{"HDMI_CH5_MUX", "CH1", "DL10"},
+	{"HDMI_CH5_MUX", "CH2", "DL10"},
+	{"HDMI_CH5_MUX", "CH3", "DL10"},
+	{"HDMI_CH5_MUX", "CH4", "DL10"},
+	{"HDMI_CH5_MUX", "CH5", "DL10"},
+	{"HDMI_CH5_MUX", "CH6", "DL10"},
+	{"HDMI_CH5_MUX", "CH7", "DL10"},
+
+	{"HDMI_CH6_MUX", "CH0", "DL10"},
+	{"HDMI_CH6_MUX", "CH1", "DL10"},
+	{"HDMI_CH6_MUX", "CH2", "DL10"},
+	{"HDMI_CH6_MUX", "CH3", "DL10"},
+	{"HDMI_CH6_MUX", "CH4", "DL10"},
+	{"HDMI_CH6_MUX", "CH5", "DL10"},
+	{"HDMI_CH6_MUX", "CH6", "DL10"},
+	{"HDMI_CH6_MUX", "CH7", "DL10"},
+
+	{"HDMI_CH7_MUX", "CH0", "DL10"},
+	{"HDMI_CH7_MUX", "CH1", "DL10"},
+	{"HDMI_CH7_MUX", "CH2", "DL10"},
+	{"HDMI_CH7_MUX", "CH3", "DL10"},
+	{"HDMI_CH7_MUX", "CH4", "DL10"},
+	{"HDMI_CH7_MUX", "CH5", "DL10"},
+	{"HDMI_CH7_MUX", "CH6", "DL10"},
+	{"HDMI_CH7_MUX", "CH7", "DL10"},
+
+	{"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"},
+
+	{"ETDM3 Playback", NULL, "HDMI_OUT_MUX"},
+	{"DPTX Playback", NULL, "DPTX_OUT_MUX"},
+
+	{"ETDM_OUTPUT", NULL, "DPTX Playback"},
+	{"ETDM_OUTPUT", NULL, "ETDM1 Playback"},
+	{"ETDM_OUTPUT", NULL, "ETDM2 Playback"},
+	{"ETDM_OUTPUT", NULL, "ETDM3 Playback"},
+	{"ETDM1 Capture", NULL, "ETDM_INPUT"},
+	{"ETDM2 Capture", NULL, "ETDM_INPUT"},
+};
+
+static int mt8188_afe_enable_etdm(struct mtk_base_afe *afe, int dai_id)
+{
+	int ret = 0;
+	struct etdm_con_reg etdm_reg;
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+	unsigned long flags;
+
+	if (!is_valid_etdm_dai(dai_id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai_id];
+
+	dev_dbg(afe->dev, "%s [%d]%d\n", __func__, dai_id, etdm_data->en_ref_cnt);
+	spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+	etdm_data->en_ref_cnt++;
+	if (etdm_data->en_ref_cnt == 1) {
+		ret = get_etdm_reg(dai_id, &etdm_reg);
+		if (ret < 0)
+			goto out;
+
+		regmap_set_bits(afe->regmap, etdm_reg.con0, ETDM_CON0_EN);
+	}
+
+out:
+	spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+	return ret;
+}
+
+static int mt8188_afe_disable_etdm(struct mtk_base_afe *afe, int dai_id)
+{
+	int ret = 0;
+	struct etdm_con_reg etdm_reg;
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+	unsigned long flags;
+
+	if (!is_valid_etdm_dai(dai_id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai_id];
+
+	dev_dbg(afe->dev, "%s [%d]%d\n", __func__, dai_id, etdm_data->en_ref_cnt);
+	spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+	if (etdm_data->en_ref_cnt > 0) {
+		etdm_data->en_ref_cnt--;
+		if (etdm_data->en_ref_cnt == 0) {
+			ret = get_etdm_reg(dai_id, &etdm_reg);
+			if (ret < 0)
+				goto out;
+			regmap_clear_bits(afe->regmap, etdm_reg.con0,
+					  ETDM_CON0_EN);
+		}
+	}
+
+out:
+	spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+	return ret;
+}
+
+static int etdm_cowork_slv_sel(int id, int slave_mode)
+{
+	if (slave_mode) {
+		switch (id) {
+		case MT8188_AFE_IO_ETDM1_IN:
+			return COWORK_ETDM_IN1_S;
+		case MT8188_AFE_IO_ETDM2_IN:
+			return COWORK_ETDM_IN2_S;
+		case MT8188_AFE_IO_ETDM1_OUT:
+			return COWORK_ETDM_OUT1_S;
+		case MT8188_AFE_IO_ETDM2_OUT:
+			return COWORK_ETDM_OUT2_S;
+		case MT8188_AFE_IO_ETDM3_OUT:
+			return COWORK_ETDM_OUT3_S;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		switch (id) {
+		case MT8188_AFE_IO_ETDM1_IN:
+			return COWORK_ETDM_IN1_M;
+		case MT8188_AFE_IO_ETDM2_IN:
+			return COWORK_ETDM_IN2_M;
+		case MT8188_AFE_IO_ETDM1_OUT:
+			return COWORK_ETDM_OUT1_M;
+		case MT8188_AFE_IO_ETDM2_OUT:
+			return COWORK_ETDM_OUT2_M;
+		case MT8188_AFE_IO_ETDM3_OUT:
+			return COWORK_ETDM_OUT3_M;
+		default:
+			return -EINVAL;
+		}
+	}
+}
+
+static int etdm_cowork_sync_sel(int id)
+{
+	switch (id) {
+	case MT8188_AFE_IO_ETDM1_IN:
+		return ETDM_SYNC_FROM_IN1;
+	case MT8188_AFE_IO_ETDM2_IN:
+		return ETDM_SYNC_FROM_IN2;
+	case MT8188_AFE_IO_ETDM1_OUT:
+		return ETDM_SYNC_FROM_OUT1;
+	case MT8188_AFE_IO_ETDM2_OUT:
+		return ETDM_SYNC_FROM_OUT2;
+	case MT8188_AFE_IO_ETDM3_OUT:
+		return ETDM_SYNC_FROM_OUT3;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt8188_etdm_sync_mode_slv(struct mtk_base_afe *afe, int dai_id)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+	unsigned int reg = 0;
+	unsigned int mask;
+	unsigned int val;
+	int cowork_source_sel;
+
+	if (!is_valid_etdm_dai(dai_id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai_id];
+
+	cowork_source_sel = etdm_cowork_slv_sel(etdm_data->cowork_source_id,
+						true);
+	if (cowork_source_sel < 0)
+		return cowork_source_sel;
+
+	switch (dai_id) {
+	case MT8188_AFE_IO_ETDM1_IN:
+		reg = ETDM_COWORK_CON1;
+		mask = ETDM_IN1_SLAVE_SEL_MASK;
+		val = FIELD_PREP(ETDM_IN1_SLAVE_SEL_MASK, cowork_source_sel);
+		break;
+	case MT8188_AFE_IO_ETDM2_IN:
+		reg = ETDM_COWORK_CON2;
+		mask = ETDM_IN2_SLAVE_SEL_MASK;
+		val = FIELD_PREP(ETDM_IN2_SLAVE_SEL_MASK, cowork_source_sel);
+		break;
+	case MT8188_AFE_IO_ETDM1_OUT:
+		reg = ETDM_COWORK_CON0;
+		mask = ETDM_OUT1_SLAVE_SEL_MASK;
+		val = FIELD_PREP(ETDM_OUT1_SLAVE_SEL_MASK, cowork_source_sel);
+		break;
+	case MT8188_AFE_IO_ETDM2_OUT:
+		reg = ETDM_COWORK_CON2;
+		mask = ETDM_OUT2_SLAVE_SEL_MASK;
+		val = FIELD_PREP(ETDM_OUT2_SLAVE_SEL_MASK, cowork_source_sel);
+		break;
+	case MT8188_AFE_IO_ETDM3_OUT:
+		reg = ETDM_COWORK_CON2;
+		mask = ETDM_OUT3_SLAVE_SEL_MASK;
+		val = FIELD_PREP(ETDM_OUT3_SLAVE_SEL_MASK, cowork_source_sel);
+		break;
+	default:
+		return 0;
+	}
+
+	regmap_update_bits(afe->regmap, reg, mask, val);
+
+	return 0;
+}
+
+static int mt8188_etdm_sync_mode_mst(struct mtk_base_afe *afe, int dai_id)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+	struct etdm_con_reg etdm_reg;
+	unsigned int reg = 0;
+	unsigned int mask;
+	unsigned int val;
+	int cowork_source_sel;
+	int ret;
+
+	if (!is_valid_etdm_dai(dai_id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai_id];
+
+	cowork_source_sel = etdm_cowork_sync_sel(etdm_data->cowork_source_id);
+	if (cowork_source_sel < 0)
+		return cowork_source_sel;
+
+	switch (dai_id) {
+	case MT8188_AFE_IO_ETDM1_IN:
+		reg = ETDM_COWORK_CON1;
+		mask = ETDM_IN1_SYNC_SEL_MASK;
+		val = FIELD_PREP(ETDM_IN1_SYNC_SEL_MASK, cowork_source_sel);
+		break;
+	case MT8188_AFE_IO_ETDM2_IN:
+		reg = ETDM_COWORK_CON2;
+		mask = ETDM_IN2_SYNC_SEL_MASK;
+		val = FIELD_PREP(ETDM_IN2_SYNC_SEL_MASK, cowork_source_sel);
+		break;
+	case MT8188_AFE_IO_ETDM1_OUT:
+		reg = ETDM_COWORK_CON0;
+		mask = ETDM_OUT1_SYNC_SEL_MASK;
+		val = FIELD_PREP(ETDM_OUT1_SYNC_SEL_MASK, cowork_source_sel);
+		break;
+	case MT8188_AFE_IO_ETDM2_OUT:
+		reg = ETDM_COWORK_CON2;
+		mask = ETDM_OUT2_SYNC_SEL_MASK;
+		val = FIELD_PREP(ETDM_OUT2_SYNC_SEL_MASK, cowork_source_sel);
+		break;
+	case MT8188_AFE_IO_ETDM3_OUT:
+		reg = ETDM_COWORK_CON2;
+		mask = ETDM_OUT3_SYNC_SEL_MASK;
+		val = FIELD_PREP(ETDM_OUT3_SYNC_SEL_MASK, cowork_source_sel);
+		break;
+	default:
+		return 0;
+	}
+
+	ret = get_etdm_reg(dai_id, &etdm_reg);
+	if (ret < 0)
+		return ret;
+
+	regmap_update_bits(afe->regmap, reg, mask, val);
+
+	regmap_set_bits(afe->regmap, etdm_reg.con0, ETDM_CON0_SYNC_MODE);
+
+	return 0;
+}
+
+static int mt8188_etdm_sync_mode_configure(struct mtk_base_afe *afe, int dai_id)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+
+	if (!is_valid_etdm_dai(dai_id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai_id];
+
+	if (etdm_data->cowork_source_id == COWORK_ETDM_NONE)
+		return 0;
+
+	if (etdm_data->slave_mode)
+		mt8188_etdm_sync_mode_slv(afe, dai_id);
+	else
+		mt8188_etdm_sync_mode_mst(afe, dai_id);
+
+	return 0;
+}
+
+static int mtk_dai_etdm_get_cg_id_by_dai_id(int dai_id)
+{
+	int cg_id = -1;
+
+	switch (dai_id) {
+	case MT8188_AFE_IO_DPTX:
+		cg_id = MT8188_CLK_AUD_HDMI_OUT;
+		break;
+	case MT8188_AFE_IO_ETDM1_IN:
+		cg_id = MT8188_CLK_AUD_TDM_IN;
+		break;
+	case MT8188_AFE_IO_ETDM2_IN:
+		cg_id = MT8188_CLK_AUD_I2SIN;
+		break;
+	case MT8188_AFE_IO_ETDM1_OUT:
+		cg_id = MT8188_CLK_AUD_TDM_OUT;
+		break;
+	case MT8188_AFE_IO_ETDM2_OUT:
+		cg_id = MT8188_CLK_AUD_I2S_OUT;
+		break;
+	case MT8188_AFE_IO_ETDM3_OUT:
+		cg_id = MT8188_CLK_AUD_HDMI_OUT;
+		break;
+	default:
+		break;
+	}
+
+	return cg_id;
+}
+
+static int mtk_dai_etdm_get_clk_id_by_dai_id(int dai_id)
+{
+	int clk_id = -1;
+
+	switch (dai_id) {
+	case MT8188_AFE_IO_DPTX:
+		clk_id = MT8188_CLK_TOP_DPTX_M_SEL;
+		break;
+	case MT8188_AFE_IO_ETDM1_IN:
+		clk_id = MT8188_CLK_TOP_I2SI1_M_SEL;
+		break;
+	case MT8188_AFE_IO_ETDM2_IN:
+		clk_id = MT8188_CLK_TOP_I2SI2_M_SEL;
+		break;
+	case MT8188_AFE_IO_ETDM1_OUT:
+		clk_id = MT8188_CLK_TOP_I2SO1_M_SEL;
+		break;
+	case MT8188_AFE_IO_ETDM2_OUT:
+		clk_id = MT8188_CLK_TOP_I2SO2_M_SEL;
+		break;
+	case MT8188_AFE_IO_ETDM3_OUT:
+	default:
+		break;
+	}
+
+	return clk_id;
+}
+
+static int mtk_dai_etdm_get_clkdiv_id_by_dai_id(int dai_id)
+{
+	int clk_id = -1;
+
+	switch (dai_id) {
+	case MT8188_AFE_IO_DPTX:
+		clk_id = MT8188_CLK_TOP_APLL12_DIV9;
+		break;
+	case MT8188_AFE_IO_ETDM1_IN:
+		clk_id = MT8188_CLK_TOP_APLL12_DIV0;
+		break;
+	case MT8188_AFE_IO_ETDM2_IN:
+		clk_id = MT8188_CLK_TOP_APLL12_DIV1;
+		break;
+	case MT8188_AFE_IO_ETDM1_OUT:
+		clk_id = MT8188_CLK_TOP_APLL12_DIV2;
+		break;
+	case MT8188_AFE_IO_ETDM2_OUT:
+		clk_id = MT8188_CLK_TOP_APLL12_DIV3;
+		break;
+	case MT8188_AFE_IO_ETDM3_OUT:
+	default:
+		break;
+	}
+
+	return clk_id;
+}
+
+static int mtk_dai_etdm_enable_mclk(struct mtk_base_afe *afe, int dai_id)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	int clkdiv_id = mtk_dai_etdm_get_clkdiv_id_by_dai_id(dai_id);
+
+	if (clkdiv_id < 0)
+		return -EINVAL;
+
+	mt8188_afe_enable_clk(afe, afe_priv->clk[clkdiv_id]);
+
+	return 0;
+}
+
+static int mtk_dai_etdm_disable_mclk(struct mtk_base_afe *afe, int dai_id)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	int clkdiv_id = mtk_dai_etdm_get_clkdiv_id_by_dai_id(dai_id);
+
+	if (clkdiv_id < 0)
+		return -EINVAL;
+
+	mt8188_afe_disable_clk(afe, afe_priv->clk[clkdiv_id]);
+
+	return 0;
+}
+
+/* dai ops */
+static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *mst_etdm_data;
+	int cg_id;
+	int mst_dai_id;
+	int slv_dai_id;
+	int i;
+
+	if (is_cowork_mode(dai)) {
+		mst_dai_id = get_etdm_cowork_master_id(dai);
+		if (!is_valid_etdm_dai(mst_dai_id))
+			return -EINVAL;
+		mtk_dai_etdm_enable_mclk(afe, mst_dai_id);
+
+		cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(mst_dai_id);
+		if (cg_id >= 0)
+			mt8188_afe_enable_clk(afe, afe_priv->clk[cg_id]);
+
+		mst_etdm_data = afe_priv->dai_priv[mst_dai_id];
+
+		for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) {
+			slv_dai_id = mst_etdm_data->cowork_slv_id[i];
+			cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(slv_dai_id);
+			if (cg_id >= 0)
+				mt8188_afe_enable_clk(afe,
+						      afe_priv->clk[cg_id]);
+		}
+	} else {
+		mtk_dai_etdm_enable_mclk(afe, dai->id);
+
+		cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id);
+		if (cg_id >= 0)
+			mt8188_afe_enable_clk(afe, afe_priv->clk[cg_id]);
+	}
+
+	return 0;
+}
+
+static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *mst_etdm_data = afe_priv->dai_priv[dai->id];
+	int cg_id;
+	int mst_dai_id;
+	int slv_dai_id;
+	int i;
+	int ret = 0;
+
+	dev_dbg(afe->dev, "%s(), dai id %d, prepared %d\n", __func__, dai->id,
+		mst_etdm_data->is_prepared);
+
+	if (mst_etdm_data->is_prepared) {
+		mst_etdm_data->is_prepared = false;
+
+		if (is_cowork_mode(dai)) {
+			mst_dai_id = get_etdm_cowork_master_id(dai);
+			if (!is_valid_etdm_dai(mst_dai_id))
+				return;
+			mst_etdm_data = afe_priv->dai_priv[mst_dai_id];
+
+			ret |= mt8188_afe_disable_etdm(afe, mst_dai_id);
+			for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) {
+				slv_dai_id = mst_etdm_data->cowork_slv_id[i];
+				ret |= mt8188_afe_disable_etdm(afe, slv_dai_id);
+			}
+		} else {
+			ret = mt8188_afe_disable_etdm(afe, dai->id);
+		}
+
+		if (ret)
+			dev_dbg(afe->dev, "%s disable failed\n", __func__);
+	}
+
+	if (is_cowork_mode(dai)) {
+		mst_dai_id = get_etdm_cowork_master_id(dai);
+		if (!is_valid_etdm_dai(mst_dai_id))
+			return;
+		cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(mst_dai_id);
+		if (cg_id >= 0)
+			mt8188_afe_disable_clk(afe, afe_priv->clk[cg_id]);
+
+		mst_etdm_data = afe_priv->dai_priv[mst_dai_id];
+		for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) {
+			slv_dai_id = mst_etdm_data->cowork_slv_id[i];
+			cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(slv_dai_id);
+			if (cg_id >= 0)
+				mt8188_afe_disable_clk(afe,
+						       afe_priv->clk[cg_id]);
+		}
+		mtk_dai_etdm_disable_mclk(afe, mst_dai_id);
+	} else {
+		cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id);
+		if (cg_id >= 0)
+			mt8188_afe_disable_clk(afe, afe_priv->clk[cg_id]);
+
+		mtk_dai_etdm_disable_mclk(afe, dai->id);
+	}
+}
+
+static int mtk_dai_etdm_fifo_mode(struct mtk_base_afe *afe,
+				  int dai_id, unsigned int rate)
+{
+	unsigned int mode = 0;
+	unsigned int reg = 0;
+	unsigned int val = 0;
+	unsigned int mask = (ETDM_IN_AFIFO_MODE_MASK | ETDM_IN_USE_AFIFO);
+
+	if (rate != 0)
+		mode = mt8188_afe_fs_timing(rate);
+
+	switch (dai_id) {
+	case MT8188_AFE_IO_ETDM1_IN:
+		reg = ETDM_IN1_AFIFO_CON;
+		if (rate == 0)
+			mode = MT8188_ETDM_IN1_1X_EN;
+		break;
+	case MT8188_AFE_IO_ETDM2_IN:
+		reg = ETDM_IN2_AFIFO_CON;
+		if (rate == 0)
+			mode = MT8188_ETDM_IN2_1X_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val = (mode | ETDM_IN_USE_AFIFO);
+
+	regmap_update_bits(afe->regmap, reg, mask, val);
+	return 0;
+}
+
+static int mtk_dai_etdm_in_configure(struct mtk_base_afe *afe,
+				     unsigned int rate,
+				     unsigned int channels,
+				     int dai_id)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id];
+	struct etdm_con_reg etdm_reg;
+	bool slave_mode = etdm_data->slave_mode;
+	unsigned int data_mode = etdm_data->data_mode;
+	unsigned int lrck_width = etdm_data->lrck_width;
+	unsigned int val = 0;
+	unsigned int mask = 0;
+	int i;
+	int ret;
+
+	dev_dbg(afe->dev, "%s rate %u channels %u, id %d\n",
+		__func__, rate, channels, dai_id);
+
+	ret = get_etdm_reg(dai_id, &etdm_reg);
+	if (ret < 0)
+		return ret;
+
+	if (etdm_data->cowork_source_id != COWORK_ETDM_NONE)
+		slave_mode = true;
+
+	/* afifo */
+	if (slave_mode)
+		mtk_dai_etdm_fifo_mode(afe, dai_id, 0);
+	else
+		mtk_dai_etdm_fifo_mode(afe, dai_id, rate);
+
+	/* con1 */
+	if (lrck_width > 0) {
+		mask |= (ETDM_IN_CON1_LRCK_AUTO_MODE |
+			ETDM_IN_CON1_LRCK_WIDTH_MASK);
+		val |= FIELD_PREP(ETDM_IN_CON1_LRCK_WIDTH_MASK, lrck_width - 1);
+	}
+	regmap_update_bits(afe->regmap, etdm_reg.con1, mask, val);
+
+	mask = 0;
+	val = 0;
+
+	/* con2 */
+	if (!slave_mode) {
+		mask |= ETDM_IN_CON2_UPDATE_GAP_MASK;
+		if (rate == 352800 || rate == 384000)
+			val |= FIELD_PREP(ETDM_IN_CON2_UPDATE_GAP_MASK, 4);
+		else
+			val |= FIELD_PREP(ETDM_IN_CON2_UPDATE_GAP_MASK, 3);
+	}
+	mask |= (ETDM_IN_CON2_MULTI_IP_2CH_MODE |
+		ETDM_IN_CON2_MULTI_IP_TOTAL_CH_MASK);
+	if (data_mode == MTK_DAI_ETDM_DATA_MULTI_PIN) {
+		val |= ETDM_IN_CON2_MULTI_IP_2CH_MODE |
+		       FIELD_PREP(ETDM_IN_CON2_MULTI_IP_TOTAL_CH_MASK, channels - 1);
+	}
+	regmap_update_bits(afe->regmap, etdm_reg.con2, mask, val);
+
+	mask = 0;
+	val = 0;
+
+	/* con3 */
+	mask |= ETDM_IN_CON3_DISABLE_OUT_MASK;
+	for (i = 0; i < channels; i += 2) {
+		if (etdm_data->in_disable_ch[i] &&
+		    etdm_data->in_disable_ch[i + 1])
+			val |= ETDM_IN_CON3_DISABLE_OUT(i >> 1);
+	}
+	if (!slave_mode) {
+		mask |= ETDM_IN_CON3_FS_MASK;
+		val |= FIELD_PREP(ETDM_IN_CON3_FS_MASK, get_etdm_fs_timing(rate));
+	}
+	regmap_update_bits(afe->regmap, etdm_reg.con3, mask, val);
+
+	mask = 0;
+	val = 0;
+
+	/* con4 */
+	mask |= (ETDM_IN_CON4_MASTER_LRCK_INV | ETDM_IN_CON4_MASTER_BCK_INV |
+		ETDM_IN_CON4_SLAVE_LRCK_INV | ETDM_IN_CON4_SLAVE_BCK_INV);
+	if (slave_mode) {
+		if (etdm_data->lrck_inv)
+			val |= ETDM_IN_CON4_SLAVE_LRCK_INV;
+		if (etdm_data->bck_inv)
+			val |= ETDM_IN_CON4_SLAVE_BCK_INV;
+	} else {
+		if (etdm_data->lrck_inv)
+			val |= ETDM_IN_CON4_MASTER_LRCK_INV;
+		if (etdm_data->bck_inv)
+			val |= ETDM_IN_CON4_MASTER_BCK_INV;
+	}
+	regmap_update_bits(afe->regmap, etdm_reg.con4, mask, val);
+
+	mask = 0;
+	val = 0;
+
+	/* con5 */
+	mask |= ETDM_IN_CON5_LR_SWAP_MASK;
+	mask |= ETDM_IN_CON5_ENABLE_ODD_MASK;
+	for (i = 0; i < channels; i += 2) {
+		if (etdm_data->in_disable_ch[i] &&
+		    !etdm_data->in_disable_ch[i + 1]) {
+			val |= ETDM_IN_CON5_LR_SWAP(i >> 1);
+			val |= ETDM_IN_CON5_ENABLE_ODD(i >> 1);
+		} else if (!etdm_data->in_disable_ch[i] &&
+			   etdm_data->in_disable_ch[i + 1]) {
+			val |= ETDM_IN_CON5_ENABLE_ODD(i >> 1);
+		}
+	}
+	regmap_update_bits(afe->regmap, etdm_reg.con5, mask, val);
+	return 0;
+}
+
+static int mtk_dai_etdm_out_configure(struct mtk_base_afe *afe,
+				      unsigned int rate,
+				      unsigned int channels,
+				      int dai_id)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id];
+	struct etdm_con_reg etdm_reg;
+	bool slave_mode = etdm_data->slave_mode;
+	unsigned int lrck_width = etdm_data->lrck_width;
+	unsigned int val = 0;
+	unsigned int mask = 0;
+	int ret;
+	int fs = 0;
+
+	dev_dbg(afe->dev, "%s rate %u channels %u, id %d\n",
+		__func__, rate, channels, dai_id);
+
+	ret = get_etdm_reg(dai_id, &etdm_reg);
+	if (ret < 0)
+		return ret;
+
+	if (etdm_data->cowork_source_id != COWORK_ETDM_NONE)
+		slave_mode = true;
+
+	/* con0 */
+	mask = ETDM_OUT_CON0_RELATCH_DOMAIN_MASK;
+	val = FIELD_PREP(ETDM_OUT_CON0_RELATCH_DOMAIN_MASK,
+			 ETDM_RELATCH_TIMING_A1A2SYS);
+	regmap_update_bits(afe->regmap, etdm_reg.con0, mask, val);
+
+	mask = 0;
+	val = 0;
+
+	/* con1 */
+	if (lrck_width > 0) {
+		mask |= (ETDM_OUT_CON1_LRCK_AUTO_MODE |
+			ETDM_OUT_CON1_LRCK_WIDTH_MASK);
+		val |= FIELD_PREP(ETDM_OUT_CON1_LRCK_WIDTH_MASK, lrck_width - 1);
+	}
+	regmap_update_bits(afe->regmap, etdm_reg.con1, mask, val);
+
+	mask = 0;
+	val = 0;
+
+	if (!slave_mode) {
+		/* con4 */
+		mask |= ETDM_OUT_CON4_FS_MASK;
+		val |= FIELD_PREP(ETDM_OUT_CON4_FS_MASK, get_etdm_fs_timing(rate));
+	}
+
+	mask |= ETDM_OUT_CON4_RELATCH_EN_MASK;
+	if (dai_id == MT8188_AFE_IO_ETDM1_OUT)
+		fs = MT8188_ETDM_OUT1_1X_EN;
+	else if (dai_id == MT8188_AFE_IO_ETDM2_OUT)
+		fs = MT8188_ETDM_OUT2_1X_EN;
+
+	val |= FIELD_PREP(ETDM_OUT_CON4_RELATCH_EN_MASK, fs);
+
+	regmap_update_bits(afe->regmap, etdm_reg.con4, mask, val);
+
+	mask = 0;
+	val = 0;
+
+	/* con5 */
+	mask |= (ETDM_OUT_CON5_MASTER_LRCK_INV | ETDM_OUT_CON5_MASTER_BCK_INV |
+		ETDM_OUT_CON5_SLAVE_LRCK_INV | ETDM_OUT_CON5_SLAVE_BCK_INV);
+	if (slave_mode) {
+		if (etdm_data->lrck_inv)
+			val |= ETDM_OUT_CON5_SLAVE_LRCK_INV;
+		if (etdm_data->bck_inv)
+			val |= ETDM_OUT_CON5_SLAVE_BCK_INV;
+	} else {
+		if (etdm_data->lrck_inv)
+			val |= ETDM_OUT_CON5_MASTER_LRCK_INV;
+		if (etdm_data->bck_inv)
+			val |= ETDM_OUT_CON5_MASTER_BCK_INV;
+	}
+	regmap_update_bits(afe->regmap, etdm_reg.con5, mask, val);
+
+	return 0;
+}
+
+static int mtk_dai_etdm_mclk_configure(struct mtk_base_afe *afe, int dai_id)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id];
+	int clk_id = mtk_dai_etdm_get_clk_id_by_dai_id(dai_id);
+	int clkdiv_id = mtk_dai_etdm_get_clkdiv_id_by_dai_id(dai_id);
+	int apll;
+	int apll_clk_id;
+	struct etdm_con_reg etdm_reg;
+	int ret = 0;
+
+	if (clk_id < 0 || clkdiv_id < 0)
+		return 0;
+
+	ret = get_etdm_reg(dai_id, &etdm_reg);
+	if (ret < 0)
+		return ret;
+
+	if (etdm_data->mclk_dir == SND_SOC_CLOCK_OUT)
+		regmap_set_bits(afe->regmap, etdm_reg.con1,
+				ETDM_CON1_MCLK_OUTPUT);
+	else
+		regmap_clear_bits(afe->regmap, etdm_reg.con1,
+				  ETDM_CON1_MCLK_OUTPUT);
+
+	if (etdm_data->mclk_freq) {
+		apll = etdm_data->mclk_apll;
+		apll_clk_id = mt8188_afe_get_mclk_source_clk_id(apll);
+		if (apll_clk_id < 0)
+			return apll_clk_id;
+
+		/* select apll */
+		ret = mt8188_afe_set_clk_parent(afe, afe_priv->clk[clk_id],
+						afe_priv->clk[apll_clk_id]);
+		if (ret)
+			return ret;
+
+		/* set rate */
+		ret = mt8188_afe_set_clk_rate(afe, afe_priv->clk[clkdiv_id],
+					      etdm_data->mclk_freq);
+	} else {
+		if (etdm_data->mclk_dir == SND_SOC_CLOCK_OUT)
+			dev_dbg(afe->dev, "%s mclk freq = 0\n", __func__);
+	}
+
+	return ret;
+}
+
+static int mtk_dai_etdm_configure(struct mtk_base_afe *afe,
+				  unsigned int rate,
+				  unsigned int channels,
+				  unsigned int bit_width,
+				  int dai_id)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id];
+	struct etdm_con_reg etdm_reg;
+	bool slave_mode = etdm_data->slave_mode;
+	unsigned int etdm_channels;
+	unsigned int val = 0;
+	unsigned int mask = 0;
+	unsigned int bck;
+	unsigned int wlen = get_etdm_wlen(bit_width);
+	int ret;
+
+	ret = get_etdm_reg(dai_id, &etdm_reg);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(afe->dev, "%s fmt %u data %u lrck %d-%u bck %d, clock %u slv %u\n",
+		__func__, etdm_data->format, etdm_data->data_mode,
+		etdm_data->lrck_inv, etdm_data->lrck_width, etdm_data->bck_inv,
+		etdm_data->clock_mode, etdm_data->slave_mode);
+	dev_dbg(afe->dev, "%s rate %u channels %u bitwidth %u, id %d\n",
+		__func__, rate, channels, bit_width, dai_id);
+
+	etdm_channels = (etdm_data->data_mode == MTK_DAI_ETDM_DATA_ONE_PIN) ?
+			get_etdm_ch_fixup(channels) : 2;
+
+	bck = rate * etdm_channels * wlen;
+	if (bck > MT8188_ETDM_NORMAL_MAX_BCK_RATE) {
+		dev_info(afe->dev, "%s bck rate %u not support\n",
+			 __func__, bck);
+		return -EINVAL;
+	}
+
+	/* con0 */
+	mask |= ETDM_CON0_BIT_LEN_MASK;
+	val |= FIELD_PREP(ETDM_CON0_BIT_LEN_MASK, bit_width - 1);
+	mask |= ETDM_CON0_WORD_LEN_MASK;
+	val |= FIELD_PREP(ETDM_CON0_WORD_LEN_MASK, wlen - 1);
+	mask |= ETDM_CON0_FORMAT_MASK;
+	val |= FIELD_PREP(ETDM_CON0_FORMAT_MASK, etdm_data->format);
+	mask |= ETDM_CON0_CH_NUM_MASK;
+	val |= FIELD_PREP(ETDM_CON0_CH_NUM_MASK, etdm_channels - 1);
+
+	mask |= ETDM_CON0_SLAVE_MODE;
+	if (slave_mode) {
+		if (dai_id == MT8188_AFE_IO_ETDM1_OUT) {
+			dev_info(afe->dev, "%s id %d only support master mode\n",
+				 __func__, dai_id);
+			return -EINVAL;
+		}
+		val |= ETDM_CON0_SLAVE_MODE;
+	}
+	regmap_update_bits(afe->regmap, etdm_reg.con0, mask, val);
+
+	if (get_etdm_dir(dai_id) == ETDM_IN)
+		mtk_dai_etdm_in_configure(afe, rate, channels, dai_id);
+	else
+		mtk_dai_etdm_out_configure(afe, rate, channels, dai_id);
+
+	return 0;
+}
+
+static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	int ret = 0;
+	unsigned int rate = params_rate(params);
+	unsigned int bit_width = params_width(params);
+	unsigned int channels = params_channels(params);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *mst_etdm_data;
+	int mst_dai_id;
+	int slv_dai_id;
+	int i;
+
+	dev_dbg(afe->dev, "%s '%s' period %u-%u\n",
+		__func__, snd_pcm_stream_str(substream),
+		params_period_size(params), params_periods(params));
+
+	if (is_cowork_mode(dai)) {
+		mst_dai_id = get_etdm_cowork_master_id(dai);
+
+		ret = mtk_dai_etdm_mclk_configure(afe, mst_dai_id);
+		if (ret)
+			return ret;
+
+		ret = mtk_dai_etdm_configure(afe, rate, channels,
+					     bit_width, mst_dai_id);
+		if (ret)
+			return ret;
+
+		mst_etdm_data = afe_priv->dai_priv[mst_dai_id];
+		for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) {
+			slv_dai_id = mst_etdm_data->cowork_slv_id[i];
+			ret = mtk_dai_etdm_configure(afe, rate, channels,
+						     bit_width, slv_dai_id);
+			if (ret)
+				return ret;
+
+			ret = mt8188_etdm_sync_mode_configure(afe, slv_dai_id);
+			if (ret)
+				return ret;
+		}
+	} else {
+		ret = mtk_dai_etdm_mclk_configure(afe, dai->id);
+		if (ret)
+			return ret;
+
+		ret = mtk_dai_etdm_configure(afe, rate, channels,
+					     bit_width, dai->id);
+	}
+
+	return ret;
+}
+
+static int mtk_dai_etdm_prepare(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *mst_etdm_data;
+	int mst_dai_id;
+	int slv_dai_id;
+	int i;
+	int ret = 0;
+
+	if (!is_valid_etdm_dai(dai->id))
+		return -EINVAL;
+	mst_etdm_data = afe_priv->dai_priv[dai->id];
+
+	dev_dbg(afe->dev, "%s(), dai id %d, prepared %d\n", __func__, dai->id,
+		mst_etdm_data->is_prepared);
+
+	if (mst_etdm_data->is_prepared)
+		return 0;
+
+	mst_etdm_data->is_prepared = true;
+
+	if (is_cowork_mode(dai)) {
+		mst_dai_id = get_etdm_cowork_master_id(dai);
+		mst_etdm_data = afe_priv->dai_priv[mst_dai_id];
+
+		for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) {
+			slv_dai_id = mst_etdm_data->cowork_slv_id[i];
+			ret |= mt8188_afe_enable_etdm(afe, slv_dai_id);
+		}
+
+		ret |= mt8188_afe_enable_etdm(afe, mst_dai_id);
+	} else {
+		ret = mt8188_afe_enable_etdm(afe, dai->id);
+	}
+
+	return ret;
+}
+
+static int mtk_dai_etdm_cal_mclk(struct mtk_base_afe *afe, int freq, int dai_id)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+	int apll;
+	int apll_rate;
+
+	if (!is_valid_etdm_dai(dai_id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai_id];
+
+	if (freq == 0) {
+		etdm_data->mclk_freq = freq;
+		return 0;
+	}
+
+	if (etdm_data->mclk_fixed_apll == 0)
+		apll = mt8188_afe_get_default_mclk_source_by_rate(freq);
+	else
+		apll = etdm_data->mclk_apll;
+
+	apll_rate = mt8188_afe_get_mclk_source_rate(afe, apll);
+
+	if (freq > apll_rate) {
+		dev_info(afe->dev, "freq %d > apll rate %d\n", freq, apll_rate);
+		return -EINVAL;
+	}
+
+	if (apll_rate % freq != 0) {
+		dev_info(afe->dev, "APLL%d cannot generate freq Hz\n", apll);
+		return -EINVAL;
+	}
+
+	if (etdm_data->mclk_fixed_apll == 0)
+		etdm_data->mclk_apll = apll;
+	etdm_data->mclk_freq = freq;
+
+	return 0;
+}
+
+static int mtk_dai_etdm_set_sysclk(struct snd_soc_dai *dai,
+				   int clk_id, unsigned int freq, int dir)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+	int dai_id;
+
+	dev_dbg(dai->dev, "%s id %d freq %u, dir %d\n",
+		__func__, dai->id, freq, dir);
+	if (is_cowork_mode(dai))
+		dai_id = get_etdm_cowork_master_id(dai);
+	else
+		dai_id = dai->id;
+
+	etdm_data = afe_priv->dai_priv[dai_id];
+	etdm_data->mclk_dir = dir;
+	return mtk_dai_etdm_cal_mclk(afe, freq, dai_id);
+}
+
+static int mtk_dai_etdm_set_tdm_slot(struct snd_soc_dai *dai,
+				     unsigned int tx_mask, unsigned int rx_mask,
+				     int slots, int slot_width)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+
+	if (!is_valid_etdm_dai(dai->id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai->id];
+
+	dev_dbg(dai->dev, "%s id %d slot_width %d\n",
+		__func__, dai->id, slot_width);
+
+	etdm_data->slots = slots;
+	etdm_data->lrck_width = slot_width;
+	return 0;
+}
+
+static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+
+	if (!is_valid_etdm_dai(dai->id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai->id];
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		etdm_data->format = MTK_DAI_ETDM_FORMAT_LJ;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		etdm_data->format = MTK_DAI_ETDM_FORMAT_RJ;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		etdm_data->bck_inv = false;
+		etdm_data->lrck_inv = false;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		etdm_data->bck_inv = false;
+		etdm_data->lrck_inv = true;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		etdm_data->bck_inv = true;
+		etdm_data->lrck_inv = false;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		etdm_data->bck_inv = true;
+		etdm_data->lrck_inv = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+	case SND_SOC_DAIFMT_BC_FC:
+		etdm_data->slave_mode = true;
+		break;
+	case SND_SOC_DAIFMT_BP_FP:
+		etdm_data->slave_mode = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mtk_dai_hdmitx_dptx_startup(struct snd_pcm_substream *substream,
+				       struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	int cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id);
+
+	if (cg_id >= 0)
+		mt8188_afe_enable_clk(afe, afe_priv->clk[cg_id]);
+
+	mtk_dai_etdm_enable_mclk(afe, dai->id);
+
+	return 0;
+}
+
+static void mtk_dai_hdmitx_dptx_shutdown(struct snd_pcm_substream *substream,
+					 struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	int cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id);
+	struct mtk_dai_etdm_priv *etdm_data;
+	int ret = 0;
+
+	if (!is_valid_etdm_dai(dai->id))
+		return;
+	etdm_data = afe_priv->dai_priv[dai->id];
+
+	if (etdm_data->is_prepared) {
+		etdm_data->is_prepared = false;
+		/* disable etdm_out3 */
+		ret = mt8188_afe_disable_etdm(afe, dai->id);
+
+		if (ret)
+			dev_dbg(afe->dev, "%s disable failed\n", __func__);
+
+		/* disable dptx interface */
+		if (dai->id == MT8188_AFE_IO_DPTX)
+			regmap_clear_bits(afe->regmap, AFE_DPTX_CON,
+					  AFE_DPTX_CON_ON);
+	}
+
+	mtk_dai_etdm_disable_mclk(afe, dai->id);
+
+	if (cg_id >= 0)
+		mt8188_afe_disable_clk(afe, afe_priv->clk[cg_id]);
+}
+
+static unsigned int mtk_dai_get_dptx_ch_en(unsigned int channel)
+{
+	switch (channel) {
+	case 1 ... 2:
+		return AFE_DPTX_CON_CH_EN_2CH;
+	case 3 ... 4:
+		return AFE_DPTX_CON_CH_EN_4CH;
+	case 5 ... 6:
+		return AFE_DPTX_CON_CH_EN_6CH;
+	case 7 ... 8:
+		return AFE_DPTX_CON_CH_EN_8CH;
+	default:
+		return AFE_DPTX_CON_CH_EN_2CH;
+	}
+}
+
+static unsigned int mtk_dai_get_dptx_ch(unsigned int ch)
+{
+	return (ch > 2) ?
+		AFE_DPTX_CON_CH_NUM_8CH : AFE_DPTX_CON_CH_NUM_2CH;
+}
+
+static unsigned int mtk_dai_get_dptx_wlen(snd_pcm_format_t format)
+{
+	return snd_pcm_format_physical_width(format) <= 16 ?
+		AFE_DPTX_CON_16BIT : AFE_DPTX_CON_24BIT;
+}
+
+static int mtk_dai_hdmitx_dptx_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 mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+	unsigned int rate = params_rate(params);
+	unsigned int channels = params_channels(params);
+	snd_pcm_format_t format = params_format(params);
+	int width = snd_pcm_format_physical_width(format);
+	int ret = 0;
+
+	if (!is_valid_etdm_dai(dai->id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai->id];
+
+	/* dptx configure */
+	if (dai->id == MT8188_AFE_IO_DPTX) {
+		regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+				   AFE_DPTX_CON_CH_EN_MASK,
+				   mtk_dai_get_dptx_ch_en(channels));
+		regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+				   AFE_DPTX_CON_CH_NUM_MASK,
+				   mtk_dai_get_dptx_ch(channels));
+		regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+				   AFE_DPTX_CON_16BIT_MASK,
+				   mtk_dai_get_dptx_wlen(format));
+
+		if (mtk_dai_get_dptx_ch(channels) == AFE_DPTX_CON_CH_NUM_8CH) {
+			etdm_data->data_mode = MTK_DAI_ETDM_DATA_ONE_PIN;
+			channels = 8;
+		} else {
+			channels = 2;
+		}
+	} else {
+		etdm_data->data_mode = MTK_DAI_ETDM_DATA_MULTI_PIN;
+	}
+
+	ret = mtk_dai_etdm_mclk_configure(afe, dai->id);
+	if (ret)
+		return ret;
+
+	ret = mtk_dai_etdm_configure(afe, rate, channels, width, dai->id);
+
+	return ret;
+}
+
+static int mtk_dai_hdmitx_dptx_prepare(struct snd_pcm_substream *substream,
+				       struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+	int ret = 0;
+
+	if (!is_valid_etdm_dai(dai->id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai->id];
+
+	dev_dbg(afe->dev, "%s(), dai id %d, prepared %d\n", __func__, dai->id,
+		etdm_data->is_prepared);
+
+	if (etdm_data->is_prepared)
+		return 0;
+
+	etdm_data->is_prepared = true;
+
+	/* enable dptx interface */
+	if (dai->id == MT8188_AFE_IO_DPTX)
+		regmap_set_bits(afe->regmap, AFE_DPTX_CON, AFE_DPTX_CON_ON);
+
+	/* enable etdm_out3 */
+	ret = mt8188_afe_enable_etdm(afe, dai->id);
+
+	return ret;
+}
+
+static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai,
+					  int clk_id,
+					  unsigned int freq,
+					  int dir)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+
+	if (!is_valid_etdm_dai(dai->id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai->id];
+
+	dev_dbg(dai->dev, "%s id %d freq %u, dir %d\n",
+		__func__, dai->id, freq, dir);
+
+	etdm_data->mclk_dir = dir;
+	return mtk_dai_etdm_cal_mclk(afe, freq, dai->id);
+}
+
+static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
+	.startup = mtk_dai_etdm_startup,
+	.shutdown = mtk_dai_etdm_shutdown,
+	.hw_params = mtk_dai_etdm_hw_params,
+	.prepare = mtk_dai_etdm_prepare,
+	.set_sysclk = mtk_dai_etdm_set_sysclk,
+	.set_fmt = mtk_dai_etdm_set_fmt,
+	.set_tdm_slot = mtk_dai_etdm_set_tdm_slot,
+};
+
+static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = {
+	.startup	= mtk_dai_hdmitx_dptx_startup,
+	.shutdown	= mtk_dai_hdmitx_dptx_shutdown,
+	.hw_params	= mtk_dai_hdmitx_dptx_hw_params,
+	.prepare	= mtk_dai_hdmitx_dptx_prepare,
+	.set_sysclk	= mtk_dai_hdmitx_dptx_set_sysclk,
+	.set_fmt	= mtk_dai_etdm_set_fmt,
+};
+
+/* dai driver */
+#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_192000)
+
+#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			  SNDRV_PCM_FMTBIT_S24_LE |\
+			  SNDRV_PCM_FMTBIT_S32_LE)
+
+static int mtk_dai_etdm_probe(struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+
+	if (!is_valid_etdm_dai(dai->id))
+		return -EINVAL;
+	etdm_data = afe_priv->dai_priv[dai->id];
+
+	dev_dbg(dai->dev, "%s id %d\n", __func__, dai->id);
+
+	if (etdm_data->mclk_freq) {
+		dev_dbg(afe->dev, "MCLK always on, rate %d\n",
+			etdm_data->mclk_freq);
+		pm_runtime_get_sync(afe->dev);
+		mtk_dai_etdm_mclk_configure(afe, dai->id);
+		mtk_dai_etdm_enable_mclk(afe, dai->id);
+		pm_runtime_put_sync(afe->dev);
+	}
+	return 0;
+}
+
+static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
+	{
+		.name = "DPTX",
+		.id = MT8188_AFE_IO_DPTX,
+		.playback = {
+			.stream_name = "DPTX Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.ops = &mtk_dai_hdmitx_dptx_ops,
+	},
+	{
+		.name = "ETDM1_IN",
+		.id = MT8188_AFE_IO_ETDM1_IN,
+		.capture = {
+			.stream_name = "ETDM1 Capture",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.ops = &mtk_dai_etdm_ops,
+		.probe = mtk_dai_etdm_probe,
+	},
+	{
+		.name = "ETDM2_IN",
+		.id = MT8188_AFE_IO_ETDM2_IN,
+		.capture = {
+			.stream_name = "ETDM2 Capture",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.ops = &mtk_dai_etdm_ops,
+		.probe = mtk_dai_etdm_probe,
+	},
+	{
+		.name = "ETDM1_OUT",
+		.id = MT8188_AFE_IO_ETDM1_OUT,
+		.playback = {
+			.stream_name = "ETDM1 Playback",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.ops = &mtk_dai_etdm_ops,
+		.probe = mtk_dai_etdm_probe,
+	},
+	{
+		.name = "ETDM2_OUT",
+		.id = MT8188_AFE_IO_ETDM2_OUT,
+		.playback = {
+			.stream_name = "ETDM2 Playback",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.ops = &mtk_dai_etdm_ops,
+		.probe = mtk_dai_etdm_probe,
+	},
+	{
+		.name = "ETDM3_OUT",
+		.id = MT8188_AFE_IO_ETDM3_OUT,
+		.playback = {
+			.stream_name = "ETDM3 Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.ops = &mtk_dai_hdmitx_dptx_ops,
+		.probe = mtk_dai_etdm_probe,
+	},
+};
+
+static void mt8188_etdm_update_sync_info(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+	struct mtk_dai_etdm_priv *mst_data;
+	int i;
+	int mst_dai_id;
+
+	for (i = MT8188_AFE_IO_ETDM_START; i < MT8188_AFE_IO_ETDM_END; i++) {
+		etdm_data = afe_priv->dai_priv[i];
+		if (etdm_data->cowork_source_id != COWORK_ETDM_NONE) {
+			mst_dai_id = etdm_data->cowork_source_id;
+			mst_data = afe_priv->dai_priv[mst_dai_id];
+			if (mst_data->cowork_source_id != COWORK_ETDM_NONE)
+				dev_info(afe->dev, "%s [%d] wrong sync source\n"
+					 , __func__, i);
+			mst_data->cowork_slv_id[mst_data->cowork_slv_count] = i;
+			mst_data->cowork_slv_count++;
+		}
+	}
+}
+
+static void mt8188_dai_etdm_parse_of(struct mtk_base_afe *afe)
+{
+	const struct device_node *of_node = afe->dev->of_node;
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+	int i, j;
+	char prop[48];
+	u8 disable_chn[MT8188_ETDM_MAX_CHANNELS];
+	int max_chn = MT8188_ETDM_MAX_CHANNELS;
+	u32 sel;
+	int ret;
+	int dai_id;
+	unsigned int sync_id;
+	struct {
+		const char *name;
+		const unsigned int sync_id;
+	} of_afe_etdms[MT8188_AFE_IO_ETDM_NUM] = {
+		{"etdm-in1", ETDM_SYNC_FROM_IN1},
+		{"etdm-in2", ETDM_SYNC_FROM_IN2},
+		{"etdm-out1", ETDM_SYNC_FROM_OUT1},
+		{"etdm-out2", ETDM_SYNC_FROM_OUT2},
+		{"etdm-out3", ETDM_SYNC_FROM_OUT3},
+	};
+
+	for (i = 0; i < MT8188_AFE_IO_ETDM_NUM; i++) {
+		dai_id = ETDM_TO_DAI_ID(i);
+		etdm_data = afe_priv->dai_priv[dai_id];
+
+		ret = snprintf(prop, sizeof(prop),
+			       "mediatek,%s-mclk-always-on-rate",
+			       of_afe_etdms[i].name);
+		if (ret < 0) {
+			dev_info(afe->dev, "%s snprintf err=%d\n",
+				 __func__, ret);
+			return;
+		}
+		ret = of_property_read_u32(of_node, prop, &sel);
+		if (ret == 0) {
+			etdm_data->mclk_dir = SND_SOC_CLOCK_OUT;
+			if (mtk_dai_etdm_cal_mclk(afe, sel, dai_id))
+				dev_info(afe->dev, "%s unsupported mclk %uHz\n",
+					 __func__, sel);
+		}
+
+		ret = snprintf(prop, sizeof(prop),
+			       "mediatek,%s-multi-pin-mode",
+			       of_afe_etdms[i].name);
+		if (ret < 0) {
+			dev_info(afe->dev, "%s snprintf err=%d\n",
+				 __func__, ret);
+			return;
+		}
+		etdm_data->data_mode = of_property_read_bool(of_node, prop);
+
+		ret = snprintf(prop, sizeof(prop),
+			       "mediatek,%s-cowork-source",
+			       of_afe_etdms[i].name);
+		if (ret < 0) {
+			dev_info(afe->dev, "%s snprintf err=%d\n",
+				 __func__, ret);
+			return;
+		}
+		ret = of_property_read_u32(of_node, prop, &sel);
+		if (ret == 0) {
+			if (sel >= MT8188_AFE_IO_ETDM_NUM) {
+				dev_info(afe->dev, "%s invalid id=%d\n",
+					 __func__, sel);
+				etdm_data->cowork_source_id = COWORK_ETDM_NONE;
+			} else {
+				sync_id = of_afe_etdms[sel].sync_id;
+				etdm_data->cowork_source_id =
+					sync_to_dai_id(sync_id);
+			}
+		} else {
+			etdm_data->cowork_source_id = COWORK_ETDM_NONE;
+		}
+	}
+
+	/* etdm in only */
+	for (i = 0; i < 2; i++) {
+		ret = snprintf(prop, sizeof(prop),
+			       "mediatek,%s-chn-disabled",
+			       of_afe_etdms[i].name);
+		if (ret < 0) {
+			dev_info(afe->dev, "%s snprintf err=%d\n",
+				 __func__, ret);
+			return;
+		}
+		ret = of_property_read_variable_u8_array(of_node, prop,
+							 disable_chn,
+							 1, max_chn);
+		if (ret < 0)
+			continue;
+
+		for (j = 0; j < ret; j++) {
+			if (disable_chn[j] >= MT8188_ETDM_MAX_CHANNELS)
+				dev_info(afe->dev, "%s [%d] invalid chn %u\n",
+					 __func__, j, disable_chn[j]);
+			else
+				etdm_data->in_disable_ch[disable_chn[j]] = true;
+		}
+	}
+	mt8188_etdm_update_sync_info(afe);
+}
+
+static int init_etdm_priv_data(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_priv;
+	int i;
+
+	for (i = MT8188_AFE_IO_ETDM_START; i < MT8188_AFE_IO_ETDM_END; i++) {
+		etdm_priv = devm_kzalloc(afe->dev,
+					 sizeof(struct mtk_dai_etdm_priv),
+					 GFP_KERNEL);
+		if (!etdm_priv)
+			return -ENOMEM;
+
+		afe_priv->dai_priv[i] = etdm_priv;
+	}
+
+	afe_priv->dai_priv[MT8188_AFE_IO_DPTX] =
+		afe_priv->dai_priv[MT8188_AFE_IO_ETDM3_OUT];
+
+	mt8188_dai_etdm_parse_of(afe);
+	return 0;
+}
+
+int mt8188_dai_etdm_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+
+	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_etdm_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver);
+
+	dai->dapm_widgets = mtk_dai_etdm_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets);
+	dai->dapm_routes = mtk_dai_etdm_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes);
+	dai->controls = mtk_dai_etdm_controls;
+	dai->num_controls = ARRAY_SIZE(mtk_dai_etdm_controls);
+
+	return init_etdm_priv_data(afe);
+}
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 06/12] ASoC: mediatek: mt8188: support pcmif in platform driver
  2022-10-21  8:27 [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC Trevor Wu
                   ` (3 preceding siblings ...)
  2022-10-21  8:27 ` [PATCH v2 05/12] ASoC: mediatek: mt8188: support etdm " Trevor Wu
@ 2022-10-21  8:27 ` Trevor Wu
  2022-10-21  8:27 ` [PATCH v2 07/12] ASoC: mediatek: mt8188: support audio clock control Trevor Wu
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Trevor Wu @ 2022-10-21  8:27 UTC (permalink / raw)
  To: broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: trevor.wu, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Add mt8188 pcmif dai driver support

Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
---
 sound/soc/mediatek/mt8188/mt8188-dai-pcm.c | 366 +++++++++++++++++++++
 1 file changed, 366 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-pcm.c

diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c b/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c
new file mode 100644
index 000000000000..4168b74ae22d
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI PCM I/F Control
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Bicycle Tsai <bicycle.tsai@mediatek.com>
+ *         Trevor Wu <trevor.wu@mediatek.com>
+ *         Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
+ */
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8188-afe-clk.h"
+#include "mt8188-afe-common.h"
+#include "mt8188-reg.h"
+
+enum {
+	MTK_DAI_PCM_FMT_I2S,
+	MTK_DAI_PCM_FMT_EIAJ,
+	MTK_DAI_PCM_FMT_MODEA,
+	MTK_DAI_PCM_FMT_MODEB,
+};
+
+enum {
+	MTK_DAI_PCM_CLK_A1SYS,
+	MTK_DAI_PCM_CLK_A2SYS,
+	MTK_DAI_PCM_CLK_26M_48K,
+	MTK_DAI_PCM_CLK_26M_441K,
+};
+
+struct mtk_dai_pcm_rate {
+	unsigned int rate;
+	unsigned int reg_value;
+};
+
+struct mtk_dai_pcmif_priv {
+	unsigned int slave_mode;
+	unsigned int lrck_inv;
+	unsigned int bck_inv;
+	unsigned int format;
+};
+
+static const struct mtk_dai_pcm_rate mtk_dai_pcm_rates[] = {
+	{ .rate = 8000, .reg_value = 0, },
+	{ .rate = 16000, .reg_value = 1, },
+	{ .rate = 32000, .reg_value = 2, },
+	{ .rate = 48000, .reg_value = 3, },
+	{ .rate = 11025, .reg_value = 1, },
+	{ .rate = 22050, .reg_value = 2, },
+	{ .rate = 44100, .reg_value = 3, },
+};
+
+static int mtk_dai_pcm_mode(unsigned int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mtk_dai_pcm_rates); i++)
+		if (mtk_dai_pcm_rates[i].rate == rate)
+			return mtk_dai_pcm_rates[i].reg_value;
+
+	return -EINVAL;
+}
+
+static const struct snd_kcontrol_new mtk_dai_pcm_o000_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN0, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN0_2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_pcm_o001_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN1, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN1_2, 7, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+	SND_SOC_DAPM_MIXER("I002", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I003", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("O000", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_pcm_o000_mix,
+			   ARRAY_SIZE(mtk_dai_pcm_o000_mix)),
+	SND_SOC_DAPM_MIXER("O001", SND_SOC_NOPM, 0, 0,
+			   mtk_dai_pcm_o001_mix,
+			   ARRAY_SIZE(mtk_dai_pcm_o001_mix)),
+
+	SND_SOC_DAPM_SUPPLY("PCM_1_EN", PCM_INTF_CON1, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_INPUT("PCM1_INPUT"),
+	SND_SOC_DAPM_OUTPUT("PCM1_OUTPUT"),
+
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_asrc11"),
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_asrc12"),
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_pcmif"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+	{"I002", NULL, "PCM1 Capture"},
+	{"I003", NULL, "PCM1 Capture"},
+
+	{"O000", "I000 Switch", "I000"},
+	{"O001", "I001 Switch", "I001"},
+
+	{"O000", "I070 Switch", "I070"},
+	{"O001", "I071 Switch", "I071"},
+
+	{"PCM1 Playback", NULL, "O000"},
+	{"PCM1 Playback", NULL, "O001"},
+
+	{"PCM1 Playback", NULL, "PCM_1_EN"},
+	{"PCM1 Playback", NULL, "aud_asrc12"},
+	{"PCM1 Playback", NULL, "aud_pcmif"},
+
+	{"PCM1 Capture", NULL, "PCM_1_EN"},
+	{"PCM1 Capture", NULL, "aud_asrc11"},
+	{"PCM1 Capture", NULL, "aud_pcmif"},
+
+	{"PCM1_OUTPUT", NULL, "PCM1 Playback"},
+	{"PCM1 Capture", NULL, "PCM1_INPUT"},
+};
+
+static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_pcm_runtime * const runtime = substream->runtime;
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_pcmif_priv *pcmif_priv = NULL;
+	unsigned int slave_mode;
+	unsigned int lrck_inv;
+	unsigned int bck_inv;
+	unsigned int fmt;
+	unsigned int bit_width = dai->sample_bits;
+	unsigned int val = 0;
+	unsigned int mask = 0;
+	int fs = 0;
+	int mode = 0;
+
+	if (dai->id < 0)
+		return -EINVAL;
+
+	pcmif_priv = afe_priv->dai_priv[dai->id];
+	slave_mode = pcmif_priv->slave_mode;
+	lrck_inv = pcmif_priv->lrck_inv;
+	bck_inv = pcmif_priv->bck_inv;
+	fmt = pcmif_priv->format;
+
+	/* sync freq mode */
+	fs = mt8188_afe_fs_timing(runtime->rate);
+	if (fs < 0)
+		return -EINVAL;
+
+	val |= FIELD_PREP(PCM_INTF_CON2_SYNC_FREQ_MODE_MASK, fs);
+	mask |= PCM_INTF_CON2_SYNC_FREQ_MODE_MASK;
+
+	/* clk domain sel */
+	if (runtime->rate % 8000)
+		val |= FIELD_PREP(PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK,
+				  MTK_DAI_PCM_CLK_26M_441K);
+	else
+		val |= FIELD_PREP(PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK,
+				  MTK_DAI_PCM_CLK_26M_48K);
+	mask |= PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK;
+
+	regmap_update_bits(afe->regmap, PCM_INTF_CON2, mask, val);
+
+	val = 0;
+	mask = 0;
+
+	/* pcm mode */
+	mode = mtk_dai_pcm_mode(runtime->rate);
+	if (mode < 0)
+		return -EINVAL;
+
+	val |= FIELD_PREP(PCM_INTF_CON1_PCM_MODE_MASK, mode);
+	mask |= PCM_INTF_CON1_PCM_MODE_MASK;
+
+	/* pcm format */
+	val |= FIELD_PREP(PCM_INTF_CON1_PCM_FMT_MASK, fmt);
+	mask |= PCM_INTF_CON1_PCM_FMT_MASK;
+
+	/* pcm sync length */
+	if (fmt == MTK_DAI_PCM_FMT_MODEA ||
+	    fmt == MTK_DAI_PCM_FMT_MODEB)
+		val |= FIELD_PREP(PCM_INTF_CON1_SYNC_LENGTH_MASK, 1);
+	else
+		val |= FIELD_PREP(PCM_INTF_CON1_SYNC_LENGTH_MASK, bit_width);
+	mask |= PCM_INTF_CON1_SYNC_LENGTH_MASK;
+
+	/* pcm bits, word length */
+	if (bit_width > 16) {
+		val |= PCM_INTF_CON1_PCM_24BIT;
+		val |= PCM_INTF_CON1_PCM_WLEN_64BCK;
+	} else {
+		val |= PCM_INTF_CON1_PCM_16BIT;
+		val |= PCM_INTF_CON1_PCM_WLEN_32BCK;
+	}
+	mask |= PCM_INTF_CON1_PCM_BIT_MASK;
+	mask |= PCM_INTF_CON1_PCM_WLEN_MASK;
+
+	/* master/slave */
+	if (!slave_mode) {
+		val |= PCM_INTF_CON1_PCM_MASTER;
+
+		if (lrck_inv)
+			val |= PCM_INTF_CON1_SYNC_OUT_INV;
+		if (bck_inv)
+			val |= PCM_INTF_CON1_BCLK_OUT_INV;
+		mask |= PCM_INTF_CON1_CLK_OUT_INV_MASK;
+	} else {
+		val |= PCM_INTF_CON1_PCM_SLAVE;
+
+		if (lrck_inv)
+			val |= PCM_INTF_CON1_SYNC_IN_INV;
+		if (bck_inv)
+			val |= PCM_INTF_CON1_BCLK_IN_INV;
+		mask |= PCM_INTF_CON1_CLK_IN_INV_MASK;
+
+		// TODO: add asrc setting for slave mode
+	}
+	mask |= PCM_INTF_CON1_PCM_M_S_MASK;
+
+	regmap_update_bits(afe->regmap, PCM_INTF_CON1, mask, val);
+
+	return 0;
+}
+
+/* dai ops */
+static int mtk_dai_pcm_prepare(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	if (dai->playback_widget->active || dai->capture_widget->active)
+		return 0;
+
+	return mtk_dai_pcm_configure(substream, dai);
+}
+
+static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_pcmif_priv *pcmif_priv = NULL;
+
+	dev_dbg(dai->dev, "%s fmt 0x%x\n", __func__, fmt);
+
+	if (dai->id < 0)
+		return -EINVAL;
+
+	pcmif_priv = afe_priv->dai_priv[dai->id];
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		pcmif_priv->format = MTK_DAI_PCM_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		pcmif_priv->format = MTK_DAI_PCM_FMT_MODEA;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		pcmif_priv->format = MTK_DAI_PCM_FMT_MODEB;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		pcmif_priv->bck_inv = 0;
+		pcmif_priv->lrck_inv = 0;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		pcmif_priv->bck_inv = 0;
+		pcmif_priv->lrck_inv = 1;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		pcmif_priv->bck_inv = 1;
+		pcmif_priv->lrck_inv = 0;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		pcmif_priv->bck_inv = 1;
+		pcmif_priv->lrck_inv = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+	case SND_SOC_DAIFMT_BC_FC:
+		pcmif_priv->slave_mode = 1;
+		break;
+	case SND_SOC_DAIFMT_BP_FP:
+		pcmif_priv->slave_mode = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
+	.prepare	= mtk_dai_pcm_prepare,
+	.set_fmt	= mtk_dai_pcm_set_fmt,
+};
+
+/* dai driver */
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
+	{
+		.name = "PCM1",
+		.id = MT8188_AFE_IO_PCM,
+		.playback = {
+			.stream_name = "PCM1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.capture = {
+			.stream_name = "PCM1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_dai_pcm_ops,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
+	},
+};
+
+static int init_pcmif_priv_data(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_pcmif_priv *pcmif_priv;
+
+	pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_pcmif_priv),
+				  GFP_KERNEL);
+	if (!pcmif_priv)
+		return -ENOMEM;
+
+	afe_priv->dai_priv[MT8188_AFE_IO_PCM] = pcmif_priv;
+	return 0;
+}
+
+int mt8188_dai_pcm_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+
+	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_pcm_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+
+	dai->dapm_widgets = mtk_dai_pcm_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+	dai->dapm_routes = mtk_dai_pcm_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+
+	return init_pcmif_priv_data(afe);
+}
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 07/12] ASoC: mediatek: mt8188: support audio clock control
  2022-10-21  8:27 [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC Trevor Wu
                   ` (4 preceding siblings ...)
  2022-10-21  8:27 ` [PATCH v2 06/12] ASoC: mediatek: mt8188: support pcmif " Trevor Wu
@ 2022-10-21  8:27 ` Trevor Wu
  2022-10-21  8:27 ` [PATCH v2 08/12] ASoC: mediatek: mt8188: add platform driver Trevor Wu
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Trevor Wu @ 2022-10-21  8:27 UTC (permalink / raw)
  To: broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: trevor.wu, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Add audio clock wrapper and audio tuner control.

Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
---
 sound/soc/mediatek/mt8188/mt8188-afe-clk.c | 656 +++++++++++++++++++++
 sound/soc/mediatek/mt8188/mt8188-afe-clk.h | 114 ++++
 2 files changed, 770 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-clk.c
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-clk.h

diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
new file mode 100644
index 000000000000..67fecc5eeaf9
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
@@ -0,0 +1,656 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8188-afe-clk.c  --  MediaTek 8188 afe clock ctrl
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Bicycle Tsai <bicycle.tsai@mediatek.com>
+ *         Trevor Wu <trevor.wu@mediatek.com>
+ *         Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
+ */
+
+#include <linux/clk.h>
+
+#include "mt8188-afe-common.h"
+#include "mt8188-afe-clk.h"
+#include "mt8188-audsys-clk.h"
+#include "mt8188-reg.h"
+
+static const char *aud_clks[MT8188_CLK_NUM] = {
+	/* xtal */
+	[MT8188_CLK_XTAL_26M] = "clk26m",
+
+	/* divider */
+	[MT8188_CLK_TOP_APLL1] = "apll1_ck",
+	[MT8188_CLK_TOP_APLL2] = "apll2_ck",
+	[MT8188_CLK_TOP_APLL12_DIV0] = "apll12_div0",
+	[MT8188_CLK_TOP_APLL12_DIV1] = "apll12_div1",
+	[MT8188_CLK_TOP_APLL12_DIV2] = "apll12_div2",
+	[MT8188_CLK_TOP_APLL12_DIV3] = "apll12_div3",
+	[MT8188_CLK_TOP_APLL12_DIV9] = "apll12_div9",
+
+	/* mux */
+	[MT8188_CLK_TOP_A1SYS_HP_SEL] = "top_a1sys_hp",
+	[MT8188_CLK_TOP_AUD_INTBUS_SEL] = "top_aud_intbus",
+	[MT8188_CLK_TOP_AUDIO_H_SEL] = "top_audio_h",
+	[MT8188_CLK_TOP_AUDIO_LOCAL_BUS_SEL] = "top_audio_local_bus",
+	[MT8188_CLK_TOP_DPTX_M_SEL] = "top_dptx",
+	[MT8188_CLK_TOP_I2SO1_M_SEL] = "top_i2so1",
+	[MT8188_CLK_TOP_I2SO2_M_SEL] = "top_i2so2",
+	[MT8188_CLK_TOP_I2SI1_M_SEL] = "top_i2si1",
+	[MT8188_CLK_TOP_I2SI2_M_SEL] = "top_i2si2",
+
+	/* clock gate */
+	[MT8188_CLK_ADSP_AUDIO_26M] = "adsp_audio_26m",
+	/* afe clock gate */
+	[MT8188_CLK_AUD_AFE] = "aud_afe",
+	[MT8188_CLK_AUD_APLL1_TUNER] = "aud_apll1_tuner",
+	[MT8188_CLK_AUD_APLL2_TUNER] = "aud_apll2_tuner",
+	[MT8188_CLK_AUD_APLL] = "aud_apll",
+	[MT8188_CLK_AUD_APLL2] = "aud_apll2",
+	[MT8188_CLK_AUD_DAC] = "aud_dac",
+	[MT8188_CLK_AUD_ADC] = "aud_adc",
+	[MT8188_CLK_AUD_DAC_HIRES] = "aud_dac_hires",
+	[MT8188_CLK_AUD_A1SYS_HP] = "aud_a1sys_hp",
+	[MT8188_CLK_AUD_ADC_HIRES] = "aud_adc_hires",
+	[MT8188_CLK_AUD_I2SIN] = "aud_i2sin",
+	[MT8188_CLK_AUD_TDM_IN] = "aud_tdm_in",
+	[MT8188_CLK_AUD_I2S_OUT] = "aud_i2s_out",
+	[MT8188_CLK_AUD_TDM_OUT] = "aud_tdm_out",
+	[MT8188_CLK_AUD_HDMI_OUT] = "aud_hdmi_out",
+	[MT8188_CLK_AUD_ASRC11] = "aud_asrc11",
+	[MT8188_CLK_AUD_ASRC12] = "aud_asrc12",
+	[MT8188_CLK_AUD_A1SYS] = "aud_a1sys",
+	[MT8188_CLK_AUD_A2SYS] = "aud_a2sys",
+	[MT8188_CLK_AUD_PCMIF] = "aud_pcmif",
+	[MT8188_CLK_AUD_MEMIF_UL1] = "aud_memif_ul1",
+	[MT8188_CLK_AUD_MEMIF_UL2] = "aud_memif_ul2",
+	[MT8188_CLK_AUD_MEMIF_UL3] = "aud_memif_ul3",
+	[MT8188_CLK_AUD_MEMIF_UL4] = "aud_memif_ul4",
+	[MT8188_CLK_AUD_MEMIF_UL5] = "aud_memif_ul5",
+	[MT8188_CLK_AUD_MEMIF_UL6] = "aud_memif_ul6",
+	[MT8188_CLK_AUD_MEMIF_UL8] = "aud_memif_ul8",
+	[MT8188_CLK_AUD_MEMIF_UL9] = "aud_memif_ul9",
+	[MT8188_CLK_AUD_MEMIF_UL10] = "aud_memif_ul10",
+	[MT8188_CLK_AUD_MEMIF_DL2] = "aud_memif_dl2",
+	[MT8188_CLK_AUD_MEMIF_DL3] = "aud_memif_dl3",
+	[MT8188_CLK_AUD_MEMIF_DL6] = "aud_memif_dl6",
+	[MT8188_CLK_AUD_MEMIF_DL7] = "aud_memif_dl7",
+	[MT8188_CLK_AUD_MEMIF_DL8] = "aud_memif_dl8",
+	[MT8188_CLK_AUD_MEMIF_DL10] = "aud_memif_dl10",
+	[MT8188_CLK_AUD_MEMIF_DL11] = "aud_memif_dl11",
+};
+
+struct mt8188_afe_tuner_cfg {
+	unsigned int id;
+	int apll_div_reg;
+	unsigned int apll_div_shift;
+	unsigned int apll_div_maskbit;
+	unsigned int apll_div_default;
+	int ref_ck_sel_reg;
+	unsigned int ref_ck_sel_shift;
+	unsigned int ref_ck_sel_maskbit;
+	unsigned int ref_ck_sel_default;
+	int tuner_en_reg;
+	unsigned int tuner_en_shift;
+	unsigned int tuner_en_maskbit;
+	int upper_bound_reg;
+	unsigned int upper_bound_shift;
+	unsigned int upper_bound_maskbit;
+	unsigned int upper_bound_default;
+	spinlock_t ctrl_lock; /* lock for apll tuner ctrl*/
+	int ref_cnt;
+};
+
+static struct mt8188_afe_tuner_cfg
+	mt8188_afe_tuner_cfgs[MT8188_AUD_PLL_NUM] = {
+	[MT8188_AUD_PLL1] = {
+		.id = MT8188_AUD_PLL1,
+		.apll_div_reg = AFE_APLL_TUNER_CFG,
+		.apll_div_shift = 4,
+		.apll_div_maskbit = 0xf,
+		.apll_div_default = 0x7,
+		.ref_ck_sel_reg = AFE_APLL_TUNER_CFG,
+		.ref_ck_sel_shift = 1,
+		.ref_ck_sel_maskbit = 0x3,
+		.ref_ck_sel_default = 0x2,
+		.tuner_en_reg = AFE_APLL_TUNER_CFG,
+		.tuner_en_shift = 0,
+		.tuner_en_maskbit = 0x1,
+		.upper_bound_reg = AFE_APLL_TUNER_CFG,
+		.upper_bound_shift = 8,
+		.upper_bound_maskbit = 0xff,
+		.upper_bound_default = 0x3,
+	},
+	[MT8188_AUD_PLL2] = {
+		.id = MT8188_AUD_PLL2,
+		.apll_div_reg = AFE_APLL_TUNER_CFG1,
+		.apll_div_shift = 4,
+		.apll_div_maskbit = 0xf,
+		.apll_div_default = 0x7,
+		.ref_ck_sel_reg = AFE_APLL_TUNER_CFG1,
+		.ref_ck_sel_shift = 1,
+		.ref_ck_sel_maskbit = 0x3,
+		.ref_ck_sel_default = 0x1,
+		.tuner_en_reg = AFE_APLL_TUNER_CFG1,
+		.tuner_en_shift = 0,
+		.tuner_en_maskbit = 0x1,
+		.upper_bound_reg = AFE_APLL_TUNER_CFG1,
+		.upper_bound_shift = 8,
+		.upper_bound_maskbit = 0xff,
+		.upper_bound_default = 0x3,
+	},
+	[MT8188_AUD_PLL3] = {
+		.id = MT8188_AUD_PLL3,
+		.apll_div_reg = AFE_EARC_APLL_TUNER_CFG,
+		.apll_div_shift = 4,
+		.apll_div_maskbit = 0x3f,
+		.apll_div_default = 0x3,
+		.ref_ck_sel_reg = AFE_EARC_APLL_TUNER_CFG,
+		.ref_ck_sel_shift = 24,
+		.ref_ck_sel_maskbit = 0x3,
+		.ref_ck_sel_default = 0x0,
+		.tuner_en_reg = AFE_EARC_APLL_TUNER_CFG,
+		.tuner_en_shift = 0,
+		.tuner_en_maskbit = 0x1,
+		.upper_bound_reg = AFE_EARC_APLL_TUNER_CFG,
+		.upper_bound_shift = 12,
+		.upper_bound_maskbit = 0xff,
+		.upper_bound_default = 0x4,
+	},
+	[MT8188_AUD_PLL4] = {
+		.id = MT8188_AUD_PLL4,
+		.apll_div_reg = AFE_SPDIFIN_APLL_TUNER_CFG,
+		.apll_div_shift = 4,
+		.apll_div_maskbit = 0x3f,
+		.apll_div_default = 0x7,
+		.ref_ck_sel_reg = AFE_SPDIFIN_APLL_TUNER_CFG1,
+		.ref_ck_sel_shift = 8,
+		.ref_ck_sel_maskbit = 0x1,
+		.ref_ck_sel_default = 0,
+		.tuner_en_reg = AFE_SPDIFIN_APLL_TUNER_CFG,
+		.tuner_en_shift = 0,
+		.tuner_en_maskbit = 0x1,
+		.upper_bound_reg = AFE_SPDIFIN_APLL_TUNER_CFG,
+		.upper_bound_shift = 12,
+		.upper_bound_maskbit = 0xff,
+		.upper_bound_default = 0x4,
+	},
+	[MT8188_AUD_PLL5] = {
+		.id = MT8188_AUD_PLL5,
+		.apll_div_reg = AFE_LINEIN_APLL_TUNER_CFG,
+		.apll_div_shift = 4,
+		.apll_div_maskbit = 0x3f,
+		.apll_div_default = 0x3,
+		.ref_ck_sel_reg = AFE_LINEIN_APLL_TUNER_CFG,
+		.ref_ck_sel_shift = 24,
+		.ref_ck_sel_maskbit = 0x1,
+		.ref_ck_sel_default = 0,
+		.tuner_en_reg = AFE_LINEIN_APLL_TUNER_CFG,
+		.tuner_en_shift = 0,
+		.tuner_en_maskbit = 0x1,
+		.upper_bound_reg = AFE_LINEIN_APLL_TUNER_CFG,
+		.upper_bound_shift = 12,
+		.upper_bound_maskbit = 0xff,
+		.upper_bound_default = 0x4,
+	},
+};
+
+static struct mt8188_afe_tuner_cfg *mt8188_afe_found_apll_tuner(unsigned int id)
+{
+	if (id >= MT8188_AUD_PLL_NUM)
+		return NULL;
+
+	return &mt8188_afe_tuner_cfgs[id];
+}
+
+static int mt8188_afe_init_apll_tuner(unsigned int id)
+{
+	struct mt8188_afe_tuner_cfg *cfg = mt8188_afe_found_apll_tuner(id);
+
+	if (!cfg)
+		return -EINVAL;
+
+	cfg->ref_cnt = 0;
+	spin_lock_init(&cfg->ctrl_lock);
+
+	return 0;
+}
+
+static int mt8188_afe_setup_apll_tuner(struct mtk_base_afe *afe, unsigned int id)
+{
+	const struct mt8188_afe_tuner_cfg *cfg = mt8188_afe_found_apll_tuner(id);
+
+	if (!cfg)
+		return -EINVAL;
+
+	regmap_update_bits(afe->regmap,
+			   cfg->apll_div_reg,
+			   cfg->apll_div_maskbit << cfg->apll_div_shift,
+			   cfg->apll_div_default << cfg->apll_div_shift);
+
+	regmap_update_bits(afe->regmap,
+			   cfg->ref_ck_sel_reg,
+			   cfg->ref_ck_sel_maskbit << cfg->ref_ck_sel_shift,
+			   cfg->ref_ck_sel_default << cfg->ref_ck_sel_shift);
+
+	regmap_update_bits(afe->regmap,
+			   cfg->upper_bound_reg,
+			   cfg->upper_bound_maskbit << cfg->upper_bound_shift,
+			   cfg->upper_bound_default << cfg->upper_bound_shift);
+
+	return 0;
+}
+
+static int mt8188_afe_enable_tuner_clk(struct mtk_base_afe *afe,
+				       unsigned int id)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+	switch (id) {
+	case MT8188_AUD_PLL1:
+		mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL]);
+		mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL1_TUNER]);
+		break;
+	case MT8188_AUD_PLL2:
+		mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL2]);
+		mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL2_TUNER]);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mt8188_afe_disable_tuner_clk(struct mtk_base_afe *afe,
+					unsigned int id)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+	switch (id) {
+	case MT8188_AUD_PLL1:
+		mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL1_TUNER]);
+		mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL]);
+		break;
+	case MT8188_AUD_PLL2:
+		mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL2_TUNER]);
+		mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL2]);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mt8188_afe_enable_apll_tuner(struct mtk_base_afe *afe, unsigned int id)
+{
+	struct mt8188_afe_tuner_cfg *cfg = mt8188_afe_found_apll_tuner(id);
+	unsigned long flags;
+	int ret;
+
+	if (!cfg)
+		return -EINVAL;
+
+	ret = mt8188_afe_setup_apll_tuner(afe, id);
+	if (ret)
+		return ret;
+
+	ret = mt8188_afe_enable_tuner_clk(afe, id);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&cfg->ctrl_lock, flags);
+
+	cfg->ref_cnt++;
+	if (cfg->ref_cnt == 1)
+		regmap_update_bits(afe->regmap,
+				   cfg->tuner_en_reg,
+				   cfg->tuner_en_maskbit << cfg->tuner_en_shift,
+				   BIT(cfg->tuner_en_shift));
+
+	spin_unlock_irqrestore(&cfg->ctrl_lock, flags);
+
+	return 0;
+}
+
+static int mt8188_afe_disable_apll_tuner(struct mtk_base_afe *afe, unsigned int id)
+{
+	struct mt8188_afe_tuner_cfg *cfg = mt8188_afe_found_apll_tuner(id);
+	unsigned long flags;
+	int ret;
+
+	if (!cfg)
+		return -EINVAL;
+
+	spin_lock_irqsave(&cfg->ctrl_lock, flags);
+
+	cfg->ref_cnt--;
+	if (cfg->ref_cnt == 0)
+		regmap_update_bits(afe->regmap,
+				   cfg->tuner_en_reg,
+				   cfg->tuner_en_maskbit << cfg->tuner_en_shift,
+				   0 << cfg->tuner_en_shift);
+	else if (cfg->ref_cnt < 0)
+		cfg->ref_cnt = 0;
+
+	spin_unlock_irqrestore(&cfg->ctrl_lock, flags);
+
+	ret = mt8188_afe_disable_tuner_clk(afe, id);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int mt8188_afe_get_mclk_source_clk_id(int sel)
+{
+	switch (sel) {
+	case MT8188_MCK_SEL_26M:
+		return MT8188_CLK_XTAL_26M;
+	case MT8188_MCK_SEL_APLL1:
+		return MT8188_CLK_TOP_APLL1;
+	case MT8188_MCK_SEL_APLL2:
+		return MT8188_CLK_TOP_APLL2;
+	default:
+		return -EINVAL;
+	}
+}
+
+int mt8188_afe_get_mclk_source_rate(struct mtk_base_afe *afe, int apll)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	int clk_id = mt8188_afe_get_mclk_source_clk_id(apll);
+
+	if (clk_id < 0) {
+		dev_dbg(afe->dev, "invalid clk id\n");
+		return 0;
+	}
+
+	return clk_get_rate(afe_priv->clk[clk_id]);
+}
+
+int mt8188_afe_get_default_mclk_source_by_rate(int rate)
+{
+	return ((rate % 8000) == 0) ?
+		MT8188_MCK_SEL_APLL1 : MT8188_MCK_SEL_APLL2;
+}
+
+int mt8188_afe_init_clock(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	int i, ret;
+
+	ret = mt8188_audsys_clk_register(afe);
+	if (ret) {
+		dev_err(afe->dev, "register audsys clk fail %d\n", ret);
+		return ret;
+	}
+
+	afe_priv->clk =
+		devm_kcalloc(afe->dev, MT8188_CLK_NUM, sizeof(*afe_priv->clk),
+			     GFP_KERNEL);
+	if (!afe_priv->clk)
+		return -ENOMEM;
+
+	for (i = 0; i < MT8188_CLK_NUM; 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]));
+			return PTR_ERR(afe_priv->clk[i]);
+		}
+	}
+
+	/* initial tuner */
+	for (i = 0; i < MT8188_AUD_PLL_NUM; i++) {
+		ret = mt8188_afe_init_apll_tuner(i);
+		if (ret) {
+			dev_info(afe->dev, "%s(), init apll_tuner%d failed",
+				 __func__, (i + 1));
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+void mt8188_afe_deinit_clock(void *priv)
+{
+	struct mtk_base_afe *afe = priv;
+
+	mt8188_audsys_clk_unregister(afe);
+}
+
+int mt8188_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk)
+{
+	int ret;
+
+	if (clk) {
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			dev_dbg(afe->dev, "%s(), failed to enable clk\n",
+				__func__);
+			return ret;
+		}
+	} else {
+		dev_dbg(afe->dev, "NULL clk\n");
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mt8188_afe_enable_clk);
+
+void mt8188_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk)
+{
+	if (clk)
+		clk_disable_unprepare(clk);
+	else
+		dev_dbg(afe->dev, "NULL clk\n");
+}
+EXPORT_SYMBOL_GPL(mt8188_afe_disable_clk);
+
+int mt8188_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk,
+			    unsigned int rate)
+{
+	int ret;
+
+	if (clk) {
+		ret = clk_set_rate(clk, rate);
+		if (ret) {
+			dev_dbg(afe->dev, "%s(), failed to set clk rate\n",
+				__func__);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+int mt8188_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk,
+			      struct clk *parent)
+{
+	int ret;
+
+	if (clk && parent) {
+		ret = clk_set_parent(clk, parent);
+		if (ret) {
+			dev_dbg(afe->dev, "%s(), failed to set clk parent\n",
+				__func__);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static unsigned int get_top_cg_reg(unsigned int cg_type)
+{
+	switch (cg_type) {
+	case MT8188_TOP_CG_A1SYS_TIMING:
+	case MT8188_TOP_CG_A2SYS_TIMING:
+	case MT8188_TOP_CG_26M_TIMING:
+		return ASYS_TOP_CON;
+	default:
+		return 0;
+	}
+}
+
+static unsigned int get_top_cg_mask(unsigned int cg_type)
+{
+	switch (cg_type) {
+	case MT8188_TOP_CG_A1SYS_TIMING:
+		return ASYS_TOP_CON_A1SYS_TIMING_ON;
+	case MT8188_TOP_CG_A2SYS_TIMING:
+		return ASYS_TOP_CON_A2SYS_TIMING_ON;
+	case MT8188_TOP_CG_26M_TIMING:
+		return ASYS_TOP_CON_26M_TIMING_ON;
+	default:
+		return 0;
+	}
+}
+
+static unsigned int get_top_cg_on_val(unsigned int cg_type)
+{
+	switch (cg_type) {
+	case MT8188_TOP_CG_A1SYS_TIMING:
+	case MT8188_TOP_CG_A2SYS_TIMING:
+	case MT8188_TOP_CG_26M_TIMING:
+		return get_top_cg_mask(cg_type);
+	default:
+		return 0;
+	}
+}
+
+static unsigned int get_top_cg_off_val(unsigned int cg_type)
+{
+	switch (cg_type) {
+	case MT8188_TOP_CG_A1SYS_TIMING:
+	case MT8188_TOP_CG_A2SYS_TIMING:
+	case MT8188_TOP_CG_26M_TIMING:
+		return 0;
+	default:
+		return get_top_cg_mask(cg_type);
+	}
+}
+
+static int mt8188_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+	unsigned int reg = get_top_cg_reg(cg_type);
+	unsigned int mask = get_top_cg_mask(cg_type);
+	unsigned int val = get_top_cg_on_val(cg_type);
+
+	regmap_update_bits(afe->regmap, reg, mask, val);
+
+	return 0;
+}
+
+static int mt8188_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+	unsigned int reg = get_top_cg_reg(cg_type);
+	unsigned int mask = get_top_cg_mask(cg_type);
+	unsigned int val = get_top_cg_off_val(cg_type);
+
+	regmap_update_bits(afe->regmap, reg, mask, val);
+
+	return 0;
+}
+
+int mt8188_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+	/* bus clock for AFE external access, like DRAM */
+	mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_AUDIO_LOCAL_BUS_SEL]);
+
+	/* bus clock for AFE internal access, like AFE SRAM */
+	mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_AUD_INTBUS_SEL]);
+
+	/* audio 26m clock source */
+	mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_ADSP_AUDIO_26M]);
+
+	/* AFE hw clock */
+	mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE]);
+	mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS_HP]);
+	mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]);
+
+	return 0;
+}
+
+int mt8188_afe_disable_reg_rw_clk(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+	mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]);
+	mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS_HP]);
+	mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE]);
+	mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_ADSP_AUDIO_26M]);
+	mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_AUD_INTBUS_SEL]);
+	mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_AUDIO_LOCAL_BUS_SEL]);
+
+	return 0;
+}
+
+static int mt8188_afe_enable_afe_on(struct mtk_base_afe *afe)
+{
+	regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
+	return 0;
+}
+
+static int mt8188_afe_disable_afe_on(struct mtk_base_afe *afe)
+{
+	regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x0);
+	return 0;
+}
+
+static int mt8188_afe_enable_timing_sys(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+	mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]);
+	mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]);
+
+	mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING);
+	mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_A2SYS_TIMING);
+	mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_26M_TIMING);
+
+	return 0;
+}
+
+static int mt8188_afe_disable_timing_sys(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+	mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]);
+	mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]);
+
+	mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_26M_TIMING);
+	mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_A2SYS_TIMING);
+	mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING);
+
+	return 0;
+}
+
+int mt8188_afe_enable_main_clock(struct mtk_base_afe *afe)
+{
+	mt8188_afe_enable_timing_sys(afe);
+
+	mt8188_afe_enable_afe_on(afe);
+
+	mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL1);
+	mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL2);
+
+	return 0;
+}
+
+int mt8188_afe_disable_main_clock(struct mtk_base_afe *afe)
+{
+	mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL2);
+	mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL1);
+
+	mt8188_afe_disable_afe_on(afe);
+
+	mt8188_afe_disable_timing_sys(afe);
+
+	return 0;
+}
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
new file mode 100644
index 000000000000..ea38767d3876
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8188-afe-clk.h  --  MediaTek 8188 afe clock ctrl definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Bicycle Tsai <bicycle.tsai@mediatek.com>
+ *         Trevor Wu <trevor.wu@mediatek.com>
+ *         Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
+ */
+
+#ifndef _MT8188_AFE_CLK_H_
+#define _MT8188_AFE_CLK_H_
+
+enum {
+	/* xtal */
+	MT8188_CLK_XTAL_26M,
+	/* divider */
+	MT8188_CLK_TOP_APLL1,
+	MT8188_CLK_TOP_APLL2,
+	MT8188_CLK_TOP_APLL12_DIV0,
+	MT8188_CLK_TOP_APLL12_DIV1,
+	MT8188_CLK_TOP_APLL12_DIV2,
+	MT8188_CLK_TOP_APLL12_DIV3,
+	MT8188_CLK_TOP_APLL12_DIV9,
+	/* mux */
+	MT8188_CLK_TOP_A1SYS_HP_SEL,
+	MT8188_CLK_TOP_AUD_INTBUS_SEL,
+	MT8188_CLK_TOP_AUDIO_H_SEL,
+	MT8188_CLK_TOP_AUDIO_LOCAL_BUS_SEL,
+	MT8188_CLK_TOP_DPTX_M_SEL,
+	MT8188_CLK_TOP_I2SO1_M_SEL,
+	MT8188_CLK_TOP_I2SO2_M_SEL,
+	MT8188_CLK_TOP_I2SI1_M_SEL,
+	MT8188_CLK_TOP_I2SI2_M_SEL,
+	/* clock gate */
+	MT8188_CLK_ADSP_AUDIO_26M,
+	MT8188_CLK_AUD_AFE,
+	MT8188_CLK_AUD_APLL1_TUNER,
+	MT8188_CLK_AUD_APLL2_TUNER,
+	MT8188_CLK_AUD_TOP0_SPDF,
+	MT8188_CLK_AUD_APLL,
+	MT8188_CLK_AUD_APLL2,
+	MT8188_CLK_AUD_DAC,
+	MT8188_CLK_AUD_ADC,
+	MT8188_CLK_AUD_DAC_HIRES,
+	MT8188_CLK_AUD_A1SYS_HP,
+	MT8188_CLK_AUD_ADC_HIRES,
+	MT8188_CLK_AUD_I2SIN,
+	MT8188_CLK_AUD_TDM_IN,
+	MT8188_CLK_AUD_I2S_OUT,
+	MT8188_CLK_AUD_TDM_OUT,
+	MT8188_CLK_AUD_HDMI_OUT,
+	MT8188_CLK_AUD_ASRC11,
+	MT8188_CLK_AUD_ASRC12,
+	MT8188_CLK_AUD_A1SYS,
+	MT8188_CLK_AUD_A2SYS,
+	MT8188_CLK_AUD_PCMIF,
+	MT8188_CLK_AUD_MEMIF_UL1,
+	MT8188_CLK_AUD_MEMIF_UL2,
+	MT8188_CLK_AUD_MEMIF_UL3,
+	MT8188_CLK_AUD_MEMIF_UL4,
+	MT8188_CLK_AUD_MEMIF_UL5,
+	MT8188_CLK_AUD_MEMIF_UL6,
+	MT8188_CLK_AUD_MEMIF_UL8,
+	MT8188_CLK_AUD_MEMIF_UL9,
+	MT8188_CLK_AUD_MEMIF_UL10,
+	MT8188_CLK_AUD_MEMIF_DL2,
+	MT8188_CLK_AUD_MEMIF_DL3,
+	MT8188_CLK_AUD_MEMIF_DL6,
+	MT8188_CLK_AUD_MEMIF_DL7,
+	MT8188_CLK_AUD_MEMIF_DL8,
+	MT8188_CLK_AUD_MEMIF_DL10,
+	MT8188_CLK_AUD_MEMIF_DL11,
+	MT8188_CLK_NUM,
+};
+
+enum {
+	MT8188_AUD_PLL1,
+	MT8188_AUD_PLL2,
+	MT8188_AUD_PLL3,
+	MT8188_AUD_PLL4,
+	MT8188_AUD_PLL5,
+	MT8188_AUD_PLL_NUM,
+};
+
+enum {
+	MT8188_MCK_SEL_26M,
+	MT8188_MCK_SEL_APLL1,
+	MT8188_MCK_SEL_APLL2,
+	MT8188_MCK_SEL_APLL3,
+	MT8188_MCK_SEL_APLL4,
+	MT8188_MCK_SEL_APLL5,
+	MT8188_MCK_SEL_NUM,
+};
+
+struct mtk_base_afe;
+
+int mt8188_afe_get_mclk_source_clk_id(int sel);
+int mt8188_afe_get_mclk_source_rate(struct mtk_base_afe *afe, int apll);
+int mt8188_afe_get_default_mclk_source_by_rate(int rate);
+int mt8188_afe_init_clock(struct mtk_base_afe *afe);
+void mt8188_afe_deinit_clock(void *priv);
+int mt8188_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
+void mt8188_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
+int mt8188_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk,
+			    unsigned int rate);
+int mt8188_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk,
+			      struct clk *parent);
+int mt8188_afe_enable_main_clock(struct mtk_base_afe *afe);
+int mt8188_afe_disable_main_clock(struct mtk_base_afe *afe);
+int mt8188_afe_enable_reg_rw_clk(struct mtk_base_afe *afe);
+int mt8188_afe_disable_reg_rw_clk(struct mtk_base_afe *afe);
+
+#endif
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 08/12] ASoC: mediatek: mt8188: add platform driver
  2022-10-21  8:27 [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC Trevor Wu
                   ` (5 preceding siblings ...)
  2022-10-21  8:27 ` [PATCH v2 07/12] ASoC: mediatek: mt8188: support audio clock control Trevor Wu
@ 2022-10-21  8:27 ` Trevor Wu
  2022-10-21  8:27 ` [PATCH v2 09/12] ASoC: mediatek: mt8188: add control for timing select Trevor Wu
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Trevor Wu @ 2022-10-21  8:27 UTC (permalink / raw)
  To: broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: trevor.wu, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Add mt8188 platform driver.

Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
---
 sound/soc/mediatek/Kconfig                 |   13 +
 sound/soc/mediatek/Makefile                |    1 +
 sound/soc/mediatek/mt8188/Makefile         |   12 +
 sound/soc/mediatek/mt8188/mt8188-afe-pcm.c | 2853 ++++++++++++++++++++
 4 files changed, 2879 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8188/Makefile
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-pcm.c

diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 363fa4d47680..cf0e4c6b61e7 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -206,6 +206,19 @@ config SND_SOC_MTK_BTCVSD
 	  Select Y if you have such device.
 	  If unsure select "N".
 
+config SND_SOC_MT8188
+	tristate "ASoC support for Mediatek MT8188 chip"
+	depends on ARCH_MEDIATEK || COMPILE_TEST
+	depends on COMMON_CLK
+	select SND_SOC_MEDIATEK
+	select SND_SOC_MT6359
+	select MFD_SYSCON if SND_SOC_MT6359
+	help
+	  This adds ASoC platform driver support for Mediatek MT8188 chip
+	  that can be used with other codecs.
+	  Select Y if you have such device.
+	  If unsure select "N".
+
 config SND_SOC_MT8192
 	tristate "ASoC support for Mediatek MT8192 chip"
 	depends on ARCH_MEDIATEK
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
index 5571c640a288..3de38cfc69e5 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -5,5 +5,6 @@ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
 obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
 obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
 obj-$(CONFIG_SND_SOC_MT8186) += mt8186/
+obj-$(CONFIG_SND_SOC_MT8188) += mt8188/
 obj-$(CONFIG_SND_SOC_MT8192) += mt8192/
 obj-$(CONFIG_SND_SOC_MT8195) += mt8195/
diff --git a/sound/soc/mediatek/mt8188/Makefile b/sound/soc/mediatek/mt8188/Makefile
new file mode 100644
index 000000000000..fa5d383c5e47
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# platform driver
+snd-soc-mt8188-afe-objs := \
+	mt8188-afe-clk.o \
+	mt8188-afe-pcm.o \
+	mt8188-audsys-clk.o \
+	mt8188-dai-adda.o \
+	mt8188-dai-etdm.o \
+	mt8188-dai-pcm.o
+
+obj-$(CONFIG_SND_SOC_MT8188) += snd-soc-mt8188-afe.o
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
new file mode 100644
index 000000000000..6bef980846fa
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
@@ -0,0 +1,2853 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC AFE platform driver for 8188
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Bicycle Tsai <bicycle.tsai@mediatek.com>
+ *         Trevor Wu <trevor.wu@mediatek.com>
+ *         Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <sound/pcm_params.h>
+#include "mt8188-afe-common.h"
+#include "mt8188-afe-clk.h"
+#include "mt8188-reg.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+#define MT8188_MEMIF_BUFFER_BYTES_ALIGN  (0x40)
+#define MT8188_MEMIF_DL7_MAX_PERIOD_SIZE (0x3fff)
+
+#define MEMIF_AXI_MINLEN 9 /* register default value */
+
+struct mtk_dai_memif_priv {
+	unsigned int asys_timing_sel;
+	unsigned int fs_timing;
+};
+
+static const struct snd_pcm_hardware mt8188_afe_hardware = {
+	.info = SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE |
+		   SNDRV_PCM_FMTBIT_S24_LE |
+		   SNDRV_PCM_FMTBIT_S32_LE,
+	.period_bytes_min = 64,
+	.period_bytes_max = 256 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
+	.buffer_bytes_max = 256 * 2 * 1024,
+};
+
+struct mt8188_afe_rate {
+	unsigned int rate;
+	unsigned int reg_value;
+};
+
+static const struct mt8188_afe_rate mt8188_afe_rates[] = {
+	{ .rate = 8000, .reg_value = 0, },
+	{ .rate = 12000, .reg_value = 1, },
+	{ .rate = 16000, .reg_value = 2, },
+	{ .rate = 24000, .reg_value = 3, },
+	{ .rate = 32000, .reg_value = 4, },
+	{ .rate = 48000, .reg_value = 5, },
+	{ .rate = 96000, .reg_value = 6, },
+	{ .rate = 192000, .reg_value = 7, },
+	{ .rate = 384000, .reg_value = 8, },
+	{ .rate = 7350, .reg_value = 16, },
+	{ .rate = 11025, .reg_value = 17, },
+	{ .rate = 14700, .reg_value = 18, },
+	{ .rate = 22050, .reg_value = 19, },
+	{ .rate = 29400, .reg_value = 20, },
+	{ .rate = 44100, .reg_value = 21, },
+	{ .rate = 88200, .reg_value = 22, },
+	{ .rate = 176400, .reg_value = 23, },
+	{ .rate = 352800, .reg_value = 24, },
+};
+
+int mt8188_afe_fs_timing(unsigned int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mt8188_afe_rates); i++)
+		if (mt8188_afe_rates[i].rate == rate)
+			return mt8188_afe_rates[i].reg_value;
+
+	return -EINVAL;
+}
+
+static int mt8188_memif_fs(struct snd_pcm_substream *substream,
+			   unsigned int rate)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_component *component = NULL;
+	struct mtk_base_afe *afe = NULL;
+	struct mt8188_afe_private *afe_priv = NULL;
+	struct mtk_base_afe_memif *memif = NULL;
+	struct mtk_dai_memif_priv *memif_priv = NULL;
+	int fs = mt8188_afe_fs_timing(rate);
+	int id = asoc_rtd_to_cpu(rtd, 0)->id;
+
+	if (id < 0)
+		return -EINVAL;
+
+	component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	if (!component)
+		return -EINVAL;
+
+	afe = snd_soc_component_get_drvdata(component);
+	memif = &afe->memif[id];
+
+	switch (memif->data->id) {
+	case MT8188_AFE_MEMIF_DL10:
+		fs = MT8188_ETDM_OUT3_1X_EN;
+		break;
+	case MT8188_AFE_MEMIF_UL8:
+		fs = MT8188_ETDM_IN1_NX_EN;
+		break;
+	case MT8188_AFE_MEMIF_UL3:
+		fs = MT8188_ETDM_IN2_NX_EN;
+		break;
+	default:
+		afe_priv = afe->platform_priv;
+		memif_priv = afe_priv->dai_priv[id];
+		if (memif_priv->fs_timing)
+			fs = memif_priv->fs_timing;
+		break;
+	}
+
+	return fs;
+}
+
+static int mt8188_irq_fs(struct snd_pcm_substream *substream,
+			 unsigned int rate)
+{
+	int fs = mt8188_memif_fs(substream, rate);
+
+	switch (fs) {
+	case MT8188_ETDM_IN1_NX_EN:
+		fs = MT8188_ETDM_IN1_1X_EN;
+		break;
+	case MT8188_ETDM_IN2_NX_EN:
+		fs = MT8188_ETDM_IN2_1X_EN;
+		break;
+	default:
+		break;
+	}
+
+	return fs;
+}
+
+enum {
+	MT8188_AFE_CM0,
+	MT8188_AFE_CM1,
+	MT8188_AFE_CM2,
+	MT8188_AFE_CM_NUM,
+};
+
+struct mt8188_afe_channel_merge {
+	int id;
+	int reg;
+	unsigned int sel_shift;
+	unsigned int sel_maskbit;
+	unsigned int sel_default;
+	unsigned int ch_num_shift;
+	unsigned int ch_num_maskbit;
+	unsigned int en_shift;
+	unsigned int en_maskbit;
+	unsigned int update_cnt_shift;
+	unsigned int update_cnt_maskbit;
+	unsigned int update_cnt_default;
+};
+
+static const struct mt8188_afe_channel_merge
+	mt8188_afe_cm[MT8188_AFE_CM_NUM] = {
+	[MT8188_AFE_CM0] = {
+		.id = MT8188_AFE_CM0,
+		.reg = AFE_CM0_CON,
+		.sel_shift = 30,
+		.sel_maskbit = 0x1,
+		.sel_default = 1,
+		.ch_num_shift = 2,
+		.ch_num_maskbit = 0x3f,
+		.en_shift = 0,
+		.en_maskbit = 0x1,
+		.update_cnt_shift = 16,
+		.update_cnt_maskbit = 0x1fff,
+		.update_cnt_default = 0x3,
+	},
+	[MT8188_AFE_CM1] = {
+		.id = MT8188_AFE_CM1,
+		.reg = AFE_CM1_CON,
+		.sel_shift = 30,
+		.sel_maskbit = 0x1,
+		.sel_default = 1,
+		.ch_num_shift = 2,
+		.ch_num_maskbit = 0x1f,
+		.en_shift = 0,
+		.en_maskbit = 0x1,
+		.update_cnt_shift = 16,
+		.update_cnt_maskbit = 0x1fff,
+		.update_cnt_default = 0x3,
+	},
+	[MT8188_AFE_CM2] = {
+		.id = MT8188_AFE_CM2,
+		.reg = AFE_CM2_CON,
+		.sel_shift = 30,
+		.sel_maskbit = 0x1,
+		.sel_default = 1,
+		.ch_num_shift = 2,
+		.ch_num_maskbit = 0x1f,
+		.en_shift = 0,
+		.en_maskbit = 0x1,
+		.update_cnt_shift = 16,
+		.update_cnt_maskbit = 0x1fff,
+		.update_cnt_default = 0x3,
+	},
+};
+
+static int mt8188_afe_memif_is_ul(int id)
+{
+	if (id >= MT8188_AFE_MEMIF_UL_START && id < MT8188_AFE_MEMIF_END)
+		return 1;
+	else
+		return 0;
+}
+
+static const struct mt8188_afe_channel_merge *
+	mt8188_afe_found_cm(struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	int id = -EINVAL;
+
+	if (mt8188_afe_memif_is_ul(dai->id) == 0)
+		return NULL;
+
+	switch (dai->id) {
+	case MT8188_AFE_MEMIF_UL9:
+		id = MT8188_AFE_CM0;
+		break;
+	case MT8188_AFE_MEMIF_UL2:
+		id = MT8188_AFE_CM1;
+		break;
+	case MT8188_AFE_MEMIF_UL10:
+		id = MT8188_AFE_CM2;
+		break;
+	default:
+		break;
+	}
+
+	if (id < 0) {
+		dev_dbg(afe->dev, "%s, memif %d cannot find CM!\n", __func__, dai->id);
+		return NULL;
+	}
+
+	return &mt8188_afe_cm[id];
+}
+
+static int mt8188_afe_config_cm(struct mtk_base_afe *afe,
+				const struct mt8188_afe_channel_merge *cm,
+				unsigned int channels)
+{
+	if (!cm)
+		return -EINVAL;
+
+	regmap_update_bits(afe->regmap,
+			   cm->reg,
+			   cm->sel_maskbit << cm->sel_shift,
+			   cm->sel_default << cm->sel_shift);
+
+	regmap_update_bits(afe->regmap,
+			   cm->reg,
+			   cm->ch_num_maskbit << cm->ch_num_shift,
+			   (channels - 1) << cm->ch_num_shift);
+
+	regmap_update_bits(afe->regmap,
+			   cm->reg,
+			   cm->update_cnt_maskbit << cm->update_cnt_shift,
+			   cm->update_cnt_default << cm->update_cnt_shift);
+
+	return 0;
+}
+
+static int mt8188_afe_enable_cm(struct mtk_base_afe *afe,
+				const struct mt8188_afe_channel_merge *cm,
+				bool enable)
+{
+	if (!cm)
+		return -EINVAL;
+
+	regmap_update_bits(afe->regmap,
+			   cm->reg,
+			   cm->en_maskbit << cm->en_shift,
+			   enable << cm->en_shift);
+
+	return 0;
+}
+
+static int mt8188_afe_fe_startup(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	int id = asoc_rtd_to_cpu(rtd, 0)->id;
+	int ret;
+
+	ret = mtk_afe_fe_startup(substream, dai);
+
+	snd_pcm_hw_constraint_step(runtime, 0,
+				   SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+				   MT8188_MEMIF_BUFFER_BYTES_ALIGN);
+
+	if (id != MT8188_AFE_MEMIF_DL7)
+		goto out;
+
+	ret = snd_pcm_hw_constraint_minmax(runtime,
+					   SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 1,
+					   MT8188_MEMIF_DL7_MAX_PERIOD_SIZE);
+	if (ret < 0)
+		dev_dbg(afe->dev, "hw_constraint_minmax failed\n");
+out:
+	return ret;
+}
+
+static void mt8188_afe_fe_shutdown(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	mtk_afe_fe_shutdown(substream, dai);
+}
+
+static int mt8188_afe_fe_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	int id = asoc_rtd_to_cpu(rtd, 0)->id;
+	struct mtk_base_afe_memif *memif = &afe->memif[id];
+	const struct mtk_base_memif_data *data = memif->data;
+	const struct mt8188_afe_channel_merge *cm = mt8188_afe_found_cm(dai);
+	unsigned int channels = params_channels(params);
+
+	mt8188_afe_config_cm(afe, cm, channels);
+
+	if (data->ch_num_reg >= 0) {
+		regmap_update_bits(afe->regmap, data->ch_num_reg,
+				   data->ch_num_maskbit << data->ch_num_shift,
+				   channels << data->ch_num_shift);
+	}
+
+	return mtk_afe_fe_hw_params(substream, params, dai);
+}
+
+static int mt8188_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
+				 struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	const struct mt8188_afe_channel_merge *cm = mt8188_afe_found_cm(dai);
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_pcm_runtime * const runtime = substream->runtime;
+	int id = asoc_rtd_to_cpu(rtd, 0)->id;
+	struct mtk_base_afe_memif *memif = &afe->memif[id];
+	struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];
+	const struct mtk_base_irq_data *irq_data = irqs->irq_data;
+	unsigned int counter = runtime->period_size;
+	int fs;
+	int ret;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		mt8188_afe_enable_cm(afe, cm, true);
+
+		ret = mtk_memif_set_enable(afe, id);
+		if (ret) {
+			dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",
+				__func__, id, ret);
+			return ret;
+		}
+
+		/* set irq counter */
+		regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,
+				   irq_data->irq_cnt_maskbit << irq_data->irq_cnt_shift,
+				   counter << irq_data->irq_cnt_shift);
+
+		/* set irq fs */
+		fs = afe->irq_fs(substream, runtime->rate);
+
+		if (fs < 0)
+			return -EINVAL;
+
+		if (irq_data->irq_fs_reg >= 0)
+			regmap_update_bits(afe->regmap, irq_data->irq_fs_reg,
+					   irq_data->irq_fs_maskbit << irq_data->irq_fs_shift,
+					   fs << irq_data->irq_fs_shift);
+
+		/* delay for uplink */
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			u32 sample_delay;
+
+			sample_delay = ((MEMIF_AXI_MINLEN + 1) * 64 +
+					(runtime->channels * runtime->sample_bits - 1)) /
+					(runtime->channels * runtime->sample_bits) + 1;
+
+			udelay(sample_delay * 1000000 / runtime->rate);
+		}
+
+		/* enable interrupt */
+		regmap_set_bits(afe->regmap, irq_data->irq_en_reg,
+				BIT(irq_data->irq_en_shift));
+		return 0;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		mt8188_afe_enable_cm(afe, cm, false);
+
+		ret = mtk_memif_set_disable(afe, id);
+		if (ret)
+			dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",
+				__func__, id, ret);
+
+		/* disable interrupt */
+
+		regmap_clear_bits(afe->regmap, irq_data->irq_en_reg,
+				  BIT(irq_data->irq_en_shift));
+		/* and clear pending IRQ */
+		regmap_write(afe->regmap, irq_data->irq_clr_reg,
+			     BIT(irq_data->irq_clr_shift));
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct snd_soc_dai_ops mt8188_afe_fe_dai_ops = {
+	.startup	= mt8188_afe_fe_startup,
+	.shutdown	= mt8188_afe_fe_shutdown,
+	.hw_params	= mt8188_afe_fe_hw_params,
+	.hw_free	= mtk_afe_fe_hw_free,
+	.prepare	= mtk_afe_fe_prepare,
+	.trigger	= mt8188_afe_fe_trigger,
+};
+
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+		       SNDRV_PCM_RATE_88200 |\
+		       SNDRV_PCM_RATE_96000 |\
+		       SNDRV_PCM_RATE_176400 |\
+		       SNDRV_PCM_RATE_192000 |\
+		       SNDRV_PCM_RATE_352800 |\
+		       SNDRV_PCM_RATE_384000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mt8188_memif_dai_driver[] = {
+	/* FE DAIs: memory intefaces to CPU */
+	{
+		.name = "DL2",
+		.id = MT8188_AFE_MEMIF_DL2,
+		.playback = {
+			.stream_name = "DL2",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "DL3",
+		.id = MT8188_AFE_MEMIF_DL3,
+		.playback = {
+			.stream_name = "DL3",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "DL6",
+		.id = MT8188_AFE_MEMIF_DL6,
+		.playback = {
+			.stream_name = "DL6",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "DL7",
+		.id = MT8188_AFE_MEMIF_DL7,
+		.playback = {
+			.stream_name = "DL7",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "DL8",
+		.id = MT8188_AFE_MEMIF_DL8,
+		.playback = {
+			.stream_name = "DL8",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "DL10",
+		.id = MT8188_AFE_MEMIF_DL10,
+		.playback = {
+			.stream_name = "DL10",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "DL11",
+		.id = MT8188_AFE_MEMIF_DL11,
+		.playback = {
+			.stream_name = "DL11",
+			.channels_min = 1,
+			.channels_max = 32,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "UL1",
+		.id = MT8188_AFE_MEMIF_UL1,
+		.capture = {
+			.stream_name = "UL1",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "UL2",
+		.id = MT8188_AFE_MEMIF_UL2,
+		.capture = {
+			.stream_name = "UL2",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "UL3",
+		.id = MT8188_AFE_MEMIF_UL3,
+		.capture = {
+			.stream_name = "UL3",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "UL4",
+		.id = MT8188_AFE_MEMIF_UL4,
+		.capture = {
+			.stream_name = "UL4",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "UL5",
+		.id = MT8188_AFE_MEMIF_UL5,
+		.capture = {
+			.stream_name = "UL5",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "UL6",
+		.id = MT8188_AFE_MEMIF_UL6,
+		.capture = {
+			.stream_name = "UL6",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "UL8",
+		.id = MT8188_AFE_MEMIF_UL8,
+		.capture = {
+			.stream_name = "UL8",
+			.channels_min = 1,
+			.channels_max = 24,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "UL9",
+		.id = MT8188_AFE_MEMIF_UL9,
+		.capture = {
+			.stream_name = "UL9",
+			.channels_min = 1,
+			.channels_max = 32,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+	{
+		.name = "UL10",
+		.id = MT8188_AFE_MEMIF_UL10,
+		.capture = {
+			.stream_name = "UL10",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mt8188_afe_fe_dai_ops,
+	},
+};
+
+static const struct snd_kcontrol_new o002_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN2, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I012 Switch", AFE_CONN2, 12, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN2, 20, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN2, 22, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN2_2, 6, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I072 Switch", AFE_CONN2_2, 8, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I168 Switch", AFE_CONN2_5, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new o003_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN3, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I013 Switch", AFE_CONN3, 13, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN3, 21, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN3, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN3_2, 7, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I073 Switch", AFE_CONN3_2, 9, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I169 Switch", AFE_CONN3_5, 9, 1, 0),
+};
+
+static const struct snd_kcontrol_new o004_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN4, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I014 Switch", AFE_CONN4, 14, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I024 Switch", AFE_CONN4, 24, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I074 Switch", AFE_CONN4_2, 10, 1, 0),
+};
+
+static const struct snd_kcontrol_new o005_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN5, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I015 Switch", AFE_CONN5, 15, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I025 Switch", AFE_CONN5, 25, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I075 Switch", AFE_CONN5_2, 11, 1, 0),
+};
+
+static const struct snd_kcontrol_new o006_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN6, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I016 Switch", AFE_CONN6, 16, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I026 Switch", AFE_CONN6, 26, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I076 Switch", AFE_CONN6_2, 12, 1, 0),
+};
+
+static const struct snd_kcontrol_new o007_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN7, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I017 Switch", AFE_CONN7, 17, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I027 Switch", AFE_CONN7, 27, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I077 Switch", AFE_CONN7_2, 13, 1, 0),
+};
+
+static const struct snd_kcontrol_new o008_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I018 Switch", AFE_CONN8, 18, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I028 Switch", AFE_CONN8, 28, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I078 Switch", AFE_CONN8_2, 14, 1, 0),
+};
+
+static const struct snd_kcontrol_new o009_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I019 Switch", AFE_CONN9, 19, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I029 Switch", AFE_CONN9, 29, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I079 Switch", AFE_CONN9_2, 15, 1, 0),
+};
+
+static const struct snd_kcontrol_new o010_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN10, 22, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I030 Switch", AFE_CONN10, 30, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I046 Switch", AFE_CONN10_1, 14, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I072 Switch", AFE_CONN10_2, 8, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I080 Switch", AFE_CONN10_2, 16, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I188 Switch", AFE_CONN10_5, 28, 1, 0),
+};
+
+static const struct snd_kcontrol_new o011_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN11, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I031 Switch", AFE_CONN11, 31, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I047 Switch", AFE_CONN11_1, 15, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I073 Switch", AFE_CONN11_2, 9, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I081 Switch", AFE_CONN11_2, 17, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I189 Switch", AFE_CONN11_5, 29, 1, 0),
+};
+
+static const struct snd_kcontrol_new o012_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I024 Switch", AFE_CONN12, 24, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I032 Switch", AFE_CONN12_1, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I048 Switch", AFE_CONN12_1, 16, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I074 Switch", AFE_CONN12_2, 10, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I082 Switch", AFE_CONN12_2, 18, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I190 Switch", AFE_CONN12_5, 30, 1, 0),
+};
+
+static const struct snd_kcontrol_new o013_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I025 Switch", AFE_CONN13, 25, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I033 Switch", AFE_CONN13_1, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I049 Switch", AFE_CONN13_1, 17, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I075 Switch", AFE_CONN13_2, 11, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I083 Switch", AFE_CONN13_2, 19, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I191 Switch", AFE_CONN13_5, 31, 1, 0),
+};
+
+static const struct snd_kcontrol_new o014_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I026 Switch", AFE_CONN14, 26, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I034 Switch", AFE_CONN14_1, 2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I050 Switch", AFE_CONN14_1, 18, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I076 Switch", AFE_CONN14_2, 12, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I084 Switch", AFE_CONN14_2, 20, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I192 Switch", AFE_CONN14_6, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new o015_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I027 Switch", AFE_CONN15, 27, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I035 Switch", AFE_CONN15_1, 3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I051 Switch", AFE_CONN15_1, 19, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I077 Switch", AFE_CONN15_2, 13, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I085 Switch", AFE_CONN15_2, 21, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I193 Switch", AFE_CONN15_6, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new o016_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I028 Switch", AFE_CONN16, 28, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I036 Switch", AFE_CONN16_1, 4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I052 Switch", AFE_CONN16_1, 20, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I078 Switch", AFE_CONN16_2, 14, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I086 Switch", AFE_CONN16_2, 22, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I194 Switch", AFE_CONN16_6, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new o017_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I029 Switch", AFE_CONN17, 29, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I037 Switch", AFE_CONN17_1, 5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I053 Switch", AFE_CONN17_1, 21, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I079 Switch", AFE_CONN17_2, 15, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I087 Switch", AFE_CONN17_2, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I195 Switch", AFE_CONN17_6, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new o018_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I080 Switch", AFE_CONN18_2, 16, 1, 0),
+};
+
+static const struct snd_kcontrol_new o019_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I081 Switch", AFE_CONN19_2, 17, 1, 0),
+};
+
+static const struct snd_kcontrol_new o020_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I082 Switch", AFE_CONN20_2, 18, 1, 0),
+};
+
+static const struct snd_kcontrol_new o021_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I083 Switch", AFE_CONN21_2, 19, 1, 0),
+};
+
+static const struct snd_kcontrol_new o022_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I084 Switch", AFE_CONN22_2, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new o023_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I085 Switch", AFE_CONN23_2, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new o024_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I086 Switch", AFE_CONN24_2, 22, 1, 0),
+};
+
+static const struct snd_kcontrol_new o025_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I087 Switch", AFE_CONN25_2, 23, 1, 0),
+};
+
+static const struct snd_kcontrol_new o026_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I046 Switch", AFE_CONN26_1, 14, 1, 0),
+};
+
+static const struct snd_kcontrol_new o027_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I047 Switch", AFE_CONN27_1, 15, 1, 0),
+};
+
+static const struct snd_kcontrol_new o028_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I048 Switch", AFE_CONN28_1, 16, 1, 0),
+};
+
+static const struct snd_kcontrol_new o029_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I049 Switch", AFE_CONN29_1, 17, 1, 0),
+};
+
+static const struct snd_kcontrol_new o030_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I050 Switch", AFE_CONN30_1, 18, 1, 0),
+};
+
+static const struct snd_kcontrol_new o031_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I051 Switch", AFE_CONN31_1, 19, 1, 0),
+};
+
+static const struct snd_kcontrol_new o032_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I052 Switch", AFE_CONN32_1, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new o033_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I053 Switch", AFE_CONN33_1, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new o034_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN34, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I002 Switch", AFE_CONN34, 2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I012 Switch", AFE_CONN34, 12, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN34, 20, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN34_2, 6, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I072 Switch", AFE_CONN34_2, 8, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I168 Switch", AFE_CONN34_5, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new o035_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN35, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I003 Switch", AFE_CONN35, 3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I013 Switch", AFE_CONN35, 13, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN35, 21, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN35_2, 7, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I073 Switch", AFE_CONN35_2, 9, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I168 Switch", AFE_CONN35_5, 8, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I169 Switch", AFE_CONN35_5, 9, 1, 0),
+};
+
+static const struct snd_kcontrol_new o036_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN36, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I012 Switch", AFE_CONN36, 12, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN36, 20, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN36_2, 6, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I168 Switch", AFE_CONN36_5, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new o037_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN37, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I013 Switch", AFE_CONN37, 13, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN37, 21, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN37_2, 7, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I169 Switch", AFE_CONN37_5, 9, 1, 0),
+};
+
+static const struct snd_kcontrol_new o038_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN38, 22, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I168 Switch", AFE_CONN38_5, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new o039_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN39, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I169 Switch", AFE_CONN39_5, 9, 1, 0),
+};
+
+static const struct snd_kcontrol_new o040_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I002 Switch", AFE_CONN40, 2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I012 Switch", AFE_CONN40, 12, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN40, 22, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I168 Switch", AFE_CONN40_5, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new o041_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I003 Switch", AFE_CONN41, 3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I013 Switch", AFE_CONN41, 13, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN41, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I169 Switch", AFE_CONN41_5, 9, 1, 0),
+};
+
+static const struct snd_kcontrol_new o042_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I014 Switch", AFE_CONN42, 14, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I024 Switch", AFE_CONN42, 24, 1, 0),
+};
+
+static const struct snd_kcontrol_new o043_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I015 Switch", AFE_CONN43, 15, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I025 Switch", AFE_CONN43, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new o044_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I016 Switch", AFE_CONN44, 16, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I026 Switch", AFE_CONN44, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new o045_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I017 Switch", AFE_CONN45, 17, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I027 Switch", AFE_CONN45, 27, 1, 0),
+};
+
+static const struct snd_kcontrol_new o046_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I018 Switch", AFE_CONN46, 18, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I028 Switch", AFE_CONN46, 28, 1, 0),
+};
+
+static const struct snd_kcontrol_new o047_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I019 Switch", AFE_CONN47, 19, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I029 Switch", AFE_CONN47, 29, 1, 0),
+};
+
+static const struct snd_kcontrol_new o182_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN182, 20, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN182, 22, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I024 Switch", AFE_CONN182, 24, 1, 0),
+};
+
+static const struct snd_kcontrol_new o183_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN183, 21, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN183, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I025 Switch", AFE_CONN183, 25, 1, 0),
+};
+
+static const char * const dl8_dl11_data_sel_mux_text[] = {
+	"dl8", "dl11",
+};
+
+static SOC_ENUM_SINGLE_DECL(dl8_dl11_data_sel_mux_enum,
+			    AFE_DAC_CON2, 0, dl8_dl11_data_sel_mux_text);
+
+static const struct snd_kcontrol_new dl8_dl11_data_sel_mux =
+	SOC_DAPM_ENUM("DL8_DL11 Sink",
+		      dl8_dl11_data_sel_mux_enum);
+
+static const struct snd_soc_dapm_widget mt8188_memif_widgets[] = {
+	/* DL6 */
+	SND_SOC_DAPM_MIXER("I000", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I001", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DL3 */
+	SND_SOC_DAPM_MIXER("I020", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I021", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DL11 */
+	SND_SOC_DAPM_MIXER("I022", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I023", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I024", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I025", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I026", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I027", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I028", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I029", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I030", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I031", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I032", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I033", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I034", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I035", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I036", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I037", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DL11/DL8 */
+	SND_SOC_DAPM_MIXER("I046", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I047", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I048", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I049", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I050", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I051", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I052", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I053", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I054", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I055", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I056", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I057", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I058", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I059", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I060", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I061", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DL2 */
+	SND_SOC_DAPM_MIXER("I070", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I071", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("DL8_DL11 Mux",
+			 SND_SOC_NOPM, 0, 0, &dl8_dl11_data_sel_mux),
+
+	/* UL9 */
+	SND_SOC_DAPM_MIXER("O002", SND_SOC_NOPM, 0, 0,
+			   o002_mix, ARRAY_SIZE(o002_mix)),
+	SND_SOC_DAPM_MIXER("O003", SND_SOC_NOPM, 0, 0,
+			   o003_mix, ARRAY_SIZE(o003_mix)),
+	SND_SOC_DAPM_MIXER("O004", SND_SOC_NOPM, 0, 0,
+			   o004_mix, ARRAY_SIZE(o004_mix)),
+	SND_SOC_DAPM_MIXER("O005", SND_SOC_NOPM, 0, 0,
+			   o005_mix, ARRAY_SIZE(o005_mix)),
+	SND_SOC_DAPM_MIXER("O006", SND_SOC_NOPM, 0, 0,
+			   o006_mix, ARRAY_SIZE(o006_mix)),
+	SND_SOC_DAPM_MIXER("O007", SND_SOC_NOPM, 0, 0,
+			   o007_mix, ARRAY_SIZE(o007_mix)),
+	SND_SOC_DAPM_MIXER("O008", SND_SOC_NOPM, 0, 0,
+			   o008_mix, ARRAY_SIZE(o008_mix)),
+	SND_SOC_DAPM_MIXER("O009", SND_SOC_NOPM, 0, 0,
+			   o009_mix, ARRAY_SIZE(o009_mix)),
+	SND_SOC_DAPM_MIXER("O010", SND_SOC_NOPM, 0, 0,
+			   o010_mix, ARRAY_SIZE(o010_mix)),
+	SND_SOC_DAPM_MIXER("O011", SND_SOC_NOPM, 0, 0,
+			   o011_mix, ARRAY_SIZE(o011_mix)),
+	SND_SOC_DAPM_MIXER("O012", SND_SOC_NOPM, 0, 0,
+			   o012_mix, ARRAY_SIZE(o012_mix)),
+	SND_SOC_DAPM_MIXER("O013", SND_SOC_NOPM, 0, 0,
+			   o013_mix, ARRAY_SIZE(o013_mix)),
+	SND_SOC_DAPM_MIXER("O014", SND_SOC_NOPM, 0, 0,
+			   o014_mix, ARRAY_SIZE(o014_mix)),
+	SND_SOC_DAPM_MIXER("O015", SND_SOC_NOPM, 0, 0,
+			   o015_mix, ARRAY_SIZE(o015_mix)),
+	SND_SOC_DAPM_MIXER("O016", SND_SOC_NOPM, 0, 0,
+			   o016_mix, ARRAY_SIZE(o016_mix)),
+	SND_SOC_DAPM_MIXER("O017", SND_SOC_NOPM, 0, 0,
+			   o017_mix, ARRAY_SIZE(o017_mix)),
+	SND_SOC_DAPM_MIXER("O018", SND_SOC_NOPM, 0, 0,
+			   o018_mix, ARRAY_SIZE(o018_mix)),
+	SND_SOC_DAPM_MIXER("O019", SND_SOC_NOPM, 0, 0,
+			   o019_mix, ARRAY_SIZE(o019_mix)),
+	SND_SOC_DAPM_MIXER("O020", SND_SOC_NOPM, 0, 0,
+			   o020_mix, ARRAY_SIZE(o020_mix)),
+	SND_SOC_DAPM_MIXER("O021", SND_SOC_NOPM, 0, 0,
+			   o021_mix, ARRAY_SIZE(o021_mix)),
+	SND_SOC_DAPM_MIXER("O022", SND_SOC_NOPM, 0, 0,
+			   o022_mix, ARRAY_SIZE(o022_mix)),
+	SND_SOC_DAPM_MIXER("O023", SND_SOC_NOPM, 0, 0,
+			   o023_mix, ARRAY_SIZE(o023_mix)),
+	SND_SOC_DAPM_MIXER("O024", SND_SOC_NOPM, 0, 0,
+			   o024_mix, ARRAY_SIZE(o024_mix)),
+	SND_SOC_DAPM_MIXER("O025", SND_SOC_NOPM, 0, 0,
+			   o025_mix, ARRAY_SIZE(o025_mix)),
+	SND_SOC_DAPM_MIXER("O026", SND_SOC_NOPM, 0, 0,
+			   o026_mix, ARRAY_SIZE(o026_mix)),
+	SND_SOC_DAPM_MIXER("O027", SND_SOC_NOPM, 0, 0,
+			   o027_mix, ARRAY_SIZE(o027_mix)),
+	SND_SOC_DAPM_MIXER("O028", SND_SOC_NOPM, 0, 0,
+			   o028_mix, ARRAY_SIZE(o028_mix)),
+	SND_SOC_DAPM_MIXER("O029", SND_SOC_NOPM, 0, 0,
+			   o029_mix, ARRAY_SIZE(o029_mix)),
+	SND_SOC_DAPM_MIXER("O030", SND_SOC_NOPM, 0, 0,
+			   o030_mix, ARRAY_SIZE(o030_mix)),
+	SND_SOC_DAPM_MIXER("O031", SND_SOC_NOPM, 0, 0,
+			   o031_mix, ARRAY_SIZE(o031_mix)),
+	SND_SOC_DAPM_MIXER("O032", SND_SOC_NOPM, 0, 0,
+			   o032_mix, ARRAY_SIZE(o032_mix)),
+	SND_SOC_DAPM_MIXER("O033", SND_SOC_NOPM, 0, 0,
+			   o033_mix, ARRAY_SIZE(o033_mix)),
+
+	/* UL4 */
+	SND_SOC_DAPM_MIXER("O034", SND_SOC_NOPM, 0, 0,
+			   o034_mix, ARRAY_SIZE(o034_mix)),
+	SND_SOC_DAPM_MIXER("O035", SND_SOC_NOPM, 0, 0,
+			   o035_mix, ARRAY_SIZE(o035_mix)),
+
+	/* UL5 */
+	SND_SOC_DAPM_MIXER("O036", SND_SOC_NOPM, 0, 0,
+			   o036_mix, ARRAY_SIZE(o036_mix)),
+	SND_SOC_DAPM_MIXER("O037", SND_SOC_NOPM, 0, 0,
+			   o037_mix, ARRAY_SIZE(o037_mix)),
+
+	/* UL10 */
+	SND_SOC_DAPM_MIXER("O038", SND_SOC_NOPM, 0, 0,
+			   o038_mix, ARRAY_SIZE(o038_mix)),
+	SND_SOC_DAPM_MIXER("O039", SND_SOC_NOPM, 0, 0,
+			   o039_mix, ARRAY_SIZE(o039_mix)),
+	SND_SOC_DAPM_MIXER("O182", SND_SOC_NOPM, 0, 0,
+			   o182_mix, ARRAY_SIZE(o182_mix)),
+	SND_SOC_DAPM_MIXER("O183", SND_SOC_NOPM, 0, 0,
+			   o183_mix, ARRAY_SIZE(o183_mix)),
+
+	/* UL2 */
+	SND_SOC_DAPM_MIXER("O040", SND_SOC_NOPM, 0, 0,
+			   o040_mix, ARRAY_SIZE(o040_mix)),
+	SND_SOC_DAPM_MIXER("O041", SND_SOC_NOPM, 0, 0,
+			   o041_mix, ARRAY_SIZE(o041_mix)),
+	SND_SOC_DAPM_MIXER("O042", SND_SOC_NOPM, 0, 0,
+			   o042_mix, ARRAY_SIZE(o042_mix)),
+	SND_SOC_DAPM_MIXER("O043", SND_SOC_NOPM, 0, 0,
+			   o043_mix, ARRAY_SIZE(o043_mix)),
+	SND_SOC_DAPM_MIXER("O044", SND_SOC_NOPM, 0, 0,
+			   o044_mix, ARRAY_SIZE(o044_mix)),
+	SND_SOC_DAPM_MIXER("O045", SND_SOC_NOPM, 0, 0,
+			   o045_mix, ARRAY_SIZE(o045_mix)),
+	SND_SOC_DAPM_MIXER("O046", SND_SOC_NOPM, 0, 0,
+			   o046_mix, ARRAY_SIZE(o046_mix)),
+	SND_SOC_DAPM_MIXER("O047", SND_SOC_NOPM, 0, 0,
+			   o047_mix, ARRAY_SIZE(o047_mix)),
+};
+
+static const struct snd_soc_dapm_route mt8188_memif_routes[] = {
+	{"I000", NULL, "DL6"},
+	{"I001", NULL, "DL6"},
+
+	{"I020", NULL, "DL3"},
+	{"I021", NULL, "DL3"},
+
+	{"I022", NULL, "DL11"},
+	{"I023", NULL, "DL11"},
+	{"I024", NULL, "DL11"},
+	{"I025", NULL, "DL11"},
+	{"I026", NULL, "DL11"},
+	{"I027", NULL, "DL11"},
+	{"I028", NULL, "DL11"},
+	{"I029", NULL, "DL11"},
+	{"I030", NULL, "DL11"},
+	{"I031", NULL, "DL11"},
+	{"I032", NULL, "DL11"},
+	{"I033", NULL, "DL11"},
+	{"I034", NULL, "DL11"},
+	{"I035", NULL, "DL11"},
+	{"I036", NULL, "DL11"},
+	{"I037", NULL, "DL11"},
+
+	{"DL8_DL11 Mux", "dl8", "DL8"},
+	{"DL8_DL11 Mux", "dl11", "DL11"},
+
+	{"I046", NULL, "DL8_DL11 Mux"},
+	{"I047", NULL, "DL8_DL11 Mux"},
+	{"I048", NULL, "DL8_DL11 Mux"},
+	{"I049", NULL, "DL8_DL11 Mux"},
+	{"I050", NULL, "DL8_DL11 Mux"},
+	{"I051", NULL, "DL8_DL11 Mux"},
+	{"I052", NULL, "DL8_DL11 Mux"},
+	{"I053", NULL, "DL8_DL11 Mux"},
+	{"I054", NULL, "DL8_DL11 Mux"},
+	{"I055", NULL, "DL8_DL11 Mux"},
+	{"I056", NULL, "DL8_DL11 Mux"},
+	{"I057", NULL, "DL8_DL11 Mux"},
+	{"I058", NULL, "DL8_DL11 Mux"},
+	{"I059", NULL, "DL8_DL11 Mux"},
+	{"I060", NULL, "DL8_DL11 Mux"},
+	{"I061", NULL, "DL8_DL11 Mux"},
+
+	{"I070", NULL, "DL2"},
+	{"I071", NULL, "DL2"},
+
+	{"UL9", NULL, "O002"},
+	{"UL9", NULL, "O003"},
+	{"UL9", NULL, "O004"},
+	{"UL9", NULL, "O005"},
+	{"UL9", NULL, "O006"},
+	{"UL9", NULL, "O007"},
+	{"UL9", NULL, "O008"},
+	{"UL9", NULL, "O009"},
+	{"UL9", NULL, "O010"},
+	{"UL9", NULL, "O011"},
+	{"UL9", NULL, "O012"},
+	{"UL9", NULL, "O013"},
+	{"UL9", NULL, "O014"},
+	{"UL9", NULL, "O015"},
+	{"UL9", NULL, "O016"},
+	{"UL9", NULL, "O017"},
+	{"UL9", NULL, "O018"},
+	{"UL9", NULL, "O019"},
+	{"UL9", NULL, "O020"},
+	{"UL9", NULL, "O021"},
+	{"UL9", NULL, "O022"},
+	{"UL9", NULL, "O023"},
+	{"UL9", NULL, "O024"},
+	{"UL9", NULL, "O025"},
+	{"UL9", NULL, "O026"},
+	{"UL9", NULL, "O027"},
+	{"UL9", NULL, "O028"},
+	{"UL9", NULL, "O029"},
+	{"UL9", NULL, "O030"},
+	{"UL9", NULL, "O031"},
+	{"UL9", NULL, "O032"},
+	{"UL9", NULL, "O033"},
+
+	{"UL4", NULL, "O034"},
+	{"UL4", NULL, "O035"},
+
+	{"UL5", NULL, "O036"},
+	{"UL5", NULL, "O037"},
+
+	{"UL10", NULL, "O038"},
+	{"UL10", NULL, "O039"},
+	{"UL10", NULL, "O182"},
+	{"UL10", NULL, "O183"},
+
+	{"UL2", NULL, "O040"},
+	{"UL2", NULL, "O041"},
+	{"UL2", NULL, "O042"},
+	{"UL2", NULL, "O043"},
+	{"UL2", NULL, "O044"},
+	{"UL2", NULL, "O045"},
+	{"UL2", NULL, "O046"},
+	{"UL2", NULL, "O047"},
+
+	{"O004", "I000 Switch", "I000"},
+	{"O005", "I001 Switch", "I001"},
+
+	{"O006", "I000 Switch", "I000"},
+	{"O007", "I001 Switch", "I001"},
+
+	{"O010", "I022 Switch", "I022"},
+	{"O011", "I023 Switch", "I023"},
+	{"O012", "I024 Switch", "I024"},
+	{"O013", "I025 Switch", "I025"},
+	{"O014", "I026 Switch", "I026"},
+	{"O015", "I027 Switch", "I027"},
+	{"O016", "I028 Switch", "I028"},
+	{"O017", "I029 Switch", "I029"},
+
+	{"O010", "I046 Switch", "I046"},
+	{"O011", "I047 Switch", "I047"},
+	{"O012", "I048 Switch", "I048"},
+	{"O013", "I049 Switch", "I049"},
+	{"O014", "I050 Switch", "I050"},
+	{"O015", "I051 Switch", "I051"},
+	{"O016", "I052 Switch", "I052"},
+	{"O017", "I053 Switch", "I053"},
+
+	{"O002", "I022 Switch", "I022"},
+	{"O003", "I023 Switch", "I023"},
+	{"O004", "I024 Switch", "I024"},
+	{"O005", "I025 Switch", "I025"},
+	{"O006", "I026 Switch", "I026"},
+	{"O007", "I027 Switch", "I027"},
+	{"O008", "I028 Switch", "I028"},
+	{"O009", "I029 Switch", "I029"},
+	{"O010", "I030 Switch", "I030"},
+	{"O011", "I031 Switch", "I031"},
+	{"O012", "I032 Switch", "I032"},
+	{"O013", "I033 Switch", "I033"},
+	{"O014", "I034 Switch", "I034"},
+	{"O015", "I035 Switch", "I035"},
+	{"O016", "I036 Switch", "I036"},
+	{"O017", "I037 Switch", "I037"},
+	{"O026", "I046 Switch", "I046"},
+	{"O027", "I047 Switch", "I047"},
+	{"O028", "I048 Switch", "I048"},
+	{"O029", "I049 Switch", "I049"},
+	{"O030", "I050 Switch", "I050"},
+	{"O031", "I051 Switch", "I051"},
+	{"O032", "I052 Switch", "I052"},
+	{"O033", "I053 Switch", "I053"},
+
+	{"O002", "I000 Switch", "I000"},
+	{"O003", "I001 Switch", "I001"},
+	{"O002", "I020 Switch", "I020"},
+	{"O003", "I021 Switch", "I021"},
+	{"O002", "I070 Switch", "I070"},
+	{"O003", "I071 Switch", "I071"},
+
+	{"O034", "I000 Switch", "I000"},
+	{"O035", "I001 Switch", "I001"},
+	{"O034", "I002 Switch", "I002"},
+	{"O035", "I003 Switch", "I003"},
+	{"O034", "I012 Switch", "I012"},
+	{"O035", "I013 Switch", "I013"},
+	{"O034", "I020 Switch", "I020"},
+	{"O035", "I021 Switch", "I021"},
+	{"O034", "I070 Switch", "I070"},
+	{"O035", "I071 Switch", "I071"},
+	{"O034", "I072 Switch", "I072"},
+	{"O035", "I073 Switch", "I073"},
+
+	{"O036", "I000 Switch", "I000"},
+	{"O037", "I001 Switch", "I001"},
+	{"O036", "I012 Switch", "I012"},
+	{"O037", "I013 Switch", "I013"},
+	{"O036", "I020 Switch", "I020"},
+	{"O037", "I021 Switch", "I021"},
+	{"O036", "I070 Switch", "I070"},
+	{"O037", "I071 Switch", "I071"},
+	{"O036", "I168 Switch", "I168"},
+	{"O037", "I169 Switch", "I169"},
+
+	{"O038", "I022 Switch", "I022"},
+	{"O039", "I023 Switch", "I023"},
+	{"O182", "I024 Switch", "I024"},
+	{"O183", "I025 Switch", "I025"},
+
+	{"O038", "I168 Switch", "I168"},
+	{"O039", "I169 Switch", "I169"},
+
+	{"O182", "I020 Switch", "I020"},
+	{"O183", "I021 Switch", "I021"},
+
+	{"O182", "I022 Switch", "I022"},
+	{"O183", "I023 Switch", "I023"},
+
+	{"O040", "I022 Switch", "I022"},
+	{"O041", "I023 Switch", "I023"},
+	{"O042", "I024 Switch", "I024"},
+	{"O043", "I025 Switch", "I025"},
+	{"O044", "I026 Switch", "I026"},
+	{"O045", "I027 Switch", "I027"},
+	{"O046", "I028 Switch", "I028"},
+	{"O047", "I029 Switch", "I029"},
+
+	{"O040", "I002 Switch", "I002"},
+	{"O041", "I003 Switch", "I003"},
+
+	{"O002", "I012 Switch", "I012"},
+	{"O003", "I013 Switch", "I013"},
+	{"O004", "I014 Switch", "I014"},
+	{"O005", "I015 Switch", "I015"},
+	{"O006", "I016 Switch", "I016"},
+	{"O007", "I017 Switch", "I017"},
+	{"O008", "I018 Switch", "I018"},
+	{"O009", "I019 Switch", "I019"},
+	{"O010", "I188 Switch", "I188"},
+	{"O011", "I189 Switch", "I189"},
+	{"O012", "I190 Switch", "I190"},
+	{"O013", "I191 Switch", "I191"},
+	{"O014", "I192 Switch", "I192"},
+	{"O015", "I193 Switch", "I193"},
+	{"O016", "I194 Switch", "I194"},
+	{"O017", "I195 Switch", "I195"},
+
+	{"O040", "I012 Switch", "I012"},
+	{"O041", "I013 Switch", "I013"},
+	{"O042", "I014 Switch", "I014"},
+	{"O043", "I015 Switch", "I015"},
+	{"O044", "I016 Switch", "I016"},
+	{"O045", "I017 Switch", "I017"},
+	{"O046", "I018 Switch", "I018"},
+	{"O047", "I019 Switch", "I019"},
+
+	{"O002", "I072 Switch", "I072"},
+	{"O003", "I073 Switch", "I073"},
+	{"O004", "I074 Switch", "I074"},
+	{"O005", "I075 Switch", "I075"},
+	{"O006", "I076 Switch", "I076"},
+	{"O007", "I077 Switch", "I077"},
+	{"O008", "I078 Switch", "I078"},
+	{"O009", "I079 Switch", "I079"},
+	{"O010", "I080 Switch", "I080"},
+	{"O011", "I081 Switch", "I081"},
+	{"O012", "I082 Switch", "I082"},
+	{"O013", "I083 Switch", "I083"},
+	{"O014", "I084 Switch", "I084"},
+	{"O015", "I085 Switch", "I085"},
+	{"O016", "I086 Switch", "I086"},
+	{"O017", "I087 Switch", "I087"},
+
+	{"O010", "I072 Switch", "I072"},
+	{"O011", "I073 Switch", "I073"},
+	{"O012", "I074 Switch", "I074"},
+	{"O013", "I075 Switch", "I075"},
+	{"O014", "I076 Switch", "I076"},
+	{"O015", "I077 Switch", "I077"},
+	{"O016", "I078 Switch", "I078"},
+	{"O017", "I079 Switch", "I079"},
+	{"O018", "I080 Switch", "I080"},
+	{"O019", "I081 Switch", "I081"},
+	{"O020", "I082 Switch", "I082"},
+	{"O021", "I083 Switch", "I083"},
+	{"O022", "I084 Switch", "I084"},
+	{"O023", "I085 Switch", "I085"},
+	{"O024", "I086 Switch", "I086"},
+	{"O025", "I087 Switch", "I087"},
+
+	{"O002", "I168 Switch", "I168"},
+	{"O003", "I169 Switch", "I169"},
+
+	{"O034", "I168 Switch", "I168"},
+	{"O035", "I168 Switch", "I168"},
+	{"O035", "I169 Switch", "I169"},
+
+	{"O040", "I168 Switch", "I168"},
+	{"O041", "I169 Switch", "I169"},
+};
+
+static const struct snd_soc_component_driver mt8188_afe_pcm_dai_component = {
+	.name = "mt8188-afe-pcm-dai",
+};
+
+static const struct mtk_base_memif_data memif_data[MT8188_AFE_MEMIF_NUM] = {
+	[MT8188_AFE_MEMIF_DL2] = {
+		.name = "DL2",
+		.id = MT8188_AFE_MEMIF_DL2,
+		.reg_ofs_base = AFE_DL2_BASE,
+		.reg_ofs_cur = AFE_DL2_CUR,
+		.reg_ofs_end = AFE_DL2_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON0,
+		.fs_shift = 10,
+		.fs_maskbit = 0x1f,
+		.mono_reg = -1,
+		.mono_shift = 0,
+		.int_odd_flag_reg = -1,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 18,
+		.hd_reg = AFE_DL2_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 18,
+		.ch_num_reg = AFE_DL2_CON0,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0x1f,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 18,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 18,
+	},
+	[MT8188_AFE_MEMIF_DL3] = {
+		.name = "DL3",
+		.id = MT8188_AFE_MEMIF_DL3,
+		.reg_ofs_base = AFE_DL3_BASE,
+		.reg_ofs_cur = AFE_DL3_CUR,
+		.reg_ofs_end = AFE_DL3_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON0,
+		.fs_shift = 15,
+		.fs_maskbit = 0x1f,
+		.mono_reg = -1,
+		.mono_shift = 0,
+		.int_odd_flag_reg = -1,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 19,
+		.hd_reg = AFE_DL3_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 19,
+		.ch_num_reg = AFE_DL3_CON0,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0x1f,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 19,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 19,
+	},
+	[MT8188_AFE_MEMIF_DL6] = {
+		.name = "DL6",
+		.id = MT8188_AFE_MEMIF_DL6,
+		.reg_ofs_base = AFE_DL6_BASE,
+		.reg_ofs_cur = AFE_DL6_CUR,
+		.reg_ofs_end = AFE_DL6_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON1,
+		.fs_shift = 0,
+		.fs_maskbit = 0x1f,
+		.mono_reg = -1,
+		.mono_shift = 0,
+		.int_odd_flag_reg = -1,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 22,
+		.hd_reg = AFE_DL6_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 22,
+		.ch_num_reg = AFE_DL6_CON0,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0x1f,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 22,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 22,
+	},
+	[MT8188_AFE_MEMIF_DL7] = {
+		.name = "DL7",
+		.id = MT8188_AFE_MEMIF_DL7,
+		.reg_ofs_base = AFE_DL7_BASE,
+		.reg_ofs_cur = AFE_DL7_CUR,
+		.reg_ofs_end = AFE_DL7_END,
+		.fs_reg = -1,
+		.fs_shift = 0,
+		.fs_maskbit = 0,
+		.mono_reg = -1,
+		.mono_shift = 0,
+		.int_odd_flag_reg = -1,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 23,
+		.hd_reg = AFE_DL7_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 23,
+		.ch_num_reg = AFE_DL7_CON0,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0x1f,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 23,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 23,
+	},
+	[MT8188_AFE_MEMIF_DL8] = {
+		.name = "DL8",
+		.id = MT8188_AFE_MEMIF_DL8,
+		.reg_ofs_base = AFE_DL8_BASE,
+		.reg_ofs_cur = AFE_DL8_CUR,
+		.reg_ofs_end = AFE_DL8_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON1,
+		.fs_shift = 10,
+		.fs_maskbit = 0x1f,
+		.mono_reg = -1,
+		.mono_shift = 0,
+		.int_odd_flag_reg = -1,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 24,
+		.hd_reg = AFE_DL8_CON0,
+		.hd_shift = 6,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 24,
+		.ch_num_reg = AFE_DL8_CON0,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0x3f,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 24,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 24,
+	},
+	[MT8188_AFE_MEMIF_DL10] = {
+		.name = "DL10",
+		.id = MT8188_AFE_MEMIF_DL10,
+		.reg_ofs_base = AFE_DL10_BASE,
+		.reg_ofs_cur = AFE_DL10_CUR,
+		.reg_ofs_end = AFE_DL10_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON1,
+		.fs_shift = 20,
+		.fs_maskbit = 0x1f,
+		.mono_reg = -1,
+		.mono_shift = 0,
+		.int_odd_flag_reg = -1,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 26,
+		.hd_reg = AFE_DL10_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 26,
+		.ch_num_reg = AFE_DL10_CON0,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0x1f,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 26,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 26,
+	},
+	[MT8188_AFE_MEMIF_DL11] = {
+		.name = "DL11",
+		.id = MT8188_AFE_MEMIF_DL11,
+		.reg_ofs_base = AFE_DL11_BASE,
+		.reg_ofs_cur = AFE_DL11_CUR,
+		.reg_ofs_end = AFE_DL11_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON1,
+		.fs_shift = 25,
+		.fs_maskbit = 0x1f,
+		.mono_reg = -1,
+		.mono_shift = 0,
+		.int_odd_flag_reg = -1,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 27,
+		.hd_reg = AFE_DL11_CON0,
+		.hd_shift = 7,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 27,
+		.ch_num_reg = AFE_DL11_CON0,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0x7f,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 27,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 27,
+	},
+	[MT8188_AFE_MEMIF_UL1] = {
+		.name = "UL1",
+		.id = MT8188_AFE_MEMIF_UL1,
+		.reg_ofs_base = AFE_UL1_BASE,
+		.reg_ofs_cur = AFE_UL1_CUR,
+		.reg_ofs_end = AFE_UL1_END,
+		.fs_reg = -1,
+		.fs_shift = 0,
+		.fs_maskbit = 0,
+		.mono_reg = AFE_UL1_CON0,
+		.mono_shift = 1,
+		.int_odd_flag_reg = AFE_UL1_CON0,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 1,
+		.hd_reg = AFE_UL1_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 0,
+		.ch_num_reg = -1,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 0,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 0,
+	},
+	[MT8188_AFE_MEMIF_UL2] = {
+		.name = "UL2",
+		.id = MT8188_AFE_MEMIF_UL2,
+		.reg_ofs_base = AFE_UL2_BASE,
+		.reg_ofs_cur = AFE_UL2_CUR,
+		.reg_ofs_end = AFE_UL2_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON2,
+		.fs_shift = 5,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_UL2_CON0,
+		.mono_shift = 1,
+		.int_odd_flag_reg = AFE_UL2_CON0,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 2,
+		.hd_reg = AFE_UL2_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 1,
+		.ch_num_reg = -1,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 1,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 1,
+	},
+	[MT8188_AFE_MEMIF_UL3] = {
+		.name = "UL3",
+		.id = MT8188_AFE_MEMIF_UL3,
+		.reg_ofs_base = AFE_UL3_BASE,
+		.reg_ofs_cur = AFE_UL3_CUR,
+		.reg_ofs_end = AFE_UL3_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON2,
+		.fs_shift = 10,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_UL3_CON0,
+		.mono_shift = 1,
+		.int_odd_flag_reg = AFE_UL3_CON0,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 3,
+		.hd_reg = AFE_UL3_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 2,
+		.ch_num_reg = -1,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 2,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 2,
+	},
+	[MT8188_AFE_MEMIF_UL4] = {
+		.name = "UL4",
+		.id = MT8188_AFE_MEMIF_UL4,
+		.reg_ofs_base = AFE_UL4_BASE,
+		.reg_ofs_cur = AFE_UL4_CUR,
+		.reg_ofs_end = AFE_UL4_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON2,
+		.fs_shift = 15,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_UL4_CON0,
+		.mono_shift = 1,
+		.int_odd_flag_reg = AFE_UL4_CON0,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 4,
+		.hd_reg = AFE_UL4_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 3,
+		.ch_num_reg = -1,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 3,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 3,
+	},
+	[MT8188_AFE_MEMIF_UL5] = {
+		.name = "UL5",
+		.id = MT8188_AFE_MEMIF_UL5,
+		.reg_ofs_base = AFE_UL5_BASE,
+		.reg_ofs_cur = AFE_UL5_CUR,
+		.reg_ofs_end = AFE_UL5_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON2,
+		.fs_shift = 20,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_UL5_CON0,
+		.mono_shift = 1,
+		.int_odd_flag_reg = AFE_UL5_CON0,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 5,
+		.hd_reg = AFE_UL5_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 4,
+		.ch_num_reg = -1,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 4,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 4,
+	},
+	[MT8188_AFE_MEMIF_UL6] = {
+		.name = "UL6",
+		.id = MT8188_AFE_MEMIF_UL6,
+		.reg_ofs_base = AFE_UL6_BASE,
+		.reg_ofs_cur = AFE_UL6_CUR,
+		.reg_ofs_end = AFE_UL6_END,
+		.fs_reg = -1,
+		.fs_shift = 0,
+		.fs_maskbit = 0,
+		.mono_reg = AFE_UL6_CON0,
+		.mono_shift = 1,
+		.int_odd_flag_reg = AFE_UL6_CON0,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 6,
+		.hd_reg = AFE_UL6_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 5,
+		.ch_num_reg = -1,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 5,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 5,
+	},
+	[MT8188_AFE_MEMIF_UL8] = {
+		.name = "UL8",
+		.id = MT8188_AFE_MEMIF_UL8,
+		.reg_ofs_base = AFE_UL8_BASE,
+		.reg_ofs_cur = AFE_UL8_CUR,
+		.reg_ofs_end = AFE_UL8_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON3,
+		.fs_shift = 5,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_UL8_CON0,
+		.mono_shift = 1,
+		.int_odd_flag_reg = AFE_UL8_CON0,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 8,
+		.hd_reg = AFE_UL8_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 7,
+		.ch_num_reg = -1,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 7,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 7,
+	},
+	[MT8188_AFE_MEMIF_UL9] = {
+		.name = "UL9",
+		.id = MT8188_AFE_MEMIF_UL9,
+		.reg_ofs_base = AFE_UL9_BASE,
+		.reg_ofs_cur = AFE_UL9_CUR,
+		.reg_ofs_end = AFE_UL9_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON3,
+		.fs_shift = 10,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_UL9_CON0,
+		.mono_shift = 1,
+		.int_odd_flag_reg = AFE_UL9_CON0,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 9,
+		.hd_reg = AFE_UL9_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 8,
+		.ch_num_reg = -1,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 8,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 8,
+	},
+	[MT8188_AFE_MEMIF_UL10] = {
+		.name = "UL10",
+		.id = MT8188_AFE_MEMIF_UL10,
+		.reg_ofs_base = AFE_UL10_BASE,
+		.reg_ofs_cur = AFE_UL10_CUR,
+		.reg_ofs_end = AFE_UL10_END,
+		.fs_reg = AFE_MEMIF_AGENT_FS_CON3,
+		.fs_shift = 15,
+		.fs_maskbit = 0x1f,
+		.mono_reg = AFE_UL10_CON0,
+		.mono_shift = 1,
+		.int_odd_flag_reg = AFE_UL10_CON0,
+		.int_odd_flag_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 10,
+		.hd_reg = AFE_UL10_CON0,
+		.hd_shift = 5,
+		.agent_disable_reg = AUDIO_TOP_CON5,
+		.agent_disable_shift = 9,
+		.ch_num_reg = -1,
+		.ch_num_shift = 0,
+		.ch_num_maskbit = 0,
+		.msb_reg = AFE_NORMAL_BASE_ADR_MSB,
+		.msb_shift = 9,
+		.msb_end_reg = AFE_NORMAL_END_ADR_MSB,
+		.msb_end_shift = 9,
+	},
+};
+
+static const struct mtk_base_irq_data irq_data[MT8188_AFE_IRQ_NUM] = {
+	[MT8188_AFE_IRQ_1] = {
+		.id = MT8188_AFE_IRQ_1,
+		.irq_cnt_reg = -1,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0,
+		.irq_fs_reg = -1,
+		.irq_fs_shift = 0,
+		.irq_fs_maskbit = 0,
+		.irq_en_reg = AFE_IRQ1_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 0,
+		.irq_status_shift = 16,
+	},
+	[MT8188_AFE_IRQ_2] = {
+		.id = MT8188_AFE_IRQ_2,
+		.irq_cnt_reg = -1,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0,
+		.irq_fs_reg = -1,
+		.irq_fs_shift = 0,
+		.irq_fs_maskbit = 0,
+		.irq_en_reg = AFE_IRQ2_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 1,
+		.irq_status_shift = 17,
+	},
+	[MT8188_AFE_IRQ_3] = {
+		.id = MT8188_AFE_IRQ_3,
+		.irq_cnt_reg = AFE_IRQ3_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = -1,
+		.irq_fs_shift = 0,
+		.irq_fs_maskbit = 0,
+		.irq_en_reg = AFE_IRQ3_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 2,
+		.irq_status_shift = 18,
+	},
+	[MT8188_AFE_IRQ_8] = {
+		.id = MT8188_AFE_IRQ_8,
+		.irq_cnt_reg = -1,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0,
+		.irq_fs_reg = -1,
+		.irq_fs_shift = 0,
+		.irq_fs_maskbit = 0,
+		.irq_en_reg = AFE_IRQ8_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 7,
+		.irq_status_shift = 23,
+	},
+	[MT8188_AFE_IRQ_9] = {
+		.id = MT8188_AFE_IRQ_9,
+		.irq_cnt_reg = AFE_IRQ9_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = -1,
+		.irq_fs_shift = 0,
+		.irq_fs_maskbit = 0,
+		.irq_en_reg = AFE_IRQ9_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 8,
+		.irq_status_shift = 24,
+	},
+	[MT8188_AFE_IRQ_10] = {
+		.id = MT8188_AFE_IRQ_10,
+		.irq_cnt_reg = -1,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0,
+		.irq_fs_reg = -1,
+		.irq_fs_shift = 0,
+		.irq_fs_maskbit = 0,
+		.irq_en_reg = AFE_IRQ10_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 9,
+		.irq_status_shift = 25,
+	},
+	[MT8188_AFE_IRQ_13] = {
+		.id = MT8188_AFE_IRQ_13,
+		.irq_cnt_reg = ASYS_IRQ1_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ1_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ1_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 0,
+		.irq_status_shift = 0,
+	},
+	[MT8188_AFE_IRQ_14] = {
+		.id = MT8188_AFE_IRQ_14,
+		.irq_cnt_reg = ASYS_IRQ2_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ2_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ2_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 1,
+		.irq_status_shift = 1,
+	},
+	[MT8188_AFE_IRQ_15] = {
+		.id = MT8188_AFE_IRQ_15,
+		.irq_cnt_reg = ASYS_IRQ3_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ3_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ3_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 2,
+		.irq_status_shift = 2,
+	},
+	[MT8188_AFE_IRQ_16] = {
+		.id = MT8188_AFE_IRQ_16,
+		.irq_cnt_reg = ASYS_IRQ4_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ4_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ4_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 3,
+		.irq_status_shift = 3,
+	},
+	[MT8188_AFE_IRQ_17] = {
+		.id = MT8188_AFE_IRQ_17,
+		.irq_cnt_reg = ASYS_IRQ5_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ5_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ5_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 4,
+		.irq_status_shift = 4,
+	},
+	[MT8188_AFE_IRQ_18] = {
+		.id = MT8188_AFE_IRQ_18,
+		.irq_cnt_reg = ASYS_IRQ6_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ6_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ6_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 5,
+		.irq_status_shift = 5,
+	},
+	[MT8188_AFE_IRQ_19] = {
+		.id = MT8188_AFE_IRQ_19,
+		.irq_cnt_reg = ASYS_IRQ7_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ7_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ7_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 6,
+		.irq_status_shift = 6,
+	},
+	[MT8188_AFE_IRQ_20] = {
+		.id = MT8188_AFE_IRQ_20,
+		.irq_cnt_reg = ASYS_IRQ8_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ8_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ8_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 7,
+		.irq_status_shift = 7,
+	},
+	[MT8188_AFE_IRQ_21] = {
+		.id = MT8188_AFE_IRQ_21,
+		.irq_cnt_reg = ASYS_IRQ9_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ9_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ9_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 8,
+		.irq_status_shift = 8,
+	},
+	[MT8188_AFE_IRQ_22] = {
+		.id = MT8188_AFE_IRQ_22,
+		.irq_cnt_reg = ASYS_IRQ10_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ10_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ10_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 9,
+		.irq_status_shift = 9,
+	},
+	[MT8188_AFE_IRQ_23] = {
+		.id = MT8188_AFE_IRQ_23,
+		.irq_cnt_reg = ASYS_IRQ11_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ11_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ11_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 10,
+		.irq_status_shift = 10,
+	},
+	[MT8188_AFE_IRQ_24] = {
+		.id = MT8188_AFE_IRQ_24,
+		.irq_cnt_reg = ASYS_IRQ12_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ12_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ12_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 11,
+		.irq_status_shift = 11,
+	},
+	[MT8188_AFE_IRQ_25] = {
+		.id = MT8188_AFE_IRQ_25,
+		.irq_cnt_reg = ASYS_IRQ13_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ13_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ13_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 12,
+		.irq_status_shift = 12,
+	},
+	[MT8188_AFE_IRQ_26] = {
+		.id = MT8188_AFE_IRQ_26,
+		.irq_cnt_reg = ASYS_IRQ14_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ14_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ14_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 13,
+		.irq_status_shift = 13,
+	},
+	[MT8188_AFE_IRQ_27] = {
+		.id = MT8188_AFE_IRQ_27,
+		.irq_cnt_reg = ASYS_IRQ15_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ15_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ15_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 14,
+		.irq_status_shift = 14,
+	},
+	[MT8188_AFE_IRQ_28] = {
+		.id = MT8188_AFE_IRQ_28,
+		.irq_cnt_reg = ASYS_IRQ16_CON,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0xffffff,
+		.irq_fs_reg = ASYS_IRQ16_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0x1ffff,
+		.irq_en_reg = ASYS_IRQ16_CON,
+		.irq_en_shift = 31,
+		.irq_clr_reg =  ASYS_IRQ_CLR,
+		.irq_clr_shift = 15,
+		.irq_status_shift = 15,
+	},
+};
+
+static const int mt8188_afe_memif_const_irqs[MT8188_AFE_MEMIF_NUM] = {
+	[MT8188_AFE_MEMIF_DL2] = MT8188_AFE_IRQ_13,
+	[MT8188_AFE_MEMIF_DL3] = MT8188_AFE_IRQ_14,
+	[MT8188_AFE_MEMIF_DL6] = MT8188_AFE_IRQ_15,
+	[MT8188_AFE_MEMIF_DL7] = MT8188_AFE_IRQ_1,
+	[MT8188_AFE_MEMIF_DL8] = MT8188_AFE_IRQ_16,
+	[MT8188_AFE_MEMIF_DL10] = MT8188_AFE_IRQ_17,
+	[MT8188_AFE_MEMIF_DL11] = MT8188_AFE_IRQ_18,
+	[MT8188_AFE_MEMIF_UL1] = MT8188_AFE_IRQ_3,
+	[MT8188_AFE_MEMIF_UL2] = MT8188_AFE_IRQ_19,
+	[MT8188_AFE_MEMIF_UL3] = MT8188_AFE_IRQ_20,
+	[MT8188_AFE_MEMIF_UL4] = MT8188_AFE_IRQ_21,
+	[MT8188_AFE_MEMIF_UL5] = MT8188_AFE_IRQ_22,
+	[MT8188_AFE_MEMIF_UL6] = MT8188_AFE_IRQ_9,
+	[MT8188_AFE_MEMIF_UL8] = MT8188_AFE_IRQ_23,
+	[MT8188_AFE_MEMIF_UL9] = MT8188_AFE_IRQ_24,
+	[MT8188_AFE_MEMIF_UL10] = MT8188_AFE_IRQ_25,
+};
+
+static bool mt8188_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	/* these auto-gen reg has read-only bit, so put it as volatile */
+	/* volatile reg cannot be cached, so cannot be set when power off */
+	switch (reg) {
+	case AUDIO_TOP_CON0:
+	case AUDIO_TOP_CON1:
+	case AUDIO_TOP_CON3:
+	case AUDIO_TOP_CON4:
+	case AUDIO_TOP_CON5:
+	case AUDIO_TOP_CON6:
+	case ASYS_IRQ_CLR:
+	case ASYS_IRQ_STATUS:
+	case ASYS_IRQ_MON1:
+	case ASYS_IRQ_MON2:
+	case AFE_IRQ_MCU_CLR:
+	case AFE_IRQ_STATUS:
+	case AFE_IRQ3_CON_MON:
+	case AFE_IRQ_MCU_MON2:
+	case ADSP_IRQ_STATUS:
+	case AUDIO_TOP_STA0:
+	case AUDIO_TOP_STA1:
+	case AFE_GAIN1_CUR:
+	case AFE_GAIN2_CUR:
+	case AFE_IEC_BURST_INFO:
+	case AFE_IEC_CHL_STAT0:
+	case AFE_IEC_CHL_STAT1:
+	case AFE_IEC_CHR_STAT0:
+	case AFE_IEC_CHR_STAT1:
+	case AFE_SPDIFIN_CHSTS1:
+	case AFE_SPDIFIN_CHSTS2:
+	case AFE_SPDIFIN_CHSTS3:
+	case AFE_SPDIFIN_CHSTS4:
+	case AFE_SPDIFIN_CHSTS5:
+	case AFE_SPDIFIN_CHSTS6:
+	case AFE_SPDIFIN_DEBUG1:
+	case AFE_SPDIFIN_DEBUG2:
+	case AFE_SPDIFIN_DEBUG3:
+	case AFE_SPDIFIN_DEBUG4:
+	case AFE_SPDIFIN_EC:
+	case AFE_SPDIFIN_CKLOCK_CFG:
+	case AFE_SPDIFIN_BR_DBG1:
+	case AFE_SPDIFIN_CKFBDIV:
+	case AFE_SPDIFIN_INT_EXT:
+	case AFE_SPDIFIN_INT_EXT2:
+	case SPDIFIN_FREQ_STATUS:
+	case SPDIFIN_USERCODE1:
+	case SPDIFIN_USERCODE2:
+	case SPDIFIN_USERCODE3:
+	case SPDIFIN_USERCODE4:
+	case SPDIFIN_USERCODE5:
+	case SPDIFIN_USERCODE6:
+	case SPDIFIN_USERCODE7:
+	case SPDIFIN_USERCODE8:
+	case SPDIFIN_USERCODE9:
+	case SPDIFIN_USERCODE10:
+	case SPDIFIN_USERCODE11:
+	case SPDIFIN_USERCODE12:
+	case AFE_LINEIN_APLL_TUNER_MON:
+	case AFE_EARC_APLL_TUNER_MON:
+	case AFE_CM0_MON:
+	case AFE_CM1_MON:
+	case AFE_CM2_MON:
+	case AFE_MPHONE_MULTI_DET_MON0:
+	case AFE_MPHONE_MULTI_DET_MON1:
+	case AFE_MPHONE_MULTI_DET_MON2:
+	case AFE_MPHONE_MULTI2_DET_MON0:
+	case AFE_MPHONE_MULTI2_DET_MON1:
+	case AFE_MPHONE_MULTI2_DET_MON2:
+	case AFE_ADDA_MTKAIF_MON0:
+	case AFE_ADDA_MTKAIF_MON1:
+	case AFE_AUD_PAD_TOP:
+	case AFE_ADDA6_MTKAIF_MON0:
+	case AFE_ADDA6_MTKAIF_MON1:
+	case AFE_ADDA6_SRC_DEBUG_MON0:
+	case AFE_ADDA6_UL_SRC_MON0:
+	case AFE_ADDA6_UL_SRC_MON1:
+	case AFE_ASRC11_NEW_CON8:
+	case AFE_ASRC11_NEW_CON9:
+	case AFE_ASRC12_NEW_CON8:
+	case AFE_ASRC12_NEW_CON9:
+	case AFE_LRCK_CNT:
+	case AFE_DAC_MON0:
+	case AFE_DL2_CUR:
+	case AFE_DL3_CUR:
+	case AFE_DL6_CUR:
+	case AFE_DL7_CUR:
+	case AFE_DL8_CUR:
+	case AFE_DL10_CUR:
+	case AFE_DL11_CUR:
+	case AFE_UL1_CUR:
+	case AFE_UL2_CUR:
+	case AFE_UL3_CUR:
+	case AFE_UL4_CUR:
+	case AFE_UL5_CUR:
+	case AFE_UL6_CUR:
+	case AFE_UL8_CUR:
+	case AFE_UL9_CUR:
+	case AFE_UL10_CUR:
+	case AFE_DL8_CHK_SUM1:
+	case AFE_DL8_CHK_SUM2:
+	case AFE_DL8_CHK_SUM3:
+	case AFE_DL8_CHK_SUM4:
+	case AFE_DL8_CHK_SUM5:
+	case AFE_DL8_CHK_SUM6:
+	case AFE_DL10_CHK_SUM1:
+	case AFE_DL10_CHK_SUM2:
+	case AFE_DL10_CHK_SUM3:
+	case AFE_DL10_CHK_SUM4:
+	case AFE_DL10_CHK_SUM5:
+	case AFE_DL10_CHK_SUM6:
+	case AFE_DL11_CHK_SUM1:
+	case AFE_DL11_CHK_SUM2:
+	case AFE_DL11_CHK_SUM3:
+	case AFE_DL11_CHK_SUM4:
+	case AFE_DL11_CHK_SUM5:
+	case AFE_DL11_CHK_SUM6:
+	case AFE_UL1_CHK_SUM1:
+	case AFE_UL1_CHK_SUM2:
+	case AFE_UL2_CHK_SUM1:
+	case AFE_UL2_CHK_SUM2:
+	case AFE_UL3_CHK_SUM1:
+	case AFE_UL3_CHK_SUM2:
+	case AFE_UL4_CHK_SUM1:
+	case AFE_UL4_CHK_SUM2:
+	case AFE_UL5_CHK_SUM1:
+	case AFE_UL5_CHK_SUM2:
+	case AFE_UL6_CHK_SUM1:
+	case AFE_UL6_CHK_SUM2:
+	case AFE_UL8_CHK_SUM1:
+	case AFE_UL8_CHK_SUM2:
+	case AFE_DL2_CHK_SUM1:
+	case AFE_DL2_CHK_SUM2:
+	case AFE_DL3_CHK_SUM1:
+	case AFE_DL3_CHK_SUM2:
+	case AFE_DL6_CHK_SUM1:
+	case AFE_DL6_CHK_SUM2:
+	case AFE_DL7_CHK_SUM1:
+	case AFE_DL7_CHK_SUM2:
+	case AFE_UL9_CHK_SUM1:
+	case AFE_UL9_CHK_SUM2:
+	case AFE_BUS_MON1:
+	case UL1_MOD2AGT_CNT_LAT:
+	case UL2_MOD2AGT_CNT_LAT:
+	case UL3_MOD2AGT_CNT_LAT:
+	case UL4_MOD2AGT_CNT_LAT:
+	case UL5_MOD2AGT_CNT_LAT:
+	case UL6_MOD2AGT_CNT_LAT:
+	case UL8_MOD2AGT_CNT_LAT:
+	case UL9_MOD2AGT_CNT_LAT:
+	case UL10_MOD2AGT_CNT_LAT:
+	case AFE_MEMIF_BUF_FULL_MON:
+	case AFE_MEMIF_BUF_MON1:
+	case AFE_MEMIF_BUF_MON3:
+	case AFE_MEMIF_BUF_MON4:
+	case AFE_MEMIF_BUF_MON5:
+	case AFE_MEMIF_BUF_MON6:
+	case AFE_MEMIF_BUF_MON7:
+	case AFE_MEMIF_BUF_MON8:
+	case AFE_MEMIF_BUF_MON9:
+	case AFE_MEMIF_BUF_MON10:
+	case DL2_AGENT2MODULE_CNT:
+	case DL3_AGENT2MODULE_CNT:
+	case DL6_AGENT2MODULE_CNT:
+	case DL7_AGENT2MODULE_CNT:
+	case DL8_AGENT2MODULE_CNT:
+	case DL10_AGENT2MODULE_CNT:
+	case DL11_AGENT2MODULE_CNT:
+	case UL1_MODULE2AGENT_CNT:
+	case UL2_MODULE2AGENT_CNT:
+	case UL3_MODULE2AGENT_CNT:
+	case UL4_MODULE2AGENT_CNT:
+	case UL5_MODULE2AGENT_CNT:
+	case UL6_MODULE2AGENT_CNT:
+	case UL8_MODULE2AGENT_CNT:
+	case UL9_MODULE2AGENT_CNT:
+	case UL10_MODULE2AGENT_CNT:
+	case AFE_DMIC0_SRC_DEBUG_MON0:
+	case AFE_DMIC0_UL_SRC_MON0:
+	case AFE_DMIC0_UL_SRC_MON1:
+	case AFE_DMIC1_SRC_DEBUG_MON0:
+	case AFE_DMIC1_UL_SRC_MON0:
+	case AFE_DMIC1_UL_SRC_MON1:
+	case AFE_DMIC2_SRC_DEBUG_MON0:
+	case AFE_DMIC2_UL_SRC_MON0:
+	case AFE_DMIC2_UL_SRC_MON1:
+	case AFE_DMIC3_SRC_DEBUG_MON0:
+	case AFE_DMIC3_UL_SRC_MON0:
+	case AFE_DMIC3_UL_SRC_MON1:
+	case DMIC_GAIN1_CUR:
+	case DMIC_GAIN2_CUR:
+	case DMIC_GAIN3_CUR:
+	case DMIC_GAIN4_CUR:
+	case ETDM_IN1_MONITOR:
+	case ETDM_IN2_MONITOR:
+	case ETDM_OUT1_MONITOR:
+	case ETDM_OUT2_MONITOR:
+	case ETDM_OUT3_MONITOR:
+	case AFE_ADDA_SRC_DEBUG_MON0:
+	case AFE_ADDA_SRC_DEBUG_MON1:
+	case AFE_ADDA_DL_SDM_FIFO_MON:
+	case AFE_ADDA_DL_SRC_LCH_MON:
+	case AFE_ADDA_DL_SRC_RCH_MON:
+	case AFE_ADDA_DL_SDM_OUT_MON:
+	case AFE_GASRC0_NEW_CON8:
+	case AFE_GASRC0_NEW_CON9:
+	case AFE_GASRC0_NEW_CON12:
+	case AFE_GASRC1_NEW_CON8:
+	case AFE_GASRC1_NEW_CON9:
+	case AFE_GASRC1_NEW_CON12:
+	case AFE_GASRC2_NEW_CON8:
+	case AFE_GASRC2_NEW_CON9:
+	case AFE_GASRC2_NEW_CON12:
+	case AFE_GASRC3_NEW_CON8:
+	case AFE_GASRC3_NEW_CON9:
+	case AFE_GASRC3_NEW_CON12:
+	case AFE_GASRC4_NEW_CON8:
+	case AFE_GASRC4_NEW_CON9:
+	case AFE_GASRC4_NEW_CON12:
+	case AFE_GASRC5_NEW_CON8:
+	case AFE_GASRC5_NEW_CON9:
+	case AFE_GASRC5_NEW_CON12:
+	case AFE_GASRC6_NEW_CON8:
+	case AFE_GASRC6_NEW_CON9:
+	case AFE_GASRC6_NEW_CON12:
+	case AFE_GASRC7_NEW_CON8:
+	case AFE_GASRC7_NEW_CON9:
+	case AFE_GASRC7_NEW_CON12:
+	case AFE_GASRC8_NEW_CON8:
+	case AFE_GASRC8_NEW_CON9:
+	case AFE_GASRC8_NEW_CON12:
+	case AFE_GASRC9_NEW_CON8:
+	case AFE_GASRC9_NEW_CON9:
+	case AFE_GASRC9_NEW_CON12:
+	case AFE_GASRC10_NEW_CON8:
+	case AFE_GASRC10_NEW_CON9:
+	case AFE_GASRC10_NEW_CON12:
+	case AFE_GASRC11_NEW_CON8:
+	case AFE_GASRC11_NEW_CON9:
+	case AFE_GASRC11_NEW_CON12:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config mt8188_afe_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.volatile_reg = mt8188_is_volatile_reg,
+	.max_register = AFE_MAX_REGISTER,
+	.num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1),
+	.cache_type = REGCACHE_FLAT,
+};
+
+#define AFE_IRQ_CLR_BITS (0x387)
+#define ASYS_IRQ_CLR_BITS (0xffff)
+
+static irqreturn_t mt8188_afe_irq_handler(int irq_id, void *dev_id)
+{
+	struct mtk_base_afe *afe = dev_id;
+	unsigned int val = 0;
+	unsigned int asys_irq_clr_bits = 0;
+	unsigned int afe_irq_clr_bits = 0;
+	unsigned int irq_status_bits = 0;
+	unsigned int irq_clr_bits = 0;
+	unsigned int mcu_irq_mask = 0;
+	int i = 0;
+	int ret = 0;
+
+	ret = regmap_read(afe->regmap, AFE_IRQ_STATUS, &val);
+	if (ret) {
+		dev_err(afe->dev, "%s irq status err\n", __func__);
+		afe_irq_clr_bits = AFE_IRQ_CLR_BITS;
+		asys_irq_clr_bits = ASYS_IRQ_CLR_BITS;
+		goto err_irq;
+	}
+
+	ret = regmap_read(afe->regmap, AFE_IRQ_MASK, &mcu_irq_mask);
+	if (ret) {
+		dev_err(afe->dev, "%s read irq mask err\n", __func__);
+		afe_irq_clr_bits = AFE_IRQ_CLR_BITS;
+		asys_irq_clr_bits = ASYS_IRQ_CLR_BITS;
+		goto err_irq;
+	}
+
+	/* only clr cpu irq */
+	val &= mcu_irq_mask;
+
+	for (i = 0; i < MT8188_AFE_MEMIF_NUM; i++) {
+		struct mtk_base_afe_memif *memif = &afe->memif[i];
+		struct mtk_base_irq_data const *irq_data;
+
+		if (memif->irq_usage < 0)
+			continue;
+
+		irq_data = afe->irqs[memif->irq_usage].irq_data;
+
+		irq_status_bits = BIT(irq_data->irq_status_shift);
+		irq_clr_bits = BIT(irq_data->irq_clr_shift);
+
+		if (!(val & irq_status_bits))
+			continue;
+
+		if (irq_data->irq_clr_reg == ASYS_IRQ_CLR)
+			asys_irq_clr_bits |= irq_clr_bits;
+		else
+			afe_irq_clr_bits |= irq_clr_bits;
+
+		snd_pcm_period_elapsed(memif->substream);
+	}
+
+err_irq:
+	/* clear irq */
+	if (asys_irq_clr_bits)
+		regmap_write(afe->regmap, ASYS_IRQ_CLR, asys_irq_clr_bits);
+	if (afe_irq_clr_bits)
+		regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, afe_irq_clr_bits);
+
+	return IRQ_HANDLED;
+}
+
+static int mt8188_afe_runtime_suspend(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+	if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+		goto skip_regmap;
+
+	mt8188_afe_disable_main_clock(afe);
+
+	regcache_cache_only(afe->regmap, true);
+	regcache_mark_dirty(afe->regmap);
+
+skip_regmap:
+	mt8188_afe_disable_reg_rw_clk(afe);
+
+	return 0;
+}
+
+static int mt8188_afe_runtime_resume(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(MTK_SIP_AUDIO_CONTROL,
+		      MTK_AUDIO_SMC_OP_DOMAIN_SIDEBANDS,
+		      0, 0, 0, 0, 0, 0, &res);
+
+	mt8188_afe_enable_reg_rw_clk(afe);
+
+	if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+		goto skip_regmap;
+
+	regcache_cache_only(afe->regmap, false);
+	regcache_sync(afe->regmap);
+
+	mt8188_afe_enable_main_clock(afe);
+skip_regmap:
+	return 0;
+}
+
+static int mt8188_afe_component_probe(struct snd_soc_component *component)
+{
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	snd_soc_component_init_regmap(component, afe->regmap);
+
+	ret = mtk_afe_add_sub_dai_control(component);
+
+	return ret;
+}
+
+static const struct snd_soc_component_driver mt8188_afe_component = {
+	.name = AFE_PCM_NAME,
+	.pointer       = mtk_afe_pcm_pointer,
+	.pcm_construct = mtk_afe_pcm_new,
+	.probe         = mt8188_afe_component_probe,
+};
+
+static int init_memif_priv_data(struct mtk_base_afe *afe)
+{
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_memif_priv *memif_priv;
+	int i;
+
+	for (i = MT8188_AFE_MEMIF_START; i < MT8188_AFE_MEMIF_END; i++) {
+		memif_priv = devm_kzalloc(afe->dev,
+					  sizeof(struct mtk_dai_memif_priv),
+					  GFP_KERNEL);
+		if (!memif_priv)
+			return -ENOMEM;
+
+		afe_priv->dai_priv[i] = memif_priv;
+	}
+
+	return 0;
+}
+
+static int mt8188_dai_memif_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+
+	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+
+	list_add(&dai->list, &afe->sub_dais);
+
+	dai->dai_drivers = mt8188_memif_dai_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mt8188_memif_dai_driver);
+
+	dai->dapm_widgets = mt8188_memif_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mt8188_memif_widgets);
+	dai->dapm_routes = mt8188_memif_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mt8188_memif_routes);
+
+	return init_memif_priv_data(afe);
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+	mt8188_dai_adda_register,
+	mt8188_dai_etdm_register,
+	mt8188_dai_pcm_register,
+	mt8188_dai_memif_register,
+};
+
+static const struct reg_sequence mt8188_afe_reg_defaults[] = {
+	{ AFE_IRQ_MASK, 0x387ffff },
+	{ AFE_IRQ3_CON, BIT(30) },
+	{ AFE_IRQ9_CON, BIT(30) },
+	{ ETDM_IN1_CON4, 0x12000100 },
+	{ ETDM_IN2_CON4, 0x12000100 },
+};
+
+static const struct reg_sequence mt8188_cg_patch[] = {
+	{ AUDIO_TOP_CON0, 0xfffffffb },
+	{ AUDIO_TOP_CON1, 0xfffffff8 },
+};
+
+static int mt8188_afe_init_registers(struct mtk_base_afe *afe)
+{
+	return regmap_multi_reg_write(afe->regmap,
+				      mt8188_afe_reg_defaults,
+				      ARRAY_SIZE(mt8188_afe_reg_defaults));
+}
+
+static int mt8188_afe_parse_of(struct mtk_base_afe *afe,
+			       struct device_node *np)
+{
+#if IS_ENABLED(CONFIG_SND_SOC_MT6359)
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+	afe_priv->topckgen = syscon_regmap_lookup_by_phandle(afe->dev->of_node,
+							     "mediatek,topckgen");
+	if (IS_ERR(afe_priv->topckgen))
+		return dev_err_probe(afe->dev,  PTR_ERR(afe_priv->topckgen),
+				     "%s() Cannot find topckgen controller\n",
+				     __func__);
+#endif
+	return 0;
+}
+
+static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+	struct mtk_base_afe *afe;
+	struct mt8188_afe_private *afe_priv;
+	struct device *dev;
+	int i, irq_id, ret;
+	struct snd_soc_component *component;
+	struct reset_control *rstc;
+
+	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33));
+	if (ret)
+		return ret;
+
+	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+	if (!afe)
+		return -ENOMEM;
+
+	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+					  GFP_KERNEL);
+	if (!afe->platform_priv)
+		return -ENOMEM;
+
+	afe_priv = afe->platform_priv;
+	afe->dev = &pdev->dev;
+	dev = afe->dev;
+
+	afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(afe->base_addr))
+		return dev_err_probe(dev, PTR_ERR(afe->base_addr),
+				     "AFE base_addr not found\n");
+
+	/* reset controller to reset audio regs before regmap cache */
+	rstc = devm_reset_control_get_exclusive(dev, "audiosys");
+	if (IS_ERR(rstc))
+		return dev_err_probe(dev, PTR_ERR(rstc),
+				     "could not get audiosys reset\n");
+
+	ret = reset_control_reset(rstc);
+	if (ret) {
+		dev_err(dev, "failed to trigger audio reset:%d\n", ret);
+		return ret;
+	}
+
+	/* initial audio related clock */
+	ret = mt8188_afe_init_clock(afe);
+	if (ret)
+		return dev_err_probe(dev, ret, "init clock error");
+
+	ret = devm_add_action_or_reset(dev, mt8188_afe_deinit_clock, (void *)afe);
+	if (ret)
+		return ret;
+
+	spin_lock_init(&afe_priv->afe_ctrl_lock);
+
+	mutex_init(&afe->irq_alloc_lock);
+
+	/* irq initialize */
+	afe->irqs_size = MT8188_AFE_IRQ_NUM;
+	afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+				 GFP_KERNEL);
+	if (!afe->irqs)
+		return -ENOMEM;
+
+	for (i = 0; i < afe->irqs_size; i++)
+		afe->irqs[i].irq_data = &irq_data[i];
+
+	/* init memif */
+	afe->memif_size = MT8188_AFE_MEMIF_NUM;
+	afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+				  GFP_KERNEL);
+	if (!afe->memif)
+		return -ENOMEM;
+
+	for (i = 0; i < afe->memif_size; i++) {
+		afe->memif[i].data = &memif_data[i];
+		afe->memif[i].irq_usage = mt8188_afe_memif_const_irqs[i];
+		afe->memif[i].const_irq = 1;
+		afe->irqs[afe->memif[i].irq_usage].irq_occupyed = true;
+	}
+
+	/* request irq */
+	irq_id = platform_get_irq(pdev, 0);
+	if (irq_id < 0)
+		return dev_err_probe(dev, irq_id < 0 ? irq_id : -ENXIO,
+				     "no irq found");
+
+	ret = devm_request_irq(dev, irq_id, mt8188_afe_irq_handler,
+			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+	if (ret)
+		return dev_err_probe(dev, ret, "could not request_irq for asys-isr\n");
+
+	/* init sub_dais */
+	INIT_LIST_HEAD(&afe->sub_dais);
+
+	for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+		ret = dai_register_cbs[i](afe);
+		if (ret)
+			return dev_err_probe(dev, ret, "dai register i %d fail\n", i);
+	}
+
+	/* init dai_driver and component_driver */
+	ret = mtk_afe_combine_sub_dai(afe);
+	if (ret)
+		return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n");
+
+	afe->mtk_afe_hardware = &mt8188_afe_hardware;
+	afe->memif_fs = mt8188_memif_fs;
+	afe->irq_fs = mt8188_irq_fs;
+
+	afe->runtime_resume = mt8188_afe_runtime_resume;
+	afe->runtime_suspend = mt8188_afe_runtime_suspend;
+
+	platform_set_drvdata(pdev, afe);
+
+	ret = mt8188_afe_parse_of(afe, pdev->dev.of_node);
+	if (ret)
+		return ret;
+
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return ret;
+
+	/* enable clock for regcache get default value from hw */
+	afe_priv->pm_runtime_bypass_reg_ctl = true;
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to resume device\n");
+
+	afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
+					    &mt8188_afe_regmap_config);
+	if (IS_ERR(afe->regmap)) {
+		ret = PTR_ERR(afe->regmap);
+		goto err_pm_put;
+	}
+
+	ret = regmap_register_patch(afe->regmap, mt8188_cg_patch,
+				    ARRAY_SIZE(mt8188_cg_patch));
+	if (ret < 0) {
+		dev_info(dev, "Failed to apply cg patch\n");
+		goto err_pm_put;
+	}
+
+	/* register component */
+	ret = devm_snd_soc_register_component(dev, &mt8188_afe_component,
+					      NULL, 0);
+	if (ret) {
+		dev_warn(dev, "err_platform\n");
+		goto err_pm_put;
+	}
+
+	component = devm_kzalloc(&pdev->dev, sizeof(*component), GFP_KERNEL);
+	if (!component) {
+		ret = -ENOMEM;
+		goto err_pm_put;
+	}
+
+	ret = snd_soc_component_initialize(component,
+					   &mt8188_afe_pcm_dai_component,
+					   &pdev->dev);
+	if (ret)
+		goto err_pm_put;
+#ifdef CONFIG_DEBUG_FS
+	component->debugfs_prefix = "pcm";
+#endif
+	ret = snd_soc_add_component(component,
+				    afe->dai_drivers,
+				    afe->num_dai_drivers);
+	if (ret) {
+		dev_warn(dev, "err_add_component\n");
+		goto err_pm_put;
+	}
+
+	mt8188_afe_init_registers(afe);
+
+	pm_runtime_put_sync(&pdev->dev);
+	afe_priv->pm_runtime_bypass_reg_ctl = false;
+
+	regcache_cache_only(afe->regmap, true);
+	regcache_mark_dirty(afe->regmap);
+
+	return 0;
+err_pm_put:
+	pm_runtime_put_sync(dev);
+
+	return ret;
+}
+
+static int mt8188_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_component(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id mt8188_afe_pcm_dt_match[] = {
+	{ .compatible = "mediatek,mt8188-afe", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mt8188_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt8188_afe_pm_ops = {
+	SET_RUNTIME_PM_OPS(mt8188_afe_runtime_suspend,
+			   mt8188_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt8188_afe_pcm_driver = {
+	.driver = {
+		   .name = "mt8188-audio",
+		   .of_match_table = mt8188_afe_pcm_dt_match,
+		   .pm = &mt8188_afe_pm_ops,
+	},
+	.probe = mt8188_afe_pcm_dev_probe,
+	.remove = mt8188_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt8188_afe_pcm_driver);
+
+MODULE_DESCRIPTION("MediaTek SoC AFE platform driver for ALSA 8188");
+MODULE_AUTHOR("Chun-Chia.Chiu <chun-chia.chiu@mediatek.com>");
+MODULE_LICENSE("GPL");
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 09/12] ASoC: mediatek: mt8188: add control for timing select
  2022-10-21  8:27 [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC Trevor Wu
                   ` (6 preceding siblings ...)
  2022-10-21  8:27 ` [PATCH v2 08/12] ASoC: mediatek: mt8188: add platform driver Trevor Wu
@ 2022-10-21  8:27 ` Trevor Wu
  2022-10-21  8:27 ` [PATCH v2 10/12] dt-bindings: mediatek: mt8188: add audio afe document Trevor Wu
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Trevor Wu @ 2022-10-21  8:27 UTC (permalink / raw)
  To: broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: trevor.wu, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Add mixer control for irq and memif timing selection.

Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
---
 sound/soc/mediatek/mt8188/mt8188-afe-pcm.c | 506 +++++++++++++++++++++
 1 file changed, 506 insertions(+)

diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
index 6bef980846fa..57a31330e5f4 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
@@ -1394,6 +1394,510 @@ static const struct snd_soc_dapm_route mt8188_memif_routes[] = {
 	{"O041", "I169 Switch", "I169"},
 };
 
+static const char * const mt8188_afe_1x_en_sel_text[] = {
+	"a1sys_a2sys", "a3sys", "a4sys",
+};
+
+static const unsigned int mt8188_afe_1x_en_sel_values[] = {
+	0, 1, 2,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(dl2_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 18, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl3_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 20, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl6_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 22, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl7_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 24, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl8_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 26, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl10_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 28, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl11_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 30, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul1_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 0, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul2_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 2, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul3_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 4, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul4_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 6, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul5_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 8, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul6_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 10, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul8_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 12, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul9_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 14, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul10_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL1, 16, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq1_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 0, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq2_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 2, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq3_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 4, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq4_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 6, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq5_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 8, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq6_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 10, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq7_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 12, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq8_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 14, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq9_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 16, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq10_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 18, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq11_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 20, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq12_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 22, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq13_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 24, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq14_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 26, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq15_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 28, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq16_1x_en_sel_enum,
+				  A3_A4_TIMING_SEL6, 30, 0x3,
+				  mt8188_afe_1x_en_sel_text,
+				  mt8188_afe_1x_en_sel_values);
+
+static const char * const mt8188_afe_fs_timing_sel_text[] = {
+	"asys",
+	"etdmout1_1x_en",
+	"etdmout2_1x_en",
+	"etdmout3_1x_en",
+	"etdmin1_1x_en",
+	"etdmin2_1x_en",
+	"etdmin1_nx_en",
+	"etdmin2_nx_en",
+};
+
+static const unsigned int mt8188_afe_fs_timing_sel_values[] = {
+	0,
+	MT8188_ETDM_OUT1_1X_EN,
+	MT8188_ETDM_OUT2_1X_EN,
+	MT8188_ETDM_OUT3_1X_EN,
+	MT8188_ETDM_IN1_1X_EN,
+	MT8188_ETDM_IN2_1X_EN,
+	MT8188_ETDM_IN1_NX_EN,
+	MT8188_ETDM_IN2_NX_EN,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(dl2_fs_timing_sel_enum,
+				  SND_SOC_NOPM, 0, 0,
+				  mt8188_afe_fs_timing_sel_text,
+				  mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl3_fs_timing_sel_enum,
+				  SND_SOC_NOPM, 0, 0,
+				  mt8188_afe_fs_timing_sel_text,
+				  mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl6_fs_timing_sel_enum,
+				  SND_SOC_NOPM, 0, 0,
+				  mt8188_afe_fs_timing_sel_text,
+				  mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl8_fs_timing_sel_enum,
+				  SND_SOC_NOPM, 0, 0,
+				  mt8188_afe_fs_timing_sel_text,
+				  mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl11_fs_timing_sel_enum,
+				  SND_SOC_NOPM, 0, 0,
+				  mt8188_afe_fs_timing_sel_text,
+				  mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul2_fs_timing_sel_enum,
+				  SND_SOC_NOPM, 0, 0,
+				  mt8188_afe_fs_timing_sel_text,
+				  mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul4_fs_timing_sel_enum,
+				  SND_SOC_NOPM, 0, 0,
+				  mt8188_afe_fs_timing_sel_text,
+				  mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul5_fs_timing_sel_enum,
+				  SND_SOC_NOPM, 0, 0,
+				  mt8188_afe_fs_timing_sel_text,
+				  mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul9_fs_timing_sel_enum,
+				  SND_SOC_NOPM, 0, 0,
+				  mt8188_afe_fs_timing_sel_text,
+				  mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul10_fs_timing_sel_enum,
+				  SND_SOC_NOPM, 0, 0,
+				  mt8188_afe_fs_timing_sel_text,
+				  mt8188_afe_fs_timing_sel_values);
+
+static int mt8188_memif_1x_en_sel_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_memif_priv *memif_priv;
+	unsigned int dai_id = kcontrol->id.device;
+	long val = ucontrol->value.integer.value[0];
+	int ret = 0;
+
+	memif_priv = afe_priv->dai_priv[dai_id];
+
+	if (val == memif_priv->asys_timing_sel)
+		return 0;
+
+	ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+
+	memif_priv->asys_timing_sel = val;
+
+	return ret;
+}
+
+static int mt8188_asys_irq_1x_en_sel_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	unsigned int id = kcontrol->id.device;
+	long val = ucontrol->value.integer.value[0];
+	int ret = 0;
+
+	if (val == afe_priv->irq_priv[id].asys_timing_sel)
+		return 0;
+
+	ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+
+	afe_priv->irq_priv[id].asys_timing_sel = val;
+
+	return ret;
+}
+
+static int mt8188_memif_fs_timing_sel_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_memif_priv *memif_priv;
+	unsigned int dai_id = kcontrol->id.device;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+	memif_priv = afe_priv->dai_priv[dai_id];
+
+	ucontrol->value.enumerated.item[0] =
+		snd_soc_enum_val_to_item(e, memif_priv->fs_timing);
+
+	return 0;
+}
+
+static int mt8188_memif_fs_timing_sel_put(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_memif_priv *memif_priv;
+	unsigned int dai_id = kcontrol->id.device;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int *item = ucontrol->value.enumerated.item;
+	unsigned int prev_item = 0;
+
+	if (item[0] >= e->items)
+		return -EINVAL;
+
+	memif_priv = afe_priv->dai_priv[dai_id];
+
+	prev_item = snd_soc_enum_val_to_item(e, memif_priv->fs_timing);
+
+	if (item[0] == prev_item)
+		return 0;
+
+	memif_priv->fs_timing = snd_soc_enum_item_to_val(e, item[0]);
+
+	return 1;
+}
+
+static const struct snd_kcontrol_new mt8188_memif_controls[] = {
+	MT8188_SOC_ENUM_EXT("dl2_1x_en_sel",
+			    dl2_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_DL2),
+	MT8188_SOC_ENUM_EXT("dl3_1x_en_sel",
+			    dl3_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_DL3),
+	MT8188_SOC_ENUM_EXT("dl6_1x_en_sel",
+			    dl6_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_DL6),
+	MT8188_SOC_ENUM_EXT("dl7_1x_en_sel",
+			    dl7_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_DL7),
+	MT8188_SOC_ENUM_EXT("dl8_1x_en_sel",
+			    dl8_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_DL8),
+	MT8188_SOC_ENUM_EXT("dl10_1x_en_sel",
+			    dl10_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_DL10),
+	MT8188_SOC_ENUM_EXT("dl11_1x_en_sel",
+			    dl11_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_DL11),
+	MT8188_SOC_ENUM_EXT("ul1_1x_en_sel",
+			    ul1_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_UL1),
+	MT8188_SOC_ENUM_EXT("ul2_1x_en_sel",
+			    ul2_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_UL2),
+	MT8188_SOC_ENUM_EXT("ul3_1x_en_sel",
+			    ul3_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_UL3),
+	MT8188_SOC_ENUM_EXT("ul4_1x_en_sel",
+			    ul4_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_UL4),
+	MT8188_SOC_ENUM_EXT("ul5_1x_en_sel",
+			    ul5_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_UL5),
+	MT8188_SOC_ENUM_EXT("ul6_1x_en_sel",
+			    ul6_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_UL6),
+	MT8188_SOC_ENUM_EXT("ul8_1x_en_sel",
+			    ul8_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_UL8),
+	MT8188_SOC_ENUM_EXT("ul9_1x_en_sel",
+			    ul9_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_UL9),
+	MT8188_SOC_ENUM_EXT("ul10_1x_en_sel",
+			    ul10_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_memif_1x_en_sel_put,
+			    MT8188_AFE_MEMIF_UL10),
+	MT8188_SOC_ENUM_EXT("asys_irq1_1x_en_sel",
+			    asys_irq1_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_13),
+	MT8188_SOC_ENUM_EXT("asys_irq2_1x_en_sel",
+			    asys_irq2_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_14),
+	MT8188_SOC_ENUM_EXT("asys_irq3_1x_en_sel",
+			    asys_irq3_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_15),
+	MT8188_SOC_ENUM_EXT("asys_irq4_1x_en_sel",
+			    asys_irq4_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_16),
+	MT8188_SOC_ENUM_EXT("asys_irq5_1x_en_sel",
+			    asys_irq5_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_17),
+	MT8188_SOC_ENUM_EXT("asys_irq6_1x_en_sel",
+			    asys_irq6_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_18),
+	MT8188_SOC_ENUM_EXT("asys_irq7_1x_en_sel",
+			    asys_irq7_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_19),
+	MT8188_SOC_ENUM_EXT("asys_irq8_1x_en_sel",
+			    asys_irq8_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_20),
+	MT8188_SOC_ENUM_EXT("asys_irq9_1x_en_sel",
+			    asys_irq9_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_21),
+	MT8188_SOC_ENUM_EXT("asys_irq10_1x_en_sel",
+			    asys_irq10_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_22),
+	MT8188_SOC_ENUM_EXT("asys_irq11_1x_en_sel",
+			    asys_irq11_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_23),
+	MT8188_SOC_ENUM_EXT("asys_irq12_1x_en_sel",
+			    asys_irq12_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_24),
+	MT8188_SOC_ENUM_EXT("asys_irq13_1x_en_sel",
+			    asys_irq13_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_25),
+	MT8188_SOC_ENUM_EXT("asys_irq14_1x_en_sel",
+			    asys_irq14_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_26),
+	MT8188_SOC_ENUM_EXT("asys_irq15_1x_en_sel",
+			    asys_irq15_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_27),
+	MT8188_SOC_ENUM_EXT("asys_irq16_1x_en_sel",
+			    asys_irq16_1x_en_sel_enum,
+			    snd_soc_get_enum_double,
+			    mt8188_asys_irq_1x_en_sel_put,
+			    MT8188_AFE_IRQ_28),
+	MT8188_SOC_ENUM_EXT("dl2_fs_timing_sel",
+			    dl2_fs_timing_sel_enum,
+			    mt8188_memif_fs_timing_sel_get,
+			    mt8188_memif_fs_timing_sel_put,
+			    MT8188_AFE_MEMIF_DL2),
+	MT8188_SOC_ENUM_EXT("dl3_fs_timing_sel",
+			    dl3_fs_timing_sel_enum,
+			    mt8188_memif_fs_timing_sel_get,
+			    mt8188_memif_fs_timing_sel_put,
+			    MT8188_AFE_MEMIF_DL3),
+	MT8188_SOC_ENUM_EXT("dl6_fs_timing_sel",
+			    dl6_fs_timing_sel_enum,
+			    mt8188_memif_fs_timing_sel_get,
+			    mt8188_memif_fs_timing_sel_put,
+			    MT8188_AFE_MEMIF_DL6),
+	MT8188_SOC_ENUM_EXT("dl8_fs_timing_sel",
+			    dl8_fs_timing_sel_enum,
+			    mt8188_memif_fs_timing_sel_get,
+			    mt8188_memif_fs_timing_sel_put,
+			    MT8188_AFE_MEMIF_DL8),
+	MT8188_SOC_ENUM_EXT("dl11_fs_timing_sel",
+			    dl11_fs_timing_sel_enum,
+			    mt8188_memif_fs_timing_sel_get,
+			    mt8188_memif_fs_timing_sel_put,
+			    MT8188_AFE_MEMIF_DL11),
+	MT8188_SOC_ENUM_EXT("ul2_fs_timing_sel",
+			    ul2_fs_timing_sel_enum,
+			    mt8188_memif_fs_timing_sel_get,
+			    mt8188_memif_fs_timing_sel_put,
+			    MT8188_AFE_MEMIF_UL2),
+	MT8188_SOC_ENUM_EXT("ul4_fs_timing_sel",
+			    ul4_fs_timing_sel_enum,
+			    mt8188_memif_fs_timing_sel_get,
+			    mt8188_memif_fs_timing_sel_put,
+			    MT8188_AFE_MEMIF_UL4),
+	MT8188_SOC_ENUM_EXT("ul5_fs_timing_sel",
+			    ul5_fs_timing_sel_enum,
+			    mt8188_memif_fs_timing_sel_get,
+			    mt8188_memif_fs_timing_sel_put,
+			    MT8188_AFE_MEMIF_UL5),
+	MT8188_SOC_ENUM_EXT("ul9_fs_timing_sel",
+			    ul9_fs_timing_sel_enum,
+			    mt8188_memif_fs_timing_sel_get,
+			    mt8188_memif_fs_timing_sel_put,
+			    MT8188_AFE_MEMIF_UL9),
+	MT8188_SOC_ENUM_EXT("ul10_fs_timing_sel",
+			    ul10_fs_timing_sel_enum,
+			    mt8188_memif_fs_timing_sel_get,
+			    mt8188_memif_fs_timing_sel_put,
+			    MT8188_AFE_MEMIF_UL10),
+};
+
 static const struct snd_soc_component_driver mt8188_afe_pcm_dai_component = {
 	.name = "mt8188-afe-pcm-dai",
 };
@@ -2583,6 +3087,8 @@ static int mt8188_dai_memif_register(struct mtk_base_afe *afe)
 	dai->num_dapm_widgets = ARRAY_SIZE(mt8188_memif_widgets);
 	dai->dapm_routes = mt8188_memif_routes;
 	dai->num_dapm_routes = ARRAY_SIZE(mt8188_memif_routes);
+	dai->controls = mt8188_memif_controls;
+	dai->num_controls = ARRAY_SIZE(mt8188_memif_controls);
 
 	return init_memif_priv_data(afe);
 }
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 10/12] dt-bindings: mediatek: mt8188: add audio afe document
  2022-10-21  8:27 [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC Trevor Wu
                   ` (7 preceding siblings ...)
  2022-10-21  8:27 ` [PATCH v2 09/12] ASoC: mediatek: mt8188: add control for timing select Trevor Wu
@ 2022-10-21  8:27 ` Trevor Wu
  2022-10-24 18:33   ` Rob Herring
  2022-10-29  0:06   ` Krzysztof Kozlowski
  2022-10-21  8:27 ` [PATCH v2 11/12] ASoC: mediatek: mt8188: add machine driver with mt6359 Trevor Wu
  2022-10-21  8:27 ` [PATCH v2 12/12] dt-bindings: mediatek: mt8188: add mt8188-mt6359 document Trevor Wu
  10 siblings, 2 replies; 27+ messages in thread
From: Trevor Wu @ 2022-10-21  8:27 UTC (permalink / raw)
  To: broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: trevor.wu, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Add mt8188 audio afe document.

Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
---
 .../bindings/sound/mt8188-afe-pcm.yaml        | 187 ++++++++++++++++++
 1 file changed, 187 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml

diff --git a/Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml b/Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml
new file mode 100644
index 000000000000..b2c548c31e4d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml
@@ -0,0 +1,187 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mt8188-afe-pcm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek AFE PCM controller for mt8188
+
+maintainers:
+  - Trevor Wu <trevor.wu@mediatek.com>
+
+properties:
+  compatible:
+    const: mediatek,mt8188-afe
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    const: audiosys
+
+  mediatek,topckgen:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: The phandle of the mediatek topckgen controller
+
+  power-domains:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: 26M clock
+      - description: audio pll1 clock
+      - description: audio pll2 clock
+      - description: clock divider for i2si1_mck
+      - description: clock divider for i2si2_mck
+      - description: clock divider for i2so1_mck
+      - description: clock divider for i2so2_mck
+      - description: clock divider for dptx_mck
+      - description: a1sys hoping clock
+      - description: audio intbus clock
+      - description: audio hires clock
+      - description: audio local bus clock
+      - description: mux for dptx_mck
+      - description: mux for i2so1_mck
+      - description: mux for i2so2_mck
+      - description: mux for i2si1_mck
+      - description: mux for i2si2_mck
+      - description: audio 26m clock
+
+  clock-names:
+    items:
+      - const: clk26m
+      - const: apll1_ck
+      - const: apll2_ck
+      - const: apll12_div0
+      - const: apll12_div1
+      - const: apll12_div2
+      - const: apll12_div3
+      - const: apll12_div9
+      - const: a1sys_hp_sel
+      - const: aud_intbus_sel
+      - const: audio_h_sel
+      - const: audio_local_bus_sel
+      - const: dptx_m_sel
+      - const: i2so1_m_sel
+      - const: i2so2_m_sel
+      - const: i2si1_m_sel
+      - const: i2si2_m_sel
+      - const: adsp_audio_26m
+
+patternProperties:
+  "^mediatek,etdm-in[1-2]-chn-disabled$":
+    $ref: /schemas/types.yaml#/definitions/uint8-array
+    maxItems: 16
+    description: |
+      Specify which input channel should be disabled, so the data of
+      specified channel won't be outputted to memory.
+    items:
+      enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
+
+  "^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
+    description: Specify etdm in mclk output rate for always on case.
+
+  "^mediatek,etdm-out[1-3]-mclk-always-on-rate-hz$":
+    description: Specify etdm out mclk output rate for always on case.
+
+  "^mediatek,etdm-in[1-2]-multi-pin-mode$":
+    type: boolean
+    description: if present, the etdm data mode is I2S.
+
+  "^mediatek,etdm-out[1-3]-multi-pin-mode$":
+    type: boolean
+    description: if present, the etdm data mode is I2S.
+
+  "^mediatek,etdm-in[1-2]-cowork-source$":
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      etdm modules can share the same external clock pin. Specify
+      which etdm clock source is required by this etdm in moudule.
+    enum:
+      - 0 # etdm1_in
+      - 1 # etdm2_in
+      - 2 # etdm1_out
+      - 3 # etdm2_out
+
+  "^mediatek,etdm-out[1-2]-cowork-source$":
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      etdm modules can share the same external clock pin. Specify
+      which etdm clock source is required by this etdm out moudule.
+    enum:
+      - 0 # etdm1_in
+      - 1 # etdm2_in
+      - 2 # etdm1_out
+      - 3 # etdm2_out
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - resets
+  - reset-names
+  - mediatek,topckgen
+  - power-domains
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    afe: afe@10b10000 {
+        compatible = "mediatek,mt8188-afe";
+        reg = <0x10b10000 0x10000>;
+        interrupts = <GIC_SPI 822 IRQ_TYPE_LEVEL_HIGH 0>;
+        resets = <&watchdog 14>;
+        reset-names = "audiosys";
+        mediatek,topckgen = <&topckgen>;
+        power-domains = <&spm 13>; //MT8188_POWER_DOMAIN_AUDIO
+        clocks = <&clk26m>,
+                 <&topckgen 72>, //CLK_TOP_APLL1
+                 <&topckgen 73>, //CLK_TOP_APLL2
+                 <&topckgen 186>, //CLK_TOP_APLL12_CK_DIV0
+                 <&topckgen 187>, //CLK_TOP_APLL12_CK_DIV1
+                 <&topckgen 188>, //CLK_TOP_APLL12_CK_DIV2
+                 <&topckgen 189>, //CLK_TOP_APLL12_CK_DIV3
+                 <&topckgen 191>, //CLK_TOP_APLL12_CK_DIV9
+                 <&topckgen 83>, //CLK_TOP_A1SYS_HP
+                 <&topckgen 31>, //CLK_TOP_AUD_INTBUS
+                 <&topckgen 32>, //CLK_TOP_AUDIO_H
+                 <&topckgen 69>, //CLK_TOP_AUDIO_LOCAL_BUS
+                 <&topckgen 81>, //CLK_TOP_DPTX
+                 <&topckgen 77>, //CLK_TOP_I2SO1
+                 <&topckgen 78>, //CLK_TOP_I2SO2
+                 <&topckgen 79>, //CLK_TOP_I2SI1
+                 <&topckgen 80>, //CLK_TOP_I2SI2
+                 <&adsp_audio26m 0>; //CLK_AUDIODSP_AUDIO26M
+        clock-names = "clk26m",
+                      "apll1_ck",
+                      "apll2_ck",
+                      "apll12_div0",
+                      "apll12_div1",
+                      "apll12_div2",
+                      "apll12_div3",
+                      "apll12_div9",
+                      "a1sys_hp_sel",
+                      "aud_intbus_sel",
+                      "audio_h_sel",
+                      "audio_local_bus_sel",
+                      "dptx_m_sel",
+                      "i2so1_m_sel",
+                      "i2so2_m_sel",
+                      "i2si1_m_sel",
+                      "i2si2_m_sel",
+                      "adsp_audio_26m";
+    };
+
+...
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 11/12] ASoC: mediatek: mt8188: add machine driver with mt6359
  2022-10-21  8:27 [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC Trevor Wu
                   ` (8 preceding siblings ...)
  2022-10-21  8:27 ` [PATCH v2 10/12] dt-bindings: mediatek: mt8188: add audio afe document Trevor Wu
@ 2022-10-21  8:27 ` Trevor Wu
  2022-10-21  8:27 ` [PATCH v2 12/12] dt-bindings: mediatek: mt8188: add mt8188-mt6359 document Trevor Wu
  10 siblings, 0 replies; 27+ messages in thread
From: Trevor Wu @ 2022-10-21  8:27 UTC (permalink / raw)
  To: broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: trevor.wu, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Add support for mt8188 board with mt6359.

Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
---
 sound/soc/mediatek/Kconfig                |  10 +
 sound/soc/mediatek/mt8188/Makefile        |   3 +
 sound/soc/mediatek/mt8188/mt8188-mt6359.c | 808 ++++++++++++++++++++++
 3 files changed, 821 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8188/mt8188-mt6359.c

diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index cf0e4c6b61e7..b746ef8f7aff 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -219,6 +219,16 @@ config SND_SOC_MT8188
 	  Select Y if you have such device.
 	  If unsure select "N".
 
+config SND_SOC_MT8188_MT6359
+	tristate "ASoC Audio driver for MT8188 with MT6359 and I2S codecs"
+	depends on SND_SOC_MT8188 && MTK_PMIC_WRAP
+	select SND_SOC_HDMI_CODEC
+	help
+	  This adds support for ASoC machine driver for Mediatek MT8188
+	  boards with the MT6359 and other I2S audio codecs.
+	  Select Y if you have such device.
+	  If unsure select "N".
+
 config SND_SOC_MT8192
 	tristate "ASoC support for Mediatek MT8192 chip"
 	depends on ARCH_MEDIATEK
diff --git a/sound/soc/mediatek/mt8188/Makefile b/sound/soc/mediatek/mt8188/Makefile
index fa5d383c5e47..781e61cbb22b 100644
--- a/sound/soc/mediatek/mt8188/Makefile
+++ b/sound/soc/mediatek/mt8188/Makefile
@@ -10,3 +10,6 @@ snd-soc-mt8188-afe-objs := \
 	mt8188-dai-pcm.o
 
 obj-$(CONFIG_SND_SOC_MT8188) += snd-soc-mt8188-afe.o
+
+# machine driver
+obj-$(CONFIG_SND_SOC_MT8188_MT6359) += mt8188-mt6359.o
diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c
new file mode 100644
index 000000000000..fa935f856dba
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c
@@ -0,0 +1,808 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8188-mt6359.c  --  MT8188-MT6359 ALSA SoC machine driver
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Trevor Wu <trevor.wu@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "mt8188-afe-common.h"
+#include "../../codecs/mt6359.h"
+#include "../common/mtk-afe-platform-driver.h"
+
+/* FE */
+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(playback3,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL3")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback6,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL6")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback7,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL7")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback8,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL8")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback10,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL10")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback11,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL11")),
+		     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(capture3,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL3")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture4,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL4")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture5,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL5")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture6,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL6")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture8,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL8")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture9,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL9")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture10,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL10")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* BE */
+SND_SOC_DAILINK_DEFS(adda,
+		     DAILINK_COMP_ARRAY(COMP_CPU("ADDA")),
+		     DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound",
+						   "mt6359-snd-codec-aif1")),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(dptx,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DPTX")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(etdm1_in,
+		     DAILINK_COMP_ARRAY(COMP_CPU("ETDM1_IN")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(etdm2_in,
+		     DAILINK_COMP_ARRAY(COMP_CPU("ETDM2_IN")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(etdm1_out,
+		     DAILINK_COMP_ARRAY(COMP_CPU("ETDM1_OUT")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(etdm2_out,
+		     DAILINK_COMP_ARRAY(COMP_CPU("ETDM2_OUT")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(etdm3_out,
+		     DAILINK_COMP_ARRAY(COMP_CPU("ETDM3_OUT")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(pcm1,
+		     DAILINK_COMP_ARRAY(COMP_CPU("PCM1")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+struct mt8188_mt6359_priv {
+	struct snd_soc_jack dp_jack;
+	struct snd_soc_jack hdmi_jack;
+};
+
+struct mt8188_card_data {
+	const char *name;
+	unsigned long quirk;
+};
+
+static const struct snd_soc_dapm_widget mt8188_mt6359_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_kcontrol_new mt8188_mt6359_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+#define CKSYS_AUD_TOP_CFG 0x032c
+#define CKSYS_AUD_TOP_MON 0x0330
+
+static int mt8188_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_component *cmpnt_afe =
+		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct snd_soc_component *cmpnt_codec =
+		asoc_rtd_to_codec(rtd, 0)->component;
+	struct mtk_base_afe *afe;
+	struct mt8188_afe_private *afe_priv;
+	struct mtkaif_param *param;
+	int chosen_phase_1, chosen_phase_2;
+	int prev_cycle_1, prev_cycle_2;
+	int test_done_1, test_done_2;
+	int cycle_1, cycle_2;
+	int mtkaif_chosen_phase[MT8188_MTKAIF_MISO_NUM];
+	int mtkaif_phase_cycle[MT8188_MTKAIF_MISO_NUM];
+	int mtkaif_calibration_num_phase;
+	bool mtkaif_calibration_ok;
+	unsigned int monitor = 0;
+	int counter;
+	int phase;
+	int i;
+
+	if (!cmpnt_afe)
+		return -EINVAL;
+
+	afe = snd_soc_component_get_drvdata(cmpnt_afe);
+	afe_priv = afe->platform_priv;
+	param = &afe_priv->mtkaif_params;
+
+	dev_dbg(afe->dev, "%s(), start\n", __func__);
+
+	param->mtkaif_calibration_ok = false;
+	for (i = 0; i < MT8188_MTKAIF_MISO_NUM; i++) {
+		param->mtkaif_chosen_phase[i] = -1;
+		param->mtkaif_phase_cycle[i] = 0;
+		mtkaif_chosen_phase[i] = -1;
+		mtkaif_phase_cycle[i] = 0;
+	}
+
+	if (IS_ERR(afe_priv->topckgen)) {
+		dev_info(afe->dev, "%s() Cannot find topckgen controller\n",
+			 __func__);
+		return 0;
+	}
+
+	pm_runtime_get_sync(afe->dev);
+	mt6359_mtkaif_calibration_enable(cmpnt_codec);
+
+	/* set test type to synchronizer pulse */
+	regmap_update_bits(afe_priv->topckgen,
+			   CKSYS_AUD_TOP_CFG, 0xffff, 0x4);
+	mtkaif_calibration_num_phase = 42;	/* mt6359: 0 ~ 42 */
+	mtkaif_calibration_ok = true;
+
+	for (phase = 0;
+	     phase <= mtkaif_calibration_num_phase && mtkaif_calibration_ok;
+	     phase++) {
+		mt6359_set_mtkaif_calibration_phase(cmpnt_codec,
+						    phase, phase, phase);
+
+		regmap_set_bits(afe_priv->topckgen, CKSYS_AUD_TOP_CFG, 0x1);
+
+		test_done_1 = 0;
+		test_done_2 = 0;
+
+		cycle_1 = -1;
+		cycle_2 = -1;
+
+		counter = 0;
+		while (!(test_done_1 & test_done_2)) {
+			regmap_read(afe_priv->topckgen,
+				    CKSYS_AUD_TOP_MON, &monitor);
+			test_done_1 = (monitor >> 28) & 0x1;
+			test_done_2 = (monitor >> 29) & 0x1;
+
+			if (test_done_1 == 1)
+				cycle_1 = monitor & 0xf;
+
+			if (test_done_2 == 1)
+				cycle_2 = (monitor >> 4) & 0xf;
+
+			/* handle if never test done */
+			if (++counter > 10000) {
+				dev_info(afe->dev, "%s(), test fail, cycle_1 %d, cycle_2 %d, monitor 0x%x\n",
+					 __func__,
+					 cycle_1, cycle_2, monitor);
+				mtkaif_calibration_ok = false;
+				break;
+			}
+		}
+
+		if (phase == 0) {
+			prev_cycle_1 = cycle_1;
+			prev_cycle_2 = cycle_2;
+		}
+
+		if (cycle_1 != prev_cycle_1 &&
+		    mtkaif_chosen_phase[MT8188_MTKAIF_MISO_0] < 0) {
+			mtkaif_chosen_phase[MT8188_MTKAIF_MISO_0] = phase - 1;
+			mtkaif_phase_cycle[MT8188_MTKAIF_MISO_0] = prev_cycle_1;
+		}
+
+		if (cycle_2 != prev_cycle_2 &&
+		    mtkaif_chosen_phase[MT8188_MTKAIF_MISO_1] < 0) {
+			mtkaif_chosen_phase[MT8188_MTKAIF_MISO_1] = phase - 1;
+			mtkaif_phase_cycle[MT8188_MTKAIF_MISO_1] = prev_cycle_2;
+		}
+
+		regmap_clear_bits(afe_priv->topckgen, CKSYS_AUD_TOP_CFG, 0x1);
+
+		if (mtkaif_chosen_phase[MT8188_MTKAIF_MISO_0] >= 0 &&
+		    mtkaif_chosen_phase[MT8188_MTKAIF_MISO_1] >= 0)
+			break;
+	}
+
+	if (mtkaif_chosen_phase[MT8188_MTKAIF_MISO_0] < 0) {
+		mtkaif_calibration_ok = false;
+		chosen_phase_1 = 0;
+	} else {
+		chosen_phase_1 = mtkaif_chosen_phase[MT8188_MTKAIF_MISO_0];
+	}
+
+	if (mtkaif_chosen_phase[MT8188_MTKAIF_MISO_1] < 0) {
+		mtkaif_calibration_ok = false;
+		chosen_phase_2 = 0;
+	} else {
+		chosen_phase_2 = mtkaif_chosen_phase[MT8188_MTKAIF_MISO_1];
+	}
+
+	mt6359_set_mtkaif_calibration_phase(cmpnt_codec,
+					    chosen_phase_1,
+					    chosen_phase_2,
+					    0);
+
+	mt6359_mtkaif_calibration_disable(cmpnt_codec);
+	pm_runtime_put(afe->dev);
+
+	param->mtkaif_calibration_ok = mtkaif_calibration_ok;
+	param->mtkaif_chosen_phase[MT8188_MTKAIF_MISO_0] = chosen_phase_1;
+	param->mtkaif_chosen_phase[MT8188_MTKAIF_MISO_1] = chosen_phase_2;
+
+	for (i = 0; i < MT8188_MTKAIF_MISO_NUM; i++)
+		param->mtkaif_phase_cycle[i] = mtkaif_phase_cycle[i];
+
+	dev_info(afe->dev, "%s(), end, calibration ok %d\n",
+		 __func__, param->mtkaif_calibration_ok);
+
+	return 0;
+}
+
+static int mt8188_mt6359_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_component *cmpnt_codec =
+		asoc_rtd_to_codec(rtd, 0)->component;
+	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_dapm_context *dapm = &card->dapm;
+
+	/* set mtkaif protocol */
+	mt6359_set_mtkaif_protocol(cmpnt_codec,
+				   MT6359_MTKAIF_PROTOCOL_2_CLK_P2);
+
+	/* mtkaif calibration */
+	mt8188_mt6359_mtkaif_calibration(rtd);
+
+	/* disable widget at init, in case of unexpected completed path */
+	snd_soc_dapm_disable_pin(dapm, "Receiver");
+	snd_soc_dapm_disable_pin(dapm, "Headphone L");
+	snd_soc_dapm_disable_pin(dapm, "Headphone R");
+	snd_soc_dapm_disable_pin(dapm, "Headphone L Ext Spk Amp");
+	snd_soc_dapm_disable_pin(dapm, "Headphone R Ext Spk Amp");
+	snd_soc_dapm_disable_pin(dapm, "LINEOUT L");
+
+	return 0;
+}
+
+enum {
+	DAI_LINK_DL2_FE,
+	DAI_LINK_DL3_FE,
+	DAI_LINK_DL6_FE,
+	DAI_LINK_DL7_FE,
+	DAI_LINK_DL8_FE,
+	DAI_LINK_DL10_FE,
+	DAI_LINK_DL11_FE,
+	DAI_LINK_UL1_FE,
+	DAI_LINK_UL2_FE,
+	DAI_LINK_UL3_FE,
+	DAI_LINK_UL4_FE,
+	DAI_LINK_UL5_FE,
+	DAI_LINK_UL6_FE,
+	DAI_LINK_UL8_FE,
+	DAI_LINK_UL9_FE,
+	DAI_LINK_UL10_FE,
+	DAI_LINK_ADDA_BE,
+	DAI_LINK_DPTX_BE,
+	DAI_LINK_ETDM1_IN_BE,
+	DAI_LINK_ETDM2_IN_BE,
+	DAI_LINK_ETDM1_OUT_BE,
+	DAI_LINK_ETDM2_OUT_BE,
+	DAI_LINK_ETDM3_OUT_BE,
+	DAI_LINK_PCM1_BE,
+};
+
+static int mt8188_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 = asoc_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 mt8188_dptx_ops = {
+	.hw_params = mt8188_dptx_hw_params,
+};
+
+static int mt8188_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+				       struct snd_pcm_hw_params *params)
+{
+	/* 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 mt8188_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct mt8188_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+	int ret = 0;
+
+	ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+				    &priv->hdmi_jack);
+	if (ret) {
+		dev_info(rtd->dev, "%s, new jack failed: %d\n", __func__, ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_set_jack(component, &priv->hdmi_jack, NULL);
+	if (ret)
+		dev_info(rtd->dev, "%s, set jack failed on %s (ret=%d)\n",
+			 __func__, component->name, ret);
+
+	return ret;
+}
+
+static int mt8188_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct mt8188_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+	int ret = 0;
+
+	ret = snd_soc_card_jack_new(rtd->card, "DP Jack", SND_JACK_LINEOUT,
+				    &priv->dp_jack);
+	if (ret) {
+		dev_info(rtd->dev, "%s, new jack failed: %d\n", __func__, ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_set_jack(component, &priv->dp_jack, NULL);
+	if (ret)
+		dev_info(rtd->dev, "%s, set jack failed on %s (ret=%d)\n",
+			 __func__, component->name, ret);
+
+	return ret;
+}
+
+static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
+	/* FE */
+	[DAI_LINK_DL2_FE] = {
+		.name = "DL2_FE",
+		.stream_name = "DL2 Playback",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback2),
+	},
+	[DAI_LINK_DL3_FE] = {
+		.name = "DL3_FE",
+		.stream_name = "DL3 Playback",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback3),
+	},
+	[DAI_LINK_DL6_FE] = {
+		.name = "DL6_FE",
+		.stream_name = "DL6 Playback",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback6),
+	},
+	[DAI_LINK_DL7_FE] = {
+		.name = "DL7_FE",
+		.stream_name = "DL7 Playback",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_PRE,
+			SND_SOC_DPCM_TRIGGER_PRE,
+		},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback7),
+	},
+	[DAI_LINK_DL8_FE] = {
+		.name = "DL8_FE",
+		.stream_name = "DL8 Playback",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback8),
+	},
+	[DAI_LINK_DL10_FE] = {
+		.name = "DL10_FE",
+		.stream_name = "DL10 Playback",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback10),
+	},
+	[DAI_LINK_DL11_FE] = {
+		.name = "DL11_FE",
+		.stream_name = "DL11 Playback",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback11),
+	},
+	[DAI_LINK_UL1_FE] = {
+		.name = "UL1_FE",
+		.stream_name = "UL1 Capture",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_PRE,
+			SND_SOC_DPCM_TRIGGER_PRE,
+		},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture1),
+	},
+	[DAI_LINK_UL2_FE] = {
+		.name = "UL2_FE",
+		.stream_name = "UL2 Capture",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture2),
+	},
+	[DAI_LINK_UL3_FE] = {
+		.name = "UL3_FE",
+		.stream_name = "UL3 Capture",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture3),
+	},
+	[DAI_LINK_UL4_FE] = {
+		.name = "UL4_FE",
+		.stream_name = "UL4 Capture",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture4),
+	},
+	[DAI_LINK_UL5_FE] = {
+		.name = "UL5_FE",
+		.stream_name = "UL5 Capture",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture5),
+	},
+	[DAI_LINK_UL6_FE] = {
+		.name = "UL6_FE",
+		.stream_name = "UL6 Capture",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_PRE,
+			SND_SOC_DPCM_TRIGGER_PRE,
+		},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture6),
+	},
+	[DAI_LINK_UL8_FE] = {
+		.name = "UL8_FE",
+		.stream_name = "UL8 Capture",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture8),
+	},
+	[DAI_LINK_UL9_FE] = {
+		.name = "UL9_FE",
+		.stream_name = "UL9 Capture",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture9),
+	},
+	[DAI_LINK_UL10_FE] = {
+		.name = "UL10_FE",
+		.stream_name = "UL10 Capture",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST,
+		},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture10),
+	},
+	/* BE */
+	[DAI_LINK_ADDA_BE] = {
+		.name = "ADDA_BE",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.init = mt8188_mt6359_init,
+		SND_SOC_DAILINK_REG(adda),
+	},
+	[DAI_LINK_DPTX_BE] = {
+		.name = "DPTX_BE",
+		.ops = &mt8188_dptx_ops,
+		.be_hw_params_fixup = mt8188_dptx_hw_params_fixup,
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(dptx),
+	},
+	[DAI_LINK_ETDM1_IN_BE] = {
+		.name = "ETDM1_IN_BE",
+		.no_pcm = 1,
+		.dai_fmt = SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBP_CFP,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(etdm1_in),
+	},
+	[DAI_LINK_ETDM2_IN_BE] = {
+		.name = "ETDM2_IN_BE",
+		.no_pcm = 1,
+		.dai_fmt = SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBP_CFP,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(etdm2_in),
+	},
+	[DAI_LINK_ETDM1_OUT_BE] = {
+		.name = "ETDM1_OUT_BE",
+		.no_pcm = 1,
+		.dai_fmt = SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBC_CFC,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(etdm1_out),
+	},
+	[DAI_LINK_ETDM2_OUT_BE] = {
+		.name = "ETDM2_OUT_BE",
+		.no_pcm = 1,
+		.dai_fmt = SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBC_CFC,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(etdm2_out),
+	},
+	[DAI_LINK_ETDM3_OUT_BE] = {
+		.name = "ETDM3_OUT_BE",
+		.no_pcm = 1,
+		.dai_fmt = SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBC_CFC,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(etdm3_out),
+	},
+	[DAI_LINK_PCM1_BE] = {
+		.name = "PCM1_BE",
+		.no_pcm = 1,
+		.dai_fmt = SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBC_CFC,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(pcm1),
+	},
+};
+
+static struct snd_soc_card mt8188_mt6359_soc_card = {
+	.owner = THIS_MODULE,
+	.dai_link = mt8188_mt6359_dai_links,
+	.num_links = ARRAY_SIZE(mt8188_mt6359_dai_links),
+	.dapm_widgets = mt8188_mt6359_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt8188_mt6359_widgets),
+	.controls = mt8188_mt6359_controls,
+	.num_controls = ARRAY_SIZE(mt8188_mt6359_controls),
+};
+
+static int mt8188_mt6359_dev_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &mt8188_mt6359_soc_card;
+	struct device_node *platform_node, *dp_node, *hdmi_node;
+	struct mt8188_mt6359_priv *priv;
+	struct mt8188_card_data *card_data;
+	struct snd_soc_dai_link *dai_link;
+	int ret, i;
+
+	card_data = (struct mt8188_card_data *)of_device_get_match_data(&pdev->dev);
+	card->dev = &pdev->dev;
+
+	ret = snd_soc_of_parse_card_name(card, "model");
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret, "%s new card name parsing error\n",
+				     __func__);
+
+	if (!card->name)
+		card->name = card_data->name;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return  -ENOMEM;
+
+	if (of_property_read_bool(pdev->dev.of_node, "audio-routing")) {
+		ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+		if (ret)
+			return ret;
+	}
+
+	platform_node = of_parse_phandle(pdev->dev.of_node,
+					 "mediatek,platform", 0);
+	if (!platform_node) {
+		ret = -EINVAL;
+		return dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n");
+	}
+
+	dp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,dptx-codec", 0);
+	hdmi_node = of_parse_phandle(pdev->dev.of_node,
+				     "mediatek,hdmi-codec", 0);
+	for_each_card_prelinks(card, i, dai_link) {
+		if (dai_link->platforms->name)
+			continue;
+		dai_link->platforms->of_node = platform_node;
+
+		if (strcmp(dai_link->name, "DPTX_BE") == 0) {
+			if (!dp_node) {
+				dev_dbg(&pdev->dev, "No property 'dptx-codec'\n");
+			} else {
+				dai_link->codecs->of_node = dp_node;
+				dai_link->codecs->name = NULL;
+				dai_link->codecs->dai_name = "i2s-hifi";
+				dai_link->init = mt8188_dptx_codec_init;
+			}
+		} else if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) {
+			if (!hdmi_node) {
+				dev_dbg(&pdev->dev, "No property 'hdmi-codec'\n");
+			} else {
+				dai_link->codecs->of_node = hdmi_node;
+				dai_link->codecs->name = NULL;
+				dai_link->codecs->dai_name = "i2s-hifi";
+				dai_link->init = mt8188_hdmi_codec_init;
+			}
+		}
+	}
+
+	snd_soc_card_set_drvdata(card, priv);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n",
+			      __func__);
+
+	of_node_put(dp_node);
+	of_node_put(hdmi_node);
+	of_node_put(platform_node);
+
+	return ret;
+}
+
+static struct mt8188_card_data mt8188_evb_card = {
+	.name = "mt8188_mt6359",
+};
+
+static const struct of_device_id mt8188_mt6359_dt_match[] = {
+	{
+		.compatible = "mediatek,mt8188_mt6359_evb",
+		.data = &mt8188_evb_card,
+	},
+	{},
+};
+
+static struct platform_driver mt8188_mt6359_driver = {
+	.driver = {
+		.name = "mt8188_mt6359",
+		.of_match_table = mt8188_mt6359_dt_match,
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = mt8188_mt6359_dev_probe,
+};
+
+module_platform_driver(mt8188_mt6359_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8188-MT6359 ALSA SoC machine driver");
+MODULE_AUTHOR("Trevor Wu <trevor.wu@mediatek.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("mt8188 mt6359 soc card");
+
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 12/12] dt-bindings: mediatek: mt8188: add mt8188-mt6359 document
  2022-10-21  8:27 [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC Trevor Wu
                   ` (9 preceding siblings ...)
  2022-10-21  8:27 ` [PATCH v2 11/12] ASoC: mediatek: mt8188: add machine driver with mt6359 Trevor Wu
@ 2022-10-21  8:27 ` Trevor Wu
  2022-10-24 18:38   ` Rob Herring
  10 siblings, 1 reply; 27+ messages in thread
From: Trevor Wu @ 2022-10-21  8:27 UTC (permalink / raw)
  To: broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: trevor.wu, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Add document for mt8188 board with mt6359.

Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
---
 .../bindings/sound/mt8188-mt6359.yaml         | 64 +++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml

diff --git a/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml b/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
new file mode 100644
index 000000000000..9c493a6101ff
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mt8188-mt6359.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT8188 ASoC sound card driver
+
+maintainers:
+  - Trevor Wu <trevor.wu@mediatek.com>
+
+description:
+  This binding describes the MT8188 sound card.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt8188_mt6359_evb
+
+  model:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: User specified audio sound card name
+
+  audio-routing:
+    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+    description:
+      A list of the connections between audio components. Each entry is a
+      sink/source pair of strings. 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,dptx-codec:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: The phandle of MT8188 Display Port Tx codec node.
+
+  mediatek,hdmi-codec:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: The phandle of MT8188 HDMI codec node.
+
+additionalProperties: false
+
+required:
+  - compatible
+  - mediatek,platform
+
+examples:
+  - |
+
+    sound: mt8188-sound {
+        compatible = "mediatek,mt8188_mt6359_evb";
+        mediatek,platform = <&afe>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&aud_pins_default>;
+        audio-routing =
+            "Headphone", "Headphone L",
+            "Headphone", "Headphone R",
+            "AIN1", "Headset Mic";
+    };
+
+...
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 04/12] ASoC: mediatek: mt8188: support adda in platform driver
  2022-10-21  8:27 ` [PATCH v2 04/12] ASoC: mediatek: mt8188: support adda in platform driver Trevor Wu
@ 2022-10-21  8:41   ` AngeloGioacchino Del Regno
  0 siblings, 0 replies; 27+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-10-21  8:41 UTC (permalink / raw)
  To: Trevor Wu, broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Il 21/10/22 10:27, Trevor Wu ha scritto:
> Add mt8188 adda dai driver support.
> 
> Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 05/12] ASoC: mediatek: mt8188: support etdm in platform driver
  2022-10-21  8:27 ` [PATCH v2 05/12] ASoC: mediatek: mt8188: support etdm " Trevor Wu
@ 2022-10-21  8:41   ` AngeloGioacchino Del Regno
  0 siblings, 0 replies; 27+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-10-21  8:41 UTC (permalink / raw)
  To: Trevor Wu, broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Il 21/10/22 10:27, Trevor Wu ha scritto:
> Add mt8188 etdm dai driver support.
> 
> Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 03/12] ASoC: mediatek: mt8188: support audsys clock
  2022-10-21  8:27 ` [PATCH v2 03/12] ASoC: mediatek: mt8188: support audsys clock Trevor Wu
@ 2022-10-21  8:41   ` AngeloGioacchino Del Regno
  2022-10-21  9:58     ` Trevor Wu (吳文良)
  0 siblings, 1 reply; 27+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-10-21  8:41 UTC (permalink / raw)
  To: Trevor Wu, broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

Il 21/10/22 10:27, Trevor Wu ha scritto:
> Add mt8188 audio cg clock control. Audio clock gates are registered to CCF
> for reference count and clock parent management.
> 
> Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
> ---
>   sound/soc/mediatek/mt8188/mt8188-audsys-clk.c | 206 ++++++++++++++++++
>   sound/soc/mediatek/mt8188/mt8188-audsys-clk.h |  15 ++
>   .../soc/mediatek/mt8188/mt8188-audsys-clkid.h |  83 +++++++
>   3 files changed, 304 insertions(+)
>   create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
>   create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
>   create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h
> 
> diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> new file mode 100644
> index 000000000000..1f294231d4c2
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> @@ -0,0 +1,206 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * mt8188-audsys-clk.c  --  MediaTek 8188 audsys clock control
> + *
> + * Copyright (c) 2022 MediaTek Inc.
> + * Author: Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include "mt8188-afe-common.h"
> +#include "mt8188-audsys-clk.h"
> +#include "mt8188-audsys-clkid.h"
> +#include "mt8188-reg.h"
> +
> +struct afe_gate {
> +	int id;
> +	const char *name;
> +	const char *parent_name;
> +	int reg;
> +	u8 bit;
> +	const struct clk_ops *ops;
> +	unsigned long flags;
> +	u8 cg_flags;
> +};
> +
> +#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, _flags, _cgflags) {\
> +		.id = _id,					\
> +		.name = _name,					\
> +		.parent_name = _parent,				\
> +		.reg = _reg,					\
> +		.bit = _bit,					\
> +		.flags = _flags,				\
> +		.cg_flags = _cgflags,				\
> +	}
> +
> +#define GATE_AFE(_id, _name, _parent, _reg, _bit)		\
> +	GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,		\
> +		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE)

Can you please explain what's the reason for CLK_IGNORE_UNUSED here?
Maybe we can solve some issue that you're facing in a cleaner way.

Regards,
Angelo


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 03/12] ASoC: mediatek: mt8188: support audsys clock
  2022-10-21  8:41   ` AngeloGioacchino Del Regno
@ 2022-10-21  9:58     ` Trevor Wu (吳文良)
  2022-10-25 10:18       ` AngeloGioacchino Del Regno
  0 siblings, 1 reply; 27+ messages in thread
From: Trevor Wu (吳文良) @ 2022-10-21  9:58 UTC (permalink / raw)
  To: robh+dt, matthias.bgg, p.zabel, angelogioacchino.delregno,
	broonie, tiwai
  Cc: linux-arm-kernel, linux-kernel, linux-mediatek, alsa-devel,
	Project_Global_Chrome_Upstream_Group, devicetree

On Fri, 2022-10-21 at 10:41 +0200, AngeloGioacchino Del Regno wrote:
> Il 21/10/22 10:27, Trevor Wu ha scritto:
> > Add mt8188 audio cg clock control. Audio clock gates are registered
> > to CCF
> > for reference count and clock parent management.
> > 
> > Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
> > ---
> >   sound/soc/mediatek/mt8188/mt8188-audsys-clk.c | 206
> > ++++++++++++++++++
> >   sound/soc/mediatek/mt8188/mt8188-audsys-clk.h |  15 ++
> >   .../soc/mediatek/mt8188/mt8188-audsys-clkid.h |  83 +++++++
> >   3 files changed, 304 insertions(+)
> >   create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> >   create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
> >   create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-
> > clkid.h
> > 
> > diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> > b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> > new file mode 100644
> > index 000000000000..1f294231d4c2
> > --- /dev/null
> > +++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> > @@ -0,0 +1,206 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * mt8188-audsys-clk.c  --  MediaTek 8188 audsys clock control
> > + *
> > + * Copyright (c) 2022 MediaTek Inc.
> > + * Author: Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/clk-provider.h>
> > +#include <linux/clkdev.h>
> > +#include "mt8188-afe-common.h"
> > +#include "mt8188-audsys-clk.h"
> > +#include "mt8188-audsys-clkid.h"
> > +#include "mt8188-reg.h"
> > +
> > +struct afe_gate {
> > +	int id;
> > +	const char *name;
> > +	const char *parent_name;
> > +	int reg;
> > +	u8 bit;
> > +	const struct clk_ops *ops;
> > +	unsigned long flags;
> > +	u8 cg_flags;
> > +};
> > +
> > +#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, _flags,
> > _cgflags) {\
> > +		.id = _id,					\
> > +		.name = _name,					\
> > +		.parent_name = _parent,				\
> > +		.reg = _reg,					\
> > +		.bit = _bit,					\
> > +		.flags = _flags,				\
> > +		.cg_flags = _cgflags,				\
> > +	}
> > +
> > +#define GATE_AFE(_id, _name, _parent, _reg, _bit)		\
> > +	GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,		\
> > +		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> > CLK_GATE_SET_TO_DISABLE)
> 
> Can you please explain what's the reason for CLK_IGNORE_UNUSED here?
> Maybe we can solve some issue that you're facing in a cleaner way.
> 
> Regards,
> Angelo

Hi Angelo,

Because clk_disable_unused() calls clk_core_is_enabled(), register
access happens in is_enabled() ops.
At the moment, the power for register access is not enabled, so the
register read results in CPU hang.

That's why I added CLK_IGNORE_UNUSED here, but it can't resolve all
issues. Actually, we met same problem when "cat
/sys/kernel/debug/clk/clk_summary" is used. We are still suffering the
problem.

I'm not sure if I can implement clk ops by myself, and exclude the
registration of is_enabled() ops.

Thanks,
Trevor
> 
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 10/12] dt-bindings: mediatek: mt8188: add audio afe document
  2022-10-21  8:27 ` [PATCH v2 10/12] dt-bindings: mediatek: mt8188: add audio afe document Trevor Wu
@ 2022-10-24 18:33   ` Rob Herring
  2022-10-31  7:11     ` Trevor Wu (吳文良)
  2022-10-29  0:06   ` Krzysztof Kozlowski
  1 sibling, 1 reply; 27+ messages in thread
From: Rob Herring @ 2022-10-24 18:33 UTC (permalink / raw)
  To: Trevor Wu
  Cc: broonie, tiwai, matthias.bgg, p.zabel, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

On Fri, Oct 21, 2022 at 04:27:17PM +0800, Trevor Wu wrote:
> Add mt8188 audio afe document.
> 
> Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
> ---
>  .../bindings/sound/mt8188-afe-pcm.yaml        | 187 ++++++++++++++++++
>  1 file changed, 187 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml
> 
> diff --git a/Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml b/Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml
> new file mode 100644
> index 000000000000..b2c548c31e4d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml
> @@ -0,0 +1,187 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/mt8188-afe-pcm.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek AFE PCM controller for mt8188
> +
> +maintainers:
> +  - Trevor Wu <trevor.wu@mediatek.com>
> +
> +properties:
> +  compatible:
> +    const: mediatek,mt8188-afe
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  resets:
> +    maxItems: 1
> +
> +  reset-names:
> +    const: audiosys
> +
> +  mediatek,topckgen:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description: The phandle of the mediatek topckgen controller
> +
> +  power-domains:
> +    maxItems: 1
> +
> +  clocks:
> +    items:
> +      - description: 26M clock
> +      - description: audio pll1 clock
> +      - description: audio pll2 clock
> +      - description: clock divider for i2si1_mck
> +      - description: clock divider for i2si2_mck
> +      - description: clock divider for i2so1_mck
> +      - description: clock divider for i2so2_mck
> +      - description: clock divider for dptx_mck
> +      - description: a1sys hoping clock
> +      - description: audio intbus clock
> +      - description: audio hires clock
> +      - description: audio local bus clock
> +      - description: mux for dptx_mck
> +      - description: mux for i2so1_mck
> +      - description: mux for i2so2_mck
> +      - description: mux for i2si1_mck
> +      - description: mux for i2si2_mck
> +      - description: audio 26m clock
> +
> +  clock-names:
> +    items:
> +      - const: clk26m
> +      - const: apll1_ck
> +      - const: apll2_ck
> +      - const: apll12_div0
> +      - const: apll12_div1
> +      - const: apll12_div2
> +      - const: apll12_div3
> +      - const: apll12_div9
> +      - const: a1sys_hp_sel
> +      - const: aud_intbus_sel
> +      - const: audio_h_sel
> +      - const: audio_local_bus_sel
> +      - const: dptx_m_sel
> +      - const: i2so1_m_sel
> +      - const: i2so2_m_sel
> +      - const: i2si1_m_sel
> +      - const: i2si2_m_sel
> +      - const: adsp_audio_26m
> +
> +patternProperties:
> +  "^mediatek,etdm-in[1-2]-chn-disabled$":
> +    $ref: /schemas/types.yaml#/definitions/uint8-array
> +    maxItems: 16
> +    description: |

Don't need '|'

> +      Specify which input channel should be disabled, so the data of
> +      specified channel won't be outputted to memory.

I'm not clear on what each of the 16 entries represents. What's index 0, 
1, 2, etc.?

> +    items:
> +      enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

maximum: 15


> +
> +  "^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
> +    description: Specify etdm in mclk output rate for always on case.
> +
> +  "^mediatek,etdm-out[1-3]-mclk-always-on-rate-hz$":
> +    description: Specify etdm out mclk output rate for always on case.
> +
> +  "^mediatek,etdm-in[1-2]-multi-pin-mode$":
> +    type: boolean
> +    description: if present, the etdm data mode is I2S.
> +
> +  "^mediatek,etdm-out[1-3]-multi-pin-mode$":
> +    type: boolean
> +    description: if present, the etdm data mode is I2S.
> +
> +  "^mediatek,etdm-in[1-2]-cowork-source$":
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: |
> +      etdm modules can share the same external clock pin. Specify
> +      which etdm clock source is required by this etdm in moudule.
> +    enum:
> +      - 0 # etdm1_in
> +      - 1 # etdm2_in
> +      - 2 # etdm1_out
> +      - 3 # etdm2_out
> +
> +  "^mediatek,etdm-out[1-2]-cowork-source$":
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: |
> +      etdm modules can share the same external clock pin. Specify
> +      which etdm clock source is required by this etdm out moudule.
> +    enum:
> +      - 0 # etdm1_in
> +      - 1 # etdm2_in
> +      - 2 # etdm1_out
> +      - 3 # etdm2_out
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - resets
> +  - reset-names
> +  - mediatek,topckgen
> +  - power-domains
> +  - clocks
> +  - clock-names
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +
> +    afe: afe@10b10000 {
> +        compatible = "mediatek,mt8188-afe";
> +        reg = <0x10b10000 0x10000>;
> +        interrupts = <GIC_SPI 822 IRQ_TYPE_LEVEL_HIGH 0>;
> +        resets = <&watchdog 14>;
> +        reset-names = "audiosys";
> +        mediatek,topckgen = <&topckgen>;
> +        power-domains = <&spm 13>; //MT8188_POWER_DOMAIN_AUDIO
> +        clocks = <&clk26m>,
> +                 <&topckgen 72>, //CLK_TOP_APLL1
> +                 <&topckgen 73>, //CLK_TOP_APLL2
> +                 <&topckgen 186>, //CLK_TOP_APLL12_CK_DIV0
> +                 <&topckgen 187>, //CLK_TOP_APLL12_CK_DIV1
> +                 <&topckgen 188>, //CLK_TOP_APLL12_CK_DIV2
> +                 <&topckgen 189>, //CLK_TOP_APLL12_CK_DIV3
> +                 <&topckgen 191>, //CLK_TOP_APLL12_CK_DIV9
> +                 <&topckgen 83>, //CLK_TOP_A1SYS_HP
> +                 <&topckgen 31>, //CLK_TOP_AUD_INTBUS
> +                 <&topckgen 32>, //CLK_TOP_AUDIO_H
> +                 <&topckgen 69>, //CLK_TOP_AUDIO_LOCAL_BUS
> +                 <&topckgen 81>, //CLK_TOP_DPTX
> +                 <&topckgen 77>, //CLK_TOP_I2SO1
> +                 <&topckgen 78>, //CLK_TOP_I2SO2
> +                 <&topckgen 79>, //CLK_TOP_I2SI1
> +                 <&topckgen 80>, //CLK_TOP_I2SI2
> +                 <&adsp_audio26m 0>; //CLK_AUDIODSP_AUDIO26M
> +        clock-names = "clk26m",
> +                      "apll1_ck",
> +                      "apll2_ck",
> +                      "apll12_div0",
> +                      "apll12_div1",
> +                      "apll12_div2",
> +                      "apll12_div3",
> +                      "apll12_div9",
> +                      "a1sys_hp_sel",
> +                      "aud_intbus_sel",
> +                      "audio_h_sel",
> +                      "audio_local_bus_sel",
> +                      "dptx_m_sel",
> +                      "i2so1_m_sel",
> +                      "i2so2_m_sel",
> +                      "i2si1_m_sel",
> +                      "i2si2_m_sel",
> +                      "adsp_audio_26m";

It's good if the examples include optional properties so we at least 
have some validation the schema matches the DTS.

> +    };
> +
> +...
> -- 
> 2.18.0
> 
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 12/12] dt-bindings: mediatek: mt8188: add mt8188-mt6359 document
  2022-10-21  8:27 ` [PATCH v2 12/12] dt-bindings: mediatek: mt8188: add mt8188-mt6359 document Trevor Wu
@ 2022-10-24 18:38   ` Rob Herring
  2022-10-31  6:53     ` Trevor Wu (吳文良)
  0 siblings, 1 reply; 27+ messages in thread
From: Rob Herring @ 2022-10-24 18:38 UTC (permalink / raw)
  To: Trevor Wu
  Cc: broonie, tiwai, matthias.bgg, p.zabel, angelogioacchino.delregno,
	Project_Global_Chrome_Upstream_Group, alsa-devel, linux-mediatek,
	linux-arm-kernel, linux-kernel, devicetree

On Fri, Oct 21, 2022 at 04:27:19PM +0800, Trevor Wu wrote:
> Add document for mt8188 board with mt6359.
> 
> Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
> ---
>  .../bindings/sound/mt8188-mt6359.yaml         | 64 +++++++++++++++++++
>  1 file changed, 64 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
> 
> diff --git a/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml b/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
> new file mode 100644
> index 000000000000..9c493a6101ff
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
> @@ -0,0 +1,64 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/mt8188-mt6359.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek MT8188 ASoC sound card driver

Drop 'driver'

> +
> +maintainers:
> +  - Trevor Wu <trevor.wu@mediatek.com>
> +
> +description:
> +  This binding describes the MT8188 sound card.

Drop, the description doesn't add anything the title didn't say.

> +
> +properties:
> +  compatible:
> +    enum:

Only 1 entry, use 'const'

> +      - mediatek,mt8188_mt6359_evb

s/_/-/

> +
> +  model:
> +    $ref: /schemas/types.yaml#/definitions/string
> +    description: User specified audio sound card name
> +
> +  audio-routing:
> +    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
> +    description:
> +      A list of the connections between audio components. Each entry is a
> +      sink/source pair of strings. 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,dptx-codec:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description: The phandle of MT8188 Display Port Tx codec node.
> +
> +  mediatek,hdmi-codec:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description: The phandle of MT8188 HDMI codec node.
> +
> +additionalProperties: false
> +
> +required:
> +  - compatible
> +  - mediatek,platform
> +
> +examples:
> +  - |
> +
> +    sound: mt8188-sound {
> +        compatible = "mediatek,mt8188_mt6359_evb";
> +        mediatek,platform = <&afe>;
> +        pinctrl-names = "default";
> +        pinctrl-0 = <&aud_pins_default>;
> +        audio-routing =
> +            "Headphone", "Headphone L",
> +            "Headphone", "Headphone R",
> +            "AIN1", "Headset Mic";
> +    };
> +
> +...
> -- 
> 2.18.0
> 
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 03/12] ASoC: mediatek: mt8188: support audsys clock
  2022-10-21  9:58     ` Trevor Wu (吳文良)
@ 2022-10-25 10:18       ` AngeloGioacchino Del Regno
  2022-10-26  4:10         ` Trevor Wu (吳文良)
  0 siblings, 1 reply; 27+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-10-25 10:18 UTC (permalink / raw)
  To: Trevor Wu (吳文良),
	robh+dt, matthias.bgg, p.zabel, broonie, tiwai
  Cc: linux-arm-kernel, linux-kernel, linux-mediatek, alsa-devel,
	Project_Global_Chrome_Upstream_Group, devicetree

Il 21/10/22 11:58, Trevor Wu (吳文良) ha scritto:
> On Fri, 2022-10-21 at 10:41 +0200, AngeloGioacchino Del Regno wrote:
>> Il 21/10/22 10:27, Trevor Wu ha scritto:
>>> Add mt8188 audio cg clock control. Audio clock gates are registered
>>> to CCF
>>> for reference count and clock parent management.
>>>
>>> Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
>>> ---
>>>    sound/soc/mediatek/mt8188/mt8188-audsys-clk.c | 206
>>> ++++++++++++++++++
>>>    sound/soc/mediatek/mt8188/mt8188-audsys-clk.h |  15 ++
>>>    .../soc/mediatek/mt8188/mt8188-audsys-clkid.h |  83 +++++++
>>>    3 files changed, 304 insertions(+)
>>>    create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
>>>    create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
>>>    create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-
>>> clkid.h
>>>
>>> diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
>>> b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
>>> new file mode 100644
>>> index 000000000000..1f294231d4c2
>>> --- /dev/null
>>> +++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
>>> @@ -0,0 +1,206 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * mt8188-audsys-clk.c  --  MediaTek 8188 audsys clock control
>>> + *
>>> + * Copyright (c) 2022 MediaTek Inc.
>>> + * Author: Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
>>> + */
>>> +
>>> +#include <linux/clk.h>
>>> +#include <linux/clk-provider.h>
>>> +#include <linux/clkdev.h>
>>> +#include "mt8188-afe-common.h"
>>> +#include "mt8188-audsys-clk.h"
>>> +#include "mt8188-audsys-clkid.h"
>>> +#include "mt8188-reg.h"
>>> +
>>> +struct afe_gate {
>>> +	int id;
>>> +	const char *name;
>>> +	const char *parent_name;
>>> +	int reg;
>>> +	u8 bit;
>>> +	const struct clk_ops *ops;
>>> +	unsigned long flags;
>>> +	u8 cg_flags;
>>> +};
>>> +
>>> +#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, _flags,
>>> _cgflags) {\
>>> +		.id = _id,					\
>>> +		.name = _name,					\
>>> +		.parent_name = _parent,				\
>>> +		.reg = _reg,					\
>>> +		.bit = _bit,					\
>>> +		.flags = _flags,				\
>>> +		.cg_flags = _cgflags,				\
>>> +	}
>>> +
>>> +#define GATE_AFE(_id, _name, _parent, _reg, _bit)		\
>>> +	GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,		\
>>> +		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> CLK_GATE_SET_TO_DISABLE)
>>
>> Can you please explain what's the reason for CLK_IGNORE_UNUSED here?
>> Maybe we can solve some issue that you're facing in a cleaner way.
>>
>> Regards,
>> Angelo
> 
> Hi Angelo,
> 
> Because clk_disable_unused() calls clk_core_is_enabled(), register
> access happens in is_enabled() ops.
> At the moment, the power for register access is not enabled, so the
> register read results in CPU hang.
> 
> That's why I added CLK_IGNORE_UNUSED here, but it can't resolve all
> issues. Actually, we met same problem when "cat
> /sys/kernel/debug/clk/clk_summary" is used. We are still suffering the
> problem.
> 
> I'm not sure if I can implement clk ops by myself, and exclude the
> registration of is_enabled() ops.
> 

Is the power for register access enabled with a power domain?

Check drivers/clk/clk.c, grep for core->rpm_enabled.

If you enable runtime PM before registering the clocks, and you register them
with the right struct device, the clock API will enable power for you before
trying to read the clock enable status.

Regards,
Angelo


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 03/12] ASoC: mediatek: mt8188: support audsys clock
  2022-10-25 10:18       ` AngeloGioacchino Del Regno
@ 2022-10-26  4:10         ` Trevor Wu (吳文良)
  2022-10-26  8:18           ` AngeloGioacchino Del Regno
  0 siblings, 1 reply; 27+ messages in thread
From: Trevor Wu (吳文良) @ 2022-10-26  4:10 UTC (permalink / raw)
  To: p.zabel, matthias.bgg, angelogioacchino.delregno, robh+dt, tiwai,
	broonie
  Cc: linux-arm-kernel, linux-kernel, linux-mediatek, alsa-devel,
	Project_Global_Chrome_Upstream_Group, devicetree

On Tue, 2022-10-25 at 12:18 +0200, AngeloGioacchino Del Regno wrote:
> Il 21/10/22 11:58, Trevor Wu (吳文良) ha scritto:
> > On Fri, 2022-10-21 at 10:41 +0200, AngeloGioacchino Del Regno
> > wrote:
> > > Il 21/10/22 10:27, Trevor Wu ha scritto:
> > > > Add mt8188 audio cg clock control. Audio clock gates are
> > > > registered
> > > > to CCF
> > > > for reference count and clock parent management.
> > > > 
> > > > Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
> > > > ---
> > > >    sound/soc/mediatek/mt8188/mt8188-audsys-clk.c | 206
> > > > ++++++++++++++++++
> > > >    sound/soc/mediatek/mt8188/mt8188-audsys-clk.h |  15 ++
> > > >    .../soc/mediatek/mt8188/mt8188-audsys-clkid.h |  83 +++++++
> > > >    3 files changed, 304 insertions(+)
> > > >    create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-
> > > > clk.c
> > > >    create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-
> > > > clk.h
> > > >    create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-
> > > > clkid.h
> > > > 
> > > > diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> > > > b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> > > > new file mode 100644
> > > > index 000000000000..1f294231d4c2
> > > > --- /dev/null
> > > > +++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> > > > @@ -0,0 +1,206 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +/*
> > > > + * mt8188-audsys-clk.c  --  MediaTek 8188 audsys clock control
> > > > + *
> > > > + * Copyright (c) 2022 MediaTek Inc.
> > > > + * Author: Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
> > > > + */
> > > > +
> > > > +#include <linux/clk.h>
> > > > +#include <linux/clk-provider.h>
> > > > +#include <linux/clkdev.h>
> > > > +#include "mt8188-afe-common.h"
> > > > +#include "mt8188-audsys-clk.h"
> > > > +#include "mt8188-audsys-clkid.h"
> > > > +#include "mt8188-reg.h"
> > > > +
> > > > +struct afe_gate {
> > > > +	int id;
> > > > +	const char *name;
> > > > +	const char *parent_name;
> > > > +	int reg;
> > > > +	u8 bit;
> > > > +	const struct clk_ops *ops;
> > > > +	unsigned long flags;
> > > > +	u8 cg_flags;
> > > > +};
> > > > +
> > > > +#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,
> > > > _flags,
> > > > _cgflags) {\
> > > > +		.id = _id,					
> > > > \
> > > > +		.name = _name,					
> > > > \
> > > > +		.parent_name = _parent,				
> > > > \
> > > > +		.reg = _reg,					
> > > > \
> > > > +		.bit = _bit,					
> > > > \
> > > > +		.flags = _flags,				
> > > > \
> > > > +		.cg_flags = _cgflags,				
> > > > \
> > > > +	}
> > > > +
> > > > +#define GATE_AFE(_id, _name, _parent, _reg, _bit)		
> > > > \
> > > > +	GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,		
> > > > \
> > > > +		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> > > > CLK_GATE_SET_TO_DISABLE)
> > > 
> > > Can you please explain what's the reason for CLK_IGNORE_UNUSED
> > > here?
> > > Maybe we can solve some issue that you're facing in a cleaner
> > > way.
> > > 
> > > Regards,
> > > Angelo
> > 
> > Hi Angelo,
> > 
> > Because clk_disable_unused() calls clk_core_is_enabled(), register
> > access happens in is_enabled() ops.
> > At the moment, the power for register access is not enabled, so the
> > register read results in CPU hang.
> > 
> > That's why I added CLK_IGNORE_UNUSED here, but it can't resolve all
> > issues. Actually, we met same problem when "cat
> > /sys/kernel/debug/clk/clk_summary" is used. We are still suffering
> > the
> > problem.
> > 
> > I'm not sure if I can implement clk ops by myself, and exclude the
> > registration of is_enabled() ops.
> > 
> 
> Is the power for register access enabled with a power domain?
> 
> Check drivers/clk/clk.c, grep for core->rpm_enabled.
> 
> If you enable runtime PM before registering the clocks, and you
> register them
> with the right struct device, the clock API will enable power for you
> before
> trying to read the clock enable status.
> 
> Regards,
> Angelo
> 

Hi Angelo,

I tried the way in MT8195, but it caused circular lock problem.

Because mtcmos depends on some clocks, clk_bulk_prepare_enable is also
used in scpsys_power_on()[1].
If the clock also depends on the power domain, this results in the
circular lock problem.
That's why I don't bind the power domain with these clocks.

[1] 
https://elixir.bootlin.com/linux/v6.1-rc2/source/drivers/soc/mediatek/mtk-pm-domains.c

Thanks,
Trevor


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 03/12] ASoC: mediatek: mt8188: support audsys clock
  2022-10-26  4:10         ` Trevor Wu (吳文良)
@ 2022-10-26  8:18           ` AngeloGioacchino Del Regno
  2022-12-01  8:43             ` Trevor Wu (吳文良)
  0 siblings, 1 reply; 27+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-10-26  8:18 UTC (permalink / raw)
  To: Trevor Wu (吳文良),
	p.zabel, matthias.bgg, robh+dt, tiwai, broonie
  Cc: linux-arm-kernel, linux-kernel, linux-mediatek, alsa-devel,
	Project_Global_Chrome_Upstream_Group, devicetree

Il 26/10/22 06:10, Trevor Wu (吳文良) ha scritto:
> On Tue, 2022-10-25 at 12:18 +0200, AngeloGioacchino Del Regno wrote:
>> Il 21/10/22 11:58, Trevor Wu (吳文良) ha scritto:
>>> On Fri, 2022-10-21 at 10:41 +0200, AngeloGioacchino Del Regno
>>> wrote:
>>>> Il 21/10/22 10:27, Trevor Wu ha scritto:
>>>>> Add mt8188 audio cg clock control. Audio clock gates are
>>>>> registered
>>>>> to CCF
>>>>> for reference count and clock parent management.
>>>>>
>>>>> Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
>>>>> ---
>>>>>     sound/soc/mediatek/mt8188/mt8188-audsys-clk.c | 206
>>>>> ++++++++++++++++++
>>>>>     sound/soc/mediatek/mt8188/mt8188-audsys-clk.h |  15 ++
>>>>>     .../soc/mediatek/mt8188/mt8188-audsys-clkid.h |  83 +++++++
>>>>>     3 files changed, 304 insertions(+)
>>>>>     create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-
>>>>> clk.c
>>>>>     create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-
>>>>> clk.h
>>>>>     create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-
>>>>> clkid.h
>>>>>
>>>>> diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
>>>>> b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
>>>>> new file mode 100644
>>>>> index 000000000000..1f294231d4c2
>>>>> --- /dev/null
>>>>> +++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
>>>>> @@ -0,0 +1,206 @@
>>>>> +// SPDX-License-Identifier: GPL-2.0
>>>>> +/*
>>>>> + * mt8188-audsys-clk.c  --  MediaTek 8188 audsys clock control
>>>>> + *
>>>>> + * Copyright (c) 2022 MediaTek Inc.
>>>>> + * Author: Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
>>>>> + */
>>>>> +
>>>>> +#include <linux/clk.h>
>>>>> +#include <linux/clk-provider.h>
>>>>> +#include <linux/clkdev.h>
>>>>> +#include "mt8188-afe-common.h"
>>>>> +#include "mt8188-audsys-clk.h"
>>>>> +#include "mt8188-audsys-clkid.h"
>>>>> +#include "mt8188-reg.h"
>>>>> +
>>>>> +struct afe_gate {
>>>>> +	int id;
>>>>> +	const char *name;
>>>>> +	const char *parent_name;
>>>>> +	int reg;
>>>>> +	u8 bit;
>>>>> +	const struct clk_ops *ops;
>>>>> +	unsigned long flags;
>>>>> +	u8 cg_flags;
>>>>> +};
>>>>> +
>>>>> +#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,
>>>>> _flags,
>>>>> _cgflags) {\
>>>>> +		.id = _id,					
>>>>> \
>>>>> +		.name = _name,					
>>>>> \
>>>>> +		.parent_name = _parent,				
>>>>> \
>>>>> +		.reg = _reg,					
>>>>> \
>>>>> +		.bit = _bit,					
>>>>> \
>>>>> +		.flags = _flags,				
>>>>> \
>>>>> +		.cg_flags = _cgflags,				
>>>>> \
>>>>> +	}
>>>>> +
>>>>> +#define GATE_AFE(_id, _name, _parent, _reg, _bit)		
>>>>> \
>>>>> +	GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,		
>>>>> \
>>>>> +		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>> CLK_GATE_SET_TO_DISABLE)
>>>>
>>>> Can you please explain what's the reason for CLK_IGNORE_UNUSED
>>>> here?
>>>> Maybe we can solve some issue that you're facing in a cleaner
>>>> way.
>>>>
>>>> Regards,
>>>> Angelo
>>>
>>> Hi Angelo,
>>>
>>> Because clk_disable_unused() calls clk_core_is_enabled(), register
>>> access happens in is_enabled() ops.
>>> At the moment, the power for register access is not enabled, so the
>>> register read results in CPU hang.
>>>
>>> That's why I added CLK_IGNORE_UNUSED here, but it can't resolve all
>>> issues. Actually, we met same problem when "cat
>>> /sys/kernel/debug/clk/clk_summary" is used. We are still suffering
>>> the
>>> problem.
>>>
>>> I'm not sure if I can implement clk ops by myself, and exclude the
>>> registration of is_enabled() ops.
>>>
>>
>> Is the power for register access enabled with a power domain?
>>
>> Check drivers/clk/clk.c, grep for core->rpm_enabled.
>>
>> If you enable runtime PM before registering the clocks, and you
>> register them
>> with the right struct device, the clock API will enable power for you
>> before
>> trying to read the clock enable status.
>>
>> Regards,
>> Angelo
>>
> 
> Hi Angelo,
> 
> I tried the way in MT8195, but it caused circular lock problem.
> 
> Because mtcmos depends on some clocks, clk_bulk_prepare_enable is also
> used in scpsys_power_on()[1].
> If the clock also depends on the power domain, this results in the
> circular lock problem.
> That's why I don't bind the power domain with these clocks.
> 

This is not supposed to happen... can you please give me a (MT8195) patch to
reproduce the issue that you're seeing?

I would like to investigate that to check if I can come up with a good solution.

Thanks,
Angelo

> [1]
> https://elixir.bootlin.com/linux/v6.1-rc2/source/drivers/soc/mediatek/mtk-pm-domains.c
> 
> Thanks,
> Trevor
> 
> 




_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 10/12] dt-bindings: mediatek: mt8188: add audio afe document
  2022-10-21  8:27 ` [PATCH v2 10/12] dt-bindings: mediatek: mt8188: add audio afe document Trevor Wu
  2022-10-24 18:33   ` Rob Herring
@ 2022-10-29  0:06   ` Krzysztof Kozlowski
  2022-10-31  6:50     ` Trevor Wu (吳文良)
  1 sibling, 1 reply; 27+ messages in thread
From: Krzysztof Kozlowski @ 2022-10-29  0:06 UTC (permalink / raw)
  To: Trevor Wu, broonie, tiwai, robh+dt, matthias.bgg, p.zabel
  Cc: angelogioacchino.delregno, Project_Global_Chrome_Upstream_Group,
	alsa-devel, linux-mediatek, linux-arm-kernel, linux-kernel,
	devicetree

On 21/10/2022 04:27, Trevor Wu wrote:
> Add mt8188 audio afe document.
> 
> Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>

Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC.  It might happen, that command when run on an older
kernel, gives you outdated entries.  Therefore please be sure you base
your patches on recent Linux kernel.

> ---
>  .../bindings/sound/mt8188-afe-pcm.yaml        | 187 ++++++++++++++++++
>  1 file changed, 187 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml
> 
> diff --git a/Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml b/Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml
> new file mode 100644
> index 000000000000..b2c548c31e4d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml

Name matching compatible.


Best regards,
Krzysztof


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 10/12] dt-bindings: mediatek: mt8188: add audio afe document
  2022-10-29  0:06   ` Krzysztof Kozlowski
@ 2022-10-31  6:50     ` Trevor Wu (吳文良)
  0 siblings, 0 replies; 27+ messages in thread
From: Trevor Wu (吳文良) @ 2022-10-31  6:50 UTC (permalink / raw)
  To: robh+dt, matthias.bgg, p.zabel, broonie, krzk, tiwai
  Cc: linux-arm-kernel, linux-kernel, linux-mediatek,
	angelogioacchino.delregno, alsa-devel,
	Project_Global_Chrome_Upstream_Group, devicetree

On Fri, 2022-10-28 at 20:06 -0400, Krzysztof Kozlowski wrote:
> On 21/10/2022 04:27, Trevor Wu wrote:
> > Add mt8188 audio afe document.
> > 
> > Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
> 
> Please use scripts/get_maintainers.pl to get a list of necessary
> people
> and lists to CC.  It might happen, that command when run on an older
> kernel, gives you outdated entries.  Therefore please be sure you
> base
> your patches on recent Linux kernel.
> 

Hi Krzysztof,

Thanks for your review first.
I did scripts/get_maintainers.pl based on latest broonie for-next tree,
but I misunderstood the rule about CC list. That's why I only picked
one maintainer for every domain. I will update the CC list in V3.

> > ---
> >  .../bindings/sound/mt8188-afe-pcm.yaml        | 187
> > ++++++++++++++++++
> >  1 file changed, 187 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/sound/mt8188-
> > afe-pcm.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/sound/mt8188-afe-
> > pcm.yaml b/Documentation/devicetree/bindings/sound/mt8188-afe-
> > pcm.yaml
> > new file mode 100644
> > index 000000000000..b2c548c31e4d
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml
> 
> Name matching compatible.
> 
OK, I will update the file name in V3.

Thanks,
Trevor

> Best regards,
> Krzysztof
> 
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 12/12] dt-bindings: mediatek: mt8188: add mt8188-mt6359 document
  2022-10-24 18:38   ` Rob Herring
@ 2022-10-31  6:53     ` Trevor Wu (吳文良)
  0 siblings, 0 replies; 27+ messages in thread
From: Trevor Wu (吳文良) @ 2022-10-31  6:53 UTC (permalink / raw)
  To: robh
  Cc: linux-mediatek, linux-kernel, devicetree, broonie, p.zabel,
	Project_Global_Chrome_Upstream_Group, tiwai, linux-arm-kernel,
	matthias.bgg, alsa-devel, angelogioacchino.delregno

Hi Rob,

Thanks for your review, I will update them in V3.

Thanks,
Trevor

On Mon, 2022-10-24 at 13:38 -0500, Rob Herring wrote:
> On Fri, Oct 21, 2022 at 04:27:19PM +0800, Trevor Wu wrote:
> > Add document for mt8188 board with mt6359.
> > 
> > Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
> > ---
> >  .../bindings/sound/mt8188-mt6359.yaml         | 64
> > +++++++++++++++++++
> >  1 file changed, 64 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/sound/mt8188-
> > mt6359.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/sound/mt8188-
> > mt6359.yaml b/Documentation/devicetree/bindings/sound/mt8188-
> > mt6359.yaml
> > new file mode 100644
> > index 000000000000..9c493a6101ff
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
> > @@ -0,0 +1,64 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: 
> > https://urldefense.com/v3/__http://devicetree.org/schemas/sound/mt8188-mt6359.yaml*__;Iw!!CTRNKA9wMg0ARbw!wCd0tqzmjkRubNK5v9V8D6t_RuPYSb8AKqLPbfITprZT-I2UVgnFbm2N5Zzjr6W91A$
> >  
> > +$schema: 
> > https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!wCd0tqzmjkRubNK5v9V8D6t_RuPYSb8AKqLPbfITprZT-I2UVgnFbm2N5Zxc9ZZ9LA$
> >  
> > +
> > +title: MediaTek MT8188 ASoC sound card driver
> 
> Drop 'driver'
> 
> > +
> > +maintainers:
> > +  - Trevor Wu <trevor.wu@mediatek.com>
> > +
> > +description:
> > +  This binding describes the MT8188 sound card.
> 
> Drop, the description doesn't add anything the title didn't say.
> 
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> 
> Only 1 entry, use 'const'
> 
> > +      - mediatek,mt8188_mt6359_evb
> 
> s/_/-/
> 
> > +
> > +  model:
> > +    $ref: /schemas/types.yaml#/definitions/string
> > +    description: User specified audio sound card name
> > +
> > +  audio-routing:
> > +    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
> > +    description:
> > +      A list of the connections between audio components. Each
> > entry is a
> > +      sink/source pair of strings. 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,dptx-codec:
> > +    $ref: /schemas/types.yaml#/definitions/phandle
> > +    description: The phandle of MT8188 Display Port Tx codec node.
> > +
> > +  mediatek,hdmi-codec:
> > +    $ref: /schemas/types.yaml#/definitions/phandle
> > +    description: The phandle of MT8188 HDMI codec node.
> > +
> > +additionalProperties: false
> > +
> > +required:
> > +  - compatible
> > +  - mediatek,platform
> > +
> > +examples:
> > +  - |
> > +
> > +    sound: mt8188-sound {
> > +        compatible = "mediatek,mt8188_mt6359_evb";
> > +        mediatek,platform = <&afe>;
> > +        pinctrl-names = "default";
> > +        pinctrl-0 = <&aud_pins_default>;
> > +        audio-routing =
> > +            "Headphone", "Headphone L",
> > +            "Headphone", "Headphone R",
> > +            "AIN1", "Headset Mic";
> > +    };
> > +
> > +...
> > -- 
> > 2.18.0
> > 
> > 
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 10/12] dt-bindings: mediatek: mt8188: add audio afe document
  2022-10-24 18:33   ` Rob Herring
@ 2022-10-31  7:11     ` Trevor Wu (吳文良)
  0 siblings, 0 replies; 27+ messages in thread
From: Trevor Wu (吳文良) @ 2022-10-31  7:11 UTC (permalink / raw)
  To: robh
  Cc: linux-mediatek, linux-kernel, devicetree, broonie, p.zabel,
	Project_Global_Chrome_Upstream_Group, tiwai, linux-arm-kernel,
	matthias.bgg, alsa-devel, angelogioacchino.delregno

On Mon, 2022-10-24 at 13:33 -0500, Rob Herring wrote:
> On Fri, Oct 21, 2022 at 04:27:17PM +0800, Trevor Wu wrote:
> > Add mt8188 audio afe document.
> > 
> > Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
> > ---
> >  .../bindings/sound/mt8188-afe-pcm.yaml        | 187
> > ++++++++++++++++++
> >  1 file changed, 187 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/sound/mt8188-
> > afe-pcm.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/sound/mt8188-afe-
> > pcm.yaml b/Documentation/devicetree/bindings/sound/mt8188-afe-
> > pcm.yaml
> > new file mode 100644
> > index 000000000000..b2c548c31e4d
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/sound/mt8188-afe-pcm.yaml
> > @@ -0,0 +1,187 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > 

..snip
> > 
> > +
> > +patternProperties:
> > +  "^mediatek,etdm-in[1-2]-chn-disabled$":
> > +    $ref: /schemas/types.yaml#/definitions/uint8-array
> > +    maxItems: 16
> > +    description: |
> 
> Don't need '|'
> 
> > +      Specify which input channel should be disabled, so the data
> > of
> > +      specified channel won't be outputted to memory.
> 
> I'm not clear on what each of the 16 entries represents. What's index
> 0, 
> 1, 2, etc.?

Hi Rob,

Ext Codec -> ETDM_IN -> MEMIF(DMA) -> Memory

The maximum channel number of etdm-in is 16.
The index matches to the input channel ID.
0 : CH0
1 : CH1
...
15: CH15

User can config the channel ID they don't want to be outputted to
memory in the property.

For example,
For 4 channels ETDM connection, and the following property is
configured.

"mediatek,etdm-in1-chn-disabled = <0>;"

Received etdm1 input data outputted to memory will be [d0_ch1, d0_ch2,
d0_ch3, d1_ch1, d1_ch2, d1_ch3, ...]. CH0 is dropped.

> 
> > +    items:
> > +      enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
> 
> maximum: 15
> 
> 
> > +
> > +  "^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
> > +    description: Specify etdm in mclk output rate for always on
> > case.
> > +
> > +  "^mediatek,etdm-out[1-3]-mclk-always-on-rate-hz$":
> > +    description: Specify etdm out mclk output rate for always on
> > case.
> > +
> > +  "^mediatek,etdm-in[1-2]-multi-pin-mode$":
> > +    type: boolean
> > +    description: if present, the etdm data mode is I2S.
> > +
> > +  "^mediatek,etdm-out[1-3]-multi-pin-mode$":
> > +    type: boolean
> > +    description: if present, the etdm data mode is I2S.
> > +
> > +  "^mediatek,etdm-in[1-2]-cowork-source$":
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    description: |
> > +      etdm modules can share the same external clock pin. Specify
> > +      which etdm clock source is required by this etdm in moudule.
> > +    enum:
> > +      - 0 # etdm1_in
> > +      - 1 # etdm2_in
> > +      - 2 # etdm1_out
> > +      - 3 # etdm2_out
> > +
> > +  "^mediatek,etdm-out[1-2]-cowork-source$":
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    description: |
> > +      etdm modules can share the same external clock pin. Specify
> > +      which etdm clock source is required by this etdm out
> > moudule.
> > +    enum:
> > +      - 0 # etdm1_in
> > +      - 1 # etdm2_in
> > +      - 2 # etdm1_out
> > +      - 3 # etdm2_out
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - resets
> > +  - reset-names
> > +  - mediatek,topckgen
> > +  - power-domains
> > +  - clocks
> > +  - clock-names
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +
> > +    afe: afe@10b10000 {
> > +        compatible = "mediatek,mt8188-afe";
> > +        reg = <0x10b10000 0x10000>;
> > +        interrupts = <GIC_SPI 822 IRQ_TYPE_LEVEL_HIGH 0>;
> > +        resets = <&watchdog 14>;
> > +        reset-names = "audiosys";
> > +        mediatek,topckgen = <&topckgen>;
> > +        power-domains = <&spm 13>; //MT8188_POWER_DOMAIN_AUDIO
> > +        clocks = <&clk26m>,
> > +                 <&topckgen 72>, //CLK_TOP_APLL1
> > +                 <&topckgen 73>, //CLK_TOP_APLL2
> > +                 <&topckgen 186>, //CLK_TOP_APLL12_CK_DIV0
> > +                 <&topckgen 187>, //CLK_TOP_APLL12_CK_DIV1
> > +                 <&topckgen 188>, //CLK_TOP_APLL12_CK_DIV2
> > +                 <&topckgen 189>, //CLK_TOP_APLL12_CK_DIV3
> > +                 <&topckgen 191>, //CLK_TOP_APLL12_CK_DIV9
> > +                 <&topckgen 83>, //CLK_TOP_A1SYS_HP
> > +                 <&topckgen 31>, //CLK_TOP_AUD_INTBUS
> > +                 <&topckgen 32>, //CLK_TOP_AUDIO_H
> > +                 <&topckgen 69>, //CLK_TOP_AUDIO_LOCAL_BUS
> > +                 <&topckgen 81>, //CLK_TOP_DPTX
> > +                 <&topckgen 77>, //CLK_TOP_I2SO1
> > +                 <&topckgen 78>, //CLK_TOP_I2SO2
> > +                 <&topckgen 79>, //CLK_TOP_I2SI1
> > +                 <&topckgen 80>, //CLK_TOP_I2SI2
> > +                 <&adsp_audio26m 0>; //CLK_AUDIODSP_AUDIO26M
> > +        clock-names = "clk26m",
> > +                      "apll1_ck",
> > +                      "apll2_ck",
> > +                      "apll12_div0",
> > +                      "apll12_div1",
> > +                      "apll12_div2",
> > +                      "apll12_div3",
> > +                      "apll12_div9",
> > +                      "a1sys_hp_sel",
> > +                      "aud_intbus_sel",
> > +                      "audio_h_sel",
> > +                      "audio_local_bus_sel",
> > +                      "dptx_m_sel",
> > +                      "i2so1_m_sel",
> > +                      "i2so2_m_sel",
> > +                      "i2si1_m_sel",
> > +                      "i2si2_m_sel",
> > +                      "adsp_audio_26m";
> 
> It's good if the examples include optional properties so we at least 
> have some validation the schema matches the DTS.
> 
OK, I will put some optional properties in V3.

Thanks,
Trevor

> > +    };
> > +
> > +...
> > -- 
> > 2.18.0
> > 
> > 
> 
> 
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 03/12] ASoC: mediatek: mt8188: support audsys clock
  2022-10-26  8:18           ` AngeloGioacchino Del Regno
@ 2022-12-01  8:43             ` Trevor Wu (吳文良)
  2022-12-01  9:42               ` AngeloGioacchino Del Regno
  0 siblings, 1 reply; 27+ messages in thread
From: Trevor Wu (吳文良) @ 2022-12-01  8:43 UTC (permalink / raw)
  To: p.zabel, matthias.bgg, angelogioacchino.delregno, robh+dt, tiwai,
	broonie
  Cc: linux-arm-kernel, linux-kernel, linux-mediatek, alsa-devel,
	Project_Global_Chrome_Upstream_Group, devicetree

On Wed, 2022-10-26 at 10:18 +0200, AngeloGioacchino Del Regno wrote:
> Il 26/10/22 06:10, Trevor Wu (吳文良) ha scritto:
> > On Tue, 2022-10-25 at 12:18 +0200, AngeloGioacchino Del Regno
> > wrote:
> > > Il 21/10/22 11:58, Trevor Wu (吳文良) ha scritto:
> > > > On Fri, 2022-10-21 at 10:41 +0200, AngeloGioacchino Del Regno
> > > > wrote:
> > > > > Il 21/10/22 10:27, Trevor Wu ha scritto:
> > > > > > Add mt8188 audio cg clock control. Audio clock gates are
> > > > > > registered
> > > > > > to CCF
> > > > > > for reference count and clock parent management.
> > > > > > 
> > > > > > Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
> > > > > > ---
> > > > > >     sound/soc/mediatek/mt8188/mt8188-audsys-clk.c | 206
> > > > > > ++++++++++++++++++
> > > > > >     sound/soc/mediatek/mt8188/mt8188-audsys-clk.h |  15 ++
> > > > > >     .../soc/mediatek/mt8188/mt8188-audsys-clkid.h |  83
> > > > > > +++++++
> > > > > >     3 files changed, 304 insertions(+)
> > > > > >     create mode 100644 sound/soc/mediatek/mt8188/mt8188-
> > > > > > audsys-
> > > > > > clk.c
> > > > > >     create mode 100644 sound/soc/mediatek/mt8188/mt8188-
> > > > > > audsys-
> > > > > > clk.h
> > > > > >     create mode 100644 sound/soc/mediatek/mt8188/mt8188-
> > > > > > audsys-
> > > > > > clkid.h
> > > > > > 
> > > > > > diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> > > > > > b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> > > > > > new file mode 100644
> > > > > > index 000000000000..1f294231d4c2
> > > > > > --- /dev/null
> > > > > > +++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> > > > > > @@ -0,0 +1,206 @@
> > > > > > +// SPDX-License-Identifier: GPL-2.0
> > > > > > +/*
> > > > > > + * mt8188-audsys-clk.c  --  MediaTek 8188 audsys clock
> > > > > > control
> > > > > > + *
> > > > > > + * Copyright (c) 2022 MediaTek Inc.
> > > > > > + * Author: Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
> > > > > > + */
> > > > > > +
> > > > > > +#include <linux/clk.h>
> > > > > > +#include <linux/clk-provider.h>
> > > > > > +#include <linux/clkdev.h>
> > > > > > +#include "mt8188-afe-common.h"
> > > > > > +#include "mt8188-audsys-clk.h"
> > > > > > +#include "mt8188-audsys-clkid.h"
> > > > > > +#include "mt8188-reg.h"
> > > > > > +
> > > > > > +struct afe_gate {
> > > > > > +	int id;
> > > > > > +	const char *name;
> > > > > > +	const char *parent_name;
> > > > > > +	int reg;
> > > > > > +	u8 bit;
> > > > > > +	const struct clk_ops *ops;
> > > > > > +	unsigned long flags;
> > > > > > +	u8 cg_flags;
> > > > > > +};
> > > > > > +
> > > > > > +#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,
> > > > > > _flags,
> > > > > > _cgflags) {\
> > > > > > +		.id = _id,					
> > > > > > \
> > > > > > +		.name = _name,					
> > > > > > \
> > > > > > +		.parent_name = _parent,				
> > > > > > \
> > > > > > +		.reg = _reg,					
> > > > > > \
> > > > > > +		.bit = _bit,					
> > > > > > \
> > > > > > +		.flags = _flags,				
> > > > > > \
> > > > > > +		.cg_flags = _cgflags,				
> > > > > > \
> > > > > > +	}
> > > > > > +
> > > > > > +#define GATE_AFE(_id, _name, _parent, _reg, _bit)		
> > > > > > \
> > > > > > +	GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,		
> > > > > > \
> > > > > > +		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> > > > > > CLK_GATE_SET_TO_DISABLE)
> > > > > 
> > > > > Can you please explain what's the reason for
> > > > > CLK_IGNORE_UNUSED
> > > > > here?
> > > > > Maybe we can solve some issue that you're facing in a cleaner
> > > > > way.
> > > > > 
> > > > > Regards,
> > > > > Angelo
> > > > 
> > > > Hi Angelo,
> > > > 
> > > > Because clk_disable_unused() calls clk_core_is_enabled(),
> > > > register
> > > > access happens in is_enabled() ops.
> > > > At the moment, the power for register access is not enabled, so
> > > > the
> > > > register read results in CPU hang.
> > > > 
> > > > That's why I added CLK_IGNORE_UNUSED here, but it can't resolve
> > > > all
> > > > issues. Actually, we met same problem when "cat
> > > > /sys/kernel/debug/clk/clk_summary" is used. We are still
> > > > suffering
> > > > the
> > > > problem.
> > > > 
> > > > I'm not sure if I can implement clk ops by myself, and exclude
> > > > the
> > > > registration of is_enabled() ops.
> > > > 
> > > 
> > > Is the power for register access enabled with a power domain?
> > > 
> > > Check drivers/clk/clk.c, grep for core->rpm_enabled.
> > > 
> > > If you enable runtime PM before registering the clocks, and you
> > > register them
> > > with the right struct device, the clock API will enable power for
> > > you
> > > before
> > > trying to read the clock enable status.
> > > 
> > > Regards,
> > > Angelo
> > > 
> > 
> > Hi Angelo,
> > 
> > I tried the way in MT8195, but it caused circular lock problem.
> > 
> > Because mtcmos depends on some clocks, clk_bulk_prepare_enable is
> > also
> > used in scpsys_power_on()[1].
> > If the clock also depends on the power domain, this results in the
> > circular lock problem.
> > That's why I don't bind the power domain with these clocks.
> > 
> 
> This is not supposed to happen... can you please give me a (MT8195)
> patch to
> reproduce the issue that you're seeing?
> 
> I would like to investigate that to check if I can come up with a
> good solution.
> 
> Thanks,
> Angelo


Hi Angelo,

Sorry for replying late.
The original implementation about clock depending on power domain was a
cusotomized request, and it's not based on upstream code base. So I
can't apply the implementation directly. I tried to implement the
suggested solution in upstream code, but I can't reproduce the problem
successfully. 

At the same time, we reviewed the difference between MT8195 and MT8188.
It's found that ADSP_INFRA should be kept ON to resolve the register
r/w access limitation in MT8188, so we can match the hardware design in
MT8195.

After discussing internally, we decided in favour of ADSP_INFRA
soloution. Althought the lock problem can't be seen, the new lock
relationship(prepare_lock -> genpd lock) is actually created. 

In conclusion, ADSP_INFRA will be kept always on and I will remove
CLK_IGNORE_UNUSED flag in V3.

Thanks,
Trevor

> 
> > [1]
> > 
https://urldefense.com/v3/__https://elixir.bootlin.com/linux/v6.1-rc2/source/drivers/soc/mediatek/mtk-pm-domains.c__;!!CTRNKA9wMg0ARbw!yVFCD-B4VZOxDXTGgDtpB0mJbVoY9tHODeICxthAC33lXMq6LRVTGS-4V-Dj129_cA$
> >  
> > 
> > Thanks,
> > Trevor
> > 
> > 
> 
> 
> 
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 03/12] ASoC: mediatek: mt8188: support audsys clock
  2022-12-01  8:43             ` Trevor Wu (吳文良)
@ 2022-12-01  9:42               ` AngeloGioacchino Del Regno
  0 siblings, 0 replies; 27+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-12-01  9:42 UTC (permalink / raw)
  To: Trevor Wu (吳文良),
	p.zabel, matthias.bgg, robh+dt, tiwai, broonie
  Cc: linux-arm-kernel, linux-kernel, linux-mediatek, alsa-devel,
	Project_Global_Chrome_Upstream_Group, devicetree

Il 01/12/22 09:43, Trevor Wu (吳文良) ha scritto:
> On Wed, 2022-10-26 at 10:18 +0200, AngeloGioacchino Del Regno wrote:
>> Il 26/10/22 06:10, Trevor Wu (吳文良) ha scritto:
>>> On Tue, 2022-10-25 at 12:18 +0200, AngeloGioacchino Del Regno
>>> wrote:
>>>> Il 21/10/22 11:58, Trevor Wu (吳文良) ha scritto:
>>>>> On Fri, 2022-10-21 at 10:41 +0200, AngeloGioacchino Del Regno
>>>>> wrote:
>>>>>> Il 21/10/22 10:27, Trevor Wu ha scritto:
>>>>>>> Add mt8188 audio cg clock control. Audio clock gates are
>>>>>>> registered
>>>>>>> to CCF
>>>>>>> for reference count and clock parent management.
>>>>>>>
>>>>>>> Signed-off-by: Trevor Wu <trevor.wu@mediatek.com>
>>>>>>> ---
>>>>>>>      sound/soc/mediatek/mt8188/mt8188-audsys-clk.c | 206
>>>>>>> ++++++++++++++++++
>>>>>>>      sound/soc/mediatek/mt8188/mt8188-audsys-clk.h |  15 ++
>>>>>>>      .../soc/mediatek/mt8188/mt8188-audsys-clkid.h |  83
>>>>>>> +++++++
>>>>>>>      3 files changed, 304 insertions(+)
>>>>>>>      create mode 100644 sound/soc/mediatek/mt8188/mt8188-
>>>>>>> audsys-
>>>>>>> clk.c
>>>>>>>      create mode 100644 sound/soc/mediatek/mt8188/mt8188-
>>>>>>> audsys-
>>>>>>> clk.h
>>>>>>>      create mode 100644 sound/soc/mediatek/mt8188/mt8188-
>>>>>>> audsys-
>>>>>>> clkid.h
>>>>>>>
>>>>>>> diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
>>>>>>> b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
>>>>>>> new file mode 100644
>>>>>>> index 000000000000..1f294231d4c2
>>>>>>> --- /dev/null
>>>>>>> +++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
>>>>>>> @@ -0,0 +1,206 @@
>>>>>>> +// SPDX-License-Identifier: GPL-2.0
>>>>>>> +/*
>>>>>>> + * mt8188-audsys-clk.c  --  MediaTek 8188 audsys clock
>>>>>>> control
>>>>>>> + *
>>>>>>> + * Copyright (c) 2022 MediaTek Inc.
>>>>>>> + * Author: Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
>>>>>>> + */
>>>>>>> +
>>>>>>> +#include <linux/clk.h>
>>>>>>> +#include <linux/clk-provider.h>
>>>>>>> +#include <linux/clkdev.h>
>>>>>>> +#include "mt8188-afe-common.h"
>>>>>>> +#include "mt8188-audsys-clk.h"
>>>>>>> +#include "mt8188-audsys-clkid.h"
>>>>>>> +#include "mt8188-reg.h"
>>>>>>> +
>>>>>>> +struct afe_gate {
>>>>>>> +	int id;
>>>>>>> +	const char *name;
>>>>>>> +	const char *parent_name;
>>>>>>> +	int reg;
>>>>>>> +	u8 bit;
>>>>>>> +	const struct clk_ops *ops;
>>>>>>> +	unsigned long flags;
>>>>>>> +	u8 cg_flags;
>>>>>>> +};
>>>>>>> +
>>>>>>> +#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,
>>>>>>> _flags,
>>>>>>> _cgflags) {\
>>>>>>> +		.id = _id,					
>>>>>>> \
>>>>>>> +		.name = _name,					
>>>>>>> \
>>>>>>> +		.parent_name = _parent,				
>>>>>>> \
>>>>>>> +		.reg = _reg,					
>>>>>>> \
>>>>>>> +		.bit = _bit,					
>>>>>>> \
>>>>>>> +		.flags = _flags,				
>>>>>>> \
>>>>>>> +		.cg_flags = _cgflags,				
>>>>>>> \
>>>>>>> +	}
>>>>>>> +
>>>>>>> +#define GATE_AFE(_id, _name, _parent, _reg, _bit)		
>>>>>>> \
>>>>>>> +	GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,		
>>>>>>> \
>>>>>>> +		       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>> CLK_GATE_SET_TO_DISABLE)
>>>>>>
>>>>>> Can you please explain what's the reason for
>>>>>> CLK_IGNORE_UNUSED
>>>>>> here?
>>>>>> Maybe we can solve some issue that you're facing in a cleaner
>>>>>> way.
>>>>>>
>>>>>> Regards,
>>>>>> Angelo
>>>>>
>>>>> Hi Angelo,
>>>>>
>>>>> Because clk_disable_unused() calls clk_core_is_enabled(),
>>>>> register
>>>>> access happens in is_enabled() ops.
>>>>> At the moment, the power for register access is not enabled, so
>>>>> the
>>>>> register read results in CPU hang.
>>>>>
>>>>> That's why I added CLK_IGNORE_UNUSED here, but it can't resolve
>>>>> all
>>>>> issues. Actually, we met same problem when "cat
>>>>> /sys/kernel/debug/clk/clk_summary" is used. We are still
>>>>> suffering
>>>>> the
>>>>> problem.
>>>>>
>>>>> I'm not sure if I can implement clk ops by myself, and exclude
>>>>> the
>>>>> registration of is_enabled() ops.
>>>>>
>>>>
>>>> Is the power for register access enabled with a power domain?
>>>>
>>>> Check drivers/clk/clk.c, grep for core->rpm_enabled.
>>>>
>>>> If you enable runtime PM before registering the clocks, and you
>>>> register them
>>>> with the right struct device, the clock API will enable power for
>>>> you
>>>> before
>>>> trying to read the clock enable status.
>>>>
>>>> Regards,
>>>> Angelo
>>>>
>>>
>>> Hi Angelo,
>>>
>>> I tried the way in MT8195, but it caused circular lock problem.
>>>
>>> Because mtcmos depends on some clocks, clk_bulk_prepare_enable is
>>> also
>>> used in scpsys_power_on()[1].
>>> If the clock also depends on the power domain, this results in the
>>> circular lock problem.
>>> That's why I don't bind the power domain with these clocks.
>>>
>>
>> This is not supposed to happen... can you please give me a (MT8195)
>> patch to
>> reproduce the issue that you're seeing?
>>
>> I would like to investigate that to check if I can come up with a
>> good solution.
>>
>> Thanks,
>> Angelo
> 
> 
> Hi Angelo,
> 
> Sorry for replying late.
> The original implementation about clock depending on power domain was a
> cusotomized request, and it's not based on upstream code base. So I
> can't apply the implementation directly. I tried to implement the
> suggested solution in upstream code, but I can't reproduce the problem
> successfully.
> 
> At the same time, we reviewed the difference between MT8195 and MT8188.
> It's found that ADSP_INFRA should be kept ON to resolve the register
> r/w access limitation in MT8188, so we can match the hardware design in
> MT8195.
> 
> After discussing internally, we decided in favour of ADSP_INFRA
> soloution. Althought the lock problem can't be seen, the new lock
> relationship(prepare_lock -> genpd lock) is actually created.
> 
> In conclusion, ADSP_INFRA will be kept always on and I will remove
> CLK_IGNORE_UNUSED flag in V3.
> 

As far as the power consumption increase is ignorable (so, power consumption
is very little more), that's a good decision and I support that.

Regards,
Angelo

> Thanks,
> Trevor
> 
>>
>>> [1]
>>>
> https://urldefense.com/v3/__https://elixir.bootlin.com/linux/v6.1-rc2/source/drivers/soc/mediatek/mtk-pm-domains.c__;!!CTRNKA9wMg0ARbw!yVFCD-B4VZOxDXTGgDtpB0mJbVoY9tHODeICxthAC33lXMq6LRVTGS-4V-Dj129_cA$
>>>   
>>>
>>> Thanks,
>>> Trevor
>>>
>>>
>>
>>
>>



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2022-12-01  9:43 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-21  8:27 [PATCH v2 00/12] ASoC: mediatek: Add support for MT8188 SoC Trevor Wu
2022-10-21  8:27 ` [PATCH v2 01/12] ASoC: mediatek: common: add SMC ops and SMC CMD Trevor Wu
2022-10-21  8:27 ` [PATCH v2 03/12] ASoC: mediatek: mt8188: support audsys clock Trevor Wu
2022-10-21  8:41   ` AngeloGioacchino Del Regno
2022-10-21  9:58     ` Trevor Wu (吳文良)
2022-10-25 10:18       ` AngeloGioacchino Del Regno
2022-10-26  4:10         ` Trevor Wu (吳文良)
2022-10-26  8:18           ` AngeloGioacchino Del Regno
2022-12-01  8:43             ` Trevor Wu (吳文良)
2022-12-01  9:42               ` AngeloGioacchino Del Regno
2022-10-21  8:27 ` [PATCH v2 04/12] ASoC: mediatek: mt8188: support adda in platform driver Trevor Wu
2022-10-21  8:41   ` AngeloGioacchino Del Regno
2022-10-21  8:27 ` [PATCH v2 05/12] ASoC: mediatek: mt8188: support etdm " Trevor Wu
2022-10-21  8:41   ` AngeloGioacchino Del Regno
2022-10-21  8:27 ` [PATCH v2 06/12] ASoC: mediatek: mt8188: support pcmif " Trevor Wu
2022-10-21  8:27 ` [PATCH v2 07/12] ASoC: mediatek: mt8188: support audio clock control Trevor Wu
2022-10-21  8:27 ` [PATCH v2 08/12] ASoC: mediatek: mt8188: add platform driver Trevor Wu
2022-10-21  8:27 ` [PATCH v2 09/12] ASoC: mediatek: mt8188: add control for timing select Trevor Wu
2022-10-21  8:27 ` [PATCH v2 10/12] dt-bindings: mediatek: mt8188: add audio afe document Trevor Wu
2022-10-24 18:33   ` Rob Herring
2022-10-31  7:11     ` Trevor Wu (吳文良)
2022-10-29  0:06   ` Krzysztof Kozlowski
2022-10-31  6:50     ` Trevor Wu (吳文良)
2022-10-21  8:27 ` [PATCH v2 11/12] ASoC: mediatek: mt8188: add machine driver with mt6359 Trevor Wu
2022-10-21  8:27 ` [PATCH v2 12/12] dt-bindings: mediatek: mt8188: add mt8188-mt6359 document Trevor Wu
2022-10-24 18:38   ` Rob Herring
2022-10-31  6:53     ` Trevor Wu (吳文良)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).