summaryrefslogtreecommitdiffstats
path: root/sound/soc/mediatek
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 10:05:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 10:05:51 +0000
commit5d1646d90e1f2cceb9f0828f4b28318cd0ec7744 (patch)
treea94efe259b9009378be6d90eb30d2b019d95c194 /sound/soc/mediatek
parentInitial commit. (diff)
downloadlinux-upstream.tar.xz
linux-upstream.zip
Adding upstream version 5.10.209.upstream/5.10.209upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sound/soc/mediatek')
-rw-r--r--sound/soc/mediatek/Kconfig160
-rw-r--r--sound/soc/mediatek/Makefile6
-rw-r--r--sound/soc/mediatek/common/Makefile6
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.c589
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.h53
-rw-r--r--sound/soc/mediatek/common/mtk-afe-platform-driver.c139
-rw-r--r--sound/soc/mediatek/common/mtk-afe-platform-driver.h28
-rw-r--r--sound/soc/mediatek/common/mtk-base-afe.h146
-rw-r--r--sound/soc/mediatek/common/mtk-btcvsd.c1418
-rw-r--r--sound/soc/mediatek/mt2701/Makefile8
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c298
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h34
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-common.h98
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-pcm.c1489
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-cs42448.c439
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-reg.h141
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-wm8960.c183
-rw-r--r--sound/soc/mediatek/mt6797/Makefile14
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-clk.c123
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-clk.h17
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-common.h59
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-pcm.c916
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-dai-adda.c402
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-dai-hostless.c118
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-dai-pcm.c317
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-interconnection.h33
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-mt6351.c264
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-reg.h1015
-rw-r--r--sound/soc/mediatek/mt8173/Makefile8
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-afe-common.h65
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-afe-pcm.c1236
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-max98090.c216
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c253
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c321
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c358
-rw-r--r--sound/soc/mediatek/mt8183/Makefile15
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-afe-clk.c615
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-afe-clk.h38
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-afe-common.h108
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-afe-pcm.c1294
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c831
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-dai-adda.c509
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-dai-hostless.c118
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-dai-i2s.c1083
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-dai-pcm.c318
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-dai-tdm.c748
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-interconnection.h33
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c765
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-reg.h1668
49 files changed, 19113 insertions, 0 deletions
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
new file mode 100644
index 000000000..76e055d1d
--- /dev/null
+++ b/sound/soc/mediatek/Kconfig
@@ -0,0 +1,160 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config SND_SOC_MEDIATEK
+ tristate
+
+config SND_SOC_MT2701
+ tristate "ASoC support for Mediatek MT2701 chip"
+ depends on ARCH_MEDIATEK
+ select SND_SOC_MEDIATEK
+ help
+ This adds ASoC driver for Mediatek MT2701 boards
+ that can be used with other codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT2701_CS42448
+ tristate "ASoc Audio driver for MT2701 with CS42448 codec"
+ depends on SND_SOC_MT2701 && I2C
+ select SND_SOC_CS42XX8_I2C
+ select SND_SOC_BT_SCO
+ help
+ This adds ASoC driver for Mediatek MT2701 boards
+ with the CS42448 codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT2701_WM8960
+ tristate "ASoc Audio driver for MT2701 with WM8960 codec"
+ depends on SND_SOC_MT2701 && I2C
+ select SND_SOC_WM8960
+ help
+ This adds ASoC driver for Mediatek MT2701 boards
+ with the WM8960 codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT6797
+ tristate "ASoC support for Mediatek MT6797 chip"
+ depends on ARCH_MEDIATEK
+ select SND_SOC_MEDIATEK
+ help
+ This adds ASoC driver for Mediatek MT6797 boards
+ that can be used with other codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT6797_MT6351
+ tristate "ASoc Audio driver for MT6797 with MT6351 codec"
+ depends on SND_SOC_MT6797 && MTK_PMIC_WRAP
+ select SND_SOC_MT6351
+ help
+ This adds ASoC driver for Mediatek MT6797 boards
+ with the MT6351 codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT8173
+ tristate "ASoC support for Mediatek MT8173 chip"
+ depends on ARCH_MEDIATEK
+ select SND_SOC_MEDIATEK
+ help
+ This adds ASoC platform driver support for Mediatek MT8173 chip
+ that can be used with other codecs.
+ Select Y if you have such device.
+ Ex: MT8173
+
+config SND_SOC_MT8173_MAX98090
+ tristate "ASoC Audio driver for MT8173 with MAX98090 codec"
+ depends on SND_SOC_MT8173 && I2C
+ select SND_SOC_MAX98090
+ help
+ This adds ASoC driver for Mediatek MT8173 boards
+ with the MAX98090 audio codec.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT8173_RT5650
+ tristate "ASoC Audio driver for MT8173 with RT5650 codec"
+ depends on SND_SOC_MT8173 && I2C
+ select SND_SOC_RT5645
+ select SND_SOC_HDMI_CODEC
+ help
+ This adds ASoC driver for Mediatek MT8173 boards
+ with the RT5650 audio codec.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT8173_RT5650_RT5514
+ tristate "ASoC Audio driver for MT8173 with RT5650 RT5514 codecs"
+ depends on SND_SOC_MT8173 && I2C
+ select SND_SOC_RT5645
+ select SND_SOC_RT5514
+ help
+ This adds ASoC driver for Mediatek MT8173 boards
+ with the RT5650 and RT5514 codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT8173_RT5650_RT5676
+ tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs"
+ depends on SND_SOC_MT8173 && I2C
+ select SND_SOC_RT5645
+ select SND_SOC_RT5677
+ select SND_SOC_HDMI_CODEC
+ help
+ This adds ASoC driver for Mediatek MT8173 boards
+ with the RT5650 and RT5676 codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT8183
+ tristate "ASoC support for Mediatek MT8183 chip"
+ depends on ARCH_MEDIATEK
+ select SND_SOC_MEDIATEK
+ help
+ This adds ASoC platform driver support for Mediatek MT8183 chip
+ that can be used with other codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A
+ tristate "ASoC Audio driver for MT8183 with MT6358 TS3A227E MAX98357A RT1015 codec"
+ depends on I2C
+ depends on SND_SOC_MT8183
+ select SND_SOC_MT6358
+ select SND_SOC_MAX98357A
+ select SND_SOC_RT1015
+ select SND_SOC_BT_SCO
+ select SND_SOC_TS3A227E
+ select SND_SOC_CROS_EC_CODEC if CROS_EC
+ select SND_SOC_HDMI_CODEC
+ help
+ This adds ASoC driver for Mediatek MT8183 boards
+ with the MT6358 TS3A227E MAX98357A RT1015 audio codec.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT8183_DA7219_MAX98357A
+ tristate "ASoC Audio driver for MT8183 with DA7219 MAX98357A RT1015 codec"
+ depends on SND_SOC_MT8183 && I2C
+ select SND_SOC_MT6358
+ select SND_SOC_MAX98357A
+ select SND_SOC_RT1015
+ select SND_SOC_RT1015P
+ select SND_SOC_DA7219
+ select SND_SOC_BT_SCO
+ select SND_SOC_HDMI_CODEC
+ help
+ This adds ASoC driver for Mediatek MT8183 boards
+ with the DA7219 MAX98357A RT1015 audio codec.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MTK_BTCVSD
+ tristate "ALSA BT SCO CVSD/MSBC Driver"
+ help
+ This is for software BTCVSD. This enable
+ the function for transferring/receiving
+ BT encoded data to/from BT firmware.
+ Select Y if you have such device.
+ If unsure select "N".
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
new file mode 100644
index 000000000..76032cae6
--- /dev/null
+++ b/sound/soc/mediatek/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
+obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
+obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
+obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
+obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
diff --git a/sound/soc/mediatek/common/Makefile b/sound/soc/mediatek/common/Makefile
new file mode 100644
index 000000000..acbe01e9e
--- /dev/null
+++ b/sound/soc/mediatek/common/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+# platform driver
+snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o
+obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o
+
+obj-$(CONFIG_SND_SOC_MTK_BTCVSD) += mtk-btcvsd.o
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
new file mode 100644
index 000000000..882cdf86c
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
@@ -0,0 +1,589 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtk-afe-fe-dais.c -- Mediatek afe fe dai operator
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "mtk-afe-platform-driver.h"
+#include <sound/pcm_params.h>
+#include "mtk-afe-fe-dai.h"
+#include "mtk-base-afe.h"
+
+#define AFE_BASE_END_OFFSET 8
+
+static int mtk_regmap_update_bits(struct regmap *map, int reg,
+ unsigned int mask,
+ unsigned int val, int shift)
+{
+ if (reg < 0 || WARN_ON_ONCE(shift < 0))
+ return 0;
+ return regmap_update_bits(map, reg, mask << shift, val << shift);
+}
+
+static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
+{
+ if (reg < 0)
+ return 0;
+ return regmap_write(map, reg, val);
+}
+
+int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int memif_num = asoc_rtd_to_cpu(rtd, 0)->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+ const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware;
+ int ret;
+
+ memif->substream = substream;
+
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
+ /* enable agent */
+ mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,
+ 1, 0, memif->data->agent_disable_shift);
+
+ snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware);
+
+ /*
+ * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be
+ * smaller than period_size due to AFE's internal buffer.
+ * This easily leads to overrun when avail_min is period_size.
+ * One more period can hold the possible unread buffer.
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ int periods_max = mtk_afe_hardware->periods_max;
+
+ ret = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS,
+ 3, periods_max);
+ if (ret < 0) {
+ dev_err(afe->dev, "hw_constraint_minmax failed\n");
+ return ret;
+ }
+ }
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+
+ /* dynamic allocate irq to memif */
+ if (memif->irq_usage < 0) {
+ int irq_id = mtk_dynamic_irq_acquire(afe);
+
+ if (irq_id != afe->irqs_size) {
+ /* link */
+ memif->irq_usage = irq_id;
+ } else {
+ dev_err(afe->dev, "%s() error: no more asys irq\n",
+ __func__);
+ ret = -EBUSY;
+ }
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_fe_startup);
+
+void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id];
+ int irq_id;
+
+ irq_id = memif->irq_usage;
+
+ mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,
+ 1, 1, memif->data->agent_disable_shift);
+
+ if (!memif->const_irq) {
+ mtk_dynamic_irq_release(afe, irq_id);
+ memif->irq_usage = -1;
+ memif->substream = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown);
+
+int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+ int ret;
+ unsigned int channels = params_channels(params);
+ unsigned int rate = params_rate(params);
+ snd_pcm_format_t format = params_format(params);
+
+ if (afe->request_dram_resource)
+ afe->request_dram_resource(afe->dev);
+
+ dev_dbg(afe->dev, "%s(), %s, ch %d, rate %d, fmt %d, dma_addr %pad, dma_area %p, dma_bytes 0x%zx\n",
+ __func__, memif->data->name,
+ channels, rate, format,
+ &substream->runtime->dma_addr,
+ substream->runtime->dma_area,
+ substream->runtime->dma_bytes);
+
+ memset_io(substream->runtime->dma_area, 0,
+ substream->runtime->dma_bytes);
+
+ /* set addr */
+ ret = mtk_memif_set_addr(afe, id,
+ substream->runtime->dma_area,
+ substream->runtime->dma_addr,
+ substream->runtime->dma_bytes);
+ if (ret) {
+ dev_err(afe->dev, "%s(), error, id %d, set addr, ret %d\n",
+ __func__, id, ret);
+ return ret;
+ }
+
+ /* set channel */
+ ret = mtk_memif_set_channel(afe, id, channels);
+ if (ret) {
+ dev_err(afe->dev, "%s(), error, id %d, set channel %d, ret %d\n",
+ __func__, id, channels, ret);
+ return ret;
+ }
+
+ /* set rate */
+ ret = mtk_memif_set_rate_substream(substream, id, rate);
+ if (ret) {
+ dev_err(afe->dev, "%s(), error, id %d, set rate %d, ret %d\n",
+ __func__, id, rate, ret);
+ return ret;
+ }
+
+ /* set format */
+ ret = mtk_memif_set_format(afe, id, format);
+ if (ret) {
+ dev_err(afe->dev, "%s(), error, id %d, set format %d, ret %d\n",
+ __func__, id, format, ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params);
+
+int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ if (afe->release_dram_resource)
+ afe->release_dram_resource(afe->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free);
+
+int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_pcm_runtime * const runtime = substream->runtime;
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+ struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];
+ const struct mtk_base_irq_data *irq_data = irqs->irq_data;
+ unsigned int counter = runtime->period_size;
+ int fs;
+ int ret;
+
+ dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ ret = mtk_memif_set_enable(afe, id);
+ if (ret) {
+ dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",
+ __func__, id, ret);
+ return ret;
+ }
+
+ /* set irq counter */
+ mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,
+ irq_data->irq_cnt_maskbit, counter,
+ irq_data->irq_cnt_shift);
+
+ /* set irq fs */
+ fs = afe->irq_fs(substream, runtime->rate);
+
+ if (fs < 0)
+ return -EINVAL;
+
+ mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg,
+ irq_data->irq_fs_maskbit, fs,
+ irq_data->irq_fs_shift);
+
+ /* enable interrupt */
+ mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
+ 1, 1, irq_data->irq_en_shift);
+
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ ret = mtk_memif_set_disable(afe, id);
+ if (ret) {
+ dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",
+ __func__, id, ret);
+ }
+
+ /* disable interrupt */
+ mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
+ 1, 0, irq_data->irq_en_shift);
+ /* and clear pending IRQ */
+ mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg,
+ 1 << irq_data->irq_clr_shift);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger);
+
+int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int pbuf_size;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (afe->get_memif_pbuf_size) {
+ pbuf_size = afe->get_memif_pbuf_size(substream);
+ mtk_memif_set_pbuf_size(afe, id, pbuf_size);
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare);
+
+const struct snd_soc_dai_ops mtk_afe_fe_ops = {
+ .startup = mtk_afe_fe_startup,
+ .shutdown = mtk_afe_fe_shutdown,
+ .hw_params = mtk_afe_fe_hw_params,
+ .hw_free = mtk_afe_fe_hw_free,
+ .prepare = mtk_afe_fe_prepare,
+ .trigger = mtk_afe_fe_trigger,
+};
+EXPORT_SYMBOL_GPL(mtk_afe_fe_ops);
+
+static DEFINE_MUTEX(irqs_lock);
+int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe)
+{
+ int i;
+
+ mutex_lock(&afe->irq_alloc_lock);
+ for (i = 0; i < afe->irqs_size; ++i) {
+ if (afe->irqs[i].irq_occupyed == 0) {
+ afe->irqs[i].irq_occupyed = 1;
+ mutex_unlock(&afe->irq_alloc_lock);
+ return i;
+ }
+ }
+ mutex_unlock(&afe->irq_alloc_lock);
+ return afe->irqs_size;
+}
+EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire);
+
+int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id)
+{
+ mutex_lock(&afe->irq_alloc_lock);
+ if (irq_id >= 0 && irq_id < afe->irqs_size) {
+ afe->irqs[irq_id].irq_occupyed = 0;
+ mutex_unlock(&afe->irq_alloc_lock);
+ return 0;
+ }
+ mutex_unlock(&afe->irq_alloc_lock);
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release);
+
+int mtk_afe_suspend(struct snd_soc_component *component)
+{
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ struct device *dev = afe->dev;
+ struct regmap *regmap = afe->regmap;
+ int i;
+
+ if (pm_runtime_status_suspended(dev) || afe->suspended)
+ return 0;
+
+ if (!afe->reg_back_up)
+ afe->reg_back_up =
+ devm_kcalloc(dev, afe->reg_back_up_list_num,
+ sizeof(unsigned int), GFP_KERNEL);
+
+ for (i = 0; i < afe->reg_back_up_list_num; i++)
+ regmap_read(regmap, afe->reg_back_up_list[i],
+ &afe->reg_back_up[i]);
+
+ afe->suspended = true;
+ afe->runtime_suspend(dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_suspend);
+
+int mtk_afe_resume(struct snd_soc_component *component)
+{
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ struct device *dev = afe->dev;
+ struct regmap *regmap = afe->regmap;
+ int i = 0;
+
+ if (pm_runtime_status_suspended(dev) || !afe->suspended)
+ return 0;
+
+ afe->runtime_resume(dev);
+
+ if (!afe->reg_back_up)
+ dev_dbg(dev, "%s no reg_backup\n", __func__);
+
+ for (i = 0; i < afe->reg_back_up_list_num; i++)
+ mtk_regmap_write(regmap, afe->reg_back_up_list[i],
+ afe->reg_back_up[i]);
+
+ afe->suspended = false;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_resume);
+
+int mtk_memif_set_enable(struct mtk_base_afe *afe, int id)
+{
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+
+ if (memif->data->enable_shift < 0) {
+ dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n",
+ __func__, id);
+ return 0;
+ }
+ return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,
+ 1, 1, memif->data->enable_shift);
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_enable);
+
+int mtk_memif_set_disable(struct mtk_base_afe *afe, int id)
+{
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+
+ if (memif->data->enable_shift < 0) {
+ dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n",
+ __func__, id);
+ return 0;
+ }
+ return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,
+ 1, 0, memif->data->enable_shift);
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_disable);
+
+int mtk_memif_set_addr(struct mtk_base_afe *afe, int id,
+ unsigned char *dma_area,
+ dma_addr_t dma_addr,
+ size_t dma_bytes)
+{
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+ int msb_at_bit33 = upper_32_bits(dma_addr) ? 1 : 0;
+ unsigned int phys_buf_addr = lower_32_bits(dma_addr);
+ unsigned int phys_buf_addr_upper_32 = upper_32_bits(dma_addr);
+
+ memif->dma_area = dma_area;
+ memif->dma_addr = dma_addr;
+ memif->dma_bytes = dma_bytes;
+
+ /* start */
+ mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base,
+ phys_buf_addr);
+ /* end */
+ if (memif->data->reg_ofs_end)
+ mtk_regmap_write(afe->regmap,
+ memif->data->reg_ofs_end,
+ phys_buf_addr + dma_bytes - 1);
+ else
+ mtk_regmap_write(afe->regmap,
+ memif->data->reg_ofs_base +
+ AFE_BASE_END_OFFSET,
+ phys_buf_addr + dma_bytes - 1);
+
+ /* set start, end, upper 32 bits */
+ if (memif->data->reg_ofs_base_msb) {
+ mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base_msb,
+ phys_buf_addr_upper_32);
+ mtk_regmap_write(afe->regmap,
+ memif->data->reg_ofs_end_msb,
+ phys_buf_addr_upper_32);
+ }
+
+ /* set MSB to 33-bit */
+ if (memif->data->msb_reg >= 0)
+ mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg,
+ 1, msb_at_bit33, memif->data->msb_shift);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_addr);
+
+int mtk_memif_set_channel(struct mtk_base_afe *afe,
+ int id, unsigned int channel)
+{
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+ unsigned int mono;
+
+ if (memif->data->mono_shift < 0)
+ return 0;
+
+ if (memif->data->quad_ch_mask) {
+ unsigned int quad_ch = (channel == 4) ? 1 : 0;
+
+ mtk_regmap_update_bits(afe->regmap, memif->data->quad_ch_reg,
+ memif->data->quad_ch_mask,
+ quad_ch, memif->data->quad_ch_shift);
+ }
+
+ if (memif->data->mono_invert)
+ mono = (channel == 1) ? 0 : 1;
+ else
+ mono = (channel == 1) ? 1 : 0;
+
+ return mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
+ 1, mono, memif->data->mono_shift);
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_channel);
+
+static int mtk_memif_set_rate_fs(struct mtk_base_afe *afe,
+ int id, int fs)
+{
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+
+ if (memif->data->fs_shift >= 0)
+ mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg,
+ memif->data->fs_maskbit,
+ fs, memif->data->fs_shift);
+
+ return 0;
+}
+
+int mtk_memif_set_rate(struct mtk_base_afe *afe,
+ int id, unsigned int rate)
+{
+ int fs = 0;
+
+ if (!afe->get_dai_fs) {
+ dev_err(afe->dev, "%s(), error, afe->get_dai_fs == NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ fs = afe->get_dai_fs(afe, id, rate);
+
+ if (fs < 0)
+ return -EINVAL;
+
+ return mtk_memif_set_rate_fs(afe, id, fs);
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_rate);
+
+int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream,
+ int id, unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+ int fs = 0;
+
+ if (!afe->memif_fs) {
+ dev_err(afe->dev, "%s(), error, afe->memif_fs == NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ fs = afe->memif_fs(substream, rate);
+
+ if (fs < 0)
+ return -EINVAL;
+
+ return mtk_memif_set_rate_fs(afe, id, fs);
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_rate_substream);
+
+int mtk_memif_set_format(struct mtk_base_afe *afe,
+ int id, snd_pcm_format_t format)
+{
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+ int hd_audio = 0;
+ int hd_align = 0;
+
+ /* set hd mode */
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_U16_LE:
+ hd_audio = 0;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_U32_LE:
+ hd_audio = 1;
+ hd_align = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_U24_LE:
+ hd_audio = 1;
+ break;
+ default:
+ dev_err(afe->dev, "%s() error: unsupported format %d\n",
+ __func__, format);
+ break;
+ }
+
+ mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
+ 1, hd_audio, memif->data->hd_shift);
+
+ mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg,
+ 1, hd_align, memif->data->hd_align_mshift);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_format);
+
+int mtk_memif_set_pbuf_size(struct mtk_base_afe *afe,
+ int id, int pbuf_size)
+{
+ const struct mtk_base_memif_data *memif_data = afe->memif[id].data;
+
+ if (memif_data->pbuf_mask == 0 || memif_data->minlen_mask == 0)
+ return 0;
+
+ mtk_regmap_update_bits(afe->regmap, memif_data->pbuf_reg,
+ memif_data->pbuf_mask,
+ pbuf_size, memif_data->pbuf_shift);
+
+ mtk_regmap_update_bits(afe->regmap, memif_data->minlen_reg,
+ memif_data->minlen_mask,
+ pbuf_size, memif_data->minlen_shift);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_pbuf_size);
+
+MODULE_DESCRIPTION("Mediatek simple fe dai operator");
+MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.h b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
new file mode 100644
index 000000000..8cec90671
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtk-afe-fe-dais.h -- Mediatek afe fe dai operator definition
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ */
+
+#ifndef _MTK_AFE_FE_DAI_H_
+#define _MTK_AFE_FE_DAI_H_
+
+struct snd_soc_dai_ops;
+struct mtk_base_afe;
+struct mtk_base_afe_memif;
+
+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,
+ struct snd_soc_dai *dai);
+int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai);
+int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai);
+
+extern const struct snd_soc_dai_ops mtk_afe_fe_ops;
+
+int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe);
+int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id);
+int mtk_afe_suspend(struct snd_soc_component *component);
+int mtk_afe_resume(struct snd_soc_component *component);
+
+int mtk_memif_set_enable(struct mtk_base_afe *afe, int id);
+int mtk_memif_set_disable(struct mtk_base_afe *afe, int id);
+int mtk_memif_set_addr(struct mtk_base_afe *afe, int id,
+ unsigned char *dma_area,
+ dma_addr_t dma_addr,
+ size_t dma_bytes);
+int mtk_memif_set_channel(struct mtk_base_afe *afe,
+ int id, unsigned int channel);
+int mtk_memif_set_rate(struct mtk_base_afe *afe,
+ int id, unsigned int rate);
+int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream,
+ int id, unsigned int rate);
+int mtk_memif_set_format(struct mtk_base_afe *afe,
+ int id, snd_pcm_format_t format);
+int mtk_memif_set_pbuf_size(struct mtk_base_afe *afe,
+ int id, int pbuf_size);
+#endif
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
new file mode 100644
index 000000000..01501d574
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtk-afe-platform-driver.c -- Mediatek afe platform driver
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <sound/soc.h>
+
+#include "mtk-afe-platform-driver.h"
+#include "mtk-base-afe.h"
+
+int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+ size_t num_dai_drivers = 0, dai_idx = 0;
+
+ /* calcualte total dai driver size */
+ list_for_each_entry(dai, &afe->sub_dais, list) {
+ num_dai_drivers += dai->num_dai_drivers;
+ }
+
+ dev_info(afe->dev, "%s(), num of dai %zd\n", __func__, num_dai_drivers);
+
+ /* combine sub_dais */
+ afe->num_dai_drivers = num_dai_drivers;
+ afe->dai_drivers = devm_kcalloc(afe->dev,
+ num_dai_drivers,
+ sizeof(struct snd_soc_dai_driver),
+ GFP_KERNEL);
+ if (!afe->dai_drivers)
+ return -ENOMEM;
+
+ list_for_each_entry(dai, &afe->sub_dais, list) {
+ /* dai driver */
+ memcpy(&afe->dai_drivers[dai_idx],
+ dai->dai_drivers,
+ dai->num_dai_drivers *
+ sizeof(struct snd_soc_dai_driver));
+ dai_idx += dai->num_dai_drivers;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai);
+
+int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
+{
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ struct mtk_base_afe_dai *dai;
+
+ list_for_each_entry(dai, &afe->sub_dais, list) {
+ if (dai->controls)
+ snd_soc_add_component_controls(component,
+ dai->controls,
+ dai->num_controls);
+
+ if (dai->dapm_widgets)
+ snd_soc_dapm_new_controls(&component->dapm,
+ dai->dapm_widgets,
+ dai->num_dapm_widgets);
+ }
+ /* add routes after all widgets are added */
+ list_for_each_entry(dai, &afe->sub_dais, list) {
+ if (dai->dapm_routes)
+ snd_soc_dapm_add_routes(&component->dapm,
+ dai->dapm_routes,
+ dai->num_dapm_routes);
+ }
+
+ snd_soc_dapm_new_widgets(component->dapm.card);
+
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control);
+
+snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id];
+ const struct mtk_base_memif_data *memif_data = memif->data;
+ struct regmap *regmap = afe->regmap;
+ struct device *dev = afe->dev;
+ int reg_ofs_base = memif_data->reg_ofs_base;
+ int reg_ofs_cur = memif_data->reg_ofs_cur;
+ unsigned int hw_ptr = 0, hw_base = 0;
+ int ret, pcm_ptr_bytes;
+
+ ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr);
+ if (ret || hw_ptr == 0) {
+ dev_err(dev, "%s hw_ptr err\n", __func__);
+ pcm_ptr_bytes = 0;
+ goto POINTER_RETURN_FRAMES;
+ }
+
+ 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;
+ }
+
+ pcm_ptr_bytes = hw_ptr - hw_base;
+
+POINTER_RETURN_FRAMES:
+ return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
+}
+EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer);
+
+int mtk_afe_pcm_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd)
+{
+ size_t size;
+ struct snd_pcm *pcm = rtd->pcm;
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+ size = afe->mtk_afe_hardware->buffer_bytes_max;
+ snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
+ afe->dev, size, size);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_pcm_new);
+
+const struct snd_soc_component_driver mtk_afe_pcm_platform = {
+ .name = AFE_PCM_NAME,
+ .pointer = mtk_afe_pcm_pointer,
+ .pcm_construct = mtk_afe_pcm_new,
+};
+EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform);
+
+MODULE_DESCRIPTION("Mediatek simple platform driver");
+MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.h b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
new file mode 100644
index 000000000..fcc923b88
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtk-afe-platform-driver.h -- Mediatek afe platform driver definition
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ */
+
+#ifndef _MTK_AFE_PLATFORM_DRIVER_H_
+#define _MTK_AFE_PLATFORM_DRIVER_H_
+
+#define AFE_PCM_NAME "mtk-afe-pcm"
+extern const struct snd_soc_component_driver mtk_afe_pcm_platform;
+
+struct mtk_base_afe;
+struct snd_pcm;
+struct snd_soc_component;
+struct snd_soc_pcm_runtime;
+
+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);
+
+int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe);
+int mtk_afe_add_sub_dai_control(struct snd_soc_component *component);
+#endif
+
diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h
new file mode 100644
index 000000000..a8cf44d98
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-base-afe.h
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtk-base-afe.h -- Mediatek base afe structure
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ */
+
+#ifndef _MTK_BASE_AFE_H_
+#define _MTK_BASE_AFE_H_
+
+#define MTK_STREAM_NUM (SNDRV_PCM_STREAM_LAST + 1)
+
+struct mtk_base_memif_data {
+ int id;
+ const char *name;
+ int reg_ofs_base;
+ int reg_ofs_cur;
+ int reg_ofs_end;
+ int reg_ofs_base_msb;
+ int reg_ofs_cur_msb;
+ int reg_ofs_end_msb;
+ int fs_reg;
+ int fs_shift;
+ int fs_maskbit;
+ int mono_reg;
+ int mono_shift;
+ int mono_invert;
+ int quad_ch_reg;
+ int quad_ch_mask;
+ int quad_ch_shift;
+ int enable_reg;
+ int enable_shift;
+ int hd_reg;
+ int hd_shift;
+ int hd_align_reg;
+ int hd_align_mshift;
+ int msb_reg;
+ int msb_shift;
+ int msb2_reg;
+ int msb2_shift;
+ int agent_disable_reg;
+ int agent_disable_shift;
+ /* playback memif only */
+ int pbuf_reg;
+ int pbuf_mask;
+ int pbuf_shift;
+ int minlen_reg;
+ int minlen_mask;
+ int minlen_shift;
+};
+
+struct mtk_base_irq_data {
+ int id;
+ int irq_cnt_reg;
+ int irq_cnt_shift;
+ int irq_cnt_maskbit;
+ int irq_fs_reg;
+ int irq_fs_shift;
+ int irq_fs_maskbit;
+ int irq_en_reg;
+ int irq_en_shift;
+ int irq_clr_reg;
+ int irq_clr_shift;
+};
+
+struct device;
+struct list_head;
+struct mtk_base_afe_memif;
+struct mtk_base_afe_irq;
+struct mtk_base_afe_dai;
+struct regmap;
+struct snd_pcm_substream;
+struct snd_soc_dai;
+
+struct mtk_base_afe {
+ void __iomem *base_addr;
+ struct device *dev;
+ struct regmap *regmap;
+ struct mutex irq_alloc_lock; /* dynamic alloc irq lock */
+
+ unsigned int const *reg_back_up_list;
+ unsigned int *reg_back_up;
+ unsigned int reg_back_up_list_num;
+
+ int (*runtime_suspend)(struct device *dev);
+ int (*runtime_resume)(struct device *dev);
+ bool suspended;
+
+ struct mtk_base_afe_memif *memif;
+ int memif_size;
+ struct mtk_base_afe_irq *irqs;
+ int irqs_size;
+
+ struct list_head sub_dais;
+ struct snd_soc_dai_driver *dai_drivers;
+ unsigned int num_dai_drivers;
+
+ const struct snd_pcm_hardware *mtk_afe_hardware;
+ int (*memif_fs)(struct snd_pcm_substream *substream,
+ unsigned int rate);
+ int (*irq_fs)(struct snd_pcm_substream *substream,
+ unsigned int rate);
+ int (*get_dai_fs)(struct mtk_base_afe *afe,
+ int dai_id, unsigned int rate);
+ int (*get_memif_pbuf_size)(struct snd_pcm_substream *substream);
+
+ int (*request_dram_resource)(struct device *dev);
+ int (*release_dram_resource)(struct device *dev);
+
+ void *platform_priv;
+};
+
+struct mtk_base_afe_memif {
+ unsigned int phys_buf_addr;
+ int buffer_size;
+ struct snd_pcm_substream *substream;
+ const struct mtk_base_memif_data *data;
+ int irq_usage;
+ int const_irq;
+ unsigned char *dma_area;
+ dma_addr_t dma_addr;
+ size_t dma_bytes;
+};
+
+struct mtk_base_afe_irq {
+ const struct mtk_base_irq_data *irq_data;
+ int irq_occupyed;
+};
+
+struct mtk_base_afe_dai {
+ struct snd_soc_dai_driver *dai_drivers;
+ unsigned int num_dai_drivers;
+
+ const struct snd_kcontrol_new *controls;
+ unsigned int num_controls;
+ const struct snd_soc_dapm_widget *dapm_widgets;
+ unsigned int num_dapm_widgets;
+ const struct snd_soc_dapm_route *dapm_routes;
+ unsigned int num_dapm_routes;
+
+ struct list_head list;
+};
+
+#endif
+
diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c
new file mode 100644
index 000000000..e1f57b0de
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-btcvsd.c
@@ -0,0 +1,1418 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Mediatek ALSA BT SCO CVSD/MSBC Driver
+//
+// Copyright (c) 2019 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/sched/clock.h>
+
+#include <sound/soc.h>
+
+#define BTCVSD_SND_NAME "mtk-btcvsd-snd"
+
+#define BT_CVSD_TX_NREADY BIT(21)
+#define BT_CVSD_RX_READY BIT(22)
+#define BT_CVSD_TX_UNDERFLOW BIT(23)
+#define BT_CVSD_RX_OVERFLOW BIT(24)
+#define BT_CVSD_INTERRUPT BIT(31)
+
+#define BT_CVSD_CLEAR \
+ (BT_CVSD_TX_NREADY | BT_CVSD_RX_READY | BT_CVSD_TX_UNDERFLOW |\
+ BT_CVSD_RX_OVERFLOW | BT_CVSD_INTERRUPT)
+
+/* TX */
+#define SCO_TX_ENCODE_SIZE (60)
+/* 18 = 6 * 180 / SCO_TX_ENCODE_SIZE */
+#define SCO_TX_PACKER_BUF_NUM (18)
+
+/* RX */
+#define SCO_RX_PLC_SIZE (30)
+#define SCO_RX_PACKER_BUF_NUM (64)
+#define SCO_RX_PACKET_MASK (0x3F)
+
+#define SCO_CVSD_PACKET_VALID_SIZE 2
+
+#define SCO_PACKET_120 120
+#define SCO_PACKET_180 180
+
+#define BTCVSD_RX_PACKET_SIZE (SCO_RX_PLC_SIZE + SCO_CVSD_PACKET_VALID_SIZE)
+#define BTCVSD_TX_PACKET_SIZE (SCO_TX_ENCODE_SIZE)
+
+#define BTCVSD_RX_BUF_SIZE (BTCVSD_RX_PACKET_SIZE * SCO_RX_PACKER_BUF_NUM)
+#define BTCVSD_TX_BUF_SIZE (BTCVSD_TX_PACKET_SIZE * SCO_TX_PACKER_BUF_NUM)
+
+enum bt_sco_state {
+ BT_SCO_STATE_IDLE,
+ BT_SCO_STATE_RUNNING,
+ BT_SCO_STATE_ENDING,
+ BT_SCO_STATE_LOOPBACK,
+};
+
+enum bt_sco_direct {
+ BT_SCO_DIRECT_BT2ARM,
+ BT_SCO_DIRECT_ARM2BT,
+};
+
+enum bt_sco_packet_len {
+ BT_SCO_CVSD_30 = 0,
+ BT_SCO_CVSD_60,
+ BT_SCO_CVSD_90,
+ BT_SCO_CVSD_120,
+ BT_SCO_CVSD_10,
+ BT_SCO_CVSD_20,
+ BT_SCO_CVSD_MAX,
+};
+
+enum BT_SCO_BAND {
+ BT_SCO_NB,
+ BT_SCO_WB,
+};
+
+struct mtk_btcvsd_snd_hw_info {
+ unsigned int num_valid_addr;
+ unsigned long bt_sram_addr[20];
+ unsigned int packet_length;
+ unsigned int packet_num;
+};
+
+struct mtk_btcvsd_snd_stream {
+ struct snd_pcm_substream *substream;
+ int stream;
+
+ enum bt_sco_state state;
+
+ unsigned int packet_size;
+ unsigned int buf_size;
+ u8 temp_packet_buf[SCO_PACKET_180];
+
+ int packet_w;
+ int packet_r;
+ snd_pcm_uframes_t prev_frame;
+ int prev_packet_idx;
+
+ unsigned int xrun:1;
+ unsigned int timeout:1;
+ unsigned int mute:1;
+ unsigned int trigger_start:1;
+ unsigned int wait_flag:1;
+ unsigned int rw_cnt;
+
+ unsigned long long time_stamp;
+ unsigned long long buf_data_equivalent_time;
+
+ struct mtk_btcvsd_snd_hw_info buffer_info;
+};
+
+struct mtk_btcvsd_snd {
+ struct device *dev;
+ int irq_id;
+
+ struct regmap *infra;
+ void __iomem *bt_pkv_base;
+ void __iomem *bt_sram_bank2_base;
+
+ unsigned int infra_misc_offset;
+ unsigned int conn_bt_cvsd_mask;
+ unsigned int cvsd_mcu_read_offset;
+ unsigned int cvsd_mcu_write_offset;
+ unsigned int cvsd_packet_indicator;
+
+ u32 *bt_reg_pkt_r;
+ u32 *bt_reg_pkt_w;
+ u32 *bt_reg_ctl;
+
+ unsigned int irq_disabled:1;
+
+ spinlock_t tx_lock; /* spinlock for bt tx stream control */
+ spinlock_t rx_lock; /* spinlock for bt rx stream control */
+ wait_queue_head_t tx_wait;
+ wait_queue_head_t rx_wait;
+
+ struct mtk_btcvsd_snd_stream *tx;
+ struct mtk_btcvsd_snd_stream *rx;
+ u8 tx_packet_buf[BTCVSD_TX_BUF_SIZE];
+ u8 rx_packet_buf[BTCVSD_RX_BUF_SIZE];
+
+ enum BT_SCO_BAND band;
+};
+
+struct mtk_btcvsd_snd_time_buffer_info {
+ unsigned long long data_count_equi_time;
+ unsigned long long time_stamp_us;
+};
+
+static const unsigned int btsco_packet_valid_mask[BT_SCO_CVSD_MAX][6] = {
+ {0x1, 0x1 << 1, 0x1 << 2, 0x1 << 3, 0x1 << 4, 0x1 << 5},
+ {0x1, 0x1, 0x2, 0x2, 0x4, 0x4},
+ {0x1, 0x1, 0x1, 0x2, 0x2, 0x2},
+ {0x1, 0x1, 0x1, 0x1, 0x0, 0x0},
+ {0x7, 0x7 << 3, 0x7 << 6, 0x7 << 9, 0x7 << 12, 0x7 << 15},
+ {0x3, 0x3 << 1, 0x3 << 3, 0x3 << 4, 0x3 << 6, 0x3 << 7},
+};
+
+static const unsigned int btsco_packet_info[BT_SCO_CVSD_MAX][4] = {
+ {30, 6, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE,
+ SCO_PACKET_180 / SCO_RX_PLC_SIZE},
+ {60, 3, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE,
+ SCO_PACKET_180 / SCO_RX_PLC_SIZE},
+ {90, 2, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE,
+ SCO_PACKET_180 / SCO_RX_PLC_SIZE},
+ {120, 1, SCO_PACKET_120 / SCO_TX_ENCODE_SIZE,
+ SCO_PACKET_120 / SCO_RX_PLC_SIZE},
+ {10, 18, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE,
+ SCO_PACKET_180 / SCO_RX_PLC_SIZE},
+ {20, 9, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE,
+ SCO_PACKET_180 / SCO_RX_PLC_SIZE},
+};
+
+static const u8 table_msbc_silence[SCO_PACKET_180] = {
+ 0x01, 0x38, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00,
+ 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d,
+ 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7,
+ 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd,
+ 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77,
+ 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00,
+ 0x01, 0xc8, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00,
+ 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d,
+ 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7,
+ 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd,
+ 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77,
+ 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00,
+ 0x01, 0xf8, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00,
+ 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d,
+ 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7,
+ 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd,
+ 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77,
+ 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00
+};
+
+static void mtk_btcvsd_snd_irq_enable(struct mtk_btcvsd_snd *bt)
+{
+ regmap_update_bits(bt->infra, bt->infra_misc_offset,
+ bt->conn_bt_cvsd_mask, 0);
+}
+
+static void mtk_btcvsd_snd_irq_disable(struct mtk_btcvsd_snd *bt)
+{
+ regmap_update_bits(bt->infra, bt->infra_misc_offset,
+ bt->conn_bt_cvsd_mask, bt->conn_bt_cvsd_mask);
+}
+
+static void mtk_btcvsd_snd_set_state(struct mtk_btcvsd_snd *bt,
+ struct mtk_btcvsd_snd_stream *bt_stream,
+ int state)
+{
+ dev_dbg(bt->dev, "%s(), stream %d, state %d, tx->state %d, rx->state %d, irq_disabled %d\n",
+ __func__,
+ bt_stream->stream, state,
+ bt->tx->state, bt->rx->state, bt->irq_disabled);
+
+ bt_stream->state = state;
+
+ if (bt->tx->state == BT_SCO_STATE_IDLE &&
+ bt->rx->state == BT_SCO_STATE_IDLE) {
+ if (!bt->irq_disabled) {
+ disable_irq(bt->irq_id);
+ mtk_btcvsd_snd_irq_disable(bt);
+ bt->irq_disabled = 1;
+ }
+ } else {
+ if (bt->irq_disabled) {
+ enable_irq(bt->irq_id);
+ mtk_btcvsd_snd_irq_enable(bt);
+ bt->irq_disabled = 0;
+ }
+ }
+}
+
+static int mtk_btcvsd_snd_tx_init(struct mtk_btcvsd_snd *bt)
+{
+ memset(bt->tx, 0, sizeof(*bt->tx));
+ memset(bt->tx_packet_buf, 0, sizeof(bt->tx_packet_buf));
+
+ bt->tx->packet_size = BTCVSD_TX_PACKET_SIZE;
+ bt->tx->buf_size = BTCVSD_TX_BUF_SIZE;
+ bt->tx->timeout = 0;
+ bt->tx->rw_cnt = 0;
+ bt->tx->stream = SNDRV_PCM_STREAM_PLAYBACK;
+ return 0;
+}
+
+static int mtk_btcvsd_snd_rx_init(struct mtk_btcvsd_snd *bt)
+{
+ memset(bt->rx, 0, sizeof(*bt->rx));
+ memset(bt->rx_packet_buf, 0, sizeof(bt->rx_packet_buf));
+
+ bt->rx->packet_size = BTCVSD_RX_PACKET_SIZE;
+ bt->rx->buf_size = BTCVSD_RX_BUF_SIZE;
+ bt->rx->timeout = 0;
+ bt->rx->rw_cnt = 0;
+ bt->rx->stream = SNDRV_PCM_STREAM_CAPTURE;
+ return 0;
+}
+
+static void get_tx_time_stamp(struct mtk_btcvsd_snd *bt,
+ struct mtk_btcvsd_snd_time_buffer_info *ts)
+{
+ ts->time_stamp_us = bt->tx->time_stamp;
+ ts->data_count_equi_time = bt->tx->buf_data_equivalent_time;
+}
+
+static void get_rx_time_stamp(struct mtk_btcvsd_snd *bt,
+ struct mtk_btcvsd_snd_time_buffer_info *ts)
+{
+ ts->time_stamp_us = bt->rx->time_stamp;
+ ts->data_count_equi_time = bt->rx->buf_data_equivalent_time;
+}
+
+static int btcvsd_bytes_to_frame(struct snd_pcm_substream *substream,
+ int bytes)
+{
+ int count = bytes;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ if (runtime->format == SNDRV_PCM_FORMAT_S32_LE ||
+ runtime->format == SNDRV_PCM_FORMAT_U32_LE)
+ count = count >> 2;
+ else
+ count = count >> 1;
+
+ count = count / runtime->channels;
+ return count;
+}
+
+static void mtk_btcvsd_snd_data_transfer(enum bt_sco_direct dir,
+ u8 *src, u8 *dst,
+ unsigned int blk_size,
+ unsigned int blk_num)
+{
+ unsigned int i, j;
+
+ if (blk_size == 60 || blk_size == 120 || blk_size == 20) {
+ u32 *src_32 = (u32 *)src;
+ u32 *dst_32 = (u32 *)dst;
+
+ for (i = 0; i < (blk_size * blk_num / 4); i++)
+ *dst_32++ = *src_32++;
+ } else {
+ u16 *src_16 = (u16 *)src;
+ u16 *dst_16 = (u16 *)dst;
+
+ for (j = 0; j < blk_num; j++) {
+ for (i = 0; i < (blk_size / 2); i++)
+ *dst_16++ = *src_16++;
+
+ if (dir == BT_SCO_DIRECT_BT2ARM)
+ src_16++;
+ else
+ dst_16++;
+ }
+ }
+}
+
+/* write encoded mute data to bt sram */
+static int btcvsd_tx_clean_buffer(struct mtk_btcvsd_snd *bt)
+{
+ unsigned int i;
+ unsigned int num_valid_addr;
+ unsigned long flags;
+ enum BT_SCO_BAND band = bt->band;
+
+ /* prepare encoded mute data */
+ if (band == BT_SCO_NB)
+ memset(bt->tx->temp_packet_buf, 170, SCO_PACKET_180);
+ else
+ memcpy(bt->tx->temp_packet_buf,
+ table_msbc_silence, SCO_PACKET_180);
+
+ /* write mute data to bt tx sram buffer */
+ spin_lock_irqsave(&bt->tx_lock, flags);
+ num_valid_addr = bt->tx->buffer_info.num_valid_addr;
+
+ dev_info(bt->dev, "%s(), band %d, num_valid_addr %u\n",
+ __func__, band, num_valid_addr);
+
+ for (i = 0; i < num_valid_addr; i++) {
+ void *dst;
+
+ dev_info(bt->dev, "%s(), clean addr 0x%lx\n", __func__,
+ bt->tx->buffer_info.bt_sram_addr[i]);
+
+ dst = (void *)bt->tx->buffer_info.bt_sram_addr[i];
+
+ mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_ARM2BT,
+ bt->tx->temp_packet_buf, dst,
+ bt->tx->buffer_info.packet_length,
+ bt->tx->buffer_info.packet_num);
+ }
+ spin_unlock_irqrestore(&bt->tx_lock, flags);
+
+ return 0;
+}
+
+static int mtk_btcvsd_read_from_bt(struct mtk_btcvsd_snd *bt,
+ enum bt_sco_packet_len packet_type,
+ unsigned int packet_length,
+ unsigned int packet_num,
+ unsigned int blk_size,
+ unsigned int control)
+{
+ unsigned int i;
+ int pv;
+ u8 *src;
+ unsigned int packet_buf_ofs;
+ unsigned long flags;
+ unsigned long connsys_addr_rx, ap_addr_rx;
+
+ connsys_addr_rx = *bt->bt_reg_pkt_r;
+ ap_addr_rx = (unsigned long)bt->bt_sram_bank2_base +
+ (connsys_addr_rx & 0xFFFF);
+
+ if (connsys_addr_rx == 0xdeadfeed) {
+ /* bt return 0xdeadfeed if read register during bt sleep */
+ dev_warn(bt->dev, "%s(), connsys_addr_rx == 0xdeadfeed",
+ __func__);
+ return -EIO;
+ }
+
+ src = (u8 *)ap_addr_rx;
+
+ mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_BT2ARM, src,
+ bt->rx->temp_packet_buf, packet_length,
+ packet_num);
+
+ spin_lock_irqsave(&bt->rx_lock, flags);
+ for (i = 0; i < blk_size; i++) {
+ packet_buf_ofs = (bt->rx->packet_w & SCO_RX_PACKET_MASK) *
+ bt->rx->packet_size;
+ memcpy(bt->rx_packet_buf + packet_buf_ofs,
+ bt->rx->temp_packet_buf + (SCO_RX_PLC_SIZE * i),
+ SCO_RX_PLC_SIZE);
+ if ((control & btsco_packet_valid_mask[packet_type][i]) ==
+ btsco_packet_valid_mask[packet_type][i])
+ pv = 1;
+ else
+ pv = 0;
+
+ packet_buf_ofs += SCO_RX_PLC_SIZE;
+ memcpy(bt->rx_packet_buf + packet_buf_ofs, (void *)&pv,
+ SCO_CVSD_PACKET_VALID_SIZE);
+ bt->rx->packet_w++;
+ }
+ spin_unlock_irqrestore(&bt->rx_lock, flags);
+ return 0;
+}
+
+static int mtk_btcvsd_write_to_bt(struct mtk_btcvsd_snd *bt,
+ enum bt_sco_packet_len packet_type,
+ unsigned int packet_length,
+ unsigned int packet_num,
+ unsigned int blk_size)
+{
+ unsigned int i;
+ unsigned long flags;
+ u8 *dst;
+ unsigned long connsys_addr_tx, ap_addr_tx;
+ bool new_ap_addr_tx = true;
+
+ connsys_addr_tx = *bt->bt_reg_pkt_w;
+ ap_addr_tx = (unsigned long)bt->bt_sram_bank2_base +
+ (connsys_addr_tx & 0xFFFF);
+
+ if (connsys_addr_tx == 0xdeadfeed) {
+ /* bt return 0xdeadfeed if read register during bt sleep */
+ dev_warn(bt->dev, "%s(), connsys_addr_tx == 0xdeadfeed\n",
+ __func__);
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&bt->tx_lock, flags);
+ for (i = 0; i < blk_size; i++) {
+ memcpy(bt->tx->temp_packet_buf + (bt->tx->packet_size * i),
+ (bt->tx_packet_buf +
+ (bt->tx->packet_r % SCO_TX_PACKER_BUF_NUM) *
+ bt->tx->packet_size),
+ bt->tx->packet_size);
+
+ bt->tx->packet_r++;
+ }
+ spin_unlock_irqrestore(&bt->tx_lock, flags);
+
+ dst = (u8 *)ap_addr_tx;
+
+ if (!bt->tx->mute) {
+ mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_ARM2BT,
+ bt->tx->temp_packet_buf, dst,
+ packet_length, packet_num);
+ }
+
+ /* store bt tx buffer sram info */
+ bt->tx->buffer_info.packet_length = packet_length;
+ bt->tx->buffer_info.packet_num = packet_num;
+ for (i = 0; i < bt->tx->buffer_info.num_valid_addr; i++) {
+ if (bt->tx->buffer_info.bt_sram_addr[i] == ap_addr_tx) {
+ new_ap_addr_tx = false;
+ break;
+ }
+ }
+ if (new_ap_addr_tx) {
+ unsigned int next_idx;
+
+ spin_lock_irqsave(&bt->tx_lock, flags);
+ bt->tx->buffer_info.num_valid_addr++;
+ next_idx = bt->tx->buffer_info.num_valid_addr - 1;
+ bt->tx->buffer_info.bt_sram_addr[next_idx] = ap_addr_tx;
+ spin_unlock_irqrestore(&bt->tx_lock, flags);
+ dev_info(bt->dev, "%s(), new ap_addr_tx = 0x%lx, num_valid_addr %d\n",
+ __func__, ap_addr_tx,
+ bt->tx->buffer_info.num_valid_addr);
+ }
+
+ if (bt->tx->mute)
+ btcvsd_tx_clean_buffer(bt);
+
+ return 0;
+}
+
+static irqreturn_t mtk_btcvsd_snd_irq_handler(int irq_id, void *dev)
+{
+ struct mtk_btcvsd_snd *bt = dev;
+ unsigned int packet_type, packet_num, packet_length;
+ unsigned int buf_cnt_tx, buf_cnt_rx, control;
+
+ if (bt->rx->state != BT_SCO_STATE_RUNNING &&
+ bt->rx->state != BT_SCO_STATE_ENDING &&
+ bt->tx->state != BT_SCO_STATE_RUNNING &&
+ bt->tx->state != BT_SCO_STATE_ENDING &&
+ bt->tx->state != BT_SCO_STATE_LOOPBACK) {
+ dev_warn(bt->dev, "%s(), in idle state: rx->state: %d, tx->state: %d\n",
+ __func__, bt->rx->state, bt->tx->state);
+ goto irq_handler_exit;
+ }
+
+ control = *bt->bt_reg_ctl;
+ packet_type = (control >> 18) & 0x7;
+
+ if (((control >> 31) & 1) == 0) {
+ dev_warn(bt->dev, "%s(), ((control >> 31) & 1) == 0, control 0x%x\n",
+ __func__, control);
+ goto irq_handler_exit;
+ }
+
+ if (packet_type >= BT_SCO_CVSD_MAX) {
+ dev_warn(bt->dev, "%s(), invalid packet_type %u, exit\n",
+ __func__, packet_type);
+ goto irq_handler_exit;
+ }
+
+ packet_length = btsco_packet_info[packet_type][0];
+ packet_num = btsco_packet_info[packet_type][1];
+ buf_cnt_tx = btsco_packet_info[packet_type][2];
+ buf_cnt_rx = btsco_packet_info[packet_type][3];
+
+ if (bt->tx->state == BT_SCO_STATE_LOOPBACK) {
+ u8 *src, *dst;
+ unsigned long connsys_addr_rx, ap_addr_rx;
+ unsigned long connsys_addr_tx, ap_addr_tx;
+
+ connsys_addr_rx = *bt->bt_reg_pkt_r;
+ ap_addr_rx = (unsigned long)bt->bt_sram_bank2_base +
+ (connsys_addr_rx & 0xFFFF);
+
+ connsys_addr_tx = *bt->bt_reg_pkt_w;
+ ap_addr_tx = (unsigned long)bt->bt_sram_bank2_base +
+ (connsys_addr_tx & 0xFFFF);
+
+ if (connsys_addr_tx == 0xdeadfeed ||
+ connsys_addr_rx == 0xdeadfeed) {
+ /* bt return 0xdeadfeed if read reg during bt sleep */
+ dev_warn(bt->dev, "%s(), connsys_addr_tx == 0xdeadfeed\n",
+ __func__);
+ goto irq_handler_exit;
+ }
+
+ src = (u8 *)ap_addr_rx;
+ dst = (u8 *)ap_addr_tx;
+
+ mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_BT2ARM, src,
+ bt->tx->temp_packet_buf,
+ packet_length,
+ packet_num);
+ mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_ARM2BT,
+ bt->tx->temp_packet_buf, dst,
+ packet_length,
+ packet_num);
+ bt->rx->rw_cnt++;
+ bt->tx->rw_cnt++;
+ }
+
+ if (bt->rx->state == BT_SCO_STATE_RUNNING ||
+ bt->rx->state == BT_SCO_STATE_ENDING) {
+ if (bt->rx->xrun) {
+ if (bt->rx->packet_w - bt->rx->packet_r <=
+ SCO_RX_PACKER_BUF_NUM - 2 * buf_cnt_rx) {
+ /*
+ * free space is larger then
+ * twice interrupt rx data size
+ */
+ bt->rx->xrun = 0;
+ dev_warn(bt->dev, "%s(), rx->xrun 0!\n",
+ __func__);
+ }
+ }
+
+ if (!bt->rx->xrun &&
+ (bt->rx->packet_w - bt->rx->packet_r <=
+ SCO_RX_PACKER_BUF_NUM - buf_cnt_rx)) {
+ mtk_btcvsd_read_from_bt(bt,
+ packet_type,
+ packet_length,
+ packet_num,
+ buf_cnt_rx,
+ control);
+ bt->rx->rw_cnt++;
+ } else {
+ bt->rx->xrun = 1;
+ dev_warn(bt->dev, "%s(), rx->xrun 1\n", __func__);
+ }
+ }
+
+ /* tx */
+ bt->tx->timeout = 0;
+ if ((bt->tx->state == BT_SCO_STATE_RUNNING ||
+ bt->tx->state == BT_SCO_STATE_ENDING) &&
+ bt->tx->trigger_start) {
+ if (bt->tx->xrun) {
+ /* prepared data is larger then twice
+ * interrupt tx data size
+ */
+ if (bt->tx->packet_w - bt->tx->packet_r >=
+ 2 * buf_cnt_tx) {
+ bt->tx->xrun = 0;
+ dev_warn(bt->dev, "%s(), tx->xrun 0\n",
+ __func__);
+ }
+ }
+
+ if ((!bt->tx->xrun &&
+ (bt->tx->packet_w - bt->tx->packet_r >= buf_cnt_tx)) ||
+ bt->tx->state == BT_SCO_STATE_ENDING) {
+ mtk_btcvsd_write_to_bt(bt,
+ packet_type,
+ packet_length,
+ packet_num,
+ buf_cnt_tx);
+ bt->tx->rw_cnt++;
+ } else {
+ bt->tx->xrun = 1;
+ dev_warn(bt->dev, "%s(), tx->xrun 1\n", __func__);
+ }
+ }
+
+ *bt->bt_reg_ctl &= ~BT_CVSD_CLEAR;
+
+ if (bt->rx->state == BT_SCO_STATE_RUNNING ||
+ bt->rx->state == BT_SCO_STATE_ENDING) {
+ bt->rx->wait_flag = 1;
+ wake_up_interruptible(&bt->rx_wait);
+ snd_pcm_period_elapsed(bt->rx->substream);
+ }
+ if (bt->tx->state == BT_SCO_STATE_RUNNING ||
+ bt->tx->state == BT_SCO_STATE_ENDING) {
+ bt->tx->wait_flag = 1;
+ wake_up_interruptible(&bt->tx_wait);
+ snd_pcm_period_elapsed(bt->tx->substream);
+ }
+
+ return IRQ_HANDLED;
+irq_handler_exit:
+ *bt->bt_reg_ctl &= ~BT_CVSD_CLEAR;
+ return IRQ_HANDLED;
+}
+
+static int wait_for_bt_irq(struct mtk_btcvsd_snd *bt,
+ struct mtk_btcvsd_snd_stream *bt_stream)
+{
+ unsigned long long t1, t2;
+ /* one interrupt period = 22.5ms */
+ unsigned long long timeout_limit = 22500000;
+ int max_timeout_trial = 2;
+ int ret;
+
+ bt_stream->wait_flag = 0;
+
+ while (max_timeout_trial && !bt_stream->wait_flag) {
+ t1 = sched_clock();
+ if (bt_stream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = wait_event_interruptible_timeout(bt->tx_wait,
+ bt_stream->wait_flag,
+ nsecs_to_jiffies(timeout_limit));
+ } else {
+ ret = wait_event_interruptible_timeout(bt->rx_wait,
+ bt_stream->wait_flag,
+ nsecs_to_jiffies(timeout_limit));
+ }
+
+ t2 = sched_clock();
+ t2 = t2 - t1; /* in ns (10^9) */
+
+ if (t2 > timeout_limit) {
+ dev_warn(bt->dev, "%s(), stream %d, timeout %llu, limit %llu, ret %d, flag %d\n",
+ __func__, bt_stream->stream,
+ t2, timeout_limit, ret,
+ bt_stream->wait_flag);
+ }
+
+ if (ret < 0) {
+ /*
+ * error, -ERESTARTSYS if it was interrupted by
+ * a signal
+ */
+ dev_warn(bt->dev, "%s(), stream %d, error, trial left %d\n",
+ __func__,
+ bt_stream->stream, max_timeout_trial);
+
+ bt_stream->timeout = 1;
+ return ret;
+ } else if (ret == 0) {
+ /* conidtion is false after timeout */
+ max_timeout_trial--;
+ dev_warn(bt->dev, "%s(), stream %d, error, timeout, condition is false, trial left %d\n",
+ __func__,
+ bt_stream->stream, max_timeout_trial);
+
+ if (max_timeout_trial <= 0) {
+ bt_stream->timeout = 1;
+ return -ETIME;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt,
+ char __user *buf,
+ size_t count)
+{
+ ssize_t read_size = 0, read_count = 0, cur_read_idx, cont;
+ unsigned int cur_buf_ofs = 0;
+ unsigned long avail;
+ unsigned long flags;
+ unsigned int packet_size = bt->rx->packet_size;
+
+ while (count) {
+ spin_lock_irqsave(&bt->rx_lock, flags);
+ /* available data in RX packet buffer */
+ avail = (bt->rx->packet_w - bt->rx->packet_r) * packet_size;
+
+ cur_read_idx = (bt->rx->packet_r & SCO_RX_PACKET_MASK) *
+ packet_size;
+ spin_unlock_irqrestore(&bt->rx_lock, flags);
+
+ if (!avail) {
+ int ret = wait_for_bt_irq(bt, bt->rx);
+
+ if (ret)
+ return read_count;
+
+ continue;
+ }
+
+ /* count must be multiple of packet_size */
+ if (count % packet_size != 0 ||
+ avail % packet_size != 0) {
+ dev_warn(bt->dev, "%s(), count %zu or d %lu is not multiple of packet_size %dd\n",
+ __func__, count, avail, packet_size);
+
+ count -= count % packet_size;
+ avail -= avail % packet_size;
+ }
+
+ if (count > avail)
+ read_size = avail;
+ else
+ read_size = count;
+
+ /* calculate continue space */
+ cont = bt->rx->buf_size - cur_read_idx;
+ if (read_size > cont)
+ read_size = cont;
+
+ if (copy_to_user(buf + cur_buf_ofs,
+ bt->rx_packet_buf + cur_read_idx,
+ read_size)) {
+ dev_warn(bt->dev, "%s(), copy_to_user fail\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ spin_lock_irqsave(&bt->rx_lock, flags);
+ bt->rx->packet_r += read_size / packet_size;
+ spin_unlock_irqrestore(&bt->rx_lock, flags);
+
+ read_count += read_size;
+ cur_buf_ofs += read_size;
+ count -= read_size;
+ }
+
+ /*
+ * save current timestamp & buffer time in times_tamp and
+ * buf_data_equivalent_time
+ */
+ bt->rx->time_stamp = sched_clock();
+ bt->rx->buf_data_equivalent_time =
+ (unsigned long long)(bt->rx->packet_w - bt->rx->packet_r) *
+ SCO_RX_PLC_SIZE * 16 * 1000 / 2 / 64;
+ bt->rx->buf_data_equivalent_time += read_count * SCO_RX_PLC_SIZE *
+ 16 * 1000 / packet_size / 2 / 64;
+ /* return equivalent time(us) to data count */
+ bt->rx->buf_data_equivalent_time *= 1000;
+
+ return read_count;
+}
+
+static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt,
+ char __user *buf,
+ size_t count)
+{
+ int written_size = count, avail = 0, cur_write_idx, write_size, cont;
+ unsigned int cur_buf_ofs = 0;
+ unsigned long flags;
+ unsigned int packet_size = bt->tx->packet_size;
+
+ /*
+ * save current timestamp & buffer time in time_stamp and
+ * buf_data_equivalent_time
+ */
+ bt->tx->time_stamp = sched_clock();
+ bt->tx->buf_data_equivalent_time =
+ (unsigned long long)(bt->tx->packet_w - bt->tx->packet_r) *
+ packet_size * 16 * 1000 / 2 / 64;
+
+ /* return equivalent time(us) to data count */
+ bt->tx->buf_data_equivalent_time *= 1000;
+
+ while (count) {
+ spin_lock_irqsave(&bt->tx_lock, flags);
+ /* free space of TX packet buffer */
+ avail = bt->tx->buf_size -
+ (bt->tx->packet_w - bt->tx->packet_r) * packet_size;
+
+ cur_write_idx = (bt->tx->packet_w % SCO_TX_PACKER_BUF_NUM) *
+ packet_size;
+ spin_unlock_irqrestore(&bt->tx_lock, flags);
+
+ if (!avail) {
+ int ret = wait_for_bt_irq(bt, bt->rx);
+
+ if (ret)
+ return written_size;
+
+ continue;
+ }
+
+ /* count must be multiple of bt->tx->packet_size */
+ if (count % packet_size != 0 ||
+ avail % packet_size != 0) {
+ dev_warn(bt->dev, "%s(), count %zu or avail %d is not multiple of packet_size %d\n",
+ __func__, count, avail, packet_size);
+ count -= count % packet_size;
+ avail -= avail % packet_size;
+ }
+
+ if (count > avail)
+ write_size = avail;
+ else
+ write_size = count;
+
+ /* calculate continue space */
+ cont = bt->tx->buf_size - cur_write_idx;
+ if (write_size > cont)
+ write_size = cont;
+
+ if (copy_from_user(bt->tx_packet_buf +
+ cur_write_idx,
+ buf + cur_buf_ofs,
+ write_size)) {
+ dev_warn(bt->dev, "%s(), copy_from_user fail\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ spin_lock_irqsave(&bt->tx_lock, flags);
+ bt->tx->packet_w += write_size / packet_size;
+ spin_unlock_irqrestore(&bt->tx_lock, flags);
+ cur_buf_ofs += write_size;
+ count -= write_size;
+ }
+
+ return written_size;
+}
+
+static struct mtk_btcvsd_snd_stream *get_bt_stream
+ (struct mtk_btcvsd_snd *bt, struct snd_pcm_substream *substream)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return bt->tx;
+ else
+ return bt->rx;
+}
+
+/* pcm ops */
+static const struct snd_pcm_hardware mtk_btcvsd_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_RESUME),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .buffer_bytes_max = 24 * 1024,
+ .period_bytes_max = 24 * 1024,
+ .periods_min = 2,
+ .periods_max = 16,
+ .fifo_size = 0,
+};
+
+static int mtk_pcm_btcvsd_open(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ dev_dbg(bt->dev, "%s(), stream %d, substream %p\n",
+ __func__, substream->stream, substream);
+
+ snd_soc_set_runtime_hwparams(substream, &mtk_btcvsd_hardware);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = mtk_btcvsd_snd_tx_init(bt);
+ bt->tx->substream = substream;
+ } else {
+ ret = mtk_btcvsd_snd_rx_init(bt);
+ bt->rx->substream = substream;
+ }
+
+ return ret;
+}
+
+static int mtk_pcm_btcvsd_close(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
+ struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream);
+
+ dev_dbg(bt->dev, "%s(), stream %d\n", __func__, substream->stream);
+
+ mtk_btcvsd_snd_set_state(bt, bt_stream, BT_SCO_STATE_IDLE);
+ bt_stream->substream = NULL;
+ return 0;
+}
+
+static int mtk_pcm_btcvsd_hw_params(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+ params_buffer_bytes(hw_params) % bt->tx->packet_size != 0) {
+ dev_warn(bt->dev, "%s(), error, buffer size %d not valid\n",
+ __func__,
+ params_buffer_bytes(hw_params));
+ return -EINVAL;
+ }
+
+ substream->runtime->dma_bytes = params_buffer_bytes(hw_params);
+ return 0;
+}
+
+static int mtk_pcm_btcvsd_hw_free(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ btcvsd_tx_clean_buffer(bt);
+
+ return 0;
+}
+
+static int mtk_pcm_btcvsd_prepare(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
+ struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream);
+
+ dev_dbg(bt->dev, "%s(), stream %d\n", __func__, substream->stream);
+
+ mtk_btcvsd_snd_set_state(bt, bt_stream, BT_SCO_STATE_RUNNING);
+ return 0;
+}
+
+static int mtk_pcm_btcvsd_trigger(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream, int cmd)
+{
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
+ struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream);
+ int stream = substream->stream;
+ int hw_packet_ptr;
+
+ dev_dbg(bt->dev, "%s(), stream %d, cmd %d\n",
+ __func__, substream->stream, cmd);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ hw_packet_ptr = stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ bt_stream->packet_r : bt_stream->packet_w;
+ bt_stream->prev_packet_idx = hw_packet_ptr;
+ bt_stream->prev_frame = 0;
+ bt_stream->trigger_start = 1;
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ bt_stream->trigger_start = 0;
+ mtk_btcvsd_snd_set_state(bt, bt_stream, BT_SCO_STATE_ENDING);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static snd_pcm_uframes_t mtk_pcm_btcvsd_pointer(
+ struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
+ struct mtk_btcvsd_snd_stream *bt_stream;
+ snd_pcm_uframes_t frame = 0;
+ int byte = 0;
+ int hw_packet_ptr;
+ int packet_diff;
+ spinlock_t *lock; /* spinlock for bt stream control */
+ unsigned long flags;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ lock = &bt->tx_lock;
+ bt_stream = bt->tx;
+ } else {
+ lock = &bt->rx_lock;
+ bt_stream = bt->rx;
+ }
+
+ spin_lock_irqsave(lock, flags);
+ hw_packet_ptr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ bt->tx->packet_r : bt->rx->packet_w;
+
+ /* get packet diff from last time */
+ if (hw_packet_ptr >= bt_stream->prev_packet_idx) {
+ packet_diff = hw_packet_ptr - bt_stream->prev_packet_idx;
+ } else {
+ /* integer overflow */
+ packet_diff = (INT_MAX - bt_stream->prev_packet_idx) +
+ (hw_packet_ptr - INT_MIN) + 1;
+ }
+ bt_stream->prev_packet_idx = hw_packet_ptr;
+
+ /* increased bytes */
+ byte = packet_diff * bt_stream->packet_size;
+
+ frame = btcvsd_bytes_to_frame(substream, byte);
+ frame += bt_stream->prev_frame;
+ frame %= substream->runtime->buffer_size;
+
+ bt_stream->prev_frame = frame;
+
+ spin_unlock_irqrestore(lock, flags);
+
+ return frame;
+}
+
+static int mtk_pcm_btcvsd_copy(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ int channel, unsigned long pos,
+ void __user *buf, unsigned long count)
+{
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return mtk_btcvsd_snd_write(bt, buf, count);
+ else
+ return mtk_btcvsd_snd_read(bt, buf, count);
+}
+
+/* kcontrol */
+static const char *const btsco_band_str[] = {"NB", "WB"};
+
+static const struct soc_enum btcvsd_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(btsco_band_str), btsco_band_str),
+};
+
+static int btcvsd_band_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
+
+ ucontrol->value.integer.value[0] = bt->band;
+ return 0;
+}
+
+static int btcvsd_band_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
+ bt->band = ucontrol->value.integer.value[0];
+ dev_dbg(bt->dev, "%s(), band %d\n", __func__, bt->band);
+ return 0;
+}
+
+static int btcvsd_loopback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
+ bool lpbk_en = bt->tx->state == BT_SCO_STATE_LOOPBACK;
+
+ ucontrol->value.integer.value[0] = lpbk_en;
+ return 0;
+}
+
+static int btcvsd_loopback_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
+
+ if (ucontrol->value.integer.value[0]) {
+ mtk_btcvsd_snd_set_state(bt, bt->tx, BT_SCO_STATE_LOOPBACK);
+ mtk_btcvsd_snd_set_state(bt, bt->rx, BT_SCO_STATE_LOOPBACK);
+ } else {
+ mtk_btcvsd_snd_set_state(bt, bt->tx, BT_SCO_STATE_RUNNING);
+ mtk_btcvsd_snd_set_state(bt, bt->rx, BT_SCO_STATE_RUNNING);
+ }
+ return 0;
+}
+
+static int btcvsd_tx_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
+
+ if (!bt->tx) {
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+ }
+
+ ucontrol->value.integer.value[0] = bt->tx->mute;
+ return 0;
+}
+
+static int btcvsd_tx_mute_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
+
+ if (!bt->tx)
+ return 0;
+
+ bt->tx->mute = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static int btcvsd_rx_irq_received_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
+
+ if (!bt->rx)
+ return 0;
+
+ ucontrol->value.integer.value[0] = bt->rx->rw_cnt ? 1 : 0;
+ return 0;
+}
+
+static int btcvsd_rx_timeout_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
+
+ if (!bt->rx)
+ return 0;
+
+ ucontrol->value.integer.value[0] = bt->rx->timeout;
+ bt->rx->timeout = 0;
+ return 0;
+}
+
+static int btcvsd_rx_timestamp_get(struct snd_kcontrol *kcontrol,
+ unsigned int __user *data, unsigned int size)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
+ int ret = 0;
+ struct mtk_btcvsd_snd_time_buffer_info time_buffer_info_rx;
+
+ if (size > sizeof(struct mtk_btcvsd_snd_time_buffer_info))
+ return -EINVAL;
+
+ get_rx_time_stamp(bt, &time_buffer_info_rx);
+
+ dev_dbg(bt->dev, "%s(), time_stamp_us %llu, data_count_equi_time %llu",
+ __func__,
+ time_buffer_info_rx.time_stamp_us,
+ time_buffer_info_rx.data_count_equi_time);
+
+ if (copy_to_user(data, &time_buffer_info_rx,
+ sizeof(struct mtk_btcvsd_snd_time_buffer_info))) {
+ dev_warn(bt->dev, "%s(), copy_to_user fail", __func__);
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+static int btcvsd_tx_irq_received_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
+
+ if (!bt->tx)
+ return 0;
+
+ ucontrol->value.integer.value[0] = bt->tx->rw_cnt ? 1 : 0;
+ return 0;
+}
+
+static int btcvsd_tx_timeout_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
+
+ ucontrol->value.integer.value[0] = bt->tx->timeout;
+ return 0;
+}
+
+static int btcvsd_tx_timestamp_get(struct snd_kcontrol *kcontrol,
+ unsigned int __user *data, unsigned int size)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
+ int ret = 0;
+ struct mtk_btcvsd_snd_time_buffer_info time_buffer_info_tx;
+
+ if (size > sizeof(struct mtk_btcvsd_snd_time_buffer_info))
+ return -EINVAL;
+
+ get_tx_time_stamp(bt, &time_buffer_info_tx);
+
+ dev_dbg(bt->dev, "%s(), time_stamp_us %llu, data_count_equi_time %llu",
+ __func__,
+ time_buffer_info_tx.time_stamp_us,
+ time_buffer_info_tx.data_count_equi_time);
+
+ if (copy_to_user(data, &time_buffer_info_tx,
+ sizeof(struct mtk_btcvsd_snd_time_buffer_info))) {
+ dev_warn(bt->dev, "%s(), copy_to_user fail", __func__);
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new mtk_btcvsd_snd_controls[] = {
+ SOC_ENUM_EXT("BTCVSD Band", btcvsd_enum[0],
+ btcvsd_band_get, btcvsd_band_set),
+ SOC_SINGLE_BOOL_EXT("BTCVSD Loopback Switch", 0,
+ btcvsd_loopback_get, btcvsd_loopback_set),
+ SOC_SINGLE_BOOL_EXT("BTCVSD Tx Mute Switch", 0,
+ btcvsd_tx_mute_get, btcvsd_tx_mute_set),
+ SOC_SINGLE_BOOL_EXT("BTCVSD Tx Irq Received Switch", 0,
+ btcvsd_tx_irq_received_get, NULL),
+ SOC_SINGLE_BOOL_EXT("BTCVSD Tx Timeout Switch", 0,
+ btcvsd_tx_timeout_get, NULL),
+ SOC_SINGLE_BOOL_EXT("BTCVSD Rx Irq Received Switch", 0,
+ btcvsd_rx_irq_received_get, NULL),
+ SOC_SINGLE_BOOL_EXT("BTCVSD Rx Timeout Switch", 0,
+ btcvsd_rx_timeout_get, NULL),
+ SND_SOC_BYTES_TLV("BTCVSD Rx Timestamp",
+ sizeof(struct mtk_btcvsd_snd_time_buffer_info),
+ btcvsd_rx_timestamp_get, NULL),
+ SND_SOC_BYTES_TLV("BTCVSD Tx Timestamp",
+ sizeof(struct mtk_btcvsd_snd_time_buffer_info),
+ btcvsd_tx_timestamp_get, NULL),
+};
+
+static int mtk_btcvsd_snd_component_probe(struct snd_soc_component *component)
+{
+ return snd_soc_add_component_controls(component,
+ mtk_btcvsd_snd_controls,
+ ARRAY_SIZE(mtk_btcvsd_snd_controls));
+}
+
+static const struct snd_soc_component_driver mtk_btcvsd_snd_platform = {
+ .name = BTCVSD_SND_NAME,
+ .probe = mtk_btcvsd_snd_component_probe,
+ .open = mtk_pcm_btcvsd_open,
+ .close = mtk_pcm_btcvsd_close,
+ .hw_params = mtk_pcm_btcvsd_hw_params,
+ .hw_free = mtk_pcm_btcvsd_hw_free,
+ .prepare = mtk_pcm_btcvsd_prepare,
+ .trigger = mtk_pcm_btcvsd_trigger,
+ .pointer = mtk_pcm_btcvsd_pointer,
+ .copy_user = mtk_pcm_btcvsd_copy,
+};
+
+static int mtk_btcvsd_snd_probe(struct platform_device *pdev)
+{
+ int ret;
+ int irq_id;
+ u32 offset[5] = {0, 0, 0, 0, 0};
+ struct mtk_btcvsd_snd *btcvsd;
+ struct device *dev = &pdev->dev;
+
+ /* init btcvsd private data */
+ btcvsd = devm_kzalloc(dev, sizeof(*btcvsd), GFP_KERNEL);
+ if (!btcvsd)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, btcvsd);
+ btcvsd->dev = dev;
+
+ /* init tx/rx */
+ btcvsd->rx = devm_kzalloc(btcvsd->dev, sizeof(*btcvsd->rx), GFP_KERNEL);
+ if (!btcvsd->rx)
+ return -ENOMEM;
+
+ btcvsd->tx = devm_kzalloc(btcvsd->dev, sizeof(*btcvsd->tx), GFP_KERNEL);
+ if (!btcvsd->tx)
+ return -ENOMEM;
+
+ spin_lock_init(&btcvsd->tx_lock);
+ spin_lock_init(&btcvsd->rx_lock);
+
+ init_waitqueue_head(&btcvsd->tx_wait);
+ init_waitqueue_head(&btcvsd->rx_wait);
+
+ mtk_btcvsd_snd_tx_init(btcvsd);
+ mtk_btcvsd_snd_rx_init(btcvsd);
+
+ /* irq */
+ irq_id = platform_get_irq(pdev, 0);
+ if (irq_id <= 0)
+ return irq_id < 0 ? irq_id : -ENXIO;
+
+ ret = devm_request_irq(dev, irq_id, mtk_btcvsd_snd_irq_handler,
+ IRQF_TRIGGER_LOW, "BTCVSD_ISR_Handle",
+ (void *)btcvsd);
+ if (ret) {
+ dev_err(dev, "could not request_irq for BTCVSD_ISR_Handle\n");
+ return ret;
+ }
+
+ btcvsd->irq_id = irq_id;
+
+ /* iomap */
+ btcvsd->bt_pkv_base = of_iomap(dev->of_node, 0);
+ if (!btcvsd->bt_pkv_base) {
+ dev_err(dev, "iomap bt_pkv_base fail\n");
+ return -EIO;
+ }
+
+ btcvsd->bt_sram_bank2_base = of_iomap(dev->of_node, 1);
+ if (!btcvsd->bt_sram_bank2_base) {
+ dev_err(dev, "iomap bt_sram_bank2_base fail\n");
+ ret = -EIO;
+ goto unmap_pkv_err;
+ }
+
+ btcvsd->infra = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "mediatek,infracfg");
+ if (IS_ERR(btcvsd->infra)) {
+ dev_err(dev, "cannot find infra controller: %ld\n",
+ PTR_ERR(btcvsd->infra));
+ ret = PTR_ERR(btcvsd->infra);
+ goto unmap_bank2_err;
+ }
+
+ /* get offset */
+ ret = of_property_read_u32_array(dev->of_node, "mediatek,offset",
+ offset,
+ ARRAY_SIZE(offset));
+ if (ret) {
+ dev_warn(dev, "%s(), get offset fail, ret %d\n", __func__, ret);
+ goto unmap_bank2_err;
+ }
+ btcvsd->infra_misc_offset = offset[0];
+ btcvsd->conn_bt_cvsd_mask = offset[1];
+ btcvsd->cvsd_mcu_read_offset = offset[2];
+ btcvsd->cvsd_mcu_write_offset = offset[3];
+ btcvsd->cvsd_packet_indicator = offset[4];
+
+ btcvsd->bt_reg_pkt_r = btcvsd->bt_pkv_base +
+ btcvsd->cvsd_mcu_read_offset;
+ btcvsd->bt_reg_pkt_w = btcvsd->bt_pkv_base +
+ btcvsd->cvsd_mcu_write_offset;
+ btcvsd->bt_reg_ctl = btcvsd->bt_pkv_base +
+ btcvsd->cvsd_packet_indicator;
+
+ /* init state */
+ mtk_btcvsd_snd_set_state(btcvsd, btcvsd->tx, BT_SCO_STATE_IDLE);
+ mtk_btcvsd_snd_set_state(btcvsd, btcvsd->rx, BT_SCO_STATE_IDLE);
+
+ ret = devm_snd_soc_register_component(dev, &mtk_btcvsd_snd_platform,
+ NULL, 0);
+ if (ret)
+ goto unmap_bank2_err;
+
+ return 0;
+
+unmap_bank2_err:
+ iounmap(btcvsd->bt_sram_bank2_base);
+unmap_pkv_err:
+ iounmap(btcvsd->bt_pkv_base);
+ return ret;
+}
+
+static int mtk_btcvsd_snd_remove(struct platform_device *pdev)
+{
+ struct mtk_btcvsd_snd *btcvsd = dev_get_drvdata(&pdev->dev);
+
+ iounmap(btcvsd->bt_pkv_base);
+ iounmap(btcvsd->bt_sram_bank2_base);
+ return 0;
+}
+
+static const struct of_device_id mtk_btcvsd_snd_dt_match[] = {
+ { .compatible = "mediatek,mtk-btcvsd-snd", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mtk_btcvsd_snd_dt_match);
+
+static struct platform_driver mtk_btcvsd_snd_driver = {
+ .driver = {
+ .name = "mtk-btcvsd-snd",
+ .of_match_table = mtk_btcvsd_snd_dt_match,
+ },
+ .probe = mtk_btcvsd_snd_probe,
+ .remove = mtk_btcvsd_snd_remove,
+};
+
+module_platform_driver(mtk_btcvsd_snd_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA BT SCO CVSD/MSBC Driver");
+MODULE_AUTHOR("KaiChieh Chuang <kaichieh.chuang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/mt2701/Makefile b/sound/soc/mediatek/mt2701/Makefile
new file mode 100644
index 000000000..21d5e697c
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+# platform driver
+snd-soc-mt2701-afe-objs := mt2701-afe-pcm.o mt2701-afe-clock-ctrl.o
+obj-$(CONFIG_SND_SOC_MT2701) += snd-soc-mt2701-afe.o
+
+# machine driver
+obj-$(CONFIG_SND_SOC_MT2701_CS42448) += mt2701-cs42448.o
+obj-$(CONFIG_SND_SOC_MT2701_WM8960) += mt2701-wm8960.o
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
new file mode 100644
index 000000000..ae620890b
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt2701-afe-clock-ctrl.c -- Mediatek 2701 afe clock ctrl
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ * Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include "mt2701-afe-common.h"
+#include "mt2701-afe-clock-ctrl.h"
+
+static const char *const base_clks[] = {
+ [MT2701_INFRA_SYS_AUDIO] = "infra_sys_audio_clk",
+ [MT2701_TOP_AUD_MCLK_SRC0] = "top_audio_mux1_sel",
+ [MT2701_TOP_AUD_MCLK_SRC1] = "top_audio_mux2_sel",
+ [MT2701_TOP_AUD_A1SYS] = "top_audio_a1sys_hp",
+ [MT2701_TOP_AUD_A2SYS] = "top_audio_a2sys_hp",
+ [MT2701_AUDSYS_AFE] = "audio_afe_pd",
+ [MT2701_AUDSYS_AFE_CONN] = "audio_afe_conn_pd",
+ [MT2701_AUDSYS_A1SYS] = "audio_a1sys_pd",
+ [MT2701_AUDSYS_A2SYS] = "audio_a2sys_pd",
+};
+
+int mt2701_init_clock(struct mtk_base_afe *afe)
+{
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ int i;
+
+ for (i = 0; i < MT2701_BASE_CLK_NUM; i++) {
+ afe_priv->base_ck[i] = devm_clk_get(afe->dev, base_clks[i]);
+ if (IS_ERR(afe_priv->base_ck[i])) {
+ dev_err(afe->dev, "failed to get %s\n", base_clks[i]);
+ return PTR_ERR(afe_priv->base_ck[i]);
+ }
+ }
+
+ /* Get I2S related clocks */
+ for (i = 0; i < afe_priv->soc->i2s_num; i++) {
+ struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i];
+ struct clk *i2s_ck;
+ char name[13];
+
+ snprintf(name, sizeof(name), "i2s%d_src_sel", i);
+ i2s_path->sel_ck = devm_clk_get(afe->dev, name);
+ if (IS_ERR(i2s_path->sel_ck)) {
+ dev_err(afe->dev, "failed to get %s\n", name);
+ return PTR_ERR(i2s_path->sel_ck);
+ }
+
+ snprintf(name, sizeof(name), "i2s%d_src_div", i);
+ i2s_path->div_ck = devm_clk_get(afe->dev, name);
+ if (IS_ERR(i2s_path->div_ck)) {
+ dev_err(afe->dev, "failed to get %s\n", name);
+ return PTR_ERR(i2s_path->div_ck);
+ }
+
+ snprintf(name, sizeof(name), "i2s%d_mclk_en", i);
+ i2s_path->mclk_ck = devm_clk_get(afe->dev, name);
+ if (IS_ERR(i2s_path->mclk_ck)) {
+ dev_err(afe->dev, "failed to get %s\n", name);
+ return PTR_ERR(i2s_path->mclk_ck);
+ }
+
+ snprintf(name, sizeof(name), "i2so%d_hop_ck", i);
+ i2s_ck = devm_clk_get(afe->dev, name);
+ if (IS_ERR(i2s_ck)) {
+ dev_err(afe->dev, "failed to get %s\n", name);
+ return PTR_ERR(i2s_ck);
+ }
+ i2s_path->hop_ck[SNDRV_PCM_STREAM_PLAYBACK] = i2s_ck;
+
+ snprintf(name, sizeof(name), "i2si%d_hop_ck", i);
+ i2s_ck = devm_clk_get(afe->dev, name);
+ if (IS_ERR(i2s_ck)) {
+ dev_err(afe->dev, "failed to get %s\n", name);
+ return PTR_ERR(i2s_ck);
+ }
+ i2s_path->hop_ck[SNDRV_PCM_STREAM_CAPTURE] = i2s_ck;
+
+ snprintf(name, sizeof(name), "asrc%d_out_ck", i);
+ i2s_path->asrco_ck = devm_clk_get(afe->dev, name);
+ if (IS_ERR(i2s_path->asrco_ck)) {
+ dev_err(afe->dev, "failed to get %s\n", name);
+ return PTR_ERR(i2s_path->asrco_ck);
+ }
+ }
+
+ /* Some platforms may support BT path */
+ afe_priv->mrgif_ck = devm_clk_get(afe->dev, "audio_mrgif_pd");
+ if (IS_ERR(afe_priv->mrgif_ck)) {
+ if (PTR_ERR(afe_priv->mrgif_ck) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ afe_priv->mrgif_ck = NULL;
+ }
+
+ return 0;
+}
+
+int mt2701_afe_enable_i2s(struct mtk_base_afe *afe,
+ struct mt2701_i2s_path *i2s_path,
+ int dir)
+{
+ int ret;
+
+ ret = clk_prepare_enable(i2s_path->asrco_ck);
+ if (ret) {
+ dev_err(afe->dev, "failed to enable ASRC clock %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(i2s_path->hop_ck[dir]);
+ if (ret) {
+ dev_err(afe->dev, "failed to enable I2S clock %d\n", ret);
+ goto err_hop_ck;
+ }
+
+ return 0;
+
+err_hop_ck:
+ clk_disable_unprepare(i2s_path->asrco_ck);
+
+ return ret;
+}
+
+void mt2701_afe_disable_i2s(struct mtk_base_afe *afe,
+ struct mt2701_i2s_path *i2s_path,
+ int dir)
+{
+ clk_disable_unprepare(i2s_path->hop_ck[dir]);
+ clk_disable_unprepare(i2s_path->asrco_ck);
+}
+
+int mt2701_afe_enable_mclk(struct mtk_base_afe *afe, int id)
+{
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
+
+ return clk_prepare_enable(i2s_path->mclk_ck);
+}
+
+void mt2701_afe_disable_mclk(struct mtk_base_afe *afe, int id)
+{
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
+
+ clk_disable_unprepare(i2s_path->mclk_ck);
+}
+
+int mt2701_enable_btmrg_clk(struct mtk_base_afe *afe)
+{
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+ return clk_prepare_enable(afe_priv->mrgif_ck);
+}
+
+void mt2701_disable_btmrg_clk(struct mtk_base_afe *afe)
+{
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+ clk_disable_unprepare(afe_priv->mrgif_ck);
+}
+
+static int mt2701_afe_enable_audsys(struct mtk_base_afe *afe)
+{
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ /* Enable infra clock gate */
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]);
+ if (ret)
+ return ret;
+
+ /* Enable top a1sys clock gate */
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]);
+ if (ret)
+ goto err_a1sys;
+
+ /* Enable top a2sys clock gate */
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]);
+ if (ret)
+ goto err_a2sys;
+
+ /* Internal clock gates */
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE]);
+ if (ret)
+ goto err_afe;
+
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]);
+ if (ret)
+ goto err_audio_a1sys;
+
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]);
+ if (ret)
+ goto err_audio_a2sys;
+
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE_CONN]);
+ if (ret)
+ goto err_afe_conn;
+
+ return 0;
+
+err_afe_conn:
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]);
+err_audio_a2sys:
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]);
+err_audio_a1sys:
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]);
+err_afe:
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]);
+err_a2sys:
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]);
+err_a1sys:
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]);
+
+ return ret;
+}
+
+static void mt2701_afe_disable_audsys(struct mtk_base_afe *afe)
+{
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE_CONN]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]);
+}
+
+int mt2701_afe_enable_clock(struct mtk_base_afe *afe)
+{
+ int ret;
+
+ /* Enable audio system */
+ ret = mt2701_afe_enable_audsys(afe);
+ if (ret) {
+ dev_err(afe->dev, "failed to enable audio system %d\n", ret);
+ return ret;
+ }
+
+ regmap_update_bits(afe->regmap, ASYS_TOP_CON,
+ ASYS_TOP_CON_ASYS_TIMING_ON,
+ ASYS_TOP_CON_ASYS_TIMING_ON);
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0,
+ AFE_DAC_CON0_AFE_ON,
+ AFE_DAC_CON0_AFE_ON);
+
+ /* Configure ASRC */
+ regmap_write(afe->regmap, PWR1_ASM_CON1, PWR1_ASM_CON1_INIT_VAL);
+ regmap_write(afe->regmap, PWR2_ASM_CON1, PWR2_ASM_CON1_INIT_VAL);
+
+ return 0;
+}
+
+int mt2701_afe_disable_clock(struct mtk_base_afe *afe)
+{
+ regmap_update_bits(afe->regmap, ASYS_TOP_CON,
+ ASYS_TOP_CON_ASYS_TIMING_ON, 0);
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0,
+ AFE_DAC_CON0_AFE_ON, 0);
+
+ mt2701_afe_disable_audsys(afe);
+
+ return 0;
+}
+
+int mt2701_mclk_configuration(struct mtk_base_afe *afe, int id)
+
+{
+ struct mt2701_afe_private *priv = afe->platform_priv;
+ struct mt2701_i2s_path *i2s_path = &priv->i2s_path[id];
+ int ret = -EINVAL;
+
+ /* Set mclk source */
+ if (!(MT2701_PLL_DOMAIN_0_RATE % i2s_path->mclk_rate))
+ ret = clk_set_parent(i2s_path->sel_ck,
+ priv->base_ck[MT2701_TOP_AUD_MCLK_SRC0]);
+ else if (!(MT2701_PLL_DOMAIN_1_RATE % i2s_path->mclk_rate))
+ ret = clk_set_parent(i2s_path->sel_ck,
+ priv->base_ck[MT2701_TOP_AUD_MCLK_SRC1]);
+
+ if (ret) {
+ dev_err(afe->dev, "failed to set mclk source\n");
+ return ret;
+ }
+
+ /* Set mclk divider */
+ ret = clk_set_rate(i2s_path->div_ck, i2s_path->mclk_rate);
+ if (ret) {
+ dev_err(afe->dev, "failed to set mclk divider %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h
new file mode 100644
index 000000000..580fead2a
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt2701-afe-clock-ctrl.h -- Mediatek 2701 afe clock ctrl definition
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ * Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#ifndef _MT2701_AFE_CLOCK_CTRL_H_
+#define _MT2701_AFE_CLOCK_CTRL_H_
+
+struct mtk_base_afe;
+struct mt2701_i2s_path;
+
+int mt2701_init_clock(struct mtk_base_afe *afe);
+int mt2701_afe_enable_clock(struct mtk_base_afe *afe);
+int mt2701_afe_disable_clock(struct mtk_base_afe *afe);
+
+int mt2701_afe_enable_i2s(struct mtk_base_afe *afe,
+ struct mt2701_i2s_path *path,
+ int dir);
+void mt2701_afe_disable_i2s(struct mtk_base_afe *afe,
+ struct mt2701_i2s_path *path,
+ int dir);
+int mt2701_afe_enable_mclk(struct mtk_base_afe *afe, int id);
+void mt2701_afe_disable_mclk(struct mtk_base_afe *afe, int id);
+
+int mt2701_enable_btmrg_clk(struct mtk_base_afe *afe);
+void mt2701_disable_btmrg_clk(struct mtk_base_afe *afe);
+
+int mt2701_mclk_configuration(struct mtk_base_afe *afe, int id);
+
+#endif
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
new file mode 100644
index 000000000..32bef5e2a
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt2701-afe-common.h -- Mediatek 2701 audio driver definitions
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ */
+
+#ifndef _MT_2701_AFE_COMMON_H_
+#define _MT_2701_AFE_COMMON_H_
+
+#include <sound/soc.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include "mt2701-reg.h"
+#include "../common/mtk-base-afe.h"
+
+#define MT2701_PLL_DOMAIN_0_RATE 98304000
+#define MT2701_PLL_DOMAIN_1_RATE 90316800
+
+enum {
+ MT2701_MEMIF_DL1,
+ MT2701_MEMIF_DL2,
+ MT2701_MEMIF_DL3,
+ MT2701_MEMIF_DL4,
+ MT2701_MEMIF_DL5,
+ MT2701_MEMIF_DL_SINGLE_NUM,
+ MT2701_MEMIF_DLM = MT2701_MEMIF_DL_SINGLE_NUM,
+ MT2701_MEMIF_UL1,
+ MT2701_MEMIF_UL2,
+ MT2701_MEMIF_UL3,
+ MT2701_MEMIF_UL4,
+ MT2701_MEMIF_UL5,
+ MT2701_MEMIF_DLBT,
+ MT2701_MEMIF_ULBT,
+ MT2701_MEMIF_NUM,
+ MT2701_IO_I2S = MT2701_MEMIF_NUM,
+ MT2701_IO_2ND_I2S,
+ MT2701_IO_3RD_I2S,
+ MT2701_IO_4TH_I2S,
+ MT2701_IO_5TH_I2S,
+ MT2701_IO_6TH_I2S,
+ MT2701_IO_MRG,
+};
+
+enum {
+ MT2701_IRQ_ASYS_IRQ1,
+ MT2701_IRQ_ASYS_IRQ2,
+ MT2701_IRQ_ASYS_IRQ3,
+ MT2701_IRQ_ASYS_END,
+};
+
+enum audio_base_clock {
+ MT2701_INFRA_SYS_AUDIO,
+ MT2701_TOP_AUD_MCLK_SRC0,
+ MT2701_TOP_AUD_MCLK_SRC1,
+ MT2701_TOP_AUD_A1SYS,
+ MT2701_TOP_AUD_A2SYS,
+ MT2701_AUDSYS_AFE,
+ MT2701_AUDSYS_AFE_CONN,
+ MT2701_AUDSYS_A1SYS,
+ MT2701_AUDSYS_A2SYS,
+ MT2701_BASE_CLK_NUM,
+};
+
+struct mt2701_i2s_data {
+ int i2s_ctrl_reg;
+ int i2s_asrc_fs_shift;
+ int i2s_asrc_fs_mask;
+};
+
+struct mt2701_i2s_path {
+ int mclk_rate;
+ int on[MTK_STREAM_NUM];
+ int occupied[MTK_STREAM_NUM];
+ const struct mt2701_i2s_data *i2s_data[MTK_STREAM_NUM];
+ struct clk *hop_ck[MTK_STREAM_NUM];
+ struct clk *sel_ck;
+ struct clk *div_ck;
+ struct clk *mclk_ck;
+ struct clk *asrco_ck;
+};
+
+struct mt2701_soc_variants {
+ bool has_one_heart_mode;
+ int i2s_num;
+};
+
+struct mt2701_afe_private {
+ struct mt2701_i2s_path *i2s_path;
+ struct clk *base_ck[MT2701_BASE_CLK_NUM];
+ struct clk *mrgif_ck;
+ bool mrg_enable[MTK_STREAM_NUM];
+
+ const struct mt2701_soc_variants *soc;
+};
+
+#endif
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
new file mode 100644
index 000000000..df29641c7
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -0,0 +1,1489 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek ALSA SoC AFE platform driver for 2701
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ * Ir Lian <ir.lian@mediatek.com>
+ * Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+
+#include "mt2701-afe-common.h"
+#include "mt2701-afe-clock-ctrl.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+static const struct snd_pcm_hardware mt2701_afe_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED
+ | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE,
+ .period_bytes_min = 1024,
+ .period_bytes_max = 1024 * 256,
+ .periods_min = 4,
+ .periods_max = 1024,
+ .buffer_bytes_max = 1024 * 1024,
+ .fifo_size = 0,
+};
+
+struct mt2701_afe_rate {
+ unsigned int rate;
+ unsigned int regvalue;
+};
+
+static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = {
+ { .rate = 8000, .regvalue = 0 },
+ { .rate = 12000, .regvalue = 1 },
+ { .rate = 16000, .regvalue = 2 },
+ { .rate = 24000, .regvalue = 3 },
+ { .rate = 32000, .regvalue = 4 },
+ { .rate = 48000, .regvalue = 5 },
+ { .rate = 96000, .regvalue = 6 },
+ { .rate = 192000, .regvalue = 7 },
+ { .rate = 384000, .regvalue = 8 },
+ { .rate = 7350, .regvalue = 16 },
+ { .rate = 11025, .regvalue = 17 },
+ { .rate = 14700, .regvalue = 18 },
+ { .rate = 22050, .regvalue = 19 },
+ { .rate = 29400, .regvalue = 20 },
+ { .rate = 44100, .regvalue = 21 },
+ { .rate = 88200, .regvalue = 22 },
+ { .rate = 176400, .regvalue = 23 },
+ { .rate = 352800, .regvalue = 24 },
+};
+
+static const unsigned int mt2701_afe_backup_list[] = {
+ AUDIO_TOP_CON0,
+ AUDIO_TOP_CON4,
+ AUDIO_TOP_CON5,
+ ASYS_TOP_CON,
+ AFE_CONN0,
+ AFE_CONN1,
+ AFE_CONN2,
+ AFE_CONN3,
+ AFE_CONN15,
+ AFE_CONN16,
+ AFE_CONN17,
+ AFE_CONN18,
+ AFE_CONN19,
+ AFE_CONN20,
+ AFE_CONN21,
+ AFE_CONN22,
+ AFE_DAC_CON0,
+ AFE_MEMIF_PBUF_SIZE,
+};
+
+static int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
+{
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ int val = num - MT2701_IO_I2S;
+
+ if (val < 0 || val >= afe_priv->soc->i2s_num) {
+ dev_err(afe->dev, "%s, num not available, num %d, val %d\n",
+ __func__, num, val);
+ return -EINVAL;
+ }
+ return val;
+}
+
+static int mt2701_afe_i2s_fs(unsigned int sample_rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mt2701_afe_i2s_rates); i++)
+ if (mt2701_afe_i2s_rates[i].rate == sample_rate)
+ return mt2701_afe_i2s_rates[i].regvalue;
+
+ return -EINVAL;
+}
+
+static int mt2701_afe_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+ bool mode = afe_priv->soc->has_one_heart_mode;
+
+ if (i2s_num < 0)
+ return i2s_num;
+
+ return mt2701_afe_enable_mclk(afe, mode ? 1 : i2s_num);
+}
+
+static int mt2701_afe_i2s_path_disable(struct mtk_base_afe *afe,
+ struct mt2701_i2s_path *i2s_path,
+ int stream_dir)
+{
+ const struct mt2701_i2s_data *i2s_data = i2s_path->i2s_data[stream_dir];
+
+ if (--i2s_path->on[stream_dir] < 0)
+ i2s_path->on[stream_dir] = 0;
+
+ if (i2s_path->on[stream_dir])
+ return 0;
+
+ /* disable i2s */
+ regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
+ ASYS_I2S_CON_I2S_EN, 0);
+
+ mt2701_afe_disable_i2s(afe, i2s_path, stream_dir);
+
+ return 0;
+}
+
+static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+ struct mt2701_i2s_path *i2s_path;
+ bool mode = afe_priv->soc->has_one_heart_mode;
+
+ if (i2s_num < 0)
+ return;
+
+ i2s_path = &afe_priv->i2s_path[i2s_num];
+
+ if (i2s_path->occupied[substream->stream])
+ i2s_path->occupied[substream->stream] = 0;
+ else
+ goto exit;
+
+ mt2701_afe_i2s_path_disable(afe, i2s_path, substream->stream);
+
+ /* need to disable i2s-out path when disable i2s-in */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ mt2701_afe_i2s_path_disable(afe, i2s_path, !substream->stream);
+
+exit:
+ /* disable mclk */
+ mt2701_afe_disable_mclk(afe, mode ? 1 : i2s_num);
+}
+
+static int mt2701_i2s_path_enable(struct mtk_base_afe *afe,
+ struct mt2701_i2s_path *i2s_path,
+ int stream_dir, int rate)
+{
+ const struct mt2701_i2s_data *i2s_data = i2s_path->i2s_data[stream_dir];
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ int reg, fs, w_len = 1; /* now we support bck 64bits only */
+ unsigned int mask, val;
+
+ /* no need to enable if already done */
+ if (++i2s_path->on[stream_dir] != 1)
+ return 0;
+
+ fs = mt2701_afe_i2s_fs(rate);
+
+ mask = ASYS_I2S_CON_FS |
+ ASYS_I2S_CON_I2S_COUPLE_MODE | /* 0 */
+ ASYS_I2S_CON_I2S_MODE |
+ ASYS_I2S_CON_WIDE_MODE;
+
+ val = ASYS_I2S_CON_FS_SET(fs) |
+ ASYS_I2S_CON_I2S_MODE |
+ ASYS_I2S_CON_WIDE_MODE_SET(w_len);
+
+ if (stream_dir == SNDRV_PCM_STREAM_CAPTURE) {
+ mask |= ASYS_I2S_IN_PHASE_FIX;
+ val |= ASYS_I2S_IN_PHASE_FIX;
+ reg = ASMI_TIMING_CON1;
+ } else {
+ if (afe_priv->soc->has_one_heart_mode) {
+ mask |= ASYS_I2S_CON_ONE_HEART_MODE;
+ val |= ASYS_I2S_CON_ONE_HEART_MODE;
+ }
+ reg = ASMO_TIMING_CON1;
+ }
+
+ regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, mask, val);
+
+ regmap_update_bits(afe->regmap, reg,
+ i2s_data->i2s_asrc_fs_mask
+ << i2s_data->i2s_asrc_fs_shift,
+ fs << i2s_data->i2s_asrc_fs_shift);
+
+ /* enable i2s */
+ mt2701_afe_enable_i2s(afe, i2s_path, stream_dir);
+
+ /* reset i2s hw status before enable */
+ regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
+ ASYS_I2S_CON_RESET, ASYS_I2S_CON_RESET);
+ udelay(1);
+ regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
+ ASYS_I2S_CON_RESET, 0);
+ udelay(1);
+ regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
+ ASYS_I2S_CON_I2S_EN, ASYS_I2S_CON_I2S_EN);
+ return 0;
+}
+
+static int mt2701_afe_i2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ int ret, i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+ struct mt2701_i2s_path *i2s_path;
+ bool mode = afe_priv->soc->has_one_heart_mode;
+
+ if (i2s_num < 0)
+ return i2s_num;
+
+ i2s_path = &afe_priv->i2s_path[i2s_num];
+
+ if (i2s_path->occupied[substream->stream])
+ return -EBUSY;
+
+ ret = mt2701_mclk_configuration(afe, mode ? 1 : i2s_num);
+ if (ret)
+ return ret;
+
+ i2s_path->occupied[substream->stream] = 1;
+
+ /* need to enable i2s-out path when enable i2s-in */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ mt2701_i2s_path_enable(afe, i2s_path, !substream->stream,
+ substream->runtime->rate);
+
+ mt2701_i2s_path_enable(afe, i2s_path, substream->stream,
+ substream->runtime->rate);
+
+ return 0;
+}
+
+static int mt2701_afe_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+ bool mode = afe_priv->soc->has_one_heart_mode;
+
+ if (i2s_num < 0)
+ return i2s_num;
+
+ /* mclk */
+ if (dir == SND_SOC_CLOCK_IN) {
+ dev_warn(dai->dev, "The SoCs doesn't support mclk input\n");
+ return -EINVAL;
+ }
+
+ afe_priv->i2s_path[mode ? 1 : i2s_num].mclk_rate = freq;
+
+ return 0;
+}
+
+static int mt2701_btmrg_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ ret = mt2701_enable_btmrg_clk(afe);
+ if (ret)
+ return ret;
+
+ afe_priv->mrg_enable[substream->stream] = 1;
+
+ return 0;
+}
+
+static int mt2701_btmrg_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int stream_fs;
+ u32 val, msk;
+
+ stream_fs = params_rate(params);
+
+ if (stream_fs != 8000 && stream_fs != 16000) {
+ dev_err(afe->dev, "unsupported rate %d\n", stream_fs);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+ AFE_MRGIF_CON_I2S_MODE_MASK,
+ AFE_MRGIF_CON_I2S_MODE_32K);
+
+ val = AFE_DAIBT_CON0_BT_FUNC_EN | AFE_DAIBT_CON0_BT_FUNC_RDY
+ | AFE_DAIBT_CON0_MRG_USE;
+ msk = val;
+
+ if (stream_fs == 16000)
+ val |= AFE_DAIBT_CON0_BT_WIDE_MODE_EN;
+
+ msk |= AFE_DAIBT_CON0_BT_WIDE_MODE_EN;
+
+ regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, msk, val);
+
+ regmap_update_bits(afe->regmap, AFE_DAIBT_CON0,
+ AFE_DAIBT_CON0_DAIBT_EN,
+ AFE_DAIBT_CON0_DAIBT_EN);
+ regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+ AFE_MRGIF_CON_MRG_I2S_EN,
+ AFE_MRGIF_CON_MRG_I2S_EN);
+ regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+ AFE_MRGIF_CON_MRG_EN,
+ AFE_MRGIF_CON_MRG_EN);
+ return 0;
+}
+
+static void mt2701_btmrg_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+ /* if the other direction stream is not occupied */
+ if (!afe_priv->mrg_enable[!substream->stream]) {
+ regmap_update_bits(afe->regmap, AFE_DAIBT_CON0,
+ AFE_DAIBT_CON0_DAIBT_EN, 0);
+ regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+ AFE_MRGIF_CON_MRG_EN, 0);
+ regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+ AFE_MRGIF_CON_MRG_I2S_EN, 0);
+ mt2701_disable_btmrg_clk(afe);
+ }
+
+ afe_priv->mrg_enable[substream->stream] = 0;
+}
+
+static int mt2701_simple_fe_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mtk_base_afe_memif *memif_tmp;
+ int stream_dir = substream->stream;
+
+ /* can't run single DL & DLM at the same time */
+ if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) {
+ memif_tmp = &afe->memif[MT2701_MEMIF_DLM];
+ if (memif_tmp->substream) {
+ dev_warn(afe->dev, "memif is not available");
+ return -EBUSY;
+ }
+ }
+
+ return mtk_afe_fe_startup(substream, dai);
+}
+
+static int mt2701_simple_fe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int stream_dir = substream->stream;
+
+ /* single DL use PAIR_INTERLEAVE */
+ if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
+ regmap_update_bits(afe->regmap,
+ AFE_MEMIF_PBUF_SIZE,
+ AFE_MEMIF_PBUF_SIZE_DLM_MASK,
+ AFE_MEMIF_PBUF_SIZE_PAIR_INTERLEAVE);
+
+ return mtk_afe_fe_hw_params(substream, params, dai);
+}
+
+static int mt2701_dlm_fe_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mtk_base_afe_memif *memif_tmp;
+ const struct mtk_base_memif_data *memif_data;
+ int i;
+
+ for (i = MT2701_MEMIF_DL1; i < MT2701_MEMIF_DL_SINGLE_NUM; ++i) {
+ memif_tmp = &afe->memif[i];
+ if (memif_tmp->substream)
+ return -EBUSY;
+ }
+
+ /* enable agent for all signal DL (due to hw design) */
+ for (i = MT2701_MEMIF_DL1; i < MT2701_MEMIF_DL_SINGLE_NUM; ++i) {
+ memif_data = afe->memif[i].data;
+ regmap_update_bits(afe->regmap,
+ memif_data->agent_disable_reg,
+ 1 << memif_data->agent_disable_shift,
+ 0 << memif_data->agent_disable_shift);
+ }
+
+ return mtk_afe_fe_startup(substream, dai);
+}
+
+static void mt2701_dlm_fe_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ const struct mtk_base_memif_data *memif_data;
+ int i;
+
+ for (i = MT2701_MEMIF_DL1; i < MT2701_MEMIF_DL_SINGLE_NUM; ++i) {
+ memif_data = afe->memif[i].data;
+ regmap_update_bits(afe->regmap,
+ memif_data->agent_disable_reg,
+ 1 << memif_data->agent_disable_shift,
+ 1 << memif_data->agent_disable_shift);
+ }
+
+ return mtk_afe_fe_shutdown(substream, dai);
+}
+
+static int mt2701_dlm_fe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int channels = params_channels(params);
+
+ regmap_update_bits(afe->regmap,
+ AFE_MEMIF_PBUF_SIZE,
+ AFE_MEMIF_PBUF_SIZE_DLM_MASK,
+ AFE_MEMIF_PBUF_SIZE_FULL_INTERLEAVE);
+ regmap_update_bits(afe->regmap,
+ AFE_MEMIF_PBUF_SIZE,
+ AFE_MEMIF_PBUF_SIZE_DLM_BYTE_MASK,
+ AFE_MEMIF_PBUF_SIZE_DLM_32BYTES);
+ regmap_update_bits(afe->regmap,
+ AFE_MEMIF_PBUF_SIZE,
+ AFE_MEMIF_PBUF_SIZE_DLM_CH_MASK,
+ AFE_MEMIF_PBUF_SIZE_DLM_CH(channels));
+
+ return mtk_afe_fe_hw_params(substream, params, dai);
+}
+
+static int mt2701_dlm_fe_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mtk_base_afe_memif *memif_tmp = &afe->memif[MT2701_MEMIF_DL1];
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ regmap_update_bits(afe->regmap, memif_tmp->data->enable_reg,
+ 1 << memif_tmp->data->enable_shift,
+ 1 << memif_tmp->data->enable_shift);
+ mtk_afe_fe_trigger(substream, cmd, dai);
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ mtk_afe_fe_trigger(substream, cmd, dai);
+ regmap_update_bits(afe->regmap, memif_tmp->data->enable_reg,
+ 1 << memif_tmp->data->enable_shift, 0);
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mt2701_memif_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ int fs;
+
+ if (asoc_rtd_to_cpu(rtd, 0)->id != MT2701_MEMIF_ULBT)
+ fs = mt2701_afe_i2s_fs(rate);
+ else
+ fs = (rate == 16000 ? 1 : 0);
+
+ return fs;
+}
+
+static int mt2701_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
+{
+ return mt2701_afe_i2s_fs(rate);
+}
+
+/* FE DAIs */
+static const struct snd_soc_dai_ops mt2701_single_memif_dai_ops = {
+ .startup = mt2701_simple_fe_startup,
+ .shutdown = mtk_afe_fe_shutdown,
+ .hw_params = mt2701_simple_fe_hw_params,
+ .hw_free = mtk_afe_fe_hw_free,
+ .prepare = mtk_afe_fe_prepare,
+ .trigger = mtk_afe_fe_trigger,
+};
+
+static const struct snd_soc_dai_ops mt2701_dlm_memif_dai_ops = {
+ .startup = mt2701_dlm_fe_startup,
+ .shutdown = mt2701_dlm_fe_shutdown,
+ .hw_params = mt2701_dlm_fe_hw_params,
+ .hw_free = mtk_afe_fe_hw_free,
+ .prepare = mtk_afe_fe_prepare,
+ .trigger = mt2701_dlm_fe_trigger,
+};
+
+/* I2S BE DAIs */
+static const struct snd_soc_dai_ops mt2701_afe_i2s_ops = {
+ .startup = mt2701_afe_i2s_startup,
+ .shutdown = mt2701_afe_i2s_shutdown,
+ .prepare = mt2701_afe_i2s_prepare,
+ .set_sysclk = mt2701_afe_i2s_set_sysclk,
+};
+
+/* MRG BE DAIs */
+static const struct snd_soc_dai_ops mt2701_btmrg_ops = {
+ .startup = mt2701_btmrg_startup,
+ .shutdown = mt2701_btmrg_shutdown,
+ .hw_params = mt2701_btmrg_hw_params,
+};
+
+static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
+ /* FE DAIs: memory intefaces to CPU */
+ {
+ .name = "PCMO0",
+ .id = MT2701_MEMIF_DL1,
+ .playback = {
+ .stream_name = "DL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE)
+ },
+ .ops = &mt2701_single_memif_dai_ops,
+ },
+ {
+ .name = "PCM_multi",
+ .id = MT2701_MEMIF_DLM,
+ .playback = {
+ .stream_name = "DLM",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE)
+
+ },
+ .ops = &mt2701_dlm_memif_dai_ops,
+ },
+ {
+ .name = "PCM0",
+ .id = MT2701_MEMIF_UL1,
+ .capture = {
+ .stream_name = "UL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE)
+ },
+ .ops = &mt2701_single_memif_dai_ops,
+ },
+ {
+ .name = "PCM1",
+ .id = MT2701_MEMIF_UL2,
+ .capture = {
+ .stream_name = "UL2",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE)
+
+ },
+ .ops = &mt2701_single_memif_dai_ops,
+ },
+ {
+ .name = "PCM_BT_DL",
+ .id = MT2701_MEMIF_DLBT,
+ .playback = {
+ .stream_name = "DLBT",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = (SNDRV_PCM_RATE_8000
+ | SNDRV_PCM_RATE_16000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &mt2701_single_memif_dai_ops,
+ },
+ {
+ .name = "PCM_BT_UL",
+ .id = MT2701_MEMIF_ULBT,
+ .capture = {
+ .stream_name = "ULBT",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = (SNDRV_PCM_RATE_8000
+ | SNDRV_PCM_RATE_16000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &mt2701_single_memif_dai_ops,
+ },
+ /* BE DAIs */
+ {
+ .name = "I2S0",
+ .id = MT2701_IO_I2S,
+ .playback = {
+ .stream_name = "I2S0 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE)
+
+ },
+ .capture = {
+ .stream_name = "I2S0 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE)
+
+ },
+ .ops = &mt2701_afe_i2s_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .name = "I2S1",
+ .id = MT2701_IO_2ND_I2S,
+ .playback = {
+ .stream_name = "I2S1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE)
+ },
+ .capture = {
+ .stream_name = "I2S1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE)
+ },
+ .ops = &mt2701_afe_i2s_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .name = "I2S2",
+ .id = MT2701_IO_3RD_I2S,
+ .playback = {
+ .stream_name = "I2S2 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE)
+ },
+ .capture = {
+ .stream_name = "I2S2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE)
+ },
+ .ops = &mt2701_afe_i2s_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .name = "I2S3",
+ .id = MT2701_IO_4TH_I2S,
+ .playback = {
+ .stream_name = "I2S3 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE)
+ },
+ .capture = {
+ .stream_name = "I2S3 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S24_LE
+ | SNDRV_PCM_FMTBIT_S32_LE)
+ },
+ .ops = &mt2701_afe_i2s_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .name = "MRG BT",
+ .id = MT2701_IO_MRG,
+ .playback = {
+ .stream_name = "BT Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = (SNDRV_PCM_RATE_8000
+ | SNDRV_PCM_RATE_16000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "BT Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = (SNDRV_PCM_RATE_8000
+ | SNDRV_PCM_RATE_16000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &mt2701_btmrg_ops,
+ .symmetric_rates = 1,
+ }
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o00_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN0, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o01_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN1, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o02_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I02 Switch", AFE_CONN2, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o03_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o14_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN14, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o15_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I12 Switch", AFE_CONN15, 12, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o16_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I13 Switch", AFE_CONN16, 13, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o17_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN17, 14, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o18_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN18, 15, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o19_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN19, 16, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o20_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN20, 17, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o21_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN21, 18, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o22_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN22, 19, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_o31_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I35 Switch", AFE_CONN41, 9, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_i02_mix[] = {
+ SOC_DAPM_SINGLE("I2S0 Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s0[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S0 Out Switch",
+ ASYS_I2SO1_CON, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s1[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S1 Out Switch",
+ ASYS_I2SO2_CON, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s2[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S2 Out Switch",
+ PWR2_TOP_CON, 17, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s3[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S3 Out Switch",
+ PWR2_TOP_CON, 18, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mt2701_afe_pcm_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I01", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I02", SND_SOC_NOPM, 0, 0, mt2701_afe_i02_mix,
+ ARRAY_SIZE(mt2701_afe_i02_mix)),
+ SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I12", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I13", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I14", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I15", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I16", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I19", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I26", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I35", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("O00", SND_SOC_NOPM, 0, 0, mt2701_afe_o00_mix,
+ ARRAY_SIZE(mt2701_afe_o00_mix)),
+ SND_SOC_DAPM_MIXER("O01", SND_SOC_NOPM, 0, 0, mt2701_afe_o01_mix,
+ ARRAY_SIZE(mt2701_afe_o01_mix)),
+ SND_SOC_DAPM_MIXER("O02", SND_SOC_NOPM, 0, 0, mt2701_afe_o02_mix,
+ ARRAY_SIZE(mt2701_afe_o02_mix)),
+ SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0, mt2701_afe_o03_mix,
+ ARRAY_SIZE(mt2701_afe_o03_mix)),
+ SND_SOC_DAPM_MIXER("O14", SND_SOC_NOPM, 0, 0, mt2701_afe_o14_mix,
+ ARRAY_SIZE(mt2701_afe_o14_mix)),
+ SND_SOC_DAPM_MIXER("O15", SND_SOC_NOPM, 0, 0, mt2701_afe_o15_mix,
+ ARRAY_SIZE(mt2701_afe_o15_mix)),
+ SND_SOC_DAPM_MIXER("O16", SND_SOC_NOPM, 0, 0, mt2701_afe_o16_mix,
+ ARRAY_SIZE(mt2701_afe_o16_mix)),
+ SND_SOC_DAPM_MIXER("O17", SND_SOC_NOPM, 0, 0, mt2701_afe_o17_mix,
+ ARRAY_SIZE(mt2701_afe_o17_mix)),
+ SND_SOC_DAPM_MIXER("O18", SND_SOC_NOPM, 0, 0, mt2701_afe_o18_mix,
+ ARRAY_SIZE(mt2701_afe_o18_mix)),
+ SND_SOC_DAPM_MIXER("O19", SND_SOC_NOPM, 0, 0, mt2701_afe_o19_mix,
+ ARRAY_SIZE(mt2701_afe_o19_mix)),
+ SND_SOC_DAPM_MIXER("O20", SND_SOC_NOPM, 0, 0, mt2701_afe_o20_mix,
+ ARRAY_SIZE(mt2701_afe_o20_mix)),
+ SND_SOC_DAPM_MIXER("O21", SND_SOC_NOPM, 0, 0, mt2701_afe_o21_mix,
+ ARRAY_SIZE(mt2701_afe_o21_mix)),
+ SND_SOC_DAPM_MIXER("O22", SND_SOC_NOPM, 0, 0, mt2701_afe_o22_mix,
+ ARRAY_SIZE(mt2701_afe_o22_mix)),
+ SND_SOC_DAPM_MIXER("O31", SND_SOC_NOPM, 0, 0, mt2701_afe_o31_mix,
+ ARRAY_SIZE(mt2701_afe_o31_mix)),
+
+ SND_SOC_DAPM_MIXER("I12I13", SND_SOC_NOPM, 0, 0,
+ mt2701_afe_multi_ch_out_i2s0,
+ ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s0)),
+ SND_SOC_DAPM_MIXER("I14I15", SND_SOC_NOPM, 0, 0,
+ mt2701_afe_multi_ch_out_i2s1,
+ ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s1)),
+ SND_SOC_DAPM_MIXER("I16I17", SND_SOC_NOPM, 0, 0,
+ mt2701_afe_multi_ch_out_i2s2,
+ ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s2)),
+ SND_SOC_DAPM_MIXER("I18I19", SND_SOC_NOPM, 0, 0,
+ mt2701_afe_multi_ch_out_i2s3,
+ ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s3)),
+};
+
+static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = {
+ {"I12", NULL, "DL1"},
+ {"I13", NULL, "DL1"},
+ {"I35", NULL, "DLBT"},
+
+ {"I2S0 Playback", NULL, "O15"},
+ {"I2S0 Playback", NULL, "O16"},
+ {"I2S1 Playback", NULL, "O17"},
+ {"I2S1 Playback", NULL, "O18"},
+ {"I2S2 Playback", NULL, "O19"},
+ {"I2S2 Playback", NULL, "O20"},
+ {"I2S3 Playback", NULL, "O21"},
+ {"I2S3 Playback", NULL, "O22"},
+ {"BT Playback", NULL, "O31"},
+
+ {"UL1", NULL, "O00"},
+ {"UL1", NULL, "O01"},
+ {"UL2", NULL, "O02"},
+ {"UL2", NULL, "O03"},
+ {"ULBT", NULL, "O14"},
+
+ {"I00", NULL, "I2S0 Capture"},
+ {"I01", NULL, "I2S0 Capture"},
+ {"I02", NULL, "I2S1 Capture"},
+ {"I03", NULL, "I2S1 Capture"},
+ /* I02,03 link to UL2, also need to open I2S0 */
+ {"I02", "I2S0 Switch", "I2S0 Capture"},
+
+ {"I26", NULL, "BT Capture"},
+
+ {"I12I13", "Multich I2S0 Out Switch", "DLM"},
+ {"I14I15", "Multich I2S1 Out Switch", "DLM"},
+ {"I16I17", "Multich I2S2 Out Switch", "DLM"},
+ {"I18I19", "Multich I2S3 Out Switch", "DLM"},
+
+ { "I12", NULL, "I12I13" },
+ { "I13", NULL, "I12I13" },
+ { "I14", NULL, "I14I15" },
+ { "I15", NULL, "I14I15" },
+ { "I16", NULL, "I16I17" },
+ { "I17", NULL, "I16I17" },
+ { "I18", NULL, "I18I19" },
+ { "I19", NULL, "I18I19" },
+
+ { "O00", "I00 Switch", "I00" },
+ { "O01", "I01 Switch", "I01" },
+ { "O02", "I02 Switch", "I02" },
+ { "O03", "I03 Switch", "I03" },
+ { "O14", "I26 Switch", "I26" },
+ { "O15", "I12 Switch", "I12" },
+ { "O16", "I13 Switch", "I13" },
+ { "O17", "I14 Switch", "I14" },
+ { "O18", "I15 Switch", "I15" },
+ { "O19", "I16 Switch", "I16" },
+ { "O20", "I17 Switch", "I17" },
+ { "O21", "I18 Switch", "I18" },
+ { "O22", "I19 Switch", "I19" },
+ { "O31", "I35 Switch", "I35" },
+};
+
+static int mt2701_afe_pcm_probe(struct snd_soc_component *component)
+{
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+ snd_soc_component_init_regmap(component, afe->regmap);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver mt2701_afe_pcm_dai_component = {
+ .probe = mt2701_afe_pcm_probe,
+ .name = "mt2701-afe-pcm-dai",
+ .dapm_widgets = mt2701_afe_pcm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt2701_afe_pcm_widgets),
+ .dapm_routes = mt2701_afe_pcm_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt2701_afe_pcm_routes),
+ .suspend = mtk_afe_suspend,
+ .resume = mtk_afe_resume,
+};
+
+static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
+ {
+ .name = "DL1",
+ .id = MT2701_MEMIF_DL1,
+ .reg_ofs_base = AFE_DL1_BASE,
+ .reg_ofs_cur = AFE_DL1_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 0,
+ .fs_maskbit = 0x1f,
+ .mono_reg = AFE_DAC_CON3,
+ .mono_shift = 16,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 1,
+ .hd_reg = AFE_MEMIF_HD_CON0,
+ .hd_shift = 0,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 6,
+ .msb_reg = -1,
+ },
+ {
+ .name = "DL2",
+ .id = MT2701_MEMIF_DL2,
+ .reg_ofs_base = AFE_DL2_BASE,
+ .reg_ofs_cur = AFE_DL2_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 5,
+ .fs_maskbit = 0x1f,
+ .mono_reg = AFE_DAC_CON3,
+ .mono_shift = 17,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 2,
+ .hd_reg = AFE_MEMIF_HD_CON0,
+ .hd_shift = 2,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 7,
+ .msb_reg = -1,
+ },
+ {
+ .name = "DL3",
+ .id = MT2701_MEMIF_DL3,
+ .reg_ofs_base = AFE_DL3_BASE,
+ .reg_ofs_cur = AFE_DL3_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 10,
+ .fs_maskbit = 0x1f,
+ .mono_reg = AFE_DAC_CON3,
+ .mono_shift = 18,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 3,
+ .hd_reg = AFE_MEMIF_HD_CON0,
+ .hd_shift = 4,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 8,
+ .msb_reg = -1,
+ },
+ {
+ .name = "DL4",
+ .id = MT2701_MEMIF_DL4,
+ .reg_ofs_base = AFE_DL4_BASE,
+ .reg_ofs_cur = AFE_DL4_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 15,
+ .fs_maskbit = 0x1f,
+ .mono_reg = AFE_DAC_CON3,
+ .mono_shift = 19,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 4,
+ .hd_reg = AFE_MEMIF_HD_CON0,
+ .hd_shift = 6,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 9,
+ .msb_reg = -1,
+ },
+ {
+ .name = "DL5",
+ .id = MT2701_MEMIF_DL5,
+ .reg_ofs_base = AFE_DL5_BASE,
+ .reg_ofs_cur = AFE_DL5_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 20,
+ .fs_maskbit = 0x1f,
+ .mono_reg = AFE_DAC_CON3,
+ .mono_shift = 20,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 5,
+ .hd_reg = AFE_MEMIF_HD_CON0,
+ .hd_shift = 8,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 10,
+ .msb_reg = -1,
+ },
+ {
+ .name = "DLM",
+ .id = MT2701_MEMIF_DLM,
+ .reg_ofs_base = AFE_DLMCH_BASE,
+ .reg_ofs_cur = AFE_DLMCH_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 0,
+ .fs_maskbit = 0x1f,
+ .mono_reg = -1,
+ .mono_shift = -1,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 7,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 28,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 12,
+ .msb_reg = -1,
+ },
+ {
+ .name = "UL1",
+ .id = MT2701_MEMIF_UL1,
+ .reg_ofs_base = AFE_VUL_BASE,
+ .reg_ofs_cur = AFE_VUL_CUR,
+ .fs_reg = AFE_DAC_CON2,
+ .fs_shift = 0,
+ .fs_maskbit = 0x1f,
+ .mono_reg = AFE_DAC_CON4,
+ .mono_shift = 0,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 10,
+ .hd_reg = AFE_MEMIF_HD_CON1,
+ .hd_shift = 0,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 0,
+ .msb_reg = -1,
+ },
+ {
+ .name = "UL2",
+ .id = MT2701_MEMIF_UL2,
+ .reg_ofs_base = AFE_UL2_BASE,
+ .reg_ofs_cur = AFE_UL2_CUR,
+ .fs_reg = AFE_DAC_CON2,
+ .fs_shift = 5,
+ .fs_maskbit = 0x1f,
+ .mono_reg = AFE_DAC_CON4,
+ .mono_shift = 2,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 11,
+ .hd_reg = AFE_MEMIF_HD_CON1,
+ .hd_shift = 2,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 1,
+ .msb_reg = -1,
+ },
+ {
+ .name = "UL3",
+ .id = MT2701_MEMIF_UL3,
+ .reg_ofs_base = AFE_UL3_BASE,
+ .reg_ofs_cur = AFE_UL3_CUR,
+ .fs_reg = AFE_DAC_CON2,
+ .fs_shift = 10,
+ .fs_maskbit = 0x1f,
+ .mono_reg = AFE_DAC_CON4,
+ .mono_shift = 4,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 12,
+ .hd_reg = AFE_MEMIF_HD_CON0,
+ .hd_shift = 0,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 2,
+ .msb_reg = -1,
+ },
+ {
+ .name = "UL4",
+ .id = MT2701_MEMIF_UL4,
+ .reg_ofs_base = AFE_UL4_BASE,
+ .reg_ofs_cur = AFE_UL4_CUR,
+ .fs_reg = AFE_DAC_CON2,
+ .fs_shift = 15,
+ .fs_maskbit = 0x1f,
+ .mono_reg = AFE_DAC_CON4,
+ .mono_shift = 6,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 13,
+ .hd_reg = AFE_MEMIF_HD_CON0,
+ .hd_shift = 6,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 3,
+ .msb_reg = -1,
+ },
+ {
+ .name = "UL5",
+ .id = MT2701_MEMIF_UL5,
+ .reg_ofs_base = AFE_UL5_BASE,
+ .reg_ofs_cur = AFE_UL5_CUR,
+ .fs_reg = AFE_DAC_CON2,
+ .fs_shift = 20,
+ .mono_reg = AFE_DAC_CON4,
+ .mono_shift = 8,
+ .fs_maskbit = 0x1f,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 14,
+ .hd_reg = AFE_MEMIF_HD_CON0,
+ .hd_shift = 8,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 4,
+ .msb_reg = -1,
+ },
+ {
+ .name = "DLBT",
+ .id = MT2701_MEMIF_DLBT,
+ .reg_ofs_base = AFE_ARB1_BASE,
+ .reg_ofs_cur = AFE_ARB1_CUR,
+ .fs_reg = AFE_DAC_CON3,
+ .fs_shift = 10,
+ .fs_maskbit = 0x1f,
+ .mono_reg = AFE_DAC_CON3,
+ .mono_shift = 22,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 8,
+ .hd_reg = AFE_MEMIF_HD_CON0,
+ .hd_shift = 14,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 13,
+ .msb_reg = -1,
+ },
+ {
+ .name = "ULBT",
+ .id = MT2701_MEMIF_ULBT,
+ .reg_ofs_base = AFE_DAI_BASE,
+ .reg_ofs_cur = AFE_DAI_CUR,
+ .fs_reg = AFE_DAC_CON2,
+ .fs_shift = 30,
+ .fs_maskbit = 0x1,
+ .mono_reg = -1,
+ .mono_shift = -1,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 17,
+ .hd_reg = AFE_MEMIF_HD_CON1,
+ .hd_shift = 20,
+ .agent_disable_reg = AUDIO_TOP_CON5,
+ .agent_disable_shift = 16,
+ .msb_reg = -1,
+ },
+};
+
+static const struct mtk_base_irq_data irq_data[MT2701_IRQ_ASYS_END] = {
+ {
+ .id = MT2701_IRQ_ASYS_IRQ1,
+ .irq_cnt_reg = ASYS_IRQ1_CON,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0xffffff,
+ .irq_fs_reg = ASYS_IRQ1_CON,
+ .irq_fs_shift = 24,
+ .irq_fs_maskbit = 0x1f,
+ .irq_en_reg = ASYS_IRQ1_CON,
+ .irq_en_shift = 31,
+ .irq_clr_reg = ASYS_IRQ_CLR,
+ .irq_clr_shift = 0,
+ },
+ {
+ .id = MT2701_IRQ_ASYS_IRQ2,
+ .irq_cnt_reg = ASYS_IRQ2_CON,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0xffffff,
+ .irq_fs_reg = ASYS_IRQ2_CON,
+ .irq_fs_shift = 24,
+ .irq_fs_maskbit = 0x1f,
+ .irq_en_reg = ASYS_IRQ2_CON,
+ .irq_en_shift = 31,
+ .irq_clr_reg = ASYS_IRQ_CLR,
+ .irq_clr_shift = 1,
+ },
+ {
+ .id = MT2701_IRQ_ASYS_IRQ3,
+ .irq_cnt_reg = ASYS_IRQ3_CON,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0xffffff,
+ .irq_fs_reg = ASYS_IRQ3_CON,
+ .irq_fs_shift = 24,
+ .irq_fs_maskbit = 0x1f,
+ .irq_en_reg = ASYS_IRQ3_CON,
+ .irq_en_shift = 31,
+ .irq_clr_reg = ASYS_IRQ_CLR,
+ .irq_clr_shift = 2,
+ }
+};
+
+static const struct mt2701_i2s_data mt2701_i2s_data[][2] = {
+ {
+ { ASYS_I2SO1_CON, 0, 0x1f },
+ { ASYS_I2SIN1_CON, 0, 0x1f },
+ },
+ {
+ { ASYS_I2SO2_CON, 5, 0x1f },
+ { ASYS_I2SIN2_CON, 5, 0x1f },
+ },
+ {
+ { ASYS_I2SO3_CON, 10, 0x1f },
+ { ASYS_I2SIN3_CON, 10, 0x1f },
+ },
+ {
+ { ASYS_I2SO4_CON, 15, 0x1f },
+ { ASYS_I2SIN4_CON, 15, 0x1f },
+ },
+ /* TODO - extend control registers supported by newer SoCs */
+};
+
+static irqreturn_t mt2701_asys_isr(int irq_id, void *dev)
+{
+ int id;
+ struct mtk_base_afe *afe = dev;
+ struct mtk_base_afe_memif *memif;
+ struct mtk_base_afe_irq *irq;
+ u32 status;
+
+ regmap_read(afe->regmap, ASYS_IRQ_STATUS, &status);
+ regmap_write(afe->regmap, ASYS_IRQ_CLR, status);
+
+ for (id = 0; id < MT2701_MEMIF_NUM; ++id) {
+ memif = &afe->memif[id];
+ if (memif->irq_usage < 0)
+ continue;
+
+ irq = &afe->irqs[memif->irq_usage];
+ if (status & 1 << irq->irq_data->irq_clr_shift)
+ snd_pcm_period_elapsed(memif->substream);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int mt2701_afe_runtime_suspend(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+
+ return mt2701_afe_disable_clock(afe);
+}
+
+static int mt2701_afe_runtime_resume(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+
+ return mt2701_afe_enable_clock(afe);
+}
+
+static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+ struct mtk_base_afe *afe;
+ struct mt2701_afe_private *afe_priv;
+ struct device *dev;
+ int i, irq_id, ret;
+
+ afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+ if (!afe)
+ return -ENOMEM;
+
+ afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+ GFP_KERNEL);
+ if (!afe->platform_priv)
+ return -ENOMEM;
+
+ afe_priv = afe->platform_priv;
+ afe_priv->soc = of_device_get_match_data(&pdev->dev);
+ afe->dev = &pdev->dev;
+ dev = afe->dev;
+
+ afe_priv->i2s_path = devm_kcalloc(dev,
+ afe_priv->soc->i2s_num,
+ sizeof(struct mt2701_i2s_path),
+ GFP_KERNEL);
+ if (!afe_priv->i2s_path)
+ return -ENOMEM;
+
+ irq_id = platform_get_irq_byname(pdev, "asys");
+ if (irq_id < 0)
+ return irq_id;
+
+ ret = devm_request_irq(dev, irq_id, mt2701_asys_isr,
+ IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+ if (ret) {
+ dev_err(dev, "could not request_irq for asys-isr\n");
+ return ret;
+ }
+
+ afe->regmap = syscon_node_to_regmap(dev->parent->of_node);
+ if (IS_ERR(afe->regmap)) {
+ dev_err(dev, "could not get regmap from parent\n");
+ return PTR_ERR(afe->regmap);
+ }
+
+ mutex_init(&afe->irq_alloc_lock);
+
+ /* memif initialize */
+ afe->memif_size = MT2701_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 = -1;
+ }
+
+ /* irq initialize */
+ afe->irqs_size = MT2701_IRQ_ASYS_END;
+ afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+ GFP_KERNEL);
+ if (!afe->irqs)
+ return -ENOMEM;
+
+ for (i = 0; i < afe->irqs_size; i++)
+ afe->irqs[i].irq_data = &irq_data[i];
+
+ /* I2S initialize */
+ for (i = 0; i < afe_priv->soc->i2s_num; i++) {
+ afe_priv->i2s_path[i].i2s_data[SNDRV_PCM_STREAM_PLAYBACK] =
+ &mt2701_i2s_data[i][SNDRV_PCM_STREAM_PLAYBACK];
+ afe_priv->i2s_path[i].i2s_data[SNDRV_PCM_STREAM_CAPTURE] =
+ &mt2701_i2s_data[i][SNDRV_PCM_STREAM_CAPTURE];
+ }
+
+ afe->mtk_afe_hardware = &mt2701_afe_hardware;
+ afe->memif_fs = mt2701_memif_fs;
+ afe->irq_fs = mt2701_irq_fs;
+ afe->reg_back_up_list = mt2701_afe_backup_list;
+ afe->reg_back_up_list_num = ARRAY_SIZE(mt2701_afe_backup_list);
+ afe->runtime_resume = mt2701_afe_runtime_resume;
+ afe->runtime_suspend = mt2701_afe_runtime_suspend;
+
+ /* initial audio related clock */
+ ret = mt2701_init_clock(afe);
+ if (ret) {
+ dev_err(dev, "init clock error\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, afe);
+
+ pm_runtime_enable(dev);
+ if (!pm_runtime_enabled(dev)) {
+ ret = mt2701_afe_runtime_resume(dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+ pm_runtime_get_sync(dev);
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &mtk_afe_pcm_platform,
+ NULL, 0);
+ if (ret) {
+ dev_warn(dev, "err_platform\n");
+ goto err_platform;
+ }
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &mt2701_afe_pcm_dai_component,
+ mt2701_afe_pcm_dais,
+ ARRAY_SIZE(mt2701_afe_pcm_dais));
+ if (ret) {
+ dev_warn(dev, "err_dai_component\n");
+ goto err_platform;
+ }
+
+ return 0;
+
+err_platform:
+ pm_runtime_put_sync(dev);
+err_pm_disable:
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static int mt2701_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mt2701_afe_runtime_suspend(&pdev->dev);
+
+ return 0;
+}
+
+static const struct mt2701_soc_variants mt2701_soc_v1 = {
+ .i2s_num = 4,
+};
+
+static const struct mt2701_soc_variants mt2701_soc_v2 = {
+ .has_one_heart_mode = true,
+ .i2s_num = 4,
+};
+
+static const struct of_device_id mt2701_afe_pcm_dt_match[] = {
+ { .compatible = "mediatek,mt2701-audio", .data = &mt2701_soc_v1 },
+ { .compatible = "mediatek,mt7622-audio", .data = &mt2701_soc_v2 },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt2701_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt2701_afe_pm_ops = {
+ SET_RUNTIME_PM_OPS(mt2701_afe_runtime_suspend,
+ mt2701_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt2701_afe_pcm_driver = {
+ .driver = {
+ .name = "mt2701-audio",
+ .of_match_table = mt2701_afe_pcm_dt_match,
+#ifdef CONFIG_PM
+ .pm = &mt2701_afe_pm_ops,
+#endif
+ },
+ .probe = mt2701_afe_pcm_dev_probe,
+ .remove = mt2701_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt2701_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 2701");
+MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
new file mode 100644
index 000000000..44a8d5cfb
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
@@ -0,0 +1,439 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt2701-cs42448.c -- MT2701 CS42448 ALSA SoC machine driver
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ir Lian <ir.lian@mediatek.com>
+ * Garlic Tseng <garlic.tseng@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_gpio.h>
+
+#include "mt2701-afe-common.h"
+
+struct mt2701_cs42448_private {
+ int i2s1_in_mux;
+ int i2s1_in_mux_gpio_sel_1;
+ int i2s1_in_mux_gpio_sel_2;
+};
+
+static const char * const i2sin_mux_switch_text[] = {
+ "ADC_SDOUT2",
+ "ADC_SDOUT3",
+ "I2S_IN_1",
+ "I2S_IN_2",
+};
+
+static const struct soc_enum i2sin_mux_enum =
+ SOC_ENUM_SINGLE_EXT(4, i2sin_mux_switch_text);
+
+static int mt2701_cs42448_i2sin1_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card);
+
+ ucontrol->value.integer.value[0] = priv->i2s1_in_mux;
+ return 0;
+}
+
+static int mt2701_cs42448_i2sin1_mux_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card);
+
+ if (ucontrol->value.integer.value[0] == priv->i2s1_in_mux)
+ return 0;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0);
+ gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0);
+ break;
+ case 1:
+ gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1);
+ gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0);
+ break;
+ case 2:
+ gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0);
+ gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1);
+ break;
+ case 3:
+ gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1);
+ gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1);
+ break;
+ default:
+ dev_warn(card->dev, "%s invalid setting\n", __func__);
+ }
+
+ priv->i2s1_in_mux = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget
+ mt2701_cs42448_asoc_card_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("Line Out Jack", NULL),
+ SND_SOC_DAPM_MIC("AMIC", NULL),
+ SND_SOC_DAPM_LINE("Tuner In", NULL),
+ SND_SOC_DAPM_LINE("Satellite Tuner In", NULL),
+ SND_SOC_DAPM_LINE("AUX In", NULL),
+};
+
+static const struct snd_kcontrol_new mt2701_cs42448_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Line Out Jack"),
+ SOC_DAPM_PIN_SWITCH("AMIC"),
+ SOC_DAPM_PIN_SWITCH("Tuner In"),
+ SOC_DAPM_PIN_SWITCH("Satellite Tuner In"),
+ SOC_DAPM_PIN_SWITCH("AUX In"),
+ SOC_ENUM_EXT("I2SIN1_MUX_Switch", i2sin_mux_enum,
+ mt2701_cs42448_i2sin1_mux_get,
+ mt2701_cs42448_i2sin1_mux_set),
+};
+
+static const unsigned int mt2701_cs42448_sampling_rates[] = {48000};
+
+static const struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = {
+ .count = ARRAY_SIZE(mt2701_cs42448_sampling_rates),
+ .list = mt2701_cs42448_sampling_rates,
+ .mask = 0,
+};
+
+static int mt2701_cs42448_fe_ops_startup(struct snd_pcm_substream *substream)
+{
+ int err;
+
+ err = snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &mt2701_cs42448_constraints_rates);
+ if (err < 0) {
+ dev_err(substream->pcm->card->dev,
+ "%s snd_pcm_hw_constraint_list failed: 0x%x\n",
+ __func__, err);
+ return err;
+ }
+ return 0;
+}
+
+static const struct snd_soc_ops mt2701_cs42448_48k_fe_ops = {
+ .startup = mt2701_cs42448_fe_ops_startup,
+};
+
+static int mt2701_cs42448_be_ops_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ unsigned int mclk_rate;
+ unsigned int rate = params_rate(params);
+ unsigned int div_mclk_over_bck = rate > 192000 ? 2 : 4;
+ unsigned int div_bck_over_lrck = 64;
+
+ mclk_rate = rate * div_bck_over_lrck * div_mclk_over_bck;
+
+ /* mt2701 mclk */
+ snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate, SND_SOC_CLOCK_OUT);
+
+ /* codec mclk */
+ snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate, SND_SOC_CLOCK_IN);
+
+ return 0;
+}
+
+static struct snd_soc_ops mt2701_cs42448_be_ops = {
+ .hw_params = mt2701_cs42448_be_ops_hw_params
+};
+
+enum {
+ DAI_LINK_FE_MULTI_CH_OUT,
+ DAI_LINK_FE_PCM0_IN,
+ DAI_LINK_FE_PCM1_IN,
+ DAI_LINK_FE_BT_OUT,
+ DAI_LINK_FE_BT_IN,
+ DAI_LINK_BE_I2S0,
+ DAI_LINK_BE_I2S1,
+ DAI_LINK_BE_I2S2,
+ DAI_LINK_BE_I2S3,
+ DAI_LINK_BE_MRG_BT,
+};
+
+SND_SOC_DAILINK_DEFS(fe_multi_ch_out,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM_multi")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(fe_pcm0_in,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(fe_pcm1_in,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(fe_bt_out,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM_BT_DL")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(fe_bt_in,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM_BT_UL")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(be_i2s0,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S0")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "cs42448")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(be_i2s1,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S1")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "cs42448")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(be_i2s2,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S2")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "cs42448")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(be_i2s3,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "cs42448")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(be_mrg_bt,
+ DAILINK_COMP_ARRAY(COMP_CPU("MRG BT")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "bt-sco-pcm-wb")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
+ /* FE */
+ [DAI_LINK_FE_MULTI_CH_OUT] = {
+ .name = "mt2701-cs42448-multi-ch-out",
+ .stream_name = "mt2701-cs42448-multi-ch-out",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ops = &mt2701_cs42448_48k_fe_ops,
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(fe_multi_ch_out),
+ },
+ [DAI_LINK_FE_PCM0_IN] = {
+ .name = "mt2701-cs42448-pcm0",
+ .stream_name = "mt2701-cs42448-pcm0-data-UL",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ops = &mt2701_cs42448_48k_fe_ops,
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(fe_pcm0_in),
+ },
+ [DAI_LINK_FE_PCM1_IN] = {
+ .name = "mt2701-cs42448-pcm1-data-UL",
+ .stream_name = "mt2701-cs42448-pcm1-data-UL",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ops = &mt2701_cs42448_48k_fe_ops,
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(fe_pcm1_in),
+ },
+ [DAI_LINK_FE_BT_OUT] = {
+ .name = "mt2701-cs42448-pcm-BT-out",
+ .stream_name = "mt2701-cs42448-pcm-BT",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(fe_bt_out),
+ },
+ [DAI_LINK_FE_BT_IN] = {
+ .name = "mt2701-cs42448-pcm-BT-in",
+ .stream_name = "mt2701-cs42448-pcm-BT",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(fe_bt_in),
+ },
+ /* BE */
+ [DAI_LINK_BE_I2S0] = {
+ .name = "mt2701-cs42448-I2S0",
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt2701_cs42448_be_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(be_i2s0),
+ },
+ [DAI_LINK_BE_I2S1] = {
+ .name = "mt2701-cs42448-I2S1",
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt2701_cs42448_be_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(be_i2s1),
+ },
+ [DAI_LINK_BE_I2S2] = {
+ .name = "mt2701-cs42448-I2S2",
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt2701_cs42448_be_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(be_i2s2),
+ },
+ [DAI_LINK_BE_I2S3] = {
+ .name = "mt2701-cs42448-I2S3",
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt2701_cs42448_be_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(be_i2s3),
+ },
+ [DAI_LINK_BE_MRG_BT] = {
+ .name = "mt2701-cs42448-MRG-BT",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(be_mrg_bt),
+ },
+};
+
+static struct snd_soc_card mt2701_cs42448_soc_card = {
+ .name = "mt2701-cs42448",
+ .owner = THIS_MODULE,
+ .dai_link = mt2701_cs42448_dai_links,
+ .num_links = ARRAY_SIZE(mt2701_cs42448_dai_links),
+ .controls = mt2701_cs42448_controls,
+ .num_controls = ARRAY_SIZE(mt2701_cs42448_controls),
+ .dapm_widgets = mt2701_cs42448_asoc_card_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt2701_cs42448_asoc_card_dapm_widgets),
+};
+
+static int mt2701_cs42448_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &mt2701_cs42448_soc_card;
+ int ret;
+ int i;
+ struct device_node *platform_node, *codec_node, *codec_node_bt_mrg;
+ struct mt2701_cs42448_private *priv =
+ devm_kzalloc(&pdev->dev, sizeof(struct mt2701_cs42448_private),
+ GFP_KERNEL);
+ struct device *dev = &pdev->dev;
+ struct snd_soc_dai_link *dai_link;
+
+ if (!priv)
+ return -ENOMEM;
+
+ platform_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,platform", 0);
+ if (!platform_node) {
+ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->platforms->name)
+ continue;
+ dai_link->platforms->of_node = platform_node;
+ }
+
+ card->dev = dev;
+
+ codec_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,audio-codec", 0);
+ if (!codec_node) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec' missing or invalid\n");
+ return -EINVAL;
+ }
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->codecs->name)
+ continue;
+ dai_link->codecs->of_node = codec_node;
+ }
+
+ codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,audio-codec-bt-mrg", 0);
+ if (!codec_node_bt_mrg) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec-bt-mrg' missing or invalid\n");
+ return -EINVAL;
+ }
+ mt2701_cs42448_dai_links[DAI_LINK_BE_MRG_BT].codecs->of_node
+ = codec_node_bt_mrg;
+
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
+ return ret;
+ }
+
+ priv->i2s1_in_mux_gpio_sel_1 =
+ of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio1", 0);
+ if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_1)) {
+ ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_1,
+ "i2s1_in_mux_gpio_sel_1");
+ if (ret)
+ dev_warn(&pdev->dev, "%s devm_gpio_request fail %d\n",
+ __func__, ret);
+ gpio_direction_output(priv->i2s1_in_mux_gpio_sel_1, 0);
+ }
+
+ priv->i2s1_in_mux_gpio_sel_2 =
+ of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio2", 0);
+ if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_2)) {
+ ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_2,
+ "i2s1_in_mux_gpio_sel_2");
+ if (ret)
+ dev_warn(&pdev->dev, "%s devm_gpio_request fail2 %d\n",
+ __func__, ret);
+ gpio_direction_output(priv->i2s1_in_mux_gpio_sel_2, 0);
+ }
+ snd_soc_card_set_drvdata(card, priv);
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+
+ if (ret)
+ dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+ __func__, ret);
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt2701_cs42448_machine_dt_match[] = {
+ {.compatible = "mediatek,mt2701-cs42448-machine",},
+ {}
+};
+#endif
+
+static struct platform_driver mt2701_cs42448_machine = {
+ .driver = {
+ .name = "mt2701-cs42448",
+ #ifdef CONFIG_OF
+ .of_match_table = mt2701_cs42448_machine_dt_match,
+ #endif
+ },
+ .probe = mt2701_cs42448_machine_probe,
+};
+
+module_platform_driver(mt2701_cs42448_machine);
+
+/* Module information */
+MODULE_DESCRIPTION("MT2701 CS42448 ALSA SoC machine driver");
+MODULE_AUTHOR("Ir Lian <ir.lian@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt2701 cs42448 soc card");
diff --git a/sound/soc/mediatek/mt2701/mt2701-reg.h b/sound/soc/mediatek/mt2701/mt2701-reg.h
new file mode 100644
index 000000000..c84d14cdd
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-reg.h
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt2701-reg.h -- Mediatek 2701 audio driver reg definition
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ */
+
+#ifndef _MT2701_REG_H_
+#define _MT2701_REG_H_
+
+#define AUDIO_TOP_CON0 0x0000
+#define AUDIO_TOP_CON4 0x0010
+#define AUDIO_TOP_CON5 0x0014
+#define AFE_DAIBT_CON0 0x001c
+#define AFE_MRGIF_CON 0x003c
+#define ASMI_TIMING_CON1 0x0100
+#define ASMO_TIMING_CON1 0x0104
+#define PWR1_ASM_CON1 0x0108
+#define ASYS_TOP_CON 0x0600
+#define ASYS_I2SIN1_CON 0x0604
+#define ASYS_I2SIN2_CON 0x0608
+#define ASYS_I2SIN3_CON 0x060c
+#define ASYS_I2SIN4_CON 0x0610
+#define ASYS_I2SIN5_CON 0x0614
+#define ASYS_I2SO1_CON 0x061C
+#define ASYS_I2SO2_CON 0x0620
+#define ASYS_I2SO3_CON 0x0624
+#define ASYS_I2SO4_CON 0x0628
+#define ASYS_I2SO5_CON 0x062c
+#define PWR2_TOP_CON 0x0634
+#define AFE_CONN0 0x06c0
+#define AFE_CONN1 0x06c4
+#define AFE_CONN2 0x06c8
+#define AFE_CONN3 0x06cc
+#define AFE_CONN14 0x06f8
+#define AFE_CONN15 0x06fc
+#define AFE_CONN16 0x0700
+#define AFE_CONN17 0x0704
+#define AFE_CONN18 0x0708
+#define AFE_CONN19 0x070c
+#define AFE_CONN20 0x0710
+#define AFE_CONN21 0x0714
+#define AFE_CONN22 0x0718
+#define AFE_CONN23 0x071c
+#define AFE_CONN24 0x0720
+#define AFE_CONN41 0x0764
+#define ASYS_IRQ1_CON 0x0780
+#define ASYS_IRQ2_CON 0x0784
+#define ASYS_IRQ3_CON 0x0788
+#define ASYS_IRQ_CLR 0x07c0
+#define ASYS_IRQ_STATUS 0x07c4
+#define PWR2_ASM_CON1 0x1070
+#define AFE_DAC_CON0 0x1200
+#define AFE_DAC_CON1 0x1204
+#define AFE_DAC_CON2 0x1208
+#define AFE_DAC_CON3 0x120c
+#define AFE_DAC_CON4 0x1210
+#define AFE_MEMIF_HD_CON1 0x121c
+#define AFE_MEMIF_PBUF_SIZE 0x1238
+#define AFE_MEMIF_HD_CON0 0x123c
+#define AFE_DL1_BASE 0x1240
+#define AFE_DL1_CUR 0x1244
+#define AFE_DL2_BASE 0x1250
+#define AFE_DL2_CUR 0x1254
+#define AFE_DL3_BASE 0x1260
+#define AFE_DL3_CUR 0x1264
+#define AFE_DL4_BASE 0x1270
+#define AFE_DL4_CUR 0x1274
+#define AFE_DL5_BASE 0x1280
+#define AFE_DL5_CUR 0x1284
+#define AFE_DLMCH_BASE 0x12a0
+#define AFE_DLMCH_CUR 0x12a4
+#define AFE_ARB1_BASE 0x12b0
+#define AFE_ARB1_CUR 0x12b4
+#define AFE_VUL_BASE 0x1300
+#define AFE_VUL_CUR 0x130c
+#define AFE_UL2_BASE 0x1310
+#define AFE_UL2_END 0x1318
+#define AFE_UL2_CUR 0x131c
+#define AFE_UL3_BASE 0x1320
+#define AFE_UL3_END 0x1328
+#define AFE_UL3_CUR 0x132c
+#define AFE_UL4_BASE 0x1330
+#define AFE_UL4_END 0x1338
+#define AFE_UL4_CUR 0x133c
+#define AFE_UL5_BASE 0x1340
+#define AFE_UL5_END 0x1348
+#define AFE_UL5_CUR 0x134c
+#define AFE_DAI_BASE 0x1370
+#define AFE_DAI_CUR 0x137c
+
+/* AFE_DAIBT_CON0 (0x001c) */
+#define AFE_DAIBT_CON0_DAIBT_EN (0x1 << 0)
+#define AFE_DAIBT_CON0_BT_FUNC_EN (0x1 << 1)
+#define AFE_DAIBT_CON0_BT_FUNC_RDY (0x1 << 3)
+#define AFE_DAIBT_CON0_BT_WIDE_MODE_EN (0x1 << 9)
+#define AFE_DAIBT_CON0_MRG_USE (0x1 << 12)
+
+/* PWR1_ASM_CON1 (0x0108) */
+#define PWR1_ASM_CON1_INIT_VAL (0x492)
+
+/* AFE_MRGIF_CON (0x003c) */
+#define AFE_MRGIF_CON_MRG_EN (0x1 << 0)
+#define AFE_MRGIF_CON_MRG_I2S_EN (0x1 << 16)
+#define AFE_MRGIF_CON_I2S_MODE_MASK (0xf << 20)
+#define AFE_MRGIF_CON_I2S_MODE_32K (0x4 << 20)
+
+/* ASYS_TOP_CON (0x0600) */
+#define ASYS_TOP_CON_ASYS_TIMING_ON (0x3 << 0)
+
+/* PWR2_ASM_CON1 (0x1070) */
+#define PWR2_ASM_CON1_INIT_VAL (0x492492)
+
+/* AFE_DAC_CON0 (0x1200) */
+#define AFE_DAC_CON0_AFE_ON (0x1 << 0)
+
+/* AFE_MEMIF_PBUF_SIZE (0x1238) */
+#define AFE_MEMIF_PBUF_SIZE_DLM_MASK (0x1 << 29)
+#define AFE_MEMIF_PBUF_SIZE_PAIR_INTERLEAVE (0x0 << 29)
+#define AFE_MEMIF_PBUF_SIZE_FULL_INTERLEAVE (0x1 << 29)
+#define DLMCH_BIT_WIDTH_MASK (0x1 << 28)
+#define AFE_MEMIF_PBUF_SIZE_DLM_CH_MASK (0xf << 24)
+#define AFE_MEMIF_PBUF_SIZE_DLM_CH(x) ((x) << 24)
+#define AFE_MEMIF_PBUF_SIZE_DLM_BYTE_MASK (0x3 << 12)
+#define AFE_MEMIF_PBUF_SIZE_DLM_32BYTES (0x1 << 12)
+
+/* I2S in/out register bit control */
+#define ASYS_I2S_CON_FS (0x1f << 8)
+#define ASYS_I2S_CON_FS_SET(x) ((x) << 8)
+#define ASYS_I2S_CON_RESET (0x1 << 30)
+#define ASYS_I2S_CON_I2S_EN (0x1 << 0)
+#define ASYS_I2S_CON_ONE_HEART_MODE (0x1 << 16)
+#define ASYS_I2S_CON_I2S_COUPLE_MODE (0x1 << 17)
+/* 0:EIAJ 1:I2S */
+#define ASYS_I2S_CON_I2S_MODE (0x1 << 3)
+#define ASYS_I2S_CON_WIDE_MODE (0x1 << 1)
+#define ASYS_I2S_CON_WIDE_MODE_SET(x) ((x) << 1)
+#define ASYS_I2S_IN_PHASE_FIX (0x1 << 31)
+
+#endif
diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c
new file mode 100644
index 000000000..70e494fb3
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt2701-wm8960.c -- MT2701 WM8960 ALSA SoC machine driver
+ *
+ * Copyright (c) 2017 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "mt2701-afe-common.h"
+
+static const struct snd_soc_dapm_widget mt2701_wm8960_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("AMIC", NULL),
+};
+
+static const struct snd_kcontrol_new mt2701_wm8960_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("AMIC"),
+};
+
+static int mt2701_wm8960_be_ops_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ unsigned int mclk_rate;
+ unsigned int rate = params_rate(params);
+ unsigned int div_mclk_over_bck = rate > 192000 ? 2 : 4;
+ unsigned int div_bck_over_lrck = 64;
+
+ mclk_rate = rate * div_bck_over_lrck * div_mclk_over_bck;
+
+ snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate, SND_SOC_CLOCK_OUT);
+ snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate, SND_SOC_CLOCK_IN);
+
+ return 0;
+}
+
+static struct snd_soc_ops mt2701_wm8960_be_ops = {
+ .hw_params = mt2701_wm8960_be_ops_hw_params
+};
+
+SND_SOC_DAILINK_DEFS(playback,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCMO0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(codec,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S0")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt2701_wm8960_dai_links[] = {
+ /* FE */
+ {
+ .name = "wm8960-playback",
+ .stream_name = "wm8960-playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback),
+ },
+ {
+ .name = "wm8960-capture",
+ .stream_name = "wm8960-capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture),
+ },
+ /* BE */
+ {
+ .name = "wm8960-codec",
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt2701_wm8960_be_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(codec),
+ },
+};
+
+static struct snd_soc_card mt2701_wm8960_card = {
+ .name = "mt2701-wm8960",
+ .owner = THIS_MODULE,
+ .dai_link = mt2701_wm8960_dai_links,
+ .num_links = ARRAY_SIZE(mt2701_wm8960_dai_links),
+ .controls = mt2701_wm8960_controls,
+ .num_controls = ARRAY_SIZE(mt2701_wm8960_controls),
+ .dapm_widgets = mt2701_wm8960_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt2701_wm8960_widgets),
+};
+
+static int mt2701_wm8960_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &mt2701_wm8960_card;
+ struct device_node *platform_node, *codec_node;
+ struct snd_soc_dai_link *dai_link;
+ int ret, i;
+
+ platform_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,platform", 0);
+ if (!platform_node) {
+ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->platforms->name)
+ continue;
+ dai_link->platforms->of_node = platform_node;
+ }
+
+ card->dev = &pdev->dev;
+
+ codec_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,audio-codec", 0);
+ if (!codec_node) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto put_platform_node;
+ }
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->codecs->name)
+ continue;
+ dai_link->codecs->of_node = codec_node;
+ }
+
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
+ goto put_codec_node;
+ }
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret)
+ dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+ __func__, ret);
+
+put_codec_node:
+ of_node_put(codec_node);
+put_platform_node:
+ of_node_put(platform_node);
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt2701_wm8960_machine_dt_match[] = {
+ {.compatible = "mediatek,mt2701-wm8960-machine",},
+ {}
+};
+#endif
+
+static struct platform_driver mt2701_wm8960_machine = {
+ .driver = {
+ .name = "mt2701-wm8960",
+#ifdef CONFIG_OF
+ .of_match_table = mt2701_wm8960_machine_dt_match,
+#endif
+ },
+ .probe = mt2701_wm8960_machine_probe,
+};
+
+module_platform_driver(mt2701_wm8960_machine);
+
+/* Module information */
+MODULE_DESCRIPTION("MT2701 WM8960 ALSA SoC machine driver");
+MODULE_AUTHOR("Ryder Lee <ryder.lee@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt2701 wm8960 soc card");
+
diff --git a/sound/soc/mediatek/mt6797/Makefile b/sound/soc/mediatek/mt6797/Makefile
new file mode 100644
index 000000000..bf6e179ea
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/Makefile
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# platform driver
+snd-soc-mt6797-afe-objs := \
+ mt6797-afe-pcm.o \
+ mt6797-afe-clk.o \
+ mt6797-dai-pcm.o \
+ mt6797-dai-hostless.o \
+ mt6797-dai-adda.o
+
+obj-$(CONFIG_SND_SOC_MT6797) += snd-soc-mt6797-afe.o
+
+# machine driver
+obj-$(CONFIG_SND_SOC_MT6797_MT6351) += mt6797-mt6351.o
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-clk.c b/sound/soc/mediatek/mt6797/mt6797-afe-clk.c
new file mode 100644
index 000000000..6f3e6acfc
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-clk.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt6797-afe-clk.c -- Mediatek 6797 afe clock ctrl
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/clk.h>
+
+#include "mt6797-afe-common.h"
+#include "mt6797-afe-clk.h"
+
+enum {
+ CLK_INFRA_SYS_AUD,
+ CLK_INFRA_SYS_AUD_26M,
+ CLK_TOP_MUX_AUD,
+ CLK_TOP_MUX_AUD_BUS,
+ CLK_TOP_SYSPLL3_D4,
+ CLK_TOP_SYSPLL1_D4,
+ CLK_CLK26M,
+ CLK_NUM
+};
+
+static const char *aud_clks[CLK_NUM] = {
+ [CLK_INFRA_SYS_AUD] = "infra_sys_audio_clk",
+ [CLK_INFRA_SYS_AUD_26M] = "infra_sys_audio_26m",
+ [CLK_TOP_MUX_AUD] = "top_mux_audio",
+ [CLK_TOP_MUX_AUD_BUS] = "top_mux_aud_intbus",
+ [CLK_TOP_SYSPLL3_D4] = "top_sys_pll3_d4",
+ [CLK_TOP_SYSPLL1_D4] = "top_sys_pll1_d4",
+ [CLK_CLK26M] = "top_clk26m_clk",
+};
+
+int mt6797_init_clock(struct mtk_base_afe *afe)
+{
+ struct mt6797_afe_private *afe_priv = afe->platform_priv;
+ int i;
+
+ 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++) {
+ afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
+ if (IS_ERR(afe_priv->clk[i])) {
+ dev_err(afe->dev, "%s(), devm_clk_get %s fail, ret %ld\n",
+ __func__, aud_clks[i],
+ PTR_ERR(afe_priv->clk[i]));
+ return PTR_ERR(afe_priv->clk[i]);
+ }
+ }
+
+ return 0;
+}
+
+int mt6797_afe_enable_clock(struct mtk_base_afe *afe)
+{
+ struct mt6797_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUD]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_INFRA_SYS_AUD], ret);
+ goto CLK_INFRA_SYS_AUDIO_ERR;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUD_26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_INFRA_SYS_AUD_26M], ret);
+ goto CLK_INFRA_SYS_AUD_26M_ERR;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD], ret);
+ goto CLK_MUX_AUDIO_ERR;
+ }
+
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD],
+ aud_clks[CLK_CLK26M], ret);
+ goto CLK_MUX_AUDIO_ERR;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_BUS]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_BUS], ret);
+ goto CLK_MUX_AUDIO_INTBUS_ERR;
+ }
+
+ return ret;
+
+CLK_MUX_AUDIO_INTBUS_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_BUS]);
+CLK_MUX_AUDIO_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD]);
+CLK_INFRA_SYS_AUD_26M_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD_26M]);
+CLK_INFRA_SYS_AUDIO_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD]);
+
+ return 0;
+}
+
+int mt6797_afe_disable_clock(struct mtk_base_afe *afe)
+{
+ struct mt6797_afe_private *afe_priv = afe->platform_priv;
+
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_BUS]);
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD]);
+ clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD_26M]);
+ clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD]);
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-clk.h b/sound/soc/mediatek/mt6797/mt6797-afe-clk.h
new file mode 100644
index 000000000..a6f0cb572
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-clk.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt6797-afe-clk.h -- Mediatek 6797 afe clock ctrl definition
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef _MT6797_AFE_CLK_H_
+#define _MT6797_AFE_CLK_H_
+
+struct mtk_base_afe;
+
+int mt6797_init_clock(struct mtk_base_afe *afe);
+int mt6797_afe_enable_clock(struct mtk_base_afe *afe);
+int mt6797_afe_disable_clock(struct mtk_base_afe *afe);
+#endif
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-common.h b/sound/soc/mediatek/mt6797/mt6797-afe-common.h
new file mode 100644
index 000000000..4eac9977b
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-common.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt6797-afe-common.h -- Mediatek 6797 audio driver definitions
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef _MT_6797_AFE_COMMON_H_
+#define _MT_6797_AFE_COMMON_H_
+
+#include <sound/soc.h>
+#include <linux/list.h>
+#include <linux/regmap.h>
+#include "../common/mtk-base-afe.h"
+
+enum {
+ MT6797_MEMIF_DL1,
+ MT6797_MEMIF_DL2,
+ MT6797_MEMIF_DL3,
+ MT6797_MEMIF_VUL,
+ MT6797_MEMIF_AWB,
+ MT6797_MEMIF_VUL12,
+ MT6797_MEMIF_DAI,
+ MT6797_MEMIF_MOD_DAI,
+ MT6797_MEMIF_NUM,
+ MT6797_DAI_ADDA = MT6797_MEMIF_NUM,
+ MT6797_DAI_PCM_1,
+ MT6797_DAI_PCM_2,
+ MT6797_DAI_HOSTLESS_LPBK,
+ MT6797_DAI_HOSTLESS_SPEECH,
+ MT6797_DAI_NUM,
+};
+
+enum {
+ MT6797_IRQ_1,
+ MT6797_IRQ_2,
+ MT6797_IRQ_3,
+ MT6797_IRQ_4,
+ MT6797_IRQ_7,
+ MT6797_IRQ_NUM,
+};
+
+struct clk;
+
+struct mt6797_afe_private {
+ struct clk **clk;
+};
+
+unsigned int mt6797_general_rate_transform(struct device *dev,
+ unsigned int rate);
+unsigned int mt6797_rate_transform(struct device *dev,
+ unsigned int rate, int aud_blk);
+
+/* dai register */
+int mt6797_dai_adda_register(struct mtk_base_afe *afe);
+int mt6797_dai_pcm_register(struct mtk_base_afe *afe);
+int mt6797_dai_hostless_register(struct mtk_base_afe *afe);
+#endif
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
new file mode 100644
index 000000000..3d68e4726
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
@@ -0,0 +1,916 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Mediatek ALSA SoC AFE platform driver for 6797
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+
+#include "mt6797-afe-common.h"
+#include "mt6797-afe-clk.h"
+#include "mt6797-interconnection.h"
+#include "mt6797-reg.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+enum {
+ MTK_AFE_RATE_8K = 0,
+ MTK_AFE_RATE_11K = 1,
+ MTK_AFE_RATE_12K = 2,
+ MTK_AFE_RATE_384K = 3,
+ MTK_AFE_RATE_16K = 4,
+ MTK_AFE_RATE_22K = 5,
+ MTK_AFE_RATE_24K = 6,
+ MTK_AFE_RATE_130K = 7,
+ MTK_AFE_RATE_32K = 8,
+ MTK_AFE_RATE_44K = 9,
+ MTK_AFE_RATE_48K = 10,
+ MTK_AFE_RATE_88K = 11,
+ MTK_AFE_RATE_96K = 12,
+ MTK_AFE_RATE_174K = 13,
+ MTK_AFE_RATE_192K = 14,
+ MTK_AFE_RATE_260K = 15,
+};
+
+enum {
+ MTK_AFE_DAI_MEMIF_RATE_8K = 0,
+ MTK_AFE_DAI_MEMIF_RATE_16K = 1,
+ MTK_AFE_DAI_MEMIF_RATE_32K = 2,
+};
+
+enum {
+ MTK_AFE_PCM_RATE_8K = 0,
+ MTK_AFE_PCM_RATE_16K = 1,
+ MTK_AFE_PCM_RATE_32K = 2,
+ MTK_AFE_PCM_RATE_48K = 3,
+};
+
+unsigned int mt6797_general_rate_transform(struct device *dev,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_RATE_8K;
+ case 11025:
+ return MTK_AFE_RATE_11K;
+ case 12000:
+ return MTK_AFE_RATE_12K;
+ case 16000:
+ return MTK_AFE_RATE_16K;
+ case 22050:
+ return MTK_AFE_RATE_22K;
+ case 24000:
+ return MTK_AFE_RATE_24K;
+ case 32000:
+ return MTK_AFE_RATE_32K;
+ case 44100:
+ return MTK_AFE_RATE_44K;
+ case 48000:
+ return MTK_AFE_RATE_48K;
+ case 88200:
+ return MTK_AFE_RATE_88K;
+ case 96000:
+ return MTK_AFE_RATE_96K;
+ case 130000:
+ return MTK_AFE_RATE_130K;
+ case 176400:
+ return MTK_AFE_RATE_174K;
+ case 192000:
+ return MTK_AFE_RATE_192K;
+ case 260000:
+ return MTK_AFE_RATE_260K;
+ default:
+ dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
+ __func__, rate, MTK_AFE_RATE_48K);
+ return MTK_AFE_RATE_48K;
+ }
+}
+
+static unsigned int dai_memif_rate_transform(struct device *dev,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_DAI_MEMIF_RATE_8K;
+ case 16000:
+ return MTK_AFE_DAI_MEMIF_RATE_16K;
+ case 32000:
+ return MTK_AFE_DAI_MEMIF_RATE_32K;
+ default:
+ dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
+ __func__, rate, MTK_AFE_DAI_MEMIF_RATE_16K);
+ return MTK_AFE_DAI_MEMIF_RATE_16K;
+ }
+}
+
+unsigned int mt6797_rate_transform(struct device *dev,
+ unsigned int rate, int aud_blk)
+{
+ switch (aud_blk) {
+ case MT6797_MEMIF_DAI:
+ case MT6797_MEMIF_MOD_DAI:
+ return dai_memif_rate_transform(dev, rate);
+ default:
+ return mt6797_general_rate_transform(dev, rate);
+ }
+}
+
+static const struct snd_pcm_hardware mt6797_afe_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .period_bytes_min = 256,
+ .period_bytes_max = 4 * 48 * 1024,
+ .periods_min = 2,
+ .periods_max = 256,
+ .buffer_bytes_max = 8 * 48 * 1024,
+ .fifo_size = 0,
+};
+
+static int mt6797_memif_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ int id = asoc_rtd_to_cpu(rtd, 0)->id;
+
+ return mt6797_rate_transform(afe->dev, rate, id);
+}
+
+static int mt6797_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+ return mt6797_general_rate_transform(afe->dev, rate);
+}
+
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_PCM_DAI_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mt6797_memif_dai_driver[] = {
+ /* FE DAIs: memory intefaces to CPU */
+ {
+ .name = "DL1",
+ .id = MT6797_MEMIF_DL1,
+ .playback = {
+ .stream_name = "DL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "DL2",
+ .id = MT6797_MEMIF_DL2,
+ .playback = {
+ .stream_name = "DL2",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "DL3",
+ .id = MT6797_MEMIF_DL3,
+ .playback = {
+ .stream_name = "DL3",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "UL1",
+ .id = MT6797_MEMIF_VUL12,
+ .capture = {
+ .stream_name = "UL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "UL2",
+ .id = MT6797_MEMIF_AWB,
+ .capture = {
+ .stream_name = "UL2",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "UL3",
+ .id = MT6797_MEMIF_VUL,
+ .capture = {
+ .stream_name = "UL3",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "UL_MONO_1",
+ .id = MT6797_MEMIF_MOD_DAI,
+ .capture = {
+ .stream_name = "UL_MONO_1",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = MTK_PCM_DAI_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "UL_MONO_2",
+ .id = MT6797_MEMIF_DAI,
+ .capture = {
+ .stream_name = "UL_MONO_2",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = MTK_PCM_DAI_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+};
+
+/* dma widget & routes*/
+static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN21,
+ I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN22,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN5,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN5,
+ I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN5,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN5,
+ I_DL3_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN6,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN6,
+ I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN6,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN6,
+ I_DL3_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN9,
+ I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN10,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_mono_1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN12,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN12,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_mono_2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN11,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN11,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mt6797_memif_widgets[] = {
+ /* memif */
+ SND_SOC_DAPM_MIXER("UL1_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul1_ch1_mix, ARRAY_SIZE(memif_ul1_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL1_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul1_ch2_mix, ARRAY_SIZE(memif_ul1_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL2_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul2_ch1_mix, ARRAY_SIZE(memif_ul2_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL2_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul2_ch2_mix, ARRAY_SIZE(memif_ul2_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL3_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul3_ch1_mix, ARRAY_SIZE(memif_ul3_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL3_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul3_ch2_mix, ARRAY_SIZE(memif_ul3_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL_MONO_1_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul_mono_1_mix,
+ ARRAY_SIZE(memif_ul_mono_1_mix)),
+
+ SND_SOC_DAPM_MIXER("UL_MONO_2_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul_mono_2_mix,
+ ARRAY_SIZE(memif_ul_mono_2_mix)),
+};
+
+static const struct snd_soc_dapm_route mt6797_memif_routes[] = {
+ /* capture */
+ {"UL1", NULL, "UL1_CH1"},
+ {"UL1", NULL, "UL1_CH2"},
+ {"UL1_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL1_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+ {"UL2", NULL, "UL2_CH1"},
+ {"UL2", NULL, "UL2_CH2"},
+ {"UL2_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL2_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+ {"UL3", NULL, "UL3_CH1"},
+ {"UL3", NULL, "UL3_CH2"},
+ {"UL3_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL3_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+ {"UL_MONO_1", NULL, "UL_MONO_1_CH1"},
+ {"UL_MONO_1_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_MONO_1_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+
+ {"UL_MONO_2", NULL, "UL_MONO_2_CH1"},
+ {"UL_MONO_2_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_MONO_2_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+};
+
+static const struct snd_soc_component_driver mt6797_afe_pcm_dai_component = {
+ .name = "mt6797-afe-pcm-dai",
+};
+
+static const struct mtk_base_memif_data memif_data[MT6797_MEMIF_NUM] = {
+ [MT6797_MEMIF_DL1] = {
+ .name = "DL1",
+ .id = MT6797_MEMIF_DL1,
+ .reg_ofs_base = AFE_DL1_BASE,
+ .reg_ofs_cur = AFE_DL1_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = DL1_MODE_SFT,
+ .fs_maskbit = DL1_MODE_MASK,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = DL1_DATA_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = DL1_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_shift = DL1_HD_SFT,
+ .agent_disable_reg = -1,
+ .msb_reg = -1,
+ },
+ [MT6797_MEMIF_DL2] = {
+ .name = "DL2",
+ .id = MT6797_MEMIF_DL2,
+ .reg_ofs_base = AFE_DL2_BASE,
+ .reg_ofs_cur = AFE_DL2_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = DL2_MODE_SFT,
+ .fs_maskbit = DL2_MODE_MASK,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = DL2_DATA_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = DL2_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_shift = DL2_HD_SFT,
+ .agent_disable_reg = -1,
+ .msb_reg = -1,
+ },
+ [MT6797_MEMIF_DL3] = {
+ .name = "DL3",
+ .id = MT6797_MEMIF_DL3,
+ .reg_ofs_base = AFE_DL3_BASE,
+ .reg_ofs_cur = AFE_DL3_CUR,
+ .fs_reg = AFE_DAC_CON0,
+ .fs_shift = DL3_MODE_SFT,
+ .fs_maskbit = DL3_MODE_MASK,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = DL3_DATA_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = DL3_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_shift = DL3_HD_SFT,
+ .agent_disable_reg = -1,
+ .msb_reg = -1,
+ },
+ [MT6797_MEMIF_VUL] = {
+ .name = "VUL",
+ .id = MT6797_MEMIF_VUL,
+ .reg_ofs_base = AFE_VUL_BASE,
+ .reg_ofs_cur = AFE_VUL_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = VUL_MODE_SFT,
+ .fs_maskbit = VUL_MODE_MASK,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = VUL_DATA_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = VUL_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_shift = VUL_HD_SFT,
+ .agent_disable_reg = -1,
+ .msb_reg = -1,
+ },
+ [MT6797_MEMIF_AWB] = {
+ .name = "AWB",
+ .id = MT6797_MEMIF_AWB,
+ .reg_ofs_base = AFE_AWB_BASE,
+ .reg_ofs_cur = AFE_AWB_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = AWB_MODE_SFT,
+ .fs_maskbit = AWB_MODE_MASK,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = AWB_DATA_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = AWB_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_shift = AWB_HD_SFT,
+ .agent_disable_reg = -1,
+ .msb_reg = -1,
+ },
+ [MT6797_MEMIF_VUL12] = {
+ .name = "VUL12",
+ .id = MT6797_MEMIF_VUL12,
+ .reg_ofs_base = AFE_VUL_D2_BASE,
+ .reg_ofs_cur = AFE_VUL_D2_CUR,
+ .fs_reg = AFE_DAC_CON0,
+ .fs_shift = VUL_DATA2_MODE_SFT,
+ .fs_maskbit = VUL_DATA2_MODE_MASK,
+ .mono_reg = AFE_DAC_CON0,
+ .mono_shift = VUL_DATA2_DATA_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = VUL_DATA2_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_shift = VUL_DATA2_HD_SFT,
+ .agent_disable_reg = -1,
+ .msb_reg = -1,
+ },
+ [MT6797_MEMIF_DAI] = {
+ .name = "DAI",
+ .id = MT6797_MEMIF_DAI,
+ .reg_ofs_base = AFE_DAI_BASE,
+ .reg_ofs_cur = AFE_DAI_CUR,
+ .fs_reg = AFE_DAC_CON0,
+ .fs_shift = DAI_MODE_SFT,
+ .fs_maskbit = DAI_MODE_MASK,
+ .mono_reg = -1,
+ .mono_shift = 0,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = DAI_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_shift = DAI_HD_SFT,
+ .agent_disable_reg = -1,
+ .msb_reg = -1,
+ },
+ [MT6797_MEMIF_MOD_DAI] = {
+ .name = "MOD_DAI",
+ .id = MT6797_MEMIF_MOD_DAI,
+ .reg_ofs_base = AFE_MOD_DAI_BASE,
+ .reg_ofs_cur = AFE_MOD_DAI_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = MOD_DAI_MODE_SFT,
+ .fs_maskbit = MOD_DAI_MODE_MASK,
+ .mono_reg = -1,
+ .mono_shift = 0,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = MOD_DAI_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_shift = MOD_DAI_HD_SFT,
+ .agent_disable_reg = -1,
+ .msb_reg = -1,
+ },
+};
+
+static const struct mtk_base_irq_data irq_data[MT6797_IRQ_NUM] = {
+ [MT6797_IRQ_1] = {
+ .id = MT6797_IRQ_1,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT1,
+ .irq_cnt_shift = AFE_IRQ_MCU_CNT1_SFT,
+ .irq_cnt_maskbit = AFE_IRQ_MCU_CNT1_MASK,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = IRQ1_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ1_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = IRQ1_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ1_MCU_CLR_SFT,
+ },
+ [MT6797_IRQ_2] = {
+ .id = MT6797_IRQ_2,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT2,
+ .irq_cnt_shift = AFE_IRQ_MCU_CNT2_SFT,
+ .irq_cnt_maskbit = AFE_IRQ_MCU_CNT2_MASK,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = IRQ2_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ2_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = IRQ2_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ2_MCU_CLR_SFT,
+ },
+ [MT6797_IRQ_3] = {
+ .id = MT6797_IRQ_3,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT3,
+ .irq_cnt_shift = AFE_IRQ_MCU_CNT3_SFT,
+ .irq_cnt_maskbit = AFE_IRQ_MCU_CNT3_MASK,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = IRQ3_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ3_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = IRQ3_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ3_MCU_CLR_SFT,
+ },
+ [MT6797_IRQ_4] = {
+ .id = MT6797_IRQ_4,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT4,
+ .irq_cnt_shift = AFE_IRQ_MCU_CNT4_SFT,
+ .irq_cnt_maskbit = AFE_IRQ_MCU_CNT4_MASK,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = IRQ4_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ4_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = IRQ4_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ4_MCU_CLR_SFT,
+ },
+ [MT6797_IRQ_7] = {
+ .id = MT6797_IRQ_7,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT7,
+ .irq_cnt_shift = AFE_IRQ_MCU_CNT7_SFT,
+ .irq_cnt_maskbit = AFE_IRQ_MCU_CNT7_MASK,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = IRQ7_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ7_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = IRQ7_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ7_MCU_CLR_SFT,
+ },
+};
+
+static const struct regmap_config mt6797_afe_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = AFE_MAX_REGISTER,
+};
+
+static irqreturn_t mt6797_afe_irq_handler(int irq_id, void *dev)
+{
+ struct mtk_base_afe *afe = dev;
+ struct mtk_base_afe_irq *irq;
+ unsigned int status;
+ unsigned int mcu_en;
+ int ret;
+ int i;
+ irqreturn_t irq_ret = IRQ_HANDLED;
+
+ /* get irq that is sent to MCU */
+ regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
+
+ ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
+ if (ret || (status & mcu_en) == 0) {
+ dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n",
+ __func__, ret, status, mcu_en);
+
+ /* only clear IRQ which is sent to MCU */
+ status = mcu_en & AFE_IRQ_STATUS_BITS;
+
+ irq_ret = IRQ_NONE;
+ goto err_irq;
+ }
+
+ for (i = 0; i < MT6797_MEMIF_NUM; i++) {
+ struct mtk_base_afe_memif *memif = &afe->memif[i];
+
+ if (!memif->substream)
+ continue;
+
+ irq = &afe->irqs[memif->irq_usage];
+
+ if (status & (1 << irq->irq_data->irq_en_shift))
+ snd_pcm_period_elapsed(memif->substream);
+ }
+
+err_irq:
+ /* clear irq */
+ regmap_write(afe->regmap,
+ AFE_IRQ_MCU_CLR,
+ status & AFE_IRQ_STATUS_BITS);
+
+ return irq_ret;
+}
+
+static int mt6797_afe_runtime_suspend(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ unsigned int afe_on_retm;
+ int retry = 0;
+
+ /* disable AFE */
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, AFE_ON_MASK_SFT, 0x0);
+ do {
+ regmap_read(afe->regmap, AFE_DAC_CON0, &afe_on_retm);
+ if ((afe_on_retm & AFE_ON_RETM_MASK_SFT) == 0)
+ break;
+
+ udelay(10);
+ } while (++retry < 100000);
+
+ if (retry)
+ dev_warn(afe->dev, "%s(), retry %d\n", __func__, retry);
+
+ /* make sure all irq status are cleared */
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
+
+ return mt6797_afe_disable_clock(afe);
+}
+
+static int mt6797_afe_runtime_resume(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ int ret;
+
+ ret = mt6797_afe_enable_clock(afe);
+ if (ret)
+ return ret;
+
+ /* irq signal to mcu only */
+ regmap_write(afe->regmap, AFE_IRQ_MCU_EN, AFE_IRQ_MCU_EN_MASK_SFT);
+
+ /* force all memif use normal mode */
+ regmap_update_bits(afe->regmap, AFE_MEMIF_HDALIGN,
+ 0x7ff << 16, 0x7ff << 16);
+ /* force cpu use normal mode when access sram data */
+ regmap_update_bits(afe->regmap, AFE_MEMIF_MSB,
+ CPU_COMPACT_MODE_MASK_SFT, 0);
+ /* force cpu use 8_24 format when writing 32bit data */
+ regmap_update_bits(afe->regmap, AFE_MEMIF_MSB,
+ CPU_HD_ALIGN_MASK_SFT, 0);
+
+ /* set all output port to 24bit */
+ regmap_update_bits(afe->regmap, AFE_CONN_24BIT,
+ 0x3fffffff, 0x3fffffff);
+
+ /* enable AFE */
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0,
+ AFE_ON_MASK_SFT,
+ 0x1 << AFE_ON_SFT);
+
+ return 0;
+}
+
+static int mt6797_afe_component_probe(struct snd_soc_component *component)
+{
+ return mtk_afe_add_sub_dai_control(component);
+}
+
+static const struct snd_soc_component_driver mt6797_afe_component = {
+ .name = AFE_PCM_NAME,
+ .probe = mt6797_afe_component_probe,
+ .pointer = mtk_afe_pcm_pointer,
+ .pcm_construct = mtk_afe_pcm_new,
+};
+
+static int mt6797_dai_memif_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mt6797_memif_dai_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mt6797_memif_dai_driver);
+
+ dai->dapm_widgets = mt6797_memif_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mt6797_memif_widgets);
+ dai->dapm_routes = mt6797_memif_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mt6797_memif_routes);
+ return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+ mt6797_dai_adda_register,
+ mt6797_dai_pcm_register,
+ mt6797_dai_hostless_register,
+ mt6797_dai_memif_register,
+};
+
+static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+ struct mtk_base_afe *afe;
+ struct mt6797_afe_private *afe_priv;
+ struct device *dev;
+ int i, irq_id, ret;
+
+ afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+ if (!afe)
+ return -ENOMEM;
+
+ 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;
+
+ /* initial audio related clock */
+ ret = mt6797_init_clock(afe);
+ if (ret) {
+ dev_err(dev, "init clock error\n");
+ return ret;
+ }
+
+ /* regmap init */
+ afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(afe->base_addr))
+ return PTR_ERR(afe->base_addr);
+
+ afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
+ &mt6797_afe_regmap_config);
+ if (IS_ERR(afe->regmap))
+ return PTR_ERR(afe->regmap);
+
+ /* init memif */
+ afe->memif_size = MT6797_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 = -1;
+ }
+
+ mutex_init(&afe->irq_alloc_lock);
+
+ /* irq initialize */
+ afe->irqs_size = MT6797_IRQ_NUM;
+ afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+ GFP_KERNEL);
+ if (!afe->irqs)
+ return -ENOMEM;
+
+ for (i = 0; i < afe->irqs_size; i++)
+ afe->irqs[i].irq_data = &irq_data[i];
+
+ /* request irq */
+ irq_id = platform_get_irq(pdev, 0);
+ if (irq_id < 0)
+ return irq_id;
+
+ ret = devm_request_irq(dev, irq_id, mt6797_afe_irq_handler,
+ IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+ if (ret) {
+ dev_err(dev, "could not request_irq for asys-isr\n");
+ return 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_warn(afe->dev, "dai register i %d fail, ret %d\n",
+ i, ret);
+ return ret;
+ }
+ }
+
+ /* init dai_driver and component_driver */
+ ret = mtk_afe_combine_sub_dai(afe);
+ if (ret) {
+ dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ afe->mtk_afe_hardware = &mt6797_afe_hardware;
+ afe->memif_fs = mt6797_memif_fs;
+ afe->irq_fs = mt6797_irq_fs;
+
+ afe->runtime_resume = mt6797_afe_runtime_resume;
+ afe->runtime_suspend = mt6797_afe_runtime_suspend;
+
+ platform_set_drvdata(pdev, afe);
+
+ pm_runtime_enable(dev);
+ if (!pm_runtime_enabled(dev))
+ goto err_pm_disable;
+ pm_runtime_get_sync(&pdev->dev);
+
+ /* register component */
+ ret = devm_snd_soc_register_component(dev, &mt6797_afe_component,
+ NULL, 0);
+ if (ret) {
+ dev_warn(dev, "err_platform\n");
+ goto err_pm_disable;
+ }
+
+ ret = devm_snd_soc_register_component(afe->dev,
+ &mt6797_afe_pcm_dai_component,
+ afe->dai_drivers,
+ afe->num_dai_drivers);
+ if (ret) {
+ dev_warn(dev, "err_dai_component\n");
+ goto err_pm_disable;
+ }
+
+ return 0;
+
+err_pm_disable:
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static int mt6797_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mt6797_afe_runtime_suspend(&pdev->dev);
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id mt6797_afe_pcm_dt_match[] = {
+ { .compatible = "mediatek,mt6797-audio", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt6797_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt6797_afe_pm_ops = {
+ SET_RUNTIME_PM_OPS(mt6797_afe_runtime_suspend,
+ mt6797_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt6797_afe_pcm_driver = {
+ .driver = {
+ .name = "mt6797-audio",
+ .of_match_table = mt6797_afe_pcm_dt_match,
+#ifdef CONFIG_PM
+ .pm = &mt6797_afe_pm_ops,
+#endif
+ },
+ .probe = mt6797_afe_pcm_dev_probe,
+ .remove = mt6797_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt6797_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 6797");
+MODULE_AUTHOR("KaiChieh Chuang <kaichieh.chuang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/mt6797/mt6797-dai-adda.c b/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
new file mode 100644
index 000000000..0ac6409c6
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
@@ -0,0 +1,402 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI ADDA Control
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include "mt6797-afe-common.h"
+#include "mt6797-interconnection.h"
+#include "mt6797-reg.h"
+
+enum {
+ MTK_AFE_ADDA_DL_RATE_8K = 0,
+ MTK_AFE_ADDA_DL_RATE_11K = 1,
+ MTK_AFE_ADDA_DL_RATE_12K = 2,
+ MTK_AFE_ADDA_DL_RATE_16K = 3,
+ MTK_AFE_ADDA_DL_RATE_22K = 4,
+ MTK_AFE_ADDA_DL_RATE_24K = 5,
+ MTK_AFE_ADDA_DL_RATE_32K = 6,
+ MTK_AFE_ADDA_DL_RATE_44K = 7,
+ MTK_AFE_ADDA_DL_RATE_48K = 8,
+ MTK_AFE_ADDA_DL_RATE_96K = 9,
+ MTK_AFE_ADDA_DL_RATE_192K = 10,
+};
+
+enum {
+ MTK_AFE_ADDA_UL_RATE_8K = 0,
+ MTK_AFE_ADDA_UL_RATE_16K = 1,
+ MTK_AFE_ADDA_UL_RATE_32K = 2,
+ MTK_AFE_ADDA_UL_RATE_48K = 3,
+ MTK_AFE_ADDA_UL_RATE_96K = 4,
+ MTK_AFE_ADDA_UL_RATE_192K = 5,
+ MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
+};
+
+static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_DL_RATE_8K;
+ case 11025:
+ return MTK_AFE_ADDA_DL_RATE_11K;
+ case 12000:
+ return MTK_AFE_ADDA_DL_RATE_12K;
+ case 16000:
+ return MTK_AFE_ADDA_DL_RATE_16K;
+ case 22050:
+ return MTK_AFE_ADDA_DL_RATE_22K;
+ case 24000:
+ return MTK_AFE_ADDA_DL_RATE_24K;
+ case 32000:
+ return MTK_AFE_ADDA_DL_RATE_32K;
+ case 44100:
+ return MTK_AFE_ADDA_DL_RATE_44K;
+ case 48000:
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_DL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_DL_RATE_192K;
+ default:
+ dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ }
+}
+
+static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_UL_RATE_8K;
+ case 16000:
+ return MTK_AFE_ADDA_UL_RATE_16K;
+ case 32000:
+ return MTK_AFE_ADDA_UL_RATE_32K;
+ case 48000:
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_UL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_UL_RATE_192K;
+ default:
+ dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ }
+}
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN3, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN3, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN3,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN3,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN3,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN3,
+ I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN4, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN4, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN4, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN4, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN4, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN4, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN4,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN4,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN4,
+ I_PCM_2_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN4,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN4,
+ I_PCM_2_CAP_CH2, 1, 0),
+};
+
+static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(125, 135);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+enum {
+ SUPPLY_SEQ_AUD_TOP_PDN,
+ SUPPLY_SEQ_ADDA_AFE_ON,
+ SUPPLY_SEQ_ADDA_DL_ON,
+ SUPPLY_SEQ_ADDA_UL_ON,
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+ /* adda */
+ 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_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
+ AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON,
+ AFE_ADDA_DL_SRC2_CON0,
+ DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+ AFE_ADDA_UL_SRC_CON0,
+ UL_SRC_ON_TMP_CTL_SFT, 0,
+ mtk_adda_ul_event,
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("aud_dac_clk", SUPPLY_SEQ_AUD_TOP_PDN,
+ AUDIO_TOP_CON0, PDN_DAC_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("aud_dac_predis_clk", SUPPLY_SEQ_AUD_TOP_PDN,
+ AUDIO_TOP_CON0, PDN_DAC_PREDIS_SFT, 1,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("aud_adc_clk", SUPPLY_SEQ_AUD_TOP_PDN,
+ AUDIO_TOP_CON0, PDN_ADC_SFT, 1,
+ NULL, 0),
+
+ SND_SOC_DAPM_CLOCK_SUPPLY("mtkaif_26m_clk"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+ /* playback */
+ {"ADDA_DL_CH1", "DL1_CH1", "DL1"},
+ {"ADDA_DL_CH2", "DL1_CH1", "DL1"},
+ {"ADDA_DL_CH2", "DL1_CH2", "DL1"},
+
+ {"ADDA_DL_CH1", "DL2_CH1", "DL2"},
+ {"ADDA_DL_CH2", "DL2_CH1", "DL2"},
+ {"ADDA_DL_CH2", "DL2_CH2", "DL2"},
+
+ {"ADDA_DL_CH1", "DL3_CH1", "DL3"},
+ {"ADDA_DL_CH2", "DL3_CH1", "DL3"},
+ {"ADDA_DL_CH2", "DL3_CH2", "DL3"},
+
+ {"ADDA Playback", NULL, "ADDA_DL_CH1"},
+ {"ADDA Playback", NULL, "ADDA_DL_CH2"},
+
+ /* adda enable */
+ {"ADDA Playback", NULL, "ADDA Enable"},
+ {"ADDA Playback", NULL, "ADDA Playback Enable"},
+ {"ADDA Capture", NULL, "ADDA Enable"},
+ {"ADDA Capture", NULL, "ADDA Capture Enable"},
+
+ /* clk */
+ {"ADDA Playback", NULL, "mtkaif_26m_clk"},
+ {"ADDA Playback", NULL, "aud_dac_clk"},
+ {"ADDA Playback", NULL, "aud_dac_predis_clk"},
+
+ {"ADDA Capture", NULL, "mtkaif_26m_clk"},
+ {"ADDA Capture", NULL, "aud_adc_clk"},
+};
+
+/* 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);
+ unsigned int rate = params_rate(params);
+
+ dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+ __func__, dai->id, substream->stream, rate);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ unsigned int dl_src2_con0 = 0;
+ unsigned int dl_src2_con1 = 0;
+
+ /* clean predistortion */
+ regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0);
+ regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0);
+
+ /* set input sampling rate */
+ dl_src2_con0 = adda_dl_rate_transform(afe, rate) << 28;
+
+ /* set output mode */
+ switch (rate) {
+ case 192000:
+ dl_src2_con0 |= (0x1 << 24); /* UP_SAMPLING_RATE_X2 */
+ dl_src2_con0 |= 1 << 14;
+ break;
+ case 96000:
+ dl_src2_con0 |= (0x2 << 24); /* UP_SAMPLING_RATE_X4 */
+ dl_src2_con0 |= 1 << 14;
+ break;
+ default:
+ dl_src2_con0 |= (0x3 << 24); /* UP_SAMPLING_RATE_X8 */
+ break;
+ }
+
+ /* turn off mute function */
+ dl_src2_con0 |= (0x03 << 11);
+
+ /* set voice input data if input sample rate is 8k or 16k */
+ if (rate == 8000 || rate == 16000)
+ dl_src2_con0 |= 0x01 << 5;
+
+ if (rate < 96000) {
+ /* SA suggest apply -0.3db to audio/speech path */
+ dl_src2_con1 = 0xf74f0000;
+ } else {
+ /* SA suggest apply -0.3db to audio/speech path
+ * with DL gain set to half,
+ * 0xFFFF = 0dB -> 0x8000 = 0dB when 96k, 192k
+ */
+ dl_src2_con1 = 0x7ba70000;
+ }
+
+ /* turn on down-link gain */
+ dl_src2_con0 = dl_src2_con0 | (0x01 << 1);
+
+ regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON0, dl_src2_con0);
+ regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON1, dl_src2_con1);
+ } else {
+ unsigned int voice_mode = 0;
+ unsigned int ul_src_con0 = 0; /* default value */
+
+ /* Using Internal ADC */
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_TOP_CON0,
+ 0x1 << 0,
+ 0x0 << 0);
+
+ voice_mode = adda_ul_rate_transform(afe, rate);
+
+ ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
+
+ /* up8x txif sat on */
+ regmap_write(afe->regmap, AFE_ADDA_NEWIF_CFG0, 0x03F87201);
+
+ if (rate >= 96000) { /* hires */
+ /* use hires format [1 0 23] */
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_NEWIF_CFG0,
+ 0x1 << 5,
+ 0x1 << 5);
+
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_NEWIF_CFG2,
+ 0xf << 28,
+ voice_mode << 28);
+ } else { /* normal 8~48k */
+ /* use fixed 260k anc path */
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_NEWIF_CFG2,
+ 0xf << 28,
+ 8 << 28);
+
+ /* ul_use_cic_out */
+ ul_src_con0 |= 0x1 << 20;
+ }
+
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_NEWIF_CFG2,
+ 0xf << 28,
+ 8 << 28);
+
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_UL_SRC_CON0,
+ 0xfffffffe,
+ ul_src_con0);
+ }
+
+ 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 = MT6797_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,
+ },
+};
+
+int mt6797_dai_adda_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_adda_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+
+ dai->dapm_widgets = mtk_dai_adda_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+ dai->dapm_routes = mtk_dai_adda_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt6797/mt6797-dai-hostless.c b/sound/soc/mediatek/mt6797/mt6797-dai-hostless.c
new file mode 100644
index 000000000..ed23e6a53
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-dai-hostless.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI Hostless Control
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include "mt6797-afe-common.h"
+
+/* dai component */
+static const struct snd_soc_dapm_route mtk_dai_hostless_routes[] = {
+ /* Hostless ADDA Loopback */
+ {"ADDA_DL_CH1", "ADDA_UL_CH1", "Hostless LPBK DL"},
+ {"ADDA_DL_CH1", "ADDA_UL_CH2", "Hostless LPBK DL"},
+ {"ADDA_DL_CH2", "ADDA_UL_CH1", "Hostless LPBK DL"},
+ {"ADDA_DL_CH2", "ADDA_UL_CH2", "Hostless LPBK DL"},
+ {"Hostless LPBK UL", NULL, "ADDA Capture"},
+
+ /* Hostless Speech */
+ {"ADDA_DL_CH1", "PCM_1_CAP_CH1", "Hostless Speech DL"},
+ {"ADDA_DL_CH2", "PCM_1_CAP_CH1", "Hostless Speech DL"},
+ {"ADDA_DL_CH2", "PCM_1_CAP_CH2", "Hostless Speech DL"},
+ {"ADDA_DL_CH1", "PCM_2_CAP_CH1", "Hostless Speech DL"},
+ {"ADDA_DL_CH2", "PCM_2_CAP_CH1", "Hostless Speech DL"},
+ {"ADDA_DL_CH2", "PCM_2_CAP_CH2", "Hostless Speech DL"},
+ {"PCM_1_PB_CH1", "ADDA_UL_CH1", "Hostless Speech DL"},
+ {"PCM_1_PB_CH2", "ADDA_UL_CH2", "Hostless Speech DL"},
+ {"PCM_2_PB_CH1", "ADDA_UL_CH1", "Hostless Speech DL"},
+ {"PCM_2_PB_CH2", "ADDA_UL_CH2", "Hostless Speech DL"},
+
+ {"Hostless Speech UL", NULL, "PCM 1 Capture"},
+ {"Hostless Speech UL", NULL, "PCM 2 Capture"},
+ {"Hostless Speech UL", NULL, "ADDA Capture"},
+};
+
+/* dai ops */
+static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ return snd_soc_set_runtime_hwparams(substream, afe->mtk_afe_hardware);
+}
+
+static const struct snd_soc_dai_ops mtk_dai_hostless_ops = {
+ .startup = mtk_dai_hostless_startup,
+};
+
+/* dai driver */
+#define MTK_HOSTLESS_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_HOSTLESS_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_hostless_driver[] = {
+ {
+ .name = "Hostless LPBK DAI",
+ .id = MT6797_DAI_HOSTLESS_LPBK,
+ .playback = {
+ .stream_name = "Hostless LPBK DL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Hostless LPBK UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+ {
+ .name = "Hostless Speech DAI",
+ .id = MT6797_DAI_HOSTLESS_SPEECH,
+ .playback = {
+ .stream_name = "Hostless Speech DL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Hostless Speech UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+};
+
+int mt6797_dai_hostless_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_hostless_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver);
+
+ dai->dapm_routes = mtk_dai_hostless_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes);
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c b/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c
new file mode 100644
index 000000000..3136f0bc7
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI I2S Control
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt6797-afe-common.h"
+#include "mt6797-interconnection.h"
+#include "mt6797-reg.h"
+
+enum AUD_TX_LCH_RPT {
+ AUD_TX_LCH_RPT_NO_REPEAT = 0,
+ AUD_TX_LCH_RPT_REPEAT = 1
+};
+
+enum AUD_VBT_16K_MODE {
+ AUD_VBT_16K_MODE_DISABLE = 0,
+ AUD_VBT_16K_MODE_ENABLE = 1
+};
+
+enum AUD_EXT_MODEM {
+ AUD_EXT_MODEM_SELECT_INTERNAL = 0,
+ AUD_EXT_MODEM_SELECT_EXTERNAL = 1
+};
+
+enum AUD_PCM_SYNC_TYPE {
+ /* bck sync length = 1 */
+ AUD_PCM_ONE_BCK_CYCLE_SYNC = 0,
+ /* bck sync length = PCM_INTF_CON1[9:13] */
+ AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1
+};
+
+enum AUD_BT_MODE {
+ AUD_BT_MODE_DUAL_MIC_ON_TX = 0,
+ AUD_BT_MODE_SINGLE_MIC_ON_TX = 1
+};
+
+enum AUD_PCM_AFIFO_SRC {
+ /* slave mode & external modem uses different crystal */
+ AUD_PCM_AFIFO_ASRC = 0,
+ /* slave mode & external modem uses the same crystal */
+ AUD_PCM_AFIFO_AFIFO = 1
+};
+
+enum AUD_PCM_CLOCK_SOURCE {
+ AUD_PCM_CLOCK_MASTER_MODE = 0,
+ AUD_PCM_CLOCK_SLAVE_MODE = 1
+};
+
+enum AUD_PCM_WLEN {
+ AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0,
+ AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1
+};
+
+enum AUD_PCM_MODE {
+ AUD_PCM_MODE_PCM_MODE_8K = 0,
+ AUD_PCM_MODE_PCM_MODE_16K = 1,
+ AUD_PCM_MODE_PCM_MODE_32K = 2,
+ AUD_PCM_MODE_PCM_MODE_48K = 3,
+};
+
+enum AUD_PCM_FMT {
+ AUD_PCM_FMT_I2S = 0,
+ AUD_PCM_FMT_EIAJ = 1,
+ AUD_PCM_FMT_PCM_MODE_A = 2,
+ AUD_PCM_FMT_PCM_MODE_B = 3
+};
+
+enum AUD_BCLK_OUT_INV {
+ AUD_BCLK_OUT_INV_NO_INVERSE = 0,
+ AUD_BCLK_OUT_INV_INVERSE = 1
+};
+
+enum AUD_PCM_EN {
+ AUD_PCM_EN_DISABLE = 0,
+ AUD_PCM_EN_ENABLE = 1
+};
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN7,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN7,
+ I_DL2_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN8,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN8,
+ I_DL2_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN27,
+ I_DL1_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN17,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN17,
+ I_DL2_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN18,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN18,
+ I_DL2_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN24,
+ I_DL1_CH1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_1_playback_ch1_mix,
+ ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)),
+ SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_1_playback_ch2_mix,
+ ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)),
+ SND_SOC_DAPM_MIXER("PCM_1_PB_CH4", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_1_playback_ch4_mix,
+ ARRAY_SIZE(mtk_pcm_1_playback_ch4_mix)),
+ SND_SOC_DAPM_MIXER("PCM_2_PB_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_2_playback_ch1_mix,
+ ARRAY_SIZE(mtk_pcm_2_playback_ch1_mix)),
+ SND_SOC_DAPM_MIXER("PCM_2_PB_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_2_playback_ch2_mix,
+ ARRAY_SIZE(mtk_pcm_2_playback_ch2_mix)),
+ SND_SOC_DAPM_MIXER("PCM_2_PB_CH4", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_2_playback_ch4_mix,
+ ARRAY_SIZE(mtk_pcm_2_playback_ch4_mix)),
+
+ SND_SOC_DAPM_SUPPLY("PCM_1_EN", PCM_INTF_CON1, PCM_EN_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("PCM_2_EN", PCM2_INTF_CON, PCM2_EN_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_INPUT("MD1_TO_AFE"),
+ SND_SOC_DAPM_INPUT("MD2_TO_AFE"),
+ SND_SOC_DAPM_OUTPUT("AFE_TO_MD1"),
+ SND_SOC_DAPM_OUTPUT("AFE_TO_MD2"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+ {"PCM 1 Playback", NULL, "PCM_1_PB_CH1"},
+ {"PCM 1 Playback", NULL, "PCM_1_PB_CH2"},
+ {"PCM 1 Playback", NULL, "PCM_1_PB_CH4"},
+ {"PCM 2 Playback", NULL, "PCM_2_PB_CH1"},
+ {"PCM 2 Playback", NULL, "PCM_2_PB_CH2"},
+ {"PCM 2 Playback", NULL, "PCM_2_PB_CH4"},
+
+ {"PCM 1 Playback", NULL, "PCM_1_EN"},
+ {"PCM 2 Playback", NULL, "PCM_2_EN"},
+ {"PCM 1 Capture", NULL, "PCM_1_EN"},
+ {"PCM 2 Capture", NULL, "PCM_2_EN"},
+
+ {"AFE_TO_MD1", NULL, "PCM 2 Playback"},
+ {"AFE_TO_MD2", NULL, "PCM 1 Playback"},
+ {"PCM 2 Capture", NULL, "MD1_TO_AFE"},
+ {"PCM 1 Capture", NULL, "MD2_TO_AFE"},
+
+ {"PCM_1_PB_CH1", "DL2_CH1", "DL2"},
+ {"PCM_1_PB_CH2", "DL2_CH2", "DL2"},
+ {"PCM_1_PB_CH4", "DL1_CH1", "DL1"},
+ {"PCM_2_PB_CH1", "DL2_CH1", "DL2"},
+ {"PCM_2_PB_CH2", "DL2_CH2", "DL2"},
+ {"PCM_2_PB_CH4", "DL1_CH1", "DL1"},
+};
+
+/* dai ops */
+static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ unsigned int rate = params_rate(params);
+ unsigned int rate_reg = mt6797_rate_transform(afe->dev, rate, dai->id);
+ unsigned int pcm_con = 0;
+
+ dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d, rate_reg %d, widget active p %d, c %d\n",
+ __func__,
+ dai->id,
+ substream->stream,
+ rate,
+ rate_reg,
+ dai->playback_widget->active,
+ dai->capture_widget->active);
+
+ if (dai->playback_widget->active || dai->capture_widget->active)
+ return 0;
+
+ switch (dai->id) {
+ case MT6797_DAI_PCM_1:
+ pcm_con |= AUD_BCLK_OUT_INV_NO_INVERSE << PCM_BCLK_OUT_INV_SFT;
+ pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT;
+ pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT;
+ pcm_con |= AUD_EXT_MODEM_SELECT_INTERNAL << PCM_EXT_MODEM_SFT;
+ pcm_con |= 0 << PCM_SYNC_LENGTH_SFT;
+ pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT;
+ pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT;
+ pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT;
+ pcm_con |= AUD_PCM_CLOCK_SLAVE_MODE << PCM_SLAVE_SFT;
+ pcm_con |= rate_reg << PCM_MODE_SFT;
+ pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM_FMT_SFT;
+
+ regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+ 0xfffffffe, pcm_con);
+ break;
+ case MT6797_DAI_PCM_2:
+ pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM2_TX_LCH_RPT_SFT;
+ pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM2_VBT_16K_MODE_SFT;
+ pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM2_BT_MODE_SFT;
+ pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM2_AFIFO_SFT;
+ pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM2_WLEN_SFT;
+ pcm_con |= rate_reg << PCM2_MODE_SFT;
+ pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM2_FMT_SFT;
+
+ regmap_update_bits(afe->regmap, PCM2_INTF_CON,
+ 0xfffffffe, pcm_con);
+ break;
+ default:
+ dev_warn(afe->dev, "%s(), id %d not support\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
+ .hw_params = mtk_dai_pcm_hw_params,
+};
+
+/* dai driver */
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 |\
+ SNDRV_PCM_RATE_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
+ {
+ .name = "PCM 1",
+ .id = MT6797_DAI_PCM_1,
+ .playback = {
+ .stream_name = "PCM 1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .capture = {
+ .stream_name = "PCM 1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_dai_pcm_ops,
+ .symmetric_rates = 1,
+ .symmetric_samplebits = 1,
+ },
+ {
+ .name = "PCM 2",
+ .id = MT6797_DAI_PCM_2,
+ .playback = {
+ .stream_name = "PCM 2 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .capture = {
+ .stream_name = "PCM 2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_dai_pcm_ops,
+ .symmetric_rates = 1,
+ .symmetric_samplebits = 1,
+ },
+};
+
+int mt6797_dai_pcm_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_pcm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+
+ dai->dapm_widgets = mtk_dai_pcm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+ dai->dapm_routes = mtk_dai_pcm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt6797/mt6797-interconnection.h b/sound/soc/mediatek/mt6797/mt6797-interconnection.h
new file mode 100644
index 000000000..07b759b20
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-interconnection.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Mediatek MT6797 audio driver interconnection definition
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef _MT6797_INTERCONNECTION_H_
+#define _MT6797_INTERCONNECTION_H_
+
+#define I_I2S0_CH1 0
+#define I_I2S0_CH2 1
+#define I_ADDA_UL_CH1 3
+#define I_ADDA_UL_CH2 4
+#define I_DL1_CH1 5
+#define I_DL1_CH2 6
+#define I_DL2_CH1 7
+#define I_DL2_CH2 8
+#define I_PCM_1_CAP_CH1 9
+#define I_GAIN1_OUT_CH1 10
+#define I_GAIN1_OUT_CH2 11
+#define I_GAIN2_OUT_CH1 12
+#define I_GAIN2_OUT_CH2 13
+#define I_PCM_2_CAP_CH1 14
+#define I_PCM_2_CAP_CH2 21
+#define I_PCM_1_CAP_CH2 22
+#define I_DL3_CH1 23
+#define I_DL3_CH2 24
+#define I_I2S2_CH1 25
+#define I_I2S2_CH2 26
+
+#endif
diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c
new file mode 100644
index 000000000..d2f6213a6
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt6797-mt6351.c -- MT6797 MT6351 ALSA SoC machine driver
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "mt6797-afe-common.h"
+
+SND_SOC_DAILINK_DEFS(playback_1,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback_2,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback_3,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL3")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture_1,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture_2,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture_3,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL3")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture_mono_1,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(hostless_lpbk,
+ DAILINK_COMP_ARRAY(COMP_CPU("Hostless LPBK DAI")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(hostless_speech,
+ DAILINK_COMP_ARRAY(COMP_CPU("Hostless Speech DAI")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(primary_codec,
+ DAILINK_COMP_ARRAY(COMP_CPU("ADDA")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "mt6351-snd-codec-aif1")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(pcm1,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(pcm2,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM 2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = {
+ /* FE */
+ {
+ .name = "Playback_1",
+ .stream_name = "Playback_1",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback_1),
+ },
+ {
+ .name = "Playback_2",
+ .stream_name = "Playback_2",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback_2),
+ },
+ {
+ .name = "Playback_3",
+ .stream_name = "Playback_3",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback_3),
+ },
+ {
+ .name = "Capture_1",
+ .stream_name = "Capture_1",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture_1),
+ },
+ {
+ .name = "Capture_2",
+ .stream_name = "Capture_2",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture_2),
+ },
+ {
+ .name = "Capture_3",
+ .stream_name = "Capture_3",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture_3),
+ },
+ {
+ .name = "Capture_Mono_1",
+ .stream_name = "Capture_Mono_1",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture_mono_1),
+ },
+ {
+ .name = "Hostless_LPBK",
+ .stream_name = "Hostless_LPBK",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(hostless_lpbk),
+ },
+ {
+ .name = "Hostless_Speech",
+ .stream_name = "Hostless_Speech",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(hostless_speech),
+ },
+ /* BE */
+ {
+ .name = "Primary Codec",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(primary_codec),
+ },
+ {
+ .name = "PCM 1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(pcm1),
+ },
+ {
+ .name = "PCM 2",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(pcm2),
+ },
+};
+
+static struct snd_soc_card mt6797_mt6351_card = {
+ .name = "mt6797-mt6351",
+ .owner = THIS_MODULE,
+ .dai_link = mt6797_mt6351_dai_links,
+ .num_links = ARRAY_SIZE(mt6797_mt6351_dai_links),
+};
+
+static int mt6797_mt6351_dev_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &mt6797_mt6351_card;
+ struct device_node *platform_node, *codec_node;
+ struct snd_soc_dai_link *dai_link;
+ int ret, i;
+
+ card->dev = &pdev->dev;
+
+ platform_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,platform", 0);
+ if (!platform_node) {
+ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->platforms->name)
+ continue;
+ dai_link->platforms->of_node = platform_node;
+ }
+
+ codec_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,audio-codec", 0);
+ if (!codec_node) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto put_platform_node;
+ }
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->codecs->name)
+ continue;
+ dai_link->codecs->of_node = codec_node;
+ }
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret)
+ dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+ __func__, ret);
+
+ of_node_put(codec_node);
+put_platform_node:
+ of_node_put(platform_node);
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt6797_mt6351_dt_match[] = {
+ {.compatible = "mediatek,mt6797-mt6351-sound",},
+ {}
+};
+#endif
+
+static struct platform_driver mt6797_mt6351_driver = {
+ .driver = {
+ .name = "mt6797-mt6351",
+#ifdef CONFIG_OF
+ .of_match_table = mt6797_mt6351_dt_match,
+#endif
+ },
+ .probe = mt6797_mt6351_dev_probe,
+};
+
+module_platform_driver(mt6797_mt6351_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT6797 MT6351 ALSA SoC machine driver");
+MODULE_AUTHOR("KaiChieh Chuang <kaichieh.chuang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt6797 mt6351 soc card");
+
diff --git a/sound/soc/mediatek/mt6797/mt6797-reg.h b/sound/soc/mediatek/mt6797/mt6797-reg.h
new file mode 100644
index 000000000..978f146c1
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-reg.h
@@ -0,0 +1,1015 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt6797-reg.h -- Mediatek 6797 audio driver reg definition
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef _MT6797_REG_H_
+#define _MT6797_REG_H_
+
+#define AUDIO_TOP_CON0 0x0000
+#define AUDIO_TOP_CON1 0x0004
+#define AUDIO_TOP_CON3 0x000c
+#define AFE_DAC_CON0 0x0010
+#define AFE_DAC_CON1 0x0014
+#define AFE_I2S_CON 0x0018
+#define AFE_DAIBT_CON0 0x001c
+#define AFE_CONN0 0x0020
+#define AFE_CONN1 0x0024
+#define AFE_CONN2 0x0028
+#define AFE_CONN3 0x002c
+#define AFE_CONN4 0x0030
+#define AFE_I2S_CON1 0x0034
+#define AFE_I2S_CON2 0x0038
+#define AFE_MRGIF_CON 0x003c
+#define AFE_DL1_BASE 0x0040
+#define AFE_DL1_CUR 0x0044
+#define AFE_DL1_END 0x0048
+#define AFE_I2S_CON3 0x004c
+#define AFE_DL2_BASE 0x0050
+#define AFE_DL2_CUR 0x0054
+#define AFE_DL2_END 0x0058
+#define AFE_CONN5 0x005c
+#define AFE_CONN_24BIT 0x006c
+#define AFE_AWB_BASE 0x0070
+#define AFE_AWB_END 0x0078
+#define AFE_AWB_CUR 0x007c
+#define AFE_VUL_BASE 0x0080
+#define AFE_VUL_END 0x0088
+#define AFE_VUL_CUR 0x008c
+#define AFE_DAI_BASE 0x0090
+#define AFE_DAI_END 0x0098
+#define AFE_DAI_CUR 0x009c
+#define AFE_CONN6 0x00bc
+#define AFE_MEMIF_MSB 0x00cc
+#define AFE_MEMIF_MON0 0x00d0
+#define AFE_MEMIF_MON1 0x00d4
+#define AFE_MEMIF_MON2 0x00d8
+#define AFE_MEMIF_MON4 0x00e0
+#define AFE_ADDA_DL_SRC2_CON0 0x0108
+#define AFE_ADDA_DL_SRC2_CON1 0x010c
+#define AFE_ADDA_UL_SRC_CON0 0x0114
+#define AFE_ADDA_UL_SRC_CON1 0x0118
+#define AFE_ADDA_TOP_CON0 0x0120
+#define AFE_ADDA_UL_DL_CON0 0x0124
+#define AFE_ADDA_SRC_DEBUG 0x012c
+#define AFE_ADDA_SRC_DEBUG_MON0 0x0130
+#define AFE_ADDA_SRC_DEBUG_MON1 0x0134
+#define AFE_ADDA_NEWIF_CFG0 0x0138
+#define AFE_ADDA_NEWIF_CFG1 0x013c
+#define AFE_ADDA_NEWIF_CFG2 0x0140
+#define AFE_DMA_CTL 0x0150
+#define AFE_DMA_MON0 0x0154
+#define AFE_DMA_MON1 0x0158
+#define AFE_SIDETONE_DEBUG 0x01d0
+#define AFE_SIDETONE_MON 0x01d4
+#define AFE_SIDETONE_CON0 0x01e0
+#define AFE_SIDETONE_COEFF 0x01e4
+#define AFE_SIDETONE_CON1 0x01e8
+#define AFE_SIDETONE_GAIN 0x01ec
+#define AFE_SGEN_CON0 0x01f0
+#define AFE_SINEGEN_CON_TDM 0x01fc
+#define AFE_TOP_CON0 0x0200
+#define AFE_ADDA_PREDIS_CON0 0x0260
+#define AFE_ADDA_PREDIS_CON1 0x0264
+#define AFE_MRGIF_MON0 0x0270
+#define AFE_MRGIF_MON1 0x0274
+#define AFE_MRGIF_MON2 0x0278
+#define AFE_I2S_MON 0x027c
+#define AFE_MOD_DAI_BASE 0x0330
+#define AFE_MOD_DAI_END 0x0338
+#define AFE_MOD_DAI_CUR 0x033c
+#define AFE_VUL_D2_BASE 0x0350
+#define AFE_VUL_D2_END 0x0358
+#define AFE_VUL_D2_CUR 0x035c
+#define AFE_DL3_BASE 0x0360
+#define AFE_DL3_CUR 0x0364
+#define AFE_DL3_END 0x0368
+#define AFE_HDMI_OUT_CON0 0x0370
+#define AFE_HDMI_BASE 0x0374
+#define AFE_HDMI_CUR 0x0378
+#define AFE_HDMI_END 0x037c
+#define AFE_HDMI_CONN0 0x0390
+#define AFE_IRQ3_MCU_CNT_MON 0x0398
+#define AFE_IRQ4_MCU_CNT_MON 0x039c
+#define AFE_IRQ_MCU_CON 0x03a0
+#define AFE_IRQ_MCU_STATUS 0x03a4
+#define AFE_IRQ_MCU_CLR 0x03a8
+#define AFE_IRQ_MCU_CNT1 0x03ac
+#define AFE_IRQ_MCU_CNT2 0x03b0
+#define AFE_IRQ_MCU_EN 0x03b4
+#define AFE_IRQ_MCU_MON2 0x03b8
+#define AFE_IRQ_MCU_CNT5 0x03bc
+#define AFE_IRQ1_MCU_CNT_MON 0x03c0
+#define AFE_IRQ2_MCU_CNT_MON 0x03c4
+#define AFE_IRQ1_MCU_EN_CNT_MON 0x03c8
+#define AFE_IRQ5_MCU_CNT_MON 0x03cc
+#define AFE_MEMIF_MINLEN 0x03d0
+#define AFE_MEMIF_MAXLEN 0x03d4
+#define AFE_MEMIF_PBUF_SIZE 0x03d8
+#define AFE_IRQ_MCU_CNT7 0x03dc
+#define AFE_IRQ7_MCU_CNT_MON 0x03e0
+#define AFE_IRQ_MCU_CNT3 0x03e4
+#define AFE_IRQ_MCU_CNT4 0x03e8
+#define AFE_APLL1_TUNER_CFG 0x03f0
+#define AFE_APLL2_TUNER_CFG 0x03f4
+#define AFE_MEMIF_HD_MODE 0x03f8
+#define AFE_MEMIF_HDALIGN 0x03fc
+#define AFE_GAIN1_CON0 0x0410
+#define AFE_GAIN1_CON1 0x0414
+#define AFE_GAIN1_CON2 0x0418
+#define AFE_GAIN1_CON3 0x041c
+#define AFE_CONN7 0x0420
+#define AFE_GAIN1_CUR 0x0424
+#define AFE_GAIN2_CON0 0x0428
+#define AFE_GAIN2_CON1 0x042c
+#define AFE_GAIN2_CON2 0x0430
+#define AFE_GAIN2_CON3 0x0434
+#define AFE_CONN8 0x0438
+#define AFE_GAIN2_CUR 0x043c
+#define AFE_CONN9 0x0440
+#define AFE_CONN10 0x0444
+#define AFE_CONN11 0x0448
+#define AFE_CONN12 0x044c
+#define AFE_CONN13 0x0450
+#define AFE_CONN14 0x0454
+#define AFE_CONN15 0x0458
+#define AFE_CONN16 0x045c
+#define AFE_CONN17 0x0460
+#define AFE_CONN18 0x0464
+#define AFE_CONN19 0x0468
+#define AFE_CONN20 0x046c
+#define AFE_CONN21 0x0470
+#define AFE_CONN22 0x0474
+#define AFE_CONN23 0x0478
+#define AFE_CONN24 0x047c
+#define AFE_CONN_RS 0x0494
+#define AFE_CONN_DI 0x0498
+#define AFE_CONN25 0x04b0
+#define AFE_CONN26 0x04b4
+#define AFE_CONN27 0x04b8
+#define AFE_CONN28 0x04bc
+#define AFE_CONN29 0x04c0
+#define AFE_SRAM_DELSEL_CON0 0x04f0
+#define AFE_SRAM_DELSEL_CON1 0x04f4
+#define AFE_ASRC_CON0 0x0500
+#define AFE_ASRC_CON1 0x0504
+#define AFE_ASRC_CON2 0x0508
+#define AFE_ASRC_CON3 0x050c
+#define AFE_ASRC_CON4 0x0510
+#define AFE_ASRC_CON5 0x0514
+#define AFE_ASRC_CON6 0x0518
+#define AFE_ASRC_CON7 0x051c
+#define AFE_ASRC_CON8 0x0520
+#define AFE_ASRC_CON9 0x0524
+#define AFE_ASRC_CON10 0x0528
+#define AFE_ASRC_CON11 0x052c
+#define PCM_INTF_CON1 0x0530
+#define PCM_INTF_CON2 0x0538
+#define PCM2_INTF_CON 0x053c
+#define AFE_TDM_CON1 0x0548
+#define AFE_TDM_CON2 0x054c
+#define AFE_ASRC_CON13 0x0550
+#define AFE_ASRC_CON14 0x0554
+#define AFE_ASRC_CON15 0x0558
+#define AFE_ASRC_CON16 0x055c
+#define AFE_ASRC_CON17 0x0560
+#define AFE_ASRC_CON18 0x0564
+#define AFE_ASRC_CON19 0x0568
+#define AFE_ASRC_CON20 0x056c
+#define AFE_ASRC_CON21 0x0570
+#define CLK_AUDDIV_0 0x05a0
+#define CLK_AUDDIV_1 0x05a4
+#define CLK_AUDDIV_2 0x05a8
+#define CLK_AUDDIV_3 0x05ac
+#define AUDIO_TOP_DBG_CON 0x05c8
+#define AUDIO_TOP_DBG_MON0 0x05cc
+#define AUDIO_TOP_DBG_MON1 0x05d0
+#define AUDIO_TOP_DBG_MON2 0x05d4
+#define AFE_ADDA2_TOP_CON0 0x0600
+#define AFE_ASRC4_CON0 0x06c0
+#define AFE_ASRC4_CON1 0x06c4
+#define AFE_ASRC4_CON2 0x06c8
+#define AFE_ASRC4_CON3 0x06cc
+#define AFE_ASRC4_CON4 0x06d0
+#define AFE_ASRC4_CON5 0x06d4
+#define AFE_ASRC4_CON6 0x06d8
+#define AFE_ASRC4_CON7 0x06dc
+#define AFE_ASRC4_CON8 0x06e0
+#define AFE_ASRC4_CON9 0x06e4
+#define AFE_ASRC4_CON10 0x06e8
+#define AFE_ASRC4_CON11 0x06ec
+#define AFE_ASRC4_CON12 0x06f0
+#define AFE_ASRC4_CON13 0x06f4
+#define AFE_ASRC4_CON14 0x06f8
+#define AFE_ASRC2_CON0 0x0700
+#define AFE_ASRC2_CON1 0x0704
+#define AFE_ASRC2_CON2 0x0708
+#define AFE_ASRC2_CON3 0x070c
+#define AFE_ASRC2_CON4 0x0710
+#define AFE_ASRC2_CON5 0x0714
+#define AFE_ASRC2_CON6 0x0718
+#define AFE_ASRC2_CON7 0x071c
+#define AFE_ASRC2_CON8 0x0720
+#define AFE_ASRC2_CON9 0x0724
+#define AFE_ASRC2_CON10 0x0728
+#define AFE_ASRC2_CON11 0x072c
+#define AFE_ASRC2_CON12 0x0730
+#define AFE_ASRC2_CON13 0x0734
+#define AFE_ASRC2_CON14 0x0738
+#define AFE_ASRC3_CON0 0x0740
+#define AFE_ASRC3_CON1 0x0744
+#define AFE_ASRC3_CON2 0x0748
+#define AFE_ASRC3_CON3 0x074c
+#define AFE_ASRC3_CON4 0x0750
+#define AFE_ASRC3_CON5 0x0754
+#define AFE_ASRC3_CON6 0x0758
+#define AFE_ASRC3_CON7 0x075c
+#define AFE_ASRC3_CON8 0x0760
+#define AFE_ASRC3_CON9 0x0764
+#define AFE_ASRC3_CON10 0x0768
+#define AFE_ASRC3_CON11 0x076c
+#define AFE_ASRC3_CON12 0x0770
+#define AFE_ASRC3_CON13 0x0774
+#define AFE_ASRC3_CON14 0x0778
+#define AFE_GENERAL_REG0 0x0800
+#define AFE_GENERAL_REG1 0x0804
+#define AFE_GENERAL_REG2 0x0808
+#define AFE_GENERAL_REG3 0x080c
+#define AFE_GENERAL_REG4 0x0810
+#define AFE_GENERAL_REG5 0x0814
+#define AFE_GENERAL_REG6 0x0818
+#define AFE_GENERAL_REG7 0x081c
+#define AFE_GENERAL_REG8 0x0820
+#define AFE_GENERAL_REG9 0x0824
+#define AFE_GENERAL_REG10 0x0828
+#define AFE_GENERAL_REG11 0x082c
+#define AFE_GENERAL_REG12 0x0830
+#define AFE_GENERAL_REG13 0x0834
+#define AFE_GENERAL_REG14 0x0838
+#define AFE_GENERAL_REG15 0x083c
+#define AFE_CBIP_CFG0 0x0840
+#define AFE_CBIP_MON0 0x0844
+#define AFE_CBIP_SLV_MUX_MON0 0x0848
+#define AFE_CBIP_SLV_DECODER_MON0 0x084c
+
+#define AFE_MAX_REGISTER AFE_CBIP_SLV_DECODER_MON0
+#define AFE_IRQ_STATUS_BITS 0x5f
+
+/* AUDIO_TOP_CON0 */
+#define AHB_IDLE_EN_INT_SFT 30
+#define AHB_IDLE_EN_INT_MASK 0x1
+#define AHB_IDLE_EN_INT_MASK_SFT (0x1 << 30)
+#define AHB_IDLE_EN_EXT_SFT 29
+#define AHB_IDLE_EN_EXT_MASK 0x1
+#define AHB_IDLE_EN_EXT_MASK_SFT (0x1 << 29)
+#define PDN_TML_SFT 27
+#define PDN_TML_MASK 0x1
+#define PDN_TML_MASK_SFT (0x1 << 27)
+#define PDN_DAC_PREDIS_SFT 26
+#define PDN_DAC_PREDIS_MASK 0x1
+#define PDN_DAC_PREDIS_MASK_SFT (0x1 << 26)
+#define PDN_DAC_SFT 25
+#define PDN_DAC_MASK 0x1
+#define PDN_DAC_MASK_SFT (0x1 << 25)
+#define PDN_ADC_SFT 24
+#define PDN_ADC_MASK 0x1
+#define PDN_ADC_MASK_SFT (0x1 << 24)
+#define PDN_TDM_CK_SFT 20
+#define PDN_TDM_CK_MASK 0x1
+#define PDN_TDM_CK_MASK_SFT (0x1 << 20)
+#define PDN_APLL_TUNER_SFT 19
+#define PDN_APLL_TUNER_MASK 0x1
+#define PDN_APLL_TUNER_MASK_SFT (0x1 << 19)
+#define PDN_APLL2_TUNER_SFT 18
+#define PDN_APLL2_TUNER_MASK 0x1
+#define PDN_APLL2_TUNER_MASK_SFT (0x1 << 18)
+#define APB3_SEL_SFT 14
+#define APB3_SEL_MASK 0x1
+#define APB3_SEL_MASK_SFT (0x1 << 14)
+#define APB_R2T_SFT 13
+#define APB_R2T_MASK 0x1
+#define APB_R2T_MASK_SFT (0x1 << 13)
+#define APB_W2T_SFT 12
+#define APB_W2T_MASK 0x1
+#define APB_W2T_MASK_SFT (0x1 << 12)
+#define PDN_24M_SFT 9
+#define PDN_24M_MASK 0x1
+#define PDN_24M_MASK_SFT (0x1 << 9)
+#define PDN_22M_SFT 8
+#define PDN_22M_MASK 0x1
+#define PDN_22M_MASK_SFT (0x1 << 8)
+#define PDN_ADDA4_ADC_SFT 7
+#define PDN_ADDA4_ADC_MASK 0x1
+#define PDN_ADDA4_ADC_MASK_SFT (0x1 << 7)
+#define PDN_I2S_SFT 6
+#define PDN_I2S_MASK 0x1
+#define PDN_I2S_MASK_SFT (0x1 << 6)
+#define PDN_AFE_SFT 2
+#define PDN_AFE_MASK 0x1
+#define PDN_AFE_MASK_SFT (0x1 << 2)
+
+/* AUDIO_TOP_CON1 */
+#define PDN_ADC_HIRES_TML_SFT 17
+#define PDN_ADC_HIRES_TML_MASK 0x1
+#define PDN_ADC_HIRES_TML_MASK_SFT (0x1 << 17)
+#define PDN_ADC_HIRES_SFT 16
+#define PDN_ADC_HIRES_MASK 0x1
+#define PDN_ADC_HIRES_MASK_SFT (0x1 << 16)
+#define I2S4_BCLK_SW_CG_SFT 7
+#define I2S4_BCLK_SW_CG_MASK 0x1
+#define I2S4_BCLK_SW_CG_MASK_SFT (0x1 << 7)
+#define I2S3_BCLK_SW_CG_SFT 6
+#define I2S3_BCLK_SW_CG_MASK 0x1
+#define I2S3_BCLK_SW_CG_MASK_SFT (0x1 << 6)
+#define I2S2_BCLK_SW_CG_SFT 5
+#define I2S2_BCLK_SW_CG_MASK 0x1
+#define I2S2_BCLK_SW_CG_MASK_SFT (0x1 << 5)
+#define I2S1_BCLK_SW_CG_SFT 4
+#define I2S1_BCLK_SW_CG_MASK 0x1
+#define I2S1_BCLK_SW_CG_MASK_SFT (0x1 << 4)
+#define I2S_SOFT_RST2_SFT 2
+#define I2S_SOFT_RST2_MASK 0x1
+#define I2S_SOFT_RST2_MASK_SFT (0x1 << 2)
+#define I2S_SOFT_RST_SFT 1
+#define I2S_SOFT_RST_MASK 0x1
+#define I2S_SOFT_RST_MASK_SFT (0x1 << 1)
+
+/* AFE_DAC_CON0 */
+#define AFE_AWB_RETM_SFT 31
+#define AFE_AWB_RETM_MASK 0x1
+#define AFE_AWB_RETM_MASK_SFT (0x1 << 31)
+#define AFE_DL1_DATA2_RETM_SFT 30
+#define AFE_DL1_DATA2_RETM_MASK 0x1
+#define AFE_DL1_DATA2_RETM_MASK_SFT (0x1 << 30)
+#define AFE_DL2_RETM_SFT 29
+#define AFE_DL2_RETM_MASK 0x1
+#define AFE_DL2_RETM_MASK_SFT (0x1 << 29)
+#define AFE_DL1_RETM_SFT 28
+#define AFE_DL1_RETM_MASK 0x1
+#define AFE_DL1_RETM_MASK_SFT (0x1 << 28)
+#define AFE_ON_RETM_SFT 27
+#define AFE_ON_RETM_MASK 0x1
+#define AFE_ON_RETM_MASK_SFT (0x1 << 27)
+#define MOD_DAI_DUP_WR_SFT 26
+#define MOD_DAI_DUP_WR_MASK 0x1
+#define MOD_DAI_DUP_WR_MASK_SFT (0x1 << 26)
+#define DAI_MODE_SFT 24
+#define DAI_MODE_MASK 0x3
+#define DAI_MODE_MASK_SFT (0x3 << 24)
+#define VUL_DATA2_MODE_SFT 20
+#define VUL_DATA2_MODE_MASK 0xf
+#define VUL_DATA2_MODE_MASK_SFT (0xf << 20)
+#define DL1_DATA2_MODE_SFT 16
+#define DL1_DATA2_MODE_MASK 0xf
+#define DL1_DATA2_MODE_MASK_SFT (0xf << 16)
+#define DL3_MODE_SFT 12
+#define DL3_MODE_MASK 0xf
+#define DL3_MODE_MASK_SFT (0xf << 12)
+#define VUL_DATA2_R_MONO_SFT 11
+#define VUL_DATA2_R_MONO_MASK 0x1
+#define VUL_DATA2_R_MONO_MASK_SFT (0x1 << 11)
+#define VUL_DATA2_DATA_SFT 10
+#define VUL_DATA2_DATA_MASK 0x1
+#define VUL_DATA2_DATA_MASK_SFT (0x1 << 10)
+#define VUL_DATA2_ON_SFT 9
+#define VUL_DATA2_ON_MASK 0x1
+#define VUL_DATA2_ON_MASK_SFT (0x1 << 9)
+#define DL1_DATA2_ON_SFT 8
+#define DL1_DATA2_ON_MASK 0x1
+#define DL1_DATA2_ON_MASK_SFT (0x1 << 8)
+#define MOD_DAI_ON_SFT 7
+#define MOD_DAI_ON_MASK 0x1
+#define MOD_DAI_ON_MASK_SFT (0x1 << 7)
+#define AWB_ON_SFT 6
+#define AWB_ON_MASK 0x1
+#define AWB_ON_MASK_SFT (0x1 << 6)
+#define DL3_ON_SFT 5
+#define DL3_ON_MASK 0x1
+#define DL3_ON_MASK_SFT (0x1 << 5)
+#define DAI_ON_SFT 4
+#define DAI_ON_MASK 0x1
+#define DAI_ON_MASK_SFT (0x1 << 4)
+#define VUL_ON_SFT 3
+#define VUL_ON_MASK 0x1
+#define VUL_ON_MASK_SFT (0x1 << 3)
+#define DL2_ON_SFT 2
+#define DL2_ON_MASK 0x1
+#define DL2_ON_MASK_SFT (0x1 << 2)
+#define DL1_ON_SFT 1
+#define DL1_ON_MASK 0x1
+#define DL1_ON_MASK_SFT (0x1 << 1)
+#define AFE_ON_SFT 0
+#define AFE_ON_MASK 0x1
+#define AFE_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_DAC_CON1 */
+#define MOD_DAI_MODE_SFT 30
+#define MOD_DAI_MODE_MASK 0x3
+#define MOD_DAI_MODE_MASK_SFT (0x3 << 30)
+#define DAI_DUP_WR_SFT 29
+#define DAI_DUP_WR_MASK 0x1
+#define DAI_DUP_WR_MASK_SFT (0x1 << 29)
+#define VUL_R_MONO_SFT 28
+#define VUL_R_MONO_MASK 0x1
+#define VUL_R_MONO_MASK_SFT (0x1 << 28)
+#define VUL_DATA_SFT 27
+#define VUL_DATA_MASK 0x1
+#define VUL_DATA_MASK_SFT (0x1 << 27)
+#define AXI_2X1_CG_DISABLE_SFT 26
+#define AXI_2X1_CG_DISABLE_MASK 0x1
+#define AXI_2X1_CG_DISABLE_MASK_SFT (0x1 << 26)
+#define AWB_R_MONO_SFT 25
+#define AWB_R_MONO_MASK 0x1
+#define AWB_R_MONO_MASK_SFT (0x1 << 25)
+#define AWB_DATA_SFT 24
+#define AWB_DATA_MASK 0x1
+#define AWB_DATA_MASK_SFT (0x1 << 24)
+#define DL3_DATA_SFT 23
+#define DL3_DATA_MASK 0x1
+#define DL3_DATA_MASK_SFT (0x1 << 23)
+#define DL2_DATA_SFT 22
+#define DL2_DATA_MASK 0x1
+#define DL2_DATA_MASK_SFT (0x1 << 22)
+#define DL1_DATA_SFT 21
+#define DL1_DATA_MASK 0x1
+#define DL1_DATA_MASK_SFT (0x1 << 21)
+#define DL1_DATA2_DATA_SFT 20
+#define DL1_DATA2_DATA_MASK 0x1
+#define DL1_DATA2_DATA_MASK_SFT (0x1 << 20)
+#define VUL_MODE_SFT 16
+#define VUL_MODE_MASK 0xf
+#define VUL_MODE_MASK_SFT (0xf << 16)
+#define AWB_MODE_SFT 12
+#define AWB_MODE_MASK 0xf
+#define AWB_MODE_MASK_SFT (0xf << 12)
+#define I2S_MODE_SFT 8
+#define I2S_MODE_MASK 0xf
+#define I2S_MODE_MASK_SFT (0xf << 8)
+#define DL2_MODE_SFT 4
+#define DL2_MODE_MASK 0xf
+#define DL2_MODE_MASK_SFT (0xf << 4)
+#define DL1_MODE_SFT 0
+#define DL1_MODE_MASK 0xf
+#define DL1_MODE_MASK_SFT (0xf << 0)
+
+/* AFE_ADDA_DL_SRC2_CON0 */
+#define DL_2_INPUT_MODE_CTL_SFT 28
+#define DL_2_INPUT_MODE_CTL_MASK 0xf
+#define DL_2_INPUT_MODE_CTL_MASK_SFT (0xf << 28)
+#define DL_2_CH1_SATURATION_EN_CTL_SFT 27
+#define DL_2_CH1_SATURATION_EN_CTL_MASK 0x1
+#define DL_2_CH1_SATURATION_EN_CTL_MASK_SFT (0x1 << 27)
+#define DL_2_CH2_SATURATION_EN_CTL_SFT 26
+#define DL_2_CH2_SATURATION_EN_CTL_MASK 0x1
+#define DL_2_CH2_SATURATION_EN_CTL_MASK_SFT (0x1 << 26)
+#define DL_2_OUTPUT_SEL_CTL_SFT 24
+#define DL_2_OUTPUT_SEL_CTL_MASK 0x3
+#define DL_2_OUTPUT_SEL_CTL_MASK_SFT (0x3 << 24)
+#define DL_2_FADEIN_0START_EN_SFT 16
+#define DL_2_FADEIN_0START_EN_MASK 0x3
+#define DL_2_FADEIN_0START_EN_MASK_SFT (0x3 << 16)
+#define DL_DISABLE_HW_CG_CTL_SFT 15
+#define DL_DISABLE_HW_CG_CTL_MASK 0x1
+#define DL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 15)
+#define C_DATA_EN_SEL_CTL_PRE_SFT 14
+#define C_DATA_EN_SEL_CTL_PRE_MASK 0x1
+#define C_DATA_EN_SEL_CTL_PRE_MASK_SFT (0x1 << 14)
+#define DL_2_SIDE_TONE_ON_CTL_PRE_SFT 13
+#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK 0x1
+#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK_SFT (0x1 << 13)
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_SFT 12
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK 0x1
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK_SFT (0x1 << 12)
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_SFT 11
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK 0x1
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK_SFT (0x1 << 11)
+#define DL2_ARAMPSP_CTL_PRE_SFT 9
+#define DL2_ARAMPSP_CTL_PRE_MASK 0x3
+#define DL2_ARAMPSP_CTL_PRE_MASK_SFT (0x3 << 9)
+#define DL_2_IIRMODE_CTL_PRE_SFT 6
+#define DL_2_IIRMODE_CTL_PRE_MASK 0x7
+#define DL_2_IIRMODE_CTL_PRE_MASK_SFT (0x7 << 6)
+#define DL_2_VOICE_MODE_CTL_PRE_SFT 5
+#define DL_2_VOICE_MODE_CTL_PRE_MASK 0x1
+#define DL_2_VOICE_MODE_CTL_PRE_MASK_SFT (0x1 << 5)
+#define D2_2_MUTE_CH1_ON_CTL_PRE_SFT 4
+#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK 0x1
+#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK_SFT (0x1 << 4)
+#define D2_2_MUTE_CH2_ON_CTL_PRE_SFT 3
+#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK 0x1
+#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK_SFT (0x1 << 3)
+#define DL_2_IIR_ON_CTL_PRE_SFT 2
+#define DL_2_IIR_ON_CTL_PRE_MASK 0x1
+#define DL_2_IIR_ON_CTL_PRE_MASK_SFT (0x1 << 2)
+#define DL_2_GAIN_ON_CTL_PRE_SFT 1
+#define DL_2_GAIN_ON_CTL_PRE_MASK 0x1
+#define DL_2_GAIN_ON_CTL_PRE_MASK_SFT (0x1 << 1)
+#define DL_2_SRC_ON_TMP_CTL_PRE_SFT 0
+#define DL_2_SRC_ON_TMP_CTL_PRE_MASK 0x1
+#define DL_2_SRC_ON_TMP_CTL_PRE_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_DL_SRC2_CON1 */
+#define DL_2_GAIN_CTL_PRE_SFT 16
+#define DL_2_GAIN_CTL_PRE_MASK 0xffff
+#define DL_2_GAIN_CTL_PRE_MASK_SFT (0xffff << 16)
+#define DL_2_GAIN_MODE_CTL_SFT 0
+#define DL_2_GAIN_MODE_CTL_MASK 0x1
+#define DL_2_GAIN_MODE_CTL_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_UL_SRC_CON0 */
+#define C_COMB_OUT_SIN_GEN_CTL_SFT 31
+#define C_COMB_OUT_SIN_GEN_CTL_MASK 0x1
+#define C_COMB_OUT_SIN_GEN_CTL_MASK_SFT (0x1 << 31)
+#define C_BASEBAND_SIN_GEN_CTL_SFT 30
+#define C_BASEBAND_SIN_GEN_CTL_MASK 0x1
+#define C_BASEBAND_SIN_GEN_CTL_MASK_SFT (0x1 << 30)
+#define C_DIGMIC_PHASE_SEL_CH1_CTL_SFT 27
+#define C_DIGMIC_PHASE_SEL_CH1_CTL_MASK 0x7
+#define C_DIGMIC_PHASE_SEL_CH1_CTL_MASK_SFT (0x7 << 27)
+#define C_DIGMIC_PHASE_SEL_CH2_CTL_SFT 24
+#define C_DIGMIC_PHASE_SEL_CH2_CTL_MASK 0x7
+#define C_DIGMIC_PHASE_SEL_CH2_CTL_MASK_SFT (0x7 << 24)
+#define C_TWO_DIGITAL_MIC_CTL_SFT 23
+#define C_TWO_DIGITAL_MIC_CTL_MASK 0x1
+#define C_TWO_DIGITAL_MIC_CTL_MASK_SFT (0x1 << 23)
+#define UL_MODE_3P25M_CH2_CTL_SFT 22
+#define UL_MODE_3P25M_CH2_CTL_MASK 0x1
+#define UL_MODE_3P25M_CH2_CTL_MASK_SFT (0x1 << 22)
+#define UL_MODE_3P25M_CH1_CTL_SFT 21
+#define UL_MODE_3P25M_CH1_CTL_MASK 0x1
+#define UL_MODE_3P25M_CH1_CTL_MASK_SFT (0x1 << 21)
+#define UL_SRC_USE_CIC_OUT_CTL_SFT 20
+#define UL_SRC_USE_CIC_OUT_CTL_MASK 0x1
+#define UL_SRC_USE_CIC_OUT_CTL_MASK_SFT (0x1 << 20)
+#define UL_VOICE_MODE_CH1_CH2_CTL_SFT 17
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK 0x7
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT (0x7 << 17)
+#define DMIC_LOW_POWER_MODE_CTL_SFT 14
+#define DMIC_LOW_POWER_MODE_CTL_MASK 0x3
+#define DMIC_LOW_POWER_MODE_CTL_MASK_SFT (0x3 << 14)
+#define DMIC_48K_SEL_CTL_SFT 13
+#define DMIC_48K_SEL_CTL_MASK 0x1
+#define DMIC_48K_SEL_CTL_MASK_SFT (0x1 << 13)
+#define UL_DISABLE_HW_CG_CTL_SFT 12
+#define UL_DISABLE_HW_CG_CTL_MASK 0x1
+#define UL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 12)
+#define UL_IIR_ON_TMP_CTL_SFT 10
+#define UL_IIR_ON_TMP_CTL_MASK 0x1
+#define UL_IIR_ON_TMP_CTL_MASK_SFT (0x1 << 10)
+#define UL_IIRMODE_CTL_SFT 7
+#define UL_IIRMODE_CTL_MASK 0x7
+#define UL_IIRMODE_CTL_MASK_SFT (0x7 << 7)
+#define DIGMIC_3P25M_1P625M_SEL_CTL_SFT 5
+#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK 0x1
+#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT (0x1 << 5)
+#define AGC_260K_SEL_CH2_CTL_SFT 4
+#define AGC_260K_SEL_CH2_CTL_MASK 0x1
+#define AGC_260K_SEL_CH2_CTL_MASK_SFT (0x1 << 4)
+#define AGC_260K_SEL_CH1_CTL_SFT 3
+#define AGC_260K_SEL_CH1_CTL_MASK 0x1
+#define AGC_260K_SEL_CH1_CTL_MASK_SFT (0x1 << 3)
+#define UL_LOOP_BACK_MODE_CTL_SFT 2
+#define UL_LOOP_BACK_MODE_CTL_MASK 0x1
+#define UL_LOOP_BACK_MODE_CTL_MASK_SFT (0x1 << 2)
+#define UL_SDM_3_LEVEL_CTL_SFT 1
+#define UL_SDM_3_LEVEL_CTL_MASK 0x1
+#define UL_SDM_3_LEVEL_CTL_MASK_SFT (0x1 << 1)
+#define UL_SRC_ON_TMP_CTL_SFT 0
+#define UL_SRC_ON_TMP_CTL_MASK 0x1
+#define UL_SRC_ON_TMP_CTL_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_UL_SRC_CON1 */
+#define C_SDM_RESET_CTL_SFT 31
+#define C_SDM_RESET_CTL_MASK 0x1
+#define C_SDM_RESET_CTL_MASK_SFT (0x1 << 31)
+#define ADITHON_CTL_SFT 30
+#define ADITHON_CTL_MASK 0x1
+#define ADITHON_CTL_MASK_SFT (0x1 << 30)
+#define ADITHVAL_CTL_SFT 28
+#define ADITHVAL_CTL_MASK 0x3
+#define ADITHVAL_CTL_MASK_SFT (0x3 << 28)
+#define C_DAC_EN_CTL_SFT 27
+#define C_DAC_EN_CTL_MASK 0x1
+#define C_DAC_EN_CTL_MASK_SFT (0x1 << 27)
+#define C_MUTE_SW_CTL_SFT 26
+#define C_MUTE_SW_CTL_MASK 0x1
+#define C_MUTE_SW_CTL_MASK_SFT (0x1 << 26)
+#define ASDM_SRC_SEL_CTL_SFT 25
+#define ASDM_SRC_SEL_CTL_MASK 0x1
+#define ASDM_SRC_SEL_CTL_MASK_SFT (0x1 << 25)
+#define C_AMP_DIV_CH2_CTL_SFT 21
+#define C_AMP_DIV_CH2_CTL_MASK 0x7
+#define C_AMP_DIV_CH2_CTL_MASK_SFT (0x7 << 21)
+#define C_FREQ_DIV_CH2_CTL_SFT 16
+#define C_FREQ_DIV_CH2_CTL_MASK 0x1f
+#define C_FREQ_DIV_CH2_CTL_MASK_SFT (0x1f << 16)
+#define C_SINE_MODE_CH2_CTL_SFT 12
+#define C_SINE_MODE_CH2_CTL_MASK 0xf
+#define C_SINE_MODE_CH2_CTL_MASK_SFT (0xf << 12)
+#define C_AMP_DIV_CH1_CTL_SFT 9
+#define C_AMP_DIV_CH1_CTL_MASK 0x7
+#define C_AMP_DIV_CH1_CTL_MASK_SFT (0x7 << 9)
+#define C_FREQ_DIV_CH1_CTL_SFT 4
+#define C_FREQ_DIV_CH1_CTL_MASK 0x1f
+#define C_FREQ_DIV_CH1_CTL_MASK_SFT (0x1f << 4)
+#define C_SINE_MODE_CH1_CTL_SFT 0
+#define C_SINE_MODE_CH1_CTL_MASK 0xf
+#define C_SINE_MODE_CH1_CTL_MASK_SFT (0xf << 0)
+
+/* AFE_ADDA_TOP_CON0 */
+#define C_LOOP_BACK_MODE_CTL_SFT 12
+#define C_LOOP_BACK_MODE_CTL_MASK 0xf
+#define C_LOOP_BACK_MODE_CTL_MASK_SFT (0xf << 12)
+#define C_EXT_ADC_CTL_SFT 0
+#define C_EXT_ADC_CTL_MASK 0x1
+#define C_EXT_ADC_CTL_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_UL_DL_CON0 */
+#define AFE_UL_DL_CON0_RESERVED_SFT 1
+#define AFE_UL_DL_CON0_RESERVED_MASK 0x3fff
+#define AFE_UL_DL_CON0_RESERVED_MASK_SFT (0x3fff << 1)
+#define ADDA_AFE_ON_SFT 0
+#define ADDA_AFE_ON_MASK 0x1
+#define ADDA_AFE_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ_MCU_CON */
+#define IRQ7_MCU_MODE_SFT 24
+#define IRQ7_MCU_MODE_MASK 0xf
+#define IRQ7_MCU_MODE_MASK_SFT (0xf << 24)
+#define IRQ4_MCU_MODE_SFT 20
+#define IRQ4_MCU_MODE_MASK 0xf
+#define IRQ4_MCU_MODE_MASK_SFT (0xf << 20)
+#define IRQ3_MCU_MODE_SFT 16
+#define IRQ3_MCU_MODE_MASK 0xf
+#define IRQ3_MCU_MODE_MASK_SFT (0xf << 16)
+#define IRQ7_MCU_ON_SFT 14
+#define IRQ7_MCU_ON_MASK 0x1
+#define IRQ7_MCU_ON_MASK_SFT (0x1 << 14)
+#define IRQ5_MCU_ON_SFT 12
+#define IRQ5_MCU_ON_MASK 0x1
+#define IRQ5_MCU_ON_MASK_SFT (0x1 << 12)
+#define IRQ2_MCU_MODE_SFT 8
+#define IRQ2_MCU_MODE_MASK 0xf
+#define IRQ2_MCU_MODE_MASK_SFT (0xf << 8)
+#define IRQ1_MCU_MODE_SFT 4
+#define IRQ1_MCU_MODE_MASK 0xf
+#define IRQ1_MCU_MODE_MASK_SFT (0xf << 4)
+#define IRQ4_MCU_ON_SFT 3
+#define IRQ4_MCU_ON_MASK 0x1
+#define IRQ4_MCU_ON_MASK_SFT (0x1 << 3)
+#define IRQ3_MCU_ON_SFT 2
+#define IRQ3_MCU_ON_MASK 0x1
+#define IRQ3_MCU_ON_MASK_SFT (0x1 << 2)
+#define IRQ2_MCU_ON_SFT 1
+#define IRQ2_MCU_ON_MASK 0x1
+#define IRQ2_MCU_ON_MASK_SFT (0x1 << 1)
+#define IRQ1_MCU_ON_SFT 0
+#define IRQ1_MCU_ON_MASK 0x1
+#define IRQ1_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ_MCU_EN */
+#define AFE_IRQ_CM4_EN_SFT 16
+#define AFE_IRQ_CM4_EN_MASK 0x7f
+#define AFE_IRQ_CM4_EN_MASK_SFT (0x7f << 16)
+#define AFE_IRQ_MD32_EN_SFT 8
+#define AFE_IRQ_MD32_EN_MASK 0x7f
+#define AFE_IRQ_MD32_EN_MASK_SFT (0x7f << 8)
+#define AFE_IRQ_MCU_EN_SFT 0
+#define AFE_IRQ_MCU_EN_MASK 0x7f
+#define AFE_IRQ_MCU_EN_MASK_SFT (0x7f << 0)
+
+/* AFE_IRQ_MCU_CLR */
+#define IRQ7_MCU_CLR_SFT 6
+#define IRQ7_MCU_CLR_MASK 0x1
+#define IRQ7_MCU_CLR_MASK_SFT (0x1 << 6)
+#define IRQ5_MCU_CLR_SFT 4
+#define IRQ5_MCU_CLR_MASK 0x1
+#define IRQ5_MCU_CLR_MASK_SFT (0x1 << 4)
+#define IRQ4_MCU_CLR_SFT 3
+#define IRQ4_MCU_CLR_MASK 0x1
+#define IRQ4_MCU_CLR_MASK_SFT (0x1 << 3)
+#define IRQ3_MCU_CLR_SFT 2
+#define IRQ3_MCU_CLR_MASK 0x1
+#define IRQ3_MCU_CLR_MASK_SFT (0x1 << 2)
+#define IRQ2_MCU_CLR_SFT 1
+#define IRQ2_MCU_CLR_MASK 0x1
+#define IRQ2_MCU_CLR_MASK_SFT (0x1 << 1)
+#define IRQ1_MCU_CLR_SFT 0
+#define IRQ1_MCU_CLR_MASK 0x1
+#define IRQ1_MCU_CLR_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ_MCU_CNT1 */
+#define AFE_IRQ_MCU_CNT1_SFT 0
+#define AFE_IRQ_MCU_CNT1_MASK 0x3ffff
+#define AFE_IRQ_MCU_CNT1_MASK_SFT (0x3ffff << 0)
+
+/* AFE_IRQ_MCU_CNT2 */
+#define AFE_IRQ_MCU_CNT2_SFT 0
+#define AFE_IRQ_MCU_CNT2_MASK 0x3ffff
+#define AFE_IRQ_MCU_CNT2_MASK_SFT (0x3ffff << 0)
+
+/* AFE_IRQ_MCU_CNT3 */
+#define AFE_IRQ_MCU_CNT3_SFT 0
+#define AFE_IRQ_MCU_CNT3_MASK 0x3ffff
+#define AFE_IRQ_MCU_CNT3_MASK_SFT (0x3ffff << 0)
+
+/* AFE_IRQ_MCU_CNT4 */
+#define AFE_IRQ_MCU_CNT4_SFT 0
+#define AFE_IRQ_MCU_CNT4_MASK 0x3ffff
+#define AFE_IRQ_MCU_CNT4_MASK_SFT (0x3ffff << 0)
+
+/* AFE_IRQ_MCU_CNT5 */
+#define AFE_IRQ_MCU_CNT5_SFT 0
+#define AFE_IRQ_MCU_CNT5_MASK 0x3ffff
+#define AFE_IRQ_MCU_CNT5_MASK_SFT (0x3ffff << 0)
+
+/* AFE_IRQ_MCU_CNT7 */
+#define AFE_IRQ_MCU_CNT7_SFT 0
+#define AFE_IRQ_MCU_CNT7_MASK 0x3ffff
+#define AFE_IRQ_MCU_CNT7_MASK_SFT (0x3ffff << 0)
+
+/* AFE_MEMIF_MSB */
+#define CPU_COMPACT_MODE_SFT 23
+#define CPU_COMPACT_MODE_MASK 0x1
+#define CPU_COMPACT_MODE_MASK_SFT (0x1 << 23)
+#define CPU_HD_ALIGN_SFT 22
+#define CPU_HD_ALIGN_MASK 0x1
+#define CPU_HD_ALIGN_MASK_SFT (0x1 << 22)
+
+/* AFE_MEMIF_HD_MODE */
+#define HDMI_HD_SFT 20
+#define HDMI_HD_MASK 0x3
+#define HDMI_HD_MASK_SFT (0x3 << 20)
+#define MOD_DAI_HD_SFT 18
+#define MOD_DAI_HD_MASK 0x3
+#define MOD_DAI_HD_MASK_SFT (0x3 << 18)
+#define DAI_HD_SFT 16
+#define DAI_HD_MASK 0x3
+#define DAI_HD_MASK_SFT (0x3 << 16)
+#define VUL_DATA2_HD_SFT 12
+#define VUL_DATA2_HD_MASK 0x3
+#define VUL_DATA2_HD_MASK_SFT (0x3 << 12)
+#define VUL_HD_SFT 10
+#define VUL_HD_MASK 0x3
+#define VUL_HD_MASK_SFT (0x3 << 10)
+#define AWB_HD_SFT 8
+#define AWB_HD_MASK 0x3
+#define AWB_HD_MASK_SFT (0x3 << 8)
+#define DL3_HD_SFT 6
+#define DL3_HD_MASK 0x3
+#define DL3_HD_MASK_SFT (0x3 << 6)
+#define DL2_HD_SFT 4
+#define DL2_HD_MASK 0x3
+#define DL2_HD_MASK_SFT (0x3 << 4)
+#define DL1_DATA2_HD_SFT 2
+#define DL1_DATA2_HD_MASK 0x3
+#define DL1_DATA2_HD_MASK_SFT (0x3 << 2)
+#define DL1_HD_SFT 0
+#define DL1_HD_MASK 0x3
+#define DL1_HD_MASK_SFT (0x3 << 0)
+
+/* AFE_MEMIF_HDALIGN */
+#define HDMI_NORMAL_MODE_SFT 26
+#define HDMI_NORMAL_MODE_MASK 0x1
+#define HDMI_NORMAL_MODE_MASK_SFT (0x1 << 26)
+#define MOD_DAI_NORMAL_MODE_SFT 25
+#define MOD_DAI_NORMAL_MODE_MASK 0x1
+#define MOD_DAI_NORMAL_MODE_MASK_SFT (0x1 << 25)
+#define DAI_NORMAL_MODE_SFT 24
+#define DAI_NORMAL_MODE_MASK 0x1
+#define DAI_NORMAL_MODE_MASK_SFT (0x1 << 24)
+#define VUL_DATA2_NORMAL_MODE_SFT 22
+#define VUL_DATA2_NORMAL_MODE_MASK 0x1
+#define VUL_DATA2_NORMAL_MODE_MASK_SFT (0x1 << 22)
+#define VUL_NORMAL_MODE_SFT 21
+#define VUL_NORMAL_MODE_MASK 0x1
+#define VUL_NORMAL_MODE_MASK_SFT (0x1 << 21)
+#define AWB_NORMAL_MODE_SFT 20
+#define AWB_NORMAL_MODE_MASK 0x1
+#define AWB_NORMAL_MODE_MASK_SFT (0x1 << 20)
+#define DL3_NORMAL_MODE_SFT 19
+#define DL3_NORMAL_MODE_MASK 0x1
+#define DL3_NORMAL_MODE_MASK_SFT (0x1 << 19)
+#define DL2_NORMAL_MODE_SFT 18
+#define DL2_NORMAL_MODE_MASK 0x1
+#define DL2_NORMAL_MODE_MASK_SFT (0x1 << 18)
+#define DL1_DATA2_NORMAL_MODE_SFT 17
+#define DL1_DATA2_NORMAL_MODE_MASK 0x1
+#define DL1_DATA2_NORMAL_MODE_MASK_SFT (0x1 << 17)
+#define DL1_NORMAL_MODE_SFT 16
+#define DL1_NORMAL_MODE_MASK 0x1
+#define DL1_NORMAL_MODE_MASK_SFT (0x1 << 16)
+#define HDMI_HD_ALIGN_SFT 10
+#define HDMI_HD_ALIGN_MASK 0x1
+#define HDMI_HD_ALIGN_MASK_SFT (0x1 << 10)
+#define MOD_DAI_HD_ALIGN_SFT 9
+#define MOD_DAI_HD_ALIGN_MASK 0x1
+#define MOD_DAI_HD_ALIGN_MASK_SFT (0x1 << 9)
+#define DAI_ALIGN_SFT 8
+#define DAI_ALIGN_MASK 0x1
+#define DAI_ALIGN_MASK_SFT (0x1 << 8)
+#define VUL2_HD_ALIGN_SFT 7
+#define VUL2_HD_ALIGN_MASK 0x1
+#define VUL2_HD_ALIGN_MASK_SFT (0x1 << 7)
+#define VUL_DATA2_HD_ALIGN_SFT 6
+#define VUL_DATA2_HD_ALIGN_MASK 0x1
+#define VUL_DATA2_HD_ALIGN_MASK_SFT (0x1 << 6)
+#define VUL_HD_ALIGN_SFT 5
+#define VUL_HD_ALIGN_MASK 0x1
+#define VUL_HD_ALIGN_MASK_SFT (0x1 << 5)
+#define AWB_HD_ALIGN_SFT 4
+#define AWB_HD_ALIGN_MASK 0x1
+#define AWB_HD_ALIGN_MASK_SFT (0x1 << 4)
+#define DL3_HD_ALIGN_SFT 3
+#define DL3_HD_ALIGN_MASK 0x1
+#define DL3_HD_ALIGN_MASK_SFT (0x1 << 3)
+#define DL2_HD_ALIGN_SFT 2
+#define DL2_HD_ALIGN_MASK 0x1
+#define DL2_HD_ALIGN_MASK_SFT (0x1 << 2)
+#define DL1_DATA2_HD_ALIGN_SFT 1
+#define DL1_DATA2_HD_ALIGN_MASK 0x1
+#define DL1_DATA2_HD_ALIGN_MASK_SFT (0x1 << 1)
+#define DL1_HD_ALIGN_SFT 0
+#define DL1_HD_ALIGN_MASK 0x1
+#define DL1_HD_ALIGN_MASK_SFT (0x1 << 0)
+
+/* PCM_INTF_CON1 */
+#define PCM_FIX_VALUE_SEL_SFT 31
+#define PCM_FIX_VALUE_SEL_MASK 0x1
+#define PCM_FIX_VALUE_SEL_MASK_SFT (0x1 << 31)
+#define PCM_BUFFER_LOOPBACK_SFT 30
+#define PCM_BUFFER_LOOPBACK_MASK 0x1
+#define PCM_BUFFER_LOOPBACK_MASK_SFT (0x1 << 30)
+#define PCM_PARALLEL_LOOPBACK_SFT 29
+#define PCM_PARALLEL_LOOPBACK_MASK 0x1
+#define PCM_PARALLEL_LOOPBACK_MASK_SFT (0x1 << 29)
+#define PCM_SERIAL_LOOPBACK_SFT 28
+#define PCM_SERIAL_LOOPBACK_MASK 0x1
+#define PCM_SERIAL_LOOPBACK_MASK_SFT (0x1 << 28)
+#define PCM_DAI_PCM_LOOPBACK_SFT 27
+#define PCM_DAI_PCM_LOOPBACK_MASK 0x1
+#define PCM_DAI_PCM_LOOPBACK_MASK_SFT (0x1 << 27)
+#define PCM_I2S_PCM_LOOPBACK_SFT 26
+#define PCM_I2S_PCM_LOOPBACK_MASK 0x1
+#define PCM_I2S_PCM_LOOPBACK_MASK_SFT (0x1 << 26)
+#define PCM_SYNC_DELSEL_SFT 25
+#define PCM_SYNC_DELSEL_MASK 0x1
+#define PCM_SYNC_DELSEL_MASK_SFT (0x1 << 25)
+#define PCM_TX_LR_SWAP_SFT 24
+#define PCM_TX_LR_SWAP_MASK 0x1
+#define PCM_TX_LR_SWAP_MASK_SFT (0x1 << 24)
+#define PCM_SYNC_OUT_INV_SFT 23
+#define PCM_SYNC_OUT_INV_MASK 0x1
+#define PCM_SYNC_OUT_INV_MASK_SFT (0x1 << 23)
+#define PCM_BCLK_OUT_INV_SFT 22
+#define PCM_BCLK_OUT_INV_MASK 0x1
+#define PCM_BCLK_OUT_INV_MASK_SFT (0x1 << 22)
+#define PCM_SYNC_IN_INV_SFT 21
+#define PCM_SYNC_IN_INV_MASK 0x1
+#define PCM_SYNC_IN_INV_MASK_SFT (0x1 << 21)
+#define PCM_BCLK_IN_INV_SFT 20
+#define PCM_BCLK_IN_INV_MASK 0x1
+#define PCM_BCLK_IN_INV_MASK_SFT (0x1 << 20)
+#define PCM_TX_LCH_RPT_SFT 19
+#define PCM_TX_LCH_RPT_MASK 0x1
+#define PCM_TX_LCH_RPT_MASK_SFT (0x1 << 19)
+#define PCM_VBT_16K_MODE_SFT 18
+#define PCM_VBT_16K_MODE_MASK 0x1
+#define PCM_VBT_16K_MODE_MASK_SFT (0x1 << 18)
+#define PCM_EXT_MODEM_SFT 17
+#define PCM_EXT_MODEM_MASK 0x1
+#define PCM_EXT_MODEM_MASK_SFT (0x1 << 17)
+#define PCM_24BIT_SFT 16
+#define PCM_24BIT_MASK 0x1
+#define PCM_24BIT_MASK_SFT (0x1 << 16)
+#define PCM_WLEN_SFT 14
+#define PCM_WLEN_MASK 0x3
+#define PCM_WLEN_MASK_SFT (0x3 << 14)
+#define PCM_SYNC_LENGTH_SFT 9
+#define PCM_SYNC_LENGTH_MASK 0x1f
+#define PCM_SYNC_LENGTH_MASK_SFT (0x1f << 9)
+#define PCM_SYNC_TYPE_SFT 8
+#define PCM_SYNC_TYPE_MASK 0x1
+#define PCM_SYNC_TYPE_MASK_SFT (0x1 << 8)
+#define PCM_BT_MODE_SFT 7
+#define PCM_BT_MODE_MASK 0x1
+#define PCM_BT_MODE_MASK_SFT (0x1 << 7)
+#define PCM_BYP_ASRC_SFT 6
+#define PCM_BYP_ASRC_MASK 0x1
+#define PCM_BYP_ASRC_MASK_SFT (0x1 << 6)
+#define PCM_SLAVE_SFT 5
+#define PCM_SLAVE_MASK 0x1
+#define PCM_SLAVE_MASK_SFT (0x1 << 5)
+#define PCM_MODE_SFT 3
+#define PCM_MODE_MASK 0x3
+#define PCM_MODE_MASK_SFT (0x3 << 3)
+#define PCM_FMT_SFT 1
+#define PCM_FMT_MASK 0x3
+#define PCM_FMT_MASK_SFT (0x3 << 1)
+#define PCM_EN_SFT 0
+#define PCM_EN_MASK 0x1
+#define PCM_EN_MASK_SFT (0x1 << 0)
+
+/* PCM_INTF_CON2 */
+#define PCM1_TX_FIFO_OV_SFT 31
+#define PCM1_TX_FIFO_OV_MASK 0x1
+#define PCM1_TX_FIFO_OV_MASK_SFT (0x1 << 31)
+#define PCM1_RX_FIFO_OV_SFT 30
+#define PCM1_RX_FIFO_OV_MASK 0x1
+#define PCM1_RX_FIFO_OV_MASK_SFT (0x1 << 30)
+#define PCM2_TX_FIFO_OV_SFT 29
+#define PCM2_TX_FIFO_OV_MASK 0x1
+#define PCM2_TX_FIFO_OV_MASK_SFT (0x1 << 29)
+#define PCM2_RX_FIFO_OV_SFT 28
+#define PCM2_RX_FIFO_OV_MASK 0x1
+#define PCM2_RX_FIFO_OV_MASK_SFT (0x1 << 28)
+#define PCM1_SYNC_GLITCH_SFT 27
+#define PCM1_SYNC_GLITCH_MASK 0x1
+#define PCM1_SYNC_GLITCH_MASK_SFT (0x1 << 27)
+#define PCM2_SYNC_GLITCH_SFT 26
+#define PCM2_SYNC_GLITCH_MASK 0x1
+#define PCM2_SYNC_GLITCH_MASK_SFT (0x1 << 26)
+#define PCM1_PCM2_LOOPBACK_SFT 15
+#define PCM1_PCM2_LOOPBACK_MASK 0x1
+#define PCM1_PCM2_LOOPBACK_MASK_SFT (0x1 << 15)
+#define DAI_PCM_LOOPBACK_CH_SFT 13
+#define DAI_PCM_LOOPBACK_CH_MASK 0x1
+#define DAI_PCM_LOOPBACK_CH_MASK_SFT (0x1 << 13)
+#define I2S_PCM_LOOPBACK_CH_SFT 12
+#define I2S_PCM_LOOPBACK_CH_MASK 0x1
+#define I2S_PCM_LOOPBACK_CH_MASK_SFT (0x1 << 12)
+#define PCM_USE_MD3_SFT 8
+#define PCM_USE_MD3_MASK 0x1
+#define PCM_USE_MD3_MASK_SFT (0x1 << 8)
+#define TX_FIX_VALUE_SFT 0
+#define TX_FIX_VALUE_MASK 0xff
+#define TX_FIX_VALUE_MASK_SFT (0xff << 0)
+
+/* PCM2_INTF_CON */
+#define PCM2_TX_FIX_VALUE_SFT 24
+#define PCM2_TX_FIX_VALUE_MASK 0xff
+#define PCM2_TX_FIX_VALUE_MASK_SFT (0xff << 24)
+#define PCM2_FIX_VALUE_SEL_SFT 23
+#define PCM2_FIX_VALUE_SEL_MASK 0x1
+#define PCM2_FIX_VALUE_SEL_MASK_SFT (0x1 << 23)
+#define PCM2_BUFFER_LOOPBACK_SFT 22
+#define PCM2_BUFFER_LOOPBACK_MASK 0x1
+#define PCM2_BUFFER_LOOPBACK_MASK_SFT (0x1 << 22)
+#define PCM2_PARALLEL_LOOPBACK_SFT 21
+#define PCM2_PARALLEL_LOOPBACK_MASK 0x1
+#define PCM2_PARALLEL_LOOPBACK_MASK_SFT (0x1 << 21)
+#define PCM2_SERIAL_LOOPBACK_SFT 20
+#define PCM2_SERIAL_LOOPBACK_MASK 0x1
+#define PCM2_SERIAL_LOOPBACK_MASK_SFT (0x1 << 20)
+#define PCM2_DAI_PCM_LOOPBACK_SFT 19
+#define PCM2_DAI_PCM_LOOPBACK_MASK 0x1
+#define PCM2_DAI_PCM_LOOPBACK_MASK_SFT (0x1 << 19)
+#define PCM2_I2S_PCM_LOOPBACK_SFT 18
+#define PCM2_I2S_PCM_LOOPBACK_MASK 0x1
+#define PCM2_I2S_PCM_LOOPBACK_MASK_SFT (0x1 << 18)
+#define PCM2_SYNC_DELSEL_SFT 17
+#define PCM2_SYNC_DELSEL_MASK 0x1
+#define PCM2_SYNC_DELSEL_MASK_SFT (0x1 << 17)
+#define PCM2_TX_LR_SWAP_SFT 16
+#define PCM2_TX_LR_SWAP_MASK 0x1
+#define PCM2_TX_LR_SWAP_MASK_SFT (0x1 << 16)
+#define PCM2_SYNC_IN_INV_SFT 15
+#define PCM2_SYNC_IN_INV_MASK 0x1
+#define PCM2_SYNC_IN_INV_MASK_SFT (0x1 << 15)
+#define PCM2_BCLK_IN_INV_SFT 14
+#define PCM2_BCLK_IN_INV_MASK 0x1
+#define PCM2_BCLK_IN_INV_MASK_SFT (0x1 << 14)
+#define PCM2_TX_LCH_RPT_SFT 13
+#define PCM2_TX_LCH_RPT_MASK 0x1
+#define PCM2_TX_LCH_RPT_MASK_SFT (0x1 << 13)
+#define PCM2_VBT_16K_MODE_SFT 12
+#define PCM2_VBT_16K_MODE_MASK 0x1
+#define PCM2_VBT_16K_MODE_MASK_SFT (0x1 << 12)
+#define PCM2_LOOPBACK_CH_SEL_SFT 10
+#define PCM2_LOOPBACK_CH_SEL_MASK 0x3
+#define PCM2_LOOPBACK_CH_SEL_MASK_SFT (0x3 << 10)
+#define PCM2_TX2_BT_MODE_SFT 8
+#define PCM2_TX2_BT_MODE_MASK 0x1
+#define PCM2_TX2_BT_MODE_MASK_SFT (0x1 << 8)
+#define PCM2_BT_MODE_SFT 7
+#define PCM2_BT_MODE_MASK 0x1
+#define PCM2_BT_MODE_MASK_SFT (0x1 << 7)
+#define PCM2_AFIFO_SFT 6
+#define PCM2_AFIFO_MASK 0x1
+#define PCM2_AFIFO_MASK_SFT (0x1 << 6)
+#define PCM2_WLEN_SFT 5
+#define PCM2_WLEN_MASK 0x1
+#define PCM2_WLEN_MASK_SFT (0x1 << 5)
+#define PCM2_MODE_SFT 3
+#define PCM2_MODE_MASK 0x3
+#define PCM2_MODE_MASK_SFT (0x3 << 3)
+#define PCM2_FMT_SFT 1
+#define PCM2_FMT_MASK 0x3
+#define PCM2_FMT_MASK_SFT (0x3 << 1)
+#define PCM2_EN_SFT 0
+#define PCM2_EN_MASK 0x1
+#define PCM2_EN_MASK_SFT (0x1 << 0)
+#endif
diff --git a/sound/soc/mediatek/mt8173/Makefile b/sound/soc/mediatek/mt8173/Makefile
new file mode 100644
index 000000000..c1eed0d26
--- /dev/null
+++ b/sound/soc/mediatek/mt8173/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+# MTK Platform Support
+obj-$(CONFIG_SND_SOC_MT8173) += mt8173-afe-pcm.o
+# Machine support
+obj-$(CONFIG_SND_SOC_MT8173_MAX98090) += mt8173-max98090.o
+obj-$(CONFIG_SND_SOC_MT8173_RT5650) += mt8173-rt5650.o
+obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5514) += mt8173-rt5650-rt5514.o
+obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5676) += mt8173-rt5650-rt5676.o
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-common.h b/sound/soc/mediatek/mt8173/mt8173-afe-common.h
new file mode 100644
index 000000000..396fe2355
--- /dev/null
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-common.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8173_afe_common.h -- Mediatek 8173 audio driver common definitions
+ *
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Koro Chen <koro.chen@mediatek.com>
+ * Sascha Hauer <s.hauer@pengutronix.de>
+ * Hidalgo Huang <hidalgo.huang@mediatek.com>
+ * Ir Lian <ir.lian@mediatek.com>
+ */
+
+#ifndef _MT8173_AFE_COMMON_H_
+#define _MT8173_AFE_COMMON_H_
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+enum {
+ MT8173_AFE_MEMIF_DL1,
+ MT8173_AFE_MEMIF_DL2,
+ MT8173_AFE_MEMIF_VUL,
+ MT8173_AFE_MEMIF_DAI,
+ MT8173_AFE_MEMIF_AWB,
+ MT8173_AFE_MEMIF_MOD_DAI,
+ MT8173_AFE_MEMIF_HDMI,
+ MT8173_AFE_MEMIF_NUM,
+ MT8173_AFE_IO_MOD_PCM1 = MT8173_AFE_MEMIF_NUM,
+ MT8173_AFE_IO_MOD_PCM2,
+ MT8173_AFE_IO_PMIC,
+ MT8173_AFE_IO_I2S,
+ MT8173_AFE_IO_2ND_I2S,
+ MT8173_AFE_IO_HW_GAIN1,
+ MT8173_AFE_IO_HW_GAIN2,
+ MT8173_AFE_IO_MRG_O,
+ MT8173_AFE_IO_MRG_I,
+ MT8173_AFE_IO_DAIBT,
+ MT8173_AFE_IO_HDMI,
+};
+
+enum {
+ MT8173_AFE_IRQ_DL1,
+ MT8173_AFE_IRQ_DL2,
+ MT8173_AFE_IRQ_VUL,
+ MT8173_AFE_IRQ_DAI,
+ MT8173_AFE_IRQ_AWB,
+ MT8173_AFE_IRQ_MOD_DAI,
+ MT8173_AFE_IRQ_HDMI,
+ MT8173_AFE_IRQ_NUM,
+};
+
+enum {
+ MT8173_CLK_INFRASYS_AUD,
+ MT8173_CLK_TOP_PDN_AUD,
+ MT8173_CLK_TOP_PDN_AUD_BUS,
+ MT8173_CLK_I2S0_M,
+ MT8173_CLK_I2S1_M,
+ MT8173_CLK_I2S2_M,
+ MT8173_CLK_I2S3_M,
+ MT8173_CLK_I2S3_B,
+ MT8173_CLK_BCK0,
+ MT8173_CLK_BCK1,
+ MT8173_CLK_NUM
+};
+
+#endif
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
new file mode 100644
index 000000000..3f6d9659e
--- /dev/null
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -0,0 +1,1236 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek 8173 ALSA SoC AFE platform driver
+ *
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Koro Chen <koro.chen@mediatek.com>
+ * Sascha Hauer <s.hauer@pengutronix.de>
+ * Hidalgo Huang <hidalgo.huang@mediatek.com>
+ * Ir Lian <ir.lian@mediatek.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include "mt8173-afe-common.h"
+#include "../common/mtk-base-afe.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+/*****************************************************************************
+ * R E G I S T E R D E F I N I T I O N
+ *****************************************************************************/
+#define AUDIO_TOP_CON0 0x0000
+#define AUDIO_TOP_CON1 0x0004
+#define AFE_DAC_CON0 0x0010
+#define AFE_DAC_CON1 0x0014
+#define AFE_I2S_CON1 0x0034
+#define AFE_I2S_CON2 0x0038
+#define AFE_CONN_24BIT 0x006c
+#define AFE_MEMIF_MSB 0x00cc
+
+#define AFE_CONN1 0x0024
+#define AFE_CONN2 0x0028
+#define AFE_CONN3 0x002c
+#define AFE_CONN7 0x0460
+#define AFE_CONN8 0x0464
+#define AFE_HDMI_CONN0 0x0390
+
+/* Memory interface */
+#define AFE_DL1_BASE 0x0040
+#define AFE_DL1_CUR 0x0044
+#define AFE_DL1_END 0x0048
+#define AFE_DL2_BASE 0x0050
+#define AFE_DL2_CUR 0x0054
+#define AFE_AWB_BASE 0x0070
+#define AFE_AWB_CUR 0x007c
+#define AFE_VUL_BASE 0x0080
+#define AFE_VUL_CUR 0x008c
+#define AFE_VUL_END 0x0088
+#define AFE_DAI_BASE 0x0090
+#define AFE_DAI_CUR 0x009c
+#define AFE_MOD_PCM_BASE 0x0330
+#define AFE_MOD_PCM_CUR 0x033c
+#define AFE_HDMI_OUT_BASE 0x0374
+#define AFE_HDMI_OUT_CUR 0x0378
+#define AFE_HDMI_OUT_END 0x037c
+
+#define AFE_ADDA_TOP_CON0 0x0120
+#define AFE_ADDA2_TOP_CON0 0x0600
+
+#define AFE_HDMI_OUT_CON0 0x0370
+
+#define AFE_IRQ_MCU_CON 0x03a0
+#define AFE_IRQ_STATUS 0x03a4
+#define AFE_IRQ_CLR 0x03a8
+#define AFE_IRQ_CNT1 0x03ac
+#define AFE_IRQ_CNT2 0x03b0
+#define AFE_IRQ_MCU_EN 0x03b4
+#define AFE_IRQ_CNT5 0x03bc
+#define AFE_IRQ_CNT7 0x03dc
+
+#define AFE_TDM_CON1 0x0548
+#define AFE_TDM_CON2 0x054c
+
+#define AFE_IRQ_STATUS_BITS 0xff
+
+/* AUDIO_TOP_CON0 (0x0000) */
+#define AUD_TCON0_PDN_SPDF (0x1 << 21)
+#define AUD_TCON0_PDN_HDMI (0x1 << 20)
+#define AUD_TCON0_PDN_24M (0x1 << 9)
+#define AUD_TCON0_PDN_22M (0x1 << 8)
+#define AUD_TCON0_PDN_AFE (0x1 << 2)
+
+/* AFE_I2S_CON1 (0x0034) */
+#define AFE_I2S_CON1_LOW_JITTER_CLK (0x1 << 12)
+#define AFE_I2S_CON1_RATE(x) (((x) & 0xf) << 8)
+#define AFE_I2S_CON1_FORMAT_I2S (0x1 << 3)
+#define AFE_I2S_CON1_EN (0x1 << 0)
+
+/* AFE_I2S_CON2 (0x0038) */
+#define AFE_I2S_CON2_LOW_JITTER_CLK (0x1 << 12)
+#define AFE_I2S_CON2_RATE(x) (((x) & 0xf) << 8)
+#define AFE_I2S_CON2_FORMAT_I2S (0x1 << 3)
+#define AFE_I2S_CON2_EN (0x1 << 0)
+
+/* AFE_CONN_24BIT (0x006c) */
+#define AFE_CONN_24BIT_O04 (0x1 << 4)
+#define AFE_CONN_24BIT_O03 (0x1 << 3)
+
+/* AFE_HDMI_CONN0 (0x0390) */
+#define AFE_HDMI_CONN0_O37_I37 (0x7 << 21)
+#define AFE_HDMI_CONN0_O36_I36 (0x6 << 18)
+#define AFE_HDMI_CONN0_O35_I33 (0x3 << 15)
+#define AFE_HDMI_CONN0_O34_I32 (0x2 << 12)
+#define AFE_HDMI_CONN0_O33_I35 (0x5 << 9)
+#define AFE_HDMI_CONN0_O32_I34 (0x4 << 6)
+#define AFE_HDMI_CONN0_O31_I31 (0x1 << 3)
+#define AFE_HDMI_CONN0_O30_I30 (0x0 << 0)
+
+/* AFE_TDM_CON1 (0x0548) */
+#define AFE_TDM_CON1_LRCK_WIDTH(x) (((x) - 1) << 24)
+#define AFE_TDM_CON1_32_BCK_CYCLES (0x2 << 12)
+#define AFE_TDM_CON1_WLEN_32BIT (0x2 << 8)
+#define AFE_TDM_CON1_MSB_ALIGNED (0x1 << 4)
+#define AFE_TDM_CON1_1_BCK_DELAY (0x1 << 3)
+#define AFE_TDM_CON1_LRCK_INV (0x1 << 2)
+#define AFE_TDM_CON1_BCK_INV (0x1 << 1)
+#define AFE_TDM_CON1_EN (0x1 << 0)
+
+enum afe_tdm_ch_start {
+ AFE_TDM_CH_START_O30_O31 = 0,
+ AFE_TDM_CH_START_O32_O33,
+ AFE_TDM_CH_START_O34_O35,
+ AFE_TDM_CH_START_O36_O37,
+ AFE_TDM_CH_ZERO,
+};
+
+static const unsigned int mt8173_afe_backup_list[] = {
+ AUDIO_TOP_CON0,
+ AFE_CONN1,
+ AFE_CONN2,
+ AFE_CONN7,
+ AFE_CONN8,
+ AFE_DAC_CON1,
+ AFE_DL1_BASE,
+ AFE_DL1_END,
+ AFE_VUL_BASE,
+ AFE_VUL_END,
+ AFE_HDMI_OUT_BASE,
+ AFE_HDMI_OUT_END,
+ AFE_HDMI_CONN0,
+ AFE_DAC_CON0,
+};
+
+struct mt8173_afe_private {
+ struct clk *clocks[MT8173_CLK_NUM];
+};
+
+static const struct snd_pcm_hardware mt8173_afe_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .buffer_bytes_max = 256 * 1024,
+ .period_bytes_min = 512,
+ .period_bytes_max = 128 * 1024,
+ .periods_min = 2,
+ .periods_max = 256,
+ .fifo_size = 0,
+};
+
+struct mt8173_afe_rate {
+ unsigned int rate;
+ unsigned int regvalue;
+};
+
+static const struct mt8173_afe_rate mt8173_afe_i2s_rates[] = {
+ { .rate = 8000, .regvalue = 0 },
+ { .rate = 11025, .regvalue = 1 },
+ { .rate = 12000, .regvalue = 2 },
+ { .rate = 16000, .regvalue = 4 },
+ { .rate = 22050, .regvalue = 5 },
+ { .rate = 24000, .regvalue = 6 },
+ { .rate = 32000, .regvalue = 8 },
+ { .rate = 44100, .regvalue = 9 },
+ { .rate = 48000, .regvalue = 10 },
+ { .rate = 88000, .regvalue = 11 },
+ { .rate = 96000, .regvalue = 12 },
+ { .rate = 174000, .regvalue = 13 },
+ { .rate = 192000, .regvalue = 14 },
+};
+
+static int mt8173_afe_i2s_fs(unsigned int sample_rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mt8173_afe_i2s_rates); i++)
+ if (mt8173_afe_i2s_rates[i].rate == sample_rate)
+ return mt8173_afe_i2s_rates[i].regvalue;
+
+ return -EINVAL;
+}
+
+static int mt8173_afe_set_i2s(struct mtk_base_afe *afe, unsigned int rate)
+{
+ unsigned int val;
+ int fs = mt8173_afe_i2s_fs(rate);
+
+ if (fs < 0)
+ return -EINVAL;
+
+ /* from external ADC */
+ regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x1);
+ regmap_update_bits(afe->regmap, AFE_ADDA2_TOP_CON0, 0x1, 0x1);
+
+ /* set input */
+ val = AFE_I2S_CON2_LOW_JITTER_CLK |
+ AFE_I2S_CON2_RATE(fs) |
+ AFE_I2S_CON2_FORMAT_I2S;
+
+ regmap_update_bits(afe->regmap, AFE_I2S_CON2, ~AFE_I2S_CON2_EN, val);
+
+ /* set output */
+ val = AFE_I2S_CON1_LOW_JITTER_CLK |
+ AFE_I2S_CON1_RATE(fs) |
+ AFE_I2S_CON1_FORMAT_I2S;
+
+ regmap_update_bits(afe->regmap, AFE_I2S_CON1, ~AFE_I2S_CON1_EN, val);
+ return 0;
+}
+
+static void mt8173_afe_set_i2s_enable(struct mtk_base_afe *afe, bool enable)
+{
+ unsigned int val;
+
+ regmap_read(afe->regmap, AFE_I2S_CON2, &val);
+ if (!!(val & AFE_I2S_CON2_EN) == enable)
+ return;
+
+ /* input */
+ regmap_update_bits(afe->regmap, AFE_I2S_CON2, 0x1, enable);
+
+ /* output */
+ regmap_update_bits(afe->regmap, AFE_I2S_CON1, 0x1, enable);
+}
+
+static int mt8173_afe_dais_enable_clks(struct mtk_base_afe *afe,
+ struct clk *m_ck, struct clk *b_ck)
+{
+ int ret;
+
+ if (m_ck) {
+ ret = clk_prepare_enable(m_ck);
+ if (ret) {
+ dev_err(afe->dev, "Failed to enable m_ck\n");
+ return ret;
+ }
+ }
+
+ if (b_ck) {
+ ret = clk_prepare_enable(b_ck);
+ if (ret) {
+ dev_err(afe->dev, "Failed to enable b_ck\n");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int mt8173_afe_dais_set_clks(struct mtk_base_afe *afe,
+ struct clk *m_ck, unsigned int mck_rate,
+ struct clk *b_ck, unsigned int bck_rate)
+{
+ int ret;
+
+ if (m_ck) {
+ ret = clk_set_rate(m_ck, mck_rate);
+ if (ret) {
+ dev_err(afe->dev, "Failed to set m_ck rate\n");
+ return ret;
+ }
+ }
+
+ if (b_ck) {
+ ret = clk_set_rate(b_ck, bck_rate);
+ if (ret) {
+ dev_err(afe->dev, "Failed to set b_ck rate\n");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static void mt8173_afe_dais_disable_clks(struct mtk_base_afe *afe,
+ struct clk *m_ck, struct clk *b_ck)
+{
+ if (m_ck)
+ clk_disable_unprepare(m_ck);
+ if (b_ck)
+ clk_disable_unprepare(b_ck);
+}
+
+static int mt8173_afe_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ if (snd_soc_dai_active(dai))
+ return 0;
+
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0);
+ return 0;
+}
+
+static void mt8173_afe_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ if (snd_soc_dai_active(dai))
+ return;
+
+ mt8173_afe_set_i2s_enable(afe, false);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M,
+ AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M);
+}
+
+static int mt8173_afe_i2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime * const runtime = substream->runtime;
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8173_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ mt8173_afe_dais_set_clks(afe, afe_priv->clocks[MT8173_CLK_I2S1_M],
+ runtime->rate * 256, NULL, 0);
+ mt8173_afe_dais_set_clks(afe, afe_priv->clocks[MT8173_CLK_I2S2_M],
+ runtime->rate * 256, NULL, 0);
+ /* config I2S */
+ ret = mt8173_afe_set_i2s(afe, substream->runtime->rate);
+ if (ret)
+ return ret;
+
+ mt8173_afe_set_i2s_enable(afe, true);
+
+ return 0;
+}
+
+static int mt8173_afe_hdmi_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8173_afe_private *afe_priv = afe->platform_priv;
+
+ if (snd_soc_dai_active(dai))
+ return 0;
+
+ mt8173_afe_dais_enable_clks(afe, afe_priv->clocks[MT8173_CLK_I2S3_M],
+ afe_priv->clocks[MT8173_CLK_I2S3_B]);
+ return 0;
+}
+
+static void mt8173_afe_hdmi_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8173_afe_private *afe_priv = afe->platform_priv;
+
+ if (snd_soc_dai_active(dai))
+ return;
+
+ mt8173_afe_dais_disable_clks(afe, afe_priv->clocks[MT8173_CLK_I2S3_M],
+ afe_priv->clocks[MT8173_CLK_I2S3_B]);
+}
+
+static int mt8173_afe_hdmi_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime * const runtime = substream->runtime;
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8173_afe_private *afe_priv = afe->platform_priv;
+
+ unsigned int val;
+
+ mt8173_afe_dais_set_clks(afe, afe_priv->clocks[MT8173_CLK_I2S3_M],
+ runtime->rate * 128,
+ afe_priv->clocks[MT8173_CLK_I2S3_B],
+ runtime->rate * runtime->channels * 32);
+
+ val = AFE_TDM_CON1_BCK_INV |
+ AFE_TDM_CON1_LRCK_INV |
+ AFE_TDM_CON1_1_BCK_DELAY |
+ AFE_TDM_CON1_MSB_ALIGNED | /* I2S mode */
+ AFE_TDM_CON1_WLEN_32BIT |
+ AFE_TDM_CON1_32_BCK_CYCLES |
+ AFE_TDM_CON1_LRCK_WIDTH(32);
+ regmap_update_bits(afe->regmap, AFE_TDM_CON1, ~AFE_TDM_CON1_EN, val);
+
+ /* set tdm2 config */
+ switch (runtime->channels) {
+ case 1:
+ case 2:
+ val = AFE_TDM_CH_START_O30_O31;
+ val |= (AFE_TDM_CH_ZERO << 4);
+ val |= (AFE_TDM_CH_ZERO << 8);
+ val |= (AFE_TDM_CH_ZERO << 12);
+ break;
+ case 3:
+ case 4:
+ val = AFE_TDM_CH_START_O30_O31;
+ val |= (AFE_TDM_CH_START_O32_O33 << 4);
+ val |= (AFE_TDM_CH_ZERO << 8);
+ val |= (AFE_TDM_CH_ZERO << 12);
+ break;
+ case 5:
+ case 6:
+ val = AFE_TDM_CH_START_O30_O31;
+ val |= (AFE_TDM_CH_START_O32_O33 << 4);
+ val |= (AFE_TDM_CH_START_O34_O35 << 8);
+ val |= (AFE_TDM_CH_ZERO << 12);
+ break;
+ case 7:
+ case 8:
+ val = AFE_TDM_CH_START_O30_O31;
+ val |= (AFE_TDM_CH_START_O32_O33 << 4);
+ val |= (AFE_TDM_CH_START_O34_O35 << 8);
+ val |= (AFE_TDM_CH_START_O36_O37 << 12);
+ break;
+ default:
+ val = 0;
+ }
+ regmap_update_bits(afe->regmap, AFE_TDM_CON2, 0x0000ffff, val);
+
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ 0x000000f0, runtime->channels << 4);
+ return 0;
+}
+
+static int mt8173_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ dev_info(afe->dev, "%s cmd=%d %s\n", __func__, cmd, dai->name);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF, 0);
+
+ /* set connections: O30~O37: L/R/LS/RS/C/LFE/CH7/CH8 */
+ regmap_write(afe->regmap, AFE_HDMI_CONN0,
+ AFE_HDMI_CONN0_O30_I30 |
+ AFE_HDMI_CONN0_O31_I31 |
+ AFE_HDMI_CONN0_O32_I34 |
+ AFE_HDMI_CONN0_O33_I35 |
+ AFE_HDMI_CONN0_O34_I32 |
+ AFE_HDMI_CONN0_O35_I33 |
+ AFE_HDMI_CONN0_O36_I36 |
+ AFE_HDMI_CONN0_O37_I37);
+
+ /* enable Out control */
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0x1);
+
+ /* enable tdm */
+ regmap_update_bits(afe->regmap, AFE_TDM_CON1, 0x1, 0x1);
+
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ /* disable tdm */
+ regmap_update_bits(afe->regmap, AFE_TDM_CON1, 0x1, 0);
+
+ /* disable Out control */
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0);
+
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF,
+ AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mt8173_memif_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id];
+ int fs;
+
+ if (memif->data->id == MT8173_AFE_MEMIF_DAI ||
+ memif->data->id == MT8173_AFE_MEMIF_MOD_DAI) {
+ switch (rate) {
+ case 8000:
+ fs = 0;
+ break;
+ case 16000:
+ fs = 1;
+ break;
+ case 32000:
+ fs = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ fs = mt8173_afe_i2s_fs(rate);
+ }
+ return fs;
+}
+
+static int mt8173_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
+{
+ return mt8173_afe_i2s_fs(rate);
+}
+
+/* BE DAIs */
+static const struct snd_soc_dai_ops mt8173_afe_i2s_ops = {
+ .startup = mt8173_afe_i2s_startup,
+ .shutdown = mt8173_afe_i2s_shutdown,
+ .prepare = mt8173_afe_i2s_prepare,
+};
+
+static const struct snd_soc_dai_ops mt8173_afe_hdmi_ops = {
+ .startup = mt8173_afe_hdmi_startup,
+ .shutdown = mt8173_afe_hdmi_shutdown,
+ .prepare = mt8173_afe_hdmi_prepare,
+ .trigger = mt8173_afe_hdmi_trigger,
+};
+
+static struct snd_soc_dai_driver mt8173_afe_pcm_dais[] = {
+ /* FE DAIs: memory intefaces to CPU */
+ {
+ .name = "DL1", /* downlink 1 */
+ .id = MT8173_AFE_MEMIF_DL1,
+ .playback = {
+ .stream_name = "DL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &mtk_afe_fe_ops,
+ }, {
+ .name = "VUL", /* voice uplink */
+ .id = MT8173_AFE_MEMIF_VUL,
+ .capture = {
+ .stream_name = "VUL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &mtk_afe_fe_ops,
+ }, {
+ /* BE DAIs */
+ .name = "I2S",
+ .id = MT8173_AFE_IO_I2S,
+ .playback = {
+ .stream_name = "I2S Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "I2S Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &mt8173_afe_i2s_ops,
+ .symmetric_rates = 1,
+ },
+};
+
+static struct snd_soc_dai_driver mt8173_afe_hdmi_dais[] = {
+ /* FE DAIs */
+ {
+ .name = "HDMI",
+ .id = MT8173_AFE_MEMIF_HDMI,
+ .playback = {
+ .stream_name = "HDMI",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &mtk_afe_fe_ops,
+ }, {
+ /* BE DAIs */
+ .name = "HDMIO",
+ .id = MT8173_AFE_IO_HDMI,
+ .playback = {
+ .stream_name = "HDMIO Playback",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &mt8173_afe_hdmi_ops,
+ },
+};
+
+static const struct snd_kcontrol_new mt8173_afe_o03_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN1, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8173_afe_o04_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8173_afe_o09_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN7, 30, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8173_afe_o10_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN3, 3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN8, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mt8173_afe_pcm_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I04", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0,
+ mt8173_afe_o03_mix, ARRAY_SIZE(mt8173_afe_o03_mix)),
+ SND_SOC_DAPM_MIXER("O04", SND_SOC_NOPM, 0, 0,
+ mt8173_afe_o04_mix, ARRAY_SIZE(mt8173_afe_o04_mix)),
+ SND_SOC_DAPM_MIXER("O09", SND_SOC_NOPM, 0, 0,
+ mt8173_afe_o09_mix, ARRAY_SIZE(mt8173_afe_o09_mix)),
+ SND_SOC_DAPM_MIXER("O10", SND_SOC_NOPM, 0, 0,
+ mt8173_afe_o10_mix, ARRAY_SIZE(mt8173_afe_o10_mix)),
+};
+
+static const struct snd_soc_dapm_route mt8173_afe_pcm_routes[] = {
+ {"I05", NULL, "DL1"},
+ {"I06", NULL, "DL1"},
+ {"I2S Playback", NULL, "O03"},
+ {"I2S Playback", NULL, "O04"},
+ {"VUL", NULL, "O09"},
+ {"VUL", NULL, "O10"},
+ {"I03", NULL, "I2S Capture"},
+ {"I04", NULL, "I2S Capture"},
+ {"I17", NULL, "I2S Capture"},
+ {"I18", NULL, "I2S Capture"},
+ { "O03", "I05 Switch", "I05" },
+ { "O04", "I06 Switch", "I06" },
+ { "O09", "I17 Switch", "I17" },
+ { "O09", "I03 Switch", "I03" },
+ { "O10", "I18 Switch", "I18" },
+ { "O10", "I04 Switch", "I04" },
+};
+
+static const struct snd_soc_dapm_route mt8173_afe_hdmi_routes[] = {
+ {"HDMIO Playback", NULL, "HDMI"},
+};
+
+static const struct snd_soc_component_driver mt8173_afe_pcm_dai_component = {
+ .name = "mt8173-afe-pcm-dai",
+ .dapm_widgets = mt8173_afe_pcm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8173_afe_pcm_widgets),
+ .dapm_routes = mt8173_afe_pcm_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8173_afe_pcm_routes),
+ .suspend = mtk_afe_suspend,
+ .resume = mtk_afe_resume,
+};
+
+static const struct snd_soc_component_driver mt8173_afe_hdmi_dai_component = {
+ .name = "mt8173-afe-hdmi-dai",
+ .dapm_routes = mt8173_afe_hdmi_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8173_afe_hdmi_routes),
+ .suspend = mtk_afe_suspend,
+ .resume = mtk_afe_resume,
+};
+
+static const char *aud_clks[MT8173_CLK_NUM] = {
+ [MT8173_CLK_INFRASYS_AUD] = "infra_sys_audio_clk",
+ [MT8173_CLK_TOP_PDN_AUD] = "top_pdn_audio",
+ [MT8173_CLK_TOP_PDN_AUD_BUS] = "top_pdn_aud_intbus",
+ [MT8173_CLK_I2S0_M] = "i2s0_m",
+ [MT8173_CLK_I2S1_M] = "i2s1_m",
+ [MT8173_CLK_I2S2_M] = "i2s2_m",
+ [MT8173_CLK_I2S3_M] = "i2s3_m",
+ [MT8173_CLK_I2S3_B] = "i2s3_b",
+ [MT8173_CLK_BCK0] = "bck0",
+ [MT8173_CLK_BCK1] = "bck1",
+};
+
+static const struct mtk_base_memif_data memif_data[MT8173_AFE_MEMIF_NUM] = {
+ {
+ .name = "DL1",
+ .id = MT8173_AFE_MEMIF_DL1,
+ .reg_ofs_base = AFE_DL1_BASE,
+ .reg_ofs_cur = AFE_DL1_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 0,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 21,
+ .hd_reg = -1,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 1,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 0,
+ .agent_disable_reg = -1,
+ }, {
+ .name = "DL2",
+ .id = MT8173_AFE_MEMIF_DL2,
+ .reg_ofs_base = AFE_DL2_BASE,
+ .reg_ofs_cur = AFE_DL2_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 4,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 22,
+ .hd_reg = -1,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 2,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 1,
+ .agent_disable_reg = -1,
+ }, {
+ .name = "VUL",
+ .id = MT8173_AFE_MEMIF_VUL,
+ .reg_ofs_base = AFE_VUL_BASE,
+ .reg_ofs_cur = AFE_VUL_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 16,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 27,
+ .hd_reg = -1,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 3,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 6,
+ .agent_disable_reg = -1,
+ }, {
+ .name = "DAI",
+ .id = MT8173_AFE_MEMIF_DAI,
+ .reg_ofs_base = AFE_DAI_BASE,
+ .reg_ofs_cur = AFE_DAI_CUR,
+ .fs_reg = AFE_DAC_CON0,
+ .fs_shift = 24,
+ .fs_maskbit = 0x3,
+ .mono_reg = -1,
+ .mono_shift = -1,
+ .hd_reg = -1,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 4,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 5,
+ .agent_disable_reg = -1,
+ }, {
+ .name = "AWB",
+ .id = MT8173_AFE_MEMIF_AWB,
+ .reg_ofs_base = AFE_AWB_BASE,
+ .reg_ofs_cur = AFE_AWB_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 12,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 24,
+ .hd_reg = -1,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 6,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 3,
+ .agent_disable_reg = -1,
+ }, {
+ .name = "MOD_DAI",
+ .id = MT8173_AFE_MEMIF_MOD_DAI,
+ .reg_ofs_base = AFE_MOD_PCM_BASE,
+ .reg_ofs_cur = AFE_MOD_PCM_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 30,
+ .fs_maskbit = 0x3,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 30,
+ .hd_reg = -1,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 7,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 4,
+ .agent_disable_reg = -1,
+ }, {
+ .name = "HDMI",
+ .id = MT8173_AFE_MEMIF_HDMI,
+ .reg_ofs_base = AFE_HDMI_OUT_BASE,
+ .reg_ofs_cur = AFE_HDMI_OUT_CUR,
+ .fs_reg = -1,
+ .fs_shift = -1,
+ .fs_maskbit = -1,
+ .mono_reg = -1,
+ .mono_shift = -1,
+ .hd_reg = -1,
+ .enable_reg = -1,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 8,
+ .agent_disable_reg = -1,
+ },
+};
+
+static const struct mtk_base_irq_data irq_data[MT8173_AFE_IRQ_NUM] = {
+ {
+ .id = MT8173_AFE_IRQ_DL1,
+ .irq_cnt_reg = AFE_IRQ_CNT1,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 0,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 4,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_CLR,
+ .irq_clr_shift = 0,
+ }, {
+ .id = MT8173_AFE_IRQ_DL2,
+ .irq_cnt_reg = AFE_IRQ_CNT1,
+ .irq_cnt_shift = 20,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 2,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 16,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_CLR,
+ .irq_clr_shift = 2,
+
+ }, {
+ .id = MT8173_AFE_IRQ_VUL,
+ .irq_cnt_reg = AFE_IRQ_CNT2,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 1,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 8,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_CLR,
+ .irq_clr_shift = 1,
+ }, {
+ .id = MT8173_AFE_IRQ_DAI,
+ .irq_cnt_reg = AFE_IRQ_CNT2,
+ .irq_cnt_shift = 20,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 3,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 20,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_CLR,
+ .irq_clr_shift = 3,
+ }, {
+ .id = MT8173_AFE_IRQ_AWB,
+ .irq_cnt_reg = AFE_IRQ_CNT7,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 14,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 24,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_CLR,
+ .irq_clr_shift = 6,
+ }, {
+ .id = MT8173_AFE_IRQ_DAI,
+ .irq_cnt_reg = AFE_IRQ_CNT2,
+ .irq_cnt_shift = 20,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 3,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 20,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_CLR,
+ .irq_clr_shift = 3,
+ }, {
+ .id = MT8173_AFE_IRQ_HDMI,
+ .irq_cnt_reg = AFE_IRQ_CNT5,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 12,
+ .irq_fs_reg = -1,
+ .irq_fs_maskbit = -1,
+ .irq_clr_reg = AFE_IRQ_CLR,
+ .irq_clr_shift = 4,
+ },
+};
+
+static const struct regmap_config mt8173_afe_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = AFE_ADDA2_TOP_CON0,
+ .cache_type = REGCACHE_NONE,
+};
+
+static irqreturn_t mt8173_afe_irq_handler(int irq, void *dev_id)
+{
+ struct mtk_base_afe *afe = dev_id;
+ unsigned int reg_value;
+ int i, ret;
+
+ ret = regmap_read(afe->regmap, AFE_IRQ_STATUS, &reg_value);
+ if (ret) {
+ dev_err(afe->dev, "%s irq status err\n", __func__);
+ reg_value = AFE_IRQ_STATUS_BITS;
+ goto err_irq;
+ }
+
+ for (i = 0; i < MT8173_AFE_MEMIF_NUM; i++) {
+ struct mtk_base_afe_memif *memif = &afe->memif[i];
+ struct mtk_base_afe_irq *irq;
+
+ if (memif->irq_usage < 0)
+ continue;
+
+ irq = &afe->irqs[memif->irq_usage];
+
+ if (!(reg_value & (1 << irq->irq_data->irq_clr_shift)))
+ continue;
+
+ snd_pcm_period_elapsed(memif->substream);
+ }
+
+err_irq:
+ /* clear irq */
+ regmap_write(afe->regmap, AFE_IRQ_CLR,
+ reg_value & AFE_IRQ_STATUS_BITS);
+
+ return IRQ_HANDLED;
+}
+
+static int mt8173_afe_runtime_suspend(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct mt8173_afe_private *afe_priv = afe->platform_priv;
+
+ /* disable AFE */
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
+
+ /* disable AFE clk */
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ AUD_TCON0_PDN_AFE, AUD_TCON0_PDN_AFE);
+
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S1_M]);
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S2_M]);
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_BCK0]);
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_BCK1]);
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD]);
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]);
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_INFRASYS_AUD]);
+ return 0;
+}
+
+static int mt8173_afe_runtime_resume(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct mt8173_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_INFRASYS_AUD]);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]);
+ if (ret)
+ goto err_infra;
+
+ ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD]);
+ if (ret)
+ goto err_top_aud_bus;
+
+ ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_BCK0]);
+ if (ret)
+ goto err_top_aud;
+
+ ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_BCK1]);
+ if (ret)
+ goto err_bck0;
+ ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_I2S1_M]);
+ if (ret)
+ goto err_i2s1_m;
+ ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_I2S2_M]);
+ if (ret)
+ goto err_i2s2_m;
+
+ /* enable AFE clk */
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_AFE, 0);
+
+ /* set O3/O4 16bits */
+ regmap_update_bits(afe->regmap, AFE_CONN_24BIT,
+ AFE_CONN_24BIT_O03 | AFE_CONN_24BIT_O04, 0);
+
+ /* unmask all IRQs */
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, 0xff, 0xff);
+
+ /* enable AFE */
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
+ return 0;
+
+err_i2s1_m:
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S1_M]);
+err_i2s2_m:
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S2_M]);
+err_bck0:
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_BCK0]);
+err_top_aud:
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD]);
+err_top_aud_bus:
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]);
+err_infra:
+ clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_INFRASYS_AUD]);
+ return ret;
+}
+
+static int mt8173_afe_init_audio_clk(struct mtk_base_afe *afe)
+{
+ size_t i;
+ struct mt8173_afe_private *afe_priv = afe->platform_priv;
+
+ for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
+ afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]);
+ if (IS_ERR(afe_priv->clocks[i])) {
+ dev_err(afe->dev, "%s devm_clk_get %s fail\n",
+ __func__, aud_clks[i]);
+ return PTR_ERR(afe_priv->clocks[i]);
+ }
+ }
+ clk_set_rate(afe_priv->clocks[MT8173_CLK_BCK0], 22579200); /* 22M */
+ clk_set_rate(afe_priv->clocks[MT8173_CLK_BCK1], 24576000); /* 24M */
+ return 0;
+}
+
+static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+ int ret, i;
+ int irq_id;
+ struct mtk_base_afe *afe;
+ struct mt8173_afe_private *afe_priv;
+ struct snd_soc_component *comp_pcm, *comp_hdmi;
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33));
+ if (ret)
+ return ret;
+
+ afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+ if (!afe)
+ return -ENOMEM;
+
+ afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+ GFP_KERNEL);
+ afe_priv = afe->platform_priv;
+ if (!afe_priv)
+ return -ENOMEM;
+
+ afe->dev = &pdev->dev;
+
+ irq_id = platform_get_irq(pdev, 0);
+ if (irq_id <= 0)
+ return irq_id < 0 ? irq_id : -ENXIO;
+
+ afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(afe->base_addr))
+ return PTR_ERR(afe->base_addr);
+
+ afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
+ &mt8173_afe_regmap_config);
+ if (IS_ERR(afe->regmap))
+ return PTR_ERR(afe->regmap);
+
+ /* initial audio related clock */
+ ret = mt8173_afe_init_audio_clk(afe);
+ if (ret) {
+ dev_err(afe->dev, "mt8173_afe_init_audio_clk fail\n");
+ return ret;
+ }
+
+ /* memif % irq initialize*/
+ afe->memif_size = MT8173_AFE_MEMIF_NUM;
+ afe->memif = devm_kcalloc(afe->dev, afe->memif_size,
+ sizeof(*afe->memif), GFP_KERNEL);
+ if (!afe->memif)
+ return -ENOMEM;
+
+ afe->irqs_size = MT8173_AFE_IRQ_NUM;
+ afe->irqs = devm_kcalloc(afe->dev, afe->irqs_size,
+ sizeof(*afe->irqs), GFP_KERNEL);
+ if (!afe->irqs)
+ return -ENOMEM;
+
+ for (i = 0; i < afe->irqs_size; i++) {
+ afe->memif[i].data = &memif_data[i];
+ afe->irqs[i].irq_data = &irq_data[i];
+ afe->irqs[i].irq_occupyed = true;
+ afe->memif[i].irq_usage = i;
+ afe->memif[i].const_irq = 1;
+ }
+
+ afe->mtk_afe_hardware = &mt8173_afe_hardware;
+ afe->memif_fs = mt8173_memif_fs;
+ afe->irq_fs = mt8173_irq_fs;
+
+ platform_set_drvdata(pdev, afe);
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = mt8173_afe_runtime_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+
+ afe->reg_back_up_list = mt8173_afe_backup_list;
+ afe->reg_back_up_list_num = ARRAY_SIZE(mt8173_afe_backup_list);
+ afe->runtime_resume = mt8173_afe_runtime_resume;
+ afe->runtime_suspend = mt8173_afe_runtime_suspend;
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &mtk_afe_pcm_platform,
+ NULL, 0);
+ if (ret)
+ goto err_pm_disable;
+
+ comp_pcm = devm_kzalloc(&pdev->dev, sizeof(*comp_pcm), GFP_KERNEL);
+ if (!comp_pcm) {
+ ret = -ENOMEM;
+ goto err_pm_disable;
+ }
+
+ ret = snd_soc_component_initialize(comp_pcm,
+ &mt8173_afe_pcm_dai_component,
+ &pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+
+#ifdef CONFIG_DEBUG_FS
+ comp_pcm->debugfs_prefix = "pcm";
+#endif
+
+ ret = snd_soc_add_component(comp_pcm,
+ mt8173_afe_pcm_dais,
+ ARRAY_SIZE(mt8173_afe_pcm_dais));
+ if (ret)
+ goto err_pm_disable;
+
+ comp_hdmi = devm_kzalloc(&pdev->dev, sizeof(*comp_hdmi), GFP_KERNEL);
+ if (!comp_hdmi) {
+ ret = -ENOMEM;
+ goto err_cleanup_components;
+ }
+
+ ret = snd_soc_component_initialize(comp_hdmi,
+ &mt8173_afe_hdmi_dai_component,
+ &pdev->dev);
+ if (ret)
+ goto err_cleanup_components;
+
+#ifdef CONFIG_DEBUG_FS
+ comp_hdmi->debugfs_prefix = "hdmi";
+#endif
+
+ ret = snd_soc_add_component(comp_hdmi,
+ mt8173_afe_hdmi_dais,
+ ARRAY_SIZE(mt8173_afe_hdmi_dais));
+ if (ret)
+ goto err_cleanup_components;
+
+ ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler,
+ 0, "Afe_ISR_Handle", (void *)afe);
+ if (ret) {
+ dev_err(afe->dev, "could not request_irq\n");
+ goto err_cleanup_components;
+ }
+
+ dev_info(&pdev->dev, "MT8173 AFE driver initialized.\n");
+ return 0;
+
+err_cleanup_components:
+ snd_soc_unregister_component(&pdev->dev);
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+}
+
+static int mt8173_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_component(&pdev->dev);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mt8173_afe_runtime_suspend(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id mt8173_afe_pcm_dt_match[] = {
+ { .compatible = "mediatek,mt8173-afe-pcm", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mt8173_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt8173_afe_pm_ops = {
+ SET_RUNTIME_PM_OPS(mt8173_afe_runtime_suspend,
+ mt8173_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt8173_afe_pcm_driver = {
+ .driver = {
+ .name = "mt8173-afe-pcm",
+ .of_match_table = mt8173_afe_pcm_dt_match,
+ .pm = &mt8173_afe_pm_ops,
+ },
+ .probe = mt8173_afe_pcm_dev_probe,
+ .remove = mt8173_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt8173_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver");
+MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c
new file mode 100644
index 000000000..5f39e810e
--- /dev/null
+++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8173-max98090.c -- MT8173 MAX98090 ALSA SoC machine driver
+ *
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Koro Chen <koro.chen@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+#include "../../codecs/max98090.h"
+
+static struct snd_soc_jack mt8173_max98090_jack;
+
+static struct snd_soc_jack_pin mt8173_max98090_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_soc_dapm_widget mt8173_max98090_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mt8173_max98090_routes[] = {
+ {"Speaker", NULL, "SPKL"},
+ {"Speaker", NULL, "SPKR"},
+ {"DMICL", NULL, "Int Mic"},
+ {"Headphone", NULL, "HPL"},
+ {"Headphone", NULL, "HPR"},
+ {"Headset Mic", NULL, "MICBIAS"},
+ {"IN34", NULL, "Headset Mic"},
+};
+
+static const struct snd_kcontrol_new mt8173_max98090_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int mt8173_max98090_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+
+ return snd_soc_dai_set_sysclk(codec_dai, 0, params_rate(params) * 256,
+ SND_SOC_CLOCK_IN);
+}
+
+static const struct snd_soc_ops mt8173_max98090_ops = {
+ .hw_params = mt8173_max98090_hw_params,
+};
+
+static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime)
+{
+ int ret;
+ struct snd_soc_card *card = runtime->card;
+ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+
+ /* enable jack detection */
+ ret = snd_soc_card_jack_new(card, "Headphone", SND_JACK_HEADPHONE,
+ &mt8173_max98090_jack,
+ mt8173_max98090_jack_pins,
+ ARRAY_SIZE(mt8173_max98090_jack_pins));
+ if (ret) {
+ dev_err(card->dev, "Can't create a new Jack %d\n", ret);
+ return ret;
+ }
+
+ return max98090_mic_detect(component, &mt8173_max98090_jack);
+}
+
+SND_SOC_DAILINK_DEFS(playback,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture,
+ DAILINK_COMP_ARRAY(COMP_CPU("VUL")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(hifi,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link mt8173_max98090_dais[] = {
+ /* Front End DAI links */
+ {
+ .name = "MAX98090 Playback",
+ .stream_name = "MAX98090 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback),
+ },
+ {
+ .name = "MAX98090 Capture",
+ .stream_name = "MAX98090 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture),
+ },
+ /* Back End DAI links */
+ {
+ .name = "Codec",
+ .no_pcm = 1,
+ .init = mt8173_max98090_init,
+ .ops = &mt8173_max98090_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(hifi),
+ },
+};
+
+static struct snd_soc_card mt8173_max98090_card = {
+ .name = "mt8173-max98090",
+ .owner = THIS_MODULE,
+ .dai_link = mt8173_max98090_dais,
+ .num_links = ARRAY_SIZE(mt8173_max98090_dais),
+ .controls = mt8173_max98090_controls,
+ .num_controls = ARRAY_SIZE(mt8173_max98090_controls),
+ .dapm_widgets = mt8173_max98090_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8173_max98090_widgets),
+ .dapm_routes = mt8173_max98090_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8173_max98090_routes),
+};
+
+static int mt8173_max98090_dev_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &mt8173_max98090_card;
+ struct device_node *codec_node, *platform_node;
+ struct snd_soc_dai_link *dai_link;
+ int ret, i;
+
+ platform_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,platform", 0);
+ if (!platform_node) {
+ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->platforms->name)
+ continue;
+ dai_link->platforms->of_node = platform_node;
+ }
+
+ codec_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,audio-codec", 0);
+ if (!codec_node) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto put_platform_node;
+ }
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->codecs->name)
+ continue;
+ dai_link->codecs->of_node = codec_node;
+ }
+ card->dev = &pdev->dev;
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret)
+ dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+ __func__, ret);
+
+ of_node_put(codec_node);
+
+put_platform_node:
+ of_node_put(platform_node);
+ return ret;
+}
+
+static const struct of_device_id mt8173_max98090_dt_match[] = {
+ { .compatible = "mediatek,mt8173-max98090", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mt8173_max98090_dt_match);
+
+static struct platform_driver mt8173_max98090_driver = {
+ .driver = {
+ .name = "mt8173-max98090",
+ .of_match_table = mt8173_max98090_dt_match,
+#ifdef CONFIG_PM
+ .pm = &snd_soc_pm_ops,
+#endif
+ },
+ .probe = mt8173_max98090_dev_probe,
+};
+
+module_platform_driver(mt8173_max98090_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8173 MAX98090 ALSA SoC machine driver");
+MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mt8173-max98090");
+
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
new file mode 100644
index 000000000..9421b919d
--- /dev/null
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8173-rt5650-rt5514.c -- MT8173 machine driver with RT5650/5514 codecs
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Koro Chen <koro.chen@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../../codecs/rt5645.h"
+
+#define MCLK_FOR_CODECS 12288000
+
+static const struct snd_soc_dapm_widget mt8173_rt5650_rt5514_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mt8173_rt5650_rt5514_routes[] = {
+ {"Speaker", NULL, "SPOL"},
+ {"Speaker", NULL, "SPOR"},
+ {"Sub DMIC1L", NULL, "Int Mic"},
+ {"Sub DMIC1R", NULL, "Int Mic"},
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+ {"IN1P", NULL, "Headset Mic"},
+ {"IN1N", NULL, "Headset Mic"},
+};
+
+static const struct snd_kcontrol_new mt8173_rt5650_rt5514_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai;
+ int i, ret;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ /* pll from mclk 12.288M */
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS,
+ params_rate(params) * 512);
+ if (ret)
+ return ret;
+
+ /* sysclk from pll */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 1,
+ params_rate(params) * 512,
+ SND_SOC_CLOCK_IN);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static const struct snd_soc_ops mt8173_rt5650_rt5514_ops = {
+ .hw_params = mt8173_rt5650_rt5514_hw_params,
+};
+
+static struct snd_soc_jack mt8173_rt5650_rt5514_jack;
+
+static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_card *card = runtime->card;
+ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ int ret;
+
+ rt5645_sel_asrc_clk_src(component,
+ RT5645_DA_STEREO_FILTER |
+ RT5645_AD_STEREO_FILTER,
+ RT5645_CLK_SEL_I2S1_ASRC);
+
+ /* enable jack detection */
+ ret = snd_soc_card_jack_new(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &mt8173_rt5650_rt5514_jack, NULL, 0);
+ if (ret) {
+ dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
+ return ret;
+ }
+
+ return rt5645_set_jack_detect(component,
+ &mt8173_rt5650_rt5514_jack,
+ &mt8173_rt5650_rt5514_jack,
+ &mt8173_rt5650_rt5514_jack);
+}
+
+enum {
+ DAI_LINK_PLAYBACK,
+ DAI_LINK_CAPTURE,
+ DAI_LINK_CODEC_I2S,
+};
+
+SND_SOC_DAILINK_DEFS(playback,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture,
+ DAILINK_COMP_ARRAY(COMP_CPU("VUL")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(codec,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5645-aif1"),
+ COMP_CODEC(NULL, "rt5514-aif1")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = {
+ /* Front End DAI links */
+ [DAI_LINK_PLAYBACK] = {
+ .name = "rt5650_rt5514 Playback",
+ .stream_name = "rt5650_rt5514 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback),
+ },
+ [DAI_LINK_CAPTURE] = {
+ .name = "rt5650_rt5514 Capture",
+ .stream_name = "rt5650_rt5514 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture),
+ },
+ /* Back End DAI links */
+ [DAI_LINK_CODEC_I2S] = {
+ .name = "Codec",
+ .no_pcm = 1,
+ .init = mt8173_rt5650_rt5514_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &mt8173_rt5650_rt5514_ops,
+ .ignore_pmdown_time = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(codec),
+ },
+};
+
+static struct snd_soc_codec_conf mt8173_rt5650_rt5514_codec_conf[] = {
+ {
+ .name_prefix = "Sub",
+ },
+};
+
+static struct snd_soc_card mt8173_rt5650_rt5514_card = {
+ .name = "mtk-rt5650-rt5514",
+ .owner = THIS_MODULE,
+ .dai_link = mt8173_rt5650_rt5514_dais,
+ .num_links = ARRAY_SIZE(mt8173_rt5650_rt5514_dais),
+ .codec_conf = mt8173_rt5650_rt5514_codec_conf,
+ .num_configs = ARRAY_SIZE(mt8173_rt5650_rt5514_codec_conf),
+ .controls = mt8173_rt5650_rt5514_controls,
+ .num_controls = ARRAY_SIZE(mt8173_rt5650_rt5514_controls),
+ .dapm_widgets = mt8173_rt5650_rt5514_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_rt5514_widgets),
+ .dapm_routes = mt8173_rt5650_rt5514_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_rt5514_routes),
+};
+
+static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &mt8173_rt5650_rt5514_card;
+ struct device_node *platform_node;
+ struct snd_soc_dai_link *dai_link;
+ int i, ret;
+
+ platform_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,platform", 0);
+ if (!platform_node) {
+ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->platforms->name)
+ continue;
+ dai_link->platforms->of_node = platform_node;
+ }
+
+ mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node =
+ of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0);
+ if (!mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =
+ of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
+ if (!mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ mt8173_rt5650_rt5514_codec_conf[0].dlc.of_node =
+ mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
+
+ card->dev = &pdev->dev;
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret)
+ dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+ __func__, ret);
+
+out:
+ of_node_put(platform_node);
+ return ret;
+}
+
+static const struct of_device_id mt8173_rt5650_rt5514_dt_match[] = {
+ { .compatible = "mediatek,mt8173-rt5650-rt5514", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5514_dt_match);
+
+static struct platform_driver mt8173_rt5650_rt5514_driver = {
+ .driver = {
+ .name = "mtk-rt5650-rt5514",
+ .of_match_table = mt8173_rt5650_rt5514_dt_match,
+#ifdef CONFIG_PM
+ .pm = &snd_soc_pm_ops,
+#endif
+ },
+ .probe = mt8173_rt5650_rt5514_dev_probe,
+};
+
+module_platform_driver(mt8173_rt5650_rt5514_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8173 RT5650 and RT5514 SoC machine driver");
+MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mtk-rt5650-rt5514");
+
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
new file mode 100644
index 000000000..94a9bbf14
--- /dev/null
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
@@ -0,0 +1,321 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8173-rt5650-rt5676.c -- MT8173 machine driver with RT5650/5676 codecs
+ *
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Koro Chen <koro.chen@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../../codecs/rt5645.h"
+#include "../../codecs/rt5677.h"
+
+#define MCLK_FOR_CODECS 12288000
+
+static const struct snd_soc_dapm_widget mt8173_rt5650_rt5676_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mt8173_rt5650_rt5676_routes[] = {
+ {"Speaker", NULL, "SPOL"},
+ {"Speaker", NULL, "SPOR"},
+ {"Speaker", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650 */
+ {"Sub DMIC L1", NULL, "Int Mic"}, /* DMIC from 5676 */
+ {"Sub DMIC R1", NULL, "Int Mic"},
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+ {"Headphone", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650 */
+ {"IN1P", NULL, "Headset Mic"},
+ {"IN1N", NULL, "Headset Mic"},
+ {"Sub AIF2RX", NULL, "Headset Mic"}, /* IF2 DAC from 5650 */
+};
+
+static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai;
+ int i, ret;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ /* pll from mclk 12.288M */
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS,
+ params_rate(params) * 512);
+ if (ret)
+ return ret;
+
+ /* sysclk from pll */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 1,
+ params_rate(params) * 512,
+ SND_SOC_CLOCK_IN);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static const struct snd_soc_ops mt8173_rt5650_rt5676_ops = {
+ .hw_params = mt8173_rt5650_rt5676_hw_params,
+};
+
+static struct snd_soc_jack mt8173_rt5650_rt5676_jack;
+
+static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_card *card = runtime->card;
+ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_component *component_sub = asoc_rtd_to_codec(runtime, 1)->component;
+ int ret;
+
+ rt5645_sel_asrc_clk_src(component,
+ RT5645_DA_STEREO_FILTER |
+ RT5645_AD_STEREO_FILTER,
+ RT5645_CLK_SEL_I2S1_ASRC);
+ rt5677_sel_asrc_clk_src(component_sub,
+ RT5677_DA_STEREO_FILTER |
+ RT5677_AD_STEREO1_FILTER,
+ RT5677_CLK_SEL_I2S1_ASRC);
+ rt5677_sel_asrc_clk_src(component_sub,
+ RT5677_AD_STEREO2_FILTER |
+ RT5677_I2S2_SOURCE,
+ RT5677_CLK_SEL_I2S2_ASRC);
+
+ /* enable jack detection */
+ ret = snd_soc_card_jack_new(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &mt8173_rt5650_rt5676_jack, NULL, 0);
+ if (ret) {
+ dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
+ return ret;
+ }
+
+ return rt5645_set_jack_detect(component,
+ &mt8173_rt5650_rt5676_jack,
+ &mt8173_rt5650_rt5676_jack,
+ &mt8173_rt5650_rt5676_jack);
+}
+
+
+enum {
+ DAI_LINK_PLAYBACK,
+ DAI_LINK_CAPTURE,
+ DAI_LINK_HDMI,
+ DAI_LINK_CODEC_I2S,
+ DAI_LINK_HDMI_I2S,
+ DAI_LINK_INTERCODEC
+};
+
+SND_SOC_DAILINK_DEFS(playback,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture,
+ DAILINK_COMP_ARRAY(COMP_CPU("VUL")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(hdmi_pcm,
+ DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(codec,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5645-aif1"),
+ COMP_CODEC(NULL, "rt5677-aif1")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(hdmi_be,
+ DAILINK_COMP_ARRAY(COMP_CPU("HDMIO")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(intercodec,
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5677-aif2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()));
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
+ /* Front End DAI links */
+ [DAI_LINK_PLAYBACK] = {
+ .name = "rt5650_rt5676 Playback",
+ .stream_name = "rt5650_rt5676 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback),
+ },
+ [DAI_LINK_CAPTURE] = {
+ .name = "rt5650_rt5676 Capture",
+ .stream_name = "rt5650_rt5676 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture),
+ },
+ [DAI_LINK_HDMI] = {
+ .name = "HDMI",
+ .stream_name = "HDMI PCM",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(hdmi_pcm),
+ },
+
+ /* Back End DAI links */
+ [DAI_LINK_CODEC_I2S] = {
+ .name = "Codec",
+ .no_pcm = 1,
+ .init = mt8173_rt5650_rt5676_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &mt8173_rt5650_rt5676_ops,
+ .ignore_pmdown_time = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(codec),
+ },
+ [DAI_LINK_HDMI_I2S] = {
+ .name = "HDMI BE",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(hdmi_be),
+ },
+ /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */
+ [DAI_LINK_INTERCODEC] = {
+ .name = "rt5650_rt5676 intercodec",
+ .stream_name = "rt5650_rt5676 intercodec",
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAILINK_REG(intercodec),
+ },
+};
+
+static struct snd_soc_codec_conf mt8173_rt5650_rt5676_codec_conf[] = {
+ {
+ .name_prefix = "Sub",
+ },
+};
+
+static struct snd_soc_card mt8173_rt5650_rt5676_card = {
+ .name = "mtk-rt5650-rt5676",
+ .owner = THIS_MODULE,
+ .dai_link = mt8173_rt5650_rt5676_dais,
+ .num_links = ARRAY_SIZE(mt8173_rt5650_rt5676_dais),
+ .codec_conf = mt8173_rt5650_rt5676_codec_conf,
+ .num_configs = ARRAY_SIZE(mt8173_rt5650_rt5676_codec_conf),
+ .controls = mt8173_rt5650_rt5676_controls,
+ .num_controls = ARRAY_SIZE(mt8173_rt5650_rt5676_controls),
+ .dapm_widgets = mt8173_rt5650_rt5676_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_rt5676_widgets),
+ .dapm_routes = mt8173_rt5650_rt5676_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_rt5676_routes),
+};
+
+static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &mt8173_rt5650_rt5676_card;
+ struct device_node *platform_node;
+ struct snd_soc_dai_link *dai_link;
+ int i, ret;
+
+ platform_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,platform", 0);
+ if (!platform_node) {
+ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->platforms->name)
+ continue;
+ dai_link->platforms->of_node = platform_node;
+ }
+
+ mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node =
+ of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0);
+ if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto put_node;
+ }
+ mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =
+ of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
+ if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto put_node;
+ }
+ mt8173_rt5650_rt5676_codec_conf[0].dlc.of_node =
+ mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
+
+ mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codecs->of_node =
+ mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
+
+ mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node =
+ of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 2);
+ if (!mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto put_node;
+ }
+
+ card->dev = &pdev->dev;
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret)
+ dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+ __func__, ret);
+
+put_node:
+ of_node_put(platform_node);
+ return ret;
+}
+
+static const struct of_device_id mt8173_rt5650_rt5676_dt_match[] = {
+ { .compatible = "mediatek,mt8173-rt5650-rt5676", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5676_dt_match);
+
+static struct platform_driver mt8173_rt5650_rt5676_driver = {
+ .driver = {
+ .name = "mtk-rt5650-rt5676",
+ .of_match_table = mt8173_rt5650_rt5676_dt_match,
+#ifdef CONFIG_PM
+ .pm = &snd_soc_pm_ops,
+#endif
+ },
+ .probe = mt8173_rt5650_rt5676_dev_probe,
+};
+
+module_platform_driver(mt8173_rt5650_rt5676_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8173 RT5650 and RT5676 SoC machine driver");
+MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mtk-rt5650-rt5676");
+
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
new file mode 100644
index 000000000..1de9dab21
--- /dev/null
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8173-rt5650.c -- MT8173 machine driver with RT5650 codecs
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Koro Chen <koro.chen@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../../codecs/rt5645.h"
+
+#define MCLK_FOR_CODECS 12288000
+
+enum mt8173_rt5650_mclk {
+ MT8173_RT5650_MCLK_EXTERNAL = 0,
+ MT8173_RT5650_MCLK_INTERNAL,
+};
+
+struct mt8173_rt5650_platform_data {
+ enum mt8173_rt5650_mclk pll_from;
+ /* 0 = external oscillator; 1 = internal source from mt8173 */
+};
+
+static struct mt8173_rt5650_platform_data mt8173_rt5650_priv = {
+ .pll_from = MT8173_RT5650_MCLK_EXTERNAL,
+};
+
+static const struct snd_soc_dapm_widget mt8173_rt5650_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mt8173_rt5650_routes[] = {
+ {"Speaker", NULL, "SPOL"},
+ {"Speaker", NULL, "SPOR"},
+ {"DMIC L1", NULL, "Int Mic"},
+ {"DMIC R1", NULL, "Int Mic"},
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+ {"IN1P", NULL, "Headset Mic"},
+ {"IN1N", NULL, "Headset Mic"},
+};
+
+static const struct snd_kcontrol_new mt8173_rt5650_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ unsigned int mclk_clock;
+ struct snd_soc_dai *codec_dai;
+ int i, ret;
+
+ switch (mt8173_rt5650_priv.pll_from) {
+ case MT8173_RT5650_MCLK_EXTERNAL:
+ /* mclk = 12.288M */
+ mclk_clock = MCLK_FOR_CODECS;
+ break;
+ case MT8173_RT5650_MCLK_INTERNAL:
+ /* mclk = sampling rate*256 */
+ mclk_clock = params_rate(params) * 256;
+ break;
+ default:
+ /* mclk = 12.288M */
+ mclk_clock = MCLK_FOR_CODECS;
+ break;
+ }
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ /* pll from mclk */
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, mclk_clock,
+ params_rate(params) * 512);
+ if (ret)
+ return ret;
+
+ /* sysclk from pll */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 1,
+ params_rate(params) * 512,
+ SND_SOC_CLOCK_IN);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static const struct snd_soc_ops mt8173_rt5650_ops = {
+ .hw_params = mt8173_rt5650_hw_params,
+};
+
+static struct snd_soc_jack mt8173_rt5650_jack, mt8173_rt5650_hdmi_jack;
+
+static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_card *card = runtime->card;
+ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ const char *codec_capture_dai = asoc_rtd_to_codec(runtime, 1)->name;
+ int ret;
+
+ rt5645_sel_asrc_clk_src(component,
+ RT5645_DA_STEREO_FILTER,
+ RT5645_CLK_SEL_I2S1_ASRC);
+
+ if (!strcmp(codec_capture_dai, "rt5645-aif1")) {
+ rt5645_sel_asrc_clk_src(component,
+ RT5645_AD_STEREO_FILTER,
+ RT5645_CLK_SEL_I2S1_ASRC);
+ } else if (!strcmp(codec_capture_dai, "rt5645-aif2")) {
+ rt5645_sel_asrc_clk_src(component,
+ RT5645_AD_STEREO_FILTER,
+ RT5645_CLK_SEL_I2S2_ASRC);
+ } else {
+ dev_warn(card->dev,
+ "Only one dai codec found in DTS, enabled rt5645 AD filter\n");
+ rt5645_sel_asrc_clk_src(component,
+ RT5645_AD_STEREO_FILTER,
+ RT5645_CLK_SEL_I2S1_ASRC);
+ }
+
+ /* enable jack detection */
+ ret = snd_soc_card_jack_new(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &mt8173_rt5650_jack, NULL, 0);
+ if (ret) {
+ dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
+ return ret;
+ }
+
+ return rt5645_set_jack_detect(component,
+ &mt8173_rt5650_jack,
+ &mt8173_rt5650_jack,
+ &mt8173_rt5650_jack);
+}
+
+static int mt8173_rt5650_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+
+ ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+ &mt8173_rt5650_hdmi_jack, NULL, 0);
+ if (ret)
+ return ret;
+
+ return snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component,
+ &mt8173_rt5650_hdmi_jack, NULL);
+}
+
+enum {
+ DAI_LINK_PLAYBACK,
+ DAI_LINK_CAPTURE,
+ DAI_LINK_HDMI,
+ DAI_LINK_CODEC_I2S,
+ DAI_LINK_HDMI_I2S,
+};
+
+SND_SOC_DAILINK_DEFS(playback,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture,
+ DAILINK_COMP_ARRAY(COMP_CPU("VUL")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(hdmi_pcm,
+ DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(codec,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5645-aif1"), /* Playback */
+ COMP_CODEC(NULL, "rt5645-aif1")),/* Capture */
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(hdmi_be,
+ DAILINK_COMP_ARRAY(COMP_CPU("HDMIO")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
+ /* Front End DAI links */
+ [DAI_LINK_PLAYBACK] = {
+ .name = "rt5650 Playback",
+ .stream_name = "rt5650 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback),
+ },
+ [DAI_LINK_CAPTURE] = {
+ .name = "rt5650 Capture",
+ .stream_name = "rt5650 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture),
+ },
+ [DAI_LINK_HDMI] = {
+ .name = "HDMI",
+ .stream_name = "HDMI PCM",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(hdmi_pcm),
+ },
+ /* Back End DAI links */
+ [DAI_LINK_CODEC_I2S] = {
+ .name = "Codec",
+ .no_pcm = 1,
+ .init = mt8173_rt5650_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &mt8173_rt5650_ops,
+ .ignore_pmdown_time = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(codec),
+ },
+ [DAI_LINK_HDMI_I2S] = {
+ .name = "HDMI BE",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .init = mt8173_rt5650_hdmi_init,
+ SND_SOC_DAILINK_REG(hdmi_be),
+ },
+};
+
+static struct snd_soc_card mt8173_rt5650_card = {
+ .name = "mtk-rt5650",
+ .owner = THIS_MODULE,
+ .dai_link = mt8173_rt5650_dais,
+ .num_links = ARRAY_SIZE(mt8173_rt5650_dais),
+ .controls = mt8173_rt5650_controls,
+ .num_controls = ARRAY_SIZE(mt8173_rt5650_controls),
+ .dapm_widgets = mt8173_rt5650_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_widgets),
+ .dapm_routes = mt8173_rt5650_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_routes),
+};
+
+static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &mt8173_rt5650_card;
+ struct device_node *platform_node;
+ struct device_node *np;
+ const char *codec_capture_dai;
+ struct snd_soc_dai_link *dai_link;
+ int i, ret;
+
+ platform_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,platform", 0);
+ if (!platform_node) {
+ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->platforms->name)
+ continue;
+ dai_link->platforms->of_node = platform_node;
+ }
+
+ mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node =
+ of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0);
+ if (!mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto put_platform_node;
+ }
+ mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =
+ mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node;
+
+ np = of_get_child_by_name(pdev->dev.of_node, "codec-capture");
+ if (np) {
+ ret = snd_soc_of_get_dai_name(np, &codec_capture_dai);
+ of_node_put(np);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "%s codec_capture_dai name fail %d\n",
+ __func__, ret);
+ goto put_platform_node;
+ }
+ mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[1].dai_name =
+ codec_capture_dai;
+ }
+
+ if (device_property_present(&pdev->dev, "mediatek,mclk")) {
+ ret = device_property_read_u32(&pdev->dev,
+ "mediatek,mclk",
+ &mt8173_rt5650_priv.pll_from);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s snd_soc_register_card fail %d\n",
+ __func__, ret);
+ }
+ }
+
+ mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codecs->of_node =
+ of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
+ if (!mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codecs->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto put_platform_node;
+ }
+ card->dev = &pdev->dev;
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret)
+ dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+ __func__, ret);
+
+put_platform_node:
+ of_node_put(platform_node);
+ return ret;
+}
+
+static const struct of_device_id mt8173_rt5650_dt_match[] = {
+ { .compatible = "mediatek,mt8173-rt5650", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mt8173_rt5650_dt_match);
+
+static struct platform_driver mt8173_rt5650_driver = {
+ .driver = {
+ .name = "mtk-rt5650",
+ .of_match_table = mt8173_rt5650_dt_match,
+#ifdef CONFIG_PM
+ .pm = &snd_soc_pm_ops,
+#endif
+ },
+ .probe = mt8173_rt5650_dev_probe,
+};
+
+module_platform_driver(mt8173_rt5650_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8173 RT5650 SoC machine driver");
+MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mtk-rt5650");
+
diff --git a/sound/soc/mediatek/mt8183/Makefile b/sound/soc/mediatek/mt8183/Makefile
new file mode 100644
index 000000000..c0a3bbc2c
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# platform driver
+snd-soc-mt8183-afe-objs := \
+ mt8183-afe-pcm.o \
+ mt8183-afe-clk.o \
+ mt8183-dai-i2s.o \
+ mt8183-dai-tdm.o \
+ mt8183-dai-pcm.o \
+ mt8183-dai-hostless.o \
+ mt8183-dai-adda.o
+
+obj-$(CONFIG_SND_SOC_MT8183) += snd-soc-mt8183-afe.o
+obj-$(CONFIG_SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A) += mt8183-mt6358-ts3a227-max98357.o
+obj-$(CONFIG_SND_SOC_MT8183_DA7219_MAX98357A) += mt8183-da7219-max98357.o
diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-clk.c b/sound/soc/mediatek/mt8183/mt8183-afe-clk.c
new file mode 100644
index 000000000..48e81c5d5
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-afe-clk.c
@@ -0,0 +1,615 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8183-afe-clk.c -- Mediatek 8183 afe clock ctrl
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/clk.h>
+
+#include "mt8183-afe-common.h"
+#include "mt8183-afe-clk.h"
+#include "mt8183-reg.h"
+
+enum {
+ CLK_AFE = 0,
+ CLK_TML,
+ CLK_APLL22M,
+ CLK_APLL24M,
+ CLK_APLL1_TUNER,
+ CLK_APLL2_TUNER,
+ CLK_I2S1_BCLK_SW,
+ CLK_I2S2_BCLK_SW,
+ CLK_I2S3_BCLK_SW,
+ CLK_I2S4_BCLK_SW,
+ CLK_INFRA_SYS_AUDIO,
+ CLK_MUX_AUDIO,
+ CLK_MUX_AUDIOINTBUS,
+ CLK_TOP_SYSPLL_D2_D4,
+ /* apll related mux */
+ CLK_TOP_MUX_AUD_1,
+ CLK_TOP_APLL1_CK,
+ CLK_TOP_MUX_AUD_2,
+ CLK_TOP_APLL2_CK,
+ CLK_TOP_MUX_AUD_ENG1,
+ CLK_TOP_APLL1_D8,
+ CLK_TOP_MUX_AUD_ENG2,
+ CLK_TOP_APLL2_D8,
+ CLK_TOP_I2S0_M_SEL,
+ CLK_TOP_I2S1_M_SEL,
+ CLK_TOP_I2S2_M_SEL,
+ CLK_TOP_I2S3_M_SEL,
+ CLK_TOP_I2S4_M_SEL,
+ CLK_TOP_I2S5_M_SEL,
+ CLK_TOP_APLL12_DIV0,
+ CLK_TOP_APLL12_DIV1,
+ CLK_TOP_APLL12_DIV2,
+ CLK_TOP_APLL12_DIV3,
+ CLK_TOP_APLL12_DIV4,
+ CLK_TOP_APLL12_DIVB,
+ CLK_CLK26M,
+ CLK_NUM
+};
+
+static const char *aud_clks[CLK_NUM] = {
+ [CLK_AFE] = "aud_afe_clk",
+ [CLK_TML] = "aud_tml_clk",
+ [CLK_APLL22M] = "aud_apll22m_clk",
+ [CLK_APLL24M] = "aud_apll24m_clk",
+ [CLK_APLL1_TUNER] = "aud_apll1_tuner_clk",
+ [CLK_APLL2_TUNER] = "aud_apll2_tuner_clk",
+ [CLK_I2S1_BCLK_SW] = "aud_i2s1_bclk_sw",
+ [CLK_I2S2_BCLK_SW] = "aud_i2s2_bclk_sw",
+ [CLK_I2S3_BCLK_SW] = "aud_i2s3_bclk_sw",
+ [CLK_I2S4_BCLK_SW] = "aud_i2s4_bclk_sw",
+ [CLK_INFRA_SYS_AUDIO] = "aud_infra_clk",
+ [CLK_MUX_AUDIO] = "top_mux_audio",
+ [CLK_MUX_AUDIOINTBUS] = "top_mux_aud_intbus",
+ [CLK_TOP_SYSPLL_D2_D4] = "top_syspll_d2_d4",
+ [CLK_TOP_MUX_AUD_1] = "top_mux_aud_1",
+ [CLK_TOP_APLL1_CK] = "top_apll1_ck",
+ [CLK_TOP_MUX_AUD_2] = "top_mux_aud_2",
+ [CLK_TOP_APLL2_CK] = "top_apll2_ck",
+ [CLK_TOP_MUX_AUD_ENG1] = "top_mux_aud_eng1",
+ [CLK_TOP_APLL1_D8] = "top_apll1_d8",
+ [CLK_TOP_MUX_AUD_ENG2] = "top_mux_aud_eng2",
+ [CLK_TOP_APLL2_D8] = "top_apll2_d8",
+ [CLK_TOP_I2S0_M_SEL] = "top_i2s0_m_sel",
+ [CLK_TOP_I2S1_M_SEL] = "top_i2s1_m_sel",
+ [CLK_TOP_I2S2_M_SEL] = "top_i2s2_m_sel",
+ [CLK_TOP_I2S3_M_SEL] = "top_i2s3_m_sel",
+ [CLK_TOP_I2S4_M_SEL] = "top_i2s4_m_sel",
+ [CLK_TOP_I2S5_M_SEL] = "top_i2s5_m_sel",
+ [CLK_TOP_APLL12_DIV0] = "top_apll12_div0",
+ [CLK_TOP_APLL12_DIV1] = "top_apll12_div1",
+ [CLK_TOP_APLL12_DIV2] = "top_apll12_div2",
+ [CLK_TOP_APLL12_DIV3] = "top_apll12_div3",
+ [CLK_TOP_APLL12_DIV4] = "top_apll12_div4",
+ [CLK_TOP_APLL12_DIVB] = "top_apll12_divb",
+ [CLK_CLK26M] = "top_clk26m_clk",
+};
+
+int mt8183_init_clock(struct mtk_base_afe *afe)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ int i;
+
+ 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++) {
+ afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
+ if (IS_ERR(afe_priv->clk[i])) {
+ dev_err(afe->dev, "%s(), devm_clk_get %s fail, ret %ld\n",
+ __func__, aud_clks[i],
+ PTR_ERR(afe_priv->clk[i]));
+ return PTR_ERR(afe_priv->clk[i]);
+ }
+ }
+
+ return 0;
+}
+
+int mt8183_afe_enable_clock(struct mtk_base_afe *afe)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_INFRA_SYS_AUDIO], ret);
+ goto CLK_INFRA_SYS_AUDIO_ERR;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIO]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_MUX_AUDIO], ret);
+ goto CLK_MUX_AUDIO_ERR;
+ }
+
+ ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIO],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_MUX_AUDIO],
+ aud_clks[CLK_CLK26M], ret);
+ goto CLK_MUX_AUDIO_ERR;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
+ goto CLK_MUX_AUDIO_INTBUS_ERR;
+ }
+
+ ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIOINTBUS],
+ afe_priv->clk[CLK_TOP_SYSPLL_D2_D4]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_MUX_AUDIOINTBUS],
+ aud_clks[CLK_TOP_SYSPLL_D2_D4], ret);
+ goto CLK_MUX_AUDIO_INTBUS_ERR;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_AFE]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_AFE], ret);
+ goto CLK_AFE_ERR;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_I2S1_BCLK_SW]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_I2S1_BCLK_SW], ret);
+ goto CLK_I2S1_BCLK_SW_ERR;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_I2S2_BCLK_SW]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_I2S2_BCLK_SW], ret);
+ goto CLK_I2S2_BCLK_SW_ERR;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_I2S3_BCLK_SW]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_I2S3_BCLK_SW], ret);
+ goto CLK_I2S3_BCLK_SW_ERR;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_I2S4_BCLK_SW]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_I2S4_BCLK_SW], ret);
+ goto CLK_I2S4_BCLK_SW_ERR;
+ }
+
+ return 0;
+
+CLK_I2S4_BCLK_SW_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_I2S3_BCLK_SW]);
+CLK_I2S3_BCLK_SW_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_I2S2_BCLK_SW]);
+CLK_I2S2_BCLK_SW_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_I2S1_BCLK_SW]);
+CLK_I2S1_BCLK_SW_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_AFE]);
+CLK_AFE_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+CLK_MUX_AUDIO_INTBUS_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]);
+CLK_MUX_AUDIO_ERR:
+ clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+CLK_INFRA_SYS_AUDIO_ERR:
+ return ret;
+}
+
+int mt8183_afe_disable_clock(struct mtk_base_afe *afe)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+
+ clk_disable_unprepare(afe_priv->clk[CLK_I2S4_BCLK_SW]);
+ clk_disable_unprepare(afe_priv->clk[CLK_I2S3_BCLK_SW]);
+ clk_disable_unprepare(afe_priv->clk[CLK_I2S2_BCLK_SW]);
+ clk_disable_unprepare(afe_priv->clk[CLK_I2S1_BCLK_SW]);
+ clk_disable_unprepare(afe_priv->clk[CLK_AFE]);
+ clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+ clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]);
+ clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+
+ return 0;
+}
+
+/* apll */
+static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ if (enable) {
+ ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_1], ret);
+ goto ERR_ENABLE_CLK_TOP_MUX_AUD_1;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[CLK_TOP_APLL1_CK]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_1],
+ aud_clks[CLK_TOP_APLL1_CK], ret);
+ goto ERR_SELECT_CLK_TOP_MUX_AUD_1;
+ }
+
+ /* 180.6336 / 8 = 22.5792MHz */
+ ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], ret);
+ goto ERR_ENABLE_CLK_TOP_MUX_AUD_ENG1;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
+ afe_priv->clk[CLK_TOP_APLL1_D8]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1],
+ aud_clks[CLK_TOP_APLL1_D8], ret);
+ goto ERR_SELECT_CLK_TOP_MUX_AUD_ENG1;
+ }
+ } else {
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1],
+ aud_clks[CLK_CLK26M], ret);
+ goto EXIT;
+ }
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
+
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_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_TOP_MUX_AUD_1],
+ aud_clks[CLK_CLK26M], ret);
+ goto EXIT;
+ }
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
+ }
+
+ return 0;
+
+ERR_SELECT_CLK_TOP_MUX_AUD_ENG1:
+ clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
+ afe_priv->clk[CLK_CLK26M]);
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
+ERR_ENABLE_CLK_TOP_MUX_AUD_ENG1:
+ERR_SELECT_CLK_TOP_MUX_AUD_1:
+ clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[CLK_CLK26M]);
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
+ERR_ENABLE_CLK_TOP_MUX_AUD_1:
+EXIT:
+ return ret;
+}
+
+static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ if (enable) {
+ ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_2], ret);
+ goto ERR_ENABLE_CLK_TOP_MUX_AUD_2;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2],
+ afe_priv->clk[CLK_TOP_APLL2_CK]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_2],
+ aud_clks[CLK_TOP_APLL2_CK], ret);
+ goto ERR_SELECT_CLK_TOP_MUX_AUD_2;
+ }
+
+ /* 196.608 / 8 = 24.576MHz */
+ ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], ret);
+ goto ERR_ENABLE_CLK_TOP_MUX_AUD_ENG2;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
+ afe_priv->clk[CLK_TOP_APLL2_D8]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2],
+ aud_clks[CLK_TOP_APLL2_D8], ret);
+ goto ERR_SELECT_CLK_TOP_MUX_AUD_ENG2;
+ }
+ } else {
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2],
+ aud_clks[CLK_CLK26M], ret);
+ goto EXIT;
+ }
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
+
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_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_TOP_MUX_AUD_2],
+ aud_clks[CLK_CLK26M], ret);
+ goto EXIT;
+ }
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
+ }
+
+ return 0;
+
+ERR_SELECT_CLK_TOP_MUX_AUD_ENG2:
+ clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
+ afe_priv->clk[CLK_CLK26M]);
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
+ERR_ENABLE_CLK_TOP_MUX_AUD_ENG2:
+ERR_SELECT_CLK_TOP_MUX_AUD_2:
+ clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2],
+ afe_priv->clk[CLK_CLK26M]);
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
+ERR_ENABLE_CLK_TOP_MUX_AUD_2:
+EXIT:
+ return ret;
+}
+
+int mt8183_apll1_enable(struct mtk_base_afe *afe)
+{
+ struct mt8183_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_APLL22M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_APLL22M], ret);
+ goto ERR_CLK_APLL22M;
+ }
+
+ 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, 0x00000832);
+ regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1);
+
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_22M_ON_MASK_SFT,
+ 0x1 << AFE_22M_ON_SFT);
+
+ return 0;
+
+ERR_CLK_APLL1_TUNER:
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]);
+ERR_CLK_APLL22M:
+ return ret;
+}
+
+void mt8183_apll1_disable(struct mtk_base_afe *afe)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_22M_ON_MASK_SFT,
+ 0x0 << AFE_22M_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_APLL22M]);
+
+ apll1_mux_setting(afe, false);
+}
+
+int mt8183_apll2_enable(struct mtk_base_afe *afe)
+{
+ struct mt8183_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_APLL24M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_APLL24M], ret);
+ goto ERR_CLK_APLL24M;
+ }
+
+ 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, 0x00000634);
+ regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1);
+
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_24M_ON_MASK_SFT,
+ 0x1 << AFE_24M_ON_SFT);
+
+ return 0;
+
+ERR_CLK_APLL2_TUNER:
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]);
+ERR_CLK_APLL24M:
+ return ret;
+}
+
+void mt8183_apll2_disable(struct mtk_base_afe *afe)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_24M_ON_MASK_SFT,
+ 0x0 << AFE_24M_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_APLL24M]);
+
+ apll2_mux_setting(afe, false);
+}
+
+int mt8183_get_apll_rate(struct mtk_base_afe *afe, int apll)
+{
+ return (apll == MT8183_APLL1) ? 180633600 : 196608000;
+}
+
+int mt8183_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
+{
+ return ((rate % 8000) == 0) ? MT8183_APLL2 : MT8183_APLL1;
+}
+
+int mt8183_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
+{
+ if (strcmp(name, APLL1_W_NAME) == 0)
+ return MT8183_APLL1;
+ else
+ return MT8183_APLL2;
+}
+
+/* mck */
+struct mt8183_mck_div {
+ int m_sel_id;
+ int div_clk_id;
+};
+
+static const struct mt8183_mck_div mck_div[MT8183_MCK_NUM] = {
+ [MT8183_I2S0_MCK] = {
+ .m_sel_id = CLK_TOP_I2S0_M_SEL,
+ .div_clk_id = CLK_TOP_APLL12_DIV0,
+ },
+ [MT8183_I2S1_MCK] = {
+ .m_sel_id = CLK_TOP_I2S1_M_SEL,
+ .div_clk_id = CLK_TOP_APLL12_DIV1,
+ },
+ [MT8183_I2S2_MCK] = {
+ .m_sel_id = CLK_TOP_I2S2_M_SEL,
+ .div_clk_id = CLK_TOP_APLL12_DIV2,
+ },
+ [MT8183_I2S3_MCK] = {
+ .m_sel_id = CLK_TOP_I2S3_M_SEL,
+ .div_clk_id = CLK_TOP_APLL12_DIV3,
+ },
+ [MT8183_I2S4_MCK] = {
+ .m_sel_id = CLK_TOP_I2S4_M_SEL,
+ .div_clk_id = CLK_TOP_APLL12_DIV4,
+ },
+ [MT8183_I2S4_BCK] = {
+ .m_sel_id = -1,
+ .div_clk_id = CLK_TOP_APLL12_DIVB,
+ },
+ [MT8183_I2S5_MCK] = {
+ .m_sel_id = -1,
+ .div_clk_id = -1,
+ },
+};
+
+int mt8183_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ int apll = mt8183_get_apll_by_rate(afe, rate);
+ int apll_clk_id = apll == MT8183_APLL1 ?
+ CLK_TOP_MUX_AUD_1 : CLK_TOP_MUX_AUD_2;
+ int m_sel_id = mck_div[mck_id].m_sel_id;
+ int div_clk_id = mck_div[mck_id].div_clk_id;
+ int ret;
+
+ /* i2s5 mck not support */
+ if (mck_id == MT8183_I2S5_MCK)
+ return 0;
+
+ /* 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);
+ goto ERR_ENABLE_MCLK;
+ }
+ 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);
+ goto ERR_SELECT_MCLK;
+ }
+ }
+
+ /* enable div, set rate */
+ 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);
+ goto ERR_ENABLE_MCLK_DIV;
+ }
+ 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);
+ goto ERR_SET_MCLK_RATE;
+ return ret;
+ }
+
+ return 0;
+
+ERR_SET_MCLK_RATE:
+ clk_disable_unprepare(afe_priv->clk[div_clk_id]);
+ERR_ENABLE_MCLK_DIV:
+ERR_SELECT_MCLK:
+ if (m_sel_id >= 0)
+ clk_disable_unprepare(afe_priv->clk[m_sel_id]);
+ERR_ENABLE_MCLK:
+ return ret;
+}
+
+void mt8183_mck_disable(struct mtk_base_afe *afe, int mck_id)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ int m_sel_id = mck_div[mck_id].m_sel_id;
+ int div_clk_id = mck_div[mck_id].div_clk_id;
+
+ /* i2s5 mck not support */
+ if (mck_id == MT8183_I2S5_MCK)
+ return;
+
+ clk_disable_unprepare(afe_priv->clk[div_clk_id]);
+ if (m_sel_id >= 0)
+ clk_disable_unprepare(afe_priv->clk[m_sel_id]);
+}
diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-clk.h b/sound/soc/mediatek/mt8183/mt8183-afe-clk.h
new file mode 100644
index 000000000..2c510aa80
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-afe-clk.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8183-afe-clk.h -- Mediatek 8183 afe clock ctrl definition
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef _MT8183_AFE_CLK_H_
+#define _MT8183_AFE_CLK_H_
+
+/* APLL */
+#define APLL1_W_NAME "APLL1"
+#define APLL2_W_NAME "APLL2"
+enum {
+ MT8183_APLL1 = 0,
+ MT8183_APLL2,
+};
+
+struct mtk_base_afe;
+
+int mt8183_init_clock(struct mtk_base_afe *afe);
+int mt8183_afe_enable_clock(struct mtk_base_afe *afe);
+int mt8183_afe_disable_clock(struct mtk_base_afe *afe);
+
+int mt8183_apll1_enable(struct mtk_base_afe *afe);
+void mt8183_apll1_disable(struct mtk_base_afe *afe);
+
+int mt8183_apll2_enable(struct mtk_base_afe *afe);
+void mt8183_apll2_disable(struct mtk_base_afe *afe);
+
+int mt8183_get_apll_rate(struct mtk_base_afe *afe, int apll);
+int mt8183_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
+int mt8183_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
+
+int mt8183_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate);
+void mt8183_mck_disable(struct mtk_base_afe *afe, int mck_id);
+#endif
diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-common.h b/sound/soc/mediatek/mt8183/mt8183-afe-common.h
new file mode 100644
index 000000000..b220e7a7d
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-afe-common.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8183-afe-common.h -- Mediatek 8183 audio driver definitions
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef _MT_8183_AFE_COMMON_H_
+#define _MT_8183_AFE_COMMON_H_
+
+#include <sound/soc.h>
+#include <linux/list.h>
+#include <linux/regmap.h>
+#include "../common/mtk-base-afe.h"
+
+enum {
+ MT8183_MEMIF_DL1,
+ MT8183_MEMIF_DL2,
+ MT8183_MEMIF_DL3,
+ MT8183_MEMIF_VUL12,
+ MT8183_MEMIF_VUL2,
+ MT8183_MEMIF_AWB,
+ MT8183_MEMIF_AWB2,
+ MT8183_MEMIF_MOD_DAI,
+ MT8183_MEMIF_HDMI,
+ MT8183_MEMIF_NUM,
+ MT8183_DAI_ADDA = MT8183_MEMIF_NUM,
+ MT8183_DAI_PCM_1,
+ MT8183_DAI_PCM_2,
+ MT8183_DAI_I2S_0,
+ MT8183_DAI_I2S_1,
+ MT8183_DAI_I2S_2,
+ MT8183_DAI_I2S_3,
+ MT8183_DAI_I2S_5,
+ MT8183_DAI_TDM,
+ MT8183_DAI_HOSTLESS_LPBK,
+ MT8183_DAI_HOSTLESS_SPEECH,
+ MT8183_DAI_NUM,
+};
+
+enum {
+ MT8183_IRQ_0,
+ MT8183_IRQ_1,
+ MT8183_IRQ_2,
+ MT8183_IRQ_3,
+ MT8183_IRQ_4,
+ MT8183_IRQ_5,
+ MT8183_IRQ_6,
+ MT8183_IRQ_7,
+ MT8183_IRQ_8, /* hw bundle to TDM */
+ MT8183_IRQ_11,
+ MT8183_IRQ_12,
+ MT8183_IRQ_NUM,
+};
+
+enum {
+ MT8183_MTKAIF_PROTOCOL_1 = 0,
+ MT8183_MTKAIF_PROTOCOL_2,
+ MT8183_MTKAIF_PROTOCOL_2_CLK_P2,
+};
+
+/* MCLK */
+enum {
+ MT8183_I2S0_MCK = 0,
+ MT8183_I2S1_MCK,
+ MT8183_I2S2_MCK,
+ MT8183_I2S3_MCK,
+ MT8183_I2S4_MCK,
+ MT8183_I2S4_BCK,
+ MT8183_I2S5_MCK,
+ MT8183_MCK_NUM,
+};
+
+struct clk;
+
+struct mt8183_afe_private {
+ struct clk **clk;
+
+ int pm_runtime_bypass_reg_ctl;
+
+ /* dai */
+ void *dai_priv[MT8183_DAI_NUM];
+
+ /* adda */
+ int mtkaif_protocol;
+ int mtkaif_calibration_ok;
+ int mtkaif_chosen_phase[4];
+ int mtkaif_phase_cycle[4];
+ int mtkaif_calibration_num_phase;
+ int mtkaif_dmic;
+
+ /* mck */
+ int mck_rate[MT8183_MCK_NUM];
+};
+
+unsigned int mt8183_general_rate_transform(struct device *dev,
+ unsigned int rate);
+unsigned int mt8183_rate_transform(struct device *dev,
+ unsigned int rate, int aud_blk);
+
+/* dai register */
+int mt8183_dai_adda_register(struct mtk_base_afe *afe);
+int mt8183_dai_pcm_register(struct mtk_base_afe *afe);
+int mt8183_dai_i2s_register(struct mtk_base_afe *afe);
+int mt8183_dai_tdm_register(struct mtk_base_afe *afe);
+int mt8183_dai_hostless_register(struct mtk_base_afe *afe);
+#endif
diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
new file mode 100644
index 000000000..14e77df06
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
@@ -0,0 +1,1294 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Mediatek ALSA SoC AFE platform driver for 8183
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include "mt8183-afe-common.h"
+#include "mt8183-afe-clk.h"
+#include "mt8183-interconnection.h"
+#include "mt8183-reg.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+enum {
+ MTK_AFE_RATE_8K = 0,
+ MTK_AFE_RATE_11K = 1,
+ MTK_AFE_RATE_12K = 2,
+ MTK_AFE_RATE_384K = 3,
+ MTK_AFE_RATE_16K = 4,
+ MTK_AFE_RATE_22K = 5,
+ MTK_AFE_RATE_24K = 6,
+ MTK_AFE_RATE_130K = 7,
+ MTK_AFE_RATE_32K = 8,
+ MTK_AFE_RATE_44K = 9,
+ MTK_AFE_RATE_48K = 10,
+ MTK_AFE_RATE_88K = 11,
+ MTK_AFE_RATE_96K = 12,
+ MTK_AFE_RATE_176K = 13,
+ MTK_AFE_RATE_192K = 14,
+ MTK_AFE_RATE_260K = 15,
+};
+
+enum {
+ MTK_AFE_DAI_MEMIF_RATE_8K = 0,
+ MTK_AFE_DAI_MEMIF_RATE_16K = 1,
+ MTK_AFE_DAI_MEMIF_RATE_32K = 2,
+ MTK_AFE_DAI_MEMIF_RATE_48K = 3,
+};
+
+enum {
+ MTK_AFE_PCM_RATE_8K = 0,
+ MTK_AFE_PCM_RATE_16K = 1,
+ MTK_AFE_PCM_RATE_32K = 2,
+ MTK_AFE_PCM_RATE_48K = 3,
+};
+
+unsigned int mt8183_general_rate_transform(struct device *dev,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_RATE_8K;
+ case 11025:
+ return MTK_AFE_RATE_11K;
+ case 12000:
+ return MTK_AFE_RATE_12K;
+ case 16000:
+ return MTK_AFE_RATE_16K;
+ case 22050:
+ return MTK_AFE_RATE_22K;
+ case 24000:
+ return MTK_AFE_RATE_24K;
+ case 32000:
+ return MTK_AFE_RATE_32K;
+ case 44100:
+ return MTK_AFE_RATE_44K;
+ case 48000:
+ return MTK_AFE_RATE_48K;
+ case 88200:
+ return MTK_AFE_RATE_88K;
+ case 96000:
+ return MTK_AFE_RATE_96K;
+ case 130000:
+ return MTK_AFE_RATE_130K;
+ case 176400:
+ return MTK_AFE_RATE_176K;
+ case 192000:
+ return MTK_AFE_RATE_192K;
+ case 260000:
+ return MTK_AFE_RATE_260K;
+ default:
+ dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
+ __func__, rate, MTK_AFE_RATE_48K);
+ return MTK_AFE_RATE_48K;
+ }
+}
+
+static unsigned int dai_memif_rate_transform(struct device *dev,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_DAI_MEMIF_RATE_8K;
+ case 16000:
+ return MTK_AFE_DAI_MEMIF_RATE_16K;
+ case 32000:
+ return MTK_AFE_DAI_MEMIF_RATE_32K;
+ case 48000:
+ return MTK_AFE_DAI_MEMIF_RATE_48K;
+ default:
+ dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
+ __func__, rate, MTK_AFE_DAI_MEMIF_RATE_16K);
+ return MTK_AFE_DAI_MEMIF_RATE_16K;
+ }
+}
+
+unsigned int mt8183_rate_transform(struct device *dev,
+ unsigned int rate, int aud_blk)
+{
+ switch (aud_blk) {
+ case MT8183_MEMIF_MOD_DAI:
+ return dai_memif_rate_transform(dev, rate);
+ default:
+ return mt8183_general_rate_transform(dev, rate);
+ }
+}
+
+static const struct snd_pcm_hardware mt8183_afe_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .period_bytes_min = 256,
+ .period_bytes_max = 4 * 48 * 1024,
+ .periods_min = 2,
+ .periods_max = 256,
+ .buffer_bytes_max = 8 * 48 * 1024,
+ .fifo_size = 0,
+};
+
+static int mt8183_memif_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ int id = asoc_rtd_to_cpu(rtd, 0)->id;
+
+ return mt8183_rate_transform(afe->dev, rate, id);
+}
+
+static int mt8183_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+ return mt8183_general_rate_transform(afe->dev, rate);
+}
+
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_PCM_DAI_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 |\
+ SNDRV_PCM_RATE_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mt8183_memif_dai_driver[] = {
+ /* FE DAIs: memory intefaces to CPU */
+ {
+ .name = "DL1",
+ .id = MT8183_MEMIF_DL1,
+ .playback = {
+ .stream_name = "DL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "DL2",
+ .id = MT8183_MEMIF_DL2,
+ .playback = {
+ .stream_name = "DL2",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "DL3",
+ .id = MT8183_MEMIF_DL3,
+ .playback = {
+ .stream_name = "DL3",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "UL1",
+ .id = MT8183_MEMIF_VUL12,
+ .capture = {
+ .stream_name = "UL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "UL2",
+ .id = MT8183_MEMIF_AWB,
+ .capture = {
+ .stream_name = "UL2",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "UL3",
+ .id = MT8183_MEMIF_VUL2,
+ .capture = {
+ .stream_name = "UL3",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "UL4",
+ .id = MT8183_MEMIF_AWB2,
+ .capture = {
+ .stream_name = "UL4",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "UL_MONO_1",
+ .id = MT8183_MEMIF_MOD_DAI,
+ .capture = {
+ .stream_name = "UL_MONO_1",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = MTK_PCM_DAI_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "HDMI",
+ .id = MT8183_MEMIF_HDMI,
+ .playback = {
+ .stream_name = "HDMI",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+};
+
+/* dma widget & routes*/
+static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN21,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN21,
+ I_I2S0_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN22,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN21,
+ I_I2S0_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN5,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN5,
+ I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN5,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN5,
+ I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN5,
+ I_I2S2_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN6,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN6,
+ I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN6,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN6,
+ I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN6,
+ I_I2S2_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN32,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN32,
+ I_I2S2_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN33,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN33,
+ I_I2S2_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul4_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN38,
+ I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul4_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN39,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_mono_1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN12,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN12,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mt8183_memif_widgets[] = {
+ /* memif */
+ SND_SOC_DAPM_MIXER("UL1_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul1_ch1_mix, ARRAY_SIZE(memif_ul1_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL1_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul1_ch2_mix, ARRAY_SIZE(memif_ul1_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL2_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul2_ch1_mix, ARRAY_SIZE(memif_ul2_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL2_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul2_ch2_mix, ARRAY_SIZE(memif_ul2_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL3_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul3_ch1_mix, ARRAY_SIZE(memif_ul3_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL3_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul3_ch2_mix, ARRAY_SIZE(memif_ul3_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL4_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul4_ch1_mix, ARRAY_SIZE(memif_ul4_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL4_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul4_ch2_mix, ARRAY_SIZE(memif_ul4_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL_MONO_1_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul_mono_1_mix,
+ ARRAY_SIZE(memif_ul_mono_1_mix)),
+};
+
+static const struct snd_soc_dapm_route mt8183_memif_routes[] = {
+ /* capture */
+ {"UL1", NULL, "UL1_CH1"},
+ {"UL1", NULL, "UL1_CH2"},
+ {"UL1_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL1_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL1_CH1", "I2S0_CH1", "I2S0"},
+ {"UL1_CH2", "I2S0_CH2", "I2S0"},
+
+ {"UL2", NULL, "UL2_CH1"},
+ {"UL2", NULL, "UL2_CH2"},
+ {"UL2_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL2_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL2_CH1", "I2S2_CH1", "I2S2"},
+ {"UL2_CH2", "I2S2_CH2", "I2S2"},
+
+ {"UL3", NULL, "UL3_CH1"},
+ {"UL3", NULL, "UL3_CH2"},
+ {"UL3_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL3_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL3_CH1", "I2S2_CH1", "I2S2"},
+ {"UL3_CH2", "I2S2_CH2", "I2S2"},
+
+ {"UL4", NULL, "UL4_CH1"},
+ {"UL4", NULL, "UL4_CH2"},
+ {"UL4_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL4_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+ {"UL_MONO_1", NULL, "UL_MONO_1_CH1"},
+ {"UL_MONO_1_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_MONO_1_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+};
+
+static const struct snd_soc_component_driver mt8183_afe_pcm_dai_component = {
+ .name = "mt8183-afe-pcm-dai",
+};
+
+static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = {
+ [MT8183_MEMIF_DL1] = {
+ .name = "DL1",
+ .id = MT8183_MEMIF_DL1,
+ .reg_ofs_base = AFE_DL1_BASE,
+ .reg_ofs_cur = AFE_DL1_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = DL1_MODE_SFT,
+ .fs_maskbit = DL1_MODE_MASK,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = DL1_DATA_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = DL1_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_align_reg = AFE_MEMIF_HDALIGN,
+ .hd_shift = DL1_HD_SFT,
+ .hd_align_mshift = DL1_HD_ALIGN_SFT,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ },
+ [MT8183_MEMIF_DL2] = {
+ .name = "DL2",
+ .id = MT8183_MEMIF_DL2,
+ .reg_ofs_base = AFE_DL2_BASE,
+ .reg_ofs_cur = AFE_DL2_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = DL2_MODE_SFT,
+ .fs_maskbit = DL2_MODE_MASK,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = DL2_DATA_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = DL2_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_align_reg = AFE_MEMIF_HDALIGN,
+ .hd_shift = DL2_HD_SFT,
+ .hd_align_mshift = DL2_HD_ALIGN_SFT,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ },
+ [MT8183_MEMIF_DL3] = {
+ .name = "DL3",
+ .id = MT8183_MEMIF_DL3,
+ .reg_ofs_base = AFE_DL3_BASE,
+ .reg_ofs_cur = AFE_DL3_CUR,
+ .fs_reg = AFE_DAC_CON2,
+ .fs_shift = DL3_MODE_SFT,
+ .fs_maskbit = DL3_MODE_MASK,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = DL3_DATA_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = DL3_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_align_reg = AFE_MEMIF_HDALIGN,
+ .hd_shift = DL3_HD_SFT,
+ .hd_align_mshift = DL3_HD_ALIGN_SFT,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ },
+ [MT8183_MEMIF_VUL2] = {
+ .name = "VUL2",
+ .id = MT8183_MEMIF_VUL2,
+ .reg_ofs_base = AFE_VUL2_BASE,
+ .reg_ofs_cur = AFE_VUL2_CUR,
+ .fs_reg = AFE_DAC_CON2,
+ .fs_shift = VUL2_MODE_SFT,
+ .fs_maskbit = VUL2_MODE_MASK,
+ .mono_reg = AFE_DAC_CON2,
+ .mono_shift = VUL2_DATA_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = VUL2_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_align_reg = AFE_MEMIF_HDALIGN,
+ .hd_shift = VUL2_HD_SFT,
+ .hd_align_mshift = VUL2_HD_ALIGN_SFT,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ },
+ [MT8183_MEMIF_AWB] = {
+ .name = "AWB",
+ .id = MT8183_MEMIF_AWB,
+ .reg_ofs_base = AFE_AWB_BASE,
+ .reg_ofs_cur = AFE_AWB_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = AWB_MODE_SFT,
+ .fs_maskbit = AWB_MODE_MASK,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = AWB_DATA_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = AWB_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_align_reg = AFE_MEMIF_HDALIGN,
+ .hd_shift = AWB_HD_SFT,
+ .hd_align_mshift = AWB_HD_ALIGN_SFT,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ },
+ [MT8183_MEMIF_AWB2] = {
+ .name = "AWB2",
+ .id = MT8183_MEMIF_AWB2,
+ .reg_ofs_base = AFE_AWB2_BASE,
+ .reg_ofs_cur = AFE_AWB2_CUR,
+ .fs_reg = AFE_DAC_CON2,
+ .fs_shift = AWB2_MODE_SFT,
+ .fs_maskbit = AWB2_MODE_MASK,
+ .mono_reg = AFE_DAC_CON2,
+ .mono_shift = AWB2_DATA_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = AWB2_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_align_reg = AFE_MEMIF_HDALIGN,
+ .hd_shift = AWB2_HD_SFT,
+ .hd_align_mshift = AWB2_ALIGN_SFT,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ },
+ [MT8183_MEMIF_VUL12] = {
+ .name = "VUL12",
+ .id = MT8183_MEMIF_VUL12,
+ .reg_ofs_base = AFE_VUL_D2_BASE,
+ .reg_ofs_cur = AFE_VUL_D2_CUR,
+ .fs_reg = AFE_DAC_CON0,
+ .fs_shift = VUL12_MODE_SFT,
+ .fs_maskbit = VUL12_MODE_MASK,
+ .mono_reg = AFE_DAC_CON0,
+ .mono_shift = VUL12_MONO_SFT,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = VUL12_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_align_reg = AFE_MEMIF_HDALIGN,
+ .hd_shift = VUL12_HD_SFT,
+ .hd_align_mshift = VUL12_HD_ALIGN_SFT,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ },
+ [MT8183_MEMIF_MOD_DAI] = {
+ .name = "MOD_DAI",
+ .id = MT8183_MEMIF_MOD_DAI,
+ .reg_ofs_base = AFE_MOD_DAI_BASE,
+ .reg_ofs_cur = AFE_MOD_DAI_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = MOD_DAI_MODE_SFT,
+ .fs_maskbit = MOD_DAI_MODE_MASK,
+ .mono_reg = -1,
+ .mono_shift = 0,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = MOD_DAI_ON_SFT,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_align_reg = AFE_MEMIF_HDALIGN,
+ .hd_shift = MOD_DAI_HD_SFT,
+ .hd_align_mshift = MOD_DAI_HD_ALIGN_SFT,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ },
+ [MT8183_MEMIF_HDMI] = {
+ .name = "HDMI",
+ .id = MT8183_MEMIF_HDMI,
+ .reg_ofs_base = AFE_HDMI_OUT_BASE,
+ .reg_ofs_cur = AFE_HDMI_OUT_CUR,
+ .fs_reg = -1,
+ .fs_shift = -1,
+ .fs_maskbit = -1,
+ .mono_reg = -1,
+ .mono_shift = -1,
+ .enable_reg = -1, /* control in tdm for sync start */
+ .enable_shift = -1,
+ .hd_reg = AFE_MEMIF_HD_MODE,
+ .hd_align_reg = AFE_MEMIF_HDALIGN,
+ .hd_shift = HDMI_HD_SFT,
+ .hd_align_mshift = HDMI_HD_ALIGN_SFT,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ },
+};
+
+static const struct mtk_base_irq_data irq_data[MT8183_IRQ_NUM] = {
+ [MT8183_IRQ_0] = {
+ .id = MT8183_IRQ_0,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT0,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_fs_reg = AFE_IRQ_MCU_CON1,
+ .irq_fs_shift = IRQ0_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ0_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON0,
+ .irq_en_shift = IRQ0_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ0_MCU_CLR_SFT,
+ },
+ [MT8183_IRQ_1] = {
+ .id = MT8183_IRQ_1,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT1,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_fs_reg = AFE_IRQ_MCU_CON1,
+ .irq_fs_shift = IRQ1_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ1_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON0,
+ .irq_en_shift = IRQ1_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ1_MCU_CLR_SFT,
+ },
+ [MT8183_IRQ_2] = {
+ .id = MT8183_IRQ_2,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT2,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_fs_reg = AFE_IRQ_MCU_CON1,
+ .irq_fs_shift = IRQ2_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ2_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON0,
+ .irq_en_shift = IRQ2_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ2_MCU_CLR_SFT,
+ },
+ [MT8183_IRQ_3] = {
+ .id = MT8183_IRQ_3,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT3,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_fs_reg = AFE_IRQ_MCU_CON1,
+ .irq_fs_shift = IRQ3_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ3_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON0,
+ .irq_en_shift = IRQ3_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ3_MCU_CLR_SFT,
+ },
+ [MT8183_IRQ_4] = {
+ .id = MT8183_IRQ_4,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT4,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_fs_reg = AFE_IRQ_MCU_CON1,
+ .irq_fs_shift = IRQ4_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ4_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON0,
+ .irq_en_shift = IRQ4_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ4_MCU_CLR_SFT,
+ },
+ [MT8183_IRQ_5] = {
+ .id = MT8183_IRQ_5,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT5,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_fs_reg = AFE_IRQ_MCU_CON1,
+ .irq_fs_shift = IRQ5_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ5_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON0,
+ .irq_en_shift = IRQ5_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ5_MCU_CLR_SFT,
+ },
+ [MT8183_IRQ_6] = {
+ .id = MT8183_IRQ_6,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT6,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_fs_reg = AFE_IRQ_MCU_CON1,
+ .irq_fs_shift = IRQ6_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ6_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON0,
+ .irq_en_shift = IRQ6_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ6_MCU_CLR_SFT,
+ },
+ [MT8183_IRQ_7] = {
+ .id = MT8183_IRQ_7,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT7,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_fs_reg = AFE_IRQ_MCU_CON1,
+ .irq_fs_shift = IRQ7_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ7_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON0,
+ .irq_en_shift = IRQ7_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ7_MCU_CLR_SFT,
+ },
+ [MT8183_IRQ_8] = {
+ .id = MT8183_IRQ_8,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT8,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_fs_reg = -1,
+ .irq_fs_shift = -1,
+ .irq_fs_maskbit = -1,
+ .irq_en_reg = AFE_IRQ_MCU_CON0,
+ .irq_en_shift = IRQ8_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ8_MCU_CLR_SFT,
+ },
+ [MT8183_IRQ_11] = {
+ .id = MT8183_IRQ_11,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT11,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_fs_reg = AFE_IRQ_MCU_CON2,
+ .irq_fs_shift = IRQ11_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ11_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON0,
+ .irq_en_shift = IRQ11_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ11_MCU_CLR_SFT,
+ },
+ [MT8183_IRQ_12] = {
+ .id = MT8183_IRQ_12,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT12,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_fs_reg = AFE_IRQ_MCU_CON2,
+ .irq_fs_shift = IRQ12_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ12_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ_MCU_CON0,
+ .irq_en_shift = IRQ12_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ12_MCU_CLR_SFT,
+ },
+};
+
+static bool mt8183_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ /* these auto-gen reg has read-only bit, so put it as volatile */
+ /* volatile reg cannot be cached, so cannot be set when power off */
+ switch (reg) {
+ case AUDIO_TOP_CON0: /* reg bit controlled by CCF */
+ case AUDIO_TOP_CON1: /* reg bit controlled by CCF */
+ case AUDIO_TOP_CON3:
+ case AFE_DL1_CUR:
+ case AFE_DL1_END:
+ case AFE_DL2_CUR:
+ case AFE_DL2_END:
+ case AFE_AWB_END:
+ case AFE_AWB_CUR:
+ case AFE_VUL_END:
+ case AFE_VUL_CUR:
+ case AFE_MEMIF_MON0:
+ case AFE_MEMIF_MON1:
+ case AFE_MEMIF_MON2:
+ case AFE_MEMIF_MON3:
+ case AFE_MEMIF_MON4:
+ case AFE_MEMIF_MON5:
+ case AFE_MEMIF_MON6:
+ case AFE_MEMIF_MON7:
+ case AFE_MEMIF_MON8:
+ case AFE_MEMIF_MON9:
+ case AFE_ADDA_SRC_DEBUG_MON0:
+ case AFE_ADDA_SRC_DEBUG_MON1:
+ case AFE_ADDA_UL_SRC_MON0:
+ case AFE_ADDA_UL_SRC_MON1:
+ case AFE_SIDETONE_MON:
+ case AFE_SIDETONE_CON0:
+ case AFE_SIDETONE_COEFF:
+ case AFE_BUS_MON0:
+ case AFE_MRGIF_MON0:
+ case AFE_MRGIF_MON1:
+ case AFE_MRGIF_MON2:
+ case AFE_I2S_MON:
+ case AFE_DAC_MON:
+ case AFE_VUL2_END:
+ case AFE_VUL2_CUR:
+ case AFE_IRQ0_MCU_CNT_MON:
+ case AFE_IRQ6_MCU_CNT_MON:
+ case AFE_MOD_DAI_END:
+ case AFE_MOD_DAI_CUR:
+ case AFE_VUL_D2_END:
+ case AFE_VUL_D2_CUR:
+ case AFE_DL3_CUR:
+ case AFE_DL3_END:
+ case AFE_HDMI_OUT_CON0:
+ case AFE_HDMI_OUT_CUR:
+ case AFE_HDMI_OUT_END:
+ case AFE_IRQ3_MCU_CNT_MON:
+ case AFE_IRQ4_MCU_CNT_MON:
+ case AFE_IRQ_MCU_STATUS:
+ case AFE_IRQ_MCU_CLR:
+ case AFE_IRQ_MCU_MON2:
+ case AFE_IRQ1_MCU_CNT_MON:
+ case AFE_IRQ2_MCU_CNT_MON:
+ case AFE_IRQ1_MCU_EN_CNT_MON:
+ case AFE_IRQ5_MCU_CNT_MON:
+ case AFE_IRQ7_MCU_CNT_MON:
+ case AFE_GAIN1_CUR:
+ case AFE_GAIN2_CUR:
+ case AFE_SRAM_DELSEL_CON0:
+ case AFE_SRAM_DELSEL_CON2:
+ case AFE_SRAM_DELSEL_CON3:
+ case AFE_ASRC_2CH_CON12:
+ case AFE_ASRC_2CH_CON13:
+ case PCM_INTF_CON2:
+ case FPGA_CFG0:
+ case FPGA_CFG1:
+ case FPGA_CFG2:
+ case FPGA_CFG3:
+ case AUDIO_TOP_DBG_MON0:
+ case AUDIO_TOP_DBG_MON1:
+ case AFE_IRQ8_MCU_CNT_MON:
+ case AFE_IRQ11_MCU_CNT_MON:
+ case AFE_IRQ12_MCU_CNT_MON:
+ case AFE_CBIP_MON0:
+ case AFE_CBIP_SLV_MUX_MON0:
+ case AFE_CBIP_SLV_DECODER_MON0:
+ case AFE_ADDA6_SRC_DEBUG_MON0:
+ case AFE_ADD6A_UL_SRC_MON0:
+ case AFE_ADDA6_UL_SRC_MON1:
+ case AFE_DL1_CUR_MSB:
+ case AFE_DL2_CUR_MSB:
+ case AFE_AWB_CUR_MSB:
+ case AFE_VUL_CUR_MSB:
+ case AFE_VUL2_CUR_MSB:
+ case AFE_MOD_DAI_CUR_MSB:
+ case AFE_VUL_D2_CUR_MSB:
+ case AFE_DL3_CUR_MSB:
+ case AFE_HDMI_OUT_CUR_MSB:
+ case AFE_AWB2_END:
+ case AFE_AWB2_CUR:
+ case AFE_AWB2_CUR_MSB:
+ case AFE_ADDA_DL_SDM_FIFO_MON:
+ case AFE_ADDA_DL_SRC_LCH_MON:
+ case AFE_ADDA_DL_SRC_RCH_MON:
+ case AFE_ADDA_DL_SDM_OUT_MON:
+ case AFE_CONNSYS_I2S_MON:
+ case AFE_ASRC_2CH_CON0:
+ case AFE_ASRC_2CH_CON2:
+ case AFE_ASRC_2CH_CON3:
+ case AFE_ASRC_2CH_CON4:
+ case AFE_ASRC_2CH_CON5:
+ case AFE_ASRC_2CH_CON7:
+ case AFE_ASRC_2CH_CON8:
+ case AFE_MEMIF_MON12:
+ case AFE_MEMIF_MON13:
+ case AFE_MEMIF_MON14:
+ case AFE_MEMIF_MON15:
+ case AFE_MEMIF_MON16:
+ case AFE_MEMIF_MON17:
+ case AFE_MEMIF_MON18:
+ case AFE_MEMIF_MON19:
+ case AFE_MEMIF_MON20:
+ case AFE_MEMIF_MON21:
+ case AFE_MEMIF_MON22:
+ case AFE_MEMIF_MON23:
+ case AFE_MEMIF_MON24:
+ case AFE_ADDA_MTKAIF_MON0:
+ case AFE_ADDA_MTKAIF_MON1:
+ case AFE_AUD_PAD_TOP:
+ case AFE_GENERAL1_ASRC_2CH_CON0:
+ case AFE_GENERAL1_ASRC_2CH_CON2:
+ case AFE_GENERAL1_ASRC_2CH_CON3:
+ case AFE_GENERAL1_ASRC_2CH_CON4:
+ case AFE_GENERAL1_ASRC_2CH_CON5:
+ case AFE_GENERAL1_ASRC_2CH_CON7:
+ case AFE_GENERAL1_ASRC_2CH_CON8:
+ case AFE_GENERAL1_ASRC_2CH_CON12:
+ case AFE_GENERAL1_ASRC_2CH_CON13:
+ case AFE_GENERAL2_ASRC_2CH_CON0:
+ case AFE_GENERAL2_ASRC_2CH_CON2:
+ case AFE_GENERAL2_ASRC_2CH_CON3:
+ case AFE_GENERAL2_ASRC_2CH_CON4:
+ case AFE_GENERAL2_ASRC_2CH_CON5:
+ case AFE_GENERAL2_ASRC_2CH_CON7:
+ case AFE_GENERAL2_ASRC_2CH_CON8:
+ case AFE_GENERAL2_ASRC_2CH_CON12:
+ case AFE_GENERAL2_ASRC_2CH_CON13:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config mt8183_afe_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .volatile_reg = mt8183_is_volatile_reg,
+
+ .max_register = AFE_MAX_REGISTER,
+ .num_reg_defaults_raw = AFE_MAX_REGISTER,
+
+ .cache_type = REGCACHE_FLAT,
+};
+
+static irqreturn_t mt8183_afe_irq_handler(int irq_id, void *dev)
+{
+ struct mtk_base_afe *afe = dev;
+ struct mtk_base_afe_irq *irq;
+ unsigned int status;
+ unsigned int status_mcu;
+ unsigned int mcu_en;
+ int ret;
+ int i;
+ irqreturn_t irq_ret = IRQ_HANDLED;
+
+ /* get irq that is sent to MCU */
+ regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
+
+ ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
+ /* only care IRQ which is sent to MCU */
+ status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS;
+
+ if (ret || status_mcu == 0) {
+ dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n",
+ __func__, ret, status, mcu_en);
+
+ irq_ret = IRQ_NONE;
+ goto err_irq;
+ }
+
+ for (i = 0; i < MT8183_MEMIF_NUM; i++) {
+ struct mtk_base_afe_memif *memif = &afe->memif[i];
+
+ if (!memif->substream)
+ continue;
+
+ if (memif->irq_usage < 0)
+ continue;
+
+ irq = &afe->irqs[memif->irq_usage];
+
+ if (status_mcu & (1 << irq->irq_data->irq_en_shift))
+ snd_pcm_period_elapsed(memif->substream);
+ }
+
+err_irq:
+ /* clear irq */
+ regmap_write(afe->regmap,
+ AFE_IRQ_MCU_CLR,
+ status_mcu);
+
+ return irq_ret;
+}
+
+static int mt8183_afe_runtime_suspend(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ unsigned int value;
+ int ret;
+
+ if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+ goto skip_regmap;
+
+ /* disable AFE */
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, AFE_ON_MASK_SFT, 0x0);
+
+ ret = regmap_read_poll_timeout(afe->regmap,
+ AFE_DAC_MON,
+ value,
+ (value & AFE_ON_RETM_MASK_SFT) == 0,
+ 20,
+ 1 * 1000 * 1000);
+ if (ret)
+ dev_warn(afe->dev, "%s(), ret %d\n", __func__, ret);
+
+ /* make sure all irq status are cleared, twice intended */
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
+
+ /* cache only */
+ regcache_cache_only(afe->regmap, true);
+ regcache_mark_dirty(afe->regmap);
+
+skip_regmap:
+ return mt8183_afe_disable_clock(afe);
+}
+
+static int mt8183_afe_runtime_resume(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ ret = mt8183_afe_enable_clock(afe);
+ if (ret)
+ return ret;
+
+ if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+ goto skip_regmap;
+
+ regcache_cache_only(afe->regmap, false);
+ regcache_sync(afe->regmap);
+
+ /* enable audio sys DCM for power saving */
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, 0x1 << 29, 0x1 << 29);
+
+ /* force cpu use 8_24 format when writing 32bit data */
+ regmap_update_bits(afe->regmap, AFE_MEMIF_MSB,
+ CPU_HD_ALIGN_MASK_SFT, 0 << CPU_HD_ALIGN_SFT);
+
+ /* set all output port to 24bit */
+ regmap_write(afe->regmap, AFE_CONN_24BIT, 0xffffffff);
+ regmap_write(afe->regmap, AFE_CONN_24BIT_1, 0xffffffff);
+
+ /* enable AFE */
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
+
+skip_regmap:
+ return 0;
+}
+
+static int mt8183_afe_component_probe(struct snd_soc_component *component)
+{
+ return mtk_afe_add_sub_dai_control(component);
+}
+
+static const struct snd_soc_component_driver mt8183_afe_component = {
+ .name = AFE_PCM_NAME,
+ .probe = mt8183_afe_component_probe,
+ .pointer = mtk_afe_pcm_pointer,
+ .pcm_construct = mtk_afe_pcm_new,
+};
+
+static int mt8183_dai_memif_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mt8183_memif_dai_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mt8183_memif_dai_driver);
+
+ dai->dapm_widgets = mt8183_memif_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mt8183_memif_widgets);
+ dai->dapm_routes = mt8183_memif_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mt8183_memif_routes);
+ return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+ mt8183_dai_adda_register,
+ mt8183_dai_i2s_register,
+ mt8183_dai_pcm_register,
+ mt8183_dai_tdm_register,
+ mt8183_dai_hostless_register,
+ mt8183_dai_memif_register,
+};
+
+static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+ struct mtk_base_afe *afe;
+ struct mt8183_afe_private *afe_priv;
+ struct device *dev;
+ struct reset_control *rstc;
+ int i, irq_id, 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;
+
+ /* initial audio related clock */
+ ret = mt8183_init_clock(afe);
+ if (ret) {
+ dev_err(dev, "init clock error\n");
+ return ret;
+ }
+
+ pm_runtime_enable(dev);
+
+ /* regmap init */
+ afe->regmap = syscon_node_to_regmap(dev->parent->of_node);
+ if (IS_ERR(afe->regmap)) {
+ dev_err(dev, "could not get regmap from parent\n");
+ ret = PTR_ERR(afe->regmap);
+ goto err_pm_disable;
+ }
+ ret = regmap_attach_dev(dev, afe->regmap, &mt8183_afe_regmap_config);
+ if (ret) {
+ dev_warn(dev, "regmap_attach_dev fail, ret %d\n", ret);
+ goto err_pm_disable;
+ }
+
+ rstc = devm_reset_control_get(dev, "audiosys");
+ if (IS_ERR(rstc)) {
+ ret = PTR_ERR(rstc);
+ dev_err(dev, "could not get audiosys reset:%d\n", ret);
+ goto err_pm_disable;
+ }
+
+ ret = reset_control_reset(rstc);
+ if (ret) {
+ dev_err(dev, "failed to trigger audio reset:%d\n", ret);
+ goto err_pm_disable;
+ }
+
+ /* enable clock for regcache get default value from hw */
+ afe_priv->pm_runtime_bypass_reg_ctl = true;
+ pm_runtime_get_sync(&pdev->dev);
+
+ ret = regmap_reinit_cache(afe->regmap, &mt8183_afe_regmap_config);
+ if (ret) {
+ dev_err(dev, "regmap_reinit_cache fail, ret %d\n", ret);
+ goto err_pm_disable;
+ }
+
+ pm_runtime_put_sync(&pdev->dev);
+ afe_priv->pm_runtime_bypass_reg_ctl = false;
+
+ regcache_cache_only(afe->regmap, true);
+ regcache_mark_dirty(afe->regmap);
+
+ /* init memif */
+ afe->memif_size = MT8183_MEMIF_NUM;
+ afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+ GFP_KERNEL);
+ if (!afe->memif) {
+ ret = -ENOMEM;
+ goto err_pm_disable;
+ }
+
+ for (i = 0; i < afe->memif_size; i++) {
+ afe->memif[i].data = &memif_data[i];
+ afe->memif[i].irq_usage = -1;
+ }
+
+ afe->memif[MT8183_MEMIF_HDMI].irq_usage = MT8183_IRQ_8;
+ afe->memif[MT8183_MEMIF_HDMI].const_irq = 1;
+
+ mutex_init(&afe->irq_alloc_lock);
+
+ /* init memif */
+ /* irq initialize */
+ afe->irqs_size = MT8183_IRQ_NUM;
+ afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+ GFP_KERNEL);
+ if (!afe->irqs) {
+ ret = -ENOMEM;
+ goto err_pm_disable;
+ }
+
+ 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) {
+ ret = irq_id;
+ goto err_pm_disable;
+ }
+
+ ret = devm_request_irq(dev, irq_id, mt8183_afe_irq_handler,
+ IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+ if (ret) {
+ dev_err(dev, "could not request_irq for asys-isr\n");
+ goto err_pm_disable;
+ }
+
+ /* 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_warn(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_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
+ ret);
+ goto err_pm_disable;
+ }
+
+ afe->mtk_afe_hardware = &mt8183_afe_hardware;
+ afe->memif_fs = mt8183_memif_fs;
+ afe->irq_fs = mt8183_irq_fs;
+
+ afe->runtime_resume = mt8183_afe_runtime_resume;
+ afe->runtime_suspend = mt8183_afe_runtime_suspend;
+
+ /* register component */
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &mt8183_afe_component,
+ NULL, 0);
+ if (ret) {
+ dev_warn(dev, "err_platform\n");
+ goto err_pm_disable;
+ }
+
+ ret = devm_snd_soc_register_component(afe->dev,
+ &mt8183_afe_pcm_dai_component,
+ afe->dai_drivers,
+ afe->num_dai_drivers);
+ if (ret) {
+ dev_warn(dev, "err_dai_component\n");
+ goto err_pm_disable;
+ }
+
+ return ret;
+
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+}
+
+static int mt8183_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mt8183_afe_runtime_suspend(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id mt8183_afe_pcm_dt_match[] = {
+ { .compatible = "mediatek,mt8183-audio", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt8183_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt8183_afe_pm_ops = {
+ SET_RUNTIME_PM_OPS(mt8183_afe_runtime_suspend,
+ mt8183_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt8183_afe_pcm_driver = {
+ .driver = {
+ .name = "mt8183-audio",
+ .of_match_table = mt8183_afe_pcm_dt_match,
+#ifdef CONFIG_PM
+ .pm = &mt8183_afe_pm_ops,
+#endif
+ },
+ .probe = mt8183_afe_pcm_dev_probe,
+ .remove = mt8183_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt8183_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 8183");
+MODULE_AUTHOR("KaiChieh Chuang <kaichieh.chuang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
new file mode 100644
index 000000000..9cc0f26b0
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -0,0 +1,831 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8183-da7219-max98357.c
+// -- MT8183-DA7219-MAX98357 ALSA SoC machine driver
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: Shunli Wang <shunli.wang@mediatek.com>
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../../codecs/da7219-aad.h"
+#include "../../codecs/da7219.h"
+#include "../../codecs/rt1015.h"
+#include "mt8183-afe-common.h"
+
+#define DA7219_CODEC_DAI "da7219-hifi"
+#define DA7219_DEV_NAME "da7219.5-001a"
+#define RT1015_CODEC_DAI "rt1015-aif"
+#define RT1015_DEV0_NAME "rt1015.6-0028"
+#define RT1015_DEV1_NAME "rt1015.6-0029"
+
+struct mt8183_da7219_max98357_priv {
+ struct snd_soc_jack headset_jack, hdmi_jack;
+};
+
+static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ unsigned int rate = params_rate(params);
+ unsigned int mclk_fs_ratio = 128;
+ unsigned int mclk_fs = rate * mclk_fs_ratio;
+
+ return snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0),
+ 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8183_mt6358_i2s_ops = {
+ .hw_params = mt8183_mt6358_i2s_hw_params,
+};
+
+static int mt8183_da7219_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai;
+ unsigned int rate = params_rate(params);
+ unsigned int mclk_fs_ratio = 256;
+ unsigned int mclk_fs = rate * mclk_fs_ratio;
+ unsigned int freq;
+ int ret = 0, j;
+
+ ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0,
+ mclk_fs, SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ dev_err(rtd->dev, "failed to set cpu dai sysclk\n");
+
+ for_each_rtd_codec_dais(rtd, j, codec_dai) {
+ if (!strcmp(codec_dai->component->name, DA7219_DEV_NAME)) {
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ DA7219_CLKSRC_MCLK,
+ mclk_fs,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(rtd->dev, "failed to set sysclk\n");
+
+ if ((rate % 8000) == 0)
+ freq = DA7219_PLL_FREQ_OUT_98304;
+ else
+ freq = DA7219_PLL_FREQ_OUT_90316;
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0,
+ DA7219_SYSCLK_PLL_SRM,
+ 0, freq);
+ if (ret)
+ dev_err(rtd->dev, "failed to start PLL: %d\n",
+ ret);
+ }
+ }
+
+ return ret;
+}
+
+static int mt8183_da7219_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai;
+ int ret = 0, j;
+
+ for_each_rtd_codec_dais(rtd, j, codec_dai) {
+ if (!strcmp(codec_dai->component->name, DA7219_DEV_NAME)) {
+ ret = snd_soc_dai_set_pll(codec_dai,
+ 0, DA7219_SYSCLK_MCLK, 0, 0);
+ if (ret < 0) {
+ dev_err(rtd->dev, "failed to stop PLL: %d\n",
+ ret);
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_ops mt8183_da7219_i2s_ops = {
+ .hw_params = mt8183_da7219_i2s_hw_params,
+ .hw_free = mt8183_da7219_hw_free,
+};
+
+static int
+mt8183_da7219_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ unsigned int rate = params_rate(params);
+ struct snd_soc_dai *codec_dai;
+ int ret = 0, i;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ if (!strcmp(codec_dai->component->name, RT1015_DEV0_NAME) ||
+ !strcmp(codec_dai->component->name, RT1015_DEV1_NAME)) {
+ ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
+ if (ret) {
+ dev_err(rtd->dev, "failed to set bclk ratio\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0,
+ RT1015_PLL_S_BCLK,
+ rate * 64, rate * 256);
+ if (ret) {
+ dev_err(rtd->dev, "failed to set pll\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ RT1015_SCLK_S_PLL,
+ rate * 256,
+ SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(rtd->dev, "failed to set sysclk\n");
+ return ret;
+ }
+ }
+ }
+
+ return mt8183_da7219_i2s_hw_params(substream, params);
+}
+
+static const struct snd_soc_ops mt8183_da7219_rt1015_i2s_ops = {
+ .hw_params = mt8183_da7219_rt1015_i2s_hw_params,
+ .hw_free = mt8183_da7219_hw_free,
+};
+
+static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ /* 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 mt8183_rt1015_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ /* 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_S24_LE);
+
+ return 0;
+}
+
+static int
+mt8183_da7219_max98357_startup(
+ struct snd_pcm_substream *substream)
+{
+ static const unsigned int rates[] = {
+ 48000,
+ };
+ static const struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+ };
+ static const unsigned int channels[] = {
+ 2,
+ };
+ static const struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+ };
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+ runtime->hw.channels_max = 2;
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+ return 0;
+}
+
+static const struct snd_soc_ops mt8183_da7219_max98357_ops = {
+ .startup = mt8183_da7219_max98357_startup,
+};
+
+static int
+mt8183_da7219_max98357_bt_sco_startup(
+ struct snd_pcm_substream *substream)
+{
+ static const unsigned int rates[] = {
+ 8000, 16000
+ };
+ static const struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+ };
+ static const unsigned int channels[] = {
+ 1,
+ };
+ static const struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+ };
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+ runtime->hw.channels_max = 1;
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+ return 0;
+}
+
+static const struct snd_soc_ops mt8183_da7219_max98357_bt_sco_ops = {
+ .startup = mt8183_da7219_max98357_bt_sco_startup,
+};
+
+/* 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(playback2,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback3,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL3")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture1,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture2,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture3,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL3")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture_mono,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback_hdmi,
+ DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* BE */
+SND_SOC_DAILINK_DEFS(primary_codec,
+ DAILINK_COMP_ARRAY(COMP_CPU("ADDA")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("mt6358-sound", "mt6358-snd-codec-aif1")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(pcm1,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(pcm2,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM 2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s0,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S0")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("bt-sco", "bt-sco-pcm")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s1,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s2,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S2")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(DA7219_DEV_NAME, DA7219_CODEC_DAI)),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s3_max98357a,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("max98357a", "HiFi"),
+ COMP_CODEC(DA7219_DEV_NAME, DA7219_CODEC_DAI)),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s3_rt1015,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(RT1015_DEV0_NAME, RT1015_CODEC_DAI),
+ COMP_CODEC(RT1015_DEV1_NAME, RT1015_CODEC_DAI),
+ COMP_CODEC(DA7219_DEV_NAME, DA7219_CODEC_DAI)),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s3_rt1015p,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("rt1015p", "HiFi"),
+ COMP_CODEC(DA7219_DEV_NAME, DA7219_CODEC_DAI)),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s5,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S5")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("bt-sco", "bt-sco-pcm")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(tdm,
+ DAILINK_COMP_ARRAY(COMP_CPU("TDM")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static int mt8183_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct mt8183_da7219_max98357_priv *priv =
+ snd_soc_card_get_drvdata(rtd->card);
+ int ret;
+
+ ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+ &priv->hdmi_jack, NULL, 0);
+ if (ret)
+ return ret;
+
+ return snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component,
+ &priv->hdmi_jack, NULL);
+}
+
+static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
+ /* FE */
+ {
+ .name = "Playback_1",
+ .stream_name = "Playback_1",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .ops = &mt8183_da7219_max98357_ops,
+ SND_SOC_DAILINK_REG(playback1),
+ },
+ {
+ .name = "Playback_2",
+ .stream_name = "Playback_2",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .ops = &mt8183_da7219_max98357_bt_sco_ops,
+ SND_SOC_DAILINK_REG(playback2),
+ },
+ {
+ .name = "Playback_3",
+ .stream_name = "Playback_3",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback3),
+ },
+ {
+ .name = "Capture_1",
+ .stream_name = "Capture_1",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .ops = &mt8183_da7219_max98357_bt_sco_ops,
+ SND_SOC_DAILINK_REG(capture1),
+ },
+ {
+ .name = "Capture_2",
+ .stream_name = "Capture_2",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture2),
+ },
+ {
+ .name = "Capture_3",
+ .stream_name = "Capture_3",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .ops = &mt8183_da7219_max98357_ops,
+ SND_SOC_DAILINK_REG(capture3),
+ },
+ {
+ .name = "Capture_Mono_1",
+ .stream_name = "Capture_Mono_1",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture_mono),
+ },
+ {
+ .name = "Playback_HDMI",
+ .stream_name = "Playback_HDMI",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback_hdmi),
+ },
+ /* BE */
+ {
+ .name = "Primary Codec",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(primary_codec),
+ },
+ {
+ .name = "PCM 1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(pcm1),
+ },
+ {
+ .name = "PCM 2",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(pcm2),
+ },
+ {
+ .name = "I2S0",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
+ .ops = &mt8183_mt6358_i2s_ops,
+ SND_SOC_DAILINK_REG(i2s0),
+ },
+ {
+ .name = "I2S1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
+ .ops = &mt8183_mt6358_i2s_ops,
+ SND_SOC_DAILINK_REG(i2s1),
+ },
+ {
+ .name = "I2S2",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
+ .ops = &mt8183_da7219_i2s_ops,
+ SND_SOC_DAILINK_REG(i2s2),
+ },
+ {
+ .name = "I2S3",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = "I2S5",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
+ .ops = &mt8183_mt6358_i2s_ops,
+ SND_SOC_DAILINK_REG(i2s5),
+ },
+ {
+ .name = "TDM",
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_IB_IF |
+ SND_SOC_DAIFMT_CBM_CFM,
+ .dpcm_playback = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
+ .ignore = 1,
+ .init = mt8183_da7219_max98357_hdmi_init,
+ SND_SOC_DAILINK_REG(tdm),
+ },
+};
+
+static int
+mt8183_da7219_max98357_headset_init(struct snd_soc_component *component)
+{
+ int ret;
+ struct mt8183_da7219_max98357_priv *priv =
+ snd_soc_card_get_drvdata(component->card);
+
+ /* Enable Headset and 4 Buttons Jack detection */
+ ret = snd_soc_card_jack_new(component->card,
+ "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_LINEOUT,
+ &priv->headset_jack,
+ NULL, 0);
+ if (ret)
+ return ret;
+
+ snd_jack_set_key(
+ priv->headset_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(
+ priv->headset_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ snd_jack_set_key(
+ priv->headset_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ snd_jack_set_key(
+ priv->headset_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+
+ da7219_aad_jack_det(component, &priv->headset_jack);
+
+ return 0;
+}
+
+static struct snd_soc_aux_dev mt8183_da7219_max98357_headset_dev = {
+ .dlc = COMP_EMPTY(),
+ .init = mt8183_da7219_max98357_headset_init,
+};
+
+static struct snd_soc_codec_conf mt6358_codec_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF("mt6358-sound"),
+ .name_prefix = "Mt6358",
+ },
+};
+
+static const struct snd_kcontrol_new mt8183_da7219_max98357_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speakers"),
+};
+
+static const
+struct snd_soc_dapm_widget mt8183_da7219_max98357_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Speakers", NULL),
+ SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL",
+ "aud_tdm_out_on", "aud_tdm_out_off"),
+};
+
+static const struct snd_soc_dapm_route mt8183_da7219_max98357_dapm_routes[] = {
+ {"Speakers", NULL, "Speaker"},
+ {"I2S Playback", NULL, "TDM_OUT_PINCTRL"},
+};
+
+static struct snd_soc_card mt8183_da7219_max98357_card = {
+ .name = "mt8183_da7219_max98357",
+ .owner = THIS_MODULE,
+ .controls = mt8183_da7219_max98357_snd_controls,
+ .num_controls = ARRAY_SIZE(mt8183_da7219_max98357_snd_controls),
+ .dapm_widgets = mt8183_da7219_max98357_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8183_da7219_max98357_dapm_widgets),
+ .dapm_routes = mt8183_da7219_max98357_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8183_da7219_max98357_dapm_routes),
+ .dai_link = mt8183_da7219_dai_links,
+ .num_links = ARRAY_SIZE(mt8183_da7219_dai_links),
+ .aux_dev = &mt8183_da7219_max98357_headset_dev,
+ .num_aux_devs = 1,
+ .codec_conf = mt6358_codec_conf,
+ .num_configs = ARRAY_SIZE(mt6358_codec_conf),
+};
+
+static struct snd_soc_codec_conf mt8183_da7219_rt1015_codec_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF("mt6358-sound"),
+ .name_prefix = "Mt6358",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME),
+ .name_prefix = "Left",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(RT1015_DEV1_NAME),
+ .name_prefix = "Right",
+ },
+};
+
+static const struct snd_kcontrol_new mt8183_da7219_rt1015_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const
+struct snd_soc_dapm_widget mt8183_da7219_rt1015_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+ SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL",
+ "aud_tdm_out_on", "aud_tdm_out_off"),
+};
+
+static const struct snd_soc_dapm_route mt8183_da7219_rt1015_dapm_routes[] = {
+ {"Left Spk", NULL, "Left SPO"},
+ {"Right Spk", NULL, "Right SPO"},
+ {"I2S Playback", NULL, "TDM_OUT_PINCTRL"},
+};
+
+static struct snd_soc_card mt8183_da7219_rt1015_card = {
+ .name = "mt8183_da7219_rt1015",
+ .owner = THIS_MODULE,
+ .controls = mt8183_da7219_rt1015_snd_controls,
+ .num_controls = ARRAY_SIZE(mt8183_da7219_rt1015_snd_controls),
+ .dapm_widgets = mt8183_da7219_rt1015_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8183_da7219_rt1015_dapm_widgets),
+ .dapm_routes = mt8183_da7219_rt1015_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8183_da7219_rt1015_dapm_routes),
+ .dai_link = mt8183_da7219_dai_links,
+ .num_links = ARRAY_SIZE(mt8183_da7219_dai_links),
+ .aux_dev = &mt8183_da7219_max98357_headset_dev,
+ .num_aux_devs = 1,
+ .codec_conf = mt8183_da7219_rt1015_codec_conf,
+ .num_configs = ARRAY_SIZE(mt8183_da7219_rt1015_codec_conf),
+};
+
+static struct snd_soc_card mt8183_da7219_rt1015p_card = {
+ .name = "mt8183_da7219_rt1015p",
+ .owner = THIS_MODULE,
+ .controls = mt8183_da7219_max98357_snd_controls,
+ .num_controls = ARRAY_SIZE(mt8183_da7219_max98357_snd_controls),
+ .dapm_widgets = mt8183_da7219_max98357_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8183_da7219_max98357_dapm_widgets),
+ .dapm_routes = mt8183_da7219_max98357_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8183_da7219_max98357_dapm_routes),
+ .dai_link = mt8183_da7219_dai_links,
+ .num_links = ARRAY_SIZE(mt8183_da7219_dai_links),
+ .aux_dev = &mt8183_da7219_max98357_headset_dev,
+ .num_aux_devs = 1,
+ .codec_conf = mt6358_codec_conf,
+ .num_configs = ARRAY_SIZE(mt6358_codec_conf),
+};
+
+static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card;
+ struct device_node *platform_node, *hdmi_codec;
+ struct snd_soc_dai_link *dai_link;
+ struct mt8183_da7219_max98357_priv *priv;
+ struct pinctrl *pinctrl;
+ const struct of_device_id *match;
+ int ret, i;
+
+ platform_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,platform", 0);
+ if (!platform_node) {
+ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev);
+ if (!match || !match->data)
+ return -EINVAL;
+
+ card = (struct snd_soc_card *)match->data;
+ card->dev = &pdev->dev;
+
+ hdmi_codec = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,hdmi-codec", 0);
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (strcmp(dai_link->name, "I2S3") == 0) {
+ if (card == &mt8183_da7219_max98357_card) {
+ dai_link->be_hw_params_fixup =
+ mt8183_i2s_hw_params_fixup;
+ dai_link->ops = &mt8183_da7219_i2s_ops;
+ dai_link->cpus = i2s3_max98357a_cpus;
+ dai_link->num_cpus =
+ ARRAY_SIZE(i2s3_max98357a_cpus);
+ dai_link->codecs = i2s3_max98357a_codecs;
+ dai_link->num_codecs =
+ ARRAY_SIZE(i2s3_max98357a_codecs);
+ dai_link->platforms = i2s3_max98357a_platforms;
+ dai_link->num_platforms =
+ ARRAY_SIZE(i2s3_max98357a_platforms);
+ } else if (card == &mt8183_da7219_rt1015_card) {
+ dai_link->be_hw_params_fixup =
+ mt8183_rt1015_i2s_hw_params_fixup;
+ dai_link->ops = &mt8183_da7219_rt1015_i2s_ops;
+ dai_link->cpus = i2s3_rt1015_cpus;
+ dai_link->num_cpus =
+ ARRAY_SIZE(i2s3_rt1015_cpus);
+ dai_link->codecs = i2s3_rt1015_codecs;
+ dai_link->num_codecs =
+ ARRAY_SIZE(i2s3_rt1015_codecs);
+ dai_link->platforms = i2s3_rt1015_platforms;
+ dai_link->num_platforms =
+ ARRAY_SIZE(i2s3_rt1015_platforms);
+ } else if (card == &mt8183_da7219_rt1015p_card) {
+ dai_link->be_hw_params_fixup =
+ mt8183_rt1015_i2s_hw_params_fixup;
+ dai_link->ops = &mt8183_da7219_i2s_ops;
+ dai_link->cpus = i2s3_rt1015p_cpus;
+ dai_link->num_cpus =
+ ARRAY_SIZE(i2s3_rt1015p_cpus);
+ dai_link->codecs = i2s3_rt1015p_codecs;
+ dai_link->num_codecs =
+ ARRAY_SIZE(i2s3_rt1015p_codecs);
+ dai_link->platforms = i2s3_rt1015p_platforms;
+ dai_link->num_platforms =
+ ARRAY_SIZE(i2s3_rt1015p_platforms);
+ }
+ }
+
+ if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0) {
+ dai_link->codecs->of_node = hdmi_codec;
+ dai_link->ignore = 0;
+ }
+
+ if (!dai_link->platforms->name)
+ dai_link->platforms->of_node = platform_node;
+ }
+
+ mt8183_da7219_max98357_headset_dev.dlc.of_node =
+ of_parse_phandle(pdev->dev.of_node,
+ "mediatek,headset-codec", 0);
+ if (!mt8183_da7219_max98357_headset_dev.dlc.of_node) {
+ dev_err(&pdev->dev,
+ "Property 'mediatek,headset-codec' missing/invalid\n");
+ return -EINVAL;
+ }
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ snd_soc_card_set_drvdata(card, priv);
+
+ pinctrl = devm_pinctrl_get_select(&pdev->dev, PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ dev_err(&pdev->dev, "%s failed to select default state %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+
+ of_node_put(platform_node);
+ of_node_put(hdmi_codec);
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt8183_da7219_max98357_dt_match[] = {
+ {
+ .compatible = "mediatek,mt8183_da7219_max98357",
+ .data = &mt8183_da7219_max98357_card,
+ },
+ {
+ .compatible = "mediatek,mt8183_da7219_rt1015",
+ .data = &mt8183_da7219_rt1015_card,
+ },
+ {
+ .compatible = "mediatek,mt8183_da7219_rt1015p",
+ .data = &mt8183_da7219_rt1015p_card,
+ },
+ {}
+};
+#endif
+
+static struct platform_driver mt8183_da7219_max98357_driver = {
+ .driver = {
+ .name = "mt8183_da7219",
+#ifdef CONFIG_OF
+ .of_match_table = mt8183_da7219_max98357_dt_match,
+#endif
+ },
+ .probe = mt8183_da7219_max98357_dev_probe,
+};
+
+module_platform_driver(mt8183_da7219_max98357_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8183-DA7219-MAX98357 ALSA SoC machine driver");
+MODULE_AUTHOR("Shunli Wang <shunli.wang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt8183_da7219_max98357 soc card");
diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-adda.c b/sound/soc/mediatek/mt8183/mt8183-dai-adda.c
new file mode 100644
index 000000000..2b758a18c
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-dai-adda.c
@@ -0,0 +1,509 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI ADDA Control
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include "mt8183-afe-common.h"
+#include "mt8183-interconnection.h"
+#include "mt8183-reg.h"
+
+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 {
+ 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 = 3,
+ MTK_AFE_ADDA_DL_RATE_22K = 4,
+ MTK_AFE_ADDA_DL_RATE_24K = 5,
+ MTK_AFE_ADDA_DL_RATE_32K = 6,
+ MTK_AFE_ADDA_DL_RATE_44K = 7,
+ MTK_AFE_ADDA_DL_RATE_48K = 8,
+ MTK_AFE_ADDA_DL_RATE_96K = 9,
+ MTK_AFE_ADDA_DL_RATE_192K = 10,
+};
+
+enum {
+ MTK_AFE_ADDA_UL_RATE_8K = 0,
+ MTK_AFE_ADDA_UL_RATE_16K = 1,
+ MTK_AFE_ADDA_UL_RATE_32K = 2,
+ MTK_AFE_ADDA_UL_RATE_48K = 3,
+ MTK_AFE_ADDA_UL_RATE_96K = 4,
+ MTK_AFE_ADDA_UL_RATE_192K = 5,
+ MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
+};
+
+static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_DL_RATE_8K;
+ case 11025:
+ return MTK_AFE_ADDA_DL_RATE_11K;
+ case 12000:
+ return MTK_AFE_ADDA_DL_RATE_12K;
+ case 16000:
+ return MTK_AFE_ADDA_DL_RATE_16K;
+ case 22050:
+ return MTK_AFE_ADDA_DL_RATE_22K;
+ case 24000:
+ return MTK_AFE_ADDA_DL_RATE_24K;
+ case 32000:
+ return MTK_AFE_ADDA_DL_RATE_32K;
+ case 44100:
+ return MTK_AFE_ADDA_DL_RATE_44K;
+ case 48000:
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_DL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_DL_RATE_192K;
+ default:
+ dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ }
+}
+
+static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_UL_RATE_8K;
+ case 16000:
+ return MTK_AFE_ADDA_UL_RATE_16K;
+ case 32000:
+ return MTK_AFE_ADDA_UL_RATE_32K;
+ case 48000:
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_UL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_UL_RATE_192K;
+ default:
+ dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ }
+}
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN3, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN3, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN3,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN3,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN3,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN3,
+ I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN4, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN4, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN4, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN4, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN4, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN4, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN4,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN4,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN4,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN4,
+ I_PCM_2_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN4,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN4,
+ I_PCM_2_CAP_CH2, 1, 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 mt8183_afe_private *afe_priv = afe->platform_priv;
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* update setting to dmic */
+ if (afe_priv->mtkaif_dmic) {
+ /* mtkaif_rxif_data_mode = 1, dmic */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0,
+ 0x1, 0x1);
+
+ /* dmic mode, 3.25M*/
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0,
+ 0x0, 0xf << 20);
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,
+ 0x0, 0x1 << 5);
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,
+ 0x0, 0x3 << 14);
+
+ /* turn on dmic, ch1, ch2 */
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,
+ 0x1 << 1, 0x1 << 1);
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,
+ 0x3 << 21, 0x3 << 21);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(125, 135);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* mtkaif dmic */
+static const char * const mt8183_adda_off_on_str[] = {
+ "Off", "On"
+};
+
+static const struct soc_enum mt8183_adda_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8183_adda_off_on_str),
+ mt8183_adda_off_on_str),
+};
+
+static int mt8183_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 mt8183_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic;
+
+ return 0;
+}
+
+static int mt8183_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 mt8183_afe_private *afe_priv = afe->platform_priv;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
+ afe_priv->mtkaif_dmic = ucontrol->value.integer.value[0];
+
+ dev_info(afe->dev, "%s(), kcontrol name %s, mtkaif_dmic %d\n",
+ __func__, kcontrol->id.name, afe_priv->mtkaif_dmic);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new mtk_adda_controls[] = {
+ SOC_ENUM_EXT("MTKAIF_DMIC", mt8183_adda_enum[0],
+ mt8183_adda_dmic_get, mt8183_adda_dmic_set),
+};
+
+enum {
+ SUPPLY_SEQ_ADDA_AFE_ON,
+ SUPPLY_SEQ_ADDA_DL_ON,
+ SUPPLY_SEQ_ADDA_UL_ON,
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+ /* adda */
+ 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_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
+ AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON,
+ AFE_ADDA_DL_SRC2_CON0,
+ DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+ AFE_ADDA_UL_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_CLOCK_SUPPLY("aud_dac_clk"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_predis_clk"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_clk"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("mtkaif_26m_clk"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+ /* playback */
+ {"ADDA_DL_CH1", "DL1_CH1", "DL1"},
+ {"ADDA_DL_CH2", "DL1_CH1", "DL1"},
+ {"ADDA_DL_CH2", "DL1_CH2", "DL1"},
+
+ {"ADDA_DL_CH1", "DL2_CH1", "DL2"},
+ {"ADDA_DL_CH2", "DL2_CH1", "DL2"},
+ {"ADDA_DL_CH2", "DL2_CH2", "DL2"},
+
+ {"ADDA_DL_CH1", "DL3_CH1", "DL3"},
+ {"ADDA_DL_CH2", "DL3_CH1", "DL3"},
+ {"ADDA_DL_CH2", "DL3_CH2", "DL3"},
+
+ {"ADDA Playback", NULL, "ADDA_DL_CH1"},
+ {"ADDA Playback", NULL, "ADDA_DL_CH2"},
+
+ /* adda enable */
+ {"ADDA Playback", NULL, "ADDA Enable"},
+ {"ADDA Playback", NULL, "ADDA Playback Enable"},
+ {"ADDA Capture", NULL, "ADDA Enable"},
+ {"ADDA Capture", NULL, "ADDA Capture Enable"},
+
+ /* clk */
+ {"ADDA Playback", NULL, "mtkaif_26m_clk"},
+ {"ADDA Playback", NULL, "aud_dac_clk"},
+ {"ADDA Playback", NULL, "aud_dac_predis_clk"},
+
+ {"ADDA Capture", NULL, "mtkaif_26m_clk"},
+ {"ADDA Capture", NULL, "aud_adc_clk"},
+};
+
+static int set_mtkaif_rx(struct mtk_base_afe *afe)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ int delay_data;
+ int delay_cycle;
+
+ switch (afe_priv->mtkaif_protocol) {
+ case MT8183_MTKAIF_PROTOCOL_2_CLK_P2:
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x38);
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x39);
+ /* mtkaif_rxif_clkinv_adc inverse for calibration */
+ regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
+ 0x80010000);
+
+ 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_ADDA_MTKAIF_RX_CFG2,
+ MTKAIF_RXIF_DELAY_DATA_MASK_SFT,
+ delay_data << MTKAIF_RXIF_DELAY_DATA_SFT);
+
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_MTKAIF_RX_CFG2,
+ MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT,
+ delay_cycle << MTKAIF_RXIF_DELAY_CYCLE_SFT);
+ break;
+ case MT8183_MTKAIF_PROTOCOL_2:
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31);
+ regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
+ 0x00010000);
+ break;
+ case MT8183_MTKAIF_PROTOCOL_1:
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31);
+ regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x0);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* 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);
+ unsigned int rate = params_rate(params);
+
+ dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+ __func__, dai->id, substream->stream, rate);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ unsigned int dl_src2_con0 = 0;
+ unsigned int dl_src2_con1 = 0;
+
+ /* clean predistortion */
+ regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0);
+ regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0);
+
+ /* set sampling rate */
+ dl_src2_con0 = adda_dl_rate_transform(afe, rate) << 28;
+
+ /* set output mode */
+ switch (rate) {
+ case 192000:
+ dl_src2_con0 |= (0x1 << 24); /* UP_SAMPLING_RATE_X2 */
+ dl_src2_con0 |= 1 << 14;
+ break;
+ case 96000:
+ dl_src2_con0 |= (0x2 << 24); /* UP_SAMPLING_RATE_X4 */
+ dl_src2_con0 |= 1 << 14;
+ break;
+ default:
+ dl_src2_con0 |= (0x3 << 24); /* UP_SAMPLING_RATE_X8 */
+ break;
+ }
+
+ /* turn off mute function */
+ dl_src2_con0 |= (0x03 << 11);
+
+ /* set voice input data if input sample rate is 8k or 16k */
+ if (rate == 8000 || rate == 16000)
+ dl_src2_con0 |= 0x01 << 5;
+
+ /* SA suggest apply -0.3db to audio/speech path */
+ dl_src2_con1 = 0xf74f0000;
+
+ /* turn on down-link gain */
+ dl_src2_con0 = dl_src2_con0 | (0x01 << 1);
+
+ regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON0, dl_src2_con0);
+ regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON1, dl_src2_con1);
+
+ /* set sdm gain */
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_DL_SDM_DCCOMP_CON,
+ ATTGAIN_CTL_MASK_SFT,
+ AUDIO_SDM_LEVEL_NORMAL << ATTGAIN_CTL_SFT);
+ } else {
+ unsigned int voice_mode = 0;
+ unsigned int ul_src_con0 = 0; /* default value */
+
+ /* set mtkaif protocol */
+ set_mtkaif_rx(afe);
+
+ /* Using Internal ADC */
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_TOP_CON0,
+ 0x1 << 0,
+ 0x0 << 0);
+
+ 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;
+
+ /* 35Hz @ 48k */
+ regmap_write(afe->regmap, AFE_ADDA_IIR_COEF_02_01, 0x00000000);
+ regmap_write(afe->regmap, AFE_ADDA_IIR_COEF_04_03, 0x00003FB8);
+ regmap_write(afe->regmap, AFE_ADDA_IIR_COEF_06_05, 0x3FB80000);
+ regmap_write(afe->regmap, AFE_ADDA_IIR_COEF_08_07, 0x3FB80000);
+ regmap_write(afe->regmap, AFE_ADDA_IIR_COEF_10_09, 0x0000C048);
+
+ regmap_write(afe->regmap, AFE_ADDA_UL_SRC_CON0, ul_src_con0);
+
+ /* mtkaif_rxif_data_mode = 0, amic */
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_MTKAIF_RX_CFG0,
+ 0x1 << 0,
+ 0x0 << 0);
+ }
+
+ 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)
+
+#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 = MT8183_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,
+ },
+};
+
+int mt8183_dai_adda_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_adda_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+
+ dai->controls = mtk_adda_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_adda_controls);
+ dai->dapm_widgets = mtk_dai_adda_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+ dai->dapm_routes = mtk_dai_adda_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-hostless.c b/sound/soc/mediatek/mt8183/mt8183-dai-hostless.c
new file mode 100644
index 000000000..1667ad352
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-dai-hostless.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI Hostless Control
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include "mt8183-afe-common.h"
+
+/* dai component */
+static const struct snd_soc_dapm_route mtk_dai_hostless_routes[] = {
+ /* Hostless ADDA Loopback */
+ {"ADDA_DL_CH1", "ADDA_UL_CH1", "Hostless LPBK DL"},
+ {"ADDA_DL_CH1", "ADDA_UL_CH2", "Hostless LPBK DL"},
+ {"ADDA_DL_CH2", "ADDA_UL_CH1", "Hostless LPBK DL"},
+ {"ADDA_DL_CH2", "ADDA_UL_CH2", "Hostless LPBK DL"},
+ {"Hostless LPBK UL", NULL, "ADDA Capture"},
+
+ /* Hostless Speech */
+ {"ADDA_DL_CH1", "PCM_1_CAP_CH1", "Hostless Speech DL"},
+ {"ADDA_DL_CH2", "PCM_1_CAP_CH1", "Hostless Speech DL"},
+ {"ADDA_DL_CH2", "PCM_1_CAP_CH2", "Hostless Speech DL"},
+ {"ADDA_DL_CH1", "PCM_2_CAP_CH1", "Hostless Speech DL"},
+ {"ADDA_DL_CH2", "PCM_2_CAP_CH1", "Hostless Speech DL"},
+ {"ADDA_DL_CH2", "PCM_2_CAP_CH2", "Hostless Speech DL"},
+ {"PCM_1_PB_CH1", "ADDA_UL_CH1", "Hostless Speech DL"},
+ {"PCM_1_PB_CH2", "ADDA_UL_CH2", "Hostless Speech DL"},
+ {"PCM_2_PB_CH1", "ADDA_UL_CH1", "Hostless Speech DL"},
+ {"PCM_2_PB_CH2", "ADDA_UL_CH2", "Hostless Speech DL"},
+
+ {"Hostless Speech UL", NULL, "PCM 1 Capture"},
+ {"Hostless Speech UL", NULL, "PCM 2 Capture"},
+ {"Hostless Speech UL", NULL, "ADDA Capture"},
+};
+
+/* dai ops */
+static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ return snd_soc_set_runtime_hwparams(substream, afe->mtk_afe_hardware);
+}
+
+static const struct snd_soc_dai_ops mtk_dai_hostless_ops = {
+ .startup = mtk_dai_hostless_startup,
+};
+
+/* dai driver */
+#define MTK_HOSTLESS_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_HOSTLESS_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_hostless_driver[] = {
+ {
+ .name = "Hostless LPBK DAI",
+ .id = MT8183_DAI_HOSTLESS_LPBK,
+ .playback = {
+ .stream_name = "Hostless LPBK DL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Hostless LPBK UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+ {
+ .name = "Hostless Speech DAI",
+ .id = MT8183_DAI_HOSTLESS_SPEECH,
+ .playback = {
+ .stream_name = "Hostless Speech DL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Hostless Speech UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+};
+
+int mt8183_dai_hostless_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_hostless_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver);
+
+ dai->dapm_routes = mtk_dai_hostless_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes);
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c
new file mode 100644
index 000000000..138591d71
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c
@@ -0,0 +1,1083 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI I2S Control
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8183-afe-clk.h"
+#include "mt8183-afe-common.h"
+#include "mt8183-interconnection.h"
+#include "mt8183-reg.h"
+
+enum {
+ I2S_FMT_EIAJ = 0,
+ I2S_FMT_I2S = 1,
+};
+
+enum {
+ I2S_WLEN_16_BIT = 0,
+ I2S_WLEN_32_BIT = 1,
+};
+
+enum {
+ I2S_HD_NORMAL = 0,
+ I2S_HD_LOW_JITTER = 1,
+};
+
+enum {
+ I2S1_SEL_O28_O29 = 0,
+ I2S1_SEL_O03_O04 = 1,
+};
+
+enum {
+ I2S_IN_PAD_CONNSYS = 0,
+ I2S_IN_PAD_IO_MUX = 1,
+};
+
+struct mtk_afe_i2s_priv {
+ int id;
+ int rate; /* for determine which apll to use */
+ int low_jitter_en;
+
+ const char *share_property_name;
+ int share_i2s_id;
+
+ int mclk_id;
+ int mclk_rate;
+ int mclk_apll;
+
+ int use_eiaj;
+};
+
+static unsigned int get_i2s_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ I2S_WLEN_16_BIT : I2S_WLEN_32_BIT;
+}
+
+#define MTK_AFE_I2S0_KCONTROL_NAME "I2S0_HD_Mux"
+#define MTK_AFE_I2S1_KCONTROL_NAME "I2S1_HD_Mux"
+#define MTK_AFE_I2S2_KCONTROL_NAME "I2S2_HD_Mux"
+#define MTK_AFE_I2S3_KCONTROL_NAME "I2S3_HD_Mux"
+#define MTK_AFE_I2S5_KCONTROL_NAME "I2S5_HD_Mux"
+
+#define I2S0_HD_EN_W_NAME "I2S0_HD_EN"
+#define I2S1_HD_EN_W_NAME "I2S1_HD_EN"
+#define I2S2_HD_EN_W_NAME "I2S2_HD_EN"
+#define I2S3_HD_EN_W_NAME "I2S3_HD_EN"
+#define I2S5_HD_EN_W_NAME "I2S5_HD_EN"
+
+#define I2S0_MCLK_EN_W_NAME "I2S0_MCLK_EN"
+#define I2S1_MCLK_EN_W_NAME "I2S1_MCLK_EN"
+#define I2S2_MCLK_EN_W_NAME "I2S2_MCLK_EN"
+#define I2S3_MCLK_EN_W_NAME "I2S3_MCLK_EN"
+#define I2S5_MCLK_EN_W_NAME "I2S5_MCLK_EN"
+
+static int get_i2s_id_by_name(struct mtk_base_afe *afe,
+ const char *name)
+{
+ if (strncmp(name, "I2S0", 4) == 0)
+ return MT8183_DAI_I2S_0;
+ else if (strncmp(name, "I2S1", 4) == 0)
+ return MT8183_DAI_I2S_1;
+ else if (strncmp(name, "I2S2", 4) == 0)
+ return MT8183_DAI_I2S_2;
+ else if (strncmp(name, "I2S3", 4) == 0)
+ return MT8183_DAI_I2S_3;
+ else if (strncmp(name, "I2S5", 4) == 0)
+ return MT8183_DAI_I2S_5;
+ else
+ return -EINVAL;
+}
+
+static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe,
+ const char *name)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_i2s_id_by_name(afe, name);
+
+ if (dai_id < 0)
+ return NULL;
+
+ return afe_priv->dai_priv[dai_id];
+}
+
+/* low jitter control */
+static const char * const mt8183_i2s_hd_str[] = {
+ "Normal", "Low_Jitter"
+};
+
+static const struct soc_enum mt8183_i2s_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8183_i2s_hd_str),
+ mt8183_i2s_hd_str),
+};
+
+static int mt8183_i2s_hd_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name);
+
+ if (!i2s_priv) {
+ dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ ucontrol->value.integer.value[0] = i2s_priv->low_jitter_en;
+
+ return 0;
+}
+
+static int mt8183_i2s_hd_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int hd_en;
+
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
+ hd_en = ucontrol->value.integer.value[0];
+
+ dev_info(afe->dev, "%s(), kcontrol name %s, hd_en %d\n",
+ __func__, kcontrol->id.name, hd_en);
+
+ i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name);
+
+ if (!i2s_priv) {
+ dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ i2s_priv->low_jitter_en = hd_en;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new mtk_dai_i2s_controls[] = {
+ SOC_ENUM_EXT(MTK_AFE_I2S0_KCONTROL_NAME, mt8183_i2s_enum[0],
+ mt8183_i2s_hd_get, mt8183_i2s_hd_set),
+ SOC_ENUM_EXT(MTK_AFE_I2S1_KCONTROL_NAME, mt8183_i2s_enum[0],
+ mt8183_i2s_hd_get, mt8183_i2s_hd_set),
+ SOC_ENUM_EXT(MTK_AFE_I2S2_KCONTROL_NAME, mt8183_i2s_enum[0],
+ mt8183_i2s_hd_get, mt8183_i2s_hd_set),
+ SOC_ENUM_EXT(MTK_AFE_I2S3_KCONTROL_NAME, mt8183_i2s_enum[0],
+ mt8183_i2s_hd_get, mt8183_i2s_hd_set),
+ SOC_ENUM_EXT(MTK_AFE_I2S5_KCONTROL_NAME, mt8183_i2s_enum[0],
+ mt8183_i2s_hd_get, mt8183_i2s_hd_set),
+};
+
+/* dai component */
+/* interconnection */
+static const struct snd_kcontrol_new mtk_i2s3_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN0, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN0, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN0, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN0,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN0,
+ I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s3_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN1,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN1,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN1,
+ I_PCM_2_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN1,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN1,
+ I_PCM_2_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s1_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN28, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN28, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN28, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN28,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN28,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN28,
+ I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s1_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN29, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN29, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN29, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN29,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN29,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN29,
+ I_PCM_2_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN29,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN29,
+ I_PCM_2_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s5_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN30, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN30, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN30, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN30,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN30,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN30,
+ I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s5_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN31, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN31, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN31, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN31,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN31,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN31,
+ I_PCM_2_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN31,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN31,
+ I_PCM_2_CAP_CH2, 1, 0),
+};
+
+enum {
+ SUPPLY_SEQ_APLL,
+ SUPPLY_SEQ_I2S_MCLK_EN,
+ SUPPLY_SEQ_I2S_HD_EN,
+ SUPPLY_SEQ_I2S_EN,
+};
+
+static int mtk_apll_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (strcmp(w->name, APLL1_W_NAME) == 0)
+ mt8183_apll1_enable(afe);
+ else
+ mt8183_apll2_enable(afe);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (strcmp(w->name, APLL1_W_NAME) == 0)
+ mt8183_apll1_disable(afe);
+ else
+ mt8183_apll2_disable(afe);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+ if (!i2s_priv) {
+ dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8183_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ i2s_priv->mclk_rate = 0;
+ mt8183_mck_disable(afe, i2s_priv->mclk_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = {
+ SND_SOC_DAPM_MIXER("I2S1_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2s1_ch1_mix,
+ ARRAY_SIZE(mtk_i2s1_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2S1_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2s1_ch2_mix,
+ ARRAY_SIZE(mtk_i2s1_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("I2S3_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2s3_ch1_mix,
+ ARRAY_SIZE(mtk_i2s3_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2S3_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2s3_ch2_mix,
+ ARRAY_SIZE(mtk_i2s3_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("I2S5_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2s5_ch1_mix,
+ ARRAY_SIZE(mtk_i2s5_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2S5_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2s5_ch2_mix,
+ ARRAY_SIZE(mtk_i2s5_ch2_mix)),
+
+ /* i2s en*/
+ SND_SOC_DAPM_SUPPLY_S("I2S0_EN", SUPPLY_SEQ_I2S_EN,
+ AFE_I2S_CON, I2S_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S1_EN", SUPPLY_SEQ_I2S_EN,
+ AFE_I2S_CON1, I2S_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S2_EN", SUPPLY_SEQ_I2S_EN,
+ AFE_I2S_CON2, I2S_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S3_EN", SUPPLY_SEQ_I2S_EN,
+ AFE_I2S_CON3, I2S_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S5_EN", SUPPLY_SEQ_I2S_EN,
+ AFE_I2S_CON4, I2S5_EN_SFT, 0,
+ NULL, 0),
+ /* i2s hd en */
+ SND_SOC_DAPM_SUPPLY_S(I2S0_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+ AFE_I2S_CON, I2S1_HD_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S(I2S1_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+ AFE_I2S_CON1, I2S2_HD_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S(I2S2_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+ AFE_I2S_CON2, I2S3_HD_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S(I2S3_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+ AFE_I2S_CON3, I2S4_HD_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S(I2S5_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+ AFE_I2S_CON4, I2S5_HD_EN_SFT, 0,
+ NULL, 0),
+
+ /* i2s mclk en */
+ SND_SOC_DAPM_SUPPLY_S(I2S0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2S1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2S2_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2S3_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2S5_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* apll */
+ SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL,
+ SND_SOC_NOPM, 0, 0,
+ mtk_apll_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL,
+ SND_SOC_NOPM, 0, 0,
+ mtk_apll_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+
+ if (!i2s_priv) {
+ dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return 0;
+ }
+
+ if (i2s_priv->share_i2s_id < 0)
+ return 0;
+
+ return i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name);
+}
+
+static int mtk_afe_i2s_hd_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+
+ if (!i2s_priv) {
+ dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return 0;
+ }
+
+ if (get_i2s_id_by_name(afe, sink->name) ==
+ get_i2s_id_by_name(afe, source->name))
+ return i2s_priv->low_jitter_en;
+
+ /* check if share i2s need hd en */
+ if (i2s_priv->share_i2s_id < 0)
+ return 0;
+
+ if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name))
+ return i2s_priv->low_jitter_en;
+
+ return 0;
+}
+
+static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int cur_apll;
+ int i2s_need_apll;
+
+ i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+ if (!i2s_priv) {
+ dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return 0;
+ }
+
+ /* which apll */
+ cur_apll = mt8183_get_apll_by_name(afe, source->name);
+
+ /* choose APLL from i2s rate */
+ i2s_need_apll = mt8183_get_apll_by_rate(afe, i2s_priv->rate);
+
+ return (i2s_need_apll == cur_apll) ? 1 : 0;
+}
+
+static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+
+ if (!i2s_priv) {
+ dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return 0;
+ }
+
+ if (get_i2s_id_by_name(afe, sink->name) ==
+ get_i2s_id_by_name(afe, source->name))
+ return (i2s_priv->mclk_rate > 0) ? 1 : 0;
+
+ /* check if share i2s need mclk */
+ if (i2s_priv->share_i2s_id < 0)
+ return 0;
+
+ if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name))
+ return (i2s_priv->mclk_rate > 0) ? 1 : 0;
+
+ return 0;
+}
+
+static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int cur_apll;
+
+ i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+ if (!i2s_priv) {
+ dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return 0;
+ }
+
+ /* which apll */
+ cur_apll = mt8183_get_apll_by_name(afe, source->name);
+
+ return (i2s_priv->mclk_apll == cur_apll) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = {
+ /* i2s0 */
+ {"I2S0", NULL, "I2S0_EN"},
+ {"I2S0", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+ {"I2S0", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+ {"I2S0", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+ {"I2S0", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+
+ {"I2S0", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S0", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S0", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S0", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S0", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {I2S0_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {I2S0_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2S0", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S0", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S0", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S0", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S0", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2S0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2S0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+ /* i2s1 */
+ {"I2S1_CH1", "DL1_CH1", "DL1"},
+ {"I2S1_CH2", "DL1_CH2", "DL1"},
+
+ {"I2S1_CH1", "DL2_CH1", "DL2"},
+ {"I2S1_CH2", "DL2_CH2", "DL2"},
+
+ {"I2S1_CH1", "DL3_CH1", "DL3"},
+ {"I2S1_CH2", "DL3_CH2", "DL3"},
+
+ {"I2S1", NULL, "I2S1_CH1"},
+ {"I2S1", NULL, "I2S1_CH2"},
+
+ {"I2S1", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+ {"I2S1", NULL, "I2S1_EN"},
+ {"I2S1", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+ {"I2S1", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+ {"I2S1", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+
+ {"I2S1", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S1", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S1", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S1", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S1", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {I2S1_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {I2S1_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2S1", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S1", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S1", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S1", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S1", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2S1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2S1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+ /* i2s2 */
+ {"I2S2", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+ {"I2S2", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+ {"I2S2", NULL, "I2S2_EN"},
+ {"I2S2", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+ {"I2S2", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+
+ {"I2S2", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S2", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S2", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S2", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S2", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {I2S2_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {I2S2_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2S2", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S2", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S2", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S2", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S2", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2S2_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2S2_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+ /* i2s3 */
+ {"I2S3_CH1", "DL1_CH1", "DL1"},
+ {"I2S3_CH2", "DL1_CH2", "DL1"},
+
+ {"I2S3_CH1", "DL2_CH1", "DL2"},
+ {"I2S3_CH2", "DL2_CH2", "DL2"},
+
+ {"I2S3_CH1", "DL3_CH1", "DL3"},
+ {"I2S3_CH2", "DL3_CH2", "DL3"},
+
+ {"I2S3", NULL, "I2S3_CH1"},
+ {"I2S3", NULL, "I2S3_CH2"},
+
+ {"I2S3", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+ {"I2S3", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+ {"I2S3", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+ {"I2S3", NULL, "I2S3_EN"},
+ {"I2S3", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+
+ {"I2S3", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S3", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S3", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S3", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S3", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {I2S3_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {I2S3_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2S3", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S3", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S3", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S3", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S3", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2S3_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2S3_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+ /* i2s5 */
+ {"I2S5_CH1", "DL1_CH1", "DL1"},
+ {"I2S5_CH2", "DL1_CH2", "DL1"},
+
+ {"I2S5_CH1", "DL2_CH1", "DL2"},
+ {"I2S5_CH2", "DL2_CH2", "DL2"},
+
+ {"I2S5_CH1", "DL3_CH1", "DL3"},
+ {"I2S5_CH2", "DL3_CH2", "DL3"},
+
+ {"I2S5", NULL, "I2S5_CH1"},
+ {"I2S5", NULL, "I2S5_CH2"},
+
+ {"I2S5", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+ {"I2S5", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+ {"I2S5", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+ {"I2S5", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+ {"I2S5", NULL, "I2S5_EN"},
+
+ {"I2S5", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S5", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S5", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S5", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S5", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {I2S5_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {I2S5_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2S5", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S5", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S5", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S5", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S5", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2S5_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2S5_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+};
+
+/* dai ops */
+static int mtk_dai_i2s_config(struct mtk_base_afe *afe,
+ struct snd_pcm_hw_params *params,
+ int i2s_id)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[i2s_id];
+
+ unsigned int rate = params_rate(params);
+ unsigned int rate_reg = mt8183_rate_transform(afe->dev,
+ rate, i2s_id);
+ snd_pcm_format_t format = params_format(params);
+ unsigned int i2s_con = 0, fmt_con = I2S_FMT_I2S << I2S_FMT_SFT;
+ int ret = 0;
+
+ dev_info(afe->dev, "%s(), id %d, rate %d, format %d\n",
+ __func__,
+ i2s_id,
+ rate, format);
+
+ if (i2s_priv) {
+ i2s_priv->rate = rate;
+
+ if (i2s_priv->use_eiaj)
+ fmt_con = I2S_FMT_EIAJ << I2S_FMT_SFT;
+ } else {
+ dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ }
+
+ switch (i2s_id) {
+ case MT8183_DAI_I2S_0:
+ regmap_update_bits(afe->regmap, AFE_DAC_CON1,
+ I2S_MODE_MASK_SFT, rate_reg << I2S_MODE_SFT);
+ i2s_con = I2S_IN_PAD_IO_MUX << I2SIN_PAD_SEL_SFT;
+ i2s_con |= fmt_con;
+ i2s_con |= get_i2s_wlen(format) << I2S_WLEN_SFT;
+ regmap_update_bits(afe->regmap, AFE_I2S_CON,
+ 0xffffeffe, i2s_con);
+ break;
+ case MT8183_DAI_I2S_1:
+ i2s_con = I2S1_SEL_O28_O29 << I2S2_SEL_O03_O04_SFT;
+ i2s_con |= rate_reg << I2S2_OUT_MODE_SFT;
+ i2s_con |= fmt_con;
+ i2s_con |= get_i2s_wlen(format) << I2S2_WLEN_SFT;
+ regmap_update_bits(afe->regmap, AFE_I2S_CON1,
+ 0xffffeffe, i2s_con);
+ break;
+ case MT8183_DAI_I2S_2:
+ i2s_con = 8 << I2S3_UPDATE_WORD_SFT;
+ i2s_con |= rate_reg << I2S3_OUT_MODE_SFT;
+ i2s_con |= fmt_con;
+ i2s_con |= get_i2s_wlen(format) << I2S3_WLEN_SFT;
+ regmap_update_bits(afe->regmap, AFE_I2S_CON2,
+ 0xffffeffe, i2s_con);
+ break;
+ case MT8183_DAI_I2S_3:
+ i2s_con = rate_reg << I2S4_OUT_MODE_SFT;
+ i2s_con |= fmt_con;
+ i2s_con |= get_i2s_wlen(format) << I2S4_WLEN_SFT;
+ regmap_update_bits(afe->regmap, AFE_I2S_CON3,
+ 0xffffeffe, i2s_con);
+ break;
+ case MT8183_DAI_I2S_5:
+ i2s_con = rate_reg << I2S5_OUT_MODE_SFT;
+ i2s_con |= fmt_con;
+ i2s_con |= get_i2s_wlen(format) << I2S5_WLEN_SFT;
+ regmap_update_bits(afe->regmap, AFE_I2S_CON4,
+ 0xffffeffe, i2s_con);
+ break;
+ default:
+ dev_warn(afe->dev, "%s(), id %d not support\n",
+ __func__, i2s_id);
+ return -EINVAL;
+ }
+
+ /* set share i2s */
+ if (i2s_priv && i2s_priv->share_i2s_id >= 0)
+ ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id);
+
+ return ret;
+}
+
+static int mtk_dai_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ return mtk_dai_i2s_config(afe, params, dai->id);
+}
+
+static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[dai->id];
+ int apll;
+ int apll_rate;
+
+ if (!i2s_priv) {
+ dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ if (dir != SND_SOC_CLOCK_OUT) {
+ dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
+ return -EINVAL;
+ }
+
+ dev_info(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+ apll = mt8183_get_apll_by_rate(afe, freq);
+ apll_rate = mt8183_get_apll_rate(afe, apll);
+
+ if (freq > apll_rate) {
+ dev_warn(afe->dev, "%s(), freq > apll rate", __func__);
+ return -EINVAL;
+ }
+
+ if (apll_rate % freq != 0) {
+ dev_warn(afe->dev, "%s(), APLL cannot generate freq Hz",
+ __func__);
+ return -EINVAL;
+ }
+
+ i2s_priv->mclk_rate = freq;
+ i2s_priv->mclk_apll = apll;
+
+ if (i2s_priv->share_i2s_id > 0) {
+ struct mtk_afe_i2s_priv *share_i2s_priv;
+
+ share_i2s_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id];
+ if (!share_i2s_priv) {
+ dev_warn(afe->dev, "%s(), share_i2s_priv == NULL",
+ __func__);
+ return -EINVAL;
+ }
+
+ share_i2s_priv->mclk_rate = i2s_priv->mclk_rate;
+ share_i2s_priv->mclk_apll = i2s_priv->mclk_apll;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ switch (dai->id) {
+ case MT8183_DAI_I2S_0:
+ case MT8183_DAI_I2S_1:
+ case MT8183_DAI_I2S_2:
+ case MT8183_DAI_I2S_3:
+ case MT8183_DAI_I2S_5:
+ break;
+ default:
+ dev_warn(afe->dev, "%s(), id %d not support\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+ i2s_priv = afe_priv->dai_priv[dai->id];
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_LEFT_J:
+ i2s_priv->use_eiaj = 1;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ i2s_priv->use_eiaj = 0;
+ break;
+ default:
+ dev_warn(afe->dev, "%s(), DAI format %d not support\n",
+ __func__, fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_i2s_ops = {
+ .hw_params = mtk_dai_i2s_hw_params,
+ .set_sysclk = mtk_dai_i2s_set_sysclk,
+ .set_fmt = mtk_dai_i2s_set_fmt,
+};
+
+/* dai driver */
+#define MTK_I2S_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = {
+ {
+ .name = "I2S0",
+ .id = MT8183_DAI_I2S_0,
+ .capture = {
+ .stream_name = "I2S0",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_I2S_RATES,
+ .formats = MTK_I2S_FORMATS,
+ },
+ .ops = &mtk_dai_i2s_ops,
+ },
+ {
+ .name = "I2S1",
+ .id = MT8183_DAI_I2S_1,
+ .playback = {
+ .stream_name = "I2S1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_I2S_RATES,
+ .formats = MTK_I2S_FORMATS,
+ },
+ .ops = &mtk_dai_i2s_ops,
+ },
+ {
+ .name = "I2S2",
+ .id = MT8183_DAI_I2S_2,
+ .capture = {
+ .stream_name = "I2S2",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_I2S_RATES,
+ .formats = MTK_I2S_FORMATS,
+ },
+ .ops = &mtk_dai_i2s_ops,
+ },
+ {
+ .name = "I2S3",
+ .id = MT8183_DAI_I2S_3,
+ .playback = {
+ .stream_name = "I2S3",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_I2S_RATES,
+ .formats = MTK_I2S_FORMATS,
+ },
+ .ops = &mtk_dai_i2s_ops,
+ },
+ {
+ .name = "I2S5",
+ .id = MT8183_DAI_I2S_5,
+ .playback = {
+ .stream_name = "I2S5",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_I2S_RATES,
+ .formats = MTK_I2S_FORMATS,
+ },
+ .ops = &mtk_dai_i2s_ops,
+ },
+};
+
+/* this enum is merely for mtk_afe_i2s_priv declare */
+enum {
+ DAI_I2S0 = 0,
+ DAI_I2S1,
+ DAI_I2S2,
+ DAI_I2S3,
+ DAI_I2S5,
+ DAI_I2S_NUM,
+};
+
+static const struct mtk_afe_i2s_priv mt8183_i2s_priv[DAI_I2S_NUM] = {
+ [DAI_I2S0] = {
+ .id = MT8183_DAI_I2S_0,
+ .mclk_id = MT8183_I2S0_MCK,
+ .share_property_name = "i2s0-share",
+ .share_i2s_id = -1,
+ },
+ [DAI_I2S1] = {
+ .id = MT8183_DAI_I2S_1,
+ .mclk_id = MT8183_I2S1_MCK,
+ .share_property_name = "i2s1-share",
+ .share_i2s_id = -1,
+ },
+ [DAI_I2S2] = {
+ .id = MT8183_DAI_I2S_2,
+ .mclk_id = MT8183_I2S2_MCK,
+ .share_property_name = "i2s2-share",
+ .share_i2s_id = -1,
+ },
+ [DAI_I2S3] = {
+ .id = MT8183_DAI_I2S_3,
+ .mclk_id = MT8183_I2S3_MCK,
+ .share_property_name = "i2s3-share",
+ .share_i2s_id = -1,
+ },
+ [DAI_I2S5] = {
+ .id = MT8183_DAI_I2S_5,
+ .mclk_id = MT8183_I2S5_MCK,
+ .share_property_name = "i2s5-share",
+ .share_i2s_id = -1,
+ },
+};
+
+static int mt8183_dai_i2s_get_share(struct mtk_base_afe *afe)
+{
+ struct mt8183_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[mt8183_i2s_priv[i].id];
+ property_name = mt8183_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 mt8183_dai_i2s_set_priv(struct mtk_base_afe *afe)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int i;
+
+ for (i = 0; i < DAI_I2S_NUM; i++) {
+ i2s_priv = devm_kzalloc(afe->dev,
+ sizeof(struct mtk_afe_i2s_priv),
+ GFP_KERNEL);
+ if (!i2s_priv)
+ return -ENOMEM;
+
+ memcpy(i2s_priv, &mt8183_i2s_priv[i],
+ sizeof(struct mtk_afe_i2s_priv));
+
+ afe_priv->dai_priv[mt8183_i2s_priv[i].id] = i2s_priv;
+ }
+
+ return 0;
+}
+
+int mt8183_dai_i2s_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+ int ret;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_i2s_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver);
+
+ dai->controls = mtk_dai_i2s_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls);
+ dai->dapm_widgets = mtk_dai_i2s_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets);
+ dai->dapm_routes = mtk_dai_i2s_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes);
+
+ /* set all dai i2s private data */
+ ret = mt8183_dai_i2s_set_priv(afe);
+ if (ret)
+ return ret;
+
+ /* parse share i2s */
+ ret = mt8183_dai_i2s_get_share(afe);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c b/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c
new file mode 100644
index 000000000..bc3ba3228
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI I2S Control
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8183-afe-common.h"
+#include "mt8183-interconnection.h"
+#include "mt8183-reg.h"
+
+enum AUD_TX_LCH_RPT {
+ AUD_TX_LCH_RPT_NO_REPEAT = 0,
+ AUD_TX_LCH_RPT_REPEAT = 1
+};
+
+enum AUD_VBT_16K_MODE {
+ AUD_VBT_16K_MODE_DISABLE = 0,
+ AUD_VBT_16K_MODE_ENABLE = 1
+};
+
+enum AUD_EXT_MODEM {
+ AUD_EXT_MODEM_SELECT_INTERNAL = 0,
+ AUD_EXT_MODEM_SELECT_EXTERNAL = 1
+};
+
+enum AUD_PCM_SYNC_TYPE {
+ /* bck sync length = 1 */
+ AUD_PCM_ONE_BCK_CYCLE_SYNC = 0,
+ /* bck sync length = PCM_INTF_CON1[9:13] */
+ AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1
+};
+
+enum AUD_BT_MODE {
+ AUD_BT_MODE_DUAL_MIC_ON_TX = 0,
+ AUD_BT_MODE_SINGLE_MIC_ON_TX = 1
+};
+
+enum AUD_PCM_AFIFO_SRC {
+ /* slave mode & external modem uses different crystal */
+ AUD_PCM_AFIFO_ASRC = 0,
+ /* slave mode & external modem uses the same crystal */
+ AUD_PCM_AFIFO_AFIFO = 1
+};
+
+enum AUD_PCM_CLOCK_SOURCE {
+ AUD_PCM_CLOCK_MASTER_MODE = 0,
+ AUD_PCM_CLOCK_SLAVE_MODE = 1
+};
+
+enum AUD_PCM_WLEN {
+ AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0,
+ AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1
+};
+
+enum AUD_PCM_MODE {
+ AUD_PCM_MODE_PCM_MODE_8K = 0,
+ AUD_PCM_MODE_PCM_MODE_16K = 1,
+ AUD_PCM_MODE_PCM_MODE_32K = 2,
+ AUD_PCM_MODE_PCM_MODE_48K = 3,
+};
+
+enum AUD_PCM_FMT {
+ AUD_PCM_FMT_I2S = 0,
+ AUD_PCM_FMT_EIAJ = 1,
+ AUD_PCM_FMT_PCM_MODE_A = 2,
+ AUD_PCM_FMT_PCM_MODE_B = 3
+};
+
+enum AUD_BCLK_OUT_INV {
+ AUD_BCLK_OUT_INV_NO_INVERSE = 0,
+ AUD_BCLK_OUT_INV_INVERSE = 1
+};
+
+enum AUD_PCM_EN {
+ AUD_PCM_EN_DISABLE = 0,
+ AUD_PCM_EN_ENABLE = 1
+};
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN7,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN7,
+ I_DL2_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN8,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN8,
+ I_DL2_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN27,
+ I_DL1_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN17,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN17,
+ I_DL2_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN18,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN18,
+ I_DL2_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN24,
+ I_DL1_CH1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_1_playback_ch1_mix,
+ ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)),
+ SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_1_playback_ch2_mix,
+ ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)),
+ SND_SOC_DAPM_MIXER("PCM_1_PB_CH4", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_1_playback_ch4_mix,
+ ARRAY_SIZE(mtk_pcm_1_playback_ch4_mix)),
+ SND_SOC_DAPM_MIXER("PCM_2_PB_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_2_playback_ch1_mix,
+ ARRAY_SIZE(mtk_pcm_2_playback_ch1_mix)),
+ SND_SOC_DAPM_MIXER("PCM_2_PB_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_2_playback_ch2_mix,
+ ARRAY_SIZE(mtk_pcm_2_playback_ch2_mix)),
+ SND_SOC_DAPM_MIXER("PCM_2_PB_CH4", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_2_playback_ch4_mix,
+ ARRAY_SIZE(mtk_pcm_2_playback_ch4_mix)),
+
+ SND_SOC_DAPM_SUPPLY("PCM_1_EN", PCM_INTF_CON1, PCM_EN_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("PCM_2_EN", PCM2_INTF_CON, PCM2_EN_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_INPUT("MD1_TO_AFE"),
+ SND_SOC_DAPM_INPUT("MD2_TO_AFE"),
+ SND_SOC_DAPM_OUTPUT("AFE_TO_MD1"),
+ SND_SOC_DAPM_OUTPUT("AFE_TO_MD2"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+ {"PCM 1 Playback", NULL, "PCM_1_PB_CH1"},
+ {"PCM 1 Playback", NULL, "PCM_1_PB_CH2"},
+ {"PCM 1 Playback", NULL, "PCM_1_PB_CH4"},
+ {"PCM 2 Playback", NULL, "PCM_2_PB_CH1"},
+ {"PCM 2 Playback", NULL, "PCM_2_PB_CH2"},
+ {"PCM 2 Playback", NULL, "PCM_2_PB_CH4"},
+
+ {"PCM 1 Playback", NULL, "PCM_1_EN"},
+ {"PCM 2 Playback", NULL, "PCM_2_EN"},
+ {"PCM 1 Capture", NULL, "PCM_1_EN"},
+ {"PCM 2 Capture", NULL, "PCM_2_EN"},
+
+ {"AFE_TO_MD1", NULL, "PCM 2 Playback"},
+ {"AFE_TO_MD2", NULL, "PCM 1 Playback"},
+ {"PCM 2 Capture", NULL, "MD1_TO_AFE"},
+ {"PCM 1 Capture", NULL, "MD2_TO_AFE"},
+
+ {"PCM_1_PB_CH1", "DL2_CH1", "DL2"},
+ {"PCM_1_PB_CH2", "DL2_CH2", "DL2"},
+ {"PCM_1_PB_CH4", "DL1_CH1", "DL1"},
+ {"PCM_2_PB_CH1", "DL2_CH1", "DL2"},
+ {"PCM_2_PB_CH2", "DL2_CH2", "DL2"},
+ {"PCM_2_PB_CH4", "DL1_CH1", "DL1"},
+};
+
+/* dai ops */
+static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ unsigned int rate = params_rate(params);
+ unsigned int rate_reg = mt8183_rate_transform(afe->dev, rate, dai->id);
+ unsigned int pcm_con = 0;
+
+ dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d, rate_reg %d, widget active p %d, c %d\n",
+ __func__,
+ dai->id,
+ substream->stream,
+ rate,
+ rate_reg,
+ dai->playback_widget->active,
+ dai->capture_widget->active);
+
+ if (dai->playback_widget->active || dai->capture_widget->active)
+ return 0;
+
+ switch (dai->id) {
+ case MT8183_DAI_PCM_1:
+ pcm_con |= AUD_BCLK_OUT_INV_NO_INVERSE << PCM_BCLK_OUT_INV_SFT;
+ pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT;
+ pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT;
+ pcm_con |= AUD_EXT_MODEM_SELECT_INTERNAL << PCM_EXT_MODEM_SFT;
+ pcm_con |= 0 << PCM_SYNC_LENGTH_SFT;
+ pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT;
+ pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT;
+ pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT;
+ pcm_con |= AUD_PCM_CLOCK_SLAVE_MODE << PCM_SLAVE_SFT;
+ pcm_con |= rate_reg << PCM_MODE_SFT;
+ pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM_FMT_SFT;
+
+ regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+ 0xfffffffe, pcm_con);
+ break;
+ case MT8183_DAI_PCM_2:
+ pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM2_TX_LCH_RPT_SFT;
+ pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM2_VBT_16K_MODE_SFT;
+ pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM2_BT_MODE_SFT;
+ pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM2_AFIFO_SFT;
+ pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM2_WLEN_SFT;
+ pcm_con |= rate_reg << PCM2_MODE_SFT;
+ pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM2_FMT_SFT;
+
+ regmap_update_bits(afe->regmap, PCM2_INTF_CON,
+ 0xfffffffe, pcm_con);
+ break;
+ default:
+ dev_warn(afe->dev, "%s(), id %d not support\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
+ .hw_params = mtk_dai_pcm_hw_params,
+};
+
+/* dai driver */
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 |\
+ SNDRV_PCM_RATE_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
+ {
+ .name = "PCM 1",
+ .id = MT8183_DAI_PCM_1,
+ .playback = {
+ .stream_name = "PCM 1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .capture = {
+ .stream_name = "PCM 1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_dai_pcm_ops,
+ .symmetric_rates = 1,
+ .symmetric_samplebits = 1,
+ },
+ {
+ .name = "PCM 2",
+ .id = MT8183_DAI_PCM_2,
+ .playback = {
+ .stream_name = "PCM 2 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .capture = {
+ .stream_name = "PCM 2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_dai_pcm_ops,
+ .symmetric_rates = 1,
+ .symmetric_samplebits = 1,
+ },
+};
+
+int mt8183_dai_pcm_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_pcm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+
+ dai->dapm_widgets = mtk_dai_pcm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+ dai->dapm_routes = mtk_dai_pcm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c
new file mode 100644
index 000000000..0d69cf440
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c
@@ -0,0 +1,748 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI TDM Control
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8183-afe-clk.h"
+#include "mt8183-afe-common.h"
+#include "mt8183-interconnection.h"
+#include "mt8183-reg.h"
+
+struct mtk_afe_tdm_priv {
+ int bck_id;
+ int bck_rate;
+ int tdm_out_mode;
+ int bck_invert;
+ int lck_invert;
+ int mclk_id;
+ int mclk_multiple; /* according to sample rate */
+ int mclk_rate;
+ int mclk_apll;
+};
+
+enum {
+ TDM_OUT_I2S = 0,
+ TDM_OUT_TDM = 1,
+};
+
+enum {
+ TDM_BCK_NON_INV = 0,
+ TDM_BCK_INV = 1,
+};
+
+enum {
+ TDM_LCK_NON_INV = 0,
+ TDM_LCK_INV = 1,
+};
+
+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 {
+ HDMI_BIT_WIDTH_16_BIT = 0,
+ HDMI_BIT_WIDTH_32_BIT = 1,
+};
+
+static unsigned int get_hdmi_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ HDMI_BIT_WIDTH_16_BIT : HDMI_BIT_WIDTH_32_BIT;
+}
+
+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_tdm_ch_fixup(unsigned int channels)
+{
+ if (channels > 4)
+ return 8;
+ else if (channels > 2)
+ return 4;
+ else
+ return 2;
+}
+
+static unsigned int get_tdm_ch_per_sdata(unsigned int mode,
+ unsigned int channels)
+{
+ if (mode == TDM_OUT_TDM)
+ return get_tdm_ch_fixup(channels);
+ else
+ return 2;
+}
+
+/* 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);
+
+enum {
+ SUPPLY_SEQ_APLL,
+ SUPPLY_SEQ_TDM_MCK_EN,
+ SUPPLY_SEQ_TDM_BCK_EN,
+};
+
+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 mt8183_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM];
+
+ dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8183_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mt8183_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 mt8183_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM];
+
+ dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8183_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ tdm_priv->mclk_rate = 0;
+ mt8183_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_CLOCK_SUPPLY("aud_tdm_clk"),
+
+ 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),
+};
+
+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 mt8183_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM];
+ int cur_apll;
+
+ /* which apll */
+ cur_apll = mt8183_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"},
+
+ {"TDM", NULL, "HDMI_CH0_MUX"},
+ {"TDM", NULL, "HDMI_CH1_MUX"},
+ {"TDM", NULL, "HDMI_CH2_MUX"},
+ {"TDM", NULL, "HDMI_CH3_MUX"},
+ {"TDM", NULL, "HDMI_CH4_MUX"},
+ {"TDM", NULL, "HDMI_CH5_MUX"},
+ {"TDM", NULL, "HDMI_CH6_MUX"},
+ {"TDM", NULL, "HDMI_CH7_MUX"},
+
+ {"TDM", NULL, "aud_tdm_clk"},
+ {"TDM", NULL, "TDM_BCK"},
+ {"TDM_BCK", NULL, "TDM_MCK"},
+ {"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
+ {"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
+};
+
+/* dai ops */
+static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
+ struct mtk_afe_tdm_priv *tdm_priv,
+ int freq)
+{
+ int apll;
+ int apll_rate;
+
+ apll = mt8183_get_apll_by_rate(afe, freq);
+ apll_rate = mt8183_get_apll_rate(afe, apll);
+
+ if (!freq || freq > apll_rate) {
+ dev_warn(afe->dev,
+ "%s(), freq(%d Hz) invalid\n", __func__, freq);
+ return -EINVAL;
+ }
+
+ if (apll_rate % freq != 0) {
+ dev_warn(afe->dev,
+ "%s(), APLL cannot generate %d Hz", __func__, freq);
+ 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 mt8183_afe_private *afe_priv = afe->platform_priv;
+ int tdm_id = dai->id;
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id];
+ unsigned int tdm_out_mode = tdm_priv->tdm_out_mode;
+ unsigned int rate = params_rate(params);
+ unsigned int channels = params_channels(params);
+ unsigned int out_channels_per_sdata =
+ get_tdm_ch_per_sdata(tdm_out_mode, channels);
+ snd_pcm_format_t format = params_format(params);
+ unsigned int tdm_con = 0;
+
+ /* 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 *
+ out_channels_per_sdata *
+ snd_pcm_format_physical_width(format);
+
+ if (tdm_priv->bck_rate > tdm_priv->mclk_rate)
+ dev_warn(afe->dev, "%s(), bck_rate > mclk_rate rate", __func__);
+
+ if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0)
+ dev_warn(afe->dev, "%s(), bck cannot generate", __func__);
+
+ 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);
+ dev_info(afe->dev, "%s(), out_channels_per_sdata = %d\n",
+ __func__, out_channels_per_sdata);
+
+ /* set tdm */
+ if (tdm_priv->bck_invert)
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON3,
+ BCK_INVERSE_MASK_SFT,
+ 0x1 << BCK_INVERSE_SFT);
+
+ if (tdm_priv->lck_invert)
+ tdm_con |= 1 << LRCK_INVERSE_SFT;
+
+ if (tdm_priv->tdm_out_mode == TDM_OUT_I2S) {
+ tdm_con |= 1 << DELAY_DATA_SFT;
+ tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT;
+ } else if (tdm_priv->tdm_out_mode == TDM_OUT_TDM) {
+ tdm_con |= 0 << DELAY_DATA_SFT;
+ tdm_con |= 0 << LRCK_TDM_WIDTH_SFT;
+ }
+
+ tdm_con |= 1 << LEFT_ALIGN_SFT;
+ tdm_con |= get_tdm_wlen(format) << WLEN_SFT;
+ tdm_con |= get_tdm_ch(out_channels_per_sdata) << CHANNEL_NUM_SFT;
+ tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT;
+ regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con);
+
+ if (out_channels_per_sdata == 2) {
+ 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;
+ }
+ } else {
+ 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;
+ }
+
+ regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con);
+
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ AFE_HDMI_OUT_CH_NUM_MASK_SFT,
+ channels << AFE_HDMI_OUT_CH_NUM_SFT);
+
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ AFE_HDMI_OUT_BIT_WIDTH_MASK_SFT,
+ get_hdmi_wlen(format) << AFE_HDMI_OUT_BIT_WIDTH_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);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ /* enable Out control */
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ AFE_HDMI_OUT_ON_MASK_SFT,
+ 0x1 << AFE_HDMI_OUT_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 Out control */
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ AFE_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 mt8183_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
+
+ if (!tdm_priv) {
+ dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ if (dir != SND_SOC_CLOCK_OUT) {
+ dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
+ return -EINVAL;
+ }
+
+ dev_info(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+ return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
+}
+
+static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
+
+ if (!tdm_priv) {
+ dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ /* DAI mode*/
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ tdm_priv->tdm_out_mode = TDM_OUT_I2S;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ tdm_priv->tdm_out_mode = TDM_OUT_TDM;
+ break;
+ default:
+ tdm_priv->tdm_out_mode = TDM_OUT_I2S;
+ }
+
+ /* DAI clock inversion*/
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ tdm_priv->bck_invert = TDM_BCK_NON_INV;
+ tdm_priv->lck_invert = TDM_LCK_NON_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ tdm_priv->bck_invert = TDM_BCK_NON_INV;
+ tdm_priv->lck_invert = TDM_LCK_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ tdm_priv->bck_invert = TDM_BCK_INV;
+ tdm_priv->lck_invert = TDM_LCK_NON_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ default:
+ tdm_priv->bck_invert = TDM_BCK_INV;
+ tdm_priv->lck_invert = TDM_LCK_INV;
+ break;
+ }
+
+ return 0;
+}
+
+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,
+ .set_fmt = mtk_dai_tdm_set_fmt,
+};
+
+/* 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 = MT8183_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,
+ },
+};
+
+int mt8183_dai_tdm_register(struct mtk_base_afe *afe)
+{
+ struct mt8183_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv;
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_tdm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
+
+ dai->dapm_widgets = mtk_dai_tdm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
+ dai->dapm_routes = mtk_dai_tdm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
+
+ tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
+ GFP_KERNEL);
+ if (!tdm_priv)
+ return -ENOMEM;
+
+ tdm_priv->mclk_multiple = 128;
+ tdm_priv->bck_id = MT8183_I2S4_BCK;
+ tdm_priv->mclk_id = MT8183_I2S4_MCK;
+
+ afe_priv->dai_priv[MT8183_DAI_TDM] = tdm_priv;
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8183/mt8183-interconnection.h b/sound/soc/mediatek/mt8183/mt8183-interconnection.h
new file mode 100644
index 000000000..6332f5f3e
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-interconnection.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Mediatek MT8183 audio driver interconnection definition
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef _MT8183_INTERCONNECTION_H_
+#define _MT8183_INTERCONNECTION_H_
+
+#define I_I2S0_CH1 0
+#define I_I2S0_CH2 1
+#define I_ADDA_UL_CH1 3
+#define I_ADDA_UL_CH2 4
+#define I_DL1_CH1 5
+#define I_DL1_CH2 6
+#define I_DL2_CH1 7
+#define I_DL2_CH2 8
+#define I_PCM_1_CAP_CH1 9
+#define I_GAIN1_OUT_CH1 10
+#define I_GAIN1_OUT_CH2 11
+#define I_GAIN2_OUT_CH1 12
+#define I_GAIN2_OUT_CH2 13
+#define I_PCM_2_CAP_CH1 14
+#define I_PCM_2_CAP_CH2 21
+#define I_PCM_1_CAP_CH2 22
+#define I_DL3_CH1 23
+#define I_DL3_CH2 24
+#define I_I2S2_CH1 25
+#define I_I2S2_CH2 26
+
+#endif
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
new file mode 100644
index 000000000..14ce8b935
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
@@ -0,0 +1,765 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8183-mt6358.c --
+// MT8183-MT6358-TS3A227-MAX98357 ALSA SoC machine driver
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: Shunli Wang <shunli.wang@mediatek.com>
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../../codecs/rt1015.h"
+#include "../../codecs/ts3a227e.h"
+#include "mt8183-afe-common.h"
+
+#define RT1015_CODEC_DAI "rt1015-aif"
+#define RT1015_DEV0_NAME "rt1015.6-0028"
+#define RT1015_DEV1_NAME "rt1015.6-0029"
+
+enum PINCTRL_PIN_STATE {
+ PIN_STATE_DEFAULT = 0,
+ PIN_TDM_OUT_ON,
+ PIN_TDM_OUT_OFF,
+ PIN_WOV,
+ PIN_STATE_MAX
+};
+
+static const char * const mt8183_pin_str[PIN_STATE_MAX] = {
+ "default", "aud_tdm_out_on", "aud_tdm_out_off", "wov",
+};
+
+struct mt8183_mt6358_ts3a227_max98357_priv {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pin_states[PIN_STATE_MAX];
+ struct snd_soc_jack headset_jack, hdmi_jack;
+};
+
+static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ unsigned int rate = params_rate(params);
+ unsigned int mclk_fs_ratio = 128;
+ unsigned int mclk_fs = rate * mclk_fs_ratio;
+
+ return snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0),
+ 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8183_mt6358_i2s_ops = {
+ .hw_params = mt8183_mt6358_i2s_hw_params,
+};
+
+static int
+mt8183_mt6358_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ unsigned int rate = params_rate(params);
+ unsigned int mclk_fs_ratio = 128;
+ unsigned int mclk_fs = rate * mclk_fs_ratio;
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dai *codec_dai;
+ int ret, i;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
+ if (ret < 0) {
+ dev_err(card->dev, "failed to set bclk ratio\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,
+ rate * 64, rate * 256);
+ if (ret < 0) {
+ dev_err(card->dev, "failed to set pll\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL,
+ rate * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "failed to set sysclk\n");
+ return ret;
+ }
+ }
+
+ return snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0),
+ 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8183_mt6358_rt1015_i2s_ops = {
+ .hw_params = mt8183_mt6358_rt1015_i2s_hw_params,
+};
+
+static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ dev_dbg(rtd->dev, "%s(), fix format to 32bit\n", __func__);
+
+ /* fix BE i2s format to 32bit, clean param mask first */
+ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
+ 0, SNDRV_PCM_FORMAT_LAST);
+
+ params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
+ return 0;
+}
+
+static int mt8183_rt1015_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ dev_dbg(rtd->dev, "%s(), fix format to 32bit\n", __func__);
+
+ /* fix BE i2s format to 32bit, clean param mask first */
+ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
+ 0, SNDRV_PCM_FORMAT_LAST);
+
+ params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+ return 0;
+}
+
+static int
+mt8183_mt6358_ts3a227_max98357_bt_sco_startup(
+ struct snd_pcm_substream *substream)
+{
+ static const unsigned int rates[] = {
+ 8000, 16000
+ };
+ static const struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+ };
+ static const unsigned int channels[] = {
+ 1,
+ };
+ static const struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+ };
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+ runtime->hw.channels_max = 1;
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+ return 0;
+}
+
+static const struct snd_soc_ops mt8183_mt6358_ts3a227_max98357_bt_sco_ops = {
+ .startup = mt8183_mt6358_ts3a227_max98357_bt_sco_startup,
+};
+
+/* 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(playback2,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback3,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL3")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture1,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture2,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture3,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL3")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture_mono,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_1")),
+ 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(wake_on_voice,
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* BE */
+SND_SOC_DAILINK_DEFS(primary_codec,
+ DAILINK_COMP_ARRAY(COMP_CPU("ADDA")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("mt6358-sound", "mt6358-snd-codec-aif1")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(pcm1,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(pcm2,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM 2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s0,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S0")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("bt-sco", "bt-sco-pcm")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s1,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s2,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s3_max98357a,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("max98357a", "HiFi")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s3_rt1015,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(RT1015_DEV0_NAME, RT1015_CODEC_DAI),
+ COMP_CODEC(RT1015_DEV1_NAME, RT1015_CODEC_DAI)),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s5,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2S5")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("bt-sco", "bt-sco-pcm")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(tdm,
+ DAILINK_COMP_ARRAY(COMP_CPU("TDM")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static int mt8183_mt6358_tdm_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct mt8183_mt6358_ts3a227_max98357_priv *priv =
+ snd_soc_card_get_drvdata(rtd->card);
+ int ret;
+
+ if (IS_ERR(priv->pin_states[PIN_TDM_OUT_ON]))
+ return PTR_ERR(priv->pin_states[PIN_TDM_OUT_ON]);
+
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_TDM_OUT_ON]);
+ if (ret)
+ dev_err(rtd->card->dev, "%s failed to select state %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static void mt8183_mt6358_tdm_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct mt8183_mt6358_ts3a227_max98357_priv *priv =
+ snd_soc_card_get_drvdata(rtd->card);
+ int ret;
+
+ if (IS_ERR(priv->pin_states[PIN_TDM_OUT_OFF]))
+ return;
+
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_TDM_OUT_OFF]);
+ if (ret)
+ dev_err(rtd->card->dev, "%s failed to select state %d\n",
+ __func__, ret);
+}
+
+static struct snd_soc_ops mt8183_mt6358_tdm_ops = {
+ .startup = mt8183_mt6358_tdm_startup,
+ .shutdown = mt8183_mt6358_tdm_shutdown,
+};
+
+static int
+mt8183_mt6358_ts3a227_max98357_wov_startup(
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_card *card = rtd->card;
+ struct mt8183_mt6358_ts3a227_max98357_priv *priv =
+ snd_soc_card_get_drvdata(card);
+
+ return pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_WOV]);
+}
+
+static void
+mt8183_mt6358_ts3a227_max98357_wov_shutdown(
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_card *card = rtd->card;
+ struct mt8183_mt6358_ts3a227_max98357_priv *priv =
+ snd_soc_card_get_drvdata(card);
+ int ret;
+
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_STATE_DEFAULT]);
+ if (ret)
+ dev_err(card->dev, "%s failed to select state %d\n",
+ __func__, ret);
+}
+
+static const struct snd_soc_ops mt8183_mt6358_ts3a227_max98357_wov_ops = {
+ .startup = mt8183_mt6358_ts3a227_max98357_wov_startup,
+ .shutdown = mt8183_mt6358_ts3a227_max98357_wov_shutdown,
+};
+
+static int
+mt8183_mt6358_ts3a227_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct mt8183_mt6358_ts3a227_max98357_priv *priv =
+ snd_soc_card_get_drvdata(rtd->card);
+ int ret;
+
+ ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+ &priv->hdmi_jack, NULL, 0);
+ if (ret)
+ return ret;
+
+ return snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component,
+ &priv->hdmi_jack, NULL);
+}
+
+static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
+ /* FE */
+ {
+ .name = "Playback_1",
+ .stream_name = "Playback_1",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback1),
+ },
+ {
+ .name = "Playback_2",
+ .stream_name = "Playback_2",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .ops = &mt8183_mt6358_ts3a227_max98357_bt_sco_ops,
+ SND_SOC_DAILINK_REG(playback2),
+ },
+ {
+ .name = "Playback_3",
+ .stream_name = "Playback_3",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback3),
+ },
+ {
+ .name = "Capture_1",
+ .stream_name = "Capture_1",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .ops = &mt8183_mt6358_ts3a227_max98357_bt_sco_ops,
+ SND_SOC_DAILINK_REG(capture1),
+ },
+ {
+ .name = "Capture_2",
+ .stream_name = "Capture_2",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture2),
+ },
+ {
+ .name = "Capture_3",
+ .stream_name = "Capture_3",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture3),
+ },
+ {
+ .name = "Capture_Mono_1",
+ .stream_name = "Capture_Mono_1",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture_mono),
+ },
+ {
+ .name = "Playback_HDMI",
+ .stream_name = "Playback_HDMI",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback_hdmi),
+ },
+ {
+ .name = "Wake on Voice",
+ .stream_name = "Wake on Voice",
+ .ignore_suspend = 1,
+ .ignore = 1,
+ SND_SOC_DAILINK_REG(wake_on_voice),
+ .ops = &mt8183_mt6358_ts3a227_max98357_wov_ops,
+ },
+
+ /* BE */
+ {
+ .name = "Primary Codec",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(primary_codec),
+ },
+ {
+ .name = "PCM 1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(pcm1),
+ },
+ {
+ .name = "PCM 2",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(pcm2),
+ },
+ {
+ .name = "I2S0",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
+ .ops = &mt8183_mt6358_i2s_ops,
+ SND_SOC_DAILINK_REG(i2s0),
+ },
+ {
+ .name = "I2S1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
+ .ops = &mt8183_mt6358_i2s_ops,
+ SND_SOC_DAILINK_REG(i2s1),
+ },
+ {
+ .name = "I2S2",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
+ .ops = &mt8183_mt6358_i2s_ops,
+ SND_SOC_DAILINK_REG(i2s2),
+ },
+ {
+ .name = "I2S3",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = "I2S5",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
+ .ops = &mt8183_mt6358_i2s_ops,
+ SND_SOC_DAILINK_REG(i2s5),
+ },
+ {
+ .name = "TDM",
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_IB_IF |
+ SND_SOC_DAIFMT_CBM_CFM,
+ .dpcm_playback = 1,
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
+ .ops = &mt8183_mt6358_tdm_ops,
+ .ignore = 1,
+ .init = mt8183_mt6358_ts3a227_max98357_hdmi_init,
+ SND_SOC_DAILINK_REG(tdm),
+ },
+};
+
+static struct snd_soc_card mt8183_mt6358_ts3a227_max98357_card = {
+ .name = "mt8183_mt6358_ts3a227_max98357",
+ .owner = THIS_MODULE,
+ .dai_link = mt8183_mt6358_ts3a227_dai_links,
+ .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
+};
+
+static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = {
+ .name = "mt8183_mt6358_ts3a227_max98357b",
+ .owner = THIS_MODULE,
+ .dai_link = mt8183_mt6358_ts3a227_dai_links,
+ .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
+};
+
+static struct snd_soc_codec_conf mt8183_mt6358_ts3a227_rt1015_amp_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME),
+ .name_prefix = "Left",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(RT1015_DEV1_NAME),
+ .name_prefix = "Right",
+ },
+};
+
+static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015_card = {
+ .name = "mt8183_mt6358_ts3a227_rt1015",
+ .owner = THIS_MODULE,
+ .dai_link = mt8183_mt6358_ts3a227_dai_links,
+ .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
+ .codec_conf = mt8183_mt6358_ts3a227_rt1015_amp_conf,
+ .num_configs = ARRAY_SIZE(mt8183_mt6358_ts3a227_rt1015_amp_conf),
+};
+
+static int
+mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component)
+{
+ int ret;
+ struct mt8183_mt6358_ts3a227_max98357_priv *priv =
+ snd_soc_card_get_drvdata(component->card);
+
+ /* Enable Headset and 4 Buttons Jack detection */
+ ret = snd_soc_card_jack_new(component->card,
+ "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &priv->headset_jack,
+ NULL, 0);
+ if (ret)
+ return ret;
+
+ ret = ts3a227e_enable_jack_detect(component, &priv->headset_jack);
+
+ return ret;
+}
+
+static struct snd_soc_aux_dev mt8183_mt6358_ts3a227_max98357_headset_dev = {
+ .dlc = COMP_EMPTY(),
+ .init = mt8183_mt6358_ts3a227_max98357_headset_init,
+};
+
+static int
+mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card;
+ struct device_node *platform_node, *ec_codec, *hdmi_codec;
+ struct snd_soc_dai_link *dai_link;
+ struct mt8183_mt6358_ts3a227_max98357_priv *priv;
+ const struct of_device_id *match;
+ int ret, i;
+
+ platform_node = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,platform", 0);
+ if (!platform_node) {
+ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev);
+ if (!match || !match->data)
+ return -EINVAL;
+
+ card = (struct snd_soc_card *)match->data;
+ card->dev = &pdev->dev;
+
+ ec_codec = of_parse_phandle(pdev->dev.of_node, "mediatek,ec-codec", 0);
+ hdmi_codec = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,hdmi-codec", 0);
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (ec_codec && strcmp(dai_link->name, "Wake on Voice") == 0) {
+ dai_link->cpus[0].name = NULL;
+ dai_link->cpus[0].of_node = ec_codec;
+ dai_link->cpus[0].dai_name = NULL;
+ dai_link->codecs[0].name = NULL;
+ dai_link->codecs[0].of_node = ec_codec;
+ dai_link->codecs[0].dai_name = "Wake on Voice";
+ dai_link->platforms[0].of_node = ec_codec;
+ dai_link->ignore = 0;
+ }
+
+ if (strcmp(dai_link->name, "I2S3") == 0) {
+ if (card == &mt8183_mt6358_ts3a227_max98357_card ||
+ card == &mt8183_mt6358_ts3a227_max98357b_card) {
+ dai_link->be_hw_params_fixup =
+ mt8183_i2s_hw_params_fixup;
+ dai_link->ops = &mt8183_mt6358_i2s_ops;
+ dai_link->cpus = i2s3_max98357a_cpus;
+ dai_link->num_cpus =
+ ARRAY_SIZE(i2s3_max98357a_cpus);
+ dai_link->codecs = i2s3_max98357a_codecs;
+ dai_link->num_codecs =
+ ARRAY_SIZE(i2s3_max98357a_codecs);
+ dai_link->platforms = i2s3_max98357a_platforms;
+ dai_link->num_platforms =
+ ARRAY_SIZE(i2s3_max98357a_platforms);
+ } else if (card == &mt8183_mt6358_ts3a227_rt1015_card) {
+ dai_link->be_hw_params_fixup =
+ mt8183_rt1015_i2s_hw_params_fixup;
+ dai_link->ops = &mt8183_mt6358_rt1015_i2s_ops;
+ dai_link->cpus = i2s3_rt1015_cpus;
+ dai_link->num_cpus =
+ ARRAY_SIZE(i2s3_rt1015_cpus);
+ dai_link->codecs = i2s3_rt1015_codecs;
+ dai_link->num_codecs =
+ ARRAY_SIZE(i2s3_rt1015_codecs);
+ dai_link->platforms = i2s3_rt1015_platforms;
+ dai_link->num_platforms =
+ ARRAY_SIZE(i2s3_rt1015_platforms);
+ }
+ }
+
+ if (card == &mt8183_mt6358_ts3a227_max98357b_card) {
+ if (strcmp(dai_link->name, "I2S2") == 0 ||
+ strcmp(dai_link->name, "I2S3") == 0)
+ dai_link->dai_fmt = SND_SOC_DAIFMT_LEFT_J |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM;
+ }
+
+ if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0) {
+ dai_link->codecs->of_node = hdmi_codec;
+ dai_link->ignore = 0;
+ }
+
+ if (!dai_link->platforms->name)
+ dai_link->platforms->of_node = platform_node;
+ }
+
+ mt8183_mt6358_ts3a227_max98357_headset_dev.dlc.of_node =
+ of_parse_phandle(pdev->dev.of_node,
+ "mediatek,headset-codec", 0);
+ if (mt8183_mt6358_ts3a227_max98357_headset_dev.dlc.of_node) {
+ card->aux_dev = &mt8183_mt6358_ts3a227_max98357_headset_dev;
+ card->num_aux_devs = 1;
+ }
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ snd_soc_card_set_drvdata(card, priv);
+
+ priv->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(priv->pinctrl)) {
+ dev_err(&pdev->dev, "%s devm_pinctrl_get failed\n",
+ __func__);
+ return PTR_ERR(priv->pinctrl);
+ }
+
+ for (i = 0; i < PIN_STATE_MAX; i++) {
+ priv->pin_states[i] = pinctrl_lookup_state(priv->pinctrl,
+ mt8183_pin_str[i]);
+ if (IS_ERR(priv->pin_states[i])) {
+ ret = PTR_ERR(priv->pin_states[i]);
+ dev_info(&pdev->dev, "%s Can't find pin state %s %d\n",
+ __func__, mt8183_pin_str[i], ret);
+ }
+ }
+
+ if (!IS_ERR(priv->pin_states[PIN_TDM_OUT_OFF])) {
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_TDM_OUT_OFF]);
+ if (ret)
+ dev_info(&pdev->dev,
+ "%s failed to select state %d\n",
+ __func__, ret);
+ }
+
+ if (!IS_ERR(priv->pin_states[PIN_STATE_DEFAULT])) {
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_STATE_DEFAULT]);
+ if (ret)
+ dev_info(&pdev->dev,
+ "%s failed to select state %d\n",
+ __func__, ret);
+ }
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+
+ of_node_put(platform_node);
+ of_node_put(ec_codec);
+ of_node_put(hdmi_codec);
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt8183_mt6358_ts3a227_max98357_dt_match[] = {
+ {
+ .compatible = "mediatek,mt8183_mt6358_ts3a227_max98357",
+ .data = &mt8183_mt6358_ts3a227_max98357_card,
+ },
+ {
+ .compatible = "mediatek,mt8183_mt6358_ts3a227_max98357b",
+ .data = &mt8183_mt6358_ts3a227_max98357b_card,
+ },
+ {
+ .compatible = "mediatek,mt8183_mt6358_ts3a227_rt1015",
+ .data = &mt8183_mt6358_ts3a227_rt1015_card,
+ },
+ {}
+};
+#endif
+
+static struct platform_driver mt8183_mt6358_ts3a227_max98357_driver = {
+ .driver = {
+ .name = "mt8183_mt6358_ts3a227",
+#ifdef CONFIG_OF
+ .of_match_table = mt8183_mt6358_ts3a227_max98357_dt_match,
+#endif
+ },
+ .probe = mt8183_mt6358_ts3a227_max98357_dev_probe,
+};
+
+module_platform_driver(mt8183_mt6358_ts3a227_max98357_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8183-MT6358-TS3A227-MAX98357 ALSA SoC machine driver");
+MODULE_AUTHOR("Shunli Wang <shunli.wang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt8183_mt6358_ts3a227_max98357 soc card");
diff --git a/sound/soc/mediatek/mt8183/mt8183-reg.h b/sound/soc/mediatek/mt8183/mt8183-reg.h
new file mode 100644
index 000000000..e544a09e1
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-reg.h
@@ -0,0 +1,1668 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8183-reg.h -- Mediatek 8183 audio driver reg definition
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef _MT8183_REG_H_
+#define _MT8183_REG_H_
+
+#define AUDIO_TOP_CON0 0x0000
+#define AUDIO_TOP_CON1 0x0004
+#define AUDIO_TOP_CON3 0x000c
+#define AFE_DAC_CON0 0x0010
+#define AFE_DAC_CON1 0x0014
+#define AFE_I2S_CON 0x0018
+#define AFE_DAIBT_CON0 0x001c
+#define AFE_CONN0 0x0020
+#define AFE_CONN1 0x0024
+#define AFE_CONN2 0x0028
+#define AFE_CONN3 0x002c
+#define AFE_CONN4 0x0030
+#define AFE_I2S_CON1 0x0034
+#define AFE_I2S_CON2 0x0038
+#define AFE_MRGIF_CON 0x003c
+#define AFE_DL1_BASE 0x0040
+#define AFE_DL1_CUR 0x0044
+#define AFE_DL1_END 0x0048
+#define AFE_I2S_CON3 0x004c
+#define AFE_DL2_BASE 0x0050
+#define AFE_DL2_CUR 0x0054
+#define AFE_DL2_END 0x0058
+#define AFE_CONN5 0x005c
+#define AFE_CONN_24BIT 0x006c
+#define AFE_AWB_BASE 0x0070
+#define AFE_AWB_END 0x0078
+#define AFE_AWB_CUR 0x007c
+#define AFE_VUL_BASE 0x0080
+#define AFE_VUL_END 0x0088
+#define AFE_VUL_CUR 0x008c
+#define AFE_CONN6 0x00bc
+#define AFE_MEMIF_MSB 0x00cc
+#define AFE_MEMIF_MON0 0x00d0
+#define AFE_MEMIF_MON1 0x00d4
+#define AFE_MEMIF_MON2 0x00d8
+#define AFE_MEMIF_MON3 0x00dc
+#define AFE_MEMIF_MON4 0x00e0
+#define AFE_MEMIF_MON5 0x00e4
+#define AFE_MEMIF_MON6 0x00e8
+#define AFE_MEMIF_MON7 0x00ec
+#define AFE_MEMIF_MON8 0x00f0
+#define AFE_MEMIF_MON9 0x00f4
+#define AFE_ADDA_DL_SRC2_CON0 0x0108
+#define AFE_ADDA_DL_SRC2_CON1 0x010c
+#define AFE_ADDA_UL_SRC_CON0 0x0114
+#define AFE_ADDA_UL_SRC_CON1 0x0118
+#define AFE_ADDA_TOP_CON0 0x0120
+#define AFE_ADDA_UL_DL_CON0 0x0124
+#define AFE_ADDA_SRC_DEBUG 0x012c
+#define AFE_ADDA_SRC_DEBUG_MON0 0x0130
+#define AFE_ADDA_SRC_DEBUG_MON1 0x0134
+#define AFE_ADDA_UL_SRC_MON0 0x0148
+#define AFE_ADDA_UL_SRC_MON1 0x014c
+#define AFE_SIDETONE_DEBUG 0x01d0
+#define AFE_SIDETONE_MON 0x01d4
+#define AFE_SINEGEN_CON2 0x01dc
+#define AFE_SIDETONE_CON0 0x01e0
+#define AFE_SIDETONE_COEFF 0x01e4
+#define AFE_SIDETONE_CON1 0x01e8
+#define AFE_SIDETONE_GAIN 0x01ec
+#define AFE_SINEGEN_CON0 0x01f0
+#define AFE_TOP_CON0 0x0200
+#define AFE_BUS_CFG 0x0240
+#define AFE_BUS_MON0 0x0244
+#define AFE_ADDA_PREDIS_CON0 0x0260
+#define AFE_ADDA_PREDIS_CON1 0x0264
+#define AFE_MRGIF_MON0 0x0270
+#define AFE_MRGIF_MON1 0x0274
+#define AFE_MRGIF_MON2 0x0278
+#define AFE_I2S_MON 0x027c
+#define AFE_ADDA_IIR_COEF_02_01 0x0290
+#define AFE_ADDA_IIR_COEF_04_03 0x0294
+#define AFE_ADDA_IIR_COEF_06_05 0x0298
+#define AFE_ADDA_IIR_COEF_08_07 0x029c
+#define AFE_ADDA_IIR_COEF_10_09 0x02a0
+#define AFE_DAC_CON2 0x02e0
+#define AFE_IRQ_MCU_CON1 0x02e4
+#define AFE_IRQ_MCU_CON2 0x02e8
+#define AFE_DAC_MON 0x02ec
+#define AFE_VUL2_BASE 0x02f0
+#define AFE_VUL2_END 0x02f8
+#define AFE_VUL2_CUR 0x02fc
+#define AFE_IRQ_MCU_CNT0 0x0300
+#define AFE_IRQ_MCU_CNT6 0x0304
+#define AFE_IRQ_MCU_CNT8 0x0308
+#define AFE_IRQ_MCU_EN1 0x030c
+#define AFE_IRQ0_MCU_CNT_MON 0x0310
+#define AFE_IRQ6_MCU_CNT_MON 0x0314
+#define AFE_MOD_DAI_BASE 0x0330
+#define AFE_MOD_DAI_END 0x0338
+#define AFE_MOD_DAI_CUR 0x033c
+#define AFE_VUL_D2_BASE 0x0350
+#define AFE_VUL_D2_END 0x0358
+#define AFE_VUL_D2_CUR 0x035c
+#define AFE_DL3_BASE 0x0360
+#define AFE_DL3_CUR 0x0364
+#define AFE_DL3_END 0x0368
+#define AFE_HDMI_OUT_CON0 0x0370
+#define AFE_HDMI_OUT_BASE 0x0374
+#define AFE_HDMI_OUT_CUR 0x0378
+#define AFE_HDMI_OUT_END 0x037c
+#define AFE_HDMI_CONN0 0x0390
+#define AFE_IRQ3_MCU_CNT_MON 0x0398
+#define AFE_IRQ4_MCU_CNT_MON 0x039c
+#define AFE_IRQ_MCU_CON0 0x03a0
+#define AFE_IRQ_MCU_STATUS 0x03a4
+#define AFE_IRQ_MCU_CLR 0x03a8
+#define AFE_IRQ_MCU_CNT1 0x03ac
+#define AFE_IRQ_MCU_CNT2 0x03b0
+#define AFE_IRQ_MCU_EN 0x03b4
+#define AFE_IRQ_MCU_MON2 0x03b8
+#define AFE_IRQ_MCU_CNT5 0x03bc
+#define AFE_IRQ1_MCU_CNT_MON 0x03c0
+#define AFE_IRQ2_MCU_CNT_MON 0x03c4
+#define AFE_IRQ1_MCU_EN_CNT_MON 0x03c8
+#define AFE_IRQ5_MCU_CNT_MON 0x03cc
+#define AFE_MEMIF_MINLEN 0x03d0
+#define AFE_MEMIF_MAXLEN 0x03d4
+#define AFE_MEMIF_PBUF_SIZE 0x03d8
+#define AFE_IRQ_MCU_CNT7 0x03dc
+#define AFE_IRQ7_MCU_CNT_MON 0x03e0
+#define AFE_IRQ_MCU_CNT3 0x03e4
+#define AFE_IRQ_MCU_CNT4 0x03e8
+#define AFE_IRQ_MCU_CNT11 0x03ec
+#define AFE_APLL1_TUNER_CFG 0x03f0
+#define AFE_APLL2_TUNER_CFG 0x03f4
+#define AFE_MEMIF_HD_MODE 0x03f8
+#define AFE_MEMIF_HDALIGN 0x03fc
+#define AFE_CONN33 0x0408
+#define AFE_IRQ_MCU_CNT12 0x040c
+#define AFE_GAIN1_CON0 0x0410
+#define AFE_GAIN1_CON1 0x0414
+#define AFE_GAIN1_CON2 0x0418
+#define AFE_GAIN1_CON3 0x041c
+#define AFE_CONN7 0x0420
+#define AFE_GAIN1_CUR 0x0424
+#define AFE_GAIN2_CON0 0x0428
+#define AFE_GAIN2_CON1 0x042c
+#define AFE_GAIN2_CON2 0x0430
+#define AFE_GAIN2_CON3 0x0434
+#define AFE_CONN8 0x0438
+#define AFE_GAIN2_CUR 0x043c
+#define AFE_CONN9 0x0440
+#define AFE_CONN10 0x0444
+#define AFE_CONN11 0x0448
+#define AFE_CONN12 0x044c
+#define AFE_CONN13 0x0450
+#define AFE_CONN14 0x0454
+#define AFE_CONN15 0x0458
+#define AFE_CONN16 0x045c
+#define AFE_CONN17 0x0460
+#define AFE_CONN18 0x0464
+#define AFE_CONN19 0x0468
+#define AFE_CONN20 0x046c
+#define AFE_CONN21 0x0470
+#define AFE_CONN22 0x0474
+#define AFE_CONN23 0x0478
+#define AFE_CONN24 0x047c
+#define AFE_CONN_RS 0x0494
+#define AFE_CONN_DI 0x0498
+#define AFE_CONN25 0x04b0
+#define AFE_CONN26 0x04b4
+#define AFE_CONN27 0x04b8
+#define AFE_CONN28 0x04bc
+#define AFE_CONN29 0x04c0
+#define AFE_CONN30 0x04c4
+#define AFE_CONN31 0x04c8
+#define AFE_CONN32 0x04cc
+#define AFE_SRAM_DELSEL_CON0 0x04f0
+#define AFE_SRAM_DELSEL_CON2 0x04f8
+#define AFE_SRAM_DELSEL_CON3 0x04fc
+#define AFE_ASRC_2CH_CON12 0x0528
+#define AFE_ASRC_2CH_CON13 0x052c
+#define PCM_INTF_CON1 0x0530
+#define PCM_INTF_CON2 0x0538
+#define PCM2_INTF_CON 0x053c
+#define AFE_TDM_CON1 0x0548
+#define AFE_TDM_CON2 0x054c
+#define AFE_CONN34 0x0580
+#define FPGA_CFG0 0x05b0
+#define FPGA_CFG1 0x05b4
+#define FPGA_CFG2 0x05c0
+#define FPGA_CFG3 0x05c4
+#define AUDIO_TOP_DBG_CON 0x05c8
+#define AUDIO_TOP_DBG_MON0 0x05cc
+#define AUDIO_TOP_DBG_MON1 0x05d0
+#define AFE_IRQ8_MCU_CNT_MON 0x05e4
+#define AFE_IRQ11_MCU_CNT_MON 0x05e8
+#define AFE_IRQ12_MCU_CNT_MON 0x05ec
+#define AFE_GENERAL_REG0 0x0800
+#define AFE_GENERAL_REG1 0x0804
+#define AFE_GENERAL_REG2 0x0808
+#define AFE_GENERAL_REG3 0x080c
+#define AFE_GENERAL_REG4 0x0810
+#define AFE_GENERAL_REG5 0x0814
+#define AFE_GENERAL_REG6 0x0818
+#define AFE_GENERAL_REG7 0x081c
+#define AFE_GENERAL_REG8 0x0820
+#define AFE_GENERAL_REG9 0x0824
+#define AFE_GENERAL_REG10 0x0828
+#define AFE_GENERAL_REG11 0x082c
+#define AFE_GENERAL_REG12 0x0830
+#define AFE_GENERAL_REG13 0x0834
+#define AFE_GENERAL_REG14 0x0838
+#define AFE_GENERAL_REG15 0x083c
+#define AFE_CBIP_CFG0 0x0840
+#define AFE_CBIP_MON0 0x0844
+#define AFE_CBIP_SLV_MUX_MON0 0x0848
+#define AFE_CBIP_SLV_DECODER_MON0 0x084c
+#define AFE_CONN0_1 0x0900
+#define AFE_CONN1_1 0x0904
+#define AFE_CONN2_1 0x0908
+#define AFE_CONN3_1 0x090c
+#define AFE_CONN4_1 0x0910
+#define AFE_CONN5_1 0x0914
+#define AFE_CONN6_1 0x0918
+#define AFE_CONN7_1 0x091c
+#define AFE_CONN8_1 0x0920
+#define AFE_CONN9_1 0x0924
+#define AFE_CONN10_1 0x0928
+#define AFE_CONN11_1 0x092c
+#define AFE_CONN12_1 0x0930
+#define AFE_CONN13_1 0x0934
+#define AFE_CONN14_1 0x0938
+#define AFE_CONN15_1 0x093c
+#define AFE_CONN16_1 0x0940
+#define AFE_CONN17_1 0x0944
+#define AFE_CONN18_1 0x0948
+#define AFE_CONN19_1 0x094c
+#define AFE_CONN20_1 0x0950
+#define AFE_CONN21_1 0x0954
+#define AFE_CONN22_1 0x0958
+#define AFE_CONN23_1 0x095c
+#define AFE_CONN24_1 0x0960
+#define AFE_CONN25_1 0x0964
+#define AFE_CONN26_1 0x0968
+#define AFE_CONN27_1 0x096c
+#define AFE_CONN28_1 0x0970
+#define AFE_CONN29_1 0x0974
+#define AFE_CONN30_1 0x0978
+#define AFE_CONN31_1 0x097c
+#define AFE_CONN32_1 0x0980
+#define AFE_CONN33_1 0x0984
+#define AFE_CONN34_1 0x0988
+#define AFE_CONN_RS_1 0x098c
+#define AFE_CONN_DI_1 0x0990
+#define AFE_CONN_24BIT_1 0x0994
+#define AFE_CONN_REG 0x0998
+#define AFE_CONN35 0x09a0
+#define AFE_CONN36 0x09a4
+#define AFE_CONN37 0x09a8
+#define AFE_CONN38 0x09ac
+#define AFE_CONN35_1 0x09b0
+#define AFE_CONN36_1 0x09b4
+#define AFE_CONN37_1 0x09b8
+#define AFE_CONN38_1 0x09bc
+#define AFE_CONN39 0x09c0
+#define AFE_CONN40 0x09c4
+#define AFE_CONN41 0x09c8
+#define AFE_CONN42 0x09cc
+#define AFE_CONN39_1 0x09e0
+#define AFE_CONN40_1 0x09e4
+#define AFE_CONN41_1 0x09e8
+#define AFE_CONN42_1 0x09ec
+#define AFE_I2S_CON4 0x09f8
+#define AFE_ADDA6_TOP_CON0 0x0a80
+#define AFE_ADDA6_UL_SRC_CON0 0x0a84
+#define AFE_ADD6_UL_SRC_CON1 0x0a88
+#define AFE_ADDA6_SRC_DEBUG 0x0a8c
+#define AFE_ADDA6_SRC_DEBUG_MON0 0x0a90
+#define AFE_ADDA6_ULCF_CFG_02_01 0x0aa0
+#define AFE_ADDA6_ULCF_CFG_04_03 0x0aa4
+#define AFE_ADDA6_ULCF_CFG_06_05 0x0aa8
+#define AFE_ADDA6_ULCF_CFG_08_07 0x0aac
+#define AFE_ADDA6_ULCF_CFG_10_09 0x0ab0
+#define AFE_ADDA6_ULCF_CFG_12_11 0x0ab4
+#define AFE_ADDA6_ULCF_CFG_14_13 0x0ab8
+#define AFE_ADDA6_ULCF_CFG_16_15 0x0abc
+#define AFE_ADDA6_ULCF_CFG_18_17 0x0ac0
+#define AFE_ADDA6_ULCF_CFG_20_19 0x0ac4
+#define AFE_ADDA6_ULCF_CFG_22_21 0x0ac8
+#define AFE_ADDA6_ULCF_CFG_24_23 0x0acc
+#define AFE_ADDA6_ULCF_CFG_26_25 0x0ad0
+#define AFE_ADDA6_ULCF_CFG_28_27 0x0ad4
+#define AFE_ADDA6_ULCF_CFG_30_29 0x0ad8
+#define AFE_ADD6A_UL_SRC_MON0 0x0ae4
+#define AFE_ADDA6_UL_SRC_MON1 0x0ae8
+#define AFE_CONN43 0x0af8
+#define AFE_CONN43_1 0x0afc
+#define AFE_DL1_BASE_MSB 0x0b00
+#define AFE_DL1_CUR_MSB 0x0b04
+#define AFE_DL1_END_MSB 0x0b08
+#define AFE_DL2_BASE_MSB 0x0b10
+#define AFE_DL2_CUR_MSB 0x0b14
+#define AFE_DL2_END_MSB 0x0b18
+#define AFE_AWB_BASE_MSB 0x0b20
+#define AFE_AWB_END_MSB 0x0b28
+#define AFE_AWB_CUR_MSB 0x0b2c
+#define AFE_VUL_BASE_MSB 0x0b30
+#define AFE_VUL_END_MSB 0x0b38
+#define AFE_VUL_CUR_MSB 0x0b3c
+#define AFE_VUL2_BASE_MSB 0x0b50
+#define AFE_VUL2_END_MSB 0x0b58
+#define AFE_VUL2_CUR_MSB 0x0b5c
+#define AFE_MOD_DAI_BASE_MSB 0x0b60
+#define AFE_MOD_DAI_END_MSB 0x0b68
+#define AFE_MOD_DAI_CUR_MSB 0x0b6c
+#define AFE_VUL_D2_BASE_MSB 0x0b80
+#define AFE_VUL_D2_END_MSB 0x0b88
+#define AFE_VUL_D2_CUR_MSB 0x0b8c
+#define AFE_DL3_BASE_MSB 0x0b90
+#define AFE_DL3_CUR_MSB 0x0b94
+#define AFE_DL3_END_MSB 0x0b98
+#define AFE_HDMI_OUT_BASE_MSB 0x0ba4
+#define AFE_HDMI_OUT_CUR_MSB 0x0ba8
+#define AFE_HDMI_OUT_END_MSB 0x0bac
+#define AFE_AWB2_BASE 0x0bd0
+#define AFE_AWB2_END 0x0bd8
+#define AFE_AWB2_CUR 0x0bdc
+#define AFE_AWB2_BASE_MSB 0x0be0
+#define AFE_AWB2_END_MSB 0x0be8
+#define AFE_AWB2_CUR_MSB 0x0bec
+#define AFE_ADDA_DL_SDM_DCCOMP_CON 0x0c50
+#define AFE_ADDA_DL_SDM_TEST 0x0c54
+#define AFE_ADDA_DL_DC_COMP_CFG0 0x0c58
+#define AFE_ADDA_DL_DC_COMP_CFG1 0x0c5c
+#define AFE_ADDA_DL_SDM_FIFO_MON 0x0c60
+#define AFE_ADDA_DL_SRC_LCH_MON 0x0c64
+#define AFE_ADDA_DL_SRC_RCH_MON 0x0c68
+#define AFE_ADDA_DL_SDM_OUT_MON 0x0c6c
+#define AFE_CONNSYS_I2S_CON 0x0c78
+#define AFE_CONNSYS_I2S_MON 0x0c7c
+#define AFE_ASRC_2CH_CON0 0x0c80
+#define AFE_ASRC_2CH_CON1 0x0c84
+#define AFE_ASRC_2CH_CON2 0x0c88
+#define AFE_ASRC_2CH_CON3 0x0c8c
+#define AFE_ASRC_2CH_CON4 0x0c90
+#define AFE_ASRC_2CH_CON5 0x0c94
+#define AFE_ASRC_2CH_CON6 0x0c98
+#define AFE_ASRC_2CH_CON7 0x0c9c
+#define AFE_ASRC_2CH_CON8 0x0ca0
+#define AFE_ASRC_2CH_CON9 0x0ca4
+#define AFE_ASRC_2CH_CON10 0x0ca8
+#define AFE_ADDA6_IIR_COEF_02_01 0x0ce0
+#define AFE_ADDA6_IIR_COEF_04_03 0x0ce4
+#define AFE_ADDA6_IIR_COEF_06_05 0x0ce8
+#define AFE_ADDA6_IIR_COEF_08_07 0x0cec
+#define AFE_ADDA6_IIR_COEF_10_09 0x0cf0
+#define AFE_ADDA_PREDIS_CON2 0x0d40
+#define AFE_ADDA_PREDIS_CON3 0x0d44
+#define AFE_MEMIF_MON12 0x0d70
+#define AFE_MEMIF_MON13 0x0d74
+#define AFE_MEMIF_MON14 0x0d78
+#define AFE_MEMIF_MON15 0x0d7c
+#define AFE_MEMIF_MON16 0x0d80
+#define AFE_MEMIF_MON17 0x0d84
+#define AFE_MEMIF_MON18 0x0d88
+#define AFE_MEMIF_MON19 0x0d8c
+#define AFE_MEMIF_MON20 0x0d90
+#define AFE_MEMIF_MON21 0x0d94
+#define AFE_MEMIF_MON22 0x0d98
+#define AFE_MEMIF_MON23 0x0d9c
+#define AFE_MEMIF_MON24 0x0da0
+#define AFE_HD_ENGEN_ENABLE 0x0dd0
+#define AFE_ADDA_MTKAIF_CFG0 0x0e00
+#define AFE_ADDA_MTKAIF_TX_CFG1 0x0e14
+#define AFE_ADDA_MTKAIF_RX_CFG0 0x0e20
+#define AFE_ADDA_MTKAIF_RX_CFG1 0x0e24
+#define AFE_ADDA_MTKAIF_RX_CFG2 0x0e28
+#define AFE_ADDA_MTKAIF_MON0 0x0e34
+#define AFE_ADDA_MTKAIF_MON1 0x0e38
+#define AFE_AUD_PAD_TOP 0x0e40
+#define AFE_GENERAL1_ASRC_2CH_CON0 0x0e80
+#define AFE_GENERAL1_ASRC_2CH_CON1 0x0e84
+#define AFE_GENERAL1_ASRC_2CH_CON2 0x0e88
+#define AFE_GENERAL1_ASRC_2CH_CON3 0x0e8c
+#define AFE_GENERAL1_ASRC_2CH_CON4 0x0e90
+#define AFE_GENERAL1_ASRC_2CH_CON5 0x0e94
+#define AFE_GENERAL1_ASRC_2CH_CON6 0x0e98
+#define AFE_GENERAL1_ASRC_2CH_CON7 0x0e9c
+#define AFE_GENERAL1_ASRC_2CH_CON8 0x0ea0
+#define AFE_GENERAL1_ASRC_2CH_CON9 0x0ea4
+#define AFE_GENERAL1_ASRC_2CH_CON10 0x0ea8
+#define AFE_GENERAL1_ASRC_2CH_CON12 0x0eb0
+#define AFE_GENERAL1_ASRC_2CH_CON13 0x0eb4
+#define GENERAL_ASRC_MODE 0x0eb8
+#define GENERAL_ASRC_EN_ON 0x0ebc
+#define AFE_GENERAL2_ASRC_2CH_CON0 0x0f00
+#define AFE_GENERAL2_ASRC_2CH_CON1 0x0f04
+#define AFE_GENERAL2_ASRC_2CH_CON2 0x0f08
+#define AFE_GENERAL2_ASRC_2CH_CON3 0x0f0c
+#define AFE_GENERAL2_ASRC_2CH_CON4 0x0f10
+#define AFE_GENERAL2_ASRC_2CH_CON5 0x0f14
+#define AFE_GENERAL2_ASRC_2CH_CON6 0x0f18
+#define AFE_GENERAL2_ASRC_2CH_CON7 0x0f1c
+#define AFE_GENERAL2_ASRC_2CH_CON8 0x0f20
+#define AFE_GENERAL2_ASRC_2CH_CON9 0x0f24
+#define AFE_GENERAL2_ASRC_2CH_CON10 0x0f28
+#define AFE_GENERAL2_ASRC_2CH_CON12 0x0f30
+#define AFE_GENERAL2_ASRC_2CH_CON13 0x0f34
+
+#define AFE_MAX_REGISTER AFE_GENERAL2_ASRC_2CH_CON13
+#define AFE_IRQ_STATUS_BITS 0x1fff
+
+/* AUDIO_TOP_CON3 */
+#define BCK_INVERSE_SFT 3
+#define BCK_INVERSE_MASK 0x1
+#define BCK_INVERSE_MASK_SFT (0x1 << 3)
+
+/* AFE_DAC_CON0 */
+#define AWB2_ON_SFT 29
+#define AWB2_ON_MASK 0x1
+#define AWB2_ON_MASK_SFT (0x1 << 29)
+#define VUL2_ON_SFT 27
+#define VUL2_ON_MASK 0x1
+#define VUL2_ON_MASK_SFT (0x1 << 27)
+#define MOD_DAI_DUP_WR_SFT 26
+#define MOD_DAI_DUP_WR_MASK 0x1
+#define MOD_DAI_DUP_WR_MASK_SFT (0x1 << 26)
+#define VUL12_MODE_SFT 20
+#define VUL12_MODE_MASK 0xf
+#define VUL12_MODE_MASK_SFT (0xf << 20)
+#define VUL12_R_MONO_SFT 11
+#define VUL12_R_MONO_MASK 0x1
+#define VUL12_R_MONO_MASK_SFT (0x1 << 11)
+#define VUL12_MONO_SFT 10
+#define VUL12_MONO_MASK 0x1
+#define VUL12_MONO_MASK_SFT (0x1 << 10)
+#define VUL12_ON_SFT 9
+#define VUL12_ON_MASK 0x1
+#define VUL12_ON_MASK_SFT (0x1 << 9)
+#define MOD_DAI_ON_SFT 7
+#define MOD_DAI_ON_MASK 0x1
+#define MOD_DAI_ON_MASK_SFT (0x1 << 7)
+#define AWB_ON_SFT 6
+#define AWB_ON_MASK 0x1
+#define AWB_ON_MASK_SFT (0x1 << 6)
+#define DL3_ON_SFT 5
+#define DL3_ON_MASK 0x1
+#define DL3_ON_MASK_SFT (0x1 << 5)
+#define VUL_ON_SFT 3
+#define VUL_ON_MASK 0x1
+#define VUL_ON_MASK_SFT (0x1 << 3)
+#define DL2_ON_SFT 2
+#define DL2_ON_MASK 0x1
+#define DL2_ON_MASK_SFT (0x1 << 2)
+#define DL1_ON_SFT 1
+#define DL1_ON_MASK 0x1
+#define DL1_ON_MASK_SFT (0x1 << 1)
+#define AFE_ON_SFT 0
+#define AFE_ON_MASK 0x1
+#define AFE_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_DAC_CON1 */
+#define MOD_DAI_MODE_SFT 30
+#define MOD_DAI_MODE_MASK 0x3
+#define MOD_DAI_MODE_MASK_SFT (0x3 << 30)
+#define VUL_R_MONO_SFT 28
+#define VUL_R_MONO_MASK 0x1
+#define VUL_R_MONO_MASK_SFT (0x1 << 28)
+#define VUL_DATA_SFT 27
+#define VUL_DATA_MASK 0x1
+#define VUL_DATA_MASK_SFT (0x1 << 27)
+#define AWB_R_MONO_SFT 25
+#define AWB_R_MONO_MASK 0x1
+#define AWB_R_MONO_MASK_SFT (0x1 << 25)
+#define AWB_DATA_SFT 24
+#define AWB_DATA_MASK 0x1
+#define AWB_DATA_MASK_SFT (0x1 << 24)
+#define DL3_DATA_SFT 23
+#define DL3_DATA_MASK 0x1
+#define DL3_DATA_MASK_SFT (0x1 << 23)
+#define DL2_DATA_SFT 22
+#define DL2_DATA_MASK 0x1
+#define DL2_DATA_MASK_SFT (0x1 << 22)
+#define DL1_DATA_SFT 21
+#define DL1_DATA_MASK 0x1
+#define DL1_DATA_MASK_SFT (0x1 << 21)
+#define VUL_MODE_SFT 16
+#define VUL_MODE_MASK 0xf
+#define VUL_MODE_MASK_SFT (0xf << 16)
+#define AWB_MODE_SFT 12
+#define AWB_MODE_MASK 0xf
+#define AWB_MODE_MASK_SFT (0xf << 12)
+#define I2S_MODE_SFT 8
+#define I2S_MODE_MASK 0xf
+#define I2S_MODE_MASK_SFT (0xf << 8)
+#define DL2_MODE_SFT 4
+#define DL2_MODE_MASK 0xf
+#define DL2_MODE_MASK_SFT (0xf << 4)
+#define DL1_MODE_SFT 0
+#define DL1_MODE_MASK 0xf
+#define DL1_MODE_MASK_SFT (0xf << 0)
+
+/* AFE_DAC_CON2 */
+#define AWB2_R_MONO_SFT 21
+#define AWB2_R_MONO_MASK 0x1
+#define AWB2_R_MONO_MASK_SFT (0x1 << 21)
+#define AWB2_DATA_SFT 20
+#define AWB2_DATA_MASK 0x1
+#define AWB2_DATA_MASK_SFT (0x1 << 20)
+#define AWB2_MODE_SFT 16
+#define AWB2_MODE_MASK 0xf
+#define AWB2_MODE_MASK_SFT (0xf << 16)
+#define DL3_MODE_SFT 8
+#define DL3_MODE_MASK 0xf
+#define DL3_MODE_MASK_SFT (0xf << 8)
+#define VUL2_MODE_SFT 4
+#define VUL2_MODE_MASK 0xf
+#define VUL2_MODE_MASK_SFT (0xf << 4)
+#define VUL2_R_MONO_SFT 1
+#define VUL2_R_MONO_MASK 0x1
+#define VUL2_R_MONO_MASK_SFT (0x1 << 1)
+#define VUL2_DATA_SFT 0
+#define VUL2_DATA_MASK 0x1
+#define VUL2_DATA_MASK_SFT (0x1 << 0)
+
+/* AFE_DAC_MON */
+#define AFE_ON_RETM_SFT 0
+#define AFE_ON_RETM_MASK 0x1
+#define AFE_ON_RETM_MASK_SFT (0x1 << 0)
+
+/* AFE_I2S_CON */
+#define BCK_NEG_EG_LATCH_SFT 30
+#define BCK_NEG_EG_LATCH_MASK 0x1
+#define BCK_NEG_EG_LATCH_MASK_SFT (0x1 << 30)
+#define BCK_INV_SFT 29
+#define BCK_INV_MASK 0x1
+#define BCK_INV_MASK_SFT (0x1 << 29)
+#define I2SIN_PAD_SEL_SFT 28
+#define I2SIN_PAD_SEL_MASK 0x1
+#define I2SIN_PAD_SEL_MASK_SFT (0x1 << 28)
+#define I2S_LOOPBACK_SFT 20
+#define I2S_LOOPBACK_MASK 0x1
+#define I2S_LOOPBACK_MASK_SFT (0x1 << 20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17)
+#define I2S1_HD_EN_SFT 12
+#define I2S1_HD_EN_MASK 0x1
+#define I2S1_HD_EN_MASK_SFT (0x1 << 12)
+#define INV_PAD_CTRL_SFT 7
+#define INV_PAD_CTRL_MASK 0x1
+#define INV_PAD_CTRL_MASK_SFT (0x1 << 7)
+#define I2S_BYPSRC_SFT 6
+#define I2S_BYPSRC_MASK 0x1
+#define I2S_BYPSRC_MASK_SFT (0x1 << 6)
+#define INV_LRCK_SFT 5
+#define INV_LRCK_MASK 0x1
+#define INV_LRCK_MASK_SFT (0x1 << 5)
+#define I2S_FMT_SFT 3
+#define I2S_FMT_MASK 0x1
+#define I2S_FMT_MASK_SFT (0x1 << 3)
+#define I2S_SRC_SFT 2
+#define I2S_SRC_MASK 0x1
+#define I2S_SRC_MASK_SFT (0x1 << 2)
+#define I2S_WLEN_SFT 1
+#define I2S_WLEN_MASK 0x1
+#define I2S_WLEN_MASK_SFT (0x1 << 1)
+#define I2S_EN_SFT 0
+#define I2S_EN_MASK 0x1
+#define I2S_EN_MASK_SFT (0x1 << 0)
+
+/* AFE_I2S_CON1 */
+#define I2S2_LR_SWAP_SFT 31
+#define I2S2_LR_SWAP_MASK 0x1
+#define I2S2_LR_SWAP_MASK_SFT (0x1 << 31)
+#define I2S2_SEL_O19_O20_SFT 18
+#define I2S2_SEL_O19_O20_MASK 0x1
+#define I2S2_SEL_O19_O20_MASK_SFT (0x1 << 18)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17)
+#define I2S2_SEL_O03_O04_SFT 16
+#define I2S2_SEL_O03_O04_MASK 0x1
+#define I2S2_SEL_O03_O04_MASK_SFT (0x1 << 16)
+#define I2S2_32BIT_EN_SFT 13
+#define I2S2_32BIT_EN_MASK 0x1
+#define I2S2_32BIT_EN_MASK_SFT (0x1 << 13)
+#define I2S2_HD_EN_SFT 12
+#define I2S2_HD_EN_MASK 0x1
+#define I2S2_HD_EN_MASK_SFT (0x1 << 12)
+#define I2S2_OUT_MODE_SFT 8
+#define I2S2_OUT_MODE_MASK 0xf
+#define I2S2_OUT_MODE_MASK_SFT (0xf << 8)
+#define INV_LRCK_SFT 5
+#define INV_LRCK_MASK 0x1
+#define INV_LRCK_MASK_SFT (0x1 << 5)
+#define I2S2_FMT_SFT 3
+#define I2S2_FMT_MASK 0x1
+#define I2S2_FMT_MASK_SFT (0x1 << 3)
+#define I2S2_WLEN_SFT 1
+#define I2S2_WLEN_MASK 0x1
+#define I2S2_WLEN_MASK_SFT (0x1 << 1)
+#define I2S2_EN_SFT 0
+#define I2S2_EN_MASK 0x1
+#define I2S2_EN_MASK_SFT (0x1 << 0)
+
+/* AFE_I2S_CON2 */
+#define I2S3_LR_SWAP_SFT 31
+#define I2S3_LR_SWAP_MASK 0x1
+#define I2S3_LR_SWAP_MASK_SFT (0x1 << 31)
+#define I2S3_UPDATE_WORD_SFT 24
+#define I2S3_UPDATE_WORD_MASK 0x1f
+#define I2S3_UPDATE_WORD_MASK_SFT (0x1f << 24)
+#define I2S3_BCK_INV_SFT 23
+#define I2S3_BCK_INV_MASK 0x1
+#define I2S3_BCK_INV_MASK_SFT (0x1 << 23)
+#define I2S3_FPGA_BIT_TEST_SFT 22
+#define I2S3_FPGA_BIT_TEST_MASK 0x1
+#define I2S3_FPGA_BIT_TEST_MASK_SFT (0x1 << 22)
+#define I2S3_FPGA_BIT_SFT 21
+#define I2S3_FPGA_BIT_MASK 0x1
+#define I2S3_FPGA_BIT_MASK_SFT (0x1 << 21)
+#define I2S3_LOOPBACK_SFT 20
+#define I2S3_LOOPBACK_MASK 0x1
+#define I2S3_LOOPBACK_MASK_SFT (0x1 << 20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17)
+#define I2S3_HD_EN_SFT 12
+#define I2S3_HD_EN_MASK 0x1
+#define I2S3_HD_EN_MASK_SFT (0x1 << 12)
+#define I2S3_OUT_MODE_SFT 8
+#define I2S3_OUT_MODE_MASK 0xf
+#define I2S3_OUT_MODE_MASK_SFT (0xf << 8)
+#define I2S3_FMT_SFT 3
+#define I2S3_FMT_MASK 0x1
+#define I2S3_FMT_MASK_SFT (0x1 << 3)
+#define I2S3_WLEN_SFT 1
+#define I2S3_WLEN_MASK 0x1
+#define I2S3_WLEN_MASK_SFT (0x1 << 1)
+#define I2S3_EN_SFT 0
+#define I2S3_EN_MASK 0x1
+#define I2S3_EN_MASK_SFT (0x1 << 0)
+
+/* AFE_I2S_CON3 */
+#define I2S4_LR_SWAP_SFT 31
+#define I2S4_LR_SWAP_MASK 0x1
+#define I2S4_LR_SWAP_MASK_SFT (0x1 << 31)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17)
+#define I2S4_32BIT_EN_SFT 13
+#define I2S4_32BIT_EN_MASK 0x1
+#define I2S4_32BIT_EN_MASK_SFT (0x1 << 13)
+#define I2S4_HD_EN_SFT 12
+#define I2S4_HD_EN_MASK 0x1
+#define I2S4_HD_EN_MASK_SFT (0x1 << 12)
+#define I2S4_OUT_MODE_SFT 8
+#define I2S4_OUT_MODE_MASK 0xf
+#define I2S4_OUT_MODE_MASK_SFT (0xf << 8)
+#define INV_LRCK_SFT 5
+#define INV_LRCK_MASK 0x1
+#define INV_LRCK_MASK_SFT (0x1 << 5)
+#define I2S4_FMT_SFT 3
+#define I2S4_FMT_MASK 0x1
+#define I2S4_FMT_MASK_SFT (0x1 << 3)
+#define I2S4_WLEN_SFT 1
+#define I2S4_WLEN_MASK 0x1
+#define I2S4_WLEN_MASK_SFT (0x1 << 1)
+#define I2S4_EN_SFT 0
+#define I2S4_EN_MASK 0x1
+#define I2S4_EN_MASK_SFT (0x1 << 0)
+
+/* AFE_I2S_CON4 */
+#define I2S5_LR_SWAP_SFT 31
+#define I2S5_LR_SWAP_MASK 0x1
+#define I2S5_LR_SWAP_MASK_SFT (0x1 << 31)
+#define I2S_LOOPBACK_SFT 20
+#define I2S_LOOPBACK_MASK 0x1
+#define I2S_LOOPBACK_MASK_SFT (0x1 << 20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17)
+#define I2S5_32BIT_EN_SFT 13
+#define I2S5_32BIT_EN_MASK 0x1
+#define I2S5_32BIT_EN_MASK_SFT (0x1 << 13)
+#define I2S5_HD_EN_SFT 12
+#define I2S5_HD_EN_MASK 0x1
+#define I2S5_HD_EN_MASK_SFT (0x1 << 12)
+#define I2S5_OUT_MODE_SFT 8
+#define I2S5_OUT_MODE_MASK 0xf
+#define I2S5_OUT_MODE_MASK_SFT (0xf << 8)
+#define INV_LRCK_SFT 5
+#define INV_LRCK_MASK 0x1
+#define INV_LRCK_MASK_SFT (0x1 << 5)
+#define I2S5_FMT_SFT 3
+#define I2S5_FMT_MASK 0x1
+#define I2S5_FMT_MASK_SFT (0x1 << 3)
+#define I2S5_WLEN_SFT 1
+#define I2S5_WLEN_MASK 0x1
+#define I2S5_WLEN_MASK_SFT (0x1 << 1)
+#define I2S5_EN_SFT 0
+#define I2S5_EN_MASK 0x1
+#define I2S5_EN_MASK_SFT (0x1 << 0)
+
+/* AFE_GAIN1_CON0 */
+#define GAIN1_SAMPLE_PER_STEP_SFT 8
+#define GAIN1_SAMPLE_PER_STEP_MASK 0xff
+#define GAIN1_SAMPLE_PER_STEP_MASK_SFT (0xff << 8)
+#define GAIN1_MODE_SFT 4
+#define GAIN1_MODE_MASK 0xf
+#define GAIN1_MODE_MASK_SFT (0xf << 4)
+#define GAIN1_ON_SFT 0
+#define GAIN1_ON_MASK 0x1
+#define GAIN1_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_GAIN1_CON1 */
+#define GAIN1_TARGET_SFT 0
+#define GAIN1_TARGET_MASK 0xfffff
+#define GAIN1_TARGET_MASK_SFT (0xfffff << 0)
+
+/* AFE_GAIN2_CON0 */
+#define GAIN2_SAMPLE_PER_STEP_SFT 8
+#define GAIN2_SAMPLE_PER_STEP_MASK 0xff
+#define GAIN2_SAMPLE_PER_STEP_MASK_SFT (0xff << 8)
+#define GAIN2_MODE_SFT 4
+#define GAIN2_MODE_MASK 0xf
+#define GAIN2_MODE_MASK_SFT (0xf << 4)
+#define GAIN2_ON_SFT 0
+#define GAIN2_ON_MASK 0x1
+#define GAIN2_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_GAIN2_CON1 */
+#define GAIN2_TARGET_SFT 0
+#define GAIN2_TARGET_MASK 0xfffff
+#define GAIN2_TARGET_MASK_SFT (0xfffff << 0)
+
+/* AFE_GAIN1_CUR */
+#define AFE_GAIN1_CUR_SFT 0
+#define AFE_GAIN1_CUR_MASK 0xfffff
+#define AFE_GAIN1_CUR_MASK_SFT (0xfffff << 0)
+
+/* AFE_GAIN2_CUR */
+#define AFE_GAIN2_CUR_SFT 0
+#define AFE_GAIN2_CUR_MASK 0xfffff
+#define AFE_GAIN2_CUR_MASK_SFT (0xfffff << 0)
+
+/* AFE_MEMIF_HD_MODE */
+#define AWB2_HD_SFT 28
+#define AWB2_HD_MASK 0x3
+#define AWB2_HD_MASK_SFT (0x3 << 28)
+#define HDMI_HD_SFT 20
+#define HDMI_HD_MASK 0x3
+#define HDMI_HD_MASK_SFT (0x3 << 20)
+#define MOD_DAI_HD_SFT 18
+#define MOD_DAI_HD_MASK 0x3
+#define MOD_DAI_HD_MASK_SFT (0x3 << 18)
+#define DAI_HD_SFT 16
+#define DAI_HD_MASK 0x3
+#define DAI_HD_MASK_SFT (0x3 << 16)
+#define VUL2_HD_SFT 14
+#define VUL2_HD_MASK 0x3
+#define VUL2_HD_MASK_SFT (0x3 << 14)
+#define VUL12_HD_SFT 12
+#define VUL12_HD_MASK 0x3
+#define VUL12_HD_MASK_SFT (0x3 << 12)
+#define VUL_HD_SFT 10
+#define VUL_HD_MASK 0x3
+#define VUL_HD_MASK_SFT (0x3 << 10)
+#define AWB_HD_SFT 8
+#define AWB_HD_MASK 0x3
+#define AWB_HD_MASK_SFT (0x3 << 8)
+#define DL3_HD_SFT 6
+#define DL3_HD_MASK 0x3
+#define DL3_HD_MASK_SFT (0x3 << 6)
+#define DL2_HD_SFT 4
+#define DL2_HD_MASK 0x3
+#define DL2_HD_MASK_SFT (0x3 << 4)
+#define DL1_HD_SFT 0
+#define DL1_HD_MASK 0x3
+#define DL1_HD_MASK_SFT (0x3 << 0)
+
+/* AFE_MEMIF_HDALIGN */
+#define AWB2_NORMAL_MODE_SFT 30
+#define AWB2_NORMAL_MODE_MASK 0x1
+#define AWB2_NORMAL_MODE_MASK_SFT (0x1 << 30)
+#define HDMI_NORMAL_MODE_SFT 26
+#define HDMI_NORMAL_MODE_MASK 0x1
+#define HDMI_NORMAL_MODE_MASK_SFT (0x1 << 26)
+#define MOD_DAI_NORMAL_MODE_SFT 25
+#define MOD_DAI_NORMAL_MODE_MASK 0x1
+#define MOD_DAI_NORMAL_MODE_MASK_SFT (0x1 << 25)
+#define DAI_NORMAL_MODE_SFT 24
+#define DAI_NORMAL_MODE_MASK 0x1
+#define DAI_NORMAL_MODE_MASK_SFT (0x1 << 24)
+#define VUL2_NORMAL_MODE_SFT 23
+#define VUL2_NORMAL_MODE_MASK 0x1
+#define VUL2_NORMAL_MODE_MASK_SFT (0x1 << 23)
+#define VUL12_NORMAL_MODE_SFT 22
+#define VUL12_NORMAL_MODE_MASK 0x1
+#define VUL12_NORMAL_MODE_MASK_SFT (0x1 << 22)
+#define VUL_NORMAL_MODE_SFT 21
+#define VUL_NORMAL_MODE_MASK 0x1
+#define VUL_NORMAL_MODE_MASK_SFT (0x1 << 21)
+#define AWB_NORMAL_MODE_SFT 20
+#define AWB_NORMAL_MODE_MASK 0x1
+#define AWB_NORMAL_MODE_MASK_SFT (0x1 << 20)
+#define DL3_NORMAL_MODE_SFT 19
+#define DL3_NORMAL_MODE_MASK 0x1
+#define DL3_NORMAL_MODE_MASK_SFT (0x1 << 19)
+#define DL2_NORMAL_MODE_SFT 18
+#define DL2_NORMAL_MODE_MASK 0x1
+#define DL2_NORMAL_MODE_MASK_SFT (0x1 << 18)
+#define DL1_NORMAL_MODE_SFT 16
+#define DL1_NORMAL_MODE_MASK 0x1
+#define DL1_NORMAL_MODE_MASK_SFT (0x1 << 16)
+#define RESERVED1_SFT 15
+#define RESERVED1_MASK 0x1
+#define RESERVED1_MASK_SFT (0x1 << 15)
+#define AWB2_ALIGN_SFT 14
+#define AWB2_ALIGN_MASK 0x1
+#define AWB2_ALIGN_MASK_SFT (0x1 << 14)
+#define HDMI_HD_ALIGN_SFT 10
+#define HDMI_HD_ALIGN_MASK 0x1
+#define HDMI_HD_ALIGN_MASK_SFT (0x1 << 10)
+#define MOD_DAI_HD_ALIGN_SFT 9
+#define MOD_DAI_HD_ALIGN_MASK 0x1
+#define MOD_DAI_HD_ALIGN_MASK_SFT (0x1 << 9)
+#define VUL2_HD_ALIGN_SFT 7
+#define VUL2_HD_ALIGN_MASK 0x1
+#define VUL2_HD_ALIGN_MASK_SFT (0x1 << 7)
+#define VUL12_HD_ALIGN_SFT 6
+#define VUL12_HD_ALIGN_MASK 0x1
+#define VUL12_HD_ALIGN_MASK_SFT (0x1 << 6)
+#define VUL_HD_ALIGN_SFT 5
+#define VUL_HD_ALIGN_MASK 0x1
+#define VUL_HD_ALIGN_MASK_SFT (0x1 << 5)
+#define AWB_HD_ALIGN_SFT 4
+#define AWB_HD_ALIGN_MASK 0x1
+#define AWB_HD_ALIGN_MASK_SFT (0x1 << 4)
+#define DL3_HD_ALIGN_SFT 3
+#define DL3_HD_ALIGN_MASK 0x1
+#define DL3_HD_ALIGN_MASK_SFT (0x1 << 3)
+#define DL2_HD_ALIGN_SFT 2
+#define DL2_HD_ALIGN_MASK 0x1
+#define DL2_HD_ALIGN_MASK_SFT (0x1 << 2)
+#define DL1_HD_ALIGN_SFT 0
+#define DL1_HD_ALIGN_MASK 0x1
+#define DL1_HD_ALIGN_MASK_SFT (0x1 << 0)
+
+/* PCM_INTF_CON1 */
+#define PCM_FIX_VALUE_SEL_SFT 31
+#define PCM_FIX_VALUE_SEL_MASK 0x1
+#define PCM_FIX_VALUE_SEL_MASK_SFT (0x1 << 31)
+#define PCM_BUFFER_LOOPBACK_SFT 30
+#define PCM_BUFFER_LOOPBACK_MASK 0x1
+#define PCM_BUFFER_LOOPBACK_MASK_SFT (0x1 << 30)
+#define PCM_PARALLEL_LOOPBACK_SFT 29
+#define PCM_PARALLEL_LOOPBACK_MASK 0x1
+#define PCM_PARALLEL_LOOPBACK_MASK_SFT (0x1 << 29)
+#define PCM_SERIAL_LOOPBACK_SFT 28
+#define PCM_SERIAL_LOOPBACK_MASK 0x1
+#define PCM_SERIAL_LOOPBACK_MASK_SFT (0x1 << 28)
+#define PCM_DAI_PCM_LOOPBACK_SFT 27
+#define PCM_DAI_PCM_LOOPBACK_MASK 0x1
+#define PCM_DAI_PCM_LOOPBACK_MASK_SFT (0x1 << 27)
+#define PCM_I2S_PCM_LOOPBACK_SFT 26
+#define PCM_I2S_PCM_LOOPBACK_MASK 0x1
+#define PCM_I2S_PCM_LOOPBACK_MASK_SFT (0x1 << 26)
+#define PCM_SYNC_DELSEL_SFT 25
+#define PCM_SYNC_DELSEL_MASK 0x1
+#define PCM_SYNC_DELSEL_MASK_SFT (0x1 << 25)
+#define PCM_TX_LR_SWAP_SFT 24
+#define PCM_TX_LR_SWAP_MASK 0x1
+#define PCM_TX_LR_SWAP_MASK_SFT (0x1 << 24)
+#define PCM_SYNC_OUT_INV_SFT 23
+#define PCM_SYNC_OUT_INV_MASK 0x1
+#define PCM_SYNC_OUT_INV_MASK_SFT (0x1 << 23)
+#define PCM_BCLK_OUT_INV_SFT 22
+#define PCM_BCLK_OUT_INV_MASK 0x1
+#define PCM_BCLK_OUT_INV_MASK_SFT (0x1 << 22)
+#define PCM_SYNC_IN_INV_SFT 21
+#define PCM_SYNC_IN_INV_MASK 0x1
+#define PCM_SYNC_IN_INV_MASK_SFT (0x1 << 21)
+#define PCM_BCLK_IN_INV_SFT 20
+#define PCM_BCLK_IN_INV_MASK 0x1
+#define PCM_BCLK_IN_INV_MASK_SFT (0x1 << 20)
+#define PCM_TX_LCH_RPT_SFT 19
+#define PCM_TX_LCH_RPT_MASK 0x1
+#define PCM_TX_LCH_RPT_MASK_SFT (0x1 << 19)
+#define PCM_VBT_16K_MODE_SFT 18
+#define PCM_VBT_16K_MODE_MASK 0x1
+#define PCM_VBT_16K_MODE_MASK_SFT (0x1 << 18)
+#define PCM_EXT_MODEM_SFT 17
+#define PCM_EXT_MODEM_MASK 0x1
+#define PCM_EXT_MODEM_MASK_SFT (0x1 << 17)
+#define PCM_24BIT_SFT 16
+#define PCM_24BIT_MASK 0x1
+#define PCM_24BIT_MASK_SFT (0x1 << 16)
+#define PCM_WLEN_SFT 14
+#define PCM_WLEN_MASK 0x3
+#define PCM_WLEN_MASK_SFT (0x3 << 14)
+#define PCM_SYNC_LENGTH_SFT 9
+#define PCM_SYNC_LENGTH_MASK 0x1f
+#define PCM_SYNC_LENGTH_MASK_SFT (0x1f << 9)
+#define PCM_SYNC_TYPE_SFT 8
+#define PCM_SYNC_TYPE_MASK 0x1
+#define PCM_SYNC_TYPE_MASK_SFT (0x1 << 8)
+#define PCM_BT_MODE_SFT 7
+#define PCM_BT_MODE_MASK 0x1
+#define PCM_BT_MODE_MASK_SFT (0x1 << 7)
+#define PCM_BYP_ASRC_SFT 6
+#define PCM_BYP_ASRC_MASK 0x1
+#define PCM_BYP_ASRC_MASK_SFT (0x1 << 6)
+#define PCM_SLAVE_SFT 5
+#define PCM_SLAVE_MASK 0x1
+#define PCM_SLAVE_MASK_SFT (0x1 << 5)
+#define PCM_MODE_SFT 3
+#define PCM_MODE_MASK 0x3
+#define PCM_MODE_MASK_SFT (0x3 << 3)
+#define PCM_FMT_SFT 1
+#define PCM_FMT_MASK 0x3
+#define PCM_FMT_MASK_SFT (0x3 << 1)
+#define PCM_EN_SFT 0
+#define PCM_EN_MASK 0x1
+#define PCM_EN_MASK_SFT (0x1 << 0)
+
+/* PCM_INTF_CON2 */
+#define PCM1_TX_FIFO_OV_SFT 31
+#define PCM1_TX_FIFO_OV_MASK 0x1
+#define PCM1_TX_FIFO_OV_MASK_SFT (0x1 << 31)
+#define PCM1_RX_FIFO_OV_SFT 30
+#define PCM1_RX_FIFO_OV_MASK 0x1
+#define PCM1_RX_FIFO_OV_MASK_SFT (0x1 << 30)
+#define PCM2_TX_FIFO_OV_SFT 29
+#define PCM2_TX_FIFO_OV_MASK 0x1
+#define PCM2_TX_FIFO_OV_MASK_SFT (0x1 << 29)
+#define PCM2_RX_FIFO_OV_SFT 28
+#define PCM2_RX_FIFO_OV_MASK 0x1
+#define PCM2_RX_FIFO_OV_MASK_SFT (0x1 << 28)
+#define PCM1_SYNC_GLITCH_SFT 27
+#define PCM1_SYNC_GLITCH_MASK 0x1
+#define PCM1_SYNC_GLITCH_MASK_SFT (0x1 << 27)
+#define PCM2_SYNC_GLITCH_SFT 26
+#define PCM2_SYNC_GLITCH_MASK 0x1
+#define PCM2_SYNC_GLITCH_MASK_SFT (0x1 << 26)
+#define TX3_RCH_DBG_MODE_SFT 17
+#define TX3_RCH_DBG_MODE_MASK 0x1
+#define TX3_RCH_DBG_MODE_MASK_SFT (0x1 << 17)
+#define PCM1_PCM2_LOOPBACK_SFT 16
+#define PCM1_PCM2_LOOPBACK_MASK 0x1
+#define PCM1_PCM2_LOOPBACK_MASK_SFT (0x1 << 16)
+#define DAI_PCM_LOOPBACK_CH_SFT 14
+#define DAI_PCM_LOOPBACK_CH_MASK 0x3
+#define DAI_PCM_LOOPBACK_CH_MASK_SFT (0x3 << 14)
+#define I2S_PCM_LOOPBACK_CH_SFT 12
+#define I2S_PCM_LOOPBACK_CH_MASK 0x3
+#define I2S_PCM_LOOPBACK_CH_MASK_SFT (0x3 << 12)
+#define TX_FIX_VALUE_SFT 0
+#define TX_FIX_VALUE_MASK 0xff
+#define TX_FIX_VALUE_MASK_SFT (0xff << 0)
+
+/* PCM2_INTF_CON */
+#define PCM2_TX_FIX_VALUE_SFT 24
+#define PCM2_TX_FIX_VALUE_MASK 0xff
+#define PCM2_TX_FIX_VALUE_MASK_SFT (0xff << 24)
+#define PCM2_FIX_VALUE_SEL_SFT 23
+#define PCM2_FIX_VALUE_SEL_MASK 0x1
+#define PCM2_FIX_VALUE_SEL_MASK_SFT (0x1 << 23)
+#define PCM2_BUFFER_LOOPBACK_SFT 22
+#define PCM2_BUFFER_LOOPBACK_MASK 0x1
+#define PCM2_BUFFER_LOOPBACK_MASK_SFT (0x1 << 22)
+#define PCM2_PARALLEL_LOOPBACK_SFT 21
+#define PCM2_PARALLEL_LOOPBACK_MASK 0x1
+#define PCM2_PARALLEL_LOOPBACK_MASK_SFT (0x1 << 21)
+#define PCM2_SERIAL_LOOPBACK_SFT 20
+#define PCM2_SERIAL_LOOPBACK_MASK 0x1
+#define PCM2_SERIAL_LOOPBACK_MASK_SFT (0x1 << 20)
+#define PCM2_DAI_PCM_LOOPBACK_SFT 19
+#define PCM2_DAI_PCM_LOOPBACK_MASK 0x1
+#define PCM2_DAI_PCM_LOOPBACK_MASK_SFT (0x1 << 19)
+#define PCM2_I2S_PCM_LOOPBACK_SFT 18
+#define PCM2_I2S_PCM_LOOPBACK_MASK 0x1
+#define PCM2_I2S_PCM_LOOPBACK_MASK_SFT (0x1 << 18)
+#define PCM2_SYNC_DELSEL_SFT 17
+#define PCM2_SYNC_DELSEL_MASK 0x1
+#define PCM2_SYNC_DELSEL_MASK_SFT (0x1 << 17)
+#define PCM2_TX_LR_SWAP_SFT 16
+#define PCM2_TX_LR_SWAP_MASK 0x1
+#define PCM2_TX_LR_SWAP_MASK_SFT (0x1 << 16)
+#define PCM2_SYNC_IN_INV_SFT 15
+#define PCM2_SYNC_IN_INV_MASK 0x1
+#define PCM2_SYNC_IN_INV_MASK_SFT (0x1 << 15)
+#define PCM2_BCLK_IN_INV_SFT 14
+#define PCM2_BCLK_IN_INV_MASK 0x1
+#define PCM2_BCLK_IN_INV_MASK_SFT (0x1 << 14)
+#define PCM2_TX_LCH_RPT_SFT 13
+#define PCM2_TX_LCH_RPT_MASK 0x1
+#define PCM2_TX_LCH_RPT_MASK_SFT (0x1 << 13)
+#define PCM2_VBT_16K_MODE_SFT 12
+#define PCM2_VBT_16K_MODE_MASK 0x1
+#define PCM2_VBT_16K_MODE_MASK_SFT (0x1 << 12)
+#define PCM2_LOOPBACK_CH_SEL_SFT 10
+#define PCM2_LOOPBACK_CH_SEL_MASK 0x3
+#define PCM2_LOOPBACK_CH_SEL_MASK_SFT (0x3 << 10)
+#define PCM2_TX2_BT_MODE_SFT 8
+#define PCM2_TX2_BT_MODE_MASK 0x1
+#define PCM2_TX2_BT_MODE_MASK_SFT (0x1 << 8)
+#define PCM2_BT_MODE_SFT 7
+#define PCM2_BT_MODE_MASK 0x1
+#define PCM2_BT_MODE_MASK_SFT (0x1 << 7)
+#define PCM2_AFIFO_SFT 6
+#define PCM2_AFIFO_MASK 0x1
+#define PCM2_AFIFO_MASK_SFT (0x1 << 6)
+#define PCM2_WLEN_SFT 5
+#define PCM2_WLEN_MASK 0x1
+#define PCM2_WLEN_MASK_SFT (0x1 << 5)
+#define PCM2_MODE_SFT 3
+#define PCM2_MODE_MASK 0x3
+#define PCM2_MODE_MASK_SFT (0x3 << 3)
+#define PCM2_FMT_SFT 1
+#define PCM2_FMT_MASK 0x3
+#define PCM2_FMT_MASK_SFT (0x3 << 1)
+#define PCM2_EN_SFT 0
+#define PCM2_EN_MASK 0x1
+#define PCM2_EN_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_MTKAIF_CFG0 */
+#define MTKAIF_RXIF_CLKINV_ADC_SFT 31
+#define MTKAIF_RXIF_CLKINV_ADC_MASK 0x1
+#define MTKAIF_RXIF_CLKINV_ADC_MASK_SFT (0x1 << 31)
+#define MTKAIF_RXIF_BYPASS_SRC_SFT 17
+#define MTKAIF_RXIF_BYPASS_SRC_MASK 0x1
+#define MTKAIF_RXIF_BYPASS_SRC_MASK_SFT (0x1 << 17)
+#define MTKAIF_RXIF_PROTOCOL2_SFT 16
+#define MTKAIF_RXIF_PROTOCOL2_MASK 0x1
+#define MTKAIF_RXIF_PROTOCOL2_MASK_SFT (0x1 << 16)
+#define MTKAIF_TXIF_BYPASS_SRC_SFT 5
+#define MTKAIF_TXIF_BYPASS_SRC_MASK 0x1
+#define MTKAIF_TXIF_BYPASS_SRC_MASK_SFT (0x1 << 5)
+#define MTKAIF_TXIF_PROTOCOL2_SFT 4
+#define MTKAIF_TXIF_PROTOCOL2_MASK 0x1
+#define MTKAIF_TXIF_PROTOCOL2_MASK_SFT (0x1 << 4)
+#define MTKAIF_TXIF_8TO5_SFT 2
+#define MTKAIF_TXIF_8TO5_MASK 0x1
+#define MTKAIF_TXIF_8TO5_MASK_SFT (0x1 << 2)
+#define MTKAIF_RXIF_8TO5_SFT 1
+#define MTKAIF_RXIF_8TO5_MASK 0x1
+#define MTKAIF_RXIF_8TO5_MASK_SFT (0x1 << 1)
+#define MTKAIF_IF_LOOPBACK1_SFT 0
+#define MTKAIF_IF_LOOPBACK1_MASK 0x1
+#define MTKAIF_IF_LOOPBACK1_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_MTKAIF_RX_CFG2 */
+#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_SFT 16
+#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK 0x1
+#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK_SFT (0x1 << 16)
+#define MTKAIF_RXIF_DELAY_CYCLE_SFT 12
+#define MTKAIF_RXIF_DELAY_CYCLE_MASK 0xf
+#define MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT (0xf << 12)
+#define MTKAIF_RXIF_DELAY_DATA_SFT 8
+#define MTKAIF_RXIF_DELAY_DATA_MASK 0x1
+#define MTKAIF_RXIF_DELAY_DATA_MASK_SFT (0x1 << 8)
+#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_SFT 4
+#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK 0x7
+#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK_SFT (0x7 << 4)
+
+/* AFE_ADDA_DL_SRC2_CON0 */
+#define DL_2_INPUT_MODE_CTL_SFT 28
+#define DL_2_INPUT_MODE_CTL_MASK 0xf
+#define DL_2_INPUT_MODE_CTL_MASK_SFT (0xf << 28)
+#define DL_2_CH1_SATURATION_EN_CTL_SFT 27
+#define DL_2_CH1_SATURATION_EN_CTL_MASK 0x1
+#define DL_2_CH1_SATURATION_EN_CTL_MASK_SFT (0x1 << 27)
+#define DL_2_CH2_SATURATION_EN_CTL_SFT 26
+#define DL_2_CH2_SATURATION_EN_CTL_MASK 0x1
+#define DL_2_CH2_SATURATION_EN_CTL_MASK_SFT (0x1 << 26)
+#define DL_2_OUTPUT_SEL_CTL_SFT 24
+#define DL_2_OUTPUT_SEL_CTL_MASK 0x3
+#define DL_2_OUTPUT_SEL_CTL_MASK_SFT (0x3 << 24)
+#define DL_2_FADEIN_0START_EN_SFT 16
+#define DL_2_FADEIN_0START_EN_MASK 0x3
+#define DL_2_FADEIN_0START_EN_MASK_SFT (0x3 << 16)
+#define DL_DISABLE_HW_CG_CTL_SFT 15
+#define DL_DISABLE_HW_CG_CTL_MASK 0x1
+#define DL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 15)
+#define C_DATA_EN_SEL_CTL_PRE_SFT 14
+#define C_DATA_EN_SEL_CTL_PRE_MASK 0x1
+#define C_DATA_EN_SEL_CTL_PRE_MASK_SFT (0x1 << 14)
+#define DL_2_SIDE_TONE_ON_CTL_PRE_SFT 13
+#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK 0x1
+#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK_SFT (0x1 << 13)
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_SFT 12
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK 0x1
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK_SFT (0x1 << 12)
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_SFT 11
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK 0x1
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK_SFT (0x1 << 11)
+#define DL2_ARAMPSP_CTL_PRE_SFT 9
+#define DL2_ARAMPSP_CTL_PRE_MASK 0x3
+#define DL2_ARAMPSP_CTL_PRE_MASK_SFT (0x3 << 9)
+#define DL_2_IIRMODE_CTL_PRE_SFT 6
+#define DL_2_IIRMODE_CTL_PRE_MASK 0x7
+#define DL_2_IIRMODE_CTL_PRE_MASK_SFT (0x7 << 6)
+#define DL_2_VOICE_MODE_CTL_PRE_SFT 5
+#define DL_2_VOICE_MODE_CTL_PRE_MASK 0x1
+#define DL_2_VOICE_MODE_CTL_PRE_MASK_SFT (0x1 << 5)
+#define D2_2_MUTE_CH1_ON_CTL_PRE_SFT 4
+#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK 0x1
+#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK_SFT (0x1 << 4)
+#define D2_2_MUTE_CH2_ON_CTL_PRE_SFT 3
+#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK 0x1
+#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK_SFT (0x1 << 3)
+#define DL_2_IIR_ON_CTL_PRE_SFT 2
+#define DL_2_IIR_ON_CTL_PRE_MASK 0x1
+#define DL_2_IIR_ON_CTL_PRE_MASK_SFT (0x1 << 2)
+#define DL_2_GAIN_ON_CTL_PRE_SFT 1
+#define DL_2_GAIN_ON_CTL_PRE_MASK 0x1
+#define DL_2_GAIN_ON_CTL_PRE_MASK_SFT (0x1 << 1)
+#define DL_2_SRC_ON_TMP_CTL_PRE_SFT 0
+#define DL_2_SRC_ON_TMP_CTL_PRE_MASK 0x1
+#define DL_2_SRC_ON_TMP_CTL_PRE_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_DL_SRC2_CON1 */
+#define DL_2_GAIN_CTL_PRE_SFT 16
+#define DL_2_GAIN_CTL_PRE_MASK 0xffff
+#define DL_2_GAIN_CTL_PRE_MASK_SFT (0xffff << 16)
+#define DL_2_GAIN_MODE_CTL_SFT 0
+#define DL_2_GAIN_MODE_CTL_MASK 0x1
+#define DL_2_GAIN_MODE_CTL_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_UL_SRC_CON0 */
+#define ULCF_CFG_EN_CTL_SFT 31
+#define ULCF_CFG_EN_CTL_MASK 0x1
+#define ULCF_CFG_EN_CTL_MASK_SFT (0x1 << 31)
+#define UL_MODE_3P25M_CH2_CTL_SFT 22
+#define UL_MODE_3P25M_CH2_CTL_MASK 0x1
+#define UL_MODE_3P25M_CH2_CTL_MASK_SFT (0x1 << 22)
+#define UL_MODE_3P25M_CH1_CTL_SFT 21
+#define UL_MODE_3P25M_CH1_CTL_MASK 0x1
+#define UL_MODE_3P25M_CH1_CTL_MASK_SFT (0x1 << 21)
+#define UL_VOICE_MODE_CH1_CH2_CTL_SFT 17
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK 0x7
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT (0x7 << 17)
+#define DMIC_LOW_POWER_MODE_CTL_SFT 14
+#define DMIC_LOW_POWER_MODE_CTL_MASK 0x3
+#define DMIC_LOW_POWER_MODE_CTL_MASK_SFT (0x3 << 14)
+#define UL_DISABLE_HW_CG_CTL_SFT 12
+#define UL_DISABLE_HW_CG_CTL_MASK 0x1
+#define UL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 12)
+#define UL_IIR_ON_TMP_CTL_SFT 10
+#define UL_IIR_ON_TMP_CTL_MASK 0x1
+#define UL_IIR_ON_TMP_CTL_MASK_SFT (0x1 << 10)
+#define UL_IIRMODE_CTL_SFT 7
+#define UL_IIRMODE_CTL_MASK 0x7
+#define UL_IIRMODE_CTL_MASK_SFT (0x7 << 7)
+#define DIGMIC_3P25M_1P625M_SEL_CTL_SFT 5
+#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK 0x1
+#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT (0x1 << 5)
+#define UL_LOOP_BACK_MODE_CTL_SFT 2
+#define UL_LOOP_BACK_MODE_CTL_MASK 0x1
+#define UL_LOOP_BACK_MODE_CTL_MASK_SFT (0x1 << 2)
+#define UL_SDM_3_LEVEL_CTL_SFT 1
+#define UL_SDM_3_LEVEL_CTL_MASK 0x1
+#define UL_SDM_3_LEVEL_CTL_MASK_SFT (0x1 << 1)
+#define UL_SRC_ON_TMP_CTL_SFT 0
+#define UL_SRC_ON_TMP_CTL_MASK 0x1
+#define UL_SRC_ON_TMP_CTL_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_UL_SRC_CON1 */
+#define C_DAC_EN_CTL_SFT 27
+#define C_DAC_EN_CTL_MASK 0x1
+#define C_DAC_EN_CTL_MASK_SFT (0x1 << 27)
+#define C_MUTE_SW_CTL_SFT 26
+#define C_MUTE_SW_CTL_MASK 0x1
+#define C_MUTE_SW_CTL_MASK_SFT (0x1 << 26)
+#define ASDM_SRC_SEL_CTL_SFT 25
+#define ASDM_SRC_SEL_CTL_MASK 0x1
+#define ASDM_SRC_SEL_CTL_MASK_SFT (0x1 << 25)
+#define C_AMP_DIV_CH2_CTL_SFT 21
+#define C_AMP_DIV_CH2_CTL_MASK 0x7
+#define C_AMP_DIV_CH2_CTL_MASK_SFT (0x7 << 21)
+#define C_FREQ_DIV_CH2_CTL_SFT 16
+#define C_FREQ_DIV_CH2_CTL_MASK 0x1f
+#define C_FREQ_DIV_CH2_CTL_MASK_SFT (0x1f << 16)
+#define C_SINE_MODE_CH2_CTL_SFT 12
+#define C_SINE_MODE_CH2_CTL_MASK 0xf
+#define C_SINE_MODE_CH2_CTL_MASK_SFT (0xf << 12)
+#define C_AMP_DIV_CH1_CTL_SFT 9
+#define C_AMP_DIV_CH1_CTL_MASK 0x7
+#define C_AMP_DIV_CH1_CTL_MASK_SFT (0x7 << 9)
+#define C_FREQ_DIV_CH1_CTL_SFT 4
+#define C_FREQ_DIV_CH1_CTL_MASK 0x1f
+#define C_FREQ_DIV_CH1_CTL_MASK_SFT (0x1f << 4)
+#define C_SINE_MODE_CH1_CTL_SFT 0
+#define C_SINE_MODE_CH1_CTL_MASK 0xf
+#define C_SINE_MODE_CH1_CTL_MASK_SFT (0xf << 0)
+
+/* AFE_ADDA_TOP_CON0 */
+#define C_LOOP_BACK_MODE_CTL_SFT 12
+#define C_LOOP_BACK_MODE_CTL_MASK 0xf
+#define C_LOOP_BACK_MODE_CTL_MASK_SFT (0xf << 12)
+#define C_EXT_ADC_CTL_SFT 0
+#define C_EXT_ADC_CTL_MASK 0x1
+#define C_EXT_ADC_CTL_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_UL_DL_CON0 */
+#define AFE_ADDA6_UL_LR_SWAP_SFT 15
+#define AFE_ADDA6_UL_LR_SWAP_MASK 0x1
+#define AFE_ADDA6_UL_LR_SWAP_MASK_SFT (0x1 << 15)
+#define AFE_ADDA6_CKDIV_RST_SFT 14
+#define AFE_ADDA6_CKDIV_RST_MASK 0x1
+#define AFE_ADDA6_CKDIV_RST_MASK_SFT (0x1 << 14)
+#define AFE_ADDA6_FIFO_AUTO_RST_SFT 13
+#define AFE_ADDA6_FIFO_AUTO_RST_MASK 0x1
+#define AFE_ADDA6_FIFO_AUTO_RST_MASK_SFT (0x1 << 13)
+#define UL_FIFO_DIGMIC_TESTIN_SFT 5
+#define UL_FIFO_DIGMIC_TESTIN_MASK 0x3
+#define UL_FIFO_DIGMIC_TESTIN_MASK_SFT (0x3 << 5)
+#define UL_FIFO_DIGMIC_WDATA_TESTEN_SFT 4
+#define UL_FIFO_DIGMIC_WDATA_TESTEN_MASK 0x1
+#define UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT (0x1 << 4)
+#define ADDA_AFE_ON_SFT 0
+#define ADDA_AFE_ON_MASK 0x1
+#define ADDA_AFE_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_SIDETONE_CON0 */
+#define R_RDY_SFT 30
+#define R_RDY_MASK 0x1
+#define R_RDY_MASK_SFT (0x1 << 30)
+#define W_RDY_SFT 29
+#define W_RDY_MASK 0x1
+#define W_RDY_MASK_SFT (0x1 << 29)
+#define R_W_EN_SFT 25
+#define R_W_EN_MASK 0x1
+#define R_W_EN_MASK_SFT (0x1 << 25)
+#define R_W_SEL_SFT 24
+#define R_W_SEL_MASK 0x1
+#define R_W_SEL_MASK_SFT (0x1 << 24)
+#define SEL_CH2_SFT 23
+#define SEL_CH2_MASK 0x1
+#define SEL_CH2_MASK_SFT (0x1 << 23)
+#define SIDE_TONE_COEFFICIENT_ADDR_SFT 16
+#define SIDE_TONE_COEFFICIENT_ADDR_MASK 0x1f
+#define SIDE_TONE_COEFFICIENT_ADDR_MASK_SFT (0x1f << 16)
+#define SIDE_TONE_COEFFICIENT_SFT 0
+#define SIDE_TONE_COEFFICIENT_MASK 0xffff
+#define SIDE_TONE_COEFFICIENT_MASK_SFT (0xffff << 0)
+
+/* AFE_SIDETONE_COEFF */
+#define SIDE_TONE_COEFF_SFT 0
+#define SIDE_TONE_COEFF_MASK 0xffff
+#define SIDE_TONE_COEFF_MASK_SFT (0xffff << 0)
+
+/* AFE_SIDETONE_CON1 */
+#define STF_BYPASS_MODE_SFT 31
+#define STF_BYPASS_MODE_MASK 0x1
+#define STF_BYPASS_MODE_MASK_SFT (0x1 << 31)
+#define STF_BYPASS_MODE_O28_O29_SFT 30
+#define STF_BYPASS_MODE_O28_O29_MASK 0x1
+#define STF_BYPASS_MODE_O28_O29_MASK_SFT (0x1 << 30)
+#define STF_BYPASS_MODE_I2S4_SFT 29
+#define STF_BYPASS_MODE_I2S4_MASK 0x1
+#define STF_BYPASS_MODE_I2S4_MASK_SFT (0x1 << 29)
+#define STF_BYPASS_MODE_I2S5_SFT 28
+#define STF_BYPASS_MODE_I2S5_MASK 0x1
+#define STF_BYPASS_MODE_I2S5_MASK_SFT (0x1 << 28)
+#define STF_INPUT_EN_SEL_SFT 13
+#define STF_INPUT_EN_SEL_MASK 0x1
+#define STF_INPUT_EN_SEL_MASK_SFT (0x1 << 13)
+#define STF_SOURCE_FROM_O19O20_SFT 12
+#define STF_SOURCE_FROM_O19O20_MASK 0x1
+#define STF_SOURCE_FROM_O19O20_MASK_SFT (0x1 << 12)
+#define SIDE_TONE_ON_SFT 8
+#define SIDE_TONE_ON_MASK 0x1
+#define SIDE_TONE_ON_MASK_SFT (0x1 << 8)
+#define SIDE_TONE_HALF_TAP_NUM_SFT 0
+#define SIDE_TONE_HALF_TAP_NUM_MASK 0x3f
+#define SIDE_TONE_HALF_TAP_NUM_MASK_SFT (0x3f << 0)
+
+/* AFE_SIDETONE_GAIN */
+#define POSITIVE_GAIN_SFT 16
+#define POSITIVE_GAIN_MASK 0x7
+#define POSITIVE_GAIN_MASK_SFT (0x7 << 16)
+#define SIDE_TONE_GAIN_SFT 0
+#define SIDE_TONE_GAIN_MASK 0xffff
+#define SIDE_TONE_GAIN_MASK_SFT (0xffff << 0)
+
+/* AFE_ADDA_DL_SDM_DCCOMP_CON */
+#define AUD_DC_COMP_EN_SFT 8
+#define AUD_DC_COMP_EN_MASK 0x1
+#define AUD_DC_COMP_EN_MASK_SFT (0x1 << 8)
+#define ATTGAIN_CTL_SFT 0
+#define ATTGAIN_CTL_MASK 0x3f
+#define ATTGAIN_CTL_MASK_SFT (0x3f << 0)
+
+/* AFE_SINEGEN_CON0 */
+#define DAC_EN_SFT 26
+#define DAC_EN_MASK 0x1
+#define DAC_EN_MASK_SFT (0x1 << 26)
+#define MUTE_SW_CH2_SFT 25
+#define MUTE_SW_CH2_MASK 0x1
+#define MUTE_SW_CH2_MASK_SFT (0x1 << 25)
+#define MUTE_SW_CH1_SFT 24
+#define MUTE_SW_CH1_MASK 0x1
+#define MUTE_SW_CH1_MASK_SFT (0x1 << 24)
+#define SINE_MODE_CH2_SFT 20
+#define SINE_MODE_CH2_MASK 0xf
+#define SINE_MODE_CH2_MASK_SFT (0xf << 20)
+#define AMP_DIV_CH2_SFT 17
+#define AMP_DIV_CH2_MASK 0x7
+#define AMP_DIV_CH2_MASK_SFT (0x7 << 17)
+#define FREQ_DIV_CH2_SFT 12
+#define FREQ_DIV_CH2_MASK 0x1f
+#define FREQ_DIV_CH2_MASK_SFT (0x1f << 12)
+#define SINE_MODE_CH1_SFT 8
+#define SINE_MODE_CH1_MASK 0xf
+#define SINE_MODE_CH1_MASK_SFT (0xf << 8)
+#define AMP_DIV_CH1_SFT 5
+#define AMP_DIV_CH1_MASK 0x7
+#define AMP_DIV_CH1_MASK_SFT (0x7 << 5)
+#define FREQ_DIV_CH1_SFT 0
+#define FREQ_DIV_CH1_MASK 0x1f
+#define FREQ_DIV_CH1_MASK_SFT (0x1f << 0)
+
+/* AFE_SINEGEN_CON2 */
+#define INNER_LOOP_BACK_MODE_SFT 0
+#define INNER_LOOP_BACK_MODE_MASK 0x3f
+#define INNER_LOOP_BACK_MODE_MASK_SFT (0x3f << 0)
+
+/* AFE_MEMIF_MINLEN */
+#define HDMI_MINLEN_SFT 24
+#define HDMI_MINLEN_MASK 0xf
+#define HDMI_MINLEN_MASK_SFT (0xf << 24)
+#define DL3_MINLEN_SFT 12
+#define DL3_MINLEN_MASK 0xf
+#define DL3_MINLEN_MASK_SFT (0xf << 12)
+#define DL2_MINLEN_SFT 8
+#define DL2_MINLEN_MASK 0xf
+#define DL2_MINLEN_MASK_SFT (0xf << 8)
+#define DL1_DATA2_MINLEN_SFT 4
+#define DL1_DATA2_MINLEN_MASK 0xf
+#define DL1_DATA2_MINLEN_MASK_SFT (0xf << 4)
+#define DL1_MINLEN_SFT 0
+#define DL1_MINLEN_MASK 0xf
+#define DL1_MINLEN_MASK_SFT (0xf << 0)
+
+/* AFE_MEMIF_MAXLEN */
+#define HDMI_MAXLEN_SFT 24
+#define HDMI_MAXLEN_MASK 0xf
+#define HDMI_MAXLEN_MASK_SFT (0xf << 24)
+#define DL3_MAXLEN_SFT 8
+#define DL3_MAXLEN_MASK 0xf
+#define DL3_MAXLEN_MASK_SFT (0xf << 8)
+#define DL2_MAXLEN_SFT 4
+#define DL2_MAXLEN_MASK 0xf
+#define DL2_MAXLEN_MASK_SFT (0xf << 4)
+#define DL1_MAXLEN_SFT 0
+#define DL1_MAXLEN_MASK 0x3
+#define DL1_MAXLEN_MASK_SFT (0x3 << 0)
+
+/* AFE_MEMIF_PBUF_SIZE */
+#define VUL12_4CH_SFT 17
+#define VUL12_4CH_MASK 0x1
+#define VUL12_4CH_MASK_SFT (0x1 << 17)
+#define DL3_PBUF_SIZE_SFT 10
+#define DL3_PBUF_SIZE_MASK 0x3
+#define DL3_PBUF_SIZE_MASK_SFT (0x3 << 10)
+#define HDMI_PBUF_SIZE_SFT 4
+#define HDMI_PBUF_SIZE_MASK 0x3
+#define HDMI_PBUF_SIZE_MASK_SFT (0x3 << 4)
+#define DL2_PBUF_SIZE_SFT 2
+#define DL2_PBUF_SIZE_MASK 0x3
+#define DL2_PBUF_SIZE_MASK_SFT (0x3 << 2)
+#define DL1_PBUF_SIZE_SFT 0
+#define DL1_PBUF_SIZE_MASK 0x3
+#define DL1_PBUF_SIZE_MASK_SFT (0x3 << 0)
+
+/* AFE_HD_ENGEN_ENABLE */
+#define AFE_24M_ON_SFT 1
+#define AFE_24M_ON_MASK 0x1
+#define AFE_24M_ON_MASK_SFT (0x1 << 1)
+#define AFE_22M_ON_SFT 0
+#define AFE_22M_ON_MASK 0x1
+#define AFE_22M_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ_MCU_CON0 */
+#define IRQ12_MCU_ON_SFT 12
+#define IRQ12_MCU_ON_MASK 0x1
+#define IRQ12_MCU_ON_MASK_SFT (0x1 << 12)
+#define IRQ11_MCU_ON_SFT 11
+#define IRQ11_MCU_ON_MASK 0x1
+#define IRQ11_MCU_ON_MASK_SFT (0x1 << 11)
+#define IRQ10_MCU_ON_SFT 10
+#define IRQ10_MCU_ON_MASK 0x1
+#define IRQ10_MCU_ON_MASK_SFT (0x1 << 10)
+#define IRQ9_MCU_ON_SFT 9
+#define IRQ9_MCU_ON_MASK 0x1
+#define IRQ9_MCU_ON_MASK_SFT (0x1 << 9)
+#define IRQ8_MCU_ON_SFT 8
+#define IRQ8_MCU_ON_MASK 0x1
+#define IRQ8_MCU_ON_MASK_SFT (0x1 << 8)
+#define IRQ7_MCU_ON_SFT 7
+#define IRQ7_MCU_ON_MASK 0x1
+#define IRQ7_MCU_ON_MASK_SFT (0x1 << 7)
+#define IRQ6_MCU_ON_SFT 6
+#define IRQ6_MCU_ON_MASK 0x1
+#define IRQ6_MCU_ON_MASK_SFT (0x1 << 6)
+#define IRQ5_MCU_ON_SFT 5
+#define IRQ5_MCU_ON_MASK 0x1
+#define IRQ5_MCU_ON_MASK_SFT (0x1 << 5)
+#define IRQ4_MCU_ON_SFT 4
+#define IRQ4_MCU_ON_MASK 0x1
+#define IRQ4_MCU_ON_MASK_SFT (0x1 << 4)
+#define IRQ3_MCU_ON_SFT 3
+#define IRQ3_MCU_ON_MASK 0x1
+#define IRQ3_MCU_ON_MASK_SFT (0x1 << 3)
+#define IRQ2_MCU_ON_SFT 2
+#define IRQ2_MCU_ON_MASK 0x1
+#define IRQ2_MCU_ON_MASK_SFT (0x1 << 2)
+#define IRQ1_MCU_ON_SFT 1
+#define IRQ1_MCU_ON_MASK 0x1
+#define IRQ1_MCU_ON_MASK_SFT (0x1 << 1)
+#define IRQ0_MCU_ON_SFT 0
+#define IRQ0_MCU_ON_MASK 0x1
+#define IRQ0_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ_MCU_CON1 */
+#define IRQ7_MCU_MODE_SFT 28
+#define IRQ7_MCU_MODE_MASK 0xf
+#define IRQ7_MCU_MODE_MASK_SFT (0xf << 28)
+#define IRQ6_MCU_MODE_SFT 24
+#define IRQ6_MCU_MODE_MASK 0xf
+#define IRQ6_MCU_MODE_MASK_SFT (0xf << 24)
+#define IRQ5_MCU_MODE_SFT 20
+#define IRQ5_MCU_MODE_MASK 0xf
+#define IRQ5_MCU_MODE_MASK_SFT (0xf << 20)
+#define IRQ4_MCU_MODE_SFT 16
+#define IRQ4_MCU_MODE_MASK 0xf
+#define IRQ4_MCU_MODE_MASK_SFT (0xf << 16)
+#define IRQ3_MCU_MODE_SFT 12
+#define IRQ3_MCU_MODE_MASK 0xf
+#define IRQ3_MCU_MODE_MASK_SFT (0xf << 12)
+#define IRQ2_MCU_MODE_SFT 8
+#define IRQ2_MCU_MODE_MASK 0xf
+#define IRQ2_MCU_MODE_MASK_SFT (0xf << 8)
+#define IRQ1_MCU_MODE_SFT 4
+#define IRQ1_MCU_MODE_MASK 0xf
+#define IRQ1_MCU_MODE_MASK_SFT (0xf << 4)
+#define IRQ0_MCU_MODE_SFT 0
+#define IRQ0_MCU_MODE_MASK 0xf
+#define IRQ0_MCU_MODE_MASK_SFT (0xf << 0)
+
+/* AFE_IRQ_MCU_CON2 */
+#define IRQ12_MCU_MODE_SFT 4
+#define IRQ12_MCU_MODE_MASK 0xf
+#define IRQ12_MCU_MODE_MASK_SFT (0xf << 4)
+#define IRQ11_MCU_MODE_SFT 0
+#define IRQ11_MCU_MODE_MASK 0xf
+#define IRQ11_MCU_MODE_MASK_SFT (0xf << 0)
+
+/* AFE_IRQ_MCU_CLR */
+#define IRQ12_MCU_MISS_CNT_CLR_SFT 28
+#define IRQ12_MCU_MISS_CNT_CLR_MASK 0x1
+#define IRQ12_MCU_MISS_CNT_CLR_MASK_SFT (0x1 << 28)
+#define IRQ11_MCU_MISS_CNT_CLR_SFT 27
+#define IRQ11_MCU_MISS_CNT_CLR_MASK 0x1
+#define IRQ11_MCU_MISS_CNT_CLR_MASK_SFT (0x1 << 27)
+#define IRQ10_MCU_MISS_CLR_SFT 26
+#define IRQ10_MCU_MISS_CLR_MASK 0x1
+#define IRQ10_MCU_MISS_CLR_MASK_SFT (0x1 << 26)
+#define IRQ9_MCU_MISS_CLR_SFT 25
+#define IRQ9_MCU_MISS_CLR_MASK 0x1
+#define IRQ9_MCU_MISS_CLR_MASK_SFT (0x1 << 25)
+#define IRQ8_MCU_MISS_CLR_SFT 24
+#define IRQ8_MCU_MISS_CLR_MASK 0x1
+#define IRQ8_MCU_MISS_CLR_MASK_SFT (0x1 << 24)
+#define IRQ7_MCU_MISS_CLR_SFT 23
+#define IRQ7_MCU_MISS_CLR_MASK 0x1
+#define IRQ7_MCU_MISS_CLR_MASK_SFT (0x1 << 23)
+#define IRQ6_MCU_MISS_CLR_SFT 22
+#define IRQ6_MCU_MISS_CLR_MASK 0x1
+#define IRQ6_MCU_MISS_CLR_MASK_SFT (0x1 << 22)
+#define IRQ5_MCU_MISS_CLR_SFT 21
+#define IRQ5_MCU_MISS_CLR_MASK 0x1
+#define IRQ5_MCU_MISS_CLR_MASK_SFT (0x1 << 21)
+#define IRQ4_MCU_MISS_CLR_SFT 20
+#define IRQ4_MCU_MISS_CLR_MASK 0x1
+#define IRQ4_MCU_MISS_CLR_MASK_SFT (0x1 << 20)
+#define IRQ3_MCU_MISS_CLR_SFT 19
+#define IRQ3_MCU_MISS_CLR_MASK 0x1
+#define IRQ3_MCU_MISS_CLR_MASK_SFT (0x1 << 19)
+#define IRQ2_MCU_MISS_CLR_SFT 18
+#define IRQ2_MCU_MISS_CLR_MASK 0x1
+#define IRQ2_MCU_MISS_CLR_MASK_SFT (0x1 << 18)
+#define IRQ1_MCU_MISS_CLR_SFT 17
+#define IRQ1_MCU_MISS_CLR_MASK 0x1
+#define IRQ1_MCU_MISS_CLR_MASK_SFT (0x1 << 17)
+#define IRQ0_MCU_MISS_CLR_SFT 16
+#define IRQ0_MCU_MISS_CLR_MASK 0x1
+#define IRQ0_MCU_MISS_CLR_MASK_SFT (0x1 << 16)
+#define IRQ12_MCU_CLR_SFT 12
+#define IRQ12_MCU_CLR_MASK 0x1
+#define IRQ12_MCU_CLR_MASK_SFT (0x1 << 12)
+#define IRQ11_MCU_CLR_SFT 11
+#define IRQ11_MCU_CLR_MASK 0x1
+#define IRQ11_MCU_CLR_MASK_SFT (0x1 << 11)
+#define IRQ10_MCU_CLR_SFT 10
+#define IRQ10_MCU_CLR_MASK 0x1
+#define IRQ10_MCU_CLR_MASK_SFT (0x1 << 10)
+#define IRQ9_MCU_CLR_SFT 9
+#define IRQ9_MCU_CLR_MASK 0x1
+#define IRQ9_MCU_CLR_MASK_SFT (0x1 << 9)
+#define IRQ8_MCU_CLR_SFT 8
+#define IRQ8_MCU_CLR_MASK 0x1
+#define IRQ8_MCU_CLR_MASK_SFT (0x1 << 8)
+#define IRQ7_MCU_CLR_SFT 7
+#define IRQ7_MCU_CLR_MASK 0x1
+#define IRQ7_MCU_CLR_MASK_SFT (0x1 << 7)
+#define IRQ6_MCU_CLR_SFT 6
+#define IRQ6_MCU_CLR_MASK 0x1
+#define IRQ6_MCU_CLR_MASK_SFT (0x1 << 6)
+#define IRQ5_MCU_CLR_SFT 5
+#define IRQ5_MCU_CLR_MASK 0x1
+#define IRQ5_MCU_CLR_MASK_SFT (0x1 << 5)
+#define IRQ4_MCU_CLR_SFT 4
+#define IRQ4_MCU_CLR_MASK 0x1
+#define IRQ4_MCU_CLR_MASK_SFT (0x1 << 4)
+#define IRQ3_MCU_CLR_SFT 3
+#define IRQ3_MCU_CLR_MASK 0x1
+#define IRQ3_MCU_CLR_MASK_SFT (0x1 << 3)
+#define IRQ2_MCU_CLR_SFT 2
+#define IRQ2_MCU_CLR_MASK 0x1
+#define IRQ2_MCU_CLR_MASK_SFT (0x1 << 2)
+#define IRQ1_MCU_CLR_SFT 1
+#define IRQ1_MCU_CLR_MASK 0x1
+#define IRQ1_MCU_CLR_MASK_SFT (0x1 << 1)
+#define IRQ0_MCU_CLR_SFT 0
+#define IRQ0_MCU_CLR_MASK 0x1
+#define IRQ0_MCU_CLR_MASK_SFT (0x1 << 0)
+
+/* AFE_MEMIF_MSB */
+#define CPU_COMPACT_MODE_SFT 29
+#define CPU_COMPACT_MODE_MASK 0x1
+#define CPU_COMPACT_MODE_MASK_SFT (0x1 << 29)
+#define CPU_HD_ALIGN_SFT 28
+#define CPU_HD_ALIGN_MASK 0x1
+#define CPU_HD_ALIGN_MASK_SFT (0x1 << 28)
+#define AWB2_AXI_WR_SIGN_SFT 24
+#define AWB2_AXI_WR_SIGN_MASK 0x1
+#define AWB2_AXI_WR_SIGN_MASK_SFT (0x1 << 24)
+#define VUL2_AXI_WR_SIGN_SFT 22
+#define VUL2_AXI_WR_SIGN_MASK 0x1
+#define VUL2_AXI_WR_SIGN_MASK_SFT (0x1 << 22)
+#define VUL12_AXI_WR_SIGN_SFT 21
+#define VUL12_AXI_WR_SIGN_MASK 0x1
+#define VUL12_AXI_WR_SIGN_MASK_SFT (0x1 << 21)
+#define VUL_AXI_WR_SIGN_SFT 20
+#define VUL_AXI_WR_SIGN_MASK 0x1
+#define VUL_AXI_WR_SIGN_MASK_SFT (0x1 << 20)
+#define MOD_DAI_AXI_WR_SIGN_SFT 18
+#define MOD_DAI_AXI_WR_SIGN_MASK 0x1
+#define MOD_DAI_AXI_WR_SIGN_MASK_SFT (0x1 << 18)
+#define AWB_MSTR_SIGN_SFT 17
+#define AWB_MSTR_SIGN_MASK 0x1
+#define AWB_MSTR_SIGN_MASK_SFT (0x1 << 17)
+#define SYSRAM_SIGN_SFT 16
+#define SYSRAM_SIGN_MASK 0x1
+#define SYSRAM_SIGN_MASK_SFT (0x1 << 16)
+
+/* AFE_HDMI_CONN0 */
+#define HDMI_O_7_SFT 21
+#define HDMI_O_7_MASK 0x7
+#define HDMI_O_7_MASK_SFT (0x7 << 21)
+#define HDMI_O_6_SFT 18
+#define HDMI_O_6_MASK 0x7
+#define HDMI_O_6_MASK_SFT (0x7 << 18)
+#define HDMI_O_5_SFT 15
+#define HDMI_O_5_MASK 0x7
+#define HDMI_O_5_MASK_SFT (0x7 << 15)
+#define HDMI_O_4_SFT 12
+#define HDMI_O_4_MASK 0x7
+#define HDMI_O_4_MASK_SFT (0x7 << 12)
+#define HDMI_O_3_SFT 9
+#define HDMI_O_3_MASK 0x7
+#define HDMI_O_3_MASK_SFT (0x7 << 9)
+#define HDMI_O_2_SFT 6
+#define HDMI_O_2_MASK 0x7
+#define HDMI_O_2_MASK_SFT (0x7 << 6)
+#define HDMI_O_1_SFT 3
+#define HDMI_O_1_MASK 0x7
+#define HDMI_O_1_MASK_SFT (0x7 << 3)
+#define HDMI_O_0_SFT 0
+#define HDMI_O_0_MASK 0x7
+#define HDMI_O_0_MASK_SFT (0x7 << 0)
+
+/* AFE_TDM_CON1 */
+#define TDM_EN_SFT 0
+#define TDM_EN_MASK 0x1
+#define TDM_EN_MASK_SFT (0x1 << 0)
+#define LRCK_INVERSE_SFT 2
+#define LRCK_INVERSE_MASK 0x1
+#define LRCK_INVERSE_MASK_SFT (0x1 << 2)
+#define DELAY_DATA_SFT 3
+#define DELAY_DATA_MASK 0x1
+#define DELAY_DATA_MASK_SFT (0x1 << 3)
+#define LEFT_ALIGN_SFT 4
+#define LEFT_ALIGN_MASK 0x1
+#define LEFT_ALIGN_MASK_SFT (0x1 << 4)
+#define WLEN_SFT 8
+#define WLEN_MASK 0x3
+#define WLEN_MASK_SFT (0x3 << 8)
+#define CHANNEL_NUM_SFT 10
+#define CHANNEL_NUM_MASK 0x3
+#define CHANNEL_NUM_MASK_SFT (0x3 << 10)
+#define CHANNEL_BCK_CYCLES_SFT 12
+#define CHANNEL_BCK_CYCLES_MASK 0x3
+#define CHANNEL_BCK_CYCLES_MASK_SFT (0x3 << 12)
+#define DAC_BIT_NUM_SFT 16
+#define DAC_BIT_NUM_MASK 0x1f
+#define DAC_BIT_NUM_MASK_SFT (0x1f << 16)
+#define LRCK_TDM_WIDTH_SFT 24
+#define LRCK_TDM_WIDTH_MASK 0xff
+#define LRCK_TDM_WIDTH_MASK_SFT (0xff << 24)
+
+/* AFE_TDM_CON2 */
+#define ST_CH_PAIR_SOUT0_SFT 0
+#define ST_CH_PAIR_SOUT0_MASK 0x7
+#define ST_CH_PAIR_SOUT0_MASK_SFT (0x7 << 0)
+#define ST_CH_PAIR_SOUT1_SFT 4
+#define ST_CH_PAIR_SOUT1_MASK 0x7
+#define ST_CH_PAIR_SOUT1_MASK_SFT (0x7 << 4)
+#define ST_CH_PAIR_SOUT2_SFT 8
+#define ST_CH_PAIR_SOUT2_MASK 0x7
+#define ST_CH_PAIR_SOUT2_MASK_SFT (0x7 << 8)
+#define ST_CH_PAIR_SOUT3_SFT 12
+#define ST_CH_PAIR_SOUT3_MASK 0x7
+#define ST_CH_PAIR_SOUT3_MASK_SFT (0x7 << 12)
+#define TDM_FIX_VALUE_SEL_SFT 16
+#define TDM_FIX_VALUE_SEL_MASK 0x1
+#define TDM_FIX_VALUE_SEL_MASK_SFT (0x1 << 16)
+#define TDM_I2S_LOOPBACK_SFT 20
+#define TDM_I2S_LOOPBACK_MASK 0x1
+#define TDM_I2S_LOOPBACK_MASK_SFT (0x1 << 20)
+#define TDM_I2S_LOOPBACK_CH_SFT 21
+#define TDM_I2S_LOOPBACK_CH_MASK 0x3
+#define TDM_I2S_LOOPBACK_CH_MASK_SFT (0x3 << 21)
+#define TDM_FIX_VALUE_SFT 24
+#define TDM_FIX_VALUE_MASK 0xff
+#define TDM_FIX_VALUE_MASK_SFT (0xff << 24)
+
+/* AFE_HDMI_OUT_CON0 */
+#define AFE_HDMI_OUT_ON_RETM_SFT 8
+#define AFE_HDMI_OUT_ON_RETM_MASK 0x1
+#define AFE_HDMI_OUT_ON_RETM_MASK_SFT (0x1 << 8)
+#define AFE_HDMI_OUT_CH_NUM_SFT 4
+#define AFE_HDMI_OUT_CH_NUM_MASK 0xf
+#define AFE_HDMI_OUT_CH_NUM_MASK_SFT (0xf << 4)
+#define AFE_HDMI_OUT_BIT_WIDTH_SFT 1
+#define AFE_HDMI_OUT_BIT_WIDTH_MASK 0x1
+#define AFE_HDMI_OUT_BIT_WIDTH_MASK_SFT (0x1 << 1)
+#define AFE_HDMI_OUT_ON_SFT 0
+#define AFE_HDMI_OUT_ON_MASK 0x1
+#define AFE_HDMI_OUT_ON_MASK_SFT (0x1 << 0)
+#endif