* [PATCH v7 00/10] ASoC: mediatek: Add support for MT8196 SoC
@ 2025-08-22 12:52 Darren.Ye
2025-08-22 12:52 ` [PATCH v7 01/10] ASoC: mediatek: common: modify mtk afe platform driver for mt8196 Darren.Ye
` (8 more replies)
0 siblings, 9 replies; 11+ messages in thread
From: Darren.Ye @ 2025-08-22 12:52 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 v6:
- optimize mtk_afe_pcm_pointer interface and improved logic checks.
- update mt8196_afe_private structure by removing unused member variables.
- only reference clocks directly supplied to afe and set required frequencies directly.
- update adda driver according to reviewer suggestions.
- update i2s driver according to reviewer suggestions.
- update tdm driver according to reviewer suggestions.
- optimize platform driver and update widget rotues.
- move the sof route from platform driver to the machine driver, and moved pinctrl to platform driver.
- update the afe yaml file to remove unnecessary clock references.
Changes since v5:
- restore the commit message for mediatek,mt8196-afe.yaml and only remove the string document.
- add reviewed owner for mediatek,mt8196-nau8825.yaml.
- use SND_JACK_AVOUT as jack status.
- use GENMASK_ULL to support 64-bit address masks.
- modify the afe platform and i2s dai driver code based on reviewer's suggestions.
Changes since v4:
- modify the mediatek,mt8196-afe.yaml commit message and add reviewed owner.
- modify the mediatek,mt8196-nau8825.yaml commit message.
- modify the audio common code based on reviewer's suggestions.
- add reviewed and tested owners in the audio common code submission message.
- fix cm update cnt calculation issue.
Changes since v3:
- the AFE TOP CG index is added to the common header.
- remove the audsys clk register and directly read and write to the regmap of afe cg clk.
- modify the clk logic according to the suggestions.
- remove the macro definition of MTKAIF4
- remove the tdm cg event and directly read and write the tdm cg reg form the widget.
- remove the i2s and cm cg event and directly read and write cg reg.
- afe hopping and f26m clk cg are placed in remap_register_patch and enable.
- the yaml file is modified according to the suggestions.
- replace SND_SOC_DAIFMT_CBS_CFS with SND_SOC_DAIFMT_CBC_CFC.
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
ASoC: mediatek: mt8196: add machine driver with nau8825
ASoC: dt-bindings: mediatek,mt8196-nau8825: Add audio sound card
.../bindings/sound/mediatek,mt8196-afe.yaml | 113 +
.../sound/mediatek,mt8196-nau8825.yaml | 100 +
sound/soc/mediatek/Kconfig | 30 +
sound/soc/mediatek/Makefile | 1 +
.../mediatek/common/mtk-afe-platform-driver.c | 56 +-
.../mediatek/common/mtk-afe-platform-driver.h | 2 +
sound/soc/mediatek/mt8196/Makefile | 14 +
sound/soc/mediatek/mt8196/mt8196-afe-clk.c | 580 +
sound/soc/mediatek/mt8196/mt8196-afe-clk.h | 64 +
sound/soc/mediatek/mt8196/mt8196-afe-common.h | 205 +
sound/soc/mediatek/mt8196/mt8196-afe-pcm.c | 2497 ++++
sound/soc/mediatek/mt8196/mt8196-dai-adda.c | 845 ++
sound/soc/mediatek/mt8196/mt8196-dai-i2s.c | 2613 ++++
sound/soc/mediatek/mt8196/mt8196-dai-tdm.c | 675 +
.../mediatek/mt8196/mt8196-interconnection.h | 121 +
sound/soc/mediatek/mt8196/mt8196-nau8825.c | 868 ++
sound/soc/mediatek/mt8196/mt8196-reg.h | 12068 ++++++++++++++++
17 files changed, 20834 insertions(+), 18 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-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] 11+ messages in thread
* [PATCH v7 01/10] ASoC: mediatek: common: modify mtk afe platform driver for mt8196
2025-08-22 12:52 [PATCH v7 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
@ 2025-08-22 12:52 ` Darren.Ye
2025-08-22 12:52 ` [PATCH v7 03/10] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
` (7 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Darren.Ye @ 2025-08-22 12:52 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, Louis-Alexis Eyraud
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>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
.../mediatek/common/mtk-afe-platform-driver.c | 56 +++++++++++++------
.../mediatek/common/mtk-afe-platform-driver.h | 2 +
2 files changed, 40 insertions(+), 18 deletions(-)
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
index 70fd05d5ff48..df7da3fd86fc 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
@@ -86,29 +86,49 @@ 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;
- goto POINTER_RETURN_FRAMES;
+ 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) {
+ dev_err(dev, "%s hw_ptr_lower32 err\n", __func__);
+ return 0;
}
- 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__);
+ return 0;
+ }
}
- pcm_ptr_bytes = hw_ptr - hw_base;
+ ret = regmap_read(regmap, memif_data->reg_ofs_base, &hw_base_lower32);
+ if (ret) {
+ dev_err(dev, "%s hw_base_lower32 err\n", __func__);
+ return 0;
+ }
+ 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__);
+ return 0;
+ }
+ }
+
+ hw_ptr = ((unsigned long long)hw_ptr_upper32 << 32) | hw_ptr_lower32;
+ hw_base = ((unsigned long long)hw_base_upper32 << 32) | hw_base_lower32;
+
+ if (!hw_ptr || !hw_base) {
+ dev_err(dev, "hw_ptr or hw_base = 0 err\n");
+ return 0;
+ }
-POINTER_RETURN_FRAMES:
- return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
+ pcm_ptr_bytes = MTK_ALIGN_16BYTES(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..71070b26f8f8 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_ALIGN_16BYTES(x) ((x) & GENMASK_ULL(39, 4))
+
struct mtk_base_afe;
struct snd_pcm;
struct snd_soc_component;
--
2.45.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v7 03/10] ASoC: mediatek: mt8196: support audio clock control
2025-08-22 12:52 [PATCH v7 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
2025-08-22 12:52 ` [PATCH v7 01/10] ASoC: mediatek: common: modify mtk afe platform driver for mt8196 Darren.Ye
@ 2025-08-22 12:52 ` Darren.Ye
2025-08-22 12:52 ` [PATCH v7 04/10] ASoC: mediatek: mt8196: support ADDA in platform driver Darren.Ye
` (6 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Darren.Ye @ 2025-08-22 12:52 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 | 580 +++++++++++++++++++++
sound/soc/mediatek/mt8196/mt8196-afe-clk.h | 64 +++
2 files changed, 644 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.h
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.c b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
new file mode 100644
index 000000000000..d7f48f62ddc6
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
@@ -0,0 +1,580 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8196-afe-clk.c -- Mediatek 8196 afe clock ctrl
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "mt8196-afe-clk.h"
+#include "mt8196-afe-common.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",
+ /* pll */
+ [MT8196_CLK_TOP_APLL1_CK] = "apll1",
+ [MT8196_CLK_TOP_APLL2_CK] = "apll2",
+ /* divider */
+ [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_ADSP_SEL] = "top_adsp",
+};
+
+int mt8196_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk)
+{
+ int ret;
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ dev_err(afe->dev, "failed to enable clk\n");
+ return ret;
+ }
+
+ 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_err(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_err(afe->dev, "failed to set clk rate\n");
+ 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;
+ case MT8196_CG_AUDIO_HOPPING_CK:
+ case MT8196_CG_AUDIO_F26M_CK:
+ case MT8196_CG_APLL1_CK:
+ case MT8196_CG_APLL2_CK:
+ case MT8196_PDN_APLL_TUNER2:
+ case MT8196_PDN_APLL_TUNER1:
+ return AUDIO_TOP_CON4;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_mask(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case 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;
+ case MT8196_CG_AUDIO_HOPPING_CK:
+ return CG_AUDIO_HOPPING_CK_MASK_SFT;
+ case MT8196_CG_AUDIO_F26M_CK:
+ return CG_AUDIO_F26M_CK_MASK_SFT;
+ case MT8196_CG_APLL1_CK:
+ return CG_APLL1_CK_MASK_SFT;
+ case MT8196_CG_APLL2_CK:
+ return CG_APLL2_CK_MASK_SFT;
+ case MT8196_PDN_APLL_TUNER2:
+ return PDN_APLL_TUNER2_MASK_SFT;
+ case MT8196_PDN_APLL_TUNER1:
+ return PDN_APLL_TUNER1_MASK_SFT;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_on_val(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case 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);
+ case MT8196_CG_AUDIO_HOPPING_CK:
+ case MT8196_CG_AUDIO_F26M_CK:
+ case MT8196_CG_APLL1_CK:
+ case MT8196_CG_APLL2_CK:
+ case MT8196_PDN_APLL_TUNER2:
+ case MT8196_PDN_APLL_TUNER1:
+ return 0;
+ 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;
+ case MT8196_CG_AUDIO_HOPPING_CK:
+ case MT8196_CG_AUDIO_F26M_CK:
+ case MT8196_CG_APLL1_CK:
+ case MT8196_CG_APLL2_CK:
+ case MT8196_PDN_APLL_TUNER2:
+ case MT8196_PDN_APLL_TUNER1:
+ return get_top_cg_mask(cg_type);
+ default:
+ return get_top_cg_mask(cg_type);
+ }
+}
+
+static int mt8196_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+ int ret;
+ unsigned int reg = get_top_cg_reg(cg_type);
+ unsigned int mask = get_top_cg_mask(cg_type);
+ unsigned int val = get_top_cg_on_val(cg_type);
+
+ if (!afe->regmap) {
+ dev_err(afe->dev, "afe regmap is null !!!\n");
+ return 0;
+ }
+
+ dev_dbg(afe->dev, "reg: 0x%x, mask: 0x%x, val: 0x%x\n", reg, mask, val);
+
+ ret = regmap_update_bits(afe->regmap, reg, mask, val);
+ if (ret)
+ dev_err(afe->dev, "regmap_update_bits failed: %d\n", ret);
+
+ return ret;
+}
+
+static int mt8196_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+ int ret;
+ unsigned int reg = get_top_cg_reg(cg_type);
+ unsigned int mask = get_top_cg_mask(cg_type);
+ unsigned int val = get_top_cg_off_val(cg_type);
+
+ if (!afe->regmap) {
+ dev_err(afe->dev, "afe regmap is null !!!\n");
+ return 0;
+ }
+
+ dev_dbg(afe->dev, "reg: 0x%x, mask: 0x%x, val: 0x%x\n", reg, mask, val);
+
+ ret = regmap_update_bits(afe->regmap, reg, mask, val);
+ if (ret)
+ dev_err(afe->dev, "regmap_update_bits failed: %d\n", ret);
+
+ return ret;
+}
+
+static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int apll_rate;
+ int ret;
+
+ dev_dbg(afe->dev, "enable: %d\n", enable);
+
+ if (enable) {
+ apll_rate = mt8196_get_apll_rate(afe, MT8196_APLL1);
+
+ /* 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_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1],
+ MT8196_AUD_ENG1_CLK);
+ 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_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
+ apll_rate);
+ if (ret)
+ return ret;
+ } else {
+ ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1],
+ MT8196_AFE_26M);
+ if (ret)
+ return ret;
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1]);
+
+ ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
+ MT8196_AFE_26M);
+ if (ret)
+ return ret;
+
+ 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 apll_rate;
+ int ret;
+
+ dev_dbg(afe->dev, "enable: %d\n", enable);
+
+ if (enable) {
+ apll_rate = mt8196_get_apll_rate(afe, MT8196_APLL2);
+
+ /* 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_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2],
+ MT8196_AUD_ENG2_CLK);
+ 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_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H], apll_rate);
+ if (ret)
+ return ret;
+ } else {
+ ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2],
+ MT8196_AFE_26M);
+ if (ret)
+ return ret;
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2]);
+
+ ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
+ MT8196_AFE_26M);
+ if (ret)
+ return ret;
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ }
+
+ return 0;
+}
+
+int mt8196_apll1_enable(struct mtk_base_afe *afe)
+{
+ int ret;
+
+ /* setting for APLL */
+ apll1_mux_setting(afe, true);
+
+ ret = mt8196_afe_enable_top_cg(afe, MT8196_CG_APLL1_CK);
+ if (ret)
+ goto err_clk_apll1;
+
+ ret = mt8196_afe_enable_top_cg(afe, MT8196_PDN_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_top_cg(afe, MT8196_PDN_APLL_TUNER1);
+err_clk_apll1:
+ mt8196_afe_disable_top_cg(afe, MT8196_CG_APLL1_CK);
+ return ret;
+}
+
+void mt8196_apll1_disable(struct mtk_base_afe *afe)
+{
+ /* 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_top_cg(afe, MT8196_PDN_APLL_TUNER1);
+ mt8196_afe_disable_top_cg(afe, MT8196_CG_APLL1_CK);
+ apll1_mux_setting(afe, false);
+}
+
+int mt8196_apll2_enable(struct mtk_base_afe *afe)
+{
+ int ret;
+
+ /* setting for APLL */
+ apll2_mux_setting(afe, true);
+
+ ret = mt8196_afe_enable_top_cg(afe, MT8196_CG_APLL2_CK);
+ if (ret)
+ goto err_clk_apll2;
+
+ ret = mt8196_afe_enable_top_cg(afe, MT8196_PDN_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_top_cg(afe, MT8196_PDN_APLL_TUNER2);
+err_clk_apll2:
+ mt8196_afe_disable_top_cg(afe, MT8196_CG_APLL2_CK);
+ return 0;
+}
+
+void mt8196_apll2_disable(struct mtk_base_afe *afe)
+{
+ /* 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_top_cg(afe, MT8196_PDN_APLL_TUNER2);
+ mt8196_afe_disable_top_cg(afe, MT8196_CG_APLL2_CK);
+ 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 %d\n", apll);
+ 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]);
+}
+
+/* 48K: select APLL2; 44.1k: select APLL1 */
+int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
+{
+ 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;
+
+ return MT8196_APLL2;
+}
+
+static const int mck_div[MT8196_MCK_NUM] = {
+ [MT8196_I2SIN0_MCK] = MT8196_CLK_TOP_APLL12_DIV_I2SIN0,
+ [MT8196_I2SIN1_MCK] = MT8196_CLK_TOP_APLL12_DIV_I2SIN1,
+ [MT8196_FMI2S_MCK] = MT8196_CLK_TOP_APLL12_DIV_FMI2S,
+ [MT8196_TDMOUT_MCK] = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_M,
+ [MT8196_TDMOUT_BCK] = 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 div_clk_id;
+ 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;
+
+ div_clk_id = mck_div[mck_id];
+
+ /* 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 *= 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 div_clk_id;
+ int ret;
+
+ 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;
+ }
+
+ div_clk_id = mck_div[mck_id];
+
+ if (div_clk_id < 0) {
+ dev_err(afe->dev, "div_clk_id = %d < 0\n",
+ div_clk_id);
+ return -EINVAL;
+ }
+
+ ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[div_clk_id], MT8196_AFE_26M);
+ if (ret)
+ return ret;
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[div_clk_id]);
+
+ return 0;
+}
+
+int mt8196_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ /* 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]);
+ ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS],
+ MT8196_AFE_26M);
+ if (ret)
+ return ret;
+
+ /* enable audio h clock */
+ mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
+ MT8196_AFE_26M);
+ if (ret)
+ return ret;
+
+ /* AFE hw clock */
+ /* IPM2.0: USE HOPPING & 26M */
+ /* set in the regmap_register_patch */
+ 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 */
+ /* set in the regmap_register_patch */
+
+ mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
+ 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_top_cg(afe, MT8196_AUDIO_26M_EN_ON);
+ return 0;
+}
+
+int mt8196_afe_disable_main_clock(struct mtk_base_afe *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 i;
+
+ 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]);
+ }
+ }
+
+ 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..7d47dcff768b
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8196-afe-clk.h -- Mediatek MT8196 AFE Clock Control definitions
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#ifndef _MT8196_AFE_CLOCK_CTRL_H_
+#define _MT8196_AFE_CLOCK_CTRL_H_
+
+#define MT8196_AFE_26M 26000000
+#define MT8196_AUD_ENG1_CLK 45158400
+#define MT8196_AUD_ENG2_CLK 49152000
+
+/* 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,
+ /* pll */
+ MT8196_CLK_TOP_APLL1_CK,
+ MT8196_CLK_TOP_APLL2_CK,
+ /* divider */
+ 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_ADSP_SEL,
+ 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
--
2.45.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v7 04/10] ASoC: mediatek: mt8196: support ADDA in platform driver
2025-08-22 12:52 [PATCH v7 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
2025-08-22 12:52 ` [PATCH v7 01/10] ASoC: mediatek: common: modify mtk afe platform driver for mt8196 Darren.Ye
2025-08-22 12:52 ` [PATCH v7 03/10] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
@ 2025-08-22 12:52 ` Darren.Ye
2025-08-22 12:52 ` [PATCH v7 05/10] ASoC: mediatek: mt8196: support I2S " Darren.Ye
` (5 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Darren.Ye @ 2025-08-22 12:52 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 | 845 ++++++++++++++++++++
1 file changed, 845 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..9a91db4e79ae
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-dai-adda.c
@@ -0,0 +1,845 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI ADDA Control
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/regmap.h>
+
+#include "mt8196-afe-clk.h"
+#include "mt8196-afe-common.h"
+#include "mt8196-interconnection.h"
+
+enum {
+ UL_IIR_SW,
+ UL_IIR_5HZ,
+ UL_IIR_10HZ,
+ UL_IIR_25HZ,
+ UL_IIR_50HZ,
+ UL_IIR_75HZ,
+};
+
+enum {
+ MTK_AFE_ADDA_UL_RATE_8K,
+ MTK_AFE_ADDA_UL_RATE_16K,
+ MTK_AFE_ADDA_UL_RATE_32K,
+ MTK_AFE_ADDA_UL_RATE_48K,
+ MTK_AFE_ADDA_UL_RATE_96K,
+ MTK_AFE_ADDA_UL_RATE_192K,
+ MTK_AFE_ADDA_UL_RATE_48K_HD,
+};
+
+enum {
+ MTK_AFE_MTKAIF_RATE_8K,
+ MTK_AFE_MTKAIF_RATE_12K,
+ MTK_AFE_MTKAIF_RATE_16K,
+ MTK_AFE_MTKAIF_RATE_24K,
+ MTK_AFE_MTKAIF_RATE_32K,
+ MTK_AFE_MTKAIF_RATE_48K,
+ MTK_AFE_MTKAIF_RATE_64K,
+ MTK_AFE_MTKAIF_RATE_96K,
+ MTK_AFE_MTKAIF_RATE_128K,
+ MTK_AFE_MTKAIF_RATE_192K,
+ MTK_AFE_MTKAIF_RATE_256K,
+ MTK_AFE_MTKAIF_RATE_384K,
+ MTK_AFE_MTKAIF_RATE_11K = 0x10,
+ MTK_AFE_MTKAIF_RATE_22K,
+ MTK_AFE_MTKAIF_RATE_44K,
+ MTK_AFE_MTKAIF_RATE_88K,
+ MTK_AFE_MTKAIF_RATE_176K,
+ MTK_AFE_MTKAIF_RATE_352K,
+};
+
+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_warn(afe->dev, "rate %d invalid, use 48kHz!!!\n", rate);
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ }
+}
+
+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_warn(afe->dev, "rate %d invalid, use 48kHz!!!\n", rate);
+ return MTK_AFE_MTKAIF_RATE_48K;
+ }
+}
+
+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_set_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_set_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_enable_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_sleep_on_pmd_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;
+}
+
+/* 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_sleep_on_pmd_event,
+ 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_sleep_on_pmd_event,
+ 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_sleep_on_pmd_event,
+ 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_sleep_on_pmd_event,
+ 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"),
+};
+
+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_INPUT"},
+ {"AP DMIC MULTICH Capture", NULL, "AP_DMIC_INPUT"},
+};
+
+/* dai ops */
+static int set_playback_hw_params(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);
+ struct mtk_afe_adda_priv *adda_priv;
+ unsigned int mtkaif_rate = 0;
+ int id = dai->id;
+
+ adda_priv = afe_priv->dai_priv[id];
+ if (!adda_priv)
+ return -EINVAL;
+
+ adda_priv->dl_rate = rate;
+
+ /* get mtkaif dl rate */
+ mtkaif_rate = mtkaif_rate_transform(afe, adda_priv->dl_rate);
+
+ if (id == MT8196_DAI_ADDA) {
+ /* 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);
+ /* clean predistortion */
+ } else {
+ /* 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);
+ }
+
+ return 0;
+};
+
+static int set_capture_hw_params(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);
+ struct mtk_afe_adda_priv *adda_priv;
+ unsigned int voice_mode = 0;
+ unsigned int ul_src_con0 = 0;
+ unsigned int mtkaif_rate = 0;
+ int id = dai->id;
+
+ adda_priv = afe_priv->dai_priv[id];
+ if (!adda_priv)
+ return -EINVAL;
+
+ adda_priv->ul_rate = rate;
+
+ /* get mtkaif dl rate */
+ mtkaif_rate = mtkaif_rate_transform(afe, adda_priv->ul_rate);
+
+ voice_mode = adda_ul_rate_transform(afe, rate);
+
+ ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
+
+ /* enable iir */
+ ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) &
+ UL_IIR_ON_TMP_CTL_MASK_SFT;
+ ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) &
+ UL_IIRMODE_CTL_MASK_SFT;
+
+ 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:
+ 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);
+
+ /* 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:
+ /* 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);
+
+ /* 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_enable_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_set_dmic_phase_sync(afe);
+ mtk_adda_ul_src_enable_dmic(afe, MT8196_DAI_AP_DMIC);
+ mtk_adda_ul_src_enable_dmic(afe, MT8196_DAI_AP_DMIC_CH34);
+ mtk_adda_ul_src_set_dmic_phase_sync_clock(afe);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+};
+
+static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int id = dai->id;
+
+ if (id >= MT8196_DAI_NUM || id < 0)
+ return -EINVAL;
+
+ dev_dbg(afe->dev, "id %d, stream %d, rate %d\n",
+ id, substream->stream, params_rate(params));
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return set_playback_hw_params(params, dai);
+ else
+ return set_capture_hw_params(params, dai);
+
+ 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,
+ },
+ /*
+ * Multich DMIC combines two DMIC controllers for use together,
+ * so AP_DMIC and Multich DMIC cannot be used at the same time.
+ */
+ {
+ .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;
+ int ret;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ dai->dai_drivers = mtk_dai_adda_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+ dai->dapm_widgets = mtk_dai_adda_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+ dai->dapm_routes = mtk_dai_adda_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+
+ ret = init_adda_priv_data(afe);
+ if (ret)
+ return ret;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ return 0;
+}
+
--
2.45.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v7 05/10] ASoC: mediatek: mt8196: support I2S in platform driver
2025-08-22 12:52 [PATCH v7 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (2 preceding siblings ...)
2025-08-22 12:52 ` [PATCH v7 04/10] ASoC: mediatek: mt8196: support ADDA in platform driver Darren.Ye
@ 2025-08-22 12:52 ` Darren.Ye
2025-08-22 12:52 ` [PATCH v7 06/10] ASoC: mediatek: mt8196: support TDM " Darren.Ye
` (4 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Darren.Ye @ 2025-08-22 12:52 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 I2S DAI driver support.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/mt8196/mt8196-dai-i2s.c | 2613 ++++++++++++++++++++
1 file changed, 2613 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-i2s.c
diff --git a/sound/soc/mediatek/mt8196/mt8196-dai-i2s.c b/sound/soc/mediatek/mt8196/mt8196-dai-i2s.c
new file mode 100644
index 000000000000..ef5cde0ba829
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-dai-i2s.c
@@ -0,0 +1,2613 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI I2S Control
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+
+#include <sound/pcm_params.h>
+
+#include "mt8196-afe-clk.h"
+#include "mt8196-afe-common.h"
+#include "mt8196-interconnection.h"
+
+#include "../common/mtk-afe-fe-dai.h"
+
+#define ETDM_22M_CLOCK_THRES 11289600
+
+enum {
+ ETDM_CLK_SOURCE_H26M,
+ ETDM_CLK_SOURCE_APLL,
+ ETDM_CLK_SOURCE_SPDIF,
+ ETDM_CLK_SOURCE_HDMI,
+ ETDM_CLK_SOURCE_EARC,
+ ETDM_CLK_SOURCE_LINEIN,
+};
+
+enum {
+ ETDM_RELATCH_SEL_H26M,
+ ETDM_RELATCH_SEL_APLL,
+};
+
+enum {
+ ETDM_RATE_8K,
+ ETDM_RATE_12K,
+ ETDM_RATE_16K,
+ ETDM_RATE_24K,
+ ETDM_RATE_32K,
+ ETDM_RATE_48K,
+ ETDM_RATE_64K,
+ ETDM_RATE_96K,
+ ETDM_RATE_128K,
+ ETDM_RATE_192K,
+ ETDM_RATE_256K,
+ ETDM_RATE_384K,
+ ETDM_RATE_11025 = 16,
+ ETDM_RATE_22050,
+ ETDM_RATE_44100,
+ ETDM_RATE_88200,
+ ETDM_RATE_176400,
+ ETDM_RATE_352800,
+};
+
+enum {
+ ETDM_CONN_8K,
+ ETDM_CONN_11K,
+ ETDM_CONN_12K,
+ ETDM_CONN_16K = 4,
+ ETDM_CONN_22K,
+ ETDM_CONN_24K,
+ ETDM_CONN_32K = 8,
+ ETDM_CONN_44K,
+ ETDM_CONN_48K,
+ ETDM_CONN_88K = 13,
+ ETDM_CONN_96K,
+ ETDM_CONN_176K = 17,
+ ETDM_CONN_192K,
+ ETDM_CONN_352K = 21,
+ ETDM_CONN_384K,
+};
+
+enum {
+ ETDM_WLEN_8_BIT = 0x7,
+ ETDM_WLEN_16_BIT = 0xf,
+ ETDM_WLEN_32_BIT = 0x1f,
+};
+
+enum {
+ ETDM_SLAVE_SEL_ETDMIN0_MASTER,
+ ETDM_SLAVE_SEL_ETDMIN0_SLAVE,
+ ETDM_SLAVE_SEL_ETDMIN1_MASTER,
+ ETDM_SLAVE_SEL_ETDMIN1_SLAVE,
+ ETDM_SLAVE_SEL_ETDMIN2_MASTER,
+ ETDM_SLAVE_SEL_ETDMIN2_SLAVE,
+ ETDM_SLAVE_SEL_ETDMIN3_MASTER,
+ ETDM_SLAVE_SEL_ETDMIN3_SLAVE,
+ ETDM_SLAVE_SEL_ETDMOUT0_MASTER,
+ ETDM_SLAVE_SEL_ETDMOUT0_SLAVE,
+ ETDM_SLAVE_SEL_ETDMOUT1_MASTER,
+ ETDM_SLAVE_SEL_ETDMOUT1_SLAVE,
+ ETDM_SLAVE_SEL_ETDMOUT2_MASTER,
+ ETDM_SLAVE_SEL_ETDMOUT2_SLAVE,
+ ETDM_SLAVE_SEL_ETDMOUT3_MASTER,
+ ETDM_SLAVE_SEL_ETDMOUT3_SLAVE,
+};
+
+enum {
+ ETDM_SLAVE_SEL_ETDMIN4_MASTER,
+ ETDM_SLAVE_SEL_ETDMIN4_SLAVE,
+ ETDM_SLAVE_SEL_ETDMIN5_MASTER,
+ ETDM_SLAVE_SEL_ETDMIN5_SLAVE,
+ ETDM_SLAVE_SEL_ETDMIN6_MASTER,
+ ETDM_SLAVE_SEL_ETDMIN6_SLAVE,
+ ETDM_SLAVE_SEL_ETDMIN7_MASTER,
+ ETDM_SLAVE_SEL_ETDMIN7_SLAVE,
+ ETDM_SLAVE_SEL_ETDMOUT4_MASTER,
+ ETDM_SLAVE_SEL_ETDMOUT4_SLAVE,
+ ETDM_SLAVE_SEL_ETDMOUT5_MASTER,
+ ETDM_SLAVE_SEL_ETDMOUT5_SLAVE,
+ ETDM_SLAVE_SEL_ETDMOUT6_MASTER,
+ ETDM_SLAVE_SEL_ETDMOUT6_SLAVE,
+ ETDM_SLAVE_SEL_ETDMOUT7_MASTER,
+ ETDM_SLAVE_SEL_ETDMOUT7_SLAVE,
+};
+
+enum {
+ MTK_DAI_ETDM_FORMAT_I2S,
+ MTK_DAI_ETDM_FORMAT_LJ,
+ MTK_DAI_ETDM_FORMAT_RJ,
+ MTK_DAI_ETDM_FORMAT_EIAJ,
+ MTK_DAI_ETDM_FORMAT_DSPA,
+ MTK_DAI_ETDM_FORMAT_DSPB,
+};
+
+static unsigned int get_etdm_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) < 16 ?
+ ETDM_WLEN_16_BIT : ETDM_WLEN_32_BIT;
+}
+
+static unsigned int get_etdm_lrck_width(snd_pcm_format_t format)
+{
+ /* The valid data bit number should be large than 7 due to hardware limitation. */
+ return snd_pcm_format_physical_width(format) - 1;
+}
+
+static unsigned int get_etdm_rate(unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return ETDM_RATE_8K;
+ case 12000:
+ return ETDM_RATE_12K;
+ case 16000:
+ return ETDM_RATE_16K;
+ case 24000:
+ return ETDM_RATE_24K;
+ case 32000:
+ return ETDM_RATE_32K;
+ case 48000:
+ return ETDM_RATE_48K;
+ case 64000:
+ return ETDM_RATE_64K;
+ case 96000:
+ return ETDM_RATE_96K;
+ case 128000:
+ return ETDM_RATE_128K;
+ case 192000:
+ return ETDM_RATE_192K;
+ case 256000:
+ return ETDM_RATE_256K;
+ case 384000:
+ return ETDM_RATE_384K;
+ case 11025:
+ return ETDM_RATE_11025;
+ case 22050:
+ return ETDM_RATE_22050;
+ case 44100:
+ return ETDM_RATE_44100;
+ case 88200:
+ return ETDM_RATE_88200;
+ case 176400:
+ return ETDM_RATE_176400;
+ case 352800:
+ return ETDM_RATE_352800;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_etdm_inconn_rate(unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return ETDM_CONN_8K;
+ case 12000:
+ return ETDM_CONN_12K;
+ case 16000:
+ return ETDM_CONN_16K;
+ case 24000:
+ return ETDM_CONN_24K;
+ case 32000:
+ return ETDM_CONN_32K;
+ case 48000:
+ return ETDM_CONN_48K;
+ case 96000:
+ return ETDM_CONN_96K;
+ case 192000:
+ return ETDM_CONN_192K;
+ case 384000:
+ return ETDM_CONN_384K;
+ case 11025:
+ return ETDM_CONN_11K;
+ case 22050:
+ return ETDM_CONN_22K;
+ case 44100:
+ return ETDM_CONN_44K;
+ case 88200:
+ return ETDM_CONN_88K;
+ case 176400:
+ return ETDM_CONN_176K;
+ case 352800:
+ return ETDM_CONN_352K;
+ default:
+ return 0;
+ }
+}
+
+struct mtk_afe_i2s_priv {
+ u8 id;
+ u32 rate; /* for determine which apll to use */
+ int low_jitter_en;
+ const char *share_property_name;
+ int share_i2s_id;
+ u32 mclk_rate;
+ u8 mclk_id;
+ u8 mclk_apll;
+ u8 ch_num;
+ u8 sync;
+ u8 ip_mode;
+ u8 format;
+};
+
+/* this enum is merely for mtk_afe_i2s_priv & mtk_base_etdm_data declare */
+enum {
+ DAI_I2SIN0,
+ DAI_I2SIN1,
+ DAI_I2SIN2,
+ DAI_I2SIN3,
+ DAI_I2SIN4,
+ DAI_I2SIN6,
+ DAI_I2SOUT0,
+ DAI_I2SOUT1,
+ DAI_I2SOUT2,
+ DAI_I2SOUT3,
+ DAI_I2SOUT4,
+ DAI_I2SOUT6,
+ DAI_FMI2S_MASTER,
+ DAI_I2S_NUM,
+};
+
+static bool is_etdm_in_pad_top(unsigned int dai_num)
+{
+ switch (dai_num) {
+ case DAI_I2SOUT4:
+ case DAI_I2SIN4:
+ return true;
+ default:
+ return false;
+ }
+}
+
+struct mtk_base_etdm_data {
+ u16 enable_reg;
+ u16 enable_mask;
+ u8 enable_shift;
+ u16 sync_reg;
+ u16 sync_mask;
+ u8 sync_shift;
+ u16 ch_reg;
+ u16 ch_mask;
+ u8 ch_shift;
+ u16 ip_mode_reg;
+ u16 ip_mode_mask;
+ u8 ip_mode_shift;
+ u16 init_count_reg;
+ u16 init_count_mask;
+ u8 init_count_shift;
+ u16 init_point_reg;
+ u16 init_point_mask;
+ u8 init_point_shift;
+ u16 lrck_reset_reg;
+ u16 lrck_reset_mask;
+ u8 lrck_reset_shift;
+ u16 clk_source_reg;
+ u16 clk_source_mask;
+ u8 clk_source_shift;
+ u16 ck_en_sel_reg;
+ u16 ck_en_sel_mask;
+ u8 ck_en_sel_shift;
+ u16 fs_timing_reg;
+ u16 fs_timing_mask;
+ u8 fs_timing_shift;
+ u16 relatch_en_sel_reg;
+ u16 relatch_en_sel_mask;
+ u8 relatch_en_sel_shift;
+ u16 use_afifo_reg;
+ u16 use_afifo_mask;
+ u8 use_afifo_shift;
+ u16 afifo_mode_reg;
+ u16 afifo_mode_mask;
+ u8 afifo_mode_shift;
+ u16 almost_end_ch_reg;
+ u16 almost_end_ch_mask;
+ u8 almost_end_ch_shift;
+ u16 almost_end_bit_reg;
+ u16 almost_end_bit_mask;
+ u8 almost_end_bit_shift;
+ u16 out2latch_time_reg;
+ u16 out2latch_time_mask;
+ u8 out2latch_time_shift;
+ u16 tdm_mode_reg;
+ u16 tdm_mode_mask;
+ u8 tdm_mode_shift;
+ u16 relatch_domain_sel_reg;
+ u16 relatch_domain_sel_mask;
+ u8 relatch_domain_sel_shift;
+ u16 bit_length_reg;
+ u16 bit_length_mask;
+ u8 bit_length_shift;
+ u16 word_length_reg;
+ u16 word_length_mask;
+ u8 word_length_shift;
+ u16 cowork_reg;
+ u16 cowork_mask;
+ u8 cowork_shift;
+ u32 cowork_val;
+ u16 in2latch_time_reg;
+ u16 in2latch_time_mask;
+ u8 in2latch_time_shift;
+ u16 pad_top_ck_en_reg;
+ u16 pad_top_ck_en_mask;
+ u8 pad_top_ck_en_shift;
+ u16 master_latch_reg;
+ u16 master_latch_mask;
+ u8 master_latch_shift;
+};
+
+/*
+ * _cfg_vlp_reg should be a variable or constant, not an expression
+ * with side effects.
+ */
+#define MTK_ETDM_IN_DATA(_id, _cowork, _cfg_vlp_reg) \
+ [DAI_I2SIN##_id] = { \
+ .enable_reg = ETDM_IN##_id##_CON0, \
+ .enable_mask = REG_ETDM_IN_EN_MASK, \
+ .enable_shift = REG_ETDM_IN_EN_SFT, \
+ .sync_reg = ETDM_IN##_id##_CON0, \
+ .sync_mask = REG_SYNC_MODE_MASK, \
+ .sync_shift = REG_SYNC_MODE_SFT, \
+ .ch_reg = ETDM_IN##_id##_CON0, \
+ .ch_mask = REG_CH_NUM_MASK, \
+ .ch_shift = REG_CH_NUM_SFT, \
+ .ip_mode_reg = ETDM_IN##_id##_CON2, \
+ .ip_mode_mask = REG_MULTI_IP_MODE_MASK, \
+ .ip_mode_shift = REG_MULTI_IP_MODE_SFT, \
+ .init_count_reg = ETDM_IN##_id##_CON1, \
+ .init_count_mask = REG_INITIAL_COUNT_MASK, \
+ .init_count_shift = REG_INITIAL_COUNT_SFT, \
+ .init_point_reg = ETDM_IN##_id##_CON1, \
+ .init_point_mask = REG_INITIAL_POINT_MASK, \
+ .init_point_shift = REG_INITIAL_POINT_SFT, \
+ .lrck_reset_reg = ETDM_IN##_id##_CON1, \
+ .lrck_reset_mask = REG_LRCK_RESET_MASK, \
+ .lrck_reset_shift = REG_LRCK_RESET_SFT, \
+ .clk_source_reg = ETDM_IN##_id##_CON2, \
+ .clk_source_mask = REG_CLOCK_SOURCE_SEL_MASK, \
+ .clk_source_shift = REG_CLOCK_SOURCE_SEL_SFT, \
+ .ck_en_sel_reg = ETDM_IN##_id##_CON2, \
+ .ck_en_sel_mask = REG_CK_EN_SEL_AUTO_MASK, \
+ .ck_en_sel_shift = REG_CK_EN_SEL_AUTO_SFT, \
+ .fs_timing_reg = ETDM_IN##_id##_CON3, \
+ .fs_timing_mask = REG_FS_TIMING_SEL_MASK, \
+ .fs_timing_shift = REG_FS_TIMING_SEL_SFT, \
+ .relatch_en_sel_reg = ETDM_IN##_id##_CON4, \
+ .relatch_en_sel_mask = REG_RELATCH_1X_EN_SEL_MASK, \
+ .relatch_en_sel_shift = REG_RELATCH_1X_EN_SEL_SFT, \
+ .use_afifo_reg = ETDM_IN##_id##_CON8, \
+ .use_afifo_mask = REG_ETDM_USE_AFIFO_MASK, \
+ .use_afifo_shift = REG_ETDM_USE_AFIFO_SFT, \
+ .afifo_mode_reg = ETDM_IN##_id##_CON8, \
+ .afifo_mode_mask = REG_AFIFO_MODE_MASK, \
+ .afifo_mode_shift = REG_AFIFO_MODE_SFT, \
+ .almost_end_ch_reg = ETDM_IN##_id##_CON9, \
+ .almost_end_ch_mask = REG_ALMOST_END_CH_COUNT_MASK, \
+ .almost_end_ch_shift = REG_ALMOST_END_CH_COUNT_SFT, \
+ .almost_end_bit_reg = ETDM_IN##_id##_CON9, \
+ .almost_end_bit_mask = REG_ALMOST_END_BIT_COUNT_MASK, \
+ .almost_end_bit_shift = REG_ALMOST_END_BIT_COUNT_SFT, \
+ .out2latch_time_reg = ETDM_IN##_id##_CON9, \
+ .out2latch_time_mask = REG_OUT2LATCH_TIME_MASK, \
+ .out2latch_time_shift = REG_OUT2LATCH_TIME_SFT, \
+ .tdm_mode_reg = ETDM_IN##_id##_CON0, \
+ .tdm_mode_mask = REG_FMT_MASK, \
+ .tdm_mode_shift = REG_FMT_SFT, \
+ .relatch_domain_sel_reg = ETDM_IN##_id##_CON0, \
+ .relatch_domain_sel_mask = REG_RELATCH_1X_EN_DOMAIN_SEL_MASK, \
+ .relatch_domain_sel_shift = REG_RELATCH_1X_EN_DOMAIN_SEL_SFT, \
+ .bit_length_reg = ETDM_IN##_id##_CON0, \
+ .bit_length_mask = REG_BIT_LENGTH_MASK, \
+ .bit_length_shift = REG_BIT_LENGTH_SFT, \
+ .word_length_reg = ETDM_IN##_id##_CON0, \
+ .word_length_mask = REG_WORD_LENGTH_MASK, \
+ .word_length_shift = REG_WORD_LENGTH_SFT, \
+ .cowork_reg = _cowork, \
+ .cowork_mask = ETDM_IN##_id##_SLAVE_SEL_MASK, \
+ .cowork_shift = ETDM_IN##_id##_SLAVE_SEL_SFT, \
+ .cowork_val = ETDM_SLAVE_SEL_ETDMOUT##_id##_MASTER, \
+ .pad_top_ck_en_reg = _cfg_vlp_reg, \
+ .pad_top_ck_en_mask = RG_I2S4_PAD_TOP_CK_EN_MASK, \
+ .pad_top_ck_en_shift = RG_I2S4_PAD_TOP_CK_EN_SFT, \
+ .master_latch_reg = _cfg_vlp_reg, \
+ .master_latch_mask = RG_I2S4_IN_BCK_NEG_EG_LATCH_MASK, \
+ .master_latch_shift = RG_I2S4_IN_BCK_NEG_EG_LATCH_SFT, \
+ }
+
+/*
+ * _cfg_vlp_reg should be a variable or constant, not an expression
+ * with side effects.
+ */
+#define MTK_ETDM_OUT_DATA(_id, _cowork, _cfg_vlp_reg) \
+ [DAI_I2SOUT##_id] = { \
+ .enable_reg = ETDM_OUT##_id##_CON0, \
+ .enable_mask = OUT_REG_ETDM_OUT_EN_MASK, \
+ .enable_shift = OUT_REG_ETDM_OUT_EN_SFT, \
+ .sync_reg = ETDM_OUT##_id##_CON0, \
+ .sync_mask = REG_SYNC_MODE_MASK, \
+ .sync_shift = REG_SYNC_MODE_SFT, \
+ .ch_reg = ETDM_OUT##_id##_CON0, \
+ .ch_mask = REG_CH_NUM_MASK, \
+ .ch_shift = REG_CH_NUM_SFT, \
+ .init_count_reg = ETDM_OUT##_id##_CON1, \
+ .init_count_mask = OUT_REG_INITIAL_COUNT_MASK, \
+ .init_count_shift = OUT_REG_INITIAL_COUNT_SFT, \
+ .init_point_reg = ETDM_OUT##_id##_CON1, \
+ .init_point_mask = OUT_REG_INITIAL_POINT_MASK, \
+ .init_point_shift = OUT_REG_INITIAL_POINT_SFT, \
+ .lrck_reset_reg = ETDM_OUT##_id##_CON1, \
+ .lrck_reset_mask = OUT_REG_LRCK_RESET_MASK, \
+ .lrck_reset_shift = OUT_REG_LRCK_RESET_SFT, \
+ .clk_source_reg = ETDM_OUT##_id##_CON4, \
+ .clk_source_mask = OUT_REG_CLOCK_SOURCE_SEL_MASK, \
+ .clk_source_shift = OUT_REG_CLOCK_SOURCE_SEL_SFT, \
+ .fs_timing_reg = ETDM_OUT##_id##_CON4, \
+ .fs_timing_mask = OUT_REG_FS_TIMING_SEL_MASK, \
+ .fs_timing_shift = OUT_REG_FS_TIMING_SEL_SFT, \
+ .relatch_en_sel_reg = ETDM_OUT##_id##_CON4, \
+ .relatch_en_sel_mask = OUT_REG_RELATCH_EN_SEL_MASK, \
+ .relatch_en_sel_shift = OUT_REG_RELATCH_EN_SEL_SFT, \
+ .tdm_mode_reg = ETDM_OUT##_id##_CON0, \
+ .tdm_mode_mask = OUT_REG_FMT_MASK, \
+ .tdm_mode_shift = OUT_REG_FMT_SFT, \
+ .relatch_domain_sel_reg = ETDM_OUT##_id##_CON0, \
+ .relatch_domain_sel_mask = OUT_REG_RELATCH_DOMAIN_SEL_MASK, \
+ .relatch_domain_sel_shift = OUT_REG_RELATCH_DOMAIN_SEL_SFT, \
+ .bit_length_reg = ETDM_OUT##_id##_CON0, \
+ .bit_length_mask = OUT_REG_BIT_LENGTH_MASK, \
+ .bit_length_shift = OUT_REG_BIT_LENGTH_SFT, \
+ .word_length_reg = ETDM_OUT##_id##_CON0, \
+ .word_length_mask = OUT_REG_WORD_LENGTH_MASK, \
+ .word_length_shift = OUT_REG_WORD_LENGTH_SFT, \
+ .cowork_reg = _cowork, \
+ .cowork_mask = ETDM_OUT##_id##_SLAVE_SEL_MASK, \
+ .cowork_shift = ETDM_OUT##_id##_SLAVE_SEL_SFT, \
+ .cowork_val = ETDM_SLAVE_SEL_ETDMIN##_id##_MASTER, \
+ .in2latch_time_reg = ETDM_OUT##_id##_CON2, \
+ .in2latch_time_mask = OUT_REG_IN2LATCH_TIME_MASK, \
+ .in2latch_time_shift = OUT_REG_IN2LATCH_TIME_SFT, \
+ .pad_top_ck_en_reg = _cfg_vlp_reg, \
+ .pad_top_ck_en_mask = RG_I2S4_PAD_TOP_CK_EN_MASK, \
+ .pad_top_ck_en_shift = RG_I2S4_PAD_TOP_CK_EN_SFT, \
+ .master_latch_reg = _cfg_vlp_reg, \
+ .master_latch_mask = RG_I2S4_OUT_BCK_NEG_EG_LATCH_MASK, \
+ .master_latch_shift = RG_I2S4_OUT_BCK_NEG_EG_LATCH_SFT, \
+ }
+
+static const struct mtk_base_etdm_data mtk_etdm_data[DAI_I2S_NUM] = {
+ MTK_ETDM_IN_DATA(0, ETDM_0_3_COWORK_CON0, 0),
+ MTK_ETDM_IN_DATA(1, ETDM_0_3_COWORK_CON1, 0),
+ MTK_ETDM_IN_DATA(2, ETDM_0_3_COWORK_CON2, 0),
+ MTK_ETDM_IN_DATA(3, ETDM_0_3_COWORK_CON3, 0),
+ MTK_ETDM_IN_DATA(4, ETDM_4_7_COWORK_CON0, AUD_TOP_CFG_VLP_RG),
+ MTK_ETDM_IN_DATA(6, ETDM_4_7_COWORK_CON2, 0),
+
+ MTK_ETDM_OUT_DATA(0, ETDM_0_3_COWORK_CON0, 0),
+ MTK_ETDM_OUT_DATA(1, ETDM_0_3_COWORK_CON0, 0),
+ MTK_ETDM_OUT_DATA(2, ETDM_0_3_COWORK_CON2, 0),
+ MTK_ETDM_OUT_DATA(3, ETDM_0_3_COWORK_CON2, 0),
+ MTK_ETDM_OUT_DATA(4, ETDM_4_7_COWORK_CON0, AUD_TOP_CFG_VLP_RG),
+ MTK_ETDM_OUT_DATA(6, ETDM_4_7_COWORK_CON2, 0),
+};
+
+enum {
+ I2S_FMT_EIAJ,
+ I2S_FMT_I2S,
+};
+
+enum {
+ I2S_WLEN_16_BIT,
+ I2S_WLEN_32_BIT,
+};
+
+enum {
+ I2S_IN_PAD_CONNSYS,
+ I2S_IN_PAD_IO_MUX,
+};
+
+static unsigned int get_i2s_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ I2S_WLEN_16_BIT : I2S_WLEN_32_BIT;
+}
+
+#define I2SIN0_MCLK_EN_W_NAME "I2SIN0_MCLK_EN"
+#define I2SIN1_MCLK_EN_W_NAME "I2SIN1_MCLK_EN"
+#define I2SIN2_MCLK_EN_W_NAME "I2SIN2_MCLK_EN"
+#define I2SIN3_MCLK_EN_W_NAME "I2SIN3_MCLK_EN"
+#define I2SIN4_MCLK_EN_W_NAME "I2SIN4_MCLK_EN"
+#define I2SIN6_MCLK_EN_W_NAME "I2SIN6_MCLK_EN"
+#define I2SOUT0_MCLK_EN_W_NAME "I2SOUT0_MCLK_EN"
+#define I2SOUT1_MCLK_EN_W_NAME "I2SOUT1_MCLK_EN"
+#define I2SOUT2_MCLK_EN_W_NAME "I2SOUT2_MCLK_EN"
+#define I2SOUT3_MCLK_EN_W_NAME "I2SOUT3_MCLK_EN"
+#define I2SOUT4_MCLK_EN_W_NAME "I2SOUT4_MCLK_EN"
+#define I2SOUT6_MCLK_EN_W_NAME "I2SOUT6_MCLK_EN"
+#define FMI2S_MASTER_MCLK_EN_W_NAME "FMI2S_MASTER_MCLK_EN"
+
+static int get_i2s_id_by_name(struct mtk_base_afe *afe,
+ const char *name)
+{
+ if (strncmp(name, "I2SIN0", 6) == 0)
+ return MT8196_DAI_I2S_IN0;
+ else if (strncmp(name, "I2SIN1", 6) == 0)
+ return MT8196_DAI_I2S_IN1;
+ else if (strncmp(name, "I2SIN2", 6) == 0)
+ return MT8196_DAI_I2S_IN2;
+ else if (strncmp(name, "I2SIN3", 6) == 0)
+ return MT8196_DAI_I2S_IN3;
+ else if (strncmp(name, "I2SIN4", 6) == 0)
+ return MT8196_DAI_I2S_IN4;
+ else if (strncmp(name, "I2SIN6", 6) == 0)
+ return MT8196_DAI_I2S_IN6;
+ else if (strncmp(name, "I2SOUT0", 7) == 0)
+ return MT8196_DAI_I2S_OUT0;
+ else if (strncmp(name, "I2SOUT1", 7) == 0)
+ return MT8196_DAI_I2S_OUT1;
+ else if (strncmp(name, "I2SOUT2", 7) == 0)
+ return MT8196_DAI_I2S_OUT2;
+ else if (strncmp(name, "I2SOUT3", 7) == 0)
+ return MT8196_DAI_I2S_OUT3;
+ else if (strncmp(name, "I2SOUT4", 7) == 0)
+ return MT8196_DAI_I2S_OUT4;
+ else if (strncmp(name, "I2SOUT6", 7) == 0)
+ return MT8196_DAI_I2S_OUT6;
+ else if (strncmp(name, "FMI2S_MASTER", 12) == 0)
+ return MT8196_DAI_FM_I2S_MASTER;
+ else
+ return -EINVAL;
+}
+
+static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe,
+ const char *name)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_i2s_id_by_name(afe, name);
+
+ if (dai_id < 0)
+ return NULL;
+
+ return afe_priv->dai_priv[dai_id];
+}
+
+static const char * const etdm_0_3_loopback_text[] = {
+ "etdmin0", "etdmin1",
+ "etdmin2", "etdmin3",
+ "etdmout0", "etdmout1",
+ "etdmout2", "etdmout3"
+};
+
+static const char * const etdm_4_7_loopback_text[] = {
+ "etdmin4", "etdmin5",
+ "etdmin6", "etdmin7",
+ "etdmout4", "etdmout5",
+ "etdmout6", "etdmout7"
+};
+
+static const u32 etdm_loopback_values[] = {
+ 0, 2, 4, 6, 8, 10, 12, 14
+};
+
+static const struct soc_enum i2sin0_loopback_enum =
+ SOC_VALUE_ENUM_SINGLE(ETDM_0_3_COWORK_CON1, ETDM_IN0_SDATA0_SEL_SFT,
+ ETDM_IN0_SDATA0_SEL_MASK, ARRAY_SIZE(etdm_0_3_loopback_text),
+ etdm_0_3_loopback_text, etdm_loopback_values);
+
+static const struct soc_enum i2sin1_loopback_enum =
+ SOC_VALUE_ENUM_SINGLE(ETDM_0_3_COWORK_CON1, ETDM_IN1_SDATA0_SEL_SFT,
+ ETDM_IN1_SDATA0_SEL_MASK, ARRAY_SIZE(etdm_0_3_loopback_text),
+ etdm_0_3_loopback_text, etdm_loopback_values);
+
+static const struct soc_enum i2sin2_loopback_enum =
+ SOC_VALUE_ENUM_SINGLE(ETDM_0_3_COWORK_CON3, ETDM_IN2_SDATA0_SEL_SFT,
+ ETDM_IN2_SDATA0_SEL_MASK, ARRAY_SIZE(etdm_0_3_loopback_text),
+ etdm_0_3_loopback_text, etdm_loopback_values);
+
+static const struct soc_enum i2sin3_loopback_enum =
+ SOC_VALUE_ENUM_SINGLE(ETDM_0_3_COWORK_CON3, ETDM_IN3_SDATA0_SEL_SFT,
+ ETDM_IN3_SDATA0_SEL_MASK, ARRAY_SIZE(etdm_0_3_loopback_text),
+ etdm_0_3_loopback_text, etdm_loopback_values);
+
+static const struct soc_enum i2sin4_loopback_enum =
+ SOC_VALUE_ENUM_SINGLE(ETDM_4_7_COWORK_CON1, ETDM_IN4_SDATA0_SEL_SFT,
+ ETDM_IN4_SDATA0_SEL_MASK, ARRAY_SIZE(etdm_4_7_loopback_text),
+ etdm_4_7_loopback_text, etdm_loopback_values);
+
+static const struct soc_enum i2sin6_loopback_enum =
+ SOC_VALUE_ENUM_SINGLE(ETDM_4_7_COWORK_CON3, ETDM_IN6_SDATA0_SEL_SFT,
+ ETDM_IN6_SDATA0_SEL_MASK, ARRAY_SIZE(etdm_4_7_loopback_text),
+ etdm_4_7_loopback_text, etdm_loopback_values);
+
+static const struct snd_kcontrol_new mtk_dai_i2s_controls[] = {
+ SOC_ENUM("I2SIN0 LOOPBACK", i2sin0_loopback_enum),
+ SOC_ENUM("I2SIN1 LOOPBACK", i2sin1_loopback_enum),
+ SOC_ENUM("I2SIN2 LOOPBACK", i2sin2_loopback_enum),
+ SOC_ENUM("I2SIN3 LOOPBACK", i2sin3_loopback_enum),
+ /* The following I2S does not support multi-ip mode */
+ SOC_ENUM("I2SIN4 LOOPBACK", i2sin4_loopback_enum),
+ SOC_ENUM("I2SIN6 LOOPBACK", i2sin6_loopback_enum),
+};
+
+/* interconnection */
+static const struct snd_kcontrol_new mtk_i2sout0_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN108_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN108_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN108_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN108_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN108_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN108_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN108_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN108_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN108_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN108_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL23_CH1", AFE_CONN108_2, I_DL23_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH1", AFE_CONN108_2, I_DL24_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN108_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN108_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN108_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN108_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN108_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN108_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN108_6,
+ I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout0_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN109_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN109_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN109_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN109_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN109_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN109_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN109_1, I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN109_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN109_1, I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN109_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL23_CH2", AFE_CONN109_2, I_DL23_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH2", AFE_CONN109_2, I_DL24_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN109_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN109_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN109_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN109_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN109_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN109_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN109_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN109_4,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN109_6,
+ I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout1_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN110_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN110_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN110_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN110_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN110_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN110_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN110_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN110_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN110_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN110_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN110_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN110_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN110_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN110_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout1_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN111_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN111_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN111_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN111_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN111_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN111_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN111_1, I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN111_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN111_1, I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN111_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN111_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN111_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN111_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN111_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN111_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN111_4,
+ I_PCM_1_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout2_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN112_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN112_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN112_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN112_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN112_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN112_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN112_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN112_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN112_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN112_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN112_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN112_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN112_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN112_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout2_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN113_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN113_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN113_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN113_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN113_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN113_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN113_1, I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN113_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN113_1, I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN113_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN113_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN113_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN113_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN113_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN113_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN113_4,
+ I_PCM_1_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout3_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN114_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN114_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN114_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN114_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN114_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN114_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN114_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN114_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN114_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN114_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN114_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN114_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN114_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN114_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout3_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN115_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN115_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN115_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN115_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN115_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN115_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN115_1, I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN115_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN115_1, I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN115_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN115_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN115_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN115_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN115_4,
+ I_PCM_1_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN116_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN116_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN116_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN116_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN116_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN116_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN116_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN116_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN116_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN116_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH1", AFE_CONN116_2, I_DL24_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN116_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN116_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN116_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN116_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN116_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN116_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN116_6,
+ I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN117_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN117_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN117_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN117_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN117_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN117_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN117_1, I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN117_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN117_1, I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN117_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH2", AFE_CONN117_2, I_DL24_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN117_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN117_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN117_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN117_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN117_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN117_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN117_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN117_4,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN117_6,
+ I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch3_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH3", AFE_CONN118_1, I_DL_24CH_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN118_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN118_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH4", AFE_CONN119_1, I_DL_24CH_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN118_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN118_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch5_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH5", AFE_CONN120_1, I_DL_24CH_CH5, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch6_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH6", AFE_CONN121_1, I_DL_24CH_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch7_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH7", AFE_CONN122_1, I_DL_24CH_CH7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch8_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH8", AFE_CONN123_1, I_DL_24CH_CH8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout6_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN148_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN148_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN148_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN148_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN148_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN148_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN148_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN148_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN148_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL23_CH1", AFE_CONN148_2, I_DL23_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN148_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN148_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN148_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN148_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN148_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN148_6,
+ I_SRC_1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout6_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN149_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN149_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN149_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN149_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN149_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN149_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN149_1, I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN149_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN149_1, I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL23_CH2", AFE_CONN149_2, I_DL23_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN149_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN149_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN149_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN149_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN149_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN149_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN149_4,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN148_6,
+ I_SRC_1_OUT_CH2, 1, 0),
+};
+
+enum {
+ SUPPLY_SEQ_APLL,
+ SUPPLY_SEQ_I2S_MCLK_EN,
+ SUPPLY_SEQ_I2S_CG_EN,
+ SUPPLY_SEQ_I2S_EN,
+};
+
+static int mtk_apll_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(cmpnt->dev, "name %s, event 0x%x\n", w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (strcmp(w->name, APLL1_W_NAME) == 0)
+ mt8196_apll1_enable(afe);
+ else
+ mt8196_apll2_enable(afe);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (strcmp(w->name, APLL1_W_NAME) == 0)
+ mt8196_apll1_disable(afe);
+ else
+ mt8196_apll2_disable(afe);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ dev_dbg(cmpnt->dev, "name %s, event 0x%x\n", w->name, event);
+
+ i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+ if (!i2s_priv)
+ return -EINVAL;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ i2s_priv->mclk_rate = 0;
+ mt8196_mck_disable(afe, i2s_priv->mclk_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = {
+ SND_SOC_DAPM_MIXER("I2SOUT0_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout0_ch1_mix,
+ ARRAY_SIZE(mtk_i2sout0_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT0_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout0_ch2_mix,
+ ARRAY_SIZE(mtk_i2sout0_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("I2SOUT1_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout1_ch1_mix,
+ ARRAY_SIZE(mtk_i2sout1_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT1_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout1_ch2_mix,
+ ARRAY_SIZE(mtk_i2sout1_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("I2SOUT2_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout2_ch1_mix,
+ ARRAY_SIZE(mtk_i2sout2_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT2_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout2_ch2_mix,
+ ARRAY_SIZE(mtk_i2sout2_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("I2SOUT3_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout3_ch1_mix,
+ ARRAY_SIZE(mtk_i2sout3_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT3_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout3_ch2_mix,
+ ARRAY_SIZE(mtk_i2sout3_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch1_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch2_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch2_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH3", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch3_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch3_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH4", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch4_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch4_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH5", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch5_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch5_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH6", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch6_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch6_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH7", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch7_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch7_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH8", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch8_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch8_mix)),
+
+ SND_SOC_DAPM_MIXER("I2SOUT6_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout6_ch1_mix,
+ ARRAY_SIZE(mtk_i2sout6_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT6_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout6_ch2_mix,
+ ARRAY_SIZE(mtk_i2sout6_ch2_mix)),
+
+ /* i2s en*/
+ SND_SOC_DAPM_SUPPLY_S("I2SIN0_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_IN0_CON0, REG_ETDM_IN_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN1_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_IN1_CON0, REG_ETDM_IN_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN2_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_IN2_CON0, REG_ETDM_IN_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN3_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_IN3_CON0, REG_ETDM_IN_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN4_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_IN4_CON0, REG_ETDM_IN_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN6_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_IN6_CON0, REG_ETDM_IN_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT0_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_OUT0_CON0, OUT_REG_ETDM_OUT_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT1_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_OUT1_CON0, OUT_REG_ETDM_OUT_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT2_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_OUT2_CON0, OUT_REG_ETDM_OUT_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT3_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_OUT3_CON0, OUT_REG_ETDM_OUT_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT4_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_OUT4_CON0, OUT_REG_ETDM_OUT_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT6_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_OUT6_CON0, OUT_REG_ETDM_OUT_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("FMI2S_MASTER_EN", SUPPLY_SEQ_I2S_EN,
+ AFE_CONNSYS_I2S_CON, I2S_EN_SFT, 0,
+ NULL, 0),
+
+ /* i2s mclk en */
+ SND_SOC_DAPM_SUPPLY_S(I2SIN0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SIN1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SIN2_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SIN3_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SIN4_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SIN6_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SOUT0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SOUT1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SOUT2_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SOUT3_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SOUT4_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SOUT6_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(FMI2S_MASTER_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* cg */
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT0_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_OUT0_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT1_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_OUT1_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT2_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_OUT2_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT3_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_OUT3_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT4_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_OUT4_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT6_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_OUT6_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN0_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_IN0_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN1_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_IN1_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN2_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_IN2_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN3_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_IN3_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN4_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_IN4_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN6_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_IN6_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("FMI2S_MASTER_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON0, PDN_FM_I2S_SFT, 1,
+ NULL, 0),
+
+ /* apll */
+ SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL,
+ SND_SOC_NOPM, 0, 0,
+ mtk_apll_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL,
+ SND_SOC_NOPM, 0, 0,
+ mtk_apll_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER("SOF_DMA_DL_24CH", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SOF_DMA_DL1", SND_SOC_NOPM, 0, 0, NULL, 0),
+};
+
+static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(sink->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+ if (!i2s_priv)
+ return 0;
+
+ if (i2s_priv->share_i2s_id < 0)
+ return 0;
+
+ return i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name);
+}
+
+static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(sink->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int cur_apll;
+ int needed_apll;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+ if (!i2s_priv)
+ return 0;
+
+ /* which apll */
+ cur_apll = mt8196_get_apll_by_name(afe, source->name);
+
+ /* choose APLL from i2s rate */
+ needed_apll = mt8196_get_apll_by_rate(afe, i2s_priv->rate);
+
+ return needed_apll == cur_apll;
+}
+
+static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(sink->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int i2s_num;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+ if (!i2s_priv)
+ return 0;
+
+ i2s_num = get_i2s_id_by_name(afe, source->name);
+ if (get_i2s_id_by_name(afe, sink->name) == i2s_num)
+ return i2s_priv->mclk_rate > 0;
+
+ /* check if share i2s need mclk */
+ if (i2s_priv->share_i2s_id < 0)
+ return 0;
+
+ if (i2s_priv->share_i2s_id == i2s_num)
+ return i2s_priv->mclk_rate > 0;
+
+ return 0;
+}
+
+static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(sink->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int cur_apll;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+ if (!i2s_priv)
+ return 0;
+
+ /* which apll */
+ cur_apll = mt8196_get_apll_by_name(afe, source->name);
+
+ return i2s_priv->mclk_apll == cur_apll;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = {
+ /* i2sin0 */
+ {"I2SIN0", NULL, "I2SIN0_EN"},
+ {"I2SIN0", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SIN2_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SIN3_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SIN4_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SIN6_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SOUT2_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SOUT3_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SOUT6_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "FMI2S_MASTER_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SIN0", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SIN0", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2SIN0", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+
+ {I2SIN0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SIN0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SIN0", NULL, "I2SIN0_CG"},
+
+ /* i2sin1 */
+ {"I2SIN1", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SIN1_EN"},
+ {"I2SIN1", NULL, "I2SIN2_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SIN3_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SIN4_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SIN6_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SOUT2_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SOUT3_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SOUT6_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "FMI2S_MASTER_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SIN1", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SIN1", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2SIN1", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SIN1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SIN1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SIN1", NULL, "I2SIN1_CG"},
+
+ /* i2sin2 */
+ {"I2SIN2", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN2", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN2", NULL, "I2SIN2_EN"},
+ {"I2SIN2", NULL, "I2SIN3_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN2", NULL, "I2SIN4_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN2", NULL, "I2SIN6_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN2", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN2", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN2", NULL, "I2SOUT2_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN2", NULL, "I2SOUT3_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN2", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN2", NULL, "I2SOUT6_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN2", NULL, "FMI2S_MASTER_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SIN2", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SIN2", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2SIN2", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN2", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN2", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN2", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN2", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN2", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN2", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN2", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN2", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN2", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN2", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN2", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN2", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SIN2_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SIN2_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SIN2", NULL, "I2SIN2_CG"},
+
+ /* i2sin3 */
+ {"I2SIN3", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN3", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN3", NULL, "I2SIN2_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN3", NULL, "I2SIN3_EN"},
+ {"I2SIN3", NULL, "I2SIN4_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN3", NULL, "I2SIN6_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN3", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN3", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN3", NULL, "I2SOUT2_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN3", NULL, "I2SOUT3_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN3", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN3", NULL, "I2SOUT6_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN3", NULL, "FMI2S_MASTER_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SIN3", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SIN3", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2SIN3", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN3", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN3", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN3", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN3", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN3", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN3", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN3", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN3", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN3", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN3", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN3", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN3", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SIN3_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SIN3_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SIN3", NULL, "I2SIN3_CG"},
+
+ /* i2sin4 */
+ {"I2SIN4", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN4", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN4", NULL, "I2SIN2_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN4", NULL, "I2SIN3_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN4", NULL, "I2SIN4_EN"},
+ {"I2SIN4", NULL, "I2SIN6_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN4", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN4", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN4", NULL, "I2SOUT2_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN4", NULL, "I2SOUT3_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN4", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN4", NULL, "I2SOUT6_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN4", NULL, "FMI2S_MASTER_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SIN4", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SIN4", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2SIN4", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN4", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN4", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN4", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN4", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN4", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN4", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN4", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN4", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN4", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN4", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN4", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN4", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SIN4_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SIN4_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SIN4", NULL, "I2SIN4_CG"},
+
+ /* i2sin6 */
+ {"I2SIN6", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN6", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN6", NULL, "I2SIN2_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN6", NULL, "I2SIN3_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN6", NULL, "I2SIN4_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN6", NULL, "I2SIN6_EN"},
+ {"I2SIN6", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN6", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN6", NULL, "I2SOUT2_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN6", NULL, "I2SOUT3_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN6", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN6", NULL, "I2SOUT6_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN6", NULL, "FMI2S_MASTER_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SIN6", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SIN6", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2SIN6", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN6", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN6", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN6", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN6", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN6", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN6", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN6", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN6", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN6", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN6", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN6", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN6", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SIN6_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SIN6_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SIN6", NULL, "I2SIN6_CG"},
+ {"I2SIN6", NULL, "I2SOUT6_CG"},
+
+ /* i2sout0 */
+ {"I2SOUT0_CH1", "DL0_CH1", "DL0"},
+ {"I2SOUT0_CH2", "DL0_CH2", "DL0"},
+ {"I2SOUT0_CH1", "DL1_CH1", "DL1"},
+ {"I2SOUT0_CH2", "DL1_CH2", "DL1"},
+ {"I2SOUT0_CH1", "DL2_CH1", "DL2"},
+ {"I2SOUT0_CH2", "DL2_CH2", "DL2"},
+ {"I2SOUT0_CH1", "DL3_CH1", "DL3"},
+ {"I2SOUT0_CH2", "DL3_CH2", "DL3"},
+ {"I2SOUT0_CH1", "DL4_CH1", "DL4"},
+ {"I2SOUT0_CH2", "DL4_CH2", "DL4"},
+ {"I2SOUT0_CH1", "DL5_CH1", "DL5"},
+ {"I2SOUT0_CH2", "DL5_CH2", "DL5"},
+ {"I2SOUT0_CH1", "DL6_CH1", "DL6"},
+ {"I2SOUT0_CH2", "DL6_CH2", "DL6"},
+ {"I2SOUT0_CH1", "DL7_CH1", "DL7"},
+ {"I2SOUT0_CH2", "DL7_CH2", "DL7"},
+ {"I2SOUT0_CH1", "DL8_CH1", "DL8"},
+ {"I2SOUT0_CH2", "DL8_CH2", "DL8"},
+ {"I2SOUT0_CH1", "DL23_CH1", "DL23"},
+ {"I2SOUT0_CH2", "DL23_CH2", "DL23"},
+ {"I2SOUT0_CH1", "DL_24CH_CH1", "DL_24CH"},
+ {"I2SOUT0_CH2", "DL_24CH_CH2", "DL_24CH"},
+
+ {"I2SOUT0_CH1", "DL24_CH1", "DL24"},
+ {"I2SOUT0_CH2", "DL24_CH2", "DL24"},
+
+ {"I2SOUT0", NULL, "I2SOUT0_CH1"},
+ {"I2SOUT0", NULL, "I2SOUT0_CH2"},
+
+ {"I2SOUT0", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SIN2_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SIN3_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SIN4_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SIN6_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SOUT0_EN"},
+ {"I2SOUT0", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SOUT2_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SOUT3_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SOUT6_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "FMI2S_MASTER_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SOUT0", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SOUT0", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2SOUT0", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SOUT0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SOUT0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SOUT0", NULL, "I2SOUT0_CG"},
+ {"I2SOUT0", NULL, "I2SIN0_CG"},
+
+ /* i2sout1 */
+ {"I2SOUT1_CH1", "DL0_CH1", "DL0"},
+ {"I2SOUT1_CH2", "DL0_CH2", "DL0"},
+ {"I2SOUT1_CH1", "DL1_CH1", "DL1"},
+ {"I2SOUT1_CH2", "DL1_CH2", "DL1"},
+ {"I2SOUT1_CH1", "DL2_CH1", "DL2"},
+ {"I2SOUT1_CH2", "DL2_CH2", "DL2"},
+ {"I2SOUT1_CH1", "DL3_CH1", "DL3"},
+ {"I2SOUT1_CH2", "DL3_CH2", "DL3"},
+ {"I2SOUT1_CH1", "DL4_CH1", "DL4"},
+ {"I2SOUT1_CH2", "DL4_CH2", "DL4"},
+ {"I2SOUT1_CH1", "DL5_CH1", "DL5"},
+ {"I2SOUT1_CH2", "DL5_CH2", "DL5"},
+ {"I2SOUT1_CH1", "DL6_CH1", "DL6"},
+ {"I2SOUT1_CH2", "DL6_CH2", "DL6"},
+ {"I2SOUT1_CH1", "DL7_CH1", "DL7"},
+ {"I2SOUT1_CH2", "DL7_CH2", "DL7"},
+ {"I2SOUT1_CH1", "DL8_CH1", "DL8"},
+ {"I2SOUT1_CH2", "DL8_CH2", "DL8"},
+ {"I2SOUT1_CH1", "DL_24CH_CH1", "DL_24CH"},
+ {"I2SOUT1_CH2", "DL_24CH_CH2", "DL_24CH"},
+
+ {"I2SOUT1", NULL, "I2SOUT1_CH1"},
+ {"I2SOUT1", NULL, "I2SOUT1_CH2"},
+
+ {"I2SOUT1", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SIN2_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SIN3_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SIN4_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SIN6_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SOUT1_EN"},
+ {"I2SOUT1", NULL, "I2SOUT2_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SOUT3_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SOUT6_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "FMI2S_MASTER_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SOUT1", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SOUT1", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2SOUT1", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SOUT1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SOUT1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SOUT1", NULL, "I2SOUT1_CG"},
+ {"I2SOUT1", NULL, "I2SIN1_CG"},
+
+ /* i2sout2 */
+ {"I2SOUT2_CH1", "DL0_CH1", "DL0"},
+ {"I2SOUT2_CH2", "DL0_CH2", "DL0"},
+ {"I2SOUT2_CH1", "DL1_CH1", "DL1"},
+ {"I2SOUT2_CH2", "DL1_CH2", "DL1"},
+ {"I2SOUT2_CH1", "DL2_CH1", "DL2"},
+ {"I2SOUT2_CH2", "DL2_CH2", "DL2"},
+ {"I2SOUT2_CH1", "DL3_CH1", "DL3"},
+ {"I2SOUT2_CH2", "DL3_CH2", "DL3"},
+ {"I2SOUT2_CH1", "DL4_CH1", "DL4"},
+ {"I2SOUT2_CH2", "DL4_CH2", "DL4"},
+ {"I2SOUT2_CH1", "DL5_CH1", "DL5"},
+ {"I2SOUT2_CH2", "DL5_CH2", "DL5"},
+ {"I2SOUT2_CH1", "DL6_CH1", "DL6"},
+ {"I2SOUT2_CH2", "DL6_CH2", "DL6"},
+ {"I2SOUT2_CH1", "DL7_CH1", "DL7"},
+ {"I2SOUT2_CH2", "DL7_CH2", "DL7"},
+ {"I2SOUT2_CH1", "DL8_CH1", "DL8"},
+ {"I2SOUT2_CH2", "DL8_CH2", "DL8"},
+ {"I2SOUT2_CH1", "DL_24CH_CH1", "DL_24CH"},
+ {"I2SOUT2_CH2", "DL_24CH_CH2", "DL_24CH"},
+
+ {"I2SOUT2", NULL, "I2SOUT2_CH1"},
+ {"I2SOUT2", NULL, "I2SOUT2_CH2"},
+
+ {"I2SOUT2", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT2", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT2", NULL, "I2SIN2_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT2", NULL, "I2SIN3_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT2", NULL, "I2SIN4_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT2", NULL, "I2SIN6_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT2", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT2", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT2", NULL, "I2SOUT2_EN"},
+ {"I2SOUT2", NULL, "I2SOUT3_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT2", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT2", NULL, "I2SOUT6_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT2", NULL, "FMI2S_MASTER_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SOUT2", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SOUT2", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2SOUT2", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT2", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT2", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT2", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT2", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT2", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT2", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT2", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT2", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT2", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT2", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT2", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT2", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SOUT2_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SOUT2_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SOUT2", NULL, "I2SOUT2_CG"},
+ {"I2SOUT2", NULL, "I2SIN2_CG"},
+
+ /* i2sout3 */
+ {"I2SOUT3_CH1", "DL0_CH1", "DL0"},
+ {"I2SOUT3_CH2", "DL0_CH2", "DL0"},
+ {"I2SOUT3_CH1", "DL1_CH1", "DL1"},
+ {"I2SOUT3_CH2", "DL1_CH2", "DL1"},
+ {"I2SOUT3_CH1", "DL2_CH1", "DL2"},
+ {"I2SOUT3_CH2", "DL2_CH2", "DL2"},
+ {"I2SOUT3_CH1", "DL3_CH1", "DL3"},
+ {"I2SOUT3_CH2", "DL3_CH2", "DL3"},
+ {"I2SOUT3_CH1", "DL4_CH1", "DL4"},
+ {"I2SOUT3_CH2", "DL4_CH2", "DL4"},
+ {"I2SOUT3_CH1", "DL5_CH1", "DL5"},
+ {"I2SOUT3_CH2", "DL5_CH2", "DL5"},
+ {"I2SOUT3_CH1", "DL6_CH1", "DL6"},
+ {"I2SOUT3_CH2", "DL6_CH2", "DL6"},
+ {"I2SOUT3_CH1", "DL7_CH1", "DL7"},
+ {"I2SOUT3_CH2", "DL7_CH2", "DL7"},
+ {"I2SOUT3_CH1", "DL8_CH1", "DL8"},
+ {"I2SOUT3_CH2", "DL8_CH2", "DL8"},
+ {"I2SOUT3_CH1", "DL_24CH_CH1", "DL_24CH"},
+ {"I2SOUT3_CH2", "DL_24CH_CH2", "DL_24CH"},
+
+ {"I2SOUT3", NULL, "I2SOUT3_CH1"},
+ {"I2SOUT3", NULL, "I2SOUT3_CH2"},
+
+ {"I2SOUT3", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT3", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT3", NULL, "I2SIN2_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT3", NULL, "I2SIN3_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT3", NULL, "I2SIN4_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT3", NULL, "I2SIN6_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT3", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT3", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT3", NULL, "I2SOUT2_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT3", NULL, "I2SOUT3_EN"},
+ {"I2SOUT3", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT3", NULL, "I2SOUT6_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT3", NULL, "FMI2S_MASTER_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SOUT3", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SOUT3", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2SOUT3", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT3", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT3", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT3", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT3", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT3", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT3", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT3", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT3", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT3", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT3", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT3", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT3", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SOUT3_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SOUT3_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SOUT3", NULL, "I2SOUT3_CG"},
+ {"I2SOUT3", NULL, "I2SIN3_CG"},
+
+ /* i2sout4 */
+ {"I2SOUT4_CH1", "DL0_CH1", "DL0"},
+ {"I2SOUT4_CH2", "DL0_CH2", "DL0"},
+ {"I2SOUT4_CH1", "DL1_CH1", "DL1"},
+ {"I2SOUT4_CH2", "DL1_CH2", "DL1"},
+ {"I2SOUT4_CH1", "DL2_CH1", "DL2"},
+ {"I2SOUT4_CH2", "DL2_CH2", "DL2"},
+ {"I2SOUT4_CH1", "DL3_CH1", "DL3"},
+ {"I2SOUT4_CH2", "DL3_CH2", "DL3"},
+ {"I2SOUT4_CH1", "DL4_CH1", "DL4"},
+ {"I2SOUT4_CH2", "DL4_CH2", "DL4"},
+ {"I2SOUT4_CH1", "DL5_CH1", "DL5"},
+ {"I2SOUT4_CH2", "DL5_CH2", "DL5"},
+ {"I2SOUT4_CH1", "DL6_CH1", "DL6"},
+ {"I2SOUT4_CH2", "DL6_CH2", "DL6"},
+ {"I2SOUT4_CH1", "DL7_CH1", "DL7"},
+ {"I2SOUT4_CH2", "DL7_CH2", "DL7"},
+ {"I2SOUT4_CH1", "DL8_CH1", "DL8"},
+ {"I2SOUT4_CH2", "DL8_CH2", "DL8"},
+ {"I2SOUT4_CH1", "DL_24CH_CH1", "DL_24CH"},
+ {"I2SOUT4_CH2", "DL_24CH_CH2", "DL_24CH"},
+ {"I2SOUT4_CH3", "DL_24CH_CH3", "DL_24CH"},
+ {"I2SOUT4_CH4", "DL_24CH_CH4", "DL_24CH"},
+ {"I2SOUT4_CH5", "DL_24CH_CH5", "DL_24CH"},
+ {"I2SOUT4_CH6", "DL_24CH_CH6", "DL_24CH"},
+ {"I2SOUT4_CH7", "DL_24CH_CH7", "DL_24CH"},
+ {"I2SOUT4_CH8", "DL_24CH_CH8", "DL_24CH"},
+ {"I2SOUT4_CH1", "DL24_CH1", "DL24"},
+ {"I2SOUT4_CH2", "DL24_CH2", "DL24"},
+
+ /* SOF Downlink */
+ {"I2SOUT4_CH1", "DL_24CH_CH1", "SOF_DMA_DL_24CH"},
+ {"I2SOUT4_CH2", "DL_24CH_CH2", "SOF_DMA_DL_24CH"},
+ {"I2SOUT4_CH3", "DL_24CH_CH3", "SOF_DMA_DL_24CH"},
+ {"I2SOUT4_CH4", "DL_24CH_CH4", "SOF_DMA_DL_24CH"},
+
+ {"I2SOUT4", NULL, "I2SOUT4_CH1"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH2"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH3"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH4"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH5"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH6"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH7"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH8"},
+
+ {"I2SOUT4", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SIN2_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SIN3_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SIN4_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SIN6_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SOUT2_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SOUT3_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SOUT4_EN"},
+ {"I2SOUT4", NULL, "I2SOUT6_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "FMI2S_MASTER_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SOUT4", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SOUT4", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2SOUT4", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SOUT4_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SOUT4_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ /* CG */
+ {"I2SOUT4", NULL, "I2SOUT4_CG"},
+ {"I2SOUT4", NULL, "I2SIN4_CG"},
+
+ /* i2sout6 */
+ {"I2SOUT6_CH1", "DL0_CH1", "DL0"},
+ {"I2SOUT6_CH2", "DL0_CH2", "DL0"},
+ {"I2SOUT6_CH1", "DL1_CH1", "DL1"},
+ {"I2SOUT6_CH2", "DL1_CH2", "DL1"},
+ {"I2SOUT6_CH1", "DL2_CH1", "DL2"},
+ {"I2SOUT6_CH2", "DL2_CH2", "DL2"},
+ {"I2SOUT6_CH1", "DL3_CH1", "DL3"},
+ {"I2SOUT6_CH2", "DL3_CH2", "DL3"},
+ {"I2SOUT6_CH1", "DL4_CH1", "DL4"},
+ {"I2SOUT6_CH2", "DL4_CH2", "DL4"},
+ {"I2SOUT6_CH1", "DL5_CH1", "DL5"},
+ {"I2SOUT6_CH2", "DL5_CH2", "DL5"},
+ {"I2SOUT6_CH1", "DL6_CH1", "DL6"},
+ {"I2SOUT6_CH2", "DL6_CH2", "DL6"},
+ {"I2SOUT6_CH1", "DL7_CH1", "DL7"},
+ {"I2SOUT6_CH2", "DL7_CH2", "DL7"},
+ {"I2SOUT6_CH1", "DL8_CH1", "DL8"},
+ {"I2SOUT6_CH2", "DL8_CH2", "DL8"},
+ {"I2SOUT6_CH1", "DL23_CH1", "DL23"},
+ {"I2SOUT6_CH2", "DL23_CH2", "DL23"},
+ {"I2SOUT6_CH1", "DL_24CH_CH1", "DL_24CH"},
+ {"I2SOUT6_CH2", "DL_24CH_CH2", "DL_24CH"},
+
+ /* SOF Downlink */
+ {"I2SOUT6_CH1", "DL1_CH1", "SOF_DMA_DL1"},
+ {"I2SOUT6_CH2", "DL1_CH2", "SOF_DMA_DL1"},
+ {"I2SOUT6_CH1", "DL_24CH_CH1", "SOF_DMA_DL_24CH"},
+ {"I2SOUT6_CH2", "DL_24CH_CH2", "SOF_DMA_DL_24CH"},
+
+ {"I2SOUT6", NULL, "I2SOUT6_CH1"},
+ {"I2SOUT6", NULL, "I2SOUT6_CH2"},
+
+ {"I2SOUT6", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT6", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT6", NULL, "I2SIN2_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT6", NULL, "I2SIN3_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT6", NULL, "I2SIN4_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT6", NULL, "I2SIN6_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT6", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT6", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT6", NULL, "I2SOUT2_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT6", NULL, "I2SOUT3_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT6", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT6", NULL, "I2SOUT6_EN"},
+ {"I2SOUT6", NULL, "FMI2S_MASTER_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SOUT6", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SOUT6", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2SOUT6", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT6", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT6", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT6", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT6", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT6", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT6", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT6", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT6", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT6", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT6", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT6", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT6", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SOUT6_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SOUT6_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ /* CG */
+ {"I2SOUT6", NULL, "I2SOUT6_CG"},
+ {"I2SOUT6", NULL, "I2SIN6_CG"},
+
+ /* fmi2s */
+ {"FMI2S_MASTER", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"FMI2S_MASTER", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"FMI2S_MASTER", NULL, "I2SIN2_EN", mtk_afe_i2s_share_connect},
+ {"FMI2S_MASTER", NULL, "I2SIN3_EN", mtk_afe_i2s_share_connect},
+ {"FMI2S_MASTER", NULL, "I2SIN4_EN", mtk_afe_i2s_share_connect},
+ {"FMI2S_MASTER", NULL, "I2SIN6_EN", mtk_afe_i2s_share_connect},
+ {"FMI2S_MASTER", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"FMI2S_MASTER", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"FMI2S_MASTER", NULL, "I2SOUT2_EN", mtk_afe_i2s_share_connect},
+ {"FMI2S_MASTER", NULL, "I2SOUT3_EN", mtk_afe_i2s_share_connect},
+ {"FMI2S_MASTER", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+ {"FMI2S_MASTER", NULL, "I2SOUT6_EN", mtk_afe_i2s_share_connect},
+ {"FMI2S_MASTER", NULL, "FMI2S_MASTER_EN"},
+
+ {"FMI2S_MASTER", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"FMI2S_MASTER", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"FMI2S_MASTER", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"FMI2S_MASTER", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"FMI2S_MASTER", NULL, I2SIN2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"FMI2S_MASTER", NULL, I2SIN3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"FMI2S_MASTER", NULL, I2SIN4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"FMI2S_MASTER", NULL, I2SIN6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"FMI2S_MASTER", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"FMI2S_MASTER", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"FMI2S_MASTER", NULL, I2SOUT2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"FMI2S_MASTER", NULL, I2SOUT3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"FMI2S_MASTER", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"FMI2S_MASTER", NULL, I2SOUT6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"FMI2S_MASTER", NULL, FMI2S_MASTER_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {FMI2S_MASTER_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {FMI2S_MASTER_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ /* CG */
+ {"FMI2S_MASTER", NULL, "FMI2S_MASTER_CG"},
+};
+
+/* i2s dai ops*/
+static int mtk_dai_i2s_config(struct mtk_base_afe *afe,
+ struct snd_pcm_hw_params *params,
+ int i2s_id)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv;
+ struct mtk_afe_i2s_priv *i2sin_priv = NULL;
+ int id = i2s_id - MT8196_DAI_I2S_IN0;
+ struct mtk_base_etdm_data etdm_data;
+ unsigned int rate = params_rate(params);
+ unsigned int rate_reg = get_etdm_inconn_rate(rate);
+ snd_pcm_format_t format = params_format(params);
+ unsigned int channels = params_channels(params);
+ int ret;
+ unsigned int i2s_con;
+ int pad_top;
+
+ if (i2s_id >= MT8196_DAI_NUM || i2s_id < 0 || id < 0 || id >= DAI_I2S_NUM)
+ return -EINVAL;
+
+ i2s_priv = afe_priv->dai_priv[i2s_id];
+ if (!i2s_priv)
+ return -EINVAL;
+
+ dev_dbg(afe->dev, "id: %d, rate: %d, pcm_fmt: %d, fmt: %d, ch: %d\n",
+ i2s_id, rate, format, i2s_priv->format, channels);
+
+ i2s_priv->rate = rate;
+ etdm_data = mtk_etdm_data[id];
+
+ if (is_etdm_in_pad_top(id))
+ pad_top = 0x3;
+ else
+ pad_top = 0x5;
+
+ switch (id) {
+ case DAI_FMI2S_MASTER:
+ i2s_con = I2S_IN_PAD_IO_MUX << I2SIN_PAD_SEL_SFT;
+ i2s_con |= rate_reg << I2S_MODE_SFT;
+ i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT;
+ i2s_con |= get_i2s_wlen(format) << I2S_WLEN_SFT;
+ regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON,
+ 0xffffeffe, i2s_con);
+ break;
+
+ case DAI_I2SIN0:
+ case DAI_I2SIN1:
+ case DAI_I2SIN2:
+ case DAI_I2SIN3:
+ case DAI_I2SIN4:
+ case DAI_I2SIN6:
+ /* ---etdm in --- */
+ regmap_update_bits(afe->regmap,
+ etdm_data.init_count_reg,
+ etdm_data.init_count_mask << etdm_data.init_count_shift,
+ 0x5 << etdm_data.init_count_shift);
+
+ /* 3: pad top 5: no pad top */
+ regmap_update_bits(afe->regmap,
+ etdm_data.init_point_reg,
+ etdm_data.init_point_mask << etdm_data.init_point_shift,
+ pad_top << etdm_data.init_point_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.lrck_reset_reg,
+ etdm_data.lrck_reset_mask << etdm_data.lrck_reset_shift,
+ 0x1 << etdm_data.lrck_reset_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.clk_source_reg,
+ etdm_data.clk_source_mask << etdm_data.clk_source_shift,
+ ETDM_CLK_SOURCE_APLL << etdm_data.clk_source_shift);
+
+ /* 0: manual 1: auto */
+ regmap_update_bits(afe->regmap,
+ etdm_data.ck_en_sel_reg,
+ etdm_data.ck_en_sel_mask << etdm_data.ck_en_sel_shift,
+ 0x1 << etdm_data.ck_en_sel_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.fs_timing_reg,
+ etdm_data.fs_timing_mask << etdm_data.fs_timing_shift,
+ get_etdm_rate(rate) << etdm_data.fs_timing_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.relatch_en_sel_reg,
+ etdm_data.relatch_en_sel_mask << etdm_data.relatch_en_sel_shift,
+ get_etdm_inconn_rate(rate) << etdm_data.relatch_en_sel_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.use_afifo_reg,
+ etdm_data.use_afifo_mask << etdm_data.use_afifo_shift,
+ 0x0);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.afifo_mode_reg,
+ etdm_data.afifo_mode_mask << etdm_data.afifo_mode_shift,
+ 0x0);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.almost_end_ch_reg,
+ etdm_data.almost_end_ch_mask << etdm_data.almost_end_ch_shift,
+ 0x0);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.almost_end_bit_reg,
+ etdm_data.almost_end_bit_mask << etdm_data.almost_end_bit_shift,
+ 0x0);
+
+ if (is_etdm_in_pad_top(id)) {
+ regmap_update_bits(afe->regmap,
+ etdm_data.out2latch_time_reg,
+ etdm_data.out2latch_time_mask <<
+ etdm_data.out2latch_time_shift,
+ 0x6 << etdm_data.out2latch_time_shift);
+ } else {
+ regmap_update_bits(afe->regmap,
+ etdm_data.out2latch_time_reg,
+ etdm_data.out2latch_time_mask <<
+ etdm_data.out2latch_time_shift,
+ 0x4 << etdm_data.out2latch_time_shift);
+ }
+
+ if (id == DAI_I2SIN4) {
+ dev_dbg(afe->dev, "i2sin4, id: %d, fmt: %d, ch: %d, ip_mode: %d, sync: %d\n",
+ id, i2s_priv->format, channels, i2s_priv->ip_mode, i2s_priv->sync);
+
+ /* Fmt Mode: 0x00 i2s, 0x04 adsp_a, DSP_A mode for multi-channel */
+ regmap_update_bits(afe->regmap,
+ etdm_data.tdm_mode_reg,
+ etdm_data.tdm_mode_mask << etdm_data.tdm_mode_shift,
+ i2s_priv->format << etdm_data.tdm_mode_shift);
+
+ /* set etdm ch */
+ regmap_update_bits(afe->regmap,
+ etdm_data.ch_reg,
+ etdm_data.ch_mask << etdm_data.ch_shift,
+ (channels - 1) << etdm_data.ch_shift);
+
+ /* set etdm ip mode */
+ regmap_update_bits(afe->regmap,
+ etdm_data.ip_mode_reg,
+ etdm_data.ip_mode_mask << etdm_data.ip_mode_shift,
+ i2s_priv->ip_mode << etdm_data.ip_mode_shift);
+
+ /* set etdm sync */
+ regmap_update_bits(afe->regmap,
+ etdm_data.sync_reg,
+ etdm_data.sync_mask << etdm_data.sync_shift,
+ i2s_priv->sync << etdm_data.sync_shift);
+ } else {
+ /* default i2s */
+ regmap_update_bits(afe->regmap,
+ etdm_data.tdm_mode_reg,
+ etdm_data.tdm_mode_mask << etdm_data.tdm_mode_shift,
+ 0x0 << etdm_data.tdm_mode_shift);
+
+ /* set etdm sync */
+ regmap_update_bits(afe->regmap,
+ etdm_data.sync_reg,
+ etdm_data.sync_mask << etdm_data.sync_shift,
+ 0x0 << etdm_data.sync_shift);
+ }
+
+ /* APLL */
+ regmap_update_bits(afe->regmap,
+ etdm_data.relatch_domain_sel_reg,
+ etdm_data.relatch_domain_sel_mask <<
+ etdm_data.relatch_domain_sel_shift,
+ ETDM_RELATCH_SEL_APLL << etdm_data.relatch_domain_sel_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.bit_length_reg,
+ etdm_data.bit_length_mask << etdm_data.bit_length_shift,
+ get_etdm_lrck_width(format) << etdm_data.bit_length_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.word_length_reg,
+ etdm_data.word_length_mask << etdm_data.word_length_shift,
+ get_etdm_wlen(format) << etdm_data.word_length_shift);
+
+ /* ---etdm cowork --- */
+ regmap_update_bits(afe->regmap,
+ etdm_data.cowork_reg,
+ etdm_data.cowork_mask << etdm_data.cowork_shift,
+ etdm_data.cowork_val << etdm_data.cowork_shift);
+
+ /* i2s with pad top setting */
+ if (is_etdm_in_pad_top(id) && etdm_data.pad_top_ck_en_reg != 0) {
+ regmap_update_bits(afe->regmap,
+ etdm_data.pad_top_ck_en_reg,
+ etdm_data.pad_top_ck_en_mask <<
+ etdm_data.pad_top_ck_en_shift,
+ 0x1 << etdm_data.pad_top_ck_en_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.master_latch_reg,
+ etdm_data.master_latch_mask <<
+ etdm_data.master_latch_shift,
+ 0x0);
+ }
+ break;
+
+ case DAI_I2SOUT0:
+ case DAI_I2SOUT1:
+ case DAI_I2SOUT2:
+ case DAI_I2SOUT3:
+ case DAI_I2SOUT4:
+ case DAI_I2SOUT6:
+ /* ---etdm out --- */
+ regmap_update_bits(afe->regmap,
+ etdm_data.init_count_reg,
+ etdm_data.init_count_mask << etdm_data.init_count_shift,
+ 0x5 << etdm_data.init_count_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.init_point_reg,
+ etdm_data.init_point_mask << etdm_data.init_point_shift,
+ 0x6 << etdm_data.init_point_shift);
+
+ // clock speed > 22M need to set relatch time to avoid duplicate porint
+ if (rate * channels * (get_etdm_wlen(format) + 1) >= ETDM_22M_CLOCK_THRES &&
+ get_etdm_wlen(format) >= 2) {
+ regmap_update_bits(afe->regmap,
+ etdm_data.in2latch_time_reg,
+ etdm_data.in2latch_time_mask <<
+ etdm_data.in2latch_time_shift,
+ (get_etdm_wlen(format) - 2) <<
+ etdm_data.in2latch_time_shift);
+ } else {
+ regmap_update_bits(afe->regmap,
+ etdm_data.in2latch_time_reg,
+ etdm_data.in2latch_time_mask <<
+ etdm_data.in2latch_time_shift,
+ 0x6 << etdm_data.in2latch_time_shift);
+ }
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.lrck_reset_reg,
+ etdm_data.lrck_reset_mask << etdm_data.lrck_reset_shift,
+ 0x1 << etdm_data.lrck_reset_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.fs_timing_reg,
+ etdm_data.fs_timing_mask << etdm_data.fs_timing_shift,
+ get_etdm_rate(rate) << etdm_data.fs_timing_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.clk_source_reg,
+ etdm_data.clk_source_mask << etdm_data.clk_source_shift,
+ ETDM_CLK_SOURCE_APLL << etdm_data.clk_source_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.relatch_en_sel_reg,
+ etdm_data.relatch_en_sel_mask << etdm_data.relatch_en_sel_shift,
+ get_etdm_inconn_rate(rate) << etdm_data.relatch_en_sel_shift);
+
+ if (id == DAI_I2SOUT4) {
+ dev_dbg(afe->dev, "i2sout4, id: %d fmt: %d, ch: %d, sync: %d\n",
+ id, i2s_priv->format, channels, i2s_priv->sync);
+
+ /* Fmt Mode: 0x00 i2s, 0x04 adsp_a, DSP_A mode for multi-channel */
+ regmap_update_bits(afe->regmap,
+ etdm_data.tdm_mode_reg,
+ etdm_data.tdm_mode_mask << etdm_data.tdm_mode_shift,
+ i2s_priv->format << etdm_data.tdm_mode_shift);
+
+ /* set etdm ch */
+ regmap_update_bits(afe->regmap,
+ etdm_data.ch_reg,
+ etdm_data.ch_mask << etdm_data.ch_shift,
+ (channels - 1) << etdm_data.ch_shift);
+
+ /* set etdm sync */
+ regmap_update_bits(afe->regmap,
+ etdm_data.sync_reg,
+ etdm_data.sync_mask << etdm_data.sync_shift,
+ i2s_priv->sync << etdm_data.sync_shift);
+ } else {
+ regmap_update_bits(afe->regmap,
+ etdm_data.tdm_mode_reg,
+ etdm_data.tdm_mode_mask << etdm_data.tdm_mode_shift,
+ 0x0);
+ }
+
+ /* APLL */
+ regmap_update_bits(afe->regmap,
+ etdm_data.relatch_domain_sel_reg,
+ etdm_data.relatch_domain_sel_mask <<
+ etdm_data.relatch_domain_sel_shift,
+ ETDM_RELATCH_SEL_APLL << etdm_data.relatch_domain_sel_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.bit_length_reg,
+ etdm_data.bit_length_mask << etdm_data.bit_length_shift,
+ get_etdm_lrck_width(format) << etdm_data.bit_length_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.word_length_reg,
+ etdm_data.word_length_mask << etdm_data.word_length_shift,
+ get_etdm_wlen(format) << etdm_data.word_length_shift);
+
+ /* ---etdm cowork --- */
+ regmap_update_bits(afe->regmap,
+ etdm_data.cowork_reg,
+ etdm_data.cowork_mask << etdm_data.cowork_shift,
+ etdm_data.cowork_val << etdm_data.cowork_shift);
+
+ /* i2s with pad top setting */
+ if (is_etdm_in_pad_top(id) && etdm_data.pad_top_ck_en_reg != 0) {
+ regmap_update_bits(afe->regmap,
+ etdm_data.pad_top_ck_en_reg,
+ etdm_data.cowork_mask << etdm_data.pad_top_ck_en_shift,
+ 0x1 << etdm_data.pad_top_ck_en_shift);
+
+ regmap_update_bits(afe->regmap,
+ etdm_data.master_latch_reg,
+ etdm_data.master_latch_mask <<
+ etdm_data.master_latch_shift,
+ 0x0);
+ }
+ break;
+
+ default:
+ dev_err(afe->dev, "id %d not support\n", id);
+ return -EINVAL;
+ }
+
+ /* set share i2s */
+ if (i2s_priv && i2s_priv->share_i2s_id >= 0) {
+ i2sin_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id];
+ i2sin_priv->format = i2s_priv->format;
+ ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ return mtk_dai_i2s_config(afe, params, dai->id);
+}
+
+static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int apll;
+ int apll_rate;
+
+ if (dai->id >= MT8196_DAI_NUM || dai->id < 0 || dir != SND_SOC_CLOCK_OUT)
+ return -EINVAL;
+
+ i2s_priv = afe_priv->dai_priv[dai->id];
+ if (!i2s_priv)
+ return -EINVAL;
+
+ dev_dbg(afe->dev, "freq: %u\n", freq);
+
+ apll = mt8196_get_apll_by_rate(afe, freq);
+ apll_rate = mt8196_get_apll_rate(afe, apll);
+
+ if (freq > apll_rate || apll_rate % freq)
+ return -EINVAL;
+
+ i2s_priv->mclk_rate = freq;
+ i2s_priv->mclk_apll = apll;
+
+ if (i2s_priv->share_i2s_id > 0) {
+ struct mtk_afe_i2s_priv *share_i2s_priv;
+
+ share_i2s_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id];
+ if (!share_i2s_priv)
+ return -EINVAL;
+
+ share_i2s_priv->mclk_rate = i2s_priv->mclk_rate;
+ share_i2s_priv->mclk_apll = i2s_priv->mclk_apll;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ if (dai->id >= MT8196_DAI_NUM || dai->id < 0)
+ return -EINVAL;
+
+ i2s_priv = afe_priv->dai_priv[dai->id];
+ if (!i2s_priv)
+ return -EINVAL;
+
+ dev_dbg(afe->dev, "dai->id: %d, fmt: 0x%x\n", dai->id, fmt);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ i2s_priv->format = MTK_DAI_ETDM_FORMAT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ i2s_priv->format = MTK_DAI_ETDM_FORMAT_LJ;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ i2s_priv->format = MTK_DAI_ETDM_FORMAT_RJ;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ i2s_priv->format = MTK_DAI_ETDM_FORMAT_DSPA;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ i2s_priv->format = MTK_DAI_ETDM_FORMAT_DSPB;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_i2s_ops = {
+ .hw_params = mtk_dai_i2s_hw_params,
+ .set_sysclk = mtk_dai_i2s_set_sysclk,
+ .set_fmt = mtk_dai_i2s_set_fmt,
+};
+
+/* dai driver */
+#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_384000)
+#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S8 |\
+ SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define MT8196_I2S_DAI(_name, _id, max_ch, dir) \
+{ \
+ .name = #_name, \
+ .id = _id, \
+ .dir = { \
+ .stream_name = #_name, \
+ .channels_min = 1, \
+ .channels_max = max_ch, \
+ .rates = MTK_ETDM_RATES, \
+ .formats = MTK_ETDM_FORMATS, \
+ }, \
+ .ops = &mtk_dai_i2s_ops, \
+}
+
+static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = {
+ /* capture */
+ MT8196_I2S_DAI(I2SIN0, MT8196_DAI_I2S_IN0, 2, capture),
+ MT8196_I2S_DAI(I2SIN1, MT8196_DAI_I2S_IN1, 2, capture),
+ MT8196_I2S_DAI(I2SIN2, MT8196_DAI_I2S_IN2, 2, capture),
+ MT8196_I2S_DAI(I2SIN3, MT8196_DAI_I2S_IN3, 2, capture),
+ MT8196_I2S_DAI(I2SIN4, MT8196_DAI_I2S_IN4, 8, capture),
+ MT8196_I2S_DAI(I2SIN6, MT8196_DAI_I2S_IN6, 2, capture),
+ MT8196_I2S_DAI(FMI2S_MASTER, MT8196_DAI_FM_I2S_MASTER, 2, capture),
+ /* playback */
+ MT8196_I2S_DAI(I2SOUT0, MT8196_DAI_I2S_OUT0, 2, playback),
+ MT8196_I2S_DAI(I2SOUT1, MT8196_DAI_I2S_OUT1, 2, playback),
+ MT8196_I2S_DAI(I2SOUT2, MT8196_DAI_I2S_OUT2, 2, playback),
+ MT8196_I2S_DAI(I2SOUT3, MT8196_DAI_I2S_OUT3, 2, playback),
+ MT8196_I2S_DAI(I2SOUT4, MT8196_DAI_I2S_OUT4, 8, playback),
+ MT8196_I2S_DAI(I2SOUT6, MT8196_DAI_I2S_OUT6, 2, playback),
+};
+
+static const struct mtk_afe_i2s_priv mt8196_i2s_priv[DAI_I2S_NUM] = {
+ [DAI_I2SIN0] = {
+ .id = MT8196_DAI_I2S_IN0,
+ .mclk_id = MT8196_I2SIN0_MCK,
+ .share_property_name = "i2sin0-share",
+ .share_i2s_id = -1,
+ },
+ [DAI_I2SIN1] = {
+ .id = MT8196_DAI_I2S_IN1,
+ .mclk_id = MT8196_I2SIN1_MCK,
+ .share_property_name = "i2sin1-share",
+ .share_i2s_id = -1,
+ },
+ [DAI_I2SIN2] = {
+ .id = MT8196_DAI_I2S_IN2,
+ .mclk_id = MT8196_I2SIN0_MCK,
+ .share_property_name = "i2sin2-share",
+ .share_i2s_id = -1,
+ },
+ [DAI_I2SIN3] = {
+ .id = MT8196_DAI_I2S_IN3,
+ .mclk_id = MT8196_I2SIN0_MCK,
+ .share_property_name = "i2sin3-share",
+ .share_i2s_id = -1,
+ },
+ [DAI_I2SIN4] = {
+ .id = MT8196_DAI_I2S_IN4,
+ .mclk_id = MT8196_I2SIN0_MCK,
+ .share_property_name = "i2sin4-share",
+ .share_i2s_id = -1,
+ .sync = 0,
+ .ip_mode = 0,
+ },
+ [DAI_I2SIN6] = {
+ .id = MT8196_DAI_I2S_IN6,
+ .mclk_id = MT8196_I2SIN0_MCK,
+ .share_property_name = "i2sout6-share",
+ .share_i2s_id = -1,
+ },
+ [DAI_I2SOUT0] = {
+ .id = MT8196_DAI_I2S_OUT0,
+ .mclk_id = MT8196_I2SIN0_MCK,
+ .share_property_name = "i2sout0-share",
+ .share_i2s_id = MT8196_DAI_I2S_IN0,
+ },
+ [DAI_I2SOUT1] = {
+ .id = MT8196_DAI_I2S_OUT1,
+ .mclk_id = MT8196_I2SIN1_MCK,
+ .share_property_name = "i2sout1-share",
+ .share_i2s_id = MT8196_DAI_I2S_IN1,
+ },
+ [DAI_I2SOUT2] = {
+ .id = MT8196_DAI_I2S_OUT2,
+ .mclk_id = MT8196_I2SIN0_MCK,
+ .share_property_name = "i2sout2-share",
+ .share_i2s_id = MT8196_DAI_I2S_IN2,
+ },
+ [DAI_I2SOUT3] = {
+ .id = MT8196_DAI_I2S_OUT3,
+ .mclk_id = MT8196_I2SIN0_MCK,
+ .share_property_name = "i2sout3-share",
+ .share_i2s_id = MT8196_DAI_I2S_IN3,
+ },
+ [DAI_I2SOUT4] = {
+ .id = MT8196_DAI_I2S_OUT4,
+ .mclk_id = MT8196_I2SIN0_MCK,
+ .share_property_name = "i2sout4-share",
+ .share_i2s_id = MT8196_DAI_I2S_IN4,
+ .sync = 0,
+ },
+ [DAI_I2SOUT6] = {
+ .id = MT8196_DAI_I2S_OUT6,
+ .mclk_id = MT8196_I2SIN0_MCK,
+ .share_property_name = "i2sout6-share",
+ .share_i2s_id = MT8196_DAI_I2S_IN6,
+ },
+ [DAI_FMI2S_MASTER] = {
+ .id = MT8196_DAI_FM_I2S_MASTER,
+ .mclk_id = MT8196_FMI2S_MCK,
+ .share_property_name = "fmi2s-share",
+ .share_i2s_id = -1,
+ },
+};
+
+static int mt8196_dai_i2s_get_share(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ const struct device_node *of_node = afe->dev->of_node;
+
+ for (int i = 0; i < DAI_I2S_NUM; i++) {
+ const char *of_str;
+ struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[mt8196_i2s_priv[i].id];
+ const char *property_name = mt8196_i2s_priv[i].share_property_name;
+
+ if (of_property_read_string(of_node, property_name, &of_str))
+ continue;
+
+ i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str);
+ }
+
+ return 0;
+}
+
+static int init_i2s_priv_data(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ for (int i = 0; i < DAI_I2S_NUM; i++) {
+ int id = mt8196_i2s_priv[i].id;
+ size_t size = sizeof(struct mtk_afe_i2s_priv);
+
+ if (id >= MT8196_DAI_NUM || id < 0)
+ return -EINVAL;
+
+ i2s_priv = devm_kzalloc(afe->dev, size, GFP_KERNEL);
+ if (!i2s_priv)
+ return -ENOMEM;
+
+ memcpy(i2s_priv, &mt8196_i2s_priv[i], size);
+
+ afe_priv->dai_priv[id] = i2s_priv;
+ }
+
+ return 0;
+}
+
+int mt8196_dai_i2s_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+ int ret;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ dai->dai_drivers = mtk_dai_i2s_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver);
+
+ dai->controls = mtk_dai_i2s_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls);
+ dai->dapm_widgets = mtk_dai_i2s_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets);
+ dai->dapm_routes = mtk_dai_i2s_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes);
+
+ /* set all dai i2s private data */
+ ret = init_i2s_priv_data(afe);
+ if (ret)
+ return ret;
+
+ /* parse share i2s */
+ ret = mt8196_dai_i2s_get_share(afe);
+ if (ret)
+ return ret;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ return 0;
+}
--
2.45.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v7 06/10] ASoC: mediatek: mt8196: support TDM in platform driver
2025-08-22 12:52 [PATCH v7 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (3 preceding siblings ...)
2025-08-22 12:52 ` [PATCH v7 05/10] ASoC: mediatek: mt8196: support I2S " Darren.Ye
@ 2025-08-22 12:52 ` Darren.Ye
2025-08-22 12:52 ` [PATCH v7 07/10] ASoC: mediatek: mt8196: add " Darren.Ye
` (3 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Darren.Ye @ 2025-08-22 12:52 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 | 675 +++++++++++++++++++++
1 file changed, 675 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..b7aeee939d88
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-dai-tdm.c
@@ -0,0 +1,675 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI TDM Control
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+
+#include "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_8_BIT,
+ TDM_WLEN_16_BIT,
+ TDM_WLEN_24_BIT,
+ TDM_WLEN_32_BIT,
+};
+
+enum {
+ TDM_CHANNEL_BCK_16,
+ TDM_CHANNEL_BCK_24,
+ TDM_CHANNEL_BCK_32,
+};
+
+enum {
+ TDM_CHANNEL_NUM_2,
+ TDM_CHANNEL_NUM_4,
+ TDM_CHANNEL_NUM_8,
+};
+
+enum {
+ TDM_CH_START_O30_O31,
+ 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,
+};
+
+#define DPTX_CH_EN_MASK_2CH (0x3)
+#define DPTX_CH_EN_MASK_4CH (0xf)
+#define DPTX_CH_EN_MASK_6CH (0x3f)
+#define DPTX_CH_EN_MASK_8CH (0xff)
+
+static unsigned int get_tdm_wlen(snd_pcm_format_t format)
+{
+ return (snd_pcm_format_physical_width(format) / 8) - 1;
+}
+
+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(struct device *dev, 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:
+ dev_warn(dev, "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,
+ 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 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 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 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 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 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 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 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 mtk_dai_tdm_controls[] = {
+ SOC_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum),
+ SOC_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum),
+ SOC_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum),
+ SOC_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum),
+ SOC_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum),
+ SOC_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum),
+ SOC_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum),
+ SOC_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum),
+};
+
+static const char *const tdm_out_demux_texts[] = {
+ "NONE", "TDMOUT", "DPTXOUT",
+};
+
+static SOC_ENUM_SINGLE_DECL(tdm_out_demux_enum,
+ SND_SOC_NOPM,
+ 0,
+ tdm_out_demux_texts);
+static const struct snd_kcontrol_new tdm_out_demux_control =
+ SOC_DAPM_ENUM("TDM DEMUX ROUTE", tdm_out_demux_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 const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
+ SND_SOC_DAPM_DEMUX("TDM_DEMUX", SND_SOC_NOPM, 0, 0,
+ &tdm_out_demux_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,
+ AUDIO_TOP_CON2, PDN_TDM_OUT_SFT, 1,
+ NULL, 0),
+};
+
+static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(sink->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(sink->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[] = {
+ {"TDM_DEMUX", NULL, "HDMI"},
+
+ {"TDM", "TDMOUT", "TDM_DEMUX"},
+ {"TDM", NULL, "TDM_BCK"},
+ {"TDM", NULL, "TDM_CG"},
+
+ {"TDM_DPTX", "DPTXOUT", "TDM_DEMUX"},
+ {"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},
+};
+
+/* 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_dbg(afe->dev, "id %d, rate %d, ch %d, fmt %d, mclk %d, bck %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(afe->dev, 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;
+
+ dai->dai_drivers = mtk_dai_tdm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
+ dai->controls = mtk_dai_tdm_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_dai_tdm_controls);
+ 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;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ 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] 11+ messages in thread
* [PATCH v7 07/10] ASoC: mediatek: mt8196: add platform driver
2025-08-22 12:52 [PATCH v7 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (4 preceding siblings ...)
2025-08-22 12:52 ` [PATCH v7 06/10] ASoC: mediatek: mt8196: support TDM " Darren.Ye
@ 2025-08-22 12:52 ` Darren.Ye
2025-08-22 12:52 ` [PATCH v7 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE Darren.Ye
` (2 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Darren.Ye @ 2025-08-22 12:52 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 | 12 +
sound/soc/mediatek/mt8196/mt8196-afe-pcm.c | 2497 ++++++++++++++++++++
4 files changed, 2520 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 10ca8bccabdd..7003d71b847c 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -322,4 +322,14 @@ config SND_SOC_MT8365_MT6357
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".
+
endmenu
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..0c6a018190a2
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# platform driver
+snd-soc-mt8196-afe-objs += \
+ mt8196-afe-pcm.o \
+ mt8196-afe-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..749df0625e25
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
@@ -0,0 +1,2497 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek ALSA SoC AFE platform driver for 8196
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include "mt8196-afe-clk.h"
+#include "mt8196-afe-common.h"
+#include "mt8196-interconnection.h"
+
+#include "../common/mtk-afe-fe-dai.h"
+#include "../common/mtk-afe-platform-driver.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_err(dev, "rate %u invalid, use %d!!!\n",
+ rate, MTK_AFE_IPM2P0_RATE_48K);
+ return MTK_AFE_IPM2P0_RATE_48K;
+ }
+}
+
+static int mt8196_set_cm(struct mtk_base_afe *afe, int id,
+ bool update, bool swap, unsigned int ch)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ unsigned int rate = afe_priv->cm_rate[id];
+ unsigned int rate_val = mt8196_rate_transform(afe->dev, rate);
+ unsigned int update_val = update ? ((((26000000 / rate) - 10) / (ch / 2)) - 1) : 0x64;
+ int reg = AFE_CM0_CON0 + 0x10 * id;
+
+ dev_dbg(afe->dev, "CM%d, rate %d, update %d, swap %d, ch %d\n",
+ id, rate, update, swap, ch);
+
+ /* update cnt */
+ regmap_update_bits(afe->regmap, reg,
+ AFE_CM_UPDATE_CNT_MASK << AFE_CM_UPDATE_CNT_SFT,
+ update_val << AFE_CM_UPDATE_CNT_SFT);
+
+ /* rate */
+ regmap_update_bits(afe->regmap, reg,
+ AFE_CM_1X_EN_SEL_FS_MASK << AFE_CM_1X_EN_SEL_FS_SFT,
+ rate_val << AFE_CM_1X_EN_SEL_FS_SFT);
+
+ /* ch num */
+ ch = ch - 1;
+ 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)
+{
+ return regmap_update_bits(afe->regmap,
+ AFE_CM0_CON0 + 0x10 * id,
+ AFE_CM_BYPASS_MODE_MASK << AFE_CM_BYPASS_MODE_SFT,
+ en << AFE_CM_BYPASS_MODE_SFT);
+}
+
+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);
+
+ if (memif_num == MT8196_MEMIF_VUL_CM0)
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16);
+
+ snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware);
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ dev_warn(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+
+ /* dynamic allocate irq to memif */
+ if (memif->irq_usage < 0) {
+ int irq_id = mtk_dynamic_irq_acquire(afe);
+
+ if (irq_id != afe->irqs_size) {
+ /* link */
+ memif->irq_usage = irq_id;
+ } else {
+ dev_err(afe->dev, "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 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;
+
+ 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;
+ int cm;
+
+ 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);
+ }
+
+ 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;
+ }
+
+ afe_priv->cm_rate[cm] = params_rate(params);
+
+ 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);
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->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;
+ unsigned int tmp_reg;
+ int fs;
+ int ret;
+
+ dev_dbg(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.
+ * the context of this ops triger is atmoic, so it cannot sleep.
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ if ((runtime->period_size * 1000) / rate <= 10)
+ udelay(300);
+
+ 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, 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, if the register read as one, there is no need to write
+ * one to clear operaton.
+ */
+ 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;
+ unsigned int rate_reg;
+
+ if (!component)
+ return -EINVAL;
+
+ afe = snd_soc_component_get_drvdata(component);
+ if (!afe)
+ return -EINVAL;
+
+ rate_reg = mt8196_rate_transform(afe->dev, rate);
+
+ 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(_name, _id, max_ch, dir) \
+{ \
+ .name = #_name, \
+ .id = _id, \
+ .dir = { \
+ .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(DL0, MT8196_MEMIF_DL0, 2, playback),
+ MT8196_FE_DAI(DL1, MT8196_MEMIF_DL1, 2, playback),
+ MT8196_FE_DAI(DL2, MT8196_MEMIF_DL2, 2, playback),
+ MT8196_FE_DAI(DL3, MT8196_MEMIF_DL3, 2, playback),
+ MT8196_FE_DAI(DL4, MT8196_MEMIF_DL4, 2, playback),
+ MT8196_FE_DAI(DL5, MT8196_MEMIF_DL5, 2, playback),
+ MT8196_FE_DAI(DL6, MT8196_MEMIF_DL6, 2, playback),
+ MT8196_FE_DAI(DL7, MT8196_MEMIF_DL7, 2, playback),
+ MT8196_FE_DAI(DL8, MT8196_MEMIF_DL8, 2, playback),
+ MT8196_FE_DAI(DL23, MT8196_MEMIF_DL23, 2, playback),
+ MT8196_FE_DAI(DL24, MT8196_MEMIF_DL24, 2, playback),
+ MT8196_FE_DAI(DL25, MT8196_MEMIF_DL25, 2, playback),
+ MT8196_FE_DAI(DL26, MT8196_MEMIF_DL26, 2, playback),
+ MT8196_FE_DAI(DL_4CH, MT8196_MEMIF_DL_4CH, 4, playback),
+ MT8196_FE_DAI(DL_24CH, MT8196_MEMIF_DL_24CH, 8, playback),
+ MT8196_FE_DAI(HDMI, MT8196_MEMIF_HDMI, 8, playback),
+ /* Capture */
+ MT8196_FE_DAI(UL0, MT8196_MEMIF_VUL0, 2, capture),
+ MT8196_FE_DAI(UL1, MT8196_MEMIF_VUL1, 2, capture),
+ MT8196_FE_DAI(UL2, MT8196_MEMIF_VUL2, 2, capture),
+ MT8196_FE_DAI(UL3, MT8196_MEMIF_VUL3, 2, capture),
+ MT8196_FE_DAI(UL4, MT8196_MEMIF_VUL4, 2, capture),
+ MT8196_FE_DAI(UL5, MT8196_MEMIF_VUL5, 2, capture),
+ MT8196_FE_DAI(UL6, MT8196_MEMIF_VUL6, 2, capture),
+ MT8196_FE_DAI(UL7, MT8196_MEMIF_VUL7, 2, capture),
+ MT8196_FE_DAI(UL8, MT8196_MEMIF_VUL8, 2, capture),
+ MT8196_FE_DAI(UL9, MT8196_MEMIF_VUL9, 16, capture),
+ MT8196_FE_DAI(UL10, MT8196_MEMIF_VUL10, 2, capture),
+ MT8196_FE_DAI(UL24, MT8196_MEMIF_VUL24, 2, capture),
+ MT8196_FE_DAI(UL25, MT8196_MEMIF_VUL25, 2, capture),
+ MT8196_FE_DAI(UL26, MT8196_MEMIF_VUL26, 2, capture),
+ MT8196_FE_DAI(UL_CM0, MT8196_MEMIF_VUL_CM0, 8, capture),
+ MT8196_FE_DAI(UL_CM1, MT8196_MEMIF_VUL_CM1, 16, capture),
+ MT8196_FE_DAI(UL_CM2, MT8196_MEMIF_VUL_CM2, 32, capture),
+ MT8196_FE_DAI(UL_ETDM_IN0, MT8196_MEMIF_ETDM_IN0, 2, capture),
+ MT8196_FE_DAI(UL_ETDM_IN1, MT8196_MEMIF_ETDM_IN1, 2, capture),
+ MT8196_FE_DAI(UL_ETDM_IN2, MT8196_MEMIF_ETDM_IN2, 2, capture),
+ MT8196_FE_DAI(UL_ETDM_IN3, MT8196_MEMIF_ETDM_IN3, 2, capture),
+ MT8196_FE_DAI(UL_ETDM_IN4, MT8196_MEMIF_ETDM_IN4, 2, capture),
+ MT8196_FE_DAI(UL_ETDM_IN6, MT8196_MEMIF_ETDM_IN6, 2, capture),
+};
+
+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, false);
+ mt8196_set_cm(afe, CM0, true, false, channels);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ PDN_CM0_MASK_SFT, 0 << PDN_CM0_SFT);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mt8196_enable_cm_bypass(afe, CM0, true);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ PDN_CM0_MASK_SFT, 1 << PDN_CM0_SFT);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int ul_cm1_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct 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, false);
+ mt8196_set_cm(afe, CM1, true, false, channels);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ PDN_CM1_MASK_SFT, 0 << PDN_CM1_SFT);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mt8196_enable_cm_bypass(afe, CM1, true);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ PDN_CM1_MASK_SFT, 1 << PDN_CM1_SFT);
+ 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, false);
+ mt8196_set_cm(afe, CM2, true, false, channels);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ PDN_CM2_MASK_SFT, 0 << PDN_CM2_SFT);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mt8196_enable_cm_bypass(afe, CM2, true);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ PDN_CM2_MASK_SFT, 1 << PDN_CM2_SFT);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * dma widget & routes
+ * The mixer controls and routes are by no means fully implemented,
+ * only the ones that are intended to be used are, as other wise a fully
+ * interconnected switch bar mixer would introduce way too many unused
+ * controls.
+ */
+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[] = {
+ "UL8_2CH_PATH",
+ "CM0_8CH_PATH",
+};
+
+static const char * const cm1_mux_map[] = {
+ "UL9_2CH_PATH",
+ "CM1_16CH_PATH",
+};
+
+static const char * const cm2_mux_map[] = {
+ "UL10_2CH_PATH",
+ "CM2_32CH_PATH",
+};
+
+static SOC_ENUM_SINGLE_DECL(ul_cm0_mux_map_enum, AFE_CM0_CON0,
+ AFE_CM0_OUTPUT_MUX_SFT, cm0_mux_map);
+
+static SOC_ENUM_SINGLE_DECL(ul_cm1_mux_map_enum, AFE_CM1_CON0,
+ AFE_CM1_OUTPUT_MUX_SFT, cm1_mux_map);
+
+static SOC_ENUM_SINGLE_DECL(ul_cm2_mux_map_enum, AFE_CM2_CON0,
+ AFE_CM2_OUTPUT_MUX_SFT, cm2_mux_map);
+
+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),
+
+ /* dynamic pinctrl */
+ SND_SOC_DAPM_PINCTRL("I2S3_PIN", "aud-gpio-i2s3-on", "aud-gpio-i2s3-off"),
+ SND_SOC_DAPM_PINCTRL("I2S4_PIN", "aud-gpio-i2s4-on", "aud-gpio-i2s4-off"),
+ SND_SOC_DAPM_PINCTRL("I2S6_PIN", "aud-gpio-i2s6-on", "aud-gpio-i2s6-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_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"},
+
+ {"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"},
+
+ {"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"},
+
+ {"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", 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", 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", 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"},
+
+ /* Audio Pin */
+ {"I2SOUT4", NULL, "I2S4_PIN"},
+ {"I2SIN4", NULL, "I2S4_PIN"},
+ {"I2SOUT6", NULL, "I2S6_PIN"},
+ {"I2SIN6", NULL, "I2S6_PIN"},
+ {"I2SOUT3", NULL, "I2S3_PIN"},
+ {"I2SIN3", NULL, "I2S3_PIN"},
+ {"AP DMIC Capture", NULL, "AP_DMIC0_PIN"},
+ {"AP DMIC CH34 Capture", NULL, "AP_DMIC1_PIN"},
+};
+
+#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 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_CUSTOM_IRQ_MCU_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;
+ u32 status;
+ u32 status_mcu;
+ u32 mcu_en;
+ u32 cus_status;
+ u32 cus_status_mcu;
+ u32 cus_mcu_en;
+ u32 tmp_reg;
+ int ret, cus_ret;
+ int i;
+ struct timespec64 ts64;
+ u64 t1, t2;
+ /* one interrupt period = 5ms */
+ const u64 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_err(afe->dev, "ret %d, sat 0x%x, en 0x%x,csat 0x%x, cen 0x%x\n",
+ ret, status, mcu_en, cus_status_mcu, cus_mcu_en);
+ return IRQ_NONE;
+ }
+
+ ktime_get_ts64(&ts64);
+ t1 = ktime_get_ns();
+
+ 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 & BIT(irq->irq_data->id))
+ snd_pcm_period_elapsed(memif->substream);
+ } else {
+ if (status_mcu & BIT(irq->irq_data->id))
+ snd_pcm_period_elapsed(memif->substream);
+ }
+ }
+
+ ktime_get_ts64(&ts64);
+ t2 = ktime_get_ns();
+ t2 = t2 - t1; /* in ns (10^9) */
+
+ if (t2 > timeout_limit)
+ dev_warn(afe->dev, "IRQ handler exceeded time limit by %llu ns\n",
+ t2 - timeout_limit);
+
+ /* clear irq */
+ for (i = 0; i < MT8196_IRQ_NUM; ++i) {
+ /* cus_status_mcu only bit0 is used for TDM */
+ if ((status_mcu & BIT(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;
+ unsigned int tmp_reg;
+ int ret, 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_warn(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)
+{
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+ if (component) {
+ /* enable clock for regcache get default value from hw */
+ pm_runtime_get_sync(afe->dev);
+ mtk_afe_add_sub_dai_control(component);
+ pm_runtime_put_sync(afe->dev);
+ }
+ return 0;
+}
+
+static int 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->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 const struct reg_sequence mt8196_cg_patch[] = {
+ { AUDIO_TOP_CON4, 0x361c },
+};
+
+static int mt8196_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+ int ret, i;
+ unsigned int tmp_reg;
+ 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", afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "could not request_irq for Afe_ISR_Handle\n");
+
+ /* init sub_dais */
+ INIT_LIST_HEAD(&afe->sub_dais);
+
+ for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+ ret = dai_register_cbs[i](afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "dai register i %d fail\n", i);
+ }
+
+ /* init dai_driver and component_driver */
+ ret = mtk_afe_combine_sub_dai(afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n");
+
+ /* 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. Registering it as a syscore device ensure
+ * the proper power-on sequence of the AFE device.
+ */
+ 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);
+
+ ret = regmap_register_patch(afe->regmap, mt8196_cg_patch,
+ ARRAY_SIZE(mt8196_cg_patch));
+ if (ret < 0) {
+ dev_err(dev, "Failed to apply cg patch\n");
+ goto err_pm_disable;
+ }
+
+ regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &tmp_reg);
+ regmap_write(afe->regmap, AFE_IRQ_MCU_EN, 0xffffffff);
+ regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &tmp_reg);
+
+ pm_runtime_put_sync(dev);
+
+ regcache_cache_only(afe->regmap, true);
+ regcache_mark_dirty(afe->regmap);
+
+ /* register component */
+ ret = devm_snd_soc_register_component(dev,
+ &mt8196_afe_component,
+ afe->dai_drivers,
+ afe->num_dai_drivers);
+ if (ret) {
+ dev_err(dev, "afe component err\n");
+ goto err_pm_disable;
+ }
+
+ return 0;
+
+err_pm_disable:
+ pm_runtime_put_sync(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_put_sync(dev);
+ if (!pm_runtime_status_suspended(dev))
+ mt8196_afe_runtime_suspend(dev);
+
+ mt8196_afe_disable_main_clock(afe);
+ /* disable afe clock */
+ mt8196_afe_disable_reg_rw_clk(afe);
+}
+
+static const struct of_device_id mt8196_afe_pcm_dt_match[] = {
+ { .compatible = "mediatek,mt8196-afe", },
+ { /* sentinel */ },
+};
+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,
+ .pm = &mt8196_afe_pm_ops,
+ },
+ .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] 11+ messages in thread
* [PATCH v7 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE
2025-08-22 12:52 [PATCH v7 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (5 preceding siblings ...)
2025-08-22 12:52 ` [PATCH v7 07/10] ASoC: mediatek: mt8196: add " Darren.Ye
@ 2025-08-22 12:52 ` Darren.Ye
2025-08-22 12:52 ` [PATCH v7 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825 Darren.Ye
2025-08-22 12:52 ` [PATCH v7 10/10] ASoC: dt-bindings: mediatek,mt8196-nau8825: Add audio sound card Darren.Ye
8 siblings, 0 replies; 11+ messages in thread
From: Darren.Ye @ 2025-08-22 12:52 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, Krzysztof Kozlowski
From: Darren Ye <darren.ye@mediatek.com>
Add mt8196 audio AFE.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
.../bindings/sound/mediatek,mt8196-afe.yaml | 113 ++++++++++++++++++
1 file changed, 113 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..949f8622baf9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
@@ -0,0 +1,113 @@
+# 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
+
+ power-domains:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: mux for audio intbus
+ - description: mux for audio engen1
+ - description: mux for audio engen2
+ - description: mux for audio h
+ - description: audio apll1 clock
+ - description: audio apll2 clock
+ - description: audio 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 adsp clock
+
+ clock-names:
+ items:
+ - const: top_aud_intbus
+ - const: top_aud_eng1
+ - const: top_aud_eng2
+ - const: top_aud_h
+ - const: apll1
+ - const: apll2
+ - const: apll12_div_i2sin0
+ - const: apll12_div_i2sin1
+ - const: apll12_div_fmi2s
+ - const: apll12_div_tdmout_m
+ - const: apll12_div_tdmout_b
+ - const: top_adsp
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - memory-region
+ - power-domains
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ afe@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>;
+ power-domains = <&scpsys 14>; //MT8196_POWER_DOMAIN_AUDIO
+ pinctrl-names = "default";
+ pinctrl-0 = <&aud_pins_default>;
+ 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 0>, //CLK_VLP_CK_VLP_APLL1
+ <&vlp_cksys_clk 1>, //CLK_VLP_CK_VLP_APLL2
+ <&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 45>; //CLK_CK_ADSP_SEL
+ clock-names = "top_aud_intbus",
+ "top_aud_eng1",
+ "top_aud_eng2",
+ "top_aud_h",
+ "apll1",
+ "apll2",
+ "apll12_div_i2sin0",
+ "apll12_div_i2sin1",
+ "apll12_div_fmi2s",
+ "apll12_div_tdmout_m",
+ "apll12_div_tdmout_b",
+ "top_adsp";
+ };
+ };
+
+...
--
2.45.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v7 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825
2025-08-22 12:52 [PATCH v7 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (6 preceding siblings ...)
2025-08-22 12:52 ` [PATCH v7 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE Darren.Ye
@ 2025-08-22 12:52 ` Darren.Ye
2025-08-26 2:47 ` kernel test robot
2025-08-22 12:52 ` [PATCH v7 10/10] ASoC: dt-bindings: mediatek,mt8196-nau8825: Add audio sound card Darren.Ye
8 siblings, 1 reply; 11+ messages in thread
From: Darren.Ye @ 2025-08-22 12:52 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 | 20 +
sound/soc/mediatek/mt8196/Makefile | 2 +
sound/soc/mediatek/mt8196/mt8196-nau8825.c | 868 +++++++++++++++++++++
3 files changed, 890 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-nau8825.c
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 7003d71b847c..2889600652a0 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -332,4 +332,24 @@ config SND_SOC_MT8196
Select Y if you have such device.
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".
+
endmenu
diff --git a/sound/soc/mediatek/mt8196/Makefile b/sound/soc/mediatek/mt8196/Makefile
index 0c6a018190a2..91de200071d7 100644
--- a/sound/soc/mediatek/mt8196/Makefile
+++ b/sound/soc/mediatek/mt8196/Makefile
@@ -10,3 +10,5 @@ snd-soc-mt8196-afe-objs += \
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..e6184c36415e
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-nau8825.c
@@ -0,0 +1,868 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8196-nau8825.c -- mt8196 nau8825 ALSA SoC machine driver
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+
+#include "mt8196-afe-common.h"
+
+#include "../../codecs/nau8825.h"
+#include "../../codecs/rt5682s.h"
+
+#include "../common/mtk-soc-card.h"
+#include "../common/mtk-dsp-sof-common.h"
+#include "../common/mtk-soundcard-driver.h"
+#include "../common/mtk-afe-platform-driver.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_AVOUT,
+ },
+};
+
+static struct snd_soc_jack_pin mt8196_hdmi_jack_pins[] = {
+ {
+ .pin = "HDMI",
+ .mask = SND_JACK_AVOUT,
+ },
+};
+
+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_SPK("Ext Spk", 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[] = {
+ /* SOF Uplink */
+ 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),
+
+ /*
+ * SOF Downlink
+ * the widgets on the machine driver cannot use the parameter with kcontrol
+ * because the widget domain is its platform driver. so sof downlink route
+ * is written in the i2s dai driver.
+ */
+};
+
+static const struct snd_soc_dapm_route mt8196_nau8825_card_routes[] = {
+ /* SOF Uplink */
+ {"SOF_DMA_UL0", NULL, "UL0_CH1"},
+ {"SOF_DMA_UL0", NULL, "UL0_CH2"},
+ /* SOF Uplink */
+ {"SOF_DMA_UL1", NULL, "UL1_CH1"},
+ {"SOF_DMA_UL1", NULL, "UL1_CH2"},
+ /* SOF Uplink */
+ {"SOF_DMA_UL2", NULL, "UL2_CH1"},
+ {"SOF_DMA_UL2", NULL, "UL2_CH2"},
+};
+
+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_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_CBC_CFC
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_nau8825_i2s_ops,
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8196_hw_params_fixup,
+ SND_SOC_DAILINK_REG(i2sin6),
+ },
+ {
+ .name = "I2SOUT4_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+ | 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_hw_params_fixup,
+ SND_SOC_DAILINK_REG(i2sout4),
+ },
+ {
+ .name = "I2SOUT6_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_nau8825_i2s_ops,
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8196_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_CBC_CFC
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_dptx_ops,
+ .be_hw_params_fixup = mt8196_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_CBC_CFC
+ | 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_AVOUT,
+ 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_AVOUT,
+ 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] 11+ messages in thread
* [PATCH v7 10/10] ASoC: dt-bindings: mediatek,mt8196-nau8825: Add audio sound card
2025-08-22 12:52 [PATCH v7 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (7 preceding siblings ...)
2025-08-22 12:52 ` [PATCH v7 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825 Darren.Ye
@ 2025-08-22 12:52 ` Darren.Ye
8 siblings, 0 replies; 11+ messages in thread
From: Darren.Ye @ 2025-08-22 12:52 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, Krzysztof Kozlowski
From: Darren Ye <darren.ye@mediatek.com>
Add soundcard bindings for the MT8196 SoC with the NAU8825 audio codec.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
.../sound/mediatek,mt8196-nau8825.yaml | 100 ++++++++++++++++++
1 file changed, 100 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..83350faa1e29
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8196-nau8825.yaml
@@ -0,0 +1,100 @@
+# 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
+
+ mediatek,platform:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of MT8188 ASoC platform.
+
+patternProperties:
+ "^dai-link-[0-9]+$":
+ type: object
+ description:
+ Container for dai-link level properties and CODEC sub-nodes.
+
+ properties:
+ link-name:
+ description:
+ This property corresponds to the name of the BE dai-link to which
+ we are going to update parameters in this node.
+ items:
+ enum:
+ - TDM_DPTX_BE
+ - 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.
+ enum:
+ - cpu
+ - codec
+
+ additionalProperties: false
+
+ required:
+ - link-name
+
+required:
+ - compatible
+ - mediatek,platform
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ sound {
+ compatible = "mediatek,mt8196-nau8825-sound";
+ model = "mt8196-nau8825";
+ mediatek,platform = <&afe>;
+ 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] 11+ messages in thread
* Re: [PATCH v7 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825
2025-08-22 12:52 ` [PATCH v7 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825 Darren.Ye
@ 2025-08-26 2:47 ` kernel test robot
0 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2025-08-26 2:47 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.17-rc3 next-20250825]
[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/20250822-210108
base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
patch link: https://lore.kernel.org/r/20250822125301.12333-10-darren.ye%40mediatek.com
patch subject: [PATCH v7 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825
config: arm64-randconfig-r131-20250826 (https://download.01.org/0day-ci/archive/20250826/202508261004.7adPXk4m-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project d26ea02060b1c9db751d188b2edb0059a9eb273d)
reproduce: (https://download.01.org/0day-ci/archive/20250826/202508261004.7adPXk4m-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/202508261004.7adPXk4m-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> sound/soc/mediatek/mt8196/mt8196-nau8825.c:183:33: sparse: sparse: incorrect type in argument 3 (different base types) @@ expected unsigned int to @@ got restricted snd_pcm_format_t [usertype] @@
sound/soc/mediatek/mt8196/mt8196-nau8825.c:183:33: sparse: expected unsigned int to
sound/soc/mediatek/mt8196/mt8196-nau8825.c:183:33: sparse: got restricted snd_pcm_format_t [usertype]
vim +183 sound/soc/mediatek/mt8196/mt8196-nau8825.c
175
176 static int mt8196_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
177 struct snd_pcm_hw_params *params)
178 {
179 dev_info(rtd->dev, "fix format to 32bit\n");
180
181 /* fix BE i2s format to 32bit, clean param mask first */
182 snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
> 183 0, SNDRV_PCM_FORMAT_LAST);
184
185 params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
186 return 0;
187 }
188
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-08-26 2:50 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-22 12:52 [PATCH v7 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
2025-08-22 12:52 ` [PATCH v7 01/10] ASoC: mediatek: common: modify mtk afe platform driver for mt8196 Darren.Ye
2025-08-22 12:52 ` [PATCH v7 03/10] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
2025-08-22 12:52 ` [PATCH v7 04/10] ASoC: mediatek: mt8196: support ADDA in platform driver Darren.Ye
2025-08-22 12:52 ` [PATCH v7 05/10] ASoC: mediatek: mt8196: support I2S " Darren.Ye
2025-08-22 12:52 ` [PATCH v7 06/10] ASoC: mediatek: mt8196: support TDM " Darren.Ye
2025-08-22 12:52 ` [PATCH v7 07/10] ASoC: mediatek: mt8196: add " Darren.Ye
2025-08-22 12:52 ` [PATCH v7 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE Darren.Ye
2025-08-22 12:52 ` [PATCH v7 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825 Darren.Ye
2025-08-26 2:47 ` kernel test robot
2025-08-22 12:52 ` [PATCH v7 10/10] ASoC: dt-bindings: mediatek,mt8196-nau8825: Add audio sound card 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).