This series of patches adds support for Mediatek AFE of MT8188 SoC.
Patches are based on broonie tree "for-next" branch.
Changes since v2:
- drop CLK_IGNORE_UNUSED flag
- include bitfield.h to reslove the issue reported by kernel test robot
- rename mt8188-afe-pcm.yaml to mt8188-afe.yaml
- refine dt-binding files based on reviewer's suggestions
Changes since v1:
- remove bus protection functions in case of unmerged dependency problem
- replace some bit operation macro with FIELD_PREP
- simplify register control by regmap_set_bits and regmap_clear_bits
- fix dt-binding errors
- rename compatible string for recognition
Trevor Wu (12):
ASoC: mediatek: common: add SMC ops and SMC CMD
ASoC: mediatek: mt8188: add common header
ASoC: mediatek: mt8188: support audsys clock
ASoC: mediatek: mt8188: support adda in platform driver
ASoC: mediatek: mt8188: support etdm in platform driver
ASoC: mediatek: mt8188: support pcmif in platform driver
ASoC: mediatek: mt8188: support audio clock control
ASoC: mediatek: mt8188: add platform driver
ASoC: mediatek: mt8188: add control for timing select
dt-bindings: mediatek: mt8188: add audio afe document
ASoC: mediatek: mt8188: add machine driver with mt6359
dt-bindings: mediatek: mt8188: add mt8188-mt6359 document
.../devicetree/bindings/sound/mt8188-afe.yaml | 196 +
.../bindings/sound/mt8188-mt6359.yaml | 60 +
sound/soc/mediatek/Kconfig | 23 +
sound/soc/mediatek/Makefile | 1 +
sound/soc/mediatek/common/mtk-base-afe.h | 19 +
sound/soc/mediatek/mt8188/Makefile | 15 +
sound/soc/mediatek/mt8188/mt8188-afe-clk.c | 656 ++++
sound/soc/mediatek/mt8188/mt8188-afe-clk.h | 114 +
sound/soc/mediatek/mt8188/mt8188-afe-common.h | 151 +
sound/soc/mediatek/mt8188/mt8188-afe-pcm.c | 3359 +++++++++++++++++
sound/soc/mediatek/mt8188/mt8188-audsys-clk.c | 205 +
sound/soc/mediatek/mt8188/mt8188-audsys-clk.h | 15 +
.../soc/mediatek/mt8188/mt8188-audsys-clkid.h | 83 +
sound/soc/mediatek/mt8188/mt8188-dai-adda.c | 632 ++++
sound/soc/mediatek/mt8188/mt8188-dai-etdm.c | 2591 +++++++++++++
sound/soc/mediatek/mt8188/mt8188-dai-pcm.c | 367 ++
sound/soc/mediatek/mt8188/mt8188-mt6359.c | 808 ++++
sound/soc/mediatek/mt8188/mt8188-reg.h | 3180 ++++++++++++++++
18 files changed, 12475 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/mt8188-afe.yaml
create mode 100644 Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
create mode 100644 sound/soc/mediatek/mt8188/Makefile
create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-clk.c
create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-clk.h
create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-common.h
create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h
create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-adda.c
create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-pcm.c
create mode 100644 sound/soc/mediatek/mt8188/mt8188-mt6359.c
create mode 100644 sound/soc/mediatek/mt8188/mt8188-reg.h
--
2.18.0
Add document for mt8188 board with mt6359.
Signed-off-by: Trevor Wu <[email protected]>
---
.../bindings/sound/mt8188-mt6359.yaml | 60 +++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
diff --git a/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml b/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
new file mode 100644
index 000000000000..eac1c87b693a
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mt8188-mt6359.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT8188 ASoC sound card
+
+maintainers:
+ - Trevor Wu <[email protected]>
+
+properties:
+ compatible:
+ const: mediatek,mt8188-mt6359-evb
+
+ model:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: User specified audio sound card name
+
+ audio-routing:
+ $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+ description:
+ A list of the connections between audio components. Each entry is a
+ sink/source pair of strings. Valid names could be the input or output
+ widgets of audio components, power supplies, MicBias of codec and the
+ software switch.
+
+ mediatek,platform:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of MT8188 ASoC platform.
+
+ mediatek,dptx-codec:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of MT8188 Display Port Tx codec node.
+
+ mediatek,hdmi-codec:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of MT8188 HDMI codec node.
+
+additionalProperties: false
+
+required:
+ - compatible
+ - mediatek,platform
+
+examples:
+ - |
+
+ sound: mt8188-sound {
+ compatible = "mediatek,mt8188-mt6359-evb";
+ mediatek,platform = <&afe>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&aud_pins_default>;
+ audio-routing =
+ "Headphone", "Headphone L",
+ "Headphone", "Headphone R",
+ "AIN1", "Headset Mic";
+ };
+
+...
--
2.18.0
Add audio clock wrapper and audio tuner control.
Signed-off-by: Trevor Wu <[email protected]>
---
sound/soc/mediatek/mt8188/mt8188-afe-clk.c | 656 +++++++++++++++++++++
sound/soc/mediatek/mt8188/mt8188-afe-clk.h | 114 ++++
2 files changed, 770 insertions(+)
create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-clk.c
create mode 100644 sound/soc/mediatek/mt8188/mt8188-afe-clk.h
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
new file mode 100644
index 000000000000..67fecc5eeaf9
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
@@ -0,0 +1,656 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8188-afe-clk.c -- MediaTek 8188 afe clock ctrl
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Bicycle Tsai <[email protected]>
+ * Trevor Wu <[email protected]>
+ * Chun-Chia Chiu <[email protected]>
+ */
+
+#include <linux/clk.h>
+
+#include "mt8188-afe-common.h"
+#include "mt8188-afe-clk.h"
+#include "mt8188-audsys-clk.h"
+#include "mt8188-reg.h"
+
+static const char *aud_clks[MT8188_CLK_NUM] = {
+ /* xtal */
+ [MT8188_CLK_XTAL_26M] = "clk26m",
+
+ /* divider */
+ [MT8188_CLK_TOP_APLL1] = "apll1_ck",
+ [MT8188_CLK_TOP_APLL2] = "apll2_ck",
+ [MT8188_CLK_TOP_APLL12_DIV0] = "apll12_div0",
+ [MT8188_CLK_TOP_APLL12_DIV1] = "apll12_div1",
+ [MT8188_CLK_TOP_APLL12_DIV2] = "apll12_div2",
+ [MT8188_CLK_TOP_APLL12_DIV3] = "apll12_div3",
+ [MT8188_CLK_TOP_APLL12_DIV9] = "apll12_div9",
+
+ /* mux */
+ [MT8188_CLK_TOP_A1SYS_HP_SEL] = "top_a1sys_hp",
+ [MT8188_CLK_TOP_AUD_INTBUS_SEL] = "top_aud_intbus",
+ [MT8188_CLK_TOP_AUDIO_H_SEL] = "top_audio_h",
+ [MT8188_CLK_TOP_AUDIO_LOCAL_BUS_SEL] = "top_audio_local_bus",
+ [MT8188_CLK_TOP_DPTX_M_SEL] = "top_dptx",
+ [MT8188_CLK_TOP_I2SO1_M_SEL] = "top_i2so1",
+ [MT8188_CLK_TOP_I2SO2_M_SEL] = "top_i2so2",
+ [MT8188_CLK_TOP_I2SI1_M_SEL] = "top_i2si1",
+ [MT8188_CLK_TOP_I2SI2_M_SEL] = "top_i2si2",
+
+ /* clock gate */
+ [MT8188_CLK_ADSP_AUDIO_26M] = "adsp_audio_26m",
+ /* afe clock gate */
+ [MT8188_CLK_AUD_AFE] = "aud_afe",
+ [MT8188_CLK_AUD_APLL1_TUNER] = "aud_apll1_tuner",
+ [MT8188_CLK_AUD_APLL2_TUNER] = "aud_apll2_tuner",
+ [MT8188_CLK_AUD_APLL] = "aud_apll",
+ [MT8188_CLK_AUD_APLL2] = "aud_apll2",
+ [MT8188_CLK_AUD_DAC] = "aud_dac",
+ [MT8188_CLK_AUD_ADC] = "aud_adc",
+ [MT8188_CLK_AUD_DAC_HIRES] = "aud_dac_hires",
+ [MT8188_CLK_AUD_A1SYS_HP] = "aud_a1sys_hp",
+ [MT8188_CLK_AUD_ADC_HIRES] = "aud_adc_hires",
+ [MT8188_CLK_AUD_I2SIN] = "aud_i2sin",
+ [MT8188_CLK_AUD_TDM_IN] = "aud_tdm_in",
+ [MT8188_CLK_AUD_I2S_OUT] = "aud_i2s_out",
+ [MT8188_CLK_AUD_TDM_OUT] = "aud_tdm_out",
+ [MT8188_CLK_AUD_HDMI_OUT] = "aud_hdmi_out",
+ [MT8188_CLK_AUD_ASRC11] = "aud_asrc11",
+ [MT8188_CLK_AUD_ASRC12] = "aud_asrc12",
+ [MT8188_CLK_AUD_A1SYS] = "aud_a1sys",
+ [MT8188_CLK_AUD_A2SYS] = "aud_a2sys",
+ [MT8188_CLK_AUD_PCMIF] = "aud_pcmif",
+ [MT8188_CLK_AUD_MEMIF_UL1] = "aud_memif_ul1",
+ [MT8188_CLK_AUD_MEMIF_UL2] = "aud_memif_ul2",
+ [MT8188_CLK_AUD_MEMIF_UL3] = "aud_memif_ul3",
+ [MT8188_CLK_AUD_MEMIF_UL4] = "aud_memif_ul4",
+ [MT8188_CLK_AUD_MEMIF_UL5] = "aud_memif_ul5",
+ [MT8188_CLK_AUD_MEMIF_UL6] = "aud_memif_ul6",
+ [MT8188_CLK_AUD_MEMIF_UL8] = "aud_memif_ul8",
+ [MT8188_CLK_AUD_MEMIF_UL9] = "aud_memif_ul9",
+ [MT8188_CLK_AUD_MEMIF_UL10] = "aud_memif_ul10",
+ [MT8188_CLK_AUD_MEMIF_DL2] = "aud_memif_dl2",
+ [MT8188_CLK_AUD_MEMIF_DL3] = "aud_memif_dl3",
+ [MT8188_CLK_AUD_MEMIF_DL6] = "aud_memif_dl6",
+ [MT8188_CLK_AUD_MEMIF_DL7] = "aud_memif_dl7",
+ [MT8188_CLK_AUD_MEMIF_DL8] = "aud_memif_dl8",
+ [MT8188_CLK_AUD_MEMIF_DL10] = "aud_memif_dl10",
+ [MT8188_CLK_AUD_MEMIF_DL11] = "aud_memif_dl11",
+};
+
+struct mt8188_afe_tuner_cfg {
+ unsigned int id;
+ int apll_div_reg;
+ unsigned int apll_div_shift;
+ unsigned int apll_div_maskbit;
+ unsigned int apll_div_default;
+ int ref_ck_sel_reg;
+ unsigned int ref_ck_sel_shift;
+ unsigned int ref_ck_sel_maskbit;
+ unsigned int ref_ck_sel_default;
+ int tuner_en_reg;
+ unsigned int tuner_en_shift;
+ unsigned int tuner_en_maskbit;
+ int upper_bound_reg;
+ unsigned int upper_bound_shift;
+ unsigned int upper_bound_maskbit;
+ unsigned int upper_bound_default;
+ spinlock_t ctrl_lock; /* lock for apll tuner ctrl*/
+ int ref_cnt;
+};
+
+static struct mt8188_afe_tuner_cfg
+ mt8188_afe_tuner_cfgs[MT8188_AUD_PLL_NUM] = {
+ [MT8188_AUD_PLL1] = {
+ .id = MT8188_AUD_PLL1,
+ .apll_div_reg = AFE_APLL_TUNER_CFG,
+ .apll_div_shift = 4,
+ .apll_div_maskbit = 0xf,
+ .apll_div_default = 0x7,
+ .ref_ck_sel_reg = AFE_APLL_TUNER_CFG,
+ .ref_ck_sel_shift = 1,
+ .ref_ck_sel_maskbit = 0x3,
+ .ref_ck_sel_default = 0x2,
+ .tuner_en_reg = AFE_APLL_TUNER_CFG,
+ .tuner_en_shift = 0,
+ .tuner_en_maskbit = 0x1,
+ .upper_bound_reg = AFE_APLL_TUNER_CFG,
+ .upper_bound_shift = 8,
+ .upper_bound_maskbit = 0xff,
+ .upper_bound_default = 0x3,
+ },
+ [MT8188_AUD_PLL2] = {
+ .id = MT8188_AUD_PLL2,
+ .apll_div_reg = AFE_APLL_TUNER_CFG1,
+ .apll_div_shift = 4,
+ .apll_div_maskbit = 0xf,
+ .apll_div_default = 0x7,
+ .ref_ck_sel_reg = AFE_APLL_TUNER_CFG1,
+ .ref_ck_sel_shift = 1,
+ .ref_ck_sel_maskbit = 0x3,
+ .ref_ck_sel_default = 0x1,
+ .tuner_en_reg = AFE_APLL_TUNER_CFG1,
+ .tuner_en_shift = 0,
+ .tuner_en_maskbit = 0x1,
+ .upper_bound_reg = AFE_APLL_TUNER_CFG1,
+ .upper_bound_shift = 8,
+ .upper_bound_maskbit = 0xff,
+ .upper_bound_default = 0x3,
+ },
+ [MT8188_AUD_PLL3] = {
+ .id = MT8188_AUD_PLL3,
+ .apll_div_reg = AFE_EARC_APLL_TUNER_CFG,
+ .apll_div_shift = 4,
+ .apll_div_maskbit = 0x3f,
+ .apll_div_default = 0x3,
+ .ref_ck_sel_reg = AFE_EARC_APLL_TUNER_CFG,
+ .ref_ck_sel_shift = 24,
+ .ref_ck_sel_maskbit = 0x3,
+ .ref_ck_sel_default = 0x0,
+ .tuner_en_reg = AFE_EARC_APLL_TUNER_CFG,
+ .tuner_en_shift = 0,
+ .tuner_en_maskbit = 0x1,
+ .upper_bound_reg = AFE_EARC_APLL_TUNER_CFG,
+ .upper_bound_shift = 12,
+ .upper_bound_maskbit = 0xff,
+ .upper_bound_default = 0x4,
+ },
+ [MT8188_AUD_PLL4] = {
+ .id = MT8188_AUD_PLL4,
+ .apll_div_reg = AFE_SPDIFIN_APLL_TUNER_CFG,
+ .apll_div_shift = 4,
+ .apll_div_maskbit = 0x3f,
+ .apll_div_default = 0x7,
+ .ref_ck_sel_reg = AFE_SPDIFIN_APLL_TUNER_CFG1,
+ .ref_ck_sel_shift = 8,
+ .ref_ck_sel_maskbit = 0x1,
+ .ref_ck_sel_default = 0,
+ .tuner_en_reg = AFE_SPDIFIN_APLL_TUNER_CFG,
+ .tuner_en_shift = 0,
+ .tuner_en_maskbit = 0x1,
+ .upper_bound_reg = AFE_SPDIFIN_APLL_TUNER_CFG,
+ .upper_bound_shift = 12,
+ .upper_bound_maskbit = 0xff,
+ .upper_bound_default = 0x4,
+ },
+ [MT8188_AUD_PLL5] = {
+ .id = MT8188_AUD_PLL5,
+ .apll_div_reg = AFE_LINEIN_APLL_TUNER_CFG,
+ .apll_div_shift = 4,
+ .apll_div_maskbit = 0x3f,
+ .apll_div_default = 0x3,
+ .ref_ck_sel_reg = AFE_LINEIN_APLL_TUNER_CFG,
+ .ref_ck_sel_shift = 24,
+ .ref_ck_sel_maskbit = 0x1,
+ .ref_ck_sel_default = 0,
+ .tuner_en_reg = AFE_LINEIN_APLL_TUNER_CFG,
+ .tuner_en_shift = 0,
+ .tuner_en_maskbit = 0x1,
+ .upper_bound_reg = AFE_LINEIN_APLL_TUNER_CFG,
+ .upper_bound_shift = 12,
+ .upper_bound_maskbit = 0xff,
+ .upper_bound_default = 0x4,
+ },
+};
+
+static struct mt8188_afe_tuner_cfg *mt8188_afe_found_apll_tuner(unsigned int id)
+{
+ if (id >= MT8188_AUD_PLL_NUM)
+ return NULL;
+
+ return &mt8188_afe_tuner_cfgs[id];
+}
+
+static int mt8188_afe_init_apll_tuner(unsigned int id)
+{
+ struct mt8188_afe_tuner_cfg *cfg = mt8188_afe_found_apll_tuner(id);
+
+ if (!cfg)
+ return -EINVAL;
+
+ cfg->ref_cnt = 0;
+ spin_lock_init(&cfg->ctrl_lock);
+
+ return 0;
+}
+
+static int mt8188_afe_setup_apll_tuner(struct mtk_base_afe *afe, unsigned int id)
+{
+ const struct mt8188_afe_tuner_cfg *cfg = mt8188_afe_found_apll_tuner(id);
+
+ if (!cfg)
+ return -EINVAL;
+
+ regmap_update_bits(afe->regmap,
+ cfg->apll_div_reg,
+ cfg->apll_div_maskbit << cfg->apll_div_shift,
+ cfg->apll_div_default << cfg->apll_div_shift);
+
+ regmap_update_bits(afe->regmap,
+ cfg->ref_ck_sel_reg,
+ cfg->ref_ck_sel_maskbit << cfg->ref_ck_sel_shift,
+ cfg->ref_ck_sel_default << cfg->ref_ck_sel_shift);
+
+ regmap_update_bits(afe->regmap,
+ cfg->upper_bound_reg,
+ cfg->upper_bound_maskbit << cfg->upper_bound_shift,
+ cfg->upper_bound_default << cfg->upper_bound_shift);
+
+ return 0;
+}
+
+static int mt8188_afe_enable_tuner_clk(struct mtk_base_afe *afe,
+ unsigned int id)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+ switch (id) {
+ case MT8188_AUD_PLL1:
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL]);
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL1_TUNER]);
+ break;
+ case MT8188_AUD_PLL2:
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL2]);
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL2_TUNER]);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mt8188_afe_disable_tuner_clk(struct mtk_base_afe *afe,
+ unsigned int id)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+ switch (id) {
+ case MT8188_AUD_PLL1:
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL1_TUNER]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL]);
+ break;
+ case MT8188_AUD_PLL2:
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL2_TUNER]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_APLL2]);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mt8188_afe_enable_apll_tuner(struct mtk_base_afe *afe, unsigned int id)
+{
+ struct mt8188_afe_tuner_cfg *cfg = mt8188_afe_found_apll_tuner(id);
+ unsigned long flags;
+ int ret;
+
+ if (!cfg)
+ return -EINVAL;
+
+ ret = mt8188_afe_setup_apll_tuner(afe, id);
+ if (ret)
+ return ret;
+
+ ret = mt8188_afe_enable_tuner_clk(afe, id);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&cfg->ctrl_lock, flags);
+
+ cfg->ref_cnt++;
+ if (cfg->ref_cnt == 1)
+ regmap_update_bits(afe->regmap,
+ cfg->tuner_en_reg,
+ cfg->tuner_en_maskbit << cfg->tuner_en_shift,
+ BIT(cfg->tuner_en_shift));
+
+ spin_unlock_irqrestore(&cfg->ctrl_lock, flags);
+
+ return 0;
+}
+
+static int mt8188_afe_disable_apll_tuner(struct mtk_base_afe *afe, unsigned int id)
+{
+ struct mt8188_afe_tuner_cfg *cfg = mt8188_afe_found_apll_tuner(id);
+ unsigned long flags;
+ int ret;
+
+ if (!cfg)
+ return -EINVAL;
+
+ spin_lock_irqsave(&cfg->ctrl_lock, flags);
+
+ cfg->ref_cnt--;
+ if (cfg->ref_cnt == 0)
+ regmap_update_bits(afe->regmap,
+ cfg->tuner_en_reg,
+ cfg->tuner_en_maskbit << cfg->tuner_en_shift,
+ 0 << cfg->tuner_en_shift);
+ else if (cfg->ref_cnt < 0)
+ cfg->ref_cnt = 0;
+
+ spin_unlock_irqrestore(&cfg->ctrl_lock, flags);
+
+ ret = mt8188_afe_disable_tuner_clk(afe, id);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int mt8188_afe_get_mclk_source_clk_id(int sel)
+{
+ switch (sel) {
+ case MT8188_MCK_SEL_26M:
+ return MT8188_CLK_XTAL_26M;
+ case MT8188_MCK_SEL_APLL1:
+ return MT8188_CLK_TOP_APLL1;
+ case MT8188_MCK_SEL_APLL2:
+ return MT8188_CLK_TOP_APLL2;
+ default:
+ return -EINVAL;
+ }
+}
+
+int mt8188_afe_get_mclk_source_rate(struct mtk_base_afe *afe, int apll)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ int clk_id = mt8188_afe_get_mclk_source_clk_id(apll);
+
+ if (clk_id < 0) {
+ dev_dbg(afe->dev, "invalid clk id\n");
+ return 0;
+ }
+
+ return clk_get_rate(afe_priv->clk[clk_id]);
+}
+
+int mt8188_afe_get_default_mclk_source_by_rate(int rate)
+{
+ return ((rate % 8000) == 0) ?
+ MT8188_MCK_SEL_APLL1 : MT8188_MCK_SEL_APLL2;
+}
+
+int mt8188_afe_init_clock(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ int i, ret;
+
+ ret = mt8188_audsys_clk_register(afe);
+ if (ret) {
+ dev_err(afe->dev, "register audsys clk fail %d\n", ret);
+ return ret;
+ }
+
+ afe_priv->clk =
+ devm_kcalloc(afe->dev, MT8188_CLK_NUM, sizeof(*afe_priv->clk),
+ GFP_KERNEL);
+ if (!afe_priv->clk)
+ return -ENOMEM;
+
+ for (i = 0; i < MT8188_CLK_NUM; i++) {
+ afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
+ if (IS_ERR(afe_priv->clk[i])) {
+ dev_err(afe->dev, "%s(), devm_clk_get %s fail, ret %ld\n",
+ __func__, aud_clks[i],
+ PTR_ERR(afe_priv->clk[i]));
+ return PTR_ERR(afe_priv->clk[i]);
+ }
+ }
+
+ /* initial tuner */
+ for (i = 0; i < MT8188_AUD_PLL_NUM; i++) {
+ ret = mt8188_afe_init_apll_tuner(i);
+ if (ret) {
+ dev_info(afe->dev, "%s(), init apll_tuner%d failed",
+ __func__, (i + 1));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+void mt8188_afe_deinit_clock(void *priv)
+{
+ struct mtk_base_afe *afe = priv;
+
+ mt8188_audsys_clk_unregister(afe);
+}
+
+int mt8188_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk)
+{
+ int ret;
+
+ if (clk) {
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ dev_dbg(afe->dev, "%s(), failed to enable clk\n",
+ __func__);
+ return ret;
+ }
+ } else {
+ dev_dbg(afe->dev, "NULL clk\n");
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt8188_afe_enable_clk);
+
+void mt8188_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk)
+{
+ if (clk)
+ clk_disable_unprepare(clk);
+ else
+ dev_dbg(afe->dev, "NULL clk\n");
+}
+EXPORT_SYMBOL_GPL(mt8188_afe_disable_clk);
+
+int mt8188_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk,
+ unsigned int rate)
+{
+ int ret;
+
+ if (clk) {
+ ret = clk_set_rate(clk, rate);
+ if (ret) {
+ dev_dbg(afe->dev, "%s(), failed to set clk rate\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int mt8188_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk,
+ struct clk *parent)
+{
+ int ret;
+
+ if (clk && parent) {
+ ret = clk_set_parent(clk, parent);
+ if (ret) {
+ dev_dbg(afe->dev, "%s(), failed to set clk parent\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int get_top_cg_reg(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8188_TOP_CG_A1SYS_TIMING:
+ case MT8188_TOP_CG_A2SYS_TIMING:
+ case MT8188_TOP_CG_26M_TIMING:
+ return ASYS_TOP_CON;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_mask(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8188_TOP_CG_A1SYS_TIMING:
+ return ASYS_TOP_CON_A1SYS_TIMING_ON;
+ case MT8188_TOP_CG_A2SYS_TIMING:
+ return ASYS_TOP_CON_A2SYS_TIMING_ON;
+ case MT8188_TOP_CG_26M_TIMING:
+ return ASYS_TOP_CON_26M_TIMING_ON;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_on_val(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8188_TOP_CG_A1SYS_TIMING:
+ case MT8188_TOP_CG_A2SYS_TIMING:
+ case MT8188_TOP_CG_26M_TIMING:
+ return get_top_cg_mask(cg_type);
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_off_val(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8188_TOP_CG_A1SYS_TIMING:
+ case MT8188_TOP_CG_A2SYS_TIMING:
+ case MT8188_TOP_CG_26M_TIMING:
+ return 0;
+ default:
+ return get_top_cg_mask(cg_type);
+ }
+}
+
+static int mt8188_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+ unsigned int reg = get_top_cg_reg(cg_type);
+ unsigned int mask = get_top_cg_mask(cg_type);
+ unsigned int val = get_top_cg_on_val(cg_type);
+
+ regmap_update_bits(afe->regmap, reg, mask, val);
+
+ return 0;
+}
+
+static int mt8188_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+ unsigned int reg = get_top_cg_reg(cg_type);
+ unsigned int mask = get_top_cg_mask(cg_type);
+ unsigned int val = get_top_cg_off_val(cg_type);
+
+ regmap_update_bits(afe->regmap, reg, mask, val);
+
+ return 0;
+}
+
+int mt8188_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+ /* bus clock for AFE external access, like DRAM */
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_AUDIO_LOCAL_BUS_SEL]);
+
+ /* bus clock for AFE internal access, like AFE SRAM */
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_AUD_INTBUS_SEL]);
+
+ /* audio 26m clock source */
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_ADSP_AUDIO_26M]);
+
+ /* AFE hw clock */
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE]);
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS_HP]);
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]);
+
+ return 0;
+}
+
+int mt8188_afe_disable_reg_rw_clk(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS_HP]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_ADSP_AUDIO_26M]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_AUD_INTBUS_SEL]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_AUDIO_LOCAL_BUS_SEL]);
+
+ return 0;
+}
+
+static int mt8188_afe_enable_afe_on(struct mtk_base_afe *afe)
+{
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
+ return 0;
+}
+
+static int mt8188_afe_disable_afe_on(struct mtk_base_afe *afe)
+{
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x0);
+ return 0;
+}
+
+static int mt8188_afe_enable_timing_sys(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]);
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]);
+
+ mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING);
+ mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_A2SYS_TIMING);
+ mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_26M_TIMING);
+
+ return 0;
+}
+
+static int mt8188_afe_disable_timing_sys(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]);
+
+ mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_26M_TIMING);
+ mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_A2SYS_TIMING);
+ mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING);
+
+ return 0;
+}
+
+int mt8188_afe_enable_main_clock(struct mtk_base_afe *afe)
+{
+ mt8188_afe_enable_timing_sys(afe);
+
+ mt8188_afe_enable_afe_on(afe);
+
+ mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL1);
+ mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL2);
+
+ return 0;
+}
+
+int mt8188_afe_disable_main_clock(struct mtk_base_afe *afe)
+{
+ mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL2);
+ mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL1);
+
+ mt8188_afe_disable_afe_on(afe);
+
+ mt8188_afe_disable_timing_sys(afe);
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
new file mode 100644
index 000000000000..ea38767d3876
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8188-afe-clk.h -- MediaTek 8188 afe clock ctrl definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Bicycle Tsai <[email protected]>
+ * Trevor Wu <[email protected]>
+ * Chun-Chia Chiu <[email protected]>
+ */
+
+#ifndef _MT8188_AFE_CLK_H_
+#define _MT8188_AFE_CLK_H_
+
+enum {
+ /* xtal */
+ MT8188_CLK_XTAL_26M,
+ /* divider */
+ MT8188_CLK_TOP_APLL1,
+ MT8188_CLK_TOP_APLL2,
+ MT8188_CLK_TOP_APLL12_DIV0,
+ MT8188_CLK_TOP_APLL12_DIV1,
+ MT8188_CLK_TOP_APLL12_DIV2,
+ MT8188_CLK_TOP_APLL12_DIV3,
+ MT8188_CLK_TOP_APLL12_DIV9,
+ /* mux */
+ MT8188_CLK_TOP_A1SYS_HP_SEL,
+ MT8188_CLK_TOP_AUD_INTBUS_SEL,
+ MT8188_CLK_TOP_AUDIO_H_SEL,
+ MT8188_CLK_TOP_AUDIO_LOCAL_BUS_SEL,
+ MT8188_CLK_TOP_DPTX_M_SEL,
+ MT8188_CLK_TOP_I2SO1_M_SEL,
+ MT8188_CLK_TOP_I2SO2_M_SEL,
+ MT8188_CLK_TOP_I2SI1_M_SEL,
+ MT8188_CLK_TOP_I2SI2_M_SEL,
+ /* clock gate */
+ MT8188_CLK_ADSP_AUDIO_26M,
+ MT8188_CLK_AUD_AFE,
+ MT8188_CLK_AUD_APLL1_TUNER,
+ MT8188_CLK_AUD_APLL2_TUNER,
+ MT8188_CLK_AUD_TOP0_SPDF,
+ MT8188_CLK_AUD_APLL,
+ MT8188_CLK_AUD_APLL2,
+ MT8188_CLK_AUD_DAC,
+ MT8188_CLK_AUD_ADC,
+ MT8188_CLK_AUD_DAC_HIRES,
+ MT8188_CLK_AUD_A1SYS_HP,
+ MT8188_CLK_AUD_ADC_HIRES,
+ MT8188_CLK_AUD_I2SIN,
+ MT8188_CLK_AUD_TDM_IN,
+ MT8188_CLK_AUD_I2S_OUT,
+ MT8188_CLK_AUD_TDM_OUT,
+ MT8188_CLK_AUD_HDMI_OUT,
+ MT8188_CLK_AUD_ASRC11,
+ MT8188_CLK_AUD_ASRC12,
+ MT8188_CLK_AUD_A1SYS,
+ MT8188_CLK_AUD_A2SYS,
+ MT8188_CLK_AUD_PCMIF,
+ MT8188_CLK_AUD_MEMIF_UL1,
+ MT8188_CLK_AUD_MEMIF_UL2,
+ MT8188_CLK_AUD_MEMIF_UL3,
+ MT8188_CLK_AUD_MEMIF_UL4,
+ MT8188_CLK_AUD_MEMIF_UL5,
+ MT8188_CLK_AUD_MEMIF_UL6,
+ MT8188_CLK_AUD_MEMIF_UL8,
+ MT8188_CLK_AUD_MEMIF_UL9,
+ MT8188_CLK_AUD_MEMIF_UL10,
+ MT8188_CLK_AUD_MEMIF_DL2,
+ MT8188_CLK_AUD_MEMIF_DL3,
+ MT8188_CLK_AUD_MEMIF_DL6,
+ MT8188_CLK_AUD_MEMIF_DL7,
+ MT8188_CLK_AUD_MEMIF_DL8,
+ MT8188_CLK_AUD_MEMIF_DL10,
+ MT8188_CLK_AUD_MEMIF_DL11,
+ MT8188_CLK_NUM,
+};
+
+enum {
+ MT8188_AUD_PLL1,
+ MT8188_AUD_PLL2,
+ MT8188_AUD_PLL3,
+ MT8188_AUD_PLL4,
+ MT8188_AUD_PLL5,
+ MT8188_AUD_PLL_NUM,
+};
+
+enum {
+ MT8188_MCK_SEL_26M,
+ MT8188_MCK_SEL_APLL1,
+ MT8188_MCK_SEL_APLL2,
+ MT8188_MCK_SEL_APLL3,
+ MT8188_MCK_SEL_APLL4,
+ MT8188_MCK_SEL_APLL5,
+ MT8188_MCK_SEL_NUM,
+};
+
+struct mtk_base_afe;
+
+int mt8188_afe_get_mclk_source_clk_id(int sel);
+int mt8188_afe_get_mclk_source_rate(struct mtk_base_afe *afe, int apll);
+int mt8188_afe_get_default_mclk_source_by_rate(int rate);
+int mt8188_afe_init_clock(struct mtk_base_afe *afe);
+void mt8188_afe_deinit_clock(void *priv);
+int mt8188_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
+void mt8188_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
+int mt8188_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk,
+ unsigned int rate);
+int mt8188_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk,
+ struct clk *parent);
+int mt8188_afe_enable_main_clock(struct mtk_base_afe *afe);
+int mt8188_afe_disable_main_clock(struct mtk_base_afe *afe);
+int mt8188_afe_enable_reg_rw_clk(struct mtk_base_afe *afe);
+int mt8188_afe_disable_reg_rw_clk(struct mtk_base_afe *afe);
+
+#endif
--
2.18.0
Add mt8188 audio afe document.
Signed-off-by: Trevor Wu <[email protected]>
---
.../devicetree/bindings/sound/mt8188-afe.yaml | 196 ++++++++++++++++++
1 file changed, 196 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/mt8188-afe.yaml
diff --git a/Documentation/devicetree/bindings/sound/mt8188-afe.yaml b/Documentation/devicetree/bindings/sound/mt8188-afe.yaml
new file mode 100644
index 000000000000..6ab26494d924
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mt8188-afe.yaml
@@ -0,0 +1,196 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mt8188-afe.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek AFE PCM controller for mt8188
+
+maintainers:
+ - Trevor Wu <[email protected]>
+
+properties:
+ compatible:
+ const: mediatek,mt8188-afe
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ reset-names:
+ const: audiosys
+
+ mediatek,topckgen:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of the mediatek topckgen controller
+
+ power-domains:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: 26M clock
+ - description: audio pll1 clock
+ - description: audio pll2 clock
+ - description: clock divider for i2si1_mck
+ - description: clock divider for i2si2_mck
+ - description: clock divider for i2so1_mck
+ - description: clock divider for i2so2_mck
+ - description: clock divider for dptx_mck
+ - description: a1sys hoping clock
+ - description: audio intbus clock
+ - description: audio hires clock
+ - description: audio local bus clock
+ - description: mux for dptx_mck
+ - description: mux for i2so1_mck
+ - description: mux for i2so2_mck
+ - description: mux for i2si1_mck
+ - description: mux for i2si2_mck
+ - description: audio 26m clock
+
+ clock-names:
+ items:
+ - const: clk26m
+ - const: apll1_ck
+ - const: apll2_ck
+ - const: apll12_div0
+ - const: apll12_div1
+ - const: apll12_div2
+ - const: apll12_div3
+ - const: apll12_div9
+ - const: a1sys_hp_sel
+ - const: aud_intbus_sel
+ - const: audio_h_sel
+ - const: audio_local_bus_sel
+ - const: dptx_m_sel
+ - const: i2so1_m_sel
+ - const: i2so2_m_sel
+ - const: i2si1_m_sel
+ - const: i2si2_m_sel
+ - const: adsp_audio_26m
+
+patternProperties:
+ "^mediatek,etdm-in[1-2]-chn-disabled$":
+ $ref: /schemas/types.yaml#/definitions/uint8-array
+ minItems: 1
+ maxItems: 16
+ description:
+ By default, all data received from ETDM pins will be outputed to
+ memory. etdm in supports disable_out in direct mode(w/o interconn).
+ User can specify the channel ID which they hope dropping and then
+ the specified channel won't be seen on memory.
+ uniqueItems: true
+ items:
+ minimum: 0
+ maximum: 15
+
+ "^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
+ description: Specify etdm in mclk output rate for always on case.
+
+ "^mediatek,etdm-out[1-3]-mclk-always-on-rate-hz$":
+ description: Specify etdm out mclk output rate for always on case.
+
+ "^mediatek,etdm-in[1-2]-multi-pin-mode$":
+ type: boolean
+ description: if present, the etdm data mode is I2S.
+
+ "^mediatek,etdm-out[1-3]-multi-pin-mode$":
+ type: boolean
+ description: if present, the etdm data mode is I2S.
+
+ "^mediatek,etdm-in[1-2]-cowork-source$":
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ etdm modules can share the same external clock pin. Specify
+ which etdm clock source is required by this etdm in moudule.
+ enum:
+ - 0 # etdm1_in
+ - 1 # etdm2_in
+ - 2 # etdm1_out
+ - 3 # etdm2_out
+
+ "^mediatek,etdm-out[1-2]-cowork-source$":
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ etdm modules can share the same external clock pin. Specify
+ which etdm clock source is required by this etdm out moudule.
+ enum:
+ - 0 # etdm1_in
+ - 1 # etdm2_in
+ - 2 # etdm1_out
+ - 3 # etdm2_out
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - resets
+ - reset-names
+ - mediatek,topckgen
+ - power-domains
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ afe: afe@10b10000 {
+ compatible = "mediatek,mt8188-afe";
+ reg = <0x10b10000 0x10000>;
+ interrupts = <GIC_SPI 822 IRQ_TYPE_LEVEL_HIGH 0>;
+ resets = <&watchdog 14>;
+ reset-names = "audiosys";
+ mediatek,topckgen = <&topckgen>;
+ power-domains = <&spm 13>; //MT8188_POWER_DOMAIN_AUDIO
+ mediatek,etdm-in2-cowork-source = <2>;
+ mediatek,etdm-out2-cowork-source = <0>;
+ mediatek,etdm-in1-multi-pin-mode;
+ mediatek,etdm-in1-chn-disabled = /bits/ 8 <0x0 0x2>;
+ clocks = <&clk26m>,
+ <&topckgen 72>, //CLK_TOP_APLL1
+ <&topckgen 73>, //CLK_TOP_APLL2
+ <&topckgen 186>, //CLK_TOP_APLL12_CK_DIV0
+ <&topckgen 187>, //CLK_TOP_APLL12_CK_DIV1
+ <&topckgen 188>, //CLK_TOP_APLL12_CK_DIV2
+ <&topckgen 189>, //CLK_TOP_APLL12_CK_DIV3
+ <&topckgen 191>, //CLK_TOP_APLL12_CK_DIV9
+ <&topckgen 83>, //CLK_TOP_A1SYS_HP
+ <&topckgen 31>, //CLK_TOP_AUD_INTBUS
+ <&topckgen 32>, //CLK_TOP_AUDIO_H
+ <&topckgen 69>, //CLK_TOP_AUDIO_LOCAL_BUS
+ <&topckgen 81>, //CLK_TOP_DPTX
+ <&topckgen 77>, //CLK_TOP_I2SO1
+ <&topckgen 78>, //CLK_TOP_I2SO2
+ <&topckgen 79>, //CLK_TOP_I2SI1
+ <&topckgen 80>, //CLK_TOP_I2SI2
+ <&adsp_audio26m 0>; //CLK_AUDIODSP_AUDIO26M
+ clock-names = "clk26m",
+ "apll1_ck",
+ "apll2_ck",
+ "apll12_div0",
+ "apll12_div1",
+ "apll12_div2",
+ "apll12_div3",
+ "apll12_div9",
+ "a1sys_hp_sel",
+ "aud_intbus_sel",
+ "audio_h_sel",
+ "audio_local_bus_sel",
+ "dptx_m_sel",
+ "i2so1_m_sel",
+ "i2so2_m_sel",
+ "i2si1_m_sel",
+ "i2si2_m_sel",
+ "adsp_audio_26m";
+ };
+
+...
--
2.18.0
Add mixer control for irq and memif timing selection.
Signed-off-by: Trevor Wu <[email protected]>
---
sound/soc/mediatek/mt8188/mt8188-afe-pcm.c | 506 +++++++++++++++++++++
1 file changed, 506 insertions(+)
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
index 6bef980846fa..57a31330e5f4 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
@@ -1394,6 +1394,510 @@ static const struct snd_soc_dapm_route mt8188_memif_routes[] = {
{"O041", "I169 Switch", "I169"},
};
+static const char * const mt8188_afe_1x_en_sel_text[] = {
+ "a1sys_a2sys", "a3sys", "a4sys",
+};
+
+static const unsigned int mt8188_afe_1x_en_sel_values[] = {
+ 0, 1, 2,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(dl2_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 18, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl3_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 20, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl6_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 22, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl7_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 24, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl8_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 26, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl10_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 28, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl11_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 30, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul1_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 0, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul2_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 2, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul3_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 4, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul4_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 6, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul5_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 8, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul6_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 10, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul8_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 12, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul9_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 14, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul10_1x_en_sel_enum,
+ A3_A4_TIMING_SEL1, 16, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq1_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 0, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq2_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 2, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq3_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 4, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq4_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 6, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq5_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 8, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq6_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 10, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq7_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 12, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq8_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 14, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq9_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 16, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq10_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 18, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq11_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 20, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq12_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 22, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq13_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 24, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq14_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 26, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq15_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 28, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(asys_irq16_1x_en_sel_enum,
+ A3_A4_TIMING_SEL6, 30, 0x3,
+ mt8188_afe_1x_en_sel_text,
+ mt8188_afe_1x_en_sel_values);
+
+static const char * const mt8188_afe_fs_timing_sel_text[] = {
+ "asys",
+ "etdmout1_1x_en",
+ "etdmout2_1x_en",
+ "etdmout3_1x_en",
+ "etdmin1_1x_en",
+ "etdmin2_1x_en",
+ "etdmin1_nx_en",
+ "etdmin2_nx_en",
+};
+
+static const unsigned int mt8188_afe_fs_timing_sel_values[] = {
+ 0,
+ MT8188_ETDM_OUT1_1X_EN,
+ MT8188_ETDM_OUT2_1X_EN,
+ MT8188_ETDM_OUT3_1X_EN,
+ MT8188_ETDM_IN1_1X_EN,
+ MT8188_ETDM_IN2_1X_EN,
+ MT8188_ETDM_IN1_NX_EN,
+ MT8188_ETDM_IN2_NX_EN,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(dl2_fs_timing_sel_enum,
+ SND_SOC_NOPM, 0, 0,
+ mt8188_afe_fs_timing_sel_text,
+ mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl3_fs_timing_sel_enum,
+ SND_SOC_NOPM, 0, 0,
+ mt8188_afe_fs_timing_sel_text,
+ mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl6_fs_timing_sel_enum,
+ SND_SOC_NOPM, 0, 0,
+ mt8188_afe_fs_timing_sel_text,
+ mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl8_fs_timing_sel_enum,
+ SND_SOC_NOPM, 0, 0,
+ mt8188_afe_fs_timing_sel_text,
+ mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(dl11_fs_timing_sel_enum,
+ SND_SOC_NOPM, 0, 0,
+ mt8188_afe_fs_timing_sel_text,
+ mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul2_fs_timing_sel_enum,
+ SND_SOC_NOPM, 0, 0,
+ mt8188_afe_fs_timing_sel_text,
+ mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul4_fs_timing_sel_enum,
+ SND_SOC_NOPM, 0, 0,
+ mt8188_afe_fs_timing_sel_text,
+ mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul5_fs_timing_sel_enum,
+ SND_SOC_NOPM, 0, 0,
+ mt8188_afe_fs_timing_sel_text,
+ mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul9_fs_timing_sel_enum,
+ SND_SOC_NOPM, 0, 0,
+ mt8188_afe_fs_timing_sel_text,
+ mt8188_afe_fs_timing_sel_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul10_fs_timing_sel_enum,
+ SND_SOC_NOPM, 0, 0,
+ mt8188_afe_fs_timing_sel_text,
+ mt8188_afe_fs_timing_sel_values);
+
+static int mt8188_memif_1x_en_sel_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_memif_priv *memif_priv;
+ unsigned int dai_id = kcontrol->id.device;
+ long val = ucontrol->value.integer.value[0];
+ int ret = 0;
+
+ memif_priv = afe_priv->dai_priv[dai_id];
+
+ if (val == memif_priv->asys_timing_sel)
+ return 0;
+
+ ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+
+ memif_priv->asys_timing_sel = val;
+
+ return ret;
+}
+
+static int mt8188_asys_irq_1x_en_sel_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ unsigned int id = kcontrol->id.device;
+ long val = ucontrol->value.integer.value[0];
+ int ret = 0;
+
+ if (val == afe_priv->irq_priv[id].asys_timing_sel)
+ return 0;
+
+ ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+
+ afe_priv->irq_priv[id].asys_timing_sel = val;
+
+ return ret;
+}
+
+static int mt8188_memif_fs_timing_sel_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_memif_priv *memif_priv;
+ unsigned int dai_id = kcontrol->id.device;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+ memif_priv = afe_priv->dai_priv[dai_id];
+
+ ucontrol->value.enumerated.item[0] =
+ snd_soc_enum_val_to_item(e, memif_priv->fs_timing);
+
+ return 0;
+}
+
+static int mt8188_memif_fs_timing_sel_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_memif_priv *memif_priv;
+ unsigned int dai_id = kcontrol->id.device;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ unsigned int prev_item = 0;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+
+ memif_priv = afe_priv->dai_priv[dai_id];
+
+ prev_item = snd_soc_enum_val_to_item(e, memif_priv->fs_timing);
+
+ if (item[0] == prev_item)
+ return 0;
+
+ memif_priv->fs_timing = snd_soc_enum_item_to_val(e, item[0]);
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new mt8188_memif_controls[] = {
+ MT8188_SOC_ENUM_EXT("dl2_1x_en_sel",
+ dl2_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_DL2),
+ MT8188_SOC_ENUM_EXT("dl3_1x_en_sel",
+ dl3_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_DL3),
+ MT8188_SOC_ENUM_EXT("dl6_1x_en_sel",
+ dl6_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_DL6),
+ MT8188_SOC_ENUM_EXT("dl7_1x_en_sel",
+ dl7_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_DL7),
+ MT8188_SOC_ENUM_EXT("dl8_1x_en_sel",
+ dl8_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_DL8),
+ MT8188_SOC_ENUM_EXT("dl10_1x_en_sel",
+ dl10_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_DL10),
+ MT8188_SOC_ENUM_EXT("dl11_1x_en_sel",
+ dl11_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_DL11),
+ MT8188_SOC_ENUM_EXT("ul1_1x_en_sel",
+ ul1_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_UL1),
+ MT8188_SOC_ENUM_EXT("ul2_1x_en_sel",
+ ul2_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_UL2),
+ MT8188_SOC_ENUM_EXT("ul3_1x_en_sel",
+ ul3_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_UL3),
+ MT8188_SOC_ENUM_EXT("ul4_1x_en_sel",
+ ul4_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_UL4),
+ MT8188_SOC_ENUM_EXT("ul5_1x_en_sel",
+ ul5_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_UL5),
+ MT8188_SOC_ENUM_EXT("ul6_1x_en_sel",
+ ul6_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_UL6),
+ MT8188_SOC_ENUM_EXT("ul8_1x_en_sel",
+ ul8_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_UL8),
+ MT8188_SOC_ENUM_EXT("ul9_1x_en_sel",
+ ul9_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_UL9),
+ MT8188_SOC_ENUM_EXT("ul10_1x_en_sel",
+ ul10_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_memif_1x_en_sel_put,
+ MT8188_AFE_MEMIF_UL10),
+ MT8188_SOC_ENUM_EXT("asys_irq1_1x_en_sel",
+ asys_irq1_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_13),
+ MT8188_SOC_ENUM_EXT("asys_irq2_1x_en_sel",
+ asys_irq2_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_14),
+ MT8188_SOC_ENUM_EXT("asys_irq3_1x_en_sel",
+ asys_irq3_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_15),
+ MT8188_SOC_ENUM_EXT("asys_irq4_1x_en_sel",
+ asys_irq4_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_16),
+ MT8188_SOC_ENUM_EXT("asys_irq5_1x_en_sel",
+ asys_irq5_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_17),
+ MT8188_SOC_ENUM_EXT("asys_irq6_1x_en_sel",
+ asys_irq6_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_18),
+ MT8188_SOC_ENUM_EXT("asys_irq7_1x_en_sel",
+ asys_irq7_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_19),
+ MT8188_SOC_ENUM_EXT("asys_irq8_1x_en_sel",
+ asys_irq8_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_20),
+ MT8188_SOC_ENUM_EXT("asys_irq9_1x_en_sel",
+ asys_irq9_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_21),
+ MT8188_SOC_ENUM_EXT("asys_irq10_1x_en_sel",
+ asys_irq10_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_22),
+ MT8188_SOC_ENUM_EXT("asys_irq11_1x_en_sel",
+ asys_irq11_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_23),
+ MT8188_SOC_ENUM_EXT("asys_irq12_1x_en_sel",
+ asys_irq12_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_24),
+ MT8188_SOC_ENUM_EXT("asys_irq13_1x_en_sel",
+ asys_irq13_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_25),
+ MT8188_SOC_ENUM_EXT("asys_irq14_1x_en_sel",
+ asys_irq14_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_26),
+ MT8188_SOC_ENUM_EXT("asys_irq15_1x_en_sel",
+ asys_irq15_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_27),
+ MT8188_SOC_ENUM_EXT("asys_irq16_1x_en_sel",
+ asys_irq16_1x_en_sel_enum,
+ snd_soc_get_enum_double,
+ mt8188_asys_irq_1x_en_sel_put,
+ MT8188_AFE_IRQ_28),
+ MT8188_SOC_ENUM_EXT("dl2_fs_timing_sel",
+ dl2_fs_timing_sel_enum,
+ mt8188_memif_fs_timing_sel_get,
+ mt8188_memif_fs_timing_sel_put,
+ MT8188_AFE_MEMIF_DL2),
+ MT8188_SOC_ENUM_EXT("dl3_fs_timing_sel",
+ dl3_fs_timing_sel_enum,
+ mt8188_memif_fs_timing_sel_get,
+ mt8188_memif_fs_timing_sel_put,
+ MT8188_AFE_MEMIF_DL3),
+ MT8188_SOC_ENUM_EXT("dl6_fs_timing_sel",
+ dl6_fs_timing_sel_enum,
+ mt8188_memif_fs_timing_sel_get,
+ mt8188_memif_fs_timing_sel_put,
+ MT8188_AFE_MEMIF_DL6),
+ MT8188_SOC_ENUM_EXT("dl8_fs_timing_sel",
+ dl8_fs_timing_sel_enum,
+ mt8188_memif_fs_timing_sel_get,
+ mt8188_memif_fs_timing_sel_put,
+ MT8188_AFE_MEMIF_DL8),
+ MT8188_SOC_ENUM_EXT("dl11_fs_timing_sel",
+ dl11_fs_timing_sel_enum,
+ mt8188_memif_fs_timing_sel_get,
+ mt8188_memif_fs_timing_sel_put,
+ MT8188_AFE_MEMIF_DL11),
+ MT8188_SOC_ENUM_EXT("ul2_fs_timing_sel",
+ ul2_fs_timing_sel_enum,
+ mt8188_memif_fs_timing_sel_get,
+ mt8188_memif_fs_timing_sel_put,
+ MT8188_AFE_MEMIF_UL2),
+ MT8188_SOC_ENUM_EXT("ul4_fs_timing_sel",
+ ul4_fs_timing_sel_enum,
+ mt8188_memif_fs_timing_sel_get,
+ mt8188_memif_fs_timing_sel_put,
+ MT8188_AFE_MEMIF_UL4),
+ MT8188_SOC_ENUM_EXT("ul5_fs_timing_sel",
+ ul5_fs_timing_sel_enum,
+ mt8188_memif_fs_timing_sel_get,
+ mt8188_memif_fs_timing_sel_put,
+ MT8188_AFE_MEMIF_UL5),
+ MT8188_SOC_ENUM_EXT("ul9_fs_timing_sel",
+ ul9_fs_timing_sel_enum,
+ mt8188_memif_fs_timing_sel_get,
+ mt8188_memif_fs_timing_sel_put,
+ MT8188_AFE_MEMIF_UL9),
+ MT8188_SOC_ENUM_EXT("ul10_fs_timing_sel",
+ ul10_fs_timing_sel_enum,
+ mt8188_memif_fs_timing_sel_get,
+ mt8188_memif_fs_timing_sel_put,
+ MT8188_AFE_MEMIF_UL10),
+};
+
static const struct snd_soc_component_driver mt8188_afe_pcm_dai_component = {
.name = "mt8188-afe-pcm-dai",
};
@@ -2583,6 +3087,8 @@ static int mt8188_dai_memif_register(struct mtk_base_afe *afe)
dai->num_dapm_widgets = ARRAY_SIZE(mt8188_memif_widgets);
dai->dapm_routes = mt8188_memif_routes;
dai->num_dapm_routes = ARRAY_SIZE(mt8188_memif_routes);
+ dai->controls = mt8188_memif_controls;
+ dai->num_controls = ARRAY_SIZE(mt8188_memif_controls);
return init_memif_priv_data(afe);
}
--
2.18.0
Add mt8188 audio cg clock control. Audio clock gates are registered to CCF
for reference count and clock parent management.
Signed-off-by: Trevor Wu <[email protected]>
---
sound/soc/mediatek/mt8188/mt8188-audsys-clk.c | 205 ++++++++++++++++++
sound/soc/mediatek/mt8188/mt8188-audsys-clk.h | 15 ++
.../soc/mediatek/mt8188/mt8188-audsys-clkid.h | 83 +++++++
3 files changed, 303 insertions(+)
create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
create mode 100644 sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h
diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
new file mode 100644
index 000000000000..be1c53bf4729
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8188-audsys-clk.c -- MediaTek 8188 audsys clock control
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Chun-Chia Chiu <[email protected]>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include "mt8188-afe-common.h"
+#include "mt8188-audsys-clk.h"
+#include "mt8188-audsys-clkid.h"
+#include "mt8188-reg.h"
+
+struct afe_gate {
+ int id;
+ const char *name;
+ const char *parent_name;
+ int reg;
+ u8 bit;
+ const struct clk_ops *ops;
+ unsigned long flags;
+ u8 cg_flags;
+};
+
+#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, _flags, _cgflags) {\
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .reg = _reg, \
+ .bit = _bit, \
+ .flags = _flags, \
+ .cg_flags = _cgflags, \
+ }
+
+#define GATE_AFE(_id, _name, _parent, _reg, _bit) \
+ GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, \
+ CLK_SET_RATE_PARENT, CLK_GATE_SET_TO_DISABLE)
+
+#define GATE_AUD0(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON0, _bit)
+
+#define GATE_AUD1(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON1, _bit)
+
+#define GATE_AUD3(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON3, _bit)
+
+#define GATE_AUD4(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON4, _bit)
+
+#define GATE_AUD5(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON5, _bit)
+
+#define GATE_AUD6(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON6, _bit)
+
+static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
+ /* AUD0 */
+ GATE_AUD0(CLK_AUD_AFE, "aud_afe", "top_a1sys_hp", 2),
+ GATE_AUD0(CLK_AUD_LRCK_CNT, "aud_lrck_cnt", "top_a1sys_hp", 4),
+ GATE_AUD0(CLK_AUD_SPDIFIN_TUNER_APLL, "aud_spdifin_tuner_apll", "top_apll4", 10),
+ GATE_AUD0(CLK_AUD_SPDIFIN_TUNER_DBG, "aud_spdifin_tuner_dbg", "top_apll4", 11),
+ GATE_AUD0(CLK_AUD_UL_TML, "aud_ul_tml", "top_a1sys_hp", 18),
+ GATE_AUD0(CLK_AUD_APLL1_TUNER, "aud_apll1_tuner", "top_apll1", 19),
+ GATE_AUD0(CLK_AUD_APLL2_TUNER, "aud_apll2_tuner", "top_apll2", 20),
+ GATE_AUD0(CLK_AUD_TOP0_SPDF, "aud_top0_spdf", "top_aud_iec_clk", 21),
+ GATE_AUD0(CLK_AUD_APLL, "aud_apll", "top_apll1", 23),
+ GATE_AUD0(CLK_AUD_APLL2, "aud_apll2", "top_apll2", 24),
+ GATE_AUD0(CLK_AUD_DAC, "aud_dac", "top_a1sys_hp", 25),
+ GATE_AUD0(CLK_AUD_DAC_PREDIS, "aud_dac_predis", "top_a1sys_hp", 26),
+ GATE_AUD0(CLK_AUD_TML, "aud_tml", "top_a1sys_hp", 27),
+ GATE_AUD0(CLK_AUD_ADC, "aud_adc", "top_a1sys_hp", 28),
+ GATE_AUD0(CLK_AUD_DAC_HIRES, "aud_dac_hires", "top_audio_h", 31),
+
+ /* AUD1 */
+ GATE_AUD1(CLK_AUD_A1SYS_HP, "aud_a1sys_hp", "top_a1sys_hp", 2),
+ GATE_AUD1(CLK_AUD_AFE_DMIC1, "aud_afe_dmic1", "top_a1sys_hp", 10),
+ GATE_AUD1(CLK_AUD_AFE_DMIC2, "aud_afe_dmic2", "top_a1sys_hp", 11),
+ GATE_AUD1(CLK_AUD_AFE_DMIC3, "aud_afe_dmic3", "top_a1sys_hp", 12),
+ GATE_AUD1(CLK_AUD_AFE_DMIC4, "aud_afe_dmic4", "top_a1sys_hp", 13),
+ GATE_AUD1(CLK_AUD_AFE_26M_DMIC_TM, "aud_afe_26m_dmic_tm", "top_a1sys_hp", 14),
+ GATE_AUD1(CLK_AUD_UL_TML_HIRES, "aud_ul_tml_hires", "top_audio_h", 16),
+ GATE_AUD1(CLK_AUD_ADC_HIRES, "aud_adc_hires", "top_audio_h", 17),
+
+ /* AUD3 */
+ GATE_AUD3(CLK_AUD_LINEIN_TUNER, "aud_linein_tuner", "top_apll5", 5),
+ GATE_AUD3(CLK_AUD_EARC_TUNER, "aud_earc_tuner", "top_apll3", 7),
+
+ /* AUD4 */
+ GATE_AUD4(CLK_AUD_I2SIN, "aud_i2sin", "top_a1sys_hp", 0),
+ GATE_AUD4(CLK_AUD_TDM_IN, "aud_tdm_in", "top_a1sys_hp", 1),
+ GATE_AUD4(CLK_AUD_I2S_OUT, "aud_i2s_out", "top_a1sys_hp", 6),
+ GATE_AUD4(CLK_AUD_TDM_OUT, "aud_tdm_out", "top_a1sys_hp", 7),
+ GATE_AUD4(CLK_AUD_HDMI_OUT, "aud_hdmi_out", "top_a1sys_hp", 8),
+ GATE_AUD4(CLK_AUD_ASRC11, "aud_asrc11", "top_a1sys_hp", 16),
+ GATE_AUD4(CLK_AUD_ASRC12, "aud_asrc12", "top_a1sys_hp", 17),
+ GATE_AUD4(CLK_AUD_MULTI_IN, "aud_multi_in", "mphone_slave_b", 19),
+ GATE_AUD4(CLK_AUD_INTDIR, "aud_intdir", "top_intdir", 20),
+ GATE_AUD4(CLK_AUD_A1SYS, "aud_a1sys", "top_a1sys_hp", 21),
+ GATE_AUD4(CLK_AUD_A2SYS, "aud_a2sys", "top_a2sys", 22),
+ GATE_AUD4(CLK_AUD_PCMIF, "aud_pcmif", "top_a1sys_hp", 24),
+ GATE_AUD4(CLK_AUD_A3SYS, "aud_a3sys", "top_a3sys", 30),
+ GATE_AUD4(CLK_AUD_A4SYS, "aud_a4sys", "top_a4sys", 31),
+
+ /* AUD5 */
+ GATE_AUD5(CLK_AUD_MEMIF_UL1, "aud_memif_ul1", "top_a1sys_hp", 0),
+ GATE_AUD5(CLK_AUD_MEMIF_UL2, "aud_memif_ul2", "top_a1sys_hp", 1),
+ GATE_AUD5(CLK_AUD_MEMIF_UL3, "aud_memif_ul3", "top_a1sys_hp", 2),
+ GATE_AUD5(CLK_AUD_MEMIF_UL4, "aud_memif_ul4", "top_a1sys_hp", 3),
+ GATE_AUD5(CLK_AUD_MEMIF_UL5, "aud_memif_ul5", "top_a1sys_hp", 4),
+ GATE_AUD5(CLK_AUD_MEMIF_UL6, "aud_memif_ul6", "top_a1sys_hp", 5),
+ GATE_AUD5(CLK_AUD_MEMIF_UL8, "aud_memif_ul8", "top_a1sys_hp", 7),
+ GATE_AUD5(CLK_AUD_MEMIF_UL9, "aud_memif_ul9", "top_a1sys_hp", 8),
+ GATE_AUD5(CLK_AUD_MEMIF_UL10, "aud_memif_ul10", "top_a1sys_hp", 9),
+ GATE_AUD5(CLK_AUD_MEMIF_DL2, "aud_memif_dl2", "top_a1sys_hp", 18),
+ GATE_AUD5(CLK_AUD_MEMIF_DL3, "aud_memif_dl3", "top_a1sys_hp", 19),
+ GATE_AUD5(CLK_AUD_MEMIF_DL6, "aud_memif_dl6", "top_a1sys_hp", 22),
+ GATE_AUD5(CLK_AUD_MEMIF_DL7, "aud_memif_dl7", "top_a1sys_hp", 23),
+ GATE_AUD5(CLK_AUD_MEMIF_DL8, "aud_memif_dl8", "top_a1sys_hp", 24),
+ GATE_AUD5(CLK_AUD_MEMIF_DL10, "aud_memif_dl10", "top_a1sys_hp", 26),
+ GATE_AUD5(CLK_AUD_MEMIF_DL11, "aud_memif_dl11", "top_a1sys_hp", 27),
+
+ /* AUD6 */
+ GATE_AUD6(CLK_AUD_GASRC0, "aud_gasrc0", "top_asm_h", 0),
+ GATE_AUD6(CLK_AUD_GASRC1, "aud_gasrc1", "top_asm_h", 1),
+ GATE_AUD6(CLK_AUD_GASRC2, "aud_gasrc2", "top_asm_h", 2),
+ GATE_AUD6(CLK_AUD_GASRC3, "aud_gasrc3", "top_asm_h", 3),
+ GATE_AUD6(CLK_AUD_GASRC4, "aud_gasrc4", "top_asm_h", 4),
+ GATE_AUD6(CLK_AUD_GASRC5, "aud_gasrc5", "top_asm_h", 5),
+ GATE_AUD6(CLK_AUD_GASRC6, "aud_gasrc6", "top_asm_h", 6),
+ GATE_AUD6(CLK_AUD_GASRC7, "aud_gasrc7", "top_asm_h", 7),
+ GATE_AUD6(CLK_AUD_GASRC8, "aud_gasrc8", "top_asm_h", 8),
+ GATE_AUD6(CLK_AUD_GASRC9, "aud_gasrc9", "top_asm_h", 9),
+ GATE_AUD6(CLK_AUD_GASRC10, "aud_gasrc10", "top_asm_h", 10),
+ GATE_AUD6(CLK_AUD_GASRC11, "aud_gasrc11", "top_asm_h", 11),
+};
+
+int mt8188_audsys_clk_register(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct clk *clk;
+ struct clk_lookup *cl;
+ int i;
+
+ afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AUD_NR_CLK,
+ sizeof(*afe_priv->lookup),
+ GFP_KERNEL);
+
+ if (!afe_priv->lookup)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
+ const struct afe_gate *gate = &aud_clks[i];
+
+ clk = clk_register_gate(afe->dev, gate->name, gate->parent_name,
+ gate->flags, afe->base_addr + gate->reg,
+ gate->bit, gate->cg_flags, NULL);
+
+ if (IS_ERR(clk)) {
+ dev_err(afe->dev, "Failed to register clk %s: %ld\n",
+ gate->name, PTR_ERR(clk));
+ continue;
+ }
+
+ /* add clk_lookup for devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */
+ cl = kzalloc(sizeof(*cl), GFP_KERNEL);
+ if (!cl)
+ return -ENOMEM;
+
+ cl->clk = clk;
+ cl->con_id = gate->name;
+ cl->dev_id = dev_name(afe->dev);
+ cl->clk_hw = NULL;
+ clkdev_add(cl);
+
+ afe_priv->lookup[i] = cl;
+ }
+
+ return 0;
+}
+
+void mt8188_audsys_clk_unregister(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct clk *clk;
+ struct clk_lookup *cl;
+ int i;
+
+ if (!afe_priv)
+ return;
+
+ for (i = 0; i < CLK_AUD_NR_CLK; i++) {
+ cl = afe_priv->lookup[i];
+ if (!cl)
+ continue;
+
+ clk = cl->clk;
+ clk_unregister_gate(clk);
+
+ clkdev_drop(cl);
+ }
+}
diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
new file mode 100644
index 000000000000..6c5f463ad7e4
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8188-audsys-clk.h -- MediaTek 8188 audsys clock definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Chun-Chia Chiu <[email protected]>
+ */
+
+#ifndef _MT8188_AUDSYS_CLK_H_
+#define _MT8188_AUDSYS_CLK_H_
+
+int mt8188_audsys_clk_register(struct mtk_base_afe *afe);
+void mt8188_audsys_clk_unregister(struct mtk_base_afe *afe);
+
+#endif
diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h b/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h
new file mode 100644
index 000000000000..6f34ffc760e0
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8188-audsys-clkid.h -- MediaTek 8188 audsys clock id definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Chun-Chia Chiu <[email protected]>
+ */
+
+#ifndef _MT8188_AUDSYS_CLKID_H_
+#define _MT8188_AUDSYS_CLKID_H_
+
+enum{
+ CLK_AUD_AFE,
+ CLK_AUD_LRCK_CNT,
+ CLK_AUD_SPDIFIN_TUNER_APLL,
+ CLK_AUD_SPDIFIN_TUNER_DBG,
+ CLK_AUD_UL_TML,
+ CLK_AUD_APLL1_TUNER,
+ CLK_AUD_APLL2_TUNER,
+ CLK_AUD_TOP0_SPDF,
+ CLK_AUD_APLL,
+ CLK_AUD_APLL2,
+ CLK_AUD_DAC,
+ CLK_AUD_DAC_PREDIS,
+ CLK_AUD_TML,
+ CLK_AUD_ADC,
+ CLK_AUD_DAC_HIRES,
+ CLK_AUD_A1SYS_HP,
+ CLK_AUD_AFE_DMIC1,
+ CLK_AUD_AFE_DMIC2,
+ CLK_AUD_AFE_DMIC3,
+ CLK_AUD_AFE_DMIC4,
+ CLK_AUD_AFE_26M_DMIC_TM,
+ CLK_AUD_UL_TML_HIRES,
+ CLK_AUD_ADC_HIRES,
+ CLK_AUD_LINEIN_TUNER,
+ CLK_AUD_EARC_TUNER,
+ CLK_AUD_I2SIN,
+ CLK_AUD_TDM_IN,
+ CLK_AUD_I2S_OUT,
+ CLK_AUD_TDM_OUT,
+ CLK_AUD_HDMI_OUT,
+ CLK_AUD_ASRC11,
+ CLK_AUD_ASRC12,
+ CLK_AUD_MULTI_IN,
+ CLK_AUD_INTDIR,
+ CLK_AUD_A1SYS,
+ CLK_AUD_A2SYS,
+ CLK_AUD_PCMIF,
+ CLK_AUD_A3SYS,
+ CLK_AUD_A4SYS,
+ CLK_AUD_MEMIF_UL1,
+ CLK_AUD_MEMIF_UL2,
+ CLK_AUD_MEMIF_UL3,
+ CLK_AUD_MEMIF_UL4,
+ CLK_AUD_MEMIF_UL5,
+ CLK_AUD_MEMIF_UL6,
+ CLK_AUD_MEMIF_UL8,
+ CLK_AUD_MEMIF_UL9,
+ CLK_AUD_MEMIF_UL10,
+ CLK_AUD_MEMIF_DL2,
+ CLK_AUD_MEMIF_DL3,
+ CLK_AUD_MEMIF_DL6,
+ CLK_AUD_MEMIF_DL7,
+ CLK_AUD_MEMIF_DL8,
+ CLK_AUD_MEMIF_DL10,
+ CLK_AUD_MEMIF_DL11,
+ CLK_AUD_GASRC0,
+ CLK_AUD_GASRC1,
+ CLK_AUD_GASRC2,
+ CLK_AUD_GASRC3,
+ CLK_AUD_GASRC4,
+ CLK_AUD_GASRC5,
+ CLK_AUD_GASRC6,
+ CLK_AUD_GASRC7,
+ CLK_AUD_GASRC8,
+ CLK_AUD_GASRC9,
+ CLK_AUD_GASRC10,
+ CLK_AUD_GASRC11,
+ CLK_AUD_NR_CLK,
+};
+
+#endif
--
2.18.0
Add mt8188 pcmif dai driver support
Signed-off-by: Trevor Wu <[email protected]>
---
sound/soc/mediatek/mt8188/mt8188-dai-pcm.c | 367 +++++++++++++++++++++
1 file changed, 367 insertions(+)
create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-pcm.c
diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c b/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c
new file mode 100644
index 000000000000..3f1696dcf81c
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI PCM I/F Control
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Bicycle Tsai <[email protected]>
+ * Trevor Wu <[email protected]>
+ * Chun-Chia Chiu <[email protected]>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8188-afe-clk.h"
+#include "mt8188-afe-common.h"
+#include "mt8188-reg.h"
+
+enum {
+ MTK_DAI_PCM_FMT_I2S,
+ MTK_DAI_PCM_FMT_EIAJ,
+ MTK_DAI_PCM_FMT_MODEA,
+ MTK_DAI_PCM_FMT_MODEB,
+};
+
+enum {
+ MTK_DAI_PCM_CLK_A1SYS,
+ MTK_DAI_PCM_CLK_A2SYS,
+ MTK_DAI_PCM_CLK_26M_48K,
+ MTK_DAI_PCM_CLK_26M_441K,
+};
+
+struct mtk_dai_pcm_rate {
+ unsigned int rate;
+ unsigned int reg_value;
+};
+
+struct mtk_dai_pcmif_priv {
+ unsigned int slave_mode;
+ unsigned int lrck_inv;
+ unsigned int bck_inv;
+ unsigned int format;
+};
+
+static const struct mtk_dai_pcm_rate mtk_dai_pcm_rates[] = {
+ { .rate = 8000, .reg_value = 0, },
+ { .rate = 16000, .reg_value = 1, },
+ { .rate = 32000, .reg_value = 2, },
+ { .rate = 48000, .reg_value = 3, },
+ { .rate = 11025, .reg_value = 1, },
+ { .rate = 22050, .reg_value = 2, },
+ { .rate = 44100, .reg_value = 3, },
+};
+
+static int mtk_dai_pcm_mode(unsigned int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mtk_dai_pcm_rates); i++)
+ if (mtk_dai_pcm_rates[i].rate == rate)
+ return mtk_dai_pcm_rates[i].reg_value;
+
+ return -EINVAL;
+}
+
+static const struct snd_kcontrol_new mtk_dai_pcm_o000_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN0, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN0_2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_pcm_o001_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN1, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN1_2, 7, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+ SND_SOC_DAPM_MIXER("I002", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I003", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("O000", SND_SOC_NOPM, 0, 0,
+ mtk_dai_pcm_o000_mix,
+ ARRAY_SIZE(mtk_dai_pcm_o000_mix)),
+ SND_SOC_DAPM_MIXER("O001", SND_SOC_NOPM, 0, 0,
+ mtk_dai_pcm_o001_mix,
+ ARRAY_SIZE(mtk_dai_pcm_o001_mix)),
+
+ SND_SOC_DAPM_SUPPLY("PCM_1_EN", PCM_INTF_CON1, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_INPUT("PCM1_INPUT"),
+ SND_SOC_DAPM_OUTPUT("PCM1_OUTPUT"),
+
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_asrc11"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_asrc12"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_pcmif"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+ {"I002", NULL, "PCM1 Capture"},
+ {"I003", NULL, "PCM1 Capture"},
+
+ {"O000", "I000 Switch", "I000"},
+ {"O001", "I001 Switch", "I001"},
+
+ {"O000", "I070 Switch", "I070"},
+ {"O001", "I071 Switch", "I071"},
+
+ {"PCM1 Playback", NULL, "O000"},
+ {"PCM1 Playback", NULL, "O001"},
+
+ {"PCM1 Playback", NULL, "PCM_1_EN"},
+ {"PCM1 Playback", NULL, "aud_asrc12"},
+ {"PCM1 Playback", NULL, "aud_pcmif"},
+
+ {"PCM1 Capture", NULL, "PCM_1_EN"},
+ {"PCM1 Capture", NULL, "aud_asrc11"},
+ {"PCM1 Capture", NULL, "aud_pcmif"},
+
+ {"PCM1_OUTPUT", NULL, "PCM1 Playback"},
+ {"PCM1 Capture", NULL, "PCM1_INPUT"},
+};
+
+static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime * const runtime = substream->runtime;
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_pcmif_priv *pcmif_priv = NULL;
+ unsigned int slave_mode;
+ unsigned int lrck_inv;
+ unsigned int bck_inv;
+ unsigned int fmt;
+ unsigned int bit_width = dai->sample_bits;
+ unsigned int val = 0;
+ unsigned int mask = 0;
+ int fs = 0;
+ int mode = 0;
+
+ if (dai->id < 0)
+ return -EINVAL;
+
+ pcmif_priv = afe_priv->dai_priv[dai->id];
+ slave_mode = pcmif_priv->slave_mode;
+ lrck_inv = pcmif_priv->lrck_inv;
+ bck_inv = pcmif_priv->bck_inv;
+ fmt = pcmif_priv->format;
+
+ /* sync freq mode */
+ fs = mt8188_afe_fs_timing(runtime->rate);
+ if (fs < 0)
+ return -EINVAL;
+
+ val |= FIELD_PREP(PCM_INTF_CON2_SYNC_FREQ_MODE_MASK, fs);
+ mask |= PCM_INTF_CON2_SYNC_FREQ_MODE_MASK;
+
+ /* clk domain sel */
+ if (runtime->rate % 8000)
+ val |= FIELD_PREP(PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK,
+ MTK_DAI_PCM_CLK_26M_441K);
+ else
+ val |= FIELD_PREP(PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK,
+ MTK_DAI_PCM_CLK_26M_48K);
+ mask |= PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK;
+
+ regmap_update_bits(afe->regmap, PCM_INTF_CON2, mask, val);
+
+ val = 0;
+ mask = 0;
+
+ /* pcm mode */
+ mode = mtk_dai_pcm_mode(runtime->rate);
+ if (mode < 0)
+ return -EINVAL;
+
+ val |= FIELD_PREP(PCM_INTF_CON1_PCM_MODE_MASK, mode);
+ mask |= PCM_INTF_CON1_PCM_MODE_MASK;
+
+ /* pcm format */
+ val |= FIELD_PREP(PCM_INTF_CON1_PCM_FMT_MASK, fmt);
+ mask |= PCM_INTF_CON1_PCM_FMT_MASK;
+
+ /* pcm sync length */
+ if (fmt == MTK_DAI_PCM_FMT_MODEA ||
+ fmt == MTK_DAI_PCM_FMT_MODEB)
+ val |= FIELD_PREP(PCM_INTF_CON1_SYNC_LENGTH_MASK, 1);
+ else
+ val |= FIELD_PREP(PCM_INTF_CON1_SYNC_LENGTH_MASK, bit_width);
+ mask |= PCM_INTF_CON1_SYNC_LENGTH_MASK;
+
+ /* pcm bits, word length */
+ if (bit_width > 16) {
+ val |= PCM_INTF_CON1_PCM_24BIT;
+ val |= PCM_INTF_CON1_PCM_WLEN_64BCK;
+ } else {
+ val |= PCM_INTF_CON1_PCM_16BIT;
+ val |= PCM_INTF_CON1_PCM_WLEN_32BCK;
+ }
+ mask |= PCM_INTF_CON1_PCM_BIT_MASK;
+ mask |= PCM_INTF_CON1_PCM_WLEN_MASK;
+
+ /* master/slave */
+ if (!slave_mode) {
+ val |= PCM_INTF_CON1_PCM_MASTER;
+
+ if (lrck_inv)
+ val |= PCM_INTF_CON1_SYNC_OUT_INV;
+ if (bck_inv)
+ val |= PCM_INTF_CON1_BCLK_OUT_INV;
+ mask |= PCM_INTF_CON1_CLK_OUT_INV_MASK;
+ } else {
+ val |= PCM_INTF_CON1_PCM_SLAVE;
+
+ if (lrck_inv)
+ val |= PCM_INTF_CON1_SYNC_IN_INV;
+ if (bck_inv)
+ val |= PCM_INTF_CON1_BCLK_IN_INV;
+ mask |= PCM_INTF_CON1_CLK_IN_INV_MASK;
+
+ // TODO: add asrc setting for slave mode
+ }
+ mask |= PCM_INTF_CON1_PCM_M_S_MASK;
+
+ regmap_update_bits(afe->regmap, PCM_INTF_CON1, mask, val);
+
+ return 0;
+}
+
+/* dai ops */
+static int mtk_dai_pcm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ if (dai->playback_widget->active || dai->capture_widget->active)
+ return 0;
+
+ return mtk_dai_pcm_configure(substream, dai);
+}
+
+static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_pcmif_priv *pcmif_priv = NULL;
+
+ dev_dbg(dai->dev, "%s fmt 0x%x\n", __func__, fmt);
+
+ if (dai->id < 0)
+ return -EINVAL;
+
+ pcmif_priv = afe_priv->dai_priv[dai->id];
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ pcmif_priv->format = MTK_DAI_PCM_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ pcmif_priv->format = MTK_DAI_PCM_FMT_MODEA;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ pcmif_priv->format = MTK_DAI_PCM_FMT_MODEB;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ pcmif_priv->bck_inv = 0;
+ pcmif_priv->lrck_inv = 0;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ pcmif_priv->bck_inv = 0;
+ pcmif_priv->lrck_inv = 1;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ pcmif_priv->bck_inv = 1;
+ pcmif_priv->lrck_inv = 0;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ pcmif_priv->bck_inv = 1;
+ pcmif_priv->lrck_inv = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
+ pcmif_priv->slave_mode = 1;
+ break;
+ case SND_SOC_DAIFMT_BP_FP:
+ pcmif_priv->slave_mode = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
+ .prepare = mtk_dai_pcm_prepare,
+ .set_fmt = mtk_dai_pcm_set_fmt,
+};
+
+/* dai driver */
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
+ {
+ .name = "PCM1",
+ .id = MT8188_AFE_IO_PCM,
+ .playback = {
+ .stream_name = "PCM1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .capture = {
+ .stream_name = "PCM1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_dai_pcm_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+ },
+};
+
+static int init_pcmif_priv_data(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_pcmif_priv *pcmif_priv;
+
+ pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_pcmif_priv),
+ GFP_KERNEL);
+ if (!pcmif_priv)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[MT8188_AFE_IO_PCM] = pcmif_priv;
+ return 0;
+}
+
+int mt8188_dai_pcm_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_pcm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+
+ dai->dapm_widgets = mtk_dai_pcm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+ dai->dapm_routes = mtk_dai_pcm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+
+ return init_pcmif_priv_data(afe);
+}
--
2.18.0
Add mt8188 etdm dai driver support.
Signed-off-by: Trevor Wu <[email protected]>
---
I don't add Reviewed-by tag because one new header file is included
in the patch to resolve compiling issue found by kernel test robot.
Additionally, I re-layout the code for better understanding of the
follow-up patch.
---
sound/soc/mediatek/mt8188/mt8188-dai-etdm.c | 2591 +++++++++++++++++++
1 file changed, 2591 insertions(+)
create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
new file mode 100644
index 000000000000..c653fa5e3f85
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
@@ -0,0 +1,2591 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI eTDM Control
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Bicycle Tsai <[email protected]>
+ * Trevor Wu <[email protected]>
+ * Chun-Chia Chiu <[email protected]>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8188-afe-clk.h"
+#include "mt8188-afe-common.h"
+#include "mt8188-reg.h"
+
+#define MT8188_ETDM_MAX_CHANNELS 16
+#define MT8188_ETDM_NORMAL_MAX_BCK_RATE 24576000
+#define ETDM_TO_DAI_ID(x) ((x) + MT8188_AFE_IO_ETDM_START)
+#define ENUM_TO_STR(x) #x
+
+enum {
+ MTK_DAI_ETDM_FORMAT_I2S = 0,
+ MTK_DAI_ETDM_FORMAT_LJ,
+ MTK_DAI_ETDM_FORMAT_RJ,
+ MTK_DAI_ETDM_FORMAT_EIAJ,
+ MTK_DAI_ETDM_FORMAT_DSPA,
+ MTK_DAI_ETDM_FORMAT_DSPB,
+};
+
+enum {
+ MTK_DAI_ETDM_DATA_ONE_PIN = 0,
+ MTK_DAI_ETDM_DATA_MULTI_PIN,
+};
+
+enum {
+ ETDM_IN,
+ ETDM_OUT,
+};
+
+enum {
+ COWORK_ETDM_NONE = 0,
+ COWORK_ETDM_IN1_M = 2,
+ COWORK_ETDM_IN1_S = 3,
+ COWORK_ETDM_IN2_M = 4,
+ COWORK_ETDM_IN2_S = 5,
+ COWORK_ETDM_OUT1_M = 10,
+ COWORK_ETDM_OUT1_S = 11,
+ COWORK_ETDM_OUT2_M = 12,
+ COWORK_ETDM_OUT2_S = 13,
+ COWORK_ETDM_OUT3_M = 14,
+ COWORK_ETDM_OUT3_S = 15,
+};
+
+enum {
+ ETDM_RELATCH_TIMING_A1A2SYS,
+ ETDM_RELATCH_TIMING_A3SYS,
+ ETDM_RELATCH_TIMING_A4SYS,
+};
+
+enum {
+ ETDM_SYNC_NONE,
+ ETDM_SYNC_FROM_IN1 = 2,
+ ETDM_SYNC_FROM_IN2 = 4,
+ ETDM_SYNC_FROM_OUT1 = 10,
+ ETDM_SYNC_FROM_OUT2 = 12,
+ ETDM_SYNC_FROM_OUT3 = 14,
+};
+
+struct etdm_con_reg {
+ unsigned int con0;
+ unsigned int con1;
+ unsigned int con2;
+ unsigned int con3;
+ unsigned int con4;
+ unsigned int con5;
+};
+
+struct mtk_dai_etdm_rate {
+ unsigned int rate;
+ unsigned int reg_value;
+};
+
+struct mtk_dai_etdm_priv {
+ unsigned int clock_mode;
+ unsigned int data_mode;
+ bool slave_mode;
+ bool lrck_inv;
+ bool bck_inv;
+ unsigned int format;
+ unsigned int slots;
+ unsigned int lrck_width;
+ unsigned int mclk_freq;
+ unsigned int mclk_fixed_apll;
+ unsigned int mclk_apll;
+ unsigned int mclk_dir;
+ int cowork_source_id; //dai id
+ unsigned int cowork_slv_count;
+ int cowork_slv_id[MT8188_AFE_IO_ETDM_NUM - 1]; //dai_id
+ bool in_disable_ch[MT8188_ETDM_MAX_CHANNELS];
+ unsigned int en_ref_cnt;
+ bool is_prepared;
+};
+
+static const struct mtk_dai_etdm_rate mt8188_etdm_rates[] = {
+ { .rate = 8000, .reg_value = 0, },
+ { .rate = 12000, .reg_value = 1, },
+ { .rate = 16000, .reg_value = 2, },
+ { .rate = 24000, .reg_value = 3, },
+ { .rate = 32000, .reg_value = 4, },
+ { .rate = 48000, .reg_value = 5, },
+ { .rate = 96000, .reg_value = 7, },
+ { .rate = 192000, .reg_value = 9, },
+ { .rate = 384000, .reg_value = 11, },
+ { .rate = 11025, .reg_value = 16, },
+ { .rate = 22050, .reg_value = 17, },
+ { .rate = 44100, .reg_value = 18, },
+ { .rate = 88200, .reg_value = 19, },
+ { .rate = 176400, .reg_value = 20, },
+ { .rate = 352800, .reg_value = 21, },
+};
+
+static int get_etdm_fs_timing(unsigned int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mt8188_etdm_rates); i++)
+ if (mt8188_etdm_rates[i].rate == rate)
+ return mt8188_etdm_rates[i].reg_value;
+
+ return -EINVAL;
+}
+
+static unsigned int get_etdm_ch_fixup(unsigned int channels)
+{
+ if (channels > 16)
+ return 24;
+ else if (channels > 8)
+ return 16;
+ else if (channels > 4)
+ return 8;
+ else if (channels > 2)
+ return 4;
+ else
+ return 2;
+}
+
+static int get_etdm_reg(unsigned int dai_id, struct etdm_con_reg *etdm_reg)
+{
+ switch (dai_id) {
+ case MT8188_AFE_IO_ETDM1_IN:
+ etdm_reg->con0 = ETDM_IN1_CON0;
+ etdm_reg->con1 = ETDM_IN1_CON1;
+ etdm_reg->con2 = ETDM_IN1_CON2;
+ etdm_reg->con3 = ETDM_IN1_CON3;
+ etdm_reg->con4 = ETDM_IN1_CON4;
+ etdm_reg->con5 = ETDM_IN1_CON5;
+ break;
+ case MT8188_AFE_IO_ETDM2_IN:
+ etdm_reg->con0 = ETDM_IN2_CON0;
+ etdm_reg->con1 = ETDM_IN2_CON1;
+ etdm_reg->con2 = ETDM_IN2_CON2;
+ etdm_reg->con3 = ETDM_IN2_CON3;
+ etdm_reg->con4 = ETDM_IN2_CON4;
+ etdm_reg->con5 = ETDM_IN2_CON5;
+ break;
+ case MT8188_AFE_IO_ETDM1_OUT:
+ etdm_reg->con0 = ETDM_OUT1_CON0;
+ etdm_reg->con1 = ETDM_OUT1_CON1;
+ etdm_reg->con2 = ETDM_OUT1_CON2;
+ etdm_reg->con3 = ETDM_OUT1_CON3;
+ etdm_reg->con4 = ETDM_OUT1_CON4;
+ etdm_reg->con5 = ETDM_OUT1_CON5;
+ break;
+ case MT8188_AFE_IO_ETDM2_OUT:
+ etdm_reg->con0 = ETDM_OUT2_CON0;
+ etdm_reg->con1 = ETDM_OUT2_CON1;
+ etdm_reg->con2 = ETDM_OUT2_CON2;
+ etdm_reg->con3 = ETDM_OUT2_CON3;
+ etdm_reg->con4 = ETDM_OUT2_CON4;
+ etdm_reg->con5 = ETDM_OUT2_CON5;
+ break;
+ case MT8188_AFE_IO_ETDM3_OUT:
+ case MT8188_AFE_IO_DPTX:
+ etdm_reg->con0 = ETDM_OUT3_CON0;
+ etdm_reg->con1 = ETDM_OUT3_CON1;
+ etdm_reg->con2 = ETDM_OUT3_CON2;
+ etdm_reg->con3 = ETDM_OUT3_CON3;
+ etdm_reg->con4 = ETDM_OUT3_CON4;
+ etdm_reg->con5 = ETDM_OUT3_CON5;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int get_etdm_dir(unsigned int dai_id)
+{
+ switch (dai_id) {
+ case MT8188_AFE_IO_ETDM1_IN:
+ case MT8188_AFE_IO_ETDM2_IN:
+ return ETDM_IN;
+ case MT8188_AFE_IO_ETDM1_OUT:
+ case MT8188_AFE_IO_ETDM2_OUT:
+ case MT8188_AFE_IO_ETDM3_OUT:
+ return ETDM_OUT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int get_etdm_wlen(unsigned int bitwidth)
+{
+ return bitwidth <= 16 ? 16 : 32;
+}
+
+static bool is_valid_etdm_dai(int dai_id)
+{
+ if (dai_id < MT8188_AFE_IO_ETDM_START || dai_id >= MT8188_AFE_IO_ETDM_END)
+ return false;
+ else
+ return true;
+}
+
+static int is_cowork_mode(struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+
+ if (!is_valid_etdm_dai(dai->id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai->id];
+
+ return (etdm_data->cowork_slv_count > 0 ||
+ etdm_data->cowork_source_id != COWORK_ETDM_NONE);
+}
+
+static int sync_to_dai_id(int source_sel)
+{
+ switch (source_sel) {
+ case ETDM_SYNC_FROM_IN1:
+ return MT8188_AFE_IO_ETDM1_IN;
+ case ETDM_SYNC_FROM_IN2:
+ return MT8188_AFE_IO_ETDM2_IN;
+ case ETDM_SYNC_FROM_OUT1:
+ return MT8188_AFE_IO_ETDM1_OUT;
+ case ETDM_SYNC_FROM_OUT2:
+ return MT8188_AFE_IO_ETDM2_OUT;
+ case ETDM_SYNC_FROM_OUT3:
+ return MT8188_AFE_IO_ETDM3_OUT;
+ default:
+ return 0;
+ }
+}
+
+static int get_etdm_cowork_master_id(struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ int dai_id;
+
+ if (!is_valid_etdm_dai(dai->id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai->id];
+ dai_id = etdm_data->cowork_source_id;
+
+ if (dai_id == COWORK_ETDM_NONE)
+ dai_id = dai->id;
+
+ return dai_id;
+}
+
+static int mtk_dai_etdm_get_cg_id_by_dai_id(int dai_id)
+{
+ int cg_id = -1;
+
+ switch (dai_id) {
+ case MT8188_AFE_IO_DPTX:
+ cg_id = MT8188_CLK_AUD_HDMI_OUT;
+ break;
+ case MT8188_AFE_IO_ETDM1_IN:
+ cg_id = MT8188_CLK_AUD_TDM_IN;
+ break;
+ case MT8188_AFE_IO_ETDM2_IN:
+ cg_id = MT8188_CLK_AUD_I2SIN;
+ break;
+ case MT8188_AFE_IO_ETDM1_OUT:
+ cg_id = MT8188_CLK_AUD_TDM_OUT;
+ break;
+ case MT8188_AFE_IO_ETDM2_OUT:
+ cg_id = MT8188_CLK_AUD_I2S_OUT;
+ break;
+ case MT8188_AFE_IO_ETDM3_OUT:
+ cg_id = MT8188_CLK_AUD_HDMI_OUT;
+ break;
+ default:
+ break;
+ }
+
+ return cg_id;
+}
+
+static int mtk_dai_etdm_get_clk_id_by_dai_id(int dai_id)
+{
+ int clk_id = -1;
+
+ switch (dai_id) {
+ case MT8188_AFE_IO_DPTX:
+ clk_id = MT8188_CLK_TOP_DPTX_M_SEL;
+ break;
+ case MT8188_AFE_IO_ETDM1_IN:
+ clk_id = MT8188_CLK_TOP_I2SI1_M_SEL;
+ break;
+ case MT8188_AFE_IO_ETDM2_IN:
+ clk_id = MT8188_CLK_TOP_I2SI2_M_SEL;
+ break;
+ case MT8188_AFE_IO_ETDM1_OUT:
+ clk_id = MT8188_CLK_TOP_I2SO1_M_SEL;
+ break;
+ case MT8188_AFE_IO_ETDM2_OUT:
+ clk_id = MT8188_CLK_TOP_I2SO2_M_SEL;
+ break;
+ case MT8188_AFE_IO_ETDM3_OUT:
+ default:
+ break;
+ }
+
+ return clk_id;
+}
+
+static int mtk_dai_etdm_get_clkdiv_id_by_dai_id(int dai_id)
+{
+ int clk_id = -1;
+
+ switch (dai_id) {
+ case MT8188_AFE_IO_DPTX:
+ clk_id = MT8188_CLK_TOP_APLL12_DIV9;
+ break;
+ case MT8188_AFE_IO_ETDM1_IN:
+ clk_id = MT8188_CLK_TOP_APLL12_DIV0;
+ break;
+ case MT8188_AFE_IO_ETDM2_IN:
+ clk_id = MT8188_CLK_TOP_APLL12_DIV1;
+ break;
+ case MT8188_AFE_IO_ETDM1_OUT:
+ clk_id = MT8188_CLK_TOP_APLL12_DIV2;
+ break;
+ case MT8188_AFE_IO_ETDM2_OUT:
+ clk_id = MT8188_CLK_TOP_APLL12_DIV3;
+ break;
+ case MT8188_AFE_IO_ETDM3_OUT:
+ default:
+ break;
+ }
+
+ return clk_id;
+}
+
+static int mtk_dai_etdm_enable_mclk(struct mtk_base_afe *afe, int dai_id)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ int clkdiv_id = mtk_dai_etdm_get_clkdiv_id_by_dai_id(dai_id);
+
+ if (clkdiv_id < 0)
+ return -EINVAL;
+
+ mt8188_afe_enable_clk(afe, afe_priv->clk[clkdiv_id]);
+
+ return 0;
+}
+
+static int mtk_dai_etdm_disable_mclk(struct mtk_base_afe *afe, int dai_id)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ int clkdiv_id = mtk_dai_etdm_get_clkdiv_id_by_dai_id(dai_id);
+
+ if (clkdiv_id < 0)
+ return -EINVAL;
+
+ mt8188_afe_disable_clk(afe, afe_priv->clk[clkdiv_id]);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o048_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN48, 20, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN48, 22, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I046 Switch", AFE_CONN48_1, 14, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN48_2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o049_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN49, 21, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN49, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I047 Switch", AFE_CONN49_1, 15, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN49_2, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o050_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I024 Switch", AFE_CONN50, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I048 Switch", AFE_CONN50_1, 16, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o051_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I025 Switch", AFE_CONN51, 25, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I049 Switch", AFE_CONN51_1, 17, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o052_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I026 Switch", AFE_CONN52, 26, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I050 Switch", AFE_CONN52_1, 18, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o053_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I027 Switch", AFE_CONN53, 27, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I051 Switch", AFE_CONN53_1, 19, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o054_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I028 Switch", AFE_CONN54, 28, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I052 Switch", AFE_CONN54_1, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o055_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I029 Switch", AFE_CONN55, 29, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I053 Switch", AFE_CONN55_1, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o056_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I030 Switch", AFE_CONN56, 30, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I054 Switch", AFE_CONN56_1, 22, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o057_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I031 Switch", AFE_CONN57, 31, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I055 Switch", AFE_CONN57_1, 23, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o058_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I032 Switch", AFE_CONN58_1, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I056 Switch", AFE_CONN58_1, 24, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o059_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I033 Switch", AFE_CONN59_1, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I057 Switch", AFE_CONN59_1, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o060_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I034 Switch", AFE_CONN60_1, 2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I058 Switch", AFE_CONN60_1, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o061_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I035 Switch", AFE_CONN61_1, 3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I059 Switch", AFE_CONN61_1, 27, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o062_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I036 Switch", AFE_CONN62_1, 4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I060 Switch", AFE_CONN62_1, 28, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o063_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I037 Switch", AFE_CONN63_1, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I061 Switch", AFE_CONN63_1, 29, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o072_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN72, 20, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN72, 22, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I046 Switch", AFE_CONN72_1, 14, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN72_2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o073_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN73, 21, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN73, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I047 Switch", AFE_CONN73_1, 15, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN73_2, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o074_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I024 Switch", AFE_CONN74, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I048 Switch", AFE_CONN74_1, 16, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o075_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I025 Switch", AFE_CONN75, 25, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I049 Switch", AFE_CONN75_1, 17, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o076_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I026 Switch", AFE_CONN76, 26, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I050 Switch", AFE_CONN76_1, 18, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o077_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I027 Switch", AFE_CONN77, 27, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I051 Switch", AFE_CONN77_1, 19, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o078_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I028 Switch", AFE_CONN78, 28, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I052 Switch", AFE_CONN78_1, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o079_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I029 Switch", AFE_CONN79, 29, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I053 Switch", AFE_CONN79_1, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o080_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I030 Switch", AFE_CONN80, 30, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I054 Switch", AFE_CONN80_1, 22, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o081_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I031 Switch", AFE_CONN81, 31, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I055 Switch", AFE_CONN81_1, 23, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o082_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I032 Switch", AFE_CONN82_1, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I056 Switch", AFE_CONN82_1, 24, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o083_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I033 Switch", AFE_CONN83_1, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I057 Switch", AFE_CONN83_1, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o084_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I034 Switch", AFE_CONN84_1, 2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I058 Switch", AFE_CONN84_1, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o085_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I035 Switch", AFE_CONN85_1, 3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I059 Switch", AFE_CONN85_1, 27, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o086_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I036 Switch", AFE_CONN86_1, 4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I060 Switch", AFE_CONN86_1, 28, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_etdm_o087_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I037 Switch", AFE_CONN87_1, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I061 Switch", AFE_CONN87_1, 29, 1, 0),
+};
+
+static const char * const mt8188_etdm_clk_src_sel_text[] = {
+ "26m",
+ "a1sys_a2sys",
+ "a3sys",
+ "a4sys",
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(etdmout_clk_src_enum,
+ mt8188_etdm_clk_src_sel_text);
+
+static const char * const hdmitx_dptx_mux_map[] = {
+ "Disconnect", "Connect",
+};
+
+static int hdmitx_dptx_mux_map_value[] = {
+ 0, 1,
+};
+
+/* HDMI_OUT_MUX */
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(hdmi_out_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ 1,
+ hdmitx_dptx_mux_map,
+ hdmitx_dptx_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_out_mux_control =
+ SOC_DAPM_ENUM("HDMI_OUT_MUX", hdmi_out_mux_map_enum);
+
+/* DPTX_OUT_MUX */
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(dptx_out_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ 1,
+ hdmitx_dptx_mux_map,
+ hdmitx_dptx_mux_map_value);
+
+static const struct snd_kcontrol_new dptx_out_mux_control =
+ SOC_DAPM_ENUM("DPTX_OUT_MUX", dptx_out_mux_map_enum);
+
+/* HDMI_CH0_MUX ~ HDMI_CH7_MUX */
+static const char *const afe_conn_hdmi_mux_map[] = {
+ "CH0", "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7",
+};
+
+static int afe_conn_hdmi_mux_map_value[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum,
+ AFE_TDMOUT_CONN0,
+ 0,
+ 0xf,
+ afe_conn_hdmi_mux_map,
+ afe_conn_hdmi_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch0_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum,
+ AFE_TDMOUT_CONN0,
+ 4,
+ 0xf,
+ afe_conn_hdmi_mux_map,
+ afe_conn_hdmi_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch1_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum,
+ AFE_TDMOUT_CONN0,
+ 8,
+ 0xf,
+ afe_conn_hdmi_mux_map,
+ afe_conn_hdmi_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch2_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum,
+ AFE_TDMOUT_CONN0,
+ 12,
+ 0xf,
+ afe_conn_hdmi_mux_map,
+ afe_conn_hdmi_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch3_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum,
+ AFE_TDMOUT_CONN0,
+ 16,
+ 0xf,
+ afe_conn_hdmi_mux_map,
+ afe_conn_hdmi_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch4_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum,
+ AFE_TDMOUT_CONN0,
+ 20,
+ 0xf,
+ afe_conn_hdmi_mux_map,
+ afe_conn_hdmi_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch5_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum,
+ AFE_TDMOUT_CONN0,
+ 24,
+ 0xf,
+ afe_conn_hdmi_mux_map,
+ afe_conn_hdmi_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch6_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum,
+ AFE_TDMOUT_CONN0,
+ 28,
+ 0xf,
+ afe_conn_hdmi_mux_map,
+ afe_conn_hdmi_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch7_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum);
+
+static int mt8188_etdm_clk_src_sel_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ unsigned int source = ucontrol->value.enumerated.item[0];
+ unsigned int val;
+ unsigned int old_val;
+ unsigned int mask;
+ unsigned int reg;
+ unsigned int shift;
+
+ if (source >= e->items)
+ return -EINVAL;
+
+ reg = 0;
+ if (!strcmp(kcontrol->id.name, "ETDM_OUT1_Clock_Source")) {
+ reg = ETDM_OUT1_CON4;
+ mask = ETDM_OUT_CON4_CLOCK_MASK;
+ shift = ETDM_OUT_CON4_CLOCK_SHIFT;
+ val = FIELD_PREP(ETDM_OUT_CON4_CLOCK_MASK, source);
+ } else if (!strcmp(kcontrol->id.name, "ETDM_OUT2_Clock_Source")) {
+ reg = ETDM_OUT2_CON4;
+ mask = ETDM_OUT_CON4_CLOCK_MASK;
+ shift = ETDM_OUT_CON4_CLOCK_SHIFT;
+ val = FIELD_PREP(ETDM_OUT_CON4_CLOCK_MASK, source);
+ } else if (!strcmp(kcontrol->id.name, "ETDM_OUT3_Clock_Source")) {
+ reg = ETDM_OUT3_CON4;
+ mask = ETDM_OUT_CON4_CLOCK_MASK;
+ shift = ETDM_OUT_CON4_CLOCK_SHIFT;
+ val = FIELD_PREP(ETDM_OUT_CON4_CLOCK_MASK, source);
+ } else if (!strcmp(kcontrol->id.name, "ETDM_IN1_Clock_Source")) {
+ reg = ETDM_IN1_CON2;
+ mask = ETDM_IN_CON2_CLOCK_MASK;
+ shift = ETDM_IN_CON2_CLOCK_SHIFT;
+ val = FIELD_PREP(ETDM_IN_CON2_CLOCK_MASK, source);
+ } else if (!strcmp(kcontrol->id.name, "ETDM_IN2_Clock_Source")) {
+ reg = ETDM_IN2_CON2;
+ mask = ETDM_IN_CON2_CLOCK_MASK;
+ shift = ETDM_IN_CON2_CLOCK_SHIFT;
+ val = FIELD_PREP(ETDM_IN_CON2_CLOCK_MASK, source);
+ }
+
+ if (reg) {
+ regmap_read(afe->regmap, reg, &old_val);
+ old_val &= mask;
+ old_val >>= shift;
+
+ if (old_val == val)
+ return 0;
+
+ regmap_update_bits(afe->regmap, reg, mask, val);
+ }
+
+ return 1;
+}
+
+static int mt8188_etdm_clk_src_sel_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ unsigned int value = 0;
+ unsigned int reg = 0;
+ unsigned int mask = 0;
+ unsigned int shift = 0;
+
+ if (!strcmp(kcontrol->id.name, "ETDM_OUT1_Clock_Source")) {
+ reg = ETDM_OUT1_CON4;
+ mask = ETDM_OUT_CON4_CLOCK_MASK;
+ shift = ETDM_OUT_CON4_CLOCK_SHIFT;
+ } else if (!strcmp(kcontrol->id.name, "ETDM_OUT2_Clock_Source")) {
+ reg = ETDM_OUT2_CON4;
+ mask = ETDM_OUT_CON4_CLOCK_MASK;
+ shift = ETDM_OUT_CON4_CLOCK_SHIFT;
+ } else if (!strcmp(kcontrol->id.name, "ETDM_OUT3_Clock_Source")) {
+ reg = ETDM_OUT3_CON4;
+ mask = ETDM_OUT_CON4_CLOCK_MASK;
+ shift = ETDM_OUT_CON4_CLOCK_SHIFT;
+ } else if (!strcmp(kcontrol->id.name, "ETDM_IN1_Clock_Source")) {
+ reg = ETDM_IN1_CON2;
+ mask = ETDM_IN_CON2_CLOCK_MASK;
+ shift = ETDM_IN_CON2_CLOCK_SHIFT;
+ } else if (!strcmp(kcontrol->id.name, "ETDM_IN2_Clock_Source")) {
+ reg = ETDM_IN2_CON2;
+ mask = ETDM_IN_CON2_CLOCK_MASK;
+ shift = ETDM_IN_CON2_CLOCK_SHIFT;
+ }
+
+ if (reg)
+ regmap_read(afe->regmap, reg, &value);
+
+ value &= mask;
+ value >>= shift;
+ ucontrol->value.enumerated.item[0] = value;
+ return 0;
+}
+
+static const struct snd_kcontrol_new mtk_dai_etdm_controls[] = {
+ SOC_ENUM_EXT("ETDM_OUT1_Clock_Source", etdmout_clk_src_enum,
+ mt8188_etdm_clk_src_sel_get,
+ mt8188_etdm_clk_src_sel_put),
+ SOC_ENUM_EXT("ETDM_OUT2_Clock_Source", etdmout_clk_src_enum,
+ mt8188_etdm_clk_src_sel_get,
+ mt8188_etdm_clk_src_sel_put),
+ SOC_ENUM_EXT("ETDM_OUT3_Clock_Source", etdmout_clk_src_enum,
+ mt8188_etdm_clk_src_sel_get,
+ mt8188_etdm_clk_src_sel_put),
+ SOC_ENUM_EXT("ETDM_IN1_Clock_Source", etdmout_clk_src_enum,
+ mt8188_etdm_clk_src_sel_get,
+ mt8188_etdm_clk_src_sel_put),
+ SOC_ENUM_EXT("ETDM_IN2_Clock_Source", etdmout_clk_src_enum,
+ mt8188_etdm_clk_src_sel_get,
+ mt8188_etdm_clk_src_sel_put),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = {
+ /* eTDM_IN2 */
+ SND_SOC_DAPM_MIXER("I012", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I013", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I014", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I015", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I016", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I017", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I018", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I019", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I188", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I189", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I190", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I191", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I192", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I193", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I194", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I195", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* eTDM_IN1 */
+ SND_SOC_DAPM_MIXER("I072", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I073", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I074", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I075", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I076", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I077", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I078", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I079", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I080", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I081", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I082", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I083", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I084", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I085", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I086", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I087", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* eTDM_OUT2 */
+ SND_SOC_DAPM_MIXER("O048", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o048_mix, ARRAY_SIZE(mtk_dai_etdm_o048_mix)),
+ SND_SOC_DAPM_MIXER("O049", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o049_mix, ARRAY_SIZE(mtk_dai_etdm_o049_mix)),
+ SND_SOC_DAPM_MIXER("O050", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o050_mix, ARRAY_SIZE(mtk_dai_etdm_o050_mix)),
+ SND_SOC_DAPM_MIXER("O051", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o051_mix, ARRAY_SIZE(mtk_dai_etdm_o051_mix)),
+ SND_SOC_DAPM_MIXER("O052", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o052_mix, ARRAY_SIZE(mtk_dai_etdm_o052_mix)),
+ SND_SOC_DAPM_MIXER("O053", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o053_mix, ARRAY_SIZE(mtk_dai_etdm_o053_mix)),
+ SND_SOC_DAPM_MIXER("O054", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o054_mix, ARRAY_SIZE(mtk_dai_etdm_o054_mix)),
+ SND_SOC_DAPM_MIXER("O055", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o055_mix, ARRAY_SIZE(mtk_dai_etdm_o055_mix)),
+ SND_SOC_DAPM_MIXER("O056", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o056_mix, ARRAY_SIZE(mtk_dai_etdm_o056_mix)),
+ SND_SOC_DAPM_MIXER("O057", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o057_mix, ARRAY_SIZE(mtk_dai_etdm_o057_mix)),
+ SND_SOC_DAPM_MIXER("O058", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o058_mix, ARRAY_SIZE(mtk_dai_etdm_o058_mix)),
+ SND_SOC_DAPM_MIXER("O059", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o059_mix, ARRAY_SIZE(mtk_dai_etdm_o059_mix)),
+ SND_SOC_DAPM_MIXER("O060", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o060_mix, ARRAY_SIZE(mtk_dai_etdm_o060_mix)),
+ SND_SOC_DAPM_MIXER("O061", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o061_mix, ARRAY_SIZE(mtk_dai_etdm_o061_mix)),
+ SND_SOC_DAPM_MIXER("O062", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o062_mix, ARRAY_SIZE(mtk_dai_etdm_o062_mix)),
+ SND_SOC_DAPM_MIXER("O063", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o063_mix, ARRAY_SIZE(mtk_dai_etdm_o063_mix)),
+
+ /* eTDM_OUT1 */
+ SND_SOC_DAPM_MIXER("O072", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o072_mix, ARRAY_SIZE(mtk_dai_etdm_o072_mix)),
+ SND_SOC_DAPM_MIXER("O073", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o073_mix, ARRAY_SIZE(mtk_dai_etdm_o073_mix)),
+ SND_SOC_DAPM_MIXER("O074", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o074_mix, ARRAY_SIZE(mtk_dai_etdm_o074_mix)),
+ SND_SOC_DAPM_MIXER("O075", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o075_mix, ARRAY_SIZE(mtk_dai_etdm_o075_mix)),
+ SND_SOC_DAPM_MIXER("O076", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o076_mix, ARRAY_SIZE(mtk_dai_etdm_o076_mix)),
+ SND_SOC_DAPM_MIXER("O077", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o077_mix, ARRAY_SIZE(mtk_dai_etdm_o077_mix)),
+ SND_SOC_DAPM_MIXER("O078", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o078_mix, ARRAY_SIZE(mtk_dai_etdm_o078_mix)),
+ SND_SOC_DAPM_MIXER("O079", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o079_mix, ARRAY_SIZE(mtk_dai_etdm_o079_mix)),
+ SND_SOC_DAPM_MIXER("O080", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o080_mix, ARRAY_SIZE(mtk_dai_etdm_o080_mix)),
+ SND_SOC_DAPM_MIXER("O081", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o081_mix, ARRAY_SIZE(mtk_dai_etdm_o081_mix)),
+ SND_SOC_DAPM_MIXER("O082", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o082_mix, ARRAY_SIZE(mtk_dai_etdm_o082_mix)),
+ SND_SOC_DAPM_MIXER("O083", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o083_mix, ARRAY_SIZE(mtk_dai_etdm_o083_mix)),
+ SND_SOC_DAPM_MIXER("O084", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o084_mix, ARRAY_SIZE(mtk_dai_etdm_o084_mix)),
+ SND_SOC_DAPM_MIXER("O085", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o085_mix, ARRAY_SIZE(mtk_dai_etdm_o085_mix)),
+ SND_SOC_DAPM_MIXER("O086", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o086_mix, ARRAY_SIZE(mtk_dai_etdm_o086_mix)),
+ SND_SOC_DAPM_MIXER("O087", SND_SOC_NOPM, 0, 0,
+ mtk_dai_etdm_o087_mix, ARRAY_SIZE(mtk_dai_etdm_o087_mix)),
+
+ /* eTDM_OUT3 */
+ SND_SOC_DAPM_MUX("HDMI_OUT_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_out_mux_control),
+ SND_SOC_DAPM_MUX("DPTX_OUT_MUX", SND_SOC_NOPM, 0, 0,
+ &dptx_out_mux_control),
+
+ SND_SOC_DAPM_MUX("HDMI_CH0_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch0_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH1_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch1_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH2_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch2_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH3_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch3_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH4_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch4_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH5_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch5_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH6_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch6_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch7_mux_control),
+
+ SND_SOC_DAPM_INPUT("ETDM_INPUT"),
+ SND_SOC_DAPM_OUTPUT("ETDM_OUTPUT"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = {
+ {"I012", NULL, "ETDM2_IN"},
+ {"I013", NULL, "ETDM2_IN"},
+ {"I014", NULL, "ETDM2_IN"},
+ {"I015", NULL, "ETDM2_IN"},
+ {"I016", NULL, "ETDM2_IN"},
+ {"I017", NULL, "ETDM2_IN"},
+ {"I018", NULL, "ETDM2_IN"},
+ {"I019", NULL, "ETDM2_IN"},
+ {"I188", NULL, "ETDM2_IN"},
+ {"I189", NULL, "ETDM2_IN"},
+ {"I190", NULL, "ETDM2_IN"},
+ {"I191", NULL, "ETDM2_IN"},
+ {"I192", NULL, "ETDM2_IN"},
+ {"I193", NULL, "ETDM2_IN"},
+ {"I194", NULL, "ETDM2_IN"},
+ {"I195", NULL, "ETDM2_IN"},
+
+ {"I072", NULL, "ETDM1_IN"},
+ {"I073", NULL, "ETDM1_IN"},
+ {"I074", NULL, "ETDM1_IN"},
+ {"I075", NULL, "ETDM1_IN"},
+ {"I076", NULL, "ETDM1_IN"},
+ {"I077", NULL, "ETDM1_IN"},
+ {"I078", NULL, "ETDM1_IN"},
+ {"I079", NULL, "ETDM1_IN"},
+ {"I080", NULL, "ETDM1_IN"},
+ {"I081", NULL, "ETDM1_IN"},
+ {"I082", NULL, "ETDM1_IN"},
+ {"I083", NULL, "ETDM1_IN"},
+ {"I084", NULL, "ETDM1_IN"},
+ {"I085", NULL, "ETDM1_IN"},
+ {"I086", NULL, "ETDM1_IN"},
+ {"I087", NULL, "ETDM1_IN"},
+
+ {"UL8", NULL, "ETDM1_IN"},
+ {"UL3", NULL, "ETDM2_IN"},
+
+ {"ETDM2_OUT", NULL, "O048"},
+ {"ETDM2_OUT", NULL, "O049"},
+ {"ETDM2_OUT", NULL, "O050"},
+ {"ETDM2_OUT", NULL, "O051"},
+ {"ETDM2_OUT", NULL, "O052"},
+ {"ETDM2_OUT", NULL, "O053"},
+ {"ETDM2_OUT", NULL, "O054"},
+ {"ETDM2_OUT", NULL, "O055"},
+ {"ETDM2_OUT", NULL, "O056"},
+ {"ETDM2_OUT", NULL, "O057"},
+ {"ETDM2_OUT", NULL, "O058"},
+ {"ETDM2_OUT", NULL, "O059"},
+ {"ETDM2_OUT", NULL, "O060"},
+ {"ETDM2_OUT", NULL, "O061"},
+ {"ETDM2_OUT", NULL, "O062"},
+ {"ETDM2_OUT", NULL, "O063"},
+
+ {"ETDM1_OUT", NULL, "O072"},
+ {"ETDM1_OUT", NULL, "O073"},
+ {"ETDM1_OUT", NULL, "O074"},
+ {"ETDM1_OUT", NULL, "O075"},
+ {"ETDM1_OUT", NULL, "O076"},
+ {"ETDM1_OUT", NULL, "O077"},
+ {"ETDM1_OUT", NULL, "O078"},
+ {"ETDM1_OUT", NULL, "O079"},
+ {"ETDM1_OUT", NULL, "O080"},
+ {"ETDM1_OUT", NULL, "O081"},
+ {"ETDM1_OUT", NULL, "O082"},
+ {"ETDM1_OUT", NULL, "O083"},
+ {"ETDM1_OUT", NULL, "O084"},
+ {"ETDM1_OUT", NULL, "O085"},
+ {"ETDM1_OUT", NULL, "O086"},
+ {"ETDM1_OUT", NULL, "O087"},
+
+ {"O048", "I020 Switch", "I020"},
+ {"O049", "I021 Switch", "I021"},
+
+ {"O048", "I022 Switch", "I022"},
+ {"O049", "I023 Switch", "I023"},
+ {"O050", "I024 Switch", "I024"},
+ {"O051", "I025 Switch", "I025"},
+ {"O052", "I026 Switch", "I026"},
+ {"O053", "I027 Switch", "I027"},
+ {"O054", "I028 Switch", "I028"},
+ {"O055", "I029 Switch", "I029"},
+ {"O056", "I030 Switch", "I030"},
+ {"O057", "I031 Switch", "I031"},
+ {"O058", "I032 Switch", "I032"},
+ {"O059", "I033 Switch", "I033"},
+ {"O060", "I034 Switch", "I034"},
+ {"O061", "I035 Switch", "I035"},
+ {"O062", "I036 Switch", "I036"},
+ {"O063", "I037 Switch", "I037"},
+
+ {"O048", "I046 Switch", "I046"},
+ {"O049", "I047 Switch", "I047"},
+ {"O050", "I048 Switch", "I048"},
+ {"O051", "I049 Switch", "I049"},
+ {"O052", "I050 Switch", "I050"},
+ {"O053", "I051 Switch", "I051"},
+ {"O054", "I052 Switch", "I052"},
+ {"O055", "I053 Switch", "I053"},
+ {"O056", "I054 Switch", "I054"},
+ {"O057", "I055 Switch", "I055"},
+ {"O058", "I056 Switch", "I056"},
+ {"O059", "I057 Switch", "I057"},
+ {"O060", "I058 Switch", "I058"},
+ {"O061", "I059 Switch", "I059"},
+ {"O062", "I060 Switch", "I060"},
+ {"O063", "I061 Switch", "I061"},
+
+ {"O048", "I070 Switch", "I070"},
+ {"O049", "I071 Switch", "I071"},
+
+ {"O072", "I020 Switch", "I020"},
+ {"O073", "I021 Switch", "I021"},
+
+ {"O072", "I022 Switch", "I022"},
+ {"O073", "I023 Switch", "I023"},
+ {"O074", "I024 Switch", "I024"},
+ {"O075", "I025 Switch", "I025"},
+ {"O076", "I026 Switch", "I026"},
+ {"O077", "I027 Switch", "I027"},
+ {"O078", "I028 Switch", "I028"},
+ {"O079", "I029 Switch", "I029"},
+ {"O080", "I030 Switch", "I030"},
+ {"O081", "I031 Switch", "I031"},
+ {"O082", "I032 Switch", "I032"},
+ {"O083", "I033 Switch", "I033"},
+ {"O084", "I034 Switch", "I034"},
+ {"O085", "I035 Switch", "I035"},
+ {"O086", "I036 Switch", "I036"},
+ {"O087", "I037 Switch", "I037"},
+
+ {"O072", "I046 Switch", "I046"},
+ {"O073", "I047 Switch", "I047"},
+ {"O074", "I048 Switch", "I048"},
+ {"O075", "I049 Switch", "I049"},
+ {"O076", "I050 Switch", "I050"},
+ {"O077", "I051 Switch", "I051"},
+ {"O078", "I052 Switch", "I052"},
+ {"O079", "I053 Switch", "I053"},
+ {"O080", "I054 Switch", "I054"},
+ {"O081", "I055 Switch", "I055"},
+ {"O082", "I056 Switch", "I056"},
+ {"O083", "I057 Switch", "I057"},
+ {"O084", "I058 Switch", "I058"},
+ {"O085", "I059 Switch", "I059"},
+ {"O086", "I060 Switch", "I060"},
+ {"O087", "I061 Switch", "I061"},
+
+ {"O072", "I070 Switch", "I070"},
+ {"O073", "I071 Switch", "I071"},
+
+ {"HDMI_CH0_MUX", "CH0", "DL10"},
+ {"HDMI_CH0_MUX", "CH1", "DL10"},
+ {"HDMI_CH0_MUX", "CH2", "DL10"},
+ {"HDMI_CH0_MUX", "CH3", "DL10"},
+ {"HDMI_CH0_MUX", "CH4", "DL10"},
+ {"HDMI_CH0_MUX", "CH5", "DL10"},
+ {"HDMI_CH0_MUX", "CH6", "DL10"},
+ {"HDMI_CH0_MUX", "CH7", "DL10"},
+
+ {"HDMI_CH1_MUX", "CH0", "DL10"},
+ {"HDMI_CH1_MUX", "CH1", "DL10"},
+ {"HDMI_CH1_MUX", "CH2", "DL10"},
+ {"HDMI_CH1_MUX", "CH3", "DL10"},
+ {"HDMI_CH1_MUX", "CH4", "DL10"},
+ {"HDMI_CH1_MUX", "CH5", "DL10"},
+ {"HDMI_CH1_MUX", "CH6", "DL10"},
+ {"HDMI_CH1_MUX", "CH7", "DL10"},
+
+ {"HDMI_CH2_MUX", "CH0", "DL10"},
+ {"HDMI_CH2_MUX", "CH1", "DL10"},
+ {"HDMI_CH2_MUX", "CH2", "DL10"},
+ {"HDMI_CH2_MUX", "CH3", "DL10"},
+ {"HDMI_CH2_MUX", "CH4", "DL10"},
+ {"HDMI_CH2_MUX", "CH5", "DL10"},
+ {"HDMI_CH2_MUX", "CH6", "DL10"},
+ {"HDMI_CH2_MUX", "CH7", "DL10"},
+
+ {"HDMI_CH3_MUX", "CH0", "DL10"},
+ {"HDMI_CH3_MUX", "CH1", "DL10"},
+ {"HDMI_CH3_MUX", "CH2", "DL10"},
+ {"HDMI_CH3_MUX", "CH3", "DL10"},
+ {"HDMI_CH3_MUX", "CH4", "DL10"},
+ {"HDMI_CH3_MUX", "CH5", "DL10"},
+ {"HDMI_CH3_MUX", "CH6", "DL10"},
+ {"HDMI_CH3_MUX", "CH7", "DL10"},
+
+ {"HDMI_CH4_MUX", "CH0", "DL10"},
+ {"HDMI_CH4_MUX", "CH1", "DL10"},
+ {"HDMI_CH4_MUX", "CH2", "DL10"},
+ {"HDMI_CH4_MUX", "CH3", "DL10"},
+ {"HDMI_CH4_MUX", "CH4", "DL10"},
+ {"HDMI_CH4_MUX", "CH5", "DL10"},
+ {"HDMI_CH4_MUX", "CH6", "DL10"},
+ {"HDMI_CH4_MUX", "CH7", "DL10"},
+
+ {"HDMI_CH5_MUX", "CH0", "DL10"},
+ {"HDMI_CH5_MUX", "CH1", "DL10"},
+ {"HDMI_CH5_MUX", "CH2", "DL10"},
+ {"HDMI_CH5_MUX", "CH3", "DL10"},
+ {"HDMI_CH5_MUX", "CH4", "DL10"},
+ {"HDMI_CH5_MUX", "CH5", "DL10"},
+ {"HDMI_CH5_MUX", "CH6", "DL10"},
+ {"HDMI_CH5_MUX", "CH7", "DL10"},
+
+ {"HDMI_CH6_MUX", "CH0", "DL10"},
+ {"HDMI_CH6_MUX", "CH1", "DL10"},
+ {"HDMI_CH6_MUX", "CH2", "DL10"},
+ {"HDMI_CH6_MUX", "CH3", "DL10"},
+ {"HDMI_CH6_MUX", "CH4", "DL10"},
+ {"HDMI_CH6_MUX", "CH5", "DL10"},
+ {"HDMI_CH6_MUX", "CH6", "DL10"},
+ {"HDMI_CH6_MUX", "CH7", "DL10"},
+
+ {"HDMI_CH7_MUX", "CH0", "DL10"},
+ {"HDMI_CH7_MUX", "CH1", "DL10"},
+ {"HDMI_CH7_MUX", "CH2", "DL10"},
+ {"HDMI_CH7_MUX", "CH3", "DL10"},
+ {"HDMI_CH7_MUX", "CH4", "DL10"},
+ {"HDMI_CH7_MUX", "CH5", "DL10"},
+ {"HDMI_CH7_MUX", "CH6", "DL10"},
+ {"HDMI_CH7_MUX", "CH7", "DL10"},
+
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH0_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH1_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH2_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH3_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH4_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH5_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH6_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH7_MUX"},
+
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH0_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH1_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH2_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH3_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH4_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH5_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH6_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH7_MUX"},
+
+ {"ETDM3_OUT", NULL, "HDMI_OUT_MUX"},
+ {"DPTX", NULL, "DPTX_OUT_MUX"},
+
+ {"ETDM_OUTPUT", NULL, "DPTX"},
+ {"ETDM_OUTPUT", NULL, "ETDM1_OUT"},
+ {"ETDM_OUTPUT", NULL, "ETDM2_OUT"},
+ {"ETDM_OUTPUT", NULL, "ETDM3_OUT"},
+ {"ETDM1_IN", NULL, "ETDM_INPUT"},
+ {"ETDM2_IN", NULL, "ETDM_INPUT"},
+};
+
+static int mt8188_afe_enable_etdm(struct mtk_base_afe *afe, int dai_id)
+{
+ int ret = 0;
+ struct etdm_con_reg etdm_reg;
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ unsigned long flags;
+
+ if (!is_valid_etdm_dai(dai_id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai_id];
+
+ dev_dbg(afe->dev, "%s [%d]%d\n", __func__, dai_id, etdm_data->en_ref_cnt);
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+ etdm_data->en_ref_cnt++;
+ if (etdm_data->en_ref_cnt == 1) {
+ ret = get_etdm_reg(dai_id, &etdm_reg);
+ if (ret < 0)
+ goto out;
+
+ regmap_set_bits(afe->regmap, etdm_reg.con0, ETDM_CON0_EN);
+ }
+
+out:
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+ return ret;
+}
+
+static int mt8188_afe_disable_etdm(struct mtk_base_afe *afe, int dai_id)
+{
+ int ret = 0;
+ struct etdm_con_reg etdm_reg;
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ unsigned long flags;
+
+ if (!is_valid_etdm_dai(dai_id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai_id];
+
+ dev_dbg(afe->dev, "%s [%d]%d\n", __func__, dai_id, etdm_data->en_ref_cnt);
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+ if (etdm_data->en_ref_cnt > 0) {
+ etdm_data->en_ref_cnt--;
+ if (etdm_data->en_ref_cnt == 0) {
+ ret = get_etdm_reg(dai_id, &etdm_reg);
+ if (ret < 0)
+ goto out;
+ regmap_clear_bits(afe->regmap, etdm_reg.con0,
+ ETDM_CON0_EN);
+ }
+ }
+
+out:
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+ return ret;
+}
+
+static int etdm_cowork_slv_sel(int id, int slave_mode)
+{
+ if (slave_mode) {
+ switch (id) {
+ case MT8188_AFE_IO_ETDM1_IN:
+ return COWORK_ETDM_IN1_S;
+ case MT8188_AFE_IO_ETDM2_IN:
+ return COWORK_ETDM_IN2_S;
+ case MT8188_AFE_IO_ETDM1_OUT:
+ return COWORK_ETDM_OUT1_S;
+ case MT8188_AFE_IO_ETDM2_OUT:
+ return COWORK_ETDM_OUT2_S;
+ case MT8188_AFE_IO_ETDM3_OUT:
+ return COWORK_ETDM_OUT3_S;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (id) {
+ case MT8188_AFE_IO_ETDM1_IN:
+ return COWORK_ETDM_IN1_M;
+ case MT8188_AFE_IO_ETDM2_IN:
+ return COWORK_ETDM_IN2_M;
+ case MT8188_AFE_IO_ETDM1_OUT:
+ return COWORK_ETDM_OUT1_M;
+ case MT8188_AFE_IO_ETDM2_OUT:
+ return COWORK_ETDM_OUT2_M;
+ case MT8188_AFE_IO_ETDM3_OUT:
+ return COWORK_ETDM_OUT3_M;
+ default:
+ return -EINVAL;
+ }
+ }
+}
+
+static int etdm_cowork_sync_sel(int id)
+{
+ switch (id) {
+ case MT8188_AFE_IO_ETDM1_IN:
+ return ETDM_SYNC_FROM_IN1;
+ case MT8188_AFE_IO_ETDM2_IN:
+ return ETDM_SYNC_FROM_IN2;
+ case MT8188_AFE_IO_ETDM1_OUT:
+ return ETDM_SYNC_FROM_OUT1;
+ case MT8188_AFE_IO_ETDM2_OUT:
+ return ETDM_SYNC_FROM_OUT2;
+ case MT8188_AFE_IO_ETDM3_OUT:
+ return ETDM_SYNC_FROM_OUT3;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mt8188_etdm_sync_mode_slv(struct mtk_base_afe *afe, int dai_id)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ unsigned int reg = 0;
+ unsigned int mask;
+ unsigned int val;
+ int cowork_source_sel;
+
+ if (!is_valid_etdm_dai(dai_id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai_id];
+
+ cowork_source_sel = etdm_cowork_slv_sel(etdm_data->cowork_source_id,
+ true);
+ if (cowork_source_sel < 0)
+ return cowork_source_sel;
+
+ switch (dai_id) {
+ case MT8188_AFE_IO_ETDM1_IN:
+ reg = ETDM_COWORK_CON1;
+ mask = ETDM_IN1_SLAVE_SEL_MASK;
+ val = FIELD_PREP(ETDM_IN1_SLAVE_SEL_MASK, cowork_source_sel);
+ break;
+ case MT8188_AFE_IO_ETDM2_IN:
+ reg = ETDM_COWORK_CON2;
+ mask = ETDM_IN2_SLAVE_SEL_MASK;
+ val = FIELD_PREP(ETDM_IN2_SLAVE_SEL_MASK, cowork_source_sel);
+ break;
+ case MT8188_AFE_IO_ETDM1_OUT:
+ reg = ETDM_COWORK_CON0;
+ mask = ETDM_OUT1_SLAVE_SEL_MASK;
+ val = FIELD_PREP(ETDM_OUT1_SLAVE_SEL_MASK, cowork_source_sel);
+ break;
+ case MT8188_AFE_IO_ETDM2_OUT:
+ reg = ETDM_COWORK_CON2;
+ mask = ETDM_OUT2_SLAVE_SEL_MASK;
+ val = FIELD_PREP(ETDM_OUT2_SLAVE_SEL_MASK, cowork_source_sel);
+ break;
+ case MT8188_AFE_IO_ETDM3_OUT:
+ reg = ETDM_COWORK_CON2;
+ mask = ETDM_OUT3_SLAVE_SEL_MASK;
+ val = FIELD_PREP(ETDM_OUT3_SLAVE_SEL_MASK, cowork_source_sel);
+ break;
+ default:
+ return 0;
+ }
+
+ regmap_update_bits(afe->regmap, reg, mask, val);
+
+ return 0;
+}
+
+static int mt8188_etdm_sync_mode_mst(struct mtk_base_afe *afe, int dai_id)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ struct etdm_con_reg etdm_reg;
+ unsigned int reg = 0;
+ unsigned int mask;
+ unsigned int val;
+ int cowork_source_sel;
+ int ret;
+
+ if (!is_valid_etdm_dai(dai_id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai_id];
+
+ cowork_source_sel = etdm_cowork_sync_sel(etdm_data->cowork_source_id);
+ if (cowork_source_sel < 0)
+ return cowork_source_sel;
+
+ switch (dai_id) {
+ case MT8188_AFE_IO_ETDM1_IN:
+ reg = ETDM_COWORK_CON1;
+ mask = ETDM_IN1_SYNC_SEL_MASK;
+ val = FIELD_PREP(ETDM_IN1_SYNC_SEL_MASK, cowork_source_sel);
+ break;
+ case MT8188_AFE_IO_ETDM2_IN:
+ reg = ETDM_COWORK_CON2;
+ mask = ETDM_IN2_SYNC_SEL_MASK;
+ val = FIELD_PREP(ETDM_IN2_SYNC_SEL_MASK, cowork_source_sel);
+ break;
+ case MT8188_AFE_IO_ETDM1_OUT:
+ reg = ETDM_COWORK_CON0;
+ mask = ETDM_OUT1_SYNC_SEL_MASK;
+ val = FIELD_PREP(ETDM_OUT1_SYNC_SEL_MASK, cowork_source_sel);
+ break;
+ case MT8188_AFE_IO_ETDM2_OUT:
+ reg = ETDM_COWORK_CON2;
+ mask = ETDM_OUT2_SYNC_SEL_MASK;
+ val = FIELD_PREP(ETDM_OUT2_SYNC_SEL_MASK, cowork_source_sel);
+ break;
+ case MT8188_AFE_IO_ETDM3_OUT:
+ reg = ETDM_COWORK_CON2;
+ mask = ETDM_OUT3_SYNC_SEL_MASK;
+ val = FIELD_PREP(ETDM_OUT3_SYNC_SEL_MASK, cowork_source_sel);
+ break;
+ default:
+ return 0;
+ }
+
+ ret = get_etdm_reg(dai_id, &etdm_reg);
+ if (ret < 0)
+ return ret;
+
+ regmap_update_bits(afe->regmap, reg, mask, val);
+
+ regmap_set_bits(afe->regmap, etdm_reg.con0, ETDM_CON0_SYNC_MODE);
+
+ return 0;
+}
+
+static int mt8188_etdm_sync_mode_configure(struct mtk_base_afe *afe, int dai_id)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+
+ if (!is_valid_etdm_dai(dai_id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai_id];
+
+ if (etdm_data->cowork_source_id == COWORK_ETDM_NONE)
+ return 0;
+
+ if (etdm_data->slave_mode)
+ mt8188_etdm_sync_mode_slv(afe, dai_id);
+ else
+ mt8188_etdm_sync_mode_mst(afe, dai_id);
+
+ return 0;
+}
+
+/* dai ops */
+static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *mst_etdm_data;
+ int cg_id;
+ int mst_dai_id;
+ int slv_dai_id;
+ int i;
+
+ if (is_cowork_mode(dai)) {
+ mst_dai_id = get_etdm_cowork_master_id(dai);
+ if (!is_valid_etdm_dai(mst_dai_id))
+ return -EINVAL;
+ mtk_dai_etdm_enable_mclk(afe, mst_dai_id);
+
+ cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(mst_dai_id);
+ if (cg_id >= 0)
+ mt8188_afe_enable_clk(afe, afe_priv->clk[cg_id]);
+
+ mst_etdm_data = afe_priv->dai_priv[mst_dai_id];
+
+ for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) {
+ slv_dai_id = mst_etdm_data->cowork_slv_id[i];
+ cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(slv_dai_id);
+ if (cg_id >= 0)
+ mt8188_afe_enable_clk(afe,
+ afe_priv->clk[cg_id]);
+ }
+ } else {
+ mtk_dai_etdm_enable_mclk(afe, dai->id);
+
+ cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id);
+ if (cg_id >= 0)
+ mt8188_afe_enable_clk(afe, afe_priv->clk[cg_id]);
+ }
+
+ return 0;
+}
+
+static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *mst_etdm_data = afe_priv->dai_priv[dai->id];
+ int cg_id;
+ int mst_dai_id;
+ int slv_dai_id;
+ int i;
+ int ret = 0;
+
+ dev_dbg(afe->dev, "%s(), dai id %d, prepared %d\n", __func__, dai->id,
+ mst_etdm_data->is_prepared);
+
+ if (mst_etdm_data->is_prepared) {
+ mst_etdm_data->is_prepared = false;
+
+ if (is_cowork_mode(dai)) {
+ mst_dai_id = get_etdm_cowork_master_id(dai);
+ if (!is_valid_etdm_dai(mst_dai_id))
+ return;
+ mst_etdm_data = afe_priv->dai_priv[mst_dai_id];
+
+ ret |= mt8188_afe_disable_etdm(afe, mst_dai_id);
+ for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) {
+ slv_dai_id = mst_etdm_data->cowork_slv_id[i];
+ ret |= mt8188_afe_disable_etdm(afe, slv_dai_id);
+ }
+ } else {
+ ret = mt8188_afe_disable_etdm(afe, dai->id);
+ }
+
+ if (ret)
+ dev_dbg(afe->dev, "%s disable failed\n", __func__);
+ }
+
+ if (is_cowork_mode(dai)) {
+ mst_dai_id = get_etdm_cowork_master_id(dai);
+ if (!is_valid_etdm_dai(mst_dai_id))
+ return;
+ cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(mst_dai_id);
+ if (cg_id >= 0)
+ mt8188_afe_disable_clk(afe, afe_priv->clk[cg_id]);
+
+ mst_etdm_data = afe_priv->dai_priv[mst_dai_id];
+ for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) {
+ slv_dai_id = mst_etdm_data->cowork_slv_id[i];
+ cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(slv_dai_id);
+ if (cg_id >= 0)
+ mt8188_afe_disable_clk(afe,
+ afe_priv->clk[cg_id]);
+ }
+ mtk_dai_etdm_disable_mclk(afe, mst_dai_id);
+ } else {
+ cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id);
+ if (cg_id >= 0)
+ mt8188_afe_disable_clk(afe, afe_priv->clk[cg_id]);
+
+ mtk_dai_etdm_disable_mclk(afe, dai->id);
+ }
+}
+
+static int mtk_dai_etdm_fifo_mode(struct mtk_base_afe *afe,
+ int dai_id, unsigned int rate)
+{
+ unsigned int mode = 0;
+ unsigned int reg = 0;
+ unsigned int val = 0;
+ unsigned int mask = (ETDM_IN_AFIFO_MODE_MASK | ETDM_IN_USE_AFIFO);
+
+ if (rate != 0)
+ mode = mt8188_afe_fs_timing(rate);
+
+ switch (dai_id) {
+ case MT8188_AFE_IO_ETDM1_IN:
+ reg = ETDM_IN1_AFIFO_CON;
+ if (rate == 0)
+ mode = MT8188_ETDM_IN1_1X_EN;
+ break;
+ case MT8188_AFE_IO_ETDM2_IN:
+ reg = ETDM_IN2_AFIFO_CON;
+ if (rate == 0)
+ mode = MT8188_ETDM_IN2_1X_EN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val = (mode | ETDM_IN_USE_AFIFO);
+
+ regmap_update_bits(afe->regmap, reg, mask, val);
+ return 0;
+}
+
+static int mtk_dai_etdm_in_configure(struct mtk_base_afe *afe,
+ unsigned int rate,
+ unsigned int channels,
+ int dai_id)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id];
+ struct etdm_con_reg etdm_reg;
+ bool slave_mode = etdm_data->slave_mode;
+ unsigned int data_mode = etdm_data->data_mode;
+ unsigned int lrck_width = etdm_data->lrck_width;
+ unsigned int val = 0;
+ unsigned int mask = 0;
+ int i;
+ int ret;
+
+ dev_dbg(afe->dev, "%s rate %u channels %u, id %d\n",
+ __func__, rate, channels, dai_id);
+
+ ret = get_etdm_reg(dai_id, &etdm_reg);
+ if (ret < 0)
+ return ret;
+
+ /* afifo */
+ if (slave_mode)
+ mtk_dai_etdm_fifo_mode(afe, dai_id, 0);
+ else
+ mtk_dai_etdm_fifo_mode(afe, dai_id, rate);
+
+ /* con1 */
+ if (lrck_width > 0) {
+ mask |= (ETDM_IN_CON1_LRCK_AUTO_MODE |
+ ETDM_IN_CON1_LRCK_WIDTH_MASK);
+ val |= FIELD_PREP(ETDM_IN_CON1_LRCK_WIDTH_MASK, lrck_width - 1);
+ }
+ regmap_update_bits(afe->regmap, etdm_reg.con1, mask, val);
+
+ mask = 0;
+ val = 0;
+
+ /* con2 */
+ if (!slave_mode) {
+ mask |= ETDM_IN_CON2_UPDATE_GAP_MASK;
+ if (rate == 352800 || rate == 384000)
+ val |= FIELD_PREP(ETDM_IN_CON2_UPDATE_GAP_MASK, 4);
+ else
+ val |= FIELD_PREP(ETDM_IN_CON2_UPDATE_GAP_MASK, 3);
+ }
+ mask |= (ETDM_IN_CON2_MULTI_IP_2CH_MODE |
+ ETDM_IN_CON2_MULTI_IP_TOTAL_CH_MASK);
+ if (data_mode == MTK_DAI_ETDM_DATA_MULTI_PIN) {
+ val |= ETDM_IN_CON2_MULTI_IP_2CH_MODE |
+ FIELD_PREP(ETDM_IN_CON2_MULTI_IP_TOTAL_CH_MASK, channels - 1);
+ }
+ regmap_update_bits(afe->regmap, etdm_reg.con2, mask, val);
+
+ mask = 0;
+ val = 0;
+
+ /* con3 */
+ mask |= ETDM_IN_CON3_DISABLE_OUT_MASK;
+ for (i = 0; i < channels; i += 2) {
+ if (etdm_data->in_disable_ch[i] &&
+ etdm_data->in_disable_ch[i + 1])
+ val |= ETDM_IN_CON3_DISABLE_OUT(i >> 1);
+ }
+ if (!slave_mode) {
+ mask |= ETDM_IN_CON3_FS_MASK;
+ val |= FIELD_PREP(ETDM_IN_CON3_FS_MASK, get_etdm_fs_timing(rate));
+ }
+ regmap_update_bits(afe->regmap, etdm_reg.con3, mask, val);
+
+ mask = 0;
+ val = 0;
+
+ /* con4 */
+ mask |= (ETDM_IN_CON4_MASTER_LRCK_INV | ETDM_IN_CON4_MASTER_BCK_INV |
+ ETDM_IN_CON4_SLAVE_LRCK_INV | ETDM_IN_CON4_SLAVE_BCK_INV);
+ if (slave_mode) {
+ if (etdm_data->lrck_inv)
+ val |= ETDM_IN_CON4_SLAVE_LRCK_INV;
+ if (etdm_data->bck_inv)
+ val |= ETDM_IN_CON4_SLAVE_BCK_INV;
+ } else {
+ if (etdm_data->lrck_inv)
+ val |= ETDM_IN_CON4_MASTER_LRCK_INV;
+ if (etdm_data->bck_inv)
+ val |= ETDM_IN_CON4_MASTER_BCK_INV;
+ }
+ regmap_update_bits(afe->regmap, etdm_reg.con4, mask, val);
+
+ mask = 0;
+ val = 0;
+
+ /* con5 */
+ mask |= ETDM_IN_CON5_LR_SWAP_MASK;
+ mask |= ETDM_IN_CON5_ENABLE_ODD_MASK;
+ for (i = 0; i < channels; i += 2) {
+ if (etdm_data->in_disable_ch[i] &&
+ !etdm_data->in_disable_ch[i + 1]) {
+ val |= ETDM_IN_CON5_LR_SWAP(i >> 1);
+ val |= ETDM_IN_CON5_ENABLE_ODD(i >> 1);
+ } else if (!etdm_data->in_disable_ch[i] &&
+ etdm_data->in_disable_ch[i + 1]) {
+ val |= ETDM_IN_CON5_ENABLE_ODD(i >> 1);
+ }
+ }
+ regmap_update_bits(afe->regmap, etdm_reg.con5, mask, val);
+ return 0;
+}
+
+static int mtk_dai_etdm_out_configure(struct mtk_base_afe *afe,
+ unsigned int rate,
+ unsigned int channels,
+ int dai_id)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id];
+ struct etdm_con_reg etdm_reg;
+ bool slave_mode = etdm_data->slave_mode;
+ unsigned int lrck_width = etdm_data->lrck_width;
+ unsigned int val = 0;
+ unsigned int mask = 0;
+ int ret;
+ int fs = 0;
+
+ dev_dbg(afe->dev, "%s rate %u channels %u, id %d\n",
+ __func__, rate, channels, dai_id);
+
+ ret = get_etdm_reg(dai_id, &etdm_reg);
+ if (ret < 0)
+ return ret;
+
+ /* con0 */
+ mask = ETDM_OUT_CON0_RELATCH_DOMAIN_MASK;
+ val = FIELD_PREP(ETDM_OUT_CON0_RELATCH_DOMAIN_MASK,
+ ETDM_RELATCH_TIMING_A1A2SYS);
+ regmap_update_bits(afe->regmap, etdm_reg.con0, mask, val);
+
+ mask = 0;
+ val = 0;
+
+ /* con1 */
+ if (lrck_width > 0) {
+ mask |= (ETDM_OUT_CON1_LRCK_AUTO_MODE |
+ ETDM_OUT_CON1_LRCK_WIDTH_MASK);
+ val |= FIELD_PREP(ETDM_OUT_CON1_LRCK_WIDTH_MASK, lrck_width - 1);
+ }
+ regmap_update_bits(afe->regmap, etdm_reg.con1, mask, val);
+
+ mask = 0;
+ val = 0;
+
+ if (!slave_mode) {
+ /* con4 */
+ mask |= ETDM_OUT_CON4_FS_MASK;
+ val |= FIELD_PREP(ETDM_OUT_CON4_FS_MASK, get_etdm_fs_timing(rate));
+ }
+
+ mask |= ETDM_OUT_CON4_RELATCH_EN_MASK;
+ if (dai_id == MT8188_AFE_IO_ETDM1_OUT)
+ fs = MT8188_ETDM_OUT1_1X_EN;
+ else if (dai_id == MT8188_AFE_IO_ETDM2_OUT)
+ fs = MT8188_ETDM_OUT2_1X_EN;
+
+ val |= FIELD_PREP(ETDM_OUT_CON4_RELATCH_EN_MASK, fs);
+
+ regmap_update_bits(afe->regmap, etdm_reg.con4, mask, val);
+
+ mask = 0;
+ val = 0;
+
+ /* con5 */
+ mask |= (ETDM_OUT_CON5_MASTER_LRCK_INV | ETDM_OUT_CON5_MASTER_BCK_INV |
+ ETDM_OUT_CON5_SLAVE_LRCK_INV | ETDM_OUT_CON5_SLAVE_BCK_INV);
+ if (slave_mode) {
+ if (etdm_data->lrck_inv)
+ val |= ETDM_OUT_CON5_SLAVE_LRCK_INV;
+ if (etdm_data->bck_inv)
+ val |= ETDM_OUT_CON5_SLAVE_BCK_INV;
+ } else {
+ if (etdm_data->lrck_inv)
+ val |= ETDM_OUT_CON5_MASTER_LRCK_INV;
+ if (etdm_data->bck_inv)
+ val |= ETDM_OUT_CON5_MASTER_BCK_INV;
+ }
+ regmap_update_bits(afe->regmap, etdm_reg.con5, mask, val);
+
+ return 0;
+}
+
+static int mtk_dai_etdm_mclk_configure(struct mtk_base_afe *afe, int dai_id)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id];
+ int clk_id = mtk_dai_etdm_get_clk_id_by_dai_id(dai_id);
+ int clkdiv_id = mtk_dai_etdm_get_clkdiv_id_by_dai_id(dai_id);
+ int apll;
+ int apll_clk_id;
+ struct etdm_con_reg etdm_reg;
+ int ret = 0;
+
+ if (clk_id < 0 || clkdiv_id < 0)
+ return 0;
+
+ ret = get_etdm_reg(dai_id, &etdm_reg);
+ if (ret < 0)
+ return ret;
+
+ if (etdm_data->mclk_dir == SND_SOC_CLOCK_OUT)
+ regmap_set_bits(afe->regmap, etdm_reg.con1,
+ ETDM_CON1_MCLK_OUTPUT);
+ else
+ regmap_clear_bits(afe->regmap, etdm_reg.con1,
+ ETDM_CON1_MCLK_OUTPUT);
+
+ if (etdm_data->mclk_freq) {
+ apll = etdm_data->mclk_apll;
+ apll_clk_id = mt8188_afe_get_mclk_source_clk_id(apll);
+ if (apll_clk_id < 0)
+ return apll_clk_id;
+
+ /* select apll */
+ ret = mt8188_afe_set_clk_parent(afe, afe_priv->clk[clk_id],
+ afe_priv->clk[apll_clk_id]);
+ if (ret)
+ return ret;
+
+ /* set rate */
+ ret = mt8188_afe_set_clk_rate(afe, afe_priv->clk[clkdiv_id],
+ etdm_data->mclk_freq);
+ } else {
+ if (etdm_data->mclk_dir == SND_SOC_CLOCK_OUT)
+ dev_dbg(afe->dev, "%s mclk freq = 0\n", __func__);
+ }
+
+ return ret;
+}
+
+static int mtk_dai_etdm_configure(struct mtk_base_afe *afe,
+ unsigned int rate,
+ unsigned int channels,
+ unsigned int bit_width,
+ int dai_id)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai_id];
+ struct etdm_con_reg etdm_reg;
+ bool slave_mode = etdm_data->slave_mode;
+ unsigned int etdm_channels;
+ unsigned int val = 0;
+ unsigned int mask = 0;
+ unsigned int bck;
+ unsigned int wlen = get_etdm_wlen(bit_width);
+ int ret;
+
+ ret = get_etdm_reg(dai_id, &etdm_reg);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(afe->dev, "%s fmt %u data %u lrck %d-%u bck %d, clock %u slv %u\n",
+ __func__, etdm_data->format, etdm_data->data_mode,
+ etdm_data->lrck_inv, etdm_data->lrck_width, etdm_data->bck_inv,
+ etdm_data->clock_mode, etdm_data->slave_mode);
+ dev_dbg(afe->dev, "%s rate %u channels %u bitwidth %u, id %d\n",
+ __func__, rate, channels, bit_width, dai_id);
+
+ etdm_channels = (etdm_data->data_mode == MTK_DAI_ETDM_DATA_ONE_PIN) ?
+ get_etdm_ch_fixup(channels) : 2;
+
+ bck = rate * etdm_channels * wlen;
+ if (bck > MT8188_ETDM_NORMAL_MAX_BCK_RATE) {
+ dev_info(afe->dev, "%s bck rate %u not support\n",
+ __func__, bck);
+ return -EINVAL;
+ }
+
+ /* con0 */
+ mask |= ETDM_CON0_BIT_LEN_MASK;
+ val |= FIELD_PREP(ETDM_CON0_BIT_LEN_MASK, bit_width - 1);
+ mask |= ETDM_CON0_WORD_LEN_MASK;
+ val |= FIELD_PREP(ETDM_CON0_WORD_LEN_MASK, wlen - 1);
+ mask |= ETDM_CON0_FORMAT_MASK;
+ val |= FIELD_PREP(ETDM_CON0_FORMAT_MASK, etdm_data->format);
+ mask |= ETDM_CON0_CH_NUM_MASK;
+ val |= FIELD_PREP(ETDM_CON0_CH_NUM_MASK, etdm_channels - 1);
+
+ mask |= ETDM_CON0_SLAVE_MODE;
+ if (slave_mode) {
+ if (dai_id == MT8188_AFE_IO_ETDM1_OUT) {
+ dev_info(afe->dev, "%s id %d only support master mode\n",
+ __func__, dai_id);
+ return -EINVAL;
+ }
+ val |= ETDM_CON0_SLAVE_MODE;
+ }
+ regmap_update_bits(afe->regmap, etdm_reg.con0, mask, val);
+
+ if (get_etdm_dir(dai_id) == ETDM_IN)
+ mtk_dai_etdm_in_configure(afe, rate, channels, dai_id);
+ else
+ mtk_dai_etdm_out_configure(afe, rate, channels, dai_id);
+
+ return 0;
+}
+
+static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ int ret = 0;
+ unsigned int rate = params_rate(params);
+ unsigned int bit_width = params_width(params);
+ unsigned int channels = params_channels(params);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *mst_etdm_data;
+ int mst_dai_id;
+ int slv_dai_id;
+ int i;
+
+ dev_dbg(afe->dev, "%s '%s' period %u-%u\n",
+ __func__, snd_pcm_stream_str(substream),
+ params_period_size(params), params_periods(params));
+
+ if (is_cowork_mode(dai)) {
+ mst_dai_id = get_etdm_cowork_master_id(dai);
+
+ ret = mtk_dai_etdm_mclk_configure(afe, mst_dai_id);
+ if (ret)
+ return ret;
+
+ ret = mtk_dai_etdm_configure(afe, rate, channels,
+ bit_width, mst_dai_id);
+ if (ret)
+ return ret;
+
+ mst_etdm_data = afe_priv->dai_priv[mst_dai_id];
+ for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) {
+ slv_dai_id = mst_etdm_data->cowork_slv_id[i];
+ ret = mtk_dai_etdm_configure(afe, rate, channels,
+ bit_width, slv_dai_id);
+ if (ret)
+ return ret;
+
+ ret = mt8188_etdm_sync_mode_configure(afe, slv_dai_id);
+ if (ret)
+ return ret;
+ }
+ } else {
+ ret = mtk_dai_etdm_mclk_configure(afe, dai->id);
+ if (ret)
+ return ret;
+
+ ret = mtk_dai_etdm_configure(afe, rate, channels,
+ bit_width, dai->id);
+ }
+
+ return ret;
+}
+
+static int mtk_dai_etdm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *mst_etdm_data;
+ int mst_dai_id;
+ int slv_dai_id;
+ int i;
+ int ret = 0;
+
+ if (!is_valid_etdm_dai(dai->id))
+ return -EINVAL;
+ mst_etdm_data = afe_priv->dai_priv[dai->id];
+
+ dev_dbg(afe->dev, "%s(), dai id %d, prepared %d\n", __func__, dai->id,
+ mst_etdm_data->is_prepared);
+
+ if (mst_etdm_data->is_prepared)
+ return 0;
+
+ mst_etdm_data->is_prepared = true;
+
+ if (is_cowork_mode(dai)) {
+ mst_dai_id = get_etdm_cowork_master_id(dai);
+ mst_etdm_data = afe_priv->dai_priv[mst_dai_id];
+
+ for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) {
+ slv_dai_id = mst_etdm_data->cowork_slv_id[i];
+ ret |= mt8188_afe_enable_etdm(afe, slv_dai_id);
+ }
+
+ ret |= mt8188_afe_enable_etdm(afe, mst_dai_id);
+ } else {
+ ret = mt8188_afe_enable_etdm(afe, dai->id);
+ }
+
+ return ret;
+}
+
+static int mtk_dai_etdm_cal_mclk(struct mtk_base_afe *afe, int freq, int dai_id)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ int apll;
+ int apll_rate;
+
+ if (!is_valid_etdm_dai(dai_id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai_id];
+
+ if (freq == 0) {
+ etdm_data->mclk_freq = freq;
+ return 0;
+ }
+
+ if (etdm_data->mclk_fixed_apll == 0)
+ apll = mt8188_afe_get_default_mclk_source_by_rate(freq);
+ else
+ apll = etdm_data->mclk_apll;
+
+ apll_rate = mt8188_afe_get_mclk_source_rate(afe, apll);
+
+ if (freq > apll_rate) {
+ dev_info(afe->dev, "freq %d > apll rate %d\n", freq, apll_rate);
+ return -EINVAL;
+ }
+
+ if (apll_rate % freq != 0) {
+ dev_info(afe->dev, "APLL%d cannot generate freq Hz\n", apll);
+ return -EINVAL;
+ }
+
+ if (etdm_data->mclk_fixed_apll == 0)
+ etdm_data->mclk_apll = apll;
+ etdm_data->mclk_freq = freq;
+
+ return 0;
+}
+
+static int mtk_dai_etdm_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ int dai_id;
+
+ dev_dbg(dai->dev, "%s id %d freq %u, dir %d\n",
+ __func__, dai->id, freq, dir);
+ if (is_cowork_mode(dai))
+ dai_id = get_etdm_cowork_master_id(dai);
+ else
+ dai_id = dai->id;
+
+ etdm_data = afe_priv->dai_priv[dai_id];
+ etdm_data->mclk_dir = dir;
+ return mtk_dai_etdm_cal_mclk(afe, freq, dai_id);
+}
+
+static int mtk_dai_etdm_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+
+ if (!is_valid_etdm_dai(dai->id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai->id];
+
+ dev_dbg(dai->dev, "%s id %d slot_width %d\n",
+ __func__, dai->id, slot_width);
+
+ etdm_data->slots = slots;
+ etdm_data->lrck_width = slot_width;
+ return 0;
+}
+
+static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+
+ if (!is_valid_etdm_dai(dai->id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai->id];
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ etdm_data->format = MTK_DAI_ETDM_FORMAT_LJ;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ etdm_data->format = MTK_DAI_ETDM_FORMAT_RJ;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ etdm_data->bck_inv = false;
+ etdm_data->lrck_inv = false;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ etdm_data->bck_inv = false;
+ etdm_data->lrck_inv = true;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ etdm_data->bck_inv = true;
+ etdm_data->lrck_inv = false;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ etdm_data->bck_inv = true;
+ etdm_data->lrck_inv = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
+ etdm_data->slave_mode = true;
+ break;
+ case SND_SOC_DAIFMT_BP_FP:
+ etdm_data->slave_mode = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_hdmitx_dptx_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ int cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id);
+
+ if (cg_id >= 0)
+ mt8188_afe_enable_clk(afe, afe_priv->clk[cg_id]);
+
+ mtk_dai_etdm_enable_mclk(afe, dai->id);
+
+ return 0;
+}
+
+static void mtk_dai_hdmitx_dptx_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ int cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id);
+ struct mtk_dai_etdm_priv *etdm_data;
+ int ret = 0;
+
+ if (!is_valid_etdm_dai(dai->id))
+ return;
+ etdm_data = afe_priv->dai_priv[dai->id];
+
+ if (etdm_data->is_prepared) {
+ etdm_data->is_prepared = false;
+ /* disable etdm_out3 */
+ ret = mt8188_afe_disable_etdm(afe, dai->id);
+
+ if (ret)
+ dev_dbg(afe->dev, "%s disable failed\n", __func__);
+
+ /* disable dptx interface */
+ if (dai->id == MT8188_AFE_IO_DPTX)
+ regmap_clear_bits(afe->regmap, AFE_DPTX_CON,
+ AFE_DPTX_CON_ON);
+ }
+
+ mtk_dai_etdm_disable_mclk(afe, dai->id);
+
+ if (cg_id >= 0)
+ mt8188_afe_disable_clk(afe, afe_priv->clk[cg_id]);
+}
+
+static unsigned int mtk_dai_get_dptx_ch_en(unsigned int channel)
+{
+ switch (channel) {
+ case 1 ... 2:
+ return AFE_DPTX_CON_CH_EN_2CH;
+ case 3 ... 4:
+ return AFE_DPTX_CON_CH_EN_4CH;
+ case 5 ... 6:
+ return AFE_DPTX_CON_CH_EN_6CH;
+ case 7 ... 8:
+ return AFE_DPTX_CON_CH_EN_8CH;
+ default:
+ return AFE_DPTX_CON_CH_EN_2CH;
+ }
+}
+
+static unsigned int mtk_dai_get_dptx_ch(unsigned int ch)
+{
+ return (ch > 2) ?
+ AFE_DPTX_CON_CH_NUM_8CH : AFE_DPTX_CON_CH_NUM_2CH;
+}
+
+static unsigned int mtk_dai_get_dptx_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ AFE_DPTX_CON_16BIT : AFE_DPTX_CON_24BIT;
+}
+
+static int mtk_dai_hdmitx_dptx_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ unsigned int rate = params_rate(params);
+ unsigned int channels = params_channels(params);
+ snd_pcm_format_t format = params_format(params);
+ int width = snd_pcm_format_physical_width(format);
+ int ret = 0;
+
+ if (!is_valid_etdm_dai(dai->id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai->id];
+
+ /* dptx configure */
+ if (dai->id == MT8188_AFE_IO_DPTX) {
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ AFE_DPTX_CON_CH_EN_MASK,
+ mtk_dai_get_dptx_ch_en(channels));
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ AFE_DPTX_CON_CH_NUM_MASK,
+ mtk_dai_get_dptx_ch(channels));
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ AFE_DPTX_CON_16BIT_MASK,
+ mtk_dai_get_dptx_wlen(format));
+
+ if (mtk_dai_get_dptx_ch(channels) == AFE_DPTX_CON_CH_NUM_8CH) {
+ etdm_data->data_mode = MTK_DAI_ETDM_DATA_ONE_PIN;
+ channels = 8;
+ } else {
+ channels = 2;
+ }
+ } else {
+ etdm_data->data_mode = MTK_DAI_ETDM_DATA_MULTI_PIN;
+ }
+
+ ret = mtk_dai_etdm_mclk_configure(afe, dai->id);
+ if (ret)
+ return ret;
+
+ ret = mtk_dai_etdm_configure(afe, rate, channels, width, dai->id);
+
+ return ret;
+}
+
+static int mtk_dai_hdmitx_dptx_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ int ret = 0;
+
+ if (!is_valid_etdm_dai(dai->id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai->id];
+
+ dev_dbg(afe->dev, "%s(), dai id %d, prepared %d\n", __func__, dai->id,
+ etdm_data->is_prepared);
+
+ if (etdm_data->is_prepared)
+ return 0;
+
+ etdm_data->is_prepared = true;
+
+ /* enable dptx interface */
+ if (dai->id == MT8188_AFE_IO_DPTX)
+ regmap_set_bits(afe->regmap, AFE_DPTX_CON, AFE_DPTX_CON_ON);
+
+ /* enable etdm_out3 */
+ ret = mt8188_afe_enable_etdm(afe, dai->id);
+
+ return ret;
+}
+
+static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id,
+ unsigned int freq,
+ int dir)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+
+ if (!is_valid_etdm_dai(dai->id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai->id];
+
+ dev_dbg(dai->dev, "%s id %d freq %u, dir %d\n",
+ __func__, dai->id, freq, dir);
+
+ etdm_data->mclk_dir = dir;
+ return mtk_dai_etdm_cal_mclk(afe, freq, dai->id);
+}
+
+static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
+ .startup = mtk_dai_etdm_startup,
+ .shutdown = mtk_dai_etdm_shutdown,
+ .hw_params = mtk_dai_etdm_hw_params,
+ .prepare = mtk_dai_etdm_prepare,
+ .set_sysclk = mtk_dai_etdm_set_sysclk,
+ .set_fmt = mtk_dai_etdm_set_fmt,
+ .set_tdm_slot = mtk_dai_etdm_set_tdm_slot,
+};
+
+static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = {
+ .startup = mtk_dai_hdmitx_dptx_startup,
+ .shutdown = mtk_dai_hdmitx_dptx_shutdown,
+ .hw_params = mtk_dai_hdmitx_dptx_hw_params,
+ .prepare = mtk_dai_hdmitx_dptx_prepare,
+ .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk,
+ .set_fmt = mtk_dai_etdm_set_fmt,
+};
+
+/* dai driver */
+#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_192000)
+
+#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static int mtk_dai_etdm_probe(struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+
+ if (!is_valid_etdm_dai(dai->id))
+ return -EINVAL;
+ etdm_data = afe_priv->dai_priv[dai->id];
+
+ dev_dbg(dai->dev, "%s id %d\n", __func__, dai->id);
+
+ if (etdm_data->mclk_freq) {
+ dev_dbg(afe->dev, "MCLK always on, rate %d\n",
+ etdm_data->mclk_freq);
+ pm_runtime_get_sync(afe->dev);
+ mtk_dai_etdm_mclk_configure(afe, dai->id);
+ mtk_dai_etdm_enable_mclk(afe, dai->id);
+ pm_runtime_put_sync(afe->dev);
+ }
+ return 0;
+}
+
+static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
+ {
+ .name = "DPTX",
+ .id = MT8188_AFE_IO_DPTX,
+ .playback = {
+ .stream_name = "DPTX",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = MTK_ETDM_RATES,
+ .formats = MTK_ETDM_FORMATS,
+ },
+ .ops = &mtk_dai_hdmitx_dptx_ops,
+ },
+ {
+ .name = "ETDM1_IN",
+ .id = MT8188_AFE_IO_ETDM1_IN,
+ .capture = {
+ .stream_name = "ETDM1_IN",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = MTK_ETDM_RATES,
+ .formats = MTK_ETDM_FORMATS,
+ },
+ .ops = &mtk_dai_etdm_ops,
+ .probe = mtk_dai_etdm_probe,
+ },
+ {
+ .name = "ETDM2_IN",
+ .id = MT8188_AFE_IO_ETDM2_IN,
+ .capture = {
+ .stream_name = "ETDM2_IN",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = MTK_ETDM_RATES,
+ .formats = MTK_ETDM_FORMATS,
+ },
+ .ops = &mtk_dai_etdm_ops,
+ .probe = mtk_dai_etdm_probe,
+ },
+ {
+ .name = "ETDM1_OUT",
+ .id = MT8188_AFE_IO_ETDM1_OUT,
+ .playback = {
+ .stream_name = "ETDM1_OUT",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = MTK_ETDM_RATES,
+ .formats = MTK_ETDM_FORMATS,
+ },
+ .ops = &mtk_dai_etdm_ops,
+ .probe = mtk_dai_etdm_probe,
+ },
+ {
+ .name = "ETDM2_OUT",
+ .id = MT8188_AFE_IO_ETDM2_OUT,
+ .playback = {
+ .stream_name = "ETDM2_OUT",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = MTK_ETDM_RATES,
+ .formats = MTK_ETDM_FORMATS,
+ },
+ .ops = &mtk_dai_etdm_ops,
+ .probe = mtk_dai_etdm_probe,
+ },
+ {
+ .name = "ETDM3_OUT",
+ .id = MT8188_AFE_IO_ETDM3_OUT,
+ .playback = {
+ .stream_name = "ETDM3_OUT",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = MTK_ETDM_RATES,
+ .formats = MTK_ETDM_FORMATS,
+ },
+ .ops = &mtk_dai_hdmitx_dptx_ops,
+ .probe = mtk_dai_etdm_probe,
+ },
+};
+
+static void mt8188_etdm_update_sync_info(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ struct mtk_dai_etdm_priv *mst_data;
+ int i;
+ int mst_dai_id;
+
+ for (i = MT8188_AFE_IO_ETDM_START; i < MT8188_AFE_IO_ETDM_END; i++) {
+ etdm_data = afe_priv->dai_priv[i];
+ if (etdm_data->cowork_source_id != COWORK_ETDM_NONE) {
+ mst_dai_id = etdm_data->cowork_source_id;
+ mst_data = afe_priv->dai_priv[mst_dai_id];
+ if (mst_data->cowork_source_id != COWORK_ETDM_NONE)
+ dev_info(afe->dev, "%s [%d] wrong sync source\n"
+ , __func__, i);
+ mst_data->cowork_slv_id[mst_data->cowork_slv_count] = i;
+ mst_data->cowork_slv_count++;
+ }
+ }
+}
+
+static void mt8188_dai_etdm_parse_of(struct mtk_base_afe *afe)
+{
+ const struct device_node *of_node = afe->dev->of_node;
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ int i, j;
+ char prop[48];
+ u8 disable_chn[MT8188_ETDM_MAX_CHANNELS];
+ int max_chn = MT8188_ETDM_MAX_CHANNELS;
+ u32 sel;
+ int ret;
+ int dai_id;
+ unsigned int sync_id;
+ struct {
+ const char *name;
+ const unsigned int sync_id;
+ } of_afe_etdms[MT8188_AFE_IO_ETDM_NUM] = {
+ {"etdm-in1", ETDM_SYNC_FROM_IN1},
+ {"etdm-in2", ETDM_SYNC_FROM_IN2},
+ {"etdm-out1", ETDM_SYNC_FROM_OUT1},
+ {"etdm-out2", ETDM_SYNC_FROM_OUT2},
+ {"etdm-out3", ETDM_SYNC_FROM_OUT3},
+ };
+
+ for (i = 0; i < MT8188_AFE_IO_ETDM_NUM; i++) {
+ dai_id = ETDM_TO_DAI_ID(i);
+ etdm_data = afe_priv->dai_priv[dai_id];
+
+ ret = snprintf(prop, sizeof(prop),
+ "mediatek,%s-mclk-always-on-rate",
+ of_afe_etdms[i].name);
+ if (ret < 0) {
+ dev_info(afe->dev, "%s snprintf err=%d\n",
+ __func__, ret);
+ return;
+ }
+ ret = of_property_read_u32(of_node, prop, &sel);
+ if (ret == 0) {
+ etdm_data->mclk_dir = SND_SOC_CLOCK_OUT;
+ if (mtk_dai_etdm_cal_mclk(afe, sel, dai_id))
+ dev_info(afe->dev, "%s unsupported mclk %uHz\n",
+ __func__, sel);
+ }
+
+ ret = snprintf(prop, sizeof(prop),
+ "mediatek,%s-multi-pin-mode",
+ of_afe_etdms[i].name);
+ if (ret < 0) {
+ dev_info(afe->dev, "%s snprintf err=%d\n",
+ __func__, ret);
+ return;
+ }
+ etdm_data->data_mode = of_property_read_bool(of_node, prop);
+
+ ret = snprintf(prop, sizeof(prop),
+ "mediatek,%s-cowork-source",
+ of_afe_etdms[i].name);
+ if (ret < 0) {
+ dev_info(afe->dev, "%s snprintf err=%d\n",
+ __func__, ret);
+ return;
+ }
+ ret = of_property_read_u32(of_node, prop, &sel);
+ if (ret == 0) {
+ if (sel >= MT8188_AFE_IO_ETDM_NUM) {
+ dev_info(afe->dev, "%s invalid id=%d\n",
+ __func__, sel);
+ etdm_data->cowork_source_id = COWORK_ETDM_NONE;
+ } else {
+ sync_id = of_afe_etdms[sel].sync_id;
+ etdm_data->cowork_source_id =
+ sync_to_dai_id(sync_id);
+ }
+ } else {
+ etdm_data->cowork_source_id = COWORK_ETDM_NONE;
+ }
+ }
+
+ /* etdm in only */
+ for (i = 0; i < 2; i++) {
+ ret = snprintf(prop, sizeof(prop),
+ "mediatek,%s-chn-disabled",
+ of_afe_etdms[i].name);
+ if (ret < 0) {
+ dev_info(afe->dev, "%s snprintf err=%d\n",
+ __func__, ret);
+ return;
+ }
+ ret = of_property_read_variable_u8_array(of_node, prop,
+ disable_chn,
+ 1, max_chn);
+ if (ret < 0)
+ continue;
+
+ for (j = 0; j < ret; j++) {
+ if (disable_chn[j] >= MT8188_ETDM_MAX_CHANNELS)
+ dev_info(afe->dev, "%s [%d] invalid chn %u\n",
+ __func__, j, disable_chn[j]);
+ else
+ etdm_data->in_disable_ch[disable_chn[j]] = true;
+ }
+ }
+ mt8188_etdm_update_sync_info(afe);
+}
+
+static int init_etdm_priv_data(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_priv;
+ int i;
+
+ for (i = MT8188_AFE_IO_ETDM_START; i < MT8188_AFE_IO_ETDM_END; i++) {
+ etdm_priv = devm_kzalloc(afe->dev,
+ sizeof(struct mtk_dai_etdm_priv),
+ GFP_KERNEL);
+ if (!etdm_priv)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[i] = etdm_priv;
+ }
+
+ afe_priv->dai_priv[MT8188_AFE_IO_DPTX] =
+ afe_priv->dai_priv[MT8188_AFE_IO_ETDM3_OUT];
+
+ mt8188_dai_etdm_parse_of(afe);
+ return 0;
+}
+
+int mt8188_dai_etdm_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_etdm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver);
+
+ dai->dapm_widgets = mtk_dai_etdm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets);
+ dai->dapm_routes = mtk_dai_etdm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes);
+ dai->controls = mtk_dai_etdm_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_dai_etdm_controls);
+
+ return init_etdm_priv_data(afe);
+}
--
2.18.0
SMC call is required to communicate with ATF for some secure operations,
so we add SMC ops IDs and SMC CMD ID to common header.
Signed-off-by: Trevor Wu <[email protected]>
---
sound/soc/mediatek/common/mtk-base-afe.h | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h
index ef83e78c22a8..f51578b6c50a 100644
--- a/sound/soc/mediatek/common/mtk-base-afe.h
+++ b/sound/soc/mediatek/common/mtk-base-afe.h
@@ -9,7 +9,26 @@
#ifndef _MTK_BASE_AFE_H_
#define _MTK_BASE_AFE_H_
+#include <linux/soc/mediatek/mtk_sip_svc.h>
+
#define MTK_STREAM_NUM (SNDRV_PCM_STREAM_LAST + 1)
+#define MTK_SIP_AUDIO_CONTROL MTK_SIP_SMC_CMD(0x517)
+
+/* SMC CALL Operations */
+enum mtk_audio_smc_call_op {
+ MTK_AUDIO_SMC_OP_INIT = 0,
+ MTK_AUDIO_SMC_OP_DRAM_REQUEST,
+ MTK_AUDIO_SMC_OP_DRAM_RELEASE,
+ MTK_AUDIO_SMC_OP_SRAM_REQUEST,
+ MTK_AUDIO_SMC_OP_SRAM_RELEASE,
+ MTK_AUDIO_SMC_OP_ADSP_REQUEST,
+ MTK_AUDIO_SMC_OP_ADSP_RELEASE,
+ MTK_AUDIO_SMC_OP_DOMAIN_SIDEBANDS,
+ MTK_AUDIO_SMC_OP_BTCVSD_WRITE,
+ MTK_AUDIO_SMC_OP_BTCVSD_UPDATE_CTRL_CLEAR,
+ MTK_AUDIO_SMC_OP_BTCVSD_UPDATE_CTRL_UNDERFLOW,
+ MTK_AUDIO_SMC_OP_NUM
+};
struct mtk_base_memif_data {
int id;
--
2.18.0
Add mt8188 adda dai driver support.
Signed-off-by: Trevor Wu <[email protected]>
---
I don't add Reviewed-by tag because one new header file is included
in the patch to resolve compiling issue found by kernel test robot.
---
sound/soc/mediatek/mt8188/mt8188-dai-adda.c | 632 ++++++++++++++++++++
1 file changed, 632 insertions(+)
create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-adda.c
diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-adda.c b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c
new file mode 100644
index 000000000000..2f3080ff9e21
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c
@@ -0,0 +1,632 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI ADDA Control
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Bicycle Tsai <[email protected]>
+ * Trevor Wu <[email protected]>
+ * Chun-Chia Chiu <[email protected]>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include "mt8188-afe-clk.h"
+#include "mt8188-afe-common.h"
+#include "mt8188-reg.h"
+
+#define ADDA_HIRES_THRES 48000
+
+enum {
+ SUPPLY_SEQ_CLOCK_SEL,
+ SUPPLY_SEQ_ADDA_DL_ON,
+ SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+ SUPPLY_SEQ_ADDA_UL_ON,
+ SUPPLY_SEQ_ADDA_AFE_ON,
+};
+
+enum {
+ MTK_AFE_ADDA_DL_RATE_8K = 0,
+ MTK_AFE_ADDA_DL_RATE_11K = 1,
+ MTK_AFE_ADDA_DL_RATE_12K = 2,
+ MTK_AFE_ADDA_DL_RATE_16K = 3,
+ MTK_AFE_ADDA_DL_RATE_22K = 4,
+ MTK_AFE_ADDA_DL_RATE_24K = 5,
+ MTK_AFE_ADDA_DL_RATE_32K = 6,
+ MTK_AFE_ADDA_DL_RATE_44K = 7,
+ MTK_AFE_ADDA_DL_RATE_48K = 8,
+ MTK_AFE_ADDA_DL_RATE_96K = 9,
+ MTK_AFE_ADDA_DL_RATE_192K = 10,
+};
+
+enum {
+ MTK_AFE_ADDA_UL_RATE_8K = 0,
+ MTK_AFE_ADDA_UL_RATE_16K = 1,
+ MTK_AFE_ADDA_UL_RATE_32K = 2,
+ MTK_AFE_ADDA_UL_RATE_48K = 3,
+ MTK_AFE_ADDA_UL_RATE_96K = 4,
+ MTK_AFE_ADDA_UL_RATE_192K = 5,
+};
+
+enum {
+ DELAY_DATA_MISO1 = 0,
+ DELAY_DATA_MISO0 = 1,
+};
+
+struct mtk_dai_adda_priv {
+ unsigned int dl_rate;
+ unsigned int ul_rate;
+};
+
+static unsigned int afe_adda_dl_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_DL_RATE_8K;
+ case 11025:
+ return MTK_AFE_ADDA_DL_RATE_11K;
+ case 12000:
+ return MTK_AFE_ADDA_DL_RATE_12K;
+ case 16000:
+ return MTK_AFE_ADDA_DL_RATE_16K;
+ case 22050:
+ return MTK_AFE_ADDA_DL_RATE_22K;
+ case 24000:
+ return MTK_AFE_ADDA_DL_RATE_24K;
+ case 32000:
+ return MTK_AFE_ADDA_DL_RATE_32K;
+ case 44100:
+ return MTK_AFE_ADDA_DL_RATE_44K;
+ case 48000:
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_DL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_DL_RATE_192K;
+ default:
+ dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ }
+}
+
+static unsigned int afe_adda_ul_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_UL_RATE_8K;
+ case 16000:
+ return MTK_AFE_ADDA_UL_RATE_16K;
+ case 32000:
+ return MTK_AFE_ADDA_UL_RATE_32K;
+ case 48000:
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_UL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_UL_RATE_192K;
+ default:
+ dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ }
+}
+
+static int mt8188_adda_mtkaif_init(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtkaif_param *param = &afe_priv->mtkaif_params;
+ int delay_data;
+ int delay_cycle;
+ unsigned int mask = 0;
+ unsigned int val = 0;
+
+ /* set rx protocol 2 & mtkaif_rxif_clkinv_adc inverse */
+ regmap_set_bits(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
+ MTKAIF_RXIF_CLKINV_ADC | MTKAIF_RXIF_PROTOCOL2);
+
+ regmap_set_bits(afe->regmap, AFE_AUD_PAD_TOP, RG_RX_PROTOCOL2);
+
+ if (!param->mtkaif_calibration_ok) {
+ dev_info(afe->dev, "%s(), calibration fail\n", __func__);
+ return 0;
+ }
+
+ /* set delay for ch1, ch2 */
+ if (param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_0] >=
+ param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_1]) {
+ delay_data = DELAY_DATA_MISO1;
+ delay_cycle =
+ param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_0] -
+ param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_1];
+ } else {
+ delay_data = DELAY_DATA_MISO0;
+ delay_cycle =
+ param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_1] -
+ param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_0];
+ }
+
+ val = 0;
+ mask = (MTKAIF_RXIF_DELAY_DATA | MTKAIF_RXIF_DELAY_CYCLE_MASK);
+ val |= FIELD_PREP(MTKAIF_RXIF_DELAY_CYCLE_MASK, delay_cycle);
+ val |= FIELD_PREP(MTKAIF_RXIF_DELAY_DATA, delay_data);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG2, mask, val);
+
+ return 0;
+}
+
+static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8188_adda_mtkaif_init(afe);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(125, 135);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void mtk_adda_ul_mictype(struct mtk_base_afe *afe, bool dmic)
+{
+ unsigned int reg = AFE_ADDA_UL_SRC_CON0;
+ unsigned int val;
+
+ val = (UL_SDM3_LEVEL_CTL | UL_MODE_3P25M_CH1_CTL |
+ UL_MODE_3P25M_CH2_CTL);
+
+ /* turn on dmic, ch1, ch2 */
+ if (dmic)
+ regmap_set_bits(afe->regmap, reg, val);
+ else
+ regmap_clear_bits(afe->regmap, reg, val);
+}
+
+static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtkaif_param *param = &afe_priv->mtkaif_params;
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mtk_adda_ul_mictype(afe, param->mtkaif_dmic_on);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(125, 135);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_audio_hires_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct clk *clk = afe_priv->clk[MT8188_CLK_TOP_AUDIO_H_SEL];
+ struct clk *clk_parent;
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ clk_parent = afe_priv->clk[MT8188_CLK_TOP_APLL1];
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ clk_parent = afe_priv->clk[MT8188_CLK_XTAL_26M];
+ break;
+ default:
+ return 0;
+ }
+ mt8188_afe_set_clk_parent(afe, clk, clk_parent);
+
+ return 0;
+}
+
+static int mtk_afe_adc_hires_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = source;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_adda_priv *adda_priv;
+
+ adda_priv = afe_priv->dai_priv[MT8188_AFE_IO_ADDA];
+
+ if (!adda_priv) {
+ dev_err(afe->dev, "%s adda_priv == NULL", __func__);
+ return 0;
+ }
+
+ return !!(adda_priv->ul_rate > ADDA_HIRES_THRES);
+}
+
+static int mtk_afe_dac_hires_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = source;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_adda_priv *adda_priv;
+
+ adda_priv = afe_priv->dai_priv[MT8188_AFE_IO_ADDA];
+
+ if (!adda_priv) {
+ dev_err(afe->dev, "%s adda_priv == NULL", __func__);
+ return 0;
+ }
+
+ return !!(adda_priv->dl_rate > ADDA_HIRES_THRES);
+}
+
+static const struct snd_kcontrol_new mtk_dai_adda_o176_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN176, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I002 Switch", AFE_CONN176, 2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN176, 20, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN176, 22, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN176_2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_dai_adda_o177_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN177, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I003 Switch", AFE_CONN177, 3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN177, 21, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN177, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN177_2, 7, 1, 0),
+};
+
+static const char * const adda_dlgain_mux_map[] = {
+ "Bypass", "Connect",
+};
+
+static SOC_ENUM_SINGLE_DECL(adda_dlgain_mux_map_enum,
+ SND_SOC_NOPM, 0,
+ adda_dlgain_mux_map);
+
+static const struct snd_kcontrol_new adda_dlgain_mux_control =
+ SOC_DAPM_ENUM("DL_GAIN_MUX", adda_dlgain_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+ SND_SOC_DAPM_MIXER("I168", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I169", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("O176", SND_SOC_NOPM, 0, 0,
+ mtk_dai_adda_o176_mix,
+ ARRAY_SIZE(mtk_dai_adda_o176_mix)),
+ SND_SOC_DAPM_MIXER("O177", SND_SOC_NOPM, 0, 0,
+ mtk_dai_adda_o177_mix,
+ ARRAY_SIZE(mtk_dai_adda_o177_mix)),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
+ AFE_ADDA_UL_DL_CON0,
+ ADDA_AFE_ON_SHIFT, 0,
+ NULL,
+ 0),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON,
+ AFE_ADDA_DL_SRC2_CON0,
+ DL_2_SRC_ON_TMP_CTRL_PRE_SHIFT, 0,
+ mtk_adda_dl_event,
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+ AFE_ADDA_UL_SRC_CON0,
+ UL_SRC_ON_TMP_CTL_SHIFT, 0,
+ mtk_adda_ul_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_HIRES", SUPPLY_SEQ_CLOCK_SEL,
+ SND_SOC_NOPM,
+ 0, 0,
+ mtk_audio_hires_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+ SND_SOC_NOPM,
+ 0, 0,
+ mtk_adda_mtkaif_cfg_event,
+ SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX("DL_GAIN_MUX", SND_SOC_NOPM, 0, 0,
+ &adda_dlgain_mux_control),
+
+ SND_SOC_DAPM_PGA("DL_GAIN", AFE_ADDA_DL_SRC2_CON0,
+ DL_2_GAIN_ON_CTL_PRE_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_INPUT("ADDA_INPUT"),
+ SND_SOC_DAPM_OUTPUT("ADDA_OUTPUT"),
+
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_hires"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_hires"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+ {"ADDA Capture", NULL, "ADDA Enable"},
+ {"ADDA Capture", NULL, "ADDA Capture Enable"},
+ {"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"},
+ {"ADDA Capture", NULL, "aud_adc"},
+ {"ADDA Capture", NULL, "aud_adc_hires", mtk_afe_adc_hires_connect},
+ {"aud_adc_hires", NULL, "AUDIO_HIRES"},
+
+ {"I168", NULL, "ADDA Capture"},
+ {"I169", NULL, "ADDA Capture"},
+
+ {"ADDA Playback", NULL, "ADDA Enable"},
+ {"ADDA Playback", NULL, "ADDA Playback Enable"},
+ {"ADDA Playback", NULL, "aud_dac"},
+ {"ADDA Playback", NULL, "aud_dac_hires", mtk_afe_dac_hires_connect},
+ {"aud_dac_hires", NULL, "AUDIO_HIRES"},
+
+ {"DL_GAIN", NULL, "O176"},
+ {"DL_GAIN", NULL, "O177"},
+
+ {"DL_GAIN_MUX", "Bypass", "O176"},
+ {"DL_GAIN_MUX", "Bypass", "O177"},
+ {"DL_GAIN_MUX", "Connect", "DL_GAIN"},
+
+ {"ADDA Playback", NULL, "DL_GAIN_MUX"},
+
+ {"O176", "I000 Switch", "I000"},
+ {"O177", "I001 Switch", "I001"},
+
+ {"O176", "I002 Switch", "I002"},
+ {"O177", "I003 Switch", "I003"},
+
+ {"O176", "I020 Switch", "I020"},
+ {"O177", "I021 Switch", "I021"},
+
+ {"O176", "I022 Switch", "I022"},
+ {"O177", "I023 Switch", "I023"},
+
+ {"O176", "I070 Switch", "I070"},
+ {"O177", "I071 Switch", "I071"},
+
+ {"ADDA Capture", NULL, "ADDA_INPUT"},
+ {"ADDA_OUTPUT", NULL, "ADDA Playback"},
+};
+
+static int mt8188_adda_dmic_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtkaif_param *param = &afe_priv->mtkaif_params;
+
+ ucontrol->value.integer.value[0] = param->mtkaif_dmic_on;
+ return 0;
+}
+
+static int mt8188_adda_dmic_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtkaif_param *param = &afe_priv->mtkaif_params;
+ int dmic_on;
+
+ dmic_on = !!ucontrol->value.integer.value[0];
+
+ dev_dbg(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n",
+ __func__, kcontrol->id.name, dmic_on);
+
+ if (param->mtkaif_dmic_on == dmic_on)
+ return 0;
+
+ param->mtkaif_dmic_on = dmic_on;
+ return 1;
+}
+
+static const struct snd_kcontrol_new mtk_dai_adda_controls[] = {
+ SOC_SINGLE("ADDA_DL_GAIN", AFE_ADDA_DL_SRC2_CON1,
+ DL_2_GAIN_CTL_PRE_SHIFT, 65535, 0),
+ SOC_SINGLE_BOOL_EXT("MTKAIF_DMIC Switch", 0,
+ mt8188_adda_dmic_get, mt8188_adda_dmic_set),
+};
+
+static int mtk_dai_da_configure(struct mtk_base_afe *afe,
+ unsigned int rate, int id)
+{
+ unsigned int val = 0;
+ unsigned int mask = 0;
+
+ /* set sampling rate */
+ mask |= DL_2_INPUT_MODE_CTL_MASK;
+ val |= FIELD_PREP(DL_2_INPUT_MODE_CTL_MASK,
+ afe_adda_dl_rate_transform(afe, rate));
+
+ /* turn off saturation */
+ mask |= DL_2_CH1_SATURATION_EN_CTL;
+ mask |= DL_2_CH2_SATURATION_EN_CTL;
+
+ /* turn off mute function */
+ mask |= DL_2_MUTE_CH1_OFF_CTL_PRE;
+ mask |= DL_2_MUTE_CH2_OFF_CTL_PRE;
+ val |= DL_2_MUTE_CH1_OFF_CTL_PRE;
+ val |= DL_2_MUTE_CH2_OFF_CTL_PRE;
+
+ /* set voice input data if input sample rate is 8k or 16k */
+ mask |= DL_2_VOICE_MODE_CTL_PRE;
+ if (rate == 8000 || rate == 16000)
+ val |= DL_2_VOICE_MODE_CTL_PRE;
+
+ regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, mask, val);
+
+ /* new 2nd sdm */
+ regmap_set_bits(afe->regmap, AFE_ADDA_DL_SDM_DCCOMP_CON,
+ DL_USE_NEW_2ND_SDM);
+
+ return 0;
+}
+
+static int mtk_dai_ad_configure(struct mtk_base_afe *afe,
+ unsigned int rate, int id)
+{
+ unsigned int val;
+ unsigned int mask;
+
+ mask = UL_VOICE_MODE_CTL_MASK;
+ val = FIELD_PREP(UL_VOICE_MODE_CTL_MASK,
+ afe_adda_ul_rate_transform(afe, rate));
+
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,
+ mask, val);
+ return 0;
+}
+
+static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_adda_priv *adda_priv = afe_priv->dai_priv[dai->id];
+ unsigned int rate = params_rate(params);
+ int id = dai->id;
+ int ret = 0;
+
+ dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+ __func__, id, substream->stream, rate);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ adda_priv->dl_rate = rate;
+ ret = mtk_dai_da_configure(afe, rate, id);
+ } else {
+ adda_priv->ul_rate = rate;
+ ret = mtk_dai_ad_configure(afe, rate, id);
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_adda_ops = {
+ .hw_params = mtk_dai_adda_hw_params,
+};
+
+/* dai driver */
+#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 |\
+ SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
+ {
+ .name = "ADDA",
+ .id = MT8188_AFE_IO_ADDA,
+ .playback = {
+ .stream_name = "ADDA Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_PLAYBACK_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ADDA Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+};
+
+static int init_adda_priv_data(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_adda_priv *adda_priv;
+
+ adda_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_adda_priv),
+ GFP_KERNEL);
+ if (!adda_priv)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[MT8188_AFE_IO_ADDA] = adda_priv;
+
+ return 0;
+}
+
+int mt8188_dai_adda_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_adda_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+
+ dai->dapm_widgets = mtk_dai_adda_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+ dai->dapm_routes = mtk_dai_adda_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+ dai->controls = mtk_dai_adda_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_dai_adda_controls);
+
+ return init_adda_priv_data(afe);
+}
--
2.18.0
On 08/12/2022 04:31, Trevor Wu wrote:
> Add document for mt8188 board with mt6359.
>
> Signed-off-by: Trevor Wu <[email protected]>
> ---
> .../bindings/sound/mt8188-mt6359.yaml | 60 +++++++++++++++++++
> 1 file changed, 60 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
>
> diff --git a/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml b/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
> new file mode 100644
> index 000000000000..eac1c87b693a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
Missing vendor prefix. You got comments for it already.
> @@ -0,0 +1,60 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/mt8188-mt6359.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek MT8188 ASoC sound card
> +
> +maintainers:
> + - Trevor Wu <[email protected]>
> +
> +properties:
> + compatible:
> + const: mediatek,mt8188-mt6359-evb
> +
> + model:
> + $ref: /schemas/types.yaml#/definitions/string
> + description: User specified audio sound card name
> +
> + audio-routing:
> + $ref: /schemas/types.yaml#/definitions/non-unique-string-array
> + description:
> + A list of the connections between audio components. Each entry is a
> + sink/source pair of strings. Valid names could be the input or output
> + widgets of audio components, power supplies, MicBias of codec and the
> + software switch.
> +
> + mediatek,platform:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: The phandle of MT8188 ASoC platform.
> +
> + mediatek,dptx-codec:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: The phandle of MT8188 Display Port Tx codec node.
> +
> + mediatek,hdmi-codec:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: The phandle of MT8188 HDMI codec node.
Why you do not use DAI links for all these?
> +
> +additionalProperties: false
> +
> +required:
> + - compatible
> + - mediatek,platform
> +
> +examples:
> + - |
> +
Drop blank line.
> + sound: mt8188-sound {
Drop label, not used. Use generic node names, so just "sound".
> + compatible = "mediatek,mt8188-mt6359-evb";
Best regards,
Krzysztof
On 08/12/2022 04:31, Trevor Wu wrote:
> Add mt8188 audio afe document.
Use subject prefixes matching the subsystem (git log --oneline -- ...).
>
> Signed-off-by: Trevor Wu <[email protected]>
> ---
> .../devicetree/bindings/sound/mt8188-afe.yaml | 196 ++++++++++++++++++
> 1 file changed, 196 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/sound/mt8188-afe.yaml
>
> diff --git a/Documentation/devicetree/bindings/sound/mt8188-afe.yaml b/Documentation/devicetree/bindings/sound/mt8188-afe.yaml
> new file mode 100644
> index 000000000000..6ab26494d924
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/mt8188-afe.yaml
This is a friendly reminder during the review process.
It seems my previous comments were not fully addressed. Maybe my
feedback got lost between the quotes, maybe you just forgot to apply it.
Please go back to the previous discussion and either implement all
requested changes or keep discussing them.
Thank you.
Comment was about filename matching compatible, so with vendor prefix.
> @@ -0,0 +1,196 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/mt8188-afe.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek AFE PCM controller for mt8188
> +
> +maintainers:
> + - Trevor Wu <[email protected]>
> +
> +properties:
> + compatible:
> + const: mediatek,mt8188-afe
> +
> + reg:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + resets:
> + maxItems: 1
> +
> + reset-names:
> + const: audiosys
> +
> + mediatek,topckgen:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: The phandle of the mediatek topckgen controller
> +
> + power-domains:
> + maxItems: 1
> +
> + clocks:
> + items:
> + - description: 26M clock
> + - description: audio pll1 clock
> + - description: audio pll2 clock
> + - description: clock divider for i2si1_mck
> + - description: clock divider for i2si2_mck
> + - description: clock divider for i2so1_mck
> + - description: clock divider for i2so2_mck
> + - description: clock divider for dptx_mck
> + - description: a1sys hoping clock
> + - description: audio intbus clock
> + - description: audio hires clock
> + - description: audio local bus clock
> + - description: mux for dptx_mck
> + - description: mux for i2so1_mck
> + - description: mux for i2so2_mck
> + - description: mux for i2si1_mck
> + - description: mux for i2si2_mck
> + - description: audio 26m clock
> +
> + clock-names:
> + items:
> + - const: clk26m
> + - const: apll1_ck
> + - const: apll2_ck
> + - const: apll12_div0
> + - const: apll12_div1
> + - const: apll12_div2
> + - const: apll12_div3
> + - const: apll12_div9
> + - const: a1sys_hp_sel
> + - const: aud_intbus_sel
> + - const: audio_h_sel
> + - const: audio_local_bus_sel
> + - const: dptx_m_sel
> + - const: i2so1_m_sel
> + - const: i2so2_m_sel
> + - const: i2si1_m_sel
> + - const: i2si2_m_sel
> + - const: adsp_audio_26m
> +
> +patternProperties:
> + "^mediatek,etdm-in[1-2]-chn-disabled$":
> + $ref: /schemas/types.yaml#/definitions/uint8-array
> + minItems: 1
> + maxItems: 16
> + description:
> + By default, all data received from ETDM pins will be outputed to
> + memory. etdm in supports disable_out in direct mode(w/o interconn).
> + User can specify the channel ID which they hope dropping and then
> + the specified channel won't be seen on memory.
So we know what are the IDs but it's a mystery what are the values.
Especially with unique values - how any of these should case that
channel "won't be seen in memory"?
> + uniqueItems: true
> + items:
> + minimum: 0
> + maximum: 15
> +
> + "^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
> + description: Specify etdm in mclk output rate for always on case.
How is it different than assigned-clock-rates?
> +
> + "^mediatek,etdm-out[1-3]-mclk-always-on-rate-hz$":
> + description: Specify etdm out mclk output rate for always on case.
> +
> + "^mediatek,etdm-in[1-2]-multi-pin-mode$":
> + type: boolean
> + description: if present, the etdm data mode is I2S.
> +
> + "^mediatek,etdm-out[1-3]-multi-pin-mode$":
> + type: boolean
> + description: if present, the etdm data mode is I2S.
> +
> + "^mediatek,etdm-in[1-2]-cowork-source$":
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description:
> + etdm modules can share the same external clock pin. Specify
> + which etdm clock source is required by this etdm in moudule.
typo: module
> + enum:
> + - 0 # etdm1_in
> + - 1 # etdm2_in
> + - 2 # etdm1_out
I don't get. This suggests that etdm1_out can be clock source of
etdm-in1. Or etdm1_in can be clock source of etdm-in1... It does not
make sense...
> + - 3 # etdm2_out
> +
> + "^mediatek,etdm-out[1-2]-cowork-source$":
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: |
> + etdm modules can share the same external clock pin. Specify
> + which etdm clock source is required by this etdm out moudule.
> + enum:
> + - 0 # etdm1_in
> + - 1 # etdm2_in
> + - 2 # etdm1_out
> + - 3 # etdm2_out
> +
> +required:
> + - compatible
> + - reg
> + - interrupts
> + - resets
> + - reset-names
> + - mediatek,topckgen
> + - power-domains
> + - clocks
> + - clock-names
> +
Best regards,
Krzysztof
On Fri, 2022-12-09 at 11:15 +0100, Krzysztof Kozlowski wrote:
> On 08/12/2022 04:31, Trevor Wu wrote:
> > Add mt8188 audio afe document.
>
> Use subject prefixes matching the subsystem (git log --oneline --
> ...).
>
> >
> > Signed-off-by: Trevor Wu <[email protected]>
> > ---
> > .../devicetree/bindings/sound/mt8188-afe.yaml | 196
> > ++++++++++++++++++
> > 1 file changed, 196 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/sound/mt8188-
> > afe.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/sound/mt8188-
> > afe.yaml b/Documentation/devicetree/bindings/sound/mt8188-afe.yaml
> > new file mode 100644
> > index 000000000000..6ab26494d924
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/sound/mt8188-afe.yaml
>
>
> This is a friendly reminder during the review process.
>
> It seems my previous comments were not fully addressed. Maybe my
> feedback got lost between the quotes, maybe you just forgot to apply
> it.
> Please go back to the previous discussion and either implement all
> requested changes or keep discussing them.
>
> Thank you.
>
> Comment was about filename matching compatible, so with vendor
> prefix.
Hi Krzysztof,
Thanks for your review first.
I aplogyize for my misunderstanding to your comment.
I just renamed the file name(mt8188-afe-pcm.yaml -> mt8188-afe.yaml),
and I didn't notice vendor prefix should be included.
I will correct the name in v4.
>
> > @@ -0,0 +1,196 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id:
> > https://urldefense.com/v3/__http://devicetree.org/schemas/sound/mt8188-afe.yaml*__;Iw!!CTRNKA9wMg0ARbw!kiYsaIYR-KZ9KTQq3rOBRr3GeIC2UtnjFMWMKExmd_V7pW75AaEz30DuKv0nifWtMlknW8os7MiJ2pCCVT7ixRMsg7TpXw$
> >
> > +$schema:
> > https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!kiYsaIYR-KZ9KTQq3rOBRr3GeIC2UtnjFMWMKExmd_V7pW75AaEz30DuKv0nifWtMlknW8os7MiJ2pCCVT7ixRO-2YqhFw$
> >
> > +
> > +title: MediaTek AFE PCM controller for mt8188
> > +
> > +maintainers:
> > + - Trevor Wu <[email protected]>
> > +
> > +properties:
> > + compatible:
> > + const: mediatek,mt8188-afe
> > +
> > + reg:
> > + maxItems: 1
> > +
> > + interrupts:
> > + maxItems: 1
> > +
> > + resets:
> > + maxItems: 1
> > +
> > + reset-names:
> > + const: audiosys
> > +
> > + mediatek,topckgen:
> > + $ref: /schemas/types.yaml#/definitions/phandle
> > + description: The phandle of the mediatek topckgen controller
> > +
> > + power-domains:
> > + maxItems: 1
> > +
> > + clocks:
> > + items:
> > + - description: 26M clock
> > + - description: audio pll1 clock
> > + - description: audio pll2 clock
> > + - description: clock divider for i2si1_mck
> > + - description: clock divider for i2si2_mck
> > + - description: clock divider for i2so1_mck
> > + - description: clock divider for i2so2_mck
> > + - description: clock divider for dptx_mck
> > + - description: a1sys hoping clock
> > + - description: audio intbus clock
> > + - description: audio hires clock
> > + - description: audio local bus clock
> > + - description: mux for dptx_mck
> > + - description: mux for i2so1_mck
> > + - description: mux for i2so2_mck
> > + - description: mux for i2si1_mck
> > + - description: mux for i2si2_mck
> > + - description: audio 26m clock
> > +
> > + clock-names:
> > + items:
> > + - const: clk26m
> > + - const: apll1_ck
> > + - const: apll2_ck
> > + - const: apll12_div0
> > + - const: apll12_div1
> > + - const: apll12_div2
> > + - const: apll12_div3
> > + - const: apll12_div9
> > + - const: a1sys_hp_sel
> > + - const: aud_intbus_sel
> > + - const: audio_h_sel
> > + - const: audio_local_bus_sel
> > + - const: dptx_m_sel
> > + - const: i2so1_m_sel
> > + - const: i2so2_m_sel
> > + - const: i2si1_m_sel
> > + - const: i2si2_m_sel
> > + - const: adsp_audio_26m
> > +
> > +patternProperties:
> > + "^mediatek,etdm-in[1-2]-chn-disabled$":
> > + $ref: /schemas/types.yaml#/definitions/uint8-array
> > + minItems: 1
> > + maxItems: 16
> > + description:
> > + By default, all data received from ETDM pins will be
> > outputed to
> > + memory. etdm in supports disable_out in direct mode(w/o
> > interconn).
> > + User can specify the channel ID which they hope dropping and
> > then
> > + the specified channel won't be seen on memory.
>
> So we know what are the IDs but it's a mystery what are the values.
> Especially with unique values - how any of these should case that
> channel "won't be seen in memory"?
>
For example,
FE can support 14ch, but BE(etdm) can't support 14ch(it can support
16ch).
In the case, we can configure 16ch to etdm and make use of the property
to disable the last two channels.
mediatek,etdm-in1-chn-disabled = /bits/ 8 <0xE 0xF>;
> > + uniqueItems: true
> > + items:
> > + minimum: 0
> > + maximum: 15
> > +
> > + "^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
> > + description: Specify etdm in mclk output rate for always on
> > case.
>
> How is it different than assigned-clock-rates?
>
This includes clock enabling at init stage.
> > +
> > + "^mediatek,etdm-out[1-3]-mclk-always-on-rate-hz$":
> > + description: Specify etdm out mclk output rate for always on
> > case.
> > +
> > + "^mediatek,etdm-in[1-2]-multi-pin-mode$":
> > + type: boolean
> > + description: if present, the etdm data mode is I2S.
> > +
> > + "^mediatek,etdm-out[1-3]-multi-pin-mode$":
> > + type: boolean
> > + description: if present, the etdm data mode is I2S.
> > +
> > + "^mediatek,etdm-in[1-2]-cowork-source$":
> > + $ref: /schemas/types.yaml#/definitions/uint32
> > + description:
> > + etdm modules can share the same external clock pin. Specify
> > + which etdm clock source is required by this etdm in moudule.
>
> typo: module
>
Thanks, I will correct it in v4.
> > + enum:
> > + - 0 # etdm1_in
> > + - 1 # etdm2_in
> > + - 2 # etdm1_out
>
> I don't get. This suggests that etdm1_out can be clock source of
> etdm-in1. Or etdm1_in can be clock source of etdm-in1... It does not
> make sense...
>
You are correct.
etdm1_in should only choose other etdm as its clock source when user
needs this property, so etdm1_in should not be included in the enum
items for etdm-in1-cowork-source.
I will separate these properties in v4.
Thanks,
Trevor
> > + - 3 # etdm2_out
> > +
> > + "^mediatek,etdm-out[1-2]-cowork-source$":
> > + $ref: /schemas/types.yaml#/definitions/uint32
> > + description: |
> > + etdm modules can share the same external clock pin. Specify
> > + which etdm clock source is required by this etdm out
> > moudule.
> > + enum:
> > + - 0 # etdm1_in
> > + - 1 # etdm2_in
> > + - 2 # etdm1_out
> > + - 3 # etdm2_out
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - interrupts
> > + - resets
> > + - reset-names
> > + - mediatek,topckgen
> > + - power-domains
> > + - clocks
> > + - clock-names
> > +
>
> Best regards,
> Krzysztof
>
On 09/12/2022 11:56, Trevor Wu (吳文良) wrote:
>>> +
>>> +patternProperties:
>>> + "^mediatek,etdm-in[1-2]-chn-disabled$":
>>> + $ref: /schemas/types.yaml#/definitions/uint8-array
>>> + minItems: 1
>>> + maxItems: 16
>>> + description:
>>> + By default, all data received from ETDM pins will be
>>> outputed to
>>> + memory. etdm in supports disable_out in direct mode(w/o
>>> interconn).
>>> + User can specify the channel ID which they hope dropping and
>>> then
>>> + the specified channel won't be seen on memory.
>>
>> So we know what are the IDs but it's a mystery what are the values.
>> Especially with unique values - how any of these should case that
>> channel "won't be seen in memory"?
>>
> For example,
> FE can support 14ch, but BE(etdm) can't support 14ch(it can support
> 16ch).
> In the case, we can configure 16ch to etdm and make use of the property
> to disable the last two channels.
>
> mediatek,etdm-in1-chn-disabled = /bits/ 8 <0xE 0xF>;
Your description should explain that this is a list of channel IDs which
should be disabled.
>
>
>>> + uniqueItems: true
>>> + items:
>>> + minimum: 0
>>> + maximum: 15
>>> +
>>> + "^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
>>> + description: Specify etdm in mclk output rate for always on
>>> case.
>>
>> How is it different than assigned-clock-rates?
>>
> This includes clock enabling at init stage.
assigned-clock-rates are also at init stage. I asked what is different.
>
>>> +
>>> + "^mediatek,etdm-out[1-3]-mclk-always-on-rate-hz$":
>>> + description: Specify etdm out mclk output rate for always on
>>> case.
>>> +
>>> + "^mediatek,etdm-in[1-2]-multi-pin-mode$":
>>> + type: boolean
>>> + description: if present, the etdm data mode is I2S.
>>> +
>>> + "^mediatek,etdm-out[1-3]-multi-pin-mode$":
>>> + type: boolean
>>> + description: if present, the etdm data mode is I2S.
>>> +
>>> + "^mediatek,etdm-in[1-2]-cowork-source$":
>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>> + description:
>>> + etdm modules can share the same external clock pin. Specify
>>> + which etdm clock source is required by this etdm in moudule.
>>
>> typo: module
>>
Best regards,
Krzysztof
On Fri, 2022-12-09 at 15:56 +0100, Krzysztof Kozlowski wrote:
> On 09/12/2022 11:56, Trevor Wu (吳文良) wrote:
> > > > +
> > > > +patternProperties:
> > > > + "^mediatek,etdm-in[1-2]-chn-disabled$":
> > > > + $ref: /schemas/types.yaml#/definitions/uint8-array
> > > > + minItems: 1
> > > > + maxItems: 16
> > > > + description:
> > > > + By default, all data received from ETDM pins will be
> > > > outputed to
> > > > + memory. etdm in supports disable_out in direct mode(w/o
> > > > interconn).
> > > > + User can specify the channel ID which they hope dropping
> > > > and
> > > > then
> > > > + the specified channel won't be seen on memory.
> > >
> > > So we know what are the IDs but it's a mystery what are the
> > > values.
> > > Especially with unique values - how any of these should case that
> > > channel "won't be seen in memory"?
> > >
> >
> > For example,
> > FE can support 14ch, but BE(etdm) can't support 14ch(it can support
> > 16ch).
> > In the case, we can configure 16ch to etdm and make use of the
> > property
> > to disable the last two channels.
> >
> > mediatek,etdm-in1-chn-disabled = /bits/ 8 <0xE 0xF>;
>
> Your description should explain that this is a list of channel IDs
> which
> should be disabled.
>
Hi Krzysztof,
Thanks for your suggestion.
I'll put it into the description.
> >
> >
> > > > + uniqueItems: true
> > > > + items:
> > > > + minimum: 0
> > > > + maximum: 15
> > > > +
> > > > + "^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
> > > > + description: Specify etdm in mclk output rate for always
> > > > on
> > > > case.
> > >
> > > How is it different than assigned-clock-rates?
> > >
> >
> > This includes clock enabling at init stage.
>
> assigned-clock-rates are also at init stage. I asked what is
> different.
>
If the property is used, there are three parts included in dai driver
probe function.
1. set clock parent (which APLL)
2. set clock rate (MCLK rate)
3. enable clock (MCLK On)
The first two parts can be done by existing dts clock properties, but
the last one can't.
When MCLK should be enabled at boot time and kept on, this property is used. That's why I say the property is designed for always-on case.
Thanks,
Trevor.
> >
> > > > +
> > > > + "^mediatek,etdm-out[1-3]-mclk-always-on-rate-hz$":
> > > > + description: Specify etdm out mclk output rate for always
> > > > on
> > > > case.
> > > > +
> > > > + "^mediatek,etdm-in[1-2]-multi-pin-mode$":
> > > > + type: boolean
> > > > + description: if present, the etdm data mode is I2S.
> > > > +
> > > > + "^mediatek,etdm-out[1-3]-multi-pin-mode$":
> > > > + type: boolean
> > > > + description: if present, the etdm data mode is I2S.
> > > > +
> > > > + "^mediatek,etdm-in[1-2]-cowork-source$":
> > > > + $ref: /schemas/types.yaml#/definitions/uint32
> > > > + description:
> > > > + etdm modules can share the same external clock pin.
> > > > Specify
> > > > + which etdm clock source is required by this etdm in
> > > > moudule.
> > >
> > > typo: module
> > >
>
> Best regards,
> Krzysztof
>
On 12/12/2022 03:43, Trevor Wu (吳文良) wrote:
>>>
>>>>> + uniqueItems: true
>>>>> + items:
>>>>> + minimum: 0
>>>>> + maximum: 15
>>>>> +
>>>>> + "^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
>>>>> + description: Specify etdm in mclk output rate for always
>>>>> on
>>>>> case.
>>>>
>>>> How is it different than assigned-clock-rates?
>>>>
>>>
>>> This includes clock enabling at init stage.
>>
>> assigned-clock-rates are also at init stage. I asked what is
>> different.
>>
>
> If the property is used, there are three parts included in dai driver
> probe function.
>
> 1. set clock parent (which APLL)
> 2. set clock rate (MCLK rate)
> 3. enable clock (MCLK On)
>
> The first two parts can be done by existing dts clock properties, but
> the last one can't.
> When MCLK should be enabled at boot time and kept on, this property is used. That's why I say the property is designed for always-on case.
Heh, so the "always on case" means this property enables clock? How is
this even DT property? That's not how clocks should be kept enabled. You
need proper clock provider and consumer.
Best regards,
Krzysztof
On Fri, 2022-12-09 at 11:18 +0100, Krzysztof Kozlowski wrote:
> On 08/12/2022 04:31, Trevor Wu wrote:
> > Add document for mt8188 board with mt6359.
> >
> > Signed-off-by: Trevor Wu <[email protected]>
> > ---
> > .../bindings/sound/mt8188-mt6359.yaml | 60
> > +++++++++++++++++++
> > 1 file changed, 60 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/sound/mt8188-
> > mt6359.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/sound/mt8188-
> > mt6359.yaml b/Documentation/devicetree/bindings/sound/mt8188-
> > mt6359.yaml
> > new file mode 100644
> > index 000000000000..eac1c87b693a
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
>
> Missing vendor prefix. You got comments for it already.
Hi Krzysztof,
I will correct it in V4.
>
> > @@ -0,0 +1,60 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id:
> > https://urldefense.com/v3/__http://devicetree.org/schemas/sound/mt8188-mt6359.yaml*__;Iw!!CTRNKA9wMg0ARbw!nw_OzBIRlXrEP6K_EtxEWAIZzuvnD3Dm_KDuv8gpLRqlnnSfVLksNfKqMmeYiFlEVVy6F2BXwmXB8oQkDPeBuEXMtfLX2w$
> >
> > +$schema:
> > https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!nw_OzBIRlXrEP6K_EtxEWAIZzuvnD3Dm_KDuv8gpLRqlnnSfVLksNfKqMmeYiFlEVVy6F2BXwmXB8oQkDPeBuEXodFoCJA$
> >
> > +
> > +title: MediaTek MT8188 ASoC sound card
> > +
> > +maintainers:
> > + - Trevor Wu <[email protected]>
> > +
> > +properties:
> > + compatible:
> > + const: mediatek,mt8188-mt6359-evb
> > +
> > + model:
> > + $ref: /schemas/types.yaml#/definitions/string
> > + description: User specified audio sound card name
> > +
> > + audio-routing:
> > + $ref: /schemas/types.yaml#/definitions/non-unique-string-array
> > + description:
> > + A list of the connections between audio components. Each
> > entry is a
> > + sink/source pair of strings. Valid names could be the input
> > or output
> > + widgets of audio components, power supplies, MicBias of
> > codec and the
> > + software switch.
> > +
> > + mediatek,platform:
> > + $ref: /schemas/types.yaml#/definitions/phandle
> > + description: The phandle of MT8188 ASoC platform.
> > +
> > + mediatek,dptx-codec:
> > + $ref: /schemas/types.yaml#/definitions/phandle
> > + description: The phandle of MT8188 Display Port Tx codec node.
> > +
> > + mediatek,hdmi-codec:
> > + $ref: /schemas/types.yaml#/definitions/phandle
> > + description: The phandle of MT8188 HDMI codec node.
>
> Why you do not use DAI links for all these?
Are the following examples "DAI links" you mean?
hdmi-dai-link {
link-name = "HDMI Playback";
cpu {
sound-dai = <&q6afedai TERTIARY_MI2S_RX>;
};
platform {
sound-dai = <&q6routing>;
};
codec {
sound-dai = <<9611_codec 0>;
};
};
or
headset-codec {
sound-dai = <&rt5682s>;
};
As far as I know, only "mediatek,platform" was used at the beginning.
Next, hdmi-codec was introduced, and it followed the same style to get
phandle. Finally, it became three properties in mt8195, and the
implementation of mt8188 was inherited from mt8195.
I just glanced over the usage of dai links.
As I see it, I will replace the codec parts with dai link structure
like the example above first. It seems to be easier to extend more
codecs with the same tyle.
For platform part, I need more time to check if it is better to keep
the original implementation, because we still have to take SOF related
implementation into consideration.
>
> > +
> > +additionalProperties: false
> > +
> > +required:
> > + - compatible
> > + - mediatek,platform
> > +
> > +examples:
> > + - |
> > +
>
> Drop blank line.
>
OK, I will fix it in V4.
> > + sound: mt8188-sound {
>
> Drop label, not used. Use generic node names, so just "sound".
>
OK, I will fix it in V4.
Thanks,
Trevor
> > + compatible = "mediatek,mt8188-mt6359-evb";
>
> Best regards,
> Krzysztof
>
Il 08/12/22 04:31, Trevor Wu ha scritto:
> Add mt8188 audio cg clock control. Audio clock gates are registered to CCF
> for reference count and clock parent management.
>
> Signed-off-by: Trevor Wu <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
Il 08/12/22 04:31, Trevor Wu ha scritto:
> Add mt8188 pcmif dai driver support
>
> Signed-off-by: Trevor Wu <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
Il 08/12/22 04:31, Trevor Wu ha scritto:
> Add audio clock wrapper and audio tuner control.
>
> Signed-off-by: Trevor Wu <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
Il 08/12/22 04:31, Trevor Wu ha scritto:
> Add mt8188 adda dai driver support.
>
> Signed-off-by: Trevor Wu <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
> ---
> I don't add Reviewed-by tag because one new header file is included
> in the patch to resolve compiling issue found by kernel test robot.
> ---
> sound/soc/mediatek/mt8188/mt8188-dai-adda.c | 632 ++++++++++++++++++++
> 1 file changed, 632 insertions(+)
> create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-adda.c
Il 08/12/22 04:31, Trevor Wu ha scritto:
> Add mt8188 etdm dai driver support.
>
> Signed-off-by: Trevor Wu <[email protected]>
> ---
> I don't add Reviewed-by tag because one new header file is included
> in the patch to resolve compiling issue found by kernel test robot.
> Additionally, I re-layout the code for better understanding of the
> follow-up patch.
> ---
> sound/soc/mediatek/mt8188/mt8188-dai-etdm.c | 2591 +++++++++++++++++++
> 1 file changed, 2591 insertions(+)
> create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
>
> diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
> new file mode 100644
> index 000000000000..c653fa5e3f85
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
..snip..
> +
> +static void mt8188_dai_etdm_parse_of(struct mtk_base_afe *afe)
> +{
> + const struct device_node *of_node = afe->dev->of_node;
> + struct mt8188_afe_private *afe_priv = afe->platform_priv;
> + struct mtk_dai_etdm_priv *etdm_data;
> + int i, j;
> + char prop[48];
> + u8 disable_chn[MT8188_ETDM_MAX_CHANNELS];
> + int max_chn = MT8188_ETDM_MAX_CHANNELS;
> + u32 sel;
> + int ret;
> + int dai_id;
> + unsigned int sync_id;
> + struct {
> + const char *name;
> + const unsigned int sync_id;
> + } of_afe_etdms[MT8188_AFE_IO_ETDM_NUM] = {
> + {"etdm-in1", ETDM_SYNC_FROM_IN1},
> + {"etdm-in2", ETDM_SYNC_FROM_IN2},
> + {"etdm-out1", ETDM_SYNC_FROM_OUT1},
> + {"etdm-out2", ETDM_SYNC_FROM_OUT2},
> + {"etdm-out3", ETDM_SYNC_FROM_OUT3},
> + };
> +
> + for (i = 0; i < MT8188_AFE_IO_ETDM_NUM; i++) {
> + dai_id = ETDM_TO_DAI_ID(i);
> + etdm_data = afe_priv->dai_priv[dai_id];
> +
> + ret = snprintf(prop, sizeof(prop),
> + "mediatek,%s-mclk-always-on-rate",
> + of_afe_etdms[i].name);
> + if (ret < 0) {
> + dev_info(afe->dev, "%s snprintf err=%d\n",
Is this property optional? If yes, this dev_info() must be a dev_dbg(),
otherwise, this must be a dev_err().
Please fix all prints to use the right message level.
> + __func__, ret);
> + return;
Also, is it possible to specify this property only on selected eTDMs?
As it is right now, if anyone wants to specify this only on, for example,
etdm-out1 and out2, that won't work.
In that case, you should replace that return with a `continue`.
P.S.: I'm raising this question because you're not forcing "all or nothing"
in commit [10/12] where you introduce the bindings for this driver,
so I suppose that returning (hence stopping to parse) is a mistake.
> + }
> + ret = of_property_read_u32(of_node, prop, &sel);
> + if (ret == 0) {
> + etdm_data->mclk_dir = SND_SOC_CLOCK_OUT;
> + if (mtk_dai_etdm_cal_mclk(afe, sel, dai_id))
> + dev_info(afe->dev, "%s unsupported mclk %uHz\n",
> + __func__, sel);
> + }
> +
Regards,
Angelo
Il 08/12/22 04:31, Trevor Wu ha scritto:
> SMC call is required to communicate with ATF for some secure operations,
> so we add SMC ops IDs and SMC CMD ID to common header.
>
> Signed-off-by: Trevor Wu <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
On 12/12/2022 16:34, Trevor Wu (吳文良) wrote:
> On Fri, 2022-12-09 at 11:18 +0100, Krzysztof Kozlowski wrote:
>> On 08/12/2022 04:31, Trevor Wu wrote:
>>> Add document for mt8188 board with mt6359.
>>>
>>> Signed-off-by: Trevor Wu <[email protected]>
>>> ---
>>> .../bindings/sound/mt8188-mt6359.yaml | 60
>>> +++++++++++++++++++
>>> 1 file changed, 60 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/sound/mt8188-
>>> mt6359.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/sound/mt8188-
>>> mt6359.yaml b/Documentation/devicetree/bindings/sound/mt8188-
>>> mt6359.yaml
>>> new file mode 100644
>>> index 000000000000..eac1c87b693a
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/sound/mt8188-mt6359.yaml
>>
>> Missing vendor prefix. You got comments for it already.
> Hi Krzysztof,
>
> I will correct it in V4.
>
>>
>>> @@ -0,0 +1,60 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id:
>>> https://urldefense.com/v3/__http://devicetree.org/schemas/sound/mt8188-mt6359.yaml*__;Iw!!CTRNKA9wMg0ARbw!nw_OzBIRlXrEP6K_EtxEWAIZzuvnD3Dm_KDuv8gpLRqlnnSfVLksNfKqMmeYiFlEVVy6F2BXwmXB8oQkDPeBuEXMtfLX2w$
>>>
>>> +$schema:
>>> https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!nw_OzBIRlXrEP6K_EtxEWAIZzuvnD3Dm_KDuv8gpLRqlnnSfVLksNfKqMmeYiFlEVVy6F2BXwmXB8oQkDPeBuEXodFoCJA$
>>>
>>> +
>>> +title: MediaTek MT8188 ASoC sound card
>>> +
>>> +maintainers:
>>> + - Trevor Wu <[email protected]>
>>> +
>>> +properties:
>>> + compatible:
>>> + const: mediatek,mt8188-mt6359-evb
>>> +
>>> + model:
>>> + $ref: /schemas/types.yaml#/definitions/string
>>> + description: User specified audio sound card name
>>> +
>>> + audio-routing:
>>> + $ref: /schemas/types.yaml#/definitions/non-unique-string-array
>>> + description:
>>> + A list of the connections between audio components. Each
>>> entry is a
>>> + sink/source pair of strings. Valid names could be the input
>>> or output
>>> + widgets of audio components, power supplies, MicBias of
>>> codec and the
>>> + software switch.
>>> +
>>> + mediatek,platform:
>>> + $ref: /schemas/types.yaml#/definitions/phandle
>>> + description: The phandle of MT8188 ASoC platform.
>>> +
>>> + mediatek,dptx-codec:
>>> + $ref: /schemas/types.yaml#/definitions/phandle
>>> + description: The phandle of MT8188 Display Port Tx codec node.
>>> +
>>> + mediatek,hdmi-codec:
>>> + $ref: /schemas/types.yaml#/definitions/phandle
>>> + description: The phandle of MT8188 HDMI codec node.
>>
>> Why you do not use DAI links for all these?
>
> Are the following examples "DAI links" you mean?
>
> hdmi-dai-link {
> link-name = "HDMI Playback";
> cpu {
> sound-dai = <&q6afedai TERTIARY_MI2S_RX>;
> };
>
> platform {
> sound-dai = <&q6routing>;
> };
>
> codec {
> sound-dai = <<9611_codec 0>;
> };
> };
Yes, this one. I think this is preferred. But anyway the point is to use
sound-dai-cells, not pure (non-DAI) phandles).
>
> or
>
> headset-codec {
> sound-dai = <&rt5682s>;
> };
>
>
> As far as I know, only "mediatek,platform" was used at the beginning.
> Next, hdmi-codec was introduced, and it followed the same style to get
> phandle. Finally, it became three properties in mt8195, and the
> implementation of mt8188 was inherited from mt8195.
OK, if you share common code it is fine.
>
> I just glanced over the usage of dai links.
> As I see it, I will replace the codec parts with dai link structure
> like the example above first. It seems to be easier to extend more
> codecs with the same tyle.
Would be good.
>
> For platform part, I need more time to check if it is better to keep
> the original implementation, because we still have to take SOF related
> implementation into consideration.
OK
Best regards,
Krzysztof
On Tue, 2022-12-13 at 11:45 +0100, AngeloGioacchino Del Regno wrote:
> Il 08/12/22 04:31, Trevor Wu ha scritto:
> > Add mt8188 etdm dai driver support.
> >
> > Signed-off-by: Trevor Wu <[email protected]>
> > ---
> > I don't add Reviewed-by tag because one new header file is included
> > in the patch to resolve compiling issue found by kernel test robot.
> > Additionally, I re-layout the code for better understanding of the
> > follow-up patch.
> > ---
> > sound/soc/mediatek/mt8188/mt8188-dai-etdm.c | 2591
> > +++++++++++++++++++
> > 1 file changed, 2591 insertions(+)
> > create mode 100644 sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
> >
> > diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
> > b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
> > new file mode 100644
> > index 000000000000..c653fa5e3f85
> > --- /dev/null
> > +++ b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
>
> ..snip..
>
> > +
> > +static void mt8188_dai_etdm_parse_of(struct mtk_base_afe *afe)
> > +{
> > + const struct device_node *of_node = afe->dev->of_node;
> > + struct mt8188_afe_private *afe_priv = afe->platform_priv;
> > + struct mtk_dai_etdm_priv *etdm_data;
> > + int i, j;
> > + char prop[48];
> > + u8 disable_chn[MT8188_ETDM_MAX_CHANNELS];
> > + int max_chn = MT8188_ETDM_MAX_CHANNELS;
> > + u32 sel;
> > + int ret;
> > + int dai_id;
> > + unsigned int sync_id;
> > + struct {
> > + const char *name;
> > + const unsigned int sync_id;
> > + } of_afe_etdms[MT8188_AFE_IO_ETDM_NUM] = {
> > + {"etdm-in1", ETDM_SYNC_FROM_IN1},
> > + {"etdm-in2", ETDM_SYNC_FROM_IN2},
> > + {"etdm-out1", ETDM_SYNC_FROM_OUT1},
> > + {"etdm-out2", ETDM_SYNC_FROM_OUT2},
> > + {"etdm-out3", ETDM_SYNC_FROM_OUT3},
> > + };
> > +
> > + for (i = 0; i < MT8188_AFE_IO_ETDM_NUM; i++) {
> > + dai_id = ETDM_TO_DAI_ID(i);
> > + etdm_data = afe_priv->dai_priv[dai_id];
> > +
> > + ret = snprintf(prop, sizeof(prop),
> > + "mediatek,%s-mclk-always-on-rate",
> > + of_afe_etdms[i].name);
> > + if (ret < 0) {
> > + dev_info(afe->dev, "%s snprintf err=%d\n",
>
> Is this property optional? If yes, this dev_info() must be a
> dev_dbg(),
> otherwise, this must be a dev_err().
>
> Please fix all prints to use the right message level.
Hi Angelo,
Yes, this property is optional, so I don't use dev_err here.
dev_dbg is hard to find the problem.
I will make use of dev_err instead of dev_info in V4.
>
> > + __func__, ret);
> > + return;
>
> Also, is it possible to specify this property only on selected eTDMs?
>
> As it is right now, if anyone wants to specify this only on, for
> example,
> etdm-out1 and out2, that won't work.
> In that case, you should replace that return with a `continue`.
>
> P.S.: I'm raising this question because you're not forcing "all or
> nothing"
> in commit [10/12] where you introduce the bindings for this
> driver,
> so I suppose that returning (hence stopping to parse) is a
> mistake.
>
It is OK to specify only etdm-out1 and out2 on.
This is just an simple error handling for snprintf to silence coverity.
Because it shouldn't happen, I don't return an error value to make
probe failed.
Thanks,
Trevor
> > + }
> > + ret = of_property_read_u32(of_node, prop, &sel);
> > + if (ret == 0) {
> > + etdm_data->mclk_dir = SND_SOC_CLOCK_OUT;
> > + if (mtk_dai_etdm_cal_mclk(afe, sel, dai_id))
> > + dev_info(afe->dev, "%s unsupported mclk
> > %uHz\n",
> > + __func__, sel);
> > + }
> > +
>
>
> Regards,
> Angelo
>
On Mon, 2022-12-12 at 09:40 +0100, Krzysztof Kozlowski wrote:
> On 12/12/2022 03:43, Trevor Wu (吳文良) wrote:
> > > >
> > > > > > + uniqueItems: true
> > > > > > + items:
> > > > > > + minimum: 0
> > > > > > + maximum: 15
> > > > > > +
> > > > > > + "^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
> > > > > > + description: Specify etdm in mclk output rate for
> > > > > > always
> > > > > > on
> > > > > > case.
> > > > >
> > > > > How is it different than assigned-clock-rates?
> > > > >
> > > >
> > > > This includes clock enabling at init stage.
> > >
> > > assigned-clock-rates are also at init stage. I asked what is
> > > different.
> > >
> >
> > If the property is used, there are three parts included in dai
> > driver
> > probe function.
> >
> > 1. set clock parent (which APLL)
> > 2. set clock rate (MCLK rate)
> > 3. enable clock (MCLK On)
> >
> > The first two parts can be done by existing dts clock properties,
> > but
> > the last one can't.
> > When MCLK should be enabled at boot time and kept on, this property
> > is used. That's why I say the property is designed for always-on
> > case.
>
> Heh, so the "always on case" means this property enables clock? How
> is
> this even DT property? That's not how clocks should be kept enabled.
> You
> need proper clock provider and consumer.
>
>
Hi Krzysztof,
Sorry, I don't know it is not appropriate to notify driver that the
clock should be ketp enabled after boot.
The original idea is that enabling this clock in the machine driver,
but a property to inform machine driver is also required when the
machine driver is shared by different codec combination. And it's
easier to handle set_rate and set_parent in etdm dai driver, so I put
the property here.
Do you mean if the clock consumer(audio codec or external DSP) requries
the clock, the consumer should enable the clock by itself?
Thanks,
Trevor
On 13/12/2022 16:06, Trevor Wu (吳文良) wrote:
> On Mon, 2022-12-12 at 09:40 +0100, Krzysztof Kozlowski wrote:
>> On 12/12/2022 03:43, Trevor Wu (吳文良) wrote:
>>>>>
>>>>>>> + uniqueItems: true
>>>>>>> + items:
>>>>>>> + minimum: 0
>>>>>>> + maximum: 15
>>>>>>> +
>>>>>>> + "^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
>>>>>>> + description: Specify etdm in mclk output rate for
>>>>>>> always
>>>>>>> on
>>>>>>> case.
>>>>>>
>>>>>> How is it different than assigned-clock-rates?
>>>>>>
>>>>>
>>>>> This includes clock enabling at init stage.
>>>>
>>>> assigned-clock-rates are also at init stage. I asked what is
>>>> different.
>>>>
>>>
>>> If the property is used, there are three parts included in dai
>>> driver
>>> probe function.
>>>
>>> 1. set clock parent (which APLL)
>>> 2. set clock rate (MCLK rate)
>>> 3. enable clock (MCLK On)
>>>
>>> The first two parts can be done by existing dts clock properties,
>>> but
>>> the last one can't.
>>> When MCLK should be enabled at boot time and kept on, this property
>>> is used. That's why I say the property is designed for always-on
>>> case.
>>
>> Heh, so the "always on case" means this property enables clock? How
>> is
>> this even DT property? That's not how clocks should be kept enabled.
>> You
>> need proper clock provider and consumer.
>>
>>
>
> Hi Krzysztof,
>
> Sorry, I don't know it is not appropriate to notify driver that the
> clock should be ketp enabled after boot.
>
> The original idea is that enabling this clock in the machine driver,
> but a property to inform machine driver is also required when the
> machine driver is shared by different codec combination. And it's
> easier to handle set_rate and set_parent in etdm dai driver, so I put
> the property here.
>
> Do you mean if the clock consumer(audio codec or external DSP) requries
> the clock, the consumer should enable the clock by itself?
Yes, your clocks should have consumers and they keep the clock enabled
when needed. Certain clocks can be marked as IGNORE or CRITICAL to keep
enabled without consumers (or even when consumers disable), but that's
still not a DT property.
Best regards,
Krzysztof
On Wed, 2022-12-14 at 13:02 +0100, Krzysztof Kozlowski wrote:
> On 13/12/2022 16:06, Trevor Wu (吳文良) wrote:
> > On Mon, 2022-12-12 at 09:40 +0100, Krzysztof Kozlowski wrote:
> > > On 12/12/2022 03:43, Trevor Wu (吳文良) wrote:
> > > > > >
> > > > > > > > + uniqueItems: true
> > > > > > > > + items:
> > > > > > > > + minimum: 0
> > > > > > > > + maximum: 15
> > > > > > > > +
> > > > > > > > + "^mediatek,etdm-in[1-2]-mclk-always-on-rate-hz$":
> > > > > > > > + description: Specify etdm in mclk output rate for
> > > > > > > > always
> > > > > > > > on
> > > > > > > > case.
> > > > > > >
> > > > > > > How is it different than assigned-clock-rates?
> > > > > > >
> > > > > >
> > > > > > This includes clock enabling at init stage.
> > > > >
> > > > > assigned-clock-rates are also at init stage. I asked what is
> > > > > different.
> > > > >
> > > >
> > > > If the property is used, there are three parts included in dai
> > > > driver
> > > > probe function.
> > > >
> > > > 1. set clock parent (which APLL)
> > > > 2. set clock rate (MCLK rate)
> > > > 3. enable clock (MCLK On)
> > > >
> > > > The first two parts can be done by existing dts clock
> > > > properties,
> > > > but
> > > > the last one can't.
> > > > When MCLK should be enabled at boot time and kept on, this
> > > > property
> > > > is used. That's why I say the property is designed for always-
> > > > on
> > > > case.
> > >
> > > Heh, so the "always on case" means this property enables clock?
> > > How
> > > is
> > > this even DT property? That's not how clocks should be kept
> > > enabled.
> > > You
> > > need proper clock provider and consumer.
> > >
> > >
> >
> > Hi Krzysztof,
> >
> > Sorry, I don't know it is not appropriate to notify driver that the
> > clock should be ketp enabled after boot.
> >
> > The original idea is that enabling this clock in the machine
> > driver,
> > but a property to inform machine driver is also required when the
> > machine driver is shared by different codec combination. And it's
> > easier to handle set_rate and set_parent in etdm dai driver, so I
> > put
> > the property here.
> >
> > Do you mean if the clock consumer(audio codec or external DSP)
> > requries
> > the clock, the consumer should enable the clock by itself?
>
> Yes, your clocks should have consumers and they keep the clock
> enabled
> when needed. Certain clocks can be marked as IGNORE or CRITICAL to
> keep
> enabled without consumers (or even when consumers disable), but
> that's
> still not a DT property.
>
>
Hi Krzysztof,
Got it. If the implementation is not suggested, I will drop the
property in V4 and ask consumer to use existing clock property with
clock control API instead when we have such case.
Thanks,
Trevor
>