* [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC
@ 2025-03-07 12:47 Darren.Ye
2025-03-07 12:47 ` [PATCH 01/14] ASoC: mediatek: common: modify mtk afe common driver for mt8196 Darren.Ye
` (12 more replies)
0 siblings, 13 replies; 27+ messages in thread
From: Darren.Ye @ 2025-03-07 12:47 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
This series of patches adds support for Mediatek AFE of MT8196 SoC.
Patches are based on broonie tree "for-next" branch.
---
This series patches dependent on:
[1]
https://lore.kernel.org/all/20250307032942.10447-1-guangjie.song@mediatek.com/
Darren Ye (14):
ASoC: mediatek: common: modify mtk afe common driver for mt8196
ASoC: mediatek: common: modify mtk afe platform driver for mt8196
ASoC: mediatek: mt8196: add common header
ASoC: mediatek: mt8196: add common interface for mt8196 DAI driver
ASoC: mediatek: mt8196: support audio clock control
ASoC: mediatek: mt8196: support audio GPIO control
ASoC: mediatek: mt8196: support ADDA in platform driver
ASoC: mediatek: mt8196: support I2S in platform driver
ASoC: mediatek: mt8196: support TDM in platform driver
ASoC: mediatek: mt8196: support CM in platform driver
ASoC: mediatek: mt8196: add platform driver
dt-bindings: mediatek: mt8196: add audio AFE document
ASoC: mediatek: mt8196: add machine driver with mt6681
dt-bindings: mediatek: mt8196: add mt8196-mt6681 document
.../bindings/sound/mediatek,mt8196-afe.yaml | 259 +
.../sound/mediatek,mt8196-mt6681.yaml | 122 +
sound/soc/mediatek/Kconfig | 30 +
sound/soc/mediatek/Makefile | 1 +
sound/soc/mediatek/common/mtk-afe-fe-dai.c | 30 +-
sound/soc/mediatek/common/mtk-afe-fe-dai.h | 6 +
.../mediatek/common/mtk-afe-platform-driver.c | 63 +-
.../mediatek/common/mtk-afe-platform-driver.h | 5 +
sound/soc/mediatek/common/mtk-base-afe.h | 13 +
sound/soc/mediatek/mt8196/Makefile | 19 +
sound/soc/mediatek/mt8196/mt8196-afe-clk.c | 698 +
sound/soc/mediatek/mt8196/mt8196-afe-clk.h | 313 +
sound/soc/mediatek/mt8196/mt8196-afe-cm.c | 94 +
sound/soc/mediatek/mt8196/mt8196-afe-cm.h | 23 +
sound/soc/mediatek/mt8196/mt8196-afe-common.h | 290 +
.../soc/mediatek/mt8196/mt8196-afe-control.c | 109 +
sound/soc/mediatek/mt8196/mt8196-afe-gpio.c | 239 +
sound/soc/mediatek/mt8196/mt8196-afe-gpio.h | 58 +
sound/soc/mediatek/mt8196/mt8196-afe-pcm.c | 5134 +++++++
sound/soc/mediatek/mt8196/mt8196-dai-adda.c | 2207 +++
sound/soc/mediatek/mt8196/mt8196-dai-i2s.c | 4399 ++++++
sound/soc/mediatek/mt8196/mt8196-dai-tdm.c | 837 ++
.../mediatek/mt8196/mt8196-interconnection.h | 121 +
sound/soc/mediatek/mt8196/mt8196-mt6681.c | 879 ++
sound/soc/mediatek/mt8196/mt8196-reg.h | 12133 ++++++++++++++++
25 files changed, 28055 insertions(+), 27 deletions(-)
create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml
create mode 100644 sound/soc/mediatek/mt8196/Makefile
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.h
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-cm.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-cm.h
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-common.h
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-control.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-gpio.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-gpio.h
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-adda.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-i2s.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-tdm.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-interconnection.h
create mode 100644 sound/soc/mediatek/mt8196/mt8196-mt6681.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-reg.h
--
2.45.2
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 01/14] ASoC: mediatek: common: modify mtk afe common driver for mt8196
2025-03-07 12:47 [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
@ 2025-03-07 12:47 ` Darren.Ye
2025-03-07 15:20 ` Krzysztof Kozlowski
2025-03-10 15:23 ` AngeloGioacchino Del Regno
2025-03-07 12:47 ` [PATCH 02/14] ASoC: mediatek: common: modify mtk afe platform " Darren.Ye
` (11 subsequent siblings)
12 siblings, 2 replies; 27+ messages in thread
From: Darren.Ye @ 2025-03-07 12:47 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Export register read and write interface, add sample reate interface, and
update the mtk_memif_set_channel interface for the mt8196 platform.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/common/mtk-afe-fe-dai.c | 30 ++++++++++++++--------
sound/soc/mediatek/common/mtk-afe-fe-dai.h | 6 +++++
sound/soc/mediatek/common/mtk-base-afe.h | 13 ++++++++++
3 files changed, 38 insertions(+), 11 deletions(-)
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
index 3809068f5620..c36dae520f04 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
@@ -18,7 +18,7 @@
#define AFE_BASE_END_OFFSET 8
-static int mtk_regmap_update_bits(struct regmap *map, int reg,
+int mtk_regmap_update_bits(struct regmap *map, int reg,
unsigned int mask,
unsigned int val, int shift)
{
@@ -26,13 +26,16 @@ static int mtk_regmap_update_bits(struct regmap *map, int reg,
return 0;
return regmap_update_bits(map, reg, mask << shift, val << shift);
}
+EXPORT_SYMBOL(mtk_regmap_update_bits);
+
+int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
-static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
{
if (reg < 0)
return 0;
return regmap_write(map, reg, val);
}
+EXPORT_SYMBOL(mtk_regmap_write);
int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
@@ -459,8 +462,12 @@ int mtk_memif_set_channel(struct mtk_base_afe *afe,
struct mtk_base_afe_memif *memif = &afe->memif[id];
unsigned int mono;
- if (memif->data->mono_shift < 0)
- return 0;
+ dev_info(afe->dev, "%s(), id: %d, channel: %d\n", __func__, id, channel);
+ mono = memif->data->mono_invert ^ (channel == 1);
+
+ if (memif->data->mono_shift > 0)
+ mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
+ 0x1, mono, memif->data->mono_shift);
if (memif->data->quad_ch_mask) {
unsigned int quad_ch = (channel == 4) ? 1 : 0;
@@ -470,11 +477,6 @@ int mtk_memif_set_channel(struct mtk_base_afe *afe,
quad_ch, memif->data->quad_ch_shift);
}
- if (memif->data->mono_invert)
- mono = (channel == 1) ? 0 : 1;
- else
- mono = (channel == 1) ? 1 : 0;
-
/* for specific configuration of memif mono mode */
if (memif->data->int_odd_flag_reg)
mtk_regmap_update_bits(afe->regmap,
@@ -482,8 +484,14 @@ int mtk_memif_set_channel(struct mtk_base_afe *afe,
1, mono,
memif->data->int_odd_flag_shift);
- return mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
- 1, mono, memif->data->mono_shift);
+ if (memif->data->ch_num_maskbit) {
+ dev_info(afe->dev, "%s(), set ch num id: %d, channel: %d\n", __func__, id, channel);
+ mtk_regmap_update_bits(afe->regmap, memif->data->ch_num_reg,
+ memif->data->ch_num_maskbit,
+ channel, memif->data->ch_num_shift);
+ }
+
+ return 0;
}
EXPORT_SYMBOL_GPL(mtk_memif_set_channel);
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.h b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
index b6d0f2b27e86..64b10ccba291 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.h
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
@@ -12,7 +12,13 @@
struct snd_soc_dai_ops;
struct mtk_base_afe;
struct mtk_base_afe_memif;
+struct mtk_base_irq_data;
+int mtk_regmap_update_bits(struct regmap *map, int reg,
+ unsigned int mask, unsigned int val,
+ int shift);
+int mtk_regmap_write(struct regmap *map, int reg,
+ unsigned int val);
int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai);
void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h
index f51578b6c50a..01c27fe92e2f 100644
--- a/sound/soc/mediatek/common/mtk-base-afe.h
+++ b/sound/soc/mediatek/common/mtk-base-afe.h
@@ -53,9 +53,11 @@ struct mtk_base_memif_data {
int enable_reg;
int enable_shift;
int hd_reg;
+ int hd_mask;
int hd_shift;
int hd_align_reg;
int hd_align_mshift;
+ int hd_msb_shift;
int msb_reg;
int msb_shift;
int msb_end_reg;
@@ -65,6 +67,10 @@ struct mtk_base_memif_data {
int ch_num_reg;
int ch_num_shift;
int ch_num_maskbit;
+ /* VUL 24~26 only for CM2 */
+ int out_on_use_reg;
+ int out_on_use_mask;
+ int out_on_use_shift;
/* playback memif only */
int pbuf_reg;
int pbuf_mask;
@@ -72,6 +78,9 @@ struct mtk_base_memif_data {
int minlen_reg;
int minlen_mask;
int minlen_shift;
+ int maxlen_reg;
+ int maxlen_mask;
+ int maxlen_shift;
};
struct mtk_base_irq_data {
@@ -87,6 +96,10 @@ struct mtk_base_irq_data {
int irq_clr_reg;
int irq_clr_shift;
int irq_status_shift;
+ int irq_ap_en_reg;
+ int irq_ap_en_shift;
+ int irq_scp_en_reg;
+ int irq_scp_en_shift;
};
struct device;
--
2.45.2
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 02/14] ASoC: mediatek: common: modify mtk afe platform driver for mt8196
2025-03-07 12:47 [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
2025-03-07 12:47 ` [PATCH 01/14] ASoC: mediatek: common: modify mtk afe common driver for mt8196 Darren.Ye
@ 2025-03-07 12:47 ` Darren.Ye
2025-03-07 15:21 ` Krzysztof Kozlowski
2025-03-07 12:47 ` [PATCH 04/14] ASoC: mediatek: mt8196: add common interface for mt8196 DAI driver Darren.Ye
` (10 subsequent siblings)
12 siblings, 1 reply; 27+ messages in thread
From: Darren.Ye @ 2025-03-07 12:47 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Mofify the pcm pointer interface to support 64-bit address access.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
.../mediatek/common/mtk-afe-platform-driver.c | 63 ++++++++++++++-----
.../mediatek/common/mtk-afe-platform-driver.h | 5 ++
2 files changed, 52 insertions(+), 16 deletions(-)
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
index 6b6330583941..5d8f4421e665 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
@@ -77,6 +77,16 @@ int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
}
EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control);
+int mtk_afe_pcm_open(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ /* set the wait_for_avail to 2 sec*/
+ substream->wait_time = msecs_to_jiffies(2 * 1000);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_pcm_open);
+
snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
@@ -86,29 +96,44 @@ snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component,
const struct mtk_base_memif_data *memif_data = memif->data;
struct regmap *regmap = afe->regmap;
struct device *dev = afe->dev;
- int reg_ofs_base = memif_data->reg_ofs_base;
- int reg_ofs_cur = memif_data->reg_ofs_cur;
- unsigned int hw_ptr = 0, hw_base = 0;
- int ret, pcm_ptr_bytes;
-
- ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr);
- if (ret || hw_ptr == 0) {
- dev_err(dev, "%s hw_ptr err\n", __func__);
- pcm_ptr_bytes = 0;
+ unsigned int hw_ptr_lower32 = 0, hw_ptr_upper32 = 0;
+ unsigned int hw_base_lower32 = 0, hw_base_upper32 = 0;
+ unsigned long long hw_ptr = 0, hw_base = 0;
+ int ret;
+ unsigned long long pcm_ptr_bytes = 0;
+
+ ret = regmap_read(regmap, memif_data->reg_ofs_cur, &hw_ptr_lower32);
+ if (ret || hw_ptr_lower32 == 0) {
+ dev_err(dev, "%s hw_ptr_lower32 err\n", __func__);
goto POINTER_RETURN_FRAMES;
}
- ret = regmap_read(regmap, reg_ofs_base, &hw_base);
- if (ret || hw_base == 0) {
- dev_err(dev, "%s hw_ptr err\n", __func__);
- pcm_ptr_bytes = 0;
- goto POINTER_RETURN_FRAMES;
+ if (memif_data->reg_ofs_cur_msb) {
+ ret = regmap_read(regmap, memif_data->reg_ofs_cur_msb, &hw_ptr_upper32);
+ if (ret) {
+ dev_err(dev, "%s hw_ptr_upper32 err\n", __func__);
+ goto POINTER_RETURN_FRAMES;
+ }
}
- pcm_ptr_bytes = hw_ptr - hw_base;
+ ret = regmap_read(regmap, memif_data->reg_ofs_base, &hw_base_lower32);
+ if (ret || hw_base_lower32 == 0) {
+ dev_err(dev, "%s hw_base_lower32 err\n", __func__);
+ goto POINTER_RETURN_FRAMES;
+ }
+ if (memif_data->reg_ofs_base_msb) {
+ ret = regmap_read(regmap, memif_data->reg_ofs_base_msb, &hw_base_upper32);
+ if (ret) {
+ dev_err(dev, "%s hw_base_upper32 err\n", __func__);
+ goto POINTER_RETURN_FRAMES;
+ }
+ }
+ hw_ptr = ((unsigned long long)hw_ptr_upper32 << 32) + hw_ptr_lower32;
+ hw_base = ((unsigned long long)hw_base_upper32 << 32) + hw_base_lower32;
POINTER_RETURN_FRAMES:
- return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
+ pcm_ptr_bytes = MTK_WORD_SIZE_ALIGN(hw_ptr - hw_base);
+ return bytes_to_frames(substream->runtime, (ssize_t)pcm_ptr_bytes);
}
EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer);
@@ -143,6 +168,12 @@ static int mtk_afe_component_probe(struct snd_soc_component *component)
return 0;
}
+void mtk_afe_pcm_free(struct snd_soc_component *component, struct snd_pcm *pcm)
+{
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+EXPORT_SYMBOL_GPL(mtk_afe_pcm_free);
+
const struct snd_soc_component_driver mtk_afe_pcm_platform = {
.name = AFE_PCM_NAME,
.pointer = mtk_afe_pcm_pointer,
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.h b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
index fcc923b88f12..948998968a45 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.h
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
@@ -12,15 +12,20 @@
#define AFE_PCM_NAME "mtk-afe-pcm"
extern const struct snd_soc_component_driver mtk_afe_pcm_platform;
+#define MTK_WORD_SIZE_ALIGN(x) ((x) & (0xfffffffff0))
+
struct mtk_base_afe;
struct snd_pcm;
struct snd_soc_component;
struct snd_soc_pcm_runtime;
+int mtk_afe_pcm_open(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream);
snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream);
int mtk_afe_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd);
+void mtk_afe_pcm_free(struct snd_soc_component *component, struct snd_pcm *pcm);
int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe);
int mtk_afe_add_sub_dai_control(struct snd_soc_component *component);
--
2.45.2
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 04/14] ASoC: mediatek: mt8196: add common interface for mt8196 DAI driver
2025-03-07 12:47 [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
2025-03-07 12:47 ` [PATCH 01/14] ASoC: mediatek: common: modify mtk afe common driver for mt8196 Darren.Ye
2025-03-07 12:47 ` [PATCH 02/14] ASoC: mediatek: common: modify mtk afe platform " Darren.Ye
@ 2025-03-07 12:47 ` Darren.Ye
2025-03-07 15:22 ` Krzysztof Kozlowski
2025-03-10 15:23 ` AngeloGioacchino Del Regno
2025-03-07 12:47 ` [PATCH 05/14] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
` (9 subsequent siblings)
12 siblings, 2 replies; 27+ messages in thread
From: Darren.Ye @ 2025-03-07 12:47 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Implement sample rate conversion and set private data for mt8196.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
.../soc/mediatek/mt8196/mt8196-afe-control.c | 109 ++++++++++++++++++
1 file changed, 109 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-control.c
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-control.c b/sound/soc/mediatek/mt8196/mt8196-afe-control.c
new file mode 100644
index 000000000000..bb85f4ad8585
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-control.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include "mt8196-afe-common.h"
+#include <linux/pm_runtime.h>
+
+unsigned int mt8196_general_rate_transform(struct device *dev,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_IPM2P0_RATE_8K;
+ case 11025:
+ return MTK_AFE_IPM2P0_RATE_11K;
+ case 12000:
+ return MTK_AFE_IPM2P0_RATE_12K;
+ case 16000:
+ return MTK_AFE_IPM2P0_RATE_16K;
+ case 22050:
+ return MTK_AFE_IPM2P0_RATE_22K;
+ case 24000:
+ return MTK_AFE_IPM2P0_RATE_24K;
+ case 32000:
+ return MTK_AFE_IPM2P0_RATE_32K;
+ case 44100:
+ return MTK_AFE_IPM2P0_RATE_44K;
+ case 48000:
+ return MTK_AFE_IPM2P0_RATE_48K;
+ case 88200:
+ return MTK_AFE_IPM2P0_RATE_88K;
+ case 96000:
+ return MTK_AFE_IPM2P0_RATE_96K;
+ case 176400:
+ return MTK_AFE_IPM2P0_RATE_176K;
+ case 192000:
+ return MTK_AFE_IPM2P0_RATE_192K;
+ /* not support 260K */
+ case 352800:
+ return MTK_AFE_IPM2P0_RATE_352K;
+ case 384000:
+ return MTK_AFE_IPM2P0_RATE_384K;
+ default:
+ dev_info(dev, "%s(), rate %u invalid, use %d!!!\n",
+ __func__,
+ rate, MTK_AFE_IPM2P0_RATE_48K);
+ return MTK_AFE_IPM2P0_RATE_48K;
+ }
+}
+
+static unsigned int pcm_rate_transform(struct device *dev,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_PCM_RATE_8K;
+ case 16000:
+ return MTK_AFE_PCM_RATE_16K;
+ case 32000:
+ return MTK_AFE_PCM_RATE_32K;
+ case 48000:
+ return MTK_AFE_PCM_RATE_48K;
+ default:
+ dev_info(dev, "%s(), rate %u invalid, use %d!!!\n",
+ __func__,
+ rate, MTK_AFE_PCM_RATE_32K);
+ return MTK_AFE_PCM_RATE_32K;
+ }
+}
+
+unsigned int mt8196_rate_transform(struct device *dev,
+ unsigned int rate, int aud_blk)
+{
+ switch (aud_blk) {
+ case MT8196_DAI_PCM_0:
+ case MT8196_DAI_PCM_1:
+ return pcm_rate_transform(dev, rate);
+ default:
+ return mt8196_general_rate_transform(dev, rate);
+ }
+}
+
+int mt8196_dai_set_priv(struct mtk_base_afe *afe, int id,
+ int priv_size, const void *priv_data)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ void *temp_data;
+
+ temp_data = devm_kzalloc(afe->dev,
+ priv_size,
+ GFP_KERNEL);
+ if (!temp_data)
+ return -ENOMEM;
+
+ if (priv_data)
+ memcpy(temp_data, priv_data, priv_size);
+
+ if (id >= MT8196_DAI_NUM || id < 0)
+ return -EINVAL;
+
+ afe_priv->dai_priv[id] = temp_data;
+
+ return 0;
+}
+
--
2.45.2
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 05/14] ASoC: mediatek: mt8196: support audio clock control
2025-03-07 12:47 [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (2 preceding siblings ...)
2025-03-07 12:47 ` [PATCH 04/14] ASoC: mediatek: mt8196: add common interface for mt8196 DAI driver Darren.Ye
@ 2025-03-07 12:47 ` Darren.Ye
2025-03-07 15:32 ` Krzysztof Kozlowski
2025-03-10 15:23 ` AngeloGioacchino Del Regno
2025-03-07 12:47 ` [PATCH 06/14] ASoC: mediatek: mt8196: support audio GPIO control Darren.Ye
` (8 subsequent siblings)
12 siblings, 2 replies; 27+ messages in thread
From: Darren.Ye @ 2025-03-07 12:47 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add audio clock wrapper and audio tuner control.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/mt8196/mt8196-afe-clk.c | 698 +++++++++++++++++++++
sound/soc/mediatek/mt8196/mt8196-afe-clk.h | 313 +++++++++
2 files changed, 1011 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.h
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.c b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
new file mode 100644
index 000000000000..d1407d7bf775
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
@@ -0,0 +1,698 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8196-afe-clk.c -- Mediatek 8196 afe clock ctrl
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include "mt8196-afe-common.h"
+#include "mt8196-afe-clk.h"
+
+static DEFINE_MUTEX(mutex_request_dram);
+
+static const char *aud_clks[CLK_NUM] = {
+ [CLK_HOPPING] = "aud_hopping_clk",
+ [CLK_F26M] = "aud_f26m_clk",
+ [CLK_UL0_ADC_CLK] = "aud_ul0_adc_clk",
+ [CLK_UL0_ADC_HIRES_CLK] = "aud_ul0_adc_hires_clk",
+ [CLK_UL1_ADC_CLK] = "aud_ul1_adc_clk",
+ [CLK_UL1_ADC_HIRES_CLK] = "aud_ul1_adc_hires_clk",
+ [CLK_APLL1] = "aud_apll1_clk",
+ [CLK_APLL2] = "aud_apll2_clk",
+ [CLK_APLL1_TUNER] = "aud_apll_tuner1_clk",
+ [CLK_APLL2_TUNER] = "aud_apll_tuner2_clk",
+ [CLK_VLP_MUX_AUDIOINTBUS] = "vlp_mux_audio_int",
+ [CLK_VLP_MUX_AUD_ENG1] = "vlp_mux_aud_eng1",
+ [CLK_VLP_MUX_AUD_ENG2] = "vlp_mux_aud_eng2",
+ [CLK_VLP_MUX_AUDIO_H] = "vlp_mux_audio_h",
+ [CLK_VLP_CLK26M] = "vlp_clk26m_clk",
+ [CLK_CK_MAINPLL_D4_D4] = "ck_mainpll_d4_d4",
+ [CLK_CK_MUX_AUD_1] = "ck_mux_aud_1",
+ [CLK_CK_APLL1_CK] = "ck_apll1_ck",
+ [CLK_CK_MUX_AUD_2] = "ck_mux_aud_2",
+ [CLK_CK_APLL2_CK] = "ck_apll2_ck",
+ [CLK_CK_APLL1_D4] = "ck_apll1_d4",
+ [CLK_CK_APLL2_D4] = "ck_apll2_d4",
+ [CLK_CK_I2SIN0_M_SEL] = "ck_i2sin0_m_sel",
+ [CLK_CK_I2SIN1_M_SEL] = "ck_i2sin1_m_sel",
+ [CLK_CK_FMI2S_M_SEL] = "ck_fmi2s_m_sel",
+ [CLK_CK_TDMOUT_M_SEL] = "ck_tdmout_m_sel",
+ [CLK_CK_APLL12_DIV_I2SIN0] = "ck_apll12_div_i2sin0",
+ [CLK_CK_APLL12_DIV_I2SIN1] = "ck_apll12_div_i2sin1",
+ [CLK_CK_APLL12_DIV_FMI2S] = "ck_apll12_div_fmi2s",
+ [CLK_CK_APLL12_DIV_TDMOUT_M] = "ck_apll12_div_tdmout_m",
+ [CLK_CK_APLL12_DIV_TDMOUT_B] = "ck_apll12_div_tdmout_b",
+ [CLK_CK_ADSP_SEL] = "ck_adsp_sel",
+ [CLK_CLK26M] = "ck_clk26m_clk",
+};
+
+int mt8196_set_audio_int_bus_parent(struct mtk_base_afe *afe,
+ int clk_id, bool int_bus)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct clk *clk;
+ int ret;
+
+ if (clk_id >= CLK_NUM || clk_id < 0)
+ return -EINVAL;
+
+ clk = int_bus ? afe_priv->clk[CLK_VLP_MUX_AUDIOINTBUS] :
+ afe_priv->clk[CLK_VLP_MUX_AUDIO_H];
+ ret = clk_set_parent(clk, afe_priv->clk[clk_id]);
+ if (ret)
+ dev_err(afe->dev, "%s() clk_set_parent %s fail %d, int_bus %d\n",
+ __func__, aud_clks[clk_id], ret, int_bus);
+
+ return ret;
+}
+
+static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret = 0;
+
+ dev_dbg(afe->dev, "%s(), enable: %d\n", __func__, enable);
+
+ if (enable) {
+ ret = clk_prepare_enable(afe_priv->clk[CLK_CK_MUX_AUD_1]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_CK_MUX_AUD_1], ret);
+ goto EXIT;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_1],
+ afe_priv->clk[CLK_CK_APLL1_CK]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_CK_MUX_AUD_1],
+ aud_clks[CLK_CK_APLL1_CK], ret);
+ goto EXIT;
+ }
+
+ /* 180.6336 / 4 = 45.1584MHz */
+ ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUD_ENG1]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_VLP_MUX_AUD_ENG1], ret);
+ goto EXIT;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_VLP_MUX_AUD_ENG1],
+ afe_priv->clk[CLK_CK_APLL1_D4]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_VLP_MUX_AUD_ENG1],
+ aud_clks[CLK_CK_APLL1_D4], ret);
+ goto EXIT;
+ }
+ ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_VLP_MUX_AUDIO_H], ret);
+ goto EXIT;
+ }
+
+ mt8196_set_audio_int_bus_parent(afe, CLK_CK_APLL1_CK, false);
+ } else {
+ ret = clk_set_parent(afe_priv->clk[CLK_VLP_MUX_AUD_ENG1],
+ afe_priv->clk[CLK_VLP_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_VLP_MUX_AUD_ENG1],
+ aud_clks[CLK_VLP_CLK26M], ret);
+ goto EXIT;
+ }
+ clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUD_ENG1]);
+
+ ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_1],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_CK_MUX_AUD_1],
+ aud_clks[CLK_CLK26M], ret);
+ goto EXIT;
+ }
+ clk_disable_unprepare(afe_priv->clk[CLK_CK_MUX_AUD_1]);
+
+ mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, false);
+ clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]);
+ }
+
+EXIT:
+ return 0;
+}
+
+static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret = 0;
+
+ dev_dbg(afe->dev, "%s(), enable: %d\n", __func__, enable);
+
+ if (enable) {
+ ret = clk_prepare_enable(afe_priv->clk[CLK_CK_MUX_AUD_2]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_CK_MUX_AUD_2], ret);
+ goto EXIT;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_2],
+ afe_priv->clk[CLK_CK_APLL2_CK]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_CK_MUX_AUD_2],
+ aud_clks[CLK_CK_APLL2_CK], ret);
+ goto EXIT;
+ }
+
+ /* 196.608 / 4 = 49.152MHz */
+ ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUD_ENG2]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_VLP_MUX_AUD_ENG2], ret);
+ goto EXIT;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_VLP_MUX_AUD_ENG2],
+ afe_priv->clk[CLK_CK_APLL2_D4]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_VLP_MUX_AUD_ENG2],
+ aud_clks[CLK_CK_APLL2_D4], ret);
+ goto EXIT;
+ }
+ ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_VLP_MUX_AUDIO_H], ret);
+ goto EXIT;
+ }
+
+ mt8196_set_audio_int_bus_parent(afe, CLK_CK_APLL2_CK, false);
+ } else {
+ ret = clk_set_parent(afe_priv->clk[CLK_VLP_MUX_AUD_ENG2],
+ afe_priv->clk[CLK_VLP_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_VLP_MUX_AUD_ENG2],
+ aud_clks[CLK_VLP_CLK26M], ret);
+ goto EXIT;
+ }
+ clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUD_ENG2]);
+
+ ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_2],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_CK_MUX_AUD_2],
+ aud_clks[CLK_CLK26M], ret);
+ goto EXIT;
+ }
+ clk_disable_unprepare(afe_priv->clk[CLK_CK_MUX_AUD_2]);
+
+ mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, false);
+ clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]);
+ }
+EXIT:
+ return 0;
+}
+
+int mt8196_afe_disable_apll(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret = 0;
+
+ dev_dbg(afe->dev, "%s() successfully start\n", __func__);
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_VLP_MUX_AUDIO_H], ret);
+ goto EXIT;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_CK_MUX_AUD_1]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_CK_MUX_AUD_1], ret);
+ goto EXIT;
+ }
+
+ ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_1],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_CK_MUX_AUD_1],
+ aud_clks[CLK_CLK26M], ret);
+ goto EXIT;
+ }
+ ret = clk_prepare_enable(afe_priv->clk[CLK_CK_MUX_AUD_2]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_CK_MUX_AUD_2], ret);
+ goto EXIT;
+ }
+
+ ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_2],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_CK_MUX_AUD_2],
+ aud_clks[CLK_CLK26M], ret);
+ goto EXIT;
+ }
+
+ clk_disable_unprepare(afe_priv->clk[CLK_CK_MUX_AUD_1]);
+ clk_disable_unprepare(afe_priv->clk[CLK_CK_MUX_AUD_2]);
+ mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, false);
+ clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]);
+
+ return 0;
+EXIT:
+ return ret;
+}
+
+static int mt8196_afe_apll_init(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ /* VLP_APLL1_CON0 = 0x6f28bd4c
+ * VLP_APLL2_CON2 = 0x78FD5264
+ * VLP_APLL1_TUNER_CON0 = 0x6f28bd4d
+ * VLP_APLL2_TUNER_CON0 = 0x78fd5265
+ */
+ if (afe_priv->vlp_ck) {
+ regmap_write(afe_priv->vlp_ck, VLP_APLL1_TUNER_CON0, 0x6f28bd4d);
+ regmap_write(afe_priv->vlp_ck, VLP_APLL2_TUNER_CON0, 0x78fd5265);
+ } else {
+ dev_warn(afe->dev, "%s vlp_ck regmap is null ptr\n", __func__);
+ }
+ return 0;
+}
+
+int mt8196_afe_enable_clock(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret = 0;
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_CK_ADSP_SEL]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_CK_ADSP_SEL], ret);
+ goto CLK_CK_ADSP_SEL_ERR;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUDIOINTBUS]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_VLP_MUX_AUDIOINTBUS], ret);
+ goto CLK_MUX_AUDIO_INTBUS_ERR;
+ }
+ ret = mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, true);
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_VLP_MUX_AUDIO_H], ret);
+ goto CLK_AUDIO_H_ERR;
+ }
+ mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, false);
+
+ /* IPM2.0: USE HOPPING & 26M */
+ ret = clk_prepare_enable(afe_priv->clk[CLK_HOPPING]);
+ if (ret) {
+ dev_err(afe->dev, "%s() clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_HOPPING], ret);
+ goto CLK_AFE_ERR;
+ }
+ ret = clk_prepare_enable(afe_priv->clk[CLK_F26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s() clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_F26M], ret);
+ goto CLK_AFE_ERR;
+ }
+
+ return 0;
+
+CLK_AFE_ERR:
+ /* IPM2.0: Use HOPPING & 26M */
+ clk_disable_unprepare(afe_priv->clk[CLK_HOPPING]);
+ clk_disable_unprepare(afe_priv->clk[CLK_F26M]);
+CLK_AUDIO_H_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]);
+CLK_MUX_AUDIO_INTBUS_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIOINTBUS]);
+CLK_CK_ADSP_SEL_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_CK_ADSP_SEL]);
+ return ret;
+}
+
+void mt8196_afe_disable_clock(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ dev_dbg(afe->dev, "%s() successfully start\n", __func__);
+
+ /* IPM2.0: Use HOPPING & 26M */
+ clk_disable_unprepare(afe_priv->clk[CLK_HOPPING]);
+ clk_disable_unprepare(afe_priv->clk[CLK_F26M]);
+ mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, false);
+ clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]);
+ mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, true);
+ clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIOINTBUS]);
+ clk_disable_unprepare(afe_priv->clk[CLK_CK_ADSP_SEL]);
+}
+
+int mt8196_afe_dram_request(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ dev_dbg(dev, "%s(), dram_resource_counter %d\n",
+ __func__, afe_priv->dram_resource_counter);
+
+ mutex_lock(&mutex_request_dram);
+
+ afe_priv->dram_resource_counter++;
+ mutex_unlock(&mutex_request_dram);
+
+ return 0;
+}
+
+int mt8196_afe_dram_release(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ dev_dbg(dev, "%s(), dram_resource_counter %d\n",
+ __func__, afe_priv->dram_resource_counter);
+
+ mutex_lock(&mutex_request_dram);
+ afe_priv->dram_resource_counter--;
+
+ if (afe_priv->dram_resource_counter < 0) {
+ dev_warn(dev, "%s(), dram_resource_counter %d\n",
+ __func__, afe_priv->dram_resource_counter);
+ afe_priv->dram_resource_counter = 0;
+ }
+ mutex_unlock(&mutex_request_dram);
+ return 0;
+}
+
+int mt8196_apll1_enable(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ /* setting for APLL */
+ apll1_mux_setting(afe, true);
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_APLL1], ret);
+ goto ERR_CLK_APLL1;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1_TUNER]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_APLL1_TUNER], ret);
+ goto ERR_CLK_APLL1_TUNER;
+ }
+
+ regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
+ 0x0000FFF7, 0x00000372);
+ regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1);
+
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0,
+ AUDIO_APLL1_EN_ON_MASK_SFT,
+ 0x1 << AUDIO_APLL1_EN_ON_SFT);
+ return 0;
+
+ERR_CLK_APLL1_TUNER:
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]);
+ERR_CLK_APLL1:
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL1]);
+
+ return ret;
+}
+
+void mt8196_apll1_disable(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0,
+ AUDIO_APLL1_EN_ON_MASK_SFT,
+ 0x0 << AUDIO_APLL1_EN_ON_SFT);
+
+ regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x0);
+
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]);
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL1]);
+
+ apll1_mux_setting(afe, false);
+}
+
+int mt8196_apll2_enable(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ /* setting for APLL */
+ apll2_mux_setting(afe, true);
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_APLL2], ret);
+ goto ERR_CLK_APLL2;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2_TUNER]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_APLL2_TUNER], ret);
+ goto ERR_CLK_APLL2_TUNER;
+ }
+
+ regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
+ 0x0000FFF7, 0x00000374);
+ regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1);
+
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0,
+ AUDIO_APLL2_EN_ON_MASK_SFT,
+ 0x1 << AUDIO_APLL2_EN_ON_SFT);
+
+ return 0;
+
+ERR_CLK_APLL2_TUNER:
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]);
+ERR_CLK_APLL2:
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL2]);
+
+ return ret;
+
+ return 0;
+}
+
+void mt8196_apll2_disable(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0,
+ AUDIO_APLL2_EN_ON_MASK_SFT,
+ 0x0 << AUDIO_APLL2_EN_ON_SFT);
+
+ regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x0);
+
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]);
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL2]);
+
+ apll2_mux_setting(afe, false);
+}
+
+int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll)
+{
+ return (apll == MT8196_APLL1) ? 180633600 : 196608000;
+}
+
+int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
+{
+ return ((rate % 8000) == 0) ? MT8196_APLL2 : MT8196_APLL1;
+}
+
+int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
+{
+ if (strcmp(name, APLL1_W_NAME) == 0)
+ return MT8196_APLL1;
+ else
+ return MT8196_APLL2;
+}
+
+/* mck */
+struct mt8196_mck_div {
+ int m_sel_id;
+ int div_clk_id;
+};
+
+static const struct mt8196_mck_div mck_div[MT8196_MCK_NUM] = {
+ [MT8196_I2SIN0_MCK] = {
+ .m_sel_id = CLK_CK_I2SIN0_M_SEL,
+ .div_clk_id = CLK_CK_APLL12_DIV_I2SIN0,
+ },
+ [MT8196_I2SIN1_MCK] = {
+ .m_sel_id = CLK_CK_I2SIN1_M_SEL,
+ .div_clk_id = CLK_CK_APLL12_DIV_I2SIN1,
+ },
+ [MT8196_FMI2S_MCK] = {
+ .m_sel_id = CLK_CK_FMI2S_M_SEL,
+ .div_clk_id = CLK_CK_APLL12_DIV_FMI2S,
+ },
+ [MT8196_TDMOUT_MCK] = {
+ .m_sel_id = CLK_CK_TDMOUT_M_SEL,
+ .div_clk_id = CLK_CK_APLL12_DIV_TDMOUT_M,
+ },
+ [MT8196_TDMOUT_BCK] = {
+ .m_sel_id = -1,
+ .div_clk_id = CLK_CK_APLL12_DIV_TDMOUT_B,
+ },
+};
+
+int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int apll = mt8196_get_apll_by_rate(afe, rate);
+ int apll_clk_id = apll == MT8196_APLL1 ?
+ CLK_CK_MUX_AUD_1 : CLK_CK_MUX_AUD_2;
+ int m_sel_id = 0;
+ int div_clk_id = 0;
+ int ret = 0;
+
+ dev_dbg(afe->dev, "%s(), mck_id: %d\n", __func__, mck_id);
+
+ if (mck_id >= MT8196_MCK_NUM || mck_id < 0)
+ return -EINVAL;
+
+ m_sel_id = mck_div[mck_id].m_sel_id;
+ div_clk_id = mck_div[mck_id].div_clk_id;
+
+ /* select apll */
+ if (m_sel_id >= 0) {
+ ret = clk_prepare_enable(afe_priv->clk[m_sel_id]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[m_sel_id], ret);
+ return ret;
+ }
+ ret = clk_set_parent(afe_priv->clk[m_sel_id],
+ afe_priv->clk[apll_clk_id]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[m_sel_id],
+ aud_clks[apll_clk_id], ret);
+ return ret;
+ }
+ }
+
+ /* enable div, set rate */
+ if (div_clk_id < 0) {
+ dev_err(afe->dev, "%s(), invalid div_clk_id %d\n", __func__, div_clk_id);
+ return -EINVAL;
+ }
+ if (div_clk_id == CLK_CK_APLL12_DIV_TDMOUT_B)
+ rate = rate * 16;
+ ret = clk_prepare_enable(afe_priv->clk[div_clk_id]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[div_clk_id], ret);
+ return ret;
+ }
+ ret = clk_set_rate(afe_priv->clk[div_clk_id], rate);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n",
+ __func__, aud_clks[div_clk_id],
+ rate, ret);
+ return ret;
+ }
+ return 0;
+}
+
+int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int m_sel_id = 0;
+ int div_clk_id = 0;
+
+ dev_dbg(afe->dev, "%s(), mck_id: %d.\n", __func__, mck_id);
+
+ if (mck_id < 0) {
+ dev_err(afe->dev, "%s(), mck_id = %d < 0\n",
+ __func__, mck_id);
+ return -EINVAL;
+ }
+
+ m_sel_id = mck_div[mck_id].m_sel_id;
+ div_clk_id = mck_div[mck_id].div_clk_id;
+
+ if (div_clk_id < 0) {
+ dev_err(afe->dev, "%s(), div_clk_id = %d < 0\n",
+ __func__, div_clk_id);
+ return -EINVAL;
+ }
+ clk_disable_unprepare(afe_priv->clk[div_clk_id]);
+
+ if (m_sel_id >= 0)
+ clk_disable_unprepare(afe_priv->clk[m_sel_id]);
+
+ return 0;
+}
+
+int mt8196_init_clock(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int i = 0;
+
+ afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk),
+ GFP_KERNEL);
+ if (!afe_priv->clk)
+ return -ENOMEM;
+
+ for (i = 0; i < CLK_NUM; i++) {
+ if (!aud_clks[i]) {
+ dev_err(afe->dev, "%s(), clk id %d not define!!!\n",
+ __func__, 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]));
+ afe_priv->clk[i] = NULL;
+ }
+ }
+
+ afe_priv->vlp_ck = syscon_regmap_lookup_by_phandle(afe->dev->of_node,
+ "vlpcksys");
+ if (IS_ERR(afe_priv->vlp_ck)) {
+ dev_err(afe->dev, "%s() Cannot find vlpcksys: %ld\n",
+ __func__, PTR_ERR(afe_priv->vlp_ck));
+ afe_priv->vlp_ck = NULL;
+ }
+
+ afe_priv->cksys_ck = syscon_regmap_lookup_by_phandle(afe->dev->of_node,
+ "cksys");
+ if (IS_ERR(afe_priv->cksys_ck)) {
+ dev_err(afe->dev, "%s() Cannot find cksys controller: %ld\n",
+ __func__, PTR_ERR(afe_priv->cksys_ck));
+ afe_priv->cksys_ck = NULL;
+ }
+
+ mt8196_afe_apll_init(afe);
+ mt8196_afe_disable_apll(afe);
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.h b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
new file mode 100644
index 000000000000..0094aebc8bba
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
@@ -0,0 +1,313 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8196-afe-clk.h -- Mediatek 8196 afe clock ctrl definition
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#ifndef _MT8196_AFE_CLOCK_CTRL_H_
+#define _MT8196_AFE_CLOCK_CTRL_H_
+
+// vlp_cksys_clk: 0x1c016000
+#define VLP_AP_PLL_CON3 0x0264
+#define VLP_APLL1_CON0 0x0274
+#define VLP_APLL1_CON1 0x0278
+#define VLP_APLL1_CON2 0x027c
+#define VLP_APLL1_CON4 0x0284
+#define VLP_APLL1_TUNER_CON0 0x02a4
+
+#define VLP_APLL2_CON0 0x028c
+#define VLP_APLL2_CON1 0x0290
+#define VLP_APLL2_CON2 0x0294
+#define VLP_APLL2_CON4 0x029c
+#define VLP_APLL2_TUNER_CON0 0x02a8
+#define VLP_CLK_CFG_UPDATE1 0x0008
+
+// cksys_clk: 0x10000000
+#define CLK_CFG_13 0x00e0
+#define CLK_CFG_UPDATE1 0x0008
+
+#define CLK_AUDDIV_0 0x020c
+#define CLK_AUDDIV_2 0x0214
+#define CLK_AUDDIV_5 0x0228
+
+#define CKSYS_AUD_TOP_CFG 0x0218
+
+/* CLK_AUDDIV_0 */
+#define APLL12_DIV_I2SIN0_PDN_SFT 0
+#define APLL12_DIV_I2SIN0_PDN_MASK 0x1
+#define APLL12_DIV_I2SIN0_PDN_MASK_SFT (0x1 << 0)
+#define APLL12_DIV_I2SIN1_PDN_SFT 1
+#define APLL12_DIV_I2SIN1_PDN_MASK 0x1
+#define APLL12_DIV_I2SIN1_PDN_MASK_SFT (0x1 << 1)
+#define APLL12_DIV_I2SIN2_PDN_SFT 2
+#define APLL12_DIV_I2SIN2_PDN_MASK 0x1
+#define APLL12_DIV_I2SIN2_PDN_MASK_SFT (0x1 << 2)
+#define APLL12_DIV_I2SIN3_PDN_SFT 3
+#define APLL12_DIV_I2SIN3_PDN_MASK 0x1
+#define APLL12_DIV_I2SIN3_PDN_MASK_SFT (0x1 << 3)
+#define APLL12_DIV_I2SIN4_PDN_SFT 4
+#define APLL12_DIV_I2SIN4_PDN_MASK 0x1
+#define APLL12_DIV_I2SIN4_PDN_MASK_SFT (0x1 << 4)
+#define APLL12_DIV_I2SIN6_PDN_SFT 5
+#define APLL12_DIV_I2SIN6_PDN_MASK 0x1
+#define APLL12_DIV_I2SIN6_PDN_MASK_SFT (0x1 << 5)
+#define APLL12_DIV_I2SOUT0_PDN_SFT 6
+#define APLL12_DIV_I2SOUT0_PDN_MASK 0x1
+#define APLL12_DIV_I2SOUT0_PDN_MASK_SFT (0x1 << 6)
+#define APLL12_DIV_I2SOUT1_PDN_SFT 7
+#define APLL12_DIV_I2SOUT1_PDN_MASK 0x1
+#define APLL12_DIV_I2SOUT1_PDN_MASK_SFT (0x1 << 7)
+#define APLL12_DIV_I2SOUT2_PDN_SFT 8
+#define APLL12_DIV_I2SOUT2_PDN_MASK 0x1
+#define APLL12_DIV_I2SOUT2_PDN_MASK_SFT (0x1 << 8)
+#define APLL12_DIV_I2SOUT3_PDN_SFT 9
+#define APLL12_DIV_I2SOUT3_PDN_MASK 0x1
+#define APLL12_DIV_I2SOUT3_PDN_MASK_SFT (0x1 << 9)
+#define APLL12_DIV_I2SOUT4_PDN_SFT 10
+#define APLL12_DIV_I2SOUT4_PDN_MASK 0x1
+#define APLL12_DIV_I2SOUT4_PDN_MASK_SFT (0x1 << 10)
+#define APLL12_DIV_I2SOUT6_PDN_SFT 11
+#define APLL12_DIV_I2SOUT6_PDN_MASK 0x1
+#define APLL12_DIV_I2SOUT6_PDN_MASK_SFT (0x1 << 11)
+#define APLL12_DIV_FMI2S_PDN_SFT 12
+#define APLL12_DIV_FMI2S_PDN_MASK 0x1
+#define APLL12_DIV_FMI2S_PDN_MASK_SFT (0x1 << 12)
+#define APLL12_DIV_TDMOUT_M_PDN_SFT 13
+#define APLL12_DIV_TDMOUT_M_PDN_MASK 0x1
+#define APLL12_DIV_TDMOUT_M_PDN_MASK_SFT (0x1 << 13)
+#define APLL12_DIV_TDMOUT_B_PDN_SFT 14
+#define APLL12_DIV_TDMOUT_B_PDN_MASK 0x1
+#define APLL12_DIV_TDMOUT_B_PDN_MASK_SFT (0x1 << 14)
+#define APLL_I2SIN0_MCK_SEL_SFT 16
+#define APLL_I2SIN0_MCK_SEL_MASK 0x1
+#define APLL_I2SIN0_MCK_SEL_MASK_SFT (0x1 << 16)
+#define APLL_I2SIN1_MCK_SEL_SFT 17
+#define APLL_I2SIN1_MCK_SEL_MASK 0x1
+#define APLL_I2SIN1_MCK_SEL_MASK_SFT (0x1 << 17)
+#define APLL_I2SIN2_MCK_SEL_SFT 18
+#define APLL_I2SIN2_MCK_SEL_MASK 0x1
+#define APLL_I2SIN2_MCK_SEL_MASK_SFT (0x1 << 18)
+#define APLL_I2SIN3_MCK_SEL_SFT 19
+#define APLL_I2SIN3_MCK_SEL_MASK 0x1
+#define APLL_I2SIN3_MCK_SEL_MASK_SFT (0x1 << 19)
+#define APLL_I2SIN4_MCK_SEL_SFT 20
+#define APLL_I2SIN4_MCK_SEL_MASK 0x1
+#define APLL_I2SIN4_MCK_SEL_MASK_SFT (0x1 << 20)
+#define APLL_I2SIN6_MCK_SEL_SFT 21
+#define APLL_I2SIN6_MCK_SEL_MASK 0x1
+#define APLL_I2SIN6_MCK_SEL_MASK_SFT (0x1 << 21)
+#define APLL_I2SOUT0_MCK_SEL_SFT 22
+#define APLL_I2SOUT0_MCK_SEL_MASK 0x1
+#define APLL_I2SOUT0_MCK_SEL_MASK_SFT (0x1 << 22)
+#define APLL_I2SOUT1_MCK_SEL_SFT 23
+#define APLL_I2SOUT1_MCK_SEL_MASK 0x1
+#define APLL_I2SOUT1_MCK_SEL_MASK_SFT (0x1 << 23)
+#define APLL_I2SOUT2_MCK_SEL_SFT 24
+#define APLL_I2SOUT2_MCK_SEL_MASK 0x1
+#define APLL_I2SOUT2_MCK_SEL_MASK_SFT (0x1 << 24)
+#define APLL_I2SOUT3_MCK_SEL_SFT 25
+#define APLL_I2SOUT3_MCK_SEL_MASK 0x1
+#define APLL_I2SOUT3_MCK_SEL_MASK_SFT (0x1 << 25)
+#define APLL_I2SOUT4_MCK_SEL_SFT 26
+#define APLL_I2SOUT4_MCK_SEL_MASK 0x1
+#define APLL_I2SOUT4_MCK_SEL_MASK_SFT (0x1 << 26)
+#define APLL_I2SOUT6_MCK_SEL_SFT 27
+#define APLL_I2SOUT6_MCK_SEL_MASK 0x1
+#define APLL_I2SOUT6_MCK_SEL_MASK_SFT (0x1 << 27)
+#define APLL_FMI2S_MCK_SEL_SFT 28
+#define APLL_FMI2S_MCK_SEL_MASK 0x1
+#define APLL_FMI2S_MCK_SEL_MASK_SFT (0x1 << 28)
+#define APLL_TDMOUT_MCK_SEL_SFT 29
+#define APLL_TDMOUT_MCK_SEL_MASK 0x1
+#define APLL_TDMOUT_MCK_SEL_MASK_SFT (0x1 << 29)
+
+/* CLK_AUDDIV_1 */
+#define APLL12_DIV_I2SIN0_INV_SFT 0
+#define APLL12_DIV_I2SIN0_INV_MASK 0x1
+#define APLL12_DIV_I2SIN0_INV_MASK_SFT (0x1 << 0)
+#define APLL12_DIV_I2SIN1_INV_SFT 1
+#define APLL12_DIV_I2SIN1_INV_MASK 0x1
+#define APLL12_DIV_I2SIN1_INV_MASK_SFT (0x1 << 1)
+#define APLL12_DIV_I2SIN2_INV_SFT 2
+#define APLL12_DIV_I2SIN2_INV_MASK 0x1
+#define APLL12_DIV_I2SIN2_INV_MASK_SFT (0x1 << 2)
+#define APLL12_DIV_I2SIN3_INV_SFT 3
+#define APLL12_DIV_I2SIN3_INV_MASK 0x1
+#define APLL12_DIV_I2SIN3_INV_MASK_SFT (0x1 << 3)
+#define APLL12_DIV_I2SIN4_INV_SFT 4
+#define APLL12_DIV_I2SIN4_INV_MASK 0x1
+#define APLL12_DIV_I2SIN4_INV_MASK_SFT (0x1 << 4)
+#define APLL12_DIV_I2SIN6_INV_SFT 5
+#define APLL12_DIV_I2SIN6_INV_MASK 0x1
+#define APLL12_DIV_I2SIN6_INV_MASK_SFT (0x1 << 5)
+#define APLL12_DIV_I2SOUT0_INV_SFT 6
+#define APLL12_DIV_I2SOUT0_INV_MASK 0x1
+#define APLL12_DIV_I2SOUT0_INV_MASK_SFT (0x1 << 6)
+#define APLL12_DIV_I2SOUT1_INV_SFT 7
+#define APLL12_DIV_I2SOUT1_INV_MASK 0x1
+#define APLL12_DIV_I2SOUT1_INV_MASK_SFT (0x1 << 7)
+#define APLL12_DIV_I2SOUT2_INV_SFT 8
+#define APLL12_DIV_I2SOUT2_INV_MASK 0x1
+#define APLL12_DIV_I2SOUT2_INV_MASK_SFT (0x1 << 8)
+#define APLL12_DIV_I2SOUT3_INV_SFT 9
+#define APLL12_DIV_I2SOUT3_INV_MASK 0x1
+#define APLL12_DIV_I2SOUT3_INV_MASK_SFT (0x1 << 9)
+#define APLL12_DIV_I2SOUT4_INV_SFT 10
+#define APLL12_DIV_I2SOUT4_INV_MASK 0x1
+#define APLL12_DIV_I2SOUT4_INV_MASK_SFT (0x1 << 10)
+#define APLL12_DIV_I2SOUT6_INV_SFT 11
+#define APLL12_DIV_I2SOUT6_INV_MASK 0x1
+#define APLL12_DIV_I2SOUT6_INV_MASK_SFT (0x1 << 11)
+#define APLL12_DIV_FMI2S_INV_SFT 12
+#define APLL12_DIV_FMI2S_INV_MASK 0x1
+#define APLL12_DIV_FMI2S_INV_MASK_SFT (0x1 << 12)
+#define APLL12_DIV_TDMOUT_M_INV_SFT 13
+#define APLL12_DIV_TDMOUT_M_INV_MASK 0x1
+#define APLL12_DIV_TDMOUT_M_INV_MASK_SFT (0x1 << 13)
+#define APLL12_DIV_TDMOUT_B_INV_SFT 14
+#define APLL12_DIV_TDMOUT_B_INV_MASK 0x1
+#define APLL12_DIV_TDMOUT_B_INV_MASK_SFT (0x1 << 14)
+
+/* CLK_AUDDIV_2 */
+#define APLL12_CK_DIV_I2SIN0_SFT 0
+#define APLL12_CK_DIV_I2SIN0_MASK 0xff
+#define APLL12_CK_DIV_I2SIN0_MASK_SFT (0xff << 0)
+#define APLL12_CK_DIV_I2SIN1_SFT 8
+#define APLL12_CK_DIV_I2SIN1_MASK 0xff
+#define APLL12_CK_DIV_I2SIN1_MASK_SFT (0xff << 8)
+#define APLL12_CK_DIV_I2SIN2_SFT 16
+#define APLL12_CK_DIV_I2SIN2_MASK 0xff
+#define APLL12_CK_DIV_I2SIN2_MASK_SFT (0xff << 16)
+#define APLL12_CK_DIV_I2SIN3_SFT 24
+#define APLL12_CK_DIV_I2SIN3_MASK 0xff
+#define APLL12_CK_DIV_I2SIN3_MASK_SFT (0xff << 24)
+
+/* AUD_TOP_CFG */
+#define AUD_TOP_CFG_SFT 0
+#define AUD_TOP_CFG_MASK 0xffffffff
+#define AUD_TOP_CFG_MASK_SFT (0xffffffff << 0)
+
+/* AUD_TOP_MON */
+#define AUD_TOP_MON_SFT 0
+#define AUD_TOP_MON_MASK 0xffffffff
+#define AUD_TOP_MON_MASK_SFT (0xffffffff << 0)
+
+/* CLK_AUDDIV_3 */
+#define APLL12_CK_DIV_I2SIN4_SFT 0
+#define APLL12_CK_DIV_I2SIN4_MASK 0xff
+#define APLL12_CK_DIV_I2SIN4_MASK_SFT (0xff << 0)
+#define APLL12_CK_DIV_I2SIN6_SFT 8
+#define APLL12_CK_DIV_I2SIN6_MASK 0xff
+#define APLL12_CK_DIV_I2SIN6_MASK_SFT (0xff << 8)
+#define APLL12_CK_DIV_I2SOUT0_SFT 16
+#define APLL12_CK_DIV_I2SOUT0_MASK 0xff
+#define APLL12_CK_DIV_I2SOUT0_MASK_SFT (0xff << 16)
+#define APLL12_CK_DIV_I2SOUT1_SFT 24
+#define APLL12_CK_DIV_I2SOUT1_MASK 0xff
+#define APLL12_CK_DIV_I2SOUT1_MASK_SFT (0xff << 24)
+
+/* CLK_AUDDIV_4 */
+#define APLL12_CK_DIV_I2SOUT2_SFT 0
+#define APLL12_CK_DIV_I2SOUT2_MASK 0xff
+#define APLL12_CK_DIV_I2SOUT2_MASK_SFT (0xff << 0)
+#define APLL12_CK_DIV_I2SOUT3_SFT 8
+#define APLL12_CK_DIV_I2SOUT3_MASK 0xff
+#define APLL12_CK_DIV_I2SOUT3_MASK_SFT (0xff << 8)
+#define APLL12_CK_DIV_I2SOUT4_SFT 16
+#define APLL12_CK_DIV_I2SOUT4_MASK 0xff
+#define APLL12_CK_DIV_I2SOUT4_MASK_SFT (0xff << 16)
+#define APLL12_CK_DIV_I2SOUT6_SFT 24
+#define APLL12_CK_DIV_I2SOUT6_MASK 0xff
+#define APLL12_CK_DIV_I2SOUT6_MASK_SFT (0xff << 24)
+
+/* CLK_AUDDIV_5 */
+#define APLL12_CK_DIV_FMI2S_SFT 0
+#define APLL12_CK_DIV_FMI2S_MASK 0xff
+#define APLL12_CK_DIV_FMI2S_MASK_SFT (0xff << 0)
+#define APLL12_CK_DIV_TDMOUT_M_SFT 8
+#define APLL12_CK_DIV_TDMOUT_M_MASK 0xff
+#define APLL12_CK_DIV_TDMOUT_M_MASK_SFT (0xff << 8)
+#define APLL12_CK_DIV_TDMOUT_B_SFT 16
+#define APLL12_CK_DIV_TDMOUT_B_MASK 0xff
+#define APLL12_CK_DIV_TDMOUT_B_MASK_SFT (0xff << 16)
+
+/* APLL */
+#define APLL1_W_NAME "APLL1"
+#define APLL2_W_NAME "APLL2"
+enum {
+ MT8196_APLL1 = 0,
+ MT8196_APLL2,
+};
+
+enum {
+ /* afe clk */
+ CLK_HOPPING = 0,
+ CLK_F26M,
+ CLK_UL0_ADC_CLK,
+ CLK_UL0_ADC_HIRES_CLK,
+ CLK_UL1_ADC_CLK,
+ CLK_UL1_ADC_HIRES_CLK,
+ CLK_APLL1,
+ CLK_APLL2,
+ CLK_APLL1_TUNER,
+ CLK_APLL2_TUNER,
+ /* vlp clk */
+ CLK_VLP_MUX_AUDIOINTBUS,
+ CLK_VLP_MUX_AUD_ENG1,
+ CLK_VLP_MUX_AUD_ENG2,
+ CLK_VLP_MUX_AUDIO_H,
+ CLK_VLP_CLK26M,
+ /* ck clk */
+ CLK_CK_MAINPLL_D4_D4,
+ CLK_CK_MUX_AUD_1,
+ CLK_CK_APLL1_CK,
+ CLK_CK_MUX_AUD_2,
+ CLK_CK_APLL2_CK,
+ CLK_CK_APLL1_D4,
+ CLK_CK_APLL2_D4,
+ CLK_CK_I2SIN0_M_SEL,
+ CLK_CK_I2SIN1_M_SEL,
+ CLK_CK_FMI2S_M_SEL,
+ CLK_CK_TDMOUT_M_SEL,
+ CLK_CK_APLL12_DIV_I2SIN0,
+ CLK_CK_APLL12_DIV_I2SIN1,
+ CLK_CK_APLL12_DIV_FMI2S,
+ CLK_CK_APLL12_DIV_TDMOUT_M,
+ CLK_CK_APLL12_DIV_TDMOUT_B,
+ CLK_CK_ADSP_SEL,
+ CLK_CLK26M,
+ CLK_NUM
+};
+
+struct mtk_base_afe;
+
+int mt8196_init_clock(struct mtk_base_afe *afe);
+int mt8196_afe_enable_clock(struct mtk_base_afe *afe);
+void mt8196_afe_disable_clock(struct mtk_base_afe *afe);
+int mt8196_afe_disable_apll(struct mtk_base_afe *afe);
+
+int mt8196_afe_dram_request(struct device *dev);
+int mt8196_afe_dram_release(struct device *dev);
+
+int mt8196_apll1_enable(struct mtk_base_afe *afe);
+void mt8196_apll1_disable(struct mtk_base_afe *afe);
+
+int mt8196_apll2_enable(struct mtk_base_afe *afe);
+void mt8196_apll2_disable(struct mtk_base_afe *afe);
+
+int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll);
+int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
+int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
+
+void aud_intbus_mux_sel(unsigned int aud_idx);
+
+/* these will be replaced by using CCF */
+int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate);
+int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id);
+
+int mt8196_set_audio_int_bus_parent(struct mtk_base_afe *afe,
+ int clk_id, bool int_bus);
+
+#endif
--
2.45.2
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 06/14] ASoC: mediatek: mt8196: support audio GPIO control
2025-03-07 12:47 [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (3 preceding siblings ...)
2025-03-07 12:47 ` [PATCH 05/14] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
@ 2025-03-07 12:47 ` Darren.Ye
2025-03-14 10:21 ` Linus Walleij
2025-03-07 12:47 ` [PATCH 07/14] ASoC: mediatek: mt8196: support ADDA in platform driver Darren.Ye
` (7 subsequent siblings)
12 siblings, 1 reply; 27+ messages in thread
From: Darren.Ye @ 2025-03-07 12:47 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Implement mode switching for audio GPIO.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/mt8196/mt8196-afe-gpio.c | 239 ++++++++++++++++++++
sound/soc/mediatek/mt8196/mt8196-afe-gpio.h | 58 +++++
2 files changed, 297 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-gpio.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-gpio.h
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-gpio.c b/sound/soc/mediatek/mt8196/mt8196-afe-gpio.c
new file mode 100644
index 000000000000..17ba409af7c4
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-gpio.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8196-afe-gpio.c -- Mediatek 8196 afe gpio ctrl
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "mt8196-afe-common.h"
+#include "mt8196-afe-gpio.h"
+
+struct pinctrl *aud_pinctrl;
+struct audio_gpio_attr {
+ const char *name;
+ bool gpio_prepare;
+ struct pinctrl_state *gpioctrl;
+};
+
+static struct audio_gpio_attr aud_gpios[MT8196_AFE_GPIO_GPIO_NUM] = {
+ [MT8196_AFE_GPIO_DAT_MISO0_OFF] = {"aud-dat-miso0-off", false, NULL},
+ [MT8196_AFE_GPIO_DAT_MISO0_ON] = {"aud-dat-miso0-on", false, NULL},
+ [MT8196_AFE_GPIO_DAT_MISO1_OFF] = {"aud-dat-miso1-off", false, NULL},
+ [MT8196_AFE_GPIO_DAT_MISO1_ON] = {"aud-dat-miso1-on", false, NULL},
+ [MT8196_AFE_GPIO_DAT_MOSI_OFF] = {"aud-dat-mosi-off", false, NULL},
+ [MT8196_AFE_GPIO_DAT_MOSI_ON] = {"aud-dat-mosi-on", false, NULL},
+ [MT8196_AFE_GPIO_I2SOUT0_OFF] = {"aud-gpio-i2sout0-off", false, NULL},
+ [MT8196_AFE_GPIO_I2SOUT0_ON] = {"aud-gpio-i2sout0-on", false, NULL},
+ [MT8196_AFE_GPIO_I2SIN0_OFF] = {"aud-gpio-i2sin0-off", false, NULL},
+ [MT8196_AFE_GPIO_I2SIN0_ON] = {"aud-gpio-i2sin0-on", false, NULL},
+ [MT8196_AFE_GPIO_I2SOUT1_OFF] = {"aud-gpio-i2sout1-off", false, NULL},
+ [MT8196_AFE_GPIO_I2SOUT1_ON] = {"aud-gpio-i2sout1-on", false, NULL},
+ [MT8196_AFE_GPIO_I2SIN1_OFF] = {"aud-gpio-i2sin1-off", false, NULL},
+ [MT8196_AFE_GPIO_I2SIN1_ON] = {"aud-gpio-i2sin1-on", false, NULL},
+ [MT8196_AFE_GPIO_I2SOUT4_OFF] = {"aud-gpio-i2sout4-off", false, NULL},
+ [MT8196_AFE_GPIO_I2SOUT4_ON] = {"aud-gpio-i2sout4-on", false, NULL},
+ [MT8196_AFE_GPIO_I2SIN4_OFF] = {"aud-gpio-i2sin4-off", false, NULL},
+ [MT8196_AFE_GPIO_I2SIN4_ON] = {"aud-gpio-i2sin4-on", false, NULL},
+ [MT8196_AFE_GPIO_I2SOUT6_OFF] = {"aud-gpio-i2sout6-off", false, NULL},
+ [MT8196_AFE_GPIO_I2SOUT6_ON] = {"aud-gpio-i2sout6-on", false, NULL},
+ [MT8196_AFE_GPIO_I2SIN6_OFF] = {"aud-gpio-i2sin6-off", false, NULL},
+ [MT8196_AFE_GPIO_I2SIN6_ON] = {"aud-gpio-i2sin6-on", false, NULL},
+ [MT8196_AFE_GPIO_AP_DMIC_OFF] = {"aud-gpio-ap-dmic-off", false, NULL},
+ [MT8196_AFE_GPIO_AP_DMIC_ON] = {"aud-gpio-ap-dmic-on", false, NULL},
+ [MT8196_AFE_GPIO_AP_DMIC1_OFF] = {"aud-gpio-ap-dmic1-off", false, NULL},
+ [MT8196_AFE_GPIO_AP_DMIC1_ON] = {"aud-gpio-ap-dmic1-on", false, NULL},
+ [MT8196_AFE_GPIO_DAT_MOSI_CH34_OFF] = {"aud-dat-mosi-ch34-off", false, NULL},
+ [MT8196_AFE_GPIO_DAT_MOSI_CH34_ON] = {"aud-dat-mosi-ch34-on", false, NULL},
+ [MT8196_AFE_GPIO_DAT_MISO_ONLY_OFF] = {"aud-dat-miso-only-off", false, NULL},
+ [MT8196_AFE_GPIO_DAT_MISO_ONLY_ON] = {"aud-dat-miso-only-on", false, NULL},
+ [MT8196_AFE_GPIO_I2SOUT3_OFF] = {"aud-gpio-i2sout3-off", false, NULL},
+ [MT8196_AFE_GPIO_I2SOUT3_ON] = {"aud-gpio-i2sout3-on", false, NULL},
+ [MT8196_AFE_GPIO_I2SIN3_OFF] = {"aud-gpio-i2sin3-off", false, NULL},
+ [MT8196_AFE_GPIO_I2SIN3_ON] = {"aud-gpio-i2sin3-on", false, NULL},
+};
+
+static DEFINE_MUTEX(gpio_request_mutex);
+
+int mt8196_afe_gpio_init(struct mtk_base_afe *afe)
+{
+ int ret;
+ int i = 0;
+
+ aud_pinctrl = devm_pinctrl_get(afe->dev);
+ if (IS_ERR(aud_pinctrl)) {
+ ret = PTR_ERR(aud_pinctrl);
+ dev_info(afe->dev, "%s(), ret %d, cannot get aud_pinctrl!\n",
+ __func__, ret);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < MT8196_AFE_GPIO_GPIO_NUM; i++) {
+ if (!aud_gpios[i].name) {
+ dev_info(afe->dev, "%s(), gpio id %d not define!!!\n",
+ __func__, i);
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(aud_gpios); i++) {
+ aud_gpios[i].gpioctrl = pinctrl_lookup_state(aud_pinctrl,
+ aud_gpios[i].name);
+ if (IS_ERR(aud_gpios[i].gpioctrl)) {
+ ret = PTR_ERR(aud_gpios[i].gpioctrl);
+ dev_info(afe->dev, "%s(), pinctrl_lookup_state %s fail, ret %d\n",
+ __func__, aud_gpios[i].name, ret);
+ } else {
+ aud_gpios[i].gpio_prepare = true;
+ }
+ }
+
+ /* gpio status init */
+ mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA, 0);
+ mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA, 1);
+
+ return 0;
+}
+
+static int mt8196_afe_gpio_select(struct mtk_base_afe *afe,
+ enum mt8196_afe_gpio type)
+{
+ int ret = 0;
+
+ dev_dbg(afe->dev, "%s(), type: %d.\n", __func__, type);
+
+ if (type >= MT8196_AFE_GPIO_GPIO_NUM) {
+ dev_info(afe->dev, "%s(), error, invalid gpio type %d\n",
+ __func__, type);
+ return -EINVAL;
+ }
+
+ if (!aud_gpios[type].gpio_prepare) {
+ dev_info(afe->dev, "%s(), error, gpio type %d not prepared\n",
+ __func__, type);
+ return -EIO;
+ }
+
+ ret = pinctrl_select_state(aud_pinctrl,
+ aud_gpios[type].gpioctrl);
+ if (ret)
+ dev_info(afe->dev, "%s(), error, can not set gpio type %d\n",
+ __func__, type);
+
+ return ret;
+}
+
+int mt8196_afe_gpio_request(struct mtk_base_afe *afe, bool enable,
+ int dai, int uplink)
+{
+ dev_dbg(afe->dev, "%s(), enable: %d, dai: %d, uplink: %d.\n", __func__,
+ enable, dai, uplink);
+
+ mutex_lock(&gpio_request_mutex);
+ switch (dai) {
+ case MT8196_DAI_ADDA:
+ break;
+ case MT8196_DAI_ADDA_CH34:
+ break;
+ case MT8196_DAI_ADDA_CH56:
+ break;
+ case MT8196_DAI_I2S_IN0:
+ case MT8196_DAI_I2S_OUT0:
+ if (enable) {
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN0_ON);
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT0_ON);
+ } else {
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN0_OFF);
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT0_OFF);
+ }
+ break;
+ case MT8196_DAI_I2S_IN1:
+ case MT8196_DAI_I2S_OUT1:
+ if (enable) {
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN1_ON);
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT1_ON);
+ } else {
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN1_OFF);
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT1_OFF);
+ }
+ break;
+ case MT8196_DAI_I2S_IN3:
+ case MT8196_DAI_I2S_OUT3:
+ if (enable) {
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN3_ON);
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT3_ON);
+ } else {
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN3_OFF);
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT3_OFF);
+ }
+ break;
+ case MT8196_DAI_I2S_IN4:
+ case MT8196_DAI_I2S_OUT4:
+ if (enable) {
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN4_ON);
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT4_ON);
+ } else {
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN4_OFF);
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT4_OFF);
+ }
+ break;
+ case MT8196_DAI_I2S_IN6:
+ case MT8196_DAI_I2S_OUT6:
+ if (enable) {
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN6_ON);
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT6_ON);
+ } else {
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SIN6_OFF);
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_I2SOUT6_OFF);
+ }
+ break;
+ case MT8196_DAI_VOW:
+ break;
+ case MT8196_DAI_VOW_SCP_DMIC:
+ break;
+ case MT8196_DAI_MTKAIF:
+ if (enable) {
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_DAT_MISO1_ON);
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_DAT_MISO0_ON);
+ } else {
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_DAT_MISO1_OFF);
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_DAT_MISO0_OFF);
+ }
+ break;
+ case MT8196_DAI_MISO_ONLY:
+ if (enable)
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_DAT_MISO_ONLY_ON);
+ else
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_DAT_MISO_ONLY_OFF);
+ break;
+ case MT8196_DAI_AP_DMIC:
+ if (enable)
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_AP_DMIC_ON);
+ else
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_AP_DMIC_OFF);
+ break;
+ case MT8196_DAI_AP_DMIC_CH34:
+ if (enable)
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_AP_DMIC1_ON);
+ else
+ mt8196_afe_gpio_select(afe, MT8196_AFE_GPIO_AP_DMIC1_OFF);
+ break;
+ default:
+ mutex_unlock(&gpio_request_mutex);
+ dev_info(afe->dev, "%s(), invalid dai %d\n", __func__, dai);
+ return -EINVAL;
+ }
+ mutex_unlock(&gpio_request_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt8196_afe_gpio_request);
+
+bool mt8196_afe_gpio_is_prepared(enum mt8196_afe_gpio type)
+{
+ return aud_gpios[type].gpio_prepare;
+}
+EXPORT_SYMBOL(mt8196_afe_gpio_is_prepared);
+
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-gpio.h b/sound/soc/mediatek/mt8196/mt8196-afe-gpio.h
new file mode 100644
index 000000000000..b36a8201d649
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-gpio.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8196-afe-gpio.h -- Mediatek 8196 afe gpio ctrl definition
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#ifndef _MT8196_AFE_GPIO_H_
+#define _MT8196_AFE_GPIO_H_
+#include "mt8196-afe-common.h"
+
+enum mt8196_afe_gpio {
+ MT8196_AFE_GPIO_DAT_MISO0_OFF,
+ MT8196_AFE_GPIO_DAT_MISO0_ON,
+ MT8196_AFE_GPIO_DAT_MISO1_OFF,
+ MT8196_AFE_GPIO_DAT_MISO1_ON,
+ MT8196_AFE_GPIO_DAT_MOSI_OFF,
+ MT8196_AFE_GPIO_DAT_MOSI_ON,
+ MT8196_AFE_GPIO_DAT_MOSI_CH34_OFF,
+ MT8196_AFE_GPIO_DAT_MOSI_CH34_ON,
+ MT8196_AFE_GPIO_DAT_MISO_ONLY_OFF,
+ MT8196_AFE_GPIO_DAT_MISO_ONLY_ON,
+ MT8196_AFE_GPIO_I2SIN0_OFF,
+ MT8196_AFE_GPIO_I2SIN0_ON,
+ MT8196_AFE_GPIO_I2SOUT0_OFF,
+ MT8196_AFE_GPIO_I2SOUT0_ON,
+ MT8196_AFE_GPIO_I2SIN1_OFF,
+ MT8196_AFE_GPIO_I2SIN1_ON,
+ MT8196_AFE_GPIO_I2SOUT1_OFF,
+ MT8196_AFE_GPIO_I2SOUT1_ON,
+ MT8196_AFE_GPIO_I2SIN4_OFF,
+ MT8196_AFE_GPIO_I2SIN4_ON,
+ MT8196_AFE_GPIO_I2SOUT4_OFF,
+ MT8196_AFE_GPIO_I2SOUT4_ON,
+ MT8196_AFE_GPIO_I2SIN6_OFF,
+ MT8196_AFE_GPIO_I2SIN6_ON,
+ MT8196_AFE_GPIO_I2SOUT6_OFF,
+ MT8196_AFE_GPIO_I2SOUT6_ON,
+ MT8196_AFE_GPIO_AP_DMIC_OFF,
+ MT8196_AFE_GPIO_AP_DMIC_ON,
+ MT8196_AFE_GPIO_AP_DMIC1_OFF,
+ MT8196_AFE_GPIO_AP_DMIC1_ON,
+ MT8196_AFE_GPIO_I2SIN3_OFF,
+ MT8196_AFE_GPIO_I2SIN3_ON,
+ MT8196_AFE_GPIO_I2SOUT3_OFF,
+ MT8196_AFE_GPIO_I2SOUT3_ON,
+ MT8196_AFE_GPIO_GPIO_NUM
+};
+
+struct mtk_base_afe;
+
+int mt8196_afe_gpio_init(struct mtk_base_afe *afe);
+int mt8196_afe_gpio_request(struct mtk_base_afe *afe, bool enable,
+ int dai, int uplink);
+bool mt8196_afe_gpio_is_prepared(enum mt8196_afe_gpio type);
+
+#endif
--
2.45.2
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 07/14] ASoC: mediatek: mt8196: support ADDA in platform driver
2025-03-07 12:47 [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (4 preceding siblings ...)
2025-03-07 12:47 ` [PATCH 06/14] ASoC: mediatek: mt8196: support audio GPIO control Darren.Ye
@ 2025-03-07 12:47 ` Darren.Ye
2025-03-07 12:47 ` [PATCH 09/14] ASoC: mediatek: mt8196: support TDM " Darren.Ye
` (6 subsequent siblings)
12 siblings, 0 replies; 27+ messages in thread
From: Darren.Ye @ 2025-03-07 12:47 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add mt8196 ADDA DAI driver support.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/mt8196/mt8196-dai-adda.c | 2207 +++++++++++++++++++
1 file changed, 2207 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-adda.c
diff --git a/sound/soc/mediatek/mt8196/mt8196-dai-adda.c b/sound/soc/mediatek/mt8196/mt8196-dai-adda.c
new file mode 100644
index 000000000000..2934b3ba9d71
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-dai-adda.c
@@ -0,0 +1,2207 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI ADDA Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include "mt8196-afe-clk.h"
+#include "mt8196-afe-common.h"
+#include "mt8196-afe-gpio.h"
+#include "mt8196-interconnection.h"
+
+#define MTKAIF4 //for mt6338
+/* mt6363 vs1 voter */
+#define RG_BUCK_VS1_VOTER_EN_LO 0x189a
+#define RG_BUCK_VS1_VOTER_EN_LO_SET 0x189b
+#define RG_BUCK_VS1_VOTER_EN_LO_CLR 0x189c
+
+#define VS1_MT6338_MSK (0x1 << 0)
+
+enum {
+ UL_IIR_SW = 0,
+ UL_IIR_5HZ,
+ UL_IIR_10HZ,
+ UL_IIR_25HZ,
+ UL_IIR_50HZ,
+ UL_IIR_75HZ,
+};
+
+enum {
+ AUDIO_SDM_LEVEL_MUTE = 0,
+ AUDIO_SDM_LEVEL_NORMAL = 0x1d,
+ /* if you change level normal */
+ /* you need to change formula of hp impedance and dc trim too */
+};
+
+enum {
+ AUDIO_SDM_2ND = 0,
+ AUDIO_SDM_3RD,
+};
+
+enum {
+ DELAY_DATA_MISO1 = 0,
+ DELAY_DATA_MISO2,
+};
+
+enum {
+ MTK_AFE_ADDA_DL_RATE_8K = 0,
+ MTK_AFE_ADDA_DL_RATE_11K = 1,
+ MTK_AFE_ADDA_DL_RATE_12K = 2,
+ MTK_AFE_ADDA_DL_RATE_16K = 4,
+ MTK_AFE_ADDA_DL_RATE_22K = 5,
+ MTK_AFE_ADDA_DL_RATE_24K = 6,
+ MTK_AFE_ADDA_DL_RATE_32K = 8,
+ MTK_AFE_ADDA_DL_RATE_44K = 9,
+ MTK_AFE_ADDA_DL_RATE_48K = 10,
+ MTK_AFE_ADDA_DL_RATE_88K = 13,
+ MTK_AFE_ADDA_DL_RATE_96K = 14,
+ MTK_AFE_ADDA_DL_RATE_176K = 17,
+ MTK_AFE_ADDA_DL_RATE_192K = 18,
+ MTK_AFE_ADDA_DL_RATE_352K = 21,
+ MTK_AFE_ADDA_DL_RATE_384K = 22,
+};
+
+enum {
+ MTK_AFE_ADDA_UL_RATE_8K = 0,
+ MTK_AFE_ADDA_UL_RATE_16K = 1,
+ MTK_AFE_ADDA_UL_RATE_32K = 2,
+ MTK_AFE_ADDA_UL_RATE_48K = 3,
+ MTK_AFE_ADDA_UL_RATE_96K = 4,
+ MTK_AFE_ADDA_UL_RATE_192K = 5,
+ MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
+};
+
+#ifdef MTKAIF4
+enum {
+ MTK_AFE_MTKAIF_RATE_8K = 0x0,
+ MTK_AFE_MTKAIF_RATE_12K = 0x1,
+ MTK_AFE_MTKAIF_RATE_16K = 0x2,
+ MTK_AFE_MTKAIF_RATE_24K = 0x3,
+ MTK_AFE_MTKAIF_RATE_32K = 0x4,
+ MTK_AFE_MTKAIF_RATE_48K = 0x5,
+ MTK_AFE_MTKAIF_RATE_64K = 0x6,
+ MTK_AFE_MTKAIF_RATE_96K = 0x7,
+ MTK_AFE_MTKAIF_RATE_128K = 0x8,
+ MTK_AFE_MTKAIF_RATE_192K = 0x9,
+ MTK_AFE_MTKAIF_RATE_256K = 0xa,
+ MTK_AFE_MTKAIF_RATE_384K = 0xb,
+ MTK_AFE_MTKAIF_RATE_11K = 0x10,
+ MTK_AFE_MTKAIF_RATE_22K = 0x11,
+ MTK_AFE_MTKAIF_RATE_44K = 0x12,
+ MTK_AFE_MTKAIF_RATE_88K = 0x13,
+ MTK_AFE_MTKAIF_RATE_176K = 0x14,
+ MTK_AFE_MTKAIF_RATE_352K = 0x15,
+};
+#endif
+
+#define SDM_AUTO_RESET_THRESHOLD 0x190000
+
+struct mtk_afe_adda_priv {
+ int dl_rate;
+ int ul_rate;
+};
+
+static struct mtk_afe_adda_priv *get_adda_priv_by_name(struct mtk_base_afe *afe,
+ const char *name)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int dai_id;
+
+ if (strncmp(name, "aud_dl0_dac_hires_clk", 21) == 0 ||
+ strncmp(name, "aud_ul0_adc_hires_clk", 21) == 0)
+ dai_id = MT8196_DAI_ADDA;
+ else if (strncmp(name, "aud_dl1_dac_hires_clk", 21) == 0 ||
+ strncmp(name, "aud_ul1_adc_hires_clk", 21) == 0)
+ dai_id = MT8196_DAI_ADDA_CH34;
+ else
+ return NULL;
+
+ return afe_priv->dai_priv[dai_id];
+}
+
+static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_UL_RATE_8K;
+ case 16000:
+ return MTK_AFE_ADDA_UL_RATE_16K;
+ case 32000:
+ return MTK_AFE_ADDA_UL_RATE_32K;
+ case 48000:
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_UL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_UL_RATE_192K;
+ default:
+ dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ }
+}
+
+#ifdef MTKAIF4
+static unsigned int mtkaif_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_MTKAIF_RATE_8K;
+ case 11025:
+ return MTK_AFE_MTKAIF_RATE_11K;
+ case 12000:
+ return MTK_AFE_MTKAIF_RATE_12K;
+ case 16000:
+ return MTK_AFE_MTKAIF_RATE_16K;
+ case 22050:
+ return MTK_AFE_MTKAIF_RATE_22K;
+ case 24000:
+ return MTK_AFE_MTKAIF_RATE_24K;
+ case 32000:
+ return MTK_AFE_MTKAIF_RATE_32K;
+ case 44100:
+ return MTK_AFE_MTKAIF_RATE_44K;
+ case 48000:
+ return MTK_AFE_MTKAIF_RATE_48K;
+ case 96000:
+ return MTK_AFE_MTKAIF_RATE_96K;
+ case 192000:
+ return MTK_AFE_MTKAIF_RATE_192K;
+ default:
+ dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_MTKAIF_RATE_48K;
+ }
+}
+#endif
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN014_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN014_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN014_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN014_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN014_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN014_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN014_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN014_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN014_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN014_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH1", AFE_CONN014_2, I_DL24_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN014_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN014_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN014_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN014_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN014_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN014_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN014_6,
+ I_SRC_0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN014_6,
+ I_SRC_1_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN014_6,
+ I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN015_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN015_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN015_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN015_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN015_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN015_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN015_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN015_1, I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN015_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN015_1, I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN015_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH2", AFE_CONN015_2, I_DL24_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN015_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN015_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN015_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN015_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN015_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN015_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN015_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN015_4,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN015_6,
+ I_SRC_0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN015_6,
+ I_SRC_1_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN015_6,
+ I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch3_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN016_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN016_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN016_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN016_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN016_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN016_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN016_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN016_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN016_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN016_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH3", AFE_CONN016_1, I_DL_24CH_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN016_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN016_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN016_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN016_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN016_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN016_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN016_6,
+ I_SRC_0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN016_6,
+ I_SRC_1_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN016_6,
+ I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN017_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN017_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN017_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN017_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN017_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN017_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN017_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN017_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN017_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN017_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH4", AFE_CONN017_1, I_DL_24CH_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN017_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN017_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN017_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN017_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN017_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN017_4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN017_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN017_4,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN017_6,
+ I_SRC_0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN017_6,
+ I_SRC_1_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN017_6,
+ I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_stf_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN012_0,
+ I_ADDA_UL_CH1, 1, 0),
+};
+
+// Luke: dummy BE for codec fail
+static const char * const adda_mux_map[] = {
+ "Normal", "Dummy_Widget",
+};
+
+static int adda_mux_map_value[] = {
+ 0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(adda_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ 1,
+ adda_mux_map,
+ adda_mux_map_value);
+static const struct snd_kcontrol_new adda_out_mux_control =
+ SOC_DAPM_ENUM("ADDA Out Select", adda_mux_map_enum);
+static const struct snd_kcontrol_new adda_in_mux_control =
+ SOC_DAPM_ENUM("ADDA In Select", adda_mux_map_enum);
+// Luke: dummy BE for codec fail
+
+enum {
+ SUPPLY_SEQ_ADDA_AFE_ON,
+ SUPPLY_SEQ_ADDA_DL_ON,
+ SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+ SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+ SUPPLY_SEQ_ADDA6_MTKAIF_CFG,
+ SUPPLY_SEQ_ADDA_FIFO,
+ SUPPLY_SEQ_ADDA_AP_DMIC,
+ SUPPLY_SEQ_ADDA_UL_ON,
+};
+
+static int mtk_adda_ul_src_dmic_phase_sync(struct mtk_base_afe *afe)
+{
+ dev_dbg(afe->dev, "%s() set dmic phase sync\n", __func__);
+ // ul0~1
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ UL0_PHASE_SYNC_HCLK_SET_MASK_SFT,
+ 0x1 << UL0_PHASE_SYNC_HCLK_SET_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ UL0_PHASE_SYNC_FCLK_SET_MASK_SFT,
+ 0x1 << UL0_PHASE_SYNC_FCLK_SET_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ UL1_PHASE_SYNC_HCLK_SET_MASK_SFT,
+ 0x1 << UL1_PHASE_SYNC_HCLK_SET_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ UL1_PHASE_SYNC_FCLK_SET_MASK_SFT,
+ 0x1 << UL1_PHASE_SYNC_FCLK_SET_SFT);
+ // dmic 0
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ DMIC0_PHASE_SYNC_FCLK_SET_MASK_SFT,
+ 0x1 << DMIC0_PHASE_SYNC_FCLK_SET_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ DMIC0_PHASE_SYNC_HCLK_SET_MASK_SFT,
+ 0x1 << DMIC0_PHASE_SYNC_HCLK_SET_SFT);
+ // dmic 1
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ DMIC1_PHASE_SYNC_FCLK_SET_MASK_SFT,
+ 0x1 << DMIC1_PHASE_SYNC_FCLK_SET_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ DMIC1_PHASE_SYNC_HCLK_SET_MASK_SFT,
+ 0x1 << DMIC1_PHASE_SYNC_HCLK_SET_SFT);
+ // ul0~1 phase sync clock
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ DMIC1_PHASE_HCLK_SEL_MASK_SFT,
+ 0x1 << DMIC1_PHASE_HCLK_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ DMIC1_PHASE_FCLK_SEL_MASK_SFT,
+ 0x1 << DMIC1_PHASE_FCLK_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ DMIC0_PHASE_HCLK_SEL_MASK_SFT,
+ 0x1 << DMIC0_PHASE_HCLK_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ DMIC0_PHASE_FCLK_SEL_MASK_SFT,
+ 0x1 << DMIC0_PHASE_FCLK_SEL_SFT);
+ // dmic 0
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL1_PHASE_HCLK_SEL_MASK_SFT,
+ 0x2 << UL1_PHASE_HCLK_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL1_PHASE_FCLK_SEL_MASK_SFT,
+ 0x2 << UL1_PHASE_FCLK_SEL_SFT);
+ // dmic 1
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL0_PHASE_HCLK_SEL_MASK_SFT,
+ 0x2 << UL0_PHASE_HCLK_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL0_PHASE_FCLK_SEL_MASK_SFT,
+ 0x2 << UL0_PHASE_FCLK_SEL_SFT);
+
+ return 0;
+}
+
+static int mtk_adda_ul_src_dmic_phase_sync_clock(struct mtk_base_afe *afe)
+{
+ dev_dbg(afe->dev, "%s(), dmic turn on phase sync clk\n", __func__);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL_PHASE_SYNC_HCLK_1_ON_MASK_SFT,
+ 0x1 << UL_PHASE_SYNC_HCLK_1_ON_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL_PHASE_SYNC_HCLK_0_ON_MASK_SFT,
+ 0x1 << UL_PHASE_SYNC_HCLK_0_ON_SFT);
+
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL_PHASE_SYNC_FCLK_1_ON_MASK_SFT,
+ 0x1 << UL_PHASE_SYNC_FCLK_1_ON_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
+ UL_PHASE_SYNC_FCLK_0_ON_MASK_SFT,
+ 0x1 << UL_PHASE_SYNC_FCLK_0_ON_SFT);
+
+ return 0;
+}
+
+static int mtk_adda_ul_src_dmic(struct mtk_base_afe *afe, int id)
+{
+ unsigned int reg_con0 = 0, reg_con1 = 0;
+
+ dev_dbg(afe->dev, "%s(), id: %d\n", __func__, id);
+
+ switch (id) {
+ case MT8196_DAI_ADDA:
+ case MT8196_DAI_AP_DMIC:
+ reg_con0 = AFE_ADDA_UL0_SRC_CON0;
+ reg_con1 = AFE_ADDA_UL0_SRC_CON1;
+ break;
+ case MT8196_DAI_ADDA_CH34:
+ case MT8196_DAI_AP_DMIC_CH34:
+ reg_con0 = AFE_ADDA_UL1_SRC_CON0;
+ reg_con1 = AFE_ADDA_UL1_SRC_CON1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (id) {
+ case MT8196_DAI_AP_DMIC:
+ dev_dbg(afe->dev, "%s(), clear mtkaifv4 ul ch1ch2 mux\n", __func__);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT);
+ break;
+ case MT8196_DAI_AP_DMIC_CH34:
+ dev_dbg(afe->dev, "%s(), clear mtkaifv4 ul ch3ch4 mux\n", __func__);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* choose Phase */
+ regmap_update_bits(afe->regmap, reg_con0,
+ UL_DMIC_PHASE_SEL_CH1_MASK_SFT,
+ 0x0 << UL_DMIC_PHASE_SEL_CH1_SFT);
+ regmap_update_bits(afe->regmap, reg_con0,
+ UL_DMIC_PHASE_SEL_CH2_MASK_SFT,
+ 0x4 << UL_DMIC_PHASE_SEL_CH2_SFT);
+
+ /* dmic mode, 3.25M*/
+ regmap_update_bits(afe->regmap, reg_con0,
+ DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT,
+ 0x0);
+ regmap_update_bits(afe->regmap, reg_con0,
+ DMIC_LOW_POWER_MODE_CTL_MASK_SFT,
+ 0x0);
+
+ /* turn on dmic, ch1, ch2 */
+ regmap_update_bits(afe->regmap, reg_con0,
+ UL_SDM_3_LEVEL_CTL_MASK_SFT,
+ 0x1 << UL_SDM_3_LEVEL_CTL_SFT);
+ regmap_update_bits(afe->regmap, reg_con0,
+ UL_MODE_3P25M_CH1_CTL_MASK_SFT,
+ 0x1 << UL_MODE_3P25M_CH1_CTL_SFT);
+ regmap_update_bits(afe->regmap, reg_con0,
+ UL_MODE_3P25M_CH2_CTL_MASK_SFT,
+ 0x1 << UL_MODE_3P25M_CH2_CTL_SFT);
+
+ /* ul gain: gain = 0x7fff/positive_gain = 0x0/gain_mode = 0x10 */
+ regmap_update_bits(afe->regmap, reg_con1,
+ ADDA_UL_GAIN_VALUE_MASK_SFT,
+ 0x7fff << ADDA_UL_GAIN_VALUE_SFT);
+ regmap_update_bits(afe->regmap, reg_con1,
+ ADDA_UL_POSTIVEGAIN_MASK_SFT,
+ 0x0 << ADDA_UL_POSTIVEGAIN_SFT);
+ /* gain_mode = 0x10: Add 0.5 gain at CIC output */
+ regmap_update_bits(afe->regmap, reg_con1,
+ GAIN_MODE_MASK_SFT,
+ 0x02 << GAIN_MODE_SFT);
+ return 0;
+}
+
+static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int mtkaif_dmic = afe_priv->mtkaif_dmic;
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n",
+ __func__, w->name, event, mtkaif_dmic);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA, 1);
+
+ /* update setting to dmic */
+ if (mtkaif_dmic) {
+ /* mtkaif_rxif_data_mode = 1, dmic */
+ regmap_update_bits(afe->regmap, AFE_MTKAIF0_RX_CFG0,
+ 0x1, 0x1);
+
+ /* dmic mode, 3.25M*/
+ regmap_update_bits(afe->regmap, AFE_MTKAIF0_RX_CFG0,
+ RG_MTKAIF0_RXIF_VOICE_MODE_MASK_SFT,
+ 0x0);
+ mtk_adda_ul_src_dmic(afe, MT8196_DAI_ADDA);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(120, 130);
+ mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA, 1);
+
+ /* reset dmic */
+ afe_priv->mtkaif_dmic = 0;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_ch34_ul_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int mtkaif_dmic = afe_priv->mtkaif_dmic_ch34;
+ int mtkaif_adda6_only = afe_priv->mtkaif_adda6_only;
+
+ dev_dbg(afe->dev,
+ "%s(), name %s, event 0x%x, mtkaif_dmic %d, mtkaif_adda6_only %d\n",
+ __func__, w->name, event, mtkaif_dmic, mtkaif_adda6_only);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA_CH34, 1);
+
+ /* update setting to dmic */
+ if (mtkaif_dmic) {
+ /* mtkaif_rxif_data_mode = 1, dmic */
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF1_RX_CFG0,
+ 0x1, 0x1);
+
+ /* dmic mode, 3.25M*/
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF1_RX_CFG0,
+ RG_MTKAIF1_RXIF_VOICE_MODE_MASK_SFT,
+ 0x0);
+ mtk_adda_ul_src_dmic(afe, MT8196_DAI_ADDA_CH34);
+ }
+
+ /* when using adda6 without adda enabled,
+ * RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_SFT need to be set or
+ * data cannot be received.
+ */
+ if (mtkaif_adda6_only) {
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF1_RX_CFG2,
+ RG_MTKAIF1_RXIF_SYNC_WORD1_DISABLE_MASK_SFT,
+ 0x1);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(120, 130);
+ mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA_CH34, 1);
+
+ /* reset dmic */
+ afe_priv->mtkaif_dmic_ch34 = 0;
+
+ if (mtkaif_adda6_only) {
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF1_RX_CFG2,
+ RG_MTKAIF1_RXIF_SYNC_WORD1_DISABLE_MASK_SFT,
+ 0x0);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_ch56_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 mt8196_afe_private *afe_priv = afe->platform_priv;
+ int mtkaif_dmic = afe_priv->mtkaif_dmic;
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n",
+ __func__, w->name, event, mtkaif_dmic);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA_CH56, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(120, 130);
+ mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA_CH56, 1);
+
+ /* reset dmic */
+ afe_priv->mtkaif_dmic = 0;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_ul_ap_dmic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA, 1);
+ //mtk_adda_ul_src_dmic(afe, MT8196_DAI_AP_DMIC);
+ mt8196_afe_gpio_request(afe, true, MT8196_DAI_AP_DMIC, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(120, 130);
+ mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA, 1);
+ mt8196_afe_gpio_request(afe, false, MT8196_DAI_AP_DMIC, 1);
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_ch34_ul_ap_dmic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int mtkaif_adda6_only = afe_priv->mtkaif_adda6_only;
+
+ dev_dbg(afe->dev,
+ "%s(), name %s, event 0x%x, mtkaif_adda6_only %d\n",
+ __func__, w->name, event, mtkaif_adda6_only);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA_CH34, 1);
+ mt8196_afe_gpio_request(afe, true, MT8196_DAI_AP_DMIC_CH34, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(120, 130);
+ mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA_CH34, 1);
+ mt8196_afe_gpio_request(afe, false, MT8196_DAI_AP_DMIC_CH34, 1);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2)
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB8);
+ else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2)
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0);
+ else
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static bool is_adda_mtkaif_need_phase_delay(struct mt8196_afe_private *afe_priv)
+{
+ if (mt8196_afe_gpio_is_prepared(MT8196_AFE_GPIO_DAT_MISO0_ON) &&
+ afe_priv->mtkaif_chosen_phase[0] < 0) {
+ return false;
+ }
+
+ if (mt8196_afe_gpio_is_prepared(MT8196_AFE_GPIO_DAT_MISO1_ON) &&
+ afe_priv->mtkaif_chosen_phase[1] < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int delay_data;
+ int delay_cycle;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+#ifdef MTKAIF4
+ /* mtkaif_rxif_clkinv_adc inverse for calibration */
+ regmap_update_bits(afe->regmap, AFE_MTKAIF0_CFG0,
+ RG_MTKAIF0_RXIF_CLKINV_MASK_SFT,
+ 0x1 << RG_MTKAIF0_RXIF_CLKINV_SFT);
+ regmap_update_bits(afe->regmap, AFE_MTKAIF1_CFG0,
+ RG_MTKAIF1_RXIF_CLKINV_ADC_MASK_SFT,
+ 0x1 << RG_MTKAIF1_RXIF_CLKINV_ADC_SFT);
+#endif
+
+ if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) {
+ /* set protocol 2 */
+ regmap_write(afe->regmap, AFE_MTKAIF0_CFG0,
+ 0x00010000);
+ regmap_write(afe->regmap, AFE_MTKAIF1_CFG0,
+ 0x00010000);
+
+ /* mtkaif_rxif_clkinv_adc inverse for calibration */
+ regmap_update_bits(afe->regmap, AFE_MTKAIF0_CFG0,
+ RG_MTKAIF0_RXIF_CLKINV_MASK_SFT,
+ 0x1 << RG_MTKAIF0_RXIF_CLKINV_SFT);
+ regmap_update_bits(afe->regmap, AFE_MTKAIF1_CFG0,
+ RG_MTKAIF1_RXIF_CLKINV_ADC_MASK_SFT,
+ 0x1 << RG_MTKAIF1_RXIF_CLKINV_ADC_SFT);
+
+ /* This event align the phase of every miso pin */
+ /* If only 1 miso is used, there is no need to do phase delay. */
+ if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0 &&
+ !is_adda_mtkaif_need_phase_delay(afe_priv)) {
+ dev_dbg(afe->dev,
+ "%s(), check adda mtkaif_chosen_phase[0/1]:%d/%d\n",
+ __func__,
+ afe_priv->mtkaif_chosen_phase[0],
+ afe_priv->mtkaif_chosen_phase[1]);
+ break;
+ }
+
+ /* set delay for ch12 to align phase of miso0 and miso1 */
+ if (afe_priv->mtkaif_phase_cycle[0] >=
+ afe_priv->mtkaif_phase_cycle[1]) {
+ delay_data = DELAY_DATA_MISO1;
+ delay_cycle = afe_priv->mtkaif_phase_cycle[0] -
+ afe_priv->mtkaif_phase_cycle[1];
+ } else {
+ delay_data = DELAY_DATA_MISO2;
+ delay_cycle = afe_priv->mtkaif_phase_cycle[1] -
+ afe_priv->mtkaif_phase_cycle[0];
+ }
+
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF0_RX_CFG2,
+ RG_MTKAIF0_RXIF_DELAY_DATA_MASK_SFT,
+ delay_data <<
+ RG_MTKAIF0_RXIF_DELAY_DATA_SFT);
+
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF0_RX_CFG2,
+ RG_MTKAIF0_RXIF_DELAY_CYCLE_MASK_SFT,
+ delay_cycle <<
+ RG_MTKAIF0_RXIF_DELAY_CYCLE_SFT);
+
+ /* set delay between ch3 and ch2 */
+ if (afe_priv->mtkaif_phase_cycle[2] >=
+ afe_priv->mtkaif_phase_cycle[1]) {
+ delay_data = DELAY_DATA_MISO1; /* ch3 */
+ delay_cycle = afe_priv->mtkaif_phase_cycle[2] -
+ afe_priv->mtkaif_phase_cycle[1];
+ } else {
+ delay_data = DELAY_DATA_MISO2; /* ch2 */
+ delay_cycle = afe_priv->mtkaif_phase_cycle[1] -
+ afe_priv->mtkaif_phase_cycle[2];
+ }
+
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF1_RX_CFG2,
+ RG_MTKAIF1_RXIF_DELAY_DATA_MASK_SFT,
+ delay_data <<
+ RG_MTKAIF1_RXIF_DELAY_DATA_SFT);
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF1_RX_CFG2,
+ RG_MTKAIF1_RXIF_DELAY_CYCLE_MASK_SFT,
+ delay_cycle <<
+ RG_MTKAIF1_RXIF_DELAY_CYCLE_SFT);
+ } else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) {
+ regmap_write(afe->regmap, AFE_MTKAIF0_CFG0,
+ 0x00010000);
+ regmap_write(afe->regmap, AFE_MTKAIF1_CFG0,
+ 0x00010000);
+ } else {
+ regmap_write(afe->regmap, AFE_MTKAIF0_CFG0, 0x0);
+ regmap_write(afe->regmap, AFE_MTKAIF1_CFG0, 0x0);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA, 0);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(120, 130);
+ mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_ch34_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_PRE_PMU:
+ mt8196_afe_gpio_request(afe, true, MT8196_DAI_ADDA_CH34, 0);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(120, 130);
+ mt8196_afe_gpio_request(afe, false, MT8196_DAI_ADDA_CH34, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void mt6363_vs1_vote(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ bool pre_enable = afe_priv->is_mt6363_vote;
+ bool enable = false;
+
+ if (!afe_priv->pmic_regmap)
+ return;
+ enable = (afe_priv->is_adda_dl_on && afe_priv->is_adda_dl_max_vol) ||
+ afe_priv->is_adda_ul_on ||
+ afe_priv->is_vow_enable;
+ if (enable == pre_enable) {
+ dev_dbg(afe->dev, "%s() enable == pre_enable = %d\n",
+ __func__, enable);
+ return;
+ }
+ afe_priv->is_mt6363_vote = enable;
+ dev_dbg(afe->dev, "%s() enable = %d\n",
+ __func__, enable);
+ if (enable) {
+ regmap_update_bits(afe_priv->pmic_regmap, RG_BUCK_VS1_VOTER_EN_LO_SET,
+ VS1_MT6338_MSK, VS1_MT6338_MSK);
+ } else {
+ regmap_update_bits(afe_priv->pmic_regmap, RG_BUCK_VS1_VOTER_EN_LO_CLR,
+ VS1_MT6338_MSK, VS1_MT6338_MSK);
+ }
+}
+
+static int mt_vs1_voter_dl_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ dev_dbg(afe->dev, "%s(), event = 0x%x\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ afe_priv->is_adda_dl_on = true;
+ mt6363_vs1_vote(afe);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ afe_priv->is_adda_dl_on = false;
+ mt6363_vs1_vote(afe);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt_vs1_voter_ul_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ dev_dbg(afe->dev, "%s(), event = 0x%x\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ afe_priv->is_adda_ul_on = true;
+ mt6363_vs1_vote(afe);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ afe_priv->is_adda_ul_on = false;
+ mt6363_vs1_vote(afe);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* stf */
+static int stf_positive_gain_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 mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->stf_positive_gain_db;
+ return 0;
+}
+
+static int stf_positive_gain_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 mt8196_afe_private *afe_priv = afe->platform_priv;
+ int gain_db = ucontrol->value.integer.value[0];
+
+ afe_priv->stf_positive_gain_db = gain_db;
+
+ if (gain_db >= 0 && gain_db <= 24) {
+ regmap_update_bits(afe->regmap,
+ AFE_STF_GAIN,
+ SIDE_TONE_POSITIVE_GAIN_MASK_SFT,
+ (gain_db / 6) << SIDE_TONE_POSITIVE_GAIN_SFT);
+ } else {
+ dev_info(afe->dev, "%s(), gain_db %d invalid\n",
+ __func__, gain_db);
+ }
+ return 0;
+}
+
+/* mtkaif dmic */
+static const char *const mt8196_adda_off_on_str[] = {
+ "Off", "On"
+};
+
+static const struct soc_enum mt8196_adda_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8196_adda_off_on_str),
+ mt8196_adda_off_on_str),
+};
+
+static int mt8196_adda_ap_dmic_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->ap_dmic;
+ return 0;
+}
+
+static int mt8196_adda_ap_dmic_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int ap_dmic_on;
+
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
+ ap_dmic_on = ucontrol->value.integer.value[0];
+
+ dev_dbg(afe->dev, "%s(), kcontrol name %s, ap_dmic_on %d\n",
+ __func__, kcontrol->id.name, ap_dmic_on);
+
+ afe_priv->ap_dmic = ap_dmic_on;
+ return 0;
+}
+
+static int mt8196_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 mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic;
+ return 0;
+}
+
+static int mt8196_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 mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int dmic_on;
+
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
+ dmic_on = ucontrol->value.integer.value[0];
+
+ dev_dbg(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n",
+ __func__, kcontrol->id.name, dmic_on);
+
+ afe_priv->mtkaif_dmic = dmic_on;
+ afe_priv->mtkaif_dmic_ch34 = dmic_on;
+ return 0;
+}
+
+static int mt8196_adda6_only_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->mtkaif_adda6_only;
+ return 0;
+}
+
+static int mt8196_adda6_only_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int mtkaif_adda6_only;
+
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
+ mtkaif_adda6_only = ucontrol->value.integer.value[0];
+
+ dev_dbg(afe->dev, "%s(), kcontrol name %s, mtkaif_adda6_only %d\n",
+ __func__, kcontrol->id.name, mtkaif_adda6_only);
+
+ afe_priv->mtkaif_adda6_only = mtkaif_adda6_only;
+ return 0;
+}
+
+static int mt8196_adda_dl_max_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->is_adda_dl_max_vol;
+
+ return 0;
+}
+
+static int mt8196_adda_dl_max_vol_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ bool is_adda_dl_max_vol = ucontrol->value.integer.value[0];
+
+ afe_priv->is_adda_dl_max_vol = is_adda_dl_max_vol;
+ mt6363_vs1_vote(afe);
+
+ return 0;
+}
+
+static int mt8196_vow_enable_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 mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->is_vow_enable;
+
+ return 0;
+}
+
+static int mt8196_vow_enable_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 mt8196_afe_private *afe_priv = afe->platform_priv;
+ bool is_vow_enable = ucontrol->value.integer.value[0];
+
+ afe_priv->is_vow_enable = is_vow_enable;
+ mt6363_vs1_vote(afe);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new mtk_adda_controls[] = {
+ SOC_SINGLE("Sidetone_Gain", AFE_STF_GAIN,
+ SIDE_TONE_GAIN_SFT, SIDE_TONE_GAIN_MASK, 0),
+ SOC_SINGLE_EXT("Sidetone_Positive_Gain_dB", SND_SOC_NOPM, 0, 100, 0,
+ stf_positive_gain_get, stf_positive_gain_set),
+ SOC_ENUM_EXT("MTKAIF_DMIC", mt8196_adda_enum[0],
+ mt8196_adda_dmic_get, mt8196_adda_dmic_set),
+ SOC_ENUM_EXT("MTKAIF_ADDA6_ONLY", mt8196_adda_enum[0],
+ mt8196_adda6_only_get, mt8196_adda6_only_set),
+ SOC_SINGLE_EXT("ADDA_DL_MAX_VOL",
+ SND_SOC_NOPM, 0, 0x1, 0,
+ mt8196_adda_dl_max_vol_get,
+ mt8196_adda_dl_max_vol_set),
+ SOC_SINGLE_EXT("VOW_ENABLE",
+ SND_SOC_NOPM, 0, 0x1, 0,
+ mt8196_vow_enable_get,
+ mt8196_vow_enable_set),
+ SOC_ENUM_EXT("AP DMIC Used", mt8196_adda_enum[0],
+ mt8196_adda_ap_dmic_get, mt8196_adda_ap_dmic_set),
+};
+
+static const struct snd_kcontrol_new stf_ctl =
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const u16 stf_coeff_table_16k[] = {
+ 0x049C, 0x09E8, 0x09E0, 0x089C,
+ 0xFF54, 0xF488, 0xEAFC, 0xEBAC,
+ 0xfA40, 0x17AC, 0x3D1C, 0x6028,
+ 0x7538
+};
+
+static const u16 stf_coeff_table_32k[] = {
+ 0xFE52, 0x0042, 0x00C5, 0x0194,
+ 0x029A, 0x03B7, 0x04BF, 0x057D,
+ 0x05BE, 0x0555, 0x0426, 0x0230,
+ 0xFF92, 0xFC89, 0xF973, 0xF6C6,
+ 0xF500, 0xF49D, 0xF603, 0xF970,
+ 0xFEF3, 0x065F, 0x0F4F, 0x1928,
+ 0x2329, 0x2C80, 0x345E, 0x3A0D,
+ 0x3D08
+};
+
+static const u16 stf_coeff_table_48k[] = {
+ 0x0401, 0xFFB0, 0xFF5A, 0xFECE,
+ 0xFE10, 0xFD28, 0xFC21, 0xFB08,
+ 0xF9EF, 0xF8E8, 0xF80A, 0xF76C,
+ 0xF724, 0xF746, 0xF7E6, 0xF90F,
+ 0xFACC, 0xFD1E, 0xFFFF, 0x0364,
+ 0x0737, 0x0B62, 0x0FC1, 0x1431,
+ 0x188A, 0x1CA4, 0x2056, 0x237D,
+ 0x25F9, 0x27B0, 0x2890
+};
+
+static int mtk_stf_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);
+
+ size_t half_tap_num;
+ const u16 *stf_coeff_table;
+ unsigned int ul_rate;
+
+ u32 reg_value;
+ size_t coef_addr;
+
+ regmap_read(afe->regmap, AFE_ADDA_UL0_SRC_CON0, &ul_rate);
+ ul_rate = ul_rate >> UL_VOICE_MODE_CH1_CH2_CTL_SFT;
+ ul_rate = ul_rate & UL_VOICE_MODE_CH1_CH2_CTL_MASK;
+
+ if (ul_rate == MTK_AFE_ADDA_UL_RATE_48K) {
+ half_tap_num = ARRAY_SIZE(stf_coeff_table_48k);
+ stf_coeff_table = stf_coeff_table_48k;
+ } else if (ul_rate == MTK_AFE_ADDA_UL_RATE_32K) {
+ half_tap_num = ARRAY_SIZE(stf_coeff_table_32k);
+ stf_coeff_table = stf_coeff_table_32k;
+ } else {
+ half_tap_num = ARRAY_SIZE(stf_coeff_table_16k);
+ stf_coeff_table = stf_coeff_table_16k;
+ }
+
+ regmap_read(afe->regmap, AFE_STF_CON0, ®_value);
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x, ul_rate 0x%x, AFE_STF_CON0 0x%x\n",
+ __func__, w->name, event, ul_rate, reg_value);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* set side tone gain = 0 */
+ regmap_update_bits(afe->regmap,
+ AFE_STF_GAIN,
+ SIDE_TONE_GAIN_MASK_SFT,
+ 0);
+ regmap_update_bits(afe->regmap,
+ AFE_STF_GAIN,
+ SIDE_TONE_POSITIVE_GAIN_MASK_SFT,
+ 0);
+ /* set stf half tap num */
+ regmap_update_bits(afe->regmap,
+ AFE_STF_CON0,
+ SIDE_TONE_HALF_TAP_NUM_MASK_SFT,
+ half_tap_num << SIDE_TONE_HALF_TAP_NUM_SFT);
+
+ /* set side tone coefficient */
+ regmap_read(afe->regmap, AFE_STF_MON, ®_value);
+ for (coef_addr = 0; coef_addr < half_tap_num; coef_addr++) {
+ bool old_w_ready = (reg_value >> SIDE_TONE_W_RDY_SFT) & 0x1;
+ bool new_w_ready = 0;
+ int try_cnt = 0;
+
+ regmap_update_bits(afe->regmap,
+ AFE_STF_COEFF,
+ 0x11FFFFF,
+ (1 << SIDE_TONE_COEFFICIENT_R_W_SEL_SFT) |
+ (coef_addr <<
+ SIDE_TONE_COEFFICIENT_ADDR_SFT) |
+ stf_coeff_table[coef_addr]);
+
+ /* wait until flag write_ready changed */
+ for (try_cnt = 0; try_cnt < 10; try_cnt++) {
+ regmap_read(afe->regmap,
+ AFE_STF_MON, ®_value);
+ new_w_ready = (reg_value >> SIDE_TONE_W_RDY_SFT) & 0x1;
+
+ /* flip => ok */
+ if (new_w_ready == old_w_ready) {
+ usleep_range(1, 5);
+ if (try_cnt == 9) {
+ dev_info(afe->dev,
+ "%s(), write coeff not ready",
+ __func__);
+ }
+ } else {
+ break;
+ }
+ }
+
+ /* need write -> read -> write to write next coeff */
+ regmap_update_bits(afe->regmap,
+ AFE_STF_COEFF,
+ SIDE_TONE_COEFFICIENT_R_W_SEL_SFT,
+ 0x0);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* set side tone gain = 0 */
+ regmap_update_bits(afe->regmap,
+ AFE_STF_GAIN,
+ SIDE_TONE_GAIN_MASK_SFT,
+ 0);
+ regmap_update_bits(afe->regmap,
+ AFE_STF_GAIN,
+ SIDE_TONE_POSITIVE_GAIN_MASK_SFT,
+ 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* ADDA UL MUX */
+#define ADDA_UL_MUX_MASK 0x3
+enum {
+ ADDA_UL_MUX_MTKAIF = 0,
+ ADDA_UL_MUX_AP_DMIC,
+ ADDA_UL_MUX_AP_DMIC_MULTICH,
+};
+
+static const char *const adda_ul_mux_map[] = {
+ "MTKAIF", "AP_DMIC", "AP_DMIC_MULTI_CH",
+};
+
+static int adda_ul_map_value[] = {
+ ADDA_UL_MUX_MTKAIF,
+ ADDA_UL_MUX_AP_DMIC,
+ ADDA_UL_MUX_AP_DMIC_MULTICH,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ ADDA_UL_MUX_MASK,
+ adda_ul_mux_map,
+ adda_ul_map_value);
+
+static const struct snd_kcontrol_new adda_ul_mux_control =
+ SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_kcontrol_new adda_ch34_ul_mux_control =
+ SOC_DAPM_ENUM("ADDA_CH34_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_kcontrol_new adda_ch56_ul_mux_control =
+ SOC_DAPM_ENUM("ADDA_CH56_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_adda_dl_ch1_mix,
+ ARRAY_SIZE(mtk_adda_dl_ch1_mix)),
+ SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_adda_dl_ch2_mix,
+ ARRAY_SIZE(mtk_adda_dl_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("ADDA_DL_CH3", SND_SOC_NOPM, 0, 0,
+ mtk_adda_dl_ch3_mix,
+ ARRAY_SIZE(mtk_adda_dl_ch3_mix)),
+ SND_SOC_DAPM_MIXER("ADDA_DL_CH4", SND_SOC_NOPM, 0, 0,
+ mtk_adda_dl_ch4_mix,
+ ARRAY_SIZE(mtk_adda_dl_ch4_mix)),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
+ AUDIO_ENGEN_CON0, AUDIO_F3P25M_EN_ON_SFT, 0,
+ NULL, 0),
+
+ /*AFE_ADDA_MTKAIFV4_TX_CFG0 control by PAD_CLK*/
+ SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON,
+ SND_SOC_NOPM,
+ 0, 0,
+ mtk_adda_dl_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("ADDA CH34 Playback Enable",
+ SUPPLY_SEQ_ADDA_DL_ON,
+ AFE_ADDA6_MTKAIFV4_TX_CFG0,
+ ADDA6_MTKAIFV4_TXIF_AFE_ON_SFT, 0,
+ mtk_adda_ch34_dl_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+ AFE_ADDA_UL0_SRC_CON0,
+ UL_SRC_ON_TMP_CTL_SFT, 0,
+ mtk_adda_ul_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("ADDA CH34 Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+ AFE_ADDA_UL1_SRC_CON0,
+ UL_SRC_ON_TMP_CTL_SFT, 0,
+ mtk_adda_ch34_ul_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("ADDA CH56 Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+ AFE_ADDA_UL1_SRC_CON0,
+ UL_SRC_ON_TMP_CTL_SFT, 0,
+ mtk_adda_ch56_ul_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+ AFE_AUD_PAD_TOP_CFG0,
+ RG_RX_FIFO_ON_SFT, 0,
+ mtk_adda_pad_top_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("AUD_PAD_CLK", SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+ AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_TXIF_AFE_ON_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIFV4_RX", SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+ AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_AFE_ON_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADDA6_MTKAIFV4_RX", SUPPLY_SEQ_ADDA6_MTKAIF_CFG,
+ AFE_ADDA6_MTKAIFV4_RX_CFG0,
+ ADDA6_MTKAIFV4_RXIF_AFE_ON_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+ SND_SOC_NOPM, 0, 0,
+ mtk_adda_mtkaif_cfg_event,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY_S("ADDA6_MTKAIF_CFG", SUPPLY_SEQ_ADDA6_MTKAIF_CFG,
+ SND_SOC_NOPM, 0, 0,
+ mtk_adda_mtkaif_cfg_event,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY_S("ADDA7_MTKAIF_CFG", SUPPLY_SEQ_ADDA6_MTKAIF_CFG,
+ SND_SOC_NOPM, 0, 0,
+ mtk_adda_mtkaif_cfg_event,
+ SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+ AFE_ADDA_UL0_SRC_CON0,
+ UL_AP_DMIC_ON_SFT, 0,
+ mtk_adda_ul_ap_dmic_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("AP_DMIC_CH34_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+ AFE_ADDA_UL1_SRC_CON0,
+ UL_AP_DMIC_ON_SFT, 0,
+ mtk_adda_ch34_ul_ap_dmic_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+ AFE_ADDA_UL0_SRC_CON1,
+ FIFO_SOFT_RST_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADDA_CH34_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+ AFE_ADDA_UL1_SRC_CON1,
+ FIFO_SOFT_RST_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("VS1_VOTER_DL", SUPPLY_SEQ_ADDA_AFE_ON,
+ SND_SOC_NOPM, 0, 0,
+ mt_vs1_voter_dl_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("VS1_VOTER_UL", SUPPLY_SEQ_ADDA_AFE_ON,
+ SND_SOC_NOPM, 0, 0,
+ mt_vs1_voter_ul_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0,
+ &adda_ul_mux_control),
+ SND_SOC_DAPM_MUX("ADDA_CH34_UL_Mux", SND_SOC_NOPM, 0, 0,
+ &adda_ch34_ul_mux_control),
+ SND_SOC_DAPM_MUX("ADDA_CH56_UL_Mux", SND_SOC_NOPM, 0, 0,
+ &adda_ch56_ul_mux_control),
+
+ SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"),
+ SND_SOC_DAPM_INPUT("AP_DMIC_CH34_INPUT"),
+
+ /* stf */
+ SND_SOC_DAPM_SWITCH_E("Sidetone Filter",
+ AFE_STF_CON0, SIDE_TONE_ON_SFT, 0,
+ &stf_ctl,
+ mtk_stf_event,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("STF_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_stf_ch1_mix,
+ ARRAY_SIZE(mtk_stf_ch1_mix)),
+ SND_SOC_DAPM_OUTPUT("STF_OUTPUT"),
+
+ /* allow i2s on without codec on */
+ SND_SOC_DAPM_OUTPUT("ADDA_DUMMY_OUT"),
+ SND_SOC_DAPM_MUX("ADDA_Out_Mux",
+ SND_SOC_NOPM, 0, 0, &adda_out_mux_control),
+ SND_SOC_DAPM_INPUT("ADDA_DUMMY_IN"),
+ SND_SOC_DAPM_MUX("ADDA_In_Mux",
+ SND_SOC_NOPM, 0, 0, &adda_in_mux_control),
+
+ /* clock */
+ SND_SOC_DAPM_CLOCK_SUPPLY("vlp_mux_audio_h"),
+
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_ul0_adc_clk"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_ul0_adc_hires_clk"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_ul1_adc_clk"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_ul1_adc_hires_clk"),
+};
+
+#define HIRES_THRESHOLD 48000
+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 mtk_afe_adda_priv *adda_priv;
+
+ adda_priv = get_adda_priv_by_name(afe, w->name);
+
+ if (!adda_priv) {
+ AUDIO_AEE("adda_priv == NULL");
+ return 0;
+ }
+
+ return (adda_priv->ul_rate > HIRES_THRESHOLD) ? 1 : 0;
+}
+
+static int mtk_afe_record_miso1(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 mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ return (afe_priv->audio_r_miso1_enable) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+ /* playback */
+ {"ADDA_DL_CH1", "DL0_CH1", "DL0"},
+ {"ADDA_DL_CH2", "DL0_CH1", "DL0"},
+ {"ADDA_DL_CH2", "DL0_CH2", "DL0"},
+
+ {"ADDA_DL_CH1", "DL1_CH1", "DL1"},
+ {"ADDA_DL_CH2", "DL1_CH2", "DL1"},
+
+ {"ADDA_DL_CH1", "DL2_CH1", "DL2"},
+ {"ADDA_DL_CH2", "DL2_CH2", "DL2"},
+
+ {"ADDA_DL_CH1", "DL3_CH1", "DL3"},
+ {"ADDA_DL_CH2", "DL3_CH2", "DL3"},
+
+ {"ADDA_DL_CH1", "DL4_CH1", "DL4"},
+ {"ADDA_DL_CH2", "DL4_CH2", "DL4"},
+
+ {"ADDA_DL_CH1", "DL5_CH1", "DL5"},
+ {"ADDA_DL_CH2", "DL5_CH2", "DL5"},
+
+ {"ADDA_DL_CH1", "DL6_CH1", "DL6"},
+ {"ADDA_DL_CH2", "DL6_CH2", "DL6"},
+
+ {"ADDA_DL_CH1", "DL7_CH1", "DL7"},
+ {"ADDA_DL_CH2", "DL7_CH2", "DL7"},
+
+ {"ADDA_DL_CH1", "DL8_CH1", "DL8"},
+ {"ADDA_DL_CH2", "DL8_CH2", "DL8"},
+
+ {"ADDA_DL_CH1", "DL_24CH_CH1", "DL_24CH"},
+ {"ADDA_DL_CH2", "DL_24CH_CH2", "DL_24CH"},
+
+ {"ADDA_DL_CH1", "DL24_CH1", "DL24"},
+ {"ADDA_DL_CH2", "DL24_CH2", "DL24"},
+
+ {"ADDA Playback", NULL, "ADDA_DL_CH1"},
+ {"ADDA Playback", NULL, "ADDA_DL_CH2"},
+
+ {"ADDA Playback", NULL, "ADDA Enable"},
+ {"ADDA Playback", NULL, "ADDA Playback Enable"},
+ {"ADDA Playback", NULL, "AUD_PAD_CLK"},
+ {"ADDA Playback", NULL, "AUD_PAD_TOP"},
+ {"ADDA Playback", NULL, "VS1_VOTER_DL"},
+
+ {"ADDA_DL_CH3", "DL0_CH1", "DL0"},
+ {"ADDA_DL_CH4", "DL0_CH2", "DL0"},
+
+ {"ADDA_DL_CH3", "DL1_CH1", "DL1"},
+ {"ADDA_DL_CH4", "DL1_CH2", "DL1"},
+
+ {"ADDA_DL_CH3", "DL2_CH1", "DL2"},
+ {"ADDA_DL_CH4", "DL2_CH2", "DL2"},
+
+ {"ADDA_DL_CH3", "DL3_CH1", "DL3"},
+ {"ADDA_DL_CH4", "DL3_CH2", "DL3"},
+
+ {"ADDA_DL_CH3", "DL4_CH1", "DL4"},
+ {"ADDA_DL_CH4", "DL4_CH2", "DL4"},
+
+ {"ADDA_DL_CH3", "DL5_CH1", "DL5"},
+ {"ADDA_DL_CH4", "DL5_CH2", "DL5"},
+
+ {"ADDA_DL_CH3", "DL6_CH1", "DL6"},
+ {"ADDA_DL_CH4", "DL6_CH2", "DL6"},
+
+ {"ADDA_DL_CH3", "DL7_CH1", "DL7"},
+ {"ADDA_DL_CH4", "DL7_CH2", "DL7"},
+
+ {"ADDA_DL_CH3", "DL8_CH1", "DL8"},
+ {"ADDA_DL_CH4", "DL8_CH2", "DL8"},
+
+ {"ADDA_DL_CH3", "DL_24CH_CH1", "DL_24CH"},
+ {"ADDA_DL_CH4", "DL_24CH_CH2", "DL_24CH"},
+ {"ADDA_DL_CH3", "DL_24CH_CH3", "DL_24CH"},
+ {"ADDA_DL_CH4", "DL_24CH_CH4", "DL_24CH"},
+
+ {"ADDA CH34 Playback", NULL, "ADDA_DL_CH3"},
+ {"ADDA CH34 Playback", NULL, "ADDA_DL_CH4"},
+
+ {"ADDA CH34 Playback", NULL, "ADDA Enable"},
+ {"ADDA CH34 Playback", NULL, "ADDA CH34 Playback Enable"},
+ {"ADDA CH34 Playback", NULL, "AUD_PAD_CLK"},
+ {"ADDA CH34 Playback", NULL, "AUD_PAD_TOP"},
+ {"ADDA CH34 Playback", NULL, "VS1_VOTER_DL"},
+
+ /* capture */
+ {"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"},
+ {"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"},
+ {"ADDA_UL_Mux", "AP_DMIC_MULTI_CH", "AP DMIC MULTICH Capture"},
+
+ {"ADDA_CH34_UL_Mux", "MTKAIF", "ADDA CH34 Capture"},
+ {"ADDA_CH34_UL_Mux", "AP_DMIC", "AP DMIC CH34 Capture"},
+ {"ADDA_CH34_UL_Mux", "AP_DMIC_MULTI_CH", "AP DMIC MULTICH Capture"},
+
+ {"ADDA_CH56_UL_Mux", "MTKAIF", "ADDA CH56 Capture"},
+
+ {"ADDA Capture", NULL, "ADDA Enable"},
+ {"ADDA Capture", NULL, "ADDA Capture Enable"},
+ {"ADDA Capture", NULL, "AUD_PAD_CLK"},
+ {"ADDA Capture", NULL, "AUD_PAD_TOP"},
+ {"ADDA Capture", NULL, "ADDA_MTKAIFV4_RX"},
+ {"ADDA Capture", NULL, "ADDA6_MTKAIFV4_RX", mtk_afe_record_miso1},
+ {"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"},
+ {"ADDA Capture", NULL, "VS1_VOTER_UL"},
+
+ {"AP DMIC Capture", NULL, "ADDA Enable"},
+ {"AP DMIC Capture", NULL, "ADDA Capture Enable"},
+ {"AP DMIC Capture", NULL, "ADDA_FIFO"},
+ {"AP DMIC Capture", NULL, "AP_DMIC_EN"},
+
+ {"ADDA CH34 Capture", NULL, "ADDA Enable"},
+ {"ADDA CH34 Capture", NULL, "ADDA CH34 Capture Enable"},
+ {"ADDA CH34 Capture", NULL, "AUD_PAD_CLK"},
+ {"ADDA CH34 Capture", NULL, "AUD_PAD_TOP"},
+ {"ADDA CH34 Capture", NULL, "ADDA_MTKAIFV4_RX"},
+ {"ADDA CH34 Capture", NULL, "ADDA6_MTKAIFV4_RX", mtk_afe_record_miso1},
+ {"ADDA CH34 Capture", NULL, "ADDA6_MTKAIF_CFG"},
+ {"ADDA CH34 Capture", NULL, "VS1_VOTER_UL"},
+
+ {"AP DMIC CH34 Capture", NULL, "ADDA Enable"},
+ {"AP DMIC CH34 Capture", NULL, "ADDA CH34 Capture Enable"},
+ {"AP DMIC CH34 Capture", NULL, "ADDA_CH34_FIFO"},
+ {"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_EN"},
+
+ {"AP DMIC MULTICH Capture", NULL, "ADDA Enable"},
+ {"AP DMIC MULTICH Capture", NULL, "ADDA Capture Enable"},
+ {"AP DMIC MULTICH Capture", NULL, "ADDA CH34 Capture Enable"},
+ {"AP DMIC MULTICH Capture", NULL, "ADDA_FIFO"},
+ {"AP DMIC MULTICH Capture", NULL, "ADDA_CH34_FIFO"},
+ {"AP DMIC MULTICH Capture", NULL, "AP_DMIC_EN"},
+ {"AP DMIC MULTICH Capture", NULL, "AP_DMIC_CH34_EN"},
+
+ {"ADDA CH56 Capture", NULL, "ADDA Enable"},
+ {"ADDA CH56 Capture", NULL, "ADDA CH56 Capture Enable"},
+ {"ADDA CH56 Capture", NULL, "AUD_PAD_CLK"},
+ {"ADDA CH56 Capture", NULL, "AUD_PAD_TOP"},
+ {"ADDA CH56 Capture", NULL, "ADDA6_MTKAIFV4_RX"},
+ {"ADDA CH56 Capture", NULL, "ADDA7_MTKAIF_CFG"},
+ {"ADDA CH56 Capture", NULL, "VS1_VOTER_UL"},
+
+ {"AP DMIC Capture", NULL, "AP_DMIC_INPUT"},
+ {"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_INPUT"},
+ {"AP DMIC MULTICH Capture", NULL, "AP_DMIC_INPUT"},
+
+ /* sidetone filter */
+ {"Sidetone Filter", "Switch", "STF_CH1"},
+
+ {"STF_OUTPUT", NULL, "Sidetone Filter"},
+ {"ADDA Playback", NULL, "Sidetone Filter"},
+ {"ADDA CH34 Playback", NULL, "Sidetone Filter"},
+
+ /* allow i2s on without codec on */
+ {"ADDA Capture", NULL, "ADDA_In_Mux"},
+ {"ADDA_In_Mux", "Dummy_Widget", "ADDA_DUMMY_IN"},
+ {"ADDA_Out_Mux", "Dummy_Widget", "ADDA Playback"},
+ {"ADDA_DUMMY_OUT", NULL, "ADDA_Out_Mux"},
+
+ /* clk */
+ {"ADDA Capture Enable", NULL, "aud_ul0_adc_clk"},
+ {"ADDA Capture Enable", NULL, "aud_ul0_adc_hires_clk",
+ mtk_afe_adc_hires_connect},
+ {"ADDA CH34 Capture Enable", NULL, "aud_ul1_adc_clk"},
+ {"ADDA CH34 Capture Enable", NULL, "aud_ul1_adc_hires_clk",
+ mtk_afe_adc_hires_connect},
+
+ {"aud_ul0_adc_hires_clk", NULL, "vlp_mux_audio_h"},
+ {"aud_ul1_adc_hires_clk", NULL, "vlp_mux_audio_h"},
+};
+
+/* dai ops */
+static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ unsigned int rate = params_rate(params);
+#ifdef MTKAIF4
+ unsigned int mtkaif_rate = 0;
+#endif
+ int id = dai->id;
+ struct mtk_afe_adda_priv *adda_priv;
+
+ if (id >= MT8196_DAI_NUM || id < 0)
+ return -EINVAL;
+
+ adda_priv = afe_priv->dai_priv[id];
+
+ dev_info(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+ __func__,
+ id,
+ substream->stream,
+ rate);
+
+ if (!adda_priv) {
+ AUDIO_AEE("adda_priv == NULL");
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ adda_priv->dl_rate = rate;
+
+#ifdef MTKAIF4
+ /* get mtkaif dl rate */
+ mtkaif_rate =
+ mtkaif_rate_transform(afe, adda_priv->dl_rate);
+#endif
+ if (id == MT8196_DAI_ADDA) {
+#ifdef MTKAIF4
+ /* MTKAIF sample rate config */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_TXIF_INPUT_MODE_MASK_SFT,
+ mtkaif_rate << MTKAIFV4_TXIF_INPUT_MODE_SFT);
+ /* AFE_ADDA_MTKAIFV4_TX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_TXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x0 << MTKAIFV4_TXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_ADDA_OUT_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_ADDA_OUT_EN_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_ADDA6_OUT_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_ADDA6_OUT_EN_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_TXIF_V4_MASK_SFT,
+ 0x1 << MTKAIFV4_TXIF_V4_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
+ MTKAIFV4_TXIF_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_TXIF_EN_SEL_SFT);
+#endif
+ /* clean predistortion */
+ } else {
+#ifdef MTKAIF4
+ /* MTKAIF sample rate config */
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_TX_CFG0,
+ ADDA6_MTKAIFV4_TXIF_INPUT_MODE_MASK_SFT,
+ mtkaif_rate << ADDA6_MTKAIFV4_TXIF_INPUT_MODE_SFT);
+ /* AFE_ADDA6_MTKAIFV4_TX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_TX_CFG0,
+ ADDA6_MTKAIFV4_TXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x0 << ADDA6_MTKAIFV4_TXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_TX_CFG0,
+ ADDA6_MTKAIFV4_TXIF_EN_SEL_MASK_SFT,
+ 0x1 << ADDA6_MTKAIFV4_TXIF_EN_SEL_SFT);
+#endif
+ }
+ } else {
+ unsigned int voice_mode = 0;
+ unsigned int ul_src_con0 = 0; /* default value */
+
+ adda_priv->ul_rate = rate;
+
+#ifdef MTKAIF4
+ /* get mtkaif dl rate */
+ mtkaif_rate =
+ mtkaif_rate_transform(afe, adda_priv->ul_rate);
+#endif
+
+ voice_mode = adda_ul_rate_transform(afe, rate);
+
+ ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
+
+ /* enable iir */
+ ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) &
+ UL_IIR_ON_TMP_CTL_MASK_SFT;
+ ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) &
+ UL_IIRMODE_CTL_MASK_SFT;
+
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT,
+ mtkaif_rate << MTKAIFV4_RXIF_INPUT_MODE_SFT);
+
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
+ ADDA6_MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT,
+ mtkaif_rate << ADDA6_MTKAIFV4_RXIF_INPUT_MODE_SFT);
+
+ switch (id) {
+ case MT8196_DAI_ADDA:
+ case MT8196_DAI_AP_DMIC:
+ case MT8196_DAI_AP_DMIC_MULTICH:
+#ifdef MTKAIF4
+ if (afe_priv->audio_r_miso1_enable == 1) {
+ /* AFE_ADDA_MTKAIFV4_RX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x0 << MTKAIFV4_RXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_RXIF_EN_SEL_SFT);
+
+ /* AFE_ADDA6_MTKAIFV4_RX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
+ ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x1 << ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
+ ADDA6_MTKAIFV4_RXIF_EN_SEL_MASK_SFT,
+ 0x1 << ADDA6_MTKAIFV4_RXIF_EN_SEL_SFT);
+ } else {
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT,
+ mtkaif_rate << MTKAIFV4_RXIF_INPUT_MODE_SFT);
+ /* AFE_ADDA_MTKAIFV4_RX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x1 << MTKAIFV4_RXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_RXIF_EN_SEL_SFT);
+ /* [28] loopback mode
+ * 0: loopback adda tx to adda rx
+ * 1: loopback adda6 tx to adda rx
+ */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_TXIF_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_TXIF_EN_SEL_SFT);
+ }
+
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT);
+#endif
+ /* 35Hz @ 48k */
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_02_01, 0x00000000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_04_03, 0x00003FB8);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_06_05, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_08_07, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_10_09, 0x0000C048);
+
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_SRC_CON0, ul_src_con0);
+
+ /* mtkaif_rxif_data_mode = 0, amic */
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF1_RX_CFG0,
+ 0x1 << 0,
+ 0x0 << 0);
+
+ /* 35Hz @ 48k */
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_02_01, 0x00000000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_04_03, 0x00003FB8);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_06_05, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_08_07, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_10_09, 0x0000C048);
+
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_SRC_CON0, ul_src_con0);
+
+ /* mtkaif_rxif_data_mode = 0, amic */
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF0_RX_CFG0,
+ 0x1 << 0,
+ 0x0 << 0);
+ break;
+ case MT8196_DAI_ADDA_CH34:
+ case MT8196_DAI_AP_DMIC_CH34:
+#ifdef MTKAIF4
+ if (afe_priv->audio_r_miso1_enable == 0) {
+ /* AFE_ADDA_MTKAIFV4_RX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x1 << MTKAIFV4_RXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_RXIF_EN_SEL_SFT);
+ }
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT);
+
+#endif
+ /* 35Hz @ 48k */
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_02_01, 0x00000000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_04_03, 0x00003FB8);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_06_05, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_08_07, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_IIR_COEF_10_09, 0x0000C048);
+
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL1_SRC_CON0, ul_src_con0);
+
+ /* mtkaif_rxif_data_mode = 0, amic */
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF1_RX_CFG0,
+ 0x1 << 0,
+ 0x0 << 0);
+
+ break;
+ case MT8196_DAI_ADDA_CH56:
+ if (afe_priv->audio_r_miso1_enable == 1) {
+ /* AFE_ADDA_MTKAIFV4_RX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x1 << MTKAIFV4_RXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_RXIF_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_RXIF_EN_SEL_SFT);
+ /* [28] loopback mode
+ * 0: loopback adda tx to adda rx
+ * 1: loopback adda6 tx to adda rx
+ */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_TXIF_EN_SEL_MASK_SFT,
+ 0x0 << MTKAIFV4_TXIF_EN_SEL_SFT);
+ }
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
+ ADDA6_MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT,
+ mtkaif_rate << ADDA6_MTKAIFV4_RXIF_INPUT_MODE_SFT);
+ /* AFE_ADDA6_MTKAIFV4_RX_CFG0 */
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
+ ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT,
+ 0x1 << ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
+ MTKAIFV4_UL_CH5CH6_IN_EN_SEL_MASK_SFT,
+ 0x1 << MTKAIFV4_UL_CH5CH6_IN_EN_SEL_SFT);
+ regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
+ ADDA6_MTKAIFV4_RXIF_EN_SEL_MASK_SFT,
+ 0x1 << ADDA6_MTKAIFV4_RXIF_EN_SEL_SFT);
+ break;
+ default:
+ break;
+ }
+
+ /* ap dmic */
+ switch (id) {
+ case MT8196_DAI_AP_DMIC:
+ case MT8196_DAI_AP_DMIC_CH34:
+ mtk_adda_ul_src_dmic(afe, id);
+ break;
+ case MT8196_DAI_AP_DMIC_MULTICH:
+ regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
+ DMIC_CLK_PHASE_SYNC_SET_MASK_SFT,
+ 0x1 << DMIC_CLK_PHASE_SYNC_SET_SFT);
+ mtk_adda_ul_src_dmic_phase_sync(afe);
+ mtk_adda_ul_src_dmic(afe, MT8196_DAI_AP_DMIC);
+ mtk_adda_ul_src_dmic(afe, MT8196_DAI_AP_DMIC_CH34);
+ mtk_adda_ul_src_dmic_phase_sync_clock(afe);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_adda_ops = {
+ .hw_params = mtk_dai_adda_hw_params,
+};
+
+/* dai driver */
+#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 |\
+ SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
+ {
+ .name = "ADDA",
+ .id = MT8196_DAI_ADDA,
+ .playback = {
+ .stream_name = "ADDA Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_PLAYBACK_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ADDA Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "ADDA_CH34",
+ .id = MT8196_DAI_ADDA_CH34,
+ .playback = {
+ .stream_name = "ADDA CH34 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_PLAYBACK_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ADDA CH34 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "ADDA_CH56",
+ .id = MT8196_DAI_ADDA_CH56,
+ .capture = {
+ .stream_name = "ADDA CH56 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "AP_DMIC",
+ .id = MT8196_DAI_AP_DMIC,
+ .capture = {
+ .stream_name = "AP DMIC Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "AP_DMIC_CH34",
+ .id = MT8196_DAI_AP_DMIC_CH34,
+ .capture = {
+ .stream_name = "AP DMIC CH34 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "AP_DMIC_MULTICH",
+ .id = MT8196_DAI_AP_DMIC_MULTICH,
+ .capture = {
+ .stream_name = "AP DMIC MULTICH Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+};
+
+int mt8196_dai_adda_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ dev_dbg(afe->dev, "%s() successfully start\n", __func__);
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_adda_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+
+ dai->controls = mtk_adda_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_adda_controls);
+ dai->dapm_widgets = mtk_dai_adda_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+ dai->dapm_routes = mtk_dai_adda_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+
+ /* set dai priv */
+ ret = mt8196_dai_set_priv(afe, MT8196_DAI_ADDA,
+ sizeof(struct mtk_afe_adda_priv), NULL);
+ if (ret)
+ return ret;
+
+ ret = mt8196_dai_set_priv(afe, MT8196_DAI_ADDA_CH34,
+ sizeof(struct mtk_afe_adda_priv), NULL);
+ if (ret)
+ return ret;
+
+ ret = mt8196_dai_set_priv(afe, MT8196_DAI_ADDA_CH56,
+ sizeof(struct mtk_afe_adda_priv), NULL);
+ if (ret)
+ return ret;
+
+ ret = mt8196_dai_set_priv(afe, MT8196_DAI_AP_DMIC_MULTICH,
+ sizeof(struct mtk_afe_adda_priv), NULL);
+ if (ret)
+ return ret;
+
+ /* get ap mic type */
+ ret = of_property_read_u32(afe->dev->of_node, "mediatek,ap-dmic",
+ &afe_priv->ap_dmic);
+ if (ret)
+ afe_priv->ap_dmic = 0;
+
+ /* ap dmic priv share with adda */
+ afe_priv->dai_priv[MT8196_DAI_AP_DMIC] =
+ afe_priv->dai_priv[MT8196_DAI_ADDA];
+ afe_priv->dai_priv[MT8196_DAI_AP_DMIC_CH34] =
+ afe_priv->dai_priv[MT8196_DAI_ADDA_CH34];
+
+ return 0;
+}
+
--
2.45.2
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 09/14] ASoC: mediatek: mt8196: support TDM in platform driver
2025-03-07 12:47 [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (5 preceding siblings ...)
2025-03-07 12:47 ` [PATCH 07/14] ASoC: mediatek: mt8196: support ADDA in platform driver Darren.Ye
@ 2025-03-07 12:47 ` Darren.Ye
2025-03-07 12:47 ` [PATCH 10/14] ASoC: mediatek: mt8196: support CM " Darren.Ye
` (5 subsequent siblings)
12 siblings, 0 replies; 27+ messages in thread
From: Darren.Ye @ 2025-03-07 12:47 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add mt8196 TDM DAI driver support.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/mt8196/mt8196-dai-tdm.c | 837 +++++++++++++++++++++
1 file changed, 837 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-dai-tdm.c
diff --git a/sound/soc/mediatek/mt8196/mt8196-dai-tdm.c b/sound/soc/mediatek/mt8196/mt8196-dai-tdm.c
new file mode 100644
index 000000000000..465134b234bd
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-dai-tdm.c
@@ -0,0 +1,837 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI TDM Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8196-afe-clk.h"
+#include "mt8196-afe-common.h"
+#include "mt8196-interconnection.h"
+
+struct mtk_afe_tdm_priv {
+ int bck_id;
+ int bck_rate;
+
+ int mclk_id;
+ int mclk_multiple; /* according to sample rate */
+ int mclk_rate;
+ int mclk_apll;
+};
+
+enum {
+ TDM_WLEN_16_BIT = 1,
+ TDM_WLEN_32_BIT = 2,
+};
+
+enum {
+ TDM_CHANNEL_BCK_16 = 0,
+ TDM_CHANNEL_BCK_24 = 1,
+ TDM_CHANNEL_BCK_32 = 2,
+};
+
+enum {
+ TDM_CHANNEL_NUM_2 = 0,
+ TDM_CHANNEL_NUM_4 = 1,
+ TDM_CHANNEL_NUM_8 = 2,
+};
+
+enum {
+ TDM_CH_START_O30_O31 = 0,
+ TDM_CH_START_O32_O33,
+ TDM_CH_START_O34_O35,
+ TDM_CH_START_O36_O37,
+ TDM_CH_ZERO,
+};
+
+enum {
+ DPTX_CHANNEL_2,
+ DPTX_CHANNEL_8,
+};
+
+enum {
+ DPTX_WLEN_24_BIT,
+ DPTX_WLEN_16_BIT,
+};
+
+enum {
+ DPTX_CH_EN_MASK_2CH = 0x3,
+ DPTX_CH_EN_MASK_4CH = 0xf,
+ DPTX_CH_EN_MASK_6CH = 0x3f,
+ DPTX_CH_EN_MASK_8CH = 0xff,
+};
+
+static unsigned int get_tdm_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ TDM_WLEN_16_BIT : TDM_WLEN_32_BIT;
+}
+
+static unsigned int get_tdm_channel_bck(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32;
+}
+
+static unsigned int get_tdm_lrck_width(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) - 1;
+}
+
+static unsigned int get_tdm_ch(unsigned int ch)
+{
+ switch (ch) {
+ case 1:
+ case 2:
+ return TDM_CHANNEL_NUM_2;
+ case 3:
+ case 4:
+ return TDM_CHANNEL_NUM_4;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ default:
+ return TDM_CHANNEL_NUM_8;
+ }
+}
+
+static unsigned int get_dptx_ch_enable_mask(unsigned int ch)
+{
+ switch (ch) {
+ case 1:
+ case 2:
+ return DPTX_CH_EN_MASK_2CH;
+ case 3:
+ case 4:
+ return DPTX_CH_EN_MASK_4CH;
+ case 5:
+ case 6:
+ return DPTX_CH_EN_MASK_6CH;
+ case 7:
+ case 8:
+ return DPTX_CH_EN_MASK_8CH;
+ default:
+ pr_info("%s(), invalid channel num, default use 2ch\n",
+ __func__);
+ return DPTX_CH_EN_MASK_2CH;
+ }
+}
+
+static unsigned int get_dptx_ch(unsigned int ch)
+{
+ if (ch == 2)
+ return DPTX_CHANNEL_2;
+ else
+ return DPTX_CHANNEL_8;
+}
+
+static unsigned int get_dptx_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ DPTX_WLEN_16_BIT : DPTX_WLEN_24_BIT;
+}
+
+/* interconnection */
+enum {
+ HDMI_CONN_CH0 = 0,
+ HDMI_CONN_CH1,
+ HDMI_CONN_CH2,
+ HDMI_CONN_CH3,
+ HDMI_CONN_CH4,
+ HDMI_CONN_CH5,
+ HDMI_CONN_CH6,
+ HDMI_CONN_CH7,
+};
+
+static const char *const hdmi_conn_mux_map[] = {
+ "CH0", "CH1", "CH2", "CH3",
+ "CH4", "CH5", "CH6", "CH7",
+};
+
+static int hdmi_conn_mux_map_value[] = {
+ HDMI_CONN_CH0,
+ HDMI_CONN_CH1,
+ HDMI_CONN_CH2,
+ HDMI_CONN_CH3,
+ HDMI_CONN_CH4,
+ HDMI_CONN_CH5,
+ HDMI_CONN_CH6,
+ HDMI_CONN_CH7,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_0_SFT,
+ HDMI_O_0_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch0_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_1_SFT,
+ HDMI_O_1_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch1_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_2_SFT,
+ HDMI_O_2_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch2_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_3_SFT,
+ HDMI_O_3_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch3_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_4_SFT,
+ HDMI_O_4_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch4_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_5_SFT,
+ HDMI_O_5_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch5_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_6_SFT,
+ HDMI_O_6_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch6_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_7_SFT,
+ HDMI_O_7_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new hdmi_ch7_mux_control =
+ SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum);
+
+static const char *const tdm_out_mux_map[] = {
+ "Disconnect", "Connect",
+};
+
+static int tdm_out_mux_map_value[] = {
+ 0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(hdmi_out_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ 1,
+ tdm_out_mux_map,
+ tdm_out_mux_map_value);
+static const struct snd_kcontrol_new hdmi_out_mux_control =
+ SOC_DAPM_ENUM("HDMI_OUT_MUX", hdmi_out_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(dptx_out_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ 1,
+ tdm_out_mux_map,
+ tdm_out_mux_map_value);
+static const struct snd_kcontrol_new dptx_out_mux_control =
+ SOC_DAPM_ENUM("DPTX_OUT_MUX", dptx_out_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(dptx_virtual_out_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ 1,
+ tdm_out_mux_map,
+ tdm_out_mux_map_value);
+
+static const struct snd_kcontrol_new dptx_virtual_out_mux_control =
+ SOC_DAPM_ENUM("DPTX_VIRTUAL_OUT_MUX", dptx_virtual_out_mux_map_enum);
+
+enum {
+ SUPPLY_SEQ_APLL,
+ SUPPLY_SEQ_TDM_MCK_EN,
+ SUPPLY_SEQ_TDM_BCK_EN,
+ SUPPLY_SEQ_TDM_DPTX_MCK_EN,
+ SUPPLY_SEQ_TDM_DPTX_BCK_EN,
+};
+
+static int get_tdm_id_by_name(const char *name)
+{
+ if (strstr(name, "DPTX"))
+ return MT8196_DAI_TDM_DPTX;
+ else
+ return MT8196_DAI_TDM;
+}
+
+static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+ dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n",
+ __func__, w->name, event, dai_id);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mt8196_mck_disable(afe, tdm_priv->bck_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+ dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n",
+ __func__, w->name, event, dai_id);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8196_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ tdm_priv->mclk_rate = 0;
+ mt8196_mck_disable(afe, tdm_priv->mclk_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
+ SND_SOC_DAPM_MUX("HDMI_CH0_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch0_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH1_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch1_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH2_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch2_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH3_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch3_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH4_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch4_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH5_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch5_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH6_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch6_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_ch7_mux_control),
+ SND_SOC_DAPM_MUX("HDMI_OUT_MUX", SND_SOC_NOPM, 0, 0,
+ &hdmi_out_mux_control),
+ SND_SOC_DAPM_MUX("DPTX_OUT_MUX", SND_SOC_NOPM, 0, 0,
+ &dptx_out_mux_control),
+
+ SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_tdm_bck_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_tdm_mck_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("TDM_DPTX_BCK", SUPPLY_SEQ_TDM_DPTX_BCK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_tdm_bck_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("TDM_DPTX_MCK", SUPPLY_SEQ_TDM_DPTX_MCK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_tdm_mck_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("DPTX_VIRTUAL_OUT_MUX",
+ SND_SOC_NOPM, 0, 0, &dptx_virtual_out_mux_control),
+ SND_SOC_DAPM_OUTPUT("DPTX_VIRTUAL_OUT"),
+};
+
+static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+ int cur_apll;
+
+ /* which apll */
+ cur_apll = mt8196_get_apll_by_name(afe, source->name);
+
+ return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {
+ {"HDMI_CH0_MUX", "CH0", "HDMI"},
+ {"HDMI_CH0_MUX", "CH1", "HDMI"},
+ {"HDMI_CH0_MUX", "CH2", "HDMI"},
+ {"HDMI_CH0_MUX", "CH3", "HDMI"},
+ {"HDMI_CH0_MUX", "CH4", "HDMI"},
+ {"HDMI_CH0_MUX", "CH5", "HDMI"},
+ {"HDMI_CH0_MUX", "CH6", "HDMI"},
+ {"HDMI_CH0_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH1_MUX", "CH0", "HDMI"},
+ {"HDMI_CH1_MUX", "CH1", "HDMI"},
+ {"HDMI_CH1_MUX", "CH2", "HDMI"},
+ {"HDMI_CH1_MUX", "CH3", "HDMI"},
+ {"HDMI_CH1_MUX", "CH4", "HDMI"},
+ {"HDMI_CH1_MUX", "CH5", "HDMI"},
+ {"HDMI_CH1_MUX", "CH6", "HDMI"},
+ {"HDMI_CH1_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH2_MUX", "CH0", "HDMI"},
+ {"HDMI_CH2_MUX", "CH1", "HDMI"},
+ {"HDMI_CH2_MUX", "CH2", "HDMI"},
+ {"HDMI_CH2_MUX", "CH3", "HDMI"},
+ {"HDMI_CH2_MUX", "CH4", "HDMI"},
+ {"HDMI_CH2_MUX", "CH5", "HDMI"},
+ {"HDMI_CH2_MUX", "CH6", "HDMI"},
+ {"HDMI_CH2_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH3_MUX", "CH0", "HDMI"},
+ {"HDMI_CH3_MUX", "CH1", "HDMI"},
+ {"HDMI_CH3_MUX", "CH2", "HDMI"},
+ {"HDMI_CH3_MUX", "CH3", "HDMI"},
+ {"HDMI_CH3_MUX", "CH4", "HDMI"},
+ {"HDMI_CH3_MUX", "CH5", "HDMI"},
+ {"HDMI_CH3_MUX", "CH6", "HDMI"},
+ {"HDMI_CH3_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH4_MUX", "CH0", "HDMI"},
+ {"HDMI_CH4_MUX", "CH1", "HDMI"},
+ {"HDMI_CH4_MUX", "CH2", "HDMI"},
+ {"HDMI_CH4_MUX", "CH3", "HDMI"},
+ {"HDMI_CH4_MUX", "CH4", "HDMI"},
+ {"HDMI_CH4_MUX", "CH5", "HDMI"},
+ {"HDMI_CH4_MUX", "CH6", "HDMI"},
+ {"HDMI_CH4_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH5_MUX", "CH0", "HDMI"},
+ {"HDMI_CH5_MUX", "CH1", "HDMI"},
+ {"HDMI_CH5_MUX", "CH2", "HDMI"},
+ {"HDMI_CH5_MUX", "CH3", "HDMI"},
+ {"HDMI_CH5_MUX", "CH4", "HDMI"},
+ {"HDMI_CH5_MUX", "CH5", "HDMI"},
+ {"HDMI_CH5_MUX", "CH6", "HDMI"},
+ {"HDMI_CH5_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH6_MUX", "CH0", "HDMI"},
+ {"HDMI_CH6_MUX", "CH1", "HDMI"},
+ {"HDMI_CH6_MUX", "CH2", "HDMI"},
+ {"HDMI_CH6_MUX", "CH3", "HDMI"},
+ {"HDMI_CH6_MUX", "CH4", "HDMI"},
+ {"HDMI_CH6_MUX", "CH5", "HDMI"},
+ {"HDMI_CH6_MUX", "CH6", "HDMI"},
+ {"HDMI_CH6_MUX", "CH7", "HDMI"},
+
+ {"HDMI_CH7_MUX", "CH0", "HDMI"},
+ {"HDMI_CH7_MUX", "CH1", "HDMI"},
+ {"HDMI_CH7_MUX", "CH2", "HDMI"},
+ {"HDMI_CH7_MUX", "CH3", "HDMI"},
+ {"HDMI_CH7_MUX", "CH4", "HDMI"},
+ {"HDMI_CH7_MUX", "CH5", "HDMI"},
+ {"HDMI_CH7_MUX", "CH6", "HDMI"},
+ {"HDMI_CH7_MUX", "CH7", "HDMI"},
+
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH0_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH1_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH2_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH3_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH4_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH5_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH6_MUX"},
+ {"HDMI_OUT_MUX", "Connect", "HDMI_CH7_MUX"},
+
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH0_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH1_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH2_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH3_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH4_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH5_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH6_MUX"},
+ {"DPTX_OUT_MUX", "Connect", "HDMI_CH7_MUX"},
+
+ {"TDM", NULL, "HDMI_OUT_MUX"},
+ {"TDM", NULL, "TDM_BCK"},
+
+ {"TDM_DPTX", NULL, "DPTX_OUT_MUX"},
+ {"TDM_DPTX", NULL, "TDM_DPTX_BCK"},
+
+ {"TDM_BCK", NULL, "TDM_MCK"},
+ {"TDM_DPTX_BCK", NULL, "TDM_DPTX_MCK"},
+ {"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
+ {"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
+ {"TDM_DPTX_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
+ {"TDM_DPTX_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
+
+ {"DPTX_VIRTUAL_OUT_MUX", "Connect", "TDM_DPTX"},
+ {"DPTX_VIRTUAL_OUT", NULL, "DPTX_VIRTUAL_OUT_MUX"},
+};
+
+/* dai ops */
+static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
+ struct mtk_afe_tdm_priv *tdm_priv,
+ int freq)
+{
+ int apll;
+ int apll_rate;
+
+ apll = mt8196_get_apll_by_rate(afe, freq);
+ apll_rate = mt8196_get_apll_rate(afe, apll);
+
+ if (freq > apll_rate) {
+ AUDIO_AEE("freq > apll rate");
+ return -EINVAL;
+ }
+
+ if (apll_rate % freq != 0) {
+ AUDIO_AEE("APLL cannot generate freq Hz");
+ return -EINVAL;
+ }
+
+ tdm_priv->mclk_rate = freq;
+ tdm_priv->mclk_apll = apll;
+
+ return 0;
+}
+
+static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ int tdm_id = dai->id;
+ struct mtk_afe_tdm_priv *tdm_priv;
+ unsigned int rate = params_rate(params);
+ unsigned int channels = params_channels(params);
+ snd_pcm_format_t format = params_format(params);
+ unsigned int tdm_con = 0;
+
+ if (tdm_id >= MT8196_DAI_NUM || tdm_id < 0)
+ return -EINVAL;
+
+ tdm_priv = afe_priv->dai_priv[tdm_id];
+
+ /* calculate mclk_rate, if not set explicitly */
+ if (!tdm_priv->mclk_rate) {
+ tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;
+ mtk_dai_tdm_cal_mclk(afe,
+ tdm_priv,
+ tdm_priv->mclk_rate);
+ }
+
+ /* calculate bck */
+ tdm_priv->bck_rate = rate *
+ channels *
+ snd_pcm_format_physical_width(format);
+
+ if (tdm_priv->bck_rate > tdm_priv->mclk_rate)
+ AUDIO_AEE("bck_rate > mclk_rate rate");
+
+ if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0)
+ AUDIO_AEE("bck cannot generate");
+
+ dev_info(afe->dev, "%s(), id %d, rate %d, channels %d, format %d, mclk_rate %d, bck_rate %d\n",
+ __func__,
+ tdm_id, rate, channels, format,
+ tdm_priv->mclk_rate, tdm_priv->bck_rate);
+
+ /* set tdm */
+ tdm_con = 0 << BCK_INVERSE_SFT;
+ tdm_con |= 0 << LRCK_INVERSE_SFT;
+ tdm_con |= 0 << DELAY_DATA_SFT;
+ tdm_con |= 1 << LEFT_ALIGN_SFT;
+ tdm_con |= get_tdm_wlen(format) << WLEN_SFT;
+ tdm_con |= get_tdm_ch(channels) << CHANNEL_NUM_SFT;
+ tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT;
+ tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT;
+ regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con);
+
+ /* set dptx */
+ if (tdm_id == MT8196_DAI_TDM_DPTX) {
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_CHANNEL_ENABLE_MASK_SFT,
+ get_dptx_ch_enable_mask(channels) <<
+ DPTX_CHANNEL_ENABLE_SFT);
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_CHANNEL_NUMBER_MASK_SFT,
+ get_dptx_ch(channels) <<
+ DPTX_CHANNEL_NUMBER_SFT);
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_16BIT_MASK_SFT,
+ get_dptx_wlen(format) << DPTX_16BIT_SFT);
+ }
+ switch (channels) {
+ case 1:
+ case 2:
+ tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+ break;
+ case 3:
+ case 4:
+ tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+ tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+ break;
+ case 5:
+ case 6:
+ tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+ tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+ tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+ break;
+ case 7:
+ case 8:
+ tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+ tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+ tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
+ tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT;
+ break;
+ default:
+ tdm_con = 0;
+ }
+ regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con);
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ HDMI_CH_NUM_MASK_SFT,
+ channels << HDMI_CH_NUM_SFT);
+
+ return 0;
+}
+
+static int mtk_dai_tdm_trigger(struct snd_pcm_substream *substream,
+ int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int tdm_id = dai->id;
+
+ dev_dbg(afe->dev, "%s(), cmd %d, tdm_id %d\n", __func__, cmd, tdm_id);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ /* enable Out control */
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ HDMI_OUT_ON_MASK_SFT,
+ 0x1 << HDMI_OUT_ON_SFT);
+
+ /* enable dptx */
+ if (tdm_id == MT8196_DAI_TDM_DPTX) {
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_ON_MASK_SFT, 0x1 <<
+ DPTX_ON_SFT);
+ }
+
+ /* enable tdm */
+ regmap_update_bits(afe->regmap, AFE_TDM_CON1,
+ TDM_EN_MASK_SFT, 0x1 << TDM_EN_SFT);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ /* disable tdm */
+ regmap_update_bits(afe->regmap, AFE_TDM_CON1,
+ TDM_EN_MASK_SFT, 0);
+
+ /* disable dptx */
+ if (tdm_id == MT8196_DAI_TDM_DPTX) {
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_ON_MASK_SFT, 0);
+ }
+
+ /* disable Out control */
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ HDMI_OUT_ON_MASK_SFT, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv;
+
+ if (dai->id >= MT8196_DAI_NUM || dai->id < 0)
+ return -EINVAL;
+
+ tdm_priv = afe_priv->dai_priv[dai->id];
+
+ if (!tdm_priv) {
+ AUDIO_AEE("tdm_priv == NULL");
+ return -EINVAL;
+ }
+
+ if (dir != SND_SOC_CLOCK_OUT) {
+ AUDIO_AEE("dir != SND_SOC_CLOCK_OUT");
+ return -EINVAL;
+ }
+
+ dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+ return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
+}
+
+static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {
+ .hw_params = mtk_dai_tdm_hw_params,
+ .trigger = mtk_dai_tdm_trigger,
+ .set_sysclk = mtk_dai_tdm_set_sysclk,
+};
+
+/* dai driver */
+#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {
+ {
+ .name = "TDM",
+ .id = MT8196_DAI_TDM,
+ .playback = {
+ .stream_name = "TDM",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = MTK_TDM_RATES,
+ .formats = MTK_TDM_FORMATS,
+ },
+ .ops = &mtk_dai_tdm_ops,
+ },
+ {
+ .name = "TDM_DPTX",
+ .id = MT8196_DAI_TDM_DPTX,
+ .playback = {
+ .stream_name = "TDM_DPTX",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = MTK_TDM_RATES,
+ .formats = MTK_TDM_FORMATS,
+ },
+ .ops = &mtk_dai_tdm_ops,
+ },
+};
+
+static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe,
+ int id)
+{
+ struct mtk_afe_tdm_priv *tdm_priv;
+
+ tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
+ GFP_KERNEL);
+ if (!tdm_priv)
+ return NULL;
+
+ if (id == MT8196_DAI_TDM_DPTX)
+ tdm_priv->mclk_multiple = 256;
+ else
+ tdm_priv->mclk_multiple = 128;
+
+ tdm_priv->bck_id = MT8196_TDMOUT_BCK;
+ tdm_priv->mclk_id = MT8196_TDMOUT_MCK;
+
+ return tdm_priv;
+}
+
+int mt8196_dai_tdm_register(struct mtk_base_afe *afe)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv, *tdm_dptx_priv;
+ struct mtk_base_afe_dai *dai;
+
+ dev_dbg(afe->dev, "%s() successfully start\n", __func__);
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_tdm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
+
+ dai->dapm_widgets = mtk_dai_tdm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
+ dai->dapm_routes = mtk_dai_tdm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
+
+ tdm_priv = init_tdm_priv_data(afe, MT8196_DAI_TDM);
+ if (!tdm_priv)
+ return -ENOMEM;
+
+ tdm_dptx_priv = init_tdm_priv_data(afe, MT8196_DAI_TDM_DPTX);
+ if (!tdm_dptx_priv)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[MT8196_DAI_TDM] = tdm_priv;
+ afe_priv->dai_priv[MT8196_DAI_TDM_DPTX] = tdm_dptx_priv;
+
+ return 0;
+}
+
--
2.45.2
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 10/14] ASoC: mediatek: mt8196: support CM in platform driver
2025-03-07 12:47 [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (6 preceding siblings ...)
2025-03-07 12:47 ` [PATCH 09/14] ASoC: mediatek: mt8196: support TDM " Darren.Ye
@ 2025-03-07 12:47 ` Darren.Ye
2025-03-07 15:33 ` Krzysztof Kozlowski
2025-03-07 12:47 ` [PATCH 12/14] dt-bindings: mediatek: mt8196: add audio AFE document Darren.Ye
` (4 subsequent siblings)
12 siblings, 1 reply; 27+ messages in thread
From: Darren.Ye @ 2025-03-07 12:47 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add mt8196 CM driver support for ADDA multi-channel.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/mt8196/mt8196-afe-cm.c | 94 +++++++++++++++++++++++
sound/soc/mediatek/mt8196/mt8196-afe-cm.h | 23 ++++++
2 files changed, 117 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-cm.c
create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-cm.h
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-cm.c b/sound/soc/mediatek/mt8196/mt8196-afe-cm.c
new file mode 100644
index 000000000000..b923844a76f8
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-cm.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "mtk-afe-fe-dai.h"
+#include "mtk-base-afe.h"
+
+#include "mt8196-afe-cm.h"
+#include "mt8196-afe-common.h"
+
+void mt8196_set_cm_rate(struct mtk_base_afe *afe, int id, unsigned int rate)
+{
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ afe_priv->cm_rate[id] = rate;
+}
+EXPORT_SYMBOL_GPL(mt8196_set_cm_rate);
+
+static int mt8196_convert_cm_ch(unsigned int ch)
+{
+ return ch - 1;
+}
+
+static unsigned int calculate_cm_update(int rate, int ch)
+{
+ unsigned int update_val;
+
+ update_val = 26000000 / rate / (ch / 2);
+ update_val = update_val * 10 / 7;
+ if (update_val > 100)
+ update_val = 100;
+ if (update_val < 7)
+ update_val = 7;
+
+ return update_val;
+}
+
+int mt8196_set_cm(struct mtk_base_afe *afe, int id,
+ bool update, bool swap, unsigned int ch)
+{
+ unsigned int rate = 0;
+ unsigned int update_val = 0;
+ int reg;
+ struct mt8196_afe_private *afe_priv = afe->platform_priv;
+
+ dev_dbg(afe->dev, "%s()-0, CM%d, rate %d, update %d, swap %d, ch %d\n",
+ __func__, id, rate, update, swap, ch);
+
+ rate = afe_priv->cm_rate[id];
+ update_val = update ? calculate_cm_update(rate, (int)ch) : 0x64;
+
+ reg = AFE_CM0_CON0 + 0x10 * id;
+ /* update cnt */
+ mtk_regmap_update_bits(afe->regmap, reg, AFE_CM_UPDATE_CNT_MASK,
+ update_val, AFE_CM_UPDATE_CNT_SFT);
+
+ /* rate */
+ mtk_regmap_update_bits(afe->regmap, reg, AFE_CM_1X_EN_SEL_FS_MASK,
+ rate, AFE_CM_1X_EN_SEL_FS_SFT);
+
+ /* ch num */
+ ch = mt8196_convert_cm_ch(ch);
+ mtk_regmap_update_bits(afe->regmap, reg, AFE_CM_CH_NUM_MASK,
+ ch, AFE_CM_CH_NUM_SFT);
+
+ /* swap */
+ mtk_regmap_update_bits(afe->regmap, reg, AFE_CM_BYTE_SWAP_MASK,
+ swap, AFE_CM_BYTE_SWAP_SFT);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt8196_set_cm);
+
+int mt8196_enable_cm_bypass(struct mtk_base_afe *afe, int id, bool en)
+{
+ int reg = AFE_CM0_CON0 + 0x10 * id;
+
+ mtk_regmap_update_bits(afe->regmap, reg, AFE_CM_BYPASS_MODE_MASK,
+ en, AFE_CM_BYPASS_MODE_SFT);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt8196_enable_cm_bypass);
+
+MODULE_DESCRIPTION("Mediatek afe cm");
+MODULE_AUTHOR("darren ye <darren.ye@mediatek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-cm.h b/sound/soc/mediatek/mt8196/mt8196-afe-cm.h
new file mode 100644
index 000000000000..18115ec8fa70
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-cm.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2024 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#ifndef MTK_AFE_CM_H_
+#define MTK_AFE_CM_H_
+enum {
+ CM0,
+ CM1,
+ CM2,
+ CM_NUM,
+};
+
+void mt8196_set_cm_rate(struct mtk_base_afe *afe, int id, unsigned int rate);
+
+int mt8196_set_cm(struct mtk_base_afe *afe, int id, bool update,
+ bool swap, unsigned int ch);
+int mt8196_enable_cm_bypass(struct mtk_base_afe *afe, int id, bool en);
+
+#endif /* MTK_AFE_CM_H_ */
+
--
2.45.2
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 12/14] dt-bindings: mediatek: mt8196: add audio AFE document
2025-03-07 12:47 [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (7 preceding siblings ...)
2025-03-07 12:47 ` [PATCH 10/14] ASoC: mediatek: mt8196: support CM " Darren.Ye
@ 2025-03-07 12:47 ` Darren.Ye
2025-03-07 14:35 ` Rob Herring (Arm)
2025-03-07 15:15 ` Krzysztof Kozlowski
2025-03-07 12:47 ` [PATCH 13/14] ASoC: mediatek: mt8196: add machine driver with mt6681 Darren.Ye
` (3 subsequent siblings)
12 siblings, 2 replies; 27+ messages in thread
From: Darren.Ye @ 2025-03-07 12:47 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add mt8196 audio AFE document.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
.../bindings/sound/mediatek,mt8196-afe.yaml | 259 ++++++++++++++++++
1 file changed, 259 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
new file mode 100644
index 000000000000..59f8fdf3167c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
@@ -0,0 +1,259 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mt8196-afe.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Audio Front End PCM controller for MT8196
+
+maintainers:
+ - Darren Ye <darren.ye@mediatek.com>
+
+properties:
+ compatible:
+ const: mediatek,mt8196-afe-pcm
+
+ reg:
+ maxItems: 1
+
+ "#sound-dai-cells":
+ const: 0
+
+ clocks:
+ items:
+ - description: audio hopping clock
+ - description: audio f26m clock
+ - description: audio ul0 adc clock
+ - description: audio ul0 adc hires clock
+ - description: audio ul1 adc clock
+ - description: audio ul1 adc hires clock
+ - description: audio apll1 clock
+ - description: audio apll2 clock
+ - description: audio apll tuner1 clock
+ - description: audio apll tuner2 clock
+ - description: vlp mux audio int
+ - description: vlp mux aud engen1
+ - description: vlp mux aud engen2
+ - description: vlp mux audio h
+ - description: vlp clock 26m
+ - description: ck mainpll d4 d4
+ - description: ck mux aud 1
+ - description: ck apll1
+ - description: ck mux aud 2
+ - description: ck apll2
+ - description: ck apll1 d4
+ - description: ck apll2 d4
+ - description: ck i2sin0 m sel
+ - description: ck i2sin1 m sel
+ - description: ck fmi2s m sel
+ - description: ck tdmout m sel
+ - description: ck apll12 div i2sin0
+ - description: ck apll12 div i2sin1
+ - description: ck apll12 div fmi2s
+ - description: ck apll12 div tdmout m
+ - description: ck apll12 div tdmout b
+ - description: ck adsp sel
+ - description: ck clock 26m
+
+ clock-names:
+ items:
+ - const: aud_hopping_clk
+ - const: aud_f26m_clk
+ - const: aud_ul0_adc_clk
+ - const: aud_ul0_adc_hires_clk
+ - const: aud_ul1_adc_clk
+ - const: aud_ul1_adc_hires_clk
+ - const: aud_apll1_clk
+ - const: aud_apll2_clk
+ - const: aud_apll_tuner1_clk
+ - const: aud_apll_tuner2_clk
+ - const: vlp_mux_audio_int
+ - const: vlp_mux_aud_eng1
+ - const: vlp_mux_aud_eng2
+ - const: vlp_mux_audio_h
+ - const: vlp_clk26m_clk
+ - const: ck_mainpll_d4_d4
+ - const: ck_mux_aud_1
+ - const: ck_apll1_ck
+ - const: ck_mux_aud_2
+ - const: ck_apll2_ck
+ - const: ck_apll1_d4
+ - const: ck_apll2_d4
+ - const: ck_i2sin0_m_sel
+ - const: ck_i2sin1_m_sel
+ - const: ck_fmi2s_m_sel
+ - const: ck_tdmout_m_sel
+ - const: ck_apll12_div_i2sin0
+ - const: ck_apll12_div_i2sin1
+ - const: ck_apll12_div_fmi2s
+ - const: ck_apll12_div_tdmout_m
+ - const: ck_apll12_div_tdmout_b
+ - const: ck_adsp_sel
+ - const: ck_clk26m_clk
+
+ interrupts:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ cksys:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: Phandle to the cksys clock controller.
+
+ vlpcksys:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: Phandle to the vlpcksys clock controller.
+
+ memory-region:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: Phandle to the reserved memory region for AFE DMA.
+
+ pinctrl-names:
+ items:
+ - const: default
+
+ pinctrl-0:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: Phandle to the pin control group for default state.
+
+ mediatek,etdm-out-ch:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Number of ETDM output channels.
+ enum: [2]
+
+ mediatek,etdm-in-ch:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Number of ETDM input channels.
+ enum: [2]
+
+ mediatek,etdm-out-sync:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: ETDM output synchronization.
+ enum: [0, 1]
+
+ mediatek,etdm-in-sync:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: ETDM input synchronization.
+ enum: [0, 1]
+
+ mediatek,etdm-ip-mode:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: ETDM IP mode.
+ enum: [0, 1]
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - interrupts
+ - power-domains
+ - cksys
+ - vlpcksys
+ - memory-region
+ - pinctrl-names
+ - pinctrl-0
+ - mediatek,etdm-out-ch
+ - mediatek,etdm-in-ch
+ - mediatek,etdm-out-sync
+ - mediatek,etdm-in-sync
+ - mediatek,etdm-ip-mode
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/mt8196-clk.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/power/mt8196-power.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ afe: mt8196-afe-pcm@1a110000 {
+ compatible = "mediatek,mt8196-afe-pcm";
+ reg = <0 0x1a110000 0 0x9000>;
+ interrupts = <GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH 0>;
+ cksys = <&cksys_clk>;
+ vlpcksys = <&vlp_cksys_clk>;
+ power-domains = <&scpsys MT8196_POWER_DOMAIN_AUDIO>;
+ memory-region = <&afe_dma_mem_reserved>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&aud_pins_default>;
+ /* Only for ETDM in/out 4 */
+ mediatek,etdm-out-ch = <2>;
+ mediatek,etdm-in-ch = <2>;
+ mediatek,etdm-out-sync = <0>;
+ mediatek,etdm-in-sync = <1>;
+ mediatek,etdm-ip-mode = <0>;
+ clocks = <&afe_clk CLK_AFE_AUDIO_HOPPING_AFE>,
+ <&afe_clk CLK_AFE_AUDIO_F26M_AFE>,
+ <&afe_clk CLK_AFE_UL0_ADC_AFE>,
+ <&afe_clk CLK_AFE_UL0_ADC_HIRES_AFE>,
+ <&afe_clk CLK_AFE_UL1_ADC_AFE>,
+ <&afe_clk CLK_AFE_UL1_ADC_HIRES_AFE>,
+ <&afe_clk CLK_AFE_APLL1_AFE>,
+ <&afe_clk CLK_AFE_APLL2_AFE>,
+ <&afe_clk CLK_AFE_APLL_TUNER1_AFE>,
+ <&afe_clk CLK_AFE_APLL_TUNER2_AFE>,
+ <&vlp_cksys_clk CLK_VLP_CK_AUD_INTBUS_SEL>,
+ <&vlp_cksys_clk CLK_VLP_CK_AUD_ENGEN1_SEL>,
+ <&vlp_cksys_clk CLK_VLP_CK_AUD_ENGEN2_SEL>,
+ <&vlp_cksys_clk CLK_VLP_CK_AUDIO_H_SEL>,
+ <&vlp_cksys_clk CLK_VLP_CK_CLKSQ>,
+ <&cksys_clk CLK_CK_MAINPLL_D4_D4>,
+ <&cksys_clk CLK_CK_AUD_1_SEL>,
+ <&cksys_clk CLK_CK_APLL1>,
+ <&cksys_clk CLK_CK_AUD_2_SEL>,
+ <&cksys_clk CLK_CK_APLL2>,
+ <&cksys_clk CLK_CK_APLL1_D4>,
+ <&cksys_clk CLK_CK_APLL2_D4>,
+ <&cksys_clk CLK_CK_APLL_I2SIN0_MCK_SEL>,
+ <&cksys_clk CLK_CK_APLL_I2SIN1_MCK_SEL>,
+ <&cksys_clk CLK_CK_APLL_FMI2S_MCK_SEL>,
+ <&cksys_clk CLK_CK_APLL_TDMOUT_MCK_SEL>,
+ <&cksys_clk CLK_CK_APLL12_CK_DIV_I2SIN0>,
+ <&cksys_clk CLK_CK_APLL12_CK_DIV_I2SIN1>,
+ <&cksys_clk CLK_CK_APLL12_CK_DIV_FMI2S>,
+ <&cksys_clk CLK_CK_APLL12_CK_DIV_TDMOUT_M>,
+ <&cksys_clk CLK_CK_APLL12_CK_DIV_TDMOUT_B>,
+ <&cksys_clk CLK_CK_ADSP_SEL>,
+ <&cksys_clk CLK_CK_TCK_26M_MX9>;
+ clock-names = "aud_hopping_clk",
+ "aud_f26m_clk",
+ "aud_ul0_adc_clk",
+ "aud_ul0_adc_hires_clk",
+ "aud_ul1_adc_clk",
+ "aud_ul1_adc_hires_clk",
+ "aud_apll1_clk",
+ "aud_apll2_clk",
+ "aud_apll_tuner1_clk",
+ "aud_apll_tuner2_clk",
+ "vlp_mux_audio_int",
+ "vlp_mux_aud_eng1",
+ "vlp_mux_aud_eng2",
+ "vlp_mux_audio_h",
+ "vlp_clk26m_clk",
+ "ck_mainpll_d4_d4",
+ "ck_mux_aud_1",
+ "ck_apll1_ck",
+ "ck_mux_aud_2",
+ "ck_apll2_ck",
+ "ck_apll1_d4",
+ "ck_apll2_d4",
+ "ck_i2sin0_m_sel",
+ "ck_i2sin1_m_sel",
+ "ck_fmi2s_m_sel",
+ "ck_tdmout_m_sel",
+ "ck_apll12_div_i2sin0",
+ "ck_apll12_div_i2sin1",
+ "ck_apll12_div_fmi2s",
+ "ck_apll12_div_tdmout_m",
+ "ck_apll12_div_tdmout_b",
+ "ck_adsp_sel",
+ "ck_clk26m_clk";
+ };
+ };
--
2.45.2
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 13/14] ASoC: mediatek: mt8196: add machine driver with mt6681
2025-03-07 12:47 [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (8 preceding siblings ...)
2025-03-07 12:47 ` [PATCH 12/14] dt-bindings: mediatek: mt8196: add audio AFE document Darren.Ye
@ 2025-03-07 12:47 ` Darren.Ye
2025-03-07 12:47 ` [PATCH 14/14] dt-bindings: mediatek: mt8196: add mt8196-mt6681 document Darren.Ye
` (2 subsequent siblings)
12 siblings, 0 replies; 27+ messages in thread
From: Darren.Ye @ 2025-03-07 12:47 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add support for mt8196 board with mt6681.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
sound/soc/mediatek/Kconfig | 20 +
sound/soc/mediatek/mt8196/Makefile | 2 +
sound/soc/mediatek/mt8196/mt8196-mt6681.c | 879 ++++++++++++++++++++++
3 files changed, 901 insertions(+)
create mode 100644 sound/soc/mediatek/mt8196/mt8196-mt6681.c
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 606f221e238c..55f9397fce91 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -214,6 +214,26 @@ config SND_SOC_MT8196
Select Y if you have such device.
If unsure select "N".
+config SND_SOC_MT8196_MT6681
+ tristate "ASoc Audio driver for MT8196 with I2S codec"
+ depends on SND_SOC_MT8196
+ depends on I2C
+ select SND_SOC_HDMI_CODEC
+ select SND_SOC_DMIC
+ select SND_SOC_NAU8315
+ select SND_SOC_NAU8825
+ select SND_SOC_RT5645
+ select SND_SOC_RT5682_I2C
+ select SND_SOC_RT5682S
+ select SND_SOC_TAS2781_COMLIB
+ select SND_SOC_TAS2781_FMWLIB
+ select SND_SOC_TAS2781_I2C
+ help
+ This adds support for ASoC machine driver for MediaTek MT8196
+ boards with the other I2S audio codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
config SND_SOC_MTK_BTCVSD
tristate "ALSA BT SCO CVSD/MSBC Driver"
help
diff --git a/sound/soc/mediatek/mt8196/Makefile b/sound/soc/mediatek/mt8196/Makefile
index 312cdfb5205b..ba5922736a59 100644
--- a/sound/soc/mediatek/mt8196/Makefile
+++ b/sound/soc/mediatek/mt8196/Makefile
@@ -15,3 +15,5 @@ snd-soc-mt8196-afe-objs += \
mt8196-dai-tdm.o \
mt8196-afe-cm.o
+# machine driver
+obj-$(CONFIG_SND_SOC_MT8196_MT6681) += mt8196-mt6681.o
diff --git a/sound/soc/mediatek/mt8196/mt8196-mt6681.c b/sound/soc/mediatek/mt8196/mt8196-mt6681.c
new file mode 100644
index 000000000000..9053e96fd193
--- /dev/null
+++ b/sound/soc/mediatek/mt8196/mt8196-mt6681.c
@@ -0,0 +1,879 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8196-mt6681.c -- mt8196 mt6681 ALSA SoC machine driver
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <linux/input.h>
+#include <linux/of_device.h>
+
+#include "mtk-afe-platform-driver.h"
+#include "mt8196-afe-common.h"
+#include "mt8196-afe-clk.h"
+#include "mt8196-afe-gpio.h"
+
+#include "../../codecs/nau8825.h"
+#include "../../codecs/rt5682s.h"
+
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-soundcard-driver.h"
+#include "../common/mtk-dsp-sof-common.h"
+#include "../common/mtk-soc-card.h"
+
+#define NAU8825_HS_PRESENT BIT(0)
+#define RT5682S_HS_PRESENT BIT(1)
+#define RT5650_HS_PRESENT BIT(2)
+
+/*
+ * Nau88l25
+ */
+#define NAU8825_CODEC_DAI "nau8825-hifi"
+
+/*
+ * Rt5682s
+ */
+#define RT5682S_CODEC_DAI "rt5682s-aif1"
+
+/*
+ * Rt5650
+ */
+#define RT5650_CODEC_DAI "rt5645-aif1"
+
+#define SOF_DMA_DL1 "SOF_DMA_DL1"
+#define SOF_DMA_DL_24CH "SOF_DMA_DL_24CH"
+#define SOF_DMA_UL0 "SOF_DMA_UL0"
+#define SOF_DMA_UL1 "SOF_DMA_UL1"
+#define SOF_DMA_UL2 "SOF_DMA_UL2"
+
+enum mt8196_jacks {
+ MT8196_JACK_HEADSET,
+ MT8196_JACK_DP,
+ MT8196_JACK_HDMI,
+ MT8196_JACK_MAX,
+};
+
+static struct snd_soc_jack_pin mt8196_dp_jack_pins[] = {
+ {
+ .pin = "DP",
+ .mask = SND_JACK_LINEOUT,
+ },
+};
+
+static struct snd_soc_jack_pin mt8196_hdmi_jack_pins[] = {
+ {
+ .pin = "HDMI",
+ .mask = SND_JACK_LINEOUT,
+ },
+};
+
+static struct snd_soc_jack_pin nau8825_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new mt8196_dumb_spk_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static const struct snd_soc_dapm_widget mt8196_dumb_spk_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const struct snd_soc_dapm_widget mt8196_nau8825_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SINK("DP"),
+};
+
+static const struct snd_kcontrol_new mt8196_nau8825_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+/*
+ * if need additional control for the ext spk amp that is connected
+ * after Lineout Buffer / HP Buffer on the codec, put the control in
+ * mt8196_mt6681_spk_amp_event()
+ */
+#define EXT_SPK_AMP_W_NAME "Ext_Speaker_Amp"
+
+static struct snd_soc_card mt8196_mt6681_soc_card;
+
+static const struct snd_soc_dapm_widget mt8196_mt6681_widgets[] = {
+};
+
+static const struct snd_soc_dapm_route mt8196_mt6681_routes[] = {
+};
+
+static const struct snd_kcontrol_new mt8196_mt6681_controls[] = {
+ SOC_DAPM_PIN_SWITCH(EXT_SPK_AMP_W_NAME),
+};
+
+/*
+ * define mtk_spk_i2s_mck node in dts when need mclk,
+ * BE i2s need assign snd_soc_ops = mt8196_mt6681_i2s_ops
+ */
+static int mt8196_mt6681_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned int rate = params_rate(params);
+ unsigned int mclk_fs_ratio = 128;
+ unsigned int mclk_fs = rate * mclk_fs_ratio;
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ return snd_soc_dai_set_sysclk(cpu_dai,
+ 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8196_mt6681_i2s_ops = {
+ .hw_params = mt8196_mt6681_i2s_hw_params,
+};
+
+static int mt8196_dptx_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned int rate = params_rate(params);
+ unsigned int mclk_fs_ratio = 256;
+ unsigned int mclk_fs = rate * mclk_fs_ratio;
+ struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ return snd_soc_dai_set_sysclk(dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8196_dptx_ops = {
+ .hw_params = mt8196_dptx_hw_params,
+};
+
+static int mt8196_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ dev_info(rtd->dev, "%s(), fix format to 32bit\n", __func__);
+
+ /* fix BE i2s format to 32bit, clean param mask first */
+ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
+ 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+
+ params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
+
+ return 0;
+}
+
+static int mt8196_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ dev_info(rtd->dev, "%s(), fix format to 32bit\n", __func__);
+
+ /* fix BE i2s format to 32bit, clean param mask first */
+ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
+ 0, SNDRV_PCM_FORMAT_LAST);
+
+ params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
+ return 0;
+}
+
+static int mt8196_sof_be_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *cmpnt_afe = NULL;
+ struct snd_soc_pcm_runtime *runtime;
+
+ /* find afe component */
+ for_each_card_rtds(rtd->card, runtime) {
+ cmpnt_afe = snd_soc_rtdcom_lookup(runtime, AFE_PCM_NAME);
+ if (cmpnt_afe) {
+ dev_info(rtd->dev, "component->name: %s\n", cmpnt_afe->name);
+ break;
+ }
+ }
+
+ if (cmpnt_afe && !pm_runtime_active(cmpnt_afe->dev)) {
+ dev_err(rtd->dev, "afe pm runtime is not active!!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops mt8196_sof_be_ops = {
+ .hw_params = mt8196_sof_be_hw_params,
+};
+
+static const struct sof_conn_stream g_sof_conn_streams[] = {
+ {
+ .sof_link = "AFE_SOF_DL1",
+ .sof_dma = SOF_DMA_DL1,
+ .stream_dir = SNDRV_PCM_STREAM_PLAYBACK
+ },
+ {
+ .sof_link = "AFE_SOF_DL_24CH",
+ .sof_dma = SOF_DMA_DL_24CH,
+ .stream_dir = SNDRV_PCM_STREAM_PLAYBACK
+ },
+ {
+ .sof_link = "AFE_SOF_UL0",
+ .sof_dma = SOF_DMA_UL0,
+ .stream_dir = SNDRV_PCM_STREAM_CAPTURE
+ },
+ {
+ .sof_link = "AFE_SOF_UL1",
+ .sof_dma = SOF_DMA_UL1,
+ .stream_dir = SNDRV_PCM_STREAM_CAPTURE
+ },
+ {
+ .sof_link = "AFE_SOF_UL2",
+ .sof_dma = SOF_DMA_UL2,
+ .stream_dir = SNDRV_PCM_STREAM_CAPTURE
+ },
+};
+
+/* FE */
+SND_SOC_DAILINK_DEFS(playback1,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback_24ch,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL_24CH")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture0,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture1,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture2,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback_hdmi,
+ DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback2,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture_cm0,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL_CM0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+/* BE */
+SND_SOC_DAILINK_DEFS(ap_dmic,
+ DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(ap_dmic_ch34,
+ DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_CH34")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(ap_dmic_multich,
+ DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_MULTICH")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sin6,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2SIN6")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sout3,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT3")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sout4,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT4")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sout6,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT6")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(tdm_dptx,
+ DAILINK_COMP_ARRAY(COMP_CPU("TDM_DPTX")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(AFE_SOF_DL_24CH,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL_24CH")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(AFE_SOF_DL1,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(AFE_SOF_UL0,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(AFE_SOF_UL1,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(AFE_SOF_UL2,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt8196_mt6681_dai_links[] = {
+ /*
+ * The SOF topology expects PCM streams 0~4 to be available
+ * for the SOF PCM streams. Put the SOF BE definitions here
+ * so that the PCM device numbers are skipped over.
+ * (BE dailinks do not have PCM devices created.)
+ */
+ {
+ .name = "AFE_SOF_DL_24CH",
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ops = &mt8196_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_DL_24CH),
+ },
+ {
+ .name = "AFE_SOF_DL1",
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ops = &mt8196_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_DL1),
+ },
+ {
+ .name = "AFE_SOF_UL0",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ops = &mt8196_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_UL0),
+ },
+ {
+ .name = "AFE_SOF_UL1",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ops = &mt8196_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_UL1),
+ },
+ {
+ .name = "AFE_SOF_UL2",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ops = &mt8196_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_UL2),
+ },
+ /* Front End DAI links */
+ {
+ .name = "HDMI_FE",
+ .stream_name = "HDMI Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback_hdmi),
+ },
+ {
+ .name = "DL2_FE",
+ .stream_name = "DL2 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback2),
+ },
+ {
+ .name = "UL_CM0_FE",
+ .stream_name = "UL_CM0 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture_cm0),
+ },
+ {
+ .name = "DL_24CH_FE",
+ .stream_name = "DL_24CH Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback_24ch),
+ },
+ {
+ .name = "DL1_FE",
+ .stream_name = "DL1 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback1),
+ },
+ {
+ .name = "UL0_FE",
+ .stream_name = "UL0 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture0),
+ },
+ {
+ .name = "UL1_FE",
+ .stream_name = "UL1 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture1),
+ },
+ {
+ .name = "UL2_FE",
+ .stream_name = "UL2 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture2),
+ },
+ /* Back End DAI links */
+ {
+ .name = "I2SIN6_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_mt6681_i2s_ops,
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8196_i2s_hw_params_fixup,
+ SND_SOC_DAILINK_REG(i2sin6),
+ },
+ {
+ .name = "I2SOUT4_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_mt6681_i2s_ops,
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = mt8196_i2s_hw_params_fixup,
+ SND_SOC_DAILINK_REG(i2sout4),
+ },
+ {
+ .name = "I2SOUT6_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_mt6681_i2s_ops,
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8196_i2s_hw_params_fixup,
+ SND_SOC_DAILINK_REG(i2sout6),
+ },
+ {
+ .name = "AP_DMIC_BE",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(ap_dmic),
+ },
+ {
+ .name = "AP_DMIC_CH34_BE",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(ap_dmic_ch34),
+ },
+ {
+ .name = "AP_DMIC_MULTICH_BE",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(ap_dmic_multich),
+ },
+ {
+ .name = "TDM_DPTX_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_dptx_ops,
+ .be_hw_params_fixup = mt8196_dptx_hw_params_fixup,
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(tdm_dptx),
+ },
+ {
+ .name = "I2SOUT3_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8196_mt6681_i2s_ops,
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(i2sout3),
+ },
+};
+
+static int mt8196_dumb_amp_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ int ret = 0;
+
+ ret = snd_soc_dapm_new_controls(&card->dapm, mt8196_dumb_spk_widgets,
+ ARRAY_SIZE(mt8196_dumb_spk_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add Dumb Speaker dapm, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, mt8196_dumb_spk_controls,
+ ARRAY_SIZE(mt8196_dumb_spk_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add Dumb card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt8196_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8196_JACK_DP];
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ int ret = 0;
+
+ ret = snd_soc_card_jack_new_pins(rtd->card, "DP Jack", SND_JACK_LINEOUT,
+ jack, mt8196_dp_jack_pins,
+ ARRAY_SIZE(mt8196_dp_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "%s, new jack failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+ if (ret) {
+ dev_err(rtd->dev, "%s, set jack failed on %s (ret=%d)\n",
+ __func__, component->name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt8196_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8196_JACK_HDMI];
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ int ret = 0;
+
+ ret = snd_soc_card_jack_new_pins(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+ jack, mt8196_hdmi_jack_pins,
+ ARRAY_SIZE(mt8196_hdmi_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "%s, new jack failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+ if (ret) {
+ dev_err(rtd->dev, "%s, set jack failed on %s (ret=%d)\n",
+ __func__, component->name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt8196_headset_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8196_JACK_HEADSET];
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ int ret;
+ int type;
+
+ ret = snd_soc_dapm_new_controls(&card->dapm, mt8196_nau8825_widgets,
+ ARRAY_SIZE(mt8196_nau8825_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add nau8825 card widget, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, mt8196_nau8825_controls,
+ ARRAY_SIZE(mt8196_nau8825_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add nau8825 card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+ SND_JACK_BTN_3,
+ jack,
+ nau8825_jack_pins,
+ ARRAY_SIZE(nau8825_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+ type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3;
+ ret = snd_soc_component_set_jack(component, jack, (void *)&type);
+
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+};
+
+static void mt8196_headset_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+
+ snd_soc_component_set_jack(component, NULL, NULL);
+}
+
+static int mt8196_nau8825_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ unsigned int rate = params_rate(params);
+ unsigned int bit_width = params_width(params);
+ int clk_freq, ret;
+
+ clk_freq = rate * 2 * bit_width;
+
+ /* Configure clock for codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret);
+ return ret;
+ }
+
+ /* Configure pll for codec */
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq,
+ params_rate(params) * 256);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops mt8196_nau8825_ops = {
+ .hw_params = mt8196_nau8825_hw_params,
+};
+
+static int mt8196_rt5682s_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ unsigned int rate = params_rate(params);
+ int bitwidth;
+ int ret;
+
+ bitwidth = snd_pcm_format_width(params_format(params));
+ if (bitwidth < 0) {
+ dev_err(card->dev, "invalid bit width: %d\n", bitwidth);
+ return bitwidth;
+ }
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth);
+ if (ret) {
+ dev_err(card->dev, "failed to set tdm slot\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL1, RT5682S_PLL_S_BCLK1,
+ rate * 32, rate * 512);
+ if (ret) {
+ dev_err(card->dev, "failed to set pll\n");
+ return ret;
+ }
+
+ dev_info(card->dev, "%s set mclk rate: %d\n", __func__, rate * 512);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_MCLK,
+ rate * 512, SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(card->dev, "failed to set sysclk\n");
+ return ret;
+ }
+
+ return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 512,
+ SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8196_rt5682s_i2s_ops = {
+ .hw_params = mt8196_rt5682s_i2s_hw_params,
+};
+
+static int mt8196_mt6681_soc_card_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)
+{
+ struct snd_soc_card *card = soc_card_data->card_data->card;
+ struct snd_soc_dai_link *dai_link;
+ bool init_nau8825 = false;
+ bool init_rt5682s = false;
+ bool init_rt5650 = false;
+ bool init_dumb = false;
+ int i;
+
+ dev_info(card->dev, "%s(), legacy: %d\n", __func__, legacy);
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (strcmp(dai_link->name, "TDM_DPTX_BE") == 0) {
+ if (dai_link->num_codecs &&
+ strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
+ dai_link->init = mt8196_dptx_codec_init;
+ } else if (strcmp(dai_link->name, "I2SOUT3_BE") == 0) {
+ if (dai_link->num_codecs &&
+ strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
+ dai_link->init = mt8196_hdmi_codec_init;
+ } else if (strcmp(dai_link->name, "I2SOUT6_BE") == 0 ||
+ strcmp(dai_link->name, "I2SIN6_BE") == 0) {
+ if (!strcmp(dai_link->codecs->dai_name, NAU8825_CODEC_DAI)) {
+ dai_link->ops = &mt8196_nau8825_ops;
+ if (!init_nau8825) {
+ dai_link->init = mt8196_headset_codec_init;
+ dai_link->exit = mt8196_headset_codec_exit;
+ init_nau8825 = true;
+ }
+ } else if (!strcmp(dai_link->codecs->dai_name, RT5682S_CODEC_DAI)) {
+ dai_link->ops = &mt8196_rt5682s_i2s_ops;
+ if (!init_rt5682s) {
+ dai_link->init = mt8196_headset_codec_init;
+ dai_link->exit = mt8196_headset_codec_exit;
+ init_rt5682s = true;
+ }
+ } else if (!strcmp(dai_link->codecs->dai_name, RT5650_CODEC_DAI)) {
+ dai_link->ops = &mt8196_rt5682s_i2s_ops;
+ if (!init_rt5650) {
+ dai_link->init = mt8196_headset_codec_init;
+ dai_link->exit = mt8196_headset_codec_exit;
+ init_rt5650 = true;
+ }
+ } else {
+ if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) {
+ if (!init_dumb) {
+ dai_link->init = mt8196_dumb_amp_init;
+ init_dumb = true;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const struct mtk_sof_priv mt8196_sof_priv = {
+ .conn_streams = g_sof_conn_streams,
+ .num_streams = ARRAY_SIZE(g_sof_conn_streams),
+};
+
+static struct snd_soc_card mt8196_mt6681_soc_card = {
+ .owner = THIS_MODULE,
+ .dai_link = mt8196_mt6681_dai_links,
+ .num_links = ARRAY_SIZE(mt8196_mt6681_dai_links),
+ .dapm_widgets = mt8196_mt6681_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8196_mt6681_widgets),
+ .dapm_routes = mt8196_mt6681_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8196_mt6681_routes),
+ .controls = mt8196_mt6681_controls,
+ .num_controls = ARRAY_SIZE(mt8196_mt6681_controls),
+};
+
+static const struct mtk_soundcard_pdata mt8196_evb_card = {
+ .card_name = "mt8196_mt6681",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8196_mt6681_soc_card,
+ .num_jacks = MT8196_JACK_MAX,
+ },
+ .sof_priv = &mt8196_sof_priv,
+ .soc_probe = mt8196_mt6681_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8196_nau8825_card = {
+ .card_name = "mt8196_nau8825",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8196_mt6681_soc_card,
+ .num_jacks = MT8196_JACK_MAX,
+ .flags = NAU8825_HS_PRESENT
+ },
+ .sof_priv = &mt8196_sof_priv,
+ .soc_probe = mt8196_mt6681_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8196_rt5682s_card = {
+ .card_name = "mt8196_rt5682s",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8196_mt6681_soc_card,
+ .num_jacks = MT8196_JACK_MAX,
+ .flags = RT5682S_HS_PRESENT
+ },
+ .sof_priv = &mt8196_sof_priv,
+ .soc_probe = mt8196_mt6681_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8196_rt5650_card = {
+ .card_name = "mt8196_rt5650",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8196_mt6681_soc_card,
+ .num_jacks = MT8196_JACK_MAX,
+ .flags = RT5650_HS_PRESENT
+ },
+ .sof_priv = &mt8196_sof_priv,
+ .soc_probe = mt8196_mt6681_soc_card_probe,
+};
+
+static const struct of_device_id mt8196_mt6681_dt_match[] = {
+ {.compatible = "mediatek,mt8196-mt6681-sound", .data = &mt8196_evb_card,},
+ {.compatible = "mediatek,mt8196-nau8825-sound", .data = &mt8196_nau8825_card,},
+ {.compatible = "mediatek,mt8196-rt5682s-sound", .data = &mt8196_rt5682s_card,},
+ {.compatible = "mediatek,mt8196-rt5650-sound", .data = &mt8196_rt5650_card,},
+ {}
+};
+MODULE_DEVICE_TABLE(of, mt8196_mt6681_dt_match);
+
+static struct platform_driver mt8196_mt6681_driver = {
+ .driver = {
+ .name = "mt8196-mt6681",
+ .of_match_table = mt8196_mt6681_dt_match,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = mtk_soundcard_common_probe,
+};
+module_platform_driver(mt8196_mt6681_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8196 mt6681 ALSA SoC machine driver");
+MODULE_AUTHOR("Darren Ye <darren.ye@mediatek.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("mt8196 mt6681 soc card");
+
--
2.45.2
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 14/14] dt-bindings: mediatek: mt8196: add mt8196-mt6681 document
2025-03-07 12:47 [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
` (9 preceding siblings ...)
2025-03-07 12:47 ` [PATCH 13/14] ASoC: mediatek: mt8196: add machine driver with mt6681 Darren.Ye
@ 2025-03-07 12:47 ` Darren.Ye
2025-03-07 14:35 ` Rob Herring (Arm)
2025-03-07 15:19 ` Krzysztof Kozlowski
[not found] ` <20250307124841.23777-9-darren.ye@mediatek.com>
[not found] ` <20250307124841.23777-12-darren.ye@mediatek.com>
12 siblings, 2 replies; 27+ messages in thread
From: Darren.Ye @ 2025-03-07 12:47 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio, Darren Ye
From: Darren Ye <darren.ye@mediatek.com>
Add document for mt8196 board with mt6681.
Signed-off-by: Darren Ye <darren.ye@mediatek.com>
---
.../sound/mediatek,mt8196-mt6681.yaml | 122 ++++++++++++++++++
1 file changed, 122 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml
new file mode 100644
index 000000000000..b144ba748c23
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml
@@ -0,0 +1,122 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mt8196-mt6681.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT8196 ASoC sound card
+
+maintainers:
+ - Darren Ye <darren.ye@mediatek.com>
+
+allOf:
+ - $ref: sound-card-common.yaml#
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - mediatek,mt8196-mt6681-sound
+ - mediatek,mt8196-nau8825-sound
+ - mediatek,mt8196-rt5682s-sound
+ - mediatek,mt8196-rt5650-sound
+ - items:
+ - const: mediatek,mt8196-mt6681-sound
+ - const: mediatek,mt8196-nau8825-sound
+
+ audio-routing:
+ description:
+ Valid names could be the input or output widgets of audio components,
+ power supplies, MicBias of codec and the software switch.
+
+ mediatek,platform:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of MT8188 ASoC platform.
+
+ mediatek,adsp:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ The phandle of the MT8188 ADSP platform, which is the optional Audio DSP
+ hardware that provides additional audio functionalities if present.
+ The AFE will link to ADSP when the phandle is provided.
+
+patternProperties:
+ "^dai-link-[0-9]+$":
+ type: object
+ description:
+ Container for dai-link level properties and CODEC sub-nodes.
+
+ properties:
+ link-name:
+ description:
+ This property corresponds to the name of the BE dai-link to which
+ we are going to update parameters in this node.
+ items:
+ enum:
+ - TDM_DPTX_BE
+ - I2SOUT6_BE
+ - I2SIN6_BE
+ - I2SOUT4_BE
+ - I2SOUT3_BE
+
+ codec:
+ description: Holds subnode which indicates codec dai.
+ type: object
+ additionalProperties: false
+ properties:
+ sound-dai:
+ minItems: 1
+ maxItems: 2
+ required:
+ - sound-dai
+
+ dai-format:
+ description: audio format.
+ items:
+ enum:
+ - i2s
+ - right_j
+ - left_j
+ - dsp_a
+ - dsp_b
+
+ mediatek,clk-provider:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: Indicates dai-link clock master.
+ items:
+ enum:
+ - cpu
+ - codec
+
+ additionalProperties: false
+
+ required:
+ - link-name
+
+unevaluatedProperties: false
+
+required:
+ - compatible
+ - mediatek,platform
+
+examples:
+ - |
+ sound {
+ compatible = "mediatek,mt8196-mt6681-sound";
+ model = "mt8196-mt6681";
+ mediatek,platform = <&afe>;
+ audio-routing = "I2SOUT4", "I2SIN4_GPIO",
+ "I2SOUT4", "I2OUT4_GPIO",
+ "I2SOUT6", "I2SIN6_GPIO",
+ "I2SOUT6", "I2SOUT6_GPIO";
+
+ dai-link-0 {
+ link-name = "I2SOUT6_BE";
+ dai-format = "i2s";
+ mediatek,clk-provider = "cpu";
+ codec {
+ sound-dai = <&nau8825>;
+ };
+ };
+ };
+
--
2.45.2
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH 12/14] dt-bindings: mediatek: mt8196: add audio AFE document
2025-03-07 12:47 ` [PATCH 12/14] dt-bindings: mediatek: mt8196: add audio AFE document Darren.Ye
@ 2025-03-07 14:35 ` Rob Herring (Arm)
2025-03-07 15:15 ` Krzysztof Kozlowski
1 sibling, 0 replies; 27+ messages in thread
From: Rob Herring (Arm) @ 2025-03-07 14:35 UTC (permalink / raw)
To: Darren.Ye
Cc: Mark Brown, Jaroslav Kysela, Linus Walleij, Takashi Iwai,
devicetree, Conor Dooley, AngeloGioacchino Del Regno, linux-sound,
Liam Girdwood, linux-arm-kernel, Bartosz Golaszewski,
linux-kernel, Matthias Brugger, linux-mediatek, linux-gpio,
Krzysztof Kozlowski
On Fri, 07 Mar 2025 20:47:38 +0800, Darren.Ye wrote:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Add mt8196 audio AFE document.
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> ---
> .../bindings/sound/mediatek,mt8196-afe.yaml | 259 ++++++++++++++++++
> 1 file changed, 259 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.example.dts:24:18: fatal error: dt-bindings/clock/mt8196-clk.h: No such file or directory
24 | #include <dt-bindings/clock/mt8196-clk.h>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [scripts/Makefile.dtbs:131: Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.example.dtb] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1511: dt_binding_check] Error 2
make: *** [Makefile:251: __sub-make] Error 2
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250307124841.23777-13-darren.ye@mediatek.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 14/14] dt-bindings: mediatek: mt8196: add mt8196-mt6681 document
2025-03-07 12:47 ` [PATCH 14/14] dt-bindings: mediatek: mt8196: add mt8196-mt6681 document Darren.Ye
@ 2025-03-07 14:35 ` Rob Herring (Arm)
2025-03-07 15:19 ` Krzysztof Kozlowski
1 sibling, 0 replies; 27+ messages in thread
From: Rob Herring (Arm) @ 2025-03-07 14:35 UTC (permalink / raw)
To: Darren.Ye
Cc: Mark Brown, AngeloGioacchino Del Regno, Matthias Brugger,
linux-mediatek, Jaroslav Kysela, Liam Girdwood, Linus Walleij,
linux-kernel, linux-sound, Krzysztof Kozlowski, linux-arm-kernel,
Conor Dooley, linux-gpio, Bartosz Golaszewski, Takashi Iwai,
devicetree
On Fri, 07 Mar 2025 20:47:40 +0800, Darren.Ye wrote:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Add document for mt8196 board with mt6681.
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> ---
> .../sound/mediatek,mt8196-mt6681.yaml | 122 ++++++++++++++++++
> 1 file changed, 122 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250307124841.23777-15-darren.ye@mediatek.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 12/14] dt-bindings: mediatek: mt8196: add audio AFE document
2025-03-07 12:47 ` [PATCH 12/14] dt-bindings: mediatek: mt8196: add audio AFE document Darren.Ye
2025-03-07 14:35 ` Rob Herring (Arm)
@ 2025-03-07 15:15 ` Krzysztof Kozlowski
1 sibling, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2025-03-07 15:15 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
On 07/03/2025 13:47, Darren.Ye wrote:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Add mt8196 audio AFE document.
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
Please use subject prefixes matching the subsystem. You can get them for
example with `git log --oneline -- DIRECTORY_OR_FILE` on the directory
your patch is touching. For bindings, the preferred subjects are
explained here:
https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters
> ---
> .../bindings/sound/mediatek,mt8196-afe.yaml | 259 ++++++++++++++++++
> 1 file changed, 259 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
>
> diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
> new file mode 100644
> index 000000000000..59f8fdf3167c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
> @@ -0,0 +1,259 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/mediatek,mt8196-afe.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek Audio Front End PCM controller for MT8196
> +
> +maintainers:
> + - Darren Ye <darren.ye@mediatek.com>
> +
> +properties:
> + compatible:
> + const: mediatek,mt8196-afe-pcm
> +
> + reg:
> + maxItems: 1
> +
> + "#sound-dai-cells":
> + const: 0
> +
> + clocks:
> + items:
> + - description: audio hopping clock
> + - description: audio f26m clock
> + - description: audio ul0 adc clock
> + - description: audio ul0 adc hires clock
> + - description: audio ul1 adc clock
> + - description: audio ul1 adc hires clock
> + - description: audio apll1 clock
> + - description: audio apll2 clock
> + - description: audio apll tuner1 clock
> + - description: audio apll tuner2 clock
> + - description: vlp mux audio int
> + - description: vlp mux aud engen1
> + - description: vlp mux aud engen2
> + - description: vlp mux audio h
> + - description: vlp clock 26m
> + - description: ck mainpll d4 d4
> + - description: ck mux aud 1
> + - description: ck apll1
> + - description: ck mux aud 2
> + - description: ck apll2
> + - description: ck apll1 d4
> + - description: ck apll2 d4
> + - description: ck i2sin0 m sel
> + - description: ck i2sin1 m sel
> + - description: ck fmi2s m sel
> + - description: ck tdmout m sel
> + - description: ck apll12 div i2sin0
> + - description: ck apll12 div i2sin1
> + - description: ck apll12 div fmi2s
> + - description: ck apll12 div tdmout m
> + - description: ck apll12 div tdmout b
> + - description: ck adsp sel
> + - description: ck clock 26m
> +
> + clock-names:
> + items:
> + - const: aud_hopping_clk
Look how other bindings call it. s/_clk//
> + - const: aud_f26m_clk
> + - const: aud_ul0_adc_clk
> + - const: aud_ul0_adc_hires_clk
> + - const: aud_ul1_adc_clk
> + - const: aud_ul1_adc_hires_clk
> + - const: aud_apll1_clk
> + - const: aud_apll2_clk
> + - const: aud_apll_tuner1_clk
> + - const: aud_apll_tuner2_clk
> + - const: vlp_mux_audio_int
> + - const: vlp_mux_aud_eng1
> + - const: vlp_mux_aud_eng2
> + - const: vlp_mux_audio_h
> + - const: vlp_clk26m_clk
> + - const: ck_mainpll_d4_d4
What does ck stand for? You should name and explain the clocks based on
this block, not the source.
> + - const: ck_mux_aud_1
> + - const: ck_apll1_ck
> + - const: ck_mux_aud_2
> + - const: ck_apll2_ck
> + - const: ck_apll1_d4
> + - const: ck_apll2_d4
> + - const: ck_i2sin0_m_sel
> + - const: ck_i2sin1_m_sel
> + - const: ck_fmi2s_m_sel
> + - const: ck_tdmout_m_sel
> + - const: ck_apll12_div_i2sin0
> + - const: ck_apll12_div_i2sin1
> + - const: ck_apll12_div_fmi2s
> + - const: ck_apll12_div_tdmout_m
> + - const: ck_apll12_div_tdmout_b
> + - const: ck_adsp_sel
> + - const: ck_clk26m_clk
s/ck//
s/clk// and this goes probably first. Look at other bindings.
> +
> + interrupts:
> + maxItems: 1
> +
> + power-domains:
> + maxItems: 1
> +
> + cksys:
Again, open existing bindings.
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: Phandle to the cksys clock controller.
This tell me not much. Why do you need it?
Drop redundant 'Phandle to' and explain how it is used.
> +
> + vlpcksys:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: Phandle to the vlpcksys clock controller.
No, because you keep encoding clock information via non-clock API.
> +
> + memory-region:
> + $ref: /schemas/types.yaml#/definitions/phandle
Drop, see other bindings.
> + description: Phandle to the reserved memory region for AFE DMA.
> +
> + pinctrl-names:
Drop
> + items:
> + - const: default
> +
> + pinctrl-0:
Drop
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: Phandle to the pin control group for default state.
> +
> + mediatek,etdm-out-ch:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: Number of ETDM output channels.
> + enum: [2]
That's pointless.
> +
> + mediatek,etdm-in-ch:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: Number of ETDM input channels.
> + enum: [2]
> +
> + mediatek,etdm-out-sync:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: ETDM output synchronization.
> + enum: [0, 1]
> +
> + mediatek,etdm-in-sync:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: ETDM input synchronization.
> + enum: [0, 1]
> +
> + mediatek,etdm-ip-mode:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: ETDM IP mode.
> + enum: [0, 1]
Drop all above properties or explain why they make any sense in the
terms of board configuration.
> +
> +required:
> + - compatible
> + - reg
> + - clocks
> + - clock-names
> + - interrupts
> + - power-domains
> + - cksys
> + - vlpcksys
> + - memory-region
> + - pinctrl-names
> + - pinctrl-0
Why?
> + - mediatek,etdm-out-ch
> + - mediatek,etdm-in-ch
> + - mediatek,etdm-out-sync
> + - mediatek,etdm-in-sync
> + - mediatek,etdm-ip-mode
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/mt8196-clk.h>
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/interrupt-controller/irq.h>
> + #include <dt-bindings/power/mt8196-power.h>
> +
> + soc {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + afe: mt8196-afe-pcm@1a110000 {
Again... look at other bindings.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 14/14] dt-bindings: mediatek: mt8196: add mt8196-mt6681 document
2025-03-07 12:47 ` [PATCH 14/14] dt-bindings: mediatek: mt8196: add mt8196-mt6681 document Darren.Ye
2025-03-07 14:35 ` Rob Herring (Arm)
@ 2025-03-07 15:19 ` Krzysztof Kozlowski
1 sibling, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2025-03-07 15:19 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
On 07/03/2025 13:47, Darren.Ye wrote:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Add document for mt8196 board with mt6681.
Why do you add bindings after its users? Fix the order (see DT
submitting patches).
Please use subject prefixes matching the subsystem. You can get them for
example with `git log --oneline -- DIRECTORY_OR_FILE` on the directory
your patch is touching. For bindings, the preferred subjects are
explained here:
https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> ---
> .../sound/mediatek,mt8196-mt6681.yaml | 122 ++++++++++++++++++
> 1 file changed, 122 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml
>
> diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml
> new file mode 100644
> index 000000000000..b144ba748c23
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8196-mt6681.yaml
> @@ -0,0 +1,122 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/mediatek,mt8196-mt6681.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek MT8196 ASoC sound card
> +
> +maintainers:
> + - Darren Ye <darren.ye@mediatek.com>
> +
> +allOf:
> + - $ref: sound-card-common.yaml#
> +
> +properties:
> + compatible:
> + oneOf:
> + - enum:
> + - mediatek,mt8196-mt6681-sound
> + - mediatek,mt8196-nau8825-sound
> + - mediatek,mt8196-rt5682s-sound
> + - mediatek,mt8196-rt5650-sound
So this is not compatible with nau8825?
> + - items:
> + - const: mediatek,mt8196-mt6681-sound
This makes no sense. Either it is or it is not compatible with nau8825.
> + - const: mediatek,mt8196-nau8825-sound
> +
> + audio-routing:
> + description:
> + Valid names could be the input or output widgets of audio components,
> + power supplies, MicBias of codec and the software switch.
Drop property, not needed.
> +
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 01/14] ASoC: mediatek: common: modify mtk afe common driver for mt8196
2025-03-07 12:47 ` [PATCH 01/14] ASoC: mediatek: common: modify mtk afe common driver for mt8196 Darren.Ye
@ 2025-03-07 15:20 ` Krzysztof Kozlowski
2025-03-10 15:23 ` AngeloGioacchino Del Regno
1 sibling, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2025-03-07 15:20 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
On 07/03/2025 13:47, Darren.Ye wrote:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Export register read and write interface, add sample reate interface, and
> update the mtk_memif_set_channel interface for the mt8196 platform.
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> ---
> sound/soc/mediatek/common/mtk-afe-fe-dai.c | 30 ++++++++++++++--------
> sound/soc/mediatek/common/mtk-afe-fe-dai.h | 6 +++++
> sound/soc/mediatek/common/mtk-base-afe.h | 13 ++++++++++
> 3 files changed, 38 insertions(+), 11 deletions(-)
>
> diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
> index 3809068f5620..c36dae520f04 100644
> --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
> +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
> @@ -18,7 +18,7 @@
>
> #define AFE_BASE_END_OFFSET 8
>
> -static int mtk_regmap_update_bits(struct regmap *map, int reg,
> +int mtk_regmap_update_bits(struct regmap *map, int reg,
You need kerneldoc for all exported functions.
> unsigned int mask,
> unsigned int val, int shift)
> {
> @@ -26,13 +26,16 @@ static int mtk_regmap_update_bits(struct regmap *map, int reg,
> return 0;
> return regmap_update_bits(map, reg, mask << shift, val << shift);
> }
> +EXPORT_SYMBOL(mtk_regmap_update_bits);
GPL
> +
> +int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
>
Why blank line?
> -static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
Missing kerneldoc
> {
> if (reg < 0)
> return 0;
> return regmap_write(map, reg, val);
> }
> +EXPORT_SYMBOL(mtk_regmap_write);
GPL
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 02/14] ASoC: mediatek: common: modify mtk afe platform driver for mt8196
2025-03-07 12:47 ` [PATCH 02/14] ASoC: mediatek: common: modify mtk afe platform " Darren.Ye
@ 2025-03-07 15:21 ` Krzysztof Kozlowski
0 siblings, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2025-03-07 15:21 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
On 07/03/2025 13:47, Darren.Ye wrote:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Mofify the pcm pointer interface to support 64-bit address access.
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> ---
> .../mediatek/common/mtk-afe-platform-driver.c | 63 ++++++++++++++-----
> .../mediatek/common/mtk-afe-platform-driver.h | 5 ++
> 2 files changed, 52 insertions(+), 16 deletions(-)
>
> diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
> index 6b6330583941..5d8f4421e665 100644
> --- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c
> +++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
> @@ -77,6 +77,16 @@ int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
> }
> EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control);
>
> +int mtk_afe_pcm_open(struct snd_soc_component *component,
How adding this is related with 64-bit addresses? It's not even used here.
> + struct snd_pcm_substream *substream)
> +{
> + /* set the wait_for_avail to 2 sec*/
> + substream->wait_time = msecs_to_jiffies(2 * 1000);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(mtk_afe_pcm_open);
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 04/14] ASoC: mediatek: mt8196: add common interface for mt8196 DAI driver
2025-03-07 12:47 ` [PATCH 04/14] ASoC: mediatek: mt8196: add common interface for mt8196 DAI driver Darren.Ye
@ 2025-03-07 15:22 ` Krzysztof Kozlowski
2025-03-10 15:23 ` AngeloGioacchino Del Regno
1 sibling, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2025-03-07 15:22 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
On 07/03/2025 13:47, Darren.Ye wrote:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Implement sample rate conversion and set private data for mt8196.
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> ---
> .../soc/mediatek/mt8196/mt8196-afe-control.c | 109 ++++++++++++++++++
> 1 file changed, 109 insertions(+)
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-control.c
>
> diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-control.c b/sound/soc/mediatek/mt8196/mt8196-afe-control.c
> new file mode 100644
> index 000000000000..bb85f4ad8585
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8196/mt8196-afe-control.c
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * MediaTek ALSA SoC Audio Control
> + *
> + * Copyright (c) 2024 MediaTek Inc.
> + * Author: Darren Ye <darren.ye@mediatek.com>
> + */
> +
> +#include "mt8196-afe-common.h"
> +#include <linux/pm_runtime.h>
> +
> +unsigned int mt8196_general_rate_transform(struct device *dev,
> + unsigned int rate)
These are not static, so you miss header for all of these changes.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 08/14] ASoC: mediatek: mt8196: support I2S in platform driver
[not found] ` <20250307124841.23777-9-darren.ye@mediatek.com>
@ 2025-03-07 15:24 ` Krzysztof Kozlowski
0 siblings, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2025-03-07 15:24 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
On 07/03/2025 13:47, Darren.Ye wrote:
> +
> +static int etdm_parse_dt(struct mtk_base_afe *afe)
> +{
> + int ret;
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + struct mtk_afe_i2s_priv *i2sin4_priv = afe_priv->dai_priv[MT8196_DAI_I2S_IN4];
> + struct mtk_afe_i2s_priv *i2sout4_priv = afe_priv->dai_priv[MT8196_DAI_I2S_OUT4];
> + unsigned int ch_num_in;
> + unsigned int ch_num_out;
> + unsigned int sync_in;
> + unsigned int sync_out;
> + unsigned int ip_mode;
> +
> + /* get etdm ch */
> + ret = of_property_read_u32(afe->dev->of_node, "mediatek,etdm-out-ch", &ch_num_out);
> + if (ret) {
> + dev_info(afe->dev, "%s() failed to read mediatek,etdm-out-ch\n", __func__);
> + return -EINVAL;
> + }
> + i2sout4_priv->ch_num = ch_num_out;
> + dev_dbg(afe->dev, "%s() mediatek,etdm-out-ch: %d\n", __func__, ch_num_out);
> +
> + ret = of_property_read_u32(afe->dev->of_node, "mediatek,etdm-in-ch", &ch_num_in);
> + if (ret) {
> + dev_info(afe->dev, "%s() failed to read mediatek,etdm-in-ch\n", __func__);
> + return -EINVAL;
> + }
> + i2sin4_priv->ch_num = ch_num_in;
> + dev_dbg(afe->dev, "%s() mediatek,etdm-in-ch: %d\n", __func__, ch_num_in);
> +
> + /* get etdm sync */
> + ret = of_property_read_u32(afe->dev->of_node, "mediatek,etdm-out-sync", &sync_out);
> + if (ret) {
> + dev_info(afe->dev, "%s() failed to read mediatek,etdm-out-sync\n", __func__);
> + return -EINVAL;
> + }
> + i2sout4_priv->sync = sync_out;
> + dev_dbg(afe->dev, "%s() mediatek,etdm-out-sync: %d\n", __func__, sync_out);
> +
> + ret = of_property_read_u32(afe->dev->of_node, "mediatek,etdm-in-sync", &sync_in);
> + if (ret) {
> + dev_info(afe->dev, "%s() failed to read mediatek,etdm-in-sync\n", __func__);
> + return -EINVAL;
> + }
> + i2sin4_priv->sync = sync_in;
> + dev_dbg(afe->dev, "%s() mediatek,etdm-in-sync: %d\n", __func__, sync_in);
> +
> + /* get etdm ip mode */
> + ret = of_property_read_u32(afe->dev->of_node, "mediatek,etdm-ip-mode", &ip_mode);
> + if (ret) {
> + dev_info(afe->dev, "%s() failed to read mediatek,etdm-ip-mode\n", __func__);
> + return -EINVAL;
> + }
> + i2sin4_priv->ip_mode = ip_mode;
> + dev_dbg(afe->dev, "%s() mediatek,etdm-ip-mode: %d\n", __func__, ip_mode);
> +
> + return 0;
> +}
> +
> +static int mt8196_dai_i2s_get_share(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + const struct device_node *of_node = afe->dev->of_node;
> + const char *of_str;
> + const char *property_name;
> + struct mtk_afe_i2s_priv *i2s_priv;
> + int i;
> +
> + for (i = 0; i < DAI_I2S_NUM; i++) {
> + i2s_priv = afe_priv->dai_priv[mt8196_i2s_priv[i].id];
> + property_name = mt8196_i2s_priv[i].share_property_name;
> + if (of_property_read_string(of_node, property_name, &of_str))
> + continue;
> + i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str);
> + }
> + return 0;
> +}
> +
> +static int mt8196_dai_i2s_set_priv(struct mtk_base_afe *afe)
> +{
> + int i;
> + int ret;
> +
> + for (i = 0; i < DAI_I2S_NUM; i++) {
> + ret = mt8196_dai_set_priv(afe, mt8196_i2s_priv[i].id,
> + sizeof(struct mtk_afe_i2s_priv),
> + &mt8196_i2s_priv[i]);
> + if (ret)
> + return ret;
> + }
> + return 0;
> +}
> +
> +int mt8196_dai_i2s_register(struct mtk_base_afe *afe)
> +{
> + struct mtk_base_afe_dai *dai;
> + int ret;
> +
> + dev_dbg(afe->dev, "%s() successfully start\n", __func__);
Well, no. Tracing is for debugging entry/exit of functions. Say
something useful or just drop such entry/exist success messages.
> +
> + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
> + if (!dai)
> + return -ENOMEM;
> +
> + list_add(&dai->list, &afe->sub_dais);
> +
> + dai->dai_drivers = mtk_dai_i2s_driver;
> + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver);
> +
> + dai->controls = mtk_dai_i2s_controls;
> + dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls);
> + dai->dapm_widgets = mtk_dai_i2s_widgets;
> + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets);
> + dai->dapm_routes = mtk_dai_i2s_routes;
> + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes);
> +
> + /* set all dai i2s private data */
> + ret = mt8196_dai_i2s_set_priv(afe);
> + if (ret)
> + return ret;
> +
> + /* parse share i2s */
> + ret = mt8196_dai_i2s_get_share(afe);
> + if (ret)
> + return ret;
> +
> + /* for customer to change ch_num & sync & ipmode from dts */
> + ret = etdm_parse_dt(afe);
> + if (ret) {
> + dev_info(afe->dev, "%s() fail to parse dts: %d\n", __func__, ret);
Why do you print errors twice?
> + return ret;
> + }
> +
> + return 0;
> +}
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 05/14] ASoC: mediatek: mt8196: support audio clock control
2025-03-07 12:47 ` [PATCH 05/14] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
@ 2025-03-07 15:32 ` Krzysztof Kozlowski
2025-03-10 15:23 ` AngeloGioacchino Del Regno
1 sibling, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2025-03-07 15:32 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
On 07/03/2025 13:47, Darren.Ye wrote:
> +
> +int mt8196_init_clock(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int i = 0;
> +
> + afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk),
> + GFP_KERNEL);
> + if (!afe_priv->clk)
> + return -ENOMEM;
> +
> + for (i = 0; i < CLK_NUM; i++) {
> + if (!aud_clks[i]) {
> + dev_err(afe->dev, "%s(), clk id %d not define!!!\n",
> + __func__, 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__,
dev_err_probe() and drop __func__ and ret.
> + aud_clks[i], PTR_ERR(afe_priv->clk[i]));
> + afe_priv->clk[i] = NULL;
> + }
> + }
> +
> + afe_priv->vlp_ck = syscon_regmap_lookup_by_phandle(afe->dev->of_node,
> + "vlpcksys");
> + if (IS_ERR(afe_priv->vlp_ck)) {
> + dev_err(afe->dev, "%s() Cannot find vlpcksys: %ld\n",
> + __func__, PTR_ERR(afe_priv->vlp_ck));
> + afe_priv->vlp_ck = NULL;
> + }
> +
> + afe_priv->cksys_ck = syscon_regmap_lookup_by_phandle(afe->dev->of_node,
> + "cksys");
> + if (IS_ERR(afe_priv->cksys_ck)) {
> + dev_err(afe->dev, "%s() Cannot find cksys controller: %ld\n",
> + __func__, PTR_ERR(afe_priv->cksys_ck));
Eeach of my comments apply to entier code to all patches. You keep
repeating same patterns from downstream. You should rather take upstream
drivers as your base.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 11/14] ASoC: mediatek: mt8196: add platform driver
[not found] ` <20250307124841.23777-12-darren.ye@mediatek.com>
@ 2025-03-07 15:32 ` Krzysztof Kozlowski
0 siblings, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2025-03-07 15:32 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
On 07/03/2025 13:47, Darren.Ye wrote:
> +
> +static int mt8196_afe_runtime_suspend(struct device *dev)
> +{
> + struct mtk_base_afe *afe = dev_get_drvdata(dev);
> + unsigned int value = 0;
> + unsigned int tmp_reg = 0;
> + int ret = 0, i;
> +
> + dev_dbg(afe->dev, "%s() ready to stop\n", __func__);
Core already provides this. Drop.
> +
> + if (!afe->regmap) {
> + dev_info(afe->dev, "%s() skip regmap\n", __func__);
> + goto skip_regmap;
> + }
> +
> + /* Add to be off for free run*/
> + /* disable AFE */
> + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, 0x1, 0x0);
> +
> + ret = regmap_read_poll_timeout(afe->regmap,
> + AUDIO_ENGEN_CON0_MON,
> + value,
> + (value & AUDIO_ENGEN_MON_SFT) == 0,
> + 20,
> + 1 * 1000 * 1000);
> + dev_dbg(afe->dev, "%s() read_poll ret %d\n", __func__, ret);
> + if (ret)
> + dev_info(afe->dev, "%s(), ret %d\n", __func__, ret);
> +
> + /* make sure all irq status are cleared */
> + for (i = 0; i < MT8196_IRQ_NUM; ++i) {
> + regmap_read(afe->regmap, irq_data[i].irq_clr_reg, &tmp_reg);
> + regmap_update_bits(afe->regmap, irq_data[i].irq_clr_reg,
> + AFE_IRQ_CLR_CFG_MASK_SFT | AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT,
> + tmp_reg ^ (AFE_IRQ_CLR_CFG_MASK_SFT |
> + AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT));
> + }
> +
> + /* reset sgen */
> + regmap_write(afe->regmap, AFE_SINEGEN_CON0, 0x0);
> + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON1,
> + SINE_DOMAIN_MASK_SFT,
> + 0x0 << SINE_DOMAIN_SFT);
> + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON1,
> + SINE_MODE_MASK_SFT,
> + 0x0 << SINE_MODE_SFT);
> + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON1,
> + INNER_LOOP_BACKI_SEL_MASK_SFT,
> + 0x0 << INNER_LOOP_BACKI_SEL_SFT);
> + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON1,
> + INNER_LOOP_BACK_MODE_MASK_SFT,
> + 0xff << INNER_LOOP_BACK_MODE_SFT);
> +
> + regmap_write(afe->regmap, AUDIO_TOP_CON4, 0x3fff);
> +
> + /* reset audio 26M request */
> + regmap_update_bits(afe->regmap,
> + AFE_SPM_CONTROL_REQ, 0x1, 0x0);
> +
> + /* cache only */
> + regcache_cache_only(afe->regmap, true);
> + regcache_mark_dirty(afe->regmap);
> +
> +skip_regmap:
> + mt8196_afe_disable_clock(afe);
> + return 0;
> +}
> +
> +static int mt8196_afe_runtime_resume(struct device *dev)
> +{
> + struct mtk_base_afe *afe = dev_get_drvdata(dev);
> + int ret = 0;
> +
> + ret = mt8196_afe_enable_clock(afe);
> + dev_dbg(afe->dev, "%s(), enable_clock ret %d\n", __func__, ret);
So you are debugging every call. I think you do not trust your code, right?
> +
> + if (ret)
> + return ret;
> +
> + if (!afe->regmap) {
> + dev_info(afe->dev, "%s() skip regmap\n", __func__);
Why dev_info? How is this condition even possible?
> + goto skip_regmap;
> + }
> + regcache_cache_only(afe->regmap, false);
> + regcache_sync(afe->regmap);
> +
> + /* set audio 26M request */
> + regmap_update_bits(afe->regmap, AFE_SPM_CONTROL_REQ, 0x1, 0x1);
> +
> + /* IPM2.0: Clear AUDIO_TOP_CON4 for enabling AP side module clk */
> + regmap_write(afe->regmap, AUDIO_TOP_CON4, 0x0);
> +
> + /* Add to be on for free run */
> + regmap_write(afe->regmap, AUDIO_TOP_CON0, 0x0);
> + regmap_write(afe->regmap, AUDIO_TOP_CON1, 0x0);
> + regmap_write(afe->regmap, AUDIO_TOP_CON2, 0x0);
> +
> + /* Can't set AUDIO_TOP_CON3 to be 0x0, it will hang in FPGA env */
> + regmap_write(afe->regmap, AUDIO_TOP_CON3, 0x0);
> +
> + regmap_update_bits(afe->regmap, AFE_CBIP_CFG0, 0x1, 0x1);
> +
> + /* force cpu use 8_24 format when writing 32bit data */
> + regmap_update_bits(afe->regmap, AFE_MEMIF_CON0,
> + CPU_HD_ALIGN_MASK_SFT, 0 << CPU_HD_ALIGN_SFT);
> +
> + /* enable AFE */
> + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, 0x1, 0x1);
> +
> +skip_regmap:
> + return 0;
...
> +
> +typedef int (*dai_register_cb)(struct mtk_base_afe *);
> +static const dai_register_cb dai_register_cbs[] = {
> + mt8196_dai_adda_register,
> + mt8196_dai_i2s_register,
> + mt8196_dai_tdm_register,
> + mt8196_dai_memif_register,
> +};
> +
> +static int mt8196_afe_pcm_dev_probe(struct platform_device *pdev)
> +{
> + int ret, i;
> + unsigned int tmp_reg = 0;
> + int irq_id;
> + struct mtk_base_afe *afe;
> + struct mt8196_afe_private *afe_priv;
> + struct resource *res;
> + struct device *dev;
> +
> + pr_info("+%s()\n", __func__);
No, drop.
> +
> + ret = of_reserved_mem_device_init(&pdev->dev);
> + if (ret)
> + dev_dbg(&pdev->dev, "failed to assign memory region: %d\n", ret);
> +
> + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
> + if (ret)
> + return ret;
> +
> + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
> + if (!afe)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, afe);
> +
> + afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
> + GFP_KERNEL);
> + if (!afe->platform_priv)
> + return -ENOMEM;
> +
> + afe_priv = afe->platform_priv;
> +
> + afe->dev = &pdev->dev;
> + dev = afe->dev;
> +
> + /* init audio related clock */
> + ret = mt8196_init_clock(afe);
> + if (ret) {
> + dev_info(dev, "init clock error: %d\n", ret);
How are you handling deferred probe? Why aren't you using dev_err_probe?
But more important - why do you keep printing errors multiple times,
including ENOMEM?
This is really poor coding style.
> + return ret;
> + }
> +
> + pm_runtime_enable(&pdev->dev);
> + if (!pm_runtime_enabled(&pdev->dev))
> + goto err_pm_disable;
> +
> + /* Audio device is part of genpd.
> + * Set audio as syscore device to prevent
> + * genpd automatically power off audio
> + * device when suspend
> + */
> + dev_pm_syscore_device(&pdev->dev, true);
> +
> + /* regmap init */
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> + afe->base_addr = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(afe->base_addr))
> + return PTR_ERR(afe->base_addr);
> +
> + /* enable clock for regcache get default value from hw */
> + pm_runtime_get_sync(&pdev->dev);
> +
> + afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
> + &mt8196_afe_regmap_config);
> + if (IS_ERR(afe->regmap))
> + return PTR_ERR(afe->regmap);
> +
> + /* IPM2.0 clock flow, need debug */
> +
> + regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &tmp_reg);
> + regmap_write(afe->regmap, AFE_IRQ_MCU_EN, 0xffffffff);
> + regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &tmp_reg);
> + /* IPM2.0 clock flow, need debug */
> +
> + pm_runtime_put_sync(&pdev->dev);
> +
> + regcache_cache_only(afe->regmap, true);
> + regcache_mark_dirty(afe->regmap);
> +
> + /* init gpio */
> + ret = mt8196_afe_gpio_init(afe);
> + if (ret)
> + dev_info(dev, "init gpio error\n");
Do not print errors twice.
> +
> + /* init memif */
> + /* IPM2.0 no need banding */
> + afe->memif_32bit_supported = 1;
> + afe->memif_size = MT8196_MEMIF_NUM;
> + afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
> + GFP_KERNEL);
> +
> + if (!afe->memif)
> + return -ENOMEM;
> +
> + for (i = 0; i < afe->memif_size; i++) {
> + afe->memif[i].data = &memif_data[i];
> + afe->memif[i].irq_usage = memif_irq_usage[i];
> + afe->memif[i].const_irq = 1;
> + }
> +
> + mutex_init(&afe->irq_alloc_lock); /* needed when dynamic irq */
> +
> + /* init irq */
> + afe->irqs_size = MT8196_IRQ_NUM;
> + afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
> + GFP_KERNEL);
> +
Drop blank line
> + if (!afe->irqs)
> + return -ENOMEM;
> +
> + for (i = 0; i < afe->irqs_size; i++)
> + afe->irqs[i].irq_data = &irq_data[i];
> +
> + /* request irq */
> + irq_id = platform_get_irq(pdev, 0);
> + if (irq_id <= 0) {
Please read documentation of platform_get_irq().
> + dev_info(dev, "%pOFn no irq found\n", dev->of_node);
Why dev_info?
> + return irq_id < 0 ? irq_id : -ENXIO;
> + }
> + ret = devm_request_irq(dev, irq_id, mt8196_afe_irq_handler,
> + IRQF_TRIGGER_NONE,
> + "Afe_ISR_Handle", (void *)afe);
> + if (ret) {
> + dev_info(dev, "could not request_irq for Afe_ISR_Handle\n");
> + return ret;
> + }
> + ret = enable_irq_wake(irq_id);
> + if (ret < 0)
> + dev_info(dev, "enable_irq_wake %d err: %d\n", irq_id, ret);
> +
> + /* init sub_dais */
> + INIT_LIST_HEAD(&afe->sub_dais);
> +
> + for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
> + ret = dai_register_cbs[i](afe);
> + if (ret) {
> + dev_info(afe->dev, "dai register i %d fail, ret %d\n",
> + i, ret);
> + goto err_pm_disable;
> + }
> + }
> +
> + /* init dai_driver and component_driver */
> + ret = mtk_afe_combine_sub_dai(afe);
> + if (ret) {
> + dev_info(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
> + ret);
> + goto err_pm_disable;
> + }
> +
> + /* others */
> + afe->mtk_afe_hardware = &mt8196_afe_hardware;
> + afe->memif_fs = mt8196_memif_fs;
> + afe->irq_fs = mt8196_irq_fs;
> + afe->get_dai_fs = mt8196_get_dai_fs;
> + afe->get_memif_pbuf_size = mt8196_get_memif_pbuf_size;
> +
> + afe->runtime_resume = mt8196_afe_runtime_resume;
> + afe->runtime_suspend = mt8196_afe_runtime_suspend;
> +
> + afe->request_dram_resource = mt8196_afe_dram_request;
> + afe->release_dram_resource = mt8196_afe_dram_release;
> +
> + /* register component */
> + ret = devm_snd_soc_register_component(&pdev->dev,
> + &mt8196_afe_component,
> + afe->dai_drivers,
> + afe->num_dai_drivers);
> + if (ret) {
> + dev_info(dev, "afe component err: %d\n", ret);
Why not dev_err? You have this unusual pattern all over your code.
> + goto err_pm_disable;
> + }
> + return 0;
> +
> +err_pm_disable:
> + pm_runtime_disable(&pdev->dev);
> + return ret;
> +}
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 10/14] ASoC: mediatek: mt8196: support CM in platform driver
2025-03-07 12:47 ` [PATCH 10/14] ASoC: mediatek: mt8196: support CM " Darren.Ye
@ 2025-03-07 15:33 ` Krzysztof Kozlowski
0 siblings, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2025-03-07 15:33 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Jaroslav Kysela, Takashi Iwai,
Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
On 07/03/2025 13:47, Darren.Ye wrote:
> +int mt8196_enable_cm_bypass(struct mtk_base_afe *afe, int id, bool en)
> +{
> + int reg = AFE_CM0_CON0 + 0x10 * id;
> +
> + mtk_regmap_update_bits(afe->regmap, reg, AFE_CM_BYPASS_MODE_MASK,
> + en, AFE_CM_BYPASS_MODE_SFT);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(mt8196_enable_cm_bypass);
> +
> +MODULE_DESCRIPTION("Mediatek afe cm");
> +MODULE_AUTHOR("darren ye <darren.ye@mediatek.com>");
> +MODULE_LICENSE("GPL");
If this is module, where is Makefile and Kconfig?
All previous comments about missing kerneldoc also apply.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 05/14] ASoC: mediatek: mt8196: support audio clock control
2025-03-07 12:47 ` [PATCH 05/14] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
2025-03-07 15:32 ` Krzysztof Kozlowski
@ 2025-03-10 15:23 ` AngeloGioacchino Del Regno
1 sibling, 0 replies; 27+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-03-10 15:23 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
Il 07/03/25 13:47, Darren.Ye ha scritto:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Add audio clock wrapper and audio tuner control.
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> ---
> sound/soc/mediatek/mt8196/mt8196-afe-clk.c | 698 +++++++++++++++++++++
> sound/soc/mediatek/mt8196/mt8196-afe-clk.h | 313 +++++++++
> 2 files changed, 1011 insertions(+)
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.h
>
> diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.c b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> new file mode 100644
> index 000000000000..d1407d7bf775
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> @@ -0,0 +1,698 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * mt8196-afe-clk.c -- Mediatek 8196 afe clock ctrl
> + *
> + * Copyright (c) 2024 MediaTek Inc.
> + * Author: Darren Ye <darren.ye@mediatek.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +#include "mt8196-afe-common.h"
> +#include "mt8196-afe-clk.h"
> +
> +static DEFINE_MUTEX(mutex_request_dram);
> +
> +static const char *aud_clks[CLK_NUM] = {
> + [CLK_HOPPING] = "aud_hopping_clk",
> + [CLK_F26M] = "aud_f26m_clk",
> + [CLK_UL0_ADC_CLK] = "aud_ul0_adc_clk",
> + [CLK_UL0_ADC_HIRES_CLK] = "aud_ul0_adc_hires_clk",
> + [CLK_UL1_ADC_CLK] = "aud_ul1_adc_clk",
> + [CLK_UL1_ADC_HIRES_CLK] = "aud_ul1_adc_hires_clk",
> + [CLK_APLL1] = "aud_apll1_clk",
> + [CLK_APLL2] = "aud_apll2_clk",
> + [CLK_APLL1_TUNER] = "aud_apll_tuner1_clk",
> + [CLK_APLL2_TUNER] = "aud_apll_tuner2_clk",
> + [CLK_VLP_MUX_AUDIOINTBUS] = "vlp_mux_audio_int",
> + [CLK_VLP_MUX_AUD_ENG1] = "vlp_mux_aud_eng1",
> + [CLK_VLP_MUX_AUD_ENG2] = "vlp_mux_aud_eng2",
> + [CLK_VLP_MUX_AUDIO_H] = "vlp_mux_audio_h",
> + [CLK_VLP_CLK26M] = "vlp_clk26m_clk",
> + [CLK_CK_MAINPLL_D4_D4] = "ck_mainpll_d4_d4",
> + [CLK_CK_MUX_AUD_1] = "ck_mux_aud_1",
> + [CLK_CK_APLL1_CK] = "ck_apll1_ck",
> + [CLK_CK_MUX_AUD_2] = "ck_mux_aud_2",
> + [CLK_CK_APLL2_CK] = "ck_apll2_ck",
> + [CLK_CK_APLL1_D4] = "ck_apll1_d4",
> + [CLK_CK_APLL2_D4] = "ck_apll2_d4",
> + [CLK_CK_I2SIN0_M_SEL] = "ck_i2sin0_m_sel",
> + [CLK_CK_I2SIN1_M_SEL] = "ck_i2sin1_m_sel",
> + [CLK_CK_FMI2S_M_SEL] = "ck_fmi2s_m_sel",
> + [CLK_CK_TDMOUT_M_SEL] = "ck_tdmout_m_sel",
> + [CLK_CK_APLL12_DIV_I2SIN0] = "ck_apll12_div_i2sin0",
> + [CLK_CK_APLL12_DIV_I2SIN1] = "ck_apll12_div_i2sin1",
> + [CLK_CK_APLL12_DIV_FMI2S] = "ck_apll12_div_fmi2s",
> + [CLK_CK_APLL12_DIV_TDMOUT_M] = "ck_apll12_div_tdmout_m",
> + [CLK_CK_APLL12_DIV_TDMOUT_B] = "ck_apll12_div_tdmout_b",
> + [CLK_CK_ADSP_SEL] = "ck_adsp_sel",
> + [CLK_CLK26M] = "ck_clk26m_clk",
> +};
> +
> +int mt8196_set_audio_int_bus_parent(struct mtk_base_afe *afe,
> + int clk_id, bool int_bus)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + struct clk *clk;
> + int ret;
> +
> + if (clk_id >= CLK_NUM || clk_id < 0)
> + return -EINVAL;
> +
> + clk = int_bus ? afe_priv->clk[CLK_VLP_MUX_AUDIOINTBUS] :
> + afe_priv->clk[CLK_VLP_MUX_AUDIO_H];
> + ret = clk_set_parent(clk, afe_priv->clk[clk_id]);
> + if (ret)
> + dev_err(afe->dev, "%s() clk_set_parent %s fail %d, int_bus %d\n",
> + __func__, aud_clks[clk_id], ret, int_bus);
if (ret) {
dev_err....
return ret;
}
return 0;
> +
> + return ret;
> +}
> +
..snip..
> +
> +int mt8196_afe_disable_apll(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int ret = 0;
> +
> + dev_dbg(afe->dev, "%s() successfully start\n", __func__);
> +
> + ret = clk_prepare_enable(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]);
> + if (ret) {
> + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
> + __func__, aud_clks[CLK_VLP_MUX_AUDIO_H], ret);
> + goto EXIT;
You don't need the goto here.
Just return ret.
> + }
> +
> + ret = clk_prepare_enable(afe_priv->clk[CLK_CK_MUX_AUD_1]);
> + if (ret) {
> + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
> + __func__, aud_clks[CLK_CK_MUX_AUD_1], ret);
> + goto EXIT;
Here you do need the goto, but that's to revert the changes that you've done
with the previous clk_prepare_enable() call.
> + }
> +
> + ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_1],
> + afe_priv->clk[CLK_CLK26M]);
> + if (ret) {
> + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
> + __func__, aud_clks[CLK_CK_MUX_AUD_1],
> + aud_clks[CLK_CLK26M], ret);
> + goto EXIT;
> + }
> + ret = clk_prepare_enable(afe_priv->clk[CLK_CK_MUX_AUD_2]);
> + if (ret) {
> + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
> + __func__, aud_clks[CLK_CK_MUX_AUD_2], ret);
> + goto EXIT;
> + }
> +
> + ret = clk_set_parent(afe_priv->clk[CLK_CK_MUX_AUD_2],
> + afe_priv->clk[CLK_CLK26M]);
> + if (ret) {
> + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
> + __func__, aud_clks[CLK_CK_MUX_AUD_2],
> + aud_clks[CLK_CLK26M], ret);
> + goto EXIT;
> + }
> +
> + clk_disable_unprepare(afe_priv->clk[CLK_CK_MUX_AUD_1]);
> + clk_disable_unprepare(afe_priv->clk[CLK_CK_MUX_AUD_2]);
> + mt8196_set_audio_int_bus_parent(afe, CLK_VLP_CLK26M, false);
> + clk_disable_unprepare(afe_priv->clk[CLK_VLP_MUX_AUDIO_H]);
> +
> + return 0;
> +EXIT:
lower case please.
> + return ret;
> +}
> +
> +static int mt8196_afe_apll_init(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
> + /* VLP_APLL1_CON0 = 0x6f28bd4c
> + * VLP_APLL2_CON2 = 0x78FD5264
> + * VLP_APLL1_TUNER_CON0 = 0x6f28bd4d
> + * VLP_APLL2_TUNER_CON0 = 0x78fd5265
> + */
> + if (afe_priv->vlp_ck) {
> + regmap_write(afe_priv->vlp_ck, VLP_APLL1_TUNER_CON0, 0x6f28bd4d);
> + regmap_write(afe_priv->vlp_ck, VLP_APLL2_TUNER_CON0, 0x78fd5265);
No magic numbers please.
> + } else {
> + dev_warn(afe->dev, "%s vlp_ck regmap is null ptr\n", __func__);
> + }
> + return 0;
> +}
> +
..snip..
> +int mt8196_apll1_enable(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int ret;
> +
> + /* setting for APLL */
> + apll1_mux_setting(afe, true);
> +
> + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1]);
> + if (ret) {
> + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
> + __func__, aud_clks[CLK_APLL1], ret);
> + goto ERR_CLK_APLL1;
> + }
> +
> + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1_TUNER]);
> + if (ret) {
> + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
> + __func__, aud_clks[CLK_APLL1_TUNER], ret);
> + goto ERR_CLK_APLL1_TUNER;
> + }
> +
> + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
> + 0x0000FFF7, 0x00000372);
No magic numbers please.
> + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1);
> +
> + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0,
> + AUDIO_APLL1_EN_ON_MASK_SFT,
> + 0x1 << AUDIO_APLL1_EN_ON_SFT);
> + return 0;
> +
> +ERR_CLK_APLL1_TUNER:
> + clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]);
> +ERR_CLK_APLL1:
> + clk_disable_unprepare(afe_priv->clk[CLK_APLL1]);
> +
> + return ret;
> +}
> +
> +void mt8196_apll1_disable(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
> + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0,
> + AUDIO_APLL1_EN_ON_MASK_SFT,
> + 0x0 << AUDIO_APLL1_EN_ON_SFT);
0 << (anything) is ... zero. Just write 0.
> +
> + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x0);
That 0x1 is a mask for a bit
#define SOMETHING BIT(0)
regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, SOMETHING, 0);
> +
> + clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]);
> + clk_disable_unprepare(afe_priv->clk[CLK_APLL1]);
> +
> + apll1_mux_setting(afe, false);
> +}
> +
> +int mt8196_apll2_enable(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int ret;
> +
> + /* setting for APLL */
> + apll2_mux_setting(afe, true);
> +
> + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2]);
> + if (ret) {
> + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
> + __func__, aud_clks[CLK_APLL2], ret);
> + goto ERR_CLK_APLL2;
> + }
> +
> + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2_TUNER]);
> + if (ret) {
> + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
> + __func__, aud_clks[CLK_APLL2_TUNER], ret);
> + goto ERR_CLK_APLL2_TUNER;
> + }
> +
> + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
> + 0x0000FFF7, 0x00000374);
> + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1);
> +
> + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0,
> + AUDIO_APLL2_EN_ON_MASK_SFT,
> + 0x1 << AUDIO_APLL2_EN_ON_SFT);
> +
> + return 0;
> +
> +ERR_CLK_APLL2_TUNER:
> + clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]);
> +ERR_CLK_APLL2:
> + clk_disable_unprepare(afe_priv->clk[CLK_APLL2]);
> +
> + return ret;
> +
> + return 0;
> +}
> +
> +void mt8196_apll2_disable(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
> + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0,
> + AUDIO_APLL2_EN_ON_MASK_SFT,
> + 0x0 << AUDIO_APLL2_EN_ON_SFT);
> +
> + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x0);
> +
> + clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]);
> + clk_disable_unprepare(afe_priv->clk[CLK_APLL2]);
> +
> + apll2_mux_setting(afe, false);
> +}
> +
> +int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll)
> +{
> + return (apll == MT8196_APLL1) ? 180633600 : 196608000;
If those are PLLs for real (and they are), you should read the rate from the actual
PLL, instead of just ignoring everything and pretending that the rate is either
X or Y.
> +}
> +
> +int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
> +{
> + return ((rate % 8000) == 0) ? MT8196_APLL2 : MT8196_APLL1;
> +}
> +
> +int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
> +{
> + if (strcmp(name, APLL1_W_NAME) == 0)
> + return MT8196_APLL1;
> + else
> + return MT8196_APLL2;
> +}
> +
..snip..
> diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.h b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
> new file mode 100644
> index 000000000000..0094aebc8bba
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
> @@ -0,0 +1,313 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * mt8196-afe-clk.h -- Mediatek 8196 afe clock ctrl definition
> + *
> + * Copyright (c) 2024 MediaTek Inc.
> + * Author: Darren Ye <darren.ye@mediatek.com>
> + */
> +
> +#ifndef _MT8196_AFE_CLOCK_CTRL_H_
> +#define _MT8196_AFE_CLOCK_CTRL_H_
> +
> +// vlp_cksys_clk: 0x1c016000
Consistent comment style please.
> +#define VLP_AP_PLL_CON3 0x0264
> +#define VLP_APLL1_CON0 0x0274
> +#define VLP_APLL1_CON1 0x0278
> +#define VLP_APLL1_CON2 0x027c
> +#define VLP_APLL1_CON4 0x0284
> +#define VLP_APLL1_TUNER_CON0 0x02a4
> +
> +#define VLP_APLL2_CON0 0x028c
> +#define VLP_APLL2_CON1 0x0290
> +#define VLP_APLL2_CON2 0x0294
> +#define VLP_APLL2_CON4 0x029c
> +#define VLP_APLL2_TUNER_CON0 0x02a8
> +#define VLP_CLK_CFG_UPDATE1 0x0008
> +
> +// cksys_clk: 0x10000000
> +#define CLK_CFG_13 0x00e0
> +#define CLK_CFG_UPDATE1 0x0008
> +
> +#define CLK_AUDDIV_0 0x020c
> +#define CLK_AUDDIV_2 0x0214
> +#define CLK_AUDDIV_5 0x0228
> +
> +#define CKSYS_AUD_TOP_CFG 0x0218
> +
> +/* CLK_AUDDIV_0 */
> +#define APLL12_DIV_I2SIN0_PDN_SFT 0
> +#define APLL12_DIV_I2SIN0_PDN_MASK 0x1
> +#define APLL12_DIV_I2SIN0_PDN_MASK_SFT (0x1 << 0)
This is BIT(0)
> +#define APLL12_DIV_I2SIN1_PDN_SFT 1
> +#define APLL12_DIV_I2SIN1_PDN_MASK 0x1
> +#define APLL12_DIV_I2SIN1_PDN_MASK_SFT (0x1 << 1)
BIT(1)
> +#define APLL12_DIV_I2SIN2_PDN_SFT 2
> +#define APLL12_DIV_I2SIN2_PDN_MASK 0x1
> +#define APLL12_DIV_I2SIN2_PDN_MASK_SFT (0x1 << 2)
BIT(2)
> +#define APLL12_DIV_I2SIN3_PDN_SFT 3
> +#define APLL12_DIV_I2SIN3_PDN_MASK 0x1
> +#define APLL12_DIV_I2SIN3_PDN_MASK_SFT (0x1 << 3)
...etc
> +#define APLL12_DIV_I2SIN4_PDN_SFT 4
> +#define APLL12_DIV_I2SIN4_PDN_MASK 0x1
> +#define APLL12_DIV_I2SIN4_PDN_MASK_SFT (0x1 << 4)
> +#define APLL12_DIV_I2SIN6_PDN_SFT 5
> +#define APLL12_DIV_I2SIN6_PDN_MASK 0x1
> +#define APLL12_DIV_I2SIN6_PDN_MASK_SFT (0x1 << 5)
> +#define APLL12_DIV_I2SOUT0_PDN_SFT 6
> +#define APLL12_DIV_I2SOUT0_PDN_MASK 0x1
> +#define APLL12_DIV_I2SOUT0_PDN_MASK_SFT (0x1 << 6)
> +#define APLL12_DIV_I2SOUT1_PDN_SFT 7
> +#define APLL12_DIV_I2SOUT1_PDN_MASK 0x1
> +#define APLL12_DIV_I2SOUT1_PDN_MASK_SFT (0x1 << 7)
> +#define APLL12_DIV_I2SOUT2_PDN_SFT 8
> +#define APLL12_DIV_I2SOUT2_PDN_MASK 0x1
> +#define APLL12_DIV_I2SOUT2_PDN_MASK_SFT (0x1 << 8)
> +#define APLL12_DIV_I2SOUT3_PDN_SFT 9
> +#define APLL12_DIV_I2SOUT3_PDN_MASK 0x1
> +#define APLL12_DIV_I2SOUT3_PDN_MASK_SFT (0x1 << 9)
> +#define APLL12_DIV_I2SOUT4_PDN_SFT 10
> +#define APLL12_DIV_I2SOUT4_PDN_MASK 0x1
> +#define APLL12_DIV_I2SOUT4_PDN_MASK_SFT (0x1 << 10)
> +#define APLL12_DIV_I2SOUT6_PDN_SFT 11
> +#define APLL12_DIV_I2SOUT6_PDN_MASK 0x1
> +#define APLL12_DIV_I2SOUT6_PDN_MASK_SFT (0x1 << 11)
> +#define APLL12_DIV_FMI2S_PDN_SFT 12
> +#define APLL12_DIV_FMI2S_PDN_MASK 0x1
> +#define APLL12_DIV_FMI2S_PDN_MASK_SFT (0x1 << 12)
> +#define APLL12_DIV_TDMOUT_M_PDN_SFT 13
> +#define APLL12_DIV_TDMOUT_M_PDN_MASK 0x1
> +#define APLL12_DIV_TDMOUT_M_PDN_MASK_SFT (0x1 << 13)
> +#define APLL12_DIV_TDMOUT_B_PDN_SFT 14
> +#define APLL12_DIV_TDMOUT_B_PDN_MASK 0x1
> +#define APLL12_DIV_TDMOUT_B_PDN_MASK_SFT (0x1 << 14)
> +#define APLL_I2SIN0_MCK_SEL_SFT 16
> +#define APLL_I2SIN0_MCK_SEL_MASK 0x1
> +#define APLL_I2SIN0_MCK_SEL_MASK_SFT (0x1 << 16)
> +#define APLL_I2SIN1_MCK_SEL_SFT 17
> +#define APLL_I2SIN1_MCK_SEL_MASK 0x1
> +#define APLL_I2SIN1_MCK_SEL_MASK_SFT (0x1 << 17)
> +#define APLL_I2SIN2_MCK_SEL_SFT 18
> +#define APLL_I2SIN2_MCK_SEL_MASK 0x1
> +#define APLL_I2SIN2_MCK_SEL_MASK_SFT (0x1 << 18)
> +#define APLL_I2SIN3_MCK_SEL_SFT 19
> +#define APLL_I2SIN3_MCK_SEL_MASK 0x1
> +#define APLL_I2SIN3_MCK_SEL_MASK_SFT (0x1 << 19)
> +#define APLL_I2SIN4_MCK_SEL_SFT 20
> +#define APLL_I2SIN4_MCK_SEL_MASK 0x1
> +#define APLL_I2SIN4_MCK_SEL_MASK_SFT (0x1 << 20)
> +#define APLL_I2SIN6_MCK_SEL_SFT 21
> +#define APLL_I2SIN6_MCK_SEL_MASK 0x1
> +#define APLL_I2SIN6_MCK_SEL_MASK_SFT (0x1 << 21)
> +#define APLL_I2SOUT0_MCK_SEL_SFT 22
> +#define APLL_I2SOUT0_MCK_SEL_MASK 0x1
> +#define APLL_I2SOUT0_MCK_SEL_MASK_SFT (0x1 << 22)
> +#define APLL_I2SOUT1_MCK_SEL_SFT 23
> +#define APLL_I2SOUT1_MCK_SEL_MASK 0x1
> +#define APLL_I2SOUT1_MCK_SEL_MASK_SFT (0x1 << 23)
> +#define APLL_I2SOUT2_MCK_SEL_SFT 24
> +#define APLL_I2SOUT2_MCK_SEL_MASK 0x1
> +#define APLL_I2SOUT2_MCK_SEL_MASK_SFT (0x1 << 24)
> +#define APLL_I2SOUT3_MCK_SEL_SFT 25
> +#define APLL_I2SOUT3_MCK_SEL_MASK 0x1
> +#define APLL_I2SOUT3_MCK_SEL_MASK_SFT (0x1 << 25)
> +#define APLL_I2SOUT4_MCK_SEL_SFT 26
> +#define APLL_I2SOUT4_MCK_SEL_MASK 0x1
> +#define APLL_I2SOUT4_MCK_SEL_MASK_SFT (0x1 << 26)
> +#define APLL_I2SOUT6_MCK_SEL_SFT 27
> +#define APLL_I2SOUT6_MCK_SEL_MASK 0x1
> +#define APLL_I2SOUT6_MCK_SEL_MASK_SFT (0x1 << 27)
> +#define APLL_FMI2S_MCK_SEL_SFT 28
> +#define APLL_FMI2S_MCK_SEL_MASK 0x1
> +#define APLL_FMI2S_MCK_SEL_MASK_SFT (0x1 << 28)
> +#define APLL_TDMOUT_MCK_SEL_SFT 29
> +#define APLL_TDMOUT_MCK_SEL_MASK 0x1
> +#define APLL_TDMOUT_MCK_SEL_MASK_SFT (0x1 << 29)
> +
> +/* CLK_AUDDIV_1 */
> +#define APLL12_DIV_I2SIN0_INV_SFT 0
> +#define APLL12_DIV_I2SIN0_INV_MASK 0x1
> +#define APLL12_DIV_I2SIN0_INV_MASK_SFT (0x1 << 0)
> +#define APLL12_DIV_I2SIN1_INV_SFT 1
> +#define APLL12_DIV_I2SIN1_INV_MASK 0x1
> +#define APLL12_DIV_I2SIN1_INV_MASK_SFT (0x1 << 1)
> +#define APLL12_DIV_I2SIN2_INV_SFT 2
> +#define APLL12_DIV_I2SIN2_INV_MASK 0x1
> +#define APLL12_DIV_I2SIN2_INV_MASK_SFT (0x1 << 2)
> +#define APLL12_DIV_I2SIN3_INV_SFT 3
> +#define APLL12_DIV_I2SIN3_INV_MASK 0x1
> +#define APLL12_DIV_I2SIN3_INV_MASK_SFT (0x1 << 3)
> +#define APLL12_DIV_I2SIN4_INV_SFT 4
> +#define APLL12_DIV_I2SIN4_INV_MASK 0x1
> +#define APLL12_DIV_I2SIN4_INV_MASK_SFT (0x1 << 4)
> +#define APLL12_DIV_I2SIN6_INV_SFT 5
> +#define APLL12_DIV_I2SIN6_INV_MASK 0x1
> +#define APLL12_DIV_I2SIN6_INV_MASK_SFT (0x1 << 5)
> +#define APLL12_DIV_I2SOUT0_INV_SFT 6
> +#define APLL12_DIV_I2SOUT0_INV_MASK 0x1
> +#define APLL12_DIV_I2SOUT0_INV_MASK_SFT (0x1 << 6)
> +#define APLL12_DIV_I2SOUT1_INV_SFT 7
> +#define APLL12_DIV_I2SOUT1_INV_MASK 0x1
> +#define APLL12_DIV_I2SOUT1_INV_MASK_SFT (0x1 << 7)
> +#define APLL12_DIV_I2SOUT2_INV_SFT 8
> +#define APLL12_DIV_I2SOUT2_INV_MASK 0x1
> +#define APLL12_DIV_I2SOUT2_INV_MASK_SFT (0x1 << 8)
> +#define APLL12_DIV_I2SOUT3_INV_SFT 9
> +#define APLL12_DIV_I2SOUT3_INV_MASK 0x1
> +#define APLL12_DIV_I2SOUT3_INV_MASK_SFT (0x1 << 9)
> +#define APLL12_DIV_I2SOUT4_INV_SFT 10
> +#define APLL12_DIV_I2SOUT4_INV_MASK 0x1
> +#define APLL12_DIV_I2SOUT4_INV_MASK_SFT (0x1 << 10)
> +#define APLL12_DIV_I2SOUT6_INV_SFT 11
> +#define APLL12_DIV_I2SOUT6_INV_MASK 0x1
> +#define APLL12_DIV_I2SOUT6_INV_MASK_SFT (0x1 << 11)
> +#define APLL12_DIV_FMI2S_INV_SFT 12
> +#define APLL12_DIV_FMI2S_INV_MASK 0x1
> +#define APLL12_DIV_FMI2S_INV_MASK_SFT (0x1 << 12)
> +#define APLL12_DIV_TDMOUT_M_INV_SFT 13
> +#define APLL12_DIV_TDMOUT_M_INV_MASK 0x1
> +#define APLL12_DIV_TDMOUT_M_INV_MASK_SFT (0x1 << 13)
> +#define APLL12_DIV_TDMOUT_B_INV_SFT 14
> +#define APLL12_DIV_TDMOUT_B_INV_MASK 0x1
> +#define APLL12_DIV_TDMOUT_B_INV_MASK_SFT (0x1 << 14)
> +
> +/* CLK_AUDDIV_2 */
> +#define APLL12_CK_DIV_I2SIN0_SFT 0
> +#define APLL12_CK_DIV_I2SIN0_MASK 0xff
> +#define APLL12_CK_DIV_I2SIN0_MASK_SFT (0xff << 0)
> +#define APLL12_CK_DIV_I2SIN1_SFT 8
> +#define APLL12_CK_DIV_I2SIN1_MASK 0xff
> +#define APLL12_CK_DIV_I2SIN1_MASK_SFT (0xff << 8)
> +#define APLL12_CK_DIV_I2SIN2_SFT 16
> +#define APLL12_CK_DIV_I2SIN2_MASK 0xff
> +#define APLL12_CK_DIV_I2SIN2_MASK_SFT (0xff << 16)
> +#define APLL12_CK_DIV_I2SIN3_SFT 24
> +#define APLL12_CK_DIV_I2SIN3_MASK 0xff
> +#define APLL12_CK_DIV_I2SIN3_MASK_SFT (0xff << 24)
> +
> +/* AUD_TOP_CFG */
> +#define AUD_TOP_CFG_SFT 0
> +#define AUD_TOP_CFG_MASK 0xffffffff
> +#define AUD_TOP_CFG_MASK_SFT (0xffffffff << 0)
Both of these are GENMASK(31, 0)
> +
> +/* AUD_TOP_MON */
> +#define AUD_TOP_MON_SFT 0
> +#define AUD_TOP_MON_MASK 0xffffffff
> +#define AUD_TOP_MON_MASK_SFT (0xffffffff << 0)
same
> +
> +/* CLK_AUDDIV_3 */
> +#define APLL12_CK_DIV_I2SIN4_SFT 0
> +#define APLL12_CK_DIV_I2SIN4_MASK 0xff
> +#define APLL12_CK_DIV_I2SIN4_MASK_SFT (0xff << 0)
GENMASK(7, 0)
> +#define APLL12_CK_DIV_I2SIN6_SFT 8
> +#define APLL12_CK_DIV_I2SIN6_MASK 0xff
> +#define APLL12_CK_DIV_I2SIN6_MASK_SFT (0xff << 8)
GENMASK(15, 8)
> +#define APLL12_CK_DIV_I2SOUT0_SFT 16
> +#define APLL12_CK_DIV_I2SOUT0_MASK 0xff
> +#define APLL12_CK_DIV_I2SOUT0_MASK_SFT (0xff << 16)
...etc
> +#define APLL12_CK_DIV_I2SOUT1_SFT 24
> +#define APLL12_CK_DIV_I2SOUT1_MASK 0xff
> +#define APLL12_CK_DIV_I2SOUT1_MASK_SFT (0xff << 24)
> +
> +/* CLK_AUDDIV_4 */
> +#define APLL12_CK_DIV_I2SOUT2_SFT 0
> +#define APLL12_CK_DIV_I2SOUT2_MASK 0xff
> +#define APLL12_CK_DIV_I2SOUT2_MASK_SFT (0xff << 0)
> +#define APLL12_CK_DIV_I2SOUT3_SFT 8
> +#define APLL12_CK_DIV_I2SOUT3_MASK 0xff
> +#define APLL12_CK_DIV_I2SOUT3_MASK_SFT (0xff << 8)
> +#define APLL12_CK_DIV_I2SOUT4_SFT 16
> +#define APLL12_CK_DIV_I2SOUT4_MASK 0xff
> +#define APLL12_CK_DIV_I2SOUT4_MASK_SFT (0xff << 16)
> +#define APLL12_CK_DIV_I2SOUT6_SFT 24
> +#define APLL12_CK_DIV_I2SOUT6_MASK 0xff
> +#define APLL12_CK_DIV_I2SOUT6_MASK_SFT (0xff << 24)
> +
> +/* CLK_AUDDIV_5 */
> +#define APLL12_CK_DIV_FMI2S_SFT 0
> +#define APLL12_CK_DIV_FMI2S_MASK 0xff
> +#define APLL12_CK_DIV_FMI2S_MASK_SFT (0xff << 0)
> +#define APLL12_CK_DIV_TDMOUT_M_SFT 8
> +#define APLL12_CK_DIV_TDMOUT_M_MASK 0xff
> +#define APLL12_CK_DIV_TDMOUT_M_MASK_SFT (0xff << 8)
> +#define APLL12_CK_DIV_TDMOUT_B_SFT 16
> +#define APLL12_CK_DIV_TDMOUT_B_MASK 0xff
> +#define APLL12_CK_DIV_TDMOUT_B_MASK_SFT (0xff << 16)
> +
> +/* APLL */
> +#define APLL1_W_NAME "APLL1"
> +#define APLL2_W_NAME "APLL2"
> +enum {
> + MT8196_APLL1 = 0,
> + MT8196_APLL2,
> +};
> +
> +enum {
> + /* afe clk */
> + CLK_HOPPING = 0,
> + CLK_F26M,
> + CLK_UL0_ADC_CLK,
> + CLK_UL0_ADC_HIRES_CLK,
> + CLK_UL1_ADC_CLK,
> + CLK_UL1_ADC_HIRES_CLK,
> + CLK_APLL1,
> + CLK_APLL2,
> + CLK_APLL1_TUNER,
> + CLK_APLL2_TUNER,
> + /* vlp clk */
> + CLK_VLP_MUX_AUDIOINTBUS,
> + CLK_VLP_MUX_AUD_ENG1,
> + CLK_VLP_MUX_AUD_ENG2,
> + CLK_VLP_MUX_AUDIO_H,
> + CLK_VLP_CLK26M,
> + /* ck clk */
> + CLK_CK_MAINPLL_D4_D4,
> + CLK_CK_MUX_AUD_1,
> + CLK_CK_APLL1_CK,
> + CLK_CK_MUX_AUD_2,
> + CLK_CK_APLL2_CK,
> + CLK_CK_APLL1_D4,
> + CLK_CK_APLL2_D4,
> + CLK_CK_I2SIN0_M_SEL,
> + CLK_CK_I2SIN1_M_SEL,
> + CLK_CK_FMI2S_M_SEL,
> + CLK_CK_TDMOUT_M_SEL,
> + CLK_CK_APLL12_DIV_I2SIN0,
> + CLK_CK_APLL12_DIV_I2SIN1,
> + CLK_CK_APLL12_DIV_FMI2S,
> + CLK_CK_APLL12_DIV_TDMOUT_M,
> + CLK_CK_APLL12_DIV_TDMOUT_B,
> + CLK_CK_ADSP_SEL,
> + CLK_CLK26M,
> + CLK_NUM
> +};
> +
> +struct mtk_base_afe;
> +
> +int mt8196_init_clock(struct mtk_base_afe *afe);
> +int mt8196_afe_enable_clock(struct mtk_base_afe *afe);
> +void mt8196_afe_disable_clock(struct mtk_base_afe *afe);
> +int mt8196_afe_disable_apll(struct mtk_base_afe *afe);
> +
> +int mt8196_afe_dram_request(struct device *dev);
> +int mt8196_afe_dram_release(struct device *dev);
> +
> +int mt8196_apll1_enable(struct mtk_base_afe *afe);
> +void mt8196_apll1_disable(struct mtk_base_afe *afe);
> +
> +int mt8196_apll2_enable(struct mtk_base_afe *afe);
> +void mt8196_apll2_disable(struct mtk_base_afe *afe);
> +
> +int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll);
> +int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
> +int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
> +
> +void aud_intbus_mux_sel(unsigned int aud_idx);
> +
> +/* these will be replaced by using CCF */
Well, just replace them now instead of fixing them later.
Regards,
Angelo
> +int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate);
> +int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id);
> +
> +int mt8196_set_audio_int_bus_parent(struct mtk_base_afe *afe,
> + int clk_id, bool int_bus);
> +
> +#endif
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 04/14] ASoC: mediatek: mt8196: add common interface for mt8196 DAI driver
2025-03-07 12:47 ` [PATCH 04/14] ASoC: mediatek: mt8196: add common interface for mt8196 DAI driver Darren.Ye
2025-03-07 15:22 ` Krzysztof Kozlowski
@ 2025-03-10 15:23 ` AngeloGioacchino Del Regno
1 sibling, 0 replies; 27+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-03-10 15:23 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
Il 07/03/25 13:47, Darren.Ye ha scritto:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Implement sample rate conversion and set private data for mt8196.
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> ---
> .../soc/mediatek/mt8196/mt8196-afe-control.c | 109 ++++++++++++++++++
> 1 file changed, 109 insertions(+)
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-control.c
>
> diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-control.c b/sound/soc/mediatek/mt8196/mt8196-afe-control.c
> new file mode 100644
> index 000000000000..bb85f4ad8585
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8196/mt8196-afe-control.c
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * MediaTek ALSA SoC Audio Control
> + *
> + * Copyright (c) 2024 MediaTek Inc.
> + * Author: Darren Ye <darren.ye@mediatek.com>
> + */
> +
> +#include "mt8196-afe-common.h"
> +#include <linux/pm_runtime.h>
> +
> +unsigned int mt8196_general_rate_transform(struct device *dev,
> + unsigned int rate)
> +{
> + switch (rate) {
> + case 8000:
> + return MTK_AFE_IPM2P0_RATE_8K;
> + case 11025:
> + return MTK_AFE_IPM2P0_RATE_11K;
> + case 12000:
> + return MTK_AFE_IPM2P0_RATE_12K;
> + case 16000:
> + return MTK_AFE_IPM2P0_RATE_16K;
> + case 22050:
> + return MTK_AFE_IPM2P0_RATE_22K;
> + case 24000:
> + return MTK_AFE_IPM2P0_RATE_24K;
> + case 32000:
> + return MTK_AFE_IPM2P0_RATE_32K;
> + case 44100:
> + return MTK_AFE_IPM2P0_RATE_44K;
> + case 48000:
> + return MTK_AFE_IPM2P0_RATE_48K;
> + case 88200:
> + return MTK_AFE_IPM2P0_RATE_88K;
> + case 96000:
> + return MTK_AFE_IPM2P0_RATE_96K;
> + case 176400:
> + return MTK_AFE_IPM2P0_RATE_176K;
> + case 192000:
> + return MTK_AFE_IPM2P0_RATE_192K;
> + /* not support 260K */
> + case 352800:
> + return MTK_AFE_IPM2P0_RATE_352K;
> + case 384000:
> + return MTK_AFE_IPM2P0_RATE_384K;
> + default:
> + dev_info(dev, "%s(), rate %u invalid, use %d!!!\n",
> + __func__,
> + rate, MTK_AFE_IPM2P0_RATE_48K);
> + return MTK_AFE_IPM2P0_RATE_48K;
> + }
> +}
> +
> +static unsigned int pcm_rate_transform(struct device *dev,
> + unsigned int rate)
> +{
You have this function in mt8186-afe-control.c and mt8192-afe-control.c, with
the only difference being the default case.
Please commonize this function and handle the default case for each SoC (if needed)
in each SoC-specific driver.
While at it, please do the same with mt8196_general_rate_transform, as this IPM2.0
will be in other MediaTek SoCs, and this function will otherwise be commonized next
time anyway.
Possible names could be mtk_afe_pcm_rate_transform() for one, and probably
mtk_ipm20_general_rate_transform() for the other.
> + switch (rate) {
> + case 8000:
> + return MTK_AFE_PCM_RATE_8K;
> + case 16000:
> + return MTK_AFE_PCM_RATE_16K;
> + case 32000:
> + return MTK_AFE_PCM_RATE_32K;
> + case 48000:
> + return MTK_AFE_PCM_RATE_48K;
> + default:
> + dev_info(dev, "%s(), rate %u invalid, use %d!!!\n",
> + __func__,
> + rate, MTK_AFE_PCM_RATE_32K);
> + return MTK_AFE_PCM_RATE_32K;
> + }
> +}
> +
> +unsigned int mt8196_rate_transform(struct device *dev,
> + unsigned int rate, int aud_blk)
> +{
> + switch (aud_blk) {
> + case MT8196_DAI_PCM_0:
> + case MT8196_DAI_PCM_1:
> + return pcm_rate_transform(dev, rate);
> + default:
> + return mt8196_general_rate_transform(dev, rate);
> + }
> +}
> +
> +int mt8196_dai_set_priv(struct mtk_base_afe *afe, int id,
> + int priv_size, const void *priv_data)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + void *temp_data;
> +
> + temp_data = devm_kzalloc(afe->dev,
> + priv_size,
> + GFP_KERNEL);
> + if (!temp_data)
> + return -ENOMEM;
> +
> + if (priv_data)
> + memcpy(temp_data, priv_data, priv_size);
> +
> + if (id >= MT8196_DAI_NUM || id < 0)
> + return -EINVAL;
> +
> + afe_priv->dai_priv[id] = temp_data;
> +
> + return 0;
> +}
> +
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 01/14] ASoC: mediatek: common: modify mtk afe common driver for mt8196
2025-03-07 12:47 ` [PATCH 01/14] ASoC: mediatek: common: modify mtk afe common driver for mt8196 Darren.Ye
2025-03-07 15:20 ` Krzysztof Kozlowski
@ 2025-03-10 15:23 ` AngeloGioacchino Del Regno
1 sibling, 0 replies; 27+ messages in thread
From: AngeloGioacchino Del Regno @ 2025-03-10 15:23 UTC (permalink / raw)
To: Darren.Ye, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
Jaroslav Kysela, Takashi Iwai, Linus Walleij, Bartosz Golaszewski
Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-gpio
Il 07/03/25 13:47, Darren.Ye ha scritto:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Export register read and write interface, add sample reate interface, and
> update the mtk_memif_set_channel interface for the mt8196 platform.
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> ---
> sound/soc/mediatek/common/mtk-afe-fe-dai.c | 30 ++++++++++++++--------
> sound/soc/mediatek/common/mtk-afe-fe-dai.h | 6 +++++
> sound/soc/mediatek/common/mtk-base-afe.h | 13 ++++++++++
> 3 files changed, 38 insertions(+), 11 deletions(-)
>
> diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
> index 3809068f5620..c36dae520f04 100644
> --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
> +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
> @@ -18,7 +18,7 @@
>
> #define AFE_BASE_END_OFFSET 8
>
> -static int mtk_regmap_update_bits(struct regmap *map, int reg,
> +int mtk_regmap_update_bits(struct regmap *map, int reg,
> unsigned int mask,
> unsigned int val, int shift)
> {
> @@ -26,13 +26,16 @@ static int mtk_regmap_update_bits(struct regmap *map, int reg,
> return 0;
> return regmap_update_bits(map, reg, mask << shift, val << shift);
> }
> +EXPORT_SYMBOL(mtk_regmap_update_bits);
Please don't export this function: it's not the greatest, `reg` should be unsigned
and so it should the shift - it's kinda wrong in principle, and you can simply use
regmap_update_bits() directly in your drivers. Please, do so.
> +
> +int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
>
> -static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
> {
> if (reg < 0)
> return 0;
> return regmap_write(map, reg, val);
> }
> +EXPORT_SYMBOL(mtk_regmap_write);
>
Same here
> int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
> struct snd_soc_dai *dai)
> @@ -459,8 +462,12 @@ int mtk_memif_set_channel(struct mtk_base_afe *afe,
> struct mtk_base_afe_memif *memif = &afe->memif[id];
> unsigned int mono;
>
> - if (memif->data->mono_shift < 0)
> - return 0;
> + dev_info(afe->dev, "%s(), id: %d, channel: %d\n", __func__, id, channel);
If you really really really need this print, it's for debugging, so this should be
dev_dbg() instead... but otherwise just delete it.
> + mono = memif->data->mono_invert ^ (channel == 1);
> +
> + if (memif->data->mono_shift > 0)
> + mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
> + 0x1, mono, memif->data->mono_shift);
>
> if (memif->data->quad_ch_mask) {
> unsigned int quad_ch = (channel == 4) ? 1 : 0;
> @@ -470,11 +477,6 @@ int mtk_memif_set_channel(struct mtk_base_afe *afe,
> quad_ch, memif->data->quad_ch_shift);
> }
>
> - if (memif->data->mono_invert)
> - mono = (channel == 1) ? 0 : 1;
> - else
> - mono = (channel == 1) ? 1 : 0;
> -
> /* for specific configuration of memif mono mode */
> if (memif->data->int_odd_flag_reg)
> mtk_regmap_update_bits(afe->regmap,
> @@ -482,8 +484,14 @@ int mtk_memif_set_channel(struct mtk_base_afe *afe,
> 1, mono,
> memif->data->int_odd_flag_shift);
>
> - return mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
> - 1, mono, memif->data->mono_shift);
Don't break older platforms. You're removing functionality here.
> + if (memif->data->ch_num_maskbit) {
> + dev_info(afe->dev, "%s(), set ch num id: %d, channel: %d\n", __func__, id, channel);
Same comment applies (plus, this is a double print, even worse).
> + mtk_regmap_update_bits(afe->regmap, memif->data->ch_num_reg,
> + memif->data->ch_num_maskbit,
> + channel, memif->data->ch_num_shift);
> + }
> +
> + return 0;
> }
> EXPORT_SYMBOL_GPL(mtk_memif_set_channel);
>
> diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.h b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
> index b6d0f2b27e86..64b10ccba291 100644
> --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.h
> +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
> @@ -12,7 +12,13 @@
> struct snd_soc_dai_ops;
> struct mtk_base_afe;
> struct mtk_base_afe_memif;
> +struct mtk_base_irq_data;
>
> +int mtk_regmap_update_bits(struct regmap *map, int reg,
> + unsigned int mask, unsigned int val,
> + int shift);
> +int mtk_regmap_write(struct regmap *map, int reg,
> + unsigned int val);
No, don't export these. Use regmap directly.
Regards,
Angelo
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 06/14] ASoC: mediatek: mt8196: support audio GPIO control
2025-03-07 12:47 ` [PATCH 06/14] ASoC: mediatek: mt8196: support audio GPIO control Darren.Ye
@ 2025-03-14 10:21 ` Linus Walleij
0 siblings, 0 replies; 27+ messages in thread
From: Linus Walleij @ 2025-03-14 10:21 UTC (permalink / raw)
To: Darren.Ye
Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Bartosz Golaszewski, linux-sound,
devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
linux-gpio
Hi Darren,
thanks for your patch!
On Fri, Mar 7, 2025 at 1:49 PM Darren.Ye <darren.ye@mediatek.com> wrote:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Implement mode switching for audio GPIO.
>
> Signed-off-by: Darren Ye <darren.ye@mediatek.com>
> +#include <linux/gpio.h>
Please don't include this legacy header. I don't think you even need it,
you are not using any gpio_ symbols at all.
> +#include <linux/pinctrl/consumer.h>
You don't seem to use anything from this include either.
Find more specific headers if you need the code to compile.
I think you should drop both, the name "GPIO" in this file is a bit confusing
because it's not very generic but dealing with audio IO routing. But I guess
it is what Mediatek calls it.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2025-03-14 10:25 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-07 12:47 [PATCH 00/14] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
2025-03-07 12:47 ` [PATCH 01/14] ASoC: mediatek: common: modify mtk afe common driver for mt8196 Darren.Ye
2025-03-07 15:20 ` Krzysztof Kozlowski
2025-03-10 15:23 ` AngeloGioacchino Del Regno
2025-03-07 12:47 ` [PATCH 02/14] ASoC: mediatek: common: modify mtk afe platform " Darren.Ye
2025-03-07 15:21 ` Krzysztof Kozlowski
2025-03-07 12:47 ` [PATCH 04/14] ASoC: mediatek: mt8196: add common interface for mt8196 DAI driver Darren.Ye
2025-03-07 15:22 ` Krzysztof Kozlowski
2025-03-10 15:23 ` AngeloGioacchino Del Regno
2025-03-07 12:47 ` [PATCH 05/14] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
2025-03-07 15:32 ` Krzysztof Kozlowski
2025-03-10 15:23 ` AngeloGioacchino Del Regno
2025-03-07 12:47 ` [PATCH 06/14] ASoC: mediatek: mt8196: support audio GPIO control Darren.Ye
2025-03-14 10:21 ` Linus Walleij
2025-03-07 12:47 ` [PATCH 07/14] ASoC: mediatek: mt8196: support ADDA in platform driver Darren.Ye
2025-03-07 12:47 ` [PATCH 09/14] ASoC: mediatek: mt8196: support TDM " Darren.Ye
2025-03-07 12:47 ` [PATCH 10/14] ASoC: mediatek: mt8196: support CM " Darren.Ye
2025-03-07 15:33 ` Krzysztof Kozlowski
2025-03-07 12:47 ` [PATCH 12/14] dt-bindings: mediatek: mt8196: add audio AFE document Darren.Ye
2025-03-07 14:35 ` Rob Herring (Arm)
2025-03-07 15:15 ` Krzysztof Kozlowski
2025-03-07 12:47 ` [PATCH 13/14] ASoC: mediatek: mt8196: add machine driver with mt6681 Darren.Ye
2025-03-07 12:47 ` [PATCH 14/14] dt-bindings: mediatek: mt8196: add mt8196-mt6681 document Darren.Ye
2025-03-07 14:35 ` Rob Herring (Arm)
2025-03-07 15:19 ` Krzysztof Kozlowski
[not found] ` <20250307124841.23777-9-darren.ye@mediatek.com>
2025-03-07 15:24 ` [PATCH 08/14] ASoC: mediatek: mt8196: support I2S in platform driver Krzysztof Kozlowski
[not found] ` <20250307124841.23777-12-darren.ye@mediatek.com>
2025-03-07 15:32 ` [PATCH 11/14] ASoC: mediatek: mt8196: add " Krzysztof Kozlowski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).