linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/10] ASoC: mediatek: Add support for MT8189 SoC
@ 2025-06-28  7:14 Cyril
  2025-06-28  7:14 ` [PATCH 02/10] ASoC: mediatek: mt8189: support audio clock control Cyril
                   ` (8 more replies)
  0 siblings, 9 replies; 17+ messages in thread
From: Cyril @ 2025-06-28  7:14 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group, cyril.chao,
	Cyril

Based on tag: next-20250626, linux-next/master

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

Cyril Chao (10):
  ASoC: mediatek: mt8189: add common header
  ASoC: mediatek: mt8189: support audio clock control
  ASoC: mediatek: mt8189: support ADDA in platform driver
  ASoC: mediatek: mt8189: support I2S in platform driver
  ASoC: mediatek: mt8189: support TDM in platform driver
  ASoC: mediatek: mt8189: support PCM in platform driver
  ASoC: mediatek: mt8189: add platform driver
  ASoC: dt-bindings: mediatek,mt8189-afe-pcm: add audio afe document
  ASoC: mediatek: mt8189: add machine driver with nau8825
  ASoC: dt-bindings: mediatek,mt8189-nau8825: add mt8189-nau8825
    document

 .../sound/mediatek,mt8189-afe-pcm.yaml        |   162 +
 .../sound/mediatek,mt8189-nau8825.yaml        |   103 +
 sound/soc/mediatek/Kconfig                    |    28 +
 sound/soc/mediatek/Makefile                   |     1 +
 sound/soc/mediatek/mt8189/Makefile            |    18 +
 sound/soc/mediatek/mt8189/mt8189-afe-clk.c    |   763 ++
 sound/soc/mediatek/mt8189/mt8189-afe-clk.h    |   109 +
 sound/soc/mediatek/mt8189/mt8189-afe-common.h |   294 +
 sound/soc/mediatek/mt8189/mt8189-afe-pcm.c    |  2682 ++++
 sound/soc/mediatek/mt8189/mt8189-dai-adda.c   |  1327 ++
 sound/soc/mediatek/mt8189/mt8189-dai-i2s.c    |  1795 +++
 sound/soc/mediatek/mt8189/mt8189-dai-pcm.c    |   337 +
 sound/soc/mediatek/mt8189/mt8189-dai-tdm.c    |   828 ++
 .../mediatek/mt8189/mt8189-interconnection.h  |    97 +
 sound/soc/mediatek/mt8189/mt8189-nau8825.c    |  1054 ++
 sound/soc/mediatek/mt8189/mt8189-reg.h        | 10773 ++++++++++++++++
 16 files changed, 20371 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8189-afe-pcm.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8189-nau8825.yaml
 create mode 100644 sound/soc/mediatek/mt8189/Makefile
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-afe-clk.c
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-afe-clk.h
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-afe-common.h
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-afe-pcm.c
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-dai-adda.c
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-dai-i2s.c
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-dai-pcm.c
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-dai-tdm.c
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-interconnection.h
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-nau8825.c
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-reg.h

-- 
2.46.0



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

* [PATCH 02/10] ASoC: mediatek: mt8189: support audio clock control
  2025-06-28  7:14 [PATCH 00/10] ASoC: mediatek: Add support for MT8189 SoC Cyril
@ 2025-06-28  7:14 ` Cyril
  2025-06-28  7:14 ` [PATCH 03/10] ASoC: mediatek: mt8189: support ADDA in platform driver Cyril
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Cyril @ 2025-06-28  7:14 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group, cyril.chao,
	Cyril Chao

From: Cyril Chao <Cyril.Chao@mediatek.com>

Add audio clock wrapper and audio tuner control.

Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
---
 sound/soc/mediatek/mt8189/mt8189-afe-clk.c | 763 +++++++++++++++++++++
 sound/soc/mediatek/mt8189/mt8189-afe-clk.h | 109 +++
 2 files changed, 872 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-afe-clk.c
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-afe-clk.h

diff --git a/sound/soc/mediatek/mt8189/mt8189-afe-clk.c b/sound/soc/mediatek/mt8189/mt8189-afe-clk.c
new file mode 100644
index 000000000..655a2cacf
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-afe-clk.c
@@ -0,0 +1,763 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  mt8189-afe-clk.c  --  Mediatek 8189 afe clock ctrl
+ *
+ *  Copyright (c) 2025 MediaTek Inc.
+ *  Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "mt8189-afe-common.h"
+#include "mt8189-afe-clk.h"
+
+/* mck */
+struct mt8189_mck_div {
+	int m_sel_id;
+	int div_clk_id;
+};
+
+static const struct mt8189_mck_div mck_div[MT8189_MCK_NUM] = {
+	[MT8189_I2SIN0_MCK] = {
+		.m_sel_id = MT8189_CLK_TOP_I2SIN0_M_SEL,
+		.div_clk_id = MT8189_CLK_TOP_APLL12_DIV_I2SIN0,
+	},
+	[MT8189_I2SIN1_MCK] = {
+		.m_sel_id = MT8189_CLK_TOP_I2SIN1_M_SEL,
+		.div_clk_id = MT8189_CLK_TOP_APLL12_DIV_I2SIN1,
+	},
+	[MT8189_FMI2S_MCK] = {
+		.m_sel_id = MT8189_CLK_TOP_FMI2S_M_SEL,
+		.div_clk_id = MT8189_CLK_TOP_APLL12_DIV_FMI2S,
+	},
+	[MT8189_TDMOUT_MCK] = {
+		.m_sel_id = MT8189_CLK_TOP_TDMOUT_M_SEL,
+		.div_clk_id = MT8189_CLK_TOP_APLL12_DIV_TDMOUT_M,
+	},
+	[MT8189_TDMOUT_BCK] = {
+		.m_sel_id = -1,
+		.div_clk_id = MT8189_CLK_TOP_APLL12_DIV_TDMOUT_B,
+	},
+};
+
+static const char *aud_clks[MT8189_CLK_NUM] = {
+	[MT8189_CLK_TOP_MUX_AUDIOINTBUS] = "top_aud_intbus",
+	[MT8189_CLK_TOP_MUX_AUD_ENG1] = "top_aud_eng1",
+	[MT8189_CLK_TOP_MUX_AUD_ENG2] = "top_aud_eng2",
+	[MT8189_CLK_TOP_MUX_AUDIO_H] = "top_aud_h",
+	/* pll */
+	[MT8189_CLK_TOP_APLL1_CK] = "apll1",
+	[MT8189_CLK_TOP_APLL2_CK] = "apll2",
+	/* divider */
+	[MT8189_CLK_TOP_APLL1_D4] = "apll1_d4",
+	[MT8189_CLK_TOP_APLL2_D4] = "apll2_d4",
+	[MT8189_CLK_TOP_APLL12_DIV_I2SIN0] = "apll12_div_i2sin0",
+	[MT8189_CLK_TOP_APLL12_DIV_I2SIN1] = "apll12_div_i2sin1",
+	[MT8189_CLK_TOP_APLL12_DIV_FMI2S] = "apll12_div_fmi2s",
+	[MT8189_CLK_TOP_APLL12_DIV_TDMOUT_M] = "apll12_div_tdmout_m",
+	[MT8189_CLK_TOP_APLL12_DIV_TDMOUT_B] = "apll12_div_tdmout_b",
+	/* mux */
+	[MT8189_CLK_TOP_MUX_AUD_1] = "top_apll1",
+	[MT8189_CLK_TOP_MUX_AUD_2] = "top_apll2",
+	[MT8189_CLK_TOP_I2SIN0_M_SEL] = "top_i2sin0",
+	[MT8189_CLK_TOP_I2SIN1_M_SEL] = "top_i2sin1",
+	[MT8189_CLK_TOP_FMI2S_M_SEL] = "top_fmi2s",
+	[MT8189_CLK_TOP_TDMOUT_M_SEL] = "top_dptx",
+	/* top 26m*/
+	[MT8189_CLK_TOP_CLK26M] = "clk26m",
+	/* peri */
+	[MT8189_CLK_PERAO_AUDIO_SLV_CK_PERI] = "aud_slv_ck_peri",
+	[MT8189_CLK_PERAO_AUDIO_MST_CK_PERI] = "aud_mst_ck_peri",
+	[MT8189_CLK_PERAO_INTBUS_CK_PERI] = "aud_intbus_ck_peri",
+};
+
+int mt8189_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, "failed to enable clk\n");
+			return ret;
+		}
+	} else {
+		dev_dbg(afe->dev, "NULL clk\n");
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mt8189_afe_enable_clk);
+
+void mt8189_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(mt8189_afe_disable_clk);
+
+static int mt8189_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, "failed to set clk rate\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int mt8189_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, "failed to set clk parent %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static unsigned int get_top_cg_reg(unsigned int cg_type)
+{
+	switch (cg_type) {
+	case MT8189_AUDIO_26M_EN_ON:
+	case MT8189_AUDIO_F3P25M_EN_ON:
+	case MT8189_AUDIO_APLL1_EN_ON:
+	case MT8189_AUDIO_APLL2_EN_ON:
+		return AUDIO_ENGEN_CON0;
+	case MT8189_CG_AUDIO_HOPPING_CK:
+	case MT8189_CG_AUDIO_F26M_CK:
+	case MT8189_CG_APLL1_CK:
+	case MT8189_CG_APLL2_CK:
+	case MT8189_PDN_APLL_TUNER2:
+	case MT8189_PDN_APLL_TUNER1:
+		return AUDIO_TOP_CON4;
+	default:
+		return 0;
+	}
+}
+
+static unsigned int get_top_cg_mask(unsigned int cg_type)
+{
+	switch (cg_type) {
+	case MT8189_AUDIO_26M_EN_ON:
+		return AUDIO_26M_EN_ON_MASK_SFT;
+	case MT8189_AUDIO_F3P25M_EN_ON:
+		return AUDIO_F3P25M_EN_ON_MASK_SFT;
+	case MT8189_AUDIO_APLL1_EN_ON:
+		return AUDIO_APLL1_EN_ON_MASK_SFT;
+	case MT8189_AUDIO_APLL2_EN_ON:
+		return AUDIO_APLL2_EN_ON_MASK_SFT;
+	case MT8189_CG_AUDIO_HOPPING_CK:
+		return CG_AUDIO_HOPPING_CK_MASK_SFT;
+	case MT8189_CG_AUDIO_F26M_CK:
+		return CG_AUDIO_F26M_CK_MASK_SFT;
+	case MT8189_CG_APLL1_CK:
+		return CG_APLL1_CK_MASK_SFT;
+	case MT8189_CG_APLL2_CK:
+		return CG_APLL2_CK_MASK_SFT;
+	case MT8189_PDN_APLL_TUNER2:
+		return PDN_APLL_TUNER2_MASK_SFT;
+	case MT8189_PDN_APLL_TUNER1:
+		return PDN_APLL_TUNER1_MASK_SFT;
+	default:
+		return 0;
+	}
+}
+
+static unsigned int get_top_cg_on_val(unsigned int cg_type)
+{
+	switch (cg_type) {
+	case MT8189_AUDIO_26M_EN_ON:
+	case MT8189_AUDIO_F3P25M_EN_ON:
+	case MT8189_AUDIO_APLL1_EN_ON:
+	case MT8189_AUDIO_APLL2_EN_ON:
+		return get_top_cg_mask(cg_type);
+	case MT8189_CG_AUDIO_HOPPING_CK:
+	case MT8189_CG_AUDIO_F26M_CK:
+	case MT8189_CG_APLL1_CK:
+	case MT8189_CG_APLL2_CK:
+	case MT8189_PDN_APLL_TUNER2:
+	case MT8189_PDN_APLL_TUNER1:
+		return 0;
+	default:
+		return 0;
+	}
+}
+
+static unsigned int get_top_cg_off_val(unsigned int cg_type)
+{
+	switch (cg_type) {
+	case MT8189_AUDIO_26M_EN_ON:
+	case MT8189_AUDIO_F3P25M_EN_ON:
+	case MT8189_AUDIO_APLL1_EN_ON:
+	case MT8189_AUDIO_APLL2_EN_ON:
+		return 0;
+	case MT8189_CG_AUDIO_HOPPING_CK:
+	case MT8189_CG_AUDIO_F26M_CK:
+	case MT8189_CG_APLL1_CK:
+	case MT8189_CG_APLL2_CK:
+	case MT8189_PDN_APLL_TUNER2:
+	case MT8189_PDN_APLL_TUNER1:
+		return get_top_cg_mask(cg_type);
+	default:
+		return get_top_cg_mask(cg_type);
+	}
+}
+
+static int mt8189_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);
+
+	if (!afe->regmap) {
+		dev_warn(afe->dev, "skip regmap\n");
+		return 0;
+	}
+
+	dev_dbg(afe->dev, "reg: 0x%x, mask: 0x%x, val: 0x%x\n", reg, mask, val);
+
+	return regmap_update_bits(afe->regmap, reg, mask, val);
+}
+
+static void mt8189_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);
+
+	if (!afe->regmap) {
+		dev_warn(afe->dev, "skip regmap\n");
+		return;
+	}
+
+	dev_dbg(afe->dev, "reg: 0x%x, mask: 0x%x, val: 0x%x\n", reg, mask, val);
+	regmap_update_bits(afe->regmap, reg, mask, val);
+}
+
+static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	dev_dbg(afe->dev, "enable: %d\n", enable);
+
+	if (enable) {
+		ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1]);
+		if (ret)
+			return ret;
+
+		ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1],
+						afe_priv->clk[MT8189_CLK_TOP_APLL1_CK]);
+		if (ret)
+			goto clk_ck_mux_aud1_parent_err;
+
+		/* 180.6336 / 4 = 45.1584MHz */
+		ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG1]);
+		if (ret)
+			goto clk_ck_mux_eng1_err;
+
+		ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG1],
+						afe_priv->clk[MT8189_CLK_TOP_APLL1_D4]);
+		if (ret)
+			goto clk_ck_mux_eng1_parent_err;
+
+		ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+		if (ret)
+			goto clk_ck_mux_audio_h_err;
+
+		ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+						afe_priv->clk[MT8189_CLK_TOP_APLL1_CK]);
+		if (ret)
+			goto clk_ck_mux_audio_h_parent_err;
+	} else {
+		mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG1],
+					  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+
+		mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG1]);
+
+		mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1],
+					  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+
+		mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1]);
+		mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+					  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+		mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+	}
+
+	return 0;
+
+clk_ck_mux_audio_h_parent_err:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+clk_ck_mux_audio_h_err:
+	mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG1],
+				  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+clk_ck_mux_eng1_parent_err:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG1]);
+clk_ck_mux_eng1_err:
+	mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1],
+				  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+clk_ck_mux_aud1_parent_err:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1]);
+
+	return ret;
+}
+
+static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	dev_dbg(afe->dev, "enable: %d\n", enable);
+
+	if (enable) {
+		ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2]);
+		if (ret)
+			return ret;
+
+		ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2],
+						afe_priv->clk[MT8189_CLK_TOP_APLL2_CK]);
+		if (ret)
+			goto clk_ck_mux_aud2_parent_err;
+
+		/* 196.608 / 4 = 49.152MHz */
+		ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG2]);
+		if (ret)
+			goto clk_ck_mux_eng2_err;
+
+		ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG2],
+						afe_priv->clk[MT8189_CLK_TOP_APLL2_D4]);
+		if (ret)
+			goto clk_ck_mux_eng2_parent_err;
+
+		ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+		if (ret)
+			goto clk_ck_mux_audio_h_err;
+
+		ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+						afe_priv->clk[MT8189_CLK_TOP_APLL2_CK]);
+		if (ret)
+			goto clk_ck_mux_audio_h_parent_err;
+	} else {
+		mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG2],
+					  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+
+		mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG2]);
+
+		mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2],
+					  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+
+		mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2]);
+		mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+					  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+		mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+	}
+
+	return 0;
+
+clk_ck_mux_audio_h_parent_err:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+clk_ck_mux_audio_h_err:
+	mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG2],
+				  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+clk_ck_mux_eng2_parent_err:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG2]);
+clk_ck_mux_eng2_err:
+	mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2],
+				  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+clk_ck_mux_aud2_parent_err:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2]);
+
+	return ret;
+}
+
+static int mt8189_afe_disable_apll(struct mtk_base_afe *afe)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+	if (ret)
+		return ret;
+
+	ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1]);
+	if (ret)
+		goto clk_ck_mux_aud1_err;
+
+	ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1],
+					afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+	if (ret)
+		goto clk_ck_mux_aud1_parent_err;
+
+	ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2]);
+	if (ret)
+		goto clk_ck_mux_aud2_err;
+
+	ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2],
+					afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+	if (ret)
+		goto clk_ck_mux_aud2_parent_err;
+
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1]);
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2]);
+	mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+				  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+	return 0;
+
+clk_ck_mux_aud2_parent_err:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2]);
+clk_ck_mux_aud2_err:
+	mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1],
+				  afe_priv->clk[MT8189_CLK_TOP_APLL1_CK]);
+clk_ck_mux_aud1_parent_err:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1]);
+clk_ck_mux_aud1_err:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+
+	return ret;
+}
+
+static void mt8189_afe_apll_init(struct mtk_base_afe *afe)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+	if (!afe_priv->apmixed) {
+		dev_warn(afe->dev, "apmixed regmap is null ptr\n");
+		return;
+	}
+
+	regmap_write(afe_priv->apmixed, APLL1_TUNER_CON0, APLL1_TUNER_CON0_VALUE);
+	regmap_write(afe_priv->apmixed, APLL2_TUNER_CON0, APLL2_TUNER_CON0_VALUE);
+}
+
+int mt8189_apll1_enable(struct mtk_base_afe *afe)
+{
+	int ret;
+
+	/* setting for APLL */
+	ret = apll1_mux_setting(afe, true);
+	if (ret)
+		return ret;
+
+	ret = mt8189_afe_enable_top_cg(afe, MT8189_CG_APLL1_CK);
+	if (ret)
+		return ret;
+
+	ret = mt8189_afe_enable_top_cg(afe, MT8189_PDN_APLL_TUNER1);
+	if (ret)
+		return ret;
+
+	/* sel 44.1kHz:1, apll_div:7, upper bound:3 */
+	regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
+			   XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT | UPPER_BOUND_MASK_SFT,
+			   (0x1 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) |
+			   (3 << UPPER_BOUND_SFT));
+
+	/* apll1 freq tuner enable */
+	regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
+			   FREQ_TUNER_EN_MASK_SFT,
+			   0x1 << FREQ_TUNER_EN_SFT);
+
+	/* audio apll1 on */
+	ret = mt8189_afe_enable_top_cg(afe, MT8189_AUDIO_APLL1_EN_ON);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void mt8189_apll1_disable(struct mtk_base_afe *afe)
+{
+	/* audio apll1 off */
+	mt8189_afe_disable_top_cg(afe, MT8189_AUDIO_APLL1_EN_ON);
+
+	/* apll1 freq tuner disable */
+	regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
+			   FREQ_TUNER_EN_MASK_SFT,
+			   0x0);
+
+	mt8189_afe_disable_top_cg(afe, MT8189_PDN_APLL_TUNER1);
+	mt8189_afe_disable_top_cg(afe, MT8189_CG_APLL1_CK);
+	apll1_mux_setting(afe, false);
+}
+
+int mt8189_apll2_enable(struct mtk_base_afe *afe)
+{
+	int ret;
+
+	/* setting for APLL */
+	ret = apll2_mux_setting(afe, true);
+	if (ret)
+		return ret;
+
+	ret = mt8189_afe_enable_top_cg(afe, MT8189_CG_APLL2_CK);
+	if (ret)
+		return ret;
+
+	ret = mt8189_afe_enable_top_cg(afe, MT8189_PDN_APLL_TUNER2);
+	if (ret)
+		return ret;
+
+	/* sel 48kHz: 2, apll_div: 7, upper bound: 3*/
+	regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
+			   XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT | UPPER_BOUND_MASK_SFT,
+			   (0x2 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) |
+			   (3 << UPPER_BOUND_SFT));
+
+	/* apll2 freq tuner enable */
+	regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
+			   FREQ_TUNER_EN_MASK_SFT,
+			   0x1 << FREQ_TUNER_EN_SFT);
+
+	/* audio apll2 on */
+	ret = mt8189_afe_enable_top_cg(afe, MT8189_AUDIO_APLL2_EN_ON);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void mt8189_apll2_disable(struct mtk_base_afe *afe)
+{
+	/* audio apll2 off */
+	mt8189_afe_disable_top_cg(afe, MT8189_AUDIO_APLL2_EN_ON);
+
+	/* apll2 freq tuner disable */
+	regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
+			   FREQ_TUNER_EN_MASK_SFT,
+			   0x0);
+
+	mt8189_afe_disable_top_cg(afe, MT8189_PDN_APLL_TUNER2);
+	mt8189_afe_disable_top_cg(afe, MT8189_CG_APLL2_CK);
+	apll2_mux_setting(afe, false);
+}
+
+int mt8189_get_apll_rate(struct mtk_base_afe *afe, int apll)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int clk_id;
+
+	if (apll < MT8189_APLL1 || apll > MT8189_APLL2) {
+		dev_warn(afe->dev, "invalid clk id %d\n", apll);
+		return 0;
+	}
+
+	if (apll == MT8189_APLL1)
+		clk_id = MT8189_CLK_TOP_APLL1_CK;
+	else
+		clk_id = MT8189_CLK_TOP_APLL2_CK;
+
+	return clk_get_rate(afe_priv->clk[clk_id]);
+}
+
+int mt8189_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
+{
+	return (rate % 8000) ? MT8189_APLL1 : MT8189_APLL2;
+}
+
+int mt8189_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
+{
+	if (strcmp(name, APLL1_W_NAME) == 0)
+		return MT8189_APLL1;
+
+	return MT8189_APLL2;
+}
+
+int mt8189_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int apll = mt8189_get_apll_by_rate(afe, rate);
+	int apll_clk_id = apll == MT8189_APLL1 ?
+			  MT8189_CLK_TOP_MUX_AUD_1 : MT8189_CLK_TOP_MUX_AUD_2;
+	int m_sel_id;
+	int div_clk_id;
+	int ret;
+
+	dev_dbg(afe->dev, "mck_id: %d, rate: %d\n", mck_id, rate);
+
+	if (mck_id >= MT8189_MCK_NUM || mck_id < 0)
+		return -EINVAL;
+
+	m_sel_id = mck_div[mck_id].m_sel_id;
+	div_clk_id = mck_div[mck_id].div_clk_id;
+
+	/* select apll */
+	if (m_sel_id >= 0) {
+		ret = mt8189_afe_enable_clk(afe, afe_priv->clk[m_sel_id]);
+		if (ret)
+			return ret;
+
+		ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[m_sel_id],
+						afe_priv->clk[apll_clk_id]);
+		if (ret)
+			return ret;
+	}
+
+	/* enable div, set rate */
+	if (div_clk_id < 0) {
+		dev_err(afe->dev, "invalid div_clk_id %d\n", div_clk_id);
+		return -EINVAL;
+	}
+
+	ret = mt8189_afe_enable_clk(afe, afe_priv->clk[div_clk_id]);
+	if (ret)
+		return ret;
+
+	ret = mt8189_afe_set_clk_rate(afe, afe_priv->clk[div_clk_id], rate);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int mt8189_mck_disable(struct mtk_base_afe *afe, int mck_id)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int m_sel_id;
+	int div_clk_id;
+
+	dev_dbg(afe->dev, "mck_id: %d.\n", mck_id);
+
+	if (mck_id < 0) {
+		dev_err(afe->dev, "mck_id = %d < 0\n", mck_id);
+		return -EINVAL;
+	}
+
+	m_sel_id = mck_div[mck_id].m_sel_id;
+	div_clk_id = mck_div[mck_id].div_clk_id;
+
+	if (div_clk_id < 0) {
+		dev_err(afe->dev, "div_clk_id = %d < 0\n",
+			div_clk_id);
+		return -EINVAL;
+	}
+
+	mt8189_afe_disable_clk(afe, afe_priv->clk[div_clk_id]);
+
+	if (m_sel_id >= 0)
+		mt8189_afe_disable_clk(afe, afe_priv->clk[m_sel_id]);
+
+	return 0;
+}
+
+int mt8189_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+	/* bus clock for AFE internal access, like AFE SRAM */
+	mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIOINTBUS]);
+	mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIOINTBUS],
+				  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+	/* enable audio clock source */
+	mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+	mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+				  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+
+	return 0;
+}
+
+int mt8189_afe_disable_reg_rw_clk(struct mtk_base_afe *afe)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+	mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+				  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+	mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIOINTBUS],
+				  afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIOINTBUS]);
+	return 0;
+}
+
+int mt8189_afe_enable_main_clock(struct mtk_base_afe *afe)
+{
+	return mt8189_afe_enable_top_cg(afe, MT8189_AUDIO_26M_EN_ON);
+}
+
+void mt8189_afe_disable_main_clock(struct mtk_base_afe *afe)
+{
+	mt8189_afe_disable_top_cg(afe, MT8189_AUDIO_26M_EN_ON);
+}
+
+static int mt8189_afe_enable_ao_clock(struct mtk_base_afe *afe)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	/* Peri clock AO enable */
+	ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_PERAO_INTBUS_CK_PERI]);
+	if (ret)
+		return ret;
+
+	ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_PERAO_AUDIO_SLV_CK_PERI]);
+	if (ret)
+		goto err_clk_perao_slv;
+
+	ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_PERAO_AUDIO_MST_CK_PERI]);
+	if (ret)
+		goto err_clk_perao_mst;
+
+	return 0;
+
+err_clk_perao_mst:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_PERAO_AUDIO_SLV_CK_PERI]);
+err_clk_perao_slv:
+	mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_PERAO_INTBUS_CK_PERI]);
+
+	return ret;
+}
+
+int mt8189_init_clock(struct mtk_base_afe *afe)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+	int i;
+
+	afe_priv->clk = devm_kcalloc(afe->dev, MT8189_CLK_NUM, sizeof(*afe_priv->clk),
+				     GFP_KERNEL);
+	if (!afe_priv->clk)
+		return -ENOMEM;
+
+	for (i = 0; i < MT8189_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, "devm_clk_get %s fail\n", aud_clks[i]);
+			return PTR_ERR(afe_priv->clk[i]);
+		}
+	}
+
+	afe_priv->apmixed = syscon_regmap_lookup_by_phandle(afe->dev->of_node,
+							    "mediatek,apmixedsys");
+	if (IS_ERR(afe_priv->apmixed)) {
+		dev_err(afe->dev, "Cannot find apmixeds\n");
+		return PTR_ERR(afe_priv->apmixed);
+	}
+
+	mt8189_afe_apll_init(afe);
+
+	ret = mt8189_afe_disable_apll(afe);
+	if (ret)
+		return ret;
+
+	ret = mt8189_afe_enable_ao_clock(afe);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/sound/soc/mediatek/mt8189/mt8189-afe-clk.h b/sound/soc/mediatek/mt8189/mt8189-afe-clk.h
new file mode 100644
index 000000000..3a7a36d07
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-afe-clk.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8189-afe-clk.h  --  Mediatek 8189 afe clock ctrl definition
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#ifndef _MT8189_AFE_CLOCK_CTRL_H_
+#define _MT8189_AFE_CLOCK_CTRL_H_
+
+#define APLL1_TUNER_CON0 0x0040
+#define APLL2_TUNER_CON0 0x0044
+/* apll1 tuner default value*/
+#define APLL1_TUNER_CON0_VALUE 0x6f28bd4d
+/* apll2 tuner default value + 1*/
+#define APLL2_TUNER_CON0_VALUE 0x78fd5265
+
+#define AP_PLL_CON3 0x000c
+#define PLLEN_ALL 0x0070
+
+#define APLL1_CON0 0x0334
+#define APLL1_CON1 0x0338
+#define APLL1_CON2 0x033c
+#define APLL1_CON4 0x0344
+
+#define APLL2_CON0 0x0348
+#define APLL2_CON1 0x034c
+#define APLL2_CON2 0x0350
+#define APLL2_CON4 0x0358
+
+#define CLK_CFG_6 0x0070
+#define CLK_CFG_7 0x0080
+#define CLK_CFG_9 0x00a0
+#define CLK_CFG_10 0x00b0
+#define CLK_CFG_11 0x00c0
+#define CLK_CFG_12 0x00d0
+#define CLK_CFG_13 0x00e0
+#define CLK_CFG_UPDATE 0x004
+#define CLK_CFG_UPDATE1 0x008
+
+#define CLK_AUDDIV_0 0x0320
+#define CLK_AUDDIV_1 0x0324
+#define CLK_AUDDIV_2 0x0328
+#define CLK_AUDDIV_3 0x0334
+#define CLK_AUDDIV_4 0x0338
+#define CLK_AUDDIV_5 0x033c
+
+/* APLL */
+#define APLL1_W_NAME "APLL1"
+#define APLL2_W_NAME "APLL2"
+
+enum {
+	MT8189_APLL1 = 0,
+	MT8189_APLL2,
+};
+
+enum {
+	MT8189_CLK_TOP_MUX_AUDIOINTBUS,
+	MT8189_CLK_TOP_MUX_AUD_ENG1,
+	MT8189_CLK_TOP_MUX_AUD_ENG2,
+	MT8189_CLK_TOP_MUX_AUDIO_H,
+	/* pll */
+	MT8189_CLK_TOP_APLL1_CK,
+	MT8189_CLK_TOP_APLL2_CK,
+	/* divider */
+	MT8189_CLK_TOP_APLL1_D4,
+	MT8189_CLK_TOP_APLL2_D4,
+	MT8189_CLK_TOP_APLL12_DIV_I2SIN0,
+	MT8189_CLK_TOP_APLL12_DIV_I2SIN1,
+	MT8189_CLK_TOP_APLL12_DIV_FMI2S,
+	MT8189_CLK_TOP_APLL12_DIV_TDMOUT_M,
+	MT8189_CLK_TOP_APLL12_DIV_TDMOUT_B,
+	/* mux */
+	MT8189_CLK_TOP_MUX_AUD_1,
+	MT8189_CLK_TOP_MUX_AUD_2,
+	MT8189_CLK_TOP_I2SIN0_M_SEL,
+	MT8189_CLK_TOP_I2SIN1_M_SEL,
+	MT8189_CLK_TOP_FMI2S_M_SEL,
+	MT8189_CLK_TOP_TDMOUT_M_SEL,
+	/* top 26m */
+	MT8189_CLK_TOP_CLK26M,
+	/* peri */
+	MT8189_CLK_PERAO_AUDIO_SLV_CK_PERI,
+	MT8189_CLK_PERAO_AUDIO_MST_CK_PERI,
+	MT8189_CLK_PERAO_INTBUS_CK_PERI,
+	MT8189_CLK_NUM,
+};
+
+struct mtk_base_afe;
+
+int mt8189_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate);
+int mt8189_mck_disable(struct mtk_base_afe *afe, int mck_id);
+int mt8189_get_apll_rate(struct mtk_base_afe *afe, int apll);
+int mt8189_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
+int mt8189_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
+int mt8189_init_clock(struct mtk_base_afe *afe);
+int mt8189_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
+void mt8189_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
+int mt8189_apll1_enable(struct mtk_base_afe *afe);
+void mt8189_apll1_disable(struct mtk_base_afe *afe);
+int mt8189_apll2_enable(struct mtk_base_afe *afe);
+void mt8189_apll2_disable(struct mtk_base_afe *afe);
+int mt8189_afe_enable_main_clock(struct mtk_base_afe *afe);
+void mt8189_afe_disable_main_clock(struct mtk_base_afe *afe);
+int mt8189_afe_enable_reg_rw_clk(struct mtk_base_afe *afe);
+int mt8189_afe_disable_reg_rw_clk(struct mtk_base_afe *afe);
+
+#endif
-- 
2.46.0



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

* [PATCH 03/10] ASoC: mediatek: mt8189: support ADDA in platform driver
  2025-06-28  7:14 [PATCH 00/10] ASoC: mediatek: Add support for MT8189 SoC Cyril
  2025-06-28  7:14 ` [PATCH 02/10] ASoC: mediatek: mt8189: support audio clock control Cyril
@ 2025-06-28  7:14 ` Cyril
  2025-06-28  7:14 ` [PATCH 04/10] ASoC: mediatek: mt8189: support I2S " Cyril
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Cyril @ 2025-06-28  7:14 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group, cyril.chao,
	Cyril Chao

From: Cyril Chao <Cyril.Chao@mediatek.com>

Add mt8189 ADDA DAI driver support.

Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
---
 sound/soc/mediatek/mt8189/mt8189-dai-adda.c | 1327 +++++++++++++++++++
 1 file changed, 1327 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-dai-adda.c

diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-adda.c b/sound/soc/mediatek/mt8189/mt8189-dai-adda.c
new file mode 100644
index 000000000..c37183331
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-dai-adda.c
@@ -0,0 +1,1327 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  MediaTek ALSA SoC Audio DAI ADDA Control
+ *
+ *  Copyright (c) 2025 MediaTek Inc.
+ *  Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include "mt8189-afe-clk.h"
+#include "mt8189-afe-common.h"
+#include "mt8189-interconnection.h"
+
+/* mt6363 vs1 voter */
+#define RG_BUCK_VS1_VOTER_EN_LO			0x189a
+#define RG_BUCK_VS1_VOTER_EN_LO_SET		0x189b
+#define RG_BUCK_VS1_VOTER_EN_LO_CLR		0x189c
+
+#define VS1_MT6338_MSK				0x1
+#define ADDA_UL_MUX_MASK			0x3
+#define AUDIO_SDM_LEVEL_NORMAL			0x1d
+#define SDM_AUTO_RESET_THRESHOLD		0x190000
+
+enum {
+	UL_IIR_SW = 0,
+	UL_IIR_5HZ,
+	UL_IIR_10HZ,
+	UL_IIR_25HZ,
+	UL_IIR_50HZ,
+	UL_IIR_75HZ,
+};
+
+enum {
+	AUDIO_SDM_2ND = 0,
+	AUDIO_SDM_3RD,
+};
+
+enum {
+	DELAY_DATA_MISO1 = 0,
+	DELAY_DATA_MISO2,
+};
+
+enum {
+	MTK_AFE_ADDA_DL_RATE_8K = 0,
+	MTK_AFE_ADDA_DL_RATE_11K = 1,
+	MTK_AFE_ADDA_DL_RATE_12K = 2,
+	MTK_AFE_ADDA_DL_RATE_16K = 4,
+	MTK_AFE_ADDA_DL_RATE_22K = 5,
+	MTK_AFE_ADDA_DL_RATE_24K = 6,
+	MTK_AFE_ADDA_DL_RATE_32K = 8,
+	MTK_AFE_ADDA_DL_RATE_44K = 9,
+	MTK_AFE_ADDA_DL_RATE_48K = 10,
+	MTK_AFE_ADDA_DL_RATE_88K = 13,
+	MTK_AFE_ADDA_DL_RATE_96K = 14,
+	MTK_AFE_ADDA_DL_RATE_176K = 17,
+	MTK_AFE_ADDA_DL_RATE_192K = 18,
+	MTK_AFE_ADDA_DL_RATE_352K = 21,
+	MTK_AFE_ADDA_DL_RATE_384K = 22,
+};
+
+enum {
+	MTK_AFE_ADDA_UL_RATE_8K = 0,
+	MTK_AFE_ADDA_UL_RATE_16K = 1,
+	MTK_AFE_ADDA_UL_RATE_32K = 2,
+	MTK_AFE_ADDA_UL_RATE_48K = 3,
+	MTK_AFE_ADDA_UL_RATE_96K = 4,
+	MTK_AFE_ADDA_UL_RATE_192K = 5,
+	MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
+};
+
+struct mtk_afe_adda_priv {
+	int dl_rate;
+	int ul_rate;
+};
+
+static unsigned int 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_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+			 __func__, rate);
+		return MTK_AFE_ADDA_DL_RATE_48K;
+	}
+}
+
+static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
+					   unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return MTK_AFE_ADDA_UL_RATE_8K;
+	case 16000:
+		return MTK_AFE_ADDA_UL_RATE_16K;
+	case 32000:
+		return MTK_AFE_ADDA_UL_RATE_32K;
+	case 48000:
+		return MTK_AFE_ADDA_UL_RATE_48K;
+	case 96000:
+		return MTK_AFE_ADDA_UL_RATE_96K;
+	case 192000:
+		return MTK_AFE_ADDA_UL_RATE_192K;
+	default:
+		dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+			 __func__, rate);
+		return MTK_AFE_ADDA_UL_RATE_48K;
+	}
+}
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN014_1, I_DL0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN014_1, I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN014_1, I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN014_1, I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN014_1, I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN014_1, I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN014_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN014_1, I_DL7_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN014_1, I_DL8_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN014_1, I_DL_24CH_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH1", AFE_CONN014_2, I_DL24_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN014_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN014_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN014_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN014_0,
+				    I_GAIN0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN014_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN014_6,
+				    I_SRC_0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN014_6,
+				    I_SRC_1_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN014_6,
+				    I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN015_1, I_DL0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN015_1, I_DL0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN015_1, I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN015_1, I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN015_1, I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN015_1, I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN015_1, I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN015_1, I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN015_1, I_DL7_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN015_1, I_DL8_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN015_1, I_DL_24CH_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH2", AFE_CONN015_2, I_DL24_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN015_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN015_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN015_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN015_0,
+				    I_GAIN0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN015_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN015_4,
+				    I_PCM_0_CAP_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN015_6,
+				    I_SRC_0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN015_6,
+				    I_SRC_1_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN015_6,
+				    I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch3_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN016_1, I_DL0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN016_1, I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN016_1, I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN016_1, I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN016_1, I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN016_1, I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN016_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN016_1, I_DL7_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN016_1, I_DL8_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN016_1, I_DL_24CH_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH3", AFE_CONN016_1, I_DL_24CH_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH1", AFE_CONN016_2, I_DL24_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN016_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN016_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN016_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN016_0,
+				    I_GAIN0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN016_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN016_6,
+				    I_SRC_0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN016_6,
+				    I_SRC_1_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN016_6,
+				    I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch4_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN017_1, I_DL0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN017_1, I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN017_1, I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN017_1, I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN017_1, I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN017_1, I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN017_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN017_1, I_DL7_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN017_1, I_DL8_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN017_1, I_DL_24CH_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH4", AFE_CONN017_1, I_DL_24CH_CH4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH2", AFE_CONN017_2, I_DL24_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN017_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN017_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN017_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN017_0,
+				    I_GAIN0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN017_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN017_4,
+				    I_PCM_0_CAP_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN017_6,
+				    I_SRC_0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN017_6,
+				    I_SRC_1_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN017_6,
+				    I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const char * const adda_mux_map[] = {
+	"Normal", "Dummy_Widget",
+};
+
+static int adda_mux_map_value[] = {
+	0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(adda_mux_map_enum,
+					      SND_SOC_NOPM,
+					      0,
+					      1,
+					      adda_mux_map,
+					      adda_mux_map_value);
+
+static const struct snd_kcontrol_new adda_out_mux_control =
+	SOC_DAPM_ENUM("ADDA Out Select", adda_mux_map_enum);
+
+static const struct snd_kcontrol_new adda_in_mux_control =
+	SOC_DAPM_ENUM("ADDA In Select", adda_mux_map_enum);
+
+enum {
+	SUPPLY_SEQ_ADDA_AFE_ON,
+	SUPPLY_SEQ_ADDA_DL_ON,
+	SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+	SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+	SUPPLY_SEQ_ADDA6_MTKAIF_CFG,
+	SUPPLY_SEQ_ADDA_FIFO,
+	SUPPLY_SEQ_ADDA_AP_DMIC,
+	SUPPLY_SEQ_ADDA_UL_ON,
+};
+
+static int mtk_adda_ul_src_dmic(struct mtk_base_afe *afe, int id)
+{
+	unsigned int reg, reg1;
+
+	switch (id) {
+	case MT8189_DAI_ADDA:
+		reg = AFE_ADDA_UL0_SRC_CON0;
+		reg1 = AFE_ADDA_UL0_SRC_CON1;
+		break;
+	case MT8189_DAI_AP_DMIC:
+		reg = AFE_ADDA_DMIC0_SRC_CON0;
+		reg1 = AFE_ADDA_DMIC0_SRC_CON1;
+		break;
+	case MT8189_DAI_AP_DMIC_CH34:
+		reg = AFE_ADDA_DMIC1_SRC_CON0;
+		reg1 = AFE_ADDA_DMIC1_SRC_CON1;
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* choose Phase */
+	regmap_update_bits(afe->regmap, reg,
+			   UL_DMIC_PHASE_SEL_CH1_MASK_SFT,
+			   0x0 << UL_DMIC_PHASE_SEL_CH1_SFT);
+	regmap_update_bits(afe->regmap, reg,
+			   UL_DMIC_PHASE_SEL_CH2_MASK_SFT,
+			   0x4 << UL_DMIC_PHASE_SEL_CH2_SFT);
+
+	/* dmic mode, 3.25M*/
+	regmap_update_bits(afe->regmap, reg,
+			   DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT,
+			   0x0);
+	regmap_update_bits(afe->regmap, reg,
+			   DMIC_LOW_POWER_MODE_CTL_MASK_SFT,
+			   0x0);
+
+	/* turn on dmic, ch1, ch2 */
+	regmap_update_bits(afe->regmap, reg,
+			   UL_SDM_3_LEVEL_CTL_MASK_SFT,
+			   0x1 << UL_SDM_3_LEVEL_CTL_SFT);
+	regmap_update_bits(afe->regmap, reg,
+			   UL_MODE_3P25M_CH1_CTL_MASK_SFT,
+			   0x1 << UL_MODE_3P25M_CH1_CTL_SFT);
+	regmap_update_bits(afe->regmap, reg,
+			   UL_MODE_3P25M_CH2_CTL_MASK_SFT,
+			   0x1 << UL_MODE_3P25M_CH2_CTL_SFT);
+
+	/* ul gain:  gain = 0x7fff/positive_gain = 0x0/gain_mode = 0x10 */
+	regmap_update_bits(afe->regmap, reg1,
+			   ADDA_UL_GAIN_VALUE_MASK_SFT,
+			   0x7fff << ADDA_UL_GAIN_VALUE_SFT);
+	regmap_update_bits(afe->regmap, reg1,
+			   ADDA_UL_POSTIVEGAIN_MASK_SFT,
+			   0x0 << ADDA_UL_POSTIVEGAIN_SFT);
+	/* gain_mode = 0x02: Add 0.5 gain at CIC output */
+	regmap_update_bits(afe->regmap, reg1,
+			   GAIN_MODE_MASK_SFT,
+			   0x02 << GAIN_MODE_SFT);
+	return 0;
+}
+
+static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol,
+			     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int mtkaif_dmic = afe_priv->mtkaif_dmic;
+
+	dev_dbg(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n",
+		__func__, w->name, event, mtkaif_dmic);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* update setting to dmic */
+		if (mtkaif_dmic) {
+			/* mtkaif_rxif_data_mode = 1, dmic */
+			regmap_update_bits(afe->regmap, AFE_MTKAIF0_RX_CFG0,
+					   0x1, 0x1);
+
+			/* dmic mode, 3.25M*/
+			regmap_update_bits(afe->regmap, AFE_MTKAIF0_RX_CFG0,
+					   RG_MTKAIF0_RXIF_VOICE_MODE_MASK_SFT,
+					   0x0);
+			mtk_adda_ul_src_dmic(afe, MT8189_DAI_ADDA);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+		usleep_range(120, 130);
+
+		/* reset dmic */
+		afe_priv->mtkaif_dmic = 0;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol,
+				  int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+	if (event == SND_SOC_DAPM_PRE_PMU) {
+		if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2)
+			regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB8);
+		else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2)
+			regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0);
+		else
+			regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0);
+	}
+
+	return 0;
+}
+
+static bool is_adda_mtkaif_need_phase_delay(struct mt8189_afe_private *afe_priv)
+{
+	return afe_priv->mtkaif_chosen_phase[0] >= 0 &&
+	       afe_priv->mtkaif_chosen_phase[1] >= 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);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int delay_data;
+	int delay_cycle;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) {
+			/* set protocol 2 */
+			regmap_write(afe->regmap, AFE_MTKAIF0_CFG0,
+				     0x00010000);
+			regmap_write(afe->regmap, AFE_MTKAIF1_CFG0,
+				     0x00010000);
+
+			/* mtkaif_rxif_clkinv_adc inverse for calibration */
+			regmap_update_bits(afe->regmap, AFE_MTKAIF0_CFG0,
+					   RG_MTKAIF0_RXIF_CLKINV_MASK_SFT,
+					   0x1 << RG_MTKAIF0_RXIF_CLKINV_SFT);
+			regmap_update_bits(afe->regmap, AFE_MTKAIF1_CFG0,
+					   RG_MTKAIF1_RXIF_CLKINV_ADC_MASK_SFT,
+					   0x1 << RG_MTKAIF1_RXIF_CLKINV_ADC_SFT);
+
+			/* This event align the phase of every miso pin */
+			/* If only 1 miso is used, there is no need to do phase delay. */
+			if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0 &&
+			    !is_adda_mtkaif_need_phase_delay(afe_priv)) {
+				dev_dbg(afe->dev,
+					"%s(), check adda mtkaif_chosen_phase[0/1]:%d/%d\n",
+					__func__,
+					afe_priv->mtkaif_chosen_phase[0],
+					afe_priv->mtkaif_chosen_phase[1]);
+				break;
+			} else if (strcmp(w->name, "ADDA6_MTKAIF_CFG") == 0 &&
+				   afe_priv->mtkaif_chosen_phase[2] < 0) {
+				dev_dbg(afe->dev,
+					"%s(), check adda6 mtkaif_chosen_phase[2]:%d\n",
+					__func__,
+					afe_priv->mtkaif_chosen_phase[2]);
+				break;
+			}
+
+			/* set delay for ch12 to align phase of miso0 and miso1 */
+			if (afe_priv->mtkaif_phase_cycle[0] >=
+			    afe_priv->mtkaif_phase_cycle[1]) {
+				delay_data = DELAY_DATA_MISO1;
+				delay_cycle = afe_priv->mtkaif_phase_cycle[0] -
+					      afe_priv->mtkaif_phase_cycle[1];
+			} else {
+				delay_data = DELAY_DATA_MISO2;
+				delay_cycle = afe_priv->mtkaif_phase_cycle[1] -
+					      afe_priv->mtkaif_phase_cycle[0];
+			}
+
+			regmap_update_bits(afe->regmap,
+					   AFE_MTKAIF0_RX_CFG2,
+					   RG_MTKAIF0_RXIF_DELAY_DATA_MASK_SFT,
+					   delay_data <<
+					   RG_MTKAIF0_RXIF_DELAY_DATA_SFT);
+
+			regmap_update_bits(afe->regmap,
+					   AFE_MTKAIF0_RX_CFG2,
+					   RG_MTKAIF0_RXIF_DELAY_CYCLE_MASK_SFT,
+					   delay_cycle <<
+					   RG_MTKAIF0_RXIF_DELAY_CYCLE_SFT);
+
+			/* set delay between ch3 and ch2 */
+			if (afe_priv->mtkaif_phase_cycle[2] >=
+			    afe_priv->mtkaif_phase_cycle[1]) {
+				delay_data = DELAY_DATA_MISO1;  /* ch3 */
+				delay_cycle = afe_priv->mtkaif_phase_cycle[2] -
+					      afe_priv->mtkaif_phase_cycle[1];
+			} else {
+				delay_data = DELAY_DATA_MISO2;  /* ch2 */
+				delay_cycle = afe_priv->mtkaif_phase_cycle[1] -
+					      afe_priv->mtkaif_phase_cycle[2];
+			}
+
+			regmap_update_bits(afe->regmap,
+					   AFE_MTKAIF1_RX_CFG2,
+					   RG_MTKAIF1_RXIF_DELAY_DATA_MASK_SFT,
+					   delay_data <<
+					   RG_MTKAIF1_RXIF_DELAY_DATA_SFT);
+			regmap_update_bits(afe->regmap,
+					   AFE_MTKAIF1_RX_CFG2,
+					   RG_MTKAIF1_RXIF_DELAY_CYCLE_MASK_SFT,
+					   delay_cycle <<
+					   RG_MTKAIF1_RXIF_DELAY_CYCLE_SFT);
+		} else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) {
+			regmap_write(afe->regmap, AFE_MTKAIF0_CFG0,
+				     0x00010000);
+			regmap_write(afe->regmap, AFE_MTKAIF1_CFG0,
+				     0x00010000);
+		} else {
+			regmap_write(afe->regmap, AFE_MTKAIF0_CFG0, 0x0);
+			regmap_write(afe->regmap, AFE_MTKAIF1_CFG0, 0x0);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol,
+			     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+	dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+		__func__, w->name, event);
+
+	/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+	if (event == SND_SOC_DAPM_POST_PMD)
+		usleep_range(120, 130);
+
+	return 0;
+}
+
+static void mt6363_vs1_vote(struct mtk_base_afe *afe)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	bool pre_enable = afe_priv->is_mt6363_vote;
+	bool enable = false;
+
+	if (!afe_priv->pmic_regmap)
+		return;
+
+	enable = (afe_priv->is_adda_dl_on && afe_priv->is_adda_dl_max_vol) ||
+		 (afe_priv->is_adda_ul_on);
+	if (enable == pre_enable) {
+		dev_dbg(afe->dev, "%s() enable == pre_enable = %d\n",
+			__func__, enable);
+		return;
+	}
+	afe_priv->is_mt6363_vote = enable;
+	dev_dbg(afe->dev, "%s() enable = %d\n", __func__, enable);
+	if (enable)
+		regmap_update_bits(afe_priv->pmic_regmap, RG_BUCK_VS1_VOTER_EN_LO_SET,
+				   VS1_MT6338_MSK, VS1_MT6338_MSK);
+	else
+		regmap_update_bits(afe_priv->pmic_regmap, RG_BUCK_VS1_VOTER_EN_LO_CLR,
+				   VS1_MT6338_MSK, VS1_MT6338_MSK);
+}
+
+static int mt_vs1_voter_dl_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol,
+				 int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+	dev_dbg(afe->dev, "%s(), event = 0x%x\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		afe_priv->is_adda_dl_on = true;
+		mt6363_vs1_vote(afe);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		afe_priv->is_adda_dl_on = false;
+		mt6363_vs1_vote(afe);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_vs1_voter_ul_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol,
+				 int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+	dev_dbg(afe->dev, "%s(), event = 0x%x\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		afe_priv->is_adda_ul_on = true;
+		mt6363_vs1_vote(afe);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		afe_priv->is_adda_ul_on = false;
+		mt6363_vs1_vote(afe);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/* mtkaif dmic */
+static const char *const mt8189_adda_off_on_str[] = {
+	"Off", "On"
+};
+
+static const struct soc_enum mt8189_adda_enum[] = {
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8189_adda_off_on_str),
+			    mt8189_adda_off_on_str),
+};
+
+static int mt8189_adda_ap_dmic_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+	ucontrol->value.integer.value[0] = afe_priv->ap_dmic;
+	return 0;
+}
+
+static int mt8189_adda_ap_dmic_set(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	int ap_dmic_on;
+
+	if (ucontrol->value.enumerated.item[0] >= e->items)
+		return -EINVAL;
+
+	ap_dmic_on = ucontrol->value.integer.value[0];
+
+	dev_dbg(afe->dev, "%s(), kcontrol name %s, ap_dmic_on %d\n",
+		__func__, kcontrol->id.name, ap_dmic_on);
+
+	afe_priv->ap_dmic = ap_dmic_on;
+	return 0;
+}
+
+static int mt8189_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+
+	ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic;
+	return 0;
+}
+
+static int mt8189_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	int dmic_on;
+
+	if (ucontrol->value.enumerated.item[0] >= e->items)
+		return -EINVAL;
+
+	dmic_on = ucontrol->value.integer.value[0];
+
+	dev_dbg(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n",
+		__func__, kcontrol->id.name, dmic_on);
+
+	afe_priv->mtkaif_dmic = dmic_on;
+	afe_priv->mtkaif_dmic_ch34 = dmic_on;
+	return 0;
+}
+
+static int mt8189_adda6_only_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+	ucontrol->value.integer.value[0] = afe_priv->mtkaif_adda6_only;
+	return 0;
+}
+
+static int mt8189_adda6_only_set(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	int mtkaif_adda6_only;
+
+	if (ucontrol->value.enumerated.item[0] >= e->items)
+		return -EINVAL;
+
+	mtkaif_adda6_only = ucontrol->value.integer.value[0];
+
+	dev_dbg(afe->dev, "%s(), kcontrol name %s, mtkaif_adda6_only %d\n",
+		__func__, kcontrol->id.name, mtkaif_adda6_only);
+
+	afe_priv->mtkaif_adda6_only = mtkaif_adda6_only;
+	return 0;
+}
+
+static int mt8189_adda_dl_max_vol_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+	ucontrol->value.integer.value[0] = afe_priv->is_adda_dl_max_vol;
+
+	return 0;
+}
+
+static int mt8189_adda_dl_max_vol_set(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	bool is_adda_dl_max_vol = ucontrol->value.integer.value[0];
+
+	afe_priv->is_adda_dl_max_vol = is_adda_dl_max_vol;
+	mt6363_vs1_vote(afe);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new mtk_adda_controls[] = {
+	SOC_SINGLE("ADDA_DL_GAIN", AFE_ADDA_DL_SRC_CON1,
+		   AFE_DL_GAIN1_CTL_PRE_SFT, AFE_DL_GAIN1_CTL_PRE_MASK, 0),
+	SOC_ENUM_EXT("MTKAIF_DMIC", mt8189_adda_enum[0],
+		     mt8189_adda_dmic_get, mt8189_adda_dmic_set),
+	SOC_ENUM_EXT("MTKAIF_ADDA6_ONLY", mt8189_adda_enum[0],
+		     mt8189_adda6_only_get, mt8189_adda6_only_set),
+	SOC_SINGLE_EXT("ADDA_DL_MAX_VOL",
+		       SND_SOC_NOPM, 0, 0x1, 0,
+		       mt8189_adda_dl_max_vol_get,
+		       mt8189_adda_dl_max_vol_set),
+	SOC_ENUM_EXT("AP DMIC Used", mt8189_adda_enum[0],
+		     mt8189_adda_ap_dmic_get, mt8189_adda_ap_dmic_set),
+};
+
+/* ADDA UL MUX */
+enum {
+	ADDA_UL_MUX_MTKAIF = 0,
+	ADDA_UL_MUX_AP_DMIC,
+	ADDA_UL_MUX_AP_DMIC_MULTICH,
+};
+
+static const char *const adda_ul_mux_map[] = {
+	"MTKAIF", "AP_DMIC", "AP_DMIC_MULTI_CH",
+};
+
+static int adda_ul_map_value[] = {
+	ADDA_UL_MUX_MTKAIF,
+	ADDA_UL_MUX_AP_DMIC,
+	ADDA_UL_MUX_AP_DMIC_MULTICH,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum,
+				  SND_SOC_NOPM,
+				  0,
+				  ADDA_UL_MUX_MASK,
+				  adda_ul_mux_map,
+				  adda_ul_map_value);
+
+static const struct snd_kcontrol_new adda_ul_mux_control =
+	SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_kcontrol_new adda_ch34_ul_mux_control =
+	SOC_DAPM_ENUM("ADDA_CH34_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+	/* inter-connections */
+	SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_adda_dl_ch1_mix,
+			   ARRAY_SIZE(mtk_adda_dl_ch1_mix)),
+	SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_adda_dl_ch2_mix,
+			   ARRAY_SIZE(mtk_adda_dl_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("ADDA_DL_CH3", SND_SOC_NOPM, 0, 0,
+			   mtk_adda_dl_ch3_mix,
+			   ARRAY_SIZE(mtk_adda_dl_ch3_mix)),
+	SND_SOC_DAPM_MIXER("ADDA_DL_CH4", SND_SOC_NOPM, 0, 0,
+			   mtk_adda_dl_ch4_mix,
+			   ARRAY_SIZE(mtk_adda_dl_ch4_mix)),
+
+	SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
+			      AUDIO_ENGEN_CON0, AUDIO_F3P25M_EN_ON_SFT, 0,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADDA_DL0_CG", SUPPLY_SEQ_ADDA_DL_ON,
+			      AUDIO_TOP_CON0,
+			      PDN_DL0_DAC_SFT, 1,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADDA_UL0_CG", SUPPLY_SEQ_ADDA_UL_ON,
+			      AUDIO_TOP_CON1,
+			      PDN_UL0_ADC_SFT, 1,
+			      NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON,
+			      AFE_ADDA_DL_SRC_CON0,
+			      AFE_DL_SRC_ON_TMP_CTL_PRE_SFT, 0,
+			      mtk_adda_dl_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+			      AFE_ADDA_UL0_SRC_CON0,
+			      UL_SRC_ON_TMP_CTL_SFT, 0,
+			      mtk_adda_ul_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("AP DMIC Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+			      AFE_ADDA_DMIC0_SRC_CON0,
+			      UL_SRC_ON_TMP_CTL_SFT, 0,
+			      NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("AP DMIC CH34 Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+			      AFE_ADDA_DMIC1_SRC_CON0,
+			      UL_SRC_ON_TMP_CTL_SFT, 0,
+			      NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+			      AFE_AUD_PAD_TOP_CFG0,
+			      RG_RX_FIFO_ON_SFT, 0,
+			      mtk_adda_pad_top_event,
+			      SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_adda_mtkaif_cfg_event,
+			      SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY_S("ADDA6_MTKAIF_CFG", SUPPLY_SEQ_ADDA6_MTKAIF_CFG,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_adda_mtkaif_cfg_event,
+			      SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+			      AFE_ADDA_DMIC0_SRC_CON0,
+			      UL_AP_DMIC_ON_SFT, 0,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AP_DMIC0_CG", SUPPLY_SEQ_ADDA_AP_DMIC,
+			      AUDIO_TOP_CON1,
+			      PDN_DMIC0_ADC_SFT, 1,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AP_DMIC_CH34_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+			      AFE_ADDA_DMIC1_SRC_CON0,
+			      UL_AP_DMIC_ON_SFT, 0,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AP_DMIC1_CG", SUPPLY_SEQ_ADDA_AP_DMIC,
+			      AUDIO_TOP_CON1,
+			      PDN_DMIC1_ADC_SFT, 1,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+			      AFE_ADDA_UL0_SRC_CON1,
+			      FIFO_SOFT_RST_SFT, 1,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AP_DMIC_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+			      AFE_ADDA_DMIC0_SRC_CON1,
+			      FIFO_SOFT_RST_SFT, 1,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AP_DMIC_CH34_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+			      AFE_ADDA_DMIC1_SRC_CON1,
+			      FIFO_SOFT_RST_SFT, 1,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("VS1_VOTER_DL", SUPPLY_SEQ_ADDA_AFE_ON,
+			      SND_SOC_NOPM, 0, 0,
+			      mt_vs1_voter_dl_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("VS1_VOTER_UL", SUPPLY_SEQ_ADDA_AFE_ON,
+			      SND_SOC_NOPM, 0, 0,
+			      mt_vs1_voter_ul_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0,
+			 &adda_ul_mux_control),
+	SND_SOC_DAPM_MUX("ADDA_CH34_UL_Mux", SND_SOC_NOPM, 0, 0,
+			 &adda_ch34_ul_mux_control),
+
+	SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"),
+	SND_SOC_DAPM_INPUT("AP_DMIC_CH34_INPUT"),
+
+	/* allow i2s on without codec on */
+	SND_SOC_DAPM_OUTPUT("ADDA_DUMMY_OUT"),
+	SND_SOC_DAPM_MUX("ADDA_Out_Mux",
+			 SND_SOC_NOPM, 0, 0, &adda_out_mux_control),
+	SND_SOC_DAPM_INPUT("ADDA_DUMMY_IN"),
+	SND_SOC_DAPM_MUX("ADDA_In_Mux",
+			 SND_SOC_NOPM, 0, 0, &adda_in_mux_control),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+	/* playback */
+	{"ADDA_DL_CH1", "DL0_CH1", "DL0"},
+	{"ADDA_DL_CH2", "DL0_CH1", "DL0"},
+	{"ADDA_DL_CH2", "DL0_CH2", "DL0"},
+
+	{"ADDA_DL_CH1", "DL1_CH1", "DL1"},
+	{"ADDA_DL_CH2", "DL1_CH2", "DL1"},
+
+	{"ADDA_DL_CH1", "DL2_CH1", "DL2"},
+	{"ADDA_DL_CH2", "DL2_CH2", "DL2"},
+
+	{"ADDA_DL_CH1", "DL3_CH1", "DL3"},
+	{"ADDA_DL_CH2", "DL3_CH2", "DL3"},
+
+	{"ADDA_DL_CH1", "DL4_CH1", "DL4"},
+	{"ADDA_DL_CH2", "DL4_CH2", "DL4"},
+
+	{"ADDA_DL_CH1", "DL5_CH1", "DL5"},
+	{"ADDA_DL_CH2", "DL5_CH2", "DL5"},
+
+	{"ADDA_DL_CH1", "DL6_CH1", "DL6"},
+	{"ADDA_DL_CH2", "DL6_CH2", "DL6"},
+
+	{"ADDA_DL_CH1", "DL7_CH1", "DL7"},
+	{"ADDA_DL_CH2", "DL7_CH2", "DL7"},
+
+	{"ADDA_DL_CH1", "DL8_CH1", "DL8"},
+	{"ADDA_DL_CH2", "DL8_CH2", "DL8"},
+
+	{"ADDA_DL_CH1", "DL_24CH_CH1", "DL_24CH"},
+	{"ADDA_DL_CH2", "DL_24CH_CH2", "DL_24CH"},
+
+	{"ADDA_DL_CH1", "DL24_CH1", "DL24"},
+	{"ADDA_DL_CH2", "DL24_CH2", "DL24"},
+
+	{"ADDA Playback", NULL, "ADDA_DL_CH1"},
+	{"ADDA Playback", NULL, "ADDA_DL_CH2"},
+
+	{"ADDA Playback", NULL, "ADDA Enable"},
+	{"ADDA Playback", NULL, "ADDA Playback Enable"},
+	{"ADDA Playback", NULL, "AUD_PAD_TOP"},
+	{"ADDA Playback", NULL, "VS1_VOTER_DL"},
+	{"ADDA Playback", NULL, "ADDA_DL0_CG"},
+
+	{"ADDA_DL_CH3", "DL0_CH1", "DL0"},
+	{"ADDA_DL_CH4", "DL0_CH2", "DL0"},
+
+	{"ADDA_DL_CH3", "DL1_CH1", "DL1"},
+	{"ADDA_DL_CH4", "DL1_CH2", "DL1"},
+
+	{"ADDA_DL_CH3", "DL2_CH1", "DL2"},
+	{"ADDA_DL_CH4", "DL2_CH2", "DL2"},
+
+	{"ADDA_DL_CH3", "DL3_CH1", "DL3"},
+	{"ADDA_DL_CH4", "DL3_CH2", "DL3"},
+
+	{"ADDA_DL_CH3", "DL4_CH1", "DL4"},
+	{"ADDA_DL_CH4", "DL4_CH2", "DL4"},
+
+	{"ADDA_DL_CH3", "DL5_CH1", "DL5"},
+	{"ADDA_DL_CH4", "DL5_CH2", "DL5"},
+
+	{"ADDA_DL_CH3", "DL6_CH1", "DL6"},
+	{"ADDA_DL_CH4", "DL6_CH2", "DL6"},
+
+	{"ADDA_DL_CH3", "DL7_CH1", "DL7"},
+	{"ADDA_DL_CH4", "DL7_CH2", "DL7"},
+
+	{"ADDA_DL_CH3", "DL8_CH1", "DL8"},
+	{"ADDA_DL_CH4", "DL8_CH2", "DL8"},
+
+	{"ADDA_DL_CH3", "DL_24CH_CH1", "DL_24CH"},
+	{"ADDA_DL_CH4", "DL_24CH_CH2", "DL_24CH"},
+	{"ADDA_DL_CH3", "DL_24CH_CH3", "DL_24CH"},
+	{"ADDA_DL_CH4", "DL_24CH_CH4", "DL_24CH"},
+
+	{"ADDA_DL_CH3", "DL24_CH1", "DL24"},
+	{"ADDA_DL_CH4", "DL24_CH2", "DL24"},
+
+	{"ADDA Capture", NULL, "ADDA Enable"},
+	{"ADDA Capture", NULL, "ADDA Capture Enable"},
+	{"ADDA Capture", NULL, "AUD_PAD_TOP"},
+	{"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"},
+	{"ADDA Capture", NULL, "VS1_VOTER_UL"},
+	{"ADDA Capture", NULL, "ADDA_UL0_CG"},
+
+	/* capture */
+	{"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"},
+	{"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"},
+	{"ADDA_CH34_UL_Mux", "AP_DMIC", "AP DMIC CH34 Capture"},
+
+	{"AP DMIC Capture", NULL, "ADDA Enable"},
+	{"AP DMIC Capture", NULL, "AP DMIC Capture Enable"},
+	{"AP DMIC Capture", NULL, "AP_DMIC_FIFO"},
+	{"AP DMIC Capture", NULL, "AP_DMIC_EN"},
+	{"AP DMIC Capture", NULL, "AP_DMIC0_CG"},
+
+	{"AP DMIC CH34 Capture", NULL, "ADDA Enable"},
+	{"AP DMIC CH34 Capture", NULL, "AP DMIC CH34 Capture Enable"},
+	{"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_FIFO"},
+	{"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_EN"},
+	{"AP DMIC CH34 Capture", NULL, "AP_DMIC1_CG"},
+
+	{"AP DMIC Capture", NULL, "AP_DMIC_INPUT"},
+	{"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_INPUT"},
+
+	/* allow i2s on without codec on */
+	{"ADDA Capture", NULL, "ADDA_In_Mux"},
+	{"ADDA_In_Mux", "Dummy_Widget", "ADDA_DUMMY_IN"},
+	{"ADDA_Out_Mux", "Dummy_Widget", "ADDA Playback"},
+	{"ADDA_DUMMY_OUT", NULL, "ADDA_Out_Mux"},
+};
+
+/* dai ops */
+static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	unsigned int rate = params_rate(params);
+	int id = dai->id;
+	struct mtk_afe_adda_priv *adda_priv = afe_priv->dai_priv[id];
+
+	dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+		__func__, id, substream->stream, rate);
+
+	if (!adda_priv)
+		return -EINVAL;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		unsigned int dl_src_con0 = 0;
+		unsigned int dl_src_con1 = 0;
+
+		adda_priv->dl_rate = rate;
+
+		/* set sampling rate */
+		dl_src_con0 = adda_dl_rate_transform(afe, rate) <<
+				AFE_DL_INPUT_MODE_CTL_SFT;
+
+		/* set output mode, UP_SAMPLING_RATE_X8 */
+		dl_src_con0 |= (0x3 << AFE_DL_OUTPUT_SEL_CTL_SFT);
+
+		/* turn off mute function */
+		dl_src_con0 |= (0x01 << AFE_DL_MUTE_CH2_OFF_CTL_PRE_SFT);
+		dl_src_con0 |= (0x01 << AFE_DL_MUTE_CH1_OFF_CTL_PRE_SFT);
+
+		/* set voice input data if input sample rate is 8k or 16k */
+		if (rate == 8000 || rate == 16000)
+			dl_src_con0 |= 0x01 << AFE_DL_VOICE_MODE_CTL_PRE_SFT;
+
+		/* SA suggest apply -0.3db to audio/speech path */
+		dl_src_con1 = MTK_AFE_ADDA_DL_GAIN_NORMAL <<
+			      AFE_DL_GAIN1_CTL_PRE_SFT;
+		dl_src_con1 |= MTK_AFE_ADDA_DL_GAIN_NORMAL <<
+			       AFE_DL_GAIN2_CTL_PRE_SFT;
+
+		/* turn on down-link gain */
+		dl_src_con0 |= (0x01 << AFE_DL_GAIN_ON_CTL_PRE_SFT);
+
+		if (id == MT8189_DAI_ADDA) {
+			/* clean predistortion */
+			regmap_write(afe->regmap, AFE_ADDA_DL_PREDIS_CON0, 0);
+			regmap_write(afe->regmap, AFE_ADDA_DL_PREDIS_CON1, 0);
+
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DL_SRC_CON0, dl_src_con0);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DL_SRC_CON1, dl_src_con1);
+
+			/* set sdm gain */
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_DL_SDM_DCCOMP_CON,
+					   AFE_DL_ATTGAIN_CTL_MASK_SFT,
+					   AUDIO_SDM_LEVEL_NORMAL <<
+					   AFE_DL_ATTGAIN_CTL_SFT);
+
+			/* 2nd sdm */
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_DL_SDM_DCCOMP_CON,
+					   AFE_DL_USE_3RD_SDM_MASK_SFT,
+					   AUDIO_SDM_2ND << AFE_DL_USE_3RD_SDM_SFT);
+
+			/* sdm auto reset */
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+				     SDM_AUTO_RESET_THRESHOLD);
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+					   AFE_DL_SDM_AUTO_RESET_TEST_ON_SFT,
+					   0x1 << AFE_DL_SDM_AUTO_RESET_TEST_ON_SFT);
+		}
+	} else {
+		unsigned int voice_mode = 0;
+		unsigned int ul_src_con0 = 0;   /* default value */
+
+		adda_priv->ul_rate = rate;
+
+		voice_mode = adda_ul_rate_transform(afe, rate);
+
+		ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
+
+		/* enable iir */
+		ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) &
+			       UL_IIR_ON_TMP_CTL_MASK_SFT;
+		ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) &
+			       UL_IIRMODE_CTL_MASK_SFT;
+
+		switch (id) {
+		case MT8189_DAI_ADDA:
+			/* 35Hz @ 48k */
+			regmap_write(afe->regmap,
+				     AFE_ADDA_UL0_IIR_COEF_02_01, 0x00000000);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_UL0_IIR_COEF_04_03, 0x00003FB8);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_UL0_IIR_COEF_06_05, 0x3FB80000);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_UL0_IIR_COEF_08_07, 0x3FB80000);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_UL0_IIR_COEF_10_09, 0x0000C048);
+
+			regmap_write(afe->regmap,
+				     AFE_ADDA_UL0_SRC_CON0, ul_src_con0);
+
+			/* mtkaif_rxif_data_mode = 0, amic */
+			regmap_update_bits(afe->regmap,
+					   AFE_MTKAIF0_RX_CFG0,
+					   0x1 << 0,
+					   0x0 << 0);
+			break;
+		case MT8189_DAI_AP_DMIC:
+			/* 35Hz @ 48k */
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DMIC0_IIR_COEF_02_01, 0x00000000);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DMIC0_IIR_COEF_04_03, 0x00003FB8);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DMIC0_IIR_COEF_06_05, 0x3FB80000);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DMIC0_IIR_COEF_08_07, 0x3FB80000);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DMIC0_IIR_COEF_10_09, 0x0000C048);
+
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DMIC0_SRC_CON0, ul_src_con0);
+			break;
+		case MT8189_DAI_AP_DMIC_CH34:
+			/* 35Hz @ 48k */
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DMIC1_IIR_COEF_02_01, 0x00000000);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DMIC1_IIR_COEF_04_03, 0x00003FB8);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DMIC1_IIR_COEF_06_05, 0x3FB80000);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DMIC1_IIR_COEF_08_07, 0x3FB80000);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DMIC1_IIR_COEF_10_09, 0x0000C048);
+
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DMIC1_SRC_CON0, ul_src_con0);
+			break;
+		default:
+			break;
+		}
+
+		/* ap dmic */
+		switch (id) {
+		case MT8189_DAI_AP_DMIC:
+		case MT8189_DAI_AP_DMIC_CH34:
+			mtk_adda_ul_src_dmic(afe, id);
+			break;
+		default:
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_adda_ops = {
+	.hw_params = mtk_dai_adda_hw_params,
+};
+
+/* dai driver */
+#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000)
+
+#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+				SNDRV_PCM_RATE_16000 |\
+				SNDRV_PCM_RATE_32000 |\
+				SNDRV_PCM_RATE_48000)
+
+#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 = MT8189_DAI_ADDA,
+		.playback = {
+			.stream_name = "ADDA Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_PLAYBACK_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.capture = {
+			.stream_name = "ADDA Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_CAPTURE_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.ops = &mtk_dai_adda_ops,
+	},
+	{
+		.name = "ADDA_CH34",
+		.id = MT8189_DAI_ADDA_CH34,
+		.playback = {
+			.stream_name = "ADDA CH34 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_PLAYBACK_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.ops = &mtk_dai_adda_ops,
+	},
+	{
+		.name = "AP_DMIC",
+		.id = MT8189_DAI_AP_DMIC,
+		.capture = {
+			.stream_name = "AP DMIC Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_CAPTURE_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.ops = &mtk_dai_adda_ops,
+	},
+	{
+		.name = "AP_DMIC_CH34",
+		.id = MT8189_DAI_AP_DMIC_CH34,
+		.capture = {
+			.stream_name = "AP DMIC CH34 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_CAPTURE_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.ops = &mtk_dai_adda_ops,
+	},
+};
+
+static int init_adda_priv_data(struct mtk_base_afe *afe)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_adda_priv *adda_priv;
+	static const int adda_dai_list[] = {
+		MT8189_DAI_ADDA,
+		MT8189_DAI_ADDA_CH34,
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(adda_dai_list); i++) {
+		adda_priv = devm_kzalloc(afe->dev,
+					 sizeof(struct mtk_afe_adda_priv),
+					 GFP_KERNEL);
+		if (!adda_priv)
+			return -ENOMEM;
+
+		afe_priv->dai_priv[adda_dai_list[i]] = adda_priv;
+	}
+
+	/* ap dmic priv share with adda */
+	afe_priv->dai_priv[MT8189_DAI_AP_DMIC] =
+		afe_priv->dai_priv[MT8189_DAI_ADDA];
+	afe_priv->dai_priv[MT8189_DAI_AP_DMIC_CH34] =
+		afe_priv->dai_priv[MT8189_DAI_ADDA_CH34];
+
+	return 0;
+}
+
+int mt8189_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->controls = mtk_adda_controls;
+	dai->num_controls = ARRAY_SIZE(mtk_adda_controls);
+	dai->dapm_widgets = mtk_dai_adda_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+	dai->dapm_routes = mtk_dai_adda_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+
+	return init_adda_priv_data(afe);
+}
-- 
2.46.0



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

* [PATCH 04/10] ASoC: mediatek: mt8189: support I2S in platform driver
  2025-06-28  7:14 [PATCH 00/10] ASoC: mediatek: Add support for MT8189 SoC Cyril
  2025-06-28  7:14 ` [PATCH 02/10] ASoC: mediatek: mt8189: support audio clock control Cyril
  2025-06-28  7:14 ` [PATCH 03/10] ASoC: mediatek: mt8189: support ADDA in platform driver Cyril
@ 2025-06-28  7:14 ` Cyril
  2025-06-28  7:14 ` [PATCH 05/10] ASoC: mediatek: mt8189: support TDM " Cyril
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Cyril @ 2025-06-28  7:14 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group, cyril.chao,
	Cyril Chao

From: Cyril Chao <Cyril.Chao@mediatek.com>

Add mt8189 I2S DAI driver support.

Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
---
 sound/soc/mediatek/mt8189/mt8189-dai-i2s.c | 1795 ++++++++++++++++++++
 1 file changed, 1795 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-dai-i2s.c

diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-i2s.c b/sound/soc/mediatek/mt8189/mt8189-dai-i2s.c
new file mode 100644
index 000000000..b3db0a2c3
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-dai-i2s.c
@@ -0,0 +1,1795 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  MediaTek ALSA SoC Audio DAI I2S Control
+ *
+ *  Copyright (c) 2025 MediaTek Inc.
+ *  Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8189-afe-clk.h"
+#include "mt8189-afe-common.h"
+#include "mt8189-interconnection.h"
+
+#define MTK_AFE_I2SIN0_KCONTROL_NAME "I2SIN0_HD_Mux"
+#define MTK_AFE_I2SIN1_KCONTROL_NAME "I2SIN1_HD_Mux"
+#define MTK_AFE_I2SOUT0_KCONTROL_NAME "I2SOUT0_HD_Mux"
+#define MTK_AFE_I2SOUT1_KCONTROL_NAME "I2SOUT1_HD_Mux"
+#define MTK_AFE_I2SOUT4_KCONTROL_NAME "I2SOUT4_HD_Mux"
+
+#define I2SIN0_HD_EN_W_NAME "I2SIN0_HD_EN"
+#define I2SIN1_HD_EN_W_NAME "I2SIN1_HD_EN"
+#define I2SOUT0_HD_EN_W_NAME "I2SOUT0_HD_EN"
+#define I2SOUT1_HD_EN_W_NAME "I2SOUT1_HD_EN"
+#define I2SOUT4_HD_EN_W_NAME "I2SOUT4_HD_EN"
+
+#define I2SIN0_MCLK_EN_W_NAME "I2SIN0_MCLK_EN"
+#define I2SIN1_MCLK_EN_W_NAME "I2SIN1_MCLK_EN"
+#define I2SOUT0_MCLK_EN_W_NAME "I2SOUT0_MCLK_EN"
+#define I2SOUT1_MCLK_EN_W_NAME "I2SOUT1_MCLK_EN"
+#define I2SOUT4_MCLK_EN_W_NAME "I2SOUT4_MCLK_EN"
+
+enum {
+	SUPPLY_SEQ_APLL = 0,
+	SUPPLY_SEQ_I2S_MCLK_EN,
+	SUPPLY_SEQ_I2S_CG_EN,
+	SUPPLY_SEQ_I2S_HD_EN,
+	SUPPLY_SEQ_I2S_EN,
+};
+
+/* this enum is merely for mtk_afe_i2s_priv declare */
+enum {
+	DAI_I2SIN0 = 0,
+	DAI_I2SIN1,
+	DAI_I2SOUT0,
+	DAI_I2SOUT1,
+	DAI_I2SOUT4,
+	DAI_I2S_NUM,
+};
+
+enum {
+	ETDM_CLK_SOURCE_H26M = 0,
+	ETDM_CLK_SOURCE_APLL,
+	ETDM_CLK_SOURCE_SPDIF,
+	ETDM_CLK_SOURCE_HDMI,
+	ETDM_CLK_SOURCE_EARC,
+	ETDM_CLK_SOURCE_LINEIN,
+};
+
+enum {
+	ETDM_RELATCH_SEL_H26M = 0,
+	ETDM_RELATCH_SEL_APLL,
+};
+
+enum {
+	ETDM_RATE_8K = 0,
+	ETDM_RATE_12K = 1,
+	ETDM_RATE_16K = 2,
+	ETDM_RATE_24K = 3,
+	ETDM_RATE_32K = 4,
+	ETDM_RATE_48K = 5,
+	ETDM_RATE_64K = 6, /* not support */
+	ETDM_RATE_96K = 7,
+	ETDM_RATE_128K = 8, /* not support */
+	ETDM_RATE_192K = 9,
+	ETDM_RATE_256K = 10, /* not support */
+	ETDM_RATE_384K = 11, /* not support */
+	ETDM_RATE_11025 = 16,
+	ETDM_RATE_22050 = 17,
+	ETDM_RATE_44100 = 18,
+	ETDM_RATE_88200 = 19,
+	ETDM_RATE_176400 = 20,
+	ETDM_RATE_352800 = 21, /* not support */
+};
+
+enum {
+	ETDM_CONN_8K = 0,
+	ETDM_CONN_11K = 1,
+	ETDM_CONN_12K = 2,
+	ETDM_CONN_16K = 4,
+	ETDM_CONN_22K = 5,
+	ETDM_CONN_24K = 6,
+	ETDM_CONN_32K = 8,
+	ETDM_CONN_44K = 9,
+	ETDM_CONN_48K = 10,
+	ETDM_CONN_88K = 13,
+	ETDM_CONN_96K = 14,
+	ETDM_CONN_176K = 17,
+	ETDM_CONN_192K = 18,
+	ETDM_CONN_352K = 21,
+	ETDM_CONN_384K = 22,
+};
+
+enum {
+	ETDM_WLEN_8_BIT = 0x7,
+	ETDM_WLEN_16_BIT = 0xf,
+	ETDM_WLEN_32_BIT = 0x1f,
+};
+
+enum {
+	ETDM_SLAVE_SEL_ETDMIN0_MASTER = 0,
+	ETDM_SLAVE_SEL_ETDMIN0_SLAVE = 1,
+	ETDM_SLAVE_SEL_ETDMIN1_MASTER = 2,
+	ETDM_SLAVE_SEL_ETDMIN1_SLAVE = 3,
+	ETDM_SLAVE_SEL_ETDMIN2_MASTER = 4,
+	ETDM_SLAVE_SEL_ETDMIN2_SLAVE = 5,
+	ETDM_SLAVE_SEL_ETDMIN3_MASTER = 6,
+	ETDM_SLAVE_SEL_ETDMIN3_SLAVE = 7,
+	ETDM_SLAVE_SEL_ETDMOUT0_MASTER = 8,
+	ETDM_SLAVE_SEL_ETDMOUT0_SLAVE = 9,
+	ETDM_SLAVE_SEL_ETDMOUT1_MASTER = 10,
+	ETDM_SLAVE_SEL_ETDMOUT1_SLAVE = 11,
+	ETDM_SLAVE_SEL_ETDMOUT2_MASTER = 12,
+	ETDM_SLAVE_SEL_ETDMOUT2_SLAVE = 13,
+	ETDM_SLAVE_SEL_ETDMOUT3_MASTER = 14,
+	ETDM_SLAVE_SEL_ETDMOUT3_SLAVE = 15,
+};
+
+struct mtk_afe_i2s_priv {
+	int id;
+	int rate; /* for determine which apll to use */
+	int low_jitter_en;
+	unsigned int i2s_low_power_mask;
+	const char *share_property_name;
+	int share_i2s_id;
+
+	int mclk_id;
+	int mclk_rate;
+	int mclk_apll;
+
+	int ch_num;
+	int sync;
+	int ip_mode;
+	int slave_mode;
+	int lpbk_mode;
+};
+
+static unsigned int get_etdm_wlen(snd_pcm_format_t format)
+{
+	unsigned int wlen = 0;
+
+	/* The reg_word_length should be >= reg_bit_length */
+	wlen = snd_pcm_format_physical_width(format);
+
+	if (wlen <= 16)
+		return ETDM_WLEN_16_BIT;
+
+	return ETDM_WLEN_32_BIT;
+}
+
+static unsigned int get_etdm_lrck_width(snd_pcm_format_t format)
+{
+	if (snd_pcm_format_physical_width(format) <= 1)
+		return 0;
+
+	/* The valid data bit number should be large than 7 due to hardware limitation. */
+	return snd_pcm_format_physical_width(format) - 1;
+}
+
+static unsigned int get_etdm_rate(unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return ETDM_RATE_8K;
+	case 12000:
+		return ETDM_RATE_12K;
+	case 16000:
+		return ETDM_RATE_16K;
+	case 24000:
+		return ETDM_RATE_24K;
+	case 32000:
+		return ETDM_RATE_32K;
+	case 48000:
+		return ETDM_RATE_48K;
+	case 64000:
+		return ETDM_RATE_64K;
+	case 96000:
+		return ETDM_RATE_96K;
+	case 128000:
+		return ETDM_RATE_128K;
+	case 192000:
+		return ETDM_RATE_192K;
+	case 256000:
+		return ETDM_RATE_256K;
+	case 384000:
+		return ETDM_RATE_384K;
+	case 11025:
+		return ETDM_RATE_11025;
+	case 22050:
+		return ETDM_RATE_22050;
+	case 44100:
+		return ETDM_RATE_44100;
+	case 88200:
+		return ETDM_RATE_88200;
+	case 176400:
+		return ETDM_RATE_176400;
+	case 352800:
+		return ETDM_RATE_352800;
+	default:
+		return 0;
+	}
+}
+
+static unsigned int get_etdm_inconn_rate(unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return ETDM_CONN_8K;
+	case 12000:
+		return ETDM_CONN_12K;
+	case 16000:
+		return ETDM_CONN_16K;
+	case 24000:
+		return ETDM_CONN_24K;
+	case 32000:
+		return ETDM_CONN_32K;
+	case 48000:
+		return ETDM_CONN_48K;
+	case 96000:
+		return ETDM_CONN_96K;
+	case 192000:
+		return ETDM_CONN_192K;
+	case 384000:
+		return ETDM_CONN_384K;
+	case 11025:
+		return ETDM_CONN_11K;
+	case 22050:
+		return ETDM_CONN_22K;
+	case 44100:
+		return ETDM_CONN_44K;
+	case 88200:
+		return ETDM_CONN_88K;
+	case 176400:
+		return ETDM_CONN_176K;
+	case 352800:
+		return ETDM_CONN_352K;
+	default:
+		return 0;
+	}
+}
+
+static const int etdm_lpbk_idx_0[] = {
+	0x0, 0x8,
+};
+
+static const int etdm_lpbk_idx_1[] = {
+	0x2, 0xa,
+};
+
+static const char *const etdm_lpbk_map[] = {
+	"Off", "On",
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(etdm_lpbk_map_enum,
+				etdm_lpbk_map);
+
+static int etdm_lpbk_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, "I2SIN0_LPBK")) {
+		reg = ETDM_0_3_COWORK_CON1;
+		mask = ETDM_IN0_SDATA0_SEL_MASK_SFT;
+		shift = ETDM_IN0_SDATA0_SEL_SFT;
+	} else if (!strcmp(kcontrol->id.name, "I2SIN1_LPBK")) {
+		reg = ETDM_0_3_COWORK_CON1;
+		mask = ETDM_IN1_SDATA0_SEL_MASK_SFT;
+		shift = ETDM_IN1_SDATA0_SEL_SFT;
+	}
+
+	if (reg)
+		regmap_read(afe->regmap, reg, &value);
+
+	value &= mask;
+	value >>= shift;
+	ucontrol->value.enumerated.item[0] = value;
+
+	if (value == 0x8 || value == 0xa || value == 0xc)
+		ucontrol->value.enumerated.item[0] = 1;
+	else
+		ucontrol->value.enumerated.item[0] = 0;
+
+	return 0;
+}
+
+static int etdm_lpbk_put(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	unsigned int value = ucontrol->value.integer.value[0];
+	unsigned int reg = 0;
+	unsigned int val = 0;
+	unsigned int mask = 0;
+
+	if (value >= ARRAY_SIZE(etdm_lpbk_idx_0))
+		return -EINVAL;
+
+	if (!strcmp(kcontrol->id.name, "I2SIN0_LPBK")) {
+		reg = ETDM_0_3_COWORK_CON1;
+		mask = ETDM_IN0_SDATA0_SEL_MASK_SFT;
+		val = etdm_lpbk_idx_0[value] << ETDM_IN0_SDATA0_SEL_SFT;
+	} else if (!strcmp(kcontrol->id.name, "I2SIN1_LPBK")) {
+		reg = ETDM_0_3_COWORK_CON1;
+		mask = ETDM_IN1_SDATA0_SEL_MASK_SFT;
+		val = etdm_lpbk_idx_1[value] << ETDM_IN1_SDATA0_SEL_SFT;
+	}
+
+	if (reg)
+		regmap_update_bits(afe->regmap, reg, mask, val);
+
+	return 0;
+}
+
+static const char *const etdm_ch_num_map[] = {
+	"2CH", "4CH", "6CH", "8CH",
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(etdm_ch_num_map_enum,
+				etdm_ch_num_map);
+
+static const int etdm_ch_num_idx[] = {
+	0x2, 0x4, 0x6, 0x8,
+};
+
+static int etdm_ch_num_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_i2s_priv *i2sout4_priv = afe_priv->dai_priv[MT8189_DAI_I2S_OUT4];
+	unsigned int value = 0;
+
+	if (!strcmp(kcontrol->id.name, "I2SOUT4_CH_NUM"))
+		value = i2sout4_priv->ch_num;
+
+	if (value == 0x2)
+		ucontrol->value.enumerated.item[0] = 0;
+	else if (value == 0x4)
+		ucontrol->value.enumerated.item[0] = 1;
+	else if (value == 0x6)
+		ucontrol->value.enumerated.item[0] = 2;
+	else
+		ucontrol->value.enumerated.item[0] = 3;
+
+	return 0;
+}
+
+static int etdm_ch_num_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_i2s_priv *i2sout4_priv = afe_priv->dai_priv[MT8189_DAI_I2S_OUT4];
+	unsigned int value = ucontrol->value.integer.value[0];
+
+	if (value >= ARRAY_SIZE(etdm_ch_num_idx))
+		return -EINVAL;
+
+	if (!strcmp(kcontrol->id.name, "I2SOUT4_CH_NUM"))
+		i2sout4_priv->ch_num = etdm_ch_num_idx[value];
+
+	return 0;
+}
+
+static int get_i2s_id_by_name(struct mtk_base_afe *afe,
+			      const char *name)
+{
+	if (strncmp(name, "I2SIN0", 6) == 0)
+		return MT8189_DAI_I2S_IN0;
+	else if (strncmp(name, "I2SIN1", 6) == 0)
+		return MT8189_DAI_I2S_IN1;
+	else if (strncmp(name, "I2SOUT0", 7) == 0)
+		return MT8189_DAI_I2S_OUT0;
+	else if (strncmp(name, "I2SOUT1", 7) == 0)
+		return MT8189_DAI_I2S_OUT1;
+	else if (strncmp(name, "I2SOUT4", 7) == 0)
+		return MT8189_DAI_I2S_OUT4;
+	else
+		return -EINVAL;
+}
+
+static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe,
+						     const char *name)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int dai_id = get_i2s_id_by_name(afe, name);
+
+	if (dai_id < 0)
+		return NULL;
+
+	return afe_priv->dai_priv[dai_id];
+}
+
+/*
+ * bit mask for i2s low power control
+ * such as bit0 for i2s0, bit1 for i2s1...
+ * if set 1, means i2s low power mode
+ * if set 0, means i2s low jitter mode
+ * 0 for all i2s bit in default
+ */
+static unsigned int i2s_low_power_mask;
+static int mtk_i2s_low_power_mask_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = i2s_low_power_mask;
+	return 0;
+}
+
+static int mtk_i2s_low_power_mask_set(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	i2s_low_power_mask = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static int mtk_is_i2s_low_power(int i2s_num)
+{
+	int i2s_bit_shift;
+
+	i2s_bit_shift = i2s_num - MT8189_DAI_I2S_IN0;
+	if (i2s_bit_shift < 0 || i2s_bit_shift > MT8189_DAI_I2S_MAX_NUM)
+		return 0;
+
+	return (i2s_low_power_mask >> i2s_bit_shift) & 0x1;
+}
+
+/* low jitter control */
+static const char *const mt8189_i2s_hd_str[] = {
+	"Normal", "Low_Jitter"
+};
+
+static const struct soc_enum mt8189_i2s_enum[] = {
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8189_i2s_hd_str),
+			    mt8189_i2s_hd_str),
+};
+
+static int mt8189_i2s_hd_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 mtk_afe_i2s_priv *i2s_priv;
+
+	i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name);
+	if (!i2s_priv)
+		return -EINVAL;
+
+	ucontrol->value.integer.value[0] = i2s_priv->low_jitter_en;
+
+	return 0;
+}
+
+static int mt8189_i2s_hd_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 mtk_afe_i2s_priv *i2s_priv;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+	i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name);
+	if (!i2s_priv)
+		return -EINVAL;
+
+	if (ucontrol->value.enumerated.item[0] >= e->items)
+		return -EINVAL;
+	i2s_priv->low_jitter_en = ucontrol->value.integer.value[0];
+
+	dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n",
+		__func__, kcontrol->id.name, i2s_priv->low_jitter_en);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new mtk_dai_i2s_controls[] = {
+	SOC_ENUM_EXT(MTK_AFE_I2SIN0_KCONTROL_NAME, mt8189_i2s_enum[0],
+		     mt8189_i2s_hd_get, mt8189_i2s_hd_set),
+	SOC_ENUM_EXT(MTK_AFE_I2SIN1_KCONTROL_NAME, mt8189_i2s_enum[0],
+		     mt8189_i2s_hd_get, mt8189_i2s_hd_set),
+	SOC_ENUM_EXT(MTK_AFE_I2SOUT0_KCONTROL_NAME, mt8189_i2s_enum[0],
+		     mt8189_i2s_hd_get, mt8189_i2s_hd_set),
+	SOC_ENUM_EXT(MTK_AFE_I2SOUT1_KCONTROL_NAME, mt8189_i2s_enum[0],
+		     mt8189_i2s_hd_get, mt8189_i2s_hd_set),
+	SOC_ENUM_EXT(MTK_AFE_I2SOUT4_KCONTROL_NAME, mt8189_i2s_enum[0],
+		     mt8189_i2s_hd_get, mt8189_i2s_hd_set),
+	SOC_SINGLE_EXT("i2s_low_power_mask", SND_SOC_NOPM, 0, 0xffff, 0,
+		       mtk_i2s_low_power_mask_get,
+		       mtk_i2s_low_power_mask_set),
+
+	SOC_ENUM_EXT("I2SIN0_LPBK", etdm_lpbk_map_enum,
+		     etdm_lpbk_get, etdm_lpbk_put),
+	SOC_ENUM_EXT("I2SIN1_LPBK", etdm_lpbk_map_enum,
+		     etdm_lpbk_get, etdm_lpbk_put),
+	SOC_ENUM_EXT("I2SOUT4_CH_NUM", etdm_ch_num_map_enum,
+		     etdm_ch_num_get, etdm_ch_num_put),
+};
+
+/* i2s virtual mux to output widget */
+static const char *const i2s_mux_map[] = {
+	"Normal", "Dummy_Widget",
+};
+
+static int i2s_mux_map_value[] = {
+	0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s_mux_map_enum,
+					      SND_SOC_NOPM,
+					      0,
+					      1,
+					      i2s_mux_map,
+					      i2s_mux_map_value);
+
+static const struct snd_kcontrol_new i2s_in0_mux_control =
+	SOC_DAPM_ENUM("I2S IN0 Select", i2s_mux_map_enum);
+static const struct snd_kcontrol_new i2s_in1_mux_control =
+	SOC_DAPM_ENUM("I2S IN1 Select", i2s_mux_map_enum);
+static const struct snd_kcontrol_new i2s_out0_mux_control =
+	SOC_DAPM_ENUM("I2S OUT0 Select", i2s_mux_map_enum);
+static const struct snd_kcontrol_new i2s_out1_mux_control =
+	SOC_DAPM_ENUM("I2S OUT1 Select", i2s_mux_map_enum);
+static const struct snd_kcontrol_new i2s_out4_mux_control =
+	SOC_DAPM_ENUM("I2S OUT4 Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new mtk_i2sout0_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN108_1, I_DL0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN108_1, I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN108_1, I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN108_1, I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN108_1, I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN108_1, I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN108_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN108_1, I_DL7_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN108_1, I_DL8_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN108_1, I_DL_24CH_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN108_0,
+				    I_GAIN0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN108_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN108_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout0_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN109_1, I_DL0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN109_1, I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN109_1, I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN109_1, I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN109_1, I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN109_1, I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN109_1, I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN109_1, I_DL7_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN109_1, I_DL8_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN109_1, I_DL_24CH_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN109_0,
+				    I_GAIN0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN109_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN109_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN109_4,
+				    I_PCM_0_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout1_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN110_1, I_DL0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN110_1, I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN110_1, I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN110_1, I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN110_1, I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN110_1, I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN110_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN110_1, I_DL7_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN110_1, I_DL8_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN110_1, I_DL_24CH_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN110_0,
+				    I_GAIN0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN110_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN110_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout1_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN111_1, I_DL0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN111_1, I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN111_1, I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN111_1, I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN111_1, I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN111_1, I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN111_1, I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN111_1, I_DL7_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN111_1, I_DL8_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN111_1, I_DL_24CH_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN111_0,
+				    I_GAIN0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN111_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN111_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN111_4,
+				    I_PCM_0_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN116_1, I_DL0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN116_1, I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN116_1, I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN116_1, I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN116_1, I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN116_1, I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN116_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN116_1, I_DL7_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN116_1, I_DL8_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN116_1, I_DL_24CH_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH1", AFE_CONN116_2, I_DL24_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN116_0,
+				    I_GAIN0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN116_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN116_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN116_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN116_6,
+				    I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN117_1, I_DL0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN117_1, I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN117_1, I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN117_1, I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN117_1, I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN117_1, I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN117_1, I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN117_1, I_DL7_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN117_1, I_DL8_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN117_1, I_DL_24CH_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH2", AFE_CONN117_2, I_DL24_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN117_0,
+				    I_GAIN0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN117_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN117_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN117_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN117_4,
+				    I_PCM_0_CAP_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN117_6,
+				    I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch3_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH3", AFE_CONN118_1, I_DL_24CH_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN118_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch4_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH4", AFE_CONN119_1, I_DL_24CH_CH4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN118_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch5_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH5", AFE_CONN120_1, I_DL_24CH_CH5, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch6_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH6", AFE_CONN121_1, I_DL_24CH_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch7_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH7", AFE_CONN122_1, I_DL_24CH_CH7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch8_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH8", AFE_CONN123_1, I_DL_24CH_CH8, 1, 0),
+};
+
+static int mtk_i2s_hd_en_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol,
+			       int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+
+	dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+		__func__, w->name, event);
+
+	return 0;
+}
+
+static int mtk_apll_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(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+		__func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (strcmp(w->name, APLL1_W_NAME) == 0)
+			mt8189_apll1_enable(afe);
+		else
+			mt8189_apll2_enable(afe);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (strcmp(w->name, APLL1_W_NAME) == 0)
+			mt8189_apll1_disable(afe);
+		else
+			mt8189_apll2_disable(afe);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol,
+			     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mtk_afe_i2s_priv *i2s_priv;
+
+	dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+		__func__, w->name, event);
+
+	i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+	if (!i2s_priv)
+		return -EINVAL;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8189_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		i2s_priv->mclk_rate = 0;
+		mt8189_mck_disable(afe, i2s_priv->mclk_id);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = {
+	SND_SOC_DAPM_MIXER("I2SOUT0_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_i2sout0_ch1_mix,
+			   ARRAY_SIZE(mtk_i2sout0_ch1_mix)),
+	SND_SOC_DAPM_MIXER("I2SOUT0_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_i2sout0_ch2_mix,
+			   ARRAY_SIZE(mtk_i2sout0_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("I2SOUT1_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_i2sout1_ch1_mix,
+			   ARRAY_SIZE(mtk_i2sout1_ch1_mix)),
+	SND_SOC_DAPM_MIXER("I2SOUT1_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_i2sout1_ch2_mix,
+			   ARRAY_SIZE(mtk_i2sout1_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("I2SOUT4_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_i2sout4_ch1_mix,
+			   ARRAY_SIZE(mtk_i2sout4_ch1_mix)),
+	SND_SOC_DAPM_MIXER("I2SOUT4_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_i2sout4_ch2_mix,
+			   ARRAY_SIZE(mtk_i2sout4_ch2_mix)),
+	SND_SOC_DAPM_MIXER("I2SOUT4_CH3", SND_SOC_NOPM, 0, 0,
+			   mtk_i2sout4_ch3_mix,
+			   ARRAY_SIZE(mtk_i2sout4_ch3_mix)),
+	SND_SOC_DAPM_MIXER("I2SOUT4_CH4", SND_SOC_NOPM, 0, 0,
+			   mtk_i2sout4_ch4_mix,
+			   ARRAY_SIZE(mtk_i2sout4_ch4_mix)),
+	SND_SOC_DAPM_MIXER("I2SOUT4_CH5", SND_SOC_NOPM, 0, 0,
+			   mtk_i2sout4_ch5_mix,
+			   ARRAY_SIZE(mtk_i2sout4_ch5_mix)),
+	SND_SOC_DAPM_MIXER("I2SOUT4_CH6", SND_SOC_NOPM, 0, 0,
+			   mtk_i2sout4_ch6_mix,
+			   ARRAY_SIZE(mtk_i2sout4_ch6_mix)),
+	SND_SOC_DAPM_MIXER("I2SOUT4_CH7", SND_SOC_NOPM, 0, 0,
+			   mtk_i2sout4_ch7_mix,
+			   ARRAY_SIZE(mtk_i2sout4_ch7_mix)),
+	SND_SOC_DAPM_MIXER("I2SOUT4_CH8", SND_SOC_NOPM, 0, 0,
+			   mtk_i2sout4_ch8_mix,
+			   ARRAY_SIZE(mtk_i2sout4_ch8_mix)),
+
+	/* i2s en*/
+	SND_SOC_DAPM_SUPPLY_S("I2SIN0_EN", SUPPLY_SEQ_I2S_EN,
+			      ETDM_IN0_CON0, REG_ETDM_IN_EN_SFT, 0,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2SIN1_EN", SUPPLY_SEQ_I2S_EN,
+			      ETDM_IN1_CON0, REG_ETDM_IN_EN_SFT, 0,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2SOUT0_EN", SUPPLY_SEQ_I2S_EN,
+			      ETDM_OUT0_CON0, OUT_REG_ETDM_OUT_EN_SFT, 0,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2SOUT1_EN", SUPPLY_SEQ_I2S_EN,
+			      ETDM_OUT1_CON0, OUT_REG_ETDM_OUT_EN_SFT, 0,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2SOUT4_EN", SUPPLY_SEQ_I2S_EN,
+			      ETDM_OUT4_CON0, OUT_REG_ETDM_OUT_EN_SFT, 0,
+			      NULL, 0),
+	/* i2s hd en */
+	SND_SOC_DAPM_SUPPLY_S(I2SIN0_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_i2s_hd_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S(I2SIN1_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_i2s_hd_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S(I2SOUT0_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_i2s_hd_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S(I2SOUT1_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_i2s_hd_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S(I2SOUT4_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_i2s_hd_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* i2s mclk en */
+	SND_SOC_DAPM_SUPPLY_S(I2SIN0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_mclk_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S(I2SIN1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_mclk_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S(I2SOUT0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_mclk_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S(I2SOUT1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_mclk_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S(I2SOUT4_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_mclk_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* cg */
+	SND_SOC_DAPM_SUPPLY_S("I2SOUT0_CG", SUPPLY_SEQ_I2S_CG_EN,
+			      AUDIO_TOP_CON2, PDN_ETDM_OUT0_SFT, 1,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2SOUT1_CG", SUPPLY_SEQ_I2S_CG_EN,
+			      AUDIO_TOP_CON2, PDN_ETDM_OUT1_SFT, 1,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2SOUT4_CG", SUPPLY_SEQ_I2S_CG_EN,
+			      AUDIO_TOP_CON2, PDN_ETDM_OUT4_SFT, 1,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2SIN0_CG", SUPPLY_SEQ_I2S_CG_EN,
+			      AUDIO_TOP_CON2, PDN_ETDM_IN0_SFT, 1,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2SIN1_CG", SUPPLY_SEQ_I2S_CG_EN,
+			      AUDIO_TOP_CON2, PDN_ETDM_IN1_SFT, 1,
+			      NULL, 0),
+
+	/* apll */
+	SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_apll_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_apll_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* allow i2s on without codec on */
+	SND_SOC_DAPM_OUTPUT("I2S_DUMMY_OUT"),
+	SND_SOC_DAPM_MUX("I2S_OUT0_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s_out0_mux_control),
+	SND_SOC_DAPM_MUX("I2S_OUT1_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s_out1_mux_control),
+	SND_SOC_DAPM_MUX("I2S_OUT4_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s_out4_mux_control),
+
+	SND_SOC_DAPM_INPUT("I2S_DUMMY_IN"),
+	SND_SOC_DAPM_MUX("I2S_IN0_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s_in0_mux_control),
+	SND_SOC_DAPM_MUX("I2S_IN1_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s_in1_mux_control),
+};
+
+static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source,
+				     struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_dapm_widget *w = sink;
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mtk_afe_i2s_priv *i2s_priv;
+	int ret = 0;
+
+	i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+
+	if (!i2s_priv)
+		return 0;
+
+	if (i2s_priv->share_i2s_id < 0)
+		return 0;
+
+	ret = (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name)) ? 1 : 0;
+
+	return ret;
+}
+
+static int mtk_afe_i2s_hd_connect(struct snd_soc_dapm_widget *source,
+				  struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_dapm_widget *w = sink;
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mtk_afe_i2s_priv *i2s_priv;
+	int i2s_num;
+
+	i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+
+	if (!i2s_priv)
+		return 0;
+
+	i2s_num = get_i2s_id_by_name(afe, source->name);
+	if (get_i2s_id_by_name(afe, sink->name) == i2s_num)
+		return !mtk_is_i2s_low_power(i2s_num) ||
+		       i2s_priv->low_jitter_en;
+
+	/* check if share i2s need hd en */
+	if (i2s_priv->share_i2s_id < 0)
+		return 0;
+
+	if (i2s_priv->share_i2s_id == i2s_num)
+		return !mtk_is_i2s_low_power(i2s_num) ||
+		       i2s_priv->low_jitter_en;
+
+	return 0;
+}
+
+static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source,
+				    struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_dapm_widget *w = sink;
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mtk_afe_i2s_priv *i2s_priv;
+	int cur_apll;
+	int i2s_need_apll;
+
+	i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+	if (!i2s_priv)
+		return 0;
+
+	/* which apll */
+	cur_apll = mt8189_get_apll_by_name(afe, source->name);
+
+	/* choose APLL from i2s rate */
+	i2s_need_apll = mt8189_get_apll_by_rate(afe, i2s_priv->rate);
+
+	return (i2s_need_apll == cur_apll) ? 1 : 0;
+}
+
+static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source,
+				    struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_dapm_widget *w = sink;
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mtk_afe_i2s_priv *i2s_priv;
+
+	i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+
+	if (!i2s_priv)
+		return 0;
+
+	if (get_i2s_id_by_name(afe, sink->name) ==
+	    get_i2s_id_by_name(afe, source->name))
+		return (i2s_priv->mclk_rate > 0);
+
+	/* check if share i2s need mclk */
+	if (i2s_priv->share_i2s_id < 0)
+		return 0;
+
+	if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name))
+		return (i2s_priv->mclk_rate > 0);
+
+	return 0;
+}
+
+static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source,
+				     struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_dapm_widget *w = sink;
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mtk_afe_i2s_priv *i2s_priv;
+	int cur_apll;
+
+	i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+	if (!i2s_priv)
+		return 0;
+
+	/* which apll */
+	cur_apll = mt8189_get_apll_by_name(afe, source->name);
+
+	return (i2s_priv->mclk_apll == cur_apll) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = {
+	/* I2SIN0 */
+	{"I2SIN0", NULL, "I2SIN0_EN"},
+	{"I2SIN0", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+	{"I2SIN0", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+	{"I2SIN0", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+	{"I2SIN0", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+
+	{"I2SIN0", NULL, I2SIN0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SIN0", NULL, I2SIN1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SIN0", NULL, I2SOUT0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SIN0", NULL, I2SOUT1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SIN0", NULL, I2SOUT4_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{I2SIN0_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+	{I2SIN0_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+	{"I2SIN0", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SIN0", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SIN0", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SIN0", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SIN0", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{I2SIN0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+	{I2SIN0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+	{"I2SIN0", NULL, "I2SOUT0_CG"},
+	{"I2SIN0", NULL, "I2SIN0_CG"},
+
+	/* i2sin1 */
+	{"I2SIN1", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+	{"I2SIN1", NULL, "I2SIN1_EN"},
+	{"I2SIN1", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+	{"I2SIN1", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+	{"I2SIN1", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+
+	{"I2SIN1", NULL, I2SIN0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SIN1", NULL, I2SIN1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SIN1", NULL, I2SOUT0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SIN1", NULL, I2SOUT1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SIN1", NULL, I2SOUT4_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{I2SIN1_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+	{I2SIN1_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+	{"I2SIN1", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SIN1", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SIN1", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SIN1", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SIN1", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{I2SIN1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+	{I2SIN1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+	{"I2SIN1", NULL, "I2SIN1_CG"},
+	{"I2SIN1", NULL, "I2SOUT1_CG"},
+
+	/* i2sout0 */
+	{"I2SOUT0_CH1", "DL0_CH1", "DL0"},
+	{"I2SOUT0_CH2", "DL0_CH2", "DL0"},
+	{"I2SOUT0_CH1", "DL1_CH1", "DL1"},
+	{"I2SOUT0_CH2", "DL1_CH2", "DL1"},
+	{"I2SOUT0_CH1", "DL2_CH1", "DL2"},
+	{"I2SOUT0_CH2", "DL2_CH2", "DL2"},
+	{"I2SOUT0_CH1", "DL3_CH1", "DL3"},
+	{"I2SOUT0_CH2", "DL3_CH2", "DL3"},
+	{"I2SOUT0_CH1", "DL4_CH1", "DL4"},
+	{"I2SOUT0_CH2", "DL4_CH2", "DL4"},
+	{"I2SOUT0_CH1", "DL5_CH1", "DL5"},
+	{"I2SOUT0_CH2", "DL5_CH2", "DL5"},
+	{"I2SOUT0_CH1", "DL6_CH1", "DL6"},
+	{"I2SOUT0_CH2", "DL6_CH2", "DL6"},
+	{"I2SOUT0_CH1", "DL7_CH1", "DL7"},
+	{"I2SOUT0_CH2", "DL7_CH2", "DL7"},
+	{"I2SOUT0_CH1", "DL8_CH1", "DL8"},
+	{"I2SOUT0_CH2", "DL8_CH2", "DL8"},
+	{"I2SOUT0_CH1", "DL_24CH_CH1", "DL_24CH"},
+	{"I2SOUT0_CH2", "DL_24CH_CH2", "DL_24CH"},
+
+	{"I2SOUT0", NULL, "I2SOUT0_CH1"},
+	{"I2SOUT0", NULL, "I2SOUT0_CH2"},
+
+	{"I2SOUT0", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+	{"I2SOUT0", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+	{"I2SOUT0", NULL, "I2SOUT0_EN"},
+	{"I2SOUT0", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+	{"I2SOUT0", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+
+	{"I2SOUT0", NULL, I2SIN0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SOUT0", NULL, I2SIN1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SOUT0", NULL, I2SOUT0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SOUT0", NULL, I2SOUT1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SOUT0", NULL, I2SOUT4_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{I2SOUT0_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+	{I2SOUT0_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+	{"I2SOUT0", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SOUT0", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SOUT0", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SOUT0", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SOUT0", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{I2SOUT0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+	{I2SOUT0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+	{"I2SOUT0", NULL, "I2SOUT0_CG"},
+	{"I2SOUT0", NULL, "I2SIN0_CG"},
+
+	/* i2sout1 */
+	{"I2SOUT1_CH1", "DL0_CH1", "DL0"},
+	{"I2SOUT1_CH2", "DL0_CH2", "DL0"},
+	{"I2SOUT1_CH1", "DL1_CH1", "DL1"},
+	{"I2SOUT1_CH2", "DL1_CH2", "DL1"},
+	{"I2SOUT1_CH1", "DL2_CH1", "DL2"},
+	{"I2SOUT1_CH2", "DL2_CH2", "DL2"},
+	{"I2SOUT1_CH1", "DL3_CH1", "DL3"},
+	{"I2SOUT1_CH2", "DL3_CH2", "DL3"},
+	{"I2SOUT1_CH1", "DL4_CH1", "DL4"},
+	{"I2SOUT1_CH2", "DL4_CH2", "DL4"},
+	{"I2SOUT1_CH1", "DL5_CH1", "DL5"},
+	{"I2SOUT1_CH2", "DL5_CH2", "DL5"},
+	{"I2SOUT1_CH1", "DL6_CH1", "DL6"},
+	{"I2SOUT1_CH2", "DL6_CH2", "DL6"},
+	{"I2SOUT1_CH1", "DL7_CH1", "DL7"},
+	{"I2SOUT1_CH2", "DL7_CH2", "DL7"},
+	{"I2SOUT1_CH1", "DL8_CH1", "DL8"},
+	{"I2SOUT1_CH2", "DL8_CH2", "DL8"},
+	{"I2SOUT1_CH1", "DL_24CH_CH1", "DL_24CH"},
+	{"I2SOUT1_CH2", "DL_24CH_CH2", "DL_24CH"},
+
+	{"I2SOUT1", NULL, "I2SOUT1_CH1"},
+	{"I2SOUT1", NULL, "I2SOUT1_CH2"},
+
+	{"I2SOUT1", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+	{"I2SOUT1", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+	{"I2SOUT1", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+	{"I2SOUT1", NULL, "I2SOUT1_EN"},
+	{"I2SOUT1", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+
+	{"I2SOUT1", NULL, I2SIN0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SOUT1", NULL, I2SIN1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SOUT1", NULL, I2SOUT0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SOUT1", NULL, I2SOUT1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SOUT1", NULL, I2SOUT4_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{I2SOUT1_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+	{I2SOUT1_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+	{"I2SOUT1", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SOUT1", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SOUT1", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SOUT1", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SOUT1", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{I2SOUT1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+	{I2SOUT1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+	{"I2SOUT1", NULL, "I2SOUT1_CG"},
+	{"I2SOUT1", NULL, "I2SIN1_CG"},
+
+	/* i2sout4 */
+	{"I2SOUT4_CH1", "DL0_CH1", "DL0"},
+	{"I2SOUT4_CH2", "DL0_CH2", "DL0"},
+	{"I2SOUT4_CH1", "DL1_CH1", "DL1"},
+	{"I2SOUT4_CH2", "DL1_CH2", "DL1"},
+	{"I2SOUT4_CH1", "DL2_CH1", "DL2"},
+	{"I2SOUT4_CH2", "DL2_CH2", "DL2"},
+	{"I2SOUT4_CH1", "DL3_CH1", "DL3"},
+	{"I2SOUT4_CH2", "DL3_CH2", "DL3"},
+	{"I2SOUT4_CH1", "DL4_CH1", "DL4"},
+	{"I2SOUT4_CH2", "DL4_CH2", "DL4"},
+	{"I2SOUT4_CH1", "DL5_CH1", "DL5"},
+	{"I2SOUT4_CH2", "DL5_CH2", "DL5"},
+	{"I2SOUT4_CH1", "DL6_CH1", "DL6"},
+	{"I2SOUT4_CH2", "DL6_CH2", "DL6"},
+	{"I2SOUT4_CH1", "DL7_CH1", "DL7"},
+	{"I2SOUT4_CH2", "DL7_CH2", "DL7"},
+	{"I2SOUT4_CH1", "DL8_CH1", "DL8"},
+	{"I2SOUT4_CH2", "DL8_CH2", "DL8"},
+	{"I2SOUT4_CH1", "DL_24CH_CH1", "DL_24CH"},
+	{"I2SOUT4_CH2", "DL_24CH_CH2", "DL_24CH"},
+	{"I2SOUT4_CH3", "DL_24CH_CH3", "DL_24CH"},
+	{"I2SOUT4_CH4", "DL_24CH_CH4", "DL_24CH"},
+	{"I2SOUT4_CH5", "DL_24CH_CH5", "DL_24CH"},
+	{"I2SOUT4_CH6", "DL_24CH_CH6", "DL_24CH"},
+	{"I2SOUT4_CH7", "DL_24CH_CH7", "DL_24CH"},
+	{"I2SOUT4_CH8", "DL_24CH_CH8", "DL_24CH"},
+	{"I2SOUT4_CH1", "DL24_CH1", "DL24"},
+	{"I2SOUT4_CH2", "DL24_CH2", "DL24"},
+
+	{"I2SOUT4", NULL, "I2SOUT4_CH1"},
+	{"I2SOUT4", NULL, "I2SOUT4_CH2"},
+	{"I2SOUT4", NULL, "I2SOUT4_CH3"},
+	{"I2SOUT4", NULL, "I2SOUT4_CH4"},
+	{"I2SOUT4", NULL, "I2SOUT4_CH5"},
+	{"I2SOUT4", NULL, "I2SOUT4_CH6"},
+	{"I2SOUT4", NULL, "I2SOUT4_CH7"},
+	{"I2SOUT4", NULL, "I2SOUT4_CH8"},
+
+	{"I2SOUT4", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+	{"I2SOUT4", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+	{"I2SOUT4", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+	{"I2SOUT4", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+	{"I2SOUT4", NULL, "I2SOUT4_EN"},
+
+	{"I2SOUT4", NULL, I2SIN0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SOUT4", NULL, I2SIN1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SOUT4", NULL, I2SOUT0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SOUT4", NULL, I2SOUT1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2SOUT4", NULL, I2SOUT4_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{I2SOUT4_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+	{I2SOUT4_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+	{"I2SOUT4", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SOUT4", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SOUT4", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SOUT4", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2SOUT4", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{I2SOUT4_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+	{I2SOUT4_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+	/* CG */
+	{"I2SOUT4", NULL, "I2SOUT4_CG"},
+
+	/* allow i2s on without codec on */
+	{"I2SIN0", NULL, "I2S_IN0_Mux"},
+	{"I2S_IN0_Mux", "Dummy_Widget", "I2S_DUMMY_IN"},
+
+	{"I2SIN1", NULL, "I2S_IN1_Mux"},
+	{"I2S_IN1_Mux", "Dummy_Widget", "I2S_DUMMY_IN"},
+
+	{"I2S_OUT0_Mux", "Dummy_Widget", "I2SOUT0"},
+	{"I2S_DUMMY_OUT", NULL, "I2S_OUT0_Mux"},
+
+	{"I2S_OUT1_Mux", "Dummy_Widget", "I2SOUT1"},
+	{"I2S_DUMMY_OUT", NULL, "I2S_OUT1_Mux"},
+
+	{"I2S_OUT4_Mux", "Dummy_Widget", "I2SOUT4"},
+	{"I2S_DUMMY_OUT", NULL, "I2S_OUT4_Mux"},
+};
+
+/* i2s dai ops*/
+static int mtk_dai_i2s_config(struct mtk_base_afe *afe,
+			      struct snd_pcm_hw_params *params,
+			      int i2s_id)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[i2s_id];
+
+	unsigned int rate = params_rate(params);
+	snd_pcm_format_t format = params_format(params);
+
+	int ret = 0;
+
+	dev_dbg(afe->dev, "%s(), id %d, rate %d, format %d\n",
+		__func__, i2s_id, rate, format);
+
+	if (i2s_priv)
+		i2s_priv->rate = rate;
+	else
+		return -EINVAL;
+
+	switch (i2s_id) {
+	case MT8189_DAI_I2S_IN0:
+		/* ---etdm in --- */
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON1,
+				   REG_INITIAL_COUNT_MASK_SFT,
+				   0x5 << REG_INITIAL_COUNT_SFT);
+		/* 3: pad top 5: no pad top */
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON1,
+				   REG_INITIAL_POINT_MASK_SFT,
+				   0x5 << REG_INITIAL_POINT_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON1,
+				   REG_LRCK_RESET_MASK_SFT,
+				   0x1 << REG_LRCK_RESET_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON2,
+				   REG_CLOCK_SOURCE_SEL_MASK_SFT,
+				   ETDM_CLK_SOURCE_APLL << REG_CLOCK_SOURCE_SEL_SFT);
+		/* 0: manual 1: auto */
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON2,
+				   REG_CK_EN_SEL_AUTO_MASK_SFT,
+				   0x1 << REG_CK_EN_SEL_AUTO_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON3,
+				   REG_FS_TIMING_SEL_MASK_SFT,
+				   get_etdm_rate(rate) << REG_FS_TIMING_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON4,
+				   REG_RELATCH_1X_EN_SEL_MASK_SFT,
+				   get_etdm_inconn_rate(rate) << REG_RELATCH_1X_EN_SEL_SFT);
+
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON8,
+				   REG_ETDM_USE_AFIFO_MASK_SFT,
+				   0x0 << REG_ETDM_USE_AFIFO_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON8,
+				   REG_AFIFO_MODE_MASK_SFT,
+				   0x0 << REG_AFIFO_MODE_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON9,
+				   REG_ALMOST_END_CH_COUNT_MASK_SFT,
+				   0x0 << REG_ALMOST_END_CH_COUNT_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON9,
+				   REG_ALMOST_END_BIT_COUNT_MASK_SFT,
+				   0x0 << REG_ALMOST_END_BIT_COUNT_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON9,
+				   REG_OUT2LATCH_TIME_MASK_SFT,
+				   0x6 << REG_OUT2LATCH_TIME_SFT);
+
+		/* 5:  TDM Mode */
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON0,
+				   REG_FMT_MASK_SFT, 0x0 << REG_FMT_SFT);
+
+		/* APLL */
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON0,
+				   REG_RELATCH_1X_EN_DOMAIN_SEL_MASK_SFT,
+				   ETDM_RELATCH_SEL_APLL
+				   << REG_RELATCH_1X_EN_DOMAIN_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON0,
+				   REG_BIT_LENGTH_MASK_SFT,
+				   get_etdm_lrck_width(format) << REG_BIT_LENGTH_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN0_CON0,
+				   REG_WORD_LENGTH_MASK_SFT,
+				   get_etdm_wlen(format) << REG_WORD_LENGTH_SFT);
+
+		/* ---etdm cowork --- */
+		regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON0,
+				   ETDM_IN0_SLAVE_SEL_MASK_SFT,
+				   ETDM_SLAVE_SEL_ETDMOUT0_MASTER
+				   << ETDM_IN0_SLAVE_SEL_SFT);
+		break;
+	case MT8189_DAI_I2S_IN1:
+		/* ---etdm in --- */
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON1,
+				   REG_INITIAL_COUNT_MASK_SFT,
+				   0x5 << REG_INITIAL_COUNT_SFT);
+		/* 3: pad top 5: no pad top */
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON1,
+				   REG_INITIAL_POINT_MASK_SFT,
+				   0x5 << REG_INITIAL_POINT_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON1,
+				   REG_LRCK_RESET_MASK_SFT,
+				   0x1 << REG_LRCK_RESET_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON2,
+				   REG_CLOCK_SOURCE_SEL_MASK_SFT,
+				   ETDM_CLK_SOURCE_APLL << REG_CLOCK_SOURCE_SEL_SFT);
+		/* 0: manual 1: auto */
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON2,
+				   REG_CK_EN_SEL_AUTO_MASK_SFT,
+				   0x1 << REG_CK_EN_SEL_AUTO_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON3,
+				   REG_FS_TIMING_SEL_MASK_SFT,
+				   get_etdm_rate(rate) << REG_FS_TIMING_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON4,
+				   REG_RELATCH_1X_EN_SEL_MASK_SFT,
+				   get_etdm_inconn_rate(rate) << REG_RELATCH_1X_EN_SEL_SFT);
+
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON8,
+				   REG_ETDM_USE_AFIFO_MASK_SFT,
+				   0x0 << REG_ETDM_USE_AFIFO_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON8,
+				   REG_AFIFO_MODE_MASK_SFT,
+				   0x0 << REG_AFIFO_MODE_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON9,
+				   REG_ALMOST_END_CH_COUNT_MASK_SFT,
+				   0x0 << REG_ALMOST_END_CH_COUNT_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON9,
+				   REG_ALMOST_END_BIT_COUNT_MASK_SFT,
+				   0x0 << REG_ALMOST_END_BIT_COUNT_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON9,
+				   REG_OUT2LATCH_TIME_MASK_SFT,
+				   0x6 << REG_OUT2LATCH_TIME_SFT);
+
+		/* 5:  TDM Mode */
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
+				   REG_FMT_MASK_SFT, 0x0 << REG_FMT_SFT);
+
+		/* APLL */
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
+				   REG_RELATCH_1X_EN_DOMAIN_SEL_MASK_SFT,
+				   ETDM_RELATCH_SEL_APLL
+				   << REG_RELATCH_1X_EN_DOMAIN_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
+				   REG_BIT_LENGTH_MASK_SFT,
+				   get_etdm_lrck_width(format) << REG_BIT_LENGTH_SFT);
+		regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
+				   REG_WORD_LENGTH_MASK_SFT,
+				   get_etdm_wlen(format) << REG_WORD_LENGTH_SFT);
+
+		/* ---etdm cowork --- */
+		regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON1,
+				   ETDM_IN1_SLAVE_SEL_MASK_SFT,
+				   ETDM_SLAVE_SEL_ETDMOUT1_MASTER
+				   << ETDM_IN1_SLAVE_SEL_SFT);
+		break;
+	case MT8189_DAI_I2S_OUT0:
+		/* ---etdm out --- */
+		regmap_update_bits(afe->regmap, ETDM_OUT0_CON1,
+				   OUT_REG_INITIAL_COUNT_MASK_SFT,
+				   0x5 << OUT_REG_INITIAL_COUNT_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT0_CON1,
+				   OUT_REG_INITIAL_POINT_MASK_SFT,
+				   0x6 << OUT_REG_INITIAL_POINT_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT0_CON1,
+				   OUT_REG_LRCK_RESET_MASK_SFT,
+				   0x1 << OUT_REG_LRCK_RESET_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT0_CON4,
+				   OUT_REG_FS_TIMING_SEL_MASK_SFT,
+				   get_etdm_rate(rate) << OUT_REG_FS_TIMING_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT0_CON4,
+				   OUT_REG_CLOCK_SOURCE_SEL_MASK_SFT,
+				   ETDM_CLK_SOURCE_APLL << OUT_REG_CLOCK_SOURCE_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT0_CON4,
+				   OUT_REG_RELATCH_EN_SEL_MASK_SFT,
+				   get_etdm_inconn_rate(rate) << OUT_REG_RELATCH_EN_SEL_SFT);
+		/* 5:  TDM Mode */
+		regmap_update_bits(afe->regmap, ETDM_OUT0_CON0,
+				   OUT_REG_FMT_MASK_SFT, 0x0 << OUT_REG_FMT_SFT);
+
+		/* APLL */
+		regmap_update_bits(afe->regmap, ETDM_OUT0_CON0,
+				   OUT_REG_RELATCH_DOMAIN_SEL_MASK_SFT,
+				   ETDM_RELATCH_SEL_APLL
+				   << OUT_REG_RELATCH_DOMAIN_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT0_CON0,
+				   OUT_REG_BIT_LENGTH_MASK_SFT,
+				   get_etdm_lrck_width(format) << OUT_REG_BIT_LENGTH_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT0_CON0,
+				   OUT_REG_WORD_LENGTH_MASK_SFT,
+				   get_etdm_wlen(format) << OUT_REG_WORD_LENGTH_SFT);
+
+		/* ---etdm cowork --- */
+		regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON0,
+				   ETDM_OUT0_SLAVE_SEL_MASK_SFT,
+				   ETDM_SLAVE_SEL_ETDMIN0_MASTER
+				   << ETDM_OUT0_SLAVE_SEL_SFT);
+		break;
+	case MT8189_DAI_I2S_OUT1:
+		/* ---etdm out --- */
+		regmap_update_bits(afe->regmap, ETDM_OUT1_CON1,
+				   OUT_REG_INITIAL_COUNT_MASK_SFT,
+				   0x5 << OUT_REG_INITIAL_COUNT_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT1_CON1,
+				   OUT_REG_INITIAL_POINT_MASK_SFT,
+				   0x6 << OUT_REG_INITIAL_POINT_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT1_CON1,
+				   OUT_REG_LRCK_RESET_MASK_SFT,
+				   0x1 << OUT_REG_LRCK_RESET_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT1_CON4,
+				   OUT_REG_FS_TIMING_SEL_MASK_SFT,
+				   get_etdm_rate(rate) << OUT_REG_FS_TIMING_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT1_CON4,
+				   OUT_REG_CLOCK_SOURCE_SEL_MASK_SFT,
+				   ETDM_CLK_SOURCE_APLL << OUT_REG_CLOCK_SOURCE_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT1_CON4,
+				   OUT_REG_RELATCH_EN_SEL_MASK_SFT,
+				   get_etdm_inconn_rate(rate) << OUT_REG_RELATCH_EN_SEL_SFT);
+		/* 5:  TDM Mode */
+		regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
+				   OUT_REG_FMT_MASK_SFT, 0x0 << OUT_REG_FMT_SFT);
+
+		/* APLL */
+		regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
+				   OUT_REG_RELATCH_DOMAIN_SEL_MASK_SFT,
+				   ETDM_RELATCH_SEL_APLL
+				   << OUT_REG_RELATCH_DOMAIN_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
+				   OUT_REG_BIT_LENGTH_MASK_SFT,
+				   get_etdm_lrck_width(format) << OUT_REG_BIT_LENGTH_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
+				   OUT_REG_WORD_LENGTH_MASK_SFT,
+				   get_etdm_wlen(format) << OUT_REG_WORD_LENGTH_SFT);
+
+		/* ---etdm cowork --- */
+		regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON0,
+				   ETDM_OUT1_SLAVE_SEL_MASK_SFT,
+				   ETDM_SLAVE_SEL_ETDMIN1_MASTER
+				   << ETDM_OUT1_SLAVE_SEL_SFT);
+		break;
+	case MT8189_DAI_I2S_OUT4:
+		/* ---etdm out --- */
+		regmap_update_bits(afe->regmap, ETDM_OUT4_CON1,
+				   OUT_REG_INITIAL_COUNT_MASK_SFT,
+				   0x5 << OUT_REG_INITIAL_COUNT_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT4_CON1,
+				   OUT_REG_INITIAL_POINT_MASK_SFT,
+				   0x6 << OUT_REG_INITIAL_POINT_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT4_CON1,
+				   OUT_REG_LRCK_RESET_MASK_SFT,
+				   0x1 << OUT_REG_LRCK_RESET_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT4_CON4,
+				   OUT_REG_FS_TIMING_SEL_MASK_SFT,
+				   get_etdm_rate(rate) << OUT_REG_FS_TIMING_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT4_CON4,
+				   OUT_REG_CLOCK_SOURCE_SEL_MASK_SFT,
+				   ETDM_CLK_SOURCE_APLL << OUT_REG_CLOCK_SOURCE_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT4_CON4,
+				   OUT_REG_RELATCH_EN_SEL_MASK_SFT,
+				   get_etdm_inconn_rate(rate) << OUT_REG_RELATCH_EN_SEL_SFT);
+		/* 5:  TDM Mode */
+		regmap_update_bits(afe->regmap, ETDM_OUT4_CON0,
+				   OUT_REG_FMT_MASK_SFT, 0x0 << OUT_REG_FMT_SFT);
+
+		/* APLL */
+		regmap_update_bits(afe->regmap, ETDM_OUT4_CON0,
+				   OUT_REG_RELATCH_DOMAIN_SEL_MASK_SFT,
+				   ETDM_RELATCH_SEL_APLL
+				   << OUT_REG_RELATCH_DOMAIN_SEL_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT4_CON0,
+				   OUT_REG_BIT_LENGTH_MASK_SFT,
+				   get_etdm_lrck_width(format) << OUT_REG_BIT_LENGTH_SFT);
+		regmap_update_bits(afe->regmap, ETDM_OUT4_CON0,
+				   OUT_REG_WORD_LENGTH_MASK_SFT,
+				   get_etdm_wlen(format) << OUT_REG_WORD_LENGTH_SFT);
+		break;
+	default:
+		dev_err(afe->dev, "%s(), id %d not support\n",
+			__func__, i2s_id);
+		return -EINVAL;
+	}
+
+	/* set share i2s */
+	if (i2s_priv && i2s_priv->share_i2s_id >= 0)
+		ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id);
+
+	return ret;
+}
+
+static int mtk_dai_i2s_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);
+
+	return mtk_dai_i2s_config(afe, params, dai->id);
+}
+
+static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[dai->id];
+	int apll;
+	int apll_rate;
+
+	if (!i2s_priv)
+		return -EINVAL;
+
+	if (dir != SND_SOC_CLOCK_OUT)
+		return -EINVAL;
+
+	dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+	apll = mt8189_get_apll_by_rate(afe, freq);
+	apll_rate = mt8189_get_apll_rate(afe, apll);
+
+	if (freq > apll_rate || (apll_rate % freq != 0)) {
+		dev_err(afe->dev, "%s(), freq %d, apll_rate %d\n",
+			__func__, freq, apll_rate);
+		return -EINVAL;
+	}
+
+	i2s_priv->mclk_rate = freq;
+	i2s_priv->mclk_apll = apll;
+
+	if (i2s_priv->share_i2s_id > 0) {
+		struct mtk_afe_i2s_priv *share_i2s_priv;
+
+		share_i2s_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id];
+		if (!share_i2s_priv)
+			return -EINVAL;
+
+		share_i2s_priv->mclk_rate = i2s_priv->mclk_rate;
+		share_i2s_priv->mclk_apll = i2s_priv->mclk_apll;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_i2s_ops = {
+	.hw_params = mtk_dai_i2s_hw_params,
+	.set_sysclk = mtk_dai_i2s_set_sysclk,
+};
+
+/* dai driver */
+#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_192000)
+#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S8 |\
+			  SNDRV_PCM_FMTBIT_S16_LE |\
+			  SNDRV_PCM_FMTBIT_S24_LE |\
+			  SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = {
+	{
+		.name = "I2SIN0",
+		.id = MT8189_DAI_I2S_IN0,
+		.capture = {
+			.stream_name = "I2SIN0",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.ops = &mtk_dai_i2s_ops,
+	},
+	{
+		.name = "I2SIN1",
+		.id = MT8189_DAI_I2S_IN1,
+		.capture = {
+			.stream_name = "I2SIN1",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.ops = &mtk_dai_i2s_ops,
+	},
+	{
+		.name = "I2SOUT0",
+		.id = MT8189_DAI_I2S_OUT0,
+		.playback = {
+			.stream_name = "I2SOUT0",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.ops = &mtk_dai_i2s_ops,
+	},
+	{
+		.name = "I2SOUT1",
+		.id = MT8189_DAI_I2S_OUT1,
+		.playback = {
+			.stream_name = "I2SOUT1",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.ops = &mtk_dai_i2s_ops,
+	},
+	{
+		.name = "I2SOUT4",
+		.id = MT8189_DAI_I2S_OUT4,
+		.playback = {
+			.stream_name = "I2SOUT4",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.ops = &mtk_dai_i2s_ops,
+	},
+};
+
+static const struct mtk_afe_i2s_priv mt8189_i2s_priv[DAI_I2S_NUM] = {
+	[DAI_I2SIN0] = {
+		.id = MT8189_DAI_I2S_IN0,
+		.mclk_id = MT8189_I2SIN0_MCK,
+		.share_property_name = "i2sin0-share",
+		.share_i2s_id = MT8189_DAI_I2S_OUT0,
+	},
+	[DAI_I2SIN1] = {
+		.id = MT8189_DAI_I2S_IN1,
+		.mclk_id = MT8189_I2SIN1_MCK,
+		.share_property_name = "i2sin1-share",
+		.share_i2s_id = MT8189_DAI_I2S_OUT1,
+	},
+	[DAI_I2SOUT0] = {
+		.id = MT8189_DAI_I2S_OUT0,
+		.mclk_id = MT8189_I2SIN0_MCK,
+		.share_property_name = "i2sout0-share",
+		.share_i2s_id = -1,
+	},
+	[DAI_I2SOUT1] = {
+		.id = MT8189_DAI_I2S_OUT1,
+		.mclk_id = MT8189_I2SIN1_MCK,
+		.share_property_name = "i2sout1-share",
+		.share_i2s_id = -1,
+	},
+	[DAI_I2SOUT4] = {
+		.id = MT8189_DAI_I2S_OUT4,
+		.mclk_id = MT8189_I2SIN1_MCK,
+		.share_property_name = "i2sout4-share",
+		.share_i2s_id = -1,
+	},
+};
+
+static int mt8189_dai_i2s_get_share(struct mtk_base_afe *afe)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	const struct device_node *of_node = afe->dev->of_node;
+	const char *of_str;
+	const char *property_name;
+	struct mtk_afe_i2s_priv *i2s_priv;
+	int i;
+
+	for (i = 0; i < DAI_I2S_NUM; i++) {
+		i2s_priv = afe_priv->dai_priv[mt8189_i2s_priv[i].id];
+		property_name = mt8189_i2s_priv[i].share_property_name;
+		if (of_property_read_string(of_node, property_name, &of_str))
+			continue;
+		i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str);
+	}
+
+	return 0;
+}
+
+static int init_i2s_priv_data(struct mtk_base_afe *afe)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_i2s_priv *i2s_priv;
+	int size;
+	int id;
+	int i;
+
+	for (i = 0; i < DAI_I2S_NUM; i++) {
+		id = mt8189_i2s_priv[i].id;
+		size = sizeof(struct mtk_afe_i2s_priv);
+
+		if (id >= MT8189_DAI_NUM || id < 0)
+			return -EINVAL;
+
+		i2s_priv = devm_kzalloc(afe->dev, size, GFP_KERNEL);
+		if (!i2s_priv)
+			return -ENOMEM;
+
+		memcpy(i2s_priv, &mt8189_i2s_priv[i], size);
+
+		afe_priv->dai_priv[id] = i2s_priv;
+	}
+
+	return 0;
+}
+
+int mt8189_dai_i2s_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+	int ret;
+
+	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_i2s_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver);
+
+	dai->controls = mtk_dai_i2s_controls;
+	dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls);
+	dai->dapm_widgets = mtk_dai_i2s_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets);
+	dai->dapm_routes = mtk_dai_i2s_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes);
+
+	/* set all dai i2s private data */
+	ret = init_i2s_priv_data(afe);
+	if (ret)
+		return ret;
+
+	/* parse share i2s */
+	ret = mt8189_dai_i2s_get_share(afe);
+	if (ret)
+		return ret;
+
+	return 0;
+}
-- 
2.46.0



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

* [PATCH 05/10] ASoC: mediatek: mt8189: support TDM in platform driver
  2025-06-28  7:14 [PATCH 00/10] ASoC: mediatek: Add support for MT8189 SoC Cyril
                   ` (2 preceding siblings ...)
  2025-06-28  7:14 ` [PATCH 04/10] ASoC: mediatek: mt8189: support I2S " Cyril
@ 2025-06-28  7:14 ` Cyril
  2025-06-28  7:14 ` [PATCH 06/10] ASoC: mediatek: mt8189: support PCM " Cyril
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Cyril @ 2025-06-28  7:14 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group, cyril.chao,
	Cyril Chao

From: Cyril Chao <Cyril.Chao@mediatek.com>

Add mt8189 TDM DAI driver support.

Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
---
 sound/soc/mediatek/mt8189/mt8189-dai-tdm.c | 828 +++++++++++++++++++++
 1 file changed, 828 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-dai-tdm.c

diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-tdm.c b/sound/soc/mediatek/mt8189/mt8189-dai-tdm.c
new file mode 100644
index 000000000..411a63518
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-dai-tdm.c
@@ -0,0 +1,828 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  MediaTek ALSA SoC Audio DAI TDM Control
+ *
+ *  Copyright (c) 2025 MediaTek Inc.
+ *  Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8189-afe-clk.h"
+#include "mt8189-afe-common.h"
+#include "mt8189-interconnection.h"
+
+enum {
+	SUPPLY_SEQ_APLL,
+	SUPPLY_SEQ_TDM_MCK_EN,
+	SUPPLY_SEQ_TDM_BCK_EN,
+	SUPPLY_SEQ_TDM_DPTX_MCK_EN,
+	SUPPLY_SEQ_TDM_DPTX_BCK_EN,
+	SUPPLY_SEQ_TDM_CG_EN,
+};
+
+enum {
+	TDM_WLEN_16_BIT = 1,
+	TDM_WLEN_32_BIT = 2,
+};
+
+enum {
+	TDM_CHANNEL_BCK_16 = 0,
+	TDM_CHANNEL_BCK_24 = 1,
+	TDM_CHANNEL_BCK_32 = 2,
+};
+
+enum {
+	TDM_CHANNEL_NUM_2 = 0,
+	TDM_CHANNEL_NUM_4 = 1,
+	TDM_CHANNEL_NUM_8 = 2,
+};
+
+enum  {
+	TDM_CH_START_O30_O31 = 0,
+	TDM_CH_START_O32_O33,
+	TDM_CH_START_O34_O35,
+	TDM_CH_START_O36_O37,
+	TDM_CH_ZERO,
+};
+
+enum {
+	DPTX_CHANNEL_2,
+	DPTX_CHANNEL_8,
+};
+
+enum {
+	DPTX_WLEN_24_BIT,
+	DPTX_WLEN_16_BIT,
+};
+
+enum {
+	DPTX_CH_EN_MASK_2CH = 0x3,
+	DPTX_CH_EN_MASK_4CH = 0xf,
+	DPTX_CH_EN_MASK_6CH = 0x3f,
+	DPTX_CH_EN_MASK_8CH = 0xff,
+};
+
+struct mtk_afe_tdm_priv {
+	int bck_id;
+	int bck_rate;
+
+	int mclk_id;
+	int mclk_multiple; /* according to sample rate */
+	int mclk_rate;
+	int mclk_apll;
+};
+
+static unsigned int get_tdm_wlen(snd_pcm_format_t format)
+{
+	return snd_pcm_format_physical_width(format) <= 16 ?
+	       TDM_WLEN_16_BIT : TDM_WLEN_32_BIT;
+}
+
+static unsigned int get_tdm_channel_bck(snd_pcm_format_t format)
+{
+	return snd_pcm_format_physical_width(format) <= 16 ?
+	       TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32;
+}
+
+static unsigned int get_tdm_lrck_width(snd_pcm_format_t format)
+{
+	return snd_pcm_format_physical_width(format) - 1;
+}
+
+static unsigned int get_tdm_ch(unsigned int ch)
+{
+	switch (ch) {
+	case 1:
+	case 2:
+		return TDM_CHANNEL_NUM_2;
+	case 3:
+	case 4:
+		return TDM_CHANNEL_NUM_4;
+	case 5:
+	case 6:
+	case 7:
+	case 8:
+	default:
+		return TDM_CHANNEL_NUM_8;
+	}
+}
+
+static unsigned int get_dptx_ch_enable_mask(unsigned int ch)
+{
+	switch (ch) {
+	case 1:
+	case 2:
+		return DPTX_CH_EN_MASK_2CH;
+	case 3:
+	case 4:
+		return DPTX_CH_EN_MASK_4CH;
+	case 5:
+	case 6:
+		return DPTX_CH_EN_MASK_6CH;
+	case 7:
+	case 8:
+		return DPTX_CH_EN_MASK_8CH;
+	default:
+		return DPTX_CH_EN_MASK_2CH;
+	}
+}
+
+static unsigned int get_dptx_ch(unsigned int ch)
+{
+	if (ch == 2)
+		return DPTX_CHANNEL_2;
+
+	return DPTX_CHANNEL_8;
+}
+
+static unsigned int get_dptx_wlen(snd_pcm_format_t format)
+{
+	return snd_pcm_format_physical_width(format) <= 16 ?
+	       DPTX_WLEN_16_BIT : DPTX_WLEN_24_BIT;
+}
+
+/* interconnection */
+enum {
+	HDMI_CONN_CH0 = 0,
+	HDMI_CONN_CH1,
+	HDMI_CONN_CH2,
+	HDMI_CONN_CH3,
+	HDMI_CONN_CH4,
+	HDMI_CONN_CH5,
+	HDMI_CONN_CH6,
+	HDMI_CONN_CH7,
+};
+
+static const char *const hdmi_conn_mux_map[] = {
+	"CH0", "CH1", "CH2", "CH3",
+	"CH4", "CH5", "CH6", "CH7",
+};
+
+static int hdmi_conn_mux_map_value[] = {
+	HDMI_CONN_CH0,
+	HDMI_CONN_CH1,
+	HDMI_CONN_CH2,
+	HDMI_CONN_CH3,
+	HDMI_CONN_CH4,
+	HDMI_CONN_CH5,
+	HDMI_CONN_CH6,
+	HDMI_CONN_CH7,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum,
+				  AFE_HDMI_CONN0,
+				  HDMI_O_0_SFT,
+				  HDMI_O_0_MASK,
+				  hdmi_conn_mux_map,
+				  hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch0_mux_control =
+	SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum,
+				  AFE_HDMI_CONN0,
+				  HDMI_O_1_SFT,
+				  HDMI_O_1_MASK,
+				  hdmi_conn_mux_map,
+				  hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch1_mux_control =
+	SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum,
+				  AFE_HDMI_CONN0,
+				  HDMI_O_2_SFT,
+				  HDMI_O_2_MASK,
+				  hdmi_conn_mux_map,
+				  hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch2_mux_control =
+	SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum,
+				  AFE_HDMI_CONN0,
+				  HDMI_O_3_SFT,
+				  HDMI_O_3_MASK,
+				  hdmi_conn_mux_map,
+				  hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch3_mux_control =
+	SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum,
+				  AFE_HDMI_CONN0,
+				  HDMI_O_4_SFT,
+				  HDMI_O_4_MASK,
+				  hdmi_conn_mux_map,
+				  hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch4_mux_control =
+	SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum,
+				  AFE_HDMI_CONN0,
+				  HDMI_O_5_SFT,
+				  HDMI_O_5_MASK,
+				  hdmi_conn_mux_map,
+				  hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch5_mux_control =
+	SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum,
+				  AFE_HDMI_CONN0,
+				  HDMI_O_6_SFT,
+				  HDMI_O_6_MASK,
+				  hdmi_conn_mux_map,
+				  hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch6_mux_control =
+	SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum,
+				  AFE_HDMI_CONN0,
+				  HDMI_O_7_SFT,
+				  HDMI_O_7_MASK,
+				  hdmi_conn_mux_map,
+				  hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch7_mux_control =
+	SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum);
+
+static const char *const tdm_out_mux_map[] = {
+	"Disconnect", "Connect",
+};
+
+static int tdm_out_mux_map_value[] = {
+	0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(hdmi_out_mux_map_enum,
+					      SND_SOC_NOPM,
+					      0,
+					      1,
+					      tdm_out_mux_map,
+					      tdm_out_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_out_mux_control =
+	SOC_DAPM_ENUM("HDMI_OUT_MUX", hdmi_out_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(dptx_out_mux_map_enum,
+					      SND_SOC_NOPM,
+					      0,
+					      1,
+					      tdm_out_mux_map,
+					      tdm_out_mux_map_value);
+
+static const struct snd_kcontrol_new dptx_out_mux_control =
+	SOC_DAPM_ENUM("DPTX_OUT_MUX", dptx_out_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(dptx_virtual_out_mux_map_enum,
+					      SND_SOC_NOPM,
+					      0,
+					      1,
+					      tdm_out_mux_map,
+					      tdm_out_mux_map_value);
+
+static const struct snd_kcontrol_new dptx_virtual_out_mux_control =
+	SOC_DAPM_ENUM("DPTX_VIRTUAL_OUT_MUX", dptx_virtual_out_mux_map_enum);
+
+static int get_tdm_id_by_name(const char *name)
+{
+	if (strstr(name, "DPTX"))
+		return MT8189_DAI_TDM_DPTX;
+
+	return MT8189_DAI_TDM;
+}
+
+static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol,
+				int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int dai_id = get_tdm_id_by_name(w->name);
+	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+	dev_dbg(cmpnt->dev, "name %s, event 0x%x, dai_id %d, bck: %d\n",
+		w->name, event, dai_id, tdm_priv->bck_rate);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8189_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		mt8189_mck_disable(afe, tdm_priv->bck_id);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol,
+				int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int dai_id = get_tdm_id_by_name(w->name);
+	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+	dev_dbg(cmpnt->dev, "name %s, event 0x%x, dai_id %d, mclk %d\n",
+		w->name, event, dai_id, tdm_priv->mclk_rate);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8189_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tdm_priv->mclk_rate = 0;
+		mt8189_mck_disable(afe, tdm_priv->mclk_id);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
+	SND_SOC_DAPM_MUX("HDMI_CH0_MUX", SND_SOC_NOPM, 0, 0,
+			 &hdmi_ch0_mux_control),
+	SND_SOC_DAPM_MUX("HDMI_CH1_MUX", SND_SOC_NOPM, 0, 0,
+			 &hdmi_ch1_mux_control),
+	SND_SOC_DAPM_MUX("HDMI_CH2_MUX", SND_SOC_NOPM, 0, 0,
+			 &hdmi_ch2_mux_control),
+	SND_SOC_DAPM_MUX("HDMI_CH3_MUX", SND_SOC_NOPM, 0, 0,
+			 &hdmi_ch3_mux_control),
+	SND_SOC_DAPM_MUX("HDMI_CH4_MUX", SND_SOC_NOPM, 0, 0,
+			 &hdmi_ch4_mux_control),
+	SND_SOC_DAPM_MUX("HDMI_CH5_MUX", SND_SOC_NOPM, 0, 0,
+			 &hdmi_ch5_mux_control),
+	SND_SOC_DAPM_MUX("HDMI_CH6_MUX", SND_SOC_NOPM, 0, 0,
+			 &hdmi_ch6_mux_control),
+	SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0,
+			 &hdmi_ch7_mux_control),
+	SND_SOC_DAPM_MUX("HDMI_OUT_MUX", SND_SOC_NOPM, 0, 0,
+			 &hdmi_out_mux_control),
+	SND_SOC_DAPM_MUX("DPTX_OUT_MUX", SND_SOC_NOPM, 0, 0,
+			 &dptx_out_mux_control),
+
+	SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_tdm_bck_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_tdm_mck_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("TDM_DPTX_BCK", SUPPLY_SEQ_TDM_DPTX_BCK_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_tdm_bck_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("TDM_DPTX_MCK", SUPPLY_SEQ_TDM_DPTX_MCK_EN,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_tdm_mck_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("TDM_CG", SUPPLY_SEQ_TDM_CG_EN,
+			      AUDIO_TOP_CON2, PDN_TDM_OUT_SFT, 1,
+			      NULL, 0),
+
+	SND_SOC_DAPM_MUX("DPTX_VIRTUAL_OUT_MUX",
+			 SND_SOC_NOPM, 0, 0, &dptx_virtual_out_mux_control),
+	SND_SOC_DAPM_OUTPUT("DPTX_VIRTUAL_OUT"),
+};
+
+static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
+				    struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_dapm_widget *w = sink;
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int dai_id = get_tdm_id_by_name(w->name);
+	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+	int cur_apll;
+
+	/* which apll */
+	cur_apll = mt8189_get_apll_by_name(afe, source->name);
+
+	return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {
+	{"HDMI_CH0_MUX", "CH0", "HDMI"},
+	{"HDMI_CH0_MUX", "CH1", "HDMI"},
+	{"HDMI_CH0_MUX", "CH2", "HDMI"},
+	{"HDMI_CH0_MUX", "CH3", "HDMI"},
+	{"HDMI_CH0_MUX", "CH4", "HDMI"},
+	{"HDMI_CH0_MUX", "CH5", "HDMI"},
+	{"HDMI_CH0_MUX", "CH6", "HDMI"},
+	{"HDMI_CH0_MUX", "CH7", "HDMI"},
+
+	{"HDMI_CH1_MUX", "CH0", "HDMI"},
+	{"HDMI_CH1_MUX", "CH1", "HDMI"},
+	{"HDMI_CH1_MUX", "CH2", "HDMI"},
+	{"HDMI_CH1_MUX", "CH3", "HDMI"},
+	{"HDMI_CH1_MUX", "CH4", "HDMI"},
+	{"HDMI_CH1_MUX", "CH5", "HDMI"},
+	{"HDMI_CH1_MUX", "CH6", "HDMI"},
+	{"HDMI_CH1_MUX", "CH7", "HDMI"},
+
+	{"HDMI_CH2_MUX", "CH0", "HDMI"},
+	{"HDMI_CH2_MUX", "CH1", "HDMI"},
+	{"HDMI_CH2_MUX", "CH2", "HDMI"},
+	{"HDMI_CH2_MUX", "CH3", "HDMI"},
+	{"HDMI_CH2_MUX", "CH4", "HDMI"},
+	{"HDMI_CH2_MUX", "CH5", "HDMI"},
+	{"HDMI_CH2_MUX", "CH6", "HDMI"},
+	{"HDMI_CH2_MUX", "CH7", "HDMI"},
+
+	{"HDMI_CH3_MUX", "CH0", "HDMI"},
+	{"HDMI_CH3_MUX", "CH1", "HDMI"},
+	{"HDMI_CH3_MUX", "CH2", "HDMI"},
+	{"HDMI_CH3_MUX", "CH3", "HDMI"},
+	{"HDMI_CH3_MUX", "CH4", "HDMI"},
+	{"HDMI_CH3_MUX", "CH5", "HDMI"},
+	{"HDMI_CH3_MUX", "CH6", "HDMI"},
+	{"HDMI_CH3_MUX", "CH7", "HDMI"},
+
+	{"HDMI_CH4_MUX", "CH0", "HDMI"},
+	{"HDMI_CH4_MUX", "CH1", "HDMI"},
+	{"HDMI_CH4_MUX", "CH2", "HDMI"},
+	{"HDMI_CH4_MUX", "CH3", "HDMI"},
+	{"HDMI_CH4_MUX", "CH4", "HDMI"},
+	{"HDMI_CH4_MUX", "CH5", "HDMI"},
+	{"HDMI_CH4_MUX", "CH6", "HDMI"},
+	{"HDMI_CH4_MUX", "CH7", "HDMI"},
+
+	{"HDMI_CH5_MUX", "CH0", "HDMI"},
+	{"HDMI_CH5_MUX", "CH1", "HDMI"},
+	{"HDMI_CH5_MUX", "CH2", "HDMI"},
+	{"HDMI_CH5_MUX", "CH3", "HDMI"},
+	{"HDMI_CH5_MUX", "CH4", "HDMI"},
+	{"HDMI_CH5_MUX", "CH5", "HDMI"},
+	{"HDMI_CH5_MUX", "CH6", "HDMI"},
+	{"HDMI_CH5_MUX", "CH7", "HDMI"},
+
+	{"HDMI_CH6_MUX", "CH0", "HDMI"},
+	{"HDMI_CH6_MUX", "CH1", "HDMI"},
+	{"HDMI_CH6_MUX", "CH2", "HDMI"},
+	{"HDMI_CH6_MUX", "CH3", "HDMI"},
+	{"HDMI_CH6_MUX", "CH4", "HDMI"},
+	{"HDMI_CH6_MUX", "CH5", "HDMI"},
+	{"HDMI_CH6_MUX", "CH6", "HDMI"},
+	{"HDMI_CH6_MUX", "CH7", "HDMI"},
+
+	{"HDMI_CH7_MUX", "CH0", "HDMI"},
+	{"HDMI_CH7_MUX", "CH1", "HDMI"},
+	{"HDMI_CH7_MUX", "CH2", "HDMI"},
+	{"HDMI_CH7_MUX", "CH3", "HDMI"},
+	{"HDMI_CH7_MUX", "CH4", "HDMI"},
+	{"HDMI_CH7_MUX", "CH5", "HDMI"},
+	{"HDMI_CH7_MUX", "CH6", "HDMI"},
+	{"HDMI_CH7_MUX", "CH7", "HDMI"},
+
+	{"HDMI_OUT_MUX", "Connect", "HDMI_CH0_MUX"},
+	{"HDMI_OUT_MUX", "Connect", "HDMI_CH1_MUX"},
+	{"HDMI_OUT_MUX", "Connect", "HDMI_CH2_MUX"},
+	{"HDMI_OUT_MUX", "Connect", "HDMI_CH3_MUX"},
+	{"HDMI_OUT_MUX", "Connect", "HDMI_CH4_MUX"},
+	{"HDMI_OUT_MUX", "Connect", "HDMI_CH5_MUX"},
+	{"HDMI_OUT_MUX", "Connect", "HDMI_CH6_MUX"},
+	{"HDMI_OUT_MUX", "Connect", "HDMI_CH7_MUX"},
+
+	{"DPTX_OUT_MUX", "Connect", "HDMI_CH0_MUX"},
+	{"DPTX_OUT_MUX", "Connect", "HDMI_CH1_MUX"},
+	{"DPTX_OUT_MUX", "Connect", "HDMI_CH2_MUX"},
+	{"DPTX_OUT_MUX", "Connect", "HDMI_CH3_MUX"},
+	{"DPTX_OUT_MUX", "Connect", "HDMI_CH4_MUX"},
+	{"DPTX_OUT_MUX", "Connect", "HDMI_CH5_MUX"},
+	{"DPTX_OUT_MUX", "Connect", "HDMI_CH6_MUX"},
+	{"DPTX_OUT_MUX", "Connect", "HDMI_CH7_MUX"},
+
+	{"TDM", NULL, "HDMI_OUT_MUX"},
+	{"TDM", NULL, "TDM_BCK"},
+	{"TDM", NULL, "TDM_CG"},
+
+	{"TDM_DPTX", NULL, "DPTX_OUT_MUX"},
+	{"TDM_DPTX", NULL, "TDM_DPTX_BCK"},
+	{"TDM_DPTX", NULL, "TDM_CG"},
+
+	{"TDM_BCK", NULL, "TDM_MCK"},
+	{"TDM_DPTX_BCK", NULL, "TDM_DPTX_MCK"},
+	{"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
+	{"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
+	{"TDM_DPTX_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
+	{"TDM_DPTX_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
+
+	{"DPTX_VIRTUAL_OUT_MUX", "Connect", "TDM_DPTX"},
+	{"DPTX_VIRTUAL_OUT", NULL, "DPTX_VIRTUAL_OUT_MUX"},
+};
+
+/* dai ops */
+static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
+				struct mtk_afe_tdm_priv *tdm_priv,
+				int freq)
+{
+	int apll;
+	int apll_rate;
+
+	apll = mt8189_get_apll_by_rate(afe, freq);
+	apll_rate = mt8189_get_apll_rate(afe, apll);
+
+	if (freq > apll_rate)
+		return -EINVAL;
+
+	if (apll_rate % freq != 0)
+		return -EINVAL;
+
+	tdm_priv->mclk_rate = freq;
+	tdm_priv->mclk_apll = apll;
+
+	return 0;
+}
+
+static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	int tdm_id = dai->id;
+	struct mtk_afe_tdm_priv *tdm_priv;
+	unsigned int rate = params_rate(params);
+	unsigned int channels = params_channels(params);
+	snd_pcm_format_t format = params_format(params);
+	unsigned int tdm_con = 0;
+
+	if (tdm_id >= MT8189_DAI_NUM || tdm_id < 0)
+		return -EINVAL;
+
+	tdm_priv = afe_priv->dai_priv[tdm_id];
+
+	/* calculate mclk_rate, if not set explicitly */
+	if (!tdm_priv->mclk_rate) {
+		tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;
+		mtk_dai_tdm_cal_mclk(afe,
+				     tdm_priv,
+				     tdm_priv->mclk_rate);
+	}
+
+	/* calculate bck */
+	tdm_priv->bck_rate = rate *
+			     channels *
+			     snd_pcm_format_physical_width(format);
+
+	if (tdm_priv->bck_rate > tdm_priv->mclk_rate)
+		return -EINVAL;
+
+	if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0)
+		return -EINVAL;
+
+	dev_dbg(afe->dev, "id %d, rate %d, channels %d, format %d, mclk_rate %d, bck_rate %d\n",
+		tdm_id, rate, channels, format,
+		tdm_priv->mclk_rate, tdm_priv->bck_rate);
+
+	/* set tdm */
+	tdm_con |= 1 << LEFT_ALIGN_SFT;
+	tdm_con |= get_tdm_wlen(format) << WLEN_SFT;
+	tdm_con |= get_tdm_ch(channels) << CHANNEL_NUM_SFT;
+	tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT;
+	tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT;
+	regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con);
+
+	/* set dptx */
+	if (tdm_id == MT8189_DAI_TDM_DPTX) {
+		regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+				   DPTX_CHANNEL_ENABLE_MASK_SFT,
+				   get_dptx_ch_enable_mask(channels) <<
+				   DPTX_CHANNEL_ENABLE_SFT);
+		regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+				   DPTX_CHANNEL_NUMBER_MASK_SFT,
+				   get_dptx_ch(channels) <<
+				   DPTX_CHANNEL_NUMBER_SFT);
+		regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+				   DPTX_16BIT_MASK_SFT,
+				   get_dptx_wlen(format) << DPTX_16BIT_SFT);
+	}
+		switch (channels) {
+		case 1:
+		case 2:
+			tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+			tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;
+			tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
+			tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+			break;
+		case 3:
+		case 4:
+			tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+			tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+			tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
+			tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+			break;
+		case 5:
+		case 6:
+			tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+			tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+			tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
+			tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+			break;
+		case 7:
+		case 8:
+			tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+			tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+			tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
+			tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT;
+			break;
+		default:
+			tdm_con = 0;
+		}
+	regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con);
+	regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+			   HDMI_CH_NUM_MASK_SFT,
+			   channels << HDMI_CH_NUM_SFT);
+	return 0;
+}
+
+static int mtk_dai_tdm_trigger(struct snd_pcm_substream *substream,
+			       int cmd,
+			       struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	int tdm_id = dai->id;
+
+	dev_dbg(afe->dev, "%s(), cmd %d, tdm_id %d\n", __func__, cmd, tdm_id);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		/* enable Out control */
+		regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+				   HDMI_OUT_ON_MASK_SFT,
+				   0x1 << HDMI_OUT_ON_SFT);
+
+		/* enable dptx */
+		if (tdm_id == MT8189_DAI_TDM_DPTX) {
+			regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+					   DPTX_ON_MASK_SFT, 0x1 <<
+					   DPTX_ON_SFT);
+		}
+
+		/* enable tdm */
+		regmap_update_bits(afe->regmap, AFE_TDM_CON1,
+				   TDM_EN_MASK_SFT, 0x1 << TDM_EN_SFT);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		/* disable tdm */
+		regmap_update_bits(afe->regmap, AFE_TDM_CON1,
+				   TDM_EN_MASK_SFT, 0);
+
+		/* disable dptx */
+		if (tdm_id == MT8189_DAI_TDM_DPTX) {
+			regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+					   DPTX_ON_MASK_SFT, 0);
+		}
+
+		/* disable Out control */
+		regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+				   HDMI_OUT_ON_MASK_SFT, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_tdm_priv *tdm_priv;
+
+	if (dai->id >= MT8189_DAI_NUM || dai->id < 0)
+		return -EINVAL;
+
+	tdm_priv = afe_priv->dai_priv[dai->id];
+
+	if (!tdm_priv)
+		return -EINVAL;
+
+	if (dir != SND_SOC_CLOCK_OUT)
+		return -EINVAL;
+
+	dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+	return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
+}
+
+static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {
+	.hw_params = mtk_dai_tdm_hw_params,
+	.trigger = mtk_dai_tdm_trigger,
+	.set_sysclk = mtk_dai_tdm_set_sysclk,
+};
+
+/* dai driver */
+#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+		       SNDRV_PCM_RATE_88200 |\
+		       SNDRV_PCM_RATE_96000 |\
+		       SNDRV_PCM_RATE_176400 |\
+		       SNDRV_PCM_RATE_192000)
+
+#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {
+	{
+		.name = "TDM",
+		.id = MT8189_DAI_TDM,
+		.playback = {
+			.stream_name = "TDM",
+			.channels_min = 2,
+			.channels_max = 8,
+			.rates = MTK_TDM_RATES,
+			.formats = MTK_TDM_FORMATS,
+		},
+		.ops = &mtk_dai_tdm_ops,
+	},
+	{
+		.name = "TDM_DPTX",
+		.id = MT8189_DAI_TDM_DPTX,
+		.playback = {
+			.stream_name = "TDM_DPTX",
+			.channels_min = 2,
+			.channels_max = 8,
+			.rates = MTK_TDM_RATES,
+			.formats = MTK_TDM_FORMATS,
+		},
+		.ops = &mtk_dai_tdm_ops,
+	},
+};
+
+static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe,
+						   int id)
+{
+	struct mtk_afe_tdm_priv *tdm_priv;
+
+	tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
+				GFP_KERNEL);
+	if (!tdm_priv)
+		return NULL;
+
+	if (id == MT8189_DAI_TDM_DPTX)
+		tdm_priv->mclk_multiple = 256;
+	else
+		tdm_priv->mclk_multiple = 128;
+
+	tdm_priv->bck_id = MT8189_TDMOUT_BCK;
+	tdm_priv->mclk_id = MT8189_TDMOUT_MCK;
+
+	return tdm_priv;
+}
+
+int mt8189_dai_tdm_register(struct mtk_base_afe *afe)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_tdm_priv *tdm_priv, *tdm_dptx_priv;
+	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_tdm_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
+
+	dai->dapm_widgets = mtk_dai_tdm_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
+	dai->dapm_routes = mtk_dai_tdm_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
+
+	tdm_priv = init_tdm_priv_data(afe, MT8189_DAI_TDM);
+	if (!tdm_priv)
+		return -ENOMEM;
+
+	tdm_dptx_priv = init_tdm_priv_data(afe, MT8189_DAI_TDM_DPTX);
+	if (!tdm_dptx_priv)
+		return -ENOMEM;
+
+	afe_priv->dai_priv[MT8189_DAI_TDM] = tdm_priv;
+	afe_priv->dai_priv[MT8189_DAI_TDM_DPTX] = tdm_dptx_priv;
+
+	return 0;
+}
-- 
2.46.0



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

* [PATCH 06/10] ASoC: mediatek: mt8189: support PCM in platform driver
  2025-06-28  7:14 [PATCH 00/10] ASoC: mediatek: Add support for MT8189 SoC Cyril
                   ` (3 preceding siblings ...)
  2025-06-28  7:14 ` [PATCH 05/10] ASoC: mediatek: mt8189: support TDM " Cyril
@ 2025-06-28  7:14 ` Cyril
  2025-06-28  7:14 ` [PATCH 07/10] ASoC: mediatek: mt8189: add " Cyril
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Cyril @ 2025-06-28  7:14 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group, cyril.chao,
	Cyril Chao

From: Cyril Chao <Cyril.Chao@mediatek.com>

Add mt8189 PCM DAI driver support.

Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
---
 sound/soc/mediatek/mt8189/mt8189-dai-pcm.c | 337 +++++++++++++++++++++
 1 file changed, 337 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-dai-pcm.c

diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-pcm.c b/sound/soc/mediatek/mt8189/mt8189-dai-pcm.c
new file mode 100644
index 000000000..f26e1fb21
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-dai-pcm.c
@@ -0,0 +1,337 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  MediaTek ALSA SoC Audio DAI I2S Control
+ *
+ *  Copyright (c) 2025 MediaTek Inc.
+ *  Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8189-afe-common.h"
+#include "mt8189-interconnection.h"
+#include "mt8189-afe-clk.h"
+
+enum AUD_TX_LCH_RPT {
+	AUD_TX_LCH_RPT_NO_REPEAT = 0,
+	AUD_TX_LCH_RPT_REPEAT = 1
+};
+
+enum AUD_VBT_16K_MODE {
+	AUD_VBT_16K_MODE_DISABLE = 0,
+	AUD_VBT_16K_MODE_ENABLE = 1
+};
+
+enum AUD_EXT_MODEM {
+	AUD_EXT_MODEM_SELECT_INTERNAL = 0,
+	AUD_EXT_MODEM_SELECT_EXTERNAL = 1
+};
+
+enum AUD_PCM_SYNC_TYPE {
+	/* bck sync length = 1 */
+	AUD_PCM_ONE_BCK_CYCLE_SYNC = 0,
+	/* bck sync length = PCM_INTF_CON1[9:13] */
+	AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1
+};
+
+enum AUD_BT_MODE {
+	AUD_BT_MODE_DUAL_MIC_ON_TX = 0,
+	AUD_BT_MODE_SINGLE_MIC_ON_TX = 1
+};
+
+enum AUD_PCM_AFIFO_SRC {
+	/* slave mode & external modem uses different crystal */
+	AUD_PCM_AFIFO_ASRC = 0,
+	/* slave mode & external modem uses the same crystal */
+	AUD_PCM_AFIFO_AFIFO = 1
+};
+
+enum AUD_PCM_CLOCK_SOURCE {
+	AUD_PCM_CLOCK_MASTER_MODE = 0,
+	AUD_PCM_CLOCK_SLAVE_MODE = 1
+};
+
+enum AUD_PCM_WLEN {
+	AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0,
+	AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1
+};
+
+enum AUD_PCM_MODE {
+	AUD_PCM_MODE_PCM_MODE_8K = 0,
+	AUD_PCM_MODE_PCM_MODE_16K = 1,
+	AUD_PCM_MODE_PCM_MODE_32K = 2,
+	AUD_PCM_MODE_PCM_MODE_48K = 3,
+};
+
+enum AUD_PCM_FMT {
+	AUD_PCM_FMT_I2S = 0,
+	AUD_PCM_FMT_EIAJ = 1,
+	AUD_PCM_FMT_PCM_MODE_A = 2,
+	AUD_PCM_FMT_PCM_MODE_B = 3
+};
+
+enum AUD_BCLK_OUT_INV {
+	AUD_BCLK_OUT_INV_NO_INVERSE = 0,
+	AUD_BCLK_OUT_INV_INVERSE = 1
+};
+
+enum AUD_PCM_EN {
+	AUD_PCM_EN_DISABLE = 0,
+	AUD_PCM_EN_ENABLE = 1
+};
+
+enum AUD_PCM1_1x_EN_DOMAIN {
+	HOPPING_26M = 0,
+	APLL = 1,
+	SLAVE = 6,
+};
+
+enum AUD_PCM1_1x_EN_SLAVE_MODE {
+	PCM0_SLAVE_1x_EN = 1,
+	PCM1_SLAVE_1x_EN = 2,
+};
+
+enum {
+	PCM_8K = 0,
+	PCM_16K = 4,
+	PCM_32K = 8,
+	PCM_48K = 10
+};
+
+static unsigned int pcm_1x_rate_transform(struct device *dev,
+					  unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return PCM_8K;
+	case 16000:
+		return PCM_16K;
+	case 32000:
+		return PCM_32K;
+	case 48000:
+		return PCM_48K;
+	default:
+		dev_warn(dev, "rate %u invalid, use %d!!!\n",
+			 rate, PCM_48K);
+		return PCM_48K;
+	}
+}
+
+static unsigned int pcm_rate_transform(struct device *dev,
+				       unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return MTK_AFE_PCM_RATE_8K;
+	case 16000:
+		return MTK_AFE_PCM_RATE_16K;
+	case 32000:
+		return MTK_AFE_PCM_RATE_32K;
+	case 48000:
+		return MTK_AFE_PCM_RATE_48K;
+	default:
+		dev_warn(dev, "rate %u invalid, use %d\n",
+			 rate, MTK_AFE_PCM_RATE_48K);
+		return MTK_AFE_PCM_RATE_48K;
+	}
+}
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_pcm_0_playback_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN096_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN096_1,
+				    I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN096_1,
+				    I_DL_24CH_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_0_playback_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN097_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN097_1,
+				    I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN097_1,
+				    I_DL_24CH_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_0_playback_ch4_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH1", AFE_CONN099_4,
+				    I_I2SIN1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH2", AFE_CONN099_4,
+				    I_I2SIN1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN099_1,
+				    I_DL0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN099_1,
+				    I_DL_24CH_CH1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+	/* inter-connections */
+	SND_SOC_DAPM_MIXER("PCM_0_PB_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_pcm_0_playback_ch1_mix,
+			   ARRAY_SIZE(mtk_pcm_0_playback_ch1_mix)),
+	SND_SOC_DAPM_MIXER("PCM_0_PB_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_pcm_0_playback_ch2_mix,
+			   ARRAY_SIZE(mtk_pcm_0_playback_ch2_mix)),
+	SND_SOC_DAPM_MIXER("PCM_0_PB_CH4", SND_SOC_NOPM, 0, 0,
+			   mtk_pcm_0_playback_ch4_mix,
+			   ARRAY_SIZE(mtk_pcm_0_playback_ch4_mix)),
+
+	SND_SOC_DAPM_SUPPLY("PCM_0_EN",
+			    AFE_PCM0_INTF_CON0, PCM0_EN_SFT, 0,
+			    NULL,
+			    0),
+
+	SND_SOC_DAPM_SUPPLY("PCM0_CG", AUDIO_TOP_CON0, PDN_PCM0_SFT, 1,
+			    NULL, 0),
+
+	SND_SOC_DAPM_INPUT("MD1_TO_AFE"),
+	SND_SOC_DAPM_INPUT("MD2_TO_AFE"),
+	SND_SOC_DAPM_OUTPUT("AFE_TO_MD1"),
+	SND_SOC_DAPM_OUTPUT("AFE_TO_MD2"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+	{"PCM 0 Playback", NULL, "PCM_0_PB_CH1"},
+	{"PCM 0 Playback", NULL, "PCM_0_PB_CH2"},
+	{"PCM 0 Playback", NULL, "PCM_0_PB_CH4"},
+
+	{"PCM 0 Playback", NULL, "PCM_0_EN"},
+	{"PCM 0 Capture", NULL, "PCM_0_EN"},
+	{"PCM 0 Playback", NULL, "PCM0_CG"},
+	{"PCM 0 Capture", NULL, "PCM0_CG"},
+
+	{"AFE_TO_MD2", NULL, "PCM 0 Playback"},
+	{"PCM 0 Capture", NULL, "MD2_TO_AFE"},
+
+	{"PCM_0_PB_CH1", "DL2_CH1", "DL2"},
+	{"PCM_0_PB_CH2", "DL2_CH2", "DL2"},
+	{"PCM_0_PB_CH4", "DL0_CH1", "DL0"},
+
+	{"PCM_0_PB_CH1", "DL_24CH_CH1", "DL_24CH"},
+	{"PCM_0_PB_CH2", "DL_24CH_CH2", "DL_24CH"},
+	{"PCM_0_PB_CH4", "DL_24CH_CH1", "DL_24CH"},
+};
+
+/* dai ops */
+static int mtk_dai_pcm_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);
+	unsigned int rate = params_rate(params);
+	unsigned int rate_reg = pcm_rate_transform(afe->dev, rate);
+	unsigned int x_rate_reg = pcm_1x_rate_transform(afe->dev, rate);
+	unsigned int pcm_con0 = 0;
+	unsigned int pcm_con1 = 0;
+	unsigned int playback_active = 0;
+	unsigned int capture_active = 0;
+	struct snd_soc_dapm_widget *playback_widget =
+		snd_soc_dai_get_widget(dai, SNDRV_PCM_STREAM_PLAYBACK);
+	struct snd_soc_dapm_widget *capture_widget =
+		snd_soc_dai_get_widget(dai, SNDRV_PCM_STREAM_CAPTURE);
+
+	if (playback_widget)
+		playback_active = playback_widget->active;
+	if (capture_widget)
+		capture_active = capture_widget->active;
+	dev_dbg(afe->dev,
+		"id %d, stream %d, rate %d, rate_reg %d, widget active p %d, c %d\n",
+		dai->id,
+		substream->stream,
+		rate,
+		rate_reg,
+		playback_active,
+		capture_active);
+
+	if (playback_active || capture_active)
+		return 0;
+	switch (dai->id) {
+	case MT8189_DAI_PCM_0:
+		pcm_con0 |= AUD_BCLK_OUT_INV_NO_INVERSE << PCM0_BCLK_OUT_INV_SFT;
+		pcm_con0 |= AUD_TX_LCH_RPT_NO_REPEAT << PCM0_TX_LCH_RPT_SFT;
+		pcm_con0 |= AUD_VBT_16K_MODE_DISABLE << PCM0_VBT_16K_MODE_SFT;
+		pcm_con0 |= 0 << PCM0_SYNC_LENGTH_SFT;
+		pcm_con0 |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM0_SYNC_TYPE_SFT;
+		pcm_con0 |= AUD_PCM_AFIFO_AFIFO << PCM0_BYP_ASRC_SFT;
+		/* no pcm0 on IPM2.0 only for lpbk debug */
+		pcm_con0 |= AUD_PCM_CLOCK_MASTER_MODE << PCM0_SLAVE_SFT;
+		pcm_con0 |= rate_reg << PCM0_MODE_SFT;
+		pcm_con0 |= AUD_PCM_FMT_I2S << PCM0_FMT_SFT;
+
+		pcm_con1 |= AUD_EXT_MODEM_SELECT_INTERNAL << PCM0_EXT_MODEM_SFT;
+		pcm_con1 |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM0_BT_MODE_SFT;
+		pcm_con1 |= HOPPING_26M << PCM0_1X_EN_DOMAIN_SFT;
+		pcm_con1 |= x_rate_reg << PCM0_1X_EN_MODE_SFT;
+
+		regmap_update_bits(afe->regmap, AFE_PCM0_INTF_CON0,
+				   0xfffffffe, pcm_con0);
+		regmap_update_bits(afe->regmap, AFE_PCM0_INTF_CON1,
+				   0xffffffff, pcm_con1);
+		break;
+	default:
+		dev_err(afe->dev, "%s(), id %d not support\n",
+			__func__, dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
+	.hw_params = mtk_dai_pcm_hw_params,
+};
+
+/* dai driver */
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\
+		       SNDRV_PCM_RATE_16000 |\
+		       SNDRV_PCM_RATE_32000 |\
+		       SNDRV_PCM_RATE_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 = "PCM 0",
+		.id = MT8189_DAI_PCM_0,
+		.playback = {
+			.stream_name = "PCM 0 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.capture = {
+			.stream_name = "PCM 0 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,
+	},
+};
+
+int mt8189_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 0;
+}
-- 
2.46.0



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

* [PATCH 07/10] ASoC: mediatek: mt8189: add platform driver
  2025-06-28  7:14 [PATCH 00/10] ASoC: mediatek: Add support for MT8189 SoC Cyril
                   ` (4 preceding siblings ...)
  2025-06-28  7:14 ` [PATCH 06/10] ASoC: mediatek: mt8189: support PCM " Cyril
@ 2025-06-28  7:14 ` Cyril
  2025-06-28  7:14 ` [PATCH 08/10] ASoC: dt-bindings: mediatek,mt8189-afe-pcm: add audio afe document Cyril
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Cyril @ 2025-06-28  7:14 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group, cyril.chao,
	Cyril Chao

From: Cyril Chao <Cyril.Chao@mediatek.com>

Add mt8189 platform driver.

Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
---
 sound/soc/mediatek/Kconfig                 |   10 +
 sound/soc/mediatek/Makefile                |    1 +
 sound/soc/mediatek/mt8189/Makefile         |   15 +
 sound/soc/mediatek/mt8189/mt8189-afe-pcm.c | 2682 ++++++++++++++++++++
 4 files changed, 2708 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8189/Makefile
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-afe-pcm.c

diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 10ca8bcca..b28648e0d 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -246,6 +246,16 @@ config SND_SOC_MT8188_MT6359
 	  Select Y if you have such device.
 	  If unsure select "N".
 
+config SND_SOC_MT8189
+	tristate "ASoC support for Mediatek MT8189 chip"
+	depends on ARCH_MEDIATEK
+	select SND_SOC_MEDIATEK
+	help
+	  This adds ASoC driver for Mediatek MT8189 boards
+	  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 4b55434f2..7cd67bce9 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_SND_SOC_MT8188) += mt8188/
 obj-$(CONFIG_SND_SOC_MT8192) += mt8192/
 obj-$(CONFIG_SND_SOC_MT8195) += mt8195/
 obj-$(CONFIG_SND_SOC_MT8365) += mt8365/
+obj-$(CONFIG_SND_SOC_MT8189) += mt8189/
diff --git a/sound/soc/mediatek/mt8189/Makefile b/sound/soc/mediatek/mt8189/Makefile
new file mode 100644
index 000000000..795b1869b
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# common include path
+subdir-ccflags-y += -I$(srctree)/sound/soc/mediatek/common
+
+# platform driver
+snd-soc-mt8189-afe-objs += \
+	mt8189-afe-pcm.o \
+	mt8189-afe-clk.o \
+	mt8189-dai-adda.o \
+	mt8189-dai-i2s.o \
+	mt8189-dai-pcm.o \
+	mt8189-dai-tdm.o
+
+obj-$(CONFIG_SND_SOC_MT8189) += snd-soc-mt8189-afe.o
diff --git a/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c b/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c
new file mode 100644
index 000000000..cb942ecd5
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c
@@ -0,0 +1,2682 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Mediatek ALSA SoC AFE platform driver for 8189
+ *
+ *  Copyright (c) 2025 MediaTek Inc.
+ *  Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <linux/regmap.h>
+#include <linux/of_device.h>
+#include <linux/of_reserved_mem.h>
+
+#include "mt8189-afe-common.h"
+#include "mtk-afe-platform-driver.h"
+#include "mtk-afe-fe-dai.h"
+#include "mt8189-afe-clk.h"
+#include "mt8189-interconnection.h"
+
+static const struct snd_pcm_hardware mt8189_afe_hardware = {
+	.info = (SNDRV_PCM_INFO_MMAP |
+		 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+		 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 = 96,
+	.period_bytes_max = 4 * 48 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
+	.buffer_bytes_max = 256 * 1024,
+	.fifo_size = 0,
+};
+
+static unsigned int mt8189_rate_transform(struct device *dev, unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return MTK_AFE_IPM2P0_RATE_8K;
+	case 11025:
+		return MTK_AFE_IPM2P0_RATE_11K;
+	case 12000:
+		return MTK_AFE_IPM2P0_RATE_12K;
+	case 16000:
+		return MTK_AFE_IPM2P0_RATE_16K;
+	case 22050:
+		return MTK_AFE_IPM2P0_RATE_22K;
+	case 24000:
+		return MTK_AFE_IPM2P0_RATE_24K;
+	case 32000:
+		return MTK_AFE_IPM2P0_RATE_32K;
+	case 44100:
+		return MTK_AFE_IPM2P0_RATE_44K;
+	case 48000:
+		return MTK_AFE_IPM2P0_RATE_48K;
+	case 88200:
+		return MTK_AFE_IPM2P0_RATE_88K;
+	case 96000:
+		return MTK_AFE_IPM2P0_RATE_96K;
+	case 176400:
+		return MTK_AFE_IPM2P0_RATE_176K;
+	case 192000:
+		return MTK_AFE_IPM2P0_RATE_192K;
+	/* not support 260K */
+	case 352800:
+		return MTK_AFE_IPM2P0_RATE_352K;
+	case 384000:
+		return MTK_AFE_IPM2P0_RATE_384K;
+	default:
+		dev_warn(dev, "rate %u invalid, use %d!!!\n",
+			 rate, MTK_AFE_IPM2P0_RATE_48K);
+		return MTK_AFE_IPM2P0_RATE_48K;
+	}
+}
+
+static void mt8189_set_cm_rate(struct mtk_base_afe *afe, int id, unsigned int rate)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+	afe_priv->cm_rate[id] = rate;
+}
+
+static unsigned int calculate_cm_update(unsigned int rate, unsigned int ch)
+{
+	unsigned int update_val;
+
+	update_val = (((26000000 / rate) - 10) / (ch / 2)) - 1;
+
+	return update_val;
+}
+
+static int mt8189_set_cm(struct mtk_base_afe *afe, int id,
+			 bool update, bool swap, unsigned int ch)
+{
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	unsigned int rate = afe_priv->cm_rate[id];
+	unsigned int rate_val = mt8189_rate_transform(afe->dev, rate);
+	unsigned int update_val = update ? calculate_cm_update(rate, ch) : 0x64;
+	int reg = AFE_CM0_CON0 + 0x10 * id;
+
+	dev_dbg(afe->dev, "%s()-0, CM%d, rate %d, update %d, swap %d, ch %d\n",
+		__func__, id, rate, update, swap, ch);
+
+	/* update cnt */
+	regmap_update_bits(afe->regmap, reg,
+			   AFE_CM_UPDATE_CNT_MASK << AFE_CM_UPDATE_CNT_SFT,
+			   update_val << AFE_CM_UPDATE_CNT_SFT);
+
+	/* rate */
+	regmap_update_bits(afe->regmap, reg,
+			   AFE_CM_1X_EN_SEL_FS_MASK << AFE_CM_1X_EN_SEL_FS_SFT,
+			   rate_val << AFE_CM_1X_EN_SEL_FS_SFT);
+
+	/* ch num */
+	regmap_update_bits(afe->regmap, reg,
+			   AFE_CM_CH_NUM_MASK << AFE_CM_CH_NUM_SFT,
+			   (ch - 1) << AFE_CM_CH_NUM_SFT);
+
+	/* swap */
+	regmap_update_bits(afe->regmap, reg,
+			   AFE_CM_BYTE_SWAP_MASK << AFE_CM_BYTE_SWAP_SFT,
+			   swap << AFE_CM_BYTE_SWAP_SFT);
+
+	return 0;
+}
+
+static int mt8189_enable_cm_bypass(struct mtk_base_afe *afe, int id, bool en)
+{
+	int reg = AFE_CM0_CON0 + 0x10 * id;
+
+	regmap_update_bits(afe->regmap, reg,
+			   AFE_CM_BYPASS_MODE_MASK << AFE_CM_BYPASS_MODE_SFT,
+			   en << AFE_CM_BYPASS_MODE_SFT);
+
+	return 0;
+}
+
+static int mt8189_fe_startup(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+	int memif_num = cpu_dai->id;
+	struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+	const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware;
+	int ret;
+
+	dev_dbg(afe->dev, "%s(), memif_num: %d.\n", __func__, memif_num);
+
+	memif->substream = substream;
+
+	snd_pcm_hw_constraint_step(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
+
+	snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware);
+
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		dev_warn(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+
+	/* dynamic allocate irq to memif */
+	if (memif->irq_usage < 0) {
+		int irq_id = mtk_dynamic_irq_acquire(afe);
+
+		if (irq_id != afe->irqs_size) {
+			/* link */
+			memif->irq_usage = irq_id;
+		} else {
+			dev_err(afe->dev, "%s() error: no more asys irq\n",
+				__func__);
+			ret = -EBUSY;
+		}
+	}
+
+	return ret;
+}
+
+static void mt8189_fe_shutdown(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+	int memif_num = cpu_dai->id;
+	struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+	int irq_id = memif->irq_usage;
+
+	dev_dbg(afe->dev, "%s(), memif_num: %d.\n", __func__, memif_num);
+
+	memif->substream = NULL;
+	afe_priv->irq_cnt[memif_num] = 0;
+	afe_priv->xrun_assert[memif_num] = 0;
+
+	if (!memif->const_irq) {
+		mtk_dynamic_irq_release(afe, irq_id);
+		memif->irq_usage = -1;
+		memif->substream = NULL;
+	}
+}
+
+static int mt8189_fe_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);
+	unsigned int channels = params_channels(params);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+	afe_priv->cm_channels = channels;
+
+	return mtk_afe_fe_hw_params(substream, params, dai);
+}
+
+static int mt8189_fe_trigger(struct snd_pcm_substream *substream, int cmd,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct snd_pcm_runtime *const runtime = substream->runtime;
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8189_afe_private *afe_priv = afe->platform_priv;
+	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+	int id = cpu_dai->id;
+	struct mtk_base_afe_memif *memif = &afe->memif[id];
+	int irq_id = memif->irq_usage;
+	struct mtk_base_afe_irq *irqs = &afe->irqs[irq_id];
+	const struct mtk_base_irq_data *irq_data = irqs->irq_data;
+	unsigned int counter = runtime->period_size;
+	unsigned int rate = runtime->rate;
+	int fs;
+	int ret = 0;
+	unsigned int tmp_reg = 0;
+
+	dev_dbg(afe->dev, "%s(), %s cmd %d, irq_id %d, dai_id %d\n", __func__,
+		memif->data->name, cmd, irq_id, id);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		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;
+		}
+
+		/*
+		 * for small latency record
+		 * ul memif need read some data before irq enable
+		 */
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			if ((runtime->period_size * 1000) / rate <= 10)
+				udelay(300);
+		}
+
+		/* set irq counter */
+		if (afe_priv->irq_cnt[id] > 0)
+			counter = afe_priv->irq_cnt[id];
+
+		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);
+
+		/* enable interrupt */
+		regmap_update_bits(afe->regmap,
+				   irq_data->irq_en_reg,
+				   1 << irq_data->irq_en_shift,
+				   1 << irq_data->irq_en_shift);
+
+		return 0;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		ret = mtk_memif_set_disable(afe, id);
+		if (ret) {
+			dev_warn(afe->dev,
+				 "error, id %d, memif enable, ret %d\n",
+				 id, ret);
+		}
+
+		/* disable interrupt */
+		regmap_update_bits(afe->regmap,
+				   irq_data->irq_en_reg,
+				   1 << irq_data->irq_en_shift,
+				   0 << irq_data->irq_en_shift);
+
+		/* clear pending IRQ */
+		regmap_read(afe->regmap, irq_data->irq_clr_reg, &tmp_reg);
+		regmap_update_bits(afe->regmap, irq_data->irq_clr_reg,
+				   AFE_IRQ_CLR_CFG_MASK_SFT |
+				   AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT,
+				   tmp_reg ^ (AFE_IRQ_CLR_CFG_MASK_SFT |
+					      AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT));
+
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt8189_memif_fs(struct snd_pcm_substream *substream,
+			   unsigned int rate)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct snd_soc_component *component =
+		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = NULL;
+	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+	int id = cpu_dai->id;
+	unsigned int rate_reg = 0;
+	int cm = 0;
+
+	if (!component)
+		return -EINVAL;
+
+	afe = snd_soc_component_get_drvdata(component);
+
+	if (!afe)
+		return -EINVAL;
+
+	rate_reg = mt8189_rate_transform(afe->dev, rate);
+
+	switch (id) {
+	case MT8189_MEMIF_VUL8:
+	case MT8189_MEMIF_VUL_CM0:
+		cm = CM0;
+		break;
+	case MT8189_MEMIF_VUL9:
+	case MT8189_MEMIF_VUL_CM1:
+		cm = CM1;
+		break;
+	default:
+		cm = CM0;
+		break;
+	}
+
+	mt8189_set_cm_rate(afe, cm, rate);
+
+	return rate_reg;
+}
+
+static int mt8189_get_dai_fs(struct mtk_base_afe *afe,
+			     int dai_id, unsigned int rate)
+{
+	return mt8189_rate_transform(afe->dev, rate);
+}
+
+static int mt8189_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct snd_soc_component *component =
+		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = NULL;
+
+	if (!component)
+		return -EINVAL;
+	afe = snd_soc_component_get_drvdata(component);
+	return mt8189_rate_transform(afe->dev, rate);
+}
+
+static int mt8189_get_memif_pbuf_size(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if ((runtime->period_size * 1000) / runtime->rate > 10)
+		return MT8189_MEMIF_PBUF_SIZE_256_BYTES;
+
+	return MT8189_MEMIF_PBUF_SIZE_32_BYTES;
+}
+
+/* FE DAIs */
+static const struct snd_soc_dai_ops mt8189_memif_dai_ops = {
+	.startup        = mt8189_fe_startup,
+	.shutdown       = mt8189_fe_shutdown,
+	.hw_params      = mt8189_fe_hw_params,
+	.hw_free        = mtk_afe_fe_hw_free,
+	.prepare        = mtk_afe_fe_prepare,
+	.trigger        = mt8189_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)
+
+#define MTK_PCM_DAI_RATES (SNDRV_PCM_RATE_8000 |\
+			   SNDRV_PCM_RATE_16000 |\
+			   SNDRV_PCM_RATE_32000 |\
+			   SNDRV_PCM_RATE_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+#define MT8189_FE_DAI_PLAYBACK(_name, _id, max_ch) \
+{ \
+	.name = #_name, \
+	.id = _id, \
+	.playback = { \
+		.stream_name = #_name, \
+		.channels_min = 1, \
+		.channels_max = max_ch, \
+		.rates = MTK_PCM_RATES, \
+		.formats = MTK_PCM_FORMATS, \
+	}, \
+	.ops = &mt8189_memif_dai_ops, \
+}
+
+#define MT8189_FE_DAI_CAPTURE(_name, _id, max_ch) \
+{ \
+	.name = #_name, \
+	.id = _id, \
+	.capture = { \
+		.stream_name = #_name, \
+		.channels_min = 1, \
+		.channels_max = max_ch, \
+		.rates = MTK_PCM_RATES, \
+		.formats = MTK_PCM_FORMATS, \
+	}, \
+	.ops = &mt8189_memif_dai_ops, \
+}
+
+static struct snd_soc_dai_driver mt8189_memif_dai_driver[] = {
+	/* FE DAIs: memory interfaces to CPU */
+	/* Playback */
+	MT8189_FE_DAI_PLAYBACK(DL0, MT8189_MEMIF_DL0, 2),
+	MT8189_FE_DAI_PLAYBACK(DL1, MT8189_MEMIF_DL1, 2),
+	MT8189_FE_DAI_PLAYBACK(DL2, MT8189_MEMIF_DL2, 2),
+	MT8189_FE_DAI_PLAYBACK(DL3, MT8189_MEMIF_DL3, 2),
+	MT8189_FE_DAI_PLAYBACK(DL4, MT8189_MEMIF_DL4, 2),
+	MT8189_FE_DAI_PLAYBACK(DL5, MT8189_MEMIF_DL5, 2),
+	MT8189_FE_DAI_PLAYBACK(DL6, MT8189_MEMIF_DL6, 2),
+	MT8189_FE_DAI_PLAYBACK(DL7, MT8189_MEMIF_DL7, 2),
+	MT8189_FE_DAI_PLAYBACK(DL8, MT8189_MEMIF_DL8, 2),
+	MT8189_FE_DAI_PLAYBACK(DL23, MT8189_MEMIF_DL23, 2),
+	MT8189_FE_DAI_PLAYBACK(DL24, MT8189_MEMIF_DL24, 2),
+	MT8189_FE_DAI_PLAYBACK(DL25, MT8189_MEMIF_DL25, 2),
+	MT8189_FE_DAI_PLAYBACK(DL_24CH, MT8189_MEMIF_DL_24CH, 8),
+	MT8189_FE_DAI_PLAYBACK(HDMI, MT8189_MEMIF_HDMI, 8),
+	/* Capture */
+	MT8189_FE_DAI_CAPTURE(UL0, MT8189_MEMIF_VUL0, 2),
+	MT8189_FE_DAI_CAPTURE(UL1, MT8189_MEMIF_VUL1, 2),
+	MT8189_FE_DAI_CAPTURE(UL2, MT8189_MEMIF_VUL2, 2),
+	MT8189_FE_DAI_CAPTURE(UL3, MT8189_MEMIF_VUL3, 2),
+	MT8189_FE_DAI_CAPTURE(UL4, MT8189_MEMIF_VUL4, 2),
+	MT8189_FE_DAI_CAPTURE(UL5, MT8189_MEMIF_VUL5, 2),
+	MT8189_FE_DAI_CAPTURE(UL6, MT8189_MEMIF_VUL6, 2),
+	MT8189_FE_DAI_CAPTURE(UL7, MT8189_MEMIF_VUL7, 2),
+	MT8189_FE_DAI_CAPTURE(UL8, MT8189_MEMIF_VUL8, 2),
+	MT8189_FE_DAI_CAPTURE(UL9, MT8189_MEMIF_VUL9, 16),
+	MT8189_FE_DAI_CAPTURE(UL10, MT8189_MEMIF_VUL10, 2),
+	MT8189_FE_DAI_CAPTURE(UL24, MT8189_MEMIF_VUL24, 2),
+	MT8189_FE_DAI_CAPTURE(UL25, MT8189_MEMIF_VUL25, 2),
+	MT8189_FE_DAI_CAPTURE(UL_CM0, MT8189_MEMIF_VUL_CM0, 8),
+	MT8189_FE_DAI_CAPTURE(UL_CM1, MT8189_MEMIF_VUL_CM1, 16),
+	MT8189_FE_DAI_CAPTURE(UL_ETDM_IN0, MT8189_MEMIF_ETDM_IN0, 2),
+	MT8189_FE_DAI_CAPTURE(UL_ETDM_IN1, MT8189_MEMIF_ETDM_IN1, 2),
+};
+
+static int ul_cm0_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+	unsigned int channels = afe_priv->cm_channels;
+
+	dev_dbg(afe->dev, "%s(), event 0x%x, name %s, channels %d\n",
+		__func__, event, w->name, channels);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8189_enable_cm_bypass(afe, CM0, 0x0);
+		mt8189_set_cm(afe, CM0, true, false, channels);
+		regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+				   PDN_CM0_MASK_SFT, 0 << PDN_CM0_SFT);
+
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		mt8189_enable_cm_bypass(afe, CM0, 0x1);
+		regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+				   PDN_CM0_MASK_SFT, 1 << PDN_CM0_SFT);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int ul_cm1_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+	unsigned int channels = afe_priv->cm_channels;
+
+	dev_dbg(afe->dev, "%s(), event 0x%x, name %s, channels %d\n",
+		__func__, event, w->name, channels);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8189_enable_cm_bypass(afe, CM1, 0x0);
+		mt8189_set_cm(afe, CM1, true, false, channels);
+		regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+				   PDN_CM1_MASK_SFT, 0 << PDN_CM1_SFT);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		mt8189_enable_cm_bypass(afe, CM1, 0x1);
+		regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+				   PDN_CM1_MASK_SFT, 1 << PDN_CM1_SFT);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_kcontrol_new mt8189_pcm_kcontrols[] = {
+};
+
+/* dma widget & routes*/
+static const struct snd_kcontrol_new memif_ul0_ch1_mix[] = {
+	/* Normal record */
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN018_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN018_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN018_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN018_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	/* AP DMIC */
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH1", AFE_CONN018_0,
+				    I_DMIC0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH2", AFE_CONN018_0,
+				    I_DMIC0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN018_1,
+				    I_DL0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN018_1,
+				    I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN018_1,
+				    I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN018_1,
+				    I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN018_1,
+				    I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN018_1,
+				    I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN018_1,
+				    I_DL7_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL23_CH1", AFE_CONN018_2,
+				    I_DL23_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN018_1,
+				    I_DL_24CH_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN018_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH1", AFE_CONN018_4,
+				    I_I2SIN0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH1", AFE_CONN018_4,
+				    I_I2SIN1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN018_6,
+				    I_SRC_0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN018_6,
+				    I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul0_ch2_mix[] = {
+	/* Normal record */
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN019_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN019_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN019_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN019_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	/* AP DMIC */
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH2", AFE_CONN019_0,
+				    I_DMIC0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN019_1,
+				    I_DL0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN019_1,
+				    I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN019_1,
+				    I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN019_1,
+				    I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN019_1,
+				    I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN019_1,
+				    I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN019_1,
+				    I_DL7_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL23_CH2", AFE_CONN018_2,
+				    I_DL23_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN019_1,
+				    I_DL_24CH_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN019_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN019_4,
+				    I_PCM_0_CAP_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH2", AFE_CONN019_4,
+				    I_I2SIN0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH2", AFE_CONN019_4,
+				    I_I2SIN1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN019_6,
+				    I_SRC_0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN019_6,
+				    I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN020_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN020_1,
+				    I_DL0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN020_1,
+				    I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN020_1,
+				    I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN020_1,
+				    I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN020_1,
+				    I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN020_1,
+				    I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN020_1,
+				    I_DL7_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL23_CH1", AFE_CONN020_2,
+				    I_DL23_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN020_1,
+				    I_DL_24CH_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN020_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH1", AFE_CONN020_4,
+				    I_I2SIN0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH1", AFE_CONN020_4,
+				    I_I2SIN1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN020_6,
+				    I_SRC_0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN020_6,
+				    I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN021_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN021_1,
+				    I_DL0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN021_1,
+				    I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN021_1,
+				    I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN021_1,
+				    I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN021_1,
+				    I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN021_1,
+				    I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN021_1,
+				    I_DL7_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL23_CH2", AFE_CONN021_2,
+				    I_DL23_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN021_1,
+				    I_DL_24CH_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN021_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN021_4,
+				    I_PCM_0_CAP_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH2", AFE_CONN021_4,
+				    I_I2SIN0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH2", AFE_CONN021_4,
+				    I_I2SIN1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN021_6,
+				    I_SRC_0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN021_6,
+				    I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN022_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN022_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN022_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN022_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	/* AP DMIC */
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH3", AFE_CONN022_0,
+				    I_DMIC1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN1_OUT_CH1", AFE_CONN022_0,
+				    I_GAIN1_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN022_6,
+				    I_SRC_1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN023_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN023_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN023_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN023_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	/* AP DMIC */
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH4", AFE_CONN023_0,
+				    I_DMIC1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN1_OUT_CH2", AFE_CONN023_0,
+				    I_GAIN1_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN023_6,
+				    I_SRC_1_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN024_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH1", AFE_CONN024_4,
+				    I_I2SIN1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH1", AFE_CONN024_6,
+				    I_SRC_3_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN025_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH2", AFE_CONN025_4,
+				    I_I2SIN1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH2", AFE_CONN025_6,
+				    I_SRC_3_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul4_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN026_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN026_1,
+				    I_DL0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN026_1,
+				    I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN026_1,
+				    I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN026_1,
+				    I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN026_1,
+				    I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN026_1,
+				    I_DL_24CH_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN026_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN026_0,
+				    I_GAIN0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH1", AFE_CONN026_6,
+				    I_SRC_3_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul4_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN027_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN027_1,
+				    I_DL0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN027_1,
+				    I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN027_1,
+				    I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN027_1,
+				    I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN027_1,
+				    I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN027_1,
+				    I_DL_24CH_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN027_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN027_4,
+				    I_PCM_0_CAP_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN027_0,
+				    I_GAIN0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH2", AFE_CONN027_6,
+				    I_SRC_3_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul5_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN028_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN028_1,
+				    I_DL0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN028_1,
+				    I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN028_1,
+				    I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN028_1,
+				    I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN028_1,
+				    I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN028_1,
+				    I_DL_24CH_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN0_OUT_CH1", AFE_CONN028_0,
+				    I_GAIN0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH1", AFE_CONN028_6,
+				    I_SRC_3_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul5_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN029_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN029_1,
+				    I_DL0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN029_1,
+				    I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN029_1,
+				    I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN029_1,
+				    I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN029_1,
+				    I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN029_1,
+				    I_DL_24CH_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN029_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN029_4,
+				    I_PCM_0_CAP_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN0_OUT_CH2", AFE_CONN029_0,
+				    I_GAIN0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH2", AFE_CONN029_6,
+				    I_SRC_3_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul6_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN030_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH1", AFE_CONN030_0,
+				    I_DMIC0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN030_1,
+				    I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN030_1,
+				    I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH1", AFE_CONN030_4,
+				    I_I2SIN0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_4_OUT_CH1", AFE_CONN030_6,
+				    I_SRC_4_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul6_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN031_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH2", AFE_CONN031_0,
+				    I_DMIC0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN031_1,
+				    I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN031_1,
+				    I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH2", AFE_CONN031_4,
+				    I_I2SIN0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_4_OUT_CH2", AFE_CONN031_6,
+				    I_SRC_4_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul7_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN032_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN032_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH3", AFE_CONN032_0,
+				    I_DMIC1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN032_1,
+				    I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN032_1,
+				    I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH1", AFE_CONN032_4,
+				    I_I2SIN0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_4_OUT_CH1", AFE_CONN032_6,
+				    I_SRC_4_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul7_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN033_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN033_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH4", AFE_CONN033_0,
+				    I_DMIC1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN033_1,
+				    I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN033_1,
+				    I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH2", AFE_CONN033_4,
+				    I_I2SIN0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_4_OUT_CH2", AFE_CONN033_6,
+				    I_SRC_4_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul8_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN034_0,
+				    I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul8_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN035_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN035_4,
+				    I_PCM_0_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN035_4,
+				    I_PCM_0_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul9_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN036_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN036_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN036_0,
+				    I_ADDA_UL_CH3, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul9_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN037_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN037_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN037_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN037_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul24_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN066_0,
+				    I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul24_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN067_0,
+				    I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN040_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN040_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN040_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN040_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH1", AFE_CONN040_0,
+				    I_DMIC0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN1_OUT_CH1", AFE_CONN040_0,
+				    I_GAIN1_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN040_6,
+				    I_SRC_0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN040_6,
+				    I_SRC_1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN041_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN041_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN041_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN041_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH2", AFE_CONN041_0,
+				    I_DMIC0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN1_OUT_CH2", AFE_CONN041_0,
+				    I_GAIN1_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN041_6,
+				    I_SRC_0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN041_6,
+				    I_SRC_1_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch3_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN042_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN042_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN042_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN042_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH3", AFE_CONN042_0,
+				    I_DMIC1_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch4_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN043_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN043_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN043_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN043_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH4", AFE_CONN043_0,
+				    I_DMIC1_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch5_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN044_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN044_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN044_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN044_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch6_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN045_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN045_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN045_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN045_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch7_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN046_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN046_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN046_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN046_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch8_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN047_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN047_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN047_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN047_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN048_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN048_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN048_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN048_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN048_0,
+				    I_ADDA_UL_CH5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN048_0,
+				    I_ADDA_UL_CH6, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN048_6,
+				    I_SRC_0_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH1", AFE_CONN048_6,
+				    I_SRC_3_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_4_OUT_CH1", AFE_CONN048_6,
+				    I_SRC_4_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN049_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN049_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN049_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN049_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN049_0,
+				    I_ADDA_UL_CH5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN049_0,
+				    I_ADDA_UL_CH6, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN049_6,
+				    I_SRC_0_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH2", AFE_CONN049_6,
+				    I_SRC_3_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_4_OUT_CH2", AFE_CONN049_6,
+				    I_SRC_4_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch3_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN050_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN050_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN050_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN050_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN050_0,
+				    I_ADDA_UL_CH5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN050_0,
+				    I_ADDA_UL_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch4_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN051_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN051_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN051_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN051_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN051_0,
+				    I_ADDA_UL_CH5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN051_0,
+				    I_ADDA_UL_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch5_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN052_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN052_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN052_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN052_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN052_0,
+				    I_ADDA_UL_CH5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN052_0,
+				    I_ADDA_UL_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch6_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN053_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN053_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN053_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN053_0,
+				    I_ADDA_UL_CH4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN053_0,
+				    I_ADDA_UL_CH5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN053_0,
+				    I_ADDA_UL_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch7_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN054_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN054_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN054_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN054_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch8_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN055_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN055_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN055_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN055_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch9_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN056_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN056_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN056_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN056_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch10_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN057_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN057_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN057_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN057_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch11_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN058_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN058_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN058_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN058_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch12_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN059_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN059_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN059_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN059_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch13_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN060_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN060_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN060_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN060_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch14_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN061_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN061_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN061_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN061_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch15_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN062_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN062_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN062_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN062_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch16_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN063_0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN063_0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN063_0,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN063_0,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+enum {
+	CM0_MUX_VUL8_2CH,
+	CM0_MUX_VUL8_8CH,
+};
+
+enum {
+	CM1_MUX_VUL9_2CH,
+	CM1_MUX_VUL9_16CH,
+};
+
+static const char * const cm0_mux_map[] = {
+	"CM0_8CH_PATH",
+	"CM0_2CH_PATH",
+};
+
+static const char * const cm1_mux_map[] = {
+	"CM1_16CH_PATH",
+	"CM1_2CH_PATH",
+};
+
+static int cm0_mux_map_value[] = {
+	CM0_MUX_VUL8_8CH,
+	CM0_MUX_VUL8_2CH,
+};
+
+static int cm1_mux_map_value[] = {
+	CM1_MUX_VUL9_16CH,
+	CM1_MUX_VUL9_2CH,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(ul_cm0_mux_map_enum,
+				  AFE_CM0_CON0,
+				  AFE_CM0_OUTPUT_MUX_SFT,
+				  AFE_CM0_OUTPUT_MUX_MASK,
+				  cm0_mux_map,
+				  cm0_mux_map_value);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul_cm1_mux_map_enum,
+				  AFE_CM1_CON0,
+				  AFE_CM1_OUTPUT_MUX_SFT,
+				  AFE_CM1_OUTPUT_MUX_MASK,
+				  cm1_mux_map,
+				  cm1_mux_map_value);
+
+static const struct snd_kcontrol_new ul_cm0_mux_control =
+	SOC_DAPM_ENUM("CM0_UL_MUX Select", ul_cm0_mux_map_enum);
+static const struct snd_kcontrol_new ul_cm1_mux_control =
+	SOC_DAPM_ENUM("CM1_UL_MUX Select", ul_cm1_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mt8189_memif_widgets[] = {
+	/* inter-connections */
+	SND_SOC_DAPM_MIXER("UL0_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul0_ch1_mix, ARRAY_SIZE(memif_ul0_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL0_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul0_ch2_mix, ARRAY_SIZE(memif_ul0_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL1_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul1_ch1_mix, ARRAY_SIZE(memif_ul1_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL1_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul1_ch2_mix, ARRAY_SIZE(memif_ul1_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL2_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul2_ch1_mix, ARRAY_SIZE(memif_ul2_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL2_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul2_ch2_mix, ARRAY_SIZE(memif_ul2_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL3_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul3_ch1_mix, ARRAY_SIZE(memif_ul3_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL3_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul3_ch2_mix, ARRAY_SIZE(memif_ul3_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL4_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul4_ch1_mix, ARRAY_SIZE(memif_ul4_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL4_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul4_ch2_mix, ARRAY_SIZE(memif_ul4_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL5_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul5_ch1_mix, ARRAY_SIZE(memif_ul5_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL5_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul5_ch2_mix, ARRAY_SIZE(memif_ul5_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL6_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul6_ch1_mix, ARRAY_SIZE(memif_ul6_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL6_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul6_ch2_mix, ARRAY_SIZE(memif_ul6_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL7_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul7_ch1_mix, ARRAY_SIZE(memif_ul7_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL7_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul7_ch2_mix, ARRAY_SIZE(memif_ul7_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL8_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul8_ch1_mix, ARRAY_SIZE(memif_ul8_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL8_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul8_ch2_mix, ARRAY_SIZE(memif_ul8_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL9_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul9_ch1_mix, ARRAY_SIZE(memif_ul9_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL9_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul9_ch2_mix, ARRAY_SIZE(memif_ul9_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL24_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul24_ch1_mix, ARRAY_SIZE(memif_ul24_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL24_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul24_ch2_mix, ARRAY_SIZE(memif_ul24_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL_CM0_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm0_ch1_mix, ARRAY_SIZE(memif_ul_cm0_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM0_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm0_ch2_mix, ARRAY_SIZE(memif_ul_cm0_ch2_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM0_CH3", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm0_ch3_mix, ARRAY_SIZE(memif_ul_cm0_ch3_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM0_CH4", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm0_ch4_mix, ARRAY_SIZE(memif_ul_cm0_ch4_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM0_CH5", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm0_ch5_mix, ARRAY_SIZE(memif_ul_cm0_ch5_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM0_CH6", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm0_ch6_mix, ARRAY_SIZE(memif_ul_cm0_ch6_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM0_CH7", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm0_ch7_mix, ARRAY_SIZE(memif_ul_cm0_ch7_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM0_CH8", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm0_ch8_mix, ARRAY_SIZE(memif_ul_cm0_ch8_mix)),
+	SND_SOC_DAPM_MUX_E("CM0_UL_MUX", SND_SOC_NOPM, 0, 0,
+			   &ul_cm0_mux_control,
+			   ul_cm0_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MIXER("UL_CM1_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch1_mix, ARRAY_SIZE(memif_ul_cm1_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch2_mix, ARRAY_SIZE(memif_ul_cm1_ch2_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH3", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch3_mix, ARRAY_SIZE(memif_ul_cm1_ch3_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH4", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch4_mix, ARRAY_SIZE(memif_ul_cm1_ch4_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH5", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch5_mix, ARRAY_SIZE(memif_ul_cm1_ch5_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH6", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch6_mix, ARRAY_SIZE(memif_ul_cm1_ch6_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH7", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch7_mix, ARRAY_SIZE(memif_ul_cm1_ch7_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH8", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch8_mix, ARRAY_SIZE(memif_ul_cm1_ch8_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH9", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch9_mix, ARRAY_SIZE(memif_ul_cm1_ch9_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH10", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch10_mix, ARRAY_SIZE(memif_ul_cm1_ch10_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH11", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch11_mix, ARRAY_SIZE(memif_ul_cm1_ch11_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH12", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch12_mix, ARRAY_SIZE(memif_ul_cm1_ch12_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH13", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch13_mix, ARRAY_SIZE(memif_ul_cm1_ch13_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH14", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch14_mix, ARRAY_SIZE(memif_ul_cm1_ch14_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH15", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch15_mix, ARRAY_SIZE(memif_ul_cm1_ch15_mix)),
+	SND_SOC_DAPM_MIXER("UL_CM1_CH16", SND_SOC_NOPM, 0, 0,
+			   memif_ul_cm1_ch16_mix, ARRAY_SIZE(memif_ul_cm1_ch16_mix)),
+	SND_SOC_DAPM_MUX("CM1_UL_MUX", SND_SOC_NOPM, 0, 0,
+			 &ul_cm1_mux_control),
+	SND_SOC_DAPM_SUPPLY("CM0_Enable",
+			    AFE_CM0_CON0, AFE_CM0_ON_SFT, 0,
+			    ul_cm0_event,
+			    SND_SOC_DAPM_PRE_PMU |
+			    SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SUPPLY("CM1_Enable",
+			    AFE_CM1_CON0, AFE_CM0_ON_SFT, 0,
+			    ul_cm1_event,
+			    SND_SOC_DAPM_PRE_PMU |
+			    SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_INPUT("UL2_VIRTUAL_INPUT"),
+};
+
+static const struct snd_soc_dapm_route mt8189_memif_routes[] = {
+	{"UL0", NULL, "UL0_CH1"},
+	{"UL0", NULL, "UL0_CH2"},
+	/* Normal record */
+	{"UL0_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL0_CH1", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+	{"UL0_CH1", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+	{"UL0_CH1", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+	{"UL0_CH2", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL0_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+	{"UL0_CH2", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+	{"UL0_CH2", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+
+	{"UL0_CH1", "AP_DMIC_UL_CH1", "AP DMIC Capture"},
+	{"UL0_CH1", "AP_DMIC_UL_CH2", "AP DMIC Capture"},
+	{"UL0_CH2", "AP_DMIC_UL_CH2", "AP DMIC Capture"},
+
+	{"UL0_CH1", "I2SIN0_CH1", "I2SIN0"},
+	{"UL0_CH2", "I2SIN0_CH2", "I2SIN0"},
+	{"UL0_CH1", "I2SIN1_CH1", "I2SIN1"},
+	{"UL0_CH2", "I2SIN1_CH2", "I2SIN1"},
+
+	{"UL0_CH1", "PCM_0_CAP_CH1", "PCM 0 Capture"},
+	{"UL0_CH2", "PCM_0_CAP_CH1", "PCM 0 Capture"},
+
+	{"UL1", NULL, "UL1_CH1"},
+	{"UL1", NULL, "UL1_CH2"},
+
+	{"UL1_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL1_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+
+	{"UL1_CH1", "I2SIN0_CH1", "I2SIN0"},
+	{"UL1_CH2", "I2SIN0_CH2", "I2SIN0"},
+	{"UL1_CH1", "I2SIN1_CH1", "I2SIN1"},
+	{"UL1_CH2", "I2SIN1_CH2", "I2SIN1"},
+
+	{"UL1_CH1", "PCM_0_CAP_CH1", "PCM 0 Capture"},
+	{"UL1_CH2", "PCM_0_CAP_CH1", "PCM 0 Capture"},
+
+	{"UL2", NULL, "UL2_CH1"},
+	{"UL2", NULL, "UL2_CH2"},
+
+	{"UL2_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL2_CH1", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+	{"UL2_CH1", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+	{"UL2_CH1", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+	{"UL2_CH2", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL2_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+	{"UL2_CH2", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+	{"UL2_CH2", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+
+	{"UL2_CH1", "AP_DMIC_UL_CH3", "AP DMIC CH34 Capture"},
+	{"UL2_CH2", "AP_DMIC_UL_CH4", "AP DMIC CH34 Capture"},
+
+	{"UL3", NULL, "UL3_CH1"},
+	{"UL3", NULL, "UL3_CH2"},
+
+	{"UL3_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL3_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL3_CH1", "I2SIN1_CH1", "I2SIN1"},
+	{"UL3_CH2", "I2SIN1_CH2", "I2SIN1"},
+
+	{"UL4", NULL, "UL4_CH1"},
+	{"UL4", NULL, "UL4_CH2"},
+	{"UL4_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL4_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+	{"UL4_CH1", "PCM_0_CAP_CH1", "PCM 0 Capture"},
+	{"UL4_CH2", "PCM_0_CAP_CH1", "PCM 0 Capture"},
+
+	{"UL5", NULL, "UL5_CH1"},
+	{"UL5", NULL, "UL5_CH2"},
+
+	{"UL5_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL5_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+	{"UL6", NULL, "UL6_CH1"},
+	{"UL6", NULL, "UL6_CH2"},
+	{"UL6_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL6_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL6_CH1", "I2SIN0_CH1", "I2SIN0"},
+	{"UL6_CH2", "I2SIN0_CH2", "I2SIN0"},
+	{"UL6_CH1", "AP_DMIC_UL_CH1", "AP DMIC Capture"},
+	{"UL6_CH2", "AP_DMIC_UL_CH2", "AP DMIC Capture"},
+
+	{"UL7", NULL, "UL7_CH1"},
+	{"UL7", NULL, "UL7_CH2"},
+	{"UL7_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL7_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL7_CH2", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL7_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL7_CH1", "I2SIN0_CH1", "I2SIN0"},
+	{"UL7_CH2", "I2SIN0_CH2", "I2SIN0"},
+	{"UL7_CH1", "AP_DMIC_UL_CH3", "AP DMIC CH34 Capture"},
+	{"UL7_CH2", "AP_DMIC_UL_CH4", "AP DMIC CH34 Capture"},
+
+	{"UL8", NULL, "CM0_UL_MUX"},
+	{"CM0_UL_MUX", "CM0_2CH_PATH", "UL8_CH1"},
+	{"CM0_UL_MUX", "CM0_2CH_PATH", "UL8_CH2"},
+	{"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH1"},
+	{"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH2"},
+	{"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH3"},
+	{"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH4"},
+	{"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH5"},
+	{"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH6"},
+	{"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH7"},
+	{"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH8"},
+	{"UL_CM0_CH1", NULL, "CM0_Enable"},
+	{"UL_CM0_CH2", NULL, "CM0_Enable"},
+	{"UL_CM0_CH3", NULL, "CM0_Enable"},
+	{"UL_CM0_CH4", NULL, "CM0_Enable"},
+	{"UL_CM0_CH5", NULL, "CM0_Enable"},
+	{"UL_CM0_CH6", NULL, "CM0_Enable"},
+	{"UL_CM0_CH7", NULL, "CM0_Enable"},
+	{"UL_CM0_CH8", NULL, "CM0_Enable"},
+
+	{"UL9", NULL, "CM1_UL_MUX"},
+	{"CM1_UL_MUX", "CM1_2CH_PATH", "UL9_CH1"},
+	{"CM1_UL_MUX", "CM1_2CH_PATH", "UL9_CH2"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH1"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH2"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH3"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH4"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH5"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH6"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH7"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH8"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH9"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH10"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH11"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH12"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH13"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH14"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH15"},
+	{"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH16"},
+
+	{"UL_CM1_CH1", NULL, "CM1_Enable"},
+	{"UL_CM1_CH2", NULL, "CM1_Enable"},
+	{"UL_CM1_CH3", NULL, "CM1_Enable"},
+	{"UL_CM1_CH4", NULL, "CM1_Enable"},
+	{"UL_CM1_CH5", NULL, "CM1_Enable"},
+	{"UL_CM1_CH6", NULL, "CM1_Enable"},
+	{"UL_CM1_CH7", NULL, "CM1_Enable"},
+	{"UL_CM1_CH8", NULL, "CM1_Enable"},
+	{"UL_CM1_CH9", NULL, "CM1_Enable"},
+	{"UL_CM1_CH10", NULL, "CM1_Enable"},
+	{"UL_CM1_CH11", NULL, "CM1_Enable"},
+	{"UL_CM1_CH12", NULL, "CM1_Enable"},
+	{"UL_CM1_CH13", NULL, "CM1_Enable"},
+	{"UL_CM1_CH14", NULL, "CM1_Enable"},
+	{"UL_CM1_CH15", NULL, "CM1_Enable"},
+	{"UL_CM1_CH16", NULL, "CM1_Enable"},
+
+	/* UL9 o36o37 <- ADDA */
+	{"UL9_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL9_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL9_CH2", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL9_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+	{"UL24", NULL, "UL24_CH1"},
+	{"UL24", NULL, "UL24_CH2"},
+	{"UL24_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+
+	{"UL_CM0", NULL, "UL_CM0_CH1"},
+	{"UL_CM0", NULL, "UL_CM0_CH2"},
+	{"UL_CM0", NULL, "UL_CM0_CH3"},
+	{"UL_CM0", NULL, "UL_CM0_CH4"},
+	{"UL_CM0", NULL, "UL_CM0_CH5"},
+	{"UL_CM0", NULL, "UL_CM0_CH6"},
+	{"UL_CM0", NULL, "UL_CM0_CH7"},
+	{"UL_CM0", NULL, "UL_CM0_CH8"},
+	{"UL_CM0_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL_CM0_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL_CM0_CH2", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL_CM0_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL_CM0_CH3", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL_CM0_CH3", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL_CM0_CH4", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL_CM0_CH4", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL_CM0_CH1", "AP_DMIC_UL_CH1", "AP DMIC Capture"},
+	{"UL_CM0_CH2", "AP_DMIC_UL_CH2", "AP DMIC Capture"},
+	{"UL_CM0_CH3", "AP_DMIC_UL_CH3", "AP DMIC CH34 Capture"},
+	{"UL_CM0_CH4", "AP_DMIC_UL_CH4", "AP DMIC CH34 Capture"},
+
+	{"UL_CM1", NULL, "UL_CM1_CH1"},
+	{"UL_CM1", NULL, "UL_CM1_CH2"},
+	{"UL_CM1", NULL, "UL_CM1_CH3"},
+	{"UL_CM1", NULL, "UL_CM1_CH4"},
+	{"UL_CM1", NULL, "UL_CM1_CH5"},
+	{"UL_CM1", NULL, "UL_CM1_CH6"},
+	{"UL_CM1", NULL, "UL_CM1_CH7"},
+	{"UL_CM1", NULL, "UL_CM1_CH8"},
+	{"UL_CM1", NULL, "UL_CM1_CH9"},
+	{"UL_CM1", NULL, "UL_CM1_CH10"},
+	{"UL_CM1", NULL, "UL_CM1_CH11"},
+	{"UL_CM1", NULL, "UL_CM1_CH12"},
+	{"UL_CM1", NULL, "UL_CM1_CH13"},
+	{"UL_CM1", NULL, "UL_CM1_CH14"},
+	{"UL_CM1", NULL, "UL_CM1_CH15"},
+	{"UL_CM1", NULL, "UL_CM1_CH16"},
+	{"UL_CM1_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL_CM1_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL_CM1_CH2", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL_CM1_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL_CM1_CH3", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL_CM1_CH3", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL_CM1_CH4", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL_CM1_CH4", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL_CM1_CH5", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL_CM1_CH5", "ADDA_UL_CH2", "ADDA Capture"},
+	{"UL_CM1_CH6", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL_CM1_CH6", "ADDA_UL_CH2", "ADDA Capture"},
+};
+
+#define MT8189_DL_MEMIF(_id) \
+	[MT8189_MEMIF_##_id] = { \
+		.name = #_id, \
+		.id = MT8189_MEMIF_##_id, \
+		.reg_ofs_base = AFE_##_id##_BASE, \
+		.reg_ofs_cur = AFE_##_id##_CUR, \
+		.reg_ofs_end = AFE_##_id##_END, \
+		.reg_ofs_base_msb = AFE_##_id##_BASE_MSB, \
+		.reg_ofs_cur_msb = AFE_##_id##_CUR_MSB, \
+		.reg_ofs_end_msb = AFE_##_id##_END_MSB, \
+		.fs_reg = AFE_##_id##_CON0, \
+		.fs_shift = _id##_SEL_FS_SFT, \
+		.fs_maskbit = _id##_SEL_FS_MASK, \
+		.mono_reg = AFE_##_id##_CON0, \
+		.mono_shift = _id##_MONO_SFT, \
+		.enable_reg = AFE_##_id##_CON0, \
+		.enable_shift = _id##_ON_SFT, \
+		.hd_reg = AFE_##_id##_CON0, \
+		.hd_shift = _id##_HD_MODE_SFT, \
+		.hd_align_reg = AFE_##_id##_CON0, \
+		.hd_align_mshift = _id##_HALIGN_SFT, \
+		.agent_disable_reg = -1, \
+		.agent_disable_shift = -1, \
+		.msb_reg = -1, \
+		.msb_shift = -1, \
+		.pbuf_reg = AFE_##_id##_CON0, \
+		.pbuf_mask = _id##_PBUF_SIZE_MASK, \
+		.pbuf_shift = _id##_PBUF_SIZE_SFT, \
+		.minlen_reg = AFE_##_id##_CON0, \
+		.minlen_mask = _id##_MINLEN_MASK, \
+		.minlen_shift = _id##_MINLEN_SFT, \
+}
+
+#define MT8189_MULTI_DL_MEMIF(_id) \
+	[MT8189_MEMIF_##_id] = { \
+		.name = #_id, \
+		.id = MT8189_MEMIF_##_id, \
+		.reg_ofs_base = AFE_##_id##_BASE, \
+		.reg_ofs_cur = AFE_##_id##_CUR, \
+		.reg_ofs_end = AFE_##_id##_END, \
+		.reg_ofs_base_msb = AFE_##_id##_BASE_MSB, \
+		.reg_ofs_cur_msb = AFE_##_id##_CUR_MSB, \
+		.reg_ofs_end_msb = AFE_##_id##_END_MSB, \
+		.fs_reg = AFE_##_id##_CON0, \
+		.fs_shift = _id##_SEL_FS_SFT, \
+		.fs_maskbit = _id##_SEL_FS_MASK, \
+		.mono_reg = -1, \
+		.mono_shift = -1, \
+		.enable_reg = AFE_##_id##_CON0, \
+		.enable_shift = _id##_ON_SFT, \
+		.hd_reg = AFE_##_id##_CON0, \
+		.hd_shift = _id##_HD_MODE_SFT, \
+		.hd_align_reg = AFE_##_id##_CON0, \
+		.hd_align_mshift = _id##_HALIGN_SFT, \
+		.agent_disable_reg = -1, \
+		.agent_disable_shift = -1, \
+		.msb_reg = -1, \
+		.msb_shift = -1, \
+		.pbuf_reg = AFE_##_id##_CON0, \
+		.pbuf_mask = _id##_PBUF_SIZE_MASK, \
+		.pbuf_shift = _id##_PBUF_SIZE_SFT, \
+		.minlen_reg = AFE_##_id##_CON0, \
+		.minlen_mask = _id##_MINLEN_MASK, \
+		.minlen_shift = _id##_MINLEN_SFT, \
+		.ch_num_reg = AFE_##_id##_CON0, \
+		.ch_num_maskbit = _id##_NUM_MASK, \
+		.ch_num_shift = _id##_NUM_SFT, \
+}
+
+#define MT8189_UL_MEMIF(_id, _fs_shift, _fs_maskbit, _mono_shift) \
+	[MT8189_MEMIF_##_id] = { \
+		.name = #_id, \
+		.id = MT8189_MEMIF_##_id, \
+		.reg_ofs_base = AFE_##_id##_BASE, \
+		.reg_ofs_cur = AFE_##_id##_CUR, \
+		.reg_ofs_end = AFE_##_id##_END, \
+		.reg_ofs_base_msb = AFE_##_id##_BASE_MSB, \
+		.reg_ofs_cur_msb = AFE_##_id##_CUR_MSB, \
+		.reg_ofs_end_msb = AFE_##_id##_END_MSB, \
+		.fs_reg = AFE_##_id##_CON0, \
+		.fs_shift = _fs_shift, \
+		.fs_maskbit = _fs_maskbit, \
+		.mono_reg = AFE_##_id##_CON0, \
+		.mono_shift = _mono_shift, \
+		.enable_reg = AFE_##_id##_CON0, \
+		.enable_shift = _id##_ON_SFT, \
+		.hd_reg = AFE_##_id##_CON0, \
+		.hd_shift = _id##_HD_MODE_SFT, \
+		.hd_align_reg = AFE_##_id##_CON0, \
+		.hd_align_mshift = _id##_HALIGN_SFT, \
+		.agent_disable_reg = -1, \
+		.agent_disable_shift = -1, \
+		.msb_reg = -1, \
+		.msb_shift = -1, \
+	}
+
+/* For convenience with macros: missing register fields */
+#define HDMI_SEL_FS_SFT			-1
+#define HDMI_SEL_FS_MASK		-1
+
+/* For convenience with macros: register name differences */
+#define AFE_HDMI_BASE			AFE_HDMI_OUT_BASE
+#define AFE_HDMI_CUR			AFE_HDMI_OUT_CUR
+#define AFE_HDMI_END			AFE_HDMI_OUT_END
+#define AFE_HDMI_BASE_MSB		AFE_HDMI_OUT_BASE_MSB
+#define AFE_HDMI_CUR_MSB		AFE_HDMI_OUT_CUR_MSB
+#define AFE_HDMI_END_MSB		AFE_HDMI_OUT_END_MSB
+#define AFE_HDMI_CON0			AFE_HDMI_OUT_CON0
+#define HDMI_ON_SFT			HDMI_OUT_ON_SFT
+#define HDMI_HD_MODE_SFT		HDMI_OUT_HD_MODE_SFT
+#define HDMI_HALIGN_SFT			HDMI_OUT_HALIGN_SFT
+#define HDMI_PBUF_SIZE_MASK		HDMI_OUT_PBUF_SIZE_MASK
+#define HDMI_PBUF_SIZE_SFT		HDMI_OUT_PBUF_SIZE_SFT
+#define HDMI_MINLEN_MASK		HDMI_OUT_MINLEN_MASK
+#define HDMI_MINLEN_SFT			HDMI_OUT_MINLEN_SFT
+#define HDMI_NUM_MASK			HDMI_CH_NUM_MASK
+#define HDMI_NUM_SFT			HDMI_CH_NUM_SFT
+
+static const struct mtk_base_memif_data memif_data[MT8189_MEMIF_NUM] = {
+	MT8189_DL_MEMIF(DL0),
+	MT8189_DL_MEMIF(DL1),
+	MT8189_DL_MEMIF(DL2),
+	MT8189_DL_MEMIF(DL3),
+	MT8189_DL_MEMIF(DL4),
+	MT8189_DL_MEMIF(DL5),
+	MT8189_DL_MEMIF(DL6),
+	MT8189_DL_MEMIF(DL7),
+	MT8189_DL_MEMIF(DL8),
+	MT8189_DL_MEMIF(DL23),
+	MT8189_DL_MEMIF(DL24),
+	MT8189_DL_MEMIF(DL25),
+	MT8189_MULTI_DL_MEMIF(DL_24CH),
+	MT8189_MULTI_DL_MEMIF(HDMI),
+	MT8189_UL_MEMIF(VUL0, VUL0_SEL_FS_SFT, VUL0_SEL_FS_MASK, VUL0_MONO_SFT),
+	MT8189_UL_MEMIF(VUL1, VUL1_SEL_FS_SFT, VUL1_SEL_FS_MASK, VUL1_MONO_SFT),
+	MT8189_UL_MEMIF(VUL2, VUL2_SEL_FS_SFT, VUL2_SEL_FS_MASK, VUL2_MONO_SFT),
+	MT8189_UL_MEMIF(VUL3, VUL3_SEL_FS_SFT, VUL3_SEL_FS_MASK, VUL3_MONO_SFT),
+	MT8189_UL_MEMIF(VUL4, VUL4_SEL_FS_SFT, VUL4_SEL_FS_MASK, VUL4_MONO_SFT),
+	MT8189_UL_MEMIF(VUL5, VUL5_SEL_FS_SFT, VUL5_SEL_FS_MASK, VUL5_MONO_SFT),
+	MT8189_UL_MEMIF(VUL6, VUL6_SEL_FS_SFT, VUL6_SEL_FS_MASK, VUL6_MONO_SFT),
+	MT8189_UL_MEMIF(VUL7, VUL7_SEL_FS_SFT, VUL7_SEL_FS_MASK, VUL7_MONO_SFT),
+	MT8189_UL_MEMIF(VUL8, VUL8_SEL_FS_SFT, VUL8_SEL_FS_MASK, VUL8_MONO_SFT),
+	MT8189_UL_MEMIF(VUL9, VUL9_SEL_FS_SFT, VUL9_SEL_FS_MASK, VUL9_MONO_SFT),
+	MT8189_UL_MEMIF(VUL10, VUL10_SEL_FS_SFT, VUL10_SEL_FS_MASK, VUL10_MONO_SFT),
+	MT8189_UL_MEMIF(VUL24, VUL24_SEL_FS_SFT, VUL24_SEL_FS_MASK, VUL24_MONO_SFT),
+	MT8189_UL_MEMIF(VUL25, VUL25_SEL_FS_SFT, VUL25_SEL_FS_MASK, VUL25_MONO_SFT),
+	MT8189_UL_MEMIF(VUL_CM0, -1, -1, -1),
+	MT8189_UL_MEMIF(VUL_CM1, -1, -1, -1),
+	MT8189_UL_MEMIF(ETDM_IN0, REG_FS_TIMING_SEL_SFT, REG_FS_TIMING_SEL_MASK, -1),
+	MT8189_UL_MEMIF(ETDM_IN1, REG_FS_TIMING_SEL_SFT, REG_FS_TIMING_SEL_MASK, -1),
+};
+
+#define MT8189_AFE_IRQ(_id)	\
+	[MT8189_IRQ_##_id] = { \
+		.id = MT8189_IRQ_##_id, \
+		.irq_cnt_reg = AFE_IRQ##_id##_MCU_CFG1, \
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT, \
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK, \
+		.irq_fs_reg = AFE_IRQ##_id##_MCU_CFG0, \
+		.irq_fs_shift = AFE_IRQ##_id##_MCU_FS_SFT, \
+		.irq_fs_maskbit = AFE_IRQ##_id##_MCU_FS_MASK, \
+		.irq_en_reg = AFE_IRQ##_id##_MCU_CFG0, \
+		.irq_en_shift = AFE_IRQ##_id##_MCU_ON_SFT, \
+		.irq_clr_reg = AFE_IRQ##_id##_MCU_CFG1, \
+		.irq_clr_shift = AFE_IRQ##_id##_CLR_CFG_SFT, \
+	}
+
+#define MT8189_AFE_TDM_IRQ(_id)	\
+	[MT8189_IRQ_##_id] = { \
+		.id = MT8189_CUS_IRQ_TDM, \
+		.irq_cnt_reg = AFE_CUSTOM_IRQ0_MCU_CFG1, \
+		.irq_cnt_shift = AFE_CUSTOM_IRQ0_MCU_CNT_SFT, \
+		.irq_cnt_maskbit = AFE_CUSTOM_IRQ0_MCU_CNT_MASK, \
+		.irq_fs_reg = -1, \
+		.irq_fs_shift = -1, \
+		.irq_fs_maskbit = -1, \
+		.irq_en_reg = AFE_CUSTOM_IRQ0_MCU_CFG0, \
+		.irq_en_shift = AFE_CUSTOM_IRQ0_MCU_ON_SFT, \
+		.irq_clr_reg = AFE_CUSTOM_IRQ0_MCU_CFG1, \
+		.irq_clr_shift = AFE_CUSTOM_IRQ0_CLR_CFG_SFT, \
+	}
+
+static const struct mtk_base_irq_data irq_data[MT8189_IRQ_NUM] = {
+	MT8189_AFE_IRQ(0),
+	MT8189_AFE_IRQ(1),
+	MT8189_AFE_IRQ(2),
+	MT8189_AFE_IRQ(3),
+	MT8189_AFE_IRQ(4),
+	MT8189_AFE_IRQ(5),
+	MT8189_AFE_IRQ(6),
+	MT8189_AFE_IRQ(7),
+	MT8189_AFE_IRQ(8),
+	MT8189_AFE_IRQ(9),
+	MT8189_AFE_IRQ(10),
+	MT8189_AFE_IRQ(11),
+	MT8189_AFE_IRQ(12),
+	MT8189_AFE_IRQ(13),
+	MT8189_AFE_IRQ(14),
+	MT8189_AFE_IRQ(15),
+	MT8189_AFE_IRQ(16),
+	MT8189_AFE_IRQ(17),
+	MT8189_AFE_IRQ(18),
+	MT8189_AFE_IRQ(19),
+	MT8189_AFE_IRQ(20),
+	MT8189_AFE_IRQ(21),
+	MT8189_AFE_IRQ(22),
+	MT8189_AFE_IRQ(23),
+	MT8189_AFE_IRQ(24),
+	MT8189_AFE_IRQ(25),
+	MT8189_AFE_IRQ(26),
+	MT8189_AFE_TDM_IRQ(31),
+};
+
+static const int memif_irq_usage[MT8189_MEMIF_NUM] = {
+	/* TODO: verify each memif & irq */
+	[MT8189_MEMIF_DL0] = MT8189_IRQ_0,
+	[MT8189_MEMIF_DL1] = MT8189_IRQ_1,
+	[MT8189_MEMIF_DL2] = MT8189_IRQ_2,
+	[MT8189_MEMIF_DL3] = MT8189_IRQ_3,
+	[MT8189_MEMIF_DL4] = MT8189_IRQ_4,
+	[MT8189_MEMIF_DL5] = MT8189_IRQ_5,
+	[MT8189_MEMIF_DL6] = MT8189_IRQ_6,
+	[MT8189_MEMIF_DL7] = MT8189_IRQ_7,
+	[MT8189_MEMIF_DL8] = MT8189_IRQ_8,
+	[MT8189_MEMIF_DL23] = MT8189_IRQ_9,
+	[MT8189_MEMIF_DL24] = MT8189_IRQ_10,
+	[MT8189_MEMIF_DL25] = MT8189_IRQ_11,
+	[MT8189_MEMIF_DL_24CH] = MT8189_IRQ_12,
+	[MT8189_MEMIF_VUL0] = MT8189_IRQ_13,
+	[MT8189_MEMIF_VUL1] = MT8189_IRQ_14,
+	[MT8189_MEMIF_VUL2] = MT8189_IRQ_15,
+	[MT8189_MEMIF_VUL3] = MT8189_IRQ_16,
+	[MT8189_MEMIF_VUL4] = MT8189_IRQ_17,
+	[MT8189_MEMIF_VUL5] = MT8189_IRQ_18,
+	[MT8189_MEMIF_VUL6] = MT8189_IRQ_19,
+	[MT8189_MEMIF_VUL7] = MT8189_IRQ_20,
+	[MT8189_MEMIF_VUL8] = MT8189_IRQ_21,
+	[MT8189_MEMIF_VUL9] = MT8189_IRQ_22,
+	[MT8189_MEMIF_VUL10] = MT8189_IRQ_23,
+	[MT8189_MEMIF_VUL24] = MT8189_IRQ_24,
+	[MT8189_MEMIF_VUL25] = MT8189_IRQ_25,
+	[MT8189_MEMIF_VUL_CM0] = MT8189_IRQ_26,
+	[MT8189_MEMIF_VUL_CM1] = MT8189_IRQ_0,
+	[MT8189_MEMIF_ETDM_IN0] = MT8189_IRQ_0,
+	[MT8189_MEMIF_ETDM_IN1] = MT8189_IRQ_0,
+	[MT8189_MEMIF_HDMI] = MT8189_IRQ_31
+};
+
+static bool mt8189_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:    /* reg bit controlled by CCF */
+	case AUDIO_TOP_CON1:    /* reg bit controlled by CCF */
+	case AUDIO_TOP_CON2:
+	case AUDIO_TOP_CON3:
+	case AUDIO_TOP_CON4:
+	case AFE_APLL1_TUNER_MON0:
+	case AFE_APLL2_TUNER_MON0:
+	case AFE_SPM_CONTROL_ACK:
+	case AUDIO_TOP_IP_VERSION:
+	case AUDIO_ENGEN_CON0_MON:
+	case AFE_CONNSYS_I2S_IPM_VER_MON:
+	case AFE_CONNSYS_I2S_MON:
+	case AFE_PCM_INTF_MON:
+	case AFE_PCM_TOP_IP_VERSION:
+	case AFE_IRQ_MCU_STATUS:
+	case AFE_CUSTOM_IRQ_MCU_STATUS:
+	case AFE_IRQ_MCU_MON0:
+	case AFE_IRQ_MCU_MON1:
+	case AFE_IRQ_MCU_MON2:
+	case AFE_IRQ0_CNT_MON:
+	case AFE_IRQ1_CNT_MON:
+	case AFE_IRQ2_CNT_MON:
+	case AFE_IRQ3_CNT_MON:
+	case AFE_IRQ4_CNT_MON:
+	case AFE_IRQ5_CNT_MON:
+	case AFE_IRQ6_CNT_MON:
+	case AFE_IRQ7_CNT_MON:
+	case AFE_IRQ8_CNT_MON:
+	case AFE_IRQ9_CNT_MON:
+	case AFE_IRQ10_CNT_MON:
+	case AFE_IRQ11_CNT_MON:
+	case AFE_IRQ12_CNT_MON:
+	case AFE_IRQ13_CNT_MON:
+	case AFE_IRQ14_CNT_MON:
+	case AFE_IRQ15_CNT_MON:
+	case AFE_IRQ16_CNT_MON:
+	case AFE_IRQ17_CNT_MON:
+	case AFE_IRQ18_CNT_MON:
+	case AFE_IRQ19_CNT_MON:
+	case AFE_IRQ20_CNT_MON:
+	case AFE_IRQ21_CNT_MON:
+	case AFE_IRQ22_CNT_MON:
+	case AFE_IRQ23_CNT_MON:
+	case AFE_IRQ24_CNT_MON:
+	case AFE_IRQ25_CNT_MON:
+	case AFE_IRQ26_CNT_MON:
+	case AFE_CM0_MON:
+	case AFE_CM0_IP_VERSION:
+	case AFE_CM1_MON:
+	case AFE_CM1_IP_VERSION:
+	case AFE_ADDA_UL0_SRC_DEBUG_MON0:
+	case AFE_ADDA_UL0_SRC_MON0:
+	case AFE_ADDA_UL0_SRC_MON1:
+	case AFE_ADDA_UL0_IP_VERSION:
+	case AFE_ADDA_DMIC0_SRC_DEBUG_MON0:
+	case AFE_ADDA_DMIC0_SRC_MON0:
+	case AFE_ADDA_DMIC0_SRC_MON1:
+	case AFE_ADDA_DMIC0_IP_VERSION:
+	case AFE_ADDA_DMIC1_SRC_DEBUG_MON0:
+	case AFE_ADDA_DMIC1_SRC_MON0:
+	case AFE_ADDA_DMIC1_SRC_MON1:
+	case AFE_ADDA_DMIC1_IP_VERSION:
+	case AFE_MTKAIF_IPM_VER_MON:
+	case AFE_MTKAIF_MON:
+	case AFE_AUD_PAD_TOP_MON:
+	case AFE_ADDA_MTKAIFV4_MON0:
+	case AFE_ADDA_MTKAIFV4_MON1:
+	case AFE_ADDA6_MTKAIFV4_MON0:
+	case ETDM_IN0_MON:
+	case ETDM_IN1_MON:
+	case ETDM_OUT0_MON:
+	case ETDM_OUT1_MON:
+	case ETDM_OUT4_MON:
+	case AFE_CONN_MON0:
+	case AFE_CONN_MON1:
+	case AFE_CONN_MON2:
+	case AFE_CONN_MON3:
+	case AFE_CONN_MON4:
+	case AFE_CONN_MON5:
+	case AFE_CBIP_SLV_DECODER_MON0:
+	case AFE_CBIP_SLV_DECODER_MON1:
+	case AFE_CBIP_SLV_MUX_MON0:
+	case AFE_CBIP_SLV_MUX_MON1:
+	case AFE_DL0_CUR_MSB:
+	case AFE_DL0_CUR:
+	case AFE_DL0_RCH_MON:
+	case AFE_DL0_LCH_MON:
+	case AFE_DL1_CUR_MSB:
+	case AFE_DL1_CUR:
+	case AFE_DL1_RCH_MON:
+	case AFE_DL1_LCH_MON:
+	case AFE_DL2_CUR_MSB:
+	case AFE_DL2_CUR:
+	case AFE_DL2_RCH_MON:
+	case AFE_DL2_LCH_MON:
+	case AFE_DL3_CUR_MSB:
+	case AFE_DL3_CUR:
+	case AFE_DL3_RCH_MON:
+	case AFE_DL3_LCH_MON:
+	case AFE_DL4_CUR_MSB:
+	case AFE_DL4_CUR:
+	case AFE_DL4_RCH_MON:
+	case AFE_DL4_LCH_MON:
+	case AFE_DL5_CUR_MSB:
+	case AFE_DL5_CUR:
+	case AFE_DL5_RCH_MON:
+	case AFE_DL5_LCH_MON:
+	case AFE_DL6_CUR_MSB:
+	case AFE_DL6_CUR:
+	case AFE_DL6_RCH_MON:
+	case AFE_DL6_LCH_MON:
+	case AFE_DL7_CUR_MSB:
+	case AFE_DL7_CUR:
+	case AFE_DL7_RCH_MON:
+	case AFE_DL7_LCH_MON:
+	case AFE_DL8_CUR_MSB:
+	case AFE_DL8_CUR:
+	case AFE_DL8_RCH_MON:
+	case AFE_DL8_LCH_MON:
+	case AFE_DL_24CH_CUR_MSB:
+	case AFE_DL_24CH_CUR:
+	case AFE_DL23_CUR_MSB:
+	case AFE_DL23_CUR:
+	case AFE_DL23_RCH_MON:
+	case AFE_DL23_LCH_MON:
+	case AFE_DL24_CUR_MSB:
+	case AFE_DL24_CUR:
+	case AFE_DL24_RCH_MON:
+	case AFE_DL24_LCH_MON:
+	case AFE_DL25_CUR_MSB:
+	case AFE_DL25_CUR:
+	case AFE_DL25_RCH_MON:
+	case AFE_DL25_LCH_MON:
+	case AFE_VUL0_CUR_MSB:
+	case AFE_VUL0_CUR:
+	case AFE_VUL1_CUR_MSB:
+	case AFE_VUL1_CUR:
+	case AFE_VUL2_CUR_MSB:
+	case AFE_VUL2_CUR:
+	case AFE_VUL3_CUR_MSB:
+	case AFE_VUL3_CUR:
+	case AFE_VUL4_CUR_MSB:
+	case AFE_VUL4_CUR:
+	case AFE_VUL5_CUR_MSB:
+	case AFE_VUL5_CUR:
+	case AFE_VUL6_CUR_MSB:
+	case AFE_VUL6_CUR:
+	case AFE_VUL7_CUR_MSB:
+	case AFE_VUL7_CUR:
+	case AFE_VUL8_CUR_MSB:
+	case AFE_VUL8_CUR:
+	case AFE_VUL9_CUR_MSB:
+	case AFE_VUL9_CUR:
+	case AFE_VUL10_CUR_MSB:
+	case AFE_VUL10_CUR:
+	case AFE_VUL24_CUR_MSB:
+	case AFE_VUL24_CUR:
+	case AFE_VUL25_CUR_MSB:
+	case AFE_VUL25_CUR:
+	case AFE_VUL_CM0_CUR_MSB:
+	case AFE_VUL_CM0_CUR:
+	case AFE_VUL_CM1_CUR_MSB:
+	case AFE_VUL_CM1_CUR:
+	case AFE_ETDM_IN0_CUR_MSB:
+	case AFE_ETDM_IN0_CUR:
+	case AFE_ETDM_IN1_CUR_MSB:
+	case AFE_ETDM_IN1_CUR:
+	case AFE_HDMI_OUT_CUR_MSB:
+	case AFE_HDMI_OUT_CUR:
+	case AFE_HDMI_OUT_END:
+	case AFE_HDMI_OUT_MON0:
+	case AFE_PROT_SIDEBAND0_MON:
+	case AFE_PROT_SIDEBAND1_MON:
+	case AFE_PROT_SIDEBAND2_MON:
+	case AFE_PROT_SIDEBAND3_MON:
+	case AFE_DOMAIN_SIDEBAND0_MON:
+	case AFE_DOMAIN_SIDEBAND1_MON:
+	case AFE_DOMAIN_SIDEBAND2_MON:
+	case AFE_DOMAIN_SIDEBAND3_MON:
+	case AFE_DOMAIN_SIDEBAND4_MON:
+	case AFE_DOMAIN_SIDEBAND5_MON:
+	case AFE_DOMAIN_SIDEBAND6_MON:
+	case AFE_DOMAIN_SIDEBAND7_MON:
+	case AFE_DOMAIN_SIDEBAND8_MON:
+	case AFE_DOMAIN_SIDEBAND9_MON:
+	case AFE_PCM0_INTF_CON1_MASK_MON:
+	case AFE_CONNSYS_I2S_CON_MASK_MON:
+	case AFE_MTKAIF0_CFG0_MASK_MON:
+	case AFE_MTKAIF1_CFG0_MASK_MON:
+	case AFE_ADDA_UL0_SRC_CON0_MASK_MON:
+	case AFE_ASRC_NEW_CON0:
+	case AFE_ASRC_NEW_CON6:
+	case AFE_ASRC_NEW_CON8:
+	case AFE_ASRC_NEW_CON9:
+	case AFE_ASRC_NEW_CON12:
+	case AFE_ASRC_NEW_IP_VERSION:
+	case AFE_GASRC0_NEW_CON0:
+	case AFE_GASRC0_NEW_CON6:
+	case AFE_GASRC0_NEW_CON8:
+	case AFE_GASRC0_NEW_CON9:
+	case AFE_GASRC0_NEW_CON10:
+	case AFE_GASRC0_NEW_CON11:
+	case AFE_GASRC0_NEW_CON12:
+	case AFE_GASRC0_NEW_IP_VERSION:
+	case AFE_GASRC1_NEW_CON0:
+	case AFE_GASRC1_NEW_CON6:
+	case AFE_GASRC1_NEW_CON8:
+	case AFE_GASRC1_NEW_CON9:
+	case AFE_GASRC1_NEW_CON12:
+	case AFE_GASRC1_NEW_IP_VERSION:
+	case AFE_GASRC2_NEW_CON0:
+	case AFE_GASRC2_NEW_CON6:
+	case AFE_GASRC2_NEW_CON8:
+	case AFE_GASRC2_NEW_CON9:
+	case AFE_GASRC2_NEW_CON12:
+	case AFE_GASRC2_NEW_IP_VERSION:
+	case AFE_GAIN0_CUR_L:
+	case AFE_GAIN0_CUR_R:
+	case AFE_GAIN1_CUR_L:
+	case AFE_GAIN1_CUR_R:
+	case AFE_GAIN2_CUR_L:
+	case AFE_GAIN2_CUR_R:
+	case AFE_GAIN3_CUR_L:
+	case AFE_GAIN3_CUR_R:
+	case AFE_IRQ_MCU_EN:
+	case AFE_CUSTOM_IRQ_MCU_EN:
+	case AFE_IRQ_MCU_DSP_EN:
+	case AFE_IRQ_MCU_DSP2_EN:
+	case AFE_DL5_CON0:
+	case AFE_DL6_CON0:
+	case AFE_DL23_CON0:
+	case AFE_DL_24CH_CON0:
+	case AFE_VUL1_CON0:
+	case AFE_VUL3_CON0:
+	case AFE_VUL4_CON0:
+	case AFE_VUL5_CON0:
+	case AFE_VUL9_CON0:
+	case AFE_VUL25_CON0:
+	case AFE_IRQ0_MCU_CFG0:
+	case AFE_IRQ1_MCU_CFG0:
+	case AFE_IRQ2_MCU_CFG0:
+	case AFE_IRQ3_MCU_CFG0:
+	case AFE_IRQ4_MCU_CFG0:
+	case AFE_IRQ5_MCU_CFG0:
+	case AFE_IRQ6_MCU_CFG0:
+	case AFE_IRQ7_MCU_CFG0:
+	case AFE_IRQ8_MCU_CFG0:
+	case AFE_IRQ9_MCU_CFG0:
+	case AFE_IRQ10_MCU_CFG0:
+	case AFE_IRQ11_MCU_CFG0:
+	case AFE_IRQ12_MCU_CFG0:
+	case AFE_IRQ13_MCU_CFG0:
+	case AFE_IRQ14_MCU_CFG0:
+	case AFE_IRQ15_MCU_CFG0:
+	case AFE_IRQ16_MCU_CFG0:
+	case AFE_IRQ17_MCU_CFG0:
+	case AFE_IRQ18_MCU_CFG0:
+	case AFE_IRQ19_MCU_CFG0:
+	case AFE_IRQ20_MCU_CFG0:
+	case AFE_IRQ21_MCU_CFG0:
+	case AFE_IRQ22_MCU_CFG0:
+	case AFE_IRQ23_MCU_CFG0:
+	case AFE_IRQ24_MCU_CFG0:
+	case AFE_IRQ25_MCU_CFG0:
+	case AFE_IRQ26_MCU_CFG0:
+	case AFE_CUSTOM_IRQ0_MCU_CFG0:
+	case AFE_IRQ0_MCU_CFG1:
+	case AFE_IRQ1_MCU_CFG1:
+	case AFE_IRQ2_MCU_CFG1:
+	case AFE_IRQ3_MCU_CFG1:
+	case AFE_IRQ4_MCU_CFG1:
+	case AFE_IRQ5_MCU_CFG1:
+	case AFE_IRQ6_MCU_CFG1:
+	case AFE_IRQ7_MCU_CFG1:
+	case AFE_IRQ8_MCU_CFG1:
+	case AFE_IRQ9_MCU_CFG1:
+	case AFE_IRQ10_MCU_CFG1:
+	case AFE_IRQ11_MCU_CFG1:
+	case AFE_IRQ12_MCU_CFG1:
+	case AFE_IRQ13_MCU_CFG1:
+	case AFE_IRQ14_MCU_CFG1:
+	case AFE_IRQ15_MCU_CFG1:
+	case AFE_IRQ16_MCU_CFG1:
+	case AFE_IRQ17_MCU_CFG1:
+	case AFE_IRQ18_MCU_CFG1:
+	case AFE_IRQ19_MCU_CFG1:
+	case AFE_IRQ20_MCU_CFG1:
+	case AFE_IRQ21_MCU_CFG1:
+	case AFE_IRQ22_MCU_CFG1:
+	case AFE_IRQ23_MCU_CFG1:
+	case AFE_IRQ24_MCU_CFG1:
+	case AFE_IRQ25_MCU_CFG1:
+	case AFE_IRQ26_MCU_CFG1:
+	case AFE_CUSTOM_IRQ0_MCU_CFG1:
+	/* for vow using */
+	case AFE_IRQ_MCU_SCP_EN:
+	case AFE_VUL_CM0_BASE_MSB:
+	case AFE_VUL_CM0_BASE:
+	case AFE_VUL_CM0_END_MSB:
+	case AFE_VUL_CM0_END:
+	case AFE_VUL_CM0_CON0:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config mt8189_afe_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+
+	.volatile_reg = mt8189_is_volatile_reg,
+
+	.max_register = AFE_MAX_REGISTER,
+	.num_reg_defaults_raw = AFE_MAX_REGISTER,
+
+	.cache_type = REGCACHE_FLAT,
+};
+
+static irqreturn_t mt8189_afe_irq_handler(int irq_id, void *dev)
+{
+	struct mtk_base_afe *afe = dev;
+	struct mtk_base_afe_irq *irq;
+	unsigned int status = 0;
+	unsigned int status_mcu;
+	unsigned int mcu_en = 0;
+	unsigned int cus_status = 0;
+	unsigned int cus_status_mcu;
+	unsigned int cus_mcu_en = 0;
+	unsigned int tmp_reg = 0;
+	int ret, cus_ret;
+	int i;
+	struct timespec64 ts64;
+	unsigned long long t1, t2;
+	/* one interrupt period = 5ms */
+	unsigned long long timeout_limit = 5000000;
+
+	/* get irq that is sent to MCU */
+	regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
+	regmap_read(afe->regmap, AFE_CUSTOM_IRQ_MCU_EN, &cus_mcu_en);
+
+	ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
+	cus_ret = regmap_read(afe->regmap, AFE_CUSTOM_IRQ_MCU_STATUS, &cus_status);
+	/* only care IRQ which is sent to MCU */
+	status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS;
+	cus_status_mcu = cus_status & cus_mcu_en & AFE_IRQ_STATUS_BITS;
+	if ((ret || status_mcu == 0) && (cus_ret || cus_status_mcu == 0)) {
+		dev_err(afe->dev, "%s(), irq status err, ret %d, 0x%x:0x%x:0x%x:0x%x\n",
+			__func__, ret, status, mcu_en, cus_status_mcu, cus_mcu_en);
+
+		goto err_irq;
+	}
+
+	ktime_get_ts64(&ts64);
+	t1 = timespec64_to_ns(&ts64);
+
+	for (i = 0; i < MT8189_MEMIF_NUM; i++) {
+		struct mtk_base_afe_memif *memif = &afe->memif[i];
+
+		if (!memif->substream)
+			continue;
+
+		if (memif->irq_usage < 0)
+			continue;
+		irq = &afe->irqs[memif->irq_usage];
+
+		if (i == MT8189_MEMIF_HDMI) {
+			if (cus_status_mcu & (0x1 << irq->irq_data->id))
+				snd_pcm_period_elapsed(memif->substream);
+		} else if (status_mcu & (0x1 << irq->irq_data->id)) {
+			snd_pcm_period_elapsed(memif->substream);
+		}
+	}
+
+	ktime_get_ts64(&ts64);
+	t2 = timespec64_to_ns(&ts64);
+	t2 = t2 - t1; /* in ns (10^9) */
+
+	if (t2 > timeout_limit)
+		dev_warn(afe->dev, "%s(), mcu_en 0x%x, cus_mcu_en 0x%x, timeout %llu, limit %llu, ret %d\n",
+			 __func__, mcu_en, cus_mcu_en, t2, timeout_limit, ret);
+
+err_irq:
+	/* clear irq */
+	for (i = 0; i < MT8189_IRQ_NUM; ++i) {
+		if (((cus_status_mcu & (0x1 << irq_data[i].id)) && i == MT8189_IRQ_31) ||
+		    ((status_mcu & (0x1 << irq_data[i].id)) && i != MT8189_IRQ_31)) {
+			regmap_read(afe->regmap, irq_data[i].irq_clr_reg, &tmp_reg);
+			regmap_update_bits(afe->regmap, irq_data[i].irq_clr_reg,
+					   AFE_IRQ_CLR_CFG_MASK_SFT |
+					   AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT,
+					   tmp_reg ^ (AFE_IRQ_CLR_CFG_MASK_SFT |
+					   AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT));
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mt8189_afe_runtime_suspend(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	unsigned int value = 0;
+	unsigned int tmp_reg = 0;
+	int ret, i;
+
+	dev_dbg(afe->dev, "%s() successfully start\n", __func__);
+
+	if (!afe->regmap) {
+		dev_warn(afe->dev, "%s() skip regmap\n", __func__);
+		goto skip_regmap;
+	}
+
+	/* disable AFE */
+	mt8189_afe_disable_main_clock(afe);
+
+	ret = regmap_read_poll_timeout(afe->regmap,
+				       AUDIO_ENGEN_CON0_MON,
+				       value,
+				       (value & AUDIO_ENGEN_MON_SFT) == 0,
+				       20,
+				       1 * 1000 * 1000);
+	dev_dbg(afe->dev, "%s() read_poll ret %d\n", __func__, ret);
+	if (ret)
+		dev_warn(afe->dev, "%s(), ret %d\n", __func__, ret);
+
+	/* make sure all irq status are cleared */
+	for (i = 0; i < MT8189_IRQ_NUM; i++) {
+		regmap_read(afe->regmap, irq_data[i].irq_clr_reg, &tmp_reg);
+		regmap_update_bits(afe->regmap, irq_data[i].irq_clr_reg,
+				   AFE_IRQ_CLR_CFG_MASK_SFT |
+				   AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT,
+				   tmp_reg ^ (AFE_IRQ_CLR_CFG_MASK_SFT |
+					      AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT));
+	}
+
+	/* reset audio 26M request */
+	regmap_update_bits(afe->regmap,
+			   AFE_SPM_CONTROL_REQ, 0x1, 0x0);
+
+	/* cache only */
+	regcache_cache_only(afe->regmap, true);
+	regcache_mark_dirty(afe->regmap);
+
+skip_regmap:
+	mt8189_afe_disable_reg_rw_clk(afe);
+	return 0;
+}
+
+static int mt8189_afe_runtime_resume(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	int ret;
+
+	dev_dbg(afe->dev, "%s() successfully start\n", __func__);
+
+	ret = mt8189_afe_enable_reg_rw_clk(afe);
+	if (ret)
+		return ret;
+
+	if (!afe->regmap) {
+		dev_warn(afe->dev, "skip regmap\n");
+		return 0;
+	}
+
+	regcache_cache_only(afe->regmap, false);
+	regcache_sync(afe->regmap);
+
+	/* set audio 26M request */
+	regmap_update_bits(afe->regmap, AFE_SPM_CONTROL_REQ, 0x1, 0x1);
+	regmap_update_bits(afe->regmap, AFE_CBIP_CFG0, 0x1, 0x1);
+
+	/* force cpu use 8_24 format when writing 32bit data */
+	regmap_update_bits(afe->regmap, AFE_MEMIF_CON0,
+			   CPU_HD_ALIGN_MASK_SFT, 0 << CPU_HD_ALIGN_SFT);
+
+	/* enable AFE */
+	mt8189_afe_enable_main_clock(afe);
+
+	return 0;
+}
+
+static int mt8189_afe_component_probe(struct snd_soc_component *component)
+{
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+	if (component) {
+		/* enable clock for regcache get default value from hw */
+		pm_runtime_get_sync(afe->dev);
+		mtk_afe_add_sub_dai_control(component);
+		pm_runtime_put_sync(afe->dev);
+	}
+
+	return 0;
+}
+
+static int mt8189_afe_pcm_open(struct snd_soc_component *component,
+			       struct snd_pcm_substream *substream)
+{
+	/* set the wait_for_avail to 2 sec*/
+	substream->wait_time = msecs_to_jiffies(2 * 1000);
+
+	return 0;
+}
+
+static void mt8189_afe_pcm_free(struct snd_soc_component *component,
+				struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static const struct snd_soc_component_driver mt8189_afe_component = {
+	.name = AFE_PCM_NAME,
+	.probe = mt8189_afe_component_probe,
+	.pcm_construct = mtk_afe_pcm_new,
+	.pcm_destruct = mt8189_afe_pcm_free,
+	.open = mt8189_afe_pcm_open,
+	.pointer = mtk_afe_pcm_pointer,
+};
+
+static int mt8189_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 = mt8189_memif_dai_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mt8189_memif_dai_driver);
+
+	dai->controls = mt8189_pcm_kcontrols;
+	dai->num_controls = ARRAY_SIZE(mt8189_pcm_kcontrols);
+	dai->dapm_widgets = mt8189_memif_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mt8189_memif_widgets);
+	dai->dapm_routes = mt8189_memif_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mt8189_memif_routes);
+	return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+	mt8189_dai_adda_register,
+	mt8189_dai_i2s_register,
+	mt8189_dai_pcm_register,
+	mt8189_dai_tdm_register,
+	mt8189_dai_memif_register,
+};
+
+static const struct reg_sequence mt8189_cg_patch[] = {
+	{ AUDIO_TOP_CON4, 0x361c },
+};
+
+static int mt8189_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+	int ret, i;
+	unsigned int tmp_reg = 0;
+	int irq_id;
+	struct mtk_base_afe *afe;
+	struct mt8189_afe_private *afe_priv;
+	struct device *dev = &pdev->dev;
+
+	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34));
+	if (ret)
+		return ret;
+
+	ret = of_reserved_mem_device_init(dev);
+	if (ret)
+		dev_warn(dev, "failed to assign memory region: %d\n", ret);
+
+	afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL);
+	if (!afe)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, afe);
+
+	afe->platform_priv = devm_kzalloc(dev, sizeof(*afe_priv),
+					  GFP_KERNEL);
+	if (!afe->platform_priv)
+		return -ENOMEM;
+
+	afe_priv = afe->platform_priv;
+	afe->dev = 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");
+
+	/* init audio related clock */
+	ret = mt8189_init_clock(afe);
+	if (ret)
+		return dev_err_probe(dev, ret, "init clock error.\n");
+
+	/* init memif */
+	/* IPM2.0 no need banding */
+	afe->memif_32bit_supported = 1;
+	afe->memif_size = MT8189_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 = memif_irq_usage[i];
+		afe->memif[i].const_irq = 1;
+	}
+
+	mutex_init(&afe->irq_alloc_lock);
+
+	/* init irq */
+	afe->irqs_size = MT8189_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];
+
+	/* request irq */
+	irq_id = platform_get_irq(pdev, 0);
+	if (irq_id < 0)
+		return dev_err_probe(dev, irq_id, "no irq found");
+
+	ret = devm_request_irq(dev, irq_id, mt8189_afe_irq_handler,
+			       IRQF_TRIGGER_NONE,
+			       "Afe_ISR_Handle", (void *)afe);
+	if (ret)
+		return dev_err_probe(dev, ret, "could not request_irq for Afe_ISR_Handle\n");
+
+	ret = enable_irq_wake(irq_id);
+	if (ret < 0)
+		dev_warn(dev, "enable_irq_wake %d err: %d\n", irq_id, ret);
+
+	/* 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");
+
+	/* others */
+	afe->mtk_afe_hardware = &mt8189_afe_hardware;
+	afe->memif_fs = mt8189_memif_fs;
+	afe->irq_fs = mt8189_irq_fs;
+	afe->get_dai_fs = mt8189_get_dai_fs;
+	afe->get_memif_pbuf_size = mt8189_get_memif_pbuf_size;
+
+	afe->runtime_resume = mt8189_afe_runtime_resume;
+	afe->runtime_suspend = mt8189_afe_runtime_suspend;
+
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return ret;
+
+	/* Audio device is part of genpd.
+	 * Set audio as syscore device to prevent
+	 * genpd automatically power off audio
+	 * device when suspend
+	 */
+	dev_pm_syscore_device(dev, true);
+
+	/* enable clock for regcache get default value from hw */
+	pm_runtime_get_sync(dev);
+
+	afe->regmap = devm_regmap_init_mmio(dev, afe->base_addr,
+					    &mt8189_afe_regmap_config);
+	if (IS_ERR(afe->regmap))
+		return PTR_ERR(afe->regmap);
+
+	ret = regmap_register_patch(afe->regmap, mt8189_cg_patch,
+				    ARRAY_SIZE(mt8189_cg_patch));
+	if (ret < 0) {
+		dev_err(dev, "Failed to apply cg patch\n");
+		goto err_pm_disable;
+	}
+
+	regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &tmp_reg);
+	regmap_write(afe->regmap, AFE_IRQ_MCU_EN, 0xffffffff);
+	regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &tmp_reg);
+
+	pm_runtime_put_sync(dev);
+
+	regcache_cache_only(afe->regmap, true);
+	regcache_mark_dirty(afe->regmap);
+
+	/* register component */
+	ret = devm_snd_soc_register_component(dev,
+					      &mt8189_afe_component,
+					      afe->dai_drivers,
+					      afe->num_dai_drivers);
+	if (ret) {
+		dev_err(dev, "afe component err: %d\n", ret);
+		goto err_pm_disable;
+	}
+
+	return 0;
+
+err_pm_disable:
+	pm_runtime_disable(dev);
+	return ret;
+}
+
+static void mt8189_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+	struct mtk_base_afe *afe = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+
+	pm_runtime_disable(dev);
+	if (!pm_runtime_status_suspended(dev))
+		mt8189_afe_runtime_suspend(dev);
+
+	/* disable afe clock */
+	mt8189_afe_disable_reg_rw_clk(afe);
+	mt8189_afe_disable_main_clock(afe);
+	of_reserved_mem_device_release(dev);
+}
+
+static const struct of_device_id mt8189_afe_pcm_dt_match[] = {
+	{ .compatible = "mediatek,mt8189-afe-pcm", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mt8189_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt8189_afe_pm_ops = {
+	SET_RUNTIME_PM_OPS(mt8189_afe_runtime_suspend,
+			   mt8189_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt8189_afe_pcm_driver = {
+	.driver = {
+		.name = "mt8189-afe-pcm",
+		.of_match_table = mt8189_afe_pcm_dt_match,
+#if IS_ENABLED(CONFIG_PM)
+		.pm = &mt8189_afe_pm_ops,
+#endif
+	},
+	.probe = mt8189_afe_pcm_dev_probe,
+	.remove = mt8189_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt8189_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 8189");
+MODULE_AUTHOR("Darren Ye <darren.ye@mediatek.com>");
+MODULE_LICENSE("GPL");
-- 
2.46.0



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

* [PATCH 08/10] ASoC: dt-bindings: mediatek,mt8189-afe-pcm: add audio afe document
  2025-06-28  7:14 [PATCH 00/10] ASoC: mediatek: Add support for MT8189 SoC Cyril
                   ` (5 preceding siblings ...)
  2025-06-28  7:14 ` [PATCH 07/10] ASoC: mediatek: mt8189: add " Cyril
@ 2025-06-28  7:14 ` Cyril
  2025-06-28 12:46   ` Krzysztof Kozlowski
  2025-06-28  7:14 ` [PATCH 09/10] ASoC: mediatek: mt8189: add machine driver with nau8825 Cyril
  2025-06-28  7:14 ` [PATCH 10/10] ASoC: dt-bindings: mediatek,mt8189-nau8825: add mt8189-nau8825 document Cyril
  8 siblings, 1 reply; 17+ messages in thread
From: Cyril @ 2025-06-28  7:14 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group, cyril.chao,
	Cyril Chao

From: Cyril Chao <Cyril.Chao@mediatek.com>

Add mt8189 audio afe document.

Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
---
 .../sound/mediatek,mt8189-afe-pcm.yaml        | 162 ++++++++++++++++++
 1 file changed, 162 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8189-afe-pcm.yaml

diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8189-afe-pcm.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8189-afe-pcm.yaml
new file mode 100644
index 000000000..f0bfc3bcf
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8189-afe-pcm.yaml
@@ -0,0 +1,162 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mt8189-afe-pcm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Audio Front End PCM controller for MT8189
+
+maintainers:
+  - Darren Ye <darren.ye@mediatek.com>
+  - Cyril Chao <cyril.chao@mediatek.com>
+
+properties:
+  compatible:
+    const: mediatek,mt8189-afe-pcm
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  memory-region:
+    maxItems: 1
+
+  mediatek,apmixedsys:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: To set up the apll12 tuner
+
+  power-domains:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: mux for audio intbus
+      - description: mux for audio engen1
+      - description: mux for audio engen2
+      - description: mux for audio h
+      - description: audio apll1 clock
+      - description: audio apll2 clock
+      - description: audio apll1 divide4
+      - description: audio apll2 divide4
+      - description: audio apll12 divide for i2sin0
+      - description: audio apll12 divide for i2sin1
+      - description: audio apll12 divide for fmi2s
+      - description: audio apll12 divide for tdmout mck
+      - description: audio apll12 divide for tdmout bck
+      - description: mux for audio apll1
+      - description: mux for audio apll2
+      - description: mux for i2sin0 mck
+      - description: mux for i2sin1 mck
+      - description: mux for fmi2s mck
+      - description: mux for tdmout mck
+      - description: 26m clock
+      - description: audio slv clock
+      - description: audio mst clock
+      - description: audio intbus clock
+
+  clock-names:
+    items:
+      - const: top_aud_intbus
+      - const: top_aud_eng1
+      - const: top_aud_eng2
+      - const: top_aud_h
+      - const: apll1
+      - const: apll2
+      - const: apll1_d4
+      - const: apll2_d4
+      - const: apll12_div_i2sin0
+      - const: apll12_div_i2sin1
+      - const: apll12_div_fmi2s
+      - const: apll12_div_tdmout_m
+      - const: apll12_div_tdmout_b
+      - const: top_apll1
+      - const: top_apll2
+      - const: top_i2sin0
+      - const: top_i2sin1
+      - const: top_fmi2s
+      - const: top_dptx
+      - const: clk26m
+      - const: aud_slv_ck_peri
+      - const: aud_mst_ck_peri
+      - const: aud_intbus_ck_peri
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - memory-region
+  - mediatek,apmixedsys
+  - power-domains
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        afe@11050000 {
+            compatible = "mediatek,mt8189-afe-pcm";
+            reg = <0 0x11050000 0 0x10000>;
+            interrupts = <GIC_SPI 392 IRQ_TYPE_LEVEL_HIGH 0>;
+            memory-region = <&afe_dma_mem_reserved>;
+            mediatek,apmixedsys = <&apmixedsys_clk>;
+            power-domains = <&scpsys 1>; //MT8189_POWER_DOMAIN_AUDIO
+            clocks = <&topckgen_clk 23>, //CLK_TOP_AUD_INTBUS_SEL
+                     <&topckgen_clk 39>, //CLK_TOP_AUD_ENGEN1_SEL
+                     <&topckgen_clk 40>, //CLK_TOP_AUD_ENGEN2_SEL
+                     <&topckgen_clk 49>, //CLK_TOP_AUDIO_H_SEL
+                     <&topckgen_clk 146>, //CLK_TOP_APLL1
+                     <&topckgen_clk 151>, //CLK_TOP_APLL2
+                     <&topckgen_clk 148>, //CLK_TOP_APLL1_D4
+                     <&topckgen_clk 153>, //CLK_TOP_APLL2_D4
+                     <&topckgen_clk 93>, //CLK_TOP_APLL12_CK_DIV_I2SIN0
+                     <&topckgen_clk 94>, //CLK_TOP_APLL12_CK_DIV_I2SIN1
+                     <&topckgen_clk 97>, //CLK_TOP_APLL12_CK_DIV_FMI2S
+                     <&topckgen_clk 98>, //CLK_TOP_APLL12_CK_DIV_TDMOUT_M
+                     <&topckgen_clk 99>, //CLK_TOP_APLL12_CK_DIV_TDMOUT_B
+                     <&topckgen_clk 44>, //CLK_TOP_AUD_1_SEL
+                     <&topckgen_clk 45>, //CLK_TOP_AUD_2_SEL
+                     <&topckgen_clk 78>, //CLK_TOP_APLL_I2SIN0_MCK_SEL
+                     <&topckgen_clk 79>, //CLK_TOP_APLL_I2SIN1_MCK_SEL
+                     <&topckgen_clk 90>, //CLK_TOP_APLL_FMI2S_MCK_SEL
+                     <&topckgen_clk 91>, //CLK_TOP_APLL_TDMOUT_MCK_SEL
+                     <&topckgen_clk 191>, //CLK_TOP_TCK_26M_MX9
+                     <&pericfg_ao_clk 77>, //CLK_PERAO_AUDIO0
+                     <&pericfg_ao_clk 78>, //CLK_PERAO_AUDIO1
+                     <&pericfg_ao_clk 79>; //CLK_PERAO_AUDIO2
+            clock-names = "top_aud_intbus",
+                          "top_aud_eng1",
+                          "top_aud_eng2",
+                          "top_aud_h",
+                          "apll1",
+                          "apll2",
+                          "apll1_d4",
+                          "apll2_d4",
+                          "apll12_div_i2sin0",
+                          "apll12_div_i2sin1",
+                          "apll12_div_fmi2s",
+                          "apll12_div_tdmout_m",
+                          "apll12_div_tdmout_b",
+                          "top_apll1",
+                          "top_apll2",
+                          "top_i2sin0",
+                          "top_i2sin1",
+                          "top_fmi2s",
+                          "top_dptx",
+                          "clk26m",
+                          "aud_slv_ck_peri",
+                          "aud_mst_ck_peri",
+                          "aud_intbus_ck_peri";
+        };
+    };
+
+...
-- 
2.46.0



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

* [PATCH 09/10] ASoC: mediatek: mt8189: add machine driver with nau8825
  2025-06-28  7:14 [PATCH 00/10] ASoC: mediatek: Add support for MT8189 SoC Cyril
                   ` (6 preceding siblings ...)
  2025-06-28  7:14 ` [PATCH 08/10] ASoC: dt-bindings: mediatek,mt8189-afe-pcm: add audio afe document Cyril
@ 2025-06-28  7:14 ` Cyril
  2025-06-28 12:39   ` Krzysztof Kozlowski
  2025-06-28  7:14 ` [PATCH 10/10] ASoC: dt-bindings: mediatek,mt8189-nau8825: add mt8189-nau8825 document Cyril
  8 siblings, 1 reply; 17+ messages in thread
From: Cyril @ 2025-06-28  7:14 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group, cyril.chao,
	Cyril Chao

From: Cyril Chao <Cyril.Chao@mediatek.com>

Add support for mt8189 board with nau8825.

Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
---
 sound/soc/mediatek/Kconfig                 |   18 +
 sound/soc/mediatek/mt8189/Makefile         |    3 +
 sound/soc/mediatek/mt8189/mt8189-nau8825.c | 1054 ++++++++++++++++++++
 3 files changed, 1075 insertions(+)
 create mode 100644 sound/soc/mediatek/mt8189/mt8189-nau8825.c

diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index b28648e0d..19689d183 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -256,6 +256,24 @@ config SND_SOC_MT8189
 	  Select Y if you have such device.
 	  If unsure select "N".
 
+config SND_SOC_MT8189_NAU8825
+	tristate "ASoc Audio driver for MT8189 with NAU8825 and I2S codec"
+	depends on SND_SOC_MT8189
+	depends on I2C
+	select SND_SOC_DMIC
+	select SND_SOC_HDMI_CODEC
+	select SND_SOC_NAU8825
+	select SND_SOC_RT5645
+	select SND_SOC_RT9123P
+	select SND_SOC_RT1015P
+	select SND_SOC_RT5682S
+	select SND_SOC_RT5682_I2C
+	help
+	  This adds support for ASoC machine driver for MediaTek MT8189
+	  boards with the NAU8828 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/mt8189/Makefile b/sound/soc/mediatek/mt8189/Makefile
index 795b1869b..83a033284 100644
--- a/sound/soc/mediatek/mt8189/Makefile
+++ b/sound/soc/mediatek/mt8189/Makefile
@@ -13,3 +13,6 @@ snd-soc-mt8189-afe-objs += \
 	mt8189-dai-tdm.o
 
 obj-$(CONFIG_SND_SOC_MT8189) += snd-soc-mt8189-afe.o
+
+# machine driver
+obj-$(CONFIG_SND_SOC_MT8189_NAU8825) += mt8189-nau8825.o
diff --git a/sound/soc/mediatek/mt8189/mt8189-nau8825.c b/sound/soc/mediatek/mt8189/mt8189-nau8825.c
new file mode 100644
index 000000000..e4b8604b8
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-nau8825.c
@@ -0,0 +1,1054 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  mt8189-nau8825.c  --  mt8189 nau8825 ALSA SoC machine driver
+ *
+ *  Copyright (c) 2025 MediaTek Inc.
+ *  Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <linux/input.h>
+
+#include "mtk-afe-platform-driver.h"
+#include "mtk-soundcard-driver.h"
+#include "mtk-soc-card.h"
+#include "mt8189-afe-common.h"
+#include "mt8189-afe-clk.h"
+
+#include "../../codecs/nau8825.h"
+#include "../../codecs/rt5682s.h"
+#include "../../codecs/rt5682.h"
+
+#define NAU8825_HS_PRESENT	BIT(0)
+#define RT5682S_HS_PRESENT	BIT(1)
+#define RT5650_HS_PRESENT	BIT(2)
+#define RT5682I_HS_PRESENT	BIT(3)
+
+/*
+ * Nau88l25
+ */
+#define NAU8825_CODEC_DAI  "nau8825-hifi"
+
+/*
+ * Rt5682s
+ */
+#define RT5682S_CODEC_DAI     "rt5682s-aif1"
+
+/*
+ * Rt5650
+ */
+#define RT5650_CODEC_DAI     "rt5645-aif1"
+
+/*
+ * Rt5682i
+ */
+#define RT5682I_CODEC_DAI     "rt5682-aif1"
+
+enum mt8189_jacks {
+	MT8189_JACK_HEADSET,
+	MT8189_JACK_DP,
+	MT8189_JACK_HDMI,
+	MT8189_JACK_MAX,
+};
+
+static struct snd_soc_jack_pin mt8189_dp_jack_pins[] = {
+	{
+		.pin = "DP",
+		.mask = SND_JACK_LINEOUT,
+	},
+};
+
+static struct snd_soc_jack_pin mt8189_hdmi_jack_pins[] = {
+	{
+		.pin = "HDMI",
+		.mask = SND_JACK_LINEOUT,
+	},
+};
+
+static struct snd_soc_jack_pin nau8825_jack_pins[] = {
+	{
+		.pin    = "Headphone Jack",
+		.mask   = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin    = "Headset Mic",
+		.mask   = SND_JACK_MICROPHONE,
+	},
+};
+
+static const struct snd_kcontrol_new mt8189_dumb_spk_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static const struct snd_soc_dapm_widget mt8189_dumb_spk_widgets[] = {
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const struct snd_soc_dapm_widget mt8189_nau8825_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_SINK("DP"),
+};
+
+static const struct snd_kcontrol_new mt8189_nau8825_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+/*
+ * if need additional control for the ext spk amp that is connected
+ * after Lineout Buffer / HP Buffer on the codec, put the control in
+ * mt8189_nau8825_spk_amp_event()
+ */
+#define EXT_SPK_AMP_W_NAME "Ext_Speaker_Amp"
+
+static const struct snd_soc_dapm_widget mt8189_nau8825_card_widgets[] = {
+	SND_SOC_DAPM_PINCTRL("ETDMIN_SPK_PIN", "aud-gpio-i2sin1-on", "aud-gpio-i2sin1-off"),
+	SND_SOC_DAPM_PINCTRL("ETDMOUT_SPK_PIN", "aud-gpio-i2sout1-on", "aud-gpio-i2sout1-off"),
+	SND_SOC_DAPM_PINCTRL("ETDMIN_HP_PIN", "aud-gpio-i2sin0-on", "aud-gpio-i2sin0-off"),
+	SND_SOC_DAPM_PINCTRL("ETDMOUT_HP_PIN", "aud-gpio-i2sout0-on", "aud-gpio-i2sout0-off"),
+	SND_SOC_DAPM_PINCTRL("ETDMOUT_HDMI_PIN", "aud-gpio-pcm-on", "aud-gpio-pcm-off"),
+	SND_SOC_DAPM_PINCTRL("AP_DMIC0_PIN", "aud-gpio-ap-dmic-on", "aud-gpio-ap-dmic-off"),
+	SND_SOC_DAPM_PINCTRL("AP_DMIC1_PIN", "aud-gpio-ap-dmic1-on", "aud-gpio-ap-dmic1-off"),
+};
+
+static const struct snd_soc_dapm_route mt8189_nau8825_card_routes[] = {
+};
+
+static const struct snd_kcontrol_new mt8189_nau8825_card_controls[] = {
+	SOC_DAPM_PIN_SWITCH(EXT_SPK_AMP_W_NAME),
+};
+
+/*
+ * define mtk_spk_i2s_mck node in dts when need mclk,
+ * BE i2s need assign snd_soc_ops = mt8189_nau8825_i2s_ops
+ */
+static int mt8189_nau8825_i2s_hw_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	unsigned int rate = params_rate(params);
+	unsigned int mclk_fs_ratio = 128;
+	unsigned int mclk_fs = rate * mclk_fs_ratio;
+	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+	return snd_soc_dai_set_sysclk(cpu_dai,
+				      0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8189_nau8825_i2s_ops = {
+	.hw_params = mt8189_nau8825_i2s_hw_params,
+};
+
+static int mt8189_dptx_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	unsigned int rate = params_rate(params);
+	unsigned int mclk_fs_ratio = 256;
+	unsigned int mclk_fs = rate * mclk_fs_ratio;
+	struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+	return snd_soc_dai_set_sysclk(dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8189_dptx_ops = {
+	.hw_params = mt8189_dptx_hw_params,
+};
+
+static int mt8189_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+				       struct snd_pcm_hw_params *params)
+{
+	dev_dbg(rtd->dev, "%s(), fix format to 32bit\n", __func__);
+
+	/* fix BE i2s format to 32bit, clean param mask first */
+	snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
+			     0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+
+	params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
+
+	return 0;
+}
+
+/* FE */
+SND_SOC_DAILINK_DEFS(playback0,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL0")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback1,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(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(playback4,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL4")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback5,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL5")),
+		     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(playback23,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL23")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback24,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL24")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback25,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL25")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback_24ch,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL_24CH")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture0,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL0")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture1,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture2,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(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(capture7,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL7")),
+		     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()));
+SND_SOC_DAILINK_DEFS(capture24,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL24")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture25,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL25")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture_cm0,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL_CM0")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture_cm1,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL_CM1")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture_etdm_in0,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL_ETDM_IN0")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture_etdm_in1,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL_ETDM_IN1")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback_hdmi,
+		     DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+/* BE */
+SND_SOC_DAILINK_DEFS(ap_dmic,
+		     DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(ap_dmic_ch34,
+		     DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_CH34")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sin0,
+		     DAILINK_COMP_ARRAY(COMP_CPU("I2SIN0")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sin1,
+		     DAILINK_COMP_ARRAY(COMP_CPU("I2SIN1")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sout0,
+		     DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT0")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sout1,
+		     DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT1")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(pcm0,
+		     DAILINK_COMP_ARRAY(COMP_CPU("PCM 0")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(tdm_dptx,
+		     DAILINK_COMP_ARRAY(COMP_CPU("TDM_DPTX")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt8189_nau8825_dai_links[] = {
+	/* Front End DAI links */
+	{
+		.name = "DL0_FE",
+		.stream_name = "DL0 Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback0),
+	},
+	{
+		.name = "DL1_FE",
+		.stream_name = "DL1 Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback1),
+	},
+	{
+		.name = "UL0_FE",
+		.stream_name = "UL0 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+				SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture0),
+	},
+	{
+		.name = "UL1_FE",
+		.stream_name = "UL1 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+				SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture1),
+	},
+	{
+		.name = "UL2_FE",
+		.stream_name = "UL2 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+				SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture2),
+	},
+	{
+		.name = "HDMI_FE",
+		.stream_name = "HDMI Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+				SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback_hdmi),
+	},
+	{
+		.name = "DL2_FE",
+		.stream_name = "DL2 Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+				SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback2),
+	},
+	{
+		.name = "DL3_FE",
+		.stream_name = "DL3 Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback3),
+	},
+	{
+		.name = "DL4_FE",
+		.stream_name = "DL4 Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback4),
+	},
+	{
+		.name = "DL5_FE",
+		.stream_name = "DL5 Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback5),
+	},
+	{
+		.name = "DL6_FE",
+		.stream_name = "DL6 Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback6),
+	},
+	{
+		.name = "DL7_FE",
+		.stream_name = "DL7 Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback7),
+	},
+	{
+		.name = "DL8 FE",
+		.stream_name = "DL8 Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback8),
+	},
+	{
+		.name = "DL23 FE",
+		.stream_name = "DL23 Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback23),
+	},
+	{
+		.name = "DL24 FE",
+		.stream_name = "DL24 Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback24),
+	},
+	{
+		.name = "DL25 FE",
+		.stream_name = "DL25 Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback25),
+	},
+	{
+		.name = "DL_24CH_FE",
+		.stream_name = "DL_24CH Playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(playback_24ch),
+	},
+	{
+		.name = "UL9_FE",
+		.stream_name = "UL9 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture9),
+	},
+	{
+		.name = "UL3_FE",
+		.stream_name = "UL3 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture3),
+	},
+	{
+		.name = "UL7_FE",
+		.stream_name = "UL7 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture7),
+	},
+	{
+		.name = "UL4_FE",
+		.stream_name = "UL4 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture4),
+	},
+	{
+		.name = "UL5_FE",
+		.stream_name = "UL5 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture5),
+	},
+	{
+		.name = "UL_CM0_FE",
+		.stream_name = "UL_CM0 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture_cm0),
+	},
+	{
+		.name = "UL_CM1_FE",
+		.stream_name = "UL_CM1 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture_cm1),
+	},
+	{
+		.name = "UL10_FE",
+		.stream_name = "UL10 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture10),
+	},
+	{
+		.name = "UL6_FE",
+		.stream_name = "UL6 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture6),
+	},
+	{
+		.name = "UL25_FE",
+		.stream_name = "UL25 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture25),
+	},
+	{
+		.name = "UL8_FE",
+		.stream_name = "UL8 Capture_Mono_1",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture8),
+	},
+	{
+		.name = "UL24_FE",
+		.stream_name = "UL24 Capture_Mono_2",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture24),
+	},
+	{
+		.name = "UL_ETDM_In0_FE",
+		.stream_name = "UL_ETDM_In0 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture_etdm_in0),
+	},
+	{
+		.name = "UL_ETDM_In1_FE",
+		.stream_name = "UL_ETDM_In1 Capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.capture_only = 1,
+		SND_SOC_DAILINK_REG(capture_etdm_in1),
+	},
+	/* Back End DAI links */
+	{
+		.name = "I2SIN0_BE",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+			| SND_SOC_DAIFMT_GATED,
+		.ops = &mt8189_nau8825_i2s_ops,
+		.no_pcm = 1,
+		.capture_only = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(i2sin0),
+	},
+	{
+		.name = "I2SIN1_BE",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+			| SND_SOC_DAIFMT_GATED,
+		.ops = &mt8189_nau8825_i2s_ops,
+		.no_pcm = 1,
+		.capture_only = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(i2sin1),
+	},
+	{
+		.name = "I2SOUT0_BE",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+			| SND_SOC_DAIFMT_GATED,
+		.ops = &mt8189_nau8825_i2s_ops,
+		.no_pcm = 1,
+		.playback_only = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(i2sout0),
+	},
+	{
+		.name = "I2SOUT1_BE",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+			| SND_SOC_DAIFMT_GATED,
+		.ops = &mt8189_nau8825_i2s_ops,
+		.no_pcm = 1,
+		.playback_only = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(i2sout1),
+	},
+	{
+		.name = "AP_DMIC_BE",
+		.no_pcm = 1,
+		.capture_only = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(ap_dmic),
+	},
+	{
+		.name = "AP_DMIC_CH34_BE",
+		.no_pcm = 1,
+		.capture_only = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(ap_dmic_ch34),
+	},
+	{
+		.name = "TDM_DPTX_BE",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+			| SND_SOC_DAIFMT_GATED,
+		.ops = &mt8189_dptx_ops,
+		.be_hw_params_fixup = mt8189_dptx_hw_params_fixup,
+		.no_pcm = 1,
+		.playback_only = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(tdm_dptx),
+	},
+	{
+		.name = "PCM_0_BE",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+			| SND_SOC_DAIFMT_GATED,
+		.no_pcm = 1,
+		.playback_only = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(pcm0),
+	},
+};
+
+static int mt8189_dumb_amp_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_card *card = rtd->card;
+	int ret = 0;
+
+	ret = snd_soc_dapm_new_controls(&card->dapm, mt8189_dumb_spk_widgets,
+					ARRAY_SIZE(mt8189_dumb_spk_widgets));
+	if (ret) {
+		dev_err(rtd->dev, "unable to add Dumb Speaker dapm, ret %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_add_card_controls(card, mt8189_dumb_spk_controls,
+					ARRAY_SIZE(mt8189_dumb_spk_controls));
+	if (ret) {
+		dev_err(rtd->dev, "unable to add Dumb card controls, ret %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mt8189_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8189_JACK_DP];
+	struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+	int ret = 0;
+
+	ret = snd_soc_card_jack_new_pins(rtd->card, "DP Jack", SND_JACK_LINEOUT,
+					 jack, mt8189_dp_jack_pins,
+					 ARRAY_SIZE(mt8189_dp_jack_pins));
+	if (ret) {
+		dev_err(rtd->dev, "%s, new jack failed: %d\n", __func__, ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_set_jack(component, jack, NULL);
+	if (ret) {
+		dev_err(rtd->dev, "%s, set jack failed on %s (ret=%d)\n",
+			__func__, component->name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mt8189_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8189_JACK_HDMI];
+	struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+	int ret = 0;
+
+	ret = snd_soc_card_jack_new_pins(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+					 jack, mt8189_hdmi_jack_pins,
+					 ARRAY_SIZE(mt8189_hdmi_jack_pins));
+	if (ret) {
+		dev_err(rtd->dev, "%s, new jack failed: %d\n", __func__, ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_set_jack(component, jack, NULL);
+	if (ret) {
+		dev_err(rtd->dev, "%s, set jack failed on %s (ret=%d)\n",
+			__func__, component->name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mt8189_headset_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_card *card = rtd->card;
+	struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+	struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8189_JACK_HEADSET];
+	struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+	int ret;
+	int type;
+
+	ret = snd_soc_dapm_new_controls(&card->dapm, mt8189_nau8825_widgets,
+					ARRAY_SIZE(mt8189_nau8825_widgets));
+	if (ret) {
+		dev_err(rtd->dev, "unable to add nau8825 card widget, ret %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_add_card_controls(card, mt8189_nau8825_controls,
+					ARRAY_SIZE(mt8189_nau8825_controls));
+	if (ret) {
+		dev_err(rtd->dev, "unable to add nau8825 card controls, ret %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+					 SND_JACK_HEADSET | SND_JACK_BTN_0 |
+					 SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+					 SND_JACK_BTN_3,
+					 jack,
+					 nau8825_jack_pins,
+					 ARRAY_SIZE(nau8825_jack_pins));
+	if (ret) {
+		dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+		return ret;
+	}
+
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+	type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3;
+	ret = snd_soc_component_set_jack(component, jack, (void *)&type);
+
+	if (ret) {
+		dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+};
+
+static void mt8189_headset_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+
+	snd_soc_component_set_jack(component, NULL, NULL);
+}
+
+static int mt8189_nau8825_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+	unsigned int rate = params_rate(params);
+	unsigned int bit_width = params_width(params);
+	int clk_freq, ret;
+
+	clk_freq = rate * 2 * bit_width;
+	dev_dbg(codec_dai->dev, "clk_freq %d, rate: %d, bit_width: %d\n",
+		clk_freq, rate, bit_width);
+
+	/* Configure clock for codec */
+	ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret);
+		return ret;
+	}
+
+	/* Configure pll for codec */
+	ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq,
+				  params_rate(params) * 256);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_ops mt8189_nau8825_ops = {
+	.hw_params = mt8189_nau8825_hw_params,
+};
+
+static int mt8189_headset_i2s_hw_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+	unsigned int rate = params_rate(params);
+	int bitwidth;
+	int ret;
+
+	bitwidth = snd_pcm_format_width(params_format(params));
+	if (bitwidth < 0) {
+		dev_err(card->dev, "invalid bit width: %d\n", bitwidth);
+		return bitwidth;
+	}
+
+	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth);
+	if (ret) {
+		dev_err(card->dev, "failed to set tdm slot\n");
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, 1, rate * 32, rate * 512);
+	if (ret) {
+		dev_err(card->dev, "failed to set pll\n");
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 1, rate * 512, SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(card->dev, "failed to set sysclk\n");
+		return ret;
+	}
+
+	return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 512,
+				      SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8189_headset_i2s_ops = {
+	.hw_params = mt8189_headset_i2s_hw_params,
+};
+
+static int mt8189_nau8825_soc_card_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)
+{
+	struct snd_soc_card *card = soc_card_data->card_data->card;
+	struct snd_soc_dai_link *dai_link;
+	bool init_nau8825 = false;
+	bool init_rt5682s = false;
+	bool init_rt5650 = false;
+	bool init_rt5682i = false;
+	bool init_dumb = false;
+	int i;
+
+	dev_dbg(card->dev, "%s(), legacy: %d\n", __func__, legacy);
+
+	for_each_card_prelinks(card, i, dai_link) {
+		if (strcmp(dai_link->name, "TDM_DPTX_BE") == 0) {
+			if (dai_link->num_codecs &&
+			    strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
+				dai_link->init = mt8189_dptx_codec_init;
+		} else if (strcmp(dai_link->name, "PCM_0_BE") == 0) {
+			if (dai_link->num_codecs &&
+			    strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
+				dai_link->init = mt8189_hdmi_codec_init;
+		} else if (strcmp(dai_link->name, "I2SOUT0_BE") == 0 ||
+			   strcmp(dai_link->name, "I2SIN0_BE") == 0) {
+			if (!strcmp(dai_link->codecs->dai_name, NAU8825_CODEC_DAI)) {
+				dai_link->ops = &mt8189_nau8825_ops;
+				if (!init_nau8825) {
+					dai_link->init = mt8189_headset_codec_init;
+					dai_link->exit = mt8189_headset_codec_exit;
+					init_nau8825 = true;
+				}
+			} else if (!strcmp(dai_link->codecs->dai_name, RT5682S_CODEC_DAI)) {
+				dai_link->ops = &mt8189_headset_i2s_ops;
+				if (!init_rt5682s) {
+					dai_link->init = mt8189_headset_codec_init;
+					dai_link->exit = mt8189_headset_codec_exit;
+					init_rt5682s = true;
+				}
+			} else if (!strcmp(dai_link->codecs->dai_name, RT5650_CODEC_DAI)) {
+				dai_link->ops = &mt8189_headset_i2s_ops;
+				if (!init_rt5650) {
+					dai_link->init = mt8189_headset_codec_init;
+					dai_link->exit = mt8189_headset_codec_exit;
+					init_rt5650 = true;
+				}
+			} else if (!strcmp(dai_link->codecs->dai_name, RT5682I_CODEC_DAI)) {
+				dai_link->ops = &mt8189_headset_i2s_ops;
+				if (!init_rt5682i) {
+					dai_link->init = mt8189_headset_codec_init;
+					dai_link->exit = mt8189_headset_codec_exit;
+					init_rt5682i = true;
+				}
+			} else {
+				if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) {
+					if (!init_dumb) {
+						dai_link->init = mt8189_dumb_amp_init;
+						init_dumb = true;
+					}
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+static struct snd_soc_card mt8189_nau8825_soc_card = {
+	.owner = THIS_MODULE,
+	.dai_link = mt8189_nau8825_dai_links,
+	.num_links = ARRAY_SIZE(mt8189_nau8825_dai_links),
+	.dapm_widgets = mt8189_nau8825_card_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt8189_nau8825_card_widgets),
+	.dapm_routes = mt8189_nau8825_card_routes,
+	.num_dapm_routes = ARRAY_SIZE(mt8189_nau8825_card_routes),
+	.controls = mt8189_nau8825_card_controls,
+	.num_controls = ARRAY_SIZE(mt8189_nau8825_card_controls),
+};
+
+static const struct mtk_soundcard_pdata mt8189_nau8825_card = {
+	.card_name = "mt8189_nau8825",
+	.card_data = &(struct mtk_platform_card_data) {
+		.card = &mt8189_nau8825_soc_card,
+		.num_jacks = MT8189_JACK_MAX,
+		.flags = NAU8825_HS_PRESENT
+	},
+	.sof_priv = NULL,
+	.soc_probe = mt8189_nau8825_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8189_rt5650_card = {
+	.card_name = "mt8189_rt5650",
+	.card_data = &(struct mtk_platform_card_data) {
+		.card = &mt8189_nau8825_soc_card,
+		.num_jacks = MT8189_JACK_MAX,
+		.flags = RT5650_HS_PRESENT
+	},
+	.sof_priv = NULL,
+	.soc_probe = mt8189_nau8825_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8189_rt5682s_card = {
+	.card_name = "mt8189_rt5682s",
+	.card_data = &(struct mtk_platform_card_data) {
+		.card = &mt8189_nau8825_soc_card,
+		.num_jacks = MT8189_JACK_MAX,
+		.flags = RT5682S_HS_PRESENT
+	},
+	.sof_priv = NULL,
+	.soc_probe = mt8189_nau8825_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8189_rt5682i_card = {
+	.card_name = "mt8189_rt5682i",
+	.card_data = &(struct mtk_platform_card_data) {
+		.card = &mt8189_nau8825_soc_card,
+		.num_jacks = MT8189_JACK_MAX,
+		.flags = RT5682I_HS_PRESENT
+	},
+	.sof_priv = NULL,
+	.soc_probe = mt8189_nau8825_soc_card_probe,
+};
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id mt8189_nau8825_dt_match[] = {
+	{.compatible = "mediatek,mt8189-nau8825-sound", .data = &mt8189_nau8825_card,},
+	{.compatible = "mediatek,mt8189-rt5650-sound", .data = &mt8189_rt5650_card,},
+	{.compatible = "mediatek,mt8189-rt5682s-sound", .data = &mt8189_rt5682s_card,},
+	{.compatible = "mediatek,mt8189-rt5682i-sound", .data = &mt8189_rt5682i_card,},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, mt8189_nau8825_dt_match);
+#endif
+
+static struct platform_driver mt8189_nau8825_driver = {
+	.driver = {
+		.name = "mt8189-nau8825",
+#if IS_ENABLED(CONFIG_OF)
+		.of_match_table = mt8189_nau8825_dt_match,
+#endif
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = mtk_soundcard_common_probe,
+};
+
+module_platform_driver(mt8189_nau8825_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8189 NAU8825 ALSA SoC machine driver");
+MODULE_AUTHOR("Darren Ye <darren.ye@mediatek.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("mt8189 nau8825 soc card");
-- 
2.46.0



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

* [PATCH 10/10] ASoC: dt-bindings: mediatek,mt8189-nau8825: add mt8189-nau8825 document
  2025-06-28  7:14 [PATCH 00/10] ASoC: mediatek: Add support for MT8189 SoC Cyril
                   ` (7 preceding siblings ...)
  2025-06-28  7:14 ` [PATCH 09/10] ASoC: mediatek: mt8189: add machine driver with nau8825 Cyril
@ 2025-06-28  7:14 ` Cyril
  2025-06-28 12:42   ` Krzysztof Kozlowski
  8 siblings, 1 reply; 17+ messages in thread
From: Cyril @ 2025-06-28  7:14 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group, cyril.chao,
	Cyril Chao

From: Cyril Chao <Cyril.Chao@mediatek.com>

Add document for mt8189 board with nau8825.

Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
---
 .../sound/mediatek,mt8189-nau8825.yaml        | 103 ++++++++++++++++++
 1 file changed, 103 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8189-nau8825.yaml

diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8189-nau8825.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8189-nau8825.yaml
new file mode 100644
index 000000000..331c537d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8189-nau8825.yaml
@@ -0,0 +1,103 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mt8189-nau8825.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT8189 ASoC sound card
+
+maintainers:
+  - Darren Ye <darren.ye@mediatek.com>
+  - Cyril Chao <cyril.chao@mediatek.com>
+
+allOf:
+  - $ref: sound-card-common.yaml#
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt8189-nau8825-sound
+      - mediatek,mt8189-rt5650-sound
+      - mediatek,mt8189-rt5682s-sound
+      - mediatek,mt8189-rt5682i-sound
+
+  mediatek,platform:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: The phandle of MT8189 ASoC platform.
+
+patternProperties:
+  "^dai-link-[0-9]+$":
+    type: object
+    description:
+      Container for dai-link level properties and CODEC sub-nodes.
+
+    properties:
+      link-name:
+        description:
+          This property corresponds to the name of the BE dai-link to which
+          we are going to update parameters in this node.
+        items:
+          enum:
+            - TDM_DPTX_BE
+            - I2SOUT0_BE
+            - I2SIN0_BE
+            - I2SOUT1_BE
+
+      codec:
+        description: Holds subnode which indicates codec dai.
+        type: object
+        additionalProperties: false
+        properties:
+          sound-dai:
+            minItems: 1
+            maxItems: 2
+        required:
+          - sound-dai
+
+      dai-format:
+        description: audio format.
+        items:
+          enum:
+            - i2s
+            - right_j
+            - left_j
+            - dsp_a
+            - dsp_b
+
+      mediatek,clk-provider:
+        $ref: /schemas/types.yaml#/definitions/string
+        description: Indicates dai-link clock master.
+        enum:
+          - cpu
+          - codec
+
+    additionalProperties: false
+
+    required:
+      - link-name
+
+required:
+  - compatible
+  - mediatek,platform
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    sound {
+        compatible = "mediatek,mt8189-nau8825-sound";
+        model = "mt8189_rt9123_8825";
+        mediatek,platform = <&afe>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&aud_pins_default>;
+        dai-link-0 {
+            link-name = "I2SOUT1_BE";
+            dai-format = "i2s";
+            mediatek,clk-provider = "cpu";
+            codec {
+                sound-dai = <&nau8825>;
+            };
+        };
+    };
+
+...
-- 
2.46.0



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

* Re: [PATCH 09/10] ASoC: mediatek: mt8189: add machine driver with nau8825
  2025-06-28  7:14 ` [PATCH 09/10] ASoC: mediatek: mt8189: add machine driver with nau8825 Cyril
@ 2025-06-28 12:39   ` Krzysztof Kozlowski
  2025-07-18  8:44     ` Cyril Chao (钞悦)
  0 siblings, 1 reply; 17+ messages in thread
From: Krzysztof Kozlowski @ 2025-06-28 12:39 UTC (permalink / raw)
  To: Cyril, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group

On 28/06/2025 09:14, Cyril wrote:
> +
> +static int mt8189_nau8825_soc_card_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)
> +{
> +	struct snd_soc_card *card = soc_card_data->card_data->card;
> +	struct snd_soc_dai_link *dai_link;
> +	bool init_nau8825 = false;
> +	bool init_rt5682s = false;
> +	bool init_rt5650 = false;
> +	bool init_rt5682i = false;
> +	bool init_dumb = false;
> +	int i;
> +
> +	dev_dbg(card->dev, "%s(), legacy: %d\n", __func__, legacy);

Drop probe success/start/finish messages. Pretty useless.

> +
> +	for_each_card_prelinks(card, i, dai_link) {
> +		if (strcmp(dai_link->name, "TDM_DPTX_BE") == 0) {
> +			if (dai_link->num_codecs &&
> +			    strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
> +				dai_link->init = mt8189_dptx_codec_init;
> +		} else if (strcmp(dai_link->name, "PCM_0_BE") == 0) {
> +			if (dai_link->num_codecs &&
> +			    strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
> +				dai_link->init = mt8189_hdmi_codec_init;
> +		} else if (strcmp(dai_link->name, "I2SOUT0_BE") == 0 ||
> +			   strcmp(dai_link->name, "I2SIN0_BE") == 0) {
> +			if (!strcmp(dai_link->codecs->dai_name, NAU8825_CODEC_DAI)) {
> +				dai_link->ops = &mt8189_nau8825_ops;
> +				if (!init_nau8825) {
> +					dai_link->init = mt8189_headset_codec_init;
> +					dai_link->exit = mt8189_headset_codec_exit;
> +					init_nau8825 = true;
> +				}
> +			} else if (!strcmp(dai_link->codecs->dai_name, RT5682S_CODEC_DAI)) {
> +				dai_link->ops = &mt8189_headset_i2s_ops;
> +				if (!init_rt5682s) {
> +					dai_link->init = mt8189_headset_codec_init;
> +					dai_link->exit = mt8189_headset_codec_exit;
> +					init_rt5682s = true;
> +				}
> +			} else if (!strcmp(dai_link->codecs->dai_name, RT5650_CODEC_DAI)) {
> +				dai_link->ops = &mt8189_headset_i2s_ops;
> +				if (!init_rt5650) {
> +					dai_link->init = mt8189_headset_codec_init;
> +					dai_link->exit = mt8189_headset_codec_exit;
> +					init_rt5650 = true;
> +				}
> +			} else if (!strcmp(dai_link->codecs->dai_name, RT5682I_CODEC_DAI)) {
> +				dai_link->ops = &mt8189_headset_i2s_ops;
> +				if (!init_rt5682i) {
> +					dai_link->init = mt8189_headset_codec_init;
> +					dai_link->exit = mt8189_headset_codec_exit;
> +					init_rt5682i = true;
> +				}
> +			} else {
> +				if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) {
> +					if (!init_dumb) {
> +						dai_link->init = mt8189_dumb_amp_init;
> +						init_dumb = true;
> +					}
> +				}
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static struct snd_soc_card mt8189_nau8825_soc_card = {
> +	.owner = THIS_MODULE,
> +	.dai_link = mt8189_nau8825_dai_links,
> +	.num_links = ARRAY_SIZE(mt8189_nau8825_dai_links),
> +	.dapm_widgets = mt8189_nau8825_card_widgets,
> +	.num_dapm_widgets = ARRAY_SIZE(mt8189_nau8825_card_widgets),
> +	.dapm_routes = mt8189_nau8825_card_routes,
> +	.num_dapm_routes = ARRAY_SIZE(mt8189_nau8825_card_routes),
> +	.controls = mt8189_nau8825_card_controls,
> +	.num_controls = ARRAY_SIZE(mt8189_nau8825_card_controls),
> +};
> +
> +static const struct mtk_soundcard_pdata mt8189_nau8825_card = {
> +	.card_name = "mt8189_nau8825",
> +	.card_data = &(struct mtk_platform_card_data) {
> +		.card = &mt8189_nau8825_soc_card,
> +		.num_jacks = MT8189_JACK_MAX,
> +		.flags = NAU8825_HS_PRESENT
> +	},
> +	.sof_priv = NULL,
> +	.soc_probe = mt8189_nau8825_soc_card_probe,
> +};
> +
> +static const struct mtk_soundcard_pdata mt8189_rt5650_card = {
> +	.card_name = "mt8189_rt5650",
> +	.card_data = &(struct mtk_platform_card_data) {
> +		.card = &mt8189_nau8825_soc_card,
> +		.num_jacks = MT8189_JACK_MAX,
> +		.flags = RT5650_HS_PRESENT
> +	},
> +	.sof_priv = NULL,
> +	.soc_probe = mt8189_nau8825_soc_card_probe,
> +};
> +
> +static const struct mtk_soundcard_pdata mt8189_rt5682s_card = {
> +	.card_name = "mt8189_rt5682s",
> +	.card_data = &(struct mtk_platform_card_data) {
> +		.card = &mt8189_nau8825_soc_card,
> +		.num_jacks = MT8189_JACK_MAX,
> +		.flags = RT5682S_HS_PRESENT
> +	},
> +	.sof_priv = NULL,
> +	.soc_probe = mt8189_nau8825_soc_card_probe,
> +};
> +
> +static const struct mtk_soundcard_pdata mt8189_rt5682i_card = {
> +	.card_name = "mt8189_rt5682i",
> +	.card_data = &(struct mtk_platform_card_data) {
> +		.card = &mt8189_nau8825_soc_card,
> +		.num_jacks = MT8189_JACK_MAX,
> +		.flags = RT5682I_HS_PRESENT
> +	},
> +	.sof_priv = NULL,
> +	.soc_probe = mt8189_nau8825_soc_card_probe,
> +};
> +
> +#if IS_ENABLED(CONFIG_OF)

Drop, you have warnings now :/

> +static const struct of_device_id mt8189_nau8825_dt_match[] = {
> +	{.compatible = "mediatek,mt8189-nau8825-sound", .data = &mt8189_nau8825_card,},
> +	{.compatible = "mediatek,mt8189-rt5650-sound", .data = &mt8189_rt5650_card,},
> +	{.compatible = "mediatek,mt8189-rt5682s-sound", .data = &mt8189_rt5682s_card,},
> +	{.compatible = "mediatek,mt8189-rt5682i-sound", .data = &mt8189_rt5682i_card,},
> +	{}
> +};
> +
> +MODULE_DEVICE_TABLE(of, mt8189_nau8825_dt_match);
> +#endif
> +
> +static struct platform_driver mt8189_nau8825_driver = {
> +	.driver = {
> +		.name = "mt8189-nau8825",
> +#if IS_ENABLED(CONFIG_OF)

Drop all this ifdefry, not helpful.

> +		.of_match_table = mt8189_nau8825_dt_match,
> +#endif
> +		.pm = &snd_soc_pm_ops,
> +	},
> +	.probe = mtk_soundcard_common_probe,
> +};
> +
> +module_platform_driver(mt8189_nau8825_driver);
> +
> +/* Module information */
> +MODULE_DESCRIPTION("MT8189 NAU8825 ALSA SoC machine driver");
> +MODULE_AUTHOR("Darren Ye <darren.ye@mediatek.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("mt8189 nau8825 soc card");

That's neither needed nor correct. Look how aliases are created first.


Best regards,
Krzysztof


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

* Re: [PATCH 10/10] ASoC: dt-bindings: mediatek,mt8189-nau8825: add mt8189-nau8825 document
  2025-06-28  7:14 ` [PATCH 10/10] ASoC: dt-bindings: mediatek,mt8189-nau8825: add mt8189-nau8825 document Cyril
@ 2025-06-28 12:42   ` Krzysztof Kozlowski
  2025-07-18  8:48     ` Cyril Chao (钞悦)
  0 siblings, 1 reply; 17+ messages in thread
From: Krzysztof Kozlowski @ 2025-06-28 12:42 UTC (permalink / raw)
  To: Cyril, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group

On 28/06/2025 09:14, Cyril wrote:
> From: Cyril Chao <Cyril.Chao@mediatek.com>
> 
> Add document for mt8189 board with nau8825.
> 
> Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>

Why does the binding come after user? Follow submitting patches in DT.

> ---
>  .../sound/mediatek,mt8189-nau8825.yaml        | 103 ++++++++++++++++++
>  1 file changed, 103 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8189-nau8825.yaml
> 
> diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8189-nau8825.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8189-nau8825.yaml
> new file mode 100644
> index 000000000..331c537d3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8189-nau8825.yaml
> @@ -0,0 +1,103 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/mediatek,mt8189-nau8825.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek MT8189 ASoC sound card
> +
> +maintainers:
> +  - Darren Ye <darren.ye@mediatek.com>
> +  - Cyril Chao <cyril.chao@mediatek.com>
> +
> +allOf:
> +  - $ref: sound-card-common.yaml#
> +
> +properties:
> +  compatible:
> +    enum:
> +      - mediatek,mt8189-nau8825-sound
> +      - mediatek,mt8189-rt5650-sound
> +      - mediatek,mt8189-rt5682s-sound
> +      - mediatek,mt8189-rt5682i-sound

Sound is redundant. Can it be anything else?


Best regards,
Krzysztof


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

* Re: [PATCH 08/10] ASoC: dt-bindings: mediatek,mt8189-afe-pcm: add audio afe document
  2025-06-28  7:14 ` [PATCH 08/10] ASoC: dt-bindings: mediatek,mt8189-afe-pcm: add audio afe document Cyril
@ 2025-06-28 12:46   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 17+ messages in thread
From: Krzysztof Kozlowski @ 2025-06-28 12:46 UTC (permalink / raw)
  To: Cyril, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, Project_Global_Chrome_Upstream_Group

On 28/06/2025 09:14, Cyril wrote:
> From: Cyril Chao <Cyril.Chao@mediatek.com>
> 
> Add mt8189 audio afe document.
> 
> Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
> ---
>  .../sound/mediatek,mt8189-afe-pcm.yaml        | 162 ++++++++++++++++++
>  1 file changed, 162 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8189-afe-pcm.yaml
> 
All your properties should follow same order as DTS coding style, but...
 meh...

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof


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

* Re: [PATCH 09/10] ASoC: mediatek: mt8189: add machine driver with nau8825
  2025-06-28 12:39   ` Krzysztof Kozlowski
@ 2025-07-18  8:44     ` Cyril Chao (钞悦)
  2025-07-18  9:18       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 17+ messages in thread
From: Cyril Chao (钞悦) @ 2025-07-18  8:44 UTC (permalink / raw)
  To: krzk@kernel.org, broonie@kernel.org, conor+dt@kernel.org,
	tiwai@suse.com, robh@kernel.org, lgirdwood@gmail.com,
	matthias.bgg@gmail.com, krzk+dt@kernel.org, perex@perex.cz,
	AngeloGioacchino Del Regno
  Cc: linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
	linux-sound@vger.kernel.org, devicetree@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group

On Sat, 2025-06-28 at 14:39 +0200, Krzysztof Kozlowski wrote:
> > +             .of_match_table = mt8189_nau8825_dt_match,
> > +#endif
> > +             .pm = &snd_soc_pm_ops,
> > +     },
> > +     .probe = mtk_soundcard_common_probe,
> > +};
> > +
> > +module_platform_driver(mt8189_nau8825_driver);
> > +
> > +/* Module information */
> > +MODULE_DESCRIPTION("MT8189 NAU8825 ALSA SoC machine driver");
> > +MODULE_AUTHOR("Darren Ye <darren.ye@mediatek.com>");
> > +MODULE_LICENSE("GPL");
> > +MODULE_ALIAS("mt8189 nau8825 soc card");
> 
> That's neither needed nor correct. Look how aliases are created
> first.

I reffered to the previous platform(mt8188). Could you help to give an
example about MODULE_ALIAS or some doc for me to reffer? Much thanks ~~

Best Regards
Cyril Chao

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

* Re: [PATCH 10/10] ASoC: dt-bindings: mediatek,mt8189-nau8825: add mt8189-nau8825 document
  2025-06-28 12:42   ` Krzysztof Kozlowski
@ 2025-07-18  8:48     ` Cyril Chao (钞悦)
  2025-07-18  9:19       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 17+ messages in thread
From: Cyril Chao (钞悦) @ 2025-07-18  8:48 UTC (permalink / raw)
  To: krzk@kernel.org, broonie@kernel.org, conor+dt@kernel.org,
	tiwai@suse.com, robh@kernel.org, lgirdwood@gmail.com,
	matthias.bgg@gmail.com, krzk+dt@kernel.org, perex@perex.cz,
	AngeloGioacchino Del Regno
  Cc: linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
	linux-sound@vger.kernel.org, devicetree@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group

On Sat, 2025-06-28 at 14:42 +0200, Krzysztof Kozlowski wrote:
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
> 
> 
> On 28/06/2025 09:14, Cyril wrote:
> > From: Cyril Chao <Cyril.Chao@mediatek.com>
> > 
> > Add document for mt8189 board with nau8825.
> > 
> > Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
> 
> Why does the binding come after user? Follow submitting patches in
> DT.
> 
Could you help to clarify this? Is it the order in which I submitted
the dt-binding patch that's incorrect? Much thanks~~

> > ---
> >  .../sound/mediatek,mt8189-nau8825.yaml        | 103
> > ++++++++++++++++++
> >  1 file changed, 103 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/sound/mediatek,mt8189-
> > nau8825.yaml
> > 
> > diff --git
> > a/Documentation/devicetree/bindings/sound/mediatek,mt8189-
> > nau8825.yaml
> > b/Documentation/devicetree/bindings/sound/mediatek,mt8189-
> > nau8825.yaml
> > new file mode 100644
> > index 000000000..331c537d3
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8189-
> > nau8825.yaml
> > @@ -0,0 +1,103 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: 
> > https://urldefense.com/v3/__http://devicetree.org/schemas/sound/mediatek,mt8189-nau8825.yaml*__;Iw!!CTRNKA9wMg0ARbw!j89p8C_6FDSbTlAEyYXTN2T5R6NmwjSwuhNHbIBLbbCRLSUqEWDlBy-FlOeo8rxCTSJeuH6BLVZS00w$
> > +$schema: 
> > https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!j89p8C_6FDSbTlAEyYXTN2T5R6NmwjSwuhNHbIBLbbCRLSUqEWDlBy-FlOeo8rxCTSJeuH6BzAjmYYE$
> > +
> > +title: MediaTek MT8189 ASoC sound card
> > +
> > +maintainers:
> > +  - Darren Ye <darren.ye@mediatek.com>
> > +  - Cyril Chao <cyril.chao@mediatek.com>
> > +
> > +allOf:
> > +  - $ref: sound-card-common.yaml#
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - mediatek,mt8189-nau8825-sound
> > +      - mediatek,mt8189-rt5650-sound
> > +      - mediatek,mt8189-rt5682s-sound
> > +      - mediatek,mt8189-rt5682i-sound
> 
> Sound is redundant. Can it be anything else?
> 
Okay, I will remove 'sound' next version, and like this:
mediatek,mt8189-nau8825
mediatek,mt8189-rt5650
mediatek,mt8189-rt5682s
mediatek,mt8189-rt5682i

Thanks for review~~~

Best Regards
Cyril Chao

> 
> Best regards,
> Krzysztof

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

* Re: [PATCH 09/10] ASoC: mediatek: mt8189: add machine driver with nau8825
  2025-07-18  8:44     ` Cyril Chao (钞悦)
@ 2025-07-18  9:18       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 17+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-18  9:18 UTC (permalink / raw)
  To: Cyril Chao (钞悦), broonie@kernel.org,
	conor+dt@kernel.org, tiwai@suse.com, robh@kernel.org,
	lgirdwood@gmail.com, matthias.bgg@gmail.com, krzk+dt@kernel.org,
	perex@perex.cz, AngeloGioacchino Del Regno
  Cc: linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
	linux-sound@vger.kernel.org, devicetree@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group

On 18/07/2025 10:44, Cyril Chao (钞悦) wrote:
> On Sat, 2025-06-28 at 14:39 +0200, Krzysztof Kozlowski wrote:
>>> +             .of_match_table = mt8189_nau8825_dt_match,
>>> +#endif
>>> +             .pm = &snd_soc_pm_ops,
>>> +     },
>>> +     .probe = mtk_soundcard_common_probe,
>>> +};
>>> +
>>> +module_platform_driver(mt8189_nau8825_driver);
>>> +
>>> +/* Module information */
>>> +MODULE_DESCRIPTION("MT8189 NAU8825 ALSA SoC machine driver");
>>> +MODULE_AUTHOR("Darren Ye <darren.ye@mediatek.com>");
>>> +MODULE_LICENSE("GPL");
>>> +MODULE_ALIAS("mt8189 nau8825 soc card");
>>
>> That's neither needed nor correct. Look how aliases are created
>> first.
> 
> I reffered to the previous platform(mt8188). Could you help to give an
> example about MODULE_ALIAS or some doc for me to reffer? Much thanks ~~

If you ask for doc, then it feels like you do not know if you need it. I
think you do not need it and the burden of proving why you need it is on
you.

Best regards,
Krzysztof


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

* Re: [PATCH 10/10] ASoC: dt-bindings: mediatek,mt8189-nau8825: add mt8189-nau8825 document
  2025-07-18  8:48     ` Cyril Chao (钞悦)
@ 2025-07-18  9:19       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 17+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-18  9:19 UTC (permalink / raw)
  To: Cyril Chao (钞悦), broonie@kernel.org,
	conor+dt@kernel.org, tiwai@suse.com, robh@kernel.org,
	lgirdwood@gmail.com, matthias.bgg@gmail.com, krzk+dt@kernel.org,
	perex@perex.cz, AngeloGioacchino Del Regno
  Cc: linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
	linux-sound@vger.kernel.org, devicetree@vger.kernel.org,
	Project_Global_Chrome_Upstream_Group

On 18/07/2025 10:48, Cyril Chao (钞悦) wrote:
> On Sat, 2025-06-28 at 14:42 +0200, Krzysztof Kozlowski wrote:
>> External email : Please do not click links or open attachments until
>> you have verified the sender or the content.
>>
>>
>> On 28/06/2025 09:14, Cyril wrote:
>>> From: Cyril Chao <Cyril.Chao@mediatek.com>
>>>
>>> Add document for mt8189 board with nau8825.
>>>
>>> Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
>>
>> Why does the binding come after user? Follow submitting patches in
>> DT.
>>
> Could you help to clarify this? Is it the order in which I submitted
> the dt-binding patch that's incorrect? Much thanks~~


Yes, it is incorrect. What does the mentioned doc say? I really hope you
read the doc before you just responded to me..

Best regards,
Krzysztof


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

end of thread, other threads:[~2025-07-18  9:45 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-28  7:14 [PATCH 00/10] ASoC: mediatek: Add support for MT8189 SoC Cyril
2025-06-28  7:14 ` [PATCH 02/10] ASoC: mediatek: mt8189: support audio clock control Cyril
2025-06-28  7:14 ` [PATCH 03/10] ASoC: mediatek: mt8189: support ADDA in platform driver Cyril
2025-06-28  7:14 ` [PATCH 04/10] ASoC: mediatek: mt8189: support I2S " Cyril
2025-06-28  7:14 ` [PATCH 05/10] ASoC: mediatek: mt8189: support TDM " Cyril
2025-06-28  7:14 ` [PATCH 06/10] ASoC: mediatek: mt8189: support PCM " Cyril
2025-06-28  7:14 ` [PATCH 07/10] ASoC: mediatek: mt8189: add " Cyril
2025-06-28  7:14 ` [PATCH 08/10] ASoC: dt-bindings: mediatek,mt8189-afe-pcm: add audio afe document Cyril
2025-06-28 12:46   ` Krzysztof Kozlowski
2025-06-28  7:14 ` [PATCH 09/10] ASoC: mediatek: mt8189: add machine driver with nau8825 Cyril
2025-06-28 12:39   ` Krzysztof Kozlowski
2025-07-18  8:44     ` Cyril Chao (钞悦)
2025-07-18  9:18       ` Krzysztof Kozlowski
2025-06-28  7:14 ` [PATCH 10/10] ASoC: dt-bindings: mediatek,mt8189-nau8825: add mt8189-nau8825 document Cyril
2025-06-28 12:42   ` Krzysztof Kozlowski
2025-07-18  8:48     ` Cyril Chao (钞悦)
2025-07-18  9:19       ` Krzysztof Kozlowski

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).