* [PATCH v3 00/10] ASoC: mediatek: Add support for MT8196 SoC
@ 2025-05-14 8:11 Darren.Ye
2025-05-14 8:11 ` [PATCH v3 01/10] ASoC: mediatek: common: modify mtk afe platform driver for mt8196 Darren.Ye
` (7 more replies)
0 siblings, 8 replies; 23+ messages in thread
From: Darren.Ye @ 2025-05-14 8:11 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
This series of patches adds support for Mediatek AFE of MT8196 SoC.
Patches are based on broonie tree "for-next" branch.
Changes since v2:
- remove the mtk_memif_set_channel interface modify.
- remove duplicate definitions from the header file.
- move the afe gate clk to the audio driver for management and registration
and manage the afe clk gate in each dai driver.
- delete the useless clk source.
- the i2s driver adds i2s clk gate management, removes the additional dts
configuration of i2s4.
- the afe and i2s dai driver,memif and irq data structs are encapsulated using
macros to reduce the amount of code.
- the volatile reg is modified as suggested.
- mt6681 codec is not supported, the mt6681 keyword is removed.
- the name of the machine driver is changed from mt8196-mt6681.c to mt8196-nau8825.c
- remove the i2s4 configuration from mt8196-afe.yaml and make the modifications as suggested.
- change the mt8196-mt6681.yaml to mt8196-nau8825.yaml and make the modifications as suggested.
Changes since v1:
- modify mtk_memif_set_channel and mtk_afe_pcm_pointer interfaces
are improved to support mt8196.
- remove duplicate definitions in the mt8196 common header file.
- cm logic is merge into the afe platform driver.
- modify afe clk to return judgment logic and remove useless clk sources.
- refactor the mt8196 adda dai driver.
- remove the gpio module and use SND_SOC_DAPM_PINCTRL to manage it.
- removes CONNSYS_I2S related functions that are not supported in i2s dai driver.
- fixed mt8196-afe.yaml and mt8196-mt6681.yaml syntax issues.
- modify log printing in all modules.
- optimize the header file included for machine driver.
Darren Ye (10):
ASoC: mediatek: common: modify mtk afe platform driver for mt8196
ASoC: mediatek: mt8196: add common header
ASoC: mediatek: mt8196: support audio clock control
ASoC: mediatek: mt8196: support ADDA in platform driver
ASoC: mediatek: mt8196: support I2S in platform driver
ASoC: mediatek: mt8196: support TDM in platform driver
ASoC: mediatek: mt8196: add platform driver
ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE document
ASoC: mediatek: mt8196: add machine driver with nau8825
ASoC: dt-bindings: mediatek,mt8196-nau8825: add mt8196-nau8825
document
.../bindings/sound/mediatek,mt8196-afe.yaml | 155 +
.../sound/mediatek,mt8196-nau8825.yaml | 115 +
sound/soc/mediatek/Kconfig | 30 +
sound/soc/mediatek/Makefile | 1 +
.../mediatek/common/mtk-afe-platform-driver.c | 47 +-
.../mediatek/common/mtk-afe-platform-driver.h | 2 +
sound/soc/mediatek/mt8196/Makefile | 18 +
sound/soc/mediatek/mt8196/mt8196-afe-clk.c | 723 +
sound/soc/mediatek/mt8196/mt8196-afe-clk.h | 142 +
sound/soc/mediatek/mt8196/mt8196-afe-common.h | 206 +
sound/soc/mediatek/mt8196/mt8196-afe-pcm.c | 2642 ++++
sound/soc/mediatek/mt8196/mt8196-audsys-clk.c | 252 +
sound/soc/mediatek/mt8196/mt8196-audsys-clk.h | 14 +
.../soc/mediatek/mt8196/mt8196-audsys-clkid.h | 78 +
sound/soc/mediatek/mt8196/mt8196-dai-adda.c | 918 ++
sound/soc/mediatek/mt8196/mt8196-dai-i2s.c | 4052 ++++++
sound/soc/mediatek/mt8196/mt8196-dai-tdm.c | 862 ++
.../mediatek/mt8196/mt8196-interconnection.h | 121 +
sound/soc/mediatek/mt8196/mt8196-nau8825.c | 869 ++
sound/soc/mediatek/mt8196/mt8196-reg.h | 12068 ++++++++++++++++
20 files changed, 23299 insertions(+), 16 deletions(-)
create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-nau8825.yaml
create mode 100644 sound/soc/mediatek/mt8196/Makefile
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.h
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-common.h
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clk.h
create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clkid.h
create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-adda.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-i2s.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-tdm.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-interconnection.h
create mode 100644 sound/soc/mediatek/mt8196/mt8196-nau8825.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-reg.h
--
2.45.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH v3 01/10] ASoC: mediatek: common: modify mtk afe platform driver for mt8196
2025-05-14 8:11 [PATCH v3 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
@ 2025-05-14 8:11 ` Darren.Ye
2025-05-14 8:11 ` [PATCH v3 03/10] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
` (6 subsequent siblings)
7 siblings, 0 replies; 23+ messages in thread
From: Darren.Ye @ 2025-05-14 8:11 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Mofify the pcm pointer interface to support 64-bit address access.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
.../mediatek/common/mtk-afe-platform-driver.c | 47 ++++++++++++-------
.../mediatek/common/mtk-afe-platform-driver.h | 2 +
2 files changed, 33 insertions(+), 16 deletions(-)
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
index 6b6330583941..a86594dca2b7 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
@@ -86,29 +86,44 @@ snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component,
const struct mtk_base_memif_data *memif_data = memif->data;
struct regmap *regmap = afe->regmap;
struct device *dev = afe->dev;
- int reg_ofs_base = memif_data->reg_ofs_base;
- int reg_ofs_cur = memif_data->reg_ofs_cur;
- unsigned int hw_ptr = 0, hw_base = 0;
- int ret, pcm_ptr_bytes;
-
- ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr);
- if (ret || hw_ptr == 0) {
- dev_err(dev, "%s hw_ptr err\n", __func__);
- pcm_ptr_bytes = 0;
+ unsigned int hw_ptr_lower32 = 0, hw_ptr_upper32 = 0;
+ unsigned int hw_base_lower32 = 0, hw_base_upper32 = 0;
+ unsigned long long hw_ptr = 0, hw_base = 0;
+ int ret;
+ unsigned long long pcm_ptr_bytes = 0;
+
+ ret = regmap_read(regmap, memif_data->reg_ofs_cur, &hw_ptr_lower32);
+ if (ret || hw_ptr_lower32 == 0) {
+ dev_err(dev, "%s hw_ptr_lower32 err\n", __func__);
goto POINTER_RETURN_FRAMES;
}
- ret = regmap_read(regmap, reg_ofs_base, &hw_base);
- if (ret || hw_base == 0) {
- dev_err(dev, "%s hw_ptr err\n", __func__);
- pcm_ptr_bytes = 0;
- goto POINTER_RETURN_FRAMES;
+ if (memif_data->reg_ofs_cur_msb) {
+ ret = regmap_read(regmap, memif_data->reg_ofs_cur_msb, &hw_ptr_upper32);
+ if (ret) {
+ dev_err(dev, "%s hw_ptr_upper32 err\n", __func__);
+ goto POINTER_RETURN_FRAMES;
+ }
}
- pcm_ptr_bytes = hw_ptr - hw_base;
+ ret = regmap_read(regmap, memif_data->reg_ofs_base, &hw_base_lower32);
+ if (ret || hw_base_lower32 == 0) {
+ dev_err(dev, "%s hw_base_lower32 err\n", __func__);
+ goto POINTER_RETURN_FRAMES;
+ }
+ if (memif_data->reg_ofs_base_msb) {
+ ret = regmap_read(regmap, memif_data->reg_ofs_base_msb, &hw_base_upper32);
+ if (ret) {
+ dev_err(dev, "%s hw_base_upper32 err\n", __func__);
+ goto POINTER_RETURN_FRAMES;
+ }
+ }
+ hw_ptr = ((unsigned long long)hw_ptr_upper32 << 32) + hw_ptr_lower32;
+ hw_base = ((unsigned long long)hw_base_upper32 << 32) + hw_base_lower32;
POINTER_RETURN_FRAMES:
- return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
+ pcm_ptr_bytes = MTK_WORD_SIZE_ALIGN(hw_ptr - hw_base);
+ return bytes_to_frames(substream->runtime, (ssize_t)pcm_ptr_bytes);
}
EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer);
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.h b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
index fcc923b88f12..9809e60db511 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.h
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
@@ -12,6 +12,8 @@
#define AFE_PCM_NAME "mtk-afe-pcm"
extern const struct snd_soc_component_driver mtk_afe_pcm_platform;
+#define MTK_WORD_SIZE_ALIGN(x) ((x) & (0xfffffffff0))
+
struct mtk_base_afe;
struct snd_pcm;
struct snd_soc_component;
--
2.45.2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v3 03/10] ASoC: mediatek: mt8196: support audio clock control
2025-05-14 8:11 [PATCH v3 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
2025-05-14 8:11 ` [PATCH v3 01/10] ASoC: mediatek: common: modify mtk afe platform driver for mt8196 Darren.Ye
@ 2025-05-14 8:11 ` Darren.Ye
2025-05-15 8:30 ` AngeloGioacchino Del Regno
2025-05-14 8:11 ` [PATCH v3 04/10] ASoC: mediatek: mt8196: support ADDA in platform driver Darren.Ye
` (5 subsequent siblings)
7 siblings, 1 reply; 23+ messages in thread
From: Darren.Ye @ 2025-05-14 8:11 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add audio clock wrapper and audio tuner control.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/mt8196/mt8196-afe-clk.c | 723 ++++++++++++++++++
sound/soc/mediatek/mt8196/mt8196-afe-clk.h | 142 ++++
sound/soc/mediatek/mt8196/mt8196-audsys-clk.c | 252 ++++++
sound/soc/mediatek/mt8196/mt8196-audsys-clk.h | 14 +
.../soc/mediatek/mt8196/mt8196-audsys-clkid.h | 78 ++
5 files changed, 1209 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.h
create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clk.h
create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clkid.h
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.c b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
new file mode 100644
index 000000000000..83b5ee9d30ef
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
@@ -0,0 +1,723 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8196-afe-clk.c -- Mediatek 8196 afe clock ctrl
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include "mt8196-afe-common.h"
+#include "mt8196-audsys-clk.h"
+#include "mt8196-afe-clk.h"
+
+static const char *aud_clks[MT8196_CLK_NUM] = {
+ /* vlp clk */
+ [MT8196_CLK_VLP_MUX_AUDIOINTBUS] = "top_aud_intbus",
+ [MT8196_CLK_VLP_MUX_AUD_ENG1] = "top_aud_eng1",
+ [MT8196_CLK_VLP_MUX_AUD_ENG2] = "top_aud_eng2",
+ [MT8196_CLK_VLP_MUX_AUDIO_H] = "top_aud_h",
+ [MT8196_CLK_VLP_CLK26M] = "vlp_clk26m",
+ /* pll */
+ [MT8196_CLK_TOP_APLL1_CK] = "apll1",
+ [MT8196_CLK_TOP_APLL2_CK] = "apll2",
+ /* divider */
+ [MT8196_CLK_TOP_APLL1_D4] = "apll1_d4",
+ [MT8196_CLK_TOP_APLL2_D4] = "apll2_d4",
+ [MT8196_CLK_TOP_APLL12_DIV_I2SIN0] = "apll12_div_i2sin0",
+ [MT8196_CLK_TOP_APLL12_DIV_I2SIN1] = "apll12_div_i2sin1",
+ [MT8196_CLK_TOP_APLL12_DIV_FMI2S] = "apll12_div_fmi2s",
+ [MT8196_CLK_TOP_APLL12_DIV_TDMOUT_M] = "apll12_div_tdmout_m",
+ [MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B] = "apll12_div_tdmout_b",
+ /* mux */
+ [MT8196_CLK_TOP_MUX_AUD_1] = "top_apll1",
+ [MT8196_CLK_TOP_MUX_AUD_2] = "top_apll2",
+ [MT8196_CLK_TOP_I2SIN0_M_SEL] = "top_i2sin0",
+ [MT8196_CLK_TOP_I2SIN1_M_SEL] = "top_i2sin1",
+ [MT8196_CLK_TOP_FMI2S_M_SEL] = "top_fmi2s",
+ [MT8196_CLK_TOP_TDMOUT_M_SEL] = "top_dptx",
+ [MT8196_CLK_TOP_ADSP_SEL] = "top_adsp",
+ /* top 26m*/
+ [MT8196_CLK_TOP_CLK26M] = "clk26m",
+ /* clock gate */
+ [MT8196_CLK_AFE_AUDIO_HOPPING] = "afe_audio_hopping_ck",
+ [MT8196_CLK_AFE_AUDIO_F26M] = "afe_audio_f26m_ck",
+ [MT8196_CLK_AFE_APLL1] = "afe_apll1_ck",
+ [MT8196_CLK_AFE_APLL2] = "afe_apll2_ck",
+ [MT8196_CLK_AFE_APLL_TUNER1] = "afe_apll_tuner1",
+ [MT8196_CLK_AFE_APLL_TUNER2] = "afe_apll_tuner2",
+ [MT8196_CLK_AFE_ETDM_OUT4] = "afe_etdm_out4",
+ [MT8196_CLK_AFE_ETDM_IN6] = "afe_etdm_in6",
+ [MT8196_CLK_AFE_ETDM_OUT6] = "afe_etdm_out6",
+ [MT8196_CLK_AFE_TDM_OUT] = "afe_tdm_out",
+ [MT8196_CLK_AFE_CM0] = "afe_cm0",
+ [MT8196_CLK_AFE_CM1] = "afe_cm1",
+ [MT8196_CLK_AFE_CM2] = "afe_cm2",
+};
+
+int mt8196_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(mt8196_afe_enable_clk);
+
+void mt8196_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(mt8196_afe_disable_clk);
+
+static int mt8196_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 mt8196_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 MT8196_AUDIO_26M_EN_ON:
+ case MT8196_AUDIO_F3P25M_EN_ON:
+ case MT8196_AUDIO_APLL1_EN_ON:
+ case MT8196_AUDIO_APLL2_EN_ON:
+ return AUDIO_ENGEN_CON0;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_mask(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8196_AUDIO_26M_EN_ON:
+ return AUDIO_26M_EN_ON_MASK_SFT;
+ case MT8196_AUDIO_F3P25M_EN_ON:
+ return AUDIO_F3P25M_EN_ON_MASK_SFT;
+ case MT8196_AUDIO_APLL1_EN_ON:
+ return AUDIO_APLL1_EN_ON_MASK_SFT;
+ case MT8196_AUDIO_APLL2_EN_ON:
+ return AUDIO_APLL2_EN_ON_MASK_SFT;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_on_val(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8196_AUDIO_26M_EN_ON:
+ case MT8196_AUDIO_F3P25M_EN_ON:
+ case MT8196_AUDIO_APLL1_EN_ON:
+ case MT8196_AUDIO_APLL2_EN_ON:
+ return get_top_cg_mask(cg_type);
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_off_val(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8196_AUDIO_26M_EN_ON:
+ case MT8196_AUDIO_F3P25M_EN_ON:
+ case MT8196_AUDIO_APLL1_EN_ON:
+ case MT8196_AUDIO_APLL2_EN_ON:
+ return 0;
+ default:
+ return get_top_cg_mask(cg_type);
+ }
+}
+
+static int mt8196_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+ unsigned int reg = get_top_cg_reg(cg_type);
+ unsigned int mask = get_top_cg_mask(cg_type);
+ unsigned int val = get_top_cg_on_val(cg_type);
+
+ regmap_update_bits(afe->regmap, reg, mask, val);
+ return 0;
+}
+
+static int mt8196_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+ unsigned int reg = get_top_cg_reg(cg_type);
+ unsigned int mask = get_top_cg_mask(cg_type);
+ unsigned int val = get_top_cg_off_val(cg_type);
+
+ regmap_update_bits(afe->regmap, reg, mask, val);
+ return 0;
+}
+
+static int mt8196_afe_enable_afe_on(struct mtk_base_afe *afe)
+{
+ mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_26M_EN_ON);
+ return 0;
+}
+
+static int mt8196_afe_disable_afe_on(struct mtk_base_afe *afe)
+{
+ mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_26M_EN_ON);
+ return 0;
+}
+
+static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret = 0;
+
+ dev_dbg(afe->dev, "enable: %d\n", enable);
+
+ if (enable) {
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
+ if (ret)
+ return ret;
+
+ ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[MT8196_CLK_TOP_APLL1_CK]);
+ if (ret)
+ return ret;
+
+ /* 180.6336 / 4 = 45.1584MHz */
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1]);
+ if (ret)
+ return ret;
+
+ ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1],
+ afe_priv->clk[MT8196_CLK_TOP_APLL1_D4]);
+ if (ret)
+ return ret;
+
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ if (ret)
+ return ret;
+
+ ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
+ afe_priv->clk[MT8196_CLK_TOP_APLL1_CK]);
+ if (ret)
+ return ret;
+ } else {
+ ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1],
+ afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
+ if (ret)
+ return ret;
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1]);
+
+ ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[MT8196_CLK_TOP_CLK26M]);
+ if (ret)
+ return ret;
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
+ mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
+ afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ }
+
+ return 0;
+}
+
+static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret = 0;
+
+ dev_dbg(afe->dev, "enable: %d\n", enable);
+
+ if (enable) {
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
+ if (ret)
+ return ret;
+
+ ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2],
+ afe_priv->clk[MT8196_CLK_TOP_APLL2_CK]);
+ if (ret)
+ return ret;
+
+ /* 196.608 / 4 = 49.152MHz */
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2]);
+ if (ret)
+ return ret;
+
+ ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2],
+ afe_priv->clk[MT8196_CLK_TOP_APLL2_D4]);
+ if (ret)
+ return ret;
+
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ if (ret)
+ return ret;
+
+ ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
+ afe_priv->clk[MT8196_CLK_TOP_APLL2_CK]);
+ if (ret)
+ return ret;
+ } else {
+ ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2],
+ afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
+ if (ret)
+ return ret;
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2]);
+
+ ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2],
+ afe_priv->clk[MT8196_CLK_TOP_CLK26M]);
+ if (ret)
+ return ret;
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
+ mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
+ afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ }
+
+ return 0;
+}
+
+static int mt8196_afe_disable_apll(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret = 0;
+
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ if (ret)
+ return ret;
+
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
+ if (ret)
+ goto clk_ck_mux_aud1_err;
+
+ ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[MT8196_CLK_TOP_CLK26M]);
+ if (ret)
+ goto clk_ck_mux_aud1_parent_err;
+
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
+ if (ret)
+ goto clk_ck_mux_aud2_err;
+
+ ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2],
+ afe_priv->clk[MT8196_CLK_TOP_CLK26M]);
+ if (ret)
+ goto clk_ck_mux_aud2_parent_err;
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
+ mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
+ afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ return 0;
+
+clk_ck_mux_aud2_parent_err:
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
+clk_ck_mux_aud2_err:
+ mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[MT8196_CLK_TOP_APLL1_CK]);
+clk_ck_mux_aud1_parent_err:
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
+clk_ck_mux_aud1_err:
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+
+ return ret;
+}
+
+static void mt8196_afe_apll_init(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ if (afe_priv->vlp_ck) {
+ regmap_write(afe_priv->vlp_ck, VLP_APLL1_TUNER_CON0, VLP_APLL1_TUNER_CON0_VALUE);
+ regmap_write(afe_priv->vlp_ck, VLP_APLL2_TUNER_CON0, VLP_APLL2_TUNER_CON0_VALUE);
+ } else {
+ dev_warn(afe->dev, "vlp_ck regmap is null ptr\n");
+ }
+}
+
+int mt8196_apll1_enable(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ /* setting for APLL */
+ apll1_mux_setting(afe, true);
+
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL1]);
+ if (ret)
+ goto ERR_CLK_APLL1;
+
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER1]);
+ if (ret)
+ goto ERR_CLK_APLL1_TUNER;
+
+ /* 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 */
+ mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_APLL1_EN_ON);
+
+ return 0;
+
+ERR_CLK_APLL1_TUNER:
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER1]);
+ERR_CLK_APLL1:
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL1]);
+ return ret;
+}
+
+void mt8196_apll1_disable(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ /* audio apll1 off */
+ mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_APLL1_EN_ON);
+
+ /* apll1 freq tuner disable */
+ regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
+ FREQ_TUNER_EN_MASK_SFT,
+ 0x0);
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER1]);
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL1]);
+ apll1_mux_setting(afe, false);
+}
+
+int mt8196_apll2_enable(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ /* setting for APLL */
+ apll2_mux_setting(afe, true);
+
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL2]);
+ if (ret)
+ goto ERR_CLK_APLL2;
+
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER2]);
+ if (ret)
+ goto ERR_CLK_APLL2_TUNER;
+
+ /* 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 */
+ mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_APLL2_EN_ON);
+ return 0;
+
+ERR_CLK_APLL2_TUNER:
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER2]);
+ERR_CLK_APLL2:
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL2]);
+ return ret;
+
+ return 0;
+}
+
+void mt8196_apll2_disable(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ /* audio apll2 off */
+ mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_APLL2_EN_ON);
+
+ /* apll2 freq tuner disable */
+ regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
+ FREQ_TUNER_EN_MASK_SFT,
+ 0x0);
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER2]);
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL2]);
+ apll2_mux_setting(afe, false);
+}
+
+int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int clk_id = 0;
+
+ if (apll < MT8196_APLL1 || apll > MT8196_APLL2) {
+ dev_warn(afe->dev, "invalid clk id\n");
+ return 0;
+ }
+
+ if (apll == MT8196_APLL1)
+ clk_id = MT8196_CLK_TOP_APLL1_CK;
+ else
+ clk_id = MT8196_CLK_TOP_APLL2_CK;
+
+ return clk_get_rate(afe_priv->clk[clk_id]);
+}
+
+int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
+{
+ return ((rate % 8000) == 0) ? MT8196_APLL2 : MT8196_APLL1;
+}
+
+int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
+{
+ if (strcmp(name, APLL1_W_NAME) == 0)
+ return MT8196_APLL1;
+ else
+ return MT8196_APLL2;
+}
+
+/* mck */
+struct mt8196_mck_div {
+ int m_sel_id;
+ int div_clk_id;
+};
+
+static const struct mt8196_mck_div mck_div[MT8196_MCK_NUM] = {
+ [MT8196_I2SIN0_MCK] = {
+ .m_sel_id = MT8196_CLK_TOP_I2SIN0_M_SEL,
+ .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_I2SIN0,
+ },
+ [MT8196_I2SIN1_MCK] = {
+ .m_sel_id = MT8196_CLK_TOP_I2SIN1_M_SEL,
+ .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_I2SIN1,
+ },
+ [MT8196_FMI2S_MCK] = {
+ .m_sel_id = MT8196_CLK_TOP_FMI2S_M_SEL,
+ .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_FMI2S,
+ },
+ [MT8196_TDMOUT_MCK] = {
+ .m_sel_id = MT8196_CLK_TOP_TDMOUT_M_SEL,
+ .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_M,
+ },
+ [MT8196_TDMOUT_BCK] = {
+ .m_sel_id = -1,
+ .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B,
+ },
+};
+
+int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int apll = mt8196_get_apll_by_rate(afe, rate);
+ int apll_clk_id = apll == MT8196_APLL1 ?
+ MT8196_CLK_TOP_MUX_AUD_1 : MT8196_CLK_TOP_MUX_AUD_2;
+ int m_sel_id = 0;
+ int div_clk_id = 0;
+ int ret = 0;
+
+ dev_dbg(afe->dev, "mck_id: %d, rate: %d\n", mck_id, rate);
+
+ if (mck_id >= MT8196_MCK_NUM || mck_id < 0)
+ return -EINVAL;
+
+ m_sel_id = mck_div[mck_id].m_sel_id;
+ div_clk_id = mck_div[mck_id].div_clk_id;
+
+ /* select apll */
+ if (m_sel_id >= 0) {
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[m_sel_id]);
+ if (ret)
+ return ret;
+
+ ret = mt8196_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;
+ }
+ if (div_clk_id == MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B)
+ rate = rate * 16;
+
+ ret = mt8196_afe_enable_clk(afe, afe_priv->clk[div_clk_id]);
+ if (ret)
+ return ret;
+
+ ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[div_clk_id], rate);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int m_sel_id = 0;
+ int div_clk_id = 0;
+
+ dev_dbg(afe->dev, "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;
+ }
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[div_clk_id]);
+
+ if (m_sel_id >= 0)
+ mt8196_afe_disable_clk(afe, afe_priv->clk[m_sel_id]);
+
+ return 0;
+}
+
+int mt8196_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ /* bus clock for AFE external access, like DRAM */
+ mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
+
+ /* bus clock for AFE internal access, like AFE SRAM */
+ mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
+ mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS],
+ afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
+ /* enable audio vlp clock source */
+ mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
+ afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
+
+ /* AFE hw clock */
+ /* IPM2.0: USE HOPPING & 26M */
+ mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_HOPPING]);
+ mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_F26M]);
+ return 0;
+}
+
+int mt8196_afe_disable_reg_rw_clk(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ /* IPM2.0: Use HOPPING & 26M */
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_HOPPING]);
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_F26M]);
+ mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
+ afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS],
+ afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
+ return 0;
+}
+
+int mt8196_afe_enable_main_clock(struct mtk_base_afe *afe)
+{
+ mt8196_afe_enable_afe_on(afe);
+ return 0;
+}
+
+int mt8196_afe_disable_main_clock(struct mtk_base_afe *afe)
+{
+ mt8196_afe_disable_afe_on(afe);
+ return 0;
+}
+
+int mt8196_init_clock(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret = 0;
+ int i = 0;
+
+ ret = mt8196_audsys_clk_register(afe);
+ if (ret) {
+ dev_err(afe->dev, "register audsys clk fail %d\n", ret);
+ return ret;
+ }
+
+ afe_priv->clk = devm_kcalloc(afe->dev, MT8196_CLK_NUM, sizeof(*afe_priv->clk),
+ GFP_KERNEL);
+ if (!afe_priv->clk)
+ return -ENOMEM;
+
+ for (i = 0; i < MT8196_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->vlp_ck = syscon_regmap_lookup_by_phandle(afe->dev->of_node,
+ "vlpcksys");
+ if (IS_ERR(afe_priv->vlp_ck)) {
+ dev_err(afe->dev, "Cannot find vlpcksys\n");
+ return PTR_ERR(afe_priv->vlp_ck);
+ }
+
+ mt8196_afe_apll_init(afe);
+
+ ret = mt8196_afe_disable_apll(afe);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.h b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
new file mode 100644
index 000000000000..60f5e5a157d5
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8196-afe-clk.h -- Mediatek 8196 afe clock ctrl definition
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#ifndef _MT8196_AFE_CLOCK_CTRL_H_
+#define _MT8196_AFE_CLOCK_CTRL_H_
+
+/* vlp_cksys_clk: 0x1c016000 */
+#define VLP_APLL1_TUNER_CON0 0x02a4
+#define VLP_APLL2_TUNER_CON0 0x02a8
+
+/* vlp apll1 tuner default value*/
+#define VLP_APLL1_TUNER_CON0_VALUE 0x6f28bd4d
+/* vlp apll2 tuner default value + 1*/
+#define VLP_APLL2_TUNER_CON0_VALUE 0x78fd5265
+
+/* APLL */
+#define APLL1_W_NAME "APLL1"
+#define APLL2_W_NAME "APLL2"
+
+enum {
+ MT8196_APLL1 = 0,
+ MT8196_APLL2,
+};
+
+enum {
+ /* vlp clk */
+ MT8196_CLK_VLP_MUX_AUDIOINTBUS,
+ MT8196_CLK_VLP_MUX_AUD_ENG1,
+ MT8196_CLK_VLP_MUX_AUD_ENG2,
+ MT8196_CLK_VLP_MUX_AUDIO_H,
+ MT8196_CLK_VLP_CLK26M,
+ /* pll */
+ MT8196_CLK_TOP_APLL1_CK,
+ MT8196_CLK_TOP_APLL2_CK,
+ /* divider */
+ MT8196_CLK_TOP_APLL1_D4,
+ MT8196_CLK_TOP_APLL2_D4,
+ MT8196_CLK_TOP_APLL12_DIV_I2SIN0,
+ MT8196_CLK_TOP_APLL12_DIV_I2SIN1,
+ MT8196_CLK_TOP_APLL12_DIV_FMI2S,
+ MT8196_CLK_TOP_APLL12_DIV_TDMOUT_M,
+ MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B,
+ /* mux */
+ MT8196_CLK_TOP_MUX_AUD_1,
+ MT8196_CLK_TOP_MUX_AUD_2,
+ MT8196_CLK_TOP_I2SIN0_M_SEL,
+ MT8196_CLK_TOP_I2SIN1_M_SEL,
+ MT8196_CLK_TOP_FMI2S_M_SEL,
+ MT8196_CLK_TOP_TDMOUT_M_SEL,
+ MT8196_CLK_TOP_ADSP_SEL,
+ /* top 26m */
+ MT8196_CLK_TOP_CLK26M,
+ /* clock gate */
+ MT8196_CLK_AFE_PCM1,
+ MT8196_CLK_AFE_PCM0,
+ MT8196_CLK_AFE_CM2,
+ MT8196_CLK_AFE_CM1,
+ MT8196_CLK_AFE_CM0,
+ MT8196_CLK_AFE_STF,
+ MT8196_CLK_AFE_HW_GAIN23,
+ MT8196_CLK_AFE_HW_GAIN01,
+ MT8196_CLK_AFE_FM_I2S,
+ MT8196_CLK_AFE_MTKAIFV4,
+ MT8196_CLK_AFE_UL2_ADC_HIRES_TML,
+ MT8196_CLK_AFE_UL2_ADC_HIRES,
+ MT8196_CLK_AFE_UL2_TML,
+ MT8196_CLK_AFE_UL2_ADC,
+ MT8196_CLK_AFE_UL1_ADC_HIRES_TML,
+ MT8196_CLK_AFE_UL1_ADC_HIRES,
+ MT8196_CLK_AFE_UL1_TML,
+ MT8196_CLK_AFE_UL1_ADC,
+ MT8196_CLK_AFE_UL0_ADC_HIRES_TML,
+ MT8196_CLK_AFE_UL0_ADC_HIRES,
+ MT8196_CLK_AFE_UL0_TML,
+ MT8196_CLK_AFE_UL0_ADC,
+ MT8196_CLK_AFE_ETDM_IN6,
+ MT8196_CLK_AFE_ETDM_IN5,
+ MT8196_CLK_AFE_ETDM_IN4,
+ MT8196_CLK_AFE_ETDM_IN3,
+ MT8196_CLK_AFE_ETDM_IN2,
+ MT8196_CLK_AFE_ETDM_IN1,
+ MT8196_CLK_AFE_ETDM_IN0,
+ MT8196_CLK_AFE_ETDM_OUT6,
+ MT8196_CLK_AFE_ETDM_OUT5,
+ MT8196_CLK_AFE_ETDM_OUT4,
+ MT8196_CLK_AFE_ETDM_OUT3,
+ MT8196_CLK_AFE_ETDM_OUT2,
+ MT8196_CLK_AFE_ETDM_OUT1,
+ MT8196_CLK_AFE_ETDM_OUT0,
+ MT8196_CLK_AFE_TDM_OUT,
+ MT8196_CLK_AFE_GENERAL15_ASRC,
+ MT8196_CLK_AFE_GENERAL14_ASRC,
+ MT8196_CLK_AFE_GENERAL13_ASRC,
+ MT8196_CLK_AFE_GENERAL12_ASRC,
+ MT8196_CLK_AFE_GENERAL11_ASRC,
+ MT8196_CLK_AFE_GENERAL10_ASRC,
+ MT8196_CLK_AFE_GENERAL9_ASRC,
+ MT8196_CLK_AFE_GENERAL8_ASRC,
+ MT8196_CLK_AFE_GENERAL7_ASRC,
+ MT8196_CLK_AFE_GENERAL6_ASRC,
+ MT8196_CLK_AFE_GENERAL5_ASRC,
+ MT8196_CLK_AFE_GENERAL4_ASRC,
+ MT8196_CLK_AFE_GENERAL3_ASRC,
+ MT8196_CLK_AFE_GENERAL2_ASRC,
+ MT8196_CLK_AFE_GENERAL1_ASRC,
+ MT8196_CLK_AFE_GENERAL0_ASRC,
+ MT8196_CLK_AFE_CONNSYS_I2S_ASRC,
+ MT8196_CLK_AFE_AUDIO_HOPPING,
+ MT8196_CLK_AFE_AUDIO_F26M,
+ MT8196_CLK_AFE_APLL1,
+ MT8196_CLK_AFE_APLL2,
+ MT8196_CLK_AFE_H208M,
+ MT8196_CLK_AFE_APLL_TUNER2,
+ MT8196_CLK_AFE_APLL_TUNER1,
+ MT8196_CLK_NUM,
+};
+
+struct mtk_base_afe;
+
+int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate);
+int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id);
+int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll);
+int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
+int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
+int mt8196_init_clock(struct mtk_base_afe *afe);
+int mt8196_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
+void mt8196_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
+int mt8196_apll1_enable(struct mtk_base_afe *afe);
+void mt8196_apll1_disable(struct mtk_base_afe *afe);
+int mt8196_apll2_enable(struct mtk_base_afe *afe);
+void mt8196_apll2_disable(struct mtk_base_afe *afe);
+int mt8196_afe_enable_main_clock(struct mtk_base_afe *afe);
+int mt8196_afe_disable_main_clock(struct mtk_base_afe *afe);
+int mt8196_afe_enable_reg_rw_clk(struct mtk_base_afe *afe);
+int mt8196_afe_disable_reg_rw_clk(struct mtk_base_afe *afe);
+
+#endif
diff --git a/sound/soc/mediatek/mt8196/mt8196-audsys-clk.c b/sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
new file mode 100644
index 000000000000..aa40f02698ac
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8196-audsys-clk.c -- MediaTek 8196 audsys clock control
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include "mt8196-afe-common.h"
+#include "mt8196-audsys-clk.h"
+#include "mt8196-audsys-clkid.h"
+#include "mt8196-reg.h"
+
+struct afe_gate {
+ int id;
+ const char *name;
+ const char *parent_name;
+ int reg;
+ u8 bit;
+ const struct clk_ops *ops;
+ unsigned long flags;
+ u8 cg_flags;
+};
+
+#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, _flags, _cgflags) {\
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .reg = _reg, \
+ .bit = _bit, \
+ .flags = _flags, \
+ .cg_flags = _cgflags, \
+ }
+
+#define GATE_AFE(_id, _name, _parent, _reg, _bit) \
+ GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, \
+ CLK_SET_RATE_PARENT, CLK_GATE_SET_TO_DISABLE)
+
+#define GATE_AUD0(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON0, _bit)
+
+#define GATE_AUD1(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON1, _bit)
+
+#define GATE_AUD2(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON2, _bit)
+
+#define GATE_AUD3(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON3, _bit)
+
+#define GATE_AUD4(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON4, _bit)
+
+static const struct afe_gate aud_clks[CLK_AFE_NR_CLK] = {
+ /* AFE0 */
+ GATE_AUD0(CLK_AFE_PCM1, "afe_pcm1",
+ "vlp_aud_clksq_ck", 13),
+ GATE_AUD0(CLK_AFE_PCM0, "afe_pcm0",
+ "vlp_aud_clksq_ck", 14),
+ GATE_AUD0(CLK_AFE_CM2, "afe_cm2",
+ "vlp_aud_clksq_ck", 16),
+ GATE_AUD0(CLK_AFE_CM1, "afe_cm1",
+ "vlp_aud_clksq_ck", 17),
+ GATE_AUD0(CLK_AFE_CM0, "afe_cm0",
+ "vlp_aud_clksq_ck", 18),
+ GATE_AUD0(CLK_AFE_STF, "afe_stf",
+ "vlp_aud_clksq_ck", 19),
+ GATE_AUD0(CLK_AFE_HW_GAIN23, "afe_hw_gain23",
+ "vlp_aud_clksq_ck", 20),
+ GATE_AUD0(CLK_AFE_HW_GAIN01, "afe_hw_gain01",
+ "vlp_aud_clksq_ck", 21),
+ GATE_AUD0(CLK_AFE_FM_I2S, "afe_fm_i2s",
+ "vlp_aud_clksq_ck", 24),
+ GATE_AUD0(CLK_AFE_MTKAIFV4, "afe_mtkaifv4",
+ "vlp_aud_clksq_ck", 25),
+ /* AFE1 */
+ GATE_AUD1(CLK_AFE_UL2_ADC_HIRES_TML, "afe_ul2_aht",
+ "vlp_audio_h_ck", 12),
+ GATE_AUD1(CLK_AFE_UL2_ADC_HIRES, "afe_ul2_adc_hires",
+ "vlp_audio_h_ck", 13),
+ GATE_AUD1(CLK_AFE_UL2_TML, "afe_ul2_tml",
+ "vlp_aud_clksq_ck", 14),
+ GATE_AUD1(CLK_AFE_UL2_ADC, "afe_ul2_adc",
+ "vlp_aud_clksq_ck", 15),
+ GATE_AUD1(CLK_AFE_UL1_ADC_HIRES_TML, "afe_ul1_aht",
+ "vlp_audio_h_ck", 16),
+ GATE_AUD1(CLK_AFE_UL1_ADC_HIRES, "afe_ul1_adc_hires",
+ "vlp_audio_h_ck", 17),
+ GATE_AUD1(CLK_AFE_UL1_TML, "afe_ul1_tml",
+ "vlp_aud_clksq_ck", 18),
+ GATE_AUD1(CLK_AFE_UL1_ADC, "afe_ul1_adc",
+ "vlp_aud_clksq_ck", 19),
+ GATE_AUD1(CLK_AFE_UL0_ADC_HIRES_TML, "afe_ul0_aht",
+ "vlp_audio_h_ck", 20),
+ GATE_AUD1(CLK_AFE_UL0_ADC_HIRES, "afe_ul0_adc_hires",
+ "vlp_audio_h_ck", 21),
+ GATE_AUD1(CLK_AFE_UL0_TML, "afe_ul0_tml",
+ "vlp_aud_clksq_ck", 22),
+ GATE_AUD1(CLK_AFE_UL0_ADC, "afe_ul0_adc",
+ "vlp_aud_clksq_ck", 23),
+ /* AFE2 */
+ GATE_AUD2(CLK_AFE_ETDM_IN6, "afe_etdm_in6",
+ "vlp_aud_clksq_ck", 7),
+ GATE_AUD2(CLK_AFE_ETDM_IN5, "afe_etdm_in5",
+ "vlp_aud_clksq_ck", 8),
+ GATE_AUD2(CLK_AFE_ETDM_IN4, "afe_etdm_in4",
+ "vlp_aud_clksq_ck", 9),
+ GATE_AUD2(CLK_AFE_ETDM_IN3, "afe_etdm_in3",
+ "vlp_aud_clksq_ck", 10),
+ GATE_AUD2(CLK_AFE_ETDM_IN2, "afe_etdm_in2",
+ "vlp_aud_clksq_ck", 11),
+ GATE_AUD2(CLK_AFE_ETDM_IN1, "afe_etdm_in1",
+ "vlp_aud_clksq_ck", 12),
+ GATE_AUD2(CLK_AFE_ETDM_IN0, "afe_etdm_in0",
+ "vlp_aud_clksq_ck", 13),
+ GATE_AUD2(CLK_AFE_ETDM_OUT6, "afe_etdm_out6",
+ "vlp_aud_clksq_ck", 15),
+ GATE_AUD2(CLK_AFE_ETDM_OUT5, "afe_etdm_out5",
+ "vlp_aud_clksq_ck", 16),
+ GATE_AUD2(CLK_AFE_ETDM_OUT4, "afe_etdm_out4",
+ "vlp_aud_clksq_ck", 17),
+ GATE_AUD2(CLK_AFE_ETDM_OUT3, "afe_etdm_out3",
+ "vlp_aud_clksq_ck", 18),
+ GATE_AUD2(CLK_AFE_ETDM_OUT2, "afe_etdm_out2",
+ "vlp_aud_clksq_ck", 19),
+ GATE_AUD2(CLK_AFE_ETDM_OUT1, "afe_etdm_out1",
+ "vlp_aud_clksq_ck", 20),
+ GATE_AUD2(CLK_AFE_ETDM_OUT0, "afe_etdm_out0",
+ "vlp_aud_clksq_ck", 21),
+ GATE_AUD2(CLK_AFE_TDM_OUT, "afe_tdm_out",
+ "ck_aud_1_ck", 24),
+ /* AFE3 */
+ GATE_AUD3(CLK_AFE_GENERAL15_ASRC, "afe_general15_asrc",
+ "vlp_aud_clksq_ck", 9),
+ GATE_AUD3(CLK_AFE_GENERAL14_ASRC, "afe_general14_asrc",
+ "vlp_aud_clksq_ck", 10),
+ GATE_AUD3(CLK_AFE_GENERAL13_ASRC, "afe_general13_asrc",
+ "vlp_aud_clksq_ck", 11),
+ GATE_AUD3(CLK_AFE_GENERAL12_ASRC, "afe_general12_asrc",
+ "vlp_aud_clksq_ck", 12),
+ GATE_AUD3(CLK_AFE_GENERAL11_ASRC, "afe_general11_asrc",
+ "vlp_aud_clksq_ck", 13),
+ GATE_AUD3(CLK_AFE_GENERAL10_ASRC, "afe_general10_asrc",
+ "vlp_aud_clksq_ck", 14),
+ GATE_AUD3(CLK_AFE_GENERAL9_ASRC, "afe_general9_asrc",
+ "vlp_aud_clksq_ck", 15),
+ GATE_AUD3(CLK_AFE_GENERAL8_ASRC, "afe_general8_asrc",
+ "vlp_aud_clksq_ck", 16),
+ GATE_AUD3(CLK_AFE_GENERAL7_ASRC, "afe_general7_asrc",
+ "vlp_aud_clksq_ck", 17),
+ GATE_AUD3(CLK_AFE_GENERAL6_ASRC, "afe_general6_asrc",
+ "vlp_aud_clksq_ck", 18),
+ GATE_AUD3(CLK_AFE_GENERAL5_ASRC, "afe_general5_asrc",
+ "vlp_aud_clksq_ck", 19),
+ GATE_AUD3(CLK_AFE_GENERAL4_ASRC, "afe_general4_asrc",
+ "vlp_aud_clksq_ck", 20),
+ GATE_AUD3(CLK_AFE_GENERAL3_ASRC, "afe_general3_asrc",
+ "vlp_aud_clksq_ck", 21),
+ GATE_AUD3(CLK_AFE_GENERAL2_ASRC, "afe_general2_asrc",
+ "vlp_aud_clksq_ck", 22),
+ GATE_AUD3(CLK_AFE_GENERAL1_ASRC, "afe_general1_asrc",
+ "vlp_aud_clksq_ck", 23),
+ GATE_AUD3(CLK_AFE_GENERAL0_ASRC, "afe_general0_asrc",
+ "vlp_aud_clksq_ck", 24),
+ GATE_AUD3(CLK_AFE_CONNSYS_I2S_ASRC, "afe_connsys_i2s_asrc",
+ "vlp_aud_clksq_ck", 25),
+ /* AFE4 */
+ GATE_AUD4(CLK_AFE_AUDIO_HOPPING, "afe_audio_hopping_ck",
+ "vlp_aud_clksq_ck", 0),
+ GATE_AUD4(CLK_AFE_AUDIO_F26M, "afe_audio_f26m_ck",
+ "vlp_aud_clksq_ck", 1),
+ GATE_AUD4(CLK_AFE_APLL1, "afe_apll1_ck",
+ "ck_aud_1_ck", 2),
+ GATE_AUD4(CLK_AFE_APLL2, "afe_apll2_ck",
+ "ck_aud_2_ck", 3),
+ GATE_AUD4(CLK_AFE_H208M, "afe_h208m_ck",
+ "vlp_audio_h_ck", 4),
+ GATE_AUD4(CLK_AFE_APLL_TUNER2, "afe_apll_tuner2",
+ "vlp_aud_engen2_ck", 12),
+ GATE_AUD4(CLK_AFE_APLL_TUNER1, "afe_apll_tuner1",
+ "vlp_aud_engen1_ck", 13),
+};
+
+static void mt8196_audsys_clk_unregister(void *data)
+{
+ struct mtk_base_afe *afe = data;
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct clk *clk;
+ struct clk_lookup *cl;
+ int i;
+
+ if (!afe_priv)
+ return;
+
+ for (i = 0; i < CLK_AFE_NR_CLK; i++) {
+ cl = afe_priv->lookup[i];
+ if (!cl)
+ continue;
+
+ clk = cl->clk;
+ clk_unregister_gate(clk);
+
+ clkdev_drop(cl);
+ }
+}
+
+int mt8196_audsys_clk_register(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct clk *clk;
+ struct clk_lookup *cl;
+ int i;
+
+ afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AFE_NR_CLK,
+ sizeof(*afe_priv->lookup),
+ GFP_KERNEL);
+
+ if (!afe_priv->lookup)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
+ const struct afe_gate *gate = &aud_clks[i];
+
+ clk = clk_register_gate(afe->dev, gate->name, gate->parent_name,
+ gate->flags, afe->base_addr + gate->reg,
+ gate->bit, gate->cg_flags, NULL);
+
+ if (IS_ERR(clk)) {
+ dev_err(afe->dev, "Failed to register clk %s: %ld\n",
+ gate->name, PTR_ERR(clk));
+ continue;
+ }
+
+ /* add clk_lookup for devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */
+ cl = kzalloc(sizeof(*cl), GFP_KERNEL);
+ if (!cl)
+ return -ENOMEM;
+
+ cl->clk = clk;
+ cl->con_id = gate->name;
+ cl->dev_id = dev_name(afe->dev);
+ cl->clk_hw = NULL;
+ clkdev_add(cl);
+
+ afe_priv->lookup[i] = cl;
+ }
+
+ return devm_add_action_or_reset(afe->dev, mt8196_audsys_clk_unregister, afe);
+}
diff --git a/sound/soc/mediatek/mt8196/mt8196-audsys-clk.h b/sound/soc/mediatek/mt8196/mt8196-audsys-clk.h
new file mode 100644
index 000000000000..fad3a38a5ccb
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-audsys-clk.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8196-audsys-clk.h -- MediaTek 8196 audsys clock definition
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#ifndef _MT8196_AUDSYS_CLK_H_
+#define _MT8196_AUDSYS_CLK_H_
+
+int mt8196_audsys_clk_register(struct mtk_base_afe *afe);
+
+#endif
diff --git a/sound/soc/mediatek/mt8196/mt8196-audsys-clkid.h b/sound/soc/mediatek/mt8196/mt8196-audsys-clkid.h
new file mode 100644
index 000000000000..b61db004eb2b
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-audsys-clkid.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8196-audsys-clkid.h -- MediaTek 8196 audsys clock id definition
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#ifndef _MT8196_AUDSYS_CLKID_H_
+#define _MT8196_AUDSYS_CLKID_H_
+
+enum{
+ /* AFE */
+ CLK_AFE_PCM1,
+ CLK_AFE_PCM0,
+ CLK_AFE_CM2,
+ CLK_AFE_CM1,
+ CLK_AFE_CM0,
+ CLK_AFE_STF,
+ CLK_AFE_HW_GAIN23,
+ CLK_AFE_HW_GAIN01,
+ CLK_AFE_FM_I2S,
+ CLK_AFE_MTKAIFV4,
+ CLK_AFE_UL2_ADC_HIRES_TML,
+ CLK_AFE_UL2_ADC_HIRES,
+ CLK_AFE_UL2_TML,
+ CLK_AFE_UL2_ADC,
+ CLK_AFE_UL1_ADC_HIRES_TML,
+ CLK_AFE_UL1_ADC_HIRES,
+ CLK_AFE_UL1_TML,
+ CLK_AFE_UL1_ADC,
+ CLK_AFE_UL0_ADC_HIRES_TML,
+ CLK_AFE_UL0_ADC_HIRES,
+ CLK_AFE_UL0_TML,
+ CLK_AFE_UL0_ADC,
+ CLK_AFE_ETDM_IN6,
+ CLK_AFE_ETDM_IN5,
+ CLK_AFE_ETDM_IN4,
+ CLK_AFE_ETDM_IN3,
+ CLK_AFE_ETDM_IN2,
+ CLK_AFE_ETDM_IN1,
+ CLK_AFE_ETDM_IN0,
+ CLK_AFE_ETDM_OUT6,
+ CLK_AFE_ETDM_OUT5,
+ CLK_AFE_ETDM_OUT4,
+ CLK_AFE_ETDM_OUT3,
+ CLK_AFE_ETDM_OUT2,
+ CLK_AFE_ETDM_OUT1,
+ CLK_AFE_ETDM_OUT0,
+ CLK_AFE_TDM_OUT,
+ CLK_AFE_GENERAL15_ASRC,
+ CLK_AFE_GENERAL14_ASRC,
+ CLK_AFE_GENERAL13_ASRC,
+ CLK_AFE_GENERAL12_ASRC,
+ CLK_AFE_GENERAL11_ASRC,
+ CLK_AFE_GENERAL10_ASRC,
+ CLK_AFE_GENERAL9_ASRC,
+ CLK_AFE_GENERAL8_ASRC,
+ CLK_AFE_GENERAL7_ASRC,
+ CLK_AFE_GENERAL6_ASRC,
+ CLK_AFE_GENERAL5_ASRC,
+ CLK_AFE_GENERAL4_ASRC,
+ CLK_AFE_GENERAL3_ASRC,
+ CLK_AFE_GENERAL2_ASRC,
+ CLK_AFE_GENERAL1_ASRC,
+ CLK_AFE_GENERAL0_ASRC,
+ CLK_AFE_CONNSYS_I2S_ASRC,
+ CLK_AFE_AUDIO_HOPPING,
+ CLK_AFE_AUDIO_F26M,
+ CLK_AFE_APLL1,
+ CLK_AFE_APLL2,
+ CLK_AFE_H208M,
+ CLK_AFE_APLL_TUNER2,
+ CLK_AFE_APLL_TUNER1,
+ CLK_AFE_NR_CLK,
+};
+
+#endif
--
2.45.2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v3 04/10] ASoC: mediatek: mt8196: support ADDA in platform driver
2025-05-14 8:11 [PATCH v3 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
2025-05-14 8:11 ` [PATCH v3 01/10] ASoC: mediatek: common: modify mtk afe platform driver for mt8196 Darren.Ye
2025-05-14 8:11 ` [PATCH v3 03/10] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
@ 2025-05-14 8:11 ` Darren.Ye
2025-05-14 8:17 ` Mark Brown
2025-05-14 8:11 ` [PATCH v3 06/10] ASoC: mediatek: mt8196: support TDM " Darren.Ye
` (4 subsequent siblings)
7 siblings, 1 reply; 23+ messages in thread
From: Darren.Ye @ 2025-05-14 8:11 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add mt8196 ADDA DAI driver support.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/mt8196/mt8196-dai-adda.c | 918 ++++++++++++++++++++
1 file changed, 918 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-adda.c
diff --git a/sound/soc/mediatek/mt8196/mt8196-dai-adda.c b/sound/soc/mediatek/mt8196/mt8196-dai-adda.c
new file mode 100644
index 000000000000..1ccffd0030c3
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-dai-adda.c
@@ -0,0 +1,918 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI ADDA Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include "mt8196-afe-clk.h"
+#include "mt8196-afe-common.h"
+#include "mt8196-interconnection.h"
+
+#define MTKAIF4
+
+enum {
+ UL_IIR_SW = 0,
+ UL_IIR_5HZ,
+ UL_IIR_10HZ,
+ UL_IIR_25HZ,
+ UL_IIR_50HZ,
+ UL_IIR_75HZ,
+};
+
+enum {
+ MTK_AFE_ADDA_UL_RATE_8K = 0,
+ MTK_AFE_ADDA_UL_RATE_16K = 1,
+ MTK_AFE_ADDA_UL_RATE_32K = 2,
+ MTK_AFE_ADDA_UL_RATE_48K = 3,
+ MTK_AFE_ADDA_UL_RATE_96K = 4,
+ MTK_AFE_ADDA_UL_RATE_192K = 5,
+ MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
+};
+
+#ifdef MTKAIF4
+enum {
+ MTK_AFE_MTKAIF_RATE_8K = 0x0,
+ MTK_AFE_MTKAIF_RATE_12K = 0x1,
+ MTK_AFE_MTKAIF_RATE_16K = 0x2,
+ MTK_AFE_MTKAIF_RATE_24K = 0x3,
+ MTK_AFE_MTKAIF_RATE_32K = 0x4,
+ MTK_AFE_MTKAIF_RATE_48K = 0x5,
+ MTK_AFE_MTKAIF_RATE_64K = 0x6,
+ MTK_AFE_MTKAIF_RATE_96K = 0x7,
+ MTK_AFE_MTKAIF_RATE_128K = 0x8,
+ MTK_AFE_MTKAIF_RATE_192K = 0x9,
+ MTK_AFE_MTKAIF_RATE_256K = 0xa,
+ MTK_AFE_MTKAIF_RATE_384K = 0xb,
+ MTK_AFE_MTKAIF_RATE_11K = 0x10,
+ MTK_AFE_MTKAIF_RATE_22K = 0x11,
+ MTK_AFE_MTKAIF_RATE_44K = 0x12,
+ MTK_AFE_MTKAIF_RATE_88K = 0x13,
+ MTK_AFE_MTKAIF_RATE_176K = 0x14,
+ MTK_AFE_MTKAIF_RATE_352K = 0x15,
+};
+#endif
+
+struct mtk_afe_adda_priv {
+ int dl_rate;
+ int ul_rate;
+};
+
+static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_UL_RATE_8K;
+ case 16000:
+ return MTK_AFE_ADDA_UL_RATE_16K;
+ case 32000:
+ return MTK_AFE_ADDA_UL_RATE_32K;
+ case 48000:
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_UL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_UL_RATE_192K;
+ default:
+ dev_info(afe->dev, "rate %d invalid, use 48kHz!!!\n", rate);
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ }
+}
+
+#ifdef MTKAIF4
+static unsigned int mtkaif_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_MTKAIF_RATE_8K;
+ case 11025:
+ return MTK_AFE_MTKAIF_RATE_11K;
+ case 12000:
+ return MTK_AFE_MTKAIF_RATE_12K;
+ case 16000:
+ return MTK_AFE_MTKAIF_RATE_16K;
+ case 22050:
+ return MTK_AFE_MTKAIF_RATE_22K;
+ case 24000:
+ return MTK_AFE_MTKAIF_RATE_24K;
+ case 32000:
+ return MTK_AFE_MTKAIF_RATE_32K;
+ case 44100:
+ return MTK_AFE_MTKAIF_RATE_44K;
+ case 48000:
+ return MTK_AFE_MTKAIF_RATE_48K;
+ case 96000:
+ return MTK_AFE_MTKAIF_RATE_96K;
+ case 192000:
+ return MTK_AFE_MTKAIF_RATE_192K;
+ default:
+ dev_info(afe->dev, "rate %d invalid, use 48kHz!!!\n", rate);
+ return MTK_AFE_MTKAIF_RATE_48K;
+ }
+}
+#endif
+
+enum {
+ SUPPLY_SEQ_ADDA_AFE_ON,
+ SUPPLY_SEQ_ADDA_FIFO,
+ SUPPLY_SEQ_ADDA_AP_DMIC,
+ SUPPLY_SEQ_ADDA_UL_ON,
+};
+
+static int mtk_adda_ul_src_dmic_phase_sync(struct mtk_base_afe *afe)
+{
+ dev_dbg(afe->dev, "set dmic phase sync\n");
+ // ul0~1
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ UL0_PHASE_SYNC_HCLK_SET_MASK_SFT,
+ 0x1 << UL0_PHASE_SYNC_HCLK_SET_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ UL0_PHASE_SYNC_FCLK_SET_MASK_SFT,
+ 0x1 << UL0_PHASE_SYNC_FCLK_SET_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ UL1_PHASE_SYNC_HCLK_SET_MASK_SFT,
+ 0x1 << UL1_PHASE_SYNC_HCLK_SET_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ UL1_PHASE_SYNC_FCLK_SET_MASK_SFT,
+ 0x1 << UL1_PHASE_SYNC_FCLK_SET_SFT);
+ // dmic 0
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ DMIC0_PHASE_SYNC_FCLK_SET_MASK_SFT,
+ 0x1 << DMIC0_PHASE_SYNC_FCLK_SET_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ DMIC0_PHASE_SYNC_HCLK_SET_MASK_SFT,
+ 0x1 << DMIC0_PHASE_SYNC_HCLK_SET_SFT);
+ // dmic 1
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ DMIC1_PHASE_SYNC_FCLK_SET_MASK_SFT,
+ 0x1 << DMIC1_PHASE_SYNC_FCLK_SET_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ DMIC1_PHASE_SYNC_HCLK_SET_MASK_SFT,
+ 0x1 << DMIC1_PHASE_SYNC_HCLK_SET_SFT);
+ // ul0~1 phase sync clock
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ DMIC1_PHASE_HCLK_SEL_MASK_SFT,
+ 0x1 << DMIC1_PHASE_HCLK_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ DMIC1_PHASE_FCLK_SEL_MASK_SFT,
+ 0x1 << DMIC1_PHASE_FCLK_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ DMIC0_PHASE_HCLK_SEL_MASK_SFT,
+ 0x1 << DMIC0_PHASE_HCLK_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ DMIC0_PHASE_FCLK_SEL_MASK_SFT,
+ 0x1 << DMIC0_PHASE_FCLK_SEL_SFT);
+ // dmic 0
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL1_PHASE_HCLK_SEL_MASK_SFT,
+ 0x2 << UL1_PHASE_HCLK_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL1_PHASE_FCLK_SEL_MASK_SFT,
+ 0x2 << UL1_PHASE_FCLK_SEL_SFT);
+ // dmic 1
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL0_PHASE_HCLK_SEL_MASK_SFT,
+ 0x2 << UL0_PHASE_HCLK_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL0_PHASE_FCLK_SEL_MASK_SFT,
+ 0x2 << UL0_PHASE_FCLK_SEL_SFT);
+
+ return 0;
+}
+
+static int mtk_adda_ul_src_dmic_phase_sync_clock(struct mtk_base_afe *afe)
+{
+ dev_dbg(afe->dev, "dmic turn on phase sync clk\n");
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL_PHASE_SYNC_HCLK_1_ON_MASK_SFT,
+ 0x1 << UL_PHASE_SYNC_HCLK_1_ON_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL_PHASE_SYNC_HCLK_0_ON_MASK_SFT,
+ 0x1 << UL_PHASE_SYNC_HCLK_0_ON_SFT);
+
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL_PHASE_SYNC_FCLK_1_ON_MASK_SFT,
+ 0x1 << UL_PHASE_SYNC_FCLK_1_ON_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL_PHASE_SYNC_FCLK_0_ON_MASK_SFT,
+ 0x1 << UL_PHASE_SYNC_FCLK_0_ON_SFT);
+
+ return 0;
+}
+
+static int mtk_adda_ul_src_dmic(struct mtk_base_afe *afe, int id)
+{
+ unsigned int reg_con0 = 0, reg_con1 = 0;
+
+ dev_dbg(afe->dev, "id: %d\n", id);
+
+ switch (id) {
+ case MT8196_DAI_ADDA:
+ case MT8196_DAI_AP_DMIC:
+ reg_con0 = AFE_ADDA_UL0_SRC_CON0;
+ reg_con1 = AFE_ADDA_UL0_SRC_CON1;
+ break;
+ case MT8196_DAI_ADDA_CH34:
+ case MT8196_DAI_AP_DMIC_CH34:
+ reg_con0 = AFE_ADDA_UL1_SRC_CON0;
+ reg_con1 = AFE_ADDA_UL1_SRC_CON1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (id) {
+ case MT8196_DAI_AP_DMIC:
+ dev_dbg(afe->dev, "clear mtkaifv4 ul ch1ch2 mux\n");
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT);
+ break;
+ case MT8196_DAI_AP_DMIC_CH34:
+ dev_dbg(afe->dev, "clear mtkaifv4 ul ch3ch4 mux\n");
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* choose Phase */
+ regmap_update_bits(afe->regmap, reg_con0,
+ UL_DMIC_PHASE_SEL_CH1_MASK_SFT,
+ 0x0 << UL_DMIC_PHASE_SEL_CH1_SFT);
+ regmap_update_bits(afe->regmap, reg_con0,
+ UL_DMIC_PHASE_SEL_CH2_MASK_SFT,
+ 0x4 << UL_DMIC_PHASE_SEL_CH2_SFT);
+
+ /* dmic mode, 3.25M*/
+ regmap_update_bits(afe->regmap, reg_con0,
+ DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT,
+ 0x0);
+ regmap_update_bits(afe->regmap, reg_con0,
+ DMIC_LOW_POWER_MODE_CTL_MASK_SFT,
+ 0x0);
+
+ /* turn on dmic, ch1, ch2 */
+ regmap_update_bits(afe->regmap, reg_con0,
+ UL_SDM_3_LEVEL_CTL_MASK_SFT,
+ 0x1 << UL_SDM_3_LEVEL_CTL_SFT);
+ regmap_update_bits(afe->regmap, reg_con0,
+ UL_MODE_3P25M_CH1_CTL_MASK_SFT,
+ 0x1 << UL_MODE_3P25M_CH1_CTL_SFT);
+ regmap_update_bits(afe->regmap, reg_con0,
+ UL_MODE_3P25M_CH2_CTL_MASK_SFT,
+ 0x1 << UL_MODE_3P25M_CH2_CTL_SFT);
+
+ /* ul gain: gain = 0x7fff/positive_gain = 0x0/gain_mode = 0x10 */
+ regmap_update_bits(afe->regmap, reg_con1,
+ ADDA_UL_GAIN_VALUE_MASK_SFT,
+ 0x7fff << ADDA_UL_GAIN_VALUE_SFT);
+ regmap_update_bits(afe->regmap, reg_con1,
+ ADDA_UL_POSTIVEGAIN_MASK_SFT,
+ 0x0 << ADDA_UL_POSTIVEGAIN_SFT);
+ /* gain_mode = 0x10: Add 0.5 gain at CIC output */
+ regmap_update_bits(afe->regmap, reg_con1,
+ GAIN_MODE_MASK_SFT,
+ 0x02 << GAIN_MODE_SFT);
+ return 0;
+}
+
+static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(afe->dev, "name %s, event 0x%x\n", w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(120, 130);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_ch34_ul_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(afe->dev, "name %s, event 0x%x\n", w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(120, 130);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_ul_ap_dmic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_info(afe->dev, "name %s, event 0x%x\n", w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(120, 130);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_ch34_ul_ap_dmic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(afe->dev, "name %s, event 0x%x\n", w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(120, 130);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* mtkaif dmic */
+static const char *const mt8196_adda_off_on_str[] = {
+ "Off", "On"
+};
+
+static const struct soc_enum mt8196_adda_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8196_adda_off_on_str),
+ mt8196_adda_off_on_str),
+};
+
+static const struct snd_kcontrol_new mtk_adda_controls[] = {
+};
+
+/* ADDA UL MUX */
+#define ADDA_UL_MUX_MASK 0x3
+enum {
+ ADDA_UL_MUX_MTKAIF = 0,
+ ADDA_UL_MUX_AP_DMIC,
+ ADDA_UL_MUX_AP_DMIC_MULTICH,
+};
+
+static const char *const adda_ul_mux_map[] = {
+ "MTKAIF", "AP_DMIC", "AP_DMIC_MULTI_CH",
+};
+
+static int adda_ul_map_value[] = {
+ ADDA_UL_MUX_MTKAIF,
+ ADDA_UL_MUX_AP_DMIC,
+ ADDA_UL_MUX_AP_DMIC_MULTICH,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ ADDA_UL_MUX_MASK,
+ adda_ul_mux_map,
+ adda_ul_map_value);
+
+static const struct snd_kcontrol_new adda_ul_mux_control =
+ SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_kcontrol_new adda_ch34_ul_mux_control =
+ SOC_DAPM_ENUM("ADDA_CH34_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+ /* inter-connections */
+ 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 Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+ AFE_ADDA_UL0_SRC_CON0,
+ UL_SRC_ON_TMP_CTL_SFT, 0,
+ mtk_adda_ul_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("ADDA CH34 Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+ AFE_ADDA_UL1_SRC_CON0,
+ UL_SRC_ON_TMP_CTL_SFT, 0,
+ mtk_adda_ch34_ul_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+ AFE_ADDA_UL0_SRC_CON0,
+ UL_AP_DMIC_ON_SFT, 0,
+ mtk_adda_ul_ap_dmic_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("AP_DMIC_CH34_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+ AFE_ADDA_UL1_SRC_CON0,
+ UL_AP_DMIC_ON_SFT, 0,
+ mtk_adda_ch34_ul_ap_dmic_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+ AFE_ADDA_UL0_SRC_CON1,
+ FIFO_SOFT_RST_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADDA_CH34_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+ AFE_ADDA_UL1_SRC_CON1,
+ FIFO_SOFT_RST_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_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"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+ /* capture */
+ {"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"},
+ {"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"},
+ {"ADDA_UL_Mux", "AP_DMIC_MULTI_CH", "AP DMIC MULTICH Capture"},
+
+ {"ADDA_CH34_UL_Mux", "MTKAIF", "ADDA CH34 Capture"},
+ {"ADDA_CH34_UL_Mux", "AP_DMIC", "AP DMIC CH34 Capture"},
+ {"ADDA_CH34_UL_Mux", "AP_DMIC_MULTI_CH", "AP DMIC MULTICH Capture"},
+
+ {"AP DMIC Capture", NULL, "ADDA Enable"},
+ {"AP DMIC Capture", NULL, "ADDA Capture Enable"},
+ {"AP DMIC Capture", NULL, "ADDA_FIFO"},
+ {"AP DMIC Capture", NULL, "AP_DMIC_EN"},
+
+ {"AP DMIC CH34 Capture", NULL, "ADDA Enable"},
+ {"AP DMIC CH34 Capture", NULL, "ADDA CH34 Capture Enable"},
+ {"AP DMIC CH34 Capture", NULL, "ADDA_CH34_FIFO"},
+ {"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_EN"},
+
+ {"AP DMIC MULTICH Capture", NULL, "ADDA Enable"},
+ {"AP DMIC MULTICH Capture", NULL, "ADDA Capture Enable"},
+ {"AP DMIC MULTICH Capture", NULL, "ADDA CH34 Capture Enable"},
+ {"AP DMIC MULTICH Capture", NULL, "ADDA_FIFO"},
+ {"AP DMIC MULTICH Capture", NULL, "ADDA_CH34_FIFO"},
+ {"AP DMIC MULTICH Capture", NULL, "AP_DMIC_EN"},
+ {"AP DMIC MULTICH Capture", NULL, "AP_DMIC_CH34_EN"},
+ {"AP DMIC Capture", NULL, "AP_DMIC_INPUT"},
+ {"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_INPUT"},
+ {"AP DMIC MULTICH Capture", NULL, "AP_DMIC_INPUT"},
+};
+
+/* dai ops */
+static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ unsigned int rate = params_rate(params);
+#ifdef MTKAIF4
+ unsigned int mtkaif_rate = 0;
+#endif
+ int id = dai->id;
+ struct mtk_afe_adda_priv *adda_priv;
+
+ if (id >= MT8196_DAI_NUM || id < 0)
+ return -EINVAL;
+
+ adda_priv = afe_priv->dai_priv[id];
+
+ dev_info(afe->dev, "id %d, stream %d, rate %d\n",
+ id,
+ substream->stream,
+ rate);
+
+ if (!adda_priv)
+ return -EINVAL;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ adda_priv->dl_rate = rate;
+
+#ifdef MTKAIF4
+ /* get mtkaif dl rate */
+ mtkaif_rate =
+ mtkaif_rate_transform(afe, adda_priv->dl_rate);
+#endif
+ if (id == MT8196_DAI_ADDA) {
+#ifdef MTKAIF4
+ /* MTKAIF sample rate config */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_TXIF_INPUT_MODE_MASK_SFT,
+ mtkaif_rate << MTKAIFV4_TXIF_INPUT_MODE_SFT);
+ /* AFE_ADDA_MTKAIFV4_TX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_TXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x0 << MTKAIFV4_TXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_ADDA_OUT_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_ADDA_OUT_EN_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_ADDA6_OUT_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_ADDA6_OUT_EN_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_TXIF_V4_MASK_SFT,
+ 0x1 << MTKAIFV4_TXIF_V4_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_TXIF_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_TXIF_EN_SEL_SFT);
+#endif
+ /* clean predistortion */
+ } else {
+#ifdef MTKAIF4
+ /* MTKAIF sample rate config */
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_TX_CFG0,
+ ADDA6_MTKAIFV4_TXIF_INPUT_MODE_MASK_SFT,
+ mtkaif_rate << ADDA6_MTKAIFV4_TXIF_INPUT_MODE_SFT);
+ /* AFE_ADDA6_MTKAIFV4_TX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_TX_CFG0,
+ ADDA6_MTKAIFV4_TXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x0 << ADDA6_MTKAIFV4_TXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_TX_CFG0,
+ ADDA6_MTKAIFV4_TXIF_EN_SEL_MASK_SFT,
+ 0x1 << ADDA6_MTKAIFV4_TXIF_EN_SEL_SFT);
+#endif
+ }
+ } else {
+ unsigned int voice_mode = 0;
+ unsigned int ul_src_con0 = 0; /* default value */
+
+ adda_priv->ul_rate = rate;
+
+#ifdef MTKAIF4
+ /* get mtkaif dl rate */
+ mtkaif_rate =
+ mtkaif_rate_transform(afe, adda_priv->ul_rate);
+#endif
+
+ voice_mode = adda_ul_rate_transform(afe, rate);
+
+ ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
+
+ /* enable iir */
+ ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) &
+ UL_IIR_ON_TMP_CTL_MASK_SFT;
+ ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) &
+ UL_IIRMODE_CTL_MASK_SFT;
+
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT,
+ mtkaif_rate << MTKAIFV4_RXIF_INPUT_MODE_SFT);
+
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
+ ADDA6_MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT,
+ mtkaif_rate << ADDA6_MTKAIFV4_RXIF_INPUT_MODE_SFT);
+
+ switch (id) {
+ case MT8196_DAI_ADDA:
+ case MT8196_DAI_AP_DMIC:
+ case MT8196_DAI_AP_DMIC_MULTICH:
+#ifdef MTKAIF4
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT,
+ mtkaif_rate << MTKAIFV4_RXIF_INPUT_MODE_SFT);
+ /* AFE_ADDA_MTKAIFV4_RX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x1 << MTKAIFV4_RXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_RXIF_EN_SEL_SFT);
+ /* [28] loopback mode
+ * 0: loopback adda tx to adda rx
+ * 1: loopback adda6 tx to adda rx
+ */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_TXIF_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_TXIF_EN_SEL_SFT);
+
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT);
+#endif
+
+ /* 35Hz @ 48k */
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_02_01, 0x00000000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_04_03, 0x00003FB8);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_06_05, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_08_07, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_10_09, 0x0000C048);
+
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_SRC_CON0, ul_src_con0);
+
+ /* mtkaif_rxif_data_mode = 0, amic */
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF1_RX_CFG0,
+ 0x1 << 0,
+ 0x0 << 0);
+
+ /* 35Hz @ 48k */
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_02_01, 0x00000000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_04_03, 0x00003FB8);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_06_05, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_08_07, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_10_09, 0x0000C048);
+
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_SRC_CON0, ul_src_con0);
+
+ /* mtkaif_rxif_data_mode = 0, amic */
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF0_RX_CFG0,
+ 0x1 << 0,
+ 0x0 << 0);
+ break;
+ case MT8196_DAI_ADDA_CH34:
+ case MT8196_DAI_AP_DMIC_CH34:
+#ifdef MTKAIF4
+ /* AFE_ADDA_MTKAIFV4_RX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x1 << MTKAIFV4_RXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_RXIF_EN_SEL_SFT);
+
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT);
+
+#endif
+ /* 35Hz @ 48k */
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_02_01, 0x00000000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_04_03, 0x00003FB8);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_06_05, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_08_07, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_10_09, 0x0000C048);
+
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_SRC_CON0, ul_src_con0);
+
+ /* mtkaif_rxif_data_mode = 0, amic */
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF1_RX_CFG0,
+ 0x1 << 0,
+ 0x0 << 0);
+
+ break;
+ case MT8196_DAI_ADDA_CH56:
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
+ ADDA6_MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT,
+ mtkaif_rate << ADDA6_MTKAIFV4_RXIF_INPUT_MODE_SFT);
+ /* AFE_ADDA6_MTKAIFV4_RX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
+ ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x1 << ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH5CH6_IN_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_UL_CH5CH6_IN_EN_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
+ ADDA6_MTKAIFV4_RXIF_EN_SEL_MASK_SFT,
+ 0x1 << ADDA6_MTKAIFV4_RXIF_EN_SEL_SFT);
+ break;
+ default:
+ break;
+ }
+
+ /* ap dmic */
+ switch (id) {
+ case MT8196_DAI_AP_DMIC:
+ case MT8196_DAI_AP_DMIC_CH34:
+ mtk_adda_ul_src_dmic(afe, id);
+ break;
+ case MT8196_DAI_AP_DMIC_MULTICH:
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ DMIC_CLK_PHASE_SYNC_SET_MASK_SFT,
+ 0x1 << DMIC_CLK_PHASE_SYNC_SET_SFT);
+ mtk_adda_ul_src_dmic_phase_sync(afe);
+ mtk_adda_ul_src_dmic(afe, MT8196_DAI_AP_DMIC);
+ mtk_adda_ul_src_dmic(afe, MT8196_DAI_AP_DMIC_CH34);
+ mtk_adda_ul_src_dmic_phase_sync_clock(afe);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_adda_ops = {
+ .hw_params = mtk_dai_adda_hw_params,
+};
+
+/* dai driver */
+#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 |\
+ SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
+ {
+ .name = "ADDA",
+ .id = MT8196_DAI_ADDA,
+ .playback = {
+ .stream_name = "ADDA Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_PLAYBACK_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ADDA Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "ADDA_CH34",
+ .id = MT8196_DAI_ADDA_CH34,
+ .playback = {
+ .stream_name = "ADDA CH34 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_PLAYBACK_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ADDA CH34 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "ADDA_CH56",
+ .id = MT8196_DAI_ADDA_CH56,
+ .capture = {
+ .stream_name = "ADDA CH56 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "AP_DMIC",
+ .id = MT8196_DAI_AP_DMIC,
+ .capture = {
+ .stream_name = "AP DMIC Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "AP_DMIC_CH34",
+ .id = MT8196_DAI_AP_DMIC_CH34,
+ .capture = {
+ .stream_name = "AP DMIC CH34 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "AP_DMIC_MULTICH",
+ .id = MT8196_DAI_AP_DMIC_MULTICH,
+ .capture = {
+ .stream_name = "AP DMIC MULTICH Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+};
+
+static int init_adda_priv_data(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_adda_priv *adda_priv;
+ static const int adda_dai_list[] = {
+ MT8196_DAI_ADDA,
+ MT8196_DAI_ADDA_CH34,
+ MT8196_DAI_ADDA_CH56,
+ MT8196_DAI_AP_DMIC_MULTICH
+ };
+ 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[MT8196_DAI_AP_DMIC] =
+ afe_priv->dai_priv[MT8196_DAI_ADDA];
+ afe_priv->dai_priv[MT8196_DAI_AP_DMIC_CH34] =
+ afe_priv->dai_priv[MT8196_DAI_ADDA_CH34];
+
+ return 0;
+}
+
+int mt8196_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.45.2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v3 06/10] ASoC: mediatek: mt8196: support TDM in platform driver
2025-05-14 8:11 [PATCH v3 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (2 preceding siblings ...)
2025-05-14 8:11 ` [PATCH v3 04/10] ASoC: mediatek: mt8196: support ADDA in platform driver Darren.Ye
@ 2025-05-14 8:11 ` Darren.Ye
2025-05-14 8:11 ` [PATCH v3 07/10] ASoC: mediatek: mt8196: add " Darren.Ye
` (3 subsequent siblings)
7 siblings, 0 replies; 23+ messages in thread
From: Darren.Ye @ 2025-05-14 8:11 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add mt8196 TDM DAI driver support.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/mt8196/mt8196-dai-tdm.c | 862 +++++++++++++++++++++
1 file changed, 862 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-tdm.c
diff --git a/sound/soc/mediatek/mt8196/mt8196-dai-tdm.c b/sound/soc/mediatek/mt8196/mt8196-dai-tdm.c
new file mode 100644
index 000000000000..c938d72ad39f
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-dai-tdm.c
@@ -0,0 +1,862 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI TDM Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8196-afe-clk.h"
+#include "mt8196-afe-common.h"
+#include "mt8196-interconnection.h"
+
+struct mtk_afe_tdm_priv {
+ int bck_id;
+ int bck_rate;
+
+ int mclk_id;
+ int mclk_multiple; /* according to sample rate */
+ int mclk_rate;
+ int mclk_apll;
+};
+
+enum {
+ TDM_WLEN_16_BIT = 1,
+ TDM_WLEN_32_BIT = 2,
+};
+
+enum {
+ TDM_CHANNEL_BCK_16 = 0,
+ TDM_CHANNEL_BCK_24 = 1,
+ TDM_CHANNEL_BCK_32 = 2,
+};
+
+enum {
+ TDM_CHANNEL_NUM_2 = 0,
+ TDM_CHANNEL_NUM_4 = 1,
+ TDM_CHANNEL_NUM_8 = 2,
+};
+
+enum {
+ TDM_CH_START_O30_O31 = 0,
+ TDM_CH_START_O32_O33,
+ TDM_CH_START_O34_O35,
+ TDM_CH_START_O36_O37,
+ TDM_CH_ZERO,
+};
+
+enum {
+ DPTX_CHANNEL_2,
+ DPTX_CHANNEL_8,
+};
+
+enum {
+ DPTX_WLEN_24_BIT,
+ DPTX_WLEN_16_BIT,
+};
+
+enum {
+ DPTX_CH_EN_MASK_2CH = 0x3,
+ DPTX_CH_EN_MASK_4CH = 0xf,
+ DPTX_CH_EN_MASK_6CH = 0x3f,
+ DPTX_CH_EN_MASK_8CH = 0xff,
+};
+
+static unsigned int get_tdm_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ TDM_WLEN_16_BIT : TDM_WLEN_32_BIT;
+}
+
+static unsigned int get_tdm_channel_bck(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32;
+}
+
+static unsigned int get_tdm_lrck_width(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) - 1;
+}
+
+static unsigned int get_tdm_ch(unsigned int ch)
+{
+ switch (ch) {
+ case 1:
+ case 2:
+ return TDM_CHANNEL_NUM_2;
+ case 3:
+ case 4:
+ return TDM_CHANNEL_NUM_4;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ default:
+ return TDM_CHANNEL_NUM_8;
+ }
+}
+
+static unsigned int get_dptx_ch_enable_mask(unsigned int ch)
+{
+ switch (ch) {
+ case 1:
+ case 2:
+ return DPTX_CH_EN_MASK_2CH;
+ case 3:
+ case 4:
+ return DPTX_CH_EN_MASK_4CH;
+ case 5:
+ case 6:
+ return DPTX_CH_EN_MASK_6CH;
+ case 7:
+ case 8:
+ return DPTX_CH_EN_MASK_8CH;
+ default:
+ pr_info("invalid channel num, default use 2ch\n");
+ return DPTX_CH_EN_MASK_2CH;
+ }
+}
+
+static unsigned int get_dptx_ch(unsigned int ch)
+{
+ if (ch == 2)
+ return DPTX_CHANNEL_2;
+ else
+ return DPTX_CHANNEL_8;
+}
+
+static unsigned int get_dptx_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ DPTX_WLEN_16_BIT : DPTX_WLEN_24_BIT;
+}
+
+/* interconnection */
+enum {
+ HDMI_CONN_CH0 = 0,
+ HDMI_CONN_CH1,
+ HDMI_CONN_CH2,
+ HDMI_CONN_CH3,
+ HDMI_CONN_CH4,
+ HDMI_CONN_CH5,
+ HDMI_CONN_CH6,
+ HDMI_CONN_CH7,
+};
+
+static const char *const hdmi_conn_mux_map[] = {
+ "CH0", "CH1", "CH2", "CH3",
+ "CH4", "CH5", "CH6", "CH7",
+};
+
+static int hdmi_conn_mux_map_value[] = {
+ HDMI_CONN_CH0,
+ HDMI_CONN_CH1,
+ HDMI_CONN_CH2,
+ HDMI_CONN_CH3,
+ HDMI_CONN_CH4,
+ HDMI_CONN_CH5,
+ HDMI_CONN_CH6,
+ HDMI_CONN_CH7,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_0_SFT,
+ HDMI_O_0_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch0_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_1_SFT,
+ HDMI_O_1_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch1_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_2_SFT,
+ HDMI_O_2_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch2_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_3_SFT,
+ HDMI_O_3_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch3_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_4_SFT,
+ HDMI_O_4_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch4_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_5_SFT,
+ HDMI_O_5_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch5_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_6_SFT,
+ HDMI_O_6_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch6_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_7_SFT,
+ HDMI_O_7_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch7_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum);
+
+static const char *const tdm_out_mux_map[] = {
+ "Disconnect", "Connect",
+};
+
+static int tdm_out_mux_map_value[] = {
+ 0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(hdmi_out_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ 1,
+ tdm_out_mux_map,
+ tdm_out_mux_map_value);
+static const struct snd_kcontrol_new hdmi_out_mux_control =
+ SOC_DAPM_ENUM("HDMI_OUT_MUX", hdmi_out_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(dptx_out_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ 1,
+ tdm_out_mux_map,
+ tdm_out_mux_map_value);
+static const struct snd_kcontrol_new dptx_out_mux_control =
+ SOC_DAPM_ENUM("DPTX_OUT_MUX", dptx_out_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(dptx_virtual_out_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ 1,
+ tdm_out_mux_map,
+ tdm_out_mux_map_value);
+
+static const struct snd_kcontrol_new dptx_virtual_out_mux_control =
+ SOC_DAPM_ENUM("DPTX_VIRTUAL_OUT_MUX", dptx_virtual_out_mux_map_enum);
+
+enum {
+ SUPPLY_SEQ_APLL,
+ SUPPLY_SEQ_TDM_MCK_EN,
+ SUPPLY_SEQ_TDM_BCK_EN,
+ SUPPLY_SEQ_TDM_DPTX_MCK_EN,
+ SUPPLY_SEQ_TDM_DPTX_BCK_EN,
+ SUPPLY_SEQ_TDM_CG_EN,
+};
+
+static int get_tdm_id_by_name(const char *name)
+{
+ if (strstr(name, "DPTX"))
+ return MT8196_DAI_TDM_DPTX;
+ else
+ return MT8196_DAI_TDM;
+}
+
+static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+ dev_dbg(cmpnt->dev, "name %s, event 0x%x, dai_id %d\n",
+ w->name, event, dai_id);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mt8196_mck_disable(afe, tdm_priv->bck_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+ dev_dbg(cmpnt->dev, "name %s, event 0x%x, dai_id %d\n",
+ w->name, event, dai_id);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ tdm_priv->mclk_rate = 0;
+ mt8196_mck_disable(afe, tdm_priv->mclk_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_tdm_cg_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int cg_id = MT8196_CLK_AFE_TDM_OUT;
+
+ dev_dbg(cmpnt->dev, "name %s, event 0x%x\n", w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_afe_enable_clk(afe, afe_priv->clk[cg_id]);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mt8196_afe_disable_clk(afe, afe_priv->clk[cg_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),
+
+ /* cg */
+ SND_SOC_DAPM_SUPPLY_S("TDM_CG", SUPPLY_SEQ_TDM_CG_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_tdm_cg_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("DPTX_VIRTUAL_OUT_MUX",
+ SND_SOC_NOPM, 0, 0, &dptx_virtual_out_mux_control),
+ SND_SOC_DAPM_OUTPUT("DPTX_VIRTUAL_OUT"),
+};
+
+static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+ int cur_apll;
+
+ /* which apll */
+ cur_apll = mt8196_get_apll_by_name(afe, source->name);
+
+ return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {
+ {"HDMI_CH0_MUX", "CH0", "HDMI"},
+ {"HDMI_CH0_MUX", "CH1", "HDMI"},
+ {"HDMI_CH0_MUX", "CH2", "HDMI"},
+ {"HDMI_CH0_MUX", "CH3", "HDMI"},
+ {"HDMI_CH0_MUX", "CH4", "HDMI"},
+ {"HDMI_CH0_MUX", "CH5", "HDMI"},
+ {"HDMI_CH0_MUX", "CH6", "HDMI"},
+ {"HDMI_CH0_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH1_MUX", "CH0", "HDMI"},
+ {"HDMI_CH1_MUX", "CH1", "HDMI"},
+ {"HDMI_CH1_MUX", "CH2", "HDMI"},
+ {"HDMI_CH1_MUX", "CH3", "HDMI"},
+ {"HDMI_CH1_MUX", "CH4", "HDMI"},
+ {"HDMI_CH1_MUX", "CH5", "HDMI"},
+ {"HDMI_CH1_MUX", "CH6", "HDMI"},
+ {"HDMI_CH1_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH2_MUX", "CH0", "HDMI"},
+ {"HDMI_CH2_MUX", "CH1", "HDMI"},
+ {"HDMI_CH2_MUX", "CH2", "HDMI"},
+ {"HDMI_CH2_MUX", "CH3", "HDMI"},
+ {"HDMI_CH2_MUX", "CH4", "HDMI"},
+ {"HDMI_CH2_MUX", "CH5", "HDMI"},
+ {"HDMI_CH2_MUX", "CH6", "HDMI"},
+ {"HDMI_CH2_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH3_MUX", "CH0", "HDMI"},
+ {"HDMI_CH3_MUX", "CH1", "HDMI"},
+ {"HDMI_CH3_MUX", "CH2", "HDMI"},
+ {"HDMI_CH3_MUX", "CH3", "HDMI"},
+ {"HDMI_CH3_MUX", "CH4", "HDMI"},
+ {"HDMI_CH3_MUX", "CH5", "HDMI"},
+ {"HDMI_CH3_MUX", "CH6", "HDMI"},
+ {"HDMI_CH3_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH4_MUX", "CH0", "HDMI"},
+ {"HDMI_CH4_MUX", "CH1", "HDMI"},
+ {"HDMI_CH4_MUX", "CH2", "HDMI"},
+ {"HDMI_CH4_MUX", "CH3", "HDMI"},
+ {"HDMI_CH4_MUX", "CH4", "HDMI"},
+ {"HDMI_CH4_MUX", "CH5", "HDMI"},
+ {"HDMI_CH4_MUX", "CH6", "HDMI"},
+ {"HDMI_CH4_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH5_MUX", "CH0", "HDMI"},
+ {"HDMI_CH5_MUX", "CH1", "HDMI"},
+ {"HDMI_CH5_MUX", "CH2", "HDMI"},
+ {"HDMI_CH5_MUX", "CH3", "HDMI"},
+ {"HDMI_CH5_MUX", "CH4", "HDMI"},
+ {"HDMI_CH5_MUX", "CH5", "HDMI"},
+ {"HDMI_CH5_MUX", "CH6", "HDMI"},
+ {"HDMI_CH5_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH6_MUX", "CH0", "HDMI"},
+ {"HDMI_CH6_MUX", "CH1", "HDMI"},
+ {"HDMI_CH6_MUX", "CH2", "HDMI"},
+ {"HDMI_CH6_MUX", "CH3", "HDMI"},
+ {"HDMI_CH6_MUX", "CH4", "HDMI"},
+ {"HDMI_CH6_MUX", "CH5", "HDMI"},
+ {"HDMI_CH6_MUX", "CH6", "HDMI"},
+ {"HDMI_CH6_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH7_MUX", "CH0", "HDMI"},
+ {"HDMI_CH7_MUX", "CH1", "HDMI"},
+ {"HDMI_CH7_MUX", "CH2", "HDMI"},
+ {"HDMI_CH7_MUX", "CH3", "HDMI"},
+ {"HDMI_CH7_MUX", "CH4", "HDMI"},
+ {"HDMI_CH7_MUX", "CH5", "HDMI"},
+ {"HDMI_CH7_MUX", "CH6", "HDMI"},
+ {"HDMI_CH7_MUX", "CH7", "HDMI"},
+
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH0_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH1_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH2_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH3_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH4_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH5_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH6_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH7_MUX"},
+
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH0_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH1_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH2_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH3_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH4_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH5_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH6_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH7_MUX"},
+
+ {"TDM", NULL, "HDMI_OUT_MUX"},
+ {"TDM", NULL, "TDM_BCK"},
+ {"TDM", 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 = mt8196_get_apll_by_rate(afe, freq);
+ apll_rate = mt8196_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 mt8196_afe_private *afe_priv = afe->platform_priv;
+ int tdm_id = dai->id;
+ struct mtk_afe_tdm_priv *tdm_priv;
+ unsigned int rate = params_rate(params);
+ unsigned int channels = params_channels(params);
+ snd_pcm_format_t format = params_format(params);
+ unsigned int tdm_con = 0;
+
+ if (tdm_id >= MT8196_DAI_NUM || tdm_id < 0)
+ return -EINVAL;
+
+ tdm_priv = afe_priv->dai_priv[tdm_id];
+
+ if (!tdm_priv)
+ return -EINVAL;
+
+ /* 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_info(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 = 0 << BCK_INVERSE_SFT;
+ tdm_con |= 0 << LRCK_INVERSE_SFT;
+ tdm_con |= 0 << DELAY_DATA_SFT;
+ tdm_con |= 1 << LEFT_ALIGN_SFT;
+ tdm_con |= get_tdm_wlen(format) << WLEN_SFT;
+ tdm_con |= get_tdm_ch(channels) << CHANNEL_NUM_SFT;
+ tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT;
+ tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT;
+ regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con);
+
+ /* set dptx */
+ if (tdm_id == MT8196_DAI_TDM_DPTX) {
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_CHANNEL_ENABLE_MASK_SFT,
+ get_dptx_ch_enable_mask(channels) <<
+ DPTX_CHANNEL_ENABLE_SFT);
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_CHANNEL_NUMBER_MASK_SFT,
+ get_dptx_ch(channels) <<
+ DPTX_CHANNEL_NUMBER_SFT);
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_16BIT_MASK_SFT,
+ get_dptx_wlen(format) << DPTX_16BIT_SFT);
+ }
+ switch (channels) {
+ case 1:
+ case 2:
+ tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+ break;
+ case 3:
+ case 4:
+ tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+ tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+ break;
+ case 5:
+ case 6:
+ tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+ tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+ tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+ break;
+ case 7:
+ case 8:
+ tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+ tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+ tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
+ tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT;
+ break;
+ default:
+ tdm_con = 0;
+ }
+ regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con);
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ HDMI_CH_NUM_MASK_SFT,
+ channels << HDMI_CH_NUM_SFT);
+
+ return 0;
+}
+
+static int mtk_dai_tdm_trigger(struct snd_pcm_substream *substream,
+ int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int tdm_id = dai->id;
+
+ dev_dbg(afe->dev, "cmd %d, tdm_id %d\n", cmd, tdm_id);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ /* enable Out control */
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ HDMI_OUT_ON_MASK_SFT,
+ 0x1 << HDMI_OUT_ON_SFT);
+
+ /* enable dptx */
+ if (tdm_id == MT8196_DAI_TDM_DPTX) {
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_ON_MASK_SFT, 0x1 <<
+ DPTX_ON_SFT);
+ }
+
+ /* enable tdm */
+ regmap_update_bits(afe->regmap, AFE_TDM_CON1,
+ TDM_EN_MASK_SFT, 0x1 << TDM_EN_SFT);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ /* disable tdm */
+ regmap_update_bits(afe->regmap, AFE_TDM_CON1,
+ TDM_EN_MASK_SFT, 0);
+
+ /* disable dptx */
+ if (tdm_id == MT8196_DAI_TDM_DPTX) {
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_ON_MASK_SFT, 0);
+ }
+
+ /* disable Out control */
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ HDMI_OUT_ON_MASK_SFT, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv;
+
+ if (dai->id >= MT8196_DAI_NUM || dai->id < 0)
+ return -EINVAL;
+
+ tdm_priv = afe_priv->dai_priv[dai->id];
+
+ if (!tdm_priv)
+ return -EINVAL;
+
+ if (dir != SND_SOC_CLOCK_OUT)
+ return -EINVAL;
+
+ dev_dbg(afe->dev, "freq %d\n", freq);
+
+ return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
+}
+
+static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {
+ .hw_params = mtk_dai_tdm_hw_params,
+ .trigger = mtk_dai_tdm_trigger,
+ .set_sysclk = mtk_dai_tdm_set_sysclk,
+};
+
+/* dai driver */
+#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {
+ {
+ .name = "TDM",
+ .id = MT8196_DAI_TDM,
+ .playback = {
+ .stream_name = "TDM",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = MTK_TDM_RATES,
+ .formats = MTK_TDM_FORMATS,
+ },
+ .ops = &mtk_dai_tdm_ops,
+ },
+ {
+ .name = "TDM_DPTX",
+ .id = MT8196_DAI_TDM_DPTX,
+ .playback = {
+ .stream_name = "TDM_DPTX",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = MTK_TDM_RATES,
+ .formats = MTK_TDM_FORMATS,
+ },
+ .ops = &mtk_dai_tdm_ops,
+ },
+};
+
+static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe,
+ int id)
+{
+ struct mtk_afe_tdm_priv *tdm_priv;
+
+ tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
+ GFP_KERNEL);
+ if (!tdm_priv)
+ return NULL;
+
+ if (id == MT8196_DAI_TDM_DPTX)
+ tdm_priv->mclk_multiple = 256;
+ else
+ tdm_priv->mclk_multiple = 128;
+
+ tdm_priv->bck_id = MT8196_TDMOUT_BCK;
+ tdm_priv->mclk_id = MT8196_TDMOUT_MCK;
+
+ return tdm_priv;
+}
+
+int mt8196_dai_tdm_register(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv, *tdm_dptx_priv;
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_tdm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
+
+ dai->dapm_widgets = mtk_dai_tdm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
+ dai->dapm_routes = mtk_dai_tdm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
+
+ tdm_priv = init_tdm_priv_data(afe, MT8196_DAI_TDM);
+ if (!tdm_priv)
+ return -ENOMEM;
+
+ tdm_dptx_priv = init_tdm_priv_data(afe, MT8196_DAI_TDM_DPTX);
+ if (!tdm_dptx_priv)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[MT8196_DAI_TDM] = tdm_priv;
+ afe_priv->dai_priv[MT8196_DAI_TDM_DPTX] = tdm_dptx_priv;
+
+ return 0;
+}
+
--
2.45.2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v3 07/10] ASoC: mediatek: mt8196: add platform driver
2025-05-14 8:11 [PATCH v3 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (3 preceding siblings ...)
2025-05-14 8:11 ` [PATCH v3 06/10] ASoC: mediatek: mt8196: support TDM " Darren.Ye
@ 2025-05-14 8:11 ` Darren.Ye
2025-05-15 4:41 ` kernel test robot
2025-05-14 8:11 ` [PATCH v3 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE document Darren.Ye
` (2 subsequent siblings)
7 siblings, 1 reply; 23+ messages in thread
From: Darren.Ye @ 2025-05-14 8:11 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add mt8196 platform driver.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/Kconfig | 10 +
sound/soc/mediatek/Makefile | 1 +
sound/soc/mediatek/mt8196/Makefile | 15 +
sound/soc/mediatek/mt8196/mt8196-afe-pcm.c | 2642 ++++++++++++++++++++
4 files changed, 2668 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/Makefile
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 90e367586493..63d4abebb539 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -319,3 +319,13 @@ config SND_SOC_MT8365_MT6357
boards with the MT6357 PMIC codec.
Select Y if you have such device.
If unsure select "N".
+
+config SND_SOC_MT8196
+ tristate "ASoC support for Mediatek MT8196 chip"
+ depends on ARCH_MEDIATEK
+ select SND_SOC_MEDIATEK
+ help
+ This adds ASoC driver for Mediatek MT8196 boards
+ that can be used with other codecs.
+ Select Y if you have such device.
+ If unsure select "N".
\ No newline at end of file
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
index 4b55434f2168..11d7c484a5d3 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_MT8196) += mt8196/
diff --git a/sound/soc/mediatek/mt8196/Makefile b/sound/soc/mediatek/mt8196/Makefile
new file mode 100644
index 000000000000..b8a51a53d52a
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/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-mt8196-afe-objs += \
+ mt8196-afe-pcm.o \
+ mt8196-afe-clk.o \
+ mt8196-audsys-clk.o \
+ mt8196-dai-adda.o \
+ mt8196-dai-i2s.o \
+ mt8196-dai-tdm.o
+
+obj-$(CONFIG_SND_SOC_MT8196) += snd-soc-mt8196-afe.o
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c b/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
new file mode 100644
index 000000000000..c790827727e0
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
@@ -0,0 +1,2642 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek ALSA SoC AFE platform driver for 8196
+ *
+ * Copyright (c) 2024 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 <linux/regmap.h>
+#include <linux/of_device.h>
+#include <sound/soc.h>
+#include <linux/of_reserved_mem.h>
+
+#include "mt8196-afe-clk.h"
+#include "mt8196-afe-common.h"
+#include "mtk-afe-fe-dai.h"
+#include "mtk-afe-platform-driver.h"
+#include "mt8196-interconnection.h"
+
+static const struct snd_pcm_hardware mt8196_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 mt8196_rate_transform(struct device *dev,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_IPM2P0_RATE_8K;
+ case 11025:
+ return MTK_AFE_IPM2P0_RATE_11K;
+ case 12000:
+ return MTK_AFE_IPM2P0_RATE_12K;
+ case 16000:
+ return MTK_AFE_IPM2P0_RATE_16K;
+ case 22050:
+ return MTK_AFE_IPM2P0_RATE_22K;
+ case 24000:
+ return MTK_AFE_IPM2P0_RATE_24K;
+ case 32000:
+ return MTK_AFE_IPM2P0_RATE_32K;
+ case 44100:
+ return MTK_AFE_IPM2P0_RATE_44K;
+ case 48000:
+ return MTK_AFE_IPM2P0_RATE_48K;
+ case 88200:
+ return MTK_AFE_IPM2P0_RATE_88K;
+ case 96000:
+ return MTK_AFE_IPM2P0_RATE_96K;
+ case 176400:
+ return MTK_AFE_IPM2P0_RATE_176K;
+ case 192000:
+ return MTK_AFE_IPM2P0_RATE_192K;
+ /* not support 260K */
+ case 352800:
+ return MTK_AFE_IPM2P0_RATE_352K;
+ case 384000:
+ return MTK_AFE_IPM2P0_RATE_384K;
+ default:
+ dev_info(dev, "rate %u invalid, use %d!!!\n",
+ rate, MTK_AFE_IPM2P0_RATE_48K);
+ return MTK_AFE_IPM2P0_RATE_48K;
+ }
+}
+
+static void mt8196_set_cm_rate(struct mtk_base_afe *afe, int id, unsigned int rate)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ afe_priv->cm_rate[id] = rate;
+}
+
+static int mt8196_convert_cm_ch(unsigned int ch)
+{
+ return ch - 1;
+}
+
+static unsigned int calculate_cm_update(int rate, int ch)
+{
+ unsigned int update_val;
+
+ update_val = 26000000 / rate / (ch / 2);
+ update_val = update_val * 10 / 7;
+ if (update_val > 100)
+ update_val = 100;
+ if (update_val < 7)
+ update_val = 7;
+
+ return update_val;
+}
+
+static int mt8196_set_cm(struct mtk_base_afe *afe, int id,
+ bool update, bool swap, unsigned int ch)
+{
+ unsigned int rate = 0;
+ unsigned int update_val = 0;
+ int reg;
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ dev_dbg(afe->dev, "CM%d, rate %d, update %d, swap %d, ch %d\n",
+ id, rate, update, swap, ch);
+
+ rate = afe_priv->cm_rate[id];
+ update_val = update ? calculate_cm_update(rate, (int)ch) : 0x64;
+
+ reg = AFE_CM0_CON0 + 0x10 * id;
+ /* update cnt */
+ 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 << AFE_CM_1X_EN_SEL_FS_SFT);
+
+ /* ch num */
+ ch = mt8196_convert_cm_ch(ch);
+ regmap_update_bits(afe->regmap,
+ reg,
+ AFE_CM_CH_NUM_MASK << AFE_CM_CH_NUM_SFT,
+ ch << 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 mt8196_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 mt8196_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, "memif_num: %d.\n", 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_info(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, "no more asys irq\n");
+ ret = -EBUSY;
+ }
+ }
+ return ret;
+}
+
+static void mt8196_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 mt8196_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, "memif_num: %d.\n", 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 mt8196_fe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ unsigned int channels = params_channels(params);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+ const struct mtk_base_memif_data *data = memif->data;
+
+ afe_priv->cm_channels = channels;
+
+ /* set channels */
+ if (data->ch_num_shift >= 0) {
+ regmap_update_bits(afe->regmap, data->ch_num_reg,
+ data->ch_num_maskbit << data->ch_num_shift,
+ channels << data->ch_num_shift);
+ }
+
+ return mtk_afe_fe_hw_params(substream, params, dai);
+}
+
+static int mt8196_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 mt8196_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_info(afe->dev, "%s cmd %d, irq_id %d\n",
+ memif->data->name, cmd, irq_id);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ dev_dbg(afe->dev, "%s cmd %d, id %d\n",
+ memif->data->name, cmd, id);
+ ret = mtk_memif_set_enable(afe, id);
+ if (ret) {
+ dev_err(afe->dev, "id %d, memif enable fail.\n", id);
+ 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)
+ usleep_range(300, 350);
+ }
+
+ /* 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,
+ "id %d, memif disable fail\n", id);
+ }
+
+ /* 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 mt8196_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 = mt8196_rate_transform(afe->dev, rate);
+
+ switch (id) {
+ case MT8196_MEMIF_VUL8:
+ case MT8196_MEMIF_VUL_CM0:
+ cm = CM0;
+ break;
+ case MT8196_MEMIF_VUL9:
+ case MT8196_MEMIF_VUL_CM1:
+ cm = CM1;
+ break;
+ case MT8196_MEMIF_VUL10:
+ case MT8196_MEMIF_VUL_CM2:
+ cm = CM2;
+ break;
+ default:
+ cm = CM0;
+ break;
+ }
+
+ mt8196_set_cm_rate(afe, cm, rate_reg);
+
+ return rate_reg;
+}
+
+static int mt8196_get_dai_fs(struct mtk_base_afe *afe,
+ int dai_id, unsigned int rate)
+{
+ return mt8196_rate_transform(afe->dev, rate);
+}
+
+static int mt8196_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 mt8196_rate_transform(afe->dev, rate);
+}
+
+static int mt8196_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 MT8196_MEMIF_PBUF_SIZE_256_BYTES;
+ else
+ return MT8196_MEMIF_PBUF_SIZE_32_BYTES;
+}
+
+/* FE DAIs */
+static const struct snd_soc_dai_ops mt8196_memif_dai_ops = {
+ .startup = mt8196_fe_startup,
+ .shutdown = mt8196_fe_shutdown,
+ .hw_params = mt8196_fe_hw_params,
+ .hw_free = mtk_afe_fe_hw_free,
+ .prepare = mtk_afe_fe_prepare,
+ .trigger = mt8196_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 MT8196_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 = &mt8196_memif_dai_ops, \
+}
+
+#define MT8196_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 = &mt8196_memif_dai_ops, \
+}
+
+static struct snd_soc_dai_driver mt8196_memif_dai_driver[] = {
+ /* FE DAIs: memory intefaces to CPU */
+ /* Playback */
+ MT8196_FE_DAI_PLAYBACK(DL0, MT8196_MEMIF_DL0, 2),
+ MT8196_FE_DAI_PLAYBACK(DL1, MT8196_MEMIF_DL1, 2),
+ MT8196_FE_DAI_PLAYBACK(DL2, MT8196_MEMIF_DL2, 2),
+ MT8196_FE_DAI_PLAYBACK(DL3, MT8196_MEMIF_DL3, 2),
+ MT8196_FE_DAI_PLAYBACK(DL4, MT8196_MEMIF_DL4, 2),
+ MT8196_FE_DAI_PLAYBACK(DL5, MT8196_MEMIF_DL5, 2),
+ MT8196_FE_DAI_PLAYBACK(DL6, MT8196_MEMIF_DL6, 2),
+ MT8196_FE_DAI_PLAYBACK(DL7, MT8196_MEMIF_DL7, 2),
+ MT8196_FE_DAI_PLAYBACK(DL8, MT8196_MEMIF_DL8, 2),
+ MT8196_FE_DAI_PLAYBACK(DL23, MT8196_MEMIF_DL23, 2),
+ MT8196_FE_DAI_PLAYBACK(DL24, MT8196_MEMIF_DL24, 2),
+ MT8196_FE_DAI_PLAYBACK(DL25, MT8196_MEMIF_DL25, 2),
+ MT8196_FE_DAI_PLAYBACK(DL26, MT8196_MEMIF_DL26, 2),
+ MT8196_FE_DAI_PLAYBACK(DL_4CH, MT8196_MEMIF_DL_4CH, 4),
+ MT8196_FE_DAI_PLAYBACK(DL_24CH, MT8196_MEMIF_DL_24CH, 8),
+ MT8196_FE_DAI_PLAYBACK(HDMI, MT8196_MEMIF_HDMI, 8),
+ /* Capture */
+ MT8196_FE_DAI_CAPTURE(UL0, MT8196_MEMIF_VUL0, 2),
+ MT8196_FE_DAI_CAPTURE(UL1, MT8196_MEMIF_VUL1, 2),
+ MT8196_FE_DAI_CAPTURE(UL2, MT8196_MEMIF_VUL2, 2),
+ MT8196_FE_DAI_CAPTURE(UL3, MT8196_MEMIF_VUL3, 2),
+ MT8196_FE_DAI_CAPTURE(UL4, MT8196_MEMIF_VUL4, 2),
+ MT8196_FE_DAI_CAPTURE(UL5, MT8196_MEMIF_VUL5, 2),
+ MT8196_FE_DAI_CAPTURE(UL6, MT8196_MEMIF_VUL6, 2),
+ MT8196_FE_DAI_CAPTURE(UL7, MT8196_MEMIF_VUL7, 2),
+ MT8196_FE_DAI_CAPTURE(UL8, MT8196_MEMIF_VUL8, 2),
+ MT8196_FE_DAI_CAPTURE(UL9, MT8196_MEMIF_VUL9, 16),
+ MT8196_FE_DAI_CAPTURE(UL10, MT8196_MEMIF_VUL10, 2),
+ MT8196_FE_DAI_CAPTURE(UL24, MT8196_MEMIF_VUL24, 2),
+ MT8196_FE_DAI_CAPTURE(UL25, MT8196_MEMIF_VUL25, 2),
+ MT8196_FE_DAI_CAPTURE(UL26, MT8196_MEMIF_VUL26, 2),
+ MT8196_FE_DAI_CAPTURE(UL_CM0, MT8196_MEMIF_VUL_CM0, 8),
+ MT8196_FE_DAI_CAPTURE(UL_CM1, MT8196_MEMIF_VUL_CM1, 16),
+ MT8196_FE_DAI_CAPTURE(UL_CM2, MT8196_MEMIF_VUL_CM2, 32),
+ MT8196_FE_DAI_CAPTURE(UL_ETDM_IN0, MT8196_MEMIF_ETDM_IN0, 2),
+ MT8196_FE_DAI_CAPTURE(UL_ETDM_IN1, MT8196_MEMIF_ETDM_IN1, 2),
+ MT8196_FE_DAI_CAPTURE(UL_ETDM_IN2, MT8196_MEMIF_ETDM_IN2, 2),
+ MT8196_FE_DAI_CAPTURE(UL_ETDM_IN3, MT8196_MEMIF_ETDM_IN3, 2),
+ MT8196_FE_DAI_CAPTURE(UL_ETDM_IN4, MT8196_MEMIF_ETDM_IN4, 2),
+ MT8196_FE_DAI_CAPTURE(UL_ETDM_IN6, MT8196_MEMIF_ETDM_IN6, 2),
+};
+
+static const struct snd_kcontrol_new mt8196_pcm_kcontrols[] = {
+};
+
+enum {
+ CM0_MUX_VUL8_2CH,
+ CM0_MUX_VUL8_8CH,
+ CM0_MUX_MASK,
+};
+
+enum {
+ CM1_MUX_VUL9_2CH,
+ CM1_MUX_VUL9_16CH,
+ CM1_MUX_MASK,
+};
+
+enum {
+ CM2_MUX_VUL10_2CH,
+ CM2_MUX_VUL10_32CH,
+ CM2_MUX_MASK,
+};
+
+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 mt8196_afe_private *afe_priv = afe->platform_priv;
+ unsigned int channels = afe_priv->cm_channels;
+
+ dev_dbg(afe->dev, "event 0x%x, name %s, channels %u\n",
+ event, w->name, channels);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_enable_cm_bypass(afe, CM0, 0x0);
+ mt8196_set_cm(afe, CM0, true, false, channels);
+ mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_CM0]);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ mt8196_enable_cm_bypass(afe, CM0, 0x1);
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_CM0]);
+ 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 mt8196_afe_private *afe_priv = afe->platform_priv;
+ unsigned int channels = afe_priv->cm_channels;
+
+ dev_dbg(afe->dev, "event 0x%x, name %s, channels %u\n",
+ event, w->name, channels);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_enable_cm_bypass(afe, CM1, 0x0);
+ mt8196_set_cm(afe, CM1, true, false, channels);
+ mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_CM1]);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ mt8196_enable_cm_bypass(afe, CM1, 0x1);
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_CM1]);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int ul_cm2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ unsigned int channels = afe_priv->cm_channels;
+
+ dev_dbg(afe->dev, "event 0x%x, name %s, channels %u\n",
+ event, w->name, channels);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_enable_cm_bypass(afe, CM2, 0x0);
+ mt8196_set_cm(afe, CM2, true, false, channels);
+ mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_CM2]);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ mt8196_enable_cm_bypass(afe, CM2, 0x1);
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_CM2]);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/* 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),
+};
+
+static const struct snd_kcontrol_new memif_ul0_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN019_0,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN4_CH1", AFE_CONN020_4,
+ I_I2SIN4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN6_CH1", AFE_CONN020_5,
+ I_I2SIN6_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN4_CH2", AFE_CONN021_4,
+ I_I2SIN4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN6_CH2", AFE_CONN021_5,
+ I_I2SIN6_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN022_0,
+ I_ADDA_UL_CH3, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN023_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH1", AFE_CONN024_4,
+ I_I2SIN0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH1", AFE_CONN024_4,
+ I_I2SIN1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN3_CH1", AFE_CONN024_4,
+ I_I2SIN3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN4_CH1", AFE_CONN024_4,
+ I_I2SIN4_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH2", AFE_CONN025_4,
+ I_I2SIN0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH2", AFE_CONN025_4,
+ I_I2SIN1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN3_CH2", AFE_CONN025_4,
+ I_I2SIN3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN4_CH2", AFE_CONN025_4,
+ I_I2SIN4_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("I2SIN0_CH1", AFE_CONN026_4,
+ I_I2SIN0_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("I2SIN0_CH2", AFE_CONN027_4,
+ I_I2SIN0_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul5_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN3_CH1", AFE_CONN028_4,
+ I_I2SIN3_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul5_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN3_CH2", AFE_CONN029_4,
+ I_I2SIN3_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),
+};
+
+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),
+};
+
+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),
+};
+
+static const struct snd_kcontrol_new memif_ul7_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN033_0,
+ I_ADDA_UL_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),
+};
+
+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),
+};
+
+static const struct snd_kcontrol_new memif_ul9_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN037_0,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul10_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN038_0,
+ I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul10_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN039_0,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul24_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH1", AFE_CONN066_4,
+ I_I2SIN0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN6_CH1", AFE_CONN066_5,
+ I_I2SIN6_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul24_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH2", AFE_CONN067_4,
+ I_I2SIN0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN6_CH2", AFE_CONN067_5,
+ I_I2SIN6_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul25_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH1", AFE_CONN068_4,
+ I_I2SIN0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN6_CH1", AFE_CONN068_5,
+ I_I2SIN6_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul25_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH2", AFE_CONN069_4,
+ I_I2SIN0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN6_CH2", AFE_CONN069_5,
+ I_I2SIN6_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul26_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH1", AFE_CONN070_4,
+ I_I2SIN0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN6_CH1", AFE_CONN070_5,
+ I_I2SIN6_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul26_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH2", AFE_CONN071_4,
+ I_I2SIN0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN6_CH2", AFE_CONN071_5,
+ I_I2SIN6_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),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN041_0,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch3_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN042_0,
+ I_ADDA_UL_CH3, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN043_0,
+ I_ADDA_UL_CH4, 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),
+};
+
+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),
+};
+
+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),
+};
+
+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),
+};
+
+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),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN049_0,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch3_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN050_0,
+ I_ADDA_UL_CH3, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN051_0,
+ I_ADDA_UL_CH4, 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),
+};
+
+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),
+};
+
+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),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN064_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN064_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN064_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN064_0, I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN064_0, I_ADDA_UL_CH5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN064_0, I_ADDA_UL_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN065_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN065_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN065_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN065_0, I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN065_0, I_ADDA_UL_CH5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN065_0, I_ADDA_UL_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch3_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN066_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN066_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN066_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN066_0, I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN066_0, I_ADDA_UL_CH5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN066_0, I_ADDA_UL_CH6, 1, 0)
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN067_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN067_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN067_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN067_0, I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN067_0, I_ADDA_UL_CH5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN067_0, I_ADDA_UL_CH6, 1, 0)
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch5_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN068_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN068_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN068_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN068_0, I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN068_0, I_ADDA_UL_CH5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN068_0, I_ADDA_UL_CH6, 1, 0)
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch6_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN069_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN069_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN069_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN069_0, I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN069_0, I_ADDA_UL_CH5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN069_0, I_ADDA_UL_CH6, 1, 0)
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch7_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN070_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN070_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN070_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN070_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch8_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN071_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN071_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN071_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN071_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch9_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN072_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN072_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN072_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN072_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch10_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN073_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN073_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN073_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN073_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch11_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN074_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN074_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN074_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN074_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch12_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN075_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN075_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN075_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN075_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch13_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN076_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN076_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN076_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN076_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch14_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN077_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN077_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN077_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN077_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch15_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN078_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN078_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN078_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN078_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch16_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN079_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN079_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN079_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN079_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch17_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN080_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN080_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN080_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN080_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch18_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN081_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN081_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN081_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN081_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch19_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN082_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN082_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN082_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN082_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch20_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN083_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN083_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN083_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN083_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch21_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN084_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN084_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN084_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN084_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch22_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN085_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN085_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN085_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN085_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch23_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN086_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN086_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN086_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN086_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch24_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN087_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN087_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN087_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN087_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch25_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN088_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN088_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN088_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN088_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch26_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN089_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN089_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN089_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN089_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch27_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN090_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN090_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN090_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN090_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch28_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN091_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN091_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN091_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN091_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch29_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN092_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN092_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN092_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN092_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch30_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN093_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN093_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN093_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN093_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch31_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN094_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN094_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN094_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN094_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm2_ch32_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN095_0, I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN095_0, I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN095_0, I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN095_0, I_ADDA_UL_CH4, 1, 0),
+};
+
+static const char * const cm0_mux_map[] = {
+ "CM0_8CH_PATH",
+ "UL8_2CH_PATH",
+};
+
+static const char * const cm1_mux_map[] = {
+ "CM1_16CH_PATH",
+ "UL9_2CH_PATH",
+};
+
+static const char * const cm2_mux_map[] = {
+ "CM2_32CH_PATH",
+ "UL10_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 int cm2_mux_map_value[] = {
+ CM2_MUX_VUL10_32CH,
+ CM2_MUX_VUL10_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 SOC_VALUE_ENUM_SINGLE_DECL(ul_cm2_mux_map_enum,
+ AFE_CM2_CON0,
+ AFE_CM2_OUTPUT_MUX_SFT,
+ AFE_CM2_OUTPUT_MUX_MASK,
+ cm2_mux_map,
+ cm2_mux_map_value);
+
+static const struct snd_kcontrol_new ul_cm0_mux_control =
+ SOC_DAPM_ENUM("CM0_UL_MUX Route", ul_cm0_mux_map_enum);
+
+static const struct snd_kcontrol_new ul_cm1_mux_control =
+ SOC_DAPM_ENUM("CM1_UL_MUX Route", ul_cm1_mux_map_enum);
+
+static const struct snd_kcontrol_new ul_cm2_mux_control =
+ SOC_DAPM_ENUM("CM2_UL_MUX Route", ul_cm2_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mt8196_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("UL10_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul10_ch1_mix, ARRAY_SIZE(memif_ul10_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL10_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul10_ch2_mix, ARRAY_SIZE(memif_ul10_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("UL25_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul25_ch1_mix, ARRAY_SIZE(memif_ul25_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL25_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul25_ch2_mix, ARRAY_SIZE(memif_ul25_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL26_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul26_ch1_mix, ARRAY_SIZE(memif_ul26_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL26_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul26_ch2_mix, ARRAY_SIZE(memif_ul26_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("CM0_UL_MUX", SND_SOC_NOPM, 0, 0,
+ &ul_cm0_mux_control),
+ 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_MIXER("UL_CM2_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch1_mix, ARRAY_SIZE(memif_ul_cm2_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch2_mix, ARRAY_SIZE(memif_ul_cm2_ch2_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH3", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch3_mix, ARRAY_SIZE(memif_ul_cm2_ch3_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH4", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch4_mix, ARRAY_SIZE(memif_ul_cm2_ch4_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH5", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch5_mix, ARRAY_SIZE(memif_ul_cm2_ch5_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH6", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch6_mix, ARRAY_SIZE(memif_ul_cm2_ch6_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH7", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch7_mix, ARRAY_SIZE(memif_ul_cm2_ch7_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH8", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch8_mix, ARRAY_SIZE(memif_ul_cm2_ch8_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH9", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch9_mix, ARRAY_SIZE(memif_ul_cm2_ch9_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH10", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch10_mix, ARRAY_SIZE(memif_ul_cm2_ch10_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH11", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch11_mix, ARRAY_SIZE(memif_ul_cm2_ch11_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH12", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch12_mix, ARRAY_SIZE(memif_ul_cm2_ch12_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH13", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch13_mix, ARRAY_SIZE(memif_ul_cm2_ch13_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH14", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch14_mix, ARRAY_SIZE(memif_ul_cm2_ch14_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH15", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch15_mix, ARRAY_SIZE(memif_ul_cm2_ch15_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH16", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch16_mix, ARRAY_SIZE(memif_ul_cm2_ch16_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH17", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch17_mix, ARRAY_SIZE(memif_ul_cm2_ch17_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH18", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch18_mix, ARRAY_SIZE(memif_ul_cm2_ch18_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH19", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch19_mix, ARRAY_SIZE(memif_ul_cm2_ch19_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH20", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch20_mix, ARRAY_SIZE(memif_ul_cm2_ch20_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH21", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch21_mix, ARRAY_SIZE(memif_ul_cm2_ch21_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH22", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch22_mix, ARRAY_SIZE(memif_ul_cm2_ch22_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH23", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch23_mix, ARRAY_SIZE(memif_ul_cm2_ch23_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH24", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch24_mix, ARRAY_SIZE(memif_ul_cm2_ch24_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH25", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch25_mix, ARRAY_SIZE(memif_ul_cm2_ch25_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH26", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch26_mix, ARRAY_SIZE(memif_ul_cm2_ch26_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH27", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch27_mix, ARRAY_SIZE(memif_ul_cm2_ch27_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH28", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch28_mix, ARRAY_SIZE(memif_ul_cm2_ch28_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH29", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch29_mix, ARRAY_SIZE(memif_ul_cm2_ch29_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH30", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch30_mix, ARRAY_SIZE(memif_ul_cm2_ch30_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH31", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch31_mix, ARRAY_SIZE(memif_ul_cm2_ch31_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM2_CH32", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm2_ch32_mix, ARRAY_SIZE(memif_ul_cm2_ch32_mix)),
+ SND_SOC_DAPM_MUX("CM2_UL_MUX", SND_SOC_NOPM, 0, 0,
+ &ul_cm2_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_CM1_ON_SFT, 0,
+ ul_cm1_event,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_SUPPLY("CM2_Enable",
+ AFE_CM2_CON0, AFE_CM2_ON_SFT, 0,
+ ul_cm2_event,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_MIXER("SOF_DMA_UL0", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SOF_DMA_UL1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SOF_DMA_UL2", SND_SOC_NOPM, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route mt8196_memif_routes[] = {
+ {"UL0", NULL, "UL0_CH1"},
+ {"UL0", NULL, "UL0_CH2"},
+ /* Normal record */
+ {"UL0_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+ {"UL0_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+ /* SOF Uplink */
+ {"SOF_DMA_UL0", NULL, "UL0_CH1"},
+ {"SOF_DMA_UL0", NULL, "UL0_CH2"},
+
+ {"UL1", NULL, "UL1_CH1"},
+ {"UL1", NULL, "UL1_CH2"},
+ {"UL1_CH1", "I2SIN4_CH1", "I2SIN4"},
+ {"UL1_CH2", "I2SIN4_CH2", "I2SIN4"},
+ {"UL1_CH1", "I2SIN6_CH1", "I2SIN6"},
+ {"UL1_CH2", "I2SIN6_CH2", "I2SIN6"},
+ /* SOF Uplink */
+ {"SOF_DMA_UL1", NULL, "UL1_CH1"},
+ {"SOF_DMA_UL1", NULL, "UL1_CH2"},
+
+ {"UL2", NULL, "UL2_CH1"},
+ {"UL2", NULL, "UL2_CH2"},
+ {"UL2_CH1", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+ {"UL2_CH2", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+ /* SOF Uplink */
+ {"SOF_DMA_UL2", NULL, "UL2_CH1"},
+ {"SOF_DMA_UL2", NULL, "UL2_CH2"},
+
+ {"UL3", NULL, "UL3_CH1"},
+ {"UL3", NULL, "UL3_CH2"},
+ {"UL3_CH1", "I2SIN0_CH1", "I2SIN0"},
+ {"UL3_CH2", "I2SIN0_CH2", "I2SIN0"},
+ {"UL3_CH1", "I2SIN1_CH1", "I2SIN1"},
+ {"UL3_CH2", "I2SIN1_CH2", "I2SIN1"},
+ {"UL3_CH1", "I2SIN3_CH1", "I2SIN3"},
+ {"UL3_CH2", "I2SIN3_CH2", "I2SIN3"},
+ {"UL3_CH1", "I2SIN4_CH1", "I2SIN4"},
+ {"UL3_CH2", "I2SIN4_CH2", "I2SIN4"},
+
+ {"UL4", NULL, "UL4_CH1"},
+ {"UL4", NULL, "UL4_CH2"},
+ {"UL4_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+ {"UL4_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+ {"UL4_CH1", "I2SIN0_CH1", "I2SIN0"},
+ {"UL4_CH2", "I2SIN0_CH2", "I2SIN0"},
+
+ {"UL5", NULL, "UL5_CH1"},
+ {"UL5", NULL, "UL5_CH2"},
+ {"UL5_CH1", "I2SIN3_CH1", "I2SIN3"},
+ {"UL5_CH2", "I2SIN3_CH2", "I2SIN3"},
+
+ {"UL6", NULL, "UL6_CH1"},
+ {"UL6", NULL, "UL6_CH2"},
+ {"UL6_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+ {"UL6_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+
+ {"UL7", NULL, "UL7_CH1"},
+ {"UL7", NULL, "UL7_CH2"},
+ {"UL7_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+ {"UL7_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+
+ {"UL8", NULL, "CM0_UL_MUX"},
+ {"CM0_UL_MUX", "UL8_2CH_PATH", "UL8_CH1"},
+ {"CM0_UL_MUX", "UL8_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 */
+ {"UL9", NULL, "CM1_UL_MUX"},
+ {"CM1_UL_MUX", "UL9_2CH_PATH", "UL9_CH1"},
+ {"CM1_UL_MUX", "UL9_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_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+ {"UL9_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+
+ {"UL10", NULL, "CM2_UL_MUX"},
+ {"CM2_UL_MUX", "UL10_2CH_PATH", "UL10_CH1"},
+ {"CM2_UL_MUX", "UL10_2CH_PATH", "UL10_CH2"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH1"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH2"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH3"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH4"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH5"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH6"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH7"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH8"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH9"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH10"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH11"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH12"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH13"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH14"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH15"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH16"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH17"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH18"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH19"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH20"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH21"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH22"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH23"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH24"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH25"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH26"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH27"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH28"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH29"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH30"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH31"},
+ {"CM2_UL_MUX", "CM2_32CH_PATH", "UL_CM2_CH32"},
+ {"UL_CM2_CH1", NULL, "CM2_Enable"},
+ {"UL_CM2_CH2", NULL, "CM2_Enable"},
+ {"UL_CM2_CH3", NULL, "CM2_Enable"},
+ {"UL_CM2_CH4", NULL, "CM2_Enable"},
+ {"UL_CM2_CH5", NULL, "CM2_Enable"},
+ {"UL_CM2_CH6", NULL, "CM2_Enable"},
+ {"UL_CM2_CH7", NULL, "CM2_Enable"},
+ {"UL_CM2_CH8", NULL, "CM2_Enable"},
+ {"UL_CM2_CH9", NULL, "CM2_Enable"},
+ {"UL_CM2_CH10", NULL, "CM2_Enable"},
+ {"UL_CM2_CH11", NULL, "CM2_Enable"},
+ {"UL_CM2_CH12", NULL, "CM2_Enable"},
+ {"UL_CM2_CH13", NULL, "CM2_Enable"},
+ {"UL_CM2_CH14", NULL, "CM2_Enable"},
+ {"UL_CM2_CH15", NULL, "CM2_Enable"},
+ {"UL_CM2_CH16", NULL, "CM2_Enable"},
+ {"UL_CM2_CH17", NULL, "CM2_Enable"},
+ {"UL_CM2_CH18", NULL, "CM2_Enable"},
+ {"UL_CM2_CH19", NULL, "CM2_Enable"},
+ {"UL_CM2_CH20", NULL, "CM2_Enable"},
+ {"UL_CM2_CH21", NULL, "CM2_Enable"},
+ {"UL_CM2_CH22", NULL, "CM2_Enable"},
+ {"UL_CM2_CH23", NULL, "CM2_Enable"},
+ {"UL_CM2_CH24", NULL, "CM2_Enable"},
+ {"UL_CM2_CH25", NULL, "CM2_Enable"},
+ {"UL_CM2_CH26", NULL, "CM2_Enable"},
+ {"UL_CM2_CH27", NULL, "CM2_Enable"},
+ {"UL_CM2_CH28", NULL, "CM2_Enable"},
+ {"UL_CM2_CH29", NULL, "CM2_Enable"},
+ {"UL_CM2_CH30", NULL, "CM2_Enable"},
+ {"UL_CM2_CH31", NULL, "CM2_Enable"},
+ {"UL_CM2_CH32", NULL, "CM2_Enable"},
+ {"UL10_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+ {"UL10_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+
+ {"UL24", NULL, "UL24_CH1"},
+ {"UL24", NULL, "UL24_CH2"},
+ {"UL24_CH1", "I2SIN6_CH1", "I2SIN6"},
+ {"UL24_CH2", "I2SIN6_CH2", "I2SIN6"},
+ {"UL24_CH1", "I2SIN0_CH1", "I2SIN0"},
+ {"UL24_CH2", "I2SIN0_CH2", "I2SIN0"},
+
+ {"UL25", NULL, "UL25_CH1"},
+ {"UL25", NULL, "UL25_CH2"},
+ {"UL25_CH1", "I2SIN6_CH1", "I2SIN6"},
+ {"UL25_CH2", "I2SIN6_CH2", "I2SIN6"},
+ {"UL25_CH1", "I2SIN0_CH1", "I2SIN0"},
+ {"UL25_CH2", "I2SIN0_CH2", "I2SIN0"},
+
+ {"UL26", NULL, "UL26_CH1"},
+ {"UL26", NULL, "UL26_CH2"},
+ {"UL26_CH1", "I2SIN6_CH1", "I2SIN6"},
+ {"UL26_CH2", "I2SIN6_CH2", "I2SIN6"},
+ {"UL26_CH1", "I2SIN0_CH1", "I2SIN0"},
+ {"UL26_CH2", "I2SIN0_CH2", "I2SIN0"},
+
+ {"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_UL_Mux"},
+ {"UL_CM0_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+ {"UL_CM0_CH3", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+ {"UL_CM0_CH4", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+
+ {"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_UL_Mux"},
+ {"UL_CM1_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+ {"UL_CM1_CH3", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+ {"UL_CM1_CH4", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+
+ {"UL_CM2", NULL, "UL_CM2_CH1"},
+ {"UL_CM2", NULL, "UL_CM2_CH2"},
+ {"UL_CM2", NULL, "UL_CM2_CH3"},
+ {"UL_CM2", NULL, "UL_CM2_CH4"},
+ {"UL_CM2", NULL, "UL_CM2_CH5"},
+ {"UL_CM2", NULL, "UL_CM2_CH6"},
+ {"UL_CM2", NULL, "UL_CM2_CH7"},
+ {"UL_CM2", NULL, "UL_CM2_CH8"},
+ {"UL_CM2", NULL, "UL_CM2_CH9"},
+ {"UL_CM2", NULL, "UL_CM2_CH10"},
+ {"UL_CM2", NULL, "UL_CM2_CH11"},
+ {"UL_CM2", NULL, "UL_CM2_CH12"},
+ {"UL_CM2", NULL, "UL_CM2_CH13"},
+ {"UL_CM2", NULL, "UL_CM2_CH14"},
+ {"UL_CM2", NULL, "UL_CM2_CH15"},
+ {"UL_CM2", NULL, "UL_CM2_CH16"},
+ {"UL_CM2", NULL, "UL_CM2_CH17"},
+ {"UL_CM2", NULL, "UL_CM2_CH18"},
+ {"UL_CM2", NULL, "UL_CM2_CH19"},
+ {"UL_CM2", NULL, "UL_CM2_CH20"},
+ {"UL_CM2", NULL, "UL_CM2_CH21"},
+ {"UL_CM2", NULL, "UL_CM2_CH22"},
+ {"UL_CM2", NULL, "UL_CM2_CH23"},
+ {"UL_CM2", NULL, "UL_CM2_CH24"},
+ {"UL_CM2", NULL, "UL_CM2_CH25"},
+ {"UL_CM2", NULL, "UL_CM2_CH26"},
+ {"UL_CM2", NULL, "UL_CM2_CH27"},
+ {"UL_CM2", NULL, "UL_CM2_CH28"},
+ {"UL_CM2", NULL, "UL_CM2_CH29"},
+ {"UL_CM2", NULL, "UL_CM2_CH30"},
+ {"UL_CM2", NULL, "UL_CM2_CH31"},
+ {"UL_CM2", NULL, "UL_CM2_CH32"},
+ {"UL_CM2_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+ {"UL_CM2_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+ {"UL_CM2_CH3", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+ {"UL_CM2_CH4", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+};
+
+#define MT8196_DL_MEMIF(_id) \
+ [MT8196_MEMIF_##_id] = { \
+ .name = #_id, \
+ .id = MT8196_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 MT8196_MULTI_DL_MEMIF(_id) \
+ [MT8196_MEMIF_##_id] = { \
+ .name = #_id, \
+ .id = MT8196_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 MT8196_UL_MEMIF(_id, _fs_shift, _fs_maskbit, _mono_shift) \
+ [MT8196_MEMIF_##_id] = { \
+ .name = #_id, \
+ .id = MT8196_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[MT8196_MEMIF_NUM] = {
+ MT8196_DL_MEMIF(DL0),
+ MT8196_DL_MEMIF(DL1),
+ MT8196_DL_MEMIF(DL2),
+ MT8196_DL_MEMIF(DL3),
+ MT8196_DL_MEMIF(DL4),
+ MT8196_DL_MEMIF(DL5),
+ MT8196_DL_MEMIF(DL6),
+ MT8196_DL_MEMIF(DL7),
+ MT8196_DL_MEMIF(DL8),
+ MT8196_DL_MEMIF(DL23),
+ MT8196_DL_MEMIF(DL24),
+ MT8196_DL_MEMIF(DL25),
+ MT8196_DL_MEMIF(DL26),
+ MT8196_MULTI_DL_MEMIF(DL_4CH),
+ MT8196_MULTI_DL_MEMIF(DL_24CH),
+ MT8196_MULTI_DL_MEMIF(HDMI),
+ MT8196_UL_MEMIF(VUL0, VUL0_SEL_FS_SFT, VUL0_SEL_FS_MASK, VUL0_MONO_SFT),
+ MT8196_UL_MEMIF(VUL1, VUL1_SEL_FS_SFT, VUL1_SEL_FS_MASK, VUL1_MONO_SFT),
+ MT8196_UL_MEMIF(VUL2, VUL2_SEL_FS_SFT, VUL2_SEL_FS_MASK, VUL2_MONO_SFT),
+ MT8196_UL_MEMIF(VUL3, VUL3_SEL_FS_SFT, VUL3_SEL_FS_MASK, VUL3_MONO_SFT),
+ MT8196_UL_MEMIF(VUL4, VUL4_SEL_FS_SFT, VUL4_SEL_FS_MASK, VUL4_MONO_SFT),
+ MT8196_UL_MEMIF(VUL5, VUL5_SEL_FS_SFT, VUL5_SEL_FS_MASK, VUL5_MONO_SFT),
+ MT8196_UL_MEMIF(VUL6, VUL6_SEL_FS_SFT, VUL6_SEL_FS_MASK, VUL6_MONO_SFT),
+ MT8196_UL_MEMIF(VUL7, VUL7_SEL_FS_SFT, VUL7_SEL_FS_MASK, VUL7_MONO_SFT),
+ MT8196_UL_MEMIF(VUL8, VUL8_SEL_FS_SFT, VUL8_SEL_FS_MASK, VUL8_MONO_SFT),
+ MT8196_UL_MEMIF(VUL9, VUL9_SEL_FS_SFT, VUL9_SEL_FS_MASK, VUL9_MONO_SFT),
+ MT8196_UL_MEMIF(VUL10, VUL10_SEL_FS_SFT, VUL10_SEL_FS_MASK, VUL10_MONO_SFT),
+ MT8196_UL_MEMIF(VUL24, VUL24_SEL_FS_SFT, VUL24_SEL_FS_MASK, VUL24_MONO_SFT),
+ MT8196_UL_MEMIF(VUL25, VUL25_SEL_FS_SFT, VUL25_SEL_FS_MASK, VUL25_MONO_SFT),
+ MT8196_UL_MEMIF(VUL26, VUL26_SEL_FS_SFT, VUL26_SEL_FS_MASK, VUL26_MONO_SFT),
+ MT8196_UL_MEMIF(VUL_CM0, -1, -1, -1),
+ MT8196_UL_MEMIF(VUL_CM1, -1, -1, -1),
+ MT8196_UL_MEMIF(VUL_CM2, -1, -1, -1),
+ MT8196_UL_MEMIF(ETDM_IN0, REG_FS_TIMING_SEL_SFT, REG_FS_TIMING_SEL_MASK, -1),
+ MT8196_UL_MEMIF(ETDM_IN1, REG_FS_TIMING_SEL_SFT, REG_FS_TIMING_SEL_MASK, -1),
+ MT8196_UL_MEMIF(ETDM_IN2, REG_FS_TIMING_SEL_SFT, REG_FS_TIMING_SEL_MASK, -1),
+ MT8196_UL_MEMIF(ETDM_IN3, REG_FS_TIMING_SEL_SFT, REG_FS_TIMING_SEL_MASK, -1),
+ MT8196_UL_MEMIF(ETDM_IN4, REG_FS_TIMING_SEL_SFT, REG_FS_TIMING_SEL_MASK, -1),
+ MT8196_UL_MEMIF(ETDM_IN6, REG_FS_TIMING_SEL_SFT, REG_FS_TIMING_SEL_MASK, -1),
+};
+
+#define MT8183_AFE_IRQ_BASE(_id, _fs_reg, _fs_shift, _fs_maskbit) \
+ [MT8183_IRQ_##_id] = { \
+ .id = MT8183_IRQ_##_id, \
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT##_id, \
+ .irq_cnt_shift = 0, \
+ .irq_cnt_maskbit = 0x3ffff, \
+ .irq_fs_reg = _fs_reg, \
+ .irq_fs_shift = _fs_shift, \
+ .irq_fs_maskbit = _fs_maskbit, \
+ .irq_en_reg = AFE_IRQ_MCU_CON0, \
+ .irq_en_shift = IRQ##_id##_MCU_ON_SFT, \
+ .irq_clr_reg = AFE_IRQ_MCU_CLR, \
+ .irq_clr_shift = IRQ##_id##_MCU_CLR_SFT, \
+ }
+
+#define MT8196_AFE_IRQ(_id) \
+ [MT8196_IRQ_##_id] = { \
+ .id = MT8196_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 MT8196_AFE_TDM_IRQ(_id) \
+ [MT8196_IRQ_##_id] = { \
+ .id = MT8196_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[MT8196_IRQ_NUM] = {
+ MT8196_AFE_IRQ(0),
+ MT8196_AFE_IRQ(1),
+ MT8196_AFE_IRQ(2),
+ MT8196_AFE_IRQ(3),
+ MT8196_AFE_IRQ(4),
+ MT8196_AFE_IRQ(5),
+ MT8196_AFE_IRQ(6),
+ MT8196_AFE_IRQ(7),
+ MT8196_AFE_IRQ(8),
+ MT8196_AFE_IRQ(9),
+ MT8196_AFE_IRQ(10),
+ MT8196_AFE_IRQ(11),
+ MT8196_AFE_IRQ(12),
+ MT8196_AFE_IRQ(13),
+ MT8196_AFE_IRQ(14),
+ MT8196_AFE_IRQ(15),
+ MT8196_AFE_IRQ(16),
+ MT8196_AFE_IRQ(17),
+ MT8196_AFE_IRQ(18),
+ MT8196_AFE_IRQ(19),
+ MT8196_AFE_IRQ(20),
+ MT8196_AFE_IRQ(21),
+ MT8196_AFE_IRQ(22),
+ MT8196_AFE_IRQ(23),
+ MT8196_AFE_IRQ(24),
+ MT8196_AFE_IRQ(25),
+ MT8196_AFE_IRQ(26),
+ MT8196_AFE_TDM_IRQ(31),
+};
+
+static const int memif_irq_usage[MT8196_MEMIF_NUM] = {
+ /* TODO: verify each memif & irq */
+ [MT8196_MEMIF_DL0] = MT8196_IRQ_0,
+ [MT8196_MEMIF_DL1] = MT8196_IRQ_1,
+ [MT8196_MEMIF_DL2] = MT8196_IRQ_2,
+ [MT8196_MEMIF_DL3] = MT8196_IRQ_3,
+ [MT8196_MEMIF_DL4] = MT8196_IRQ_4,
+ [MT8196_MEMIF_DL5] = MT8196_IRQ_5,
+ [MT8196_MEMIF_DL6] = MT8196_IRQ_6,
+ [MT8196_MEMIF_DL7] = MT8196_IRQ_7,
+ [MT8196_MEMIF_DL8] = MT8196_IRQ_8,
+ [MT8196_MEMIF_DL23] = MT8196_IRQ_9,
+ [MT8196_MEMIF_DL24] = MT8196_IRQ_10,
+ [MT8196_MEMIF_DL25] = MT8196_IRQ_11,
+ [MT8196_MEMIF_DL26] = MT8196_IRQ_0,
+ [MT8196_MEMIF_DL_4CH] = MT8196_IRQ_0,
+ [MT8196_MEMIF_DL_24CH] = MT8196_IRQ_12,
+ [MT8196_MEMIF_VUL0] = MT8196_IRQ_13,
+ [MT8196_MEMIF_VUL1] = MT8196_IRQ_14,
+ [MT8196_MEMIF_VUL2] = MT8196_IRQ_15,
+ [MT8196_MEMIF_VUL3] = MT8196_IRQ_16,
+ [MT8196_MEMIF_VUL4] = MT8196_IRQ_17,
+ [MT8196_MEMIF_VUL5] = MT8196_IRQ_18,
+ [MT8196_MEMIF_VUL6] = MT8196_IRQ_19,
+ [MT8196_MEMIF_VUL7] = MT8196_IRQ_20,
+ [MT8196_MEMIF_VUL8] = MT8196_IRQ_21,
+ [MT8196_MEMIF_VUL9] = MT8196_IRQ_22,
+ [MT8196_MEMIF_VUL10] = MT8196_IRQ_23,
+ [MT8196_MEMIF_VUL24] = MT8196_IRQ_24,
+ [MT8196_MEMIF_VUL25] = MT8196_IRQ_25,
+ [MT8196_MEMIF_VUL26] = MT8196_IRQ_0,
+ [MT8196_MEMIF_VUL_CM0] = MT8196_IRQ_26,
+ [MT8196_MEMIF_VUL_CM1] = MT8196_IRQ_0,
+ [MT8196_MEMIF_VUL_CM2] = MT8196_IRQ_0,
+ [MT8196_MEMIF_ETDM_IN0] = MT8196_IRQ_0,
+ [MT8196_MEMIF_ETDM_IN1] = MT8196_IRQ_0,
+ [MT8196_MEMIF_ETDM_IN2] = MT8196_IRQ_0,
+ [MT8196_MEMIF_ETDM_IN3] = MT8196_IRQ_0,
+ [MT8196_MEMIF_ETDM_IN4] = MT8196_IRQ_0,
+ [MT8196_MEMIF_ETDM_IN6] = MT8196_IRQ_0,
+ [MT8196_MEMIF_HDMI] = MT8196_IRQ_31
+};
+
+static bool mt8196_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 ... 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 AUD_TOP_MON_RG:
+ 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 ... AFE_IRQ26_CNT_MON:
+ case AFE_CUSTOM_IRQ0_CNT_MON:
+ case AFE_STF_MON:
+ case AFE_STF_IP_VERSION:
+ 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 ... AFE_ADDA_UL0_SRC_MON1:
+ case AFE_ADDA_UL0_IP_VERSION:
+ case AFE_ADDA_UL1_SRC_DEBUG_MON0 ... AFE_ADDA_UL1_SRC_MON1:
+ case AFE_ADDA_UL1_IP_VERSION:
+ case AFE_MTKAIF_IPM_VER_MON:
+ case AFE_MTKAIF_MON:
+ case AFE_AUD_PAD_TOP_MON:
+ case AFE_ADDA_MTKAIFV4_MON0 ... AFE_ADDA6_MTKAIFV4_MON0:
+ case ETDM_IN0_MON:
+ case ETDM_IN1_MON:
+ case ETDM_IN2_MON:
+ case ETDM_IN4_MON:
+ case ETDM_IN6_MON:
+ case ETDM_OUT0_MON:
+ case ETDM_OUT1_MON:
+ case ETDM_OUT2_MON:
+ case ETDM_OUT4_MON:
+ case ETDM_OUT6_MON:
+ case AFE_DPTX_MON:
+ case AFE_TDM_TOP_IP_VERSION:
+ case AFE_CONN_MON0 ... AFE_CONN_MON5:
+ case AFE_CBIP_SLV_DECODER_MON0 ... AFE_CBIP_SLV_MUX_MON1:
+ case AFE_DL0_CUR_MSB ... AFE_DL0_CUR:
+ case AFE_DL0_RCH_MON ... AFE_DL0_LCH_MON:
+ case AFE_DL1_CUR_MSB ... AFE_DL1_CUR:
+ case AFE_DL1_RCH_MON ... AFE_DL1_LCH_MON:
+ case AFE_DL2_CUR_MSB ... AFE_DL2_CUR:
+ case AFE_DL2_RCH_MON ... AFE_DL2_LCH_MON:
+ case AFE_DL3_CUR_MSB ... AFE_DL3_CUR:
+ case AFE_DL3_RCH_MON ... AFE_DL3_LCH_MON:
+ case AFE_DL4_CUR_MSB ... AFE_DL4_CUR:
+ case AFE_DL4_RCH_MON ... AFE_DL4_LCH_MON:
+ case AFE_DL5_CUR_MSB ... AFE_DL5_CUR:
+ case AFE_DL5_RCH_MON ... AFE_DL5_LCH_MON:
+ case AFE_DL6_CUR_MSB ... AFE_DL6_CUR:
+ case AFE_DL6_RCH_MON ... AFE_DL6_LCH_MON:
+ case AFE_DL7_CUR_MSB ... AFE_DL7_CUR:
+ case AFE_DL7_RCH_MON ... AFE_DL7_LCH_MON:
+ case AFE_DL8_CUR_MSB ... AFE_DL8_CUR:
+ case AFE_DL8_RCH_MON ... AFE_DL8_LCH_MON:
+ case AFE_DL_24CH_CUR_MSB ... AFE_DL_24CH_CUR:
+ case AFE_DL_4CH_CUR_MSB ... AFE_DL_4CH_CUR:
+ case AFE_DL23_CUR_MSB ... AFE_DL23_CUR:
+ case AFE_DL23_RCH_MON ... AFE_DL23_LCH_MON:
+ case AFE_DL24_CUR_MSB ... AFE_DL24_CUR:
+ case AFE_DL24_RCH_MON ... AFE_DL24_LCH_MON:
+ case AFE_DL25_CUR_MSB ... AFE_DL25_CUR:
+ case AFE_DL25_RCH_MON ... AFE_DL25_LCH_MON:
+ case AFE_DL26_CUR_MSB ... AFE_DL26_CUR:
+ case AFE_DL26_RCH_MON ... AFE_DL26_LCH_MON:
+ case AFE_VUL0_CUR_MSB ... AFE_VUL0_CUR:
+ case AFE_VUL1_CUR_MSB ... AFE_VUL1_CUR:
+ case AFE_VUL2_CUR_MSB ... AFE_VUL2_CUR:
+ case AFE_VUL3_CUR_MSB ... AFE_VUL3_CUR:
+ case AFE_VUL4_CUR_MSB ... AFE_VUL4_CUR:
+ case AFE_VUL5_CUR_MSB ... AFE_VUL5_CUR:
+ case AFE_VUL6_CUR_MSB ... AFE_VUL6_CUR:
+ case AFE_VUL7_CUR_MSB ... AFE_VUL7_CUR:
+ case AFE_VUL8_CUR_MSB ... AFE_VUL8_CUR:
+ case AFE_VUL9_CUR_MSB ... AFE_VUL9_CUR:
+ case AFE_VUL10_CUR_MSB ... AFE_VUL10_CUR:
+ case AFE_VUL24_CUR_MSB ... AFE_VUL24_CUR:
+ case AFE_VUL25_CUR_MSB ... AFE_VUL25_CUR:
+ case AFE_VUL25_RCH_MON ... AFE_VUL25_LCH_MON:
+ case AFE_VUL26_CUR_MSB ... AFE_VUL26_CUR:
+ case AFE_VUL_CM0_BASE_MSB ... AFE_VUL_CM0_CON0:
+ case AFE_VUL_CM1_CUR_MSB ... AFE_VUL_CM1_CUR:
+ case AFE_VUL_CM2_CUR_MSB ... AFE_VUL_CM2_CUR:
+ case AFE_ETDM_IN0_CUR_MSB ... AFE_ETDM_IN0_CUR:
+ case AFE_ETDM_IN1_CUR_MSB ... AFE_ETDM_IN1_CUR:
+ case AFE_ETDM_IN2_CUR_MSB ... AFE_ETDM_IN2_CUR:
+ case AFE_ETDM_IN3_CUR_MSB ... AFE_ETDM_IN3_CUR:
+ case AFE_ETDM_IN4_CUR_MSB ... AFE_ETDM_IN4_CUR:
+ case AFE_ETDM_IN6_CUR_MSB ... AFE_ETDM_IN6_CUR:
+ case AFE_HDMI_OUT_CUR_MSB ... AFE_HDMI_OUT_CUR:
+ case AFE_HDMI_OUT_END:
+ case AFE_PROT_SIDEBAND0_MON ... AFE_DOMAIN_SIDEBAND9_MON:
+ case AFE_PCM0_INTF_CON1_MASK_MON ... AFE_ADDA_UL1_SRC_CON0_MASK_MON:
+ case AFE_IRQ_MCU_EN ... 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 ... AFE_IRQ26_MCU_CFG1:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config mt8196_afe_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .volatile_reg = mt8196_is_volatile_reg,
+
+ .max_register = AFE_MAX_REGISTER,
+ .num_reg_defaults_raw = AFE_MAX_REGISTER,
+
+ .cache_type = REGCACHE_FLAT,
+};
+
+static irqreturn_t mt8196_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) &&
+ (cus_ret || !cus_status_mcu)) {
+ dev_info(afe->dev, "irq status err, ret %d, status 0x%x, mcu_en 0x%x\n",
+ ret, status, mcu_en);
+ dev_info(afe->dev, "irq status err, ret %d, cus_status_mcu 0x%x, cus_mcu_en 0x%x\n",
+ ret, cus_status_mcu, cus_mcu_en);
+
+ goto err_irq;
+ }
+
+ ktime_get_ts64(&ts64);
+ t1 = timespec64_to_ns(&ts64);
+
+ for (i = 0; i < MT8196_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 == MT8196_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, "mcu_en 0x%x, cus_mcu_en 0x%x, timeout %llu, limit %llu, ret %d\n",
+ mcu_en, cus_mcu_en,
+ t2, timeout_limit, ret);
+ }
+
+err_irq:
+ /* clear irq */
+ for (i = 0; i < MT8196_IRQ_NUM; ++i) {
+ /* cus_status_mcu only bit0 is used for TDM */
+ if ((status_mcu & (0x1 << i)) || (cus_status_mcu & 0x1)) {
+ 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 mt8196_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 = 0, i;
+
+ if (!afe->regmap) {
+ dev_err(afe->dev, "skip regmap\n");
+ goto skip_regmap;
+ }
+
+ /* disable AFE */
+ mt8196_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, "read_poll ret %d\n", ret);
+ if (ret)
+ dev_info(afe->dev, "ret %d\n", ret);
+
+ /* make sure all irq status are cleared */
+ for (i = 0; i < MT8196_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:
+ mt8196_afe_disable_reg_rw_clk(afe);
+ return 0;
+}
+
+static int mt8196_afe_runtime_resume(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = mt8196_afe_enable_reg_rw_clk(afe);
+ if (ret)
+ return ret;
+
+ if (!afe->regmap) {
+ dev_warn(afe->dev, "skip regmap\n");
+ goto skip_regmap;
+ }
+ 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 */
+ mt8196_afe_enable_main_clock(afe);
+
+skip_regmap:
+ return 0;
+}
+
+static int mt8196_afe_component_probe(struct snd_soc_component *component)
+{
+ if (component)
+ mtk_afe_add_sub_dai_control(component);
+
+ return 0;
+}
+
+static int mt8196_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 mt8196_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 mt8196_afe_component = {
+ .name = AFE_PCM_NAME,
+ .probe = mt8196_afe_component_probe,
+ .pcm_construct = mtk_afe_pcm_new,
+ .pcm_destruct = mt8196_afe_pcm_free,
+ .open = mt8196_afe_pcm_open,
+ .pointer = mtk_afe_pcm_pointer,
+};
+
+static int mt8196_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 = mt8196_memif_dai_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mt8196_memif_dai_driver);
+
+ dai->controls = mt8196_pcm_kcontrols;
+ dai->num_controls = ARRAY_SIZE(mt8196_pcm_kcontrols);
+ dai->dapm_widgets = mt8196_memif_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mt8196_memif_widgets);
+ dai->dapm_routes = mt8196_memif_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mt8196_memif_routes);
+ return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+ mt8196_dai_adda_register,
+ mt8196_dai_i2s_register,
+ mt8196_dai_tdm_register,
+ mt8196_dai_memif_register,
+};
+
+static int mt8196_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 mt8196_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_err(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 = mt8196_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 = MT8196_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 = MT8196_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, mt8196_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 ret: %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 = &mt8196_afe_hardware;
+ afe->memif_fs = mt8196_memif_fs;
+ afe->irq_fs = mt8196_irq_fs;
+ afe->get_dai_fs = mt8196_get_dai_fs;
+ afe->get_memif_pbuf_size = mt8196_get_memif_pbuf_size;
+
+ afe->runtime_resume = mt8196_afe_runtime_resume;
+ afe->runtime_suspend = mt8196_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,
+ &mt8196_afe_regmap_config);
+ if (IS_ERR(afe->regmap))
+ return PTR_ERR(afe->regmap);
+
+ 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,
+ &mt8196_afe_component,
+ afe->dai_drivers,
+ afe->num_dai_drivers);
+ if (ret) {
+ dev_warn(dev, "afe component err\n");
+ goto err_pm_disable;
+ }
+
+ return 0;
+
+err_pm_disable:
+ pm_runtime_disable(dev);
+ return ret;
+}
+
+static void mt8196_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))
+ mt8196_afe_runtime_suspend(dev);
+
+ /* disable afe clock */
+ mt8196_afe_disable_reg_rw_clk(afe);
+ mt8196_afe_disable_main_clock(afe);
+}
+
+static const struct of_device_id mt8196_afe_pcm_dt_match[] = {
+ { .compatible = "mediatek,mt8196-afe", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt8196_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt8196_afe_pm_ops = {
+ SET_RUNTIME_PM_OPS(mt8196_afe_runtime_suspend,
+ mt8196_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt8196_afe_pcm_driver = {
+ .driver = {
+ .name = "mt8196-afe",
+ .of_match_table = mt8196_afe_pcm_dt_match,
+#if IS_ENABLED(CONFIG_PM)
+ .pm = &mt8196_afe_pm_ops,
+#endif
+ },
+ .probe = mt8196_afe_pcm_dev_probe,
+ .remove = mt8196_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt8196_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 8196");
+MODULE_AUTHOR("Darren Ye <darren.ye@mediatek.com>");
+MODULE_LICENSE("GPL");
--
2.45.2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v3 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE document
2025-05-14 8:11 [PATCH v3 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (4 preceding siblings ...)
2025-05-14 8:11 ` [PATCH v3 07/10] ASoC: mediatek: mt8196: add " Darren.Ye
@ 2025-05-14 8:11 ` Darren.Ye
2025-05-14 10:54 ` Krzysztof Kozlowski
2025-05-14 8:11 ` [PATCH v3 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825 Darren.Ye
2025-05-14 8:11 ` [PATCH v3 10/10] ASoC: dt-bindings: mediatek,mt8196-nau8825: add mt8196-nau8825 document Darren.Ye
7 siblings, 1 reply; 23+ messages in thread
From: Darren.Ye @ 2025-05-14 8:11 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add mt8196 audio AFE document.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
.../bindings/sound/mediatek,mt8196-afe.yaml | 155 ++++++++++++++++++
1 file changed, 155 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
new file mode 100644
index 000000000000..384a97ab5f4e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
@@ -0,0 +1,155 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mt8196-afe.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Audio Front End PCM controller for MT8196
+
+maintainers:
+ - Darren Ye <darren.ye@mediatek.com>
+
+properties:
+ compatible:
+ const: mediatek,mt8196-afe
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ memory-region:
+ maxItems: 1
+
+ mediatek,vlpcksys:
+ $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: vlp 26m clock
+ - 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: mux for adsp clock
+ - description: 26m clock
+
+ clock-names:
+ items:
+ - const: top_aud_intbus
+ - const: top_aud_eng1
+ - const: top_aud_eng2
+ - const: top_aud_h
+ - const: vlp_clk26m
+ - 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_tdmout
+ - const: top_adsp
+ - const: clk26m
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - mediatek,vlpcksys
+ - power-domains
+ - memory-region
+ - 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@1a110000 {
+ compatible = "mediatek,mt8196-afe";
+ reg = <0 0x1a110000 0 0x9000>;
+ interrupts = <GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH 0>;
+ memory-region = <&afe_dma_mem_reserved>;
+ mediatek,vlpcksys = <&vlp_cksys_clk>;
+ power-domains = <&scpsys 14>; //MT8196_POWER_DOMAIN_AUDIO
+ clocks = <&vlp_cksys_clk 40>, //CLK_VLP_CK_AUD_INTBUS_SEL
+ <&vlp_cksys_clk 38>, //CLK_VLP_CK_AUD_ENGEN1_SEL
+ <&vlp_cksys_clk 39>, //CLK_VLP_CK_AUD_ENGEN2_SEL
+ <&vlp_cksys_clk 37>, //CLK_VLP_CK_AUDIO_H_SEL
+ <&vlp_cksys_clk 45>, //CLK_VLP_CK_CLKSQ
+ <&cksys_clk 129>, //CLK_CK_APLL1
+ <&cksys_clk 132>, //CLK_CK_APLL2
+ <&cksys_clk 130>, //CLK_CK_APLL1_D4
+ <&cksys_clk 133>, //CLK_CK_APLL2_D4
+ <&cksys_clk 80>, //CLK_CK_APLL12_CK_DIV_I2SIN0
+ <&cksys_clk 81>, //CLK_CK_APLL12_CK_DIV_I2SIN1
+ <&cksys_clk 92>, //CLK_CK_APLL12_CK_DIV_FMI2S
+ <&cksys_clk 93>, //CLK_CK_APLL12_CK_DIV_TDMOUT_M
+ <&cksys_clk 94>, //CLK_CK_APLL12_CK_DIV_TDMOUT_B
+ <&cksys_clk 43>, //CLK_CK_AUD_1_SEL
+ <&cksys_clk 44>, //CLK_CK_AUD_2_SEL
+ <&cksys_clk 66>, //CLK_CK_APLL_I2SIN0_MCK_SEL
+ <&cksys_clk 67>, //CLK_CK_APLL_I2SIN1_MCK_SEL
+ <&cksys_clk 78>, //CLK_CK_APLL_FMI2S_MCK_SEL
+ <&cksys_clk 79>, //CLK_CK_APLL_TDMOUT_MCK_SEL
+ <&cksys_clk 45>, //CLK_CK_ADSP_SEL
+ <&cksys_clk 140>; //CLK_CK_TCK_26M_MX9
+ clock-names = "top_aud_intbus",
+ "top_aud_eng1",
+ "top_aud_eng2",
+ "top_aud_h",
+ "vlp_clk26m",
+ "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_tdmout",
+ "top_adsp",
+ "clk26m";
+ };
+ };
--
2.45.2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v3 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825
2025-05-14 8:11 [PATCH v3 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (5 preceding siblings ...)
2025-05-14 8:11 ` [PATCH v3 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE document Darren.Ye
@ 2025-05-14 8:11 ` Darren.Ye
2025-05-15 7:27 ` kernel test robot
2025-05-14 8:11 ` [PATCH v3 10/10] ASoC: dt-bindings: mediatek,mt8196-nau8825: add mt8196-nau8825 document Darren.Ye
7 siblings, 1 reply; 23+ messages in thread
From: Darren.Ye @ 2025-05-14 8:11 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add support for mt8196 board with nau8825.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/Kconfig | 22 +-
sound/soc/mediatek/mt8196/Makefile | 3 +
sound/soc/mediatek/mt8196/mt8196-nau8825.c | 869 +++++++++++++++++++++
3 files changed, 893 insertions(+), 1 deletion(-)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-nau8825.c
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 63d4abebb539..90515f7df2cb 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -328,4 +328,24 @@ config SND_SOC_MT8196
This adds ASoC driver for Mediatek MT8196 boards
that can be used with other codecs.
Select Y if you have such device.
- If unsure select "N".
\ No newline at end of file
+ If unsure select "N".
+
+config SND_SOC_MT8196_NAU8825
+ tristate "ASoc Audio driver for MT8196 with NAU8825 and I2S codec"
+ depends on SND_SOC_MT8196
+ depends on I2C
+ select SND_SOC_HDMI_CODEC
+ select SND_SOC_DMIC
+ select SND_SOC_NAU8315
+ select SND_SOC_NAU8825
+ select SND_SOC_RT5645
+ select SND_SOC_RT5682_I2C
+ select SND_SOC_RT5682S
+ select SND_SOC_TAS2781_COMLIB
+ select SND_SOC_TAS2781_FMWLIB
+ select SND_SOC_TAS2781_I2C
+ help
+ This adds support for ASoC machine driver for MediaTek MT8196
+ boards with the NAU8825 and other I2S audio codecs.
+ Select Y if you have such device.
+ If unsure select "N".
diff --git a/sound/soc/mediatek/mt8196/Makefile b/sound/soc/mediatek/mt8196/Makefile
index b8a51a53d52a..453279a11313 100644
--- a/sound/soc/mediatek/mt8196/Makefile
+++ b/sound/soc/mediatek/mt8196/Makefile
@@ -13,3 +13,6 @@ snd-soc-mt8196-afe-objs += \
mt8196-dai-tdm.o
obj-$(CONFIG_SND_SOC_MT8196) += snd-soc-mt8196-afe.o
+
+# machine driver
+obj-$(CONFIG_SND_SOC_MT8196_NAU8825) += mt8196-nau8825.o
diff --git a/sound/soc/mediatek/mt8196/mt8196-nau8825.c b/sound/soc/mediatek/mt8196/mt8196-nau8825.c
new file mode 100644
index 000000000000..6452484a2777
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-nau8825.c
@@ -0,0 +1,869 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8196-nau8825.c -- mt8196 nau8825 ALSA SoC machine driver
+ *
+ * Copyright (c) 2024 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 <linux/of_device.h>
+
+#include "mtk-afe-platform-driver.h"
+#include "mt8196-afe-common.h"
+#include "mtk-afe-platform-driver.h"
+#include "mtk-soundcard-driver.h"
+#include "mtk-dsp-sof-common.h"
+#include "mtk-soc-card.h"
+
+#include "../../codecs/nau8825.h"
+#include "../../codecs/rt5682s.h"
+
+#define NAU8825_HS_PRESENT BIT(0)
+#define RT5682S_HS_PRESENT BIT(1)
+#define RT5650_HS_PRESENT BIT(2)
+
+/*
+ * Nau88l25
+ */
+#define NAU8825_CODEC_DAI "nau8825-hifi"
+
+/*
+ * Rt5682s
+ */
+#define RT5682S_CODEC_DAI "rt5682s-aif1"
+
+/*
+ * Rt5650
+ */
+#define RT5650_CODEC_DAI "rt5645-aif1"
+
+#define SOF_DMA_DL1 "SOF_DMA_DL1"
+#define SOF_DMA_DL_24CH "SOF_DMA_DL_24CH"
+#define SOF_DMA_UL0 "SOF_DMA_UL0"
+#define SOF_DMA_UL1 "SOF_DMA_UL1"
+#define SOF_DMA_UL2 "SOF_DMA_UL2"
+
+enum mt8196_jacks {
+ MT8196_JACK_HEADSET,
+ MT8196_JACK_DP,
+ MT8196_JACK_HDMI,
+ MT8196_JACK_MAX,
+};
+
+static struct snd_soc_jack_pin mt8196_dp_jack_pins[] = {
+ {
+ .pin = "DP",
+ .mask = SND_JACK_LINEOUT,
+ },
+};
+
+static struct snd_soc_jack_pin mt8196_hdmi_jack_pins[] = {
+ {
+ .pin = "HDMI",
+ .mask = SND_JACK_LINEOUT,
+ },
+};
+
+static struct snd_soc_jack_pin nau8825_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new mt8196_dumb_spk_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static const struct snd_soc_dapm_widget mt8196_dumb_spk_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const struct snd_soc_dapm_widget mt8196_nau8825_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SINK("DP"),
+};
+
+static const struct snd_kcontrol_new mt8196_nau8825_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+#define EXT_SPK_AMP_W_NAME "Ext_Speaker_Amp"
+
+static struct snd_soc_card mt8196_nau8825_soc_card;
+
+static const struct snd_soc_dapm_widget mt8196_nau8825_card_widgets[] = {
+ /* dynamic pinctrl */
+ SND_SOC_DAPM_PINCTRL("ETDMIN_SPK_PIN", "aud-gpio-i2sin4-on", "aud-gpio-i2sin4-off"),
+ SND_SOC_DAPM_PINCTRL("ETDMOUT_SPK_PIN", "aud-gpio-i2sout4-on", "aud-gpio-i2sout4-off"),
+ SND_SOC_DAPM_PINCTRL("ETDMIN_HP_PIN", "aud-gpio-i2sin6-on", "aud-gpio-i2sin6-off"),
+ SND_SOC_DAPM_PINCTRL("ETDMOUT_HP_PIN", "aud-gpio-i2sout6-on", "aud-gpio-i2sout6-off"),
+ SND_SOC_DAPM_PINCTRL("ETDMIN_HDMI_PIN", "aud-gpio-i2sin3-on", "aud-gpio-i2sin3-off"),
+ SND_SOC_DAPM_PINCTRL("ETDMOUT_HDMI_PIN", "aud-gpio-i2sout3-on", "aud-gpio-i2sout3-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 mt8196_nau8825_card_routes[] = {
+};
+
+static const struct snd_kcontrol_new mt8196_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 = mt8196_nau8825_i2s_ops
+ */
+static int mt8196_nau8825_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned int rate = params_rate(params);
+ unsigned int mclk_fs_ratio = 128;
+ unsigned int mclk_fs = rate * mclk_fs_ratio;
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ return snd_soc_dai_set_sysclk(cpu_dai,
+ 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8196_nau8825_i2s_ops = {
+ .hw_params = mt8196_nau8825_i2s_hw_params,
+};
+
+static int mt8196_dptx_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned int rate = params_rate(params);
+ unsigned int mclk_fs_ratio = 256;
+ unsigned int mclk_fs = rate * mclk_fs_ratio;
+ struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ return snd_soc_dai_set_sysclk(dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8196_dptx_ops = {
+ .hw_params = mt8196_dptx_hw_params,
+};
+
+static int mt8196_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ dev_info(rtd->dev, "fix format to 32bit\n");
+
+ /* fix BE i2s format to 32bit, clean param mask first */
+ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
+ 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+
+ params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
+
+ return 0;
+}
+
+static int mt8196_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ dev_info(rtd->dev, "fix format to 32bit\n");
+
+ /* fix BE i2s format to 32bit, clean param mask first */
+ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
+ 0, SNDRV_PCM_FORMAT_LAST);
+
+ params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
+ return 0;
+}
+
+static int mt8196_sof_be_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *cmpnt_afe = NULL;
+ struct snd_soc_pcm_runtime *runtime;
+
+ /* find afe component */
+ for_each_card_rtds(rtd->card, runtime) {
+ cmpnt_afe = snd_soc_rtdcom_lookup(runtime, AFE_PCM_NAME);
+ if (cmpnt_afe) {
+ dev_info(rtd->dev, "component->name: %s\n", cmpnt_afe->name);
+ break;
+ }
+ }
+
+ if (cmpnt_afe && !pm_runtime_active(cmpnt_afe->dev)) {
+ dev_err(rtd->dev, "afe pm runtime is not active!!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops mt8196_sof_be_ops = {
+ .hw_params = mt8196_sof_be_hw_params,
+};
+
+static const struct sof_conn_stream g_sof_conn_streams[] = {
+ {
+ .sof_link = "AFE_SOF_DL1",
+ .sof_dma = SOF_DMA_DL1,
+ .stream_dir = SNDRV_PCM_STREAM_PLAYBACK
+ },
+ {
+ .sof_link = "AFE_SOF_DL_24CH",
+ .sof_dma = SOF_DMA_DL_24CH,
+ .stream_dir = SNDRV_PCM_STREAM_PLAYBACK
+ },
+ {
+ .sof_link = "AFE_SOF_UL0",
+ .sof_dma = SOF_DMA_UL0,
+ .stream_dir = SNDRV_PCM_STREAM_CAPTURE
+ },
+ {
+ .sof_link = "AFE_SOF_UL1",
+ .sof_dma = SOF_DMA_UL1,
+ .stream_dir = SNDRV_PCM_STREAM_CAPTURE
+ },
+ {
+ .sof_link = "AFE_SOF_UL2",
+ .sof_dma = SOF_DMA_UL2,
+ .stream_dir = SNDRV_PCM_STREAM_CAPTURE
+ },
+};
+
+/* FE */
+SND_SOC_DAILINK_DEFS(playback1,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback_24ch,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL_24CH")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture0,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture1,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture2,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback_hdmi,
+ DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback2,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture_cm0,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL_CM0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+/* BE */
+SND_SOC_DAILINK_DEFS(ap_dmic,
+ DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(ap_dmic_ch34,
+ DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_CH34")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(ap_dmic_multich,
+ DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_MULTICH")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sin6,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2SIN6")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sout3,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT3")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sout4,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT4")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sout6,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT6")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(tdm_dptx,
+ DAILINK_COMP_ARRAY(COMP_CPU("TDM_DPTX")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(AFE_SOF_DL_24CH,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL_24CH")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(AFE_SOF_DL1,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(AFE_SOF_UL0,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(AFE_SOF_UL1,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(AFE_SOF_UL2,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt8196_nau8825_dai_links[] = {
+ /*
+ * The SOF topology expects PCM streams 0~4 to be available
+ * for the SOF PCM streams. Put the SOF BE definitions here
+ * so that the PCM device numbers are skipped over.
+ * (BE dailinks do not have PCM devices created.)
+ */
+ {
+ .name = "AFE_SOF_DL_24CH",
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ops = &mt8196_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_DL_24CH),
+ },
+ {
+ .name = "AFE_SOF_DL1",
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ops = &mt8196_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_DL1),
+ },
+ {
+ .name = "AFE_SOF_UL0",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ops = &mt8196_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_UL0),
+ },
+ {
+ .name = "AFE_SOF_UL1",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ops = &mt8196_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_UL1),
+ },
+ {
+ .name = "AFE_SOF_UL2",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ops = &mt8196_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_UL2),
+ },
+ /* Front End DAI links */
+ {
+ .name = "HDMI_FE",
+ .stream_name = "HDMI Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback_hdmi),
+ },
+ {
+ .name = "DL2_FE",
+ .stream_name = "DL2 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback2),
+ },
+ {
+ .name = "UL_CM0_FE",
+ .stream_name = "UL_CM0 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture_cm0),
+ },
+ {
+ .name = "DL_24CH_FE",
+ .stream_name = "DL_24CH Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback_24ch),
+ },
+ {
+ .name = "DL1_FE",
+ .stream_name = "DL1 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback1),
+ },
+ {
+ .name = "UL0_FE",
+ .stream_name = "UL0 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture0),
+ },
+ {
+ .name = "UL1_FE",
+ .stream_name = "UL1 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture1),
+ },
+ {
+ .name = "UL2_FE",
+ .stream_name = "UL2 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture2),
+ },
+ /* Back End DAI links */
+ {
+ .name = "I2SIN6_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_nau8825_i2s_ops,
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8196_i2s_hw_params_fixup,
+ SND_SOC_DAILINK_REG(i2sin6),
+ },
+ {
+ .name = "I2SOUT4_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_nau8825_i2s_ops,
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = mt8196_i2s_hw_params_fixup,
+ SND_SOC_DAILINK_REG(i2sout4),
+ },
+ {
+ .name = "I2SOUT6_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_nau8825_i2s_ops,
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8196_i2s_hw_params_fixup,
+ SND_SOC_DAILINK_REG(i2sout6),
+ },
+ {
+ .name = "AP_DMIC_BE",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(ap_dmic),
+ },
+ {
+ .name = "AP_DMIC_CH34_BE",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(ap_dmic_ch34),
+ },
+ {
+ .name = "AP_DMIC_MULTICH_BE",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(ap_dmic_multich),
+ },
+ {
+ .name = "TDM_DPTX_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_dptx_ops,
+ .be_hw_params_fixup = mt8196_dptx_hw_params_fixup,
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(tdm_dptx),
+ },
+ {
+ .name = "I2SOUT3_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_nau8825_i2s_ops,
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(i2sout3),
+ },
+};
+
+static int mt8196_dumb_amp_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ int ret = 0;
+
+ ret = snd_soc_dapm_new_controls(&card->dapm, mt8196_dumb_spk_widgets,
+ ARRAY_SIZE(mt8196_dumb_spk_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add Dumb Speaker dapm, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, mt8196_dumb_spk_controls,
+ ARRAY_SIZE(mt8196_dumb_spk_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add Dumb card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt8196_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8196_JACK_DP];
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ int ret = 0;
+
+ ret = snd_soc_card_jack_new_pins(rtd->card, "DP Jack", SND_JACK_LINEOUT,
+ jack, mt8196_dp_jack_pins,
+ ARRAY_SIZE(mt8196_dp_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "new jack failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+ if (ret) {
+ dev_err(rtd->dev, "set jack failed on %s (ret=%d)\n",
+ component->name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt8196_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8196_JACK_HDMI];
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ int ret = 0;
+
+ ret = snd_soc_card_jack_new_pins(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+ jack, mt8196_hdmi_jack_pins,
+ ARRAY_SIZE(mt8196_hdmi_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "new jack failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+ if (ret) {
+ dev_err(rtd->dev, "set jack failed on %s (ret=%d)\n",
+ component->name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt8196_headset_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8196_JACK_HEADSET];
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ int ret;
+ int type;
+
+ ret = snd_soc_dapm_new_controls(&card->dapm, mt8196_nau8825_widgets,
+ ARRAY_SIZE(mt8196_nau8825_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add nau8825 card widget, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, mt8196_nau8825_controls,
+ ARRAY_SIZE(mt8196_nau8825_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add nau8825 card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+ SND_JACK_BTN_3,
+ jack,
+ nau8825_jack_pins,
+ ARRAY_SIZE(nau8825_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+ type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3;
+ ret = snd_soc_component_set_jack(component, jack, (void *)&type);
+
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+};
+
+static void mt8196_headset_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+
+ snd_soc_component_set_jack(component, NULL, NULL);
+}
+
+static int mt8196_nau8825_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ unsigned int rate = params_rate(params);
+ unsigned int bit_width = params_width(params);
+ int clk_freq, ret;
+
+ clk_freq = rate * 2 * bit_width;
+
+ /* Configure clock for codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret);
+ return ret;
+ }
+
+ /* Configure pll for codec */
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq,
+ params_rate(params) * 256);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops mt8196_nau8825_ops = {
+ .hw_params = mt8196_nau8825_hw_params,
+};
+
+static int mt8196_rt5682s_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ unsigned int rate = params_rate(params);
+ int bitwidth;
+ int ret;
+
+ bitwidth = snd_pcm_format_width(params_format(params));
+ if (bitwidth < 0) {
+ dev_err(card->dev, "invalid bit width: %d\n", bitwidth);
+ return bitwidth;
+ }
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth);
+ if (ret) {
+ dev_err(card->dev, "failed to set tdm slot\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL1, RT5682S_PLL_S_BCLK1,
+ rate * 32, rate * 512);
+ if (ret) {
+ dev_err(card->dev, "failed to set pll\n");
+ return ret;
+ }
+
+ dev_info(card->dev, "%s set mclk rate: %d\n", __func__, rate * 512);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_MCLK,
+ rate * 512, SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(card->dev, "failed to set sysclk\n");
+ return ret;
+ }
+
+ return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 512,
+ SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8196_rt5682s_i2s_ops = {
+ .hw_params = mt8196_rt5682s_i2s_hw_params,
+};
+
+static int mt8196_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_dumb = false;
+ int i;
+
+ dev_info(card->dev, "legacy: %d\n", legacy);
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (strcmp(dai_link->name, "TDM_DPTX_BE") == 0) {
+ if (dai_link->num_codecs &&
+ strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
+ dai_link->init = mt8196_dptx_codec_init;
+ } else if (strcmp(dai_link->name, "I2SOUT3_BE") == 0) {
+ if (dai_link->num_codecs &&
+ strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
+ dai_link->init = mt8196_hdmi_codec_init;
+ } else if (strcmp(dai_link->name, "I2SOUT6_BE") == 0 ||
+ strcmp(dai_link->name, "I2SIN6_BE") == 0) {
+ if (!strcmp(dai_link->codecs->dai_name, NAU8825_CODEC_DAI)) {
+ dai_link->ops = &mt8196_nau8825_ops;
+ if (!init_nau8825) {
+ dai_link->init = mt8196_headset_codec_init;
+ dai_link->exit = mt8196_headset_codec_exit;
+ init_nau8825 = true;
+ }
+ } else if (!strcmp(dai_link->codecs->dai_name, RT5682S_CODEC_DAI)) {
+ dai_link->ops = &mt8196_rt5682s_i2s_ops;
+ if (!init_rt5682s) {
+ dai_link->init = mt8196_headset_codec_init;
+ dai_link->exit = mt8196_headset_codec_exit;
+ init_rt5682s = true;
+ }
+ } else if (!strcmp(dai_link->codecs->dai_name, RT5650_CODEC_DAI)) {
+ dai_link->ops = &mt8196_rt5682s_i2s_ops;
+ if (!init_rt5650) {
+ dai_link->init = mt8196_headset_codec_init;
+ dai_link->exit = mt8196_headset_codec_exit;
+ init_rt5650 = true;
+ }
+ } else {
+ if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) {
+ if (!init_dumb) {
+ dai_link->init = mt8196_dumb_amp_init;
+ init_dumb = true;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const struct mtk_sof_priv mt8196_sof_priv = {
+ .conn_streams = g_sof_conn_streams,
+ .num_streams = ARRAY_SIZE(g_sof_conn_streams),
+};
+
+static struct snd_soc_card mt8196_nau8825_soc_card = {
+ .owner = THIS_MODULE,
+ .dai_link = mt8196_nau8825_dai_links,
+ .num_links = ARRAY_SIZE(mt8196_nau8825_dai_links),
+ .dapm_widgets = mt8196_nau8825_card_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8196_nau8825_card_widgets),
+ .dapm_routes = mt8196_nau8825_card_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8196_nau8825_card_routes),
+ .controls = mt8196_nau8825_card_controls,
+ .num_controls = ARRAY_SIZE(mt8196_nau8825_card_controls),
+};
+
+static const struct mtk_soundcard_pdata mt8196_nau8825_card = {
+ .card_name = "mt8196_nau8825",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8196_nau8825_soc_card,
+ .num_jacks = MT8196_JACK_MAX,
+ .flags = NAU8825_HS_PRESENT
+ },
+ .sof_priv = &mt8196_sof_priv,
+ .soc_probe = mt8196_nau8825_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8196_rt5682s_card = {
+ .card_name = "mt8196_rt5682s",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8196_nau8825_soc_card,
+ .num_jacks = MT8196_JACK_MAX,
+ .flags = RT5682S_HS_PRESENT
+ },
+ .sof_priv = &mt8196_sof_priv,
+ .soc_probe = mt8196_nau8825_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8196_rt5650_card = {
+ .card_name = "mt8196_rt5650",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8196_nau8825_soc_card,
+ .num_jacks = MT8196_JACK_MAX,
+ .flags = RT5650_HS_PRESENT
+ },
+ .sof_priv = &mt8196_sof_priv,
+ .soc_probe = mt8196_nau8825_soc_card_probe,
+};
+
+static const struct of_device_id mt8196_nau8825_dt_match[] = {
+ {.compatible = "mediatek,mt8196-nau8825-sound", .data = &mt8196_nau8825_card,},
+ {.compatible = "mediatek,mt8196-rt5682s-sound", .data = &mt8196_rt5682s_card,},
+ {.compatible = "mediatek,mt8196-rt5650-sound", .data = &mt8196_rt5650_card,},
+ {}
+};
+MODULE_DEVICE_TABLE(of, mt8196_nau8825_dt_match);
+
+static struct platform_driver mt8196_nau8825_driver = {
+ .driver = {
+ .name = "mt8196-nau8825",
+ .of_match_table = mt8196_nau8825_dt_match,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = mtk_soundcard_common_probe,
+};
+module_platform_driver(mt8196_nau8825_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8196 nau8825 ALSA SoC machine driver");
+MODULE_AUTHOR("Darren Ye <darren.ye@mediatek.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("mt8196 nau8825 soc card");
+
--
2.45.2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v3 10/10] ASoC: dt-bindings: mediatek,mt8196-nau8825: add mt8196-nau8825 document
2025-05-14 8:11 [PATCH v3 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (6 preceding siblings ...)
2025-05-14 8:11 ` [PATCH v3 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825 Darren.Ye
@ 2025-05-14 8:11 ` Darren.Ye
2025-05-14 10:51 ` Krzysztof Kozlowski
7 siblings, 1 reply; 23+ messages in thread
From: Darren.Ye @ 2025-05-14 8:11 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add document for mt8196 board with nau8825.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
.../sound/mediatek,mt8196-nau8825.yaml | 115 ++++++++++++++++++
1 file changed, 115 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-nau8825.yaml
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8196-nau8825.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8196-nau8825.yaml
new file mode 100644
index 000000000000..8f9aa8b816e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8196-nau8825.yaml
@@ -0,0 +1,115 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mt8196-nau8825.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT8196 ASoC sound card
+
+maintainers:
+ - Darren Ye <darren.ye@mediatek.com>
+
+allOf:
+ - $ref: sound-card-common.yaml#
+
+properties:
+ compatible:
+ enum:
+ - mediatek,mt8196-nau8825-sound
+ - mediatek,mt8196-rt5682s-sound
+ - mediatek,mt8196-rt5650-sound
+
+ audio-routing:
+ description:
+ Valid names could be the input or output widgets of audio components,
+ power supplies, MicBias of codec and the software switch.
+
+ mediatek,platform:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of MT8188 ASoC platform.
+
+ mediatek,adsp:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ The phandle of the MT8188 ADSP platform, which is the optional Audio DSP
+ hardware that provides additional audio functionalities if present.
+ The AFE will link to ADSP when the phandle is provided.
+
+patternProperties:
+ "^dai-link-[0-9]+$":
+ type: object
+ description:
+ Container for dai-link level properties and CODEC sub-nodes.
+
+ properties:
+ link-name:
+ description:
+ This property corresponds to the name of the BE dai-link to which
+ we are going to update parameters in this node.
+ items:
+ enum:
+ - TDM_DPTX_BE
+ - I2SOUT6_BE
+ - I2SIN6_BE
+ - I2SOUT4_BE
+ - I2SOUT3_BE
+
+ codec:
+ description: Holds subnode which indicates codec dai.
+ type: object
+ additionalProperties: false
+ properties:
+ sound-dai:
+ minItems: 1
+ maxItems: 2
+ required:
+ - sound-dai
+
+ dai-format:
+ description: audio format.
+ items:
+ enum:
+ - i2s
+ - right_j
+ - left_j
+ - dsp_a
+ - dsp_b
+
+ mediatek,clk-provider:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: Indicates dai-link clock master.
+ items:
+ enum:
+ - cpu
+ - codec
+
+ additionalProperties: false
+
+ required:
+ - link-name
+
+unevaluatedProperties: false
+
+required:
+ - compatible
+ - mediatek,platform
+
+examples:
+ - |
+ sound {
+ compatible = "mediatek,mt8196-nau8825-sound";
+ model = "mt8196-nau8825";
+ mediatek,platform = <&afe>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&aud_pins_default>;
+ dai-link-0 {
+ link-name = "I2SOUT6_BE";
+ dai-format = "i2s";
+ mediatek,clk-provider = "cpu";
+ codec {
+ sound-dai = <&nau8825>;
+ };
+ };
+ };
+
+...
--
2.45.2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH v3 04/10] ASoC: mediatek: mt8196: support ADDA in platform driver
2025-05-14 8:11 ` [PATCH v3 04/10] ASoC: mediatek: mt8196: support ADDA in platform driver Darren.Ye
@ 2025-05-14 8:17 ` Mark Brown
2025-05-14 8:58 ` Darren Ye (叶飞)
0 siblings, 1 reply; 23+ messages in thread
From: Mark Brown @ 2025-05-14 8:17 UTC (permalink / raw)
To: Darren.Ye
Cc: Liam Girdwood, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Jaroslav Kysela,
Takashi Iwai, Linus Walleij, Bartosz Golaszewski, linux-sound,
devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
linux-gpio
[-- Attachment #1: Type: text/plain, Size: 298 bytes --]
On Wed, May 14, 2025 at 04:11:06PM +0800, Darren.Ye wrote:
> +#include <linux/regmap.h>
> +#include <linux/delay.h>
> +#include "mt8196-afe-clk.h"
> +#include "mt8196-afe-common.h"
> +#include "mt8196-interconnection.h"
> +
> +#define MTKAIF4
This define is there unconditionally, what's it for?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 04/10] ASoC: mediatek: mt8196: support ADDA in platform driver
2025-05-14 8:17 ` Mark Brown
@ 2025-05-14 8:58 ` Darren Ye (叶飞)
0 siblings, 0 replies; 23+ messages in thread
From: Darren Ye (叶飞) @ 2025-05-14 8:58 UTC (permalink / raw)
To: broonie@kernel.org
Cc: linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
devicetree@vger.kernel.org, linus.walleij@linaro.org,
linux-sound@vger.kernel.org, linux-gpio@vger.kernel.org,
brgl@bgdev.pl, conor+dt@kernel.org, tiwai@suse.com,
robh@kernel.org, lgirdwood@gmail.com,
linux-arm-kernel@lists.infradead.org, matthias.bgg@gmail.com,
krzk+dt@kernel.org, perex@perex.cz, AngeloGioacchino Del Regno
On Wed, 2025-05-14 at 10:17 +0200, Mark Brown wrote:
> On Wed, May 14, 2025 at 04:11:06PM +0800, Darren.Ye wrote:
>
> > +#include <linux/regmap.h>
> > +#include <linux/delay.h>
> > +#include "mt8196-afe-clk.h"
> > +#include "mt8196-afe-common.h"
> > +#include "mt8196-interconnection.h"
> > +
> > +#define MTKAIF4
>
> This define is there unconditionally, what's it for?
> In order for the DMIC and MTKAIF4 interface to coexist, this define
can be removed.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 10/10] ASoC: dt-bindings: mediatek,mt8196-nau8825: add mt8196-nau8825 document
2025-05-14 8:11 ` [PATCH v3 10/10] ASoC: dt-bindings: mediatek,mt8196-nau8825: add mt8196-nau8825 document Darren.Ye
@ 2025-05-14 10:51 ` Krzysztof Kozlowski
2025-05-15 3:50 ` Darren Ye (叶飞)
0 siblings, 1 reply; 23+ messages in thread
From: Krzysztof Kozlowski @ 2025-05-14 10:51 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
On 14/05/2025 10:11, Darren.Ye wrote:
A nit, subject: drop second/last, redundant "document". The
"dt-bindings" prefix is already stating that this is a document.
See also:
https://elixir.bootlin.com/linux/v6.7-rc8/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
> +
> +properties:
> + compatible:
> + enum:
> + - mediatek,mt8196-nau8825-sound
> + - mediatek,mt8196-rt5682s-sound
> + - mediatek,mt8196-rt5650-sound
> +
> + audio-routing:
> + description:
> + Valid names could be the input or output widgets of audio components,
> + power supplies, MicBias of codec and the software switch.
Nothing improved. I asked to drop the property. Why do you need it?
> +
> + mediatek,platform:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: The phandle of MT8188 ASoC platform.
> +
> + mediatek,adsp:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description:
> + The phandle of the MT8188 ADSP platform, which is the optional Audio DSP
> + hardware that provides additional audio functionalities if present.
> + The AFE will link to ADSP when the phandle is provided.
> +
...
> + codec:
> + description: Holds subnode which indicates codec dai.
> + type: object
> + additionalProperties: false
> + properties:
> + sound-dai:
> + minItems: 1
> + maxItems: 2
> + required:
> + - sound-dai
> +
> + dai-format:
> + description: audio format.
> + items:
> + enum:
> + - i2s
> + - right_j
> + - left_j
> + - dsp_a
> + - dsp_b
> +
> + mediatek,clk-provider:
> + $ref: /schemas/types.yaml#/definitions/string
> + description: Indicates dai-link clock master.
> + items:
Drop items
> + enum:
> + - cpu
> + - codec
> +
> + additionalProperties: false
> +
> + required:
> + - link-name
> +
> +unevaluatedProperties: false
This goes after required: block.
> +
> +required:
> + - compatible
> + - mediatek,platform
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE document
2025-05-14 8:11 ` [PATCH v3 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE document Darren.Ye
@ 2025-05-14 10:54 ` Krzysztof Kozlowski
2025-05-15 3:57 ` Darren Ye (叶飞)
2025-06-11 9:32 ` Krzysztof Kozlowski
0 siblings, 2 replies; 23+ messages in thread
From: Krzysztof Kozlowski @ 2025-05-14 10:54 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
On 14/05/2025 10:11, Darren.Ye wrote:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Add mt8196 audio AFE document.
A nit, subject: drop second/last, redundant "document".
See also:
https://elixir.bootlin.com/linux/v6.7-rc8/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
...
> +
> +required:
> + - compatible
> + - reg
> + - interrupts
> + - mediatek,vlpcksys
> + - power-domains
> + - memory-region
> + - clocks
> + - clock-names
Keep the same order as in properties:.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
<form letter>
This is an automated instruction, just in case, because many review tags
are being ignored. If you know the process, you can skip it (please do
not feel offended by me posting it here - no bad intentions intended).
If you do not know the process, here is a short explanation:
Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
of patchset, under or above your Signed-off-by tag, unless patch changed
significantly (e.g. new properties added to the DT bindings). Tag is
"received", when provided in a message replied to you on the mailing
list. Tools like b4 can help here. However, there's no need to repost
patches *only* to add the tags. The upstream maintainer will do that for
tags received on the version they apply.
Full context and explanation:
https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
</form letter>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 10/10] ASoC: dt-bindings: mediatek,mt8196-nau8825: add mt8196-nau8825 document
2025-05-14 10:51 ` Krzysztof Kozlowski
@ 2025-05-15 3:50 ` Darren Ye (叶飞)
0 siblings, 0 replies; 23+ messages in thread
From: Darren Ye (叶飞) @ 2025-05-15 3:50 UTC (permalink / raw)
To: krzk@kernel.org, linus.walleij@linaro.org, broonie@kernel.org,
brgl@bgdev.pl, 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, linux-gpio@vger.kernel.org,
devicetree@vger.kernel.org
On Wed, 2025-05-14 at 12:51 +0200, Krzysztof Kozlowski wrote:
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>
>
> On 14/05/2025 10:11, Darren.Ye wrote:
>
>
> A nit, subject: drop second/last, redundant "document". The
> "dt-bindings" prefix is already stating that this is a document.
> See also:
>
https://urldefense.com/v3/__https://elixir.bootlin.com/linux/v6.7-rc8/source/Documentation/devicetree/bindings/submitting-patches.rst*L18__;Iw!!CTRNKA9wMg0ARbw!n2tXtMjEajr9rjHgxY8HrobIrVxtB-rr5xjm626EgyDG7NvXrrcPBhoZZwxgdLatAHHuyyUpD9gF0g$
>
> > +
> > +properties:
> > + compatible:
> > + enum:
> > + - mediatek,mt8196-nau8825-sound
> > + - mediatek,mt8196-rt5682s-sound
> > + - mediatek,mt8196-rt5650-sound
> > +
> > + audio-routing:
> > + description:
> > + Valid names could be the input or output widgets of audio
> > components,
> > + power supplies, MicBias of codec and the software switch.
>
> Nothing improved. I asked to drop the property. Why do you need it?
> I am so sorry to lose your advice and make up the next version,
thanks. confirm with you again the remove of audio-routing property.
>
> > +
> > + mediatek,platform:
> > + $ref: /schemas/types.yaml#/definitions/phandle
> > + description: The phandle of MT8188 ASoC platform.
> > +
> > + mediatek,adsp:
> > + $ref: /schemas/types.yaml#/definitions/phandle
> > + description:
> > + The phandle of the MT8188 ADSP platform, which is the
> > optional Audio DSP
> > + hardware that provides additional audio functionalities if
> > present.
> > + The AFE will link to ADSP when the phandle is provided.
> > +
>
> ...
> remove of mediatek,adsp property.
>
> > + codec:
> > + description: Holds subnode which indicates codec dai.
> > + type: object
> > + additionalProperties: false
> > + properties:
> > + sound-dai:
> > + minItems: 1
> > + maxItems: 2
> > + required:
> > + - sound-dai
> > +
> > + dai-format:
> > + description: audio format.
> > + items:
> > + enum:
> > + - i2s
> > + - right_j
> > + - left_j
> > + - dsp_a
> > + - dsp_b
> > +
> > + mediatek,clk-provider:
> > + $ref: /schemas/types.yaml#/definitions/string
> > + description: Indicates dai-link clock master.
> > + items:
>
> Drop items
>
> Drop items: line
>
> + enum:
> > + - cpu
> > + - codec
> > +
> > + additionalProperties: false
> > +
> > + required:
> > + - link-name
> > +
> > +unevaluatedProperties: false
>
> This goes after required: block.
>
> modify as follows
> required:
> - compatible
> - mediatek,platform
>
> unevaluatedProperties: false
>
> Best regards,
> Darren
>
> > +
> > +required:
> > + - compatible
> > + - mediatek,platform
>
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE document
2025-05-14 10:54 ` Krzysztof Kozlowski
@ 2025-05-15 3:57 ` Darren Ye (叶飞)
2025-06-11 9:32 ` Krzysztof Kozlowski
1 sibling, 0 replies; 23+ messages in thread
From: Darren Ye (叶飞) @ 2025-05-15 3:57 UTC (permalink / raw)
To: krzk@kernel.org, linus.walleij@linaro.org, broonie@kernel.org,
brgl@bgdev.pl, 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, linux-gpio@vger.kernel.org,
devicetree@vger.kernel.org
On Wed, 2025-05-14 at 12:54 +0200, Krzysztof Kozlowski wrote:
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>
>
> On 14/05/2025 10:11, Darren.Ye wrote:
> > From: Darren Ye <darren.ye@mediatek.com>
> >
> > Add mt8196 audio AFE document.
>
> A nit, subject: drop second/last, redundant "document".
> See also:
>
https://urldefense.com/v3/__https://elixir.bootlin.com/linux/v6.7-rc8/source/Documentation/devicetree/bindings/submitting-patches.rst*L18__;Iw!!CTRNKA9wMg0ARbw!iSQl6_WMX8Q6wsBj4pVe7Tdnbd2zpPwSmHMSm4hlhkD0lO7h5JSAr28-dUj_DwLrXhU_IByy_QWQGQ$
>
> >
> > Signed-off-by: Darren Ye <darren.ye@mediatek.com>
>
>
> ...
>
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - interrupts
> > + - mediatek,vlpcksys
> > + - power-domains
> > + - memory-region
> > + - clocks
> > + - clock-names
>
>
> Keep the same order as in properties:.
>
ok, thanks.
Best regards,
Darren
>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>
> <form letter>
> This is an automated instruction, just in case, because many review
> tags
> are being ignored. If you know the process, you can skip it (please
> do
> not feel offended by me posting it here - no bad intentions
> intended).
> If you do not know the process, here is a short explanation:
>
> Please add Acked-by/Reviewed-by/Tested-by tags when posting new
> versions
> of patchset, under or above your Signed-off-by tag, unless patch
> changed
> significantly (e.g. new properties added to the DT bindings). Tag is
> "received", when provided in a message replied to you on the mailing
> list. Tools like b4 can help here. However, there's no need to repost
> patches *only* to add the tags. The upstream maintainer will do that
> for
> tags received on the version they apply.
>
> Full context and explanation:
>
https://urldefense.com/v3/__https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst*L577__;Iw!!CTRNKA9wMg0ARbw!iSQl6_WMX8Q6wsBj4pVe7Tdnbd2zpPwSmHMSm4hlhkD0lO7h5JSAr28-dUj_DwLrXhU_IBzvkGpWKg$
> </form letter>
>
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 07/10] ASoC: mediatek: mt8196: add platform driver
2025-05-14 8:11 ` [PATCH v3 07/10] ASoC: mediatek: mt8196: add " Darren.Ye
@ 2025-05-15 4:41 ` kernel test robot
0 siblings, 0 replies; 23+ messages in thread
From: kernel test robot @ 2025-05-15 4:41 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: oe-kbuild-all, linux-sound, devicetree, linux-kernel,
linux-arm-kernel, linux-mediatek, linux-gpio, Darren Ye
Hi Darren.Ye,
kernel test robot noticed the following build warnings:
[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on broonie-spi/for-next robh/for-next linus/master v6.15-rc6 next-20250514]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Darren-Ye/ASoC-mediatek-common-modify-mtk-afe-platform-driver-for-mt8196/20250514-161921
base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
patch link: https://lore.kernel.org/r/20250514081125.24475-8-darren.ye%40mediatek.com
patch subject: [PATCH v3 07/10] ASoC: mediatek: mt8196: add platform driver
config: arm-allmodconfig (https://download.01.org/0day-ci/archive/20250515/202505151200.uFAkmc5O-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250515/202505151200.uFAkmc5O-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202505151200.uFAkmc5O-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> sound/soc/mediatek/mt8196/mt8196-dai-adda.c:384:30: warning: 'mt8196_adda_enum' defined but not used [-Wunused-const-variable=]
384 | static const struct soc_enum mt8196_adda_enum[] = {
| ^~~~~~~~~~~~~~~~
--
sound/soc/mediatek/mt8196/mt8196-dai-i2s.c: In function 'init_i2s_priv_data':
>> sound/soc/mediatek/mt8196/mt8196-dai-i2s.c:4001:21: warning: the comparison will always evaluate as 'true' for the address of 'mt8196_i2s_priv' will never be NULL [-Waddress]
4001 | if (&mt8196_i2s_priv[i]) {
| ^
sound/soc/mediatek/mt8196/mt8196-dai-i2s.c:3889:38: note: 'mt8196_i2s_priv' declared here
3889 | static const struct mtk_afe_i2s_priv mt8196_i2s_priv[DAI_I2S_NUM] = {
| ^~~~~~~~~~~~~~~
vim +/mt8196_adda_enum +384 sound/soc/mediatek/mt8196/mt8196-dai-adda.c
640b731680b027 Darren Ye 2025-05-14 383
640b731680b027 Darren Ye 2025-05-14 @384 static const struct soc_enum mt8196_adda_enum[] = {
640b731680b027 Darren Ye 2025-05-14 385 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8196_adda_off_on_str),
640b731680b027 Darren Ye 2025-05-14 386 mt8196_adda_off_on_str),
640b731680b027 Darren Ye 2025-05-14 387 };
640b731680b027 Darren Ye 2025-05-14 388
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825
2025-05-14 8:11 ` [PATCH v3 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825 Darren.Ye
@ 2025-05-15 7:27 ` kernel test robot
0 siblings, 0 replies; 23+ messages in thread
From: kernel test robot @ 2025-05-15 7:27 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: oe-kbuild-all, linux-sound, devicetree, linux-kernel,
linux-arm-kernel, linux-mediatek, linux-gpio, Darren Ye
Hi Darren.Ye,
kernel test robot noticed the following build errors:
[auto build test ERROR on broonie-sound/for-next]
[also build test ERROR on broonie-spi/for-next robh/for-next linus/master v6.15-rc6 next-20250514]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Darren-Ye/ASoC-mediatek-common-modify-mtk-afe-platform-driver-for-mt8196/20250514-161921
base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
patch link: https://lore.kernel.org/r/20250514081125.24475-10-darren.ye%40mediatek.com
patch subject: [PATCH v3 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825
config: arm-allmodconfig (https://download.01.org/0day-ci/archive/20250515/202505151544.DAAAOmfW-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250515/202505151544.DAAAOmfW-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202505151544.DAAAOmfW-lkp@intel.com/
All errors (new ones prefixed by >>):
>> sound/soc/mediatek/mt8196/mt8196-nau8825.c:451:49: error: 'SND_SOC_DAIFMT_CBS_CFS' undeclared here (not in a function); did you mean 'SND_SOC_DAIFMT_CBP_CFC'?
451 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
| ^~~~~~~~~~~~~~~~~~~~~~
| SND_SOC_DAIFMT_CBP_CFC
vim +451 sound/soc/mediatek/mt8196/mt8196-nau8825.c
245
246 /* FE */
247 SND_SOC_DAILINK_DEFS(playback1,
248 DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
249 DAILINK_COMP_ARRAY(COMP_DUMMY()),
250 DAILINK_COMP_ARRAY(COMP_EMPTY()));
251 SND_SOC_DAILINK_DEFS(playback_24ch,
252 DAILINK_COMP_ARRAY(COMP_CPU("DL_24CH")),
253 DAILINK_COMP_ARRAY(COMP_DUMMY()),
254 DAILINK_COMP_ARRAY(COMP_EMPTY()));
255 SND_SOC_DAILINK_DEFS(capture0,
256 DAILINK_COMP_ARRAY(COMP_CPU("UL0")),
257 DAILINK_COMP_ARRAY(COMP_DUMMY()),
258 DAILINK_COMP_ARRAY(COMP_EMPTY()));
259 SND_SOC_DAILINK_DEFS(capture1,
260 DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
261 DAILINK_COMP_ARRAY(COMP_DUMMY()),
262 DAILINK_COMP_ARRAY(COMP_EMPTY()));
263 SND_SOC_DAILINK_DEFS(capture2,
264 DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
265 DAILINK_COMP_ARRAY(COMP_DUMMY()),
266 DAILINK_COMP_ARRAY(COMP_EMPTY()));
267 SND_SOC_DAILINK_DEFS(playback_hdmi,
268 DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
269 DAILINK_COMP_ARRAY(COMP_DUMMY()),
270 DAILINK_COMP_ARRAY(COMP_EMPTY()));
271 SND_SOC_DAILINK_DEFS(playback2,
272 DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
273 DAILINK_COMP_ARRAY(COMP_DUMMY()),
274 DAILINK_COMP_ARRAY(COMP_EMPTY()));
275 SND_SOC_DAILINK_DEFS(capture_cm0,
276 DAILINK_COMP_ARRAY(COMP_CPU("UL_CM0")),
277 DAILINK_COMP_ARRAY(COMP_DUMMY()),
278 DAILINK_COMP_ARRAY(COMP_EMPTY()));
279 /* BE */
280 SND_SOC_DAILINK_DEFS(ap_dmic,
281 DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC")),
282 DAILINK_COMP_ARRAY(COMP_DUMMY()),
283 DAILINK_COMP_ARRAY(COMP_EMPTY()));
284 SND_SOC_DAILINK_DEFS(ap_dmic_ch34,
285 DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_CH34")),
286 DAILINK_COMP_ARRAY(COMP_DUMMY()),
287 DAILINK_COMP_ARRAY(COMP_EMPTY()));
288 SND_SOC_DAILINK_DEFS(ap_dmic_multich,
289 DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_MULTICH")),
290 DAILINK_COMP_ARRAY(COMP_DUMMY()),
291 DAILINK_COMP_ARRAY(COMP_EMPTY()));
292 SND_SOC_DAILINK_DEFS(i2sin6,
293 DAILINK_COMP_ARRAY(COMP_CPU("I2SIN6")),
294 DAILINK_COMP_ARRAY(COMP_DUMMY()),
295 DAILINK_COMP_ARRAY(COMP_EMPTY()));
296 SND_SOC_DAILINK_DEFS(i2sout3,
297 DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT3")),
298 DAILINK_COMP_ARRAY(COMP_DUMMY()),
299 DAILINK_COMP_ARRAY(COMP_EMPTY()));
300 SND_SOC_DAILINK_DEFS(i2sout4,
301 DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT4")),
302 DAILINK_COMP_ARRAY(COMP_DUMMY()),
303 DAILINK_COMP_ARRAY(COMP_EMPTY()));
304 SND_SOC_DAILINK_DEFS(i2sout6,
305 DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT6")),
306 DAILINK_COMP_ARRAY(COMP_DUMMY()),
307 DAILINK_COMP_ARRAY(COMP_EMPTY()));
308 SND_SOC_DAILINK_DEFS(tdm_dptx,
309 DAILINK_COMP_ARRAY(COMP_CPU("TDM_DPTX")),
310 DAILINK_COMP_ARRAY(COMP_DUMMY()),
311 DAILINK_COMP_ARRAY(COMP_EMPTY()));
312 SND_SOC_DAILINK_DEFS(AFE_SOF_DL_24CH,
313 DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL_24CH")),
314 DAILINK_COMP_ARRAY(COMP_DUMMY()),
315 DAILINK_COMP_ARRAY(COMP_EMPTY()));
316 SND_SOC_DAILINK_DEFS(AFE_SOF_DL1,
317 DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL1")),
318 DAILINK_COMP_ARRAY(COMP_DUMMY()),
319 DAILINK_COMP_ARRAY(COMP_EMPTY()));
320 SND_SOC_DAILINK_DEFS(AFE_SOF_UL0,
321 DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL0")),
322 DAILINK_COMP_ARRAY(COMP_DUMMY()),
323 DAILINK_COMP_ARRAY(COMP_EMPTY()));
324 SND_SOC_DAILINK_DEFS(AFE_SOF_UL1,
325 DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL1")),
326 DAILINK_COMP_ARRAY(COMP_DUMMY()),
327 DAILINK_COMP_ARRAY(COMP_EMPTY()));
328 SND_SOC_DAILINK_DEFS(AFE_SOF_UL2,
329 DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL2")),
330 DAILINK_COMP_ARRAY(COMP_DUMMY()),
331 DAILINK_COMP_ARRAY(COMP_EMPTY()));
332
333 static struct snd_soc_dai_link mt8196_nau8825_dai_links[] = {
334 /*
335 * The SOF topology expects PCM streams 0~4 to be available
336 * for the SOF PCM streams. Put the SOF BE definitions here
337 * so that the PCM device numbers are skipped over.
338 * (BE dailinks do not have PCM devices created.)
339 */
340 {
341 .name = "AFE_SOF_DL_24CH",
342 .no_pcm = 1,
343 .playback_only = 1,
344 .ops = &mt8196_sof_be_ops,
345 SND_SOC_DAILINK_REG(AFE_SOF_DL_24CH),
346 },
347 {
348 .name = "AFE_SOF_DL1",
349 .no_pcm = 1,
350 .playback_only = 1,
351 .ops = &mt8196_sof_be_ops,
352 SND_SOC_DAILINK_REG(AFE_SOF_DL1),
353 },
354 {
355 .name = "AFE_SOF_UL0",
356 .no_pcm = 1,
357 .capture_only = 1,
358 .ops = &mt8196_sof_be_ops,
359 SND_SOC_DAILINK_REG(AFE_SOF_UL0),
360 },
361 {
362 .name = "AFE_SOF_UL1",
363 .no_pcm = 1,
364 .capture_only = 1,
365 .ops = &mt8196_sof_be_ops,
366 SND_SOC_DAILINK_REG(AFE_SOF_UL1),
367 },
368 {
369 .name = "AFE_SOF_UL2",
370 .no_pcm = 1,
371 .capture_only = 1,
372 .ops = &mt8196_sof_be_ops,
373 SND_SOC_DAILINK_REG(AFE_SOF_UL2),
374 },
375 /* Front End DAI links */
376 {
377 .name = "HDMI_FE",
378 .stream_name = "HDMI Playback",
379 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
380 SND_SOC_DPCM_TRIGGER_PRE},
381 .dynamic = 1,
382 .playback_only = 1,
383 SND_SOC_DAILINK_REG(playback_hdmi),
384 },
385 {
386 .name = "DL2_FE",
387 .stream_name = "DL2 Playback",
388 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
389 SND_SOC_DPCM_TRIGGER_PRE},
390 .dynamic = 1,
391 .playback_only = 1,
392 SND_SOC_DAILINK_REG(playback2),
393 },
394 {
395 .name = "UL_CM0_FE",
396 .stream_name = "UL_CM0 Capture",
397 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
398 SND_SOC_DPCM_TRIGGER_PRE},
399 .dynamic = 1,
400 .capture_only = 1,
401 SND_SOC_DAILINK_REG(capture_cm0),
402 },
403 {
404 .name = "DL_24CH_FE",
405 .stream_name = "DL_24CH Playback",
406 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
407 SND_SOC_DPCM_TRIGGER_PRE},
408 .dynamic = 1,
409 .playback_only = 1,
410 SND_SOC_DAILINK_REG(playback_24ch),
411 },
412 {
413 .name = "DL1_FE",
414 .stream_name = "DL1 Playback",
415 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
416 SND_SOC_DPCM_TRIGGER_PRE},
417 .dynamic = 1,
418 .playback_only = 1,
419 SND_SOC_DAILINK_REG(playback1),
420 },
421 {
422 .name = "UL0_FE",
423 .stream_name = "UL0 Capture",
424 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
425 SND_SOC_DPCM_TRIGGER_PRE},
426 .dynamic = 1,
427 .capture_only = 1,
428 SND_SOC_DAILINK_REG(capture0),
429 },
430 {
431 .name = "UL1_FE",
432 .stream_name = "UL1 Capture",
433 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
434 SND_SOC_DPCM_TRIGGER_PRE},
435 .dynamic = 1,
436 .capture_only = 1,
437 SND_SOC_DAILINK_REG(capture1),
438 },
439 {
440 .name = "UL2_FE",
441 .stream_name = "UL2 Capture",
442 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
443 SND_SOC_DPCM_TRIGGER_PRE},
444 .dynamic = 1,
445 .capture_only = 1,
446 SND_SOC_DAILINK_REG(capture2),
447 },
448 /* Back End DAI links */
449 {
450 .name = "I2SIN6_BE",
> 451 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
452 | SND_SOC_DAIFMT_GATED,
453 .ops = &mt8196_nau8825_i2s_ops,
454 .no_pcm = 1,
455 .capture_only = 1,
456 .ignore_suspend = 1,
457 .be_hw_params_fixup = mt8196_i2s_hw_params_fixup,
458 SND_SOC_DAILINK_REG(i2sin6),
459 },
460 {
461 .name = "I2SOUT4_BE",
462 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
463 | SND_SOC_DAIFMT_GATED,
464 .ops = &mt8196_nau8825_i2s_ops,
465 .no_pcm = 1,
466 .playback_only = 1,
467 .ignore_suspend = 1,
468 .ignore_pmdown_time = 1,
469 .be_hw_params_fixup = mt8196_i2s_hw_params_fixup,
470 SND_SOC_DAILINK_REG(i2sout4),
471 },
472 {
473 .name = "I2SOUT6_BE",
474 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
475 | SND_SOC_DAIFMT_GATED,
476 .ops = &mt8196_nau8825_i2s_ops,
477 .no_pcm = 1,
478 .playback_only = 1,
479 .ignore_suspend = 1,
480 .be_hw_params_fixup = mt8196_i2s_hw_params_fixup,
481 SND_SOC_DAILINK_REG(i2sout6),
482 },
483 {
484 .name = "AP_DMIC_BE",
485 .no_pcm = 1,
486 .capture_only = 1,
487 .ignore_suspend = 1,
488 SND_SOC_DAILINK_REG(ap_dmic),
489 },
490 {
491 .name = "AP_DMIC_CH34_BE",
492 .no_pcm = 1,
493 .capture_only = 1,
494 .ignore_suspend = 1,
495 SND_SOC_DAILINK_REG(ap_dmic_ch34),
496 },
497 {
498 .name = "AP_DMIC_MULTICH_BE",
499 .no_pcm = 1,
500 .capture_only = 1,
501 .ignore_suspend = 1,
502 SND_SOC_DAILINK_REG(ap_dmic_multich),
503 },
504 {
505 .name = "TDM_DPTX_BE",
506 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
507 | SND_SOC_DAIFMT_GATED,
508 .ops = &mt8196_dptx_ops,
509 .be_hw_params_fixup = mt8196_dptx_hw_params_fixup,
510 .no_pcm = 1,
511 .playback_only = 1,
512 .ignore_suspend = 1,
513 SND_SOC_DAILINK_REG(tdm_dptx),
514 },
515 {
516 .name = "I2SOUT3_BE",
517 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
518 | SND_SOC_DAIFMT_GATED,
519 .ops = &mt8196_nau8825_i2s_ops,
520 .no_pcm = 1,
521 .playback_only = 1,
522 .ignore_suspend = 1,
523 SND_SOC_DAILINK_REG(i2sout3),
524 },
525 };
526
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 03/10] ASoC: mediatek: mt8196: support audio clock control
2025-05-14 8:11 ` [PATCH v3 03/10] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
@ 2025-05-15 8:30 ` AngeloGioacchino Del Regno
2025-05-15 8:50 ` Chen-Yu Tsai
0 siblings, 1 reply; 23+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-05-15 8:30 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
Il 14/05/25 10:11, Darren.Ye ha scritto:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Add audio clock wrapper and audio tuner control.
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> ---
> sound/soc/mediatek/mt8196/mt8196-afe-clk.c | 723 ++++++++++++++++++
> sound/soc/mediatek/mt8196/mt8196-afe-clk.h | 142 ++++
> sound/soc/mediatek/mt8196/mt8196-audsys-clk.c | 252 ++++++
> sound/soc/mediatek/mt8196/mt8196-audsys-clk.h | 14 +
> .../soc/mediatek/mt8196/mt8196-audsys-clkid.h | 78 ++
> 5 files changed, 1209 insertions(+)
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.h
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clk.h
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clkid.h
>
> diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.c b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> new file mode 100644
> index 000000000000..83b5ee9d30ef
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> @@ -0,0 +1,723 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * mt8196-afe-clk.c -- Mediatek 8196 afe clock ctrl
mt8196-afe-clk.c - MediaTek MT8196 AFE Clock Control
> + *
> + * Copyright (c) 2024 MediaTek Inc.
> + * Author: Darren Ye <darren.ye@mediatek.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +#include "mt8196-afe-common.h"
> +#include "mt8196-audsys-clk.h"
> +#include "mt8196-afe-clk.h"
> +
..snip..
> +
> +static int mt8196_afe_disable_apll(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int ret = 0;
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> + if (ret)
> + return ret;
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
> + if (ret)
> + goto clk_ck_mux_aud1_err;
> +
> + ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1],
> + afe_priv->clk[MT8196_CLK_TOP_CLK26M]);
> + if (ret)
> + goto clk_ck_mux_aud1_parent_err;
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
> + if (ret)
> + goto clk_ck_mux_aud2_err;
> +
> + ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2],
> + afe_priv->clk[MT8196_CLK_TOP_CLK26M]);
> + if (ret)
> + goto clk_ck_mux_aud2_parent_err;
> +
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
> + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
> + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> + return 0;
> +
> +clk_ck_mux_aud2_parent_err:
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
> +clk_ck_mux_aud2_err:
> + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1],
> + afe_priv->clk[MT8196_CLK_TOP_APLL1_CK]);
> +clk_ck_mux_aud1_parent_err:
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
> +clk_ck_mux_aud1_err:
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> +
> + return ret;
> +}
> +
> +static void mt8196_afe_apll_init(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
if (!afe_priv->vlp_clk) {
dev_warn...
return;
}
regmap_write......
> + if (afe_priv->vlp_ck) {
> + regmap_write(afe_priv->vlp_ck, VLP_APLL1_TUNER_CON0, VLP_APLL1_TUNER_CON0_VALUE);
> + regmap_write(afe_priv->vlp_ck, VLP_APLL2_TUNER_CON0, VLP_APLL2_TUNER_CON0_VALUE);
> + } else {
> + dev_warn(afe->dev, "vlp_ck regmap is null ptr\n");
> + }
> +}
> +
> +int mt8196_apll1_enable(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int ret;
> +
> + /* setting for APLL */
> + apll1_mux_setting(afe, true);
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL1]);
> + if (ret)
> + goto ERR_CLK_APLL1;
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER1]);
> + if (ret)
> + goto ERR_CLK_APLL1_TUNER;
> +
> + /* 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 */
> + mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_APLL1_EN_ON);
> +
> + return 0;
> +
> +ERR_CLK_APLL1_TUNER:
lower case for labels please
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER1]);
> +ERR_CLK_APLL1:
^^^^^^^^^
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL1]);
> + return ret;
> +}
> +
> +void mt8196_apll1_disable(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
> + /* audio apll1 off */
> + mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_APLL1_EN_ON);
> +
> + /* apll1 freq tuner disable */
> + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
> + FREQ_TUNER_EN_MASK_SFT,
> + 0x0);
> +
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER1]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL1]);
> + apll1_mux_setting(afe, false);
> +}
> +
> +int mt8196_apll2_enable(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int ret;
> +
> + /* setting for APLL */
> + apll2_mux_setting(afe, true);
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL2]);
> + if (ret)
> + goto ERR_CLK_APLL2;
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER2]);
> + if (ret)
> + goto ERR_CLK_APLL2_TUNER;
> +
> + /* 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 */
> + mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_APLL2_EN_ON);
> + return 0;
> +
> +ERR_CLK_APLL2_TUNER:
lower case for labels please
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER2]);
> +ERR_CLK_APLL2:
ditto
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL2]);
> + return ret;
> +
> + return 0;
> +}
> +
> +void mt8196_apll2_disable(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
> + /* audio apll2 off */
> + mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_APLL2_EN_ON);
> +
> + /* apll2 freq tuner disable */
> + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
> + FREQ_TUNER_EN_MASK_SFT,
> + 0x0);
> +
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER2]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL2]);
> + apll2_mux_setting(afe, false);
> +}
> +
> +int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int clk_id = 0;
> +
> + if (apll < MT8196_APLL1 || apll > MT8196_APLL2) {
> + dev_warn(afe->dev, "invalid clk id\n");
("invalid clk id %d\n", clk_id)
...otherwise it makes no sense, as it gives no useful information.
Alternatively, just drop the print.
> + return 0;
> + }
> +
> + if (apll == MT8196_APLL1)
> + clk_id = MT8196_CLK_TOP_APLL1_CK;
> + else
> + clk_id = MT8196_CLK_TOP_APLL2_CK;
> +
> + return clk_get_rate(afe_priv->clk[clk_id]);
> +}
> +
> +int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
> +{
> + return ((rate % 8000) == 0) ? MT8196_APLL2 : MT8196_APLL1;
return (rate % 8000) ? MT8196_APLL1 : MT8196_APLL2;
> +}
> +
> +int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
> +{
> + if (strcmp(name, APLL1_W_NAME) == 0)
> + return MT8196_APLL1;
> + else
> + return MT8196_APLL2;
if (strcmp ....)
return MT8196_APLL1;
return MT8196_APLL2;
> +}
> +
> +/* mck */
> +struct mt8196_mck_div {
> + int m_sel_id;
> + int div_clk_id;
> +};
> +
> +static const struct mt8196_mck_div mck_div[MT8196_MCK_NUM] = {
> + [MT8196_I2SIN0_MCK] = {
> + .m_sel_id = MT8196_CLK_TOP_I2SIN0_M_SEL,
> + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_I2SIN0,
> + },
> + [MT8196_I2SIN1_MCK] = {
> + .m_sel_id = MT8196_CLK_TOP_I2SIN1_M_SEL,
> + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_I2SIN1,
> + },
> + [MT8196_FMI2S_MCK] = {
> + .m_sel_id = MT8196_CLK_TOP_FMI2S_M_SEL,
> + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_FMI2S,
> + },
> + [MT8196_TDMOUT_MCK] = {
> + .m_sel_id = MT8196_CLK_TOP_TDMOUT_M_SEL,
> + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_M,
> + },
> + [MT8196_TDMOUT_BCK] = {
> + .m_sel_id = -1,
> + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B,
> + },
> +};
> +
> +int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int apll = mt8196_get_apll_by_rate(afe, rate);
> + int apll_clk_id = apll == MT8196_APLL1 ?
> + MT8196_CLK_TOP_MUX_AUD_1 : MT8196_CLK_TOP_MUX_AUD_2;
> + int m_sel_id = 0;
> + int div_clk_id = 0;
> + int ret = 0;
this gives double initialzation of all m_sel_id, div_clk_id and ret as you are
initializing the first two immediately after the mck_id check, and ret later;
just go for
int m_sel_id, div_clk_id, ret;
or just
int ret;
> +
> + dev_dbg(afe->dev, "mck_id: %d, rate: %d\n", mck_id, rate);
> +
> + if (mck_id >= MT8196_MCK_NUM || mck_id < 0)
> + return -EINVAL;
> +
> + m_sel_id = mck_div[mck_id].m_sel_id;
> + div_clk_id = mck_div[mck_id].div_clk_id;
> +
> + /* select apll */
> + if (m_sel_id >= 0) {
...because then I don't understand why don't you just use mck_div[mck_id] directly.
if (mck_div[mck_id].m_sel_id >= 0) {
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[m_sel_id]);
> + if (ret)
> + return ret;
> +
> + ret = mt8196_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) {
if (mck_div[mck_id].div_clk_id == MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B) {
rate ...
} else if (mck_div[mck_id].div_clk_id < 0) {
....
}
> + dev_err(afe->dev, "invalid div_clk_id %d\n", div_clk_id);
> + return -EINVAL;
> + }
> + if (div_clk_id == MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B)
> + rate = rate * 16;
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[div_clk_id]);
> + if (ret)
> + return ret;
> +
> + ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[div_clk_id], rate);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int m_sel_id = 0;
> + int div_clk_id = 0;
Double init again....
> +
> + 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;
> + }
> +
> + mt8196_afe_disable_clk(afe, afe_priv->clk[div_clk_id]);
> +
> + if (m_sel_id >= 0)
> + mt8196_afe_disable_clk(afe, afe_priv->clk[m_sel_id]);
> +
> + return 0;
> +}
> +
> +int mt8196_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
> + /* bus clock for AFE external access, like DRAM */
> + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
> +
> + /* bus clock for AFE internal access, like AFE SRAM */
> + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
> + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS],
> + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> + /* enable audio vlp clock source */
> + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
> + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> +
> + /* AFE hw clock */
> + /* IPM2.0: USE HOPPING & 26M */
> + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_HOPPING]);
> + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_F26M]);
> + return 0;
> +}
> +
> +int mt8196_afe_disable_reg_rw_clk(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
> + /* IPM2.0: Use HOPPING & 26M */
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_HOPPING]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_F26M]);
> + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
> + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> +
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS],
> + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
> + return 0;
> +}
> +
> +int mt8196_afe_enable_main_clock(struct mtk_base_afe *afe)
> +{
Just directly call
mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_26M_EN_ON);
...and drop mt8196_afe_enable_afe_on()
> + mt8196_afe_enable_afe_on(afe);
> + return 0;
> +}
> +
> +int mt8196_afe_disable_main_clock(struct mtk_base_afe *afe)
> +{
> + mt8196_afe_disable_afe_on(afe);
mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_26M_EN_ON);
> + return 0;
> +}
> +
> +int mt8196_init_clock(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int ret = 0;
> + int i = 0;
> +
> + ret = mt8196_audsys_clk_register(afe);
> + if (ret) {
> + dev_err(afe->dev, "register audsys clk fail %d\n", ret);
> + return ret;
> + }
> +
> + afe_priv->clk = devm_kcalloc(afe->dev, MT8196_CLK_NUM, sizeof(*afe_priv->clk),
> + GFP_KERNEL);
> + if (!afe_priv->clk)
> + return -ENOMEM;
> +
> + for (i = 0; i < MT8196_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->vlp_ck = syscon_regmap_lookup_by_phandle(afe->dev->of_node,
> + "vlpcksys");
> + if (IS_ERR(afe_priv->vlp_ck)) {
> + dev_err(afe->dev, "Cannot find vlpcksys\n");
> + return PTR_ERR(afe_priv->vlp_ck);
> + }
> +
> + mt8196_afe_apll_init(afe);
> +
> + ret = mt8196_afe_disable_apll(afe);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.h b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
> new file mode 100644
> index 000000000000..60f5e5a157d5
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
> @@ -0,0 +1,142 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * mt8196-afe-clk.h -- Mediatek 8196 afe clock ctrl definition
mt8196-afe-clk.h - MediaTek MT8195 AFE Clock Control definitions
> + *
> + * Copyright (c) 2024 MediaTek Inc.
> + * Author: Darren Ye <darren.ye@mediatek.com>
> + */
> +
..snip..
> diff --git a/sound/soc/mediatek/mt8196/mt8196-audsys-clk.c b/sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
> new file mode 100644
> index 000000000000..aa40f02698ac
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
> @@ -0,0 +1,252 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * mt8196-audsys-clk.c -- MediaTek 8196 audsys clock control
> + *
> + * Copyright (c) 2025 MediaTek Inc.
> + * Author: Darren Ye <darren.ye@mediatek.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include "mt8196-afe-common.h"
> +#include "mt8196-audsys-clk.h"
> +#include "mt8196-audsys-clkid.h"
> +#include "mt8196-reg.h"
> +
..snip..
> +};
> +
> +static void mt8196_audsys_clk_unregister(void *data)
> +{
> + struct mtk_base_afe *afe = data;
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + struct clk *clk;
> + struct clk_lookup *cl;
> + int i;
> +
> + if (!afe_priv)
> + return;
> +
> + for (i = 0; i < CLK_AFE_NR_CLK; i++) {
> + cl = afe_priv->lookup[i];
> + if (!cl)
> + continue;
> +
> + clk = cl->clk;
> + clk_unregister_gate(clk);
> +
> + clkdev_drop(cl);
> + }
> +}
> +
> +int mt8196_audsys_clk_register(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + struct clk *clk;
> + struct clk_lookup *cl;
> + int i;
> +
> + afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AFE_NR_CLK,
> + sizeof(*afe_priv->lookup),
> + GFP_KERNEL);
> +
> + if (!afe_priv->lookup)
> + return -ENOMEM;
> +
> + for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
> + const struct afe_gate *gate = &aud_clks[i];
> +
> + clk = clk_register_gate(afe->dev, gate->name, gate->parent_name,
> + gate->flags, afe->base_addr + gate->reg,
> + gate->bit, gate->cg_flags, NULL);
> +
> + if (IS_ERR(clk)) {
> + dev_err(afe->dev, "Failed to register clk %s: %ld\n",
> + gate->name, PTR_ERR(clk));
> + continue;
> + }
> +
All of the above, until...
> + /* add clk_lookup for devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */
> + cl = kzalloc(sizeof(*cl), GFP_KERNEL);
> + if (!cl)
> + return -ENOMEM;
> +
> + cl->clk = clk;
> + cl->con_id = gate->name;
> + cl->dev_id = dev_name(afe->dev);
> + cl->clk_hw = NULL;
> + clkdev_add(cl);
...here, can be simplified with a single call to
clk_register_clkdev(clk, gate->name, dev_name(afe->dev))
or alternatively, you could simplify it even more:
static void mt8196_audsys_clk_unregister(void *data)
{
/* nothing to do here, remove this function */
}
int mt8196_audsys_clk_register(struct mtk_base_afe *afe)
{
struct mt8196_afe_private *afe_priv = afe->platform_priv;
int i, ret;
for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
const struct afe_gate *gate = &aud_clks[i];
struct clk_hw *hw;
hw = devm_clk_hw_register_gate(afe->dev, gate->name, gate->parent_name,
gate->flags, afe->base_addr + gate->reg,
gate->bit, gate->cg_flags, NULL);
if (IS_ERR(clk)) {
dev_err(afe->dev, "Failed to register clk %s: %ld\n",
gate->name, PTR_ERR(clk));
continue;
}
ret = devm_clk_hw_register_clkdev(afe->dev, hw, gate->name, dev_name(afe->dev));
if (ret)
return ret;
}
return 0;
}
> +
> + afe_priv->lookup[i] = cl;
> + }
> +
> + return devm_add_action_or_reset(afe->dev, mt8196_audsys_clk_unregister, afe);
> +}
Cheers,
Angelo
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 03/10] ASoC: mediatek: mt8196: support audio clock control
2025-05-15 8:30 ` AngeloGioacchino Del Regno
@ 2025-05-15 8:50 ` Chen-Yu Tsai
2025-05-15 8:54 ` Mark Brown
2025-05-15 9:31 ` Darren Ye (叶飞)
0 siblings, 2 replies; 23+ messages in thread
From: Chen-Yu Tsai @ 2025-05-15 8:50 UTC (permalink / raw)
To: AngeloGioacchino Del Regno, Darren.Ye
Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski, linux-sound, devicetree,
linux-kernel, linux-arm-kernel, linux-mediatek, linux-gpio
On Thu, May 15, 2025 at 4:40 PM AngeloGioacchino Del Regno
<angelogioacchino.delregno@collabora.com> wrote:
>
> Il 14/05/25 10:11, Darren.Ye ha scritto:
> > From: Darren Ye <darren.ye@mediatek.com>
> >
> > Add audio clock wrapper and audio tuner control.
> >
> > Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> > ---
> > sound/soc/mediatek/mt8196/mt8196-afe-clk.c | 723 ++++++++++++++++++
> > sound/soc/mediatek/mt8196/mt8196-afe-clk.h | 142 ++++
> > sound/soc/mediatek/mt8196/mt8196-audsys-clk.c | 252 ++++++
> > sound/soc/mediatek/mt8196/mt8196-audsys-clk.h | 14 +
> > .../soc/mediatek/mt8196/mt8196-audsys-clkid.h | 78 ++
> > 5 files changed, 1209 insertions(+)
> > create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> > create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.h
> > create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
> > create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clk.h
> > create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clkid.h
> >
> > diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.c b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> > new file mode 100644
> > index 000000000000..83b5ee9d30ef
> > --- /dev/null
> > +++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> > @@ -0,0 +1,723 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * mt8196-afe-clk.c -- Mediatek 8196 afe clock ctrl
>
> mt8196-afe-clk.c - MediaTek MT8196 AFE Clock Control
>
> > + *
> > + * Copyright (c) 2024 MediaTek Inc.
> > + * Author: Darren Ye <darren.ye@mediatek.com>
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/regmap.h>
> > +#include <linux/mfd/syscon.h>
> > +#include "mt8196-afe-common.h"
> > +#include "mt8196-audsys-clk.h"
> > +#include "mt8196-afe-clk.h"
> > +
>
> ..snip..
>
> > +
> > +static int mt8196_afe_disable_apll(struct mtk_base_afe *afe)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > + int ret = 0;
> > +
> > + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> > + if (ret)
> > + return ret;
> > +
> > + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
> > + if (ret)
> > + goto clk_ck_mux_aud1_err;
> > +
> > + ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1],
> > + afe_priv->clk[MT8196_CLK_TOP_CLK26M]);
> > + if (ret)
> > + goto clk_ck_mux_aud1_parent_err;
> > +
> > + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
> > + if (ret)
> > + goto clk_ck_mux_aud2_err;
> > +
> > + ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2],
> > + afe_priv->clk[MT8196_CLK_TOP_CLK26M]);
> > + if (ret)
> > + goto clk_ck_mux_aud2_parent_err;
> > +
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
> > + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
> > + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> > + return 0;
> > +
> > +clk_ck_mux_aud2_parent_err:
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
> > +clk_ck_mux_aud2_err:
> > + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1],
> > + afe_priv->clk[MT8196_CLK_TOP_APLL1_CK]);
> > +clk_ck_mux_aud1_parent_err:
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
> > +clk_ck_mux_aud1_err:
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> > +
> > + return ret;
> > +}
> > +
> > +static void mt8196_afe_apll_init(struct mtk_base_afe *afe)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > +
>
> if (!afe_priv->vlp_clk) {
> dev_warn...
> return;
> }
>
> regmap_write......
>
> > + if (afe_priv->vlp_ck) {
> > + regmap_write(afe_priv->vlp_ck, VLP_APLL1_TUNER_CON0, VLP_APLL1_TUNER_CON0_VALUE);
> > + regmap_write(afe_priv->vlp_ck, VLP_APLL2_TUNER_CON0, VLP_APLL2_TUNER_CON0_VALUE);
> > + } else {
> > + dev_warn(afe->dev, "vlp_ck regmap is null ptr\n");
> > + }
> > +}
> > +
> > +int mt8196_apll1_enable(struct mtk_base_afe *afe)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > + int ret;
> > +
> > + /* setting for APLL */
> > + apll1_mux_setting(afe, true);
> > +
> > + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL1]);
> > + if (ret)
> > + goto ERR_CLK_APLL1;
> > +
> > + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER1]);
> > + if (ret)
> > + goto ERR_CLK_APLL1_TUNER;
> > +
> > + /* 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 */
> > + mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_APLL1_EN_ON);
> > +
> > + return 0;
> > +
> > +ERR_CLK_APLL1_TUNER:
>
> lower case for labels please
>
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER1]);
> > +ERR_CLK_APLL1:
>
> ^^^^^^^^^
>
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL1]);
> > + return ret;
> > +}
> > +
> > +void mt8196_apll1_disable(struct mtk_base_afe *afe)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > +
> > + /* audio apll1 off */
> > + mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_APLL1_EN_ON);
> > +
> > + /* apll1 freq tuner disable */
> > + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
> > + FREQ_TUNER_EN_MASK_SFT,
> > + 0x0);
> > +
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER1]);
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL1]);
> > + apll1_mux_setting(afe, false);
> > +}
> > +
> > +int mt8196_apll2_enable(struct mtk_base_afe *afe)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > + int ret;
> > +
> > + /* setting for APLL */
> > + apll2_mux_setting(afe, true);
> > +
> > + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL2]);
> > + if (ret)
> > + goto ERR_CLK_APLL2;
> > +
> > + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER2]);
> > + if (ret)
> > + goto ERR_CLK_APLL2_TUNER;
> > +
> > + /* 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 */
> > + mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_APLL2_EN_ON);
> > + return 0;
> > +
> > +ERR_CLK_APLL2_TUNER:
>
> lower case for labels please
>
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER2]);
> > +ERR_CLK_APLL2:
>
> ditto
>
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL2]);
> > + return ret;
> > +
> > + return 0;
> > +}
> > +
> > +void mt8196_apll2_disable(struct mtk_base_afe *afe)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > +
> > + /* audio apll2 off */
> > + mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_APLL2_EN_ON);
> > +
> > + /* apll2 freq tuner disable */
> > + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
> > + FREQ_TUNER_EN_MASK_SFT,
> > + 0x0);
> > +
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER2]);
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL2]);
> > + apll2_mux_setting(afe, false);
> > +}
> > +
> > +int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > + int clk_id = 0;
> > +
> > + if (apll < MT8196_APLL1 || apll > MT8196_APLL2) {
> > + dev_warn(afe->dev, "invalid clk id\n");
>
> ("invalid clk id %d\n", clk_id)
>
> ...otherwise it makes no sense, as it gives no useful information.
> Alternatively, just drop the print.
>
> > + return 0;
> > + }
> > +
> > + if (apll == MT8196_APLL1)
> > + clk_id = MT8196_CLK_TOP_APLL1_CK;
> > + else
> > + clk_id = MT8196_CLK_TOP_APLL2_CK;
> > +
> > + return clk_get_rate(afe_priv->clk[clk_id]);
> > +}
> > +
> > +int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
> > +{
> > + return ((rate % 8000) == 0) ? MT8196_APLL2 : MT8196_APLL1;
>
> return (rate % 8000) ? MT8196_APLL1 : MT8196_APLL2;
>
> > +}
> > +
> > +int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
> > +{
> > + if (strcmp(name, APLL1_W_NAME) == 0)
> > + return MT8196_APLL1;
> > + else
> > + return MT8196_APLL2;
>
> if (strcmp ....)
> return MT8196_APLL1;
>
> return MT8196_APLL2;
>
> > +}
> > +
> > +/* mck */
> > +struct mt8196_mck_div {
> > + int m_sel_id;
> > + int div_clk_id;
> > +};
> > +
> > +static const struct mt8196_mck_div mck_div[MT8196_MCK_NUM] = {
> > + [MT8196_I2SIN0_MCK] = {
> > + .m_sel_id = MT8196_CLK_TOP_I2SIN0_M_SEL,
> > + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_I2SIN0,
> > + },
> > + [MT8196_I2SIN1_MCK] = {
> > + .m_sel_id = MT8196_CLK_TOP_I2SIN1_M_SEL,
> > + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_I2SIN1,
> > + },
> > + [MT8196_FMI2S_MCK] = {
> > + .m_sel_id = MT8196_CLK_TOP_FMI2S_M_SEL,
> > + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_FMI2S,
> > + },
> > + [MT8196_TDMOUT_MCK] = {
> > + .m_sel_id = MT8196_CLK_TOP_TDMOUT_M_SEL,
> > + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_M,
> > + },
> > + [MT8196_TDMOUT_BCK] = {
> > + .m_sel_id = -1,
> > + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B,
> > + },
> > +};
> > +
> > +int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > + int apll = mt8196_get_apll_by_rate(afe, rate);
> > + int apll_clk_id = apll == MT8196_APLL1 ?
> > + MT8196_CLK_TOP_MUX_AUD_1 : MT8196_CLK_TOP_MUX_AUD_2;
> > + int m_sel_id = 0;
> > + int div_clk_id = 0;
> > + int ret = 0;
>
> this gives double initialzation of all m_sel_id, div_clk_id and ret as you are
> initializing the first two immediately after the mck_id check, and ret later;
> just go for
>
> int m_sel_id, div_clk_id, ret;
>
> or just
>
> int ret;
>
> > +
> > + dev_dbg(afe->dev, "mck_id: %d, rate: %d\n", mck_id, rate);
> > +
> > + if (mck_id >= MT8196_MCK_NUM || mck_id < 0)
> > + return -EINVAL;
> > +
> > + m_sel_id = mck_div[mck_id].m_sel_id;
> > + div_clk_id = mck_div[mck_id].div_clk_id;
> > +
> > + /* select apll */
> > + if (m_sel_id >= 0) {
>
> ...because then I don't understand why don't you just use mck_div[mck_id] directly.
>
> if (mck_div[mck_id].m_sel_id >= 0) {
>
> > + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[m_sel_id]);
> > + if (ret)
> > + return ret;
> > +
> > + ret = mt8196_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) {
>
> if (mck_div[mck_id].div_clk_id == MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B) {
> rate ...
> } else if (mck_div[mck_id].div_clk_id < 0) {
> ....
> }
>
>
> > + dev_err(afe->dev, "invalid div_clk_id %d\n", div_clk_id);
> > + return -EINVAL;
> > + }
> > + if (div_clk_id == MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B)
> > + rate = rate * 16;
> > +
> > + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[div_clk_id]);
> > + if (ret)
> > + return ret;
> > +
> > + ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[div_clk_id], rate);
> > + if (ret)
> > + return ret;
> > +
> > + return 0;
> > +}
> > +
> > +int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > + int m_sel_id = 0;
> > + int div_clk_id = 0;
>
> Double init again....
>
> > +
> > + 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;
> > + }
> > +
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[div_clk_id]);
> > +
> > + if (m_sel_id >= 0)
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[m_sel_id]);
> > +
> > + return 0;
> > +}
> > +
> > +int mt8196_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > +
> > + /* bus clock for AFE external access, like DRAM */
> > + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
> > +
> > + /* bus clock for AFE internal access, like AFE SRAM */
> > + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
> > + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS],
> > + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> > + /* enable audio vlp clock source */
> > + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> > + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
> > + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> > +
> > + /* AFE hw clock */
> > + /* IPM2.0: USE HOPPING & 26M */
> > + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_HOPPING]);
> > + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_F26M]);
> > + return 0;
> > +}
> > +
> > +int mt8196_afe_disable_reg_rw_clk(struct mtk_base_afe *afe)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > +
> > + /* IPM2.0: Use HOPPING & 26M */
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_HOPPING]);
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_F26M]);
> > + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
> > + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> > +
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> > + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS],
> > + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
> > + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
> > + return 0;
> > +}
> > +
> > +int mt8196_afe_enable_main_clock(struct mtk_base_afe *afe)
> > +{
>
> Just directly call
>
> mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_26M_EN_ON);
>
> ...and drop mt8196_afe_enable_afe_on()
>
> > + mt8196_afe_enable_afe_on(afe);
> > + return 0;
> > +}
> > +
> > +int mt8196_afe_disable_main_clock(struct mtk_base_afe *afe)
> > +{
> > + mt8196_afe_disable_afe_on(afe);
>
> mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_26M_EN_ON);
>
>
> > + return 0;
> > +}
> > +
> > +int mt8196_init_clock(struct mtk_base_afe *afe)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > + int ret = 0;
> > + int i = 0;
> > +
> > + ret = mt8196_audsys_clk_register(afe);
> > + if (ret) {
> > + dev_err(afe->dev, "register audsys clk fail %d\n", ret);
> > + return ret;
> > + }
> > +
> > + afe_priv->clk = devm_kcalloc(afe->dev, MT8196_CLK_NUM, sizeof(*afe_priv->clk),
> > + GFP_KERNEL);
> > + if (!afe_priv->clk)
> > + return -ENOMEM;
> > +
> > + for (i = 0; i < MT8196_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->vlp_ck = syscon_regmap_lookup_by_phandle(afe->dev->of_node,
> > + "vlpcksys");
> > + if (IS_ERR(afe_priv->vlp_ck)) {
> > + dev_err(afe->dev, "Cannot find vlpcksys\n");
> > + return PTR_ERR(afe_priv->vlp_ck);
> > + }
> > +
> > + mt8196_afe_apll_init(afe);
> > +
> > + ret = mt8196_afe_disable_apll(afe);
> > + if (ret)
> > + return ret;
> > +
> > + return 0;
> > +}
> > +
> > diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.h b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
> > new file mode 100644
> > index 000000000000..60f5e5a157d5
> > --- /dev/null
> > +++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
> > @@ -0,0 +1,142 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * mt8196-afe-clk.h -- Mediatek 8196 afe clock ctrl definition
>
> mt8196-afe-clk.h - MediaTek MT8195 AFE Clock Control definitions
>
> > + *
> > + * Copyright (c) 2024 MediaTek Inc.
> > + * Author: Darren Ye <darren.ye@mediatek.com>
> > + */
> > +
>
> ..snip..
>
> > diff --git a/sound/soc/mediatek/mt8196/mt8196-audsys-clk.c b/sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
> > new file mode 100644
> > index 000000000000..aa40f02698ac
> > --- /dev/null
> > +++ b/sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
> > @@ -0,0 +1,252 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * mt8196-audsys-clk.c -- MediaTek 8196 audsys clock control
> > + *
> > + * Copyright (c) 2025 MediaTek Inc.
> > + * Author: Darren Ye <darren.ye@mediatek.com>
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/clk-provider.h>
> > +#include <linux/clkdev.h>
> > +#include "mt8196-afe-common.h"
> > +#include "mt8196-audsys-clk.h"
> > +#include "mt8196-audsys-clkid.h"
> > +#include "mt8196-reg.h"
> > +
> ..snip..
>
>
> > +};
> > +
> > +static void mt8196_audsys_clk_unregister(void *data)
> > +{
> > + struct mtk_base_afe *afe = data;
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > + struct clk *clk;
> > + struct clk_lookup *cl;
> > + int i;
> > +
> > + if (!afe_priv)
> > + return;
> > +
> > + for (i = 0; i < CLK_AFE_NR_CLK; i++) {
> > + cl = afe_priv->lookup[i];
> > + if (!cl)
> > + continue;
> > +
> > + clk = cl->clk;
> > + clk_unregister_gate(clk);
> > +
> > + clkdev_drop(cl);
> > + }
> > +}
> > +
> > +int mt8196_audsys_clk_register(struct mtk_base_afe *afe)
> > +{
> > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > + struct clk *clk;
> > + struct clk_lookup *cl;
> > + int i;
> > +
> > + afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AFE_NR_CLK,
> > + sizeof(*afe_priv->lookup),
> > + GFP_KERNEL);
> > +
> > + if (!afe_priv->lookup)
> > + return -ENOMEM;
> > +
> > + for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
> > + const struct afe_gate *gate = &aud_clks[i];
> > +
> > + clk = clk_register_gate(afe->dev, gate->name, gate->parent_name,
> > + gate->flags, afe->base_addr + gate->reg,
> > + gate->bit, gate->cg_flags, NULL);
> > +
> > + if (IS_ERR(clk)) {
> > + dev_err(afe->dev, "Failed to register clk %s: %ld\n",
> > + gate->name, PTR_ERR(clk));
> > + continue;
> > + }
> > +
>
> All of the above, until...
>
> > + /* add clk_lookup for devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */
> > + cl = kzalloc(sizeof(*cl), GFP_KERNEL);
> > + if (!cl)
> > + return -ENOMEM;
> > +
> > + cl->clk = clk;
> > + cl->con_id = gate->name;
> > + cl->dev_id = dev_name(afe->dev);
> > + cl->clk_hw = NULL;
> > + clkdev_add(cl);
>
>
> ...here, can be simplified with a single call to
>
> clk_register_clkdev(clk, gate->name, dev_name(afe->dev))
>
> or alternatively, you could simplify it even more:
>
>
> static void mt8196_audsys_clk_unregister(void *data)
> {
> /* nothing to do here, remove this function */
> }
>
> int mt8196_audsys_clk_register(struct mtk_base_afe *afe)
> {
> struct mt8196_afe_private *afe_priv = afe->platform_priv;
> int i, ret;
>
> for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
> const struct afe_gate *gate = &aud_clks[i];
> struct clk_hw *hw;
>
> hw = devm_clk_hw_register_gate(afe->dev, gate->name, gate->parent_name,
> gate->flags, afe->base_addr + gate->reg,
> gate->bit, gate->cg_flags, NULL);
> if (IS_ERR(clk)) {
> dev_err(afe->dev, "Failed to register clk %s: %ld\n",
> gate->name, PTR_ERR(clk));
> continue;
> }
>
> ret = devm_clk_hw_register_clkdev(afe->dev, hw, gate->name, dev_name(afe->dev));
> if (ret)
> return ret;
> }
>
> return 0;
> }
There is no need to involve the clk subsystem. These are simply supply
gates, be them for power or clks, one per bit. Simply model them as ASoC
supply widgets, add appropriate routes for each so that the dependencies
are correct, and ASoC will deal with them for you. No code is needed,
just descriptions.
_That_ is why I asked for he audio clocks to be integrated into the
AFE driver.
ChenYu
> > +
> > + afe_priv->lookup[i] = cl;
> > + }
> > +
> > + return devm_add_action_or_reset(afe->dev, mt8196_audsys_clk_unregister, afe);
> > +}
>
> Cheers,
> Angelo
>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 03/10] ASoC: mediatek: mt8196: support audio clock control
2025-05-15 8:50 ` Chen-Yu Tsai
@ 2025-05-15 8:54 ` Mark Brown
2025-05-15 9:31 ` Darren Ye (叶飞)
1 sibling, 0 replies; 23+ messages in thread
From: Mark Brown @ 2025-05-15 8:54 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: AngeloGioacchino Del Regno, Darren.Ye, Liam Girdwood, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski,
linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
[-- Attachment #1: Type: text/plain, Size: 566 bytes --]
On Thu, May 15, 2025 at 04:50:33PM +0800, Chen-Yu Tsai wrote:
> On Thu, May 15, 2025 at 4:40 PM AngeloGioacchino Del Regno
> <angelogioacchino.delregno@collabora.com> wrote:
> >
> > Il 14/05/25 10:11, Darren.Ye ha scritto:
> > > From: Darren Ye <darren.ye@mediatek.com>
> > >
> > > Add audio clock wrapper and audio tuner control.
Please delete unneeded context from mails when replying. Doing this
makes it much easier to find your reply in the message, helping ensure
it won't be missed by people scrolling through the irrelevant quoted
material.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 03/10] ASoC: mediatek: mt8196: support audio clock control
2025-05-15 8:50 ` Chen-Yu Tsai
2025-05-15 8:54 ` Mark Brown
@ 2025-05-15 9:31 ` Darren Ye (叶飞)
1 sibling, 0 replies; 23+ messages in thread
From: Darren Ye (叶飞) @ 2025-05-15 9:31 UTC (permalink / raw)
To: wenst@chromium.org, AngeloGioacchino Del Regno
Cc: linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
devicetree@vger.kernel.org, linus.walleij@linaro.org,
linux-sound@vger.kernel.org, linux-gpio@vger.kernel.org,
broonie@kernel.org, brgl@bgdev.pl, conor+dt@kernel.org,
tiwai@suse.com, robh@kernel.org, lgirdwood@gmail.com,
linux-arm-kernel@lists.infradead.org, matthias.bgg@gmail.com,
krzk+dt@kernel.org, perex@perex.cz
On Thu, 2025-05-15 at 16:50 +0800, Chen-Yu Tsai wrote:
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>
>
> On Thu, May 15, 2025 at 4:40 PM AngeloGioacchino Del Regno
> <angelogioacchino.delregno@collabora.com> wrote:
> >
> > Il 14/05/25 10:11, Darren.Ye ha scritto:
> > > From: Darren Ye <darren.ye@mediatek.com>
> > >
> > > Add audio clock wrapper and audio tuner control.
> > >
> > > Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> > > ---
> > > sound/soc/mediatek/mt8196/mt8196-afe-clk.c | 723
> > > ++++++++++++++++++
> > > sound/soc/mediatek/mt8196/mt8196-afe-clk.h | 142 ++++
> > > sound/soc/mediatek/mt8196/mt8196-audsys-clk.c | 252 ++++++
> > > sound/soc/mediatek/mt8196/mt8196-audsys-clk.h | 14 +
> > > .../soc/mediatek/mt8196/mt8196-audsys-clkid.h | 78 ++
> > > 5 files changed, 1209 insertions(+)
> > > create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> > > create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.h
> > > create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-
> > > clk.c
> > > create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-
> > > clk.h
> > > create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-
> > > clkid.h
> > >
> > > diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> > > b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> > > new file mode 100644
> > > index 000000000000..83b5ee9d30ef
> > > --- /dev/null
> > > +++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> > > @@ -0,0 +1,723 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * mt8196-afe-clk.c -- Mediatek 8196 afe clock ctrl
> >
> > mt8196-afe-clk.c - MediaTek MT8196 AFE Clock Control
> >
> > > + *
> > > + * Copyright (c) 2024 MediaTek Inc.
> > > + * Author: Darren Ye <darren.ye@mediatek.com>
> > > + */
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/regmap.h>
> > > +#include <linux/mfd/syscon.h>
> > > +#include "mt8196-afe-common.h"
> > > +#include "mt8196-audsys-clk.h"
> > > +#include "mt8196-afe-clk.h"
> > > +
> >
> > > +int mt8196_audsys_clk_register(struct mtk_base_afe *afe)
> > > +{
> > > + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > > + struct clk *clk;
> > > + struct clk_lookup *cl;
> > > + int i;
> > > +
> > > + afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AFE_NR_CLK,
> > > + sizeof(*afe_priv->lookup),
> > > + GFP_KERNEL);
> > > +
> > > + if (!afe_priv->lookup)
> > > + return -ENOMEM;
> > > +
> > > + for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
> > > + const struct afe_gate *gate = &aud_clks[i];
> > > +
> > > + clk = clk_register_gate(afe->dev, gate->name, gate-
> > > >parent_name,
> > > + gate->flags, afe->base_addr
> > > + gate->reg,
> > > + gate->bit, gate->cg_flags,
> > > NULL);
> > > +
> > > + if (IS_ERR(clk)) {
> > > + dev_err(afe->dev, "Failed to register clk
> > > %s: %ld\n",
> > > + gate->name, PTR_ERR(clk));
> > > + continue;
> > > + }
> > > +
> >
> > All of the above, until...
> >
> > > + /* add clk_lookup for
> > > devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */
> > > + cl = kzalloc(sizeof(*cl), GFP_KERNEL);
> > > + if (!cl)
> > > + return -ENOMEM;
> > > +
> > > + cl->clk = clk;
> > > + cl->con_id = gate->name;
> > > + cl->dev_id = dev_name(afe->dev);
> > > + cl->clk_hw = NULL;
> > > + clkdev_add(cl);
> >
> >
> > ...here, can be simplified with a single call to
> >
> > clk_register_clkdev(clk, gate->name, dev_name(afe->dev))
> >
> > or alternatively, you could simplify it even more:
> >
> >
> > static void mt8196_audsys_clk_unregister(void *data)
> > {
> > /* nothing to do here, remove this function */
> > }
> >
> > int mt8196_audsys_clk_register(struct mtk_base_afe *afe)
> > {
> > struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > int i, ret;
> >
> > for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
> > const struct afe_gate *gate = &aud_clks[i];
> > struct clk_hw *hw;
> >
> > hw = devm_clk_hw_register_gate(afe->dev, gate-
> > >name, gate->parent_name,
> > gate->flags, afe-
> > >base_addr + gate->reg,
> > gate->bit, gate-
> > >cg_flags, NULL);
> > if (IS_ERR(clk)) {
> > dev_err(afe->dev, "Failed to register clk
> > %s: %ld\n",
> > gate->name, PTR_ERR(clk));
> > continue;
> > }
> >
> > ret = devm_clk_hw_register_clkdev(afe->dev, hw,
> > gate->name, dev_name(afe->dev));
> > if (ret)
> > return ret;
> > }
> >
> > return 0;
> > }
>
> There is no need to involve the clk subsystem. These are simply
> supply
> gates, be them for power or clks, one per bit. Simply model them as
> ASoC
> supply widgets, add appropriate routes for each so that the
> dependencies
> are correct, and ASoC will deal with them for you. No code is needed,
> just descriptions.
>
> _That_ is why I asked for he audio clocks to be integrated into the
> AFE driver.
>
> ChenYu
>
OK, I misunderstood. The next version will use widgets and route to
control the afe clk gate.
Best regards,
Darren
> > > +
> > > + afe_priv->lookup[i] = cl;
> > > + }
> > > +
> > > + return devm_add_action_or_reset(afe->dev,
> > > mt8196_audsys_clk_unregister, afe);
> > > +}
> >
> > Cheers,
> > Angelo
> >
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE document
2025-05-14 10:54 ` Krzysztof Kozlowski
2025-05-15 3:57 ` Darren Ye (叶飞)
@ 2025-06-11 9:32 ` Krzysztof Kozlowski
2025-06-11 13:05 ` Darren Ye (叶飞)
1 sibling, 1 reply; 23+ messages in thread
From: Krzysztof Kozlowski @ 2025-06-11 9:32 UTC (permalink / raw)
To: Darren.Ye, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
Jaroslav Kysela, Takashi Iwai
Cc: Rob Herring, linux-sound, Linus Walleij, devicetree, Mark Brown,
AngeloGioacchino Del Regno, linux-kernel, Bartosz Golaszewski,
linux-arm-kernel, linux-mediatek, linux-gpio, Liam Girdwood
On 14/05/2025 12:54, Krzysztof Kozlowski wrote:
> On 14/05/2025 10:11, Darren.Ye wrote:
>> From: Darren Ye <darren.ye@mediatek.com>
>>
>> Add mt8196 audio AFE document.
>
> A nit, subject: drop second/last, redundant "document".
> See also:
> https://elixir.bootlin.com/linux/v6.7-rc8/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
Since you asked what did you miss from previous review (and I replied
that EVERYTHING) then maybe this will help:
How did you implement this?
>
>>
>> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
>
>
> ...
>
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - interrupts
>> + - mediatek,vlpcksys
>> + - power-domains
>> + - memory-region
>> + - clocks
>> + - clock-names
>
>
> Keep the same order as in properties:.
How did you implement this?
>
>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
How did you implement this?
>
> <form letter>
> This is an automated instruction, just in case, because many review tags
> are being ignored. If you know the process, you can skip it (please do
> not feel offended by me posting it here - no bad intentions intended).
> If you do not know the process, here is a short explanation:
>
> Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
> of patchset, under or above your Signed-off-by tag, unless patch changed
> significantly (e.g. new properties added to the DT bindings). Tag is
> "received", when provided in a message replied to you on the mailing
> list. Tools like b4 can help here. However, there's no need to repost
> patches *only* to add the tags. The upstream maintainer will do that for
> tags received on the version they apply.
>
> Full context and explanation:
> https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
How did you implement this?
Does such questions help you to find what was missing?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v3 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE document
2025-06-11 9:32 ` Krzysztof Kozlowski
@ 2025-06-11 13:05 ` Darren Ye (叶飞)
0 siblings, 0 replies; 23+ messages in thread
From: Darren Ye (叶飞) @ 2025-06-11 13:05 UTC (permalink / raw)
To: tiwai@suse.com, matthias.bgg@gmail.com, krzk+dt@kernel.org,
conor+dt@kernel.org, krzk@kernel.org, perex@perex.cz
Cc: linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
devicetree@vger.kernel.org, linux-sound@vger.kernel.org,
linus.walleij@linaro.org, linux-gpio@vger.kernel.org,
broonie@kernel.org, brgl@bgdev.pl, robh@kernel.org,
lgirdwood@gmail.com, linux-arm-kernel@lists.infradead.org,
AngeloGioacchino Del Regno
On Wed, 2025-06-11 at 11:32 +0200, Krzysztof Kozlowski wrote:
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>
>
> On 14/05/2025 12:54, Krzysztof Kozlowski wrote:
> > On 14/05/2025 10:11, Darren.Ye wrote:
> > > From: Darren Ye <darren.ye@mediatek.com>
> > >
> > > Add mt8196 audio AFE document.
> >
> > A nit, subject: drop second/last, redundant "document".
> > See also:
> >
https://urldefense.com/v3/__https://elixir.bootlin.com/linux/v6.7-rc8/source/Documentation/devicetree/bindings/submitting-patches.rst*L18__;Iw!!CTRNKA9wMg0ARbw!l3YASE64DTMTp8bOMry9UyBMf-IcYFTvXOlP2DXfpeUEFdQK79xGYEnsxnJuMihVX7_WhEe3q1evSg$
>
> Since you asked what did you miss from previous review (and I replied
> that EVERYTHING) then maybe this will help:
>
> How did you implement this?
>
My mistake, please forgive my carelessness. I will change it to
ASoC: dt-bindings: mediatek,mt8196-afe: Add suport for MT8196 audio AFE
controller
THis patch adds initial supoprt for the audio AFE(Audio Front End)
controller on the Mediatek MT8196 platform.
> >
> > >
> > > Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> >
> >
> > ...
> >
> > > +
> > > +required:
> > > + - compatible
> > > + - reg
> > > + - interrupts
> > > + - mediatek,vlpcksys
> > > + - power-domains
> > > + - memory-region
> > > + - clocks
> > > + - clock-names
> >
> >
> > Keep the same order as in properties:.
>
> How did you implement this?
>
I have already made the change here. The "required" fields have been
sorted according to the order of the properties.
>
> >
> >
> > Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>
> How did you implement this?
Sorry, I got it now. I will add it to the commit.
>
>
> >
> > <form letter>
> > This is an automated instruction, just in case, because many review
> > tags
> > are being ignored. If you know the process, you can skip it (please
> > do
> > not feel offended by me posting it here - no bad intentions
> > intended).
> > If you do not know the process, here is a short explanation:
> >
> > Please add Acked-by/Reviewed-by/Tested-by tags when posting new
> > versions
> > of patchset, under or above your Signed-off-by tag, unless patch
> > changed
> > significantly (e.g. new properties added to the DT bindings). Tag
> > is
> > "received", when provided in a message replied to you on the
> > mailing
> > list. Tools like b4 can help here. However, there's no need to
> > repost
> > patches *only* to add the tags. The upstream maintainer will do
> > that for
> > tags received on the version they apply.
> >
> > Full context and explanation:
> >
https://urldefense.com/v3/__https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst*L577__;Iw!!CTRNKA9wMg0ARbw!l3YASE64DTMTp8bOMry9UyBMf-IcYFTvXOlP2DXfpeUEFdQK79xGYEnsxnJuMihVX7_WhEcicLV6xg$
>
> How did you implement this?
Got it.
>
> Does such questions help you to find what was missing?
>
> Best regards,
> Krzysztof
I'm very sorry, this is my first time upstreaming. Thank you for your
patient guidance.
Best Regards,
Darren
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2025-06-11 16:17 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-14 8:11 [PATCH v3 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
2025-05-14 8:11 ` [PATCH v3 01/10] ASoC: mediatek: common: modify mtk afe platform driver for mt8196 Darren.Ye
2025-05-14 8:11 ` [PATCH v3 03/10] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
2025-05-15 8:30 ` AngeloGioacchino Del Regno
2025-05-15 8:50 ` Chen-Yu Tsai
2025-05-15 8:54 ` Mark Brown
2025-05-15 9:31 ` Darren Ye (叶飞)
2025-05-14 8:11 ` [PATCH v3 04/10] ASoC: mediatek: mt8196: support ADDA in platform driver Darren.Ye
2025-05-14 8:17 ` Mark Brown
2025-05-14 8:58 ` Darren Ye (叶飞)
2025-05-14 8:11 ` [PATCH v3 06/10] ASoC: mediatek: mt8196: support TDM " Darren.Ye
2025-05-14 8:11 ` [PATCH v3 07/10] ASoC: mediatek: mt8196: add " Darren.Ye
2025-05-15 4:41 ` kernel test robot
2025-05-14 8:11 ` [PATCH v3 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE document Darren.Ye
2025-05-14 10:54 ` Krzysztof Kozlowski
2025-05-15 3:57 ` Darren Ye (叶飞)
2025-06-11 9:32 ` Krzysztof Kozlowski
2025-06-11 13:05 ` Darren Ye (叶飞)
2025-05-14 8:11 ` [PATCH v3 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825 Darren.Ye
2025-05-15 7:27 ` kernel test robot
2025-05-14 8:11 ` [PATCH v3 10/10] ASoC: dt-bindings: mediatek,mt8196-nau8825: add mt8196-nau8825 document Darren.Ye
2025-05-14 10:51 ` Krzysztof Kozlowski
2025-05-15 3:50 ` Darren Ye (叶飞)
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).