summary refs log tree commit diff
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/adi/Kconfig1
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c9
-rw-r--r--sound/soc/amd/raven/pci-acp3x.c9
-rw-r--r--sound/soc/amd/renoir/rn-pci-acp3x.c34
-rw-r--r--sound/soc/atmel/Kconfig1
-rw-r--r--sound/soc/atmel/atmel-i2s.c4
-rw-r--r--sound/soc/bcm/bcm2835-i2s.c4
-rw-r--r--sound/soc/codecs/Kconfig63
-rw-r--r--sound/soc/codecs/Makefile19
-rw-r--r--sound/soc/codecs/adau1372-i2c.c40
-rw-r--r--sound/soc/codecs/adau1372-spi.c58
-rw-r--r--sound/soc/codecs/adau1372.c1062
-rw-r--r--sound/soc/codecs/adau1372.h21
-rw-r--r--sound/soc/codecs/adau1977.c9
-rw-r--r--sound/soc/codecs/adav80x.c1
-rw-r--r--sound/soc/codecs/ak4118.c2
-rw-r--r--sound/soc/codecs/ak5558.c2
-rw-r--r--sound/soc/codecs/alc5623.c2
-rw-r--r--sound/soc/codecs/alc5632.c2
-rw-r--r--sound/soc/codecs/arizona.c1
-rw-r--r--sound/soc/codecs/bd28623.c2
-rw-r--r--sound/soc/codecs/cros_ec_codec.c2
-rw-r--r--sound/soc/codecs/cs42l52.c1
-rw-r--r--sound/soc/codecs/cs42l56.c1
-rw-r--r--sound/soc/codecs/cs47l92.c1
-rw-r--r--sound/soc/codecs/cx2072x.c4
-rw-r--r--sound/soc/codecs/da7218.c2
-rw-r--r--sound/soc/codecs/da7219.c2
-rw-r--r--sound/soc/codecs/da9055.c2
-rw-r--r--sound/soc/codecs/es7134.c4
-rw-r--r--sound/soc/codecs/es7241.c2
-rw-r--r--sound/soc/codecs/es8316.c2
-rw-r--r--sound/soc/codecs/gtm601.c2
-rw-r--r--sound/soc/codecs/hdmi-codec.c43
-rw-r--r--sound/soc/codecs/inno_rk3036.c2
-rw-r--r--sound/soc/codecs/jz4725b.c26
-rw-r--r--sound/soc/codecs/jz4740.c20
-rw-r--r--sound/soc/codecs/jz4770.c109
-rw-r--r--sound/soc/codecs/lpass-va-macro.c1497
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c2464
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.h17
-rw-r--r--sound/soc/codecs/madera.c4
-rw-r--r--sound/soc/codecs/max98090.c2
-rw-r--r--sound/soc/codecs/max98095.c2
-rw-r--r--sound/soc/codecs/max98371.c3
-rw-r--r--sound/soc/codecs/max98373-sdw.c2
-rw-r--r--sound/soc/codecs/max98390.c2
-rw-r--r--sound/soc/codecs/max9867.c2
-rw-r--r--sound/soc/codecs/max98925.c3
-rw-r--r--sound/soc/codecs/max98926.c3
-rw-r--r--sound/soc/codecs/mt6359.c152
-rw-r--r--sound/soc/codecs/mt6359.h15
-rw-r--r--sound/soc/codecs/nau8315.c166
-rw-r--r--sound/soc/codecs/pcm1789-i2c.c2
-rw-r--r--sound/soc/codecs/pcm179x-i2c.c2
-rw-r--r--sound/soc/codecs/pcm512x.c134
-rw-r--r--sound/soc/codecs/rk3328_codec.c2
-rw-r--r--sound/soc/codecs/rt1015.c211
-rw-r--r--sound/soc/codecs/rt1015.h42
-rw-r--r--sound/soc/codecs/rt1015p.c69
-rw-r--r--sound/soc/codecs/rt1308-sdw.c2
-rw-r--r--sound/soc/codecs/rt5660.c2
-rw-r--r--sound/soc/codecs/rt5682-i2c.c5
-rw-r--r--sound/soc/codecs/rt5682-sdw.c2
-rw-r--r--sound/soc/codecs/rt5682.c3
-rw-r--r--sound/soc/codecs/rt5682.h14
-rw-r--r--sound/soc/codecs/rt700.c2
-rw-r--r--sound/soc/codecs/rt711-sdw.c15
-rw-r--r--sound/soc/codecs/rt711.c2
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.c278
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.h170
-rw-r--r--sound/soc/codecs/rt715-sdca.c936
-rw-r--r--sound/soc/codecs/rt715-sdca.h124
-rw-r--r--sound/soc/codecs/rt715.c2
-rw-r--r--sound/soc/codecs/rt715.h1
-rw-r--r--sound/soc/codecs/simple-mux.c124
-rw-r--r--sound/soc/codecs/tas2562.c2
-rw-r--r--sound/soc/codecs/tas571x.c4
-rw-r--r--sound/soc/codecs/tlv320adcx140.c2
-rw-r--r--sound/soc/codecs/tlv320aic23-i2c.c2
-rw-r--r--sound/soc/codecs/ts3a227e.c2
-rw-r--r--sound/soc/codecs/tscs42xx.c6
-rw-r--r--sound/soc/codecs/tscs454.c8
-rw-r--r--sound/soc/codecs/wcd-clsh-v2.c1
-rw-r--r--sound/soc/codecs/wcd9335.c2
-rw-r--r--sound/soc/codecs/wl1273.c1
-rw-r--r--sound/soc/codecs/wm5102.c4
-rw-r--r--sound/soc/codecs/wm8350.c3
-rw-r--r--sound/soc/codecs/wm8962.c1
-rw-r--r--sound/soc/codecs/wm8994.c6
-rw-r--r--sound/soc/codecs/wm8997.c2
-rw-r--r--sound/soc/codecs/wm8998.c4
-rw-r--r--sound/soc/codecs/wm_adsp.c5
-rw-r--r--sound/soc/fsl/Kconfig77
-rw-r--r--sound/soc/fsl/Makefile16
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c13
-rw-r--r--sound/soc/fsl/fsl_aud2htx.c308
-rw-r--r--sound/soc/fsl/fsl_aud2htx.h67
-rw-r--r--sound/soc/fsl/fsl_audmix.c13
-rw-r--r--sound/soc/fsl/fsl_sai.c20
-rw-r--r--sound/soc/fsl/fsl_sai.h1
-rw-r--r--sound/soc/fsl/fsl_spdif.c73
-rw-r--r--sound/soc/fsl/fsl_spdif.h9
-rw-r--r--sound/soc/fsl/fsl_xcvr.c1360
-rw-r--r--sound/soc/fsl/fsl_xcvr.h266
-rw-r--r--sound/soc/fsl/imx-audmux.c28
-rw-r--r--sound/soc/fsl/imx-hdmi.c236
-rw-r--r--sound/soc/fsl/imx-mc13783.c156
-rw-r--r--sound/soc/fsl/imx-ssi.c651
-rw-r--r--sound/soc/fsl/mx27vis-aic32x4.c214
-rw-r--r--sound/soc/fsl/phycore-ac97.c121
-rw-r--r--sound/soc/fsl/wm1133-ev1.c289
-rw-r--r--sound/soc/generic/Kconfig2
-rw-r--r--sound/soc/generic/audio-graph-card.c175
-rw-r--r--sound/soc/intel/Kconfig5
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.c12
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.h4
-rw-r--r--sound/soc/intel/atom/sst/sst.c2
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c8
-rw-r--r--sound/soc/intel/boards/Kconfig3
-rw-r--r--sound/soc/intel/boards/Makefile2
-rw-r--r--sound/soc/intel/boards/bdw-rt5650.c17
-rw-r--r--sound/soc/intel/boards/bdw-rt5677.c18
-rw-r--r--sound/soc/intel/boards/broadwell.c20
-rw-r--r--sound/soc/intel/boards/bytcht_cx2072x.c27
-rw-r--r--sound/soc/intel/boards/bytcht_da7213.c27
-rw-r--r--sound/soc/intel/boards/bytcht_es8316.c29
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c42
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c29
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c29
-rw-r--r--sound/soc/intel/boards/cht_bsw_nau8824.c39
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c38
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c29
-rw-r--r--sound/soc/intel/boards/sof_maxim_common.c4
-rw-r--r--sound/soc/intel/boards/sof_realtek_common.c138
-rw-r--r--sound/soc/intel/boards/sof_realtek_common.h24
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c87
-rw-r--r--sound/soc/intel/boards/sof_sdw.c10
-rw-r--r--sound/soc/intel/catpt/core.h10
-rw-r--r--sound/soc/intel/catpt/device.c30
-rw-r--r--sound/soc/intel/catpt/dsp.c56
-rw-r--r--sound/soc/intel/catpt/loader.c2
-rw-r--r--sound/soc/intel/catpt/pcm.c106
-rw-r--r--sound/soc/intel/common/Makefile2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-adl-match.c52
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cml-match.c13
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-tgl-match.c17
-rw-r--r--sound/soc/intel/keembay/kmb_platform.c22
-rw-r--r--sound/soc/intel/keembay/kmb_platform.h8
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c1
-rw-r--r--sound/soc/intel/skylake/skl-topology.c9
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c9
-rw-r--r--sound/soc/kirkwood/armada-370-db.c2
-rw-r--r--sound/soc/mediatek/Kconfig25
-rw-r--r--sound/soc/mediatek/Makefile1
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.c13
-rw-r--r--sound/soc/mediatek/common/mtk-base-afe.h1
-rw-r--r--sound/soc/mediatek/common/mtk-btcvsd.c2
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-afe-clk.c1
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c1
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c1
-rw-r--r--sound/soc/mediatek/mt8192/Makefile16
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-afe-clk.c669
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-afe-clk.h244
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-afe-common.h170
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-afe-control.c163
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-afe-gpio.c308
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-afe-gpio.h19
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-afe-pcm.c2389
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-dai-adda.c1471
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-dai-i2s.c2110
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-dai-pcm.c409
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-dai-tdm.c778
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-interconnection.h65
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c1137
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-reg.h3131
-rw-r--r--sound/soc/meson/Kconfig4
-rw-r--r--sound/soc/meson/t9015.c2
-rw-r--r--sound/soc/pxa/Kconfig14
-rw-r--r--sound/soc/pxa/mmp-sspa.c4
-rw-r--r--sound/soc/pxa/pxa-ssp.c6
-rw-r--r--sound/soc/qcom/Kconfig25
-rw-r--r--sound/soc/qcom/Makefile4
-rw-r--r--sound/soc/qcom/apq8016_sbc.c2
-rw-r--r--sound/soc/qcom/common.c13
-rw-r--r--sound/soc/qcom/lpass-apq8016.c2
-rw-r--r--sound/soc/qcom/lpass-cpu.c12
-rw-r--r--sound/soc/qcom/lpass-hdmi.c2
-rw-r--r--sound/soc/qcom/lpass-ipq806x.c2
-rw-r--r--sound/soc/qcom/lpass-sc7180.c10
-rw-r--r--sound/soc/qcom/lpass.h1
-rw-r--r--sound/soc/qcom/qdsp6/q6adm.c10
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-clocks.c3
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.c10
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.c10
-rw-r--r--sound/soc/qcom/sc7180.c391
-rw-r--r--sound/soc/qcom/sm8250.c229
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c2
-rw-r--r--sound/soc/rockchip/rockchip_pdm.c2
-rw-r--r--sound/soc/rockchip/rockchip_spdif.c2
-rw-r--r--sound/soc/samsung/i2s.c11
-rw-r--r--sound/soc/samsung/midas_wm1811.c1
-rw-r--r--sound/soc/samsung/smdk_wm8994.c4
-rw-r--r--sound/soc/samsung/snow.c2
-rw-r--r--sound/soc/sh/Kconfig1
-rw-r--r--sound/soc/soc-component.c318
-rw-r--r--sound/soc/soc-compress.c397
-rw-r--r--sound/soc/soc-core.c88
-rw-r--r--sound/soc/soc-dai.c70
-rw-r--r--sound/soc/soc-dapm.c6
-rw-r--r--sound/soc/soc-link.c53
-rw-r--r--sound/soc/soc-pcm.c217
-rw-r--r--sound/soc/soc-topology.c337
-rw-r--r--sound/soc/sof/Kconfig42
-rw-r--r--sound/soc/sof/control.c42
-rw-r--r--sound/soc/sof/debug.c119
-rw-r--r--sound/soc/sof/imx/Kconfig10
-rw-r--r--sound/soc/sof/imx/imx-common.c2
-rw-r--r--sound/soc/sof/intel/Kconfig110
-rw-r--r--sound/soc/sof/intel/Makefile2
-rw-r--r--sound/soc/sof/intel/apl.c3
-rw-r--r--sound/soc/sof/intel/byt.c2
-rw-r--r--sound/soc/sof/intel/cnl.c19
-rw-r--r--sound/soc/sof/intel/ext_manifest.h35
-rw-r--r--sound/soc/sof/intel/hda-dsp.c2
-rw-r--r--sound/soc/sof/intel/hda-loader.c119
-rw-r--r--sound/soc/sof/intel/hda-pcm.c7
-rw-r--r--sound/soc/sof/intel/hda.c10
-rw-r--r--sound/soc/sof/intel/hda.h12
-rw-r--r--sound/soc/sof/intel/icl.c145
-rw-r--r--sound/soc/sof/intel/intel-ipc.c7
-rw-r--r--sound/soc/sof/intel/tgl.c19
-rw-r--r--sound/soc/sof/ipc.c9
-rw-r--r--sound/soc/sof/loader.c62
-rw-r--r--sound/soc/sof/nocodec.c18
-rw-r--r--sound/soc/sof/ops.c2
-rw-r--r--sound/soc/sof/ops.h14
-rw-r--r--sound/soc/sof/pcm.c14
-rw-r--r--sound/soc/sof/sof-acpi-dev.c14
-rw-r--r--sound/soc/sof/sof-audio.c12
-rw-r--r--sound/soc/sof/sof-audio.h5
-rw-r--r--sound/soc/sof/sof-pci-dev.c24
-rw-r--r--sound/soc/sof/sof-priv.h22
-rw-r--r--sound/soc/sof/topology.c33
-rw-r--r--sound/soc/sof/trace.c224
-rw-r--r--sound/soc/stm/Kconfig1
-rw-r--r--sound/soc/sunxi/Kconfig1
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c388
-rw-r--r--sound/soc/sunxi/sun8i-codec.c834
-rw-r--r--sound/soc/tegra/Kconfig1
-rw-r--r--sound/soc/tegra/tegra186_dspk.c6
-rw-r--r--sound/soc/tegra/tegra210_dmic.c6
-rw-r--r--sound/soc/tegra/tegra210_i2s.c6
-rw-r--r--sound/soc/tegra/tegra_alc5632.c4
-rw-r--r--sound/soc/tegra/tegra_max98090.c8
-rw-r--r--sound/soc/tegra/tegra_rt5640.c8
-rw-r--r--sound/soc/tegra/tegra_rt5677.c4
-rw-r--r--sound/soc/tegra/tegra_sgtl5000.c4
-rw-r--r--sound/soc/tegra/tegra_wm8753.c8
-rw-r--r--sound/soc/tegra/tegra_wm8903.c8
-rw-r--r--sound/soc/tegra/tegra_wm9712.c4
-rw-r--r--sound/soc/tegra/trimslice.c8
-rw-r--r--sound/soc/ti/Kconfig9
-rw-r--r--sound/soc/ti/davinci-evm.c3
-rw-r--r--sound/soc/ti/davinci-i2s.c2
-rw-r--r--sound/soc/ti/davinci-mcasp.c299
-rw-r--r--sound/soc/uniphier/aio-ld11.c2
-rw-r--r--sound/soc/uniphier/aio-pxs2.c2
-rw-r--r--sound/soc/uniphier/evea.c2
269 files changed, 27666 insertions, 3684 deletions
diff --git a/sound/soc/adi/Kconfig b/sound/soc/adi/Kconfig
index e321e3b672da..0236dc5b4e9f 100644
--- a/sound/soc/adi/Kconfig
+++ b/sound/soc/adi/Kconfig
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config SND_SOC_ADI
 	tristate "Audio support for Analog Devices reference designs"
-	depends on MICROBLAZE || ARCH_ZYNQ || COMPILE_TEST
 	help
 	  Audio support for various reference designs by Analog Devices.
 
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index a7702e64ec51..849288d01c6b 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -73,8 +73,13 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
 		return ret;
 	}
 
-	da7219_dai_wclk = clk_get(component->dev, "da7219-dai-wclk");
-	da7219_dai_bclk = clk_get(component->dev, "da7219-dai-bclk");
+	da7219_dai_wclk = devm_clk_get(component->dev, "da7219-dai-wclk");
+	if (IS_ERR(da7219_dai_wclk))
+		return PTR_ERR(da7219_dai_wclk);
+
+	da7219_dai_bclk = devm_clk_get(component->dev, "da7219-dai-bclk");
+	if (IS_ERR(da7219_dai_bclk))
+		return PTR_ERR(da7219_dai_bclk);
 
 	ret = snd_soc_card_jack_new(card, "Headset Jack",
 				SND_JACK_HEADSET | SND_JACK_LINEOUT |
diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c
index 31b797c8bfe6..8c138e490f0c 100644
--- a/sound/soc/amd/raven/pci-acp3x.c
+++ b/sound/soc/amd/raven/pci-acp3x.c
@@ -118,6 +118,10 @@ static int snd_acp3x_probe(struct pci_dev *pci,
 	int ret, i;
 	u32 addr, val;
 
+	/* Raven device detection */
+	if (pci->revision != 0x00)
+		return -ENODEV;
+
 	if (pci_enable_device(pci)) {
 		dev_err(&pci->dev, "pci_enable_device failed\n");
 		return -ENODEV;
@@ -231,9 +235,8 @@ static int snd_acp3x_probe(struct pci_dev *pci,
 		}
 		break;
 	default:
-		dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val);
-		ret = -ENODEV;
-		goto disable_msi;
+		dev_info(&pci->dev, "ACP audio mode : %d\n", val);
+		break;
 	}
 	pm_runtime_set_autosuspend_delay(&pci->dev, 2000);
 	pm_runtime_use_autosuspend(&pci->dev);
diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c
index b943e59fc302..fa169bf09886 100644
--- a/sound/soc/amd/renoir/rn-pci-acp3x.c
+++ b/sound/soc/amd/renoir/rn-pci-acp3x.c
@@ -6,6 +6,7 @@
 
 #include <linux/pci.h>
 #include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -20,14 +21,13 @@ module_param(acp_power_gating, int, 0644);
 MODULE_PARM_DESC(acp_power_gating, "Enable acp power gating");
 
 /**
- * dmic_acpi_check = -1 - Checks ACPI method to know DMIC hardware status runtime
- *                 = 0 - Skips the DMIC device creation and returns probe failure
- *                 = 1 - Assumes that platform has DMIC support and skips ACPI
- *                       method check
+ * dmic_acpi_check = -1 - Use ACPI/DMI method to detect the DMIC hardware presence at runtime
+ *                 =  0 - Skip the DMIC device creation and return probe failure
+ *                 =  1 - Force DMIC support
  */
 static int dmic_acpi_check = ACP_DMIC_AUTO;
 module_param(dmic_acpi_check, bint, 0644);
-MODULE_PARM_DESC(dmic_acpi_check, "checks Dmic hardware runtime");
+MODULE_PARM_DESC(dmic_acpi_check, "Digital microphone presence (-1=auto, 0=none, 1=force)");
 
 struct acp_dev_data {
 	void __iomem *acp_base;
@@ -163,6 +163,17 @@ static int rn_acp_deinit(void __iomem *acp_base)
 	return 0;
 }
 
+static const struct dmi_system_id rn_acp_quirk_table[] = {
+	{
+		/* Lenovo IdeaPad Flex 5 14ARE05, IdeaPad 5 15ARE05 */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "LNVNB161216"),
+		}
+	},
+	{}
+};
+
 static int snd_rn_acp_probe(struct pci_dev *pci,
 			    const struct pci_device_id *pci_id)
 {
@@ -172,10 +183,15 @@ static int snd_rn_acp_probe(struct pci_dev *pci,
 	acpi_handle handle;
 	acpi_integer dmic_status;
 #endif
+	const struct dmi_system_id *dmi_id;
 	unsigned int irqflags;
 	int ret, index;
 	u32 addr;
 
+	/* Renoir device check */
+	if (pci->revision != 0x01)
+		return -ENODEV;
+
 	if (pci_enable_device(pci)) {
 		dev_err(&pci->dev, "pci_enable_device failed\n");
 		return -ENODEV;
@@ -224,7 +240,7 @@ static int snd_rn_acp_probe(struct pci_dev *pci,
 		handle = ACPI_HANDLE(&pci->dev);
 		ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status);
 		if (ACPI_FAILURE(ret)) {
-			ret = -EINVAL;
+			ret = -ENODEV;
 			goto de_init;
 		}
 		if (!dmic_status) {
@@ -232,6 +248,12 @@ static int snd_rn_acp_probe(struct pci_dev *pci,
 			goto de_init;
 		}
 #endif
+		dmi_id = dmi_first_match(rn_acp_quirk_table);
+		if (dmi_id && !dmi_id->driver_data) {
+			dev_info(&pci->dev, "ACPI settings override using DMI (ACP mic is not present)");
+			ret = -ENODEV;
+			goto de_init;
+		}
 	}
 
 	adata->res = devm_kzalloc(&pci->dev,
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index bd8854bfd2ee..142373ec411a 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -148,6 +148,7 @@ config SND_MCHP_SOC_SPDIFTX
 config SND_MCHP_SOC_SPDIFRX
 	tristate "Microchip ASoC driver for boards using S/PDIF RX"
 	depends on OF && (ARCH_AT91 || COMPILE_TEST)
+	depends on COMMON_CLK
 	select SND_SOC_GENERIC_DMAENGINE_PCM
 	select REGMAP_MMIO
 	help
diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c
index bbe2b638abb5..232300dda548 100644
--- a/sound/soc/atmel/atmel-i2s.c
+++ b/sound/soc/atmel/atmel-i2s.c
@@ -563,8 +563,8 @@ static int atmel_i2s_sama5d2_mck_init(struct atmel_i2s_dev *dev,
 		err = PTR_ERR(muxclk);
 		if (err == -EPROBE_DEFER)
 			return -EPROBE_DEFER;
-		dev_warn(dev->dev,
-			 "failed to get the I2S clock control: %d\n", err);
+		dev_dbg(dev->dev,
+			"failed to get the I2S clock control: %d\n", err);
 		return 0;
 	}
 
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index dc34fe1559c6..c2f7631e8705 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -797,7 +797,7 @@ static bool bcm2835_i2s_volatile_reg(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg)
@@ -807,7 +807,7 @@ static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static const struct regmap_config bcm2835_regmap_config = {
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 34c6dd04b85a..5e4e68112791 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -23,6 +23,8 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_AD193X_I2C
 	imply SND_SOC_AD1980
 	imply SND_SOC_AD73311
+	imply SND_SOC_ADAU1372_I2C
+	imply SND_SOC_ADAU1372_SPI
 	imply SND_SOC_ADAU1373
 	imply SND_SOC_ADAU1761_I2C
 	imply SND_SOC_ADAU1761_SPI
@@ -130,6 +132,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_MT6358
 	imply SND_SOC_MT6359
 	imply SND_SOC_MT6660
+	imply SND_SOC_NAU8315
 	imply SND_SOC_NAU8540
 	imply SND_SOC_NAU8810
 	imply SND_SOC_NAU8822
@@ -177,10 +180,12 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_RT700_SDW
 	imply SND_SOC_RT711_SDW
 	imply SND_SOC_RT715_SDW
+	imply SND_SOC_RT715_SDCA_SDW
 	imply SND_SOC_RT1308_SDW
 	imply SND_SOC_SGTL5000
 	imply SND_SOC_SI476X
 	imply SND_SOC_SIMPLE_AMPLIFIER
+	imply SND_SOC_SIMPLE_MUX
 	imply SND_SOC_SIRF_AUDIO_CODEC
 	imply SND_SOC_SPDIF
 	imply SND_SOC_SSM2305
@@ -363,6 +368,22 @@ config SND_SOC_AD73311
 config SND_SOC_ADAU_UTILS
 	tristate
 
+config SND_SOC_ADAU1372
+	tristate
+	select SND_SOC_ADAU_UTILS
+
+config SND_SOC_ADAU1372_I2C
+	tristate "Analog Devices ADAU1372 CODEC (I2C)"
+	depends on I2C
+	select SND_SOC_ADAU1372
+	select REGMAP_I2C
+
+config SND_SOC_ADAU1372_SPI
+	tristate "Analog Devices ADAU1372 CODEC (SPI)"
+	depends on SPI
+	select SND_SOC_ADAU1372
+	select REGMAP_SPI
+
 config SND_SOC_ADAU1373
 	tristate
 	depends on I2C
@@ -517,7 +538,7 @@ config SND_SOC_AK5558
 	select REGMAP_I2C
 
 config SND_SOC_ALC5623
-       tristate "Realtek ALC5623 CODEC"
+	tristate "Realtek ALC5623 CODEC"
 	depends on I2C
 
 config SND_SOC_ALC5632
@@ -728,7 +749,7 @@ config SND_SOC_JZ4770_CODEC
 	  will be called snd-soc-jz4770-codec.
 
 config SND_SOC_L3
-       tristate
+	tristate
 
 config SND_SOC_DA7210
 	tristate
@@ -768,10 +789,10 @@ config SND_SOC_HDMI_CODEC
 	select HDMI
 
 config SND_SOC_ES7134
-       tristate "Everest Semi ES7134 CODEC"
+	tristate "Everest Semi ES7134 CODEC"
 
 config SND_SOC_ES7241
-       tristate "Everest Semi ES7241 CODEC"
+	tristate "Everest Semi ES7241 CODEC"
 
 config SND_SOC_ES8316
 	tristate "Everest Semi ES8316 CODEC"
@@ -970,10 +991,10 @@ config SND_SOC_PCM186X_SPI
 	select REGMAP_SPI
 
 config SND_SOC_PCM3008
-       tristate
+	tristate
 
 config SND_SOC_PCM3060
-       tristate
+	tristate
 
 config SND_SOC_PCM3060_I2C
 	tristate "Texas Instruments PCM3060 CODEC - I2C"
@@ -1003,7 +1024,7 @@ config SND_SOC_PCM3168A_SPI
 	select REGMAP_SPI
 
 config SND_SOC_PCM5102A
-	tristate
+	tristate "Texas Instruments PCM5102A CODEC"
 
 config SND_SOC_PCM512x
 	tristate
@@ -1216,6 +1237,12 @@ config SND_SOC_RT715_SDW
 	select SND_SOC_RT715
 	select REGMAP_SOUNDWIRE
 
+config SND_SOC_RT715_SDCA_SDW
+	tristate "Realtek RT715 SDCA Codec - SDW"
+	depends on SOUNDWIRE
+	select REGMAP_SOUNDWIRE
+	select REGMAP_SOUNDWIRE_MBQ
+
 #Freescale sgtl5000 codec
 config SND_SOC_SGTL5000
 	tristate "Freescale SGTL5000 CODEC"
@@ -1240,6 +1267,10 @@ config SND_SOC_SIMPLE_AMPLIFIER
 	tristate "Simple Audio Amplifier"
 	select GPIOLIB
 
+config SND_SOC_SIMPLE_MUX
+	tristate "Simple Audio Mux"
+	select GPIOLIB
+
 config SND_SOC_SIRF_AUDIO_CODEC
 	tristate "SiRF SoC internal audio codec"
 	select REGMAP_MMIO
@@ -1436,7 +1467,7 @@ config SND_SOC_UDA1334
 	  rate) and mute.
 
 config SND_SOC_UDA134X
-       tristate
+	tristate
 
 config SND_SOC_UDA1380
 	tristate
@@ -1760,9 +1791,13 @@ config SND_SOC_MT6660
 	  Select N if you don't have MT6660 on board.
 	  Select M to build this as module.
 
+config SND_SOC_NAU8315
+	tristate "Nuvoton Technology Corporation NAU8315 CODEC"
+	depends on GPIOLIB
+
 config SND_SOC_NAU8540
-       tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
-       depends on I2C
+	tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
+	depends on I2C
 
 config SND_SOC_NAU8810
 	tristate "Nuvoton Technology Corporation NAU88C10 CODEC"
@@ -1784,4 +1819,12 @@ config SND_SOC_TPA6130A2
 	tristate "Texas Instruments TPA6130A2 headphone amplifier"
 	depends on I2C
 
+config SND_SOC_LPASS_WSA_MACRO
+	depends on COMMON_CLK
+	tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)"
+
+config SND_SOC_LPASS_VA_MACRO
+	depends on COMMON_CLK
+	tristate "Qualcomm VA Macro in LPASS(Low Power Audio SubSystem)"
+
 endmenu
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 11ce98c25d6c..f255ec74333c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -9,6 +9,9 @@ snd-soc-ad193x-i2c-objs := ad193x-i2c.o
 snd-soc-ad1980-objs := ad1980.o
 snd-soc-ad73311-objs := ad73311.o
 snd-soc-adau-utils-objs := adau-utils.o
+snd-soc-adau1372-objs := adau1372.o
+snd-soc-adau1372-i2c-objs := adau1372-i2c.o
+snd-soc-adau1372-spi-objs := adau1372-spi.o
 snd-soc-adau1373-objs := adau1373.o
 snd-soc-adau1701-objs := adau1701.o
 snd-soc-adau17x1-objs := adau17x1.o
@@ -103,6 +106,8 @@ snd-soc-l3-objs := l3.o
 snd-soc-lm4857-objs := lm4857.o
 snd-soc-lm49453-objs := lm49453.o
 snd-soc-lochnagar-sc-objs := lochnagar-sc.o
+snd-soc-lpass-wsa-macro-objs := lpass-wsa-macro.o
+snd-soc-lpass-va-macro-objs := lpass-va-macro.o
 snd-soc-madera-objs := madera.o
 snd-soc-max9759-objs := max9759.o
 snd-soc-max9768-objs := max9768.o
@@ -129,6 +134,7 @@ snd-soc-mt6351-objs := mt6351.o
 snd-soc-mt6358-objs := mt6358.o
 snd-soc-mt6359-objs := mt6359.o
 snd-soc-mt6660-objs := mt6660.o
+snd-soc-nau8315-objs := nau8315.o
 snd-soc-nau8540-objs := nau8540.o
 snd-soc-nau8810-objs := nau8810.o
 snd-soc-nau8822-objs := nau8822.o
@@ -188,6 +194,7 @@ snd-soc-rt5682-i2c-objs := rt5682-i2c.o
 snd-soc-rt700-objs := rt700.o rt700-sdw.o
 snd-soc-rt711-objs := rt711.o rt711-sdw.o
 snd-soc-rt715-objs := rt715.o rt715-sdw.o
+snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o
 snd-soc-sgtl5000-objs := sgtl5000.o
 snd-soc-alc5623-objs := alc5623.o
 snd-soc-alc5632-objs := alc5632.o
@@ -305,6 +312,8 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o
 snd-soc-tas2552-objs := tas2552.o
 snd-soc-tas2562-objs := tas2562.o
 snd-soc-tas2764-objs := tas2764.o
+# Mux
+snd-soc-simple-mux-objs := simple-mux.o
 
 obj-$(CONFIG_SND_SOC_88PM860X)	+= snd-soc-88pm860x.o
 obj-$(CONFIG_SND_SOC_AB8500_CODEC)	+= snd-soc-ab8500-codec.o
@@ -316,6 +325,9 @@ obj-$(CONFIG_SND_SOC_AD193X_I2C)	+= snd-soc-ad193x-i2c.o
 obj-$(CONFIG_SND_SOC_AD1980)	+= snd-soc-ad1980.o
 obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_ADAU_UTILS)	+= snd-soc-adau-utils.o
+obj-$(CONFIG_SND_SOC_ADAU1372)	+= snd-soc-adau1372.o
+obj-$(CONFIG_SND_SOC_ADAU1372_I2C)	+= snd-soc-adau1372-i2c.o
+obj-$(CONFIG_SND_SOC_ADAU1372_SPI)	+= snd-soc-adau1372-spi.o
 obj-$(CONFIG_SND_SOC_ADAU1373)	+= snd-soc-adau1373.o
 obj-$(CONFIG_SND_SOC_ADAU1701)		+= snd-soc-adau1701.o
 obj-$(CONFIG_SND_SOC_ADAU17X1)		+= snd-soc-adau17x1.o
@@ -438,6 +450,7 @@ obj-$(CONFIG_SND_SOC_MT6351)	+= snd-soc-mt6351.o
 obj-$(CONFIG_SND_SOC_MT6358)	+= snd-soc-mt6358.o
 obj-$(CONFIG_SND_SOC_MT6359)	+= snd-soc-mt6359.o
 obj-$(CONFIG_SND_SOC_MT6660)	+= snd-soc-mt6660.o
+obj-$(CONFIG_SND_SOC_NAU8315)   += snd-soc-nau8315.o
 obj-$(CONFIG_SND_SOC_NAU8540)   += snd-soc-nau8540.o
 obj-$(CONFIG_SND_SOC_NAU8810)   += snd-soc-nau8810.o
 obj-$(CONFIG_SND_SOC_NAU8822)   += snd-soc-nau8822.o
@@ -498,6 +511,7 @@ obj-$(CONFIG_SND_SOC_RT5682_SDW)	+= snd-soc-rt5682-sdw.o
 obj-$(CONFIG_SND_SOC_RT700)     += snd-soc-rt700.o
 obj-$(CONFIG_SND_SOC_RT711)     += snd-soc-rt711.o
 obj-$(CONFIG_SND_SOC_RT715)     += snd-soc-rt715.o
+obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW)     += snd-soc-rt715-sdca.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 obj-$(CONFIG_SND_SOC_SIGMADSP)	+= snd-soc-sigmadsp.o
 obj-$(CONFIG_SND_SOC_SIGMADSP_I2C)	+= snd-soc-sigmadsp-i2c.o
@@ -613,3 +627,8 @@ obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
 obj-$(CONFIG_SND_SOC_MAX98504)	+= snd-soc-max98504.o
 obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER)	+= snd-soc-simple-amplifier.o
 obj-$(CONFIG_SND_SOC_TPA6130A2)	+= snd-soc-tpa6130a2.o
+obj-$(CONFIG_SND_SOC_LPASS_WSA_MACRO)	+= snd-soc-lpass-wsa-macro.o
+obj-$(CONFIG_SND_SOC_LPASS_VA_MACRO)	+= snd-soc-lpass-va-macro.o
+
+# Mux
+obj-$(CONFIG_SND_SOC_SIMPLE_MUX)	+= snd-soc-simple-mux.o
diff --git a/sound/soc/codecs/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c
new file mode 100644
index 000000000000..fc87a76ff1ee
--- /dev/null
+++ b/sound/soc/codecs/adau1372-i2c.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for ADAU1372 codec
+ *
+ * Copyright 2016 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "adau1372.h"
+
+static int adau1372_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	return adau1372_probe(&client->dev,
+		devm_regmap_init_i2c(client, &adau1372_regmap_config), NULL);
+}
+
+static const struct i2c_device_id adau1372_i2c_ids[] = {
+	{ "adau1372", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adau1372_i2c_ids);
+
+static struct i2c_driver adau1372_i2c_driver = {
+	.driver = {
+		.name = "adau1372",
+	},
+	.probe = adau1372_i2c_probe,
+	.id_table = adau1372_i2c_ids,
+};
+module_i2c_driver(adau1372_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1372 CODEC I2C driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/adau1372-spi.c b/sound/soc/codecs/adau1372-spi.c
new file mode 100644
index 000000000000..51298e00fbd6
--- /dev/null
+++ b/sound/soc/codecs/adau1372-spi.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for ADAU1372 codec
+ *
+ * Copyright 2016 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "adau1372.h"
+
+static void adau1372_spi_switch_mode(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+
+	/*
+	 * To get the device into SPI mode CLATCH has to be pulled low three
+	 * times.  Do this by issuing three dummy reads.
+	 */
+	spi_w8r8(spi, 0x00);
+	spi_w8r8(spi, 0x00);
+	spi_w8r8(spi, 0x00);
+}
+
+static int adau1372_spi_probe(struct spi_device *spi)
+{
+	struct regmap_config config;
+
+	config = adau1372_regmap_config;
+	config.read_flag_mask = 0x1;
+
+	return adau1372_probe(&spi->dev,
+		devm_regmap_init_spi(spi, &config), adau1372_spi_switch_mode);
+}
+
+static const struct spi_device_id adau1372_spi_id[] = {
+	{ "adau1372", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, adau1372_spi_id);
+
+static struct spi_driver adau1372_spi_driver = {
+	.driver = {
+		.name = "adau1372",
+	},
+	.probe = adau1372_spi_probe,
+	.id_table = adau1372_spi_id,
+};
+module_spi_driver(adau1372_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1372 CODEC SPI driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c
new file mode 100644
index 000000000000..5ccbf1b6bcf5
--- /dev/null
+++ b/sound/soc/codecs/adau1372.c
@@ -0,0 +1,1062 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Analog Devices ADAU1372 Audio Codec driver
+ *
+ * Copyright 2016 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gcd.h>
+#include <linux/gpio/consumer.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+
+#include "adau1372.h"
+#include "adau-utils.h"
+
+struct adau1372 {
+	struct clk *clk;
+	struct regmap *regmap;
+	void (*switch_mode)(struct device *dev);
+	bool use_pll;
+	bool enabled;
+	bool master;
+
+	struct snd_pcm_hw_constraint_list rate_constraints;
+	unsigned int slot_width;
+
+	struct clk *mclk;
+	struct gpio_desc *pd_gpio;
+	struct device *dev;
+};
+
+#define ADAU1372_REG_CLK_CTRL		0x00
+#define ADAU1372_REG_PLL(x)		(0x01 + (x))
+#define ADAU1372_REG_DAC_SOURCE		0x11
+#define ADAU1372_REG_SOUT_SOURCE_0_1	0x13
+#define ADAU1372_REG_SOUT_SOURCE_2_3	0x14
+#define ADAU1372_REG_SOUT_SOURCE_4_5	0x15
+#define ADAU1372_REG_SOUT_SOURCE_6_7	0x16
+#define ADAU1372_REG_ADC_SDATA_CH	0x17
+#define ADAU1372_REG_ASRCO_SOURCE_0_1	0x18
+#define ADAU1372_REG_ASRCO_SOURCE_2_3	0x19
+#define ADAU1372_REG_ASRC_MODE		0x1a
+#define ADAU1372_REG_ADC_CTRL0		0x1b
+#define ADAU1372_REG_ADC_CTRL1		0x1c
+#define ADAU1372_REG_ADC_CTRL2		0x1d
+#define ADAU1372_REG_ADC_CTRL3		0x1e
+#define ADAU1372_REG_ADC_VOL(x)		(0x1f + (x))
+#define ADAU1372_REG_PGA_CTRL(x)	(0x23 + (x))
+#define ADAU1372_REG_PGA_BOOST		0x28
+#define ADAU1372_REG_MICBIAS		0x2d
+#define ADAU1372_REG_DAC_CTRL		0x2e
+#define ADAU1372_REG_DAC_VOL(x)		(0x2f + (x))
+#define ADAU1372_REG_OP_STAGE_MUTE	0x31
+#define ADAU1372_REG_SAI0		0x32
+#define ADAU1372_REG_SAI1		0x33
+#define ADAU1372_REG_SOUT_CTRL		0x34
+#define ADAU1372_REG_MODE_MP(x)		(0x38 + (x))
+#define ADAU1372_REG_OP_STAGE_CTRL	0x43
+#define ADAU1372_REG_DECIM_PWR		0x44
+#define ADAU1372_REG_INTERP_PWR		0x45
+#define ADAU1372_REG_BIAS_CTRL0		0x46
+#define ADAU1372_REG_BIAS_CTRL1		0x47
+
+#define ADAU1372_CLK_CTRL_PLL_EN	BIT(7)
+#define ADAU1372_CLK_CTRL_XTAL_DIS	BIT(4)
+#define ADAU1372_CLK_CTRL_CLKSRC	BIT(3)
+#define ADAU1372_CLK_CTRL_CC_MDIV	BIT(1)
+#define ADAU1372_CLK_CTRL_MCLK_EN	BIT(0)
+
+#define ADAU1372_SAI0_DELAY1		(0x0 << 6)
+#define ADAU1372_SAI0_DELAY0		(0x1 << 6)
+#define ADAU1372_SAI0_DELAY_MASK	(0x3 << 6)
+#define ADAU1372_SAI0_SAI_I2S		(0x0 << 4)
+#define ADAU1372_SAI0_SAI_TDM2		(0x1 << 4)
+#define ADAU1372_SAI0_SAI_TDM4		(0x2 << 4)
+#define ADAU1372_SAI0_SAI_TDM8		(0x3 << 4)
+#define ADAU1372_SAI0_SAI_MASK		(0x3 << 4)
+#define ADAU1372_SAI0_FS_48		0x0
+#define ADAU1372_SAI0_FS_8		0x1
+#define ADAU1372_SAI0_FS_12		0x2
+#define ADAU1372_SAI0_FS_16		0x3
+#define ADAU1372_SAI0_FS_24		0x4
+#define ADAU1372_SAI0_FS_32		0x5
+#define ADAU1372_SAI0_FS_96		0x6
+#define ADAU1372_SAI0_FS_192		0x7
+#define ADAU1372_SAI0_FS_MASK		0xf
+
+#define ADAU1372_SAI1_TDM_TS		BIT(7)
+#define ADAU1372_SAI1_BCLK_TDMC		BIT(6)
+#define ADAU1372_SAI1_LR_MODE		BIT(5)
+#define ADAU1372_SAI1_LR_POL		BIT(4)
+#define ADAU1372_SAI1_BCLKRATE		BIT(2)
+#define ADAU1372_SAI1_BCLKEDGE		BIT(1)
+#define ADAU1372_SAI1_MS		BIT(0)
+
+static const unsigned int adau1372_rates[] = {
+	[ADAU1372_SAI0_FS_8] = 8000,
+	[ADAU1372_SAI0_FS_12] = 12000,
+	[ADAU1372_SAI0_FS_16] = 16000,
+	[ADAU1372_SAI0_FS_24] = 24000,
+	[ADAU1372_SAI0_FS_32] = 32000,
+	[ADAU1372_SAI0_FS_48] = 48000,
+	[ADAU1372_SAI0_FS_96] = 96000,
+	[ADAU1372_SAI0_FS_192] = 192000,
+};
+
+/* 8k, 12k, 24k, 48k */
+#define ADAU1372_RATE_MASK_TDM8 0x17
+/* + 16k, 96k */
+#define ADAU1372_RATE_MASK_TDM4_MASTER (ADAU1372_RATE_MASK_TDM8 | 0x48 | 0x20)
+/* +32k */
+#define ADAU1372_RATE_MASK_TDM4 (ADAU1372_RATE_MASK_TDM4_MASTER | 0x20)
+/* + 192k */
+#define ADAU1372_RATE_MASK_TDM2 (ADAU1372_RATE_MASK_TDM4 | 0x80)
+
+static const DECLARE_TLV_DB_MINMAX(adau1372_digital_tlv, -9563, 0);
+static const DECLARE_TLV_DB_SCALE(adau1372_pga_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adau1372_pga_boost_tlv, 0, 1000, 0);
+
+static const char * const adau1372_bias_text[] = {
+	"Normal operation", "Extreme power saving", "Enhanced performance",
+	"Power saving",
+};
+
+static const unsigned int adau1372_bias_adc_values[] = {
+	0, 2, 3,
+};
+
+static const char * const adau1372_bias_adc_text[] = {
+	"Normal operation", "Enhanced performance", "Power saving",
+};
+
+static const char * const adau1372_bias_dac_text[] = {
+	"Normal operation", "Power saving", "Superior performance",
+	"Enhanced performance",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1372_bias_hp_enum,
+	ADAU1372_REG_BIAS_CTRL0, 6, adau1372_bias_text);
+static SOC_ENUM_SINGLE_DECL(adau1372_bias_afe0_1_enum,
+	ADAU1372_REG_BIAS_CTRL0, 4, adau1372_bias_text);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_bias_adc2_3_enum,
+	ADAU1372_REG_BIAS_CTRL0, 2, 0x3, adau1372_bias_adc_text,
+	adau1372_bias_adc_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_bias_adc0_1_enum,
+	ADAU1372_REG_BIAS_CTRL0, 0, 0x3, adau1372_bias_adc_text,
+	adau1372_bias_adc_values);
+static SOC_ENUM_SINGLE_DECL(adau1372_bias_afe2_3_enum,
+	ADAU1372_REG_BIAS_CTRL1, 4, adau1372_bias_text);
+static SOC_ENUM_SINGLE_DECL(adau1372_bias_mic_enum,
+	ADAU1372_REG_BIAS_CTRL1, 2, adau1372_bias_text);
+static SOC_ENUM_SINGLE_DECL(adau1372_bias_dac_enum,
+	ADAU1372_REG_BIAS_CTRL1, 0, adau1372_bias_dac_text);
+
+static const char * const adau1372_hpf_text[] = {
+	"Off",
+	"1 Hz",
+	"4 Hz",
+	"8 Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1372_hpf0_1_enum, ADAU1372_REG_ADC_CTRL2, 5,
+			    adau1372_hpf_text);
+static SOC_ENUM_SINGLE_DECL(adau1372_hpf2_3_enum, ADAU1372_REG_ADC_CTRL3, 5,
+			    adau1372_hpf_text);
+static const struct snd_kcontrol_new adau1372_controls[] = {
+	SOC_SINGLE_TLV("ADC 0 Capture Volume", ADAU1372_REG_ADC_VOL(0),
+		       0, 0xff, 1, adau1372_digital_tlv),
+	SOC_SINGLE_TLV("ADC 1 Capture Volume", ADAU1372_REG_ADC_VOL(1),
+		       0, 0xff, 1, adau1372_digital_tlv),
+	SOC_SINGLE_TLV("ADC 2 Capture Volume", ADAU1372_REG_ADC_VOL(2),
+		       0, 0xff, 1, adau1372_digital_tlv),
+	SOC_SINGLE_TLV("ADC 3 Capture Volume", ADAU1372_REG_ADC_VOL(3),
+		       0, 0xff, 1, adau1372_digital_tlv),
+	SOC_SINGLE("ADC 0 Capture Switch", ADAU1372_REG_ADC_CTRL0, 3, 1, 1),
+	SOC_SINGLE("ADC 1 Capture Switch", ADAU1372_REG_ADC_CTRL0, 4, 1, 1),
+	SOC_SINGLE("ADC 2 Capture Switch", ADAU1372_REG_ADC_CTRL1, 3, 1, 1),
+	SOC_SINGLE("ADC 3 Capture Switch", ADAU1372_REG_ADC_CTRL1, 4, 1, 1),
+
+	SOC_ENUM("ADC 0+1 High-Pass-Filter", adau1372_hpf0_1_enum),
+	SOC_ENUM("ADC 2+3 High-Pass-Filter", adau1372_hpf2_3_enum),
+
+	SOC_SINGLE_TLV("PGA 0 Capture Volume", ADAU1372_REG_PGA_CTRL(0),
+		       0, 0x3f, 0, adau1372_pga_tlv),
+	SOC_SINGLE_TLV("PGA 1 Capture Volume", ADAU1372_REG_PGA_CTRL(1),
+		       0, 0x3f, 0, adau1372_pga_tlv),
+	SOC_SINGLE_TLV("PGA 2 Capture Volume", ADAU1372_REG_PGA_CTRL(2),
+		       0, 0x3f, 0, adau1372_pga_tlv),
+	SOC_SINGLE_TLV("PGA 3 Capture Volume", ADAU1372_REG_PGA_CTRL(3),
+		       0, 0x3f, 0, adau1372_pga_tlv),
+	SOC_SINGLE_TLV("PGA 0 Boost Capture Volume", ADAU1372_REG_PGA_BOOST,
+		       0, 1, 0, adau1372_pga_boost_tlv),
+	SOC_SINGLE_TLV("PGA 1 Boost Capture Volume", ADAU1372_REG_PGA_BOOST,
+		       1, 1, 0, adau1372_pga_boost_tlv),
+	SOC_SINGLE_TLV("PGA 2 Boost Capture Volume", ADAU1372_REG_PGA_BOOST,
+		       2, 1, 0, adau1372_pga_boost_tlv),
+	SOC_SINGLE_TLV("PGA 3 Boost Capture Volume", ADAU1372_REG_PGA_BOOST,
+		       3, 1, 0, adau1372_pga_boost_tlv),
+	SOC_SINGLE("PGA 0 Capture Switch", ADAU1372_REG_PGA_CTRL(0), 7, 1, 1),
+	SOC_SINGLE("PGA 1 Capture Switch", ADAU1372_REG_PGA_CTRL(1), 7, 1, 1),
+	SOC_SINGLE("PGA 2 Capture Switch", ADAU1372_REG_PGA_CTRL(2), 7, 1, 1),
+	SOC_SINGLE("PGA 3 Capture Switch", ADAU1372_REG_PGA_CTRL(3), 7, 1, 1),
+
+	SOC_SINGLE_TLV("DAC 0 Playback Volume", ADAU1372_REG_DAC_VOL(0),
+		       0, 0xff, 1, adau1372_digital_tlv),
+	SOC_SINGLE_TLV("DAC 1 Playback Volume", ADAU1372_REG_DAC_VOL(1),
+		       0, 0xff, 1, adau1372_digital_tlv),
+	SOC_SINGLE("DAC 0 Playback Switch", ADAU1372_REG_DAC_CTRL, 3, 1, 1),
+	SOC_SINGLE("DAC 1 Playback Switch", ADAU1372_REG_DAC_CTRL, 4, 1, 1),
+
+	SOC_ENUM("Headphone Bias", adau1372_bias_hp_enum),
+	SOC_ENUM("Microphone Bias", adau1372_bias_mic_enum),
+	SOC_ENUM("AFE 0+1 Bias", adau1372_bias_afe0_1_enum),
+	SOC_ENUM("AFE 2+3 Bias", adau1372_bias_afe2_3_enum),
+	SOC_ENUM("ADC 0+1 Bias", adau1372_bias_adc0_1_enum),
+	SOC_ENUM("ADC 2+3 Bias", adau1372_bias_adc2_3_enum),
+	SOC_ENUM("DAC 0+1 Bias", adau1372_bias_dac_enum),
+};
+
+static const char * const adau1372_decimator_mux_text[] = {
+	"ADC",
+	"DMIC",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1372_decimator0_1_mux_enum, ADAU1372_REG_ADC_CTRL2,
+			    2, adau1372_decimator_mux_text);
+
+static const struct snd_kcontrol_new adau1372_decimator0_1_mux_control =
+	SOC_DAPM_ENUM("Decimator 0+1 Capture Mux", adau1372_decimator0_1_mux_enum);
+
+static SOC_ENUM_SINGLE_DECL(adau1372_decimator2_3_mux_enum, ADAU1372_REG_ADC_CTRL3,
+			    2, adau1372_decimator_mux_text);
+
+static const struct snd_kcontrol_new adau1372_decimator2_3_mux_control =
+	SOC_DAPM_ENUM("Decimator 2+3 Capture Mux", adau1372_decimator2_3_mux_enum);
+
+static const unsigned int adau1372_asrco_mux_values[] = {
+	4, 5, 6, 7,
+};
+
+static const char * const adau1372_asrco_mux_text[] = {
+	"Decimator0",
+	"Decimator1",
+	"Decimator2",
+	"Decimator3",
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco0_mux_enum, ADAU1372_REG_ASRCO_SOURCE_0_1,
+				  0, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco1_mux_enum, ADAU1372_REG_ASRCO_SOURCE_0_1,
+				  4, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco2_mux_enum, ADAU1372_REG_ASRCO_SOURCE_2_3,
+				  0, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco3_mux_enum, ADAU1372_REG_ASRCO_SOURCE_2_3,
+				  4, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values);
+
+static const struct snd_kcontrol_new adau1372_asrco0_mux_control =
+	SOC_DAPM_ENUM("Output ASRC0 Capture Mux", adau1372_asrco0_mux_enum);
+static const struct snd_kcontrol_new adau1372_asrco1_mux_control =
+	SOC_DAPM_ENUM("Output ASRC1 Capture Mux", adau1372_asrco1_mux_enum);
+static const struct snd_kcontrol_new adau1372_asrco2_mux_control =
+	SOC_DAPM_ENUM("Output ASRC2 Capture Mux", adau1372_asrco2_mux_enum);
+static const struct snd_kcontrol_new adau1372_asrco3_mux_control =
+	SOC_DAPM_ENUM("Output ASRC3 Capture Mux", adau1372_asrco3_mux_enum);
+
+static const unsigned int adau1372_sout_mux_values[] = {
+	4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+static const char * const adau1372_sout_mux_text[] = {
+	"Output ASRC0",
+	"Output ASRC1",
+	"Output ASRC2",
+	"Output ASRC3",
+	"Serial Input 0",
+	"Serial Input 1",
+	"Serial Input 2",
+	"Serial Input 3",
+	"Serial Input 4",
+	"Serial Input 5",
+	"Serial Input 6",
+	"Serial Input 7",
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout0_mux_enum, ADAU1372_REG_SOUT_SOURCE_0_1,
+				  0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout1_mux_enum, ADAU1372_REG_SOUT_SOURCE_0_1,
+				  4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout2_mux_enum, ADAU1372_REG_SOUT_SOURCE_2_3,
+				  0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout3_mux_enum, ADAU1372_REG_SOUT_SOURCE_2_3,
+				  4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout4_mux_enum, ADAU1372_REG_SOUT_SOURCE_4_5,
+				  0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout5_mux_enum, ADAU1372_REG_SOUT_SOURCE_4_5,
+				  4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout6_mux_enum, ADAU1372_REG_SOUT_SOURCE_6_7,
+				  0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout7_mux_enum, ADAU1372_REG_SOUT_SOURCE_6_7,
+				  4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values);
+
+static const struct snd_kcontrol_new adau1372_sout0_mux_control =
+	SOC_DAPM_ENUM("Serial Output 0 Capture Mux", adau1372_sout0_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout1_mux_control =
+	SOC_DAPM_ENUM("Serial Output 1 Capture Mux", adau1372_sout1_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout2_mux_control =
+	SOC_DAPM_ENUM("Serial Output 2 Capture Mux", adau1372_sout2_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout3_mux_control =
+	SOC_DAPM_ENUM("Serial Output 3 Capture Mux", adau1372_sout3_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout4_mux_control =
+	SOC_DAPM_ENUM("Serial Output 4 Capture Mux", adau1372_sout4_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout5_mux_control =
+	SOC_DAPM_ENUM("Serial Output 5 Capture Mux", adau1372_sout5_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout6_mux_control =
+	SOC_DAPM_ENUM("Serial Output 6 Capture Mux", adau1372_sout6_mux_enum);
+static const struct snd_kcontrol_new adau1372_sout7_mux_control =
+	SOC_DAPM_ENUM("Serial Output 7 Capture Mux", adau1372_sout7_mux_enum);
+
+static const char * const adau1372_asrci_mux_text[] = {
+	"Serial Input 0+1",
+	"Serial Input 2+3",
+	"Serial Input 4+5",
+	"Serial Input 6+7",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1372_asrci_mux_enum,
+	ADAU1372_REG_ASRC_MODE, 2, adau1372_asrci_mux_text);
+
+static const struct snd_kcontrol_new adau1372_asrci_mux_control =
+	SOC_DAPM_ENUM("Input ASRC Playback Mux", adau1372_asrci_mux_enum);
+
+static const unsigned int adau1372_dac_mux_values[] = {
+	12, 13
+};
+
+static const char * const adau1372_dac_mux_text[] = {
+	"Input ASRC0",
+	"Input ASRC1",
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_dac0_mux_enum, ADAU1372_REG_DAC_SOURCE,
+				  0, 0xf, adau1372_dac_mux_text, adau1372_dac_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_dac1_mux_enum, ADAU1372_REG_DAC_SOURCE,
+				  4, 0xf, adau1372_dac_mux_text, adau1372_dac_mux_values);
+
+static const struct snd_kcontrol_new adau1372_dac0_mux_control =
+	SOC_DAPM_ENUM("DAC 0 Playback Mux", adau1372_dac0_mux_enum);
+static const struct snd_kcontrol_new adau1372_dac1_mux_control =
+	SOC_DAPM_ENUM("DAC 1 Playback Mux", adau1372_dac1_mux_enum);
+
+static const struct snd_soc_dapm_widget adau1372_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("AIN0"),
+	SND_SOC_DAPM_INPUT("AIN1"),
+	SND_SOC_DAPM_INPUT("AIN2"),
+	SND_SOC_DAPM_INPUT("AIN3"),
+	SND_SOC_DAPM_INPUT("DMIC0_1"),
+	SND_SOC_DAPM_INPUT("DMIC2_3"),
+
+	SND_SOC_DAPM_SUPPLY("MICBIAS0", ADAU1372_REG_MICBIAS, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", ADAU1372_REG_MICBIAS, 5, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("PGA0", ADAU1372_REG_PGA_CTRL(0), 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PGA1", ADAU1372_REG_PGA_CTRL(1), 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PGA2", ADAU1372_REG_PGA_CTRL(2), 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PGA3", ADAU1372_REG_PGA_CTRL(3), 6, 0, NULL, 0),
+	SND_SOC_DAPM_ADC("ADC0", NULL, ADAU1372_REG_ADC_CTRL2, 0, 0),
+	SND_SOC_DAPM_ADC("ADC1", NULL, ADAU1372_REG_ADC_CTRL2, 1, 0),
+	SND_SOC_DAPM_ADC("ADC2", NULL, ADAU1372_REG_ADC_CTRL3, 0, 0),
+	SND_SOC_DAPM_ADC("ADC3", NULL, ADAU1372_REG_ADC_CTRL3, 1, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC0 Filter", ADAU1372_REG_DECIM_PWR, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 Filter", ADAU1372_REG_DECIM_PWR, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC2 Filter", ADAU1372_REG_DECIM_PWR, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC3 Filter", ADAU1372_REG_DECIM_PWR, 3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Output ASRC0 Decimator", ADAU1372_REG_DECIM_PWR, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Output ASRC1 Decimator", ADAU1372_REG_DECIM_PWR, 5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Output ASRC2 Decimator", ADAU1372_REG_DECIM_PWR, 6, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Output ASRC3 Decimator", ADAU1372_REG_DECIM_PWR, 7, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("Decimator0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator0_1_mux_control),
+	SND_SOC_DAPM_MUX("Decimator1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator0_1_mux_control),
+	SND_SOC_DAPM_MUX("Decimator2 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator2_3_mux_control),
+	SND_SOC_DAPM_MUX("Decimator3 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator2_3_mux_control),
+
+	SND_SOC_DAPM_MUX("Output ASRC0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco0_mux_control),
+	SND_SOC_DAPM_MUX("Output ASRC1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco1_mux_control),
+	SND_SOC_DAPM_MUX("Output ASRC2 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco2_mux_control),
+	SND_SOC_DAPM_MUX("Output ASRC3 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco3_mux_control),
+	SND_SOC_DAPM_MUX("Serial Output 0 Capture Mux", SND_SOC_NOPM, 0, 0,
+			 &adau1372_sout0_mux_control),
+	SND_SOC_DAPM_MUX("Serial Output 1 Capture Mux", SND_SOC_NOPM, 0, 0,
+			 &adau1372_sout1_mux_control),
+	SND_SOC_DAPM_MUX("Serial Output 2 Capture Mux", SND_SOC_NOPM, 0, 0,
+			 &adau1372_sout2_mux_control),
+	SND_SOC_DAPM_MUX("Serial Output 3 Capture Mux", SND_SOC_NOPM, 0, 0,
+			 &adau1372_sout3_mux_control),
+	SND_SOC_DAPM_MUX("Serial Output 4 Capture Mux", SND_SOC_NOPM, 0, 0,
+			 &adau1372_sout4_mux_control),
+	SND_SOC_DAPM_MUX("Serial Output 5 Capture Mux", SND_SOC_NOPM, 0, 0,
+			 &adau1372_sout5_mux_control),
+	SND_SOC_DAPM_MUX("Serial Output 6 Capture Mux", SND_SOC_NOPM, 0, 0,
+			 &adau1372_sout6_mux_control),
+	SND_SOC_DAPM_MUX("Serial Output 7 Capture Mux", SND_SOC_NOPM, 0, 0,
+			 &adau1372_sout7_mux_control),
+
+	SND_SOC_DAPM_AIF_IN("Serial Input 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("Serial Input 1", NULL, 1, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("Serial Input 2", NULL, 2, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("Serial Input 3", NULL, 3, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("Serial Input 4", NULL, 4, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("Serial Input 5", NULL, 5, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("Serial Input 6", NULL, 6, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("Serial Input 7", NULL, 7, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT("Serial Output 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("Serial Output 1", NULL, 1, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("Serial Output 2", NULL, 2, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("Serial Output 3", NULL, 3, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("Serial Output 4", NULL, 4, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("Serial Output 5", NULL, 5, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("Serial Output 6", NULL, 6, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("Serial Output 7", NULL, 7, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("Output ASRC Supply", ADAU1372_REG_ASRC_MODE, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Input ASRC Supply", ADAU1372_REG_ASRC_MODE, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DAC1 Modulator", ADAU1372_REG_INTERP_PWR, 3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC0 Modulator", ADAU1372_REG_INTERP_PWR, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Input ASRC1 Interpolator", ADAU1372_REG_INTERP_PWR, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Input ASRC0 Interpolator", ADAU1372_REG_INTERP_PWR, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("Input ASRC0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrci_mux_control),
+	SND_SOC_DAPM_MUX("Input ASRC1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrci_mux_control),
+
+	SND_SOC_DAPM_MUX("DAC 0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_dac0_mux_control),
+	SND_SOC_DAPM_MUX("DAC 1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_dac1_mux_control),
+
+	SND_SOC_DAPM_DAC("DAC0", NULL, ADAU1372_REG_DAC_CTRL, 0, 0),
+	SND_SOC_DAPM_DAC("DAC1", NULL, ADAU1372_REG_DAC_CTRL, 1, 0),
+
+	SND_SOC_DAPM_OUT_DRV("OP_STAGE_LP", ADAU1372_REG_OP_STAGE_CTRL, 0, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("OP_STAGE_LN", ADAU1372_REG_OP_STAGE_CTRL, 1, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("OP_STAGE_RP", ADAU1372_REG_OP_STAGE_CTRL, 2, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("OP_STAGE_RN", ADAU1372_REG_OP_STAGE_CTRL, 3, 1, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPOUTL"),
+	SND_SOC_DAPM_OUTPUT("HPOUTR"),
+};
+
+#define ADAU1372_SOUT_ROUTES(x) \
+	{ "Serial Output " #x " Capture Mux", "Output ASRC0", "Output ASRC0 Mux" }, \
+	{ "Serial Output " #x " Capture Mux", "Output ASRC1", "Output ASRC1 Mux" }, \
+	{ "Serial Output " #x " Capture Mux", "Output ASRC2", "Output ASRC2 Mux" }, \
+	{ "Serial Output " #x " Capture Mux", "Output ASRC3", "Output ASRC3 Mux" }, \
+	{ "Serial Output " #x " Capture Mux", "Serial Input 0", "Serial Input 0" }, \
+	{ "Serial Output " #x " Capture Mux", "Serial Input 1", "Serial Input 1" }, \
+	{ "Serial Output " #x " Capture Mux", "Serial Input 2", "Serial Input 2" }, \
+	{ "Serial Output " #x " Capture Mux", "Serial Input 3", "Serial Input 3" }, \
+	{ "Serial Output " #x " Capture Mux", "Serial Input 4", "Serial Input 4" }, \
+	{ "Serial Output " #x " Capture Mux", "Serial Input 5", "Serial Input 5" }, \
+	{ "Serial Output " #x " Capture Mux", "Serial Input 6", "Serial Input 6" }, \
+	{ "Serial Output " #x " Capture Mux", "Serial Input 7", "Serial Input 7" }, \
+	{ "Serial Output " #x, NULL, "Serial Output " #x " Capture Mux" }, \
+	{ "Capture", NULL, "Serial Output " #x }
+
+#define ADAU1372_ASRCO_ROUTES(x) \
+	{ "Output ASRC" #x " Mux", "Decimator0", "Decimator0 Mux" }, \
+	{ "Output ASRC" #x " Mux", "Decimator1", "Decimator1 Mux" }, \
+	{ "Output ASRC" #x " Mux", "Decimator2", "Decimator2 Mux" }, \
+	{ "Output ASRC" #x " Mux", "Decimator3", "Decimator3 Mux" }
+
+static const struct snd_soc_dapm_route adau1372_dapm_routes[] = {
+	{ "PGA0", NULL, "AIN0" },
+	{ "PGA1", NULL, "AIN1" },
+	{ "PGA2", NULL, "AIN2" },
+	{ "PGA3", NULL, "AIN3" },
+
+	{ "ADC0", NULL, "PGA0" },
+	{ "ADC1", NULL, "PGA1" },
+	{ "ADC2", NULL, "PGA2" },
+	{ "ADC3", NULL, "PGA3" },
+
+	{ "Decimator0 Mux", "ADC", "ADC0" },
+	{ "Decimator1 Mux", "ADC", "ADC1" },
+	{ "Decimator2 Mux", "ADC", "ADC2" },
+	{ "Decimator3 Mux", "ADC", "ADC3" },
+
+	{ "Decimator0 Mux", "DMIC", "DMIC0_1" },
+	{ "Decimator1 Mux", "DMIC", "DMIC0_1" },
+	{ "Decimator2 Mux", "DMIC", "DMIC2_3" },
+	{ "Decimator3 Mux", "DMIC", "DMIC2_3" },
+
+	{ "Decimator0 Mux", NULL, "ADC0 Filter" },
+	{ "Decimator1 Mux", NULL, "ADC1 Filter" },
+	{ "Decimator2 Mux", NULL, "ADC2 Filter" },
+	{ "Decimator3 Mux", NULL, "ADC3 Filter" },
+
+	{ "Output ASRC0 Mux", NULL, "Output ASRC Supply" },
+	{ "Output ASRC1 Mux", NULL, "Output ASRC Supply" },
+	{ "Output ASRC2 Mux", NULL, "Output ASRC Supply" },
+	{ "Output ASRC3 Mux", NULL, "Output ASRC Supply" },
+	{ "Output ASRC0 Mux", NULL, "Output ASRC0 Decimator" },
+	{ "Output ASRC1 Mux", NULL, "Output ASRC1 Decimator" },
+	{ "Output ASRC2 Mux", NULL, "Output ASRC2 Decimator" },
+	{ "Output ASRC3 Mux", NULL, "Output ASRC3 Decimator" },
+
+	ADAU1372_ASRCO_ROUTES(0),
+	ADAU1372_ASRCO_ROUTES(1),
+	ADAU1372_ASRCO_ROUTES(2),
+	ADAU1372_ASRCO_ROUTES(3),
+
+	ADAU1372_SOUT_ROUTES(0),
+	ADAU1372_SOUT_ROUTES(1),
+	ADAU1372_SOUT_ROUTES(2),
+	ADAU1372_SOUT_ROUTES(3),
+	ADAU1372_SOUT_ROUTES(4),
+	ADAU1372_SOUT_ROUTES(5),
+	ADAU1372_SOUT_ROUTES(6),
+	ADAU1372_SOUT_ROUTES(7),
+
+	{ "Serial Input 0", NULL, "Playback" },
+	{ "Serial Input 1", NULL, "Playback" },
+	{ "Serial Input 2", NULL, "Playback" },
+	{ "Serial Input 3", NULL, "Playback" },
+	{ "Serial Input 4", NULL, "Playback" },
+	{ "Serial Input 5", NULL, "Playback" },
+	{ "Serial Input 6", NULL, "Playback" },
+	{ "Serial Input 7", NULL, "Playback" },
+
+	{ "Input ASRC0 Mux", "Serial Input 0+1", "Serial Input 0" },
+	{ "Input ASRC1 Mux", "Serial Input 0+1", "Serial Input 1" },
+	{ "Input ASRC0 Mux", "Serial Input 2+3", "Serial Input 2" },
+	{ "Input ASRC1 Mux", "Serial Input 2+3", "Serial Input 3" },
+	{ "Input ASRC0 Mux", "Serial Input 4+5", "Serial Input 4" },
+	{ "Input ASRC1 Mux", "Serial Input 4+5", "Serial Input 5" },
+	{ "Input ASRC0 Mux", "Serial Input 6+7", "Serial Input 6" },
+	{ "Input ASRC1 Mux", "Serial Input 6+7", "Serial Input 7" },
+	{ "Input ASRC0 Mux", NULL, "Input ASRC Supply" },
+	{ "Input ASRC1 Mux", NULL, "Input ASRC Supply" },
+	{ "Input ASRC0 Mux", NULL, "Input ASRC0 Interpolator" },
+	{ "Input ASRC1 Mux", NULL, "Input ASRC1 Interpolator" },
+
+	{ "DAC 0 Mux", "Input ASRC0", "Input ASRC0 Mux" },
+	{ "DAC 0 Mux", "Input ASRC1", "Input ASRC1 Mux" },
+	{ "DAC 1 Mux", "Input ASRC0", "Input ASRC0 Mux" },
+	{ "DAC 1 Mux", "Input ASRC1", "Input ASRC1 Mux" },
+
+	{ "DAC0", NULL, "DAC 0 Mux" },
+	{ "DAC1", NULL, "DAC 1 Mux" },
+	{ "DAC0", NULL, "DAC0 Modulator" },
+	{ "DAC1", NULL, "DAC1 Modulator" },
+
+	{ "OP_STAGE_LP", NULL, "DAC0" },
+	{ "OP_STAGE_LN", NULL, "DAC0" },
+	{ "OP_STAGE_RP", NULL, "DAC1" },
+	{ "OP_STAGE_RN", NULL, "DAC1" },
+
+	{ "HPOUTL", NULL, "OP_STAGE_LP" },
+	{ "HPOUTL", NULL, "OP_STAGE_LN" },
+	{ "HPOUTR", NULL, "OP_STAGE_RP" },
+	{ "HPOUTR", NULL, "OP_STAGE_RN" },
+};
+
+static int adau1372_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai);
+	unsigned int sai0 = 0, sai1 = 0;
+	bool invert_lrclk = false;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		adau1372->master = true;
+		sai1 |= ADAU1372_SAI1_MS;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		adau1372->master = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		invert_lrclk = false;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		invert_lrclk = true;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		invert_lrclk = false;
+		sai1 |= ADAU1372_SAI1_BCLKEDGE;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		invert_lrclk = true;
+		sai1 |= ADAU1372_SAI1_BCLKEDGE;
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		sai0 |= ADAU1372_SAI0_DELAY1;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		sai0 |= ADAU1372_SAI0_DELAY0;
+		invert_lrclk = !invert_lrclk;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		sai0 |= ADAU1372_SAI0_DELAY1;
+		sai1 |= ADAU1372_SAI1_LR_MODE;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		sai0 |= ADAU1372_SAI0_DELAY0;
+		sai1 |= ADAU1372_SAI1_LR_MODE;
+		break;
+	}
+
+	if (invert_lrclk)
+		sai1 |= ADAU1372_SAI1_LR_POL;
+
+	regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, ADAU1372_SAI0_DELAY_MASK, sai0);
+	regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1,
+			   ADAU1372_SAI1_MS | ADAU1372_SAI1_BCLKEDGE |
+			   ADAU1372_SAI1_LR_MODE | ADAU1372_SAI1_LR_POL, sai1);
+
+	return 0;
+}
+
+static int adau1372_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai);
+	unsigned int rate = params_rate(params);
+	unsigned int slot_width;
+	unsigned int sai0, sai1;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(adau1372_rates); i++) {
+		if (rate == adau1372_rates[i])
+			break;
+	}
+
+	if (i == ARRAY_SIZE(adau1372_rates))
+		return -EINVAL;
+
+	sai0 = i;
+
+	slot_width = adau1372->slot_width;
+	if (slot_width == 0)
+		slot_width = params_width(params);
+
+	switch (slot_width) {
+	case 16:
+		sai1 = ADAU1372_SAI1_BCLKRATE;
+		break;
+	case 32:
+		sai1 = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, ADAU1372_SAI0_FS_MASK, sai0);
+	regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, ADAU1372_SAI1_BCLKRATE, sai1);
+
+	return 0;
+}
+
+static int adau1372_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+				 unsigned int rx_mask, int slots, int width)
+{
+	struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai);
+	unsigned int sai0, sai1;
+
+	/* I2S mode */
+	if (slots == 0) {
+		/* The other settings dont matter in I2S mode */
+		regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0,
+				   ADAU1372_SAI0_SAI_MASK, ADAU1372_SAI0_SAI_I2S);
+		adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM2;
+		adau1372->slot_width = 0;
+		return 0;
+	}
+
+	/* We have 8 channels anything outside that is not supported */
+	if ((tx_mask & ~0xff) != 0 || (rx_mask & ~0xff) != 0)
+		return -EINVAL;
+
+	switch (width) {
+	case 16:
+		sai1 = ADAU1372_SAI1_BCLK_TDMC;
+		break;
+	case 32:
+		sai1 = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (slots) {
+	case 2:
+		sai0 = ADAU1372_SAI0_SAI_TDM2;
+		adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM2;
+		break;
+	case 4:
+		sai0 = ADAU1372_SAI0_SAI_TDM4;
+		if (adau1372->master)
+			adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM4_MASTER;
+		else
+			adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM4;
+		break;
+	case 8:
+		sai0 = ADAU1372_SAI0_SAI_TDM8;
+		adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	adau1372->slot_width = width;
+
+	regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, ADAU1372_SAI0_SAI_MASK, sai0);
+	regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, ADAU1372_SAI1_BCLK_TDMC, sai1);
+
+	/* Mask is inverted in hardware */
+	regmap_write(adau1372->regmap, ADAU1372_REG_SOUT_CTRL, ~tx_mask);
+
+	return 0;
+}
+
+static int adau1372_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai);
+	unsigned int sai1;
+
+	if (tristate)
+		sai1 = ADAU1372_SAI1_TDM_TS;
+	else
+		sai1 = 0;
+
+	return regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, ADAU1372_SAI1_TDM_TS, sai1);
+}
+
+static int adau1372_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai);
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+				   &adau1372->rate_constraints);
+
+	return 0;
+}
+
+static void adau1372_enable_pll(struct adau1372 *adau1372)
+{
+	unsigned int val, timeout = 0;
+	int ret;
+
+	regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL,
+			   ADAU1372_CLK_CTRL_PLL_EN, ADAU1372_CLK_CTRL_PLL_EN);
+	do {
+		/* Takes about 1ms to lock */
+		usleep_range(1000, 2000);
+		ret = regmap_read(adau1372->regmap, ADAU1372_REG_PLL(5), &val);
+		if (ret)
+			break;
+		timeout++;
+	} while (!(val & 1) && timeout < 3);
+
+	if (ret < 0 || !(val & 1))
+		dev_err(adau1372->dev, "Failed to lock PLL\n");
+}
+
+static void adau1372_set_power(struct adau1372 *adau1372, bool enable)
+{
+	if (adau1372->enabled == enable)
+		return;
+
+	if (enable) {
+		unsigned int clk_ctrl = ADAU1372_CLK_CTRL_MCLK_EN;
+
+		clk_prepare_enable(adau1372->mclk);
+		if (adau1372->pd_gpio)
+			gpiod_set_value(adau1372->pd_gpio, 0);
+
+		if (adau1372->switch_mode)
+			adau1372->switch_mode(adau1372->dev);
+
+		regcache_cache_only(adau1372->regmap, false);
+
+		/*
+		 * Clocks needs to be enabled before any other register can be
+		 * accessed.
+		 */
+		if (adau1372->use_pll) {
+			adau1372_enable_pll(adau1372);
+			clk_ctrl |= ADAU1372_CLK_CTRL_CLKSRC;
+		}
+
+		regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL,
+				   ADAU1372_CLK_CTRL_MCLK_EN | ADAU1372_CLK_CTRL_CLKSRC, clk_ctrl);
+		regcache_sync(adau1372->regmap);
+	} else {
+		if (adau1372->pd_gpio) {
+			/*
+			 * This will turn everything off and reset the register
+			 * map. No need to do any register writes to manually
+			 * turn things off.
+			 */
+			gpiod_set_value(adau1372->pd_gpio, 1);
+			regcache_mark_dirty(adau1372->regmap);
+		} else {
+			regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL,
+					   ADAU1372_CLK_CTRL_MCLK_EN | ADAU1372_CLK_CTRL_PLL_EN, 0);
+		}
+		clk_disable_unprepare(adau1372->mclk);
+		regcache_cache_only(adau1372->regmap, true);
+	}
+
+	adau1372->enabled = enable;
+}
+
+static int adau1372_set_bias_level(struct snd_soc_component *component,
+				   enum snd_soc_bias_level level)
+{
+	struct adau1372 *adau1372 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		adau1372_set_power(adau1372, true);
+		break;
+	case SND_SOC_BIAS_OFF:
+		adau1372_set_power(adau1372, false);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver adau1372_driver = {
+	.set_bias_level = adau1372_set_bias_level,
+	.controls = adau1372_controls,
+	.num_controls = ARRAY_SIZE(adau1372_controls),
+	.dapm_widgets = adau1372_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(adau1372_dapm_widgets),
+	.dapm_routes = adau1372_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(adau1372_dapm_routes),
+};
+
+static const struct snd_soc_dai_ops adau1372_dai_ops = {
+	.set_fmt = adau1372_set_dai_fmt,
+	.set_tdm_slot = adau1372_set_tdm_slot,
+	.set_tristate = adau1372_set_tristate,
+	.hw_params = adau1372_hw_params,
+	.startup = adau1372_startup,
+};
+
+#define ADAU1372_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |	SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver adau1372_dai_driver = {
+	.name = "adau1372",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = ADAU1372_FORMATS,
+		.sig_bits = 24,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = ADAU1372_FORMATS,
+		.sig_bits = 24,
+	},
+	.ops = &adau1372_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int adau1372_setup_pll(struct adau1372 *adau1372, unsigned int rate)
+{
+	u8 regs[5];
+	unsigned int i;
+	int ret;
+
+	ret = adau_calc_pll_cfg(rate, 49152000, regs);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++)
+		regmap_write(adau1372->regmap, ADAU1372_REG_PLL(i), regs[i]);
+
+	return 0;
+}
+
+int adau1372_probe(struct device *dev, struct regmap *regmap,
+		   void (*switch_mode)(struct device *dev))
+{
+	struct adau1372 *adau1372;
+	unsigned int clk_ctrl;
+	unsigned long rate;
+	int ret;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	adau1372 = devm_kzalloc(dev, sizeof(*adau1372), GFP_KERNEL);
+	if (!adau1372)
+		return -ENOMEM;
+
+	adau1372->clk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(adau1372->clk))
+		return PTR_ERR(adau1372->clk);
+
+	adau1372->pd_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH);
+	if (IS_ERR(adau1372->pd_gpio))
+		return PTR_ERR(adau1372->pd_gpio);
+
+	adau1372->regmap = regmap;
+	adau1372->switch_mode = switch_mode;
+	adau1372->dev = dev;
+	adau1372->rate_constraints.list = adau1372_rates;
+	adau1372->rate_constraints.count = ARRAY_SIZE(adau1372_rates);
+	adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM2;
+
+	dev_set_drvdata(dev, adau1372);
+
+	/*
+	 * The datasheet says that the internal MCLK always needs to run at
+	 * 12.288MHz. Automatically choose a valid configuration from the
+	 * external clock.
+	 */
+	rate = clk_get_rate(adau1372->clk);
+
+	switch (rate) {
+	case 12288000:
+		clk_ctrl = ADAU1372_CLK_CTRL_CC_MDIV;
+		break;
+	case 24576000:
+		clk_ctrl = 0;
+		break;
+	default:
+		clk_ctrl = 0;
+		ret = adau1372_setup_pll(adau1372, rate);
+		if (ret < 0)
+			return ret;
+		adau1372->use_pll = true;
+		break;
+	}
+
+	/*
+	 * Most of the registers are inaccessible unless the internal clock is
+	 * enabled.
+	 */
+	regcache_cache_only(regmap, true);
+
+	regmap_update_bits(regmap, ADAU1372_REG_CLK_CTRL, ADAU1372_CLK_CTRL_CC_MDIV, clk_ctrl);
+
+	/*
+	 * No pinctrl support yet, put the multi-purpose pins in the most
+	 * sensible mode for general purpose CODEC operation.
+	 */
+	regmap_write(regmap, ADAU1372_REG_MODE_MP(1), 0x00); /* SDATA OUT */
+	regmap_write(regmap, ADAU1372_REG_MODE_MP(6), 0x12); /* CLOCKOUT */
+
+	regmap_write(regmap, ADAU1372_REG_OP_STAGE_MUTE, 0x0);
+
+	regmap_write(regmap, 0x7, 0x01); /* CLOCK OUT */
+
+	return  devm_snd_soc_register_component(dev, &adau1372_driver, &adau1372_dai_driver, 1);
+}
+EXPORT_SYMBOL(adau1372_probe);
+
+static const struct reg_default adau1372_reg_defaults[] = {
+	{ ADAU1372_REG_CLK_CTRL,		0x00 },
+	{ ADAU1372_REG_PLL(0),			0x00 },
+	{ ADAU1372_REG_PLL(1),			0x00 },
+	{ ADAU1372_REG_PLL(2),			0x00 },
+	{ ADAU1372_REG_PLL(3),			0x00 },
+	{ ADAU1372_REG_PLL(4),			0x00 },
+	{ ADAU1372_REG_PLL(5),			0x00 },
+	{ ADAU1372_REG_DAC_SOURCE,		0x10 },
+	{ ADAU1372_REG_SOUT_SOURCE_0_1,		0x54 },
+	{ ADAU1372_REG_SOUT_SOURCE_2_3,		0x76 },
+	{ ADAU1372_REG_SOUT_SOURCE_4_5,		0x54 },
+	{ ADAU1372_REG_SOUT_SOURCE_6_7,		0x76 },
+	{ ADAU1372_REG_ADC_SDATA_CH,		0x04 },
+	{ ADAU1372_REG_ASRCO_SOURCE_0_1,	0x10 },
+	{ ADAU1372_REG_ASRCO_SOURCE_2_3,	0x32 },
+	{ ADAU1372_REG_ASRC_MODE,		0x00 },
+	{ ADAU1372_REG_ADC_CTRL0,		0x19 },
+	{ ADAU1372_REG_ADC_CTRL1,		0x19 },
+	{ ADAU1372_REG_ADC_CTRL2,		0x00 },
+	{ ADAU1372_REG_ADC_CTRL3,		0x00 },
+	{ ADAU1372_REG_ADC_VOL(0),		0x00 },
+	{ ADAU1372_REG_ADC_VOL(1),		0x00 },
+	{ ADAU1372_REG_ADC_VOL(2),		0x00 },
+	{ ADAU1372_REG_ADC_VOL(3),		0x00 },
+	{ ADAU1372_REG_PGA_CTRL(0),		0x40 },
+	{ ADAU1372_REG_PGA_CTRL(1),		0x40 },
+	{ ADAU1372_REG_PGA_CTRL(2),		0x40 },
+	{ ADAU1372_REG_PGA_CTRL(3),		0x40 },
+	{ ADAU1372_REG_PGA_BOOST,		0x00 },
+	{ ADAU1372_REG_MICBIAS,			0x00 },
+	{ ADAU1372_REG_DAC_CTRL,		0x18 },
+	{ ADAU1372_REG_DAC_VOL(0),		0x00 },
+	{ ADAU1372_REG_DAC_VOL(1),		0x00 },
+	{ ADAU1372_REG_OP_STAGE_MUTE,		0x0f },
+	{ ADAU1372_REG_SAI0,			0x00 },
+	{ ADAU1372_REG_SAI1,			0x00 },
+	{ ADAU1372_REG_SOUT_CTRL,		0x00 },
+	{ ADAU1372_REG_MODE_MP(0),		0x00 },
+	{ ADAU1372_REG_MODE_MP(1),		0x10 },
+	{ ADAU1372_REG_MODE_MP(4),		0x00 },
+	{ ADAU1372_REG_MODE_MP(5),		0x00 },
+	{ ADAU1372_REG_MODE_MP(6),		0x11 },
+	{ ADAU1372_REG_OP_STAGE_CTRL,		0x0f },
+	{ ADAU1372_REG_DECIM_PWR,		0x00 },
+	{ ADAU1372_REG_INTERP_PWR,		0x00 },
+	{ ADAU1372_REG_BIAS_CTRL0,		0x00 },
+	{ ADAU1372_REG_BIAS_CTRL1,		0x00 },
+};
+
+static bool adau1372_volatile_register(struct device *dev, unsigned int reg)
+{
+	if (reg == ADAU1372_REG_PLL(5))
+		return true;
+
+	return false;
+}
+
+const struct regmap_config adau1372_regmap_config = {
+	.val_bits = 8,
+	.reg_bits = 16,
+	.max_register = 0x4d,
+
+	.reg_defaults = adau1372_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(adau1372_reg_defaults),
+	.volatile_reg = adau1372_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(adau1372_regmap_config);
+
+MODULE_DESCRIPTION("ASoC ADAU1372 CODEC driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/adau1372.h b/sound/soc/codecs/adau1372.h
new file mode 100644
index 000000000000..a9d2c59b73a9
--- /dev/null
+++ b/sound/soc/codecs/adau1372.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ADAU1372 driver
+ *
+ * Copyright 2016 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#ifndef SOUND_SOC_CODECS_ADAU1372_H
+#define SOUND_SOC_CODECS_ADAU1372_H
+
+#include <linux/regmap.h>
+
+struct device;
+
+int adau1372_probe(struct device *dev, struct regmap *regmap,
+		   void (*switch_mode)(struct device *dev));
+
+extern const struct regmap_config adau1372_regmap_config;
+
+#endif
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
index 0a36e523584c..8260f49caa24 100644
--- a/sound/soc/codecs/adau1977.c
+++ b/sound/soc/codecs/adau1977.c
@@ -12,7 +12,6 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/platform_data/adau1977.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
@@ -24,6 +23,8 @@
 #include <sound/soc.h>
 #include <sound/tlv.h>
 
+#include <dt-bindings/sound/adi,adau1977.h>
+
 #include "adau1977.h"
 
 #define ADAU1977_REG_POWER		0x00
@@ -881,13 +882,9 @@ static const struct snd_soc_component_driver adau1977_component_driver = {
 
 static int adau1977_setup_micbias(struct adau1977 *adau1977)
 {
-	struct adau1977_platform_data *pdata = adau1977->dev->platform_data;
 	unsigned int micbias;
 
-	if (pdata)
-		micbias = pdata->micbias;
-	else if (device_property_read_u32(adau1977->dev, "adi,micbias",
-					  &micbias))
+	if (device_property_read_u32(adau1977->dev, "adi,micbias", &micbias))
 		micbias = ADAU1977_MICBIAS_8V5;
 
 	if (micbias > ADAU1977_MICBIAS_9V0) {
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index 4fd99280d7db..75a649108106 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -373,6 +373,7 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	case SND_SOC_DAIFMT_CBM_CFM:
 		capture |= ADAV80X_CAPTURE_MODE_MASTER;
 		playback |= ADAV80X_PLAYBACK_MODE_MASTER;
+		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
 		break;
 	default:
diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c
index f44d9a4a8507..5d46ae85566c 100644
--- a/sound/soc/codecs/ak4118.c
+++ b/sound/soc/codecs/ak4118.c
@@ -404,11 +404,13 @@ static int ak4118_i2c_probe(struct i2c_client *i2c,
 				&soc_component_drv_ak4118, &ak4118_dai, 1);
 }
 
+#ifdef CONFIG_OF
 static const struct of_device_id ak4118_of_match[] = {
 	{ .compatible = "asahi-kasei,ak4118", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, ak4118_of_match);
+#endif
 
 static const struct i2c_device_id ak4118_id_table[] = {
 	{ "ak4118", 0 },
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
index 2f076d5ee284..8a32b0139cb0 100644
--- a/sound/soc/codecs/ak5558.c
+++ b/sound/soc/codecs/ak5558.c
@@ -415,7 +415,7 @@ static int ak5558_i2c_remove(struct i2c_client *i2c)
 	return 0;
 }
 
-static const struct of_device_id ak5558_i2c_dt_ids[] = {
+static const struct of_device_id ak5558_i2c_dt_ids[] __maybe_unused = {
 	{ .compatible = "asahi-kasei,ak5558"},
 	{ }
 };
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index 3d1761a531f5..54f489837162 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -1068,11 +1068,13 @@ static const struct i2c_device_id alc5623_i2c_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, alc5623_i2c_table);
 
+#ifdef CONFIG_OF
 static const struct of_device_id alc5623_of_match[] = {
 	{ .compatible = "realtek,alc5623", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, alc5623_of_match);
+#endif
 
 /*  i2c codec control layer */
 static struct i2c_driver alc5623_i2c_driver = {
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index 9d6dcd3ffa57..bde5ded67754 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -1167,11 +1167,13 @@ static const struct i2c_device_id alc5632_i2c_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, alc5632_i2c_table);
 
+#ifdef CONFIG_OF
 static const struct of_device_id alc5632_of_match[] = {
 	{ .compatible = "realtek,alc5632", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, alc5632_of_match);
+#endif
 
 /* i2c codec control layer */
 static struct i2c_driver alc5632_i2c_driver = {
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 1228f2de0297..e32871b3f68a 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -1034,6 +1034,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 				priv->out_down_delay++;
 				break;
 			}
+			break;
 		default:
 			break;
 		}
diff --git a/sound/soc/codecs/bd28623.c b/sound/soc/codecs/bd28623.c
index 31904ef5c88b..a6267cb86d86 100644
--- a/sound/soc/codecs/bd28623.c
+++ b/sound/soc/codecs/bd28623.c
@@ -222,7 +222,7 @@ static int bd28623_probe(struct platform_device *pdev)
 					       &soc_dai_bd, 1);
 }
 
-static const struct of_device_id bd28623_of_match[] = {
+static const struct of_device_id bd28623_of_match[] __maybe_unused = {
 	{ .compatible = "rohm,bd28623", },
 	{}
 };
diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c
index 58894bf47514..f33a2a9654e7 100644
--- a/sound/soc/codecs/cros_ec_codec.c
+++ b/sound/soc/codecs/cros_ec_codec.c
@@ -332,7 +332,7 @@ static int i2s_rx_event(struct snd_soc_dapm_widget *w,
 		snd_soc_dapm_to_component(w->dapm);
 	struct cros_ec_codec_priv *priv =
 		snd_soc_component_get_drvdata(component);
-	struct ec_param_ec_codec_i2s_rx p;
+	struct ec_param_ec_codec_i2s_rx p = {};
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index f772628f233e..796b894c390f 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -944,6 +944,7 @@ static int cs42l52_beep_event(struct input_dev *dev, unsigned int type,
 	case SND_BELL:
 		if (hz)
 			hz = 261;
+		break;
 	case SND_TONE:
 		break;
 	default:
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index 97024a6ac96d..bb9599cc832b 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -1008,6 +1008,7 @@ static int cs42l56_beep_event(struct input_dev *dev, unsigned int type,
 	case SND_BELL:
 		if (hz)
 			hz = 261;
+		break;
 	case SND_TONE:
 		break;
 	default:
diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c
index 6e34106c268f..52dc29942ec2 100644
--- a/sound/soc/codecs/cs47l92.c
+++ b/sound/soc/codecs/cs47l92.c
@@ -201,6 +201,7 @@ static int cs47l92_outclk_ev(struct snd_soc_dapm_widget *w,
 		default:
 			break;
 		}
+		break;
 	default:
 		break;
 	}
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index 2ad00ed21bec..2f10991a8bdb 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -1579,7 +1579,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
 		.id	= CX2072X_DAI_DSP,
 		.probe = cx2072x_dsp_dai_probe,
 		.playback = {
-			.stream_name = "Playback",
+			.stream_name = "DSP Playback",
 			.channels_min = 2,
 			.channels_max = 2,
 			.rates = CX2072X_RATES_DSP,
@@ -1591,7 +1591,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
 		.name = "cx2072x-aec",
 		.id	= 3,
 		.capture = {
-			.stream_name = "Capture",
+			.stream_name = "AEC Capture",
 			.channels_min = 2,
 			.channels_max = 2,
 			.rates = CX2072X_RATES_DSP,
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index 6d78bccb55c3..2bfafbe9e3dc 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -2278,12 +2278,14 @@ static irqreturn_t da7218_irq_thread(int irq, void *data)
  * DT
  */
 
+#ifdef CONFIG_OF
 static const struct of_device_id da7218_of_match[] = {
 	{ .compatible = "dlg,da7217", .data = (void *) DA7217_DEV_ID },
 	{ .compatible = "dlg,da7218", .data = (void *) DA7218_DEV_ID },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, da7218_of_match);
+#endif
 
 static inline int da7218_of_get_id(struct device *dev)
 {
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 0b3b7909efc9..e9b45daec0ca 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -1702,11 +1702,13 @@ static struct snd_soc_dai_driver da7219_dai = {
  * DT/ACPI
  */
 
+#ifdef CONFIG_OF
 static const struct of_device_id da7219_of_match[] = {
 	{ .compatible = "dlg,da7219", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, da7219_of_match);
+#endif
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id da7219_acpi_match[] = {
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index b0d9ca6de685..aed92f615b02 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -1519,11 +1519,13 @@ static const struct i2c_device_id da9055_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id da9055_of_match[] = {
 	{ .compatible = "dlg,da9055-codec", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, da9055_of_match);
+#endif
 
 /* I2C codec control layer */
 static struct i2c_driver da9055_i2c_driver = {
diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c
index 00518406eb2b..e2b79879354b 100644
--- a/sound/soc/codecs/es7134.c
+++ b/sound/soc/codecs/es7134.c
@@ -183,7 +183,7 @@ static const struct snd_soc_dapm_route es7134_extra_routes[] = {
 	{ "Playback", NULL, "VDD", }
 };
 
-static const struct es7134_chip es7134_chip = {
+static const struct es7134_chip es7134_chip __maybe_unused = {
 	.dai_drv = &es7134_dai,
 	.modes = es7134_modes,
 	.mode_num = ARRAY_SIZE(es7134_modes),
@@ -261,7 +261,7 @@ static const struct snd_soc_dapm_route es7154_extra_routes[] = {
 	{ "Playback", NULL, "PVDD", }
 };
 
-static const struct es7134_chip es7154_chip = {
+static const struct es7134_chip es7154_chip __maybe_unused = {
 	.dai_drv = &es7154_dai,
 	.modes = es7154_modes,
 	.mode_num = ARRAY_SIZE(es7154_modes),
diff --git a/sound/soc/codecs/es7241.c b/sound/soc/codecs/es7241.c
index 87991bd4acef..2344a0b03518 100644
--- a/sound/soc/codecs/es7241.c
+++ b/sound/soc/codecs/es7241.c
@@ -203,7 +203,7 @@ static const struct es7241_clock_mode es7241_modes[] = {
 	},
 };
 
-static const struct es7241_chip es7241_chip = {
+static const struct es7241_chip es7241_chip __maybe_unused = {
 	.modes = es7241_modes,
 	.mode_num = ARRAY_SIZE(es7241_modes),
 };
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index bd5d230c5df2..f9ec5cf82599 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -834,11 +834,13 @@ static const struct i2c_device_id es8316_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, es8316_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id es8316_of_match[] = {
 	{ .compatible = "everest,es8316", },
 	{},
 };
 MODULE_DEVICE_TABLE(of, es8316_of_match);
+#endif
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id es8316_acpi_match[] = {
diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c
index ae9e1c70ca57..e1235e695b0f 100644
--- a/sound/soc/codecs/gtm601.c
+++ b/sound/soc/codecs/gtm601.c
@@ -87,7 +87,7 @@ static int gtm601_platform_probe(struct platform_device *pdev)
 			(struct snd_soc_dai_driver *)dai_driver, 1);
 }
 
-static const struct of_device_id gtm601_codec_of_match[] = {
+static const struct of_device_id gtm601_codec_of_match[] __maybe_unused = {
 	{ .compatible = "option,gtm601", .data = (void *)&gtm601_dai },
 	{ .compatible = "broadmobi,bm818", .data = (void *)&bm818_dai },
 	{},
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 403d4c6a49a8..d5fcc4db8284 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -282,6 +282,7 @@ struct hdmi_codec_priv {
 
 static const struct snd_soc_dapm_widget hdmi_widgets[] = {
 	SND_SOC_DAPM_OUTPUT("TX"),
+	SND_SOC_DAPM_OUTPUT("RX"),
 };
 
 enum {
@@ -389,6 +390,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
 			      struct snd_soc_dai *dai)
 {
 	struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 	int ret = 0;
 
 	mutex_lock(&hcp->lock);
@@ -404,7 +406,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
 			goto err;
 	}
 
-	if (hcp->hcd.ops->get_eld) {
+	if (tx && hcp->hcd.ops->get_eld) {
 		ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data,
 					    hcp->eld, sizeof(hcp->eld));
 		if (ret)
@@ -660,14 +662,20 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai)
 {
 	struct snd_soc_dapm_context *dapm;
 	struct hdmi_codec_daifmt *daifmt;
-	struct snd_soc_dapm_route route = {
-		.sink = "TX",
-		.source = dai->driver->playback.stream_name,
+	struct snd_soc_dapm_route route[] = {
+		{
+			.sink = "TX",
+			.source = dai->driver->playback.stream_name,
+		},
+		{
+			.sink = dai->driver->capture.stream_name,
+			.source = "RX",
+		},
 	};
 	int ret;
 
 	dapm = snd_soc_component_get_dapm(dai->component);
-	ret = snd_soc_dapm_add_routes(dapm, &route, 1);
+	ret = snd_soc_dapm_add_routes(dapm, route, 2);
 	if (ret)
 		return ret;
 
@@ -692,10 +700,16 @@ static void plugged_cb(struct device *dev, bool plugged)
 {
 	struct hdmi_codec_priv *hcp = dev_get_drvdata(dev);
 
-	if (plugged)
+	if (plugged) {
+		if (hcp->hcd.ops->get_eld) {
+			hcp->hcd.ops->get_eld(dev->parent, hcp->hcd.data,
+					    hcp->eld, sizeof(hcp->eld));
+		}
 		hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT);
-	else
+	} else {
 		hdmi_codec_jack_report(hcp, 0);
+		memset(hcp->eld, 0, sizeof(hcp->eld));
+	}
 }
 
 static int hdmi_codec_set_jack(struct snd_soc_component *component,
@@ -751,6 +765,14 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = {
 		.formats = I2S_FORMATS,
 		.sig_bits = 24,
 	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = HDMI_RATES,
+		.formats = I2S_FORMATS,
+		.sig_bits = 24,
+	},
 	.ops = &hdmi_codec_i2s_dai_ops,
 	.pcm_new = hdmi_codec_pcm_new,
 };
@@ -767,6 +789,13 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
 		.rates = HDMI_RATES,
 		.formats = SPDIF_FORMATS,
 	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = HDMI_RATES,
+		.formats = SPDIF_FORMATS,
+	},
 	.ops = &hdmi_codec_spdif_dai_ops,
 	.pcm_new = hdmi_codec_pcm_new,
 };
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
index d0e8f0d2fbc1..4dbce24c5f76 100644
--- a/sound/soc/codecs/inno_rk3036.c
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -467,7 +467,7 @@ static int rk3036_codec_platform_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id rk3036_codec_of_match[] = {
+static const struct of_device_id rk3036_codec_of_match[] __maybe_unused = {
 	{ .compatible = "rockchip,rk3036-codec", },
 	{}
 };
diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c
index e49374c72e70..5201a8f6d7b6 100644
--- a/sound/soc/codecs/jz4725b.c
+++ b/sound/soc/codecs/jz4725b.c
@@ -198,15 +198,15 @@ static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w,
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		return regmap_update_bits(map, JZ4725B_CODEC_REG_IFR,
-					  BIT(REG_IFR_RAMP_UP_DONE_OFFSET), 0);
+		return regmap_clear_bits(map, JZ4725B_CODEC_REG_IFR,
+					 BIT(REG_IFR_RAMP_UP_DONE_OFFSET));
 	case SND_SOC_DAPM_POST_PMU:
 		return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR,
 			       val, val & BIT(REG_IFR_RAMP_UP_DONE_OFFSET),
 			       100000, 500000);
 	case SND_SOC_DAPM_PRE_PMD:
-		return regmap_update_bits(map, JZ4725B_CODEC_REG_IFR,
-				BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET), 0);
+		return regmap_clear_bits(map, JZ4725B_CODEC_REG_IFR,
+				BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET));
 	case SND_SOC_DAPM_POST_PMD:
 		return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR,
 			       val, val & BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET),
@@ -303,24 +303,22 @@ static int jz4725b_codec_set_bias_level(struct snd_soc_component *component,
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
-				   BIT(REG_PMR2_SB_SLEEP_OFFSET), 0);
+		regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2,
+				  BIT(REG_PMR2_SB_SLEEP_OFFSET));
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		/* Enable sound hardware */
-		regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
-				   BIT(REG_PMR2_SB_OFFSET), 0);
+		regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2,
+				  BIT(REG_PMR2_SB_OFFSET));
 		msleep(224);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
-				   BIT(REG_PMR2_SB_SLEEP_OFFSET),
-				   BIT(REG_PMR2_SB_SLEEP_OFFSET));
+		regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2,
+				BIT(REG_PMR2_SB_SLEEP_OFFSET));
 		break;
 	case SND_SOC_BIAS_OFF:
-		regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
-				   BIT(REG_PMR2_SB_OFFSET),
-				   BIT(REG_PMR2_SB_OFFSET));
+		regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2,
+				BIT(REG_PMR2_SB_OFFSET));
 		break;
 	}
 
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index c9900d1cd5c2..5e58bfee2b49 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -219,12 +219,11 @@ static struct snd_soc_dai_driver jz4740_codec_dai = {
 
 static void jz4740_codec_wakeup(struct regmap *regmap)
 {
-	regmap_update_bits(regmap, JZ4740_REG_CODEC_1,
-		JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET);
+	regmap_set_bits(regmap, JZ4740_REG_CODEC_1, JZ4740_CODEC_1_RESET);
 	udelay(2);
 
-	regmap_update_bits(regmap, JZ4740_REG_CODEC_1,
-		JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0);
+	regmap_clear_bits(regmap, JZ4740_REG_CODEC_1,
+			  JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET);
 
 	regcache_sync(regmap);
 }
@@ -235,7 +234,6 @@ static int jz4740_codec_set_bias_level(struct snd_soc_component *component,
 	struct jz4740_codec *jz4740_codec = snd_soc_component_get_drvdata(component);
 	struct regmap *regmap = jz4740_codec->regmap;
 	unsigned int mask;
-	unsigned int value;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -244,9 +242,8 @@ static int jz4740_codec_set_bias_level(struct snd_soc_component *component,
 		mask = JZ4740_CODEC_1_VREF_DISABLE |
 				JZ4740_CODEC_1_VREF_AMP_DISABLE |
 				JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
-		value = 0;
 
-		regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
+		regmap_clear_bits(regmap, JZ4740_REG_CODEC_1, mask);
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* The only way to clear the suspend flag is to reset the codec */
@@ -256,17 +253,12 @@ static int jz4740_codec_set_bias_level(struct snd_soc_component *component,
 		mask = JZ4740_CODEC_1_VREF_DISABLE |
 			JZ4740_CODEC_1_VREF_AMP_DISABLE |
 			JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
-		value = JZ4740_CODEC_1_VREF_DISABLE |
-			JZ4740_CODEC_1_VREF_AMP_DISABLE |
-			JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
 
-		regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
+		regmap_set_bits(regmap, JZ4740_REG_CODEC_1, mask);
 		break;
 	case SND_SOC_BIAS_OFF:
 		mask = JZ4740_CODEC_1_SUSPEND;
-		value = JZ4740_CODEC_1_SUSPEND;
-
-		regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
+		regmap_set_bits(regmap, JZ4740_REG_CODEC_1, mask);
 		regcache_mark_dirty(regmap);
 		break;
 	default:
diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c
index 298689a07168..c9fe7f72bfcb 100644
--- a/sound/soc/codecs/jz4770.c
+++ b/sound/soc/codecs/jz4770.c
@@ -98,7 +98,7 @@ enum {
 #define REG_CR_HP_MUTE			BIT(7)
 #define REG_CR_HP_LOAD			BIT(6)
 #define REG_CR_HP_SB_OFFSET		4
-#define REG_CR_HP_SB_HPCM		BIT(3)
+#define REG_CR_HP_SB_HPCM_OFFSET	3
 #define REG_CR_HP_SEL_OFFSET		0
 #define REG_CR_HP_SEL_MASK		(0x3 << REG_CR_HP_SEL_OFFSET)
 
@@ -190,18 +190,21 @@ static int jz4770_codec_set_bias_level(struct snd_soc_component *codec,
 
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
-		regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
-				   REG_CR_VIC_SB, 0);
+		/* Reset all interrupt flags. */
+		regmap_write(regmap, JZ4770_CODEC_REG_IFR, REG_IFR_ALL_MASK);
+
+		regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
+				  REG_CR_VIC_SB);
 		msleep(250);
-		regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
-				   REG_CR_VIC_SB_SLEEP, 0);
+		regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
+				  REG_CR_VIC_SB_SLEEP);
 		msleep(400);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
-				   REG_CR_VIC_SB_SLEEP, REG_CR_VIC_SB_SLEEP);
-		regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
-				   REG_CR_VIC_SB, REG_CR_VIC_SB);
+		regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
+				REG_CR_VIC_SB_SLEEP);
+		regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
+				REG_CR_VIC_SB);
 		fallthrough;
 	default:
 		break;
@@ -284,7 +287,7 @@ static int jz4770_codec_mute_stream(struct snd_soc_dai *dai, int mute, int direc
 		err = regmap_read_poll_timeout(jz_codec->regmap,
 					       JZ4770_CODEC_REG_IFR,
 					       val, val & gain_bit,
-					       1000, 100 * USEC_PER_MSEC);
+					       1000, 1 * USEC_PER_SEC);
 		if (err) {
 			dev_err(jz_codec->dev,
 				"Timeout while setting digital mute: %d", err);
@@ -292,8 +295,8 @@ static int jz4770_codec_mute_stream(struct snd_soc_dai *dai, int mute, int direc
 		}
 
 		/* clear GUP/GDO flag */
-		regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
-				   gain_bit, gain_bit);
+		regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
+				gain_bit);
 	}
 
 	return 0;
@@ -368,9 +371,9 @@ static int hpout_event(struct snd_soc_dapm_widget *w,
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		/* set cap-less, unmute HP */
-		regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP,
-				   REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE, 0);
+		/* unmute HP */
+		regmap_clear_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP,
+				  REG_CR_HP_MUTE);
 		break;
 
 	case SND_SOC_DAPM_POST_PMU:
@@ -378,36 +381,35 @@ static int hpout_event(struct snd_soc_dapm_widget *w,
 		err = regmap_read_poll_timeout(jz_codec->regmap,
 					       JZ4770_CODEC_REG_IFR,
 					       val, val & REG_IFR_RUP,
-					       1000, 100 * USEC_PER_MSEC);
+					       1000, 1 * USEC_PER_SEC);
 		if (err) {
 			dev_err(jz_codec->dev, "RUP timeout: %d", err);
 			return err;
 		}
 
 		/* clear RUP flag */
-		regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
-				   REG_IFR_RUP, REG_IFR_RUP);
+		regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
+				REG_IFR_RUP);
 
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		/* set cap-couple, mute HP */
-		regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP,
-				   REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE,
-				   REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE);
+		/* mute HP */
+		regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP,
+				REG_CR_HP_MUTE);
 
 		err = regmap_read_poll_timeout(jz_codec->regmap,
 					       JZ4770_CODEC_REG_IFR,
 					       val, val & REG_IFR_RDO,
-					       1000, 100 * USEC_PER_MSEC);
+					       1000, 1 * USEC_PER_SEC);
 		if (err) {
 			dev_err(jz_codec->dev, "RDO timeout: %d", err);
 			return err;
 		}
 
 		/* clear RDO flag */
-		regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
-				   REG_IFR_RDO, REG_IFR_RDO);
+		regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
+				REG_IFR_RDO);
 
 		break;
 	}
@@ -517,6 +519,9 @@ static const struct snd_soc_dapm_widget jz4770_codec_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("MICBIAS", JZ4770_CODEC_REG_CR_MIC,
 			    REG_CR_MIC_BIAS_SB_OFFSET, 1, NULL, 0),
 
+	SND_SOC_DAPM_SUPPLY("Cap-less", JZ4770_CODEC_REG_CR_HP,
+			    REG_CR_HP_SB_HPCM_OFFSET, 1, NULL, 0),
+
 	SND_SOC_DAPM_INPUT("MIC1P"),
 	SND_SOC_DAPM_INPUT("MIC1N"),
 	SND_SOC_DAPM_INPUT("MIC2P"),
@@ -592,70 +597,58 @@ static void jz4770_codec_codec_init_regs(struct snd_soc_component *codec)
 	regcache_cache_only(regmap, true);
 
 	/* default HP output to PCM */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_HP,
-			   REG_CR_HP_SEL_MASK, REG_CR_HP_SEL_MASK);
+	regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_HP, REG_CR_HP_SEL_MASK);
 
 	/* default line output to PCM */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_LO,
-			   REG_CR_LO_SEL_MASK, REG_CR_LO_SEL_MASK);
+	regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_LO, REG_CR_LO_SEL_MASK);
 
 	/* Disable stereo mic */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_MIC,
-			   BIT(REG_CR_MIC_STEREO_OFFSET), 0);
+	regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_MIC,
+			  BIT(REG_CR_MIC_STEREO_OFFSET));
 
 	/* Set mic 1 as default source for ADC */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_ADC,
-			   REG_CR_ADC_IN_SEL_MASK, 0);
+	regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_ADC,
+			  REG_CR_ADC_IN_SEL_MASK);
 
 	/* ADC/DAC: serial + i2s */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_AICR_ADC,
-			   REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S,
-			   REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S);
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_AICR_DAC,
-			   REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S,
-			   REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S);
+	regmap_set_bits(regmap, JZ4770_CODEC_REG_AICR_ADC,
+			REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S);
+	regmap_set_bits(regmap, JZ4770_CODEC_REG_AICR_DAC,
+			REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S);
 
 	/* The generated IRQ is a high level */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_ICR,
-			   REG_ICR_INT_FORM_MASK, 0);
+	regmap_clear_bits(regmap, JZ4770_CODEC_REG_ICR, REG_ICR_INT_FORM_MASK);
 	regmap_update_bits(regmap, JZ4770_CODEC_REG_IMR, REG_IMR_ALL_MASK,
 			   REG_IMR_JACK_MASK | REG_IMR_RUP_MASK |
 			   REG_IMR_RDO_MASK | REG_IMR_GUP_MASK |
 			   REG_IMR_GDO_MASK);
 
 	/* 12M oscillator */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_CCR,
-			   REG_CCR_CRYSTAL_MASK, 0);
+	regmap_clear_bits(regmap, JZ4770_CODEC_REG_CCR, REG_CCR_CRYSTAL_MASK);
 
 	/* 0: 16ohm/220uF, 1: 10kohm/1uF */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_HP,
-			   REG_CR_HP_LOAD, 0);
+	regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_HP, REG_CR_HP_LOAD);
 
 	/* disable automatic gain */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_AGC1, REG_AGC1_EN, 0);
+	regmap_clear_bits(regmap, JZ4770_CODEC_REG_AGC1, REG_AGC1_EN);
 
 	/* Disable DAC lrswap */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_DAC,
-			   REG_CR_DAC_LRSWAP, REG_CR_DAC_LRSWAP);
+	regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_DAC, REG_CR_DAC_LRSWAP);
 
 	/* Independent L/R DAC gain control */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_GCR_DACL,
-			   REG_GCR_DACL_RLGOD, 0);
+	regmap_clear_bits(regmap, JZ4770_CODEC_REG_GCR_DACL,
+			  REG_GCR_DACL_RLGOD);
 
 	/* Disable ADC lrswap */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_ADC,
-			   REG_CR_ADC_LRSWAP, REG_CR_ADC_LRSWAP);
+	regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_ADC, REG_CR_ADC_LRSWAP);
 
 	/* default to cap-less mode(0) */
-	regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_HP,
-			   REG_CR_HP_SB_HPCM, 0);
+	regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_HP,
+			  BIT(REG_CR_HP_SB_HPCM_OFFSET));
 
 	/* Send collected updates. */
 	regcache_cache_only(regmap, false);
 	regcache_sync(regmap);
-
-	/* Reset all interrupt flags. */
-	regmap_write(regmap, JZ4770_CODEC_REG_IFR, REG_IFR_ALL_MASK);
 }
 
 static int jz4770_codec_codec_probe(struct snd_soc_component *codec)
@@ -814,7 +807,7 @@ static int jz4770_codec_io_wait(struct jz_codec *codec)
 
 	return readl_poll_timeout(codec->base + ICDC_RGADW_OFFSET, reg,
 				  !(reg & ICDC_RGADW_RGWR),
-				  1000, 10 * USEC_PER_MSEC);
+				  1000, 1 * USEC_PER_SEC);
 }
 
 static int jz4770_codec_reg_read(void *context, unsigned int reg,
diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c
new file mode 100644
index 000000000000..91e6890d6efc
--- /dev/null
+++ b/sound/soc/codecs/lpass-va-macro.c
@@ -0,0 +1,1497 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_clk.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+/* VA macro registers */
+#define CDC_VA_CLK_RST_CTRL_MCLK_CONTROL	(0x0000)
+#define CDC_VA_MCLK_CONTROL_EN			BIT(0)
+#define CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL	(0x0004)
+#define CDC_VA_FS_CONTROL_EN			BIT(0)
+#define CDC_VA_CLK_RST_CTRL_SWR_CONTROL		(0x0008)
+#define CDC_VA_TOP_CSR_TOP_CFG0			(0x0080)
+#define CDC_VA_FS_BROADCAST_EN			BIT(1)
+#define CDC_VA_TOP_CSR_DMIC0_CTL		(0x0084)
+#define CDC_VA_TOP_CSR_DMIC1_CTL		(0x0088)
+#define CDC_VA_TOP_CSR_DMIC2_CTL		(0x008C)
+#define CDC_VA_TOP_CSR_DMIC3_CTL		(0x0090)
+#define CDC_VA_DMIC_EN_MASK			BIT(0)
+#define CDC_VA_DMIC_ENABLE			BIT(0)
+#define CDC_VA_DMIC_CLK_SEL_MASK		GENMASK(3, 1)
+#define CDC_VA_DMIC_CLK_SEL_SHFT		1
+#define CDC_VA_DMIC_CLK_SEL_DIV0		0x0
+#define CDC_VA_DMIC_CLK_SEL_DIV1		0x2
+#define CDC_VA_DMIC_CLK_SEL_DIV2		0x4
+#define CDC_VA_DMIC_CLK_SEL_DIV3		0x6
+#define CDC_VA_DMIC_CLK_SEL_DIV4		0x8
+#define CDC_VA_DMIC_CLK_SEL_DIV5		0xa
+#define CDC_VA_TOP_CSR_DMIC_CFG			(0x0094)
+#define CDC_VA_RESET_ALL_DMICS_MASK		BIT(7)
+#define CDC_VA_RESET_ALL_DMICS_RESET		BIT(7)
+#define CDC_VA_RESET_ALL_DMICS_DISABLE		0
+#define CDC_VA_DMIC3_FREQ_CHANGE_MASK		BIT(3)
+#define CDC_VA_DMIC3_FREQ_CHANGE_EN		BIT(3)
+#define CDC_VA_DMIC2_FREQ_CHANGE_MASK		BIT(2)
+#define CDC_VA_DMIC2_FREQ_CHANGE_EN		BIT(2)
+#define CDC_VA_DMIC1_FREQ_CHANGE_MASK		BIT(1)
+#define CDC_VA_DMIC1_FREQ_CHANGE_EN		BIT(1)
+#define CDC_VA_DMIC0_FREQ_CHANGE_MASK		BIT(0)
+#define CDC_VA_DMIC0_FREQ_CHANGE_EN		BIT(0)
+#define CDC_VA_DMIC_FREQ_CHANGE_DISABLE		0
+#define CDC_VA_TOP_CSR_DEBUG_BUS		(0x009C)
+#define CDC_VA_TOP_CSR_DEBUG_EN			(0x00A0)
+#define CDC_VA_TOP_CSR_TX_I2S_CTL		(0x00A4)
+#define CDC_VA_TOP_CSR_I2S_CLK			(0x00A8)
+#define CDC_VA_TOP_CSR_I2S_RESET		(0x00AC)
+#define CDC_VA_TOP_CSR_CORE_ID_0		(0x00C0)
+#define CDC_VA_TOP_CSR_CORE_ID_1		(0x00C4)
+#define CDC_VA_TOP_CSR_CORE_ID_2		(0x00C8)
+#define CDC_VA_TOP_CSR_CORE_ID_3		(0x00CC)
+#define CDC_VA_TOP_CSR_SWR_MIC_CTL0		(0x00D0)
+#define CDC_VA_TOP_CSR_SWR_MIC_CTL1		(0x00D4)
+#define CDC_VA_TOP_CSR_SWR_MIC_CTL2		(0x00D8)
+#define CDC_VA_TOP_CSR_SWR_CTRL			(0x00DC)
+#define CDC_VA_INP_MUX_ADC_MUX0_CFG0		(0x0100)
+#define CDC_VA_INP_MUX_ADC_MUX0_CFG1		(0x0104)
+#define CDC_VA_INP_MUX_ADC_MUX1_CFG0		(0x0108)
+#define CDC_VA_INP_MUX_ADC_MUX1_CFG1		(0x010C)
+#define CDC_VA_INP_MUX_ADC_MUX2_CFG0		(0x0110)
+#define CDC_VA_INP_MUX_ADC_MUX2_CFG1		(0x0114)
+#define CDC_VA_INP_MUX_ADC_MUX3_CFG0		(0x0118)
+#define CDC_VA_INP_MUX_ADC_MUX3_CFG1		(0x011C)
+#define CDC_VA_TX0_TX_PATH_CTL			(0x0400)
+#define CDC_VA_TX_PATH_CLK_EN_MASK		BIT(5)
+#define CDC_VA_TX_PATH_CLK_EN			BIT(5)
+#define CDC_VA_TX_PATH_CLK_DISABLE		0
+#define CDC_VA_TX_PATH_PGA_MUTE_EN_MASK		BIT(4)
+#define CDC_VA_TX_PATH_PGA_MUTE_EN		BIT(4)
+#define CDC_VA_TX_PATH_PGA_MUTE_DISABLE		0
+#define CDC_VA_TX0_TX_PATH_CFG0			(0x0404)
+#define CDC_VA_ADC_MODE_MASK			GENMASK(2, 1)
+#define CDC_VA_ADC_MODE_SHIFT			1
+#define  TX_HPF_CUT_OFF_FREQ_MASK		GENMASK(6, 5)
+#define  CF_MIN_3DB_4HZ			0x0
+#define  CF_MIN_3DB_75HZ		0x1
+#define  CF_MIN_3DB_150HZ		0x2
+#define CDC_VA_TX0_TX_PATH_CFG1			(0x0408)
+#define CDC_VA_TX0_TX_VOL_CTL			(0x040C)
+#define CDC_VA_TX0_TX_PATH_SEC0			(0x0410)
+#define CDC_VA_TX0_TX_PATH_SEC1			(0x0414)
+#define CDC_VA_TX0_TX_PATH_SEC2			(0x0418)
+#define CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK	BIT(1)
+#define CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_REQ	BIT(1)
+#define CDC_VA_TX_HPF_ZERO_GATE_MASK		BIT(0)
+#define CDC_VA_TX_HPF_ZERO_NO_GATE		BIT(0)
+#define CDC_VA_TX_HPF_ZERO_GATE			0
+#define CDC_VA_TX0_TX_PATH_SEC3			(0x041C)
+#define CDC_VA_TX0_TX_PATH_SEC4			(0x0420)
+#define CDC_VA_TX0_TX_PATH_SEC5			(0x0424)
+#define CDC_VA_TX0_TX_PATH_SEC6			(0x0428)
+#define CDC_VA_TX0_TX_PATH_SEC7			(0x042C)
+#define CDC_VA_TX1_TX_PATH_CTL			(0x0480)
+#define CDC_VA_TX1_TX_PATH_CFG0			(0x0484)
+#define CDC_VA_TX1_TX_PATH_CFG1			(0x0488)
+#define CDC_VA_TX1_TX_VOL_CTL			(0x048C)
+#define CDC_VA_TX1_TX_PATH_SEC0			(0x0490)
+#define CDC_VA_TX1_TX_PATH_SEC1			(0x0494)
+#define CDC_VA_TX1_TX_PATH_SEC2			(0x0498)
+#define CDC_VA_TX1_TX_PATH_SEC3			(0x049C)
+#define CDC_VA_TX1_TX_PATH_SEC4			(0x04A0)
+#define CDC_VA_TX1_TX_PATH_SEC5			(0x04A4)
+#define CDC_VA_TX1_TX_PATH_SEC6			(0x04A8)
+#define CDC_VA_TX2_TX_PATH_CTL			(0x0500)
+#define CDC_VA_TX2_TX_PATH_CFG0			(0x0504)
+#define CDC_VA_TX2_TX_PATH_CFG1			(0x0508)
+#define CDC_VA_TX2_TX_VOL_CTL			(0x050C)
+#define CDC_VA_TX2_TX_PATH_SEC0			(0x0510)
+#define CDC_VA_TX2_TX_PATH_SEC1			(0x0514)
+#define CDC_VA_TX2_TX_PATH_SEC2			(0x0518)
+#define CDC_VA_TX2_TX_PATH_SEC3			(0x051C)
+#define CDC_VA_TX2_TX_PATH_SEC4			(0x0520)
+#define CDC_VA_TX2_TX_PATH_SEC5			(0x0524)
+#define CDC_VA_TX2_TX_PATH_SEC6			(0x0528)
+#define CDC_VA_TX3_TX_PATH_CTL			(0x0580)
+#define CDC_VA_TX3_TX_PATH_CFG0			(0x0584)
+#define CDC_VA_TX_PATH_ADC_DMIC_SEL_MASK	BIT(7)
+#define CDC_VA_TX_PATH_ADC_DMIC_SEL_DMIC	BIT(7)
+#define CDC_VA_TX_PATH_ADC_DMIC_SEL_ADC		0
+#define CDC_VA_TX3_TX_PATH_CFG1			(0x0588)
+#define CDC_VA_TX3_TX_VOL_CTL			(0x058C)
+#define CDC_VA_TX3_TX_PATH_SEC0			(0x0590)
+#define CDC_VA_TX3_TX_PATH_SEC1			(0x0594)
+#define CDC_VA_TX3_TX_PATH_SEC2			(0x0598)
+#define CDC_VA_TX3_TX_PATH_SEC3			(0x059C)
+#define CDC_VA_TX3_TX_PATH_SEC4			(0x05A0)
+#define CDC_VA_TX3_TX_PATH_SEC5			(0x05A4)
+#define CDC_VA_TX3_TX_PATH_SEC6			(0x05A8)
+
+#define VA_MAX_OFFSET				(0x07A8)
+
+#define VA_MACRO_NUM_DECIMATORS 4
+#define VA_MACRO_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 VA_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+		SNDRV_PCM_FMTBIT_S24_LE |\
+		SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define VA_MACRO_MCLK_FREQ 9600000
+#define VA_MACRO_TX_PATH_OFFSET 0x80
+#define VA_MACRO_SWR_MIC_MUX_SEL_MASK 0xF
+#define VA_MACRO_ADC_MUX_CFG_OFFSET 0x8
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
+
+enum {
+	VA_MACRO_AIF_INVALID = 0,
+	VA_MACRO_AIF1_CAP,
+	VA_MACRO_AIF2_CAP,
+	VA_MACRO_AIF3_CAP,
+	VA_MACRO_MAX_DAIS,
+};
+
+enum {
+	VA_MACRO_DEC0,
+	VA_MACRO_DEC1,
+	VA_MACRO_DEC2,
+	VA_MACRO_DEC3,
+	VA_MACRO_DEC4,
+	VA_MACRO_DEC5,
+	VA_MACRO_DEC6,
+	VA_MACRO_DEC7,
+	VA_MACRO_DEC_MAX,
+};
+
+enum {
+	VA_MACRO_CLK_DIV_2,
+	VA_MACRO_CLK_DIV_3,
+	VA_MACRO_CLK_DIV_4,
+	VA_MACRO_CLK_DIV_6,
+	VA_MACRO_CLK_DIV_8,
+	VA_MACRO_CLK_DIV_16,
+};
+
+#define VA_NUM_CLKS_MAX		3
+
+struct va_macro {
+	struct device *dev;
+	unsigned long active_ch_mask[VA_MACRO_MAX_DAIS];
+	unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS];
+	unsigned long active_decimator[VA_MACRO_MAX_DAIS];
+	u16 dmic_clk_div;
+
+	int dec_mode[VA_MACRO_NUM_DECIMATORS];
+	struct regmap *regmap;
+	struct clk_bulk_data clks[VA_NUM_CLKS_MAX];
+	struct clk_hw hw;
+
+	s32 dmic_0_1_clk_cnt;
+	s32 dmic_2_3_clk_cnt;
+	s32 dmic_4_5_clk_cnt;
+	s32 dmic_6_7_clk_cnt;
+	u8 dmic_0_1_clk_div;
+	u8 dmic_2_3_clk_div;
+	u8 dmic_4_5_clk_div;
+	u8 dmic_6_7_clk_div;
+};
+
+#define to_va_macro(_hw) container_of(_hw, struct va_macro, hw)
+
+static bool va_is_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_VA_TOP_CSR_CORE_ID_0:
+	case CDC_VA_TOP_CSR_CORE_ID_1:
+	case CDC_VA_TOP_CSR_CORE_ID_2:
+	case CDC_VA_TOP_CSR_CORE_ID_3:
+	case CDC_VA_TOP_CSR_DMIC0_CTL:
+	case CDC_VA_TOP_CSR_DMIC1_CTL:
+	case CDC_VA_TOP_CSR_DMIC2_CTL:
+	case CDC_VA_TOP_CSR_DMIC3_CTL:
+		return true;
+	}
+	return false;
+}
+
+static const struct reg_default va_defaults[] = {
+	/* VA macro */
+	{ CDC_VA_CLK_RST_CTRL_MCLK_CONTROL, 0x00},
+	{ CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00},
+	{ CDC_VA_CLK_RST_CTRL_SWR_CONTROL, 0x00},
+	{ CDC_VA_TOP_CSR_TOP_CFG0, 0x00},
+	{ CDC_VA_TOP_CSR_DMIC0_CTL, 0x00},
+	{ CDC_VA_TOP_CSR_DMIC1_CTL, 0x00},
+	{ CDC_VA_TOP_CSR_DMIC2_CTL, 0x00},
+	{ CDC_VA_TOP_CSR_DMIC3_CTL, 0x00},
+	{ CDC_VA_TOP_CSR_DMIC_CFG, 0x80},
+	{ CDC_VA_TOP_CSR_DEBUG_BUS, 0x00},
+	{ CDC_VA_TOP_CSR_DEBUG_EN, 0x00},
+	{ CDC_VA_TOP_CSR_TX_I2S_CTL, 0x0C},
+	{ CDC_VA_TOP_CSR_I2S_CLK, 0x00},
+	{ CDC_VA_TOP_CSR_I2S_RESET, 0x00},
+	{ CDC_VA_TOP_CSR_CORE_ID_0, 0x00},
+	{ CDC_VA_TOP_CSR_CORE_ID_1, 0x00},
+	{ CDC_VA_TOP_CSR_CORE_ID_2, 0x00},
+	{ CDC_VA_TOP_CSR_CORE_ID_3, 0x00},
+	{ CDC_VA_TOP_CSR_SWR_MIC_CTL0, 0xEE},
+	{ CDC_VA_TOP_CSR_SWR_MIC_CTL1, 0xEE},
+	{ CDC_VA_TOP_CSR_SWR_MIC_CTL2, 0xEE},
+	{ CDC_VA_TOP_CSR_SWR_CTRL, 0x06},
+
+	/* VA core */
+	{ CDC_VA_INP_MUX_ADC_MUX0_CFG0, 0x00},
+	{ CDC_VA_INP_MUX_ADC_MUX0_CFG1, 0x00},
+	{ CDC_VA_INP_MUX_ADC_MUX1_CFG0, 0x00},
+	{ CDC_VA_INP_MUX_ADC_MUX1_CFG1, 0x00},
+	{ CDC_VA_INP_MUX_ADC_MUX2_CFG0, 0x00},
+	{ CDC_VA_INP_MUX_ADC_MUX2_CFG1, 0x00},
+	{ CDC_VA_INP_MUX_ADC_MUX3_CFG0, 0x00},
+	{ CDC_VA_INP_MUX_ADC_MUX3_CFG1, 0x00},
+	{ CDC_VA_TX0_TX_PATH_CTL, 0x04},
+	{ CDC_VA_TX0_TX_PATH_CFG0, 0x10},
+	{ CDC_VA_TX0_TX_PATH_CFG1, 0x0B},
+	{ CDC_VA_TX0_TX_VOL_CTL, 0x00},
+	{ CDC_VA_TX0_TX_PATH_SEC0, 0x00},
+	{ CDC_VA_TX0_TX_PATH_SEC1, 0x00},
+	{ CDC_VA_TX0_TX_PATH_SEC2, 0x01},
+	{ CDC_VA_TX0_TX_PATH_SEC3, 0x3C},
+	{ CDC_VA_TX0_TX_PATH_SEC4, 0x20},
+	{ CDC_VA_TX0_TX_PATH_SEC5, 0x00},
+	{ CDC_VA_TX0_TX_PATH_SEC6, 0x00},
+	{ CDC_VA_TX0_TX_PATH_SEC7, 0x25},
+	{ CDC_VA_TX1_TX_PATH_CTL, 0x04},
+	{ CDC_VA_TX1_TX_PATH_CFG0, 0x10},
+	{ CDC_VA_TX1_TX_PATH_CFG1, 0x0B},
+	{ CDC_VA_TX1_TX_VOL_CTL, 0x00},
+	{ CDC_VA_TX1_TX_PATH_SEC0, 0x00},
+	{ CDC_VA_TX1_TX_PATH_SEC1, 0x00},
+	{ CDC_VA_TX1_TX_PATH_SEC2, 0x01},
+	{ CDC_VA_TX1_TX_PATH_SEC3, 0x3C},
+	{ CDC_VA_TX1_TX_PATH_SEC4, 0x20},
+	{ CDC_VA_TX1_TX_PATH_SEC5, 0x00},
+	{ CDC_VA_TX1_TX_PATH_SEC6, 0x00},
+	{ CDC_VA_TX2_TX_PATH_CTL, 0x04},
+	{ CDC_VA_TX2_TX_PATH_CFG0, 0x10},
+	{ CDC_VA_TX2_TX_PATH_CFG1, 0x0B},
+	{ CDC_VA_TX2_TX_VOL_CTL, 0x00},
+	{ CDC_VA_TX2_TX_PATH_SEC0, 0x00},
+	{ CDC_VA_TX2_TX_PATH_SEC1, 0x00},
+	{ CDC_VA_TX2_TX_PATH_SEC2, 0x01},
+	{ CDC_VA_TX2_TX_PATH_SEC3, 0x3C},
+	{ CDC_VA_TX2_TX_PATH_SEC4, 0x20},
+	{ CDC_VA_TX2_TX_PATH_SEC5, 0x00},
+	{ CDC_VA_TX2_TX_PATH_SEC6, 0x00},
+	{ CDC_VA_TX3_TX_PATH_CTL, 0x04},
+	{ CDC_VA_TX3_TX_PATH_CFG0, 0x10},
+	{ CDC_VA_TX3_TX_PATH_CFG1, 0x0B},
+	{ CDC_VA_TX3_TX_VOL_CTL, 0x00},
+	{ CDC_VA_TX3_TX_PATH_SEC0, 0x00},
+	{ CDC_VA_TX3_TX_PATH_SEC1, 0x00},
+	{ CDC_VA_TX3_TX_PATH_SEC2, 0x01},
+	{ CDC_VA_TX3_TX_PATH_SEC3, 0x3C},
+	{ CDC_VA_TX3_TX_PATH_SEC4, 0x20},
+	{ CDC_VA_TX3_TX_PATH_SEC5, 0x00},
+	{ CDC_VA_TX3_TX_PATH_SEC6, 0x00},
+};
+
+static bool va_is_rw_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_VA_CLK_RST_CTRL_MCLK_CONTROL:
+	case CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL:
+	case CDC_VA_CLK_RST_CTRL_SWR_CONTROL:
+	case CDC_VA_TOP_CSR_TOP_CFG0:
+	case CDC_VA_TOP_CSR_DMIC0_CTL:
+	case CDC_VA_TOP_CSR_DMIC1_CTL:
+	case CDC_VA_TOP_CSR_DMIC2_CTL:
+	case CDC_VA_TOP_CSR_DMIC3_CTL:
+	case CDC_VA_TOP_CSR_DMIC_CFG:
+	case CDC_VA_TOP_CSR_DEBUG_BUS:
+	case CDC_VA_TOP_CSR_DEBUG_EN:
+	case CDC_VA_TOP_CSR_TX_I2S_CTL:
+	case CDC_VA_TOP_CSR_I2S_CLK:
+	case CDC_VA_TOP_CSR_I2S_RESET:
+	case CDC_VA_INP_MUX_ADC_MUX0_CFG0:
+	case CDC_VA_INP_MUX_ADC_MUX0_CFG1:
+	case CDC_VA_INP_MUX_ADC_MUX1_CFG0:
+	case CDC_VA_INP_MUX_ADC_MUX1_CFG1:
+	case CDC_VA_INP_MUX_ADC_MUX2_CFG0:
+	case CDC_VA_INP_MUX_ADC_MUX2_CFG1:
+	case CDC_VA_INP_MUX_ADC_MUX3_CFG0:
+	case CDC_VA_INP_MUX_ADC_MUX3_CFG1:
+	case CDC_VA_TX0_TX_PATH_CTL:
+	case CDC_VA_TX0_TX_PATH_CFG0:
+	case CDC_VA_TX0_TX_PATH_CFG1:
+	case CDC_VA_TX0_TX_VOL_CTL:
+	case CDC_VA_TX0_TX_PATH_SEC0:
+	case CDC_VA_TX0_TX_PATH_SEC1:
+	case CDC_VA_TX0_TX_PATH_SEC2:
+	case CDC_VA_TX0_TX_PATH_SEC3:
+	case CDC_VA_TX0_TX_PATH_SEC4:
+	case CDC_VA_TX0_TX_PATH_SEC5:
+	case CDC_VA_TX0_TX_PATH_SEC6:
+	case CDC_VA_TX0_TX_PATH_SEC7:
+	case CDC_VA_TX1_TX_PATH_CTL:
+	case CDC_VA_TX1_TX_PATH_CFG0:
+	case CDC_VA_TX1_TX_PATH_CFG1:
+	case CDC_VA_TX1_TX_VOL_CTL:
+	case CDC_VA_TX1_TX_PATH_SEC0:
+	case CDC_VA_TX1_TX_PATH_SEC1:
+	case CDC_VA_TX1_TX_PATH_SEC2:
+	case CDC_VA_TX1_TX_PATH_SEC3:
+	case CDC_VA_TX1_TX_PATH_SEC4:
+	case CDC_VA_TX1_TX_PATH_SEC5:
+	case CDC_VA_TX1_TX_PATH_SEC6:
+	case CDC_VA_TX2_TX_PATH_CTL:
+	case CDC_VA_TX2_TX_PATH_CFG0:
+	case CDC_VA_TX2_TX_PATH_CFG1:
+	case CDC_VA_TX2_TX_VOL_CTL:
+	case CDC_VA_TX2_TX_PATH_SEC0:
+	case CDC_VA_TX2_TX_PATH_SEC1:
+	case CDC_VA_TX2_TX_PATH_SEC2:
+	case CDC_VA_TX2_TX_PATH_SEC3:
+	case CDC_VA_TX2_TX_PATH_SEC4:
+	case CDC_VA_TX2_TX_PATH_SEC5:
+	case CDC_VA_TX2_TX_PATH_SEC6:
+	case CDC_VA_TX3_TX_PATH_CTL:
+	case CDC_VA_TX3_TX_PATH_CFG0:
+	case CDC_VA_TX3_TX_PATH_CFG1:
+	case CDC_VA_TX3_TX_VOL_CTL:
+	case CDC_VA_TX3_TX_PATH_SEC0:
+	case CDC_VA_TX3_TX_PATH_SEC1:
+	case CDC_VA_TX3_TX_PATH_SEC2:
+	case CDC_VA_TX3_TX_PATH_SEC3:
+	case CDC_VA_TX3_TX_PATH_SEC4:
+	case CDC_VA_TX3_TX_PATH_SEC5:
+	case CDC_VA_TX3_TX_PATH_SEC6:
+		return true;
+	}
+
+	return false;
+}
+
+static bool va_is_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_VA_TOP_CSR_CORE_ID_0:
+	case CDC_VA_TOP_CSR_CORE_ID_1:
+	case CDC_VA_TOP_CSR_CORE_ID_2:
+	case CDC_VA_TOP_CSR_CORE_ID_3:
+		return true;
+	}
+
+	return va_is_rw_register(dev, reg);
+}
+
+static const struct regmap_config va_regmap_config = {
+	.name = "va_macro",
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.cache_type = REGCACHE_FLAT,
+	.reg_defaults = va_defaults,
+	.num_reg_defaults = ARRAY_SIZE(va_defaults),
+	.max_register = VA_MAX_OFFSET,
+	.volatile_reg = va_is_volatile_register,
+	.readable_reg = va_is_readable_register,
+	.writeable_reg = va_is_rw_register,
+};
+
+static int va_clk_rsc_fs_gen_request(struct va_macro *va, bool enable)
+{
+	struct regmap *regmap = va->regmap;
+
+	if (enable) {
+		regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_MCLK_CONTROL,
+				   CDC_VA_MCLK_CONTROL_EN,
+				   CDC_VA_MCLK_CONTROL_EN);
+
+		regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL,
+				   CDC_VA_FS_CONTROL_EN,
+				   CDC_VA_FS_CONTROL_EN);
+
+		regmap_update_bits(regmap, CDC_VA_TOP_CSR_TOP_CFG0,
+				   CDC_VA_FS_BROADCAST_EN,
+				   CDC_VA_FS_BROADCAST_EN);
+	} else {
+		regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_MCLK_CONTROL,
+				   CDC_VA_MCLK_CONTROL_EN, 0x0);
+
+		regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL,
+				   CDC_VA_FS_CONTROL_EN, 0x0);
+
+		regmap_update_bits(regmap, CDC_VA_TOP_CSR_TOP_CFG0,
+				   CDC_VA_FS_BROADCAST_EN, 0x0);
+	}
+
+	return 0;
+}
+
+static int va_macro_mclk_enable(struct va_macro *va, bool mclk_enable)
+{
+	struct regmap *regmap = va->regmap;
+
+	if (mclk_enable) {
+		va_clk_rsc_fs_gen_request(va, true);
+		regcache_mark_dirty(regmap);
+		regcache_sync_region(regmap, 0x0, VA_MAX_OFFSET);
+	} else {
+		va_clk_rsc_fs_gen_request(va, false);
+	}
+
+	return 0;
+}
+
+static int va_macro_mclk_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	struct va_macro *va = snd_soc_component_get_drvdata(comp);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		return va_macro_mclk_enable(va, true);
+	case SND_SOC_DAPM_POST_PMD:
+		return va_macro_mclk_enable(va, false);
+	}
+
+	return 0;
+}
+
+static int va_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget =
+		snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(widget->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val;
+	u16 mic_sel_reg;
+
+	val = ucontrol->value.enumerated.item[0];
+
+	switch (e->reg) {
+	case CDC_VA_INP_MUX_ADC_MUX0_CFG0:
+		mic_sel_reg = CDC_VA_TX0_TX_PATH_CFG0;
+		break;
+	case CDC_VA_INP_MUX_ADC_MUX1_CFG0:
+		mic_sel_reg = CDC_VA_TX1_TX_PATH_CFG0;
+		break;
+	case CDC_VA_INP_MUX_ADC_MUX2_CFG0:
+		mic_sel_reg = CDC_VA_TX2_TX_PATH_CFG0;
+		break;
+	case CDC_VA_INP_MUX_ADC_MUX3_CFG0:
+		mic_sel_reg = CDC_VA_TX3_TX_PATH_CFG0;
+		break;
+	default:
+		dev_err(component->dev, "%s: e->reg: 0x%x not expected\n",
+			__func__, e->reg);
+		return -EINVAL;
+	}
+
+	if (val != 0)
+		snd_soc_component_update_bits(component, mic_sel_reg,
+					      CDC_VA_TX_PATH_ADC_DMIC_SEL_MASK,
+					      CDC_VA_TX_PATH_ADC_DMIC_SEL_DMIC);
+
+	return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static int va_macro_tx_mixer_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget =
+		snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component =
+				snd_soc_dapm_to_component(widget->dapm);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	u32 dai_id = widget->shift;
+	u32 dec_id = mc->shift;
+	struct va_macro *va = snd_soc_component_get_drvdata(component);
+
+	if (test_bit(dec_id, &va->active_ch_mask[dai_id]))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	return 0;
+}
+
+static int va_macro_tx_mixer_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget =
+					snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component =
+				snd_soc_dapm_to_component(widget->dapm);
+	struct snd_soc_dapm_update *update = NULL;
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	u32 dai_id = widget->shift;
+	u32 dec_id = mc->shift;
+	u32 enable = ucontrol->value.integer.value[0];
+	struct va_macro *va = snd_soc_component_get_drvdata(component);
+
+	if (enable) {
+		set_bit(dec_id, &va->active_ch_mask[dai_id]);
+		va->active_ch_cnt[dai_id]++;
+		va->active_decimator[dai_id] = dec_id;
+	} else {
+		clear_bit(dec_id, &va->active_ch_mask[dai_id]);
+		va->active_ch_cnt[dai_id]--;
+		va->active_decimator[dai_id] = -1;
+	}
+
+	snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update);
+
+	return 0;
+}
+
+static int va_dmic_clk_enable(struct snd_soc_component *component,
+			      u32 dmic, bool enable)
+{
+	struct va_macro *va = snd_soc_component_get_drvdata(component);
+	u16 dmic_clk_reg;
+	s32 *dmic_clk_cnt;
+	u8 *dmic_clk_div;
+	u8 freq_change_mask;
+	u8 clk_div;
+
+	switch (dmic) {
+	case 0:
+	case 1:
+		dmic_clk_cnt = &(va->dmic_0_1_clk_cnt);
+		dmic_clk_div = &(va->dmic_0_1_clk_div);
+		dmic_clk_reg = CDC_VA_TOP_CSR_DMIC0_CTL;
+		freq_change_mask = CDC_VA_DMIC0_FREQ_CHANGE_MASK;
+		break;
+	case 2:
+	case 3:
+		dmic_clk_cnt = &(va->dmic_2_3_clk_cnt);
+		dmic_clk_div = &(va->dmic_2_3_clk_div);
+		dmic_clk_reg = CDC_VA_TOP_CSR_DMIC1_CTL;
+		freq_change_mask = CDC_VA_DMIC1_FREQ_CHANGE_MASK;
+		break;
+	case 4:
+	case 5:
+		dmic_clk_cnt = &(va->dmic_4_5_clk_cnt);
+		dmic_clk_div = &(va->dmic_4_5_clk_div);
+		dmic_clk_reg = CDC_VA_TOP_CSR_DMIC2_CTL;
+		freq_change_mask = CDC_VA_DMIC2_FREQ_CHANGE_MASK;
+		break;
+	case 6:
+	case 7:
+		dmic_clk_cnt = &(va->dmic_6_7_clk_cnt);
+		dmic_clk_div = &(va->dmic_6_7_clk_div);
+		dmic_clk_reg = CDC_VA_TOP_CSR_DMIC3_CTL;
+		freq_change_mask = CDC_VA_DMIC3_FREQ_CHANGE_MASK;
+		break;
+	default:
+		dev_err(component->dev, "%s: Invalid DMIC Selection\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (enable) {
+		clk_div = va->dmic_clk_div;
+		(*dmic_clk_cnt)++;
+		if (*dmic_clk_cnt == 1) {
+			snd_soc_component_update_bits(component,
+					      CDC_VA_TOP_CSR_DMIC_CFG,
+					      CDC_VA_RESET_ALL_DMICS_MASK,
+					      CDC_VA_RESET_ALL_DMICS_DISABLE);
+			snd_soc_component_update_bits(component, dmic_clk_reg,
+					CDC_VA_DMIC_CLK_SEL_MASK,
+					clk_div << CDC_VA_DMIC_CLK_SEL_SHFT);
+			snd_soc_component_update_bits(component, dmic_clk_reg,
+						      CDC_VA_DMIC_EN_MASK,
+						      CDC_VA_DMIC_ENABLE);
+		} else {
+			if (*dmic_clk_div > clk_div) {
+				snd_soc_component_update_bits(component,
+						CDC_VA_TOP_CSR_DMIC_CFG,
+						freq_change_mask,
+						freq_change_mask);
+				snd_soc_component_update_bits(component, dmic_clk_reg,
+						CDC_VA_DMIC_CLK_SEL_MASK,
+						clk_div << CDC_VA_DMIC_CLK_SEL_SHFT);
+				snd_soc_component_update_bits(component,
+					      CDC_VA_TOP_CSR_DMIC_CFG,
+					      freq_change_mask,
+					      CDC_VA_DMIC_FREQ_CHANGE_DISABLE);
+			} else {
+				clk_div = *dmic_clk_div;
+			}
+		}
+		*dmic_clk_div = clk_div;
+	} else {
+		(*dmic_clk_cnt)--;
+		if (*dmic_clk_cnt  == 0) {
+			snd_soc_component_update_bits(component, dmic_clk_reg,
+						      CDC_VA_DMIC_EN_MASK, 0);
+			clk_div = 0;
+			snd_soc_component_update_bits(component, dmic_clk_reg,
+						CDC_VA_DMIC_CLK_SEL_MASK,
+						clk_div << CDC_VA_DMIC_CLK_SEL_SHFT);
+		} else {
+			clk_div = va->dmic_clk_div;
+			if (*dmic_clk_div > clk_div) {
+				clk_div = va->dmic_clk_div;
+				snd_soc_component_update_bits(component,
+							CDC_VA_TOP_CSR_DMIC_CFG,
+							freq_change_mask,
+							freq_change_mask);
+				snd_soc_component_update_bits(component, dmic_clk_reg,
+						CDC_VA_DMIC_CLK_SEL_MASK,
+						clk_div << CDC_VA_DMIC_CLK_SEL_SHFT);
+				snd_soc_component_update_bits(component,
+						      CDC_VA_TOP_CSR_DMIC_CFG,
+						      freq_change_mask,
+						      CDC_VA_DMIC_FREQ_CHANGE_DISABLE);
+			} else {
+				clk_div = *dmic_clk_div;
+			}
+		}
+		*dmic_clk_div = clk_div;
+	}
+
+	return 0;
+}
+
+static int va_macro_enable_dmic(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	unsigned int dmic = w->shift;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		va_dmic_clk_enable(comp, dmic, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		va_dmic_clk_enable(comp, dmic, false);
+		break;
+	}
+
+	return 0;
+}
+
+static int va_macro_enable_dec(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	unsigned int decimator;
+	u16 tx_vol_ctl_reg, dec_cfg_reg, hpf_gate_reg;
+	u16 tx_gain_ctl_reg;
+	u8 hpf_cut_off_freq;
+
+	struct va_macro *va = snd_soc_component_get_drvdata(comp);
+
+	decimator = w->shift;
+
+	tx_vol_ctl_reg = CDC_VA_TX0_TX_PATH_CTL +
+				VA_MACRO_TX_PATH_OFFSET * decimator;
+	hpf_gate_reg = CDC_VA_TX0_TX_PATH_SEC2 +
+				VA_MACRO_TX_PATH_OFFSET * decimator;
+	dec_cfg_reg = CDC_VA_TX0_TX_PATH_CFG0 +
+				VA_MACRO_TX_PATH_OFFSET * decimator;
+	tx_gain_ctl_reg = CDC_VA_TX0_TX_VOL_CTL +
+				VA_MACRO_TX_PATH_OFFSET * decimator;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(comp,
+			dec_cfg_reg, CDC_VA_ADC_MODE_MASK,
+			va->dec_mode[decimator] << CDC_VA_ADC_MODE_SHIFT);
+		/* Enable TX PGA Mute */
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* Enable TX CLK */
+		snd_soc_component_update_bits(comp, tx_vol_ctl_reg,
+					      CDC_VA_TX_PATH_CLK_EN_MASK,
+					      CDC_VA_TX_PATH_CLK_EN);
+		snd_soc_component_update_bits(comp, hpf_gate_reg,
+					      CDC_VA_TX_HPF_ZERO_GATE_MASK,
+					      CDC_VA_TX_HPF_ZERO_GATE);
+
+		usleep_range(1000, 1010);
+		hpf_cut_off_freq = (snd_soc_component_read(comp, dec_cfg_reg) &
+				    TX_HPF_CUT_OFF_FREQ_MASK) >> 5;
+
+		if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) {
+			snd_soc_component_update_bits(comp, dec_cfg_reg,
+						      TX_HPF_CUT_OFF_FREQ_MASK,
+						      CF_MIN_3DB_150HZ << 5);
+
+			snd_soc_component_update_bits(comp, hpf_gate_reg,
+				      CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK,
+				      CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_REQ);
+
+			/*
+			 * Minimum 1 clk cycle delay is required as per HW spec
+			 */
+			usleep_range(1000, 1010);
+
+			snd_soc_component_update_bits(comp,
+				hpf_gate_reg,
+				CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK,
+				0x0);
+		}
+
+
+		usleep_range(1000, 1010);
+		snd_soc_component_update_bits(comp, hpf_gate_reg,
+					      CDC_VA_TX_HPF_ZERO_GATE_MASK,
+					      CDC_VA_TX_HPF_ZERO_NO_GATE);
+		/*
+		 * 6ms delay is required as per HW spec
+		 */
+		usleep_range(6000, 6010);
+		/* apply gain after decimator is enabled */
+		snd_soc_component_write(comp, tx_gain_ctl_reg,
+			snd_soc_component_read(comp, tx_gain_ctl_reg));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Disable TX CLK */
+		snd_soc_component_update_bits(comp, tx_vol_ctl_reg,
+						CDC_VA_TX_PATH_CLK_EN_MASK,
+						CDC_VA_TX_PATH_CLK_DISABLE);
+		break;
+	}
+	return 0;
+}
+
+static int va_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+	struct va_macro *va = snd_soc_component_get_drvdata(comp);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	int path = e->shift_l;
+
+	ucontrol->value.integer.value[0] = va->dec_mode[path];
+
+	return 0;
+}
+
+static int va_macro_dec_mode_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+	int value = ucontrol->value.integer.value[0];
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	int path = e->shift_l;
+	struct va_macro *va = snd_soc_component_get_drvdata(comp);
+
+	va->dec_mode[path] = value;
+
+	return 0;
+}
+
+static int va_macro_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	int tx_fs_rate;
+	struct snd_soc_component *component = dai->component;
+	u32 decimator, sample_rate;
+	u16 tx_fs_reg;
+	struct device *va_dev = component->dev;
+	struct va_macro *va = snd_soc_component_get_drvdata(component);
+
+	sample_rate = params_rate(params);
+	switch (sample_rate) {
+	case 8000:
+		tx_fs_rate = 0;
+		break;
+	case 16000:
+		tx_fs_rate = 1;
+		break;
+	case 32000:
+		tx_fs_rate = 3;
+		break;
+	case 48000:
+		tx_fs_rate = 4;
+		break;
+	case 96000:
+		tx_fs_rate = 5;
+		break;
+	case 192000:
+		tx_fs_rate = 6;
+		break;
+	case 384000:
+		tx_fs_rate = 7;
+		break;
+	default:
+		dev_err(va_dev, "%s: Invalid TX sample rate: %d\n",
+			__func__, params_rate(params));
+		return -EINVAL;
+	}
+
+	for_each_set_bit(decimator, &va->active_ch_mask[dai->id],
+			 VA_MACRO_DEC_MAX) {
+		tx_fs_reg = CDC_VA_TX0_TX_PATH_CTL +
+			    VA_MACRO_TX_PATH_OFFSET * decimator;
+		snd_soc_component_update_bits(component, tx_fs_reg, 0x0F,
+					      tx_fs_rate);
+	}
+	return 0;
+}
+
+static int va_macro_get_channel_map(struct snd_soc_dai *dai,
+				    unsigned int *tx_num, unsigned int *tx_slot,
+				    unsigned int *rx_num, unsigned int *rx_slot)
+{
+	struct snd_soc_component *component = dai->component;
+	struct device *va_dev = component->dev;
+	struct va_macro *va = snd_soc_component_get_drvdata(component);
+
+	switch (dai->id) {
+	case VA_MACRO_AIF1_CAP:
+	case VA_MACRO_AIF2_CAP:
+	case VA_MACRO_AIF3_CAP:
+		*tx_slot = va->active_ch_mask[dai->id];
+		*tx_num = va->active_ch_cnt[dai->id];
+		break;
+	default:
+		dev_err(va_dev, "%s: Invalid AIF\n", __func__);
+		break;
+	}
+	return 0;
+}
+
+static int va_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+	struct va_macro *va = snd_soc_component_get_drvdata(component);
+	u16 tx_vol_ctl_reg, decimator;
+
+	decimator = va->active_decimator[dai->id];
+
+	tx_vol_ctl_reg = CDC_VA_TX0_TX_PATH_CTL +
+				VA_MACRO_TX_PATH_OFFSET * decimator;
+	if (mute)
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+					      CDC_VA_TX_PATH_PGA_MUTE_EN_MASK,
+					      CDC_VA_TX_PATH_PGA_MUTE_EN);
+	else
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+					      CDC_VA_TX_PATH_PGA_MUTE_EN_MASK,
+					      CDC_VA_TX_PATH_PGA_MUTE_DISABLE);
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops va_macro_dai_ops = {
+	.hw_params = va_macro_hw_params,
+	.get_channel_map = va_macro_get_channel_map,
+	.mute_stream = va_macro_digital_mute,
+};
+
+static struct snd_soc_dai_driver va_macro_dais[] = {
+	{
+		.name = "va_macro_tx1",
+		.id = VA_MACRO_AIF1_CAP,
+		.capture = {
+			.stream_name = "VA_AIF1 Capture",
+			.rates = VA_MACRO_RATES,
+			.formats = VA_MACRO_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 8,
+		},
+		.ops = &va_macro_dai_ops,
+	},
+	{
+		.name = "va_macro_tx2",
+		.id = VA_MACRO_AIF2_CAP,
+		.capture = {
+			.stream_name = "VA_AIF2 Capture",
+			.rates = VA_MACRO_RATES,
+			.formats = VA_MACRO_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 8,
+		},
+		.ops = &va_macro_dai_ops,
+	},
+	{
+		.name = "va_macro_tx3",
+		.id = VA_MACRO_AIF3_CAP,
+		.capture = {
+			.stream_name = "VA_AIF3 Capture",
+			.rates = VA_MACRO_RATES,
+			.formats = VA_MACRO_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 8,
+		},
+		.ops = &va_macro_dai_ops,
+	},
+};
+
+static const char * const adc_mux_text[] = {
+	"VA_DMIC", "SWR_MIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(va_dec0_enum, CDC_VA_INP_MUX_ADC_MUX0_CFG1,
+		   0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(va_dec1_enum, CDC_VA_INP_MUX_ADC_MUX1_CFG1,
+		   0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(va_dec2_enum, CDC_VA_INP_MUX_ADC_MUX2_CFG1,
+		   0, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(va_dec3_enum, CDC_VA_INP_MUX_ADC_MUX3_CFG1,
+		   0, adc_mux_text);
+
+static const struct snd_kcontrol_new va_dec0_mux = SOC_DAPM_ENUM("va_dec0",
+								 va_dec0_enum);
+static const struct snd_kcontrol_new va_dec1_mux = SOC_DAPM_ENUM("va_dec1",
+								 va_dec1_enum);
+static const struct snd_kcontrol_new va_dec2_mux = SOC_DAPM_ENUM("va_dec2",
+								 va_dec2_enum);
+static const struct snd_kcontrol_new va_dec3_mux = SOC_DAPM_ENUM("va_dec3",
+								 va_dec3_enum);
+
+static const char * const dmic_mux_text[] = {
+	"ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3",
+	"DMIC4", "DMIC5", "DMIC6", "DMIC7"
+};
+
+static SOC_ENUM_SINGLE_DECL(va_dmic0_enum, CDC_VA_INP_MUX_ADC_MUX0_CFG0,
+			4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(va_dmic1_enum, CDC_VA_INP_MUX_ADC_MUX1_CFG0,
+			4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(va_dmic2_enum, CDC_VA_INP_MUX_ADC_MUX2_CFG0,
+			4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(va_dmic3_enum, CDC_VA_INP_MUX_ADC_MUX3_CFG0,
+			4, dmic_mux_text);
+
+static const struct snd_kcontrol_new va_dmic0_mux = SOC_DAPM_ENUM_EXT("va_dmic0",
+			 va_dmic0_enum, snd_soc_dapm_get_enum_double,
+			 va_macro_put_dec_enum);
+
+static const struct snd_kcontrol_new va_dmic1_mux = SOC_DAPM_ENUM_EXT("va_dmic1",
+			 va_dmic1_enum, snd_soc_dapm_get_enum_double,
+			 va_macro_put_dec_enum);
+
+static const struct snd_kcontrol_new va_dmic2_mux = SOC_DAPM_ENUM_EXT("va_dmic2",
+			 va_dmic2_enum, snd_soc_dapm_get_enum_double,
+			 va_macro_put_dec_enum);
+
+static const struct snd_kcontrol_new va_dmic3_mux = SOC_DAPM_ENUM_EXT("va_dmic3",
+			 va_dmic3_enum, snd_soc_dapm_get_enum_double,
+			 va_macro_put_dec_enum);
+
+static const struct snd_kcontrol_new va_aif1_cap_mixer[] = {
+	SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, VA_MACRO_DEC4, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, VA_MACRO_DEC5, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, VA_MACRO_DEC6, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, VA_MACRO_DEC7, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new va_aif2_cap_mixer[] = {
+	SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, VA_MACRO_DEC4, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, VA_MACRO_DEC5, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, VA_MACRO_DEC6, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, VA_MACRO_DEC7, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new va_aif3_cap_mixer[] = {
+	SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, VA_MACRO_DEC4, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, VA_MACRO_DEC5, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, VA_MACRO_DEC6, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+	SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, VA_MACRO_DEC7, 1, 0,
+			va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_OUT("VA_AIF1 CAP", "VA_AIF1 Capture", 0,
+		SND_SOC_NOPM, VA_MACRO_AIF1_CAP, 0),
+
+	SND_SOC_DAPM_AIF_OUT("VA_AIF2 CAP", "VA_AIF2 Capture", 0,
+		SND_SOC_NOPM, VA_MACRO_AIF2_CAP, 0),
+
+	SND_SOC_DAPM_AIF_OUT("VA_AIF3 CAP", "VA_AIF3 Capture", 0,
+		SND_SOC_NOPM, VA_MACRO_AIF3_CAP, 0),
+
+	SND_SOC_DAPM_MIXER("VA_AIF1_CAP Mixer", SND_SOC_NOPM,
+		VA_MACRO_AIF1_CAP, 0,
+		va_aif1_cap_mixer, ARRAY_SIZE(va_aif1_cap_mixer)),
+
+	SND_SOC_DAPM_MIXER("VA_AIF2_CAP Mixer", SND_SOC_NOPM,
+		VA_MACRO_AIF2_CAP, 0,
+		va_aif2_cap_mixer, ARRAY_SIZE(va_aif2_cap_mixer)),
+
+	SND_SOC_DAPM_MIXER("VA_AIF3_CAP Mixer", SND_SOC_NOPM,
+		VA_MACRO_AIF3_CAP, 0,
+		va_aif3_cap_mixer, ARRAY_SIZE(va_aif3_cap_mixer)),
+
+	SND_SOC_DAPM_MUX("VA DMIC MUX0", SND_SOC_NOPM, 0, 0, &va_dmic0_mux),
+	SND_SOC_DAPM_MUX("VA DMIC MUX1", SND_SOC_NOPM, 0, 0, &va_dmic1_mux),
+	SND_SOC_DAPM_MUX("VA DMIC MUX2", SND_SOC_NOPM, 0, 0, &va_dmic2_mux),
+	SND_SOC_DAPM_MUX("VA DMIC MUX3", SND_SOC_NOPM, 0, 0, &va_dmic3_mux),
+
+	SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-micb", 0, 0),
+	SND_SOC_DAPM_INPUT("DMIC0 Pin"),
+	SND_SOC_DAPM_INPUT("DMIC1 Pin"),
+	SND_SOC_DAPM_INPUT("DMIC2 Pin"),
+	SND_SOC_DAPM_INPUT("DMIC3 Pin"),
+	SND_SOC_DAPM_INPUT("DMIC4 Pin"),
+	SND_SOC_DAPM_INPUT("DMIC5 Pin"),
+	SND_SOC_DAPM_INPUT("DMIC6 Pin"),
+	SND_SOC_DAPM_INPUT("DMIC7 Pin"),
+
+	SND_SOC_DAPM_ADC_E("VA DMIC0", NULL, SND_SOC_NOPM, 0, 0,
+		va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("VA DMIC1", NULL, SND_SOC_NOPM, 1, 0,
+		va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("VA DMIC2", NULL, SND_SOC_NOPM, 2, 0,
+		va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("VA DMIC3", NULL, SND_SOC_NOPM, 3, 0,
+		va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("VA DMIC4", NULL, SND_SOC_NOPM, 4, 0,
+		va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("VA DMIC5", NULL, SND_SOC_NOPM, 5, 0,
+		va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("VA DMIC6", NULL, SND_SOC_NOPM, 6, 0,
+		va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("VA DMIC7", NULL, SND_SOC_NOPM, 7, 0,
+		va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("VA SWR_ADC0"),
+	SND_SOC_DAPM_INPUT("VA SWR_ADC1"),
+	SND_SOC_DAPM_INPUT("VA SWR_ADC2"),
+	SND_SOC_DAPM_INPUT("VA SWR_ADC3"),
+	SND_SOC_DAPM_INPUT("VA SWR_MIC0"),
+	SND_SOC_DAPM_INPUT("VA SWR_MIC1"),
+	SND_SOC_DAPM_INPUT("VA SWR_MIC2"),
+	SND_SOC_DAPM_INPUT("VA SWR_MIC3"),
+	SND_SOC_DAPM_INPUT("VA SWR_MIC4"),
+	SND_SOC_DAPM_INPUT("VA SWR_MIC5"),
+	SND_SOC_DAPM_INPUT("VA SWR_MIC6"),
+	SND_SOC_DAPM_INPUT("VA SWR_MIC7"),
+
+	SND_SOC_DAPM_MUX_E("VA DEC0 MUX", SND_SOC_NOPM, VA_MACRO_DEC0, 0,
+			   &va_dec0_mux, va_macro_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("VA DEC1 MUX", SND_SOC_NOPM, VA_MACRO_DEC1, 0,
+			   &va_dec1_mux, va_macro_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("VA DEC2 MUX", SND_SOC_NOPM, VA_MACRO_DEC2, 0,
+			   &va_dec2_mux, va_macro_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("VA DEC3 MUX", SND_SOC_NOPM, VA_MACRO_DEC3, 0,
+			   &va_dec3_mux, va_macro_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("VA_MCLK", -1, SND_SOC_NOPM, 0, 0,
+			      va_macro_mclk_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route va_audio_map[] = {
+	{"VA_AIF1 CAP", NULL, "VA_MCLK"},
+	{"VA_AIF2 CAP", NULL, "VA_MCLK"},
+	{"VA_AIF3 CAP", NULL, "VA_MCLK"},
+
+	{"VA_AIF1 CAP", NULL, "VA_AIF1_CAP Mixer"},
+	{"VA_AIF2 CAP", NULL, "VA_AIF2_CAP Mixer"},
+	{"VA_AIF3 CAP", NULL, "VA_AIF3_CAP Mixer"},
+
+	{"VA_AIF1_CAP Mixer", "DEC0", "VA DEC0 MUX"},
+	{"VA_AIF1_CAP Mixer", "DEC1", "VA DEC1 MUX"},
+	{"VA_AIF1_CAP Mixer", "DEC2", "VA DEC2 MUX"},
+	{"VA_AIF1_CAP Mixer", "DEC3", "VA DEC3 MUX"},
+
+	{"VA_AIF2_CAP Mixer", "DEC0", "VA DEC0 MUX"},
+	{"VA_AIF2_CAP Mixer", "DEC1", "VA DEC1 MUX"},
+	{"VA_AIF2_CAP Mixer", "DEC2", "VA DEC2 MUX"},
+	{"VA_AIF2_CAP Mixer", "DEC3", "VA DEC3 MUX"},
+
+	{"VA_AIF3_CAP Mixer", "DEC0", "VA DEC0 MUX"},
+	{"VA_AIF3_CAP Mixer", "DEC1", "VA DEC1 MUX"},
+	{"VA_AIF3_CAP Mixer", "DEC2", "VA DEC2 MUX"},
+	{"VA_AIF3_CAP Mixer", "DEC3", "VA DEC3 MUX"},
+
+	{"VA DEC0 MUX", "VA_DMIC", "VA DMIC MUX0"},
+	{"VA DMIC MUX0", "DMIC0", "VA DMIC0"},
+	{"VA DMIC MUX0", "DMIC1", "VA DMIC1"},
+	{"VA DMIC MUX0", "DMIC2", "VA DMIC2"},
+	{"VA DMIC MUX0", "DMIC3", "VA DMIC3"},
+	{"VA DMIC MUX0", "DMIC4", "VA DMIC4"},
+	{"VA DMIC MUX0", "DMIC5", "VA DMIC5"},
+	{"VA DMIC MUX0", "DMIC6", "VA DMIC6"},
+	{"VA DMIC MUX0", "DMIC7", "VA DMIC7"},
+
+	{"VA DEC1 MUX", "VA_DMIC", "VA DMIC MUX1"},
+	{"VA DMIC MUX1", "DMIC0", "VA DMIC0"},
+	{"VA DMIC MUX1", "DMIC1", "VA DMIC1"},
+	{"VA DMIC MUX1", "DMIC2", "VA DMIC2"},
+	{"VA DMIC MUX1", "DMIC3", "VA DMIC3"},
+	{"VA DMIC MUX1", "DMIC4", "VA DMIC4"},
+	{"VA DMIC MUX1", "DMIC5", "VA DMIC5"},
+	{"VA DMIC MUX1", "DMIC6", "VA DMIC6"},
+	{"VA DMIC MUX1", "DMIC7", "VA DMIC7"},
+
+	{"VA DEC2 MUX", "VA_DMIC", "VA DMIC MUX2"},
+	{"VA DMIC MUX2", "DMIC0", "VA DMIC0"},
+	{"VA DMIC MUX2", "DMIC1", "VA DMIC1"},
+	{"VA DMIC MUX2", "DMIC2", "VA DMIC2"},
+	{"VA DMIC MUX2", "DMIC3", "VA DMIC3"},
+	{"VA DMIC MUX2", "DMIC4", "VA DMIC4"},
+	{"VA DMIC MUX2", "DMIC5", "VA DMIC5"},
+	{"VA DMIC MUX2", "DMIC6", "VA DMIC6"},
+	{"VA DMIC MUX2", "DMIC7", "VA DMIC7"},
+
+	{"VA DEC3 MUX", "VA_DMIC", "VA DMIC MUX3"},
+	{"VA DMIC MUX3", "DMIC0", "VA DMIC0"},
+	{"VA DMIC MUX3", "DMIC1", "VA DMIC1"},
+	{"VA DMIC MUX3", "DMIC2", "VA DMIC2"},
+	{"VA DMIC MUX3", "DMIC3", "VA DMIC3"},
+	{"VA DMIC MUX3", "DMIC4", "VA DMIC4"},
+	{"VA DMIC MUX3", "DMIC5", "VA DMIC5"},
+	{"VA DMIC MUX3", "DMIC6", "VA DMIC6"},
+	{"VA DMIC MUX3", "DMIC7", "VA DMIC7"},
+
+	{ "VA DMIC0", NULL, "DMIC0 Pin" },
+	{ "VA DMIC1", NULL, "DMIC1 Pin" },
+	{ "VA DMIC2", NULL, "DMIC2 Pin" },
+	{ "VA DMIC3", NULL, "DMIC3 Pin" },
+	{ "VA DMIC4", NULL, "DMIC4 Pin" },
+	{ "VA DMIC5", NULL, "DMIC5 Pin" },
+	{ "VA DMIC6", NULL, "DMIC6 Pin" },
+	{ "VA DMIC7", NULL, "DMIC7 Pin" },
+};
+
+static const char * const dec_mode_mux_text[] = {
+	"ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF",
+};
+
+static const struct soc_enum dec_mode_mux_enum[] = {
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(dec_mode_mux_text),
+			dec_mode_mux_text),
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(dec_mode_mux_text),
+			dec_mode_mux_text),
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 2,  ARRAY_SIZE(dec_mode_mux_text),
+			dec_mode_mux_text),
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(dec_mode_mux_text),
+			dec_mode_mux_text),
+};
+
+static const struct snd_kcontrol_new va_macro_snd_controls[] = {
+	SOC_SINGLE_S8_TLV("VA_DEC0 Volume", CDC_VA_TX0_TX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("VA_DEC1 Volume", CDC_VA_TX1_TX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("VA_DEC2 Volume", CDC_VA_TX2_TX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("VA_DEC3 Volume", CDC_VA_TX3_TX_VOL_CTL,
+			  -84, 40, digital_gain),
+
+	SOC_ENUM_EXT("VA_DEC0 MODE", dec_mode_mux_enum[0],
+		     va_macro_dec_mode_get, va_macro_dec_mode_put),
+	SOC_ENUM_EXT("VA_DEC1 MODE", dec_mode_mux_enum[1],
+		     va_macro_dec_mode_get, va_macro_dec_mode_put),
+	SOC_ENUM_EXT("VA_DEC2 MODE", dec_mode_mux_enum[2],
+		     va_macro_dec_mode_get, va_macro_dec_mode_put),
+	SOC_ENUM_EXT("VA_DEC3 MODE", dec_mode_mux_enum[3],
+		     va_macro_dec_mode_get, va_macro_dec_mode_put),
+};
+
+static int va_macro_component_probe(struct snd_soc_component *component)
+{
+	struct va_macro *va = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_init_regmap(component, va->regmap);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver va_macro_component_drv = {
+	.name = "VA MACRO",
+	.probe = va_macro_component_probe,
+	.controls = va_macro_snd_controls,
+	.num_controls = ARRAY_SIZE(va_macro_snd_controls),
+	.dapm_widgets = va_macro_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(va_macro_dapm_widgets),
+	.dapm_routes = va_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(va_audio_map),
+};
+
+static int fsgen_gate_enable(struct clk_hw *hw)
+{
+	return va_macro_mclk_enable(to_va_macro(hw), true);
+}
+
+static void fsgen_gate_disable(struct clk_hw *hw)
+{
+	va_macro_mclk_enable(to_va_macro(hw), false);
+}
+
+static int fsgen_gate_is_enabled(struct clk_hw *hw)
+{
+	struct va_macro *va = to_va_macro(hw);
+	int val;
+
+	regmap_read(va->regmap, CDC_VA_TOP_CSR_TOP_CFG0, &val);
+
+	return  !!(val & CDC_VA_FS_BROADCAST_EN);
+}
+
+static const struct clk_ops fsgen_gate_ops = {
+	.prepare = fsgen_gate_enable,
+	.unprepare = fsgen_gate_disable,
+	.is_enabled = fsgen_gate_is_enabled,
+};
+
+static int va_macro_register_fsgen_output(struct va_macro *va)
+{
+	struct clk *parent = va->clks[2].clk;
+	struct device *dev = va->dev;
+	struct device_node *np = dev->of_node;
+	const char *parent_clk_name;
+	const char *clk_name = "fsgen";
+	struct clk_init_data init;
+	int ret;
+
+	parent_clk_name = __clk_get_name(parent);
+
+	of_property_read_string(np, "clock-output-names", &clk_name);
+
+	init.name = clk_name;
+	init.ops = &fsgen_gate_ops;
+	init.flags = 0;
+	init.parent_names = &parent_clk_name;
+	init.num_parents = 1;
+	va->hw.init = &init;
+	ret = devm_clk_hw_register(va->dev, &va->hw);
+	if (ret)
+		return ret;
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, va->hw.clk);
+}
+
+static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate,
+					      struct va_macro *va)
+{
+	u32 div_factor;
+	u32 mclk_rate = VA_MACRO_MCLK_FREQ;
+
+	if (!dmic_sample_rate || mclk_rate % dmic_sample_rate != 0)
+		goto undefined_rate;
+
+	div_factor = mclk_rate / dmic_sample_rate;
+
+	switch (div_factor) {
+	case 2:
+		va->dmic_clk_div = VA_MACRO_CLK_DIV_2;
+		break;
+	case 3:
+		va->dmic_clk_div = VA_MACRO_CLK_DIV_3;
+		break;
+	case 4:
+		va->dmic_clk_div = VA_MACRO_CLK_DIV_4;
+		break;
+	case 6:
+		va->dmic_clk_div = VA_MACRO_CLK_DIV_6;
+		break;
+	case 8:
+		va->dmic_clk_div = VA_MACRO_CLK_DIV_8;
+		break;
+	case 16:
+		va->dmic_clk_div = VA_MACRO_CLK_DIV_16;
+		break;
+	default:
+		/* Any other DIV factor is invalid */
+		goto undefined_rate;
+	}
+
+	return dmic_sample_rate;
+
+undefined_rate:
+	dev_err(va->dev, "%s: Invalid rate %d, for mclk %d\n",
+		__func__, dmic_sample_rate, mclk_rate);
+	dmic_sample_rate = 0;
+
+	return dmic_sample_rate;
+}
+
+static int va_macro_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct va_macro *va;
+	void __iomem *base;
+	u32 sample_rate = 0;
+	int ret;
+
+	va = devm_kzalloc(dev, sizeof(*va), GFP_KERNEL);
+	if (!va)
+		return -ENOMEM;
+
+	va->dev = dev;
+	va->clks[0].id = "macro";
+	va->clks[1].id = "dcodec";
+	va->clks[2].id = "mclk";
+
+	ret = devm_clk_bulk_get(dev, VA_NUM_CLKS_MAX, va->clks);
+	if (ret) {
+		dev_err(dev, "Error getting VA Clocks (%d)\n", ret);
+		return ret;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "qcom,dmic-sample-rate",
+				   &sample_rate);
+	if (ret) {
+		dev_err(dev, "qcom,dmic-sample-rate dt entry missing\n");
+		va->dmic_clk_div = VA_MACRO_CLK_DIV_2;
+	} else {
+		ret = va_macro_validate_dmic_sample_rate(sample_rate, va);
+		if (!ret)
+			return -EINVAL;
+	}
+
+	/* mclk rate */
+	clk_set_rate(va->clks[1].clk, VA_MACRO_MCLK_FREQ);
+	ret = clk_bulk_prepare_enable(VA_NUM_CLKS_MAX, va->clks);
+	if (ret)
+		return ret;
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base)) {
+		ret = PTR_ERR(base);
+		goto err;
+	}
+
+	va->regmap = devm_regmap_init_mmio(dev, base,  &va_regmap_config);
+	if (IS_ERR(va->regmap)) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	dev_set_drvdata(dev, va);
+	ret = va_macro_register_fsgen_output(va);
+	if (ret)
+		goto err;
+
+	ret = devm_snd_soc_register_component(dev, &va_macro_component_drv,
+					      va_macro_dais,
+					      ARRAY_SIZE(va_macro_dais));
+	if (ret)
+		goto soc_err;
+
+	return ret;
+
+soc_err:
+	of_clk_del_provider(pdev->dev.of_node);
+err:
+	clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks);
+
+	return ret;
+}
+
+static int va_macro_remove(struct platform_device *pdev)
+{
+	struct va_macro *va = dev_get_drvdata(&pdev->dev);
+
+	of_clk_del_provider(pdev->dev.of_node);
+	clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks);
+
+	return 0;
+}
+
+static const struct of_device_id va_macro_dt_match[] = {
+	{ .compatible = "qcom,sm8250-lpass-va-macro" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, va_macro_dt_match);
+
+static struct platform_driver va_macro_driver = {
+	.driver = {
+		.name = "va_macro",
+		.of_match_table = va_macro_dt_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = va_macro_probe,
+	.remove = va_macro_remove,
+};
+
+module_platform_driver(va_macro_driver);
+MODULE_DESCRIPTION("VA macro driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
new file mode 100644
index 000000000000..25f1df214ca5
--- /dev/null
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -0,0 +1,2464 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of_clk.h>
+#include <linux/clk-provider.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/of_platform.h>
+#include <sound/tlv.h>
+#include "lpass-wsa-macro.h"
+
+#define CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL	(0x0000)
+#define CDC_WSA_MCLK_EN_MASK			BIT(0)
+#define CDC_WSA_MCLK_ENABLE			BIT(0)
+#define CDC_WSA_MCLK_DISABLE			0
+#define CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL	(0x0004)
+#define CDC_WSA_FS_CNT_EN_MASK			BIT(0)
+#define CDC_WSA_FS_CNT_ENABLE			BIT(0)
+#define CDC_WSA_FS_CNT_DISABLE			0
+#define CDC_WSA_CLK_RST_CTRL_SWR_CONTROL	(0x0008)
+#define CDC_WSA_SWR_CLK_EN_MASK			BIT(0)
+#define CDC_WSA_SWR_CLK_ENABLE			BIT(0)
+#define CDC_WSA_SWR_RST_EN_MASK			BIT(1)
+#define CDC_WSA_SWR_RST_ENABLE			BIT(1)
+#define CDC_WSA_SWR_RST_DISABLE			0
+#define CDC_WSA_TOP_TOP_CFG0			(0x0080)
+#define CDC_WSA_TOP_TOP_CFG1			(0x0084)
+#define CDC_WSA_TOP_FREQ_MCLK			(0x0088)
+#define CDC_WSA_TOP_DEBUG_BUS_SEL		(0x008C)
+#define CDC_WSA_TOP_DEBUG_EN0			(0x0090)
+#define CDC_WSA_TOP_DEBUG_EN1			(0x0094)
+#define CDC_WSA_TOP_DEBUG_DSM_LB		(0x0098)
+#define CDC_WSA_TOP_RX_I2S_CTL			(0x009C)
+#define CDC_WSA_TOP_TX_I2S_CTL			(0x00A0)
+#define CDC_WSA_TOP_I2S_CLK			(0x00A4)
+#define CDC_WSA_TOP_I2S_RESET			(0x00A8)
+#define CDC_WSA_RX_INP_MUX_RX_INT0_CFG0		(0x0100)
+#define CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK	GENMASK(5, 3)
+#define CDC_WSA_RX_INTX_2_SEL_MASK		GENMASK(2, 0)
+#define CDC_WSA_RX_INP_MUX_RX_INT0_CFG1		(0x0104)
+#define CDC_WSA_RX_INP_MUX_RX_INT1_CFG0		(0x0108)
+#define CDC_WSA_RX_INP_MUX_RX_INT1_CFG1		(0x010C)
+#define CDC_WSA_RX_INP_MUX_RX_MIX_CFG0		(0x0110)
+#define CDC_WSA_RX_MIX_TX1_SEL_MASK		GENMASK(5, 3)
+#define CDC_WSA_RX_MIX_TX1_SEL_SHFT		3
+#define CDC_WSA_RX_MIX_TX0_SEL_MASK		GENMASK(2, 0)
+#define CDC_WSA_RX_INP_MUX_RX_EC_CFG0		(0x0114)
+#define CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0	(0x0118)
+#define CDC_WSA_TX0_SPKR_PROT_PATH_CTL		(0x0244)
+#define CDC_WSA_TX_SPKR_PROT_RESET_MASK		BIT(5)
+#define CDC_WSA_TX_SPKR_PROT_RESET		BIT(5)
+#define CDC_WSA_TX_SPKR_PROT_NO_RESET		0
+#define CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK	BIT(4)
+#define CDC_WSA_TX_SPKR_PROT_CLK_ENABLE		BIT(4)
+#define CDC_WSA_TX_SPKR_PROT_CLK_DISABLE	0
+#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK	GENMASK(3, 0)
+#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K	0
+#define CDC_WSA_TX0_SPKR_PROT_PATH_CFG0		(0x0248)
+#define CDC_WSA_TX1_SPKR_PROT_PATH_CTL		(0x0264)
+#define CDC_WSA_TX1_SPKR_PROT_PATH_CFG0		(0x0268)
+#define CDC_WSA_TX2_SPKR_PROT_PATH_CTL		(0x0284)
+#define CDC_WSA_TX2_SPKR_PROT_PATH_CFG0		(0x0288)
+#define CDC_WSA_TX3_SPKR_PROT_PATH_CTL		(0x02A4)
+#define CDC_WSA_TX3_SPKR_PROT_PATH_CFG0		(0x02A8)
+#define CDC_WSA_INTR_CTRL_CFG			(0x0340)
+#define CDC_WSA_INTR_CTRL_CLR_COMMIT		(0x0344)
+#define CDC_WSA_INTR_CTRL_PIN1_MASK0		(0x0360)
+#define CDC_WSA_INTR_CTRL_PIN1_STATUS0		(0x0368)
+#define CDC_WSA_INTR_CTRL_PIN1_CLEAR0		(0x0370)
+#define CDC_WSA_INTR_CTRL_PIN2_MASK0		(0x0380)
+#define CDC_WSA_INTR_CTRL_PIN2_STATUS0		(0x0388)
+#define CDC_WSA_INTR_CTRL_PIN2_CLEAR0		(0x0390)
+#define CDC_WSA_INTR_CTRL_LEVEL0		(0x03C0)
+#define CDC_WSA_INTR_CTRL_BYPASS0		(0x03C8)
+#define CDC_WSA_INTR_CTRL_SET0			(0x03D0)
+#define CDC_WSA_RX0_RX_PATH_CTL			(0x0400)
+#define CDC_WSA_RX_PATH_CLK_EN_MASK		BIT(5)
+#define CDC_WSA_RX_PATH_CLK_ENABLE		BIT(5)
+#define CDC_WSA_RX_PATH_CLK_DISABLE		0
+#define CDC_WSA_RX_PATH_PGA_MUTE_EN_MASK	BIT(4)
+#define CDC_WSA_RX_PATH_PGA_MUTE_ENABLE		BIT(4)
+#define CDC_WSA_RX_PATH_PGA_MUTE_DISABLE	0
+#define CDC_WSA_RX0_RX_PATH_CFG0		(0x0404)
+#define CDC_WSA_RX_PATH_COMP_EN_MASK		BIT(1)
+#define CDC_WSA_RX_PATH_COMP_ENABLE		BIT(1)
+#define CDC_WSA_RX_PATH_HD2_EN_MASK		BIT(2)
+#define CDC_WSA_RX_PATH_HD2_ENABLE		BIT(2)
+#define CDC_WSA_RX_PATH_SPKR_RATE_MASK		BIT(3)
+#define CDC_WSA_RX_PATH_SPKR_RATE_FS_2P4_3P072	BIT(3)
+#define CDC_WSA_RX0_RX_PATH_CFG1		(0x0408)
+#define CDC_WSA_RX_PATH_SMART_BST_EN_MASK	BIT(0)
+#define CDC_WSA_RX_PATH_SMART_BST_ENABLE	BIT(0)
+#define CDC_WSA_RX_PATH_SMART_BST_DISABLE	0
+#define CDC_WSA_RX0_RX_PATH_CFG2		(0x040C)
+#define CDC_WSA_RX0_RX_PATH_CFG3		(0x0410)
+#define CDC_WSA_RX_DC_DCOEFF_MASK		GENMASK(1, 0)
+#define CDC_WSA_RX0_RX_VOL_CTL			(0x0414)
+#define CDC_WSA_RX0_RX_PATH_MIX_CTL		(0x0418)
+#define CDC_WSA_RX_PATH_MIX_CLK_EN_MASK		BIT(5)
+#define CDC_WSA_RX_PATH_MIX_CLK_ENABLE		BIT(5)
+#define CDC_WSA_RX_PATH_MIX_CLK_DISABLE		0
+#define CDC_WSA_RX0_RX_PATH_MIX_CFG		(0x041C)
+#define CDC_WSA_RX0_RX_VOL_MIX_CTL		(0x0420)
+#define CDC_WSA_RX0_RX_PATH_SEC0		(0x0424)
+#define CDC_WSA_RX0_RX_PATH_SEC1		(0x0428)
+#define CDC_WSA_RX_PGA_HALF_DB_MASK		BIT(0)
+#define CDC_WSA_RX_PGA_HALF_DB_ENABLE		BIT(0)
+#define CDC_WSA_RX_PGA_HALF_DB_DISABLE		0
+#define CDC_WSA_RX0_RX_PATH_SEC2		(0x042C)
+#define CDC_WSA_RX0_RX_PATH_SEC3		(0x0430)
+#define CDC_WSA_RX_PATH_HD2_SCALE_MASK		GENMASK(1, 0)
+#define CDC_WSA_RX_PATH_HD2_ALPHA_MASK		GENMASK(5, 2)
+#define CDC_WSA_RX0_RX_PATH_SEC5		(0x0438)
+#define CDC_WSA_RX0_RX_PATH_SEC6		(0x043C)
+#define CDC_WSA_RX0_RX_PATH_SEC7		(0x0440)
+#define CDC_WSA_RX0_RX_PATH_MIX_SEC0		(0x0444)
+#define CDC_WSA_RX0_RX_PATH_MIX_SEC1		(0x0448)
+#define CDC_WSA_RX0_RX_PATH_DSMDEM_CTL		(0x044C)
+#define CDC_WSA_RX_DSMDEM_CLK_EN_MASK		BIT(0)
+#define CDC_WSA_RX_DSMDEM_CLK_ENABLE		BIT(0)
+#define CDC_WSA_RX1_RX_PATH_CTL			(0x0480)
+#define CDC_WSA_RX1_RX_PATH_CFG0		(0x0484)
+#define CDC_WSA_RX1_RX_PATH_CFG1		(0x0488)
+#define CDC_WSA_RX1_RX_PATH_CFG2		(0x048C)
+#define CDC_WSA_RX1_RX_PATH_CFG3		(0x0490)
+#define CDC_WSA_RX1_RX_VOL_CTL			(0x0494)
+#define CDC_WSA_RX1_RX_PATH_MIX_CTL		(0x0498)
+#define CDC_WSA_RX1_RX_PATH_MIX_CFG		(0x049C)
+#define CDC_WSA_RX1_RX_VOL_MIX_CTL		(0x04A0)
+#define CDC_WSA_RX1_RX_PATH_SEC0		(0x04A4)
+#define CDC_WSA_RX1_RX_PATH_SEC1		(0x04A8)
+#define CDC_WSA_RX1_RX_PATH_SEC2		(0x04AC)
+#define CDC_WSA_RX1_RX_PATH_SEC3		(0x04B0)
+#define CDC_WSA_RX1_RX_PATH_SEC5		(0x04B8)
+#define CDC_WSA_RX1_RX_PATH_SEC6		(0x04BC)
+#define CDC_WSA_RX1_RX_PATH_SEC7		(0x04C0)
+#define CDC_WSA_RX1_RX_PATH_MIX_SEC0		(0x04C4)
+#define CDC_WSA_RX1_RX_PATH_MIX_SEC1		(0x04C8)
+#define CDC_WSA_RX1_RX_PATH_DSMDEM_CTL		(0x04CC)
+#define CDC_WSA_BOOST0_BOOST_PATH_CTL		(0x0500)
+#define CDC_WSA_BOOST_PATH_CLK_EN_MASK		BIT(4)
+#define CDC_WSA_BOOST_PATH_CLK_ENABLE		BIT(4)
+#define CDC_WSA_BOOST_PATH_CLK_DISABLE		0
+#define CDC_WSA_BOOST0_BOOST_CTL		(0x0504)
+#define CDC_WSA_BOOST0_BOOST_CFG1		(0x0508)
+#define CDC_WSA_BOOST0_BOOST_CFG2		(0x050C)
+#define CDC_WSA_BOOST1_BOOST_PATH_CTL		(0x0540)
+#define CDC_WSA_BOOST1_BOOST_CTL		(0x0544)
+#define CDC_WSA_BOOST1_BOOST_CFG1		(0x0548)
+#define CDC_WSA_BOOST1_BOOST_CFG2		(0x054C)
+#define CDC_WSA_COMPANDER0_CTL0			(0x0580)
+#define CDC_WSA_COMPANDER_CLK_EN_MASK		BIT(0)
+#define CDC_WSA_COMPANDER_CLK_ENABLE		BIT(0)
+#define CDC_WSA_COMPANDER_SOFT_RST_MASK		BIT(1)
+#define CDC_WSA_COMPANDER_SOFT_RST_ENABLE	BIT(1)
+#define CDC_WSA_COMPANDER_HALT_MASK		BIT(2)
+#define CDC_WSA_COMPANDER_HALT			BIT(2)
+#define CDC_WSA_COMPANDER0_CTL1			(0x0584)
+#define CDC_WSA_COMPANDER0_CTL2			(0x0588)
+#define CDC_WSA_COMPANDER0_CTL3			(0x058C)
+#define CDC_WSA_COMPANDER0_CTL4			(0x0590)
+#define CDC_WSA_COMPANDER0_CTL5			(0x0594)
+#define CDC_WSA_COMPANDER0_CTL6			(0x0598)
+#define CDC_WSA_COMPANDER0_CTL7			(0x059C)
+#define CDC_WSA_COMPANDER1_CTL0			(0x05C0)
+#define CDC_WSA_COMPANDER1_CTL1			(0x05C4)
+#define CDC_WSA_COMPANDER1_CTL2			(0x05C8)
+#define CDC_WSA_COMPANDER1_CTL3			(0x05CC)
+#define CDC_WSA_COMPANDER1_CTL4			(0x05D0)
+#define CDC_WSA_COMPANDER1_CTL5			(0x05D4)
+#define CDC_WSA_COMPANDER1_CTL6			(0x05D8)
+#define CDC_WSA_COMPANDER1_CTL7			(0x05DC)
+#define CDC_WSA_SOFTCLIP0_CRC			(0x0600)
+#define CDC_WSA_SOFTCLIP_CLK_EN_MASK		BIT(0)
+#define CDC_WSA_SOFTCLIP_CLK_ENABLE		BIT(0)
+#define CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL		(0x0604)
+#define CDC_WSA_SOFTCLIP_EN_MASK		BIT(0)
+#define CDC_WSA_SOFTCLIP_ENABLE			BIT(0)
+#define CDC_WSA_SOFTCLIP1_CRC			(0x0640)
+#define CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL		(0x0644)
+#define CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL	(0x0680)
+#define CDC_WSA_EC_HQ_EC_CLK_EN_MASK		BIT(0)
+#define CDC_WSA_EC_HQ_EC_CLK_ENABLE		BIT(0)
+#define CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0		(0x0684)
+#define CDC_WSA_EC_HQ_EC_REF_PCM_RATE_MASK	GENMASK(4, 1)
+#define CDC_WSA_EC_HQ_EC_REF_PCM_RATE_48K	BIT(3)
+#define CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL	(0x06C0)
+#define CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0		(0x06C4)
+#define CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL	(0x0700)
+#define CDC_WSA_SPLINE_ASRC0_CTL0		(0x0704)
+#define CDC_WSA_SPLINE_ASRC0_CTL1		(0x0708)
+#define CDC_WSA_SPLINE_ASRC0_FIFO_CTL		(0x070C)
+#define CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB	(0x0710)
+#define CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB	(0x0714)
+#define CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB	(0x0718)
+#define CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB	(0x071C)
+#define CDC_WSA_SPLINE_ASRC0_STATUS_FIFO		(0x0720)
+#define CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL		(0x0740)
+#define CDC_WSA_SPLINE_ASRC1_CTL0		(0x0744)
+#define CDC_WSA_SPLINE_ASRC1_CTL1		(0x0748)
+#define CDC_WSA_SPLINE_ASRC1_FIFO_CTL		(0x074C)
+#define CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB (0x0750)
+#define CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB (0x0754)
+#define CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB (0x0758)
+#define CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB (0x075C)
+#define CDC_WSA_SPLINE_ASRC1_STATUS_FIFO	(0x0760)
+#define WSA_MAX_OFFSET				(0x0760)
+
+#define WSA_MACRO_RX_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 WSA_MACRO_RX_MIX_RATES (SNDRV_PCM_RATE_48000 |\
+			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define WSA_MACRO_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+		SNDRV_PCM_FMTBIT_S24_LE |\
+		SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+#define WSA_MACRO_ECHO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			SNDRV_PCM_RATE_48000)
+#define WSA_MACRO_ECHO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+		SNDRV_PCM_FMTBIT_S24_LE |\
+		SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define NUM_INTERPOLATORS 2
+#define WSA_NUM_CLKS_MAX	5
+#define WSA_MACRO_MCLK_FREQ 19200000
+#define WSA_MACRO_MUX_INP_SHFT 0x3
+#define WSA_MACRO_MUX_INP_MASK1 0x07
+#define WSA_MACRO_MUX_INP_MASK2 0x38
+#define WSA_MACRO_MUX_CFG_OFFSET 0x8
+#define WSA_MACRO_MUX_CFG1_OFFSET 0x4
+#define WSA_MACRO_RX_COMP_OFFSET 0x40
+#define WSA_MACRO_RX_SOFTCLIP_OFFSET 0x40
+#define WSA_MACRO_RX_PATH_OFFSET 0x80
+#define WSA_MACRO_RX_PATH_CFG3_OFFSET 0x10
+#define WSA_MACRO_RX_PATH_DSMDEM_OFFSET 0x4C
+#define WSA_MACRO_FS_RATE_MASK 0x0F
+#define WSA_MACRO_EC_MIX_TX0_MASK 0x03
+#define WSA_MACRO_EC_MIX_TX1_MASK 0x18
+#define WSA_MACRO_MAX_DMA_CH_PER_PORT 0x2
+
+enum {
+	WSA_MACRO_GAIN_OFFSET_M1P5_DB,
+	WSA_MACRO_GAIN_OFFSET_0_DB,
+};
+enum {
+	WSA_MACRO_RX0 = 0,
+	WSA_MACRO_RX1,
+	WSA_MACRO_RX_MIX,
+	WSA_MACRO_RX_MIX0 = WSA_MACRO_RX_MIX,
+	WSA_MACRO_RX_MIX1,
+	WSA_MACRO_RX_MAX,
+};
+
+enum {
+	WSA_MACRO_TX0 = 0,
+	WSA_MACRO_TX1,
+	WSA_MACRO_TX_MAX,
+};
+
+enum {
+	WSA_MACRO_EC0_MUX = 0,
+	WSA_MACRO_EC1_MUX,
+	WSA_MACRO_EC_MUX_MAX,
+};
+
+enum {
+	WSA_MACRO_COMP1, /* SPK_L */
+	WSA_MACRO_COMP2, /* SPK_R */
+	WSA_MACRO_COMP_MAX
+};
+
+enum {
+	WSA_MACRO_SOFTCLIP0, /* RX0 */
+	WSA_MACRO_SOFTCLIP1, /* RX1 */
+	WSA_MACRO_SOFTCLIP_MAX
+};
+
+enum {
+	INTn_1_INP_SEL_ZERO = 0,
+	INTn_1_INP_SEL_RX0,
+	INTn_1_INP_SEL_RX1,
+	INTn_1_INP_SEL_RX2,
+	INTn_1_INP_SEL_RX3,
+	INTn_1_INP_SEL_DEC0,
+	INTn_1_INP_SEL_DEC1,
+};
+
+enum {
+	INTn_2_INP_SEL_ZERO = 0,
+	INTn_2_INP_SEL_RX0,
+	INTn_2_INP_SEL_RX1,
+	INTn_2_INP_SEL_RX2,
+	INTn_2_INP_SEL_RX3,
+};
+
+struct interp_sample_rate {
+	int sample_rate;
+	int rate_val;
+};
+
+static struct interp_sample_rate int_prim_sample_rate_val[] = {
+	{8000, 0x0},	/* 8K */
+	{16000, 0x1},	/* 16K */
+	{24000, -EINVAL},/* 24K */
+	{32000, 0x3},	/* 32K */
+	{48000, 0x4},	/* 48K */
+	{96000, 0x5},	/* 96K */
+	{192000, 0x6},	/* 192K */
+	{384000, 0x7},	/* 384K */
+	{44100, 0x8}, /* 44.1K */
+};
+
+static struct interp_sample_rate int_mix_sample_rate_val[] = {
+	{48000, 0x4},	/* 48K */
+	{96000, 0x5},	/* 96K */
+	{192000, 0x6},	/* 192K */
+};
+
+enum {
+	WSA_MACRO_AIF_INVALID = 0,
+	WSA_MACRO_AIF1_PB,
+	WSA_MACRO_AIF_MIX1_PB,
+	WSA_MACRO_AIF_VI,
+	WSA_MACRO_AIF_ECHO,
+	WSA_MACRO_MAX_DAIS,
+};
+
+struct wsa_macro {
+	struct device *dev;
+	int comp_enabled[WSA_MACRO_COMP_MAX];
+	int ec_hq[WSA_MACRO_RX1 + 1];
+	u16 prim_int_users[WSA_MACRO_RX1 + 1];
+	u16 wsa_mclk_users;
+	bool reset_swr;
+	unsigned long active_ch_mask[WSA_MACRO_MAX_DAIS];
+	unsigned long active_ch_cnt[WSA_MACRO_MAX_DAIS];
+	int rx_port_value[WSA_MACRO_RX_MAX];
+	int ear_spkr_gain;
+	int spkr_gain_offset;
+	int spkr_mode;
+	int is_softclip_on[WSA_MACRO_SOFTCLIP_MAX];
+	int softclip_clk_users[WSA_MACRO_SOFTCLIP_MAX];
+	struct regmap *regmap;
+	struct clk_bulk_data clks[WSA_NUM_CLKS_MAX];
+	struct clk_hw hw;
+};
+#define to_wsa_macro(_hw) container_of(_hw, struct wsa_macro, hw)
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
+
+static const char *const rx_text[] = {
+	"ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "DEC0", "DEC1"
+};
+
+static const char *const rx_mix_text[] = {
+	"ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1"
+};
+
+static const char *const rx_mix_ec_text[] = {
+	"ZERO", "RX_MIX_TX0", "RX_MIX_TX1"
+};
+
+static const char *const rx_mux_text[] = {
+	"ZERO", "AIF1_PB", "AIF_MIX1_PB"
+};
+
+static const char *const rx_sidetone_mix_text[] = {
+	"ZERO", "SRC0"
+};
+
+static const char * const wsa_macro_ear_spkr_pa_gain_text[] = {
+	"G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB",
+	"G_4_DB", "G_5_DB", "G_6_DB"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_ear_spkr_pa_gain_enum,
+				wsa_macro_ear_spkr_pa_gain_text);
+
+/* RX INT0 */
+static const struct soc_enum rx0_prim_inp0_chain_enum =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
+		0, 7, rx_text);
+
+static const struct soc_enum rx0_prim_inp1_chain_enum =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
+		3, 7, rx_text);
+
+static const struct soc_enum rx0_prim_inp2_chain_enum =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
+		3, 7, rx_text);
+
+static const struct soc_enum rx0_mix_chain_enum =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
+		0, 5, rx_mix_text);
+
+static const struct soc_enum rx0_sidetone_mix_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_sidetone_mix_text);
+
+static const struct snd_kcontrol_new rx0_prim_inp0_mux =
+	SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx0_prim_inp1_mux =
+	SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx0_prim_inp2_mux =
+	SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx0_mix_mux =
+	SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum);
+
+static const struct snd_kcontrol_new rx0_sidetone_mix_mux =
+	SOC_DAPM_ENUM("WSA_RX0 SIDETONE MIX Mux", rx0_sidetone_mix_enum);
+
+/* RX INT1 */
+static const struct soc_enum rx1_prim_inp0_chain_enum =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
+		0, 7, rx_text);
+
+static const struct soc_enum rx1_prim_inp1_chain_enum =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
+		3, 7, rx_text);
+
+static const struct soc_enum rx1_prim_inp2_chain_enum =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
+		3, 7, rx_text);
+
+static const struct soc_enum rx1_mix_chain_enum =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
+		0, 5, rx_mix_text);
+
+static const struct snd_kcontrol_new rx1_prim_inp0_mux =
+	SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx1_prim_inp1_mux =
+	SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx1_prim_inp2_mux =
+	SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx1_mix_mux =
+	SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum);
+
+static const struct soc_enum rx_mix_ec0_enum =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_MIX_CFG0,
+		0, 3, rx_mix_ec_text);
+
+static const struct soc_enum rx_mix_ec1_enum =
+	SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_MIX_CFG0,
+		3, 3, rx_mix_ec_text);
+
+static const struct snd_kcontrol_new rx_mix_ec0_mux =
+	SOC_DAPM_ENUM("WSA RX_MIX EC0_Mux", rx_mix_ec0_enum);
+
+static const struct snd_kcontrol_new rx_mix_ec1_mux =
+	SOC_DAPM_ENUM("WSA RX_MIX EC1_Mux", rx_mix_ec1_enum);
+
+static const struct reg_default wsa_defaults[] = {
+	/* WSA Macro */
+	{ CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, 0x00},
+	{ CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00},
+	{ CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, 0x00},
+	{ CDC_WSA_TOP_TOP_CFG0, 0x00},
+	{ CDC_WSA_TOP_TOP_CFG1, 0x00},
+	{ CDC_WSA_TOP_FREQ_MCLK, 0x00},
+	{ CDC_WSA_TOP_DEBUG_BUS_SEL, 0x00},
+	{ CDC_WSA_TOP_DEBUG_EN0, 0x00},
+	{ CDC_WSA_TOP_DEBUG_EN1, 0x00},
+	{ CDC_WSA_TOP_DEBUG_DSM_LB, 0x88},
+	{ CDC_WSA_TOP_RX_I2S_CTL, 0x0C},
+	{ CDC_WSA_TOP_TX_I2S_CTL, 0x0C},
+	{ CDC_WSA_TOP_I2S_CLK, 0x02},
+	{ CDC_WSA_TOP_I2S_RESET, 0x00},
+	{ CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, 0x00},
+	{ CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, 0x00},
+	{ CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, 0x00},
+	{ CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, 0x00},
+	{ CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, 0x00},
+	{ CDC_WSA_RX_INP_MUX_RX_EC_CFG0, 0x00},
+	{ CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, 0x00},
+	{ CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x02},
+	{ CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x00},
+	{ CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x02},
+	{ CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x00},
+	{ CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x02},
+	{ CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x00},
+	{ CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x02},
+	{ CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x00},
+	{ CDC_WSA_INTR_CTRL_CFG, 0x00},
+	{ CDC_WSA_INTR_CTRL_CLR_COMMIT, 0x00},
+	{ CDC_WSA_INTR_CTRL_PIN1_MASK0, 0xFF},
+	{ CDC_WSA_INTR_CTRL_PIN1_STATUS0, 0x00},
+	{ CDC_WSA_INTR_CTRL_PIN1_CLEAR0, 0x00},
+	{ CDC_WSA_INTR_CTRL_PIN2_MASK0, 0xFF},
+	{ CDC_WSA_INTR_CTRL_PIN2_STATUS0, 0x00},
+	{ CDC_WSA_INTR_CTRL_PIN2_CLEAR0, 0x00},
+	{ CDC_WSA_INTR_CTRL_LEVEL0, 0x00},
+	{ CDC_WSA_INTR_CTRL_BYPASS0, 0x00},
+	{ CDC_WSA_INTR_CTRL_SET0, 0x00},
+	{ CDC_WSA_RX0_RX_PATH_CTL, 0x04},
+	{ CDC_WSA_RX0_RX_PATH_CFG0, 0x00},
+	{ CDC_WSA_RX0_RX_PATH_CFG1, 0x64},
+	{ CDC_WSA_RX0_RX_PATH_CFG2, 0x8F},
+	{ CDC_WSA_RX0_RX_PATH_CFG3, 0x00},
+	{ CDC_WSA_RX0_RX_VOL_CTL, 0x00},
+	{ CDC_WSA_RX0_RX_PATH_MIX_CTL, 0x04},
+	{ CDC_WSA_RX0_RX_PATH_MIX_CFG, 0x7E},
+	{ CDC_WSA_RX0_RX_VOL_MIX_CTL, 0x00},
+	{ CDC_WSA_RX0_RX_PATH_SEC0, 0x04},
+	{ CDC_WSA_RX0_RX_PATH_SEC1, 0x08},
+	{ CDC_WSA_RX0_RX_PATH_SEC2, 0x00},
+	{ CDC_WSA_RX0_RX_PATH_SEC3, 0x00},
+	{ CDC_WSA_RX0_RX_PATH_SEC5, 0x00},
+	{ CDC_WSA_RX0_RX_PATH_SEC6, 0x00},
+	{ CDC_WSA_RX0_RX_PATH_SEC7, 0x00},
+	{ CDC_WSA_RX0_RX_PATH_MIX_SEC0, 0x08},
+	{ CDC_WSA_RX0_RX_PATH_MIX_SEC1, 0x00},
+	{ CDC_WSA_RX0_RX_PATH_DSMDEM_CTL, 0x00},
+	{ CDC_WSA_RX1_RX_PATH_CFG0, 0x00},
+	{ CDC_WSA_RX1_RX_PATH_CFG1, 0x64},
+	{ CDC_WSA_RX1_RX_PATH_CFG2, 0x8F},
+	{ CDC_WSA_RX1_RX_PATH_CFG3, 0x00},
+	{ CDC_WSA_RX1_RX_VOL_CTL, 0x00},
+	{ CDC_WSA_RX1_RX_PATH_MIX_CTL, 0x04},
+	{ CDC_WSA_RX1_RX_PATH_MIX_CFG, 0x7E},
+	{ CDC_WSA_RX1_RX_VOL_MIX_CTL, 0x00},
+	{ CDC_WSA_RX1_RX_PATH_SEC0, 0x04},
+	{ CDC_WSA_RX1_RX_PATH_SEC1, 0x08},
+	{ CDC_WSA_RX1_RX_PATH_SEC2, 0x00},
+	{ CDC_WSA_RX1_RX_PATH_SEC3, 0x00},
+	{ CDC_WSA_RX1_RX_PATH_SEC5, 0x00},
+	{ CDC_WSA_RX1_RX_PATH_SEC6, 0x00},
+	{ CDC_WSA_RX1_RX_PATH_SEC7, 0x00},
+	{ CDC_WSA_RX1_RX_PATH_MIX_SEC0, 0x08},
+	{ CDC_WSA_RX1_RX_PATH_MIX_SEC1, 0x00},
+	{ CDC_WSA_RX1_RX_PATH_DSMDEM_CTL, 0x00},
+	{ CDC_WSA_BOOST0_BOOST_PATH_CTL, 0x00},
+	{ CDC_WSA_BOOST0_BOOST_CTL, 0xD0},
+	{ CDC_WSA_BOOST0_BOOST_CFG1, 0x89},
+	{ CDC_WSA_BOOST0_BOOST_CFG2, 0x04},
+	{ CDC_WSA_BOOST1_BOOST_PATH_CTL, 0x00},
+	{ CDC_WSA_BOOST1_BOOST_CTL, 0xD0},
+	{ CDC_WSA_BOOST1_BOOST_CFG1, 0x89},
+	{ CDC_WSA_BOOST1_BOOST_CFG2, 0x04},
+	{ CDC_WSA_COMPANDER0_CTL0, 0x60},
+	{ CDC_WSA_COMPANDER0_CTL1, 0xDB},
+	{ CDC_WSA_COMPANDER0_CTL2, 0xFF},
+	{ CDC_WSA_COMPANDER0_CTL3, 0x35},
+	{ CDC_WSA_COMPANDER0_CTL4, 0xFF},
+	{ CDC_WSA_COMPANDER0_CTL5, 0x00},
+	{ CDC_WSA_COMPANDER0_CTL6, 0x01},
+	{ CDC_WSA_COMPANDER0_CTL7, 0x28},
+	{ CDC_WSA_COMPANDER1_CTL0, 0x60},
+	{ CDC_WSA_COMPANDER1_CTL1, 0xDB},
+	{ CDC_WSA_COMPANDER1_CTL2, 0xFF},
+	{ CDC_WSA_COMPANDER1_CTL3, 0x35},
+	{ CDC_WSA_COMPANDER1_CTL4, 0xFF},
+	{ CDC_WSA_COMPANDER1_CTL5, 0x00},
+	{ CDC_WSA_COMPANDER1_CTL6, 0x01},
+	{ CDC_WSA_COMPANDER1_CTL7, 0x28},
+	{ CDC_WSA_SOFTCLIP0_CRC, 0x00},
+	{ CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38},
+	{ CDC_WSA_SOFTCLIP1_CRC, 0x00},
+	{ CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38},
+	{ CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL, 0x00},
+	{ CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0, 0x01},
+	{ CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL, 0x00},
+	{ CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0, 0x01},
+	{ CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL, 0x00},
+	{ CDC_WSA_SPLINE_ASRC0_CTL0, 0x00},
+	{ CDC_WSA_SPLINE_ASRC0_CTL1, 0x00},
+	{ CDC_WSA_SPLINE_ASRC0_FIFO_CTL, 0xA8},
+	{ CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00},
+	{ CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00},
+	{ CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00},
+	{ CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00},
+	{ CDC_WSA_SPLINE_ASRC0_STATUS_FIFO, 0x00},
+	{ CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL, 0x00},
+	{ CDC_WSA_SPLINE_ASRC1_CTL0, 0x00},
+	{ CDC_WSA_SPLINE_ASRC1_CTL1, 0x00},
+	{ CDC_WSA_SPLINE_ASRC1_FIFO_CTL, 0xA8},
+	{ CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00},
+	{ CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00},
+	{ CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00},
+	{ CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00},
+	{ CDC_WSA_SPLINE_ASRC1_STATUS_FIFO, 0x00},
+};
+
+static bool wsa_is_wronly_register(struct device *dev,
+					unsigned int reg)
+{
+	switch (reg) {
+	case CDC_WSA_INTR_CTRL_CLR_COMMIT:
+	case CDC_WSA_INTR_CTRL_PIN1_CLEAR0:
+	case CDC_WSA_INTR_CTRL_PIN2_CLEAR0:
+		return true;
+	}
+
+	return false;
+}
+
+static bool wsa_is_rw_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL:
+	case CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL:
+	case CDC_WSA_CLK_RST_CTRL_SWR_CONTROL:
+	case CDC_WSA_TOP_TOP_CFG0:
+	case CDC_WSA_TOP_TOP_CFG1:
+	case CDC_WSA_TOP_FREQ_MCLK:
+	case CDC_WSA_TOP_DEBUG_BUS_SEL:
+	case CDC_WSA_TOP_DEBUG_EN0:
+	case CDC_WSA_TOP_DEBUG_EN1:
+	case CDC_WSA_TOP_DEBUG_DSM_LB:
+	case CDC_WSA_TOP_RX_I2S_CTL:
+	case CDC_WSA_TOP_TX_I2S_CTL:
+	case CDC_WSA_TOP_I2S_CLK:
+	case CDC_WSA_TOP_I2S_RESET:
+	case CDC_WSA_RX_INP_MUX_RX_INT0_CFG0:
+	case CDC_WSA_RX_INP_MUX_RX_INT0_CFG1:
+	case CDC_WSA_RX_INP_MUX_RX_INT1_CFG0:
+	case CDC_WSA_RX_INP_MUX_RX_INT1_CFG1:
+	case CDC_WSA_RX_INP_MUX_RX_MIX_CFG0:
+	case CDC_WSA_RX_INP_MUX_RX_EC_CFG0:
+	case CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0:
+	case CDC_WSA_TX0_SPKR_PROT_PATH_CTL:
+	case CDC_WSA_TX0_SPKR_PROT_PATH_CFG0:
+	case CDC_WSA_TX1_SPKR_PROT_PATH_CTL:
+	case CDC_WSA_TX1_SPKR_PROT_PATH_CFG0:
+	case CDC_WSA_TX2_SPKR_PROT_PATH_CTL:
+	case CDC_WSA_TX2_SPKR_PROT_PATH_CFG0:
+	case CDC_WSA_TX3_SPKR_PROT_PATH_CTL:
+	case CDC_WSA_TX3_SPKR_PROT_PATH_CFG0:
+	case CDC_WSA_INTR_CTRL_CFG:
+	case CDC_WSA_INTR_CTRL_PIN1_MASK0:
+	case CDC_WSA_INTR_CTRL_PIN2_MASK0:
+	case CDC_WSA_INTR_CTRL_LEVEL0:
+	case CDC_WSA_INTR_CTRL_BYPASS0:
+	case CDC_WSA_INTR_CTRL_SET0:
+	case CDC_WSA_RX0_RX_PATH_CTL:
+	case CDC_WSA_RX0_RX_PATH_CFG0:
+	case CDC_WSA_RX0_RX_PATH_CFG1:
+	case CDC_WSA_RX0_RX_PATH_CFG2:
+	case CDC_WSA_RX0_RX_PATH_CFG3:
+	case CDC_WSA_RX0_RX_VOL_CTL:
+	case CDC_WSA_RX0_RX_PATH_MIX_CTL:
+	case CDC_WSA_RX0_RX_PATH_MIX_CFG:
+	case CDC_WSA_RX0_RX_VOL_MIX_CTL:
+	case CDC_WSA_RX0_RX_PATH_SEC0:
+	case CDC_WSA_RX0_RX_PATH_SEC1:
+	case CDC_WSA_RX0_RX_PATH_SEC2:
+	case CDC_WSA_RX0_RX_PATH_SEC3:
+	case CDC_WSA_RX0_RX_PATH_SEC5:
+	case CDC_WSA_RX0_RX_PATH_SEC6:
+	case CDC_WSA_RX0_RX_PATH_SEC7:
+	case CDC_WSA_RX0_RX_PATH_MIX_SEC0:
+	case CDC_WSA_RX0_RX_PATH_MIX_SEC1:
+	case CDC_WSA_RX0_RX_PATH_DSMDEM_CTL:
+	case CDC_WSA_RX1_RX_PATH_CTL:
+	case CDC_WSA_RX1_RX_PATH_CFG0:
+	case CDC_WSA_RX1_RX_PATH_CFG1:
+	case CDC_WSA_RX1_RX_PATH_CFG2:
+	case CDC_WSA_RX1_RX_PATH_CFG3:
+	case CDC_WSA_RX1_RX_VOL_CTL:
+	case CDC_WSA_RX1_RX_PATH_MIX_CTL:
+	case CDC_WSA_RX1_RX_PATH_MIX_CFG:
+	case CDC_WSA_RX1_RX_VOL_MIX_CTL:
+	case CDC_WSA_RX1_RX_PATH_SEC0:
+	case CDC_WSA_RX1_RX_PATH_SEC1:
+	case CDC_WSA_RX1_RX_PATH_SEC2:
+	case CDC_WSA_RX1_RX_PATH_SEC3:
+	case CDC_WSA_RX1_RX_PATH_SEC5:
+	case CDC_WSA_RX1_RX_PATH_SEC6:
+	case CDC_WSA_RX1_RX_PATH_SEC7:
+	case CDC_WSA_RX1_RX_PATH_MIX_SEC0:
+	case CDC_WSA_RX1_RX_PATH_MIX_SEC1:
+	case CDC_WSA_RX1_RX_PATH_DSMDEM_CTL:
+	case CDC_WSA_BOOST0_BOOST_PATH_CTL:
+	case CDC_WSA_BOOST0_BOOST_CTL:
+	case CDC_WSA_BOOST0_BOOST_CFG1:
+	case CDC_WSA_BOOST0_BOOST_CFG2:
+	case CDC_WSA_BOOST1_BOOST_PATH_CTL:
+	case CDC_WSA_BOOST1_BOOST_CTL:
+	case CDC_WSA_BOOST1_BOOST_CFG1:
+	case CDC_WSA_BOOST1_BOOST_CFG2:
+	case CDC_WSA_COMPANDER0_CTL0:
+	case CDC_WSA_COMPANDER0_CTL1:
+	case CDC_WSA_COMPANDER0_CTL2:
+	case CDC_WSA_COMPANDER0_CTL3:
+	case CDC_WSA_COMPANDER0_CTL4:
+	case CDC_WSA_COMPANDER0_CTL5:
+	case CDC_WSA_COMPANDER0_CTL7:
+	case CDC_WSA_COMPANDER1_CTL0:
+	case CDC_WSA_COMPANDER1_CTL1:
+	case CDC_WSA_COMPANDER1_CTL2:
+	case CDC_WSA_COMPANDER1_CTL3:
+	case CDC_WSA_COMPANDER1_CTL4:
+	case CDC_WSA_COMPANDER1_CTL5:
+	case CDC_WSA_COMPANDER1_CTL7:
+	case CDC_WSA_SOFTCLIP0_CRC:
+	case CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL:
+	case CDC_WSA_SOFTCLIP1_CRC:
+	case CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL:
+	case CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL:
+	case CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0:
+	case CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL:
+	case CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0:
+	case CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL:
+	case CDC_WSA_SPLINE_ASRC0_CTL0:
+	case CDC_WSA_SPLINE_ASRC0_CTL1:
+	case CDC_WSA_SPLINE_ASRC0_FIFO_CTL:
+	case CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL:
+	case CDC_WSA_SPLINE_ASRC1_CTL0:
+	case CDC_WSA_SPLINE_ASRC1_CTL1:
+	case CDC_WSA_SPLINE_ASRC1_FIFO_CTL:
+		return true;
+	}
+
+	return false;
+}
+
+static bool wsa_is_writeable_register(struct device *dev, unsigned int reg)
+{
+	bool ret;
+
+	ret = wsa_is_rw_register(dev, reg);
+	if (!ret)
+		return wsa_is_wronly_register(dev, reg);
+
+	return ret;
+}
+
+static bool wsa_is_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CDC_WSA_INTR_CTRL_CLR_COMMIT:
+	case CDC_WSA_INTR_CTRL_PIN1_CLEAR0:
+	case CDC_WSA_INTR_CTRL_PIN2_CLEAR0:
+	case CDC_WSA_INTR_CTRL_PIN1_STATUS0:
+	case CDC_WSA_INTR_CTRL_PIN2_STATUS0:
+	case CDC_WSA_COMPANDER0_CTL6:
+	case CDC_WSA_COMPANDER1_CTL6:
+	case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB:
+	case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB:
+	case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB:
+	case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB:
+	case CDC_WSA_SPLINE_ASRC0_STATUS_FIFO:
+	case CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB:
+	case CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB:
+	case CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB:
+	case CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB:
+	case CDC_WSA_SPLINE_ASRC1_STATUS_FIFO:
+		return true;
+	}
+
+	return wsa_is_rw_register(dev, reg);
+}
+
+static bool wsa_is_volatile_register(struct device *dev, unsigned int reg)
+{
+	/* Update volatile list for rx/tx macros */
+	switch (reg) {
+	case CDC_WSA_INTR_CTRL_PIN1_STATUS0:
+	case CDC_WSA_INTR_CTRL_PIN2_STATUS0:
+	case CDC_WSA_COMPANDER0_CTL6:
+	case CDC_WSA_COMPANDER1_CTL6:
+	case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB:
+	case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB:
+	case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB:
+	case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB:
+	case CDC_WSA_SPLINE_ASRC0_STATUS_FIFO:
+	case CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB:
+	case CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB:
+	case CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB:
+	case CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB:
+	case CDC_WSA_SPLINE_ASRC1_STATUS_FIFO:
+		return true;
+	}
+	return false;
+}
+
+static const struct regmap_config wsa_regmap_config = {
+	.name = "wsa_macro",
+	.reg_bits = 16,
+	.val_bits = 32, /* 8 but with 32 bit read/write */
+	.reg_stride = 4,
+	.cache_type = REGCACHE_FLAT,
+	.reg_defaults = wsa_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wsa_defaults),
+	.max_register = WSA_MAX_OFFSET,
+	.writeable_reg = wsa_is_writeable_register,
+	.volatile_reg = wsa_is_volatile_register,
+	.readable_reg = wsa_is_readable_register,
+};
+
+/**
+ * wsa_macro_set_spkr_mode - Configures speaker compander and smartboost
+ * settings based on speaker mode.
+ *
+ * @component: codec instance
+ * @mode: Indicates speaker configuration mode.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int wsa_macro_set_spkr_mode(struct snd_soc_component *component, int mode)
+{
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	wsa->spkr_mode = mode;
+
+	switch (mode) {
+	case WSA_MACRO_SPKR_MODE_1:
+		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL3, 0x80, 0x00);
+		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL3, 0x80, 0x00);
+		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL7, 0x01, 0x00);
+		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL7, 0x01, 0x00);
+		snd_soc_component_update_bits(component, CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x44);
+		snd_soc_component_update_bits(component, CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x44);
+		break;
+	default:
+		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL3, 0x80, 0x80);
+		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL3, 0x80, 0x80);
+		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL7, 0x01, 0x01);
+		snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL7, 0x01, 0x01);
+		snd_soc_component_update_bits(component, CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x58);
+		snd_soc_component_update_bits(component, CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x58);
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(wsa_macro_set_spkr_mode);
+
+static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
+						u8 int_prim_fs_rate_reg_val,
+						u32 sample_rate)
+{
+	u8 int_1_mix1_inp;
+	u32 j, port;
+	u16 int_mux_cfg0, int_mux_cfg1;
+	u16 int_fs_reg;
+	u8 int_mux_cfg0_val, int_mux_cfg1_val;
+	u8 inp0_sel, inp1_sel, inp2_sel;
+	struct snd_soc_component *component = dai->component;
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	for_each_set_bit(port, &wsa->active_ch_mask[dai->id], WSA_MACRO_RX_MAX) {
+		int_1_mix1_inp = port;
+		if ((int_1_mix1_inp < WSA_MACRO_RX0) || (int_1_mix1_inp > WSA_MACRO_RX_MIX1)) {
+			dev_err(component->dev,	"%s: Invalid RX port, Dai ID is %d\n",
+				__func__, dai->id);
+			return -EINVAL;
+		}
+
+		int_mux_cfg0 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG0;
+
+		/*
+		 * Loop through all interpolator MUX inputs and find out
+		 * to which interpolator input, the cdc_dma rx port
+		 * is connected
+		 */
+		for (j = 0; j < NUM_INTERPOLATORS; j++) {
+			int_mux_cfg1 = int_mux_cfg0 + WSA_MACRO_MUX_CFG1_OFFSET;
+			int_mux_cfg0_val = snd_soc_component_read(component,
+								  int_mux_cfg0);
+			int_mux_cfg1_val = snd_soc_component_read(component,
+								  int_mux_cfg1);
+			inp0_sel = int_mux_cfg0_val & WSA_MACRO_MUX_INP_MASK1;
+			inp1_sel = (int_mux_cfg0_val >> WSA_MACRO_MUX_INP_SHFT) &
+						WSA_MACRO_MUX_INP_MASK1;
+			inp2_sel = (int_mux_cfg1_val >> WSA_MACRO_MUX_INP_SHFT) &
+						WSA_MACRO_MUX_INP_MASK1;
+			if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
+			    (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
+			    (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) {
+				int_fs_reg = CDC_WSA_RX0_RX_PATH_CTL +
+					     WSA_MACRO_RX_PATH_OFFSET * j;
+				/* sample_rate is in Hz */
+				snd_soc_component_update_bits(component, int_fs_reg,
+							      WSA_MACRO_FS_RATE_MASK,
+							      int_prim_fs_rate_reg_val);
+			}
+			int_mux_cfg0 += WSA_MACRO_MUX_CFG_OFFSET;
+		}
+	}
+
+	return 0;
+}
+
+static int wsa_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
+					       u8 int_mix_fs_rate_reg_val,
+					       u32 sample_rate)
+{
+	u8 int_2_inp;
+	u32 j, port;
+	u16 int_mux_cfg1, int_fs_reg;
+	u8 int_mux_cfg1_val;
+	struct snd_soc_component *component = dai->component;
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	for_each_set_bit(port, &wsa->active_ch_mask[dai->id], WSA_MACRO_RX_MAX) {
+		int_2_inp = port;
+		if ((int_2_inp < WSA_MACRO_RX0) || (int_2_inp > WSA_MACRO_RX_MIX1)) {
+			dev_err(component->dev,	"%s: Invalid RX port, Dai ID is %d\n",
+				__func__, dai->id);
+			return -EINVAL;
+		}
+
+		int_mux_cfg1 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG1;
+		for (j = 0; j < NUM_INTERPOLATORS; j++) {
+			int_mux_cfg1_val = snd_soc_component_read(component,
+							int_mux_cfg1) &
+							WSA_MACRO_MUX_INP_MASK1;
+			if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) {
+				int_fs_reg = CDC_WSA_RX0_RX_PATH_MIX_CTL +
+					WSA_MACRO_RX_PATH_OFFSET * j;
+
+				snd_soc_component_update_bits(component,
+						      int_fs_reg,
+						      WSA_MACRO_FS_RATE_MASK,
+						      int_mix_fs_rate_reg_val);
+			}
+			int_mux_cfg1 += WSA_MACRO_MUX_CFG_OFFSET;
+		}
+	}
+	return 0;
+}
+
+static int wsa_macro_set_interpolator_rate(struct snd_soc_dai *dai,
+					   u32 sample_rate)
+{
+	int rate_val = 0;
+	int i, ret;
+
+	/* set mixing path rate */
+	for (i = 0; i < ARRAY_SIZE(int_mix_sample_rate_val); i++) {
+		if (sample_rate == int_mix_sample_rate_val[i].sample_rate) {
+			rate_val = int_mix_sample_rate_val[i].rate_val;
+			break;
+		}
+	}
+	if ((i == ARRAY_SIZE(int_mix_sample_rate_val)) || (rate_val < 0))
+		goto prim_rate;
+
+	ret = wsa_macro_set_mix_interpolator_rate(dai, (u8) rate_val, sample_rate);
+prim_rate:
+	/* set primary path sample rate */
+	for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) {
+		if (sample_rate == int_prim_sample_rate_val[i].sample_rate) {
+			rate_val = int_prim_sample_rate_val[i].rate_val;
+			break;
+		}
+	}
+	if ((i == ARRAY_SIZE(int_prim_sample_rate_val)) || (rate_val < 0))
+		return -EINVAL;
+
+	ret = wsa_macro_set_prim_interpolator_rate(dai, (u8) rate_val, sample_rate);
+
+	return ret;
+}
+
+static int wsa_macro_hw_params(struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *params,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	int ret;
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		ret = wsa_macro_set_interpolator_rate(dai, params_rate(params));
+		if (ret) {
+			dev_err(component->dev,
+				"%s: cannot set sample rate: %u\n",
+				__func__, params_rate(params));
+			return ret;
+		}
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int wsa_macro_get_channel_map(struct snd_soc_dai *dai,
+				     unsigned int *tx_num, unsigned int *tx_slot,
+				     unsigned int *rx_num, unsigned int *rx_slot)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+	u16 val, mask = 0, cnt = 0, temp;
+
+	switch (dai->id) {
+	case WSA_MACRO_AIF_VI:
+		*tx_slot = wsa->active_ch_mask[dai->id];
+		*tx_num = wsa->active_ch_cnt[dai->id];
+		break;
+	case WSA_MACRO_AIF1_PB:
+	case WSA_MACRO_AIF_MIX1_PB:
+		for_each_set_bit(temp, &wsa->active_ch_mask[dai->id],
+					WSA_MACRO_RX_MAX) {
+			mask |= (1 << temp);
+			if (++cnt == WSA_MACRO_MAX_DMA_CH_PER_PORT)
+				break;
+		}
+		if (mask & 0x0C)
+			mask = mask >> 0x2;
+		*rx_slot = mask;
+		*rx_num = cnt;
+		break;
+	case WSA_MACRO_AIF_ECHO:
+		val = snd_soc_component_read(component, CDC_WSA_RX_INP_MUX_RX_MIX_CFG0);
+		if (val & WSA_MACRO_EC_MIX_TX1_MASK) {
+			mask |= 0x2;
+			cnt++;
+		}
+		if (val & WSA_MACRO_EC_MIX_TX0_MASK) {
+			mask |= 0x1;
+			cnt++;
+		}
+		*tx_slot = mask;
+		*tx_num = cnt;
+		break;
+	default:
+		dev_err(component->dev, "%s: Invalid AIF\n", __func__);
+		break;
+	}
+	return 0;
+}
+
+static struct snd_soc_dai_ops wsa_macro_dai_ops = {
+	.hw_params = wsa_macro_hw_params,
+	.get_channel_map = wsa_macro_get_channel_map,
+};
+
+static struct snd_soc_dai_driver wsa_macro_dai[] = {
+	{
+		.name = "wsa_macro_rx1",
+		.id = WSA_MACRO_AIF1_PB,
+		.playback = {
+			.stream_name = "WSA_AIF1 Playback",
+			.rates = WSA_MACRO_RX_RATES,
+			.formats = WSA_MACRO_RX_FORMATS,
+			.rate_max = 384000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &wsa_macro_dai_ops,
+	},
+	{
+		.name = "wsa_macro_rx_mix",
+		.id = WSA_MACRO_AIF_MIX1_PB,
+		.playback = {
+			.stream_name = "WSA_AIF_MIX1 Playback",
+			.rates = WSA_MACRO_RX_MIX_RATES,
+			.formats = WSA_MACRO_RX_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 48000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &wsa_macro_dai_ops,
+	},
+	{
+		.name = "wsa_macro_vifeedback",
+		.id = WSA_MACRO_AIF_VI,
+		.capture = {
+			.stream_name = "WSA_AIF_VI Capture",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+			.formats = WSA_MACRO_RX_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &wsa_macro_dai_ops,
+	},
+	{
+		.name = "wsa_macro_echo",
+		.id = WSA_MACRO_AIF_ECHO,
+		.capture = {
+			.stream_name = "WSA_AIF_ECHO Capture",
+			.rates = WSA_MACRO_ECHO_RATES,
+			.formats = WSA_MACRO_ECHO_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &wsa_macro_dai_ops,
+	},
+};
+
+static void wsa_macro_mclk_enable(struct wsa_macro *wsa, bool mclk_enable)
+{
+	struct regmap *regmap = wsa->regmap;
+
+	if (mclk_enable) {
+		if (wsa->wsa_mclk_users == 0) {
+			regcache_mark_dirty(regmap);
+			regcache_sync(regmap);
+			/* 9.6MHz MCLK, set value 0x00 if other frequency */
+			regmap_update_bits(regmap, CDC_WSA_TOP_FREQ_MCLK, 0x01, 0x01);
+			regmap_update_bits(regmap,
+					   CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL,
+					   CDC_WSA_MCLK_EN_MASK,
+					   CDC_WSA_MCLK_ENABLE);
+			regmap_update_bits(regmap,
+					   CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL,
+					   CDC_WSA_FS_CNT_EN_MASK,
+					   CDC_WSA_FS_CNT_ENABLE);
+		}
+		wsa->wsa_mclk_users++;
+	} else {
+		if (wsa->wsa_mclk_users <= 0) {
+			dev_err(wsa->dev, "clock already disabled\n");
+			wsa->wsa_mclk_users = 0;
+			return;
+		}
+		wsa->wsa_mclk_users--;
+		if (wsa->wsa_mclk_users == 0) {
+			regmap_update_bits(regmap,
+					   CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL,
+					   CDC_WSA_FS_CNT_EN_MASK,
+					   CDC_WSA_FS_CNT_DISABLE);
+			regmap_update_bits(regmap,
+					   CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL,
+					   CDC_WSA_MCLK_EN_MASK,
+					   CDC_WSA_MCLK_DISABLE);
+		}
+	}
+}
+
+static int wsa_macro_mclk_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	wsa_macro_mclk_enable(wsa, event == SND_SOC_DAPM_PRE_PMU);
+	return 0;
+}
+
+static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kcontrol,
+					int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+	u32 tx_reg0, tx_reg1;
+
+	if (test_bit(WSA_MACRO_TX0, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+		tx_reg0 = CDC_WSA_TX0_SPKR_PROT_PATH_CTL;
+		tx_reg1 = CDC_WSA_TX1_SPKR_PROT_PATH_CTL;
+	} else if (test_bit(WSA_MACRO_TX1, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+		tx_reg0 = CDC_WSA_TX2_SPKR_PROT_PATH_CTL;
+		tx_reg1 = CDC_WSA_TX3_SPKR_PROT_PATH_CTL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+			/* Enable V&I sensing */
+		snd_soc_component_update_bits(component, tx_reg0,
+					      CDC_WSA_TX_SPKR_PROT_RESET_MASK,
+					      CDC_WSA_TX_SPKR_PROT_RESET);
+		snd_soc_component_update_bits(component, tx_reg1,
+					      CDC_WSA_TX_SPKR_PROT_RESET_MASK,
+					      CDC_WSA_TX_SPKR_PROT_RESET);
+		snd_soc_component_update_bits(component, tx_reg0,
+					      CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK,
+					      CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K);
+		snd_soc_component_update_bits(component, tx_reg1,
+					      CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK,
+					      CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K);
+		snd_soc_component_update_bits(component, tx_reg0,
+					      CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK,
+					      CDC_WSA_TX_SPKR_PROT_CLK_ENABLE);
+		snd_soc_component_update_bits(component, tx_reg1,
+					      CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK,
+					      CDC_WSA_TX_SPKR_PROT_CLK_ENABLE);
+		snd_soc_component_update_bits(component, tx_reg0,
+					      CDC_WSA_TX_SPKR_PROT_RESET_MASK,
+					      CDC_WSA_TX_SPKR_PROT_NO_RESET);
+		snd_soc_component_update_bits(component, tx_reg1,
+					      CDC_WSA_TX_SPKR_PROT_RESET_MASK,
+					      CDC_WSA_TX_SPKR_PROT_NO_RESET);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Disable V&I sensing */
+		snd_soc_component_update_bits(component, tx_reg0,
+					      CDC_WSA_TX_SPKR_PROT_RESET_MASK,
+					      CDC_WSA_TX_SPKR_PROT_RESET);
+		snd_soc_component_update_bits(component, tx_reg1,
+					      CDC_WSA_TX_SPKR_PROT_RESET_MASK,
+					      CDC_WSA_TX_SPKR_PROT_RESET);
+		snd_soc_component_update_bits(component, tx_reg0,
+					      CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK,
+					      CDC_WSA_TX_SPKR_PROT_CLK_DISABLE);
+		snd_soc_component_update_bits(component, tx_reg1,
+					      CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK,
+					      CDC_WSA_TX_SPKR_PROT_CLK_DISABLE);
+		break;
+	}
+
+	return 0;
+}
+
+static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 gain_reg;
+	int val;
+
+	switch (w->reg) {
+	case CDC_WSA_RX0_RX_PATH_MIX_CTL:
+		gain_reg = CDC_WSA_RX0_RX_VOL_MIX_CTL;
+		break;
+	case CDC_WSA_RX1_RX_PATH_MIX_CTL:
+		gain_reg = CDC_WSA_RX1_RX_VOL_MIX_CTL;
+		break;
+	default:
+		return 0;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		val = snd_soc_component_read(component, gain_reg);
+		snd_soc_component_write(component, gain_reg, val);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, w->reg,
+					      CDC_WSA_RX_PATH_MIX_CLK_EN_MASK,
+					      CDC_WSA_RX_PATH_MIX_CLK_DISABLE);
+		break;
+	}
+
+	return 0;
+}
+
+static void wsa_macro_hd2_control(struct snd_soc_component *component,
+				  u16 reg, int event)
+{
+	u16 hd2_scale_reg;
+	u16 hd2_enable_reg;
+
+	if (reg == CDC_WSA_RX0_RX_PATH_CTL) {
+		hd2_scale_reg = CDC_WSA_RX0_RX_PATH_SEC3;
+		hd2_enable_reg = CDC_WSA_RX0_RX_PATH_CFG0;
+	}
+	if (reg == CDC_WSA_RX1_RX_PATH_CTL) {
+		hd2_scale_reg = CDC_WSA_RX1_RX_PATH_SEC3;
+		hd2_enable_reg = CDC_WSA_RX1_RX_PATH_CFG0;
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_component_update_bits(component, hd2_scale_reg,
+					      CDC_WSA_RX_PATH_HD2_ALPHA_MASK,
+					      0x10);
+		snd_soc_component_update_bits(component, hd2_scale_reg,
+					      CDC_WSA_RX_PATH_HD2_SCALE_MASK,
+					      0x1);
+		snd_soc_component_update_bits(component, hd2_enable_reg,
+					      CDC_WSA_RX_PATH_HD2_EN_MASK,
+					      CDC_WSA_RX_PATH_HD2_ENABLE);
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_component_update_bits(component, hd2_enable_reg,
+					      CDC_WSA_RX_PATH_HD2_EN_MASK, 0);
+		snd_soc_component_update_bits(component, hd2_scale_reg,
+					      CDC_WSA_RX_PATH_HD2_SCALE_MASK,
+					      0);
+		snd_soc_component_update_bits(component, hd2_scale_reg,
+					      CDC_WSA_RX_PATH_HD2_ALPHA_MASK,
+					      0);
+	}
+}
+
+static int wsa_macro_config_compander(struct snd_soc_component *component,
+				      int comp, int event)
+{
+	u16 comp_ctl0_reg, rx_path_cfg0_reg;
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	if (!wsa->comp_enabled[comp])
+		return 0;
+
+	comp_ctl0_reg = CDC_WSA_COMPANDER0_CTL0 +
+					(comp * WSA_MACRO_RX_COMP_OFFSET);
+	rx_path_cfg0_reg = CDC_WSA_RX0_RX_PATH_CFG0 +
+					(comp * WSA_MACRO_RX_PATH_OFFSET);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Enable Compander Clock */
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					      CDC_WSA_COMPANDER_CLK_EN_MASK,
+					      CDC_WSA_COMPANDER_CLK_ENABLE);
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					      CDC_WSA_COMPANDER_SOFT_RST_MASK,
+					      CDC_WSA_COMPANDER_SOFT_RST_ENABLE);
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					      CDC_WSA_COMPANDER_SOFT_RST_MASK,
+					      0);
+		snd_soc_component_update_bits(component, rx_path_cfg0_reg,
+					      CDC_WSA_RX_PATH_COMP_EN_MASK,
+					      CDC_WSA_RX_PATH_COMP_ENABLE);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					      CDC_WSA_COMPANDER_HALT_MASK,
+					      CDC_WSA_COMPANDER_HALT);
+		snd_soc_component_update_bits(component, rx_path_cfg0_reg,
+					      CDC_WSA_RX_PATH_COMP_EN_MASK, 0);
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					      CDC_WSA_COMPANDER_SOFT_RST_MASK,
+					      CDC_WSA_COMPANDER_SOFT_RST_ENABLE);
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					      CDC_WSA_COMPANDER_SOFT_RST_MASK,
+					      0);
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					      CDC_WSA_COMPANDER_CLK_EN_MASK, 0);
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					      CDC_WSA_COMPANDER_HALT_MASK, 0);
+	}
+
+	return 0;
+}
+
+static void wsa_macro_enable_softclip_clk(struct snd_soc_component *component,
+					 struct wsa_macro *wsa,
+					 int path,
+					 bool enable)
+{
+	u16 softclip_clk_reg = CDC_WSA_SOFTCLIP0_CRC +
+			(path * WSA_MACRO_RX_SOFTCLIP_OFFSET);
+	u8 softclip_mux_mask = (1 << path);
+	u8 softclip_mux_value = (1 << path);
+
+	if (enable) {
+		if (wsa->softclip_clk_users[path] == 0) {
+			snd_soc_component_update_bits(component,
+						softclip_clk_reg,
+						CDC_WSA_SOFTCLIP_CLK_EN_MASK,
+						CDC_WSA_SOFTCLIP_CLK_ENABLE);
+			snd_soc_component_update_bits(component,
+				CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0,
+				softclip_mux_mask, softclip_mux_value);
+		}
+		wsa->softclip_clk_users[path]++;
+	} else {
+		wsa->softclip_clk_users[path]--;
+		if (wsa->softclip_clk_users[path] == 0) {
+			snd_soc_component_update_bits(component,
+						softclip_clk_reg,
+						CDC_WSA_SOFTCLIP_CLK_EN_MASK,
+						0);
+			snd_soc_component_update_bits(component,
+				CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0,
+				softclip_mux_mask, 0x00);
+		}
+	}
+}
+
+static int wsa_macro_config_softclip(struct snd_soc_component *component,
+				     int path, int event)
+{
+	u16 softclip_ctrl_reg;
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+	int softclip_path = 0;
+
+	if (path == WSA_MACRO_COMP1)
+		softclip_path = WSA_MACRO_SOFTCLIP0;
+	else if (path == WSA_MACRO_COMP2)
+		softclip_path = WSA_MACRO_SOFTCLIP1;
+
+	if (!wsa->is_softclip_on[softclip_path])
+		return 0;
+
+	softclip_ctrl_reg = CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL +
+				(softclip_path * WSA_MACRO_RX_SOFTCLIP_OFFSET);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Enable Softclip clock and mux */
+		wsa_macro_enable_softclip_clk(component, wsa, softclip_path,
+					      true);
+		/* Enable Softclip control */
+		snd_soc_component_update_bits(component, softclip_ctrl_reg,
+					      CDC_WSA_SOFTCLIP_EN_MASK,
+					      CDC_WSA_SOFTCLIP_ENABLE);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_component_update_bits(component, softclip_ctrl_reg,
+					      CDC_WSA_SOFTCLIP_EN_MASK, 0);
+		wsa_macro_enable_softclip_clk(component, wsa, softclip_path,
+					      false);
+	}
+
+	return 0;
+}
+
+static bool wsa_macro_adie_lb(struct snd_soc_component *component,
+			      int interp_idx)
+{
+	u16 int_mux_cfg0,  int_mux_cfg1;
+	u8 int_mux_cfg0_val, int_mux_cfg1_val;
+	u8 int_n_inp0, int_n_inp1, int_n_inp2;
+
+	int_mux_cfg0 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8;
+	int_mux_cfg1 = int_mux_cfg0 + 4;
+	int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0);
+	int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1);
+
+	int_n_inp0 = int_mux_cfg0_val & 0x0F;
+	if (int_n_inp0 == INTn_1_INP_SEL_DEC0 ||
+		int_n_inp0 == INTn_1_INP_SEL_DEC1)
+		return true;
+
+	int_n_inp1 = int_mux_cfg0_val >> 4;
+	if (int_n_inp1 == INTn_1_INP_SEL_DEC0 ||
+		int_n_inp1 == INTn_1_INP_SEL_DEC1)
+		return true;
+
+	int_n_inp2 = int_mux_cfg1_val >> 4;
+	if (int_n_inp2 == INTn_1_INP_SEL_DEC0 ||
+		int_n_inp2 == INTn_1_INP_SEL_DEC1)
+		return true;
+
+	return false;
+}
+
+static int wsa_macro_enable_main_path(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol,
+				      int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 reg;
+
+	reg = CDC_WSA_RX0_RX_PATH_CTL + WSA_MACRO_RX_PATH_OFFSET * w->shift;
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (wsa_macro_adie_lb(component, w->shift)) {
+			snd_soc_component_update_bits(component, reg,
+					     CDC_WSA_RX_PATH_CLK_EN_MASK,
+					     CDC_WSA_RX_PATH_CLK_ENABLE);
+		}
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int wsa_macro_interp_get_primary_reg(u16 reg, u16 *ind)
+{
+	u16 prim_int_reg = 0;
+
+	switch (reg) {
+	case CDC_WSA_RX0_RX_PATH_CTL:
+	case CDC_WSA_RX0_RX_PATH_MIX_CTL:
+		prim_int_reg = CDC_WSA_RX0_RX_PATH_CTL;
+		*ind = 0;
+		break;
+	case CDC_WSA_RX1_RX_PATH_CTL:
+	case CDC_WSA_RX1_RX_PATH_MIX_CTL:
+		prim_int_reg = CDC_WSA_RX1_RX_PATH_CTL;
+		*ind = 1;
+		break;
+	}
+
+	return prim_int_reg;
+}
+
+static int wsa_macro_enable_prim_interpolator(struct snd_soc_component *component,
+					      u16 reg, int event)
+{
+	u16 prim_int_reg;
+	u16 ind = 0;
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	prim_int_reg = wsa_macro_interp_get_primary_reg(reg, &ind);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wsa->prim_int_users[ind]++;
+		if (wsa->prim_int_users[ind] == 1) {
+			snd_soc_component_update_bits(component,
+						      prim_int_reg + WSA_MACRO_RX_PATH_CFG3_OFFSET,
+						      CDC_WSA_RX_DC_DCOEFF_MASK,
+						      0x3);
+			snd_soc_component_update_bits(component, prim_int_reg,
+					CDC_WSA_RX_PATH_PGA_MUTE_EN_MASK,
+					CDC_WSA_RX_PATH_PGA_MUTE_ENABLE);
+			wsa_macro_hd2_control(component, prim_int_reg, event);
+			snd_soc_component_update_bits(component,
+				prim_int_reg + WSA_MACRO_RX_PATH_DSMDEM_OFFSET,
+				CDC_WSA_RX_DSMDEM_CLK_EN_MASK,
+				CDC_WSA_RX_DSMDEM_CLK_ENABLE);
+		}
+		if ((reg != prim_int_reg) &&
+		    ((snd_soc_component_read(
+				component, prim_int_reg)) & 0x10))
+			snd_soc_component_update_bits(component, reg,
+					0x10, 0x10);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wsa->prim_int_users[ind]--;
+		if (wsa->prim_int_users[ind] == 0) {
+			snd_soc_component_update_bits(component,
+				prim_int_reg + WSA_MACRO_RX_PATH_DSMDEM_OFFSET,
+				CDC_WSA_RX_DSMDEM_CLK_EN_MASK, 0);
+			wsa_macro_hd2_control(component, prim_int_reg, event);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int wsa_macro_config_ear_spkr_gain(struct snd_soc_component *component,
+					  struct wsa_macro *wsa,
+					  int event, int gain_reg)
+{
+	int comp_gain_offset, val;
+
+	switch (wsa->spkr_mode) {
+	/* Compander gain in WSA_MACRO_SPKR_MODE1 case is 12 dB */
+	case WSA_MACRO_SPKR_MODE_1:
+		comp_gain_offset = -12;
+		break;
+	/* Default case compander gain is 15 dB */
+	default:
+		comp_gain_offset = -15;
+		break;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Apply ear spkr gain only if compander is enabled */
+		if (wsa->comp_enabled[WSA_MACRO_COMP1] &&
+		    (gain_reg == CDC_WSA_RX0_RX_VOL_CTL) &&
+		    (wsa->ear_spkr_gain != 0)) {
+			/* For example, val is -8(-12+5-1) for 4dB of gain */
+			val = comp_gain_offset + wsa->ear_spkr_gain - 1;
+			snd_soc_component_write(component, gain_reg, val);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/*
+		 * Reset RX0 volume to 0 dB if compander is enabled and
+		 * ear_spkr_gain is non-zero.
+		 */
+		if (wsa->comp_enabled[WSA_MACRO_COMP1] &&
+		    (gain_reg == CDC_WSA_RX0_RX_VOL_CTL) &&
+		    (wsa->ear_spkr_gain != 0)) {
+			snd_soc_component_write(component, gain_reg, 0x0);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 gain_reg;
+	u16 reg;
+	int val;
+	int offset_val = 0;
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	if (w->shift == WSA_MACRO_COMP1) {
+		reg = CDC_WSA_RX0_RX_PATH_CTL;
+		gain_reg = CDC_WSA_RX0_RX_VOL_CTL;
+	} else if (w->shift == WSA_MACRO_COMP2) {
+		reg = CDC_WSA_RX1_RX_PATH_CTL;
+		gain_reg = CDC_WSA_RX1_RX_VOL_CTL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Reset if needed */
+		wsa_macro_enable_prim_interpolator(component, reg, event);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		wsa_macro_config_compander(component, w->shift, event);
+		wsa_macro_config_softclip(component, w->shift, event);
+		/* apply gain after int clk is enabled */
+		if ((wsa->spkr_gain_offset == WSA_MACRO_GAIN_OFFSET_M1P5_DB) &&
+		    (wsa->comp_enabled[WSA_MACRO_COMP1] ||
+		     wsa->comp_enabled[WSA_MACRO_COMP2])) {
+			snd_soc_component_update_bits(component,
+					CDC_WSA_RX0_RX_PATH_SEC1,
+					CDC_WSA_RX_PGA_HALF_DB_MASK,
+					CDC_WSA_RX_PGA_HALF_DB_ENABLE);
+			snd_soc_component_update_bits(component,
+					CDC_WSA_RX0_RX_PATH_MIX_SEC0,
+					CDC_WSA_RX_PGA_HALF_DB_MASK,
+					CDC_WSA_RX_PGA_HALF_DB_ENABLE);
+			snd_soc_component_update_bits(component,
+					CDC_WSA_RX1_RX_PATH_SEC1,
+					CDC_WSA_RX_PGA_HALF_DB_MASK,
+					CDC_WSA_RX_PGA_HALF_DB_ENABLE);
+			snd_soc_component_update_bits(component,
+					CDC_WSA_RX1_RX_PATH_MIX_SEC0,
+					CDC_WSA_RX_PGA_HALF_DB_MASK,
+					CDC_WSA_RX_PGA_HALF_DB_ENABLE);
+			offset_val = -2;
+		}
+		val = snd_soc_component_read(component, gain_reg);
+		val += offset_val;
+		snd_soc_component_write(component, gain_reg, val);
+		wsa_macro_config_ear_spkr_gain(component, wsa,
+						event, gain_reg);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wsa_macro_config_compander(component, w->shift, event);
+		wsa_macro_config_softclip(component, w->shift, event);
+		wsa_macro_enable_prim_interpolator(component, reg, event);
+		if ((wsa->spkr_gain_offset == WSA_MACRO_GAIN_OFFSET_M1P5_DB) &&
+		    (wsa->comp_enabled[WSA_MACRO_COMP1] ||
+		     wsa->comp_enabled[WSA_MACRO_COMP2])) {
+			snd_soc_component_update_bits(component,
+					CDC_WSA_RX0_RX_PATH_SEC1,
+					CDC_WSA_RX_PGA_HALF_DB_MASK,
+					CDC_WSA_RX_PGA_HALF_DB_DISABLE);
+			snd_soc_component_update_bits(component,
+					CDC_WSA_RX0_RX_PATH_MIX_SEC0,
+					CDC_WSA_RX_PGA_HALF_DB_MASK,
+					CDC_WSA_RX_PGA_HALF_DB_DISABLE);
+			snd_soc_component_update_bits(component,
+					CDC_WSA_RX1_RX_PATH_SEC1,
+					CDC_WSA_RX_PGA_HALF_DB_MASK,
+					CDC_WSA_RX_PGA_HALF_DB_DISABLE);
+			snd_soc_component_update_bits(component,
+					CDC_WSA_RX1_RX_PATH_MIX_SEC0,
+					CDC_WSA_RX_PGA_HALF_DB_MASK,
+					CDC_WSA_RX_PGA_HALF_DB_DISABLE);
+			offset_val = 2;
+			val = snd_soc_component_read(component, gain_reg);
+			val += offset_val;
+			snd_soc_component_write(component, gain_reg, val);
+		}
+		wsa_macro_config_ear_spkr_gain(component, wsa,
+						event, gain_reg);
+		break;
+	}
+
+	return 0;
+}
+
+static int wsa_macro_spk_boost_event(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 boost_path_ctl, boost_path_cfg1;
+	u16 reg, reg_mix;
+
+	if (!strcmp(w->name, "WSA_RX INT0 CHAIN")) {
+		boost_path_ctl = CDC_WSA_BOOST0_BOOST_PATH_CTL;
+		boost_path_cfg1 = CDC_WSA_RX0_RX_PATH_CFG1;
+		reg = CDC_WSA_RX0_RX_PATH_CTL;
+		reg_mix = CDC_WSA_RX0_RX_PATH_MIX_CTL;
+	} else if (!strcmp(w->name, "WSA_RX INT1 CHAIN")) {
+		boost_path_ctl = CDC_WSA_BOOST1_BOOST_PATH_CTL;
+		boost_path_cfg1 = CDC_WSA_RX1_RX_PATH_CFG1;
+		reg = CDC_WSA_RX1_RX_PATH_CTL;
+		reg_mix = CDC_WSA_RX1_RX_PATH_MIX_CTL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, boost_path_cfg1,
+					      CDC_WSA_RX_PATH_SMART_BST_EN_MASK,
+					      CDC_WSA_RX_PATH_SMART_BST_ENABLE);
+		snd_soc_component_update_bits(component, boost_path_ctl,
+					      CDC_WSA_BOOST_PATH_CLK_EN_MASK,
+					      CDC_WSA_BOOST_PATH_CLK_ENABLE);
+		if ((snd_soc_component_read(component, reg_mix)) & 0x10)
+			snd_soc_component_update_bits(component, reg_mix,
+						0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, reg, 0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, boost_path_ctl,
+					      CDC_WSA_BOOST_PATH_CLK_EN_MASK,
+					      CDC_WSA_BOOST_PATH_CLK_DISABLE);
+		snd_soc_component_update_bits(component, boost_path_cfg1,
+					      CDC_WSA_RX_PATH_SMART_BST_EN_MASK,
+					      CDC_WSA_RX_PATH_SMART_BST_DISABLE);
+		break;
+	}
+
+	return 0;
+}
+
+static int wsa_macro_enable_echo(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol,
+				 int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+	u16 val, ec_tx, ec_hq_reg;
+
+	val = snd_soc_component_read(component, CDC_WSA_RX_INP_MUX_RX_MIX_CFG0);
+
+	switch (w->shift) {
+	case WSA_MACRO_EC0_MUX:
+		val = val & CDC_WSA_RX_MIX_TX0_SEL_MASK;
+		ec_tx = val - 1;
+		break;
+	case WSA_MACRO_EC1_MUX:
+		val = val & CDC_WSA_RX_MIX_TX1_SEL_MASK;
+		ec_tx = (val >> CDC_WSA_RX_MIX_TX1_SEL_SHFT) - 1;
+		break;
+	}
+
+	if (wsa->ec_hq[ec_tx]) {
+		ec_hq_reg = CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL +	0x40 * ec_tx;
+		snd_soc_component_update_bits(component, ec_hq_reg,
+					     CDC_WSA_EC_HQ_EC_CLK_EN_MASK,
+					     CDC_WSA_EC_HQ_EC_CLK_ENABLE);
+		ec_hq_reg = CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0 + 0x40 * ec_tx;
+		/* default set to 48k */
+		snd_soc_component_update_bits(component, ec_hq_reg,
+				      CDC_WSA_EC_HQ_EC_REF_PCM_RATE_MASK,
+				      CDC_WSA_EC_HQ_EC_REF_PCM_RATE_48K);
+	}
+
+	return 0;
+}
+
+static int wsa_macro_get_ec_hq(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int ec_tx = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wsa->ec_hq[ec_tx];
+
+	return 0;
+}
+
+static int wsa_macro_set_ec_hq(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int ec_tx = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	wsa->ec_hq[ec_tx] = value;
+
+	return 0;
+}
+
+static int wsa_macro_get_compander(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wsa->comp_enabled[comp];
+	return 0;
+}
+
+static int wsa_macro_set_compander(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	wsa->comp_enabled[comp] = value;
+
+	return 0;
+}
+
+static int wsa_macro_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wsa->ear_spkr_gain;
+
+	return 0;
+}
+
+static int wsa_macro_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	wsa->ear_spkr_gain =  ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int wsa_macro_rx_mux_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget =
+		snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component =
+				snd_soc_dapm_to_component(widget->dapm);
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] =
+			wsa->rx_port_value[widget->shift];
+	return 0;
+}
+
+static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget =
+		snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component =
+				snd_soc_dapm_to_component(widget->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	struct snd_soc_dapm_update *update = NULL;
+	u32 rx_port_value = ucontrol->value.integer.value[0];
+	u32 bit_input;
+	u32 aif_rst;
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+	aif_rst = wsa->rx_port_value[widget->shift];
+	if (!rx_port_value) {
+		if (aif_rst == 0) {
+			dev_err(component->dev, "%s: AIF reset already\n", __func__);
+			return 0;
+		}
+		if (aif_rst >= WSA_MACRO_RX_MAX) {
+			dev_err(component->dev, "%s: Invalid AIF reset\n", __func__);
+			return 0;
+		}
+	}
+	wsa->rx_port_value[widget->shift] = rx_port_value;
+
+	bit_input = widget->shift;
+
+	switch (rx_port_value) {
+	case 0:
+		if (wsa->active_ch_cnt[aif_rst]) {
+			clear_bit(bit_input,
+				  &wsa->active_ch_mask[aif_rst]);
+			wsa->active_ch_cnt[aif_rst]--;
+		}
+		break;
+	case 1:
+	case 2:
+		set_bit(bit_input,
+			&wsa->active_ch_mask[rx_port_value]);
+		wsa->active_ch_cnt[rx_port_value]++;
+		break;
+	default:
+		dev_err(component->dev,
+			"%s: Invalid AIF_ID for WSA RX MUX %d\n",
+			__func__, rx_port_value);
+		return -EINVAL;
+	}
+
+	snd_soc_dapm_mux_update_power(widget->dapm, kcontrol,
+					rx_port_value, e, update);
+	return 0;
+}
+
+static int wsa_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+	int path = ((struct soc_mixer_control *)kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] = wsa->is_softclip_on[path];
+
+	return 0;
+}
+
+static int wsa_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+	int path = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+
+	wsa->is_softclip_on[path] =  ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new wsa_macro_snd_controls[] = {
+	SOC_ENUM_EXT("EAR SPKR PA Gain", wsa_macro_ear_spkr_pa_gain_enum,
+		     wsa_macro_ear_spkr_pa_gain_get,
+		     wsa_macro_ear_spkr_pa_gain_put),
+	SOC_SINGLE_EXT("WSA_Softclip0 Enable", SND_SOC_NOPM,
+			WSA_MACRO_SOFTCLIP0, 1, 0,
+			wsa_macro_soft_clip_enable_get,
+			wsa_macro_soft_clip_enable_put),
+	SOC_SINGLE_EXT("WSA_Softclip1 Enable", SND_SOC_NOPM,
+			WSA_MACRO_SOFTCLIP1, 1, 0,
+			wsa_macro_soft_clip_enable_get,
+			wsa_macro_soft_clip_enable_put),
+
+	SOC_SINGLE_S8_TLV("WSA_RX0 Digital Volume", CDC_WSA_RX0_RX_VOL_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("WSA_RX1 Digital Volume", CDC_WSA_RX1_RX_VOL_CTL,
+			  -84, 40, digital_gain),
+
+	SOC_SINGLE("WSA_RX0 Digital Mute", CDC_WSA_RX0_RX_PATH_CTL, 4, 1, 0),
+	SOC_SINGLE("WSA_RX1 Digital Mute", CDC_WSA_RX1_RX_PATH_CTL, 4, 1, 0),
+	SOC_SINGLE("WSA_RX0_MIX Digital Mute", CDC_WSA_RX0_RX_PATH_MIX_CTL, 4,
+		   1, 0),
+	SOC_SINGLE("WSA_RX1_MIX Digital Mute", CDC_WSA_RX1_RX_PATH_MIX_CTL, 4,
+		   1, 0),
+	SOC_SINGLE_EXT("WSA_COMP1 Switch", SND_SOC_NOPM, WSA_MACRO_COMP1, 1, 0,
+		       wsa_macro_get_compander, wsa_macro_set_compander),
+	SOC_SINGLE_EXT("WSA_COMP2 Switch", SND_SOC_NOPM, WSA_MACRO_COMP2, 1, 0,
+		       wsa_macro_get_compander, wsa_macro_set_compander),
+	SOC_SINGLE_EXT("WSA_RX0 EC_HQ Switch", SND_SOC_NOPM, WSA_MACRO_RX0, 1, 0,
+		       wsa_macro_get_ec_hq, wsa_macro_set_ec_hq),
+	SOC_SINGLE_EXT("WSA_RX1 EC_HQ Switch", SND_SOC_NOPM, WSA_MACRO_RX1, 1, 0,
+		       wsa_macro_get_ec_hq, wsa_macro_set_ec_hq),
+};
+
+static const struct soc_enum rx_mux_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_mux_text), rx_mux_text);
+
+static const struct snd_kcontrol_new rx_mux[WSA_MACRO_RX_MAX] = {
+	SOC_DAPM_ENUM_EXT("WSA RX0 Mux", rx_mux_enum,
+			  wsa_macro_rx_mux_get, wsa_macro_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("WSA RX1 Mux", rx_mux_enum,
+			  wsa_macro_rx_mux_get, wsa_macro_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("WSA RX_MIX0 Mux", rx_mux_enum,
+			  wsa_macro_rx_mux_get, wsa_macro_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("WSA RX_MIX1 Mux", rx_mux_enum,
+			  wsa_macro_rx_mux_get, wsa_macro_rx_mux_put),
+};
+
+static int wsa_macro_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+	struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+	u32 spk_tx_id = mixer->shift;
+	u32 dai_id = widget->shift;
+
+	if (test_bit(spk_tx_id, &wsa->active_ch_mask[dai_id]))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	return 0;
+}
+
+static int wsa_macro_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+	struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+	u32 enable = ucontrol->value.integer.value[0];
+	u32 spk_tx_id = mixer->shift;
+
+	if (enable) {
+		if (spk_tx_id == WSA_MACRO_TX0 &&
+			!test_bit(WSA_MACRO_TX0,
+				&wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+			set_bit(WSA_MACRO_TX0,
+				&wsa->active_ch_mask[WSA_MACRO_AIF_VI]);
+			wsa->active_ch_cnt[WSA_MACRO_AIF_VI]++;
+		}
+		if (spk_tx_id == WSA_MACRO_TX1 &&
+			!test_bit(WSA_MACRO_TX1,
+				&wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+			set_bit(WSA_MACRO_TX1,
+				&wsa->active_ch_mask[WSA_MACRO_AIF_VI]);
+			wsa->active_ch_cnt[WSA_MACRO_AIF_VI]++;
+		}
+	} else {
+		if (spk_tx_id == WSA_MACRO_TX0 &&
+			test_bit(WSA_MACRO_TX0,
+				&wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+			clear_bit(WSA_MACRO_TX0,
+				&wsa->active_ch_mask[WSA_MACRO_AIF_VI]);
+			wsa->active_ch_cnt[WSA_MACRO_AIF_VI]--;
+		}
+		if (spk_tx_id == WSA_MACRO_TX1 &&
+			test_bit(WSA_MACRO_TX1,
+				&wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+			clear_bit(WSA_MACRO_TX1,
+				&wsa->active_ch_mask[WSA_MACRO_AIF_VI]);
+			wsa->active_ch_cnt[WSA_MACRO_AIF_VI]--;
+		}
+	}
+	snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new aif_vi_mixer[] = {
+	SOC_SINGLE_EXT("WSA_SPKR_VI_1", SND_SOC_NOPM, WSA_MACRO_TX0, 1, 0,
+			wsa_macro_vi_feed_mixer_get,
+			wsa_macro_vi_feed_mixer_put),
+	SOC_SINGLE_EXT("WSA_SPKR_VI_2", SND_SOC_NOPM, WSA_MACRO_TX1, 1, 0,
+			wsa_macro_vi_feed_mixer_get,
+			wsa_macro_vi_feed_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("WSA AIF1 PB", "WSA_AIF1 Playback", 0,
+			    SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("WSA AIF_MIX1 PB", "WSA_AIF_MIX1 Playback", 0,
+			    SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT_E("WSA AIF_VI", "WSA_AIF_VI Capture", 0,
+			       SND_SOC_NOPM, WSA_MACRO_AIF_VI, 0,
+			       wsa_macro_enable_vi_feedback,
+			       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT("WSA AIF_ECHO", "WSA_AIF_ECHO Capture", 0,
+			     SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MIXER("WSA_AIF_VI Mixer", SND_SOC_NOPM, WSA_MACRO_AIF_VI,
+			   0, aif_vi_mixer, ARRAY_SIZE(aif_vi_mixer)),
+	SND_SOC_DAPM_MUX_E("WSA RX_MIX EC0_MUX", SND_SOC_NOPM,
+			   WSA_MACRO_EC0_MUX, 0,
+			   &rx_mix_ec0_mux, wsa_macro_enable_echo,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("WSA RX_MIX EC1_MUX", SND_SOC_NOPM,
+			   WSA_MACRO_EC1_MUX, 0,
+			   &rx_mix_ec1_mux, wsa_macro_enable_echo,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("WSA RX0 MUX", SND_SOC_NOPM, WSA_MACRO_RX0, 0,
+			 &rx_mux[WSA_MACRO_RX0]),
+	SND_SOC_DAPM_MUX("WSA RX1 MUX", SND_SOC_NOPM, WSA_MACRO_RX1, 0,
+			 &rx_mux[WSA_MACRO_RX1]),
+	SND_SOC_DAPM_MUX("WSA RX_MIX0 MUX", SND_SOC_NOPM, WSA_MACRO_RX_MIX0, 0,
+			 &rx_mux[WSA_MACRO_RX_MIX0]),
+	SND_SOC_DAPM_MUX("WSA RX_MIX1 MUX", SND_SOC_NOPM, WSA_MACRO_RX_MIX1, 0,
+			 &rx_mux[WSA_MACRO_RX_MIX1]),
+
+	SND_SOC_DAPM_MIXER("WSA RX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("WSA RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("WSA RX_MIX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("WSA RX_MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux),
+	SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux),
+	SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux),
+	SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", CDC_WSA_RX0_RX_PATH_MIX_CTL,
+			   0, 0, &rx0_mix_mux, wsa_macro_enable_mix_path,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux),
+	SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux),
+	SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux),
+	SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", CDC_WSA_RX1_RX_PATH_MIX_CTL,
+			   0, 0, &rx1_mix_mux, wsa_macro_enable_mix_path,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM, 0, 0, NULL, 0,
+			     wsa_macro_enable_main_path, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MIXER_E("WSA_RX INT1 MIX", SND_SOC_NOPM, 1, 0, NULL, 0,
+			     wsa_macro_enable_main_path, SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_MIXER("WSA_RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("WSA_RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("WSA_RX0 INT0 SIDETONE MIX", CDC_WSA_RX0_RX_PATH_CFG1,
+			 4, 0, &rx0_sidetone_mix_mux),
+
+	SND_SOC_DAPM_INPUT("WSA SRC0_INP"),
+	SND_SOC_DAPM_INPUT("WSA_TX DEC0_INP"),
+	SND_SOC_DAPM_INPUT("WSA_TX DEC1_INP"),
+
+	SND_SOC_DAPM_MIXER_E("WSA_RX INT0 INTERP", SND_SOC_NOPM,
+			     WSA_MACRO_COMP1, 0, NULL, 0,
+			     wsa_macro_enable_interpolator,
+			     SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("WSA_RX INT1 INTERP", SND_SOC_NOPM,
+			     WSA_MACRO_COMP2, 0, NULL, 0,
+			     wsa_macro_enable_interpolator,
+			     SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("WSA_RX INT0 CHAIN", SND_SOC_NOPM, 0, 0,
+			     NULL, 0, wsa_macro_spk_boost_event,
+			     SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("WSA_RX INT1 CHAIN", SND_SOC_NOPM, 0, 0,
+			     NULL, 0, wsa_macro_spk_boost_event,
+			     SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			     SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("VIINPUT_WSA"),
+	SND_SOC_DAPM_OUTPUT("WSA_SPK1 OUT"),
+	SND_SOC_DAPM_OUTPUT("WSA_SPK2 OUT"),
+
+	SND_SOC_DAPM_SUPPLY("WSA_RX0_CLK", CDC_WSA_RX0_RX_PATH_CTL, 5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("WSA_RX1_CLK", CDC_WSA_RX1_RX_PATH_CTL, 5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("WSA_RX_MIX0_CLK", CDC_WSA_RX0_RX_PATH_MIX_CTL, 5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("WSA_RX_MIX1_CLK", CDC_WSA_RX1_RX_PATH_MIX_CTL, 5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("WSA_MCLK", 0, SND_SOC_NOPM, 0, 0,
+			      wsa_macro_mclk_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route wsa_audio_map[] = {
+	/* VI Feedback */
+	{"WSA_AIF_VI Mixer", "WSA_SPKR_VI_1", "VIINPUT_WSA"},
+	{"WSA_AIF_VI Mixer", "WSA_SPKR_VI_2", "VIINPUT_WSA"},
+	{"WSA AIF_VI", NULL, "WSA_AIF_VI Mixer"},
+	{"WSA AIF_VI", NULL, "WSA_MCLK"},
+
+	{"WSA RX_MIX EC0_MUX", "RX_MIX_TX0", "WSA_RX INT0 SEC MIX"},
+	{"WSA RX_MIX EC1_MUX", "RX_MIX_TX0", "WSA_RX INT0 SEC MIX"},
+	{"WSA RX_MIX EC0_MUX", "RX_MIX_TX1", "WSA_RX INT1 SEC MIX"},
+	{"WSA RX_MIX EC1_MUX", "RX_MIX_TX1", "WSA_RX INT1 SEC MIX"},
+	{"WSA AIF_ECHO", NULL, "WSA RX_MIX EC0_MUX"},
+	{"WSA AIF_ECHO", NULL, "WSA RX_MIX EC1_MUX"},
+	{"WSA AIF_ECHO", NULL, "WSA_MCLK"},
+
+	{"WSA AIF1 PB", NULL, "WSA_MCLK"},
+	{"WSA AIF_MIX1 PB", NULL, "WSA_MCLK"},
+
+	{"WSA RX0 MUX", "AIF1_PB", "WSA AIF1 PB"},
+	{"WSA RX1 MUX", "AIF1_PB", "WSA AIF1 PB"},
+	{"WSA RX_MIX0 MUX", "AIF1_PB", "WSA AIF1 PB"},
+	{"WSA RX_MIX1 MUX", "AIF1_PB", "WSA AIF1 PB"},
+
+	{"WSA RX0 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"},
+	{"WSA RX1 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"},
+	{"WSA RX_MIX0 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"},
+	{"WSA RX_MIX1 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"},
+
+	{"WSA RX0", NULL, "WSA RX0 MUX"},
+	{"WSA RX1", NULL, "WSA RX1 MUX"},
+	{"WSA RX_MIX0", NULL, "WSA RX_MIX0 MUX"},
+	{"WSA RX_MIX1", NULL, "WSA RX_MIX1 MUX"},
+
+	{"WSA RX0", NULL, "WSA_RX0_CLK"},
+	{"WSA RX1", NULL, "WSA_RX1_CLK"},
+	{"WSA RX_MIX0", NULL, "WSA_RX_MIX0_CLK"},
+	{"WSA RX_MIX1", NULL, "WSA_RX_MIX1_CLK"},
+
+	{"WSA_RX0 INP0", "RX0", "WSA RX0"},
+	{"WSA_RX0 INP0", "RX1", "WSA RX1"},
+	{"WSA_RX0 INP0", "RX_MIX0", "WSA RX_MIX0"},
+	{"WSA_RX0 INP0", "RX_MIX1", "WSA RX_MIX1"},
+	{"WSA_RX0 INP0", "DEC0", "WSA_TX DEC0_INP"},
+	{"WSA_RX0 INP0", "DEC1", "WSA_TX DEC1_INP"},
+	{"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP0"},
+
+	{"WSA_RX0 INP1", "RX0", "WSA RX0"},
+	{"WSA_RX0 INP1", "RX1", "WSA RX1"},
+	{"WSA_RX0 INP1", "RX_MIX0", "WSA RX_MIX0"},
+	{"WSA_RX0 INP1", "RX_MIX1", "WSA RX_MIX1"},
+	{"WSA_RX0 INP1", "DEC0", "WSA_TX DEC0_INP"},
+	{"WSA_RX0 INP1", "DEC1", "WSA_TX DEC1_INP"},
+	{"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP1"},
+
+	{"WSA_RX0 INP2", "RX0", "WSA RX0"},
+	{"WSA_RX0 INP2", "RX1", "WSA RX1"},
+	{"WSA_RX0 INP2", "RX_MIX0", "WSA RX_MIX0"},
+	{"WSA_RX0 INP2", "RX_MIX1", "WSA RX_MIX1"},
+	{"WSA_RX0 INP2", "DEC0", "WSA_TX DEC0_INP"},
+	{"WSA_RX0 INP2", "DEC1", "WSA_TX DEC1_INP"},
+	{"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP2"},
+
+	{"WSA_RX0 MIX INP", "RX0", "WSA RX0"},
+	{"WSA_RX0 MIX INP", "RX1", "WSA RX1"},
+	{"WSA_RX0 MIX INP", "RX_MIX0", "WSA RX_MIX0"},
+	{"WSA_RX0 MIX INP", "RX_MIX1", "WSA RX_MIX1"},
+	{"WSA_RX INT0 SEC MIX", NULL, "WSA_RX0 MIX INP"},
+
+	{"WSA_RX INT0 SEC MIX", NULL, "WSA_RX INT0 MIX"},
+	{"WSA_RX INT0 INTERP", NULL, "WSA_RX INT0 SEC MIX"},
+	{"WSA_RX0 INT0 SIDETONE MIX", "SRC0", "WSA SRC0_INP"},
+	{"WSA_RX INT0 INTERP", NULL, "WSA_RX0 INT0 SIDETONE MIX"},
+	{"WSA_RX INT0 CHAIN", NULL, "WSA_RX INT0 INTERP"},
+
+	{"WSA_SPK1 OUT", NULL, "WSA_RX INT0 CHAIN"},
+	{"WSA_SPK1 OUT", NULL, "WSA_MCLK"},
+
+	{"WSA_RX1 INP0", "RX0", "WSA RX0"},
+	{"WSA_RX1 INP0", "RX1", "WSA RX1"},
+	{"WSA_RX1 INP0", "RX_MIX0", "WSA RX_MIX0"},
+	{"WSA_RX1 INP0", "RX_MIX1", "WSA RX_MIX1"},
+	{"WSA_RX1 INP0", "DEC0", "WSA_TX DEC0_INP"},
+	{"WSA_RX1 INP0", "DEC1", "WSA_TX DEC1_INP"},
+	{"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP0"},
+
+	{"WSA_RX1 INP1", "RX0", "WSA RX0"},
+	{"WSA_RX1 INP1", "RX1", "WSA RX1"},
+	{"WSA_RX1 INP1", "RX_MIX0", "WSA RX_MIX0"},
+	{"WSA_RX1 INP1", "RX_MIX1", "WSA RX_MIX1"},
+	{"WSA_RX1 INP1", "DEC0", "WSA_TX DEC0_INP"},
+	{"WSA_RX1 INP1", "DEC1", "WSA_TX DEC1_INP"},
+	{"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP1"},
+
+	{"WSA_RX1 INP2", "RX0", "WSA RX0"},
+	{"WSA_RX1 INP2", "RX1", "WSA RX1"},
+	{"WSA_RX1 INP2", "RX_MIX0", "WSA RX_MIX0"},
+	{"WSA_RX1 INP2", "RX_MIX1", "WSA RX_MIX1"},
+	{"WSA_RX1 INP2", "DEC0", "WSA_TX DEC0_INP"},
+	{"WSA_RX1 INP2", "DEC1", "WSA_TX DEC1_INP"},
+	{"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP2"},
+
+	{"WSA_RX1 MIX INP", "RX0", "WSA RX0"},
+	{"WSA_RX1 MIX INP", "RX1", "WSA RX1"},
+	{"WSA_RX1 MIX INP", "RX_MIX0", "WSA RX_MIX0"},
+	{"WSA_RX1 MIX INP", "RX_MIX1", "WSA RX_MIX1"},
+	{"WSA_RX INT1 SEC MIX", NULL, "WSA_RX1 MIX INP"},
+
+	{"WSA_RX INT1 SEC MIX", NULL, "WSA_RX INT1 MIX"},
+	{"WSA_RX INT1 INTERP", NULL, "WSA_RX INT1 SEC MIX"},
+
+	{"WSA_RX INT1 CHAIN", NULL, "WSA_RX INT1 INTERP"},
+	{"WSA_SPK2 OUT", NULL, "WSA_RX INT1 CHAIN"},
+	{"WSA_SPK2 OUT", NULL, "WSA_MCLK"},
+};
+
+static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
+{
+	struct regmap *regmap = wsa->regmap;
+
+	if (enable) {
+		wsa_macro_mclk_enable(wsa, true);
+
+		/* reset swr ip */
+		if (wsa->reset_swr)
+			regmap_update_bits(regmap,
+					   CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+					   CDC_WSA_SWR_RST_EN_MASK,
+					   CDC_WSA_SWR_RST_ENABLE);
+
+		regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+				   CDC_WSA_SWR_CLK_EN_MASK,
+				   CDC_WSA_SWR_CLK_ENABLE);
+
+		/* Bring out of reset */
+		if (wsa->reset_swr)
+			regmap_update_bits(regmap,
+					   CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+					   CDC_WSA_SWR_RST_EN_MASK,
+					   CDC_WSA_SWR_RST_DISABLE);
+		wsa->reset_swr = false;
+	} else {
+		regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+				   CDC_WSA_SWR_CLK_EN_MASK, 0);
+		wsa_macro_mclk_enable(wsa, false);
+	}
+
+	return 0;
+}
+
+static int wsa_macro_component_probe(struct snd_soc_component *comp)
+{
+	struct wsa_macro *wsa = snd_soc_component_get_drvdata(comp);
+
+	snd_soc_component_init_regmap(comp, wsa->regmap);
+
+	wsa->spkr_gain_offset = WSA_MACRO_GAIN_OFFSET_M1P5_DB;
+
+	/* set SPKR rate to FS_2P4_3P072 */
+	snd_soc_component_update_bits(comp, CDC_WSA_RX0_RX_PATH_CFG1,
+				CDC_WSA_RX_PATH_SPKR_RATE_MASK,
+				CDC_WSA_RX_PATH_SPKR_RATE_FS_2P4_3P072);
+
+	snd_soc_component_update_bits(comp, CDC_WSA_RX1_RX_PATH_CFG1,
+				CDC_WSA_RX_PATH_SPKR_RATE_MASK,
+				CDC_WSA_RX_PATH_SPKR_RATE_FS_2P4_3P072);
+
+	wsa_macro_set_spkr_mode(comp, WSA_MACRO_SPKR_MODE_1);
+
+	return 0;
+}
+
+static int swclk_gate_enable(struct clk_hw *hw)
+{
+	return wsa_swrm_clock(to_wsa_macro(hw), true);
+}
+
+static void swclk_gate_disable(struct clk_hw *hw)
+{
+	wsa_swrm_clock(to_wsa_macro(hw), false);
+}
+
+static int swclk_gate_is_enabled(struct clk_hw *hw)
+{
+	struct wsa_macro *wsa = to_wsa_macro(hw);
+	int ret, val;
+
+	regmap_read(wsa->regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, &val);
+	ret = val & BIT(0);
+
+	return ret;
+}
+
+static unsigned long swclk_recalc_rate(struct clk_hw *hw,
+				       unsigned long parent_rate)
+{
+	return parent_rate / 2;
+}
+
+static const struct clk_ops swclk_gate_ops = {
+	.prepare = swclk_gate_enable,
+	.unprepare = swclk_gate_disable,
+	.is_enabled = swclk_gate_is_enabled,
+	.recalc_rate = swclk_recalc_rate,
+};
+
+static struct clk *wsa_macro_register_mclk_output(struct wsa_macro *wsa)
+{
+	struct device *dev = wsa->dev;
+	struct device_node *np = dev->of_node;
+	const char *parent_clk_name;
+	const char *clk_name = "mclk";
+	struct clk_hw *hw;
+	struct clk_init_data init;
+	int ret;
+
+	parent_clk_name = __clk_get_name(wsa->clks[2].clk);
+
+	init.name = clk_name;
+	init.ops = &swclk_gate_ops;
+	init.flags = 0;
+	init.parent_names = &parent_clk_name;
+	init.num_parents = 1;
+	wsa->hw.init = &init;
+	hw = &wsa->hw;
+	ret = clk_hw_register(wsa->dev, hw);
+	if (ret)
+		return ERR_PTR(ret);
+
+	of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+
+	return NULL;
+}
+
+static const struct snd_soc_component_driver wsa_macro_component_drv = {
+	.name = "WSA MACRO",
+	.probe = wsa_macro_component_probe,
+	.controls = wsa_macro_snd_controls,
+	.num_controls = ARRAY_SIZE(wsa_macro_snd_controls),
+	.dapm_widgets = wsa_macro_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets),
+	.dapm_routes = wsa_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(wsa_audio_map),
+};
+
+static int wsa_macro_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct wsa_macro *wsa;
+	void __iomem *base;
+	int ret;
+
+	wsa = devm_kzalloc(dev, sizeof(*wsa), GFP_KERNEL);
+	if (!wsa)
+		return -ENOMEM;
+
+	wsa->clks[0].id = "macro";
+	wsa->clks[1].id = "dcodec";
+	wsa->clks[2].id = "mclk";
+	wsa->clks[3].id = "npl";
+	wsa->clks[4].id = "fsgen";
+
+	ret = devm_clk_bulk_get(dev, WSA_NUM_CLKS_MAX, wsa->clks);
+	if (ret) {
+		dev_err(dev, "Error getting WSA Clocks (%d)\n", ret);
+		return ret;
+	}
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	wsa->regmap = devm_regmap_init_mmio(dev, base, &wsa_regmap_config);
+
+	dev_set_drvdata(dev, wsa);
+
+	wsa->reset_swr = true;
+	wsa->dev = dev;
+
+	/* set MCLK and NPL rates */
+	clk_set_rate(wsa->clks[2].clk, WSA_MACRO_MCLK_FREQ);
+	clk_set_rate(wsa->clks[3].clk, WSA_MACRO_MCLK_FREQ);
+
+	ret = clk_bulk_prepare_enable(WSA_NUM_CLKS_MAX, wsa->clks);
+	if (ret)
+		return ret;
+
+	wsa_macro_register_mclk_output(wsa);
+
+	ret = devm_snd_soc_register_component(dev, &wsa_macro_component_drv,
+					      wsa_macro_dai,
+					      ARRAY_SIZE(wsa_macro_dai));
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks);
+
+	return ret;
+
+}
+
+static int wsa_macro_remove(struct platform_device *pdev)
+{
+	struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev);
+
+	of_clk_del_provider(pdev->dev.of_node);
+
+	clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks);
+
+	return 0;
+}
+
+static const struct of_device_id wsa_macro_dt_match[] = {
+	{.compatible = "qcom,sm8250-lpass-wsa-macro"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, wsa_macro_dt_match);
+
+static struct platform_driver wsa_macro_driver = {
+	.driver = {
+		.name = "wsa_macro",
+		.of_match_table = wsa_macro_dt_match,
+	},
+	.probe = wsa_macro_probe,
+	.remove = wsa_macro_remove,
+};
+
+module_platform_driver(wsa_macro_driver);
+MODULE_DESCRIPTION("WSA macro driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lpass-wsa-macro.h b/sound/soc/codecs/lpass-wsa-macro.h
new file mode 100644
index 000000000000..d3d62b3f6500
--- /dev/null
+++ b/sound/soc/codecs/lpass-wsa-macro.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __LPASS_WSA_MACRO_H__
+#define __LPASS_WSA_MACRO_H__
+
+/*
+ * Selects compander and smart boost settings
+ * for a given speaker mode
+ */
+enum {
+	WSA_MACRO_SPKR_MODE_DEFAULT,
+	WSA_MACRO_SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */
+};
+
+int wsa_macro_set_spkr_mode(struct snd_soc_component *component, int mode);
+
+#endif /* __LPASS_WSA_MACRO_H__ */
diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c
index 680f31a6493a..f4ed7e04673f 100644
--- a/sound/soc/codecs/madera.c
+++ b/sound/soc/codecs/madera.c
@@ -3019,11 +3019,11 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream,
 		tar = 2 << MADERA_AIF1_RATE_SHIFT;
 		break;
 	case MADERA_CLK_ASYNCCLK_1:
-		reg = MADERA_ASYNC_SAMPLE_RATE_1,
+		reg = MADERA_ASYNC_SAMPLE_RATE_1;
 		tar = 8 << MADERA_AIF1_RATE_SHIFT;
 		break;
 	case MADERA_CLK_ASYNCCLK_2:
-		reg = MADERA_ASYNC_SAMPLE_RATE_2,
+		reg = MADERA_ASYNC_SAMPLE_RATE_2;
 		tar = 9 << MADERA_AIF1_RATE_SHIFT;
 		break;
 	default:
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 945a79e4f3eb..06276ff5f8a3 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2668,12 +2668,14 @@ static const struct i2c_device_id max98090_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max98090_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id max98090_of_match[] = {
 	{ .compatible = "maxim,max98090", },
 	{ .compatible = "maxim,max98091", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, max98090_of_match);
+#endif
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id max98090_acpi_match[] = {
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 9bdc6392382a..736cd70be725 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -2148,11 +2148,13 @@ static const struct i2c_device_id max98095_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max98095_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id max98095_of_match[] = {
 	{ .compatible = "maxim,max98095", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, max98095_of_match);
+#endif
 
 static struct i2c_driver max98095_i2c_driver = {
 	.driver = {
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
index dfee05f985bd..e424779db02b 100644
--- a/sound/soc/codecs/max98371.c
+++ b/sound/soc/codecs/max98371.c
@@ -408,16 +408,17 @@ static const struct i2c_device_id max98371_i2c_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, max98371_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id max98371_of_match[] = {
 	{ .compatible = "maxim,max98371", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, max98371_of_match);
+#endif
 
 static struct i2c_driver max98371_i2c_driver = {
 	.driver = {
 		.name = "max98371",
-		.pm = NULL,
 		.of_match_table = of_match_ptr(max98371_of_match),
 	},
 	.probe  = max98371_i2c_probe,
diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index fa589d834f9a..ec2e79c57357 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -247,7 +247,7 @@ static __maybe_unused int max98373_suspend(struct device *dev)
 	struct max98373_priv *max98373 = dev_get_drvdata(dev);
 
 	regcache_cache_only(max98373->regmap, true);
-	regcache_mark_dirty(max98373->regmap);
+
 	return 0;
 }
 
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index ff5cc9bbec29..bb736c44e68a 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -784,6 +784,7 @@ static int max98390_dsm_init(struct snd_soc_component *component)
 	if (fw->size < MAX98390_DSM_PARAM_MIN_SIZE) {
 		dev_err(component->dev,
 			"param fw is invalid.\n");
+		ret = -EINVAL;
 		goto err_alloc;
 	}
 	dsm_param = (char *)fw->data;
@@ -794,6 +795,7 @@ static int max98390_dsm_init(struct snd_soc_component *component)
 		fw->size < param_size + MAX98390_DSM_PAYLOAD_OFFSET) {
 		dev_err(component->dev,
 			"param fw is invalid.\n");
+		ret = -EINVAL;
 		goto err_alloc;
 	}
 	regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80);
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index aef2746bfb94..512e6f2513d3 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -649,11 +649,13 @@ static const struct i2c_device_id max9867_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max9867_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id max9867_of_match[] = {
 	{ .compatible = "maxim,max9867", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, max9867_of_match);
+#endif
 
 static struct i2c_driver max9867_i2c_driver = {
 	.driver = {
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
index b3e1a54fff88..ddaccc24b0cb 100644
--- a/sound/soc/codecs/max98925.c
+++ b/sound/soc/codecs/max98925.c
@@ -627,17 +627,18 @@ static const struct i2c_device_id max98925_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max98925_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id max98925_of_match[] = {
 	{ .compatible = "maxim,max98925", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, max98925_of_match);
+#endif
 
 static struct i2c_driver max98925_i2c_driver = {
 	.driver = {
 		.name = "max98925",
 		.of_match_table = of_match_ptr(max98925_of_match),
-		.pm = NULL,
 	},
 	.probe  = max98925_i2c_probe,
 	.id_table = max98925_i2c_id,
diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c
index c4dfa8ab1d49..f286e572263e 100644
--- a/sound/soc/codecs/max98926.c
+++ b/sound/soc/codecs/max98926.c
@@ -571,17 +571,18 @@ static const struct i2c_device_id max98926_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max98926_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id max98926_of_match[] = {
 	{ .compatible = "maxim,max98926", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, max98926_of_match);
+#endif
 
 static struct i2c_driver max98926_i2c_driver = {
 	.driver = {
 		.name = "max98926",
 		.of_match_table = of_match_ptr(max98926_of_match),
-		.pm = NULL,
 	},
 	.probe	= max98926_i2c_probe,
 	.id_table = max98926_i2c_id,
diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c
index 81aafb553bdd..6de0d744fa9e 100644
--- a/sound/soc/codecs/mt6359.c
+++ b/sound/soc/codecs/mt6359.c
@@ -68,6 +68,38 @@ static void mt6359_reset_capture_gpio(struct mt6359_priv *priv)
 			   0x3 << 0, 0x0);
 }
 
+/* use only when doing mtkaif calibraiton at the boot time */
+static void mt6359_set_dcxo(struct mt6359_priv *priv, bool enable)
+{
+	regmap_update_bits(priv->regmap, MT6359_DCXO_CW12,
+			   0x1 << RG_XO_AUDIO_EN_M_SFT,
+			   (enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT);
+}
+
+/* use only when doing mtkaif calibraiton at the boot time */
+static void mt6359_set_clksq(struct mt6359_priv *priv, bool enable)
+{
+	/* Enable/disable CLKSQ 26MHz */
+	regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON23,
+			   RG_CLKSQ_EN_MASK_SFT,
+			   (enable ? 1 : 0) << RG_CLKSQ_EN_SFT);
+}
+
+/* use only when doing mtkaif calibraiton at the boot time */
+static void mt6359_set_aud_global_bias(struct mt6359_priv *priv, bool enable)
+{
+	regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON13,
+			   RG_AUDGLB_PWRDN_VA32_MASK_SFT,
+			   (enable ? 0 : 1) << RG_AUDGLB_PWRDN_VA32_SFT);
+}
+
+/* use only when doing mtkaif calibraiton at the boot time */
+static void mt6359_set_topck(struct mt6359_priv *priv, bool enable)
+{
+	regmap_update_bits(priv->regmap, MT6359_AUD_TOP_CKPDN_CON0,
+			   0x0066, enable ? 0x0 : 0x66);
+}
+
 static void mt6359_set_decoder_clk(struct mt6359_priv *priv, bool enable)
 {
 	regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON13,
@@ -122,6 +154,84 @@ static void mt6359_mtkaif_tx_disable(struct mt6359_priv *priv)
 			   0xff00, 0x3000);
 }
 
+void mt6359_set_mtkaif_protocol(struct snd_soc_component *cmpnt,
+				int mtkaif_protocol)
+{
+	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	priv->mtkaif_protocol = mtkaif_protocol;
+}
+EXPORT_SYMBOL_GPL(mt6359_set_mtkaif_protocol);
+
+void mt6359_mtkaif_calibration_enable(struct snd_soc_component *cmpnt)
+{
+	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	mt6359_set_playback_gpio(priv);
+	mt6359_set_capture_gpio(priv);
+	mt6359_mtkaif_tx_enable(priv);
+
+	mt6359_set_dcxo(priv, true);
+	mt6359_set_aud_global_bias(priv, true);
+	mt6359_set_clksq(priv, true);
+	mt6359_set_topck(priv, true);
+
+	/* set dat_miso_loopback on */
+	regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG,
+			   RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT,
+			   1 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT);
+	regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG,
+			   RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT,
+			   1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT);
+	regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG1,
+			   RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_MASK_SFT,
+			   1 << RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_SFT);
+}
+EXPORT_SYMBOL_GPL(mt6359_mtkaif_calibration_enable);
+
+void mt6359_mtkaif_calibration_disable(struct snd_soc_component *cmpnt)
+{
+	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	/* set dat_miso_loopback off */
+	regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG,
+			   RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT,
+			   0 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT);
+	regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG,
+			   RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT,
+			   0 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT);
+	regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG1,
+			   RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_MASK_SFT,
+			   0 << RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_SFT);
+
+	mt6359_set_topck(priv, false);
+	mt6359_set_clksq(priv, false);
+	mt6359_set_aud_global_bias(priv, false);
+	mt6359_set_dcxo(priv, false);
+
+	mt6359_mtkaif_tx_disable(priv);
+	mt6359_reset_playback_gpio(priv);
+	mt6359_reset_capture_gpio(priv);
+}
+EXPORT_SYMBOL_GPL(mt6359_mtkaif_calibration_disable);
+
+void mt6359_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt,
+					 int phase_1, int phase_2, int phase_3)
+{
+	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG,
+			   RG_AUD_PAD_TOP_PHASE_MODE_MASK_SFT,
+			   phase_1 << RG_AUD_PAD_TOP_PHASE_MODE_SFT);
+	regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG,
+			   RG_AUD_PAD_TOP_PHASE_MODE2_MASK_SFT,
+			   phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT);
+	regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG1,
+			   RG_AUD_PAD_TOP_PHASE_MODE3_MASK_SFT,
+			   phase_3 << RG_AUD_PAD_TOP_PHASE_MODE3_SFT);
+}
+EXPORT_SYMBOL_GPL(mt6359_set_mtkaif_calibration_phase);
+
 static void zcd_disable(struct mt6359_priv *priv)
 {
 	regmap_write(priv->regmap, MT6359_ZCD_CON0, 0x0000);
@@ -1833,9 +1943,6 @@ static const struct snd_soc_dapm_widget mt6359_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF,
 			      MT6359_DCXO_CW12,
 			      RG_XO_AUDIO_EN_M_SFT, 0, NULL, 0),
-	SND_SOC_DAPM_SUPPLY_S("LDO_VAUD18", SUPPLY_SEQ_LDO_VAUD18,
-			      MT6359_LDO_VAUD18_CON0,
-			      RG_LDO_VAUD18_EN_SFT, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB,
 			      MT6359_AUDDEC_ANA_CON13,
 			      RG_AUDGLB_PWRDN_VA32_SFT, 1, NULL, 0),
@@ -1855,6 +1962,8 @@ static const struct snd_soc_dapm_widget mt6359_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY_S("AUDIF_CK", SUPPLY_SEQ_TOP_CK,
 			      MT6359_AUD_TOP_CKPDN_CON0,
 			      RG_AUDIF_CK_PDN_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("vaud18", 0, 0),
+
 	/* Digital Clock */
 	SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_AFE_CTL", SUPPLY_SEQ_AUD_TOP_LAST,
 			      MT6359_AUDIO_TOP_CON0,
@@ -2204,7 +2313,7 @@ static int mt_dcc_clk_connect(struct snd_soc_dapm_widget *source,
 static const struct snd_soc_dapm_route mt6359_dapm_routes[] = {
 	/* Capture */
 	{"AIFTX_Supply", NULL, "CLK_BUF"},
-	{"AIFTX_Supply", NULL, "LDO_VAUD18"},
+	{"AIFTX_Supply", NULL, "vaud18"},
 	{"AIFTX_Supply", NULL, "AUDGLB"},
 	{"AIFTX_Supply", NULL, "CLKSQ Audio"},
 	{"AIFTX_Supply", NULL, "AUD_CK"},
@@ -2332,7 +2441,7 @@ static const struct snd_soc_dapm_route mt6359_dapm_routes[] = {
 
 	/* DL Supply */
 	{"DL Power Supply", NULL, "CLK_BUF"},
-	{"DL Power Supply", NULL, "LDO_VAUD18"},
+	{"DL Power Supply", NULL, "vaud18"},
 	{"DL Power Supply", NULL, "AUDGLB"},
 	{"DL Power Supply", NULL, "CLKSQ Audio"},
 	{"DL Power Supply", NULL, "AUDNCP_CK"},
@@ -2697,20 +2806,6 @@ static int mt6359_platform_driver_probe(struct platform_device *pdev)
 	dev_set_drvdata(&pdev->dev, priv);
 	priv->dev = &pdev->dev;
 
-	priv->avdd_reg = devm_regulator_get(&pdev->dev, "vaud18");
-	if (IS_ERR(priv->avdd_reg)) {
-		dev_err(&pdev->dev, "%s(), have no vaud18 supply: %ld",
-			__func__, PTR_ERR(priv->avdd_reg));
-		return PTR_ERR(priv->avdd_reg);
-	}
-
-	ret = regulator_enable(priv->avdd_reg);
-	if (ret) {
-		dev_err(&pdev->dev, "%s(), failed to enable regulator!\n",
-			__func__);
-		return ret;
-	}
-
 	ret = mt6359_parse_dt(priv);
 	if (ret) {
 		dev_warn(&pdev->dev, "%s() failed to parse dts\n", __func__);
@@ -2723,30 +2818,11 @@ static int mt6359_platform_driver_probe(struct platform_device *pdev)
 					       ARRAY_SIZE(mt6359_dai_driver));
 }
 
-static int mt6359_platform_driver_remove(struct platform_device *pdev)
-{
-	struct mt6359_priv *priv = dev_get_drvdata(&pdev->dev);
-	int ret;
-
-	dev_dbg(&pdev->dev, "%s(), dev name %s\n",
-		__func__, dev_name(&pdev->dev));
-
-	ret = regulator_disable(priv->avdd_reg);
-	if (ret) {
-		dev_err(&pdev->dev, "%s(), failed to disable regulator!\n",
-			__func__);
-		return ret;
-	}
-
-	return 0;
-}
-
 static struct platform_driver mt6359_platform_driver = {
 	.driver = {
 		.name = "mt6359-sound",
 	},
 	.probe = mt6359_platform_driver_probe,
-	.remove = mt6359_platform_driver_remove,
 };
 
 module_platform_driver(mt6359_platform_driver)
diff --git a/sound/soc/codecs/mt6359.h b/sound/soc/codecs/mt6359.h
index 3792e534a91b..35f806b7396d 100644
--- a/sound/soc/codecs/mt6359.h
+++ b/sound/soc/codecs/mt6359.h
@@ -135,11 +135,6 @@
 /* MT6359_DCXO_CW12 */
 #define RG_XO_AUDIO_EN_M_SFT				13
 
-/* LDO_VAUD18_CON0 */
-#define RG_LDO_VAUD18_EN_SFT				0
-#define RG_LDO_VAUD18_EN_MASK				0x1
-#define RG_LDO_VAUD18_EN_MASK_SFT			(0x1 << 0)
-
 /* AUD_TOP_CKPDN_CON0 */
 #define RG_VOW13M_CK_PDN_SFT				13
 #define RG_VOW13M_CK_PDN_MASK				0x1
@@ -2132,7 +2127,6 @@
 
 #define MT6359_DCXO_CW11				0x7a6
 #define MT6359_DCXO_CW12				0x7a8
-#define MT6359_LDO_VAUD18_CON0				0x1c98
 
 #define MT6359_GPIO_MODE0				0xcc
 #define MT6359_GPIO_MODE0_SET				0xce
@@ -2469,7 +2463,6 @@ enum {
 enum {
 	/* common */
 	SUPPLY_SEQ_CLK_BUF,
-	SUPPLY_SEQ_LDO_VAUD18,
 	SUPPLY_SEQ_AUD_GLB,
 	SUPPLY_SEQ_HP_PULL_DOWN,
 	SUPPLY_SEQ_CLKSQ,
@@ -2629,7 +2622,6 @@ struct mt6359_priv {
 	int hp_gain_ctl;
 	int hp_hifi_mode;
 	int mtkaif_protocol;
-	struct regulator *avdd_reg;
 };
 
 #define CODEC_MT6359_NAME "mtk-codec-mt6359"
@@ -2637,4 +2629,11 @@ struct mt6359_priv {
 			   (type) == MIC_TYPE_MUX_DCC_ECM_DIFF || \
 			   (type) == MIC_TYPE_MUX_DCC_ECM_SINGLE)
 
+void mt6359_set_mtkaif_protocol(struct snd_soc_component *cmpnt,
+				int mtkaif_protocol);
+void mt6359_mtkaif_calibration_enable(struct snd_soc_component *cmpnt);
+void mt6359_mtkaif_calibration_disable(struct snd_soc_component *cmpnt);
+void mt6359_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt,
+					 int phase_1, int phase_2, int phase_3);
+
 #endif/* end _MT6359_H_ */
diff --git a/sound/soc/codecs/nau8315.c b/sound/soc/codecs/nau8315.c
new file mode 100644
index 000000000000..2b66e3f7a8b7
--- /dev/null
+++ b/sound/soc/codecs/nau8315.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// nau8315.c  --  NAU8315 ALSA SoC Audio Amplifier Driver
+//
+// Copyright 2020 Nuvoton Technology Crop.
+//
+// Author: David Lin <ctlin0@nuvoton.com>
+//
+// Based on MAX98357A.c
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+
+struct nau8315_priv {
+	struct gpio_desc *enable;
+	int enpin_switch;
+};
+
+static int nau8315_daiops_trigger(struct snd_pcm_substream *substream,
+		int cmd, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8315_priv *nau8315 =
+		snd_soc_component_get_drvdata(component);
+
+	if (!nau8315->enable)
+		return 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (nau8315->enpin_switch) {
+			gpiod_set_value(nau8315->enable, 1);
+			dev_dbg(component->dev, "set enable to 1");
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		gpiod_set_value(nau8315->enable, 0);
+		dev_dbg(component->dev, "set enable to 0");
+		break;
+	}
+
+	return 0;
+}
+
+static int nau8315_enpin_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	struct nau8315_priv *nau8315 =
+		snd_soc_component_get_drvdata(component);
+
+	if (event & SND_SOC_DAPM_PRE_PMU)
+		nau8315->enpin_switch = 1;
+	else if (event & SND_SOC_DAPM_POST_PMD)
+		nau8315->enpin_switch = 0;
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget nau8315_dapm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("Speaker"),
+	SND_SOC_DAPM_OUT_DRV_E("EN_Pin", SND_SOC_NOPM, 0, 0, NULL, 0,
+			nau8315_enpin_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route nau8315_dapm_routes[] = {
+	{"EN_Pin", NULL, "HiFi Playback"},
+	{"Speaker", NULL, "EN_Pin"},
+};
+
+static const struct snd_soc_component_driver nau8315_component_driver = {
+	.dapm_widgets		= nau8315_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(nau8315_dapm_widgets),
+	.dapm_routes		= nau8315_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(nau8315_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct snd_soc_dai_ops nau8315_dai_ops = {
+	.trigger	= nau8315_daiops_trigger,
+};
+
+#define NAU8315_RATES SNDRV_PCM_RATE_8000_96000
+#define NAU8315_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE)
+
+static struct snd_soc_dai_driver nau8315_dai_driver = {
+	.name = "nau8315-hifi",
+	.playback = {
+		.stream_name	= "HiFi Playback",
+		.formats	= NAU8315_FORMATS,
+		.rates		= NAU8315_RATES,
+		.channels_min	= 1,
+		.channels_max	= 2,
+	},
+	.ops    = &nau8315_dai_ops,
+};
+
+static int nau8315_platform_probe(struct platform_device *pdev)
+{
+	struct nau8315_priv *nau8315;
+
+	nau8315 = devm_kzalloc(&pdev->dev, sizeof(*nau8315), GFP_KERNEL);
+	if (!nau8315)
+		return -ENOMEM;
+
+	nau8315->enable = devm_gpiod_get_optional(&pdev->dev,
+				"enable", GPIOD_OUT_LOW);
+	if (IS_ERR(nau8315->enable))
+		return PTR_ERR(nau8315->enable);
+
+	dev_set_drvdata(&pdev->dev, nau8315);
+
+	return devm_snd_soc_register_component(&pdev->dev,
+			&nau8315_component_driver,
+			&nau8315_dai_driver, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8315_device_id[] = {
+	{ .compatible = "nuvoton,nau8315" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, nau8315_device_id);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id nau8315_acpi_match[] = {
+	{ "NVTN2010", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, nau8315_acpi_match);
+#endif
+
+static struct platform_driver nau8315_platform_driver = {
+	.driver = {
+		.name = "nau8315",
+		.of_match_table = of_match_ptr(nau8315_device_id),
+		.acpi_match_table = ACPI_PTR(nau8315_acpi_match),
+	},
+	.probe	= nau8315_platform_probe,
+};
+module_platform_driver(nau8315_platform_driver);
+
+MODULE_DESCRIPTION("ASoC NAU8315 Mono Class-D Amplifier Driver");
+MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm1789-i2c.c b/sound/soc/codecs/pcm1789-i2c.c
index 327ec584f240..7a6be45f8149 100644
--- a/sound/soc/codecs/pcm1789-i2c.c
+++ b/sound/soc/codecs/pcm1789-i2c.c
@@ -33,11 +33,13 @@ static int pcm1789_i2c_remove(struct i2c_client *client)
 	return pcm1789_common_exit(&client->dev);
 }
 
+#ifdef CONFIG_OF
 static const struct of_device_id pcm1789_of_match[] = {
 	{ .compatible = "ti,pcm1789", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, pcm1789_of_match);
+#endif
 
 static const struct i2c_device_id pcm1789_i2c_ids[] = {
 	{ "pcm1789", 0 },
diff --git a/sound/soc/codecs/pcm179x-i2c.c b/sound/soc/codecs/pcm179x-i2c.c
index 36e01678bef4..34a3d596f288 100644
--- a/sound/soc/codecs/pcm179x-i2c.c
+++ b/sound/soc/codecs/pcm179x-i2c.c
@@ -30,11 +30,13 @@ static int pcm179x_i2c_probe(struct i2c_client *client,
 	return pcm179x_common_init(&client->dev, regmap);
 }
 
+#ifdef CONFIG_OF
 static const struct of_device_id pcm179x_of_match[] = {
 	{ .compatible = "ti,pcm1792a", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, pcm179x_of_match);
+#endif
 
 static const struct i2c_device_id pcm179x_i2c_ids[] = {
 	{ "pcm179x", 0 },
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 8153d3d01654..4dc844f3c1fc 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -1168,8 +1168,6 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 	int alen;
 	int gpio;
-	int clock_output;
-	int master_mode;
 	int ret;
 
 	dev_dbg(component->dev, "hw_params %u Hz, %u channels\n",
@@ -1195,19 +1193,15 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBS_CFS:
-		ret = regmap_update_bits(pcm512x->regmap,
-					 PCM512x_BCLK_LRCLK_CFG,
-					 PCM512x_BCKP
-					 | PCM512x_BCKO | PCM512x_LRKO,
-					 0);
-		if (ret != 0) {
-			dev_err(component->dev,
-				"Failed to enable slave mode: %d\n", ret);
-			return ret;
-		}
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
+				 PCM512x_ALEN, alen);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set frame size: %d\n", ret);
+		return ret;
+	}
 
+	if ((pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
+	    SND_SOC_DAIFMT_CBS_CFS) {
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
 					 PCM512x_DCAS, 0);
 		if (ret != 0) {
@@ -1216,24 +1210,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 				ret);
 			return ret;
 		}
-		return 0;
-	case SND_SOC_DAIFMT_CBM_CFM:
-		clock_output = PCM512x_BCKO | PCM512x_LRKO;
-		master_mode = PCM512x_RLRK | PCM512x_RBCK;
-		break;
-	case SND_SOC_DAIFMT_CBM_CFS:
-		clock_output = PCM512x_BCKO;
-		master_mode = PCM512x_RBCK;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
-				 PCM512x_ALEN, alen);
-	if (ret != 0) {
-		dev_err(component->dev, "Failed to set frame size: %d\n", ret);
-		return ret;
+		goto skip_pll;
 	}
 
 	if (pcm512x->pll_out) {
@@ -1316,25 +1293,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 			dev_err(component->dev, "Failed to enable pll: %d\n", ret);
 			return ret;
 		}
-	}
 
-	ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG,
-				 PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
-				 clock_output);
-	if (ret != 0) {
-		dev_err(component->dev, "Failed to enable clock output: %d\n", ret);
-		return ret;
-	}
-
-	ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE,
-				 PCM512x_RLRK | PCM512x_RBCK,
-				 master_mode);
-	if (ret != 0) {
-		dev_err(component->dev, "Failed to enable master mode: %d\n", ret);
-		return ret;
-	}
-
-	if (pcm512x->pll_out) {
 		gpio = PCM512x_G1OE << (pcm512x->pll_out - 1);
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
 					 gpio, gpio);
@@ -1368,6 +1327,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 		return ret;
 	}
 
+skip_pll:
 	return 0;
 }
 
@@ -1375,6 +1335,80 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct snd_soc_component *component = dai->component;
 	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+	int afmt;
+	int offset = 0;
+	int clock_output;
+	int master_mode;
+	int ret;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		clock_output = 0;
+		master_mode = 0;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clock_output = PCM512x_BCKO | PCM512x_LRKO;
+		master_mode = PCM512x_RLRK | PCM512x_RBCK;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		clock_output = PCM512x_BCKO;
+		master_mode = PCM512x_RBCK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG,
+				 PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
+				 clock_output);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable clock output: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE,
+				 PCM512x_RLRK | PCM512x_RBCK,
+				 master_mode);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable master mode: %d\n", ret);
+		return ret;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		afmt = PCM512x_AFMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		afmt = PCM512x_AFMT_RTJ;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		afmt = PCM512x_AFMT_LTJ;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		offset = 1;
+		fallthrough;
+	case SND_SOC_DAIFMT_DSP_B:
+		afmt = PCM512x_AFMT_DSP;
+		break;
+	default:
+		dev_err(component->dev, "unsupported DAI format: 0x%x\n",
+			pcm512x->fmt);
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
+				 PCM512x_AFMT, afmt);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set data format: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_2,
+				 0xFF, offset);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set data offset: %d\n", ret);
+		return ret;
+	}
 
 	pcm512x->fmt = fmt;
 
diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c
index 940a2fa933ed..bfefefcc76d8 100644
--- a/sound/soc/codecs/rk3328_codec.c
+++ b/sound/soc/codecs/rk3328_codec.c
@@ -499,7 +499,7 @@ static int rk3328_platform_probe(struct platform_device *pdev)
 					       ARRAY_SIZE(rk3328_dai));
 }
 
-static const struct of_device_id rk3328_codec_of_match[] = {
+static const struct of_device_id rk3328_codec_of_match[] __maybe_unused = {
 		{ .compatible = "rockchip,rk3328-codec", },
 		{},
 };
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
index 3db07293c70b..32e6bcf763d1 100644
--- a/sound/soc/codecs/rt1015.c
+++ b/sound/soc/codecs/rt1015.c
@@ -497,18 +497,40 @@ static void rt1015_calibrate(struct rt1015_priv *rt1015)
 	snd_soc_dapm_mutex_lock(&component->dapm);
 	regcache_cache_bypass(regmap, true);
 
-	regmap_write(regmap, RT1015_PWR1, 0xd7df);
-	regmap_write(regmap, RT1015_PWR4, 0x00b2);
-	regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2008);
+	regmap_write(regmap, RT1015_PWR9, 0xAA60);
+	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0089);
+	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008A);
+	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008C);
+	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008D);
+	regmap_write(regmap, RT1015_PWR4, 0x80B2);
+	regmap_write(regmap, RT1015_CLASSD_SEQ, 0x5797);
+	regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2100);
+	regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0100);
+	regmap_write(regmap, RT1015_PWR5, 0x2175);
+	regmap_write(regmap, RT1015_MIXER1, 0x005D);
+	regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x00A1);
+	regmap_write(regmap, RT1015_CLSD_INTERNAL2, 0x12F7);
+	regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x1205);
+	msleep(200);
+	regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2000);
+	regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0180);
+	regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x00A1);
+	regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x0A05);
+	msleep(200);
+	regmap_write(regmap, RT1015_PWR4, 0x00B2);
+	regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2028);
 	regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0140);
-	regmap_write(regmap, RT1015_GAT_BOOST, 0x0efe);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000d);
-	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000e);
-	regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a00);
-	regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a01);
-	regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a05);
-	msleep(500);
-	regmap_write(regmap, RT1015_PWR1, 0x0);
+	regmap_write(regmap, RT1015_PWR5, 0x0175);
+	regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x1721);
+	regmap_write(regmap, RT1015_CLASSD_SEQ, 0x570E);
+	regmap_write(regmap, RT1015_MIXER1, 0x203D);
+	regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5A01);
+	regmap_write(regmap, RT1015_CLSD_INTERNAL2, 0x12FF);
+	regmap_write(regmap, RT1015_GAT_BOOST, 0x0eFE);
+	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008E);
+	regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0088);
+	regmap_write(regmap, RT1015_SYS_RST1, 0x05F5);
+	regmap_write(regmap, RT1015_SYS_RST2, 0x0b9a);
 
 	regcache_cache_bypass(regmap, false);
 	regcache_mark_dirty(regmap);
@@ -604,6 +626,8 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w,
 			snd_soc_component_write(component,
 				RT1015_SYS_RST1, 0x05f7);
 			snd_soc_component_write(component,
+				RT1015_SYS_RST2, 0x0b0a);
+			snd_soc_component_write(component,
 				RT1015_GAT_BOOST, 0xacfe);
 			snd_soc_component_write(component,
 				RT1015_PWR9, 0xaa00);
@@ -611,9 +635,13 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w,
 				RT1015_GAT_BOOST, 0xecfe);
 		} else {
 			snd_soc_component_write(component,
+				0x032d, 0xaa60);
+			snd_soc_component_write(component,
 				RT1015_SYS_RST1, 0x05f7);
 			snd_soc_component_write(component,
-				RT1015_PWR_STATE_CTRL, 0x026e);
+				RT1015_SYS_RST2, 0x0b0a);
+			snd_soc_component_write(component,
+				RT1015_PWR_STATE_CTRL, 0x008e);
 		}
 		break;
 
@@ -627,11 +655,17 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w,
 				RT1015_PWR9, 0xa800);
 			snd_soc_component_write(component,
 				RT1015_SYS_RST1, 0x05f5);
+			snd_soc_component_write(component,
+				RT1015_SYS_RST2, 0x0b9a);
 		} else {
 			snd_soc_component_write(component,
-				RT1015_PWR_STATE_CTRL, 0x0268);
+				0x032d, 0xaa60);
+			snd_soc_component_write(component,
+				RT1015_PWR_STATE_CTRL, 0x0088);
 			snd_soc_component_write(component,
 				RT1015_SYS_RST1, 0x05f5);
+			snd_soc_component_write(component,
+				RT1015_SYS_RST2, 0x0b9a);
 		}
 		rt1015->dac_is_used = 0;
 
@@ -664,38 +698,12 @@ static int rt1015_amp_drv_event(struct snd_soc_dapm_widget *w,
 }
 
 static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = {
-	SND_SOC_DAPM_SUPPLY("LDO2", RT1015_PWR1, RT1015_PWR_LDO2_BIT, 0,
-		NULL, 0),
-	SND_SOC_DAPM_SUPPLY("INT RC CLK", RT1015_PWR1, RT1015_PWR_INTCLK_BIT,
-		0, NULL, 0),
-	SND_SOC_DAPM_SUPPLY("ISENSE", RT1015_PWR1, RT1015_PWR_ISENSE_BIT, 0,
-		NULL, 0),
-	SND_SOC_DAPM_SUPPLY("VSENSE", RT1015_PWR1, RT1015_PWR_VSENSE_BIT, 0,
-		NULL, 0),
 	SND_SOC_DAPM_SUPPLY("PLL", RT1015_PWR1, RT1015_PWR_PLL_BIT, 0,
 		NULL, 0),
-	SND_SOC_DAPM_SUPPLY("BG1 BG2", RT1015_PWR1, RT1015_PWR_BG_1_2_BIT, 0,
-		NULL, 0),
-	SND_SOC_DAPM_SUPPLY("MBIAS BG", RT1015_PWR1, RT1015_PWR_MBIAS_BG_BIT, 0,
-		NULL, 0),
-	SND_SOC_DAPM_SUPPLY("VBAT", RT1015_PWR1, RT1015_PWR_VBAT_BIT, 0, NULL,
-		0),
-	SND_SOC_DAPM_SUPPLY("MBIAS", RT1015_PWR1, RT1015_PWR_MBIAS_BIT, 0,
-		NULL, 0),
-	SND_SOC_DAPM_SUPPLY("ADCV", RT1015_PWR1, RT1015_PWR_ADCV_BIT, 0, NULL,
-		0),
-	SND_SOC_DAPM_SUPPLY("MIXERV", RT1015_PWR1, RT1015_PWR_MIXERV_BIT, 0,
-		NULL, 0),
-	SND_SOC_DAPM_SUPPLY("SUMV", RT1015_PWR1, RT1015_PWR_SUMV_BIT, 0, NULL,
-		0),
-	SND_SOC_DAPM_SUPPLY("VREFLV", RT1015_PWR1, RT1015_PWR_VREFLV_BIT, 0,
-		NULL, 0),
-
 	SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0),
-	SND_SOC_DAPM_DAC_E("DAC", NULL, RT1015_PWR1, RT1015_PWR_DAC_BIT, 0,
+	SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0,
 		r1015_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
 		SND_SOC_DAPM_POST_PMD),
-
 	SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0,
 			rt1015_amp_drv_event, SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_OUTPUT("SPO"),
@@ -703,19 +711,7 @@ static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = {
 
 static const struct snd_soc_dapm_route rt1015_dapm_routes[] = {
 	{ "DAC", NULL, "AIFRX" },
-	{ "DAC", NULL, "LDO2" },
 	{ "DAC", NULL, "PLL", rt1015_is_sys_clk_from_pll},
-	{ "DAC", NULL, "INT RC CLK" },
-	{ "DAC", NULL, "ISENSE" },
-	{ "DAC", NULL, "VSENSE" },
-	{ "DAC", NULL, "BG1 BG2" },
-	{ "DAC", NULL, "MBIAS BG" },
-	{ "DAC", NULL, "VBAT" },
-	{ "DAC", NULL, "MBIAS" },
-	{ "DAC", NULL, "ADCV" },
-	{ "DAC", NULL, "MIXERV" },
-	{ "DAC", NULL, "SUMV" },
-	{ "DAC", NULL, "VREFLV" },
 	{ "Amp Drv", NULL, "DAC" },
 	{ "SPO", NULL, "Amp Drv" },
 };
@@ -950,6 +946,106 @@ static int rt1015_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 	return 0;
 }
 
+static int rt1015_set_tdm_slot(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int val = 0, rx_slotnum, tx_slotnum;
+	int ret = 0, first_bit;
+
+	switch (slots) {
+	case 2:
+		val |= RT1015_I2S_TX_2CH;
+		break;
+	case 4:
+		val |= RT1015_I2S_TX_4CH;
+		break;
+	case 6:
+		val |= RT1015_I2S_TX_6CH;
+		break;
+	case 8:
+		val |= RT1015_I2S_TX_8CH;
+		break;
+	default:
+		ret = -EINVAL;
+		goto _set_tdm_err_;
+	}
+
+	switch (slot_width) {
+	case 16:
+		val |= RT1015_I2S_CH_TX_LEN_16B;
+		break;
+	case 20:
+		val |= RT1015_I2S_CH_TX_LEN_20B;
+		break;
+	case 24:
+		val |= RT1015_I2S_CH_TX_LEN_24B;
+		break;
+	case 32:
+		val |= RT1015_I2S_CH_TX_LEN_32B;
+		break;
+	default:
+		ret = -EINVAL;
+		goto _set_tdm_err_;
+	}
+
+	/* Rx slot configuration */
+	rx_slotnum = hweight_long(rx_mask);
+	if (rx_slotnum != 1) {
+		ret = -EINVAL;
+		dev_err(component->dev, "too many rx slots or zero slot\n");
+		goto _set_tdm_err_;
+	}
+
+	/* This is an assumption that the system sends stereo audio to the amplifier typically.
+	 * And the stereo audio is placed in slot 0/2/4/6 as the starting slot.
+	 * The users could select the channel from L/R/L+R by "Mono LR Select" control.
+	 */
+	first_bit = __ffs(rx_mask);
+	switch (first_bit) {
+	case 0:
+	case 2:
+	case 4:
+	case 6:
+		snd_soc_component_update_bits(component,
+			RT1015_TDM1_4,
+			RT1015_TDM_I2S_TX_L_DAC1_1_MASK |
+			RT1015_TDM_I2S_TX_R_DAC1_1_MASK,
+			(first_bit << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) |
+			((first_bit+1) << RT1015_TDM_I2S_TX_R_DAC1_1_SFT));
+		break;
+	case 1:
+	case 3:
+	case 5:
+	case 7:
+		snd_soc_component_update_bits(component,
+			RT1015_TDM1_4,
+			RT1015_TDM_I2S_TX_L_DAC1_1_MASK |
+			RT1015_TDM_I2S_TX_R_DAC1_1_MASK,
+			((first_bit-1) << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) |
+			(first_bit << RT1015_TDM_I2S_TX_R_DAC1_1_SFT));
+		break;
+	default:
+		ret = -EINVAL;
+		goto _set_tdm_err_;
+	}
+
+	/* Tx slot configuration */
+	tx_slotnum = hweight_long(tx_mask);
+	if (tx_slotnum) {
+		ret = -EINVAL;
+		dev_err(component->dev, "doesn't need to support tx slots\n");
+		goto _set_tdm_err_;
+	}
+
+	snd_soc_component_update_bits(component, RT1015_TDM1_1,
+		RT1015_I2S_CH_TX_MASK | RT1015_I2S_CH_RX_MASK |
+		RT1015_I2S_CH_TX_LEN_MASK | RT1015_I2S_CH_RX_LEN_MASK, val);
+
+_set_tdm_err_:
+	return ret;
+}
+
 static int rt1015_probe(struct snd_soc_component *component)
 {
 	struct rt1015_priv *rt1015 =
@@ -958,7 +1054,6 @@ static int rt1015_probe(struct snd_soc_component *component)
 	rt1015->component = component;
 	rt1015->bclk_ratio = 0;
 	rt1015->cali_done = 0;
-	snd_soc_component_write(component, RT1015_BAT_RPO_STEP1, 0x061c);
 
 	INIT_DELAYED_WORK(&rt1015->flush_work, rt1015_flush_work);
 
@@ -981,6 +1076,7 @@ static struct snd_soc_dai_ops rt1015_aif_dai_ops = {
 	.hw_params = rt1015_hw_params,
 	.set_fmt = rt1015_set_dai_fmt,
 	.set_bclk_ratio = rt1015_set_bclk_ratio,
+	.set_tdm_slot = rt1015_set_tdm_slot,
 };
 
 static struct snd_soc_dai_driver rt1015_dai[] = {
@@ -1111,8 +1207,13 @@ static int rt1015_i2c_probe(struct i2c_client *i2c,
 
 	rt1015->hw_config = (i2c->addr == 0x29) ? RT1015_HW_29 : RT1015_HW_28;
 
-	regmap_read(rt1015->regmap, RT1015_DEVICE_ID, &val);
-	if ((val != RT1015_DEVICE_ID_VAL) && (val != RT1015_DEVICE_ID_VAL2)) {
+	ret = regmap_read(rt1015->regmap, RT1015_DEVICE_ID, &val);
+	if (ret) {
+		dev_err(&i2c->dev,
+			"Failed to read device register: %d\n", ret);
+		return ret;
+	} else if ((val != RT1015_DEVICE_ID_VAL) &&
+			(val != RT1015_DEVICE_ID_VAL2)) {
 		dev_err(&i2c->dev,
 			"Device with ID register %x is not rt1015\n", val);
 		return -ENODEV;
diff --git a/sound/soc/codecs/rt1015.h b/sound/soc/codecs/rt1015.h
index 15cadb361ec3..b6ea753014e1 100644
--- a/sound/soc/codecs/rt1015.h
+++ b/sound/soc/codecs/rt1015.h
@@ -214,6 +214,12 @@
 #define RT1015_ID_VERA				0x0
 #define RT1015_ID_VERB				0x1
 
+/* 0x00f2 */
+#define RT1015_MONO_LR_SEL_MASK			(0x3 << 4)
+#define RT1015_MONO_L_CHANNEL			(0x0 << 4)
+#define RT1015_MONO_R_CHANNEL			(0x1 << 4)
+#define RT1015_MONO_LR_MIX_CHANNEL			(0x2 << 4)
+
 /* 0x0102 */
 #define RT1015_DAC_VOL_MASK			(0x7f << 9)
 #define RT1015_DAC_VOL_SFT			9
@@ -276,6 +282,42 @@
 #define RT1015_TDM_INV_BCLK_MASK		(0x1 << 15)
 #define RT1015_TDM_INV_BCLK_SFT			15
 #define RT1015_TDM_INV_BCLK			(0x1 << 15)
+#define RT1015_I2S_CH_TX_MASK			(0x3 << 10)
+#define RT1015_I2S_CH_TX_SFT			10
+#define RT1015_I2S_TX_2CH			(0x0 << 10)
+#define RT1015_I2S_TX_4CH			(0x1 << 10)
+#define RT1015_I2S_TX_6CH			(0x2 << 10)
+#define RT1015_I2S_TX_8CH			(0x3 << 10)
+#define RT1015_I2S_CH_RX_MASK			(0x3 << 8)
+#define RT1015_I2S_CH_RX_SFT			8
+#define RT1015_I2S_RX_2CH			(0x0 << 8)
+#define RT1015_I2S_RX_4CH			(0x1 << 8)
+#define RT1015_I2S_RX_6CH			(0x2 << 8)
+#define RT1015_I2S_RX_8CH			(0x3 << 8)
+#define RT1015_I2S_LR_CH_SEL_MASK			(0x1 << 7)
+#define RT1015_I2S_LR_CH_SEL_SFT			7
+#define RT1015_I2S_LEFT_CH_SEL			(0x0 << 7)
+#define RT1015_I2S_RIGHT_CH_SEL			(0x1 << 7)
+#define RT1015_I2S_CH_TX_LEN_MASK			(0x7 << 4)
+#define RT1015_I2S_CH_TX_LEN_SFT			4
+#define RT1015_I2S_CH_TX_LEN_16B			(0x0 << 4)
+#define RT1015_I2S_CH_TX_LEN_20B			(0x1 << 4)
+#define RT1015_I2S_CH_TX_LEN_24B			(0x2 << 4)
+#define RT1015_I2S_CH_TX_LEN_32B			(0x3 << 4)
+#define RT1015_I2S_CH_TX_LEN_8B			(0x4 << 4)
+#define RT1015_I2S_CH_RX_LEN_MASK			(0x7 << 0)
+#define RT1015_I2S_CH_RX_LEN_SFT			0
+#define RT1015_I2S_CH_RX_LEN_16B			(0x0 << 0)
+#define RT1015_I2S_CH_RX_LEN_20B			(0x1 << 0)
+#define RT1015_I2S_CH_RX_LEN_24B			(0x2 << 0)
+#define RT1015_I2S_CH_RX_LEN_32B			(0x3 << 0)
+#define RT1015_I2S_CH_RX_LEN_8B			(0x4 << 0)
+
+/* TDM1 Setting-4 (0x011a) */
+#define RT1015_TDM_I2S_TX_L_DAC1_1_MASK			(0x7 << 12)
+#define RT1015_TDM_I2S_TX_R_DAC1_1_MASK			(0x7 << 8)
+#define RT1015_TDM_I2S_TX_L_DAC1_1_SFT 12
+#define RT1015_TDM_I2S_TX_R_DAC1_1_SFT 8
 
 /* 0x0330 */
 #define RT1015_ABST_AUTO_EN_MASK		(0x1 << 13)
diff --git a/sound/soc/codecs/rt1015p.c b/sound/soc/codecs/rt1015p.c
index 59bb60682270..671f2a2130fe 100644
--- a/sound/soc/codecs/rt1015p.c
+++ b/sound/soc/codecs/rt1015p.c
@@ -4,6 +4,7 @@
 //
 // Copyright 2020 The Linux Foundation. All rights reserved.
 
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
@@ -19,60 +20,46 @@
 
 struct rt1015p_priv {
 	struct gpio_desc *sdb;
-	int sdb_switch;
+	bool calib_done;
 };
 
-static int rt1015p_daiops_trigger(struct snd_pcm_substream *substream,
-		int cmd, struct snd_soc_dai *dai)
+static int rt1015p_sdb_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_component *component = dai->component;
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
 	struct rt1015p_priv *rt1015p =
 		snd_soc_component_get_drvdata(component);
 
 	if (!rt1015p->sdb)
 		return 0;
 
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (rt1015p->sdb_switch) {
-			gpiod_set_value(rt1015p->sdb, 1);
-			dev_dbg(component->dev, "set sdb to 1");
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		gpiod_set_value_cansleep(rt1015p->sdb, 1);
+		dev_dbg(component->dev, "set sdb to 1");
+
+		if (!rt1015p->calib_done) {
+			msleep(300);
+			rt1015p->calib_done = true;
 		}
 		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		gpiod_set_value(rt1015p->sdb, 0);
+	case SND_SOC_DAPM_POST_PMD:
+		gpiod_set_value_cansleep(rt1015p->sdb, 0);
 		dev_dbg(component->dev, "set sdb to 0");
 		break;
+	default:
+		break;
 	}
 
 	return 0;
 }
 
-static int rt1015p_sdb_event(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_component *component =
-		snd_soc_dapm_to_component(w->dapm);
-	struct rt1015p_priv *rt1015p =
-		snd_soc_component_get_drvdata(component);
-
-	if (event & SND_SOC_DAPM_POST_PMU)
-		rt1015p->sdb_switch = 1;
-	else if (event & SND_SOC_DAPM_POST_PMD)
-		rt1015p->sdb_switch = 0;
-
-	return 0;
-}
-
 static const struct snd_soc_dapm_widget rt1015p_dapm_widgets[] = {
 	SND_SOC_DAPM_OUTPUT("Speaker"),
 	SND_SOC_DAPM_OUT_DRV_E("SDB", SND_SOC_NOPM, 0, 0, NULL, 0,
 			rt1015p_sdb_event,
-			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = {
@@ -80,7 +67,20 @@ static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = {
 	{"Speaker", NULL, "SDB"},
 };
 
+#ifdef CONFIG_PM
+static int rt1015p_suspend(struct snd_soc_component *component)
+{
+	struct rt1015p_priv *rt1015p = snd_soc_component_get_drvdata(component);
+
+	rt1015p->calib_done = false;
+	return 0;
+}
+#else
+#define rt1015p_suspend NULL
+#endif
+
 static const struct snd_soc_component_driver rt1015p_component_driver = {
+	.suspend		= rt1015p_suspend,
 	.dapm_widgets		= rt1015p_dapm_widgets,
 	.num_dapm_widgets	= ARRAY_SIZE(rt1015p_dapm_widgets),
 	.dapm_routes		= rt1015p_dapm_routes,
@@ -91,10 +91,6 @@ static const struct snd_soc_component_driver rt1015p_component_driver = {
 	.non_legacy_dai_naming	= 1,
 };
 
-static const struct snd_soc_dai_ops rt1015p_dai_ops = {
-	.trigger        = rt1015p_daiops_trigger,
-};
-
 static struct snd_soc_dai_driver rt1015p_dai_driver = {
 	.name = "HiFi",
 	.playback = {
@@ -104,7 +100,6 @@ static struct snd_soc_dai_driver rt1015p_dai_driver = {
 		.channels_min	= 1,
 		.channels_max	= 2,
 	},
-	.ops    = &rt1015p_dai_ops,
 };
 
 static int rt1015p_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index c2621b0afe6c..ec5564f780e8 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -475,7 +475,7 @@ static int rt1308_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
 	if (!stream)
 		return -ENOMEM;
 
-	stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
+	stream->sdw_stream = sdw_stream;
 
 	/* Use tx_mask or rx_mask to configure stream tag and set dma_data */
 	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
index 9e3813f7583d..0edf09d3a499 100644
--- a/sound/soc/codecs/rt5660.c
+++ b/sound/soc/codecs/rt5660.c
@@ -1235,11 +1235,13 @@ static const struct i2c_device_id rt5660_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, rt5660_i2c_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id rt5660_of_match[] = {
 	{ .compatible = "realtek,rt5660", },
 	{},
 };
 MODULE_DEVICE_TABLE(of, rt5660_of_match);
+#endif
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id rt5660_acpi_match[] = {
diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c
index 6b4e0eb30c89..37d13120f5ba 100644
--- a/sound/soc/codecs/rt5682-i2c.c
+++ b/sound/soc/codecs/rt5682-i2c.c
@@ -221,6 +221,11 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
 		case RT5682_DMIC1_CLK_GPIO3: /* share with BCLK2 */
 			regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
 				RT5682_GP3_PIN_MASK, RT5682_GP3_PIN_DMIC_CLK);
+			if (rt5682->pdata.dmic_clk_driving_high)
+				regmap_update_bits(rt5682->regmap,
+					RT5682_PAD_DRIVING_CTRL,
+					RT5682_PAD_DRV_GP3_MASK,
+					2 << RT5682_PAD_DRV_GP3_SFT);
 			break;
 
 		default:
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index 58fb13132602..4d707e854875 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -103,7 +103,7 @@ static int rt5682_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
 	if (!stream)
 		return -ENOMEM;
 
-	stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
+	stream->sdw_stream = sdw_stream;
 
 	/* Use tx_mask or rx_mask to configure stream tag and set dma_data */
 	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index d9878173ff89..4d865edadd7e 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -2990,6 +2990,9 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
 			 rt5682->pdata.dai_clk_names[RT5682_DAI_WCLK_IDX],
 			 rt5682->pdata.dai_clk_names[RT5682_DAI_BCLK_IDX]);
 
+	rt5682->pdata.dmic_clk_driving_high = device_property_read_bool(dev,
+		"realtek,dmic-clk-driving-high");
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rt5682_parse_dt);
diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
index 354acd735ef4..99b85cfe6248 100644
--- a/sound/soc/codecs/rt5682.h
+++ b/sound/soc/codecs/rt5682.h
@@ -1271,6 +1271,20 @@
 #define RT5682_CP_CLK_HP_300KHZ			(0x2 << 4)
 #define RT5682_CP_CLK_HP_600KHZ			(0x3 << 4)
 
+/* Pad Driving Control (0x0136) */
+#define RT5682_PAD_DRV_GP1_MASK			(0x3 << 14)
+#define RT5682_PAD_DRV_GP1_SFT			14
+#define RT5682_PAD_DRV_GP2_MASK			(0x3 << 12)
+#define RT5682_PAD_DRV_GP2_SFT			12
+#define RT5682_PAD_DRV_GP3_MASK			(0x3 << 10)
+#define RT5682_PAD_DRV_GP3_SFT			10
+#define RT5682_PAD_DRV_GP4_MASK			(0x3 << 8)
+#define RT5682_PAD_DRV_GP4_SFT			8
+#define RT5682_PAD_DRV_GP5_MASK			(0x3 << 6)
+#define RT5682_PAD_DRV_GP5_SFT			6
+#define RT5682_PAD_DRV_GP6_MASK			(0x3 << 4)
+#define RT5682_PAD_DRV_GP6_SFT			4
+
 /* Chopper and Clock control for DAC (0x013a)*/
 #define RT5682_CKXEN_DAC1_MASK			(0x1 << 13)
 #define RT5682_CKXEN_DAC1_SFT			13
diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c
index 687ac2153666..66ec395dbbcd 100644
--- a/sound/soc/codecs/rt700.c
+++ b/sound/soc/codecs/rt700.c
@@ -867,7 +867,7 @@ static int rt700_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
 	if (!stream)
 		return -ENOMEM;
 
-	stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
+	stream->sdw_stream = sdw_stream;
 
 	/* Use tx_mask or rx_mask to configure stream tag and set dma_data */
 	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c
index f0a0691bd31c..fc7df79c3b91 100644
--- a/sound/soc/codecs/rt711-sdw.c
+++ b/sound/soc/codecs/rt711-sdw.c
@@ -338,7 +338,8 @@ static int rt711_update_status(struct sdw_slave *slave,
 static int rt711_read_prop(struct sdw_slave *slave)
 {
 	struct sdw_slave_prop *prop = &slave->prop;
-	int nval, i;
+	int nval;
+	int i, j;
 	u32 bit;
 	unsigned long addr;
 	struct sdw_dpn_prop *dpn;
@@ -379,15 +380,15 @@ static int rt711_read_prop(struct sdw_slave *slave)
 	if (!prop->sink_dpn_prop)
 		return -ENOMEM;
 
-	i = 0;
+	j = 0;
 	dpn = prop->sink_dpn_prop;
 	addr = prop->sink_ports;
 	for_each_set_bit(bit, &addr, 32) {
-		dpn[i].num = bit;
-		dpn[i].type = SDW_DPN_FULL;
-		dpn[i].simple_ch_prep_sm = true;
-		dpn[i].ch_prep_timeout = 10;
-		i++;
+		dpn[j].num = bit;
+		dpn[j].type = SDW_DPN_FULL;
+		dpn[j].simple_ch_prep_sm = true;
+		dpn[j].ch_prep_timeout = 10;
+		j++;
 	}
 
 	/* set the timeout values */
diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c
index 65b59dbfb43c..5771c02c3459 100644
--- a/sound/soc/codecs/rt711.c
+++ b/sound/soc/codecs/rt711.c
@@ -913,7 +913,7 @@ static int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
 	if (!stream)
 		return -ENOMEM;
 
-	stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
+	stream->sdw_stream = sdw_stream;
 
 	/* Use tx_mask or rx_mask to configure stream tag and set dma_data */
 	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c
new file mode 100644
index 000000000000..889b6b3b0009
--- /dev/null
+++ b/sound/soc/codecs/rt715-sdca-sdw.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt715-sdca-sdw.c -- rt715 ALSA SoC audio driver
+//
+// Copyright(c) 2020 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "rt715-sdca.h"
+#include "rt715-sdca-sdw.h"
+
+static bool rt715_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0x201a ... 0x2027:
+	case 0x2029 ... 0x202a:
+	case 0x202d ... 0x2034:
+	case 0x2200 ... 0x2204:
+	case 0x2206 ... 0x2212:
+	case 0x2230 ... 0x2239:
+	case 0x2f5b:
+	case SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+		RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00):
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt715_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0x201b:
+	case 0x201c:
+	case 0x201d:
+	case 0x201f:
+	case 0x2021:
+	case 0x2023:
+	case 0x2230:
+	case 0x202d ... 0x202f: /* BRA */
+	case 0x2200 ... 0x2212: /* i2c debug */
+	case 0x2f07:
+	case 0x2f1b ... 0x2f1e:
+	case 0x2f30 ... 0x2f34:
+	case 0x2f50 ... 0x2f51:
+	case 0x2f53 ... 0x2f59:
+	case 0x2f5c ... 0x2f5f:
+	case SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+		RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00): /* VAD Searching status */
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt715_sdca_mbq_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0x2000000:
+	case 0x200002b:
+	case 0x2000036:
+	case 0x2000037:
+	case 0x2000039:
+	case 0x6100000:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt715_sdca_mbq_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0x2000000:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config rt715_sdca_regmap = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.readable_reg = rt715_sdca_readable_register,
+	.volatile_reg = rt715_sdca_volatile_register,
+	.max_register = 0x43ffffff,
+	.reg_defaults = rt715_reg_defaults_sdca,
+	.num_reg_defaults = ARRAY_SIZE(rt715_reg_defaults_sdca),
+	.cache_type = REGCACHE_RBTREE,
+	.use_single_read = true,
+	.use_single_write = true,
+};
+
+static const struct regmap_config rt715_sdca_mbq_regmap = {
+	.name = "sdw-mbq",
+	.reg_bits = 32,
+	.val_bits = 16,
+	.readable_reg = rt715_sdca_mbq_readable_register,
+	.volatile_reg = rt715_sdca_mbq_volatile_register,
+	.max_register = 0x43ffffff,
+	.reg_defaults = rt715_mbq_reg_defaults_sdca,
+	.num_reg_defaults = ARRAY_SIZE(rt715_mbq_reg_defaults_sdca),
+	.cache_type = REGCACHE_RBTREE,
+	.use_single_read = true,
+	.use_single_write = true,
+};
+
+static int rt715_update_status(struct sdw_slave *slave,
+				enum sdw_slave_status status)
+{
+	struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev);
+
+	/* Update the status */
+	rt715->status = status;
+
+	/*
+	 * Perform initialization only if slave status is present and
+	 * hw_init flag is false
+	 */
+	if (rt715->hw_init || rt715->status != SDW_SLAVE_ATTACHED)
+		return 0;
+
+	/* perform I/O transfers required for Slave initialization */
+	return rt715_io_init(&slave->dev, slave);
+}
+
+static int rt715_read_prop(struct sdw_slave *slave)
+{
+	struct sdw_slave_prop *prop = &slave->prop;
+	int nval, i;
+	u32 bit;
+	unsigned long addr;
+	struct sdw_dpn_prop *dpn;
+
+	prop->paging_support = true;
+
+	/* first we need to allocate memory for set bits in port lists */
+	prop->source_ports = 0x50;/* BITMAP: 01010000 */
+	prop->sink_ports = 0x0;	/* BITMAP:  00000000 */
+
+	nval = hweight32(prop->source_ports);
+	prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+					sizeof(*prop->src_dpn_prop),
+					GFP_KERNEL);
+	if (!prop->src_dpn_prop)
+		return -ENOMEM;
+
+	dpn = prop->src_dpn_prop;
+	i = 0;
+	addr = prop->source_ports;
+	for_each_set_bit(bit, &addr, 32) {
+		dpn[i].num = bit;
+		dpn[i].simple_ch_prep_sm = true;
+		dpn[i].ch_prep_timeout = 10;
+		i++;
+	}
+
+	/* set the timeout values */
+	prop->clk_stop_timeout = 20;
+
+	return 0;
+}
+
+static struct sdw_slave_ops rt715_sdca_slave_ops = {
+	.read_prop = rt715_read_prop,
+	.update_status = rt715_update_status,
+};
+
+static int rt715_sdca_sdw_probe(struct sdw_slave *slave,
+			   const struct sdw_device_id *id)
+{
+	struct regmap *mbq_regmap, *regmap;
+
+	slave->ops = &rt715_sdca_slave_ops;
+
+	/* Regmap Initialization */
+	mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt715_sdca_mbq_regmap);
+	if (!mbq_regmap)
+		return -EINVAL;
+
+	regmap = devm_regmap_init_sdw(slave, &rt715_sdca_regmap);
+	if (!regmap)
+		return -EINVAL;
+
+	return rt715_init(&slave->dev, mbq_regmap, regmap, slave);
+}
+
+static const struct sdw_device_id rt715_sdca_id[] = {
+	SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x3, 0x1, 0),
+	SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x3, 0x1, 0),
+	{},
+};
+MODULE_DEVICE_TABLE(sdw, rt715_sdca_id);
+
+static int __maybe_unused rt715_dev_suspend(struct device *dev)
+{
+	struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev);
+
+	if (!rt715->hw_init)
+		return 0;
+
+	regcache_cache_only(rt715->regmap, true);
+	regcache_mark_dirty(rt715->regmap);
+	regcache_cache_only(rt715->mbq_regmap, true);
+	regcache_mark_dirty(rt715->mbq_regmap);
+
+	return 0;
+}
+
+#define RT715_PROBE_TIMEOUT 2000
+
+static int __maybe_unused rt715_dev_resume(struct device *dev)
+{
+	struct sdw_slave *slave = dev_to_sdw_dev(dev);
+	struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev);
+	unsigned long time;
+
+	if (!rt715->hw_init)
+		return 0;
+
+	if (!slave->unattach_request)
+		goto regmap_sync;
+
+	time = wait_for_completion_timeout(&slave->enumeration_complete,
+					   msecs_to_jiffies(RT715_PROBE_TIMEOUT));
+	if (!time) {
+		dev_err(&slave->dev, "Enumeration not complete, timed out\n");
+		return -ETIMEDOUT;
+	}
+
+regmap_sync:
+	slave->unattach_request = 0;
+	regcache_cache_only(rt715->regmap, false);
+	regcache_sync_region(rt715->regmap,
+		SDW_SDCA_CTL(FUN_JACK_CODEC, RT715_SDCA_ST_EN, RT715_SDCA_ST_CTRL,
+			CH_00),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+			RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00));
+	regcache_cache_only(rt715->mbq_regmap, false);
+	regcache_sync_region(rt715->mbq_regmap, 0x2000000, 0x61020ff);
+	regcache_sync_region(rt715->mbq_regmap,
+		SDW_SDCA_CTL(FUN_JACK_CODEC, RT715_SDCA_ST_EN, RT715_SDCA_ST_CTRL,
+			CH_00),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+			RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00));
+
+	return 0;
+}
+
+static const struct dev_pm_ops rt715_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume)
+	SET_RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL)
+};
+
+static struct sdw_driver rt715_sdw_driver = {
+	.driver = {
+		.name = "rt715-sdca",
+		.owner = THIS_MODULE,
+		.pm = &rt715_pm,
+	},
+	.probe = rt715_sdca_sdw_probe,
+	.ops = &rt715_sdca_slave_ops,
+	.id_table = rt715_sdca_id,
+};
+module_sdw_driver(rt715_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT715 driver SDW SDCA");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt715-sdca-sdw.h b/sound/soc/codecs/rt715-sdca-sdw.h
new file mode 100644
index 000000000000..cd365bb60747
--- /dev/null
+++ b/sound/soc/codecs/rt715-sdca-sdw.h
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt715-sdca-sdw.h -- RT715 ALSA SoC audio driver header
+ *
+ * Copyright(c) 2020 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT715_SDW_SDCA_H__
+#define __RT715_SDW_SDCA_H__
+
+#include <linux/soundwire/sdw_registers.h>
+
+static const struct reg_default rt715_reg_defaults_sdca[] = {
+	{ 0x201a, 0x00 },
+	{ 0x201e, 0x00 },
+	{ 0x2020, 0x00 },
+	{ 0x2021, 0x00 },
+	{ 0x2022, 0x00 },
+	{ 0x2023, 0x00 },
+	{ 0x2024, 0x00 },
+	{ 0x2025, 0x01 },
+	{ 0x2026, 0x00 },
+	{ 0x2027, 0x00 },
+	{ 0x2029, 0x00 },
+	{ 0x202a, 0x00 },
+	{ 0x202d, 0x00 },
+	{ 0x202e, 0x00 },
+	{ 0x202f, 0x00 },
+	{ 0x2030, 0x00 },
+	{ 0x2031, 0x00 },
+	{ 0x2032, 0x00 },
+	{ 0x2033, 0x00 },
+	{ 0x2034, 0x00 },
+	{ 0x2230, 0x00 },
+	{ 0x2231, 0x2f },
+	{ 0x2232, 0x80 },
+	{ 0x2233, 0x00 },
+	{ 0x2234, 0x00 },
+	{ 0x2235, 0x00 },
+	{ 0x2236, 0x00 },
+	{ 0x2237, 0x00 },
+	{ 0x2238, 0x00 },
+	{ 0x2239, 0x00 },
+	{ 0x2f01, 0x00 },
+	{ 0x2f02, 0x09 },
+	{ 0x2f03, 0x0b },
+	{ 0x2f04, 0x00 },
+	{ 0x2f05, 0x0e },
+	{ 0x2f06, 0x01 },
+	{ 0x2f08, 0x00 },
+	{ 0x2f09, 0x00 },
+	{ 0x2f0a, 0x00 },
+	{ 0x2f0b, 0x00 },
+	{ 0x2f0c, 0x00 },
+	{ 0x2f0d, 0x00 },
+	{ 0x2f0e, 0x12 },
+	{ 0x2f0f, 0x00 },
+	{ 0x2f10, 0x00 },
+	{ 0x2f11, 0x00 },
+	{ 0x2f12, 0x00 },
+	{ 0x2f13, 0x00 },
+	{ 0x2f14, 0x00 },
+	{ 0x2f15, 0x00 },
+	{ 0x2f16, 0x00 },
+	{ 0x2f17, 0x00 },
+	{ 0x2f18, 0x00 },
+	{ 0x2f19, 0x03 },
+	{ 0x2f1a, 0x00 },
+	{ 0x2f1f, 0x10 },
+	{ 0x2f20, 0x00 },
+	{ 0x2f21, 0x00 },
+	{ 0x2f22, 0x00 },
+	{ 0x2f23, 0x00 },
+	{ 0x2f24, 0x00 },
+	{ 0x2f25, 0x00 },
+	{ 0x2f52, 0x01 },
+	{ 0x2f5a, 0x02 },
+	{ 0x2f5b, 0x05 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN,
+		RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+		RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+		RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+		RT715_SDCA_FU_MUTE_CTRL, CH_03), 0x01 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+		RT715_SDCA_FU_MUTE_CTRL, CH_04), 0x01 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+		RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+		RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+		RT715_SDCA_FU_MUTE_CTRL, CH_03), 0x01 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+		RT715_SDCA_FU_MUTE_CTRL, CH_04), 0x01 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+		RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+		RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+		RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x02 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+		RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+		RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+		RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+};
+
+static const struct reg_default rt715_mbq_reg_defaults_sdca[] = {
+	{ 0x200002b, 0x0420 },
+	{ 0x2000036, 0x0000 },
+	{ 0x2000037, 0x0000 },
+	{ 0x2000039, 0xaa81 },
+	{ 0x6100000, 0x0100 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+		RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+		RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+		RT715_SDCA_FU_VOL_CTRL, CH_03), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+		RT715_SDCA_FU_VOL_CTRL, CH_04), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+		RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+		RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+		RT715_SDCA_FU_VOL_CTRL, CH_03), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+		RT715_SDCA_FU_VOL_CTRL, CH_04), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+		RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+		RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_02), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_03), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_04), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_05), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_02), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_03), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_04), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_05), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
+};
+#endif /* __RT715_SDW_SDCA_H__ */
diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c
new file mode 100644
index 000000000000..b843e47eb25b
--- /dev/null
+++ b/sound/soc/codecs/rt715-sdca.c
@@ -0,0 +1,936 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt715-sdca.c -- rt715 ALSA SoC audio driver
+//
+// Copyright(c) 2020 Realtek Semiconductor Corp.
+//
+//
+//
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/soundwire/sdw_registers.h>
+
+#include "rt715-sdca.h"
+
+static int rt715_index_write(struct rt715_sdca_priv *rt715, unsigned int nid,
+		unsigned int reg, unsigned int value)
+{
+	struct regmap *regmap = rt715->mbq_regmap;
+	unsigned int addr;
+	int ret;
+
+	addr = (nid << 20) | reg;
+
+	ret = regmap_write(regmap, addr, value);
+	if (ret < 0)
+		dev_err(&rt715->slave->dev,
+				"Failed to set private value: %08x <= %04x %d\n", ret, addr,
+				value);
+
+	return ret;
+}
+
+static int rt715_index_read(struct rt715_sdca_priv *rt715,
+		unsigned int nid, unsigned int reg, unsigned int *value)
+{
+	struct regmap *regmap = rt715->mbq_regmap;
+	unsigned int addr;
+	int ret;
+
+	addr = (nid << 20) | reg;
+
+	ret = regmap_read(regmap, addr, value);
+	if (ret < 0)
+		dev_err(&rt715->slave->dev,
+				"Failed to get private value: %06x => %04x ret=%d\n",
+				addr, *value, ret);
+
+	return ret;
+}
+
+static int rt715_index_update_bits(struct rt715_sdca_priv *rt715,
+	unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val)
+{
+	unsigned int tmp;
+	int ret;
+
+	ret = rt715_index_read(rt715, nid, reg, &tmp);
+	if (ret < 0)
+		return ret;
+
+	set_mask_bits(&tmp, mask, val);
+
+	return rt715_index_write(rt715, nid, reg, tmp);
+}
+
+/* SDCA Volume/Boost control */
+static int rt715_set_amp_gain_put_sdca(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+	unsigned int val_l, val_r, gain_l_val, gain_r_val;
+	int ret;
+
+	/* control value to 2s complement */
+	/* L channel */
+	gain_l_val = ucontrol->value.integer.value[0];
+	if (gain_l_val > mc->max)
+		gain_l_val = mc->max;
+	val_l = gain_l_val;
+
+	if (mc->shift == 8) {
+		gain_l_val = (gain_l_val * 10) << mc->shift;
+	} else {
+		gain_l_val =
+			((abs(gain_l_val - mc->shift) * RT715_SDCA_DB_STEP) << 8) / 1000;
+		if (val_l <= mc->shift) {
+			gain_l_val = ~gain_l_val;
+			gain_l_val += 1;
+		}
+		gain_l_val &= 0xffff;
+	}
+
+	/* R channel */
+	gain_r_val = ucontrol->value.integer.value[1];
+	if (gain_r_val > mc->max)
+		gain_r_val = mc->max;
+	val_r = gain_r_val;
+
+	if (mc->shift == 8) {
+		gain_r_val = (gain_r_val * 10) << mc->shift;
+	} else {
+		gain_r_val =
+			((abs(gain_r_val - mc->shift) * RT715_SDCA_DB_STEP) << 8) / 1000;
+		if (val_r <= mc->shift) {
+			gain_r_val = ~gain_r_val;
+			gain_r_val += 1;
+		}
+		gain_r_val &= 0xffff;
+	}
+
+	/* Lch*/
+	ret = regmap_write(rt715->mbq_regmap, mc->reg, gain_l_val);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to write 0x%x=0x%x\n", mc->reg,
+			gain_l_val);
+		return ret;
+	}
+	/* Rch */
+	ret = regmap_write(rt715->mbq_regmap, mc->rreg, gain_r_val);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to write 0x%x=0x%x\n", mc->rreg,
+			gain_r_val);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rt715_set_amp_gain_get_sdca(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+	unsigned int val_l, val_r, ctl_l, ctl_r, neg_flag = 0;
+	int ret;
+
+	ret = regmap_read(rt715->mbq_regmap, mc->reg, &val_l);
+	if (ret < 0)
+		dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", mc->reg, ret);
+	ret = regmap_read(rt715->mbq_regmap, mc->rreg, &val_r);
+	if (ret < 0)
+		dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", mc->rreg,
+				ret);
+
+	/* L channel */
+	if (mc->shift == 8) {
+		ctl_l = (val_l >> mc->shift) / 10;
+	} else {
+		ctl_l = val_l;
+		if (ctl_l & BIT(15)) {
+			ctl_l = ~(val_l - 1) & 0xffff;
+			neg_flag = 1;
+		}
+		ctl_l *= 1000;
+		ctl_l >>= 8;
+		if (neg_flag)
+			ctl_l = mc->shift - ctl_l / RT715_SDCA_DB_STEP;
+		else
+			ctl_l = mc->shift + ctl_l / RT715_SDCA_DB_STEP;
+	}
+
+	neg_flag = 0;
+	/* R channel */
+	if (mc->shift == 8) {
+		ctl_r = (val_r >> mc->shift) / 10;
+	} else {
+		ctl_r = val_r;
+		if (ctl_r & BIT(15)) {
+			ctl_r = ~(val_r - 1) & 0xffff;
+			neg_flag = 1;
+		}
+		ctl_r *= 1000;
+		ctl_r >>= 8;
+		if (neg_flag)
+			ctl_r = mc->shift - ctl_r / RT715_SDCA_DB_STEP;
+		else
+			ctl_r = mc->shift + ctl_r / RT715_SDCA_DB_STEP;
+	}
+
+	ucontrol->value.integer.value[0] = ctl_l;
+	ucontrol->value.integer.value[1] = ctl_r;
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
+
+#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\
+	 xhandler_get, xhandler_put) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.info = snd_soc_info_volsw, \
+	.get = xhandler_get, .put = xhandler_put, \
+	.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
+					    xmax, xinvert) }
+
+static const struct snd_kcontrol_new rt715_snd_controls_sdca[] = {
+	/* Capture switch */
+	SOC_DOUBLE_R("FU0A Capture Switch",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+			RT715_SDCA_FU_MUTE_CTRL, CH_01),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+			RT715_SDCA_FU_MUTE_CTRL, CH_02),
+			0, 1, 1),
+	SOC_DOUBLE_R("FU02 1_2 Capture Switch",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+			RT715_SDCA_FU_MUTE_CTRL, CH_01),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+			RT715_SDCA_FU_MUTE_CTRL, CH_02),
+			0, 1, 1),
+	SOC_DOUBLE_R("FU02 3_4 Capture Switch",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+			RT715_SDCA_FU_MUTE_CTRL, CH_03),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+			RT715_SDCA_FU_MUTE_CTRL, CH_04),
+			0, 1, 1),
+	SOC_DOUBLE_R("FU06 1_2 Capture Switch",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+			RT715_SDCA_FU_MUTE_CTRL, CH_01),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+			RT715_SDCA_FU_MUTE_CTRL, CH_02),
+			0, 1, 1),
+	SOC_DOUBLE_R("FU06 3_4 Capture Switch",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+			RT715_SDCA_FU_MUTE_CTRL, CH_03),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+			RT715_SDCA_FU_MUTE_CTRL, CH_04),
+			0, 1, 1),
+	/* Volume Control */
+	SOC_DOUBLE_R_EXT_TLV("FU0A Capture Volume",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+			RT715_SDCA_FU_VOL_CTRL, CH_01),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+			RT715_SDCA_FU_VOL_CTRL, CH_02),
+			0x2f, 0x7f, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		in_vol_tlv),
+	SOC_DOUBLE_R_EXT_TLV("FU02 1_2 Capture Volume",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+			RT715_SDCA_FU_VOL_CTRL, CH_01),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+			RT715_SDCA_FU_VOL_CTRL, CH_02),
+			0x2f, 0x7f, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		in_vol_tlv),
+	SOC_DOUBLE_R_EXT_TLV("FU02 3_4 Capture Volume",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+			RT715_SDCA_FU_VOL_CTRL,
+			CH_03),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+			RT715_SDCA_FU_VOL_CTRL,
+			CH_04), 0x2f, 0x7f, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		in_vol_tlv),
+	SOC_DOUBLE_R_EXT_TLV("FU06 1_2 Capture Volume",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+			RT715_SDCA_FU_VOL_CTRL,
+			CH_01),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+			RT715_SDCA_FU_VOL_CTRL,
+			CH_02), 0x2f, 0x7f, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		in_vol_tlv),
+	SOC_DOUBLE_R_EXT_TLV("FU06 3_4 Capture Volume",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+			RT715_SDCA_FU_VOL_CTRL,
+			CH_03),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+			RT715_SDCA_FU_VOL_CTRL,
+			CH_04), 0x2f, 0x7f, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		in_vol_tlv),
+	/* MIC Boost Control */
+	SOC_DOUBLE_R_EXT_TLV("FU0E 1_2 Boost",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_01),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_02), 8, 3, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		mic_vol_tlv),
+	SOC_DOUBLE_R_EXT_TLV("FU0E 3_4 Boost",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_03),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_04), 8, 3, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		mic_vol_tlv),
+	SOC_DOUBLE_R_EXT_TLV("FU0E 5_6 Boost",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_05),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_06), 8, 3, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		mic_vol_tlv),
+	SOC_DOUBLE_R_EXT_TLV("FU0E 7_8 Boost",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_07),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_08), 8, 3, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		mic_vol_tlv),
+	SOC_DOUBLE_R_EXT_TLV("FU0C 1_2 Boost",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_01),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_02), 8, 3, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		mic_vol_tlv),
+	SOC_DOUBLE_R_EXT_TLV("FU0C 3_4 Boost",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_03),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_04), 8, 3, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		mic_vol_tlv),
+	SOC_DOUBLE_R_EXT_TLV("FU0C 5_6 Boost",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_05),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_06), 8, 3, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		mic_vol_tlv),
+	SOC_DOUBLE_R_EXT_TLV("FU0C 7_8 Boost",
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_07),
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+			RT715_SDCA_FU_DMIC_GAIN_CTRL,
+			CH_08), 8, 3, 0,
+		rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca,
+		mic_vol_tlv),
+};
+
+static int rt715_mux_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_kcontrol_component(kcontrol);
+	struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+	unsigned int val, mask_sft;
+
+	if (strstr(ucontrol->id.name, "ADC 22 Mux"))
+		mask_sft = 12;
+	else if (strstr(ucontrol->id.name, "ADC 23 Mux"))
+		mask_sft = 8;
+	else if (strstr(ucontrol->id.name, "ADC 24 Mux"))
+		mask_sft = 4;
+	else if (strstr(ucontrol->id.name, "ADC 25 Mux"))
+		mask_sft = 0;
+	else
+		return -EINVAL;
+
+	rt715_index_read(rt715, RT715_VENDOR_HDA_CTL,
+		RT715_HDA_LEGACY_MUX_CTL1, &val);
+	val = (val >> mask_sft) & 0xf;
+
+	/*
+	 * The first two indices of ADC Mux 24/25 are routed to the same
+	 * hardware source. ie, ADC Mux 24 0/1 will both connect to MIC2.
+	 * To have a unique set of inputs, we skip the index1 of the muxes.
+	 */
+	if ((strstr(ucontrol->id.name, "ADC 24 Mux") ||
+		strstr(ucontrol->id.name, "ADC 25 Mux")) && val > 0)
+		val -= 1;
+	ucontrol->value.enumerated.item[0] = val;
+
+	return 0;
+}
+
+static int rt715_mux_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm =
+				snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int *item = ucontrol->value.enumerated.item;
+	unsigned int val, val2 = 0, change, mask_sft;
+
+	if (item[0] >= e->items)
+		return -EINVAL;
+
+	if (strstr(ucontrol->id.name, "ADC 22 Mux"))
+		mask_sft = 12;
+	else if (strstr(ucontrol->id.name, "ADC 23 Mux"))
+		mask_sft = 8;
+	else if (strstr(ucontrol->id.name, "ADC 24 Mux"))
+		mask_sft = 4;
+	else if (strstr(ucontrol->id.name, "ADC 25 Mux"))
+		mask_sft = 0;
+	else
+		return -EINVAL;
+
+	/* Verb ID = 0x701h, nid = e->reg */
+	val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+	rt715_index_read(rt715, RT715_VENDOR_HDA_CTL,
+		RT715_HDA_LEGACY_MUX_CTL1, &val2);
+	val2 = (val2 >> mask_sft) & 0xf;
+
+	change = val != val2;
+
+	if (change)
+		rt715_index_update_bits(rt715, RT715_VENDOR_HDA_CTL,
+			RT715_HDA_LEGACY_MUX_CTL1, 0xf << mask_sft, val << mask_sft);
+
+	snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL);
+
+	return change;
+}
+
+static const char * const adc_22_23_mux_text[] = {
+	"MIC1",
+	"MIC2",
+	"LINE1",
+	"LINE2",
+	"DMIC1",
+	"DMIC2",
+	"DMIC3",
+	"DMIC4",
+};
+
+/*
+ * Due to mux design for nid 24 (MUX_IN3)/25 (MUX_IN4), connection index 0 and
+ * 1 will be connected to the same dmic source, therefore we skip index 1 to
+ * avoid misunderstanding on usage of dapm routing.
+ */
+static int rt715_adc_24_25_values[] = {
+	0,
+	2,
+	3,
+	4,
+	5,
+};
+
+static const char * const adc_24_mux_text[] = {
+	"MIC2",
+	"DMIC1",
+	"DMIC2",
+	"DMIC3",
+	"DMIC4",
+};
+
+static const char * const adc_25_mux_text[] = {
+	"MIC1",
+	"DMIC1",
+	"DMIC2",
+	"DMIC3",
+	"DMIC4",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt715_adc22_enum, SND_SOC_NOPM, 0,
+	adc_22_23_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(rt715_adc23_enum, SND_SOC_NOPM, 0,
+	adc_22_23_mux_text);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc24_enum,
+	SND_SOC_NOPM, 0, 0xf,
+	adc_24_mux_text, rt715_adc_24_25_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc25_enum,
+	SND_SOC_NOPM, 0, 0xf,
+	adc_25_mux_text, rt715_adc_24_25_values);
+
+static const struct snd_kcontrol_new rt715_adc22_mux =
+	SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt715_adc22_enum,
+			rt715_mux_get, rt715_mux_put);
+
+static const struct snd_kcontrol_new rt715_adc23_mux =
+	SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt715_adc23_enum,
+			rt715_mux_get, rt715_mux_put);
+
+static const struct snd_kcontrol_new rt715_adc24_mux =
+	SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt715_adc24_enum,
+			rt715_mux_get, rt715_mux_put);
+
+static const struct snd_kcontrol_new rt715_adc25_mux =
+	SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt715_adc25_enum,
+			rt715_mux_get, rt715_mux_put);
+
+static int rt715_pde23_24_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_write(rt715->regmap,
+			SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CREQ_POW_EN,
+				RT715_SDCA_REQ_POW_CTRL,
+				CH_00), 0x00);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_write(rt715->regmap,
+			SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CREQ_POW_EN,
+				RT715_SDCA_REQ_POW_CTRL,
+				CH_00), 0x03);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt715_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("DMIC1"),
+	SND_SOC_DAPM_INPUT("DMIC2"),
+	SND_SOC_DAPM_INPUT("DMIC3"),
+	SND_SOC_DAPM_INPUT("DMIC4"),
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("LINE1"),
+	SND_SOC_DAPM_INPUT("LINE2"),
+
+	SND_SOC_DAPM_SUPPLY("PDE23_24", SND_SOC_NOPM, 0, 0,
+		rt715_pde23_24_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_ADC("ADC 07", NULL, SND_SOC_NOPM, 4, 0),
+	SND_SOC_DAPM_ADC("ADC 08", NULL, SND_SOC_NOPM, 4, 0),
+	SND_SOC_DAPM_ADC("ADC 09", NULL, SND_SOC_NOPM, 4, 0),
+	SND_SOC_DAPM_ADC("ADC 27", NULL, SND_SOC_NOPM, 4, 0),
+	SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0,
+		&rt715_adc22_mux),
+	SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0,
+		&rt715_adc23_mux),
+	SND_SOC_DAPM_MUX("ADC 24 Mux", SND_SOC_NOPM, 0, 0,
+		&rt715_adc24_mux),
+	SND_SOC_DAPM_MUX("ADC 25 Mux", SND_SOC_NOPM, 0, 0,
+		&rt715_adc25_mux),
+	SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt715_audio_map[] = {
+	{"DP6TX", NULL, "ADC 09"},
+	{"DP6TX", NULL, "ADC 08"},
+	{"DP4TX", NULL, "ADC 07"},
+	{"DP4TX", NULL, "ADC 27"},
+	{"DP4TX", NULL, "ADC 09"},
+	{"DP4TX", NULL, "ADC 08"},
+
+	{"LINE1", NULL, "PDE23_24"},
+	{"LINE2", NULL, "PDE23_24"},
+	{"MIC1", NULL, "PDE23_24"},
+	{"MIC2", NULL, "PDE23_24"},
+	{"DMIC1", NULL, "PDE23_24"},
+	{"DMIC2", NULL, "PDE23_24"},
+	{"DMIC3", NULL, "PDE23_24"},
+	{"DMIC4", NULL, "PDE23_24"},
+
+	{"ADC 09", NULL, "ADC 22 Mux"},
+	{"ADC 08", NULL, "ADC 23 Mux"},
+	{"ADC 07", NULL, "ADC 24 Mux"},
+	{"ADC 27", NULL, "ADC 25 Mux"},
+	{"ADC 22 Mux", "MIC1", "MIC1"},
+	{"ADC 22 Mux", "MIC2", "MIC2"},
+	{"ADC 22 Mux", "LINE1", "LINE1"},
+	{"ADC 22 Mux", "LINE2", "LINE2"},
+	{"ADC 22 Mux", "DMIC1", "DMIC1"},
+	{"ADC 22 Mux", "DMIC2", "DMIC2"},
+	{"ADC 22 Mux", "DMIC3", "DMIC3"},
+	{"ADC 22 Mux", "DMIC4", "DMIC4"},
+	{"ADC 23 Mux", "MIC1", "MIC1"},
+	{"ADC 23 Mux", "MIC2", "MIC2"},
+	{"ADC 23 Mux", "LINE1", "LINE1"},
+	{"ADC 23 Mux", "LINE2", "LINE2"},
+	{"ADC 23 Mux", "DMIC1", "DMIC1"},
+	{"ADC 23 Mux", "DMIC2", "DMIC2"},
+	{"ADC 23 Mux", "DMIC3", "DMIC3"},
+	{"ADC 23 Mux", "DMIC4", "DMIC4"},
+	{"ADC 24 Mux", "MIC2", "MIC2"},
+	{"ADC 24 Mux", "DMIC1", "DMIC1"},
+	{"ADC 24 Mux", "DMIC2", "DMIC2"},
+	{"ADC 24 Mux", "DMIC3", "DMIC3"},
+	{"ADC 24 Mux", "DMIC4", "DMIC4"},
+	{"ADC 25 Mux", "MIC1", "MIC1"},
+	{"ADC 25 Mux", "DMIC1", "DMIC1"},
+	{"ADC 25 Mux", "DMIC2", "DMIC2"},
+	{"ADC 25 Mux", "DMIC3", "DMIC3"},
+	{"ADC 25 Mux", "DMIC4", "DMIC4"},
+};
+
+static const struct snd_soc_component_driver soc_codec_dev_rt715_sdca = {
+	.controls = rt715_snd_controls_sdca,
+	.num_controls = ARRAY_SIZE(rt715_snd_controls_sdca),
+	.dapm_widgets = rt715_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rt715_dapm_widgets),
+	.dapm_routes = rt715_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(rt715_audio_map),
+};
+
+static int rt715_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+				int direction)
+{
+	struct rt715_sdw_stream_data *stream;
+
+	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+	if (!stream)
+		return -ENOMEM;
+
+	stream->sdw_stream = sdw_stream;
+
+	/* Use tx_mask or rx_mask to configure stream tag and set dma_data */
+	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+		dai->playback_dma_data = stream;
+	else
+		dai->capture_dma_data = stream;
+
+	return 0;
+}
+
+static void rt715_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+
+{
+	struct rt715_sdw_stream_data *stream;
+
+	stream = snd_soc_dai_get_dma_data(dai, substream);
+	if (!stream)
+		return;
+
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+	kfree(stream);
+}
+
+static int rt715_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+	struct sdw_stream_config stream_config;
+	struct sdw_port_config port_config;
+	enum sdw_data_direction direction;
+	struct rt715_sdw_stream_data *stream;
+	int retval, port, num_channels;
+	unsigned int val;
+
+	stream = snd_soc_dai_get_dma_data(dai, substream);
+
+	if (!stream)
+		return -EINVAL;
+
+	if (!rt715->slave)
+		return -EINVAL;
+
+	switch (dai->id) {
+	case RT715_AIF1:
+		direction = SDW_DATA_DIR_TX;
+		port = 6;
+		rt715_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL,
+			0xa500);
+		break;
+	case RT715_AIF2:
+		direction = SDW_DATA_DIR_TX;
+		port = 4;
+		rt715_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL,
+			0xaf00);
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI id %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	stream_config.frame_rate =  params_rate(params);
+	stream_config.ch_count = params_channels(params);
+	stream_config.bps = snd_pcm_format_width(params_format(params));
+	stream_config.direction = direction;
+
+	num_channels = params_channels(params);
+	port_config.ch_mask = GENMASK(num_channels - 1, 0);
+	port_config.num = port;
+
+	retval = sdw_stream_add_slave(rt715->slave, &stream_config,
+					&port_config, 1, stream->sdw_stream);
+	if (retval) {
+		dev_err(component->dev, "Unable to configure port, retval:%d\n",
+			retval);
+		return retval;
+	}
+
+	switch (params_rate(params)) {
+	case 8000:
+		val = 0x1;
+		break;
+	case 11025:
+		val = 0x2;
+		break;
+	case 12000:
+		val = 0x3;
+		break;
+	case 16000:
+		val = 0x4;
+		break;
+	case 22050:
+		val = 0x5;
+		break;
+	case 24000:
+		val = 0x6;
+		break;
+	case 32000:
+		val = 0x7;
+		break;
+	case 44100:
+		val = 0x8;
+		break;
+	case 48000:
+		val = 0x9;
+		break;
+	case 88200:
+		val = 0xa;
+		break;
+	case 96000:
+		val = 0xb;
+		break;
+	case 176400:
+		val = 0xc;
+		break;
+	case 192000:
+		val = 0xd;
+		break;
+	case 384000:
+		val = 0xe;
+		break;
+	case 768000:
+		val = 0xf;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample rate %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	regmap_write(rt715->regmap,
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CS_FREQ_IND_EN,
+			RT715_SDCA_FREQ_IND_CTRL, CH_00), val);
+
+	return 0;
+}
+
+static int rt715_pcm_hw_free(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+	struct rt715_sdw_stream_data *stream =
+		snd_soc_dai_get_dma_data(dai, substream);
+
+	if (!rt715->slave)
+		return -EINVAL;
+
+	sdw_stream_remove_slave(rt715->slave, stream->sdw_stream);
+	return 0;
+}
+
+#define RT715_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define RT715_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static struct snd_soc_dai_ops rt715_ops = {
+	.hw_params	= rt715_pcm_hw_params,
+	.hw_free	= rt715_pcm_hw_free,
+	.set_sdw_stream	= rt715_set_sdw_stream,
+	.shutdown	= rt715_shutdown,
+};
+
+static struct snd_soc_dai_driver rt715_dai[] = {
+	{
+		.name = "rt715-aif1",
+		.id = RT715_AIF1,
+		.capture = {
+			.stream_name = "DP6 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT715_STEREO_RATES,
+			.formats = RT715_FORMATS,
+		},
+		.ops = &rt715_ops,
+	},
+	{
+		.name = "rt715-aif2",
+		.id = RT715_AIF2,
+		.capture = {
+			.stream_name = "DP4 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT715_STEREO_RATES,
+			.formats = RT715_FORMATS,
+		},
+		.ops = &rt715_ops,
+	},
+};
+
+/* Bus clock frequency */
+#define RT715_CLK_FREQ_9600000HZ 9600000
+#define RT715_CLK_FREQ_12000000HZ 12000000
+#define RT715_CLK_FREQ_6000000HZ 6000000
+#define RT715_CLK_FREQ_4800000HZ 4800000
+#define RT715_CLK_FREQ_2400000HZ 2400000
+#define RT715_CLK_FREQ_12288000HZ 12288000
+
+int rt715_init(struct device *dev, struct regmap *mbq_regmap,
+	struct regmap *regmap, struct sdw_slave *slave)
+{
+	struct rt715_sdca_priv *rt715;
+	int ret;
+
+	rt715 = devm_kzalloc(dev, sizeof(*rt715), GFP_KERNEL);
+	if (!rt715)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, rt715);
+	rt715->slave = slave;
+	rt715->regmap = regmap;
+	rt715->mbq_regmap = mbq_regmap;
+	rt715->hw_sdw_ver = slave->id.sdw_version;
+	/*
+	 * Mark hw_init to false
+	 * HW init will be performed when device reports present
+	 */
+	rt715->hw_init = false;
+	rt715->first_init = false;
+
+	ret = devm_snd_soc_register_component(dev,
+			&soc_codec_dev_rt715_sdca,
+			rt715_dai,
+			ARRAY_SIZE(rt715_dai));
+
+	return ret;
+}
+
+int rt715_io_init(struct device *dev, struct sdw_slave *slave)
+{
+	struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev);
+	unsigned int hw_ver;
+
+	if (rt715->hw_init)
+		return 0;
+
+	/*
+	 * PM runtime is only enabled when a Slave reports as Attached
+	 */
+	if (!rt715->first_init) {
+		/* set autosuspend parameters */
+		pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+		pm_runtime_use_autosuspend(&slave->dev);
+
+		/* update count of parent 'active' children */
+		pm_runtime_set_active(&slave->dev);
+
+		/* make sure the device does not suspend immediately */
+		pm_runtime_mark_last_busy(&slave->dev);
+
+		pm_runtime_enable(&slave->dev);
+
+		rt715->first_init = true;
+	}
+
+	pm_runtime_get_noresume(&slave->dev);
+
+	rt715_index_read(rt715, RT715_VENDOR_REG,
+		RT715_PRODUCT_NUM, &hw_ver);
+	hw_ver = hw_ver & 0x000f;
+
+	/* set clock selector = external */
+	regmap_write(rt715->regmap,
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN,
+			RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1);
+	/* set GPIO_4/5/6 to be 3rd/4th DMIC usage */
+	if (hw_ver == 0x0)
+		rt715_index_update_bits(rt715, RT715_VENDOR_REG,
+			RT715_AD_FUNC_EN, 0x54, 0x54);
+	else if (hw_ver == 0x1) {
+		rt715_index_update_bits(rt715, RT715_VENDOR_REG,
+			RT715_AD_FUNC_EN, 0x55, 0x55);
+		rt715_index_update_bits(rt715, RT715_VENDOR_REG,
+			RT715_REV_1, 0x40, 0x40);
+	}
+	/* trigger mode = VAD enable */
+	regmap_write(rt715->regmap,
+		SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+			RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x2);
+	/* SMPU-1 interrupt enable mask */
+	regmap_update_bits(rt715->regmap, RT715_INT_MASK, 0x1, 0x1);
+
+	/* Mark Slave initialization complete */
+	rt715->hw_init = true;
+
+	pm_runtime_mark_last_busy(&slave->dev);
+	pm_runtime_put_autosuspend(&slave->dev);
+
+	return 0;
+}
+
+MODULE_DESCRIPTION("ASoC rt715 driver SDW SDCA");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt715-sdca.h b/sound/soc/codecs/rt715-sdca.h
new file mode 100644
index 000000000000..6326cd8c374e
--- /dev/null
+++ b/sound/soc/codecs/rt715-sdca.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt715-sdca.h -- RT715 ALSA SoC audio driver header
+ *
+ * Copyright(c) 2020 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT715_SDCA_H__
+#define __RT715_SDCA_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+
+struct rt715_sdca_priv {
+	struct regmap *regmap;
+	struct regmap *mbq_regmap;
+	struct snd_soc_codec *codec;
+	struct sdw_slave *slave;
+	struct delayed_work adc_mute_work;
+	int dbg_nid;
+	int dbg_vid;
+	int dbg_payload;
+	enum sdw_slave_status status;
+	struct sdw_bus_params params;
+	bool hw_init;
+	bool first_init;
+	int l_is_unmute;
+	int r_is_unmute;
+	int hw_sdw_ver;
+};
+
+struct rt715_sdw_stream_data {
+	struct sdw_stream_runtime *sdw_stream;
+};
+
+/* MIPI Register */
+#define RT715_INT_CTRL					0x005a
+#define RT715_INT_MASK					0x005e
+
+/* NID */
+#define RT715_AUDIO_FUNCTION_GROUP			0x01
+#define RT715_MIC_ADC					0x07
+#define RT715_LINE_ADC					0x08
+#define RT715_MIX_ADC					0x09
+#define RT715_DMIC1					0x12
+#define RT715_DMIC2					0x13
+#define RT715_MIC1					0x18
+#define RT715_MIC2					0x19
+#define RT715_LINE1					0x1a
+#define RT715_LINE2					0x1b
+#define RT715_DMIC3					0x1d
+#define RT715_DMIC4					0x29
+#define RT715_VENDOR_REG				0x20
+#define RT715_MUX_IN1					0x22
+#define RT715_MUX_IN2					0x23
+#define RT715_MUX_IN3					0x24
+#define RT715_MUX_IN4					0x25
+#define RT715_MIX_ADC2					0x27
+#define RT715_INLINE_CMD				0x55
+#define RT715_VENDOR_HDA_CTL				0x61
+
+/* Index (NID:20h) */
+#define RT715_PRODUCT_NUM				0x0
+#define RT715_IRQ_CTRL					0x2b
+#define RT715_AD_FUNC_EN				0x36
+#define RT715_REV_1					0x37
+#define RT715_SDW_INPUT_SEL				0x39
+#define RT715_EXT_DMIC_CLK_CTRL2			0x54
+
+/* Index (NID:61h) */
+#define RT715_HDA_LEGACY_MUX_CTL1			0x00
+
+/* SDCA (Function) */
+#define FUN_JACK_CODEC				0x01
+#define FUN_MIC_ARRAY				0x02
+#define FUN_HID						0x03
+/* SDCA (Entity) */
+#define RT715_SDCA_ST_EN							0x00
+#define RT715_SDCA_CS_FREQ_IND_EN					0x01
+#define RT715_SDCA_FU_ADC8_9_VOL					0x02
+#define RT715_SDCA_SMPU_TRIG_ST_EN					0x05
+#define RT715_SDCA_FU_ADC10_11_VOL					0x06
+#define RT715_SDCA_FU_ADC7_27_VOL					0x0a
+#define RT715_SDCA_FU_AMIC_GAIN_EN					0x0c
+#define RT715_SDCA_FU_DMIC_GAIN_EN					0x0e
+#define RT715_SDCA_CX_CLK_SEL_EN					0x10
+#define RT715_SDCA_CREQ_POW_EN						0x18
+/* SDCA (Control) */
+#define RT715_SDCA_ST_CTRL							0x00
+#define RT715_SDCA_CX_CLK_SEL_CTRL					0x01
+#define RT715_SDCA_REQ_POW_CTRL					0x01
+#define RT715_SDCA_FU_MUTE_CTRL					0x01
+#define RT715_SDCA_FU_VOL_CTRL						0x02
+#define RT715_SDCA_FU_DMIC_GAIN_CTRL				0x0b
+#define RT715_SDCA_FREQ_IND_CTRL					0x10
+#define RT715_SDCA_SMPU_TRIG_EN_CTRL				0x10
+#define RT715_SDCA_SMPU_TRIG_ST_CTRL				0x11
+/* SDCA (Channel) */
+#define CH_00						0x00
+#define CH_01						0x01
+#define CH_02						0x02
+#define CH_03						0x03
+#define CH_04						0x04
+#define CH_05						0x05
+#define CH_06						0x06
+#define CH_07						0x07
+#define CH_08						0x08
+
+#define RT715_SDCA_DB_STEP			375
+
+enum {
+	RT715_AIF1,
+	RT715_AIF2,
+};
+
+int rt715_io_init(struct device *dev, struct sdw_slave *slave);
+int rt715_init(struct device *dev, struct regmap *mbq_regmap,
+	struct regmap *regmap, struct sdw_slave *slave);
+
+#endif /* __RT715_SDCA_H__ */
diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c
index 532c5303e7ab..9a7d393d424a 100644
--- a/sound/soc/codecs/rt715.c
+++ b/sound/soc/codecs/rt715.c
@@ -537,7 +537,7 @@ static int rt715_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
 	if (!stream)
 		return -ENOMEM;
 
-	stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
+	stream->sdw_stream = sdw_stream;
 
 	/* Use tx_mask or rx_mask to configure stream tag and set dma_data */
 	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h
index d0d0fd2a6fdb..009a8266f606 100644
--- a/sound/soc/codecs/rt715.h
+++ b/sound/soc/codecs/rt715.h
@@ -207,7 +207,6 @@ struct sdw_stream_data {
 enum {
 	RT715_AIF1,
 	RT715_AIF2,
-	RT715_AIFS,
 };
 
 #define RT715_POWER_UP_DELAY_MS 400
diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c
new file mode 100644
index 000000000000..e0a09dadfa7c
--- /dev/null
+++ b/sound/soc/codecs/simple-mux.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020 Bootlin SA
+ * Author: Alexandre Belloni <alexandre.belloni@bootlin.com>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <sound/soc.h>
+
+struct simple_mux {
+	struct gpio_desc *gpiod_mux;
+	unsigned int mux;
+};
+
+static const char * const simple_mux_texts[] = {
+	"Input 1", "Input 2"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(simple_mux_enum, simple_mux_texts);
+
+static int simple_mux_control_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
+	struct simple_mux *priv = snd_soc_component_get_drvdata(c);
+
+	ucontrol->value.enumerated.item[0] = priv->mux;
+
+	return 0;
+}
+
+static int simple_mux_control_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
+	struct simple_mux *priv = snd_soc_component_get_drvdata(c);
+
+	if (ucontrol->value.enumerated.item[0] > e->items)
+		return -EINVAL;
+
+	if (priv->mux == ucontrol->value.enumerated.item[0])
+		return 0;
+
+	priv->mux = ucontrol->value.enumerated.item[0];
+
+	gpiod_set_value_cansleep(priv->gpiod_mux, priv->mux);
+
+	return snd_soc_dapm_mux_update_power(dapm, kcontrol,
+					     ucontrol->value.enumerated.item[0],
+					     e, NULL);
+}
+
+static const struct snd_kcontrol_new simple_mux_mux =
+	SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put);
+
+static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("IN1"),
+	SND_SOC_DAPM_INPUT("IN2"),
+	SND_SOC_DAPM_MUX("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux),
+	SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route simple_mux_dapm_routes[] = {
+	{ "OUT", NULL, "MUX" },
+	{ "MUX", "Input 1", "IN1" },
+	{ "MUX", "Input 2", "IN2" },
+};
+
+static const struct snd_soc_component_driver simple_mux_component_driver = {
+	.dapm_widgets		= simple_mux_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(simple_mux_dapm_widgets),
+	.dapm_routes		= simple_mux_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(simple_mux_dapm_routes),
+};
+
+static int simple_mux_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct simple_mux *priv;
+	int err;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, priv);
+
+	priv->gpiod_mux = devm_gpiod_get(dev, "mux", GPIOD_OUT_LOW);
+	if (IS_ERR(priv->gpiod_mux)) {
+		err = PTR_ERR(priv->gpiod_mux);
+		if (err != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get 'mux' gpio: %d", err);
+		return err;
+	}
+
+	return devm_snd_soc_register_component(dev, &simple_mux_component_driver, NULL, 0);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id simple_mux_ids[] = {
+	{ .compatible = "simple-audio-mux", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, simple_mux_ids);
+#endif
+
+static struct platform_driver simple_mux_driver = {
+	.driver = {
+		.name = "simple-mux",
+		.of_match_table = of_match_ptr(simple_mux_ids),
+	},
+	.probe = simple_mux_probe,
+};
+
+module_platform_driver(simple_mux_driver);
+
+MODULE_DESCRIPTION("ASoC Simple Audio Mux driver");
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c
index f1ff204e3ad0..19965fabe949 100644
--- a/sound/soc/codecs/tas2562.c
+++ b/sound/soc/codecs/tas2562.c
@@ -802,6 +802,7 @@ static const struct i2c_device_id tas2562_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tas2562_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id tas2562_of_match[] = {
 	{ .compatible = "ti,tas2562", },
 	{ .compatible = "ti,tas2563", },
@@ -810,6 +811,7 @@ static const struct of_device_id tas2562_of_match[] = {
 	{ },
 };
 MODULE_DEVICE_TABLE(of, tas2562_of_match);
+#endif
 
 static struct i2c_driver tas2562_i2c_driver = {
 	.driver = {
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c
index 835a723ce5bc..a3e682376946 100644
--- a/sound/soc/codecs/tas571x.c
+++ b/sound/soc/codecs/tas571x.c
@@ -773,7 +773,7 @@ static struct snd_soc_dai_driver tas571x_dai = {
 	.ops = &tas571x_dai_ops,
 };
 
-static const struct of_device_id tas571x_of_match[];
+static const struct of_device_id tas571x_of_match[] __maybe_unused;
 
 static int tas571x_i2c_probe(struct i2c_client *client,
 			     const struct i2c_device_id *id)
@@ -889,7 +889,7 @@ static int tas571x_i2c_remove(struct i2c_client *client)
 	return 0;
 }
 
-static const struct of_device_id tas571x_of_match[] = {
+static const struct of_device_id tas571x_of_match[] __maybe_unused = {
 	{ .compatible = "ti,tas5707", .data = &tas5707_chip, },
 	{ .compatible = "ti,tas5711", .data = &tas5711_chip, },
 	{ .compatible = "ti,tas5717", .data = &tas5717_chip, },
diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c
index 53a80246aee1..3f027c8234a6 100644
--- a/sound/soc/codecs/tlv320adcx140.c
+++ b/sound/soc/codecs/tlv320adcx140.c
@@ -1073,6 +1073,7 @@ static struct snd_soc_dai_driver adcx140_dai_driver[] = {
 	}
 };
 
+#ifdef CONFIG_OF
 static const struct of_device_id tlv320adcx140_of_match[] = {
 	{ .compatible = "ti,tlv320adc3140" },
 	{ .compatible = "ti,tlv320adc5140" },
@@ -1080,6 +1081,7 @@ static const struct of_device_id tlv320adcx140_of_match[] = {
 	{},
 };
 MODULE_DEVICE_TABLE(of, tlv320adcx140_of_match);
+#endif
 
 static int adcx140_i2c_probe(struct i2c_client *i2c,
 			     const struct i2c_device_id *id)
diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c
index 5025e5c43783..dbb8f969274c 100644
--- a/sound/soc/codecs/tlv320aic23-i2c.c
+++ b/sound/soc/codecs/tlv320aic23-i2c.c
@@ -35,11 +35,13 @@ static const struct i2c_device_id tlv320aic23_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
 
+#ifdef CONFIG_OF
 static const struct of_device_id tlv320aic23_of_match[] = {
 	{ .compatible = "ti,tlv320aic23", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, tlv320aic23_of_match);
+#endif
 
 static struct i2c_driver tlv320aic23_i2c_driver = {
 	.driver = {
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
index 3ed3b45fa7ba..962f5d48378a 100644
--- a/sound/soc/codecs/ts3a227e.c
+++ b/sound/soc/codecs/ts3a227e.c
@@ -366,11 +366,13 @@ static const struct i2c_device_id ts3a227e_i2c_ids[] = {
 };
 MODULE_DEVICE_TABLE(i2c, ts3a227e_i2c_ids);
 
+#ifdef CONFIG_OF
 static const struct of_device_id ts3a227e_of_match[] = {
 	{ .compatible = "ti,ts3a227e", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, ts3a227e_of_match);
+#endif
 
 #ifdef CONFIG_ACPI
 static struct acpi_device_id ts3a227e_acpi_match[] = {
diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c
index 3265d3e8cb28..6200fab7896f 100644
--- a/sound/soc/codecs/tscs42xx.c
+++ b/sound/soc/codecs/tscs42xx.c
@@ -66,7 +66,7 @@ static bool tscs42xx_volatile(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static bool tscs42xx_precious(struct device *dev, unsigned int reg)
@@ -81,7 +81,7 @@ static bool tscs42xx_precious(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static const struct regmap_config tscs42xx_regmap = {
@@ -1294,7 +1294,7 @@ static int part_is_valid(struct tscs42xx *tscs42xx)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static int set_sysclk(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c
index d0af16b4db2f..cd1f1a592386 100644
--- a/sound/soc/codecs/tscs454.c
+++ b/sound/soc/codecs/tscs454.c
@@ -177,7 +177,7 @@ static bool tscs454_volatile(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static bool tscs454_writable(struct device *dev, unsigned int reg)
@@ -197,7 +197,7 @@ static bool tscs454_writable(struct device *dev, unsigned int reg)
 		return false;
 	default:
 		return true;
-	};
+	}
 }
 
 static bool tscs454_readable(struct device *dev, unsigned int reg)
@@ -217,7 +217,7 @@ static bool tscs454_readable(struct device *dev, unsigned int reg)
 		return false;
 	default:
 		return true;
-	};
+	}
 }
 
 static bool tscs454_precious(struct device *dev, unsigned int reg)
@@ -246,7 +246,7 @@ static bool tscs454_precious(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static const struct regmap_range_cfg tscs454_regmap_range_cfg = {
diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c
index 1be82113c59a..817d8259758c 100644
--- a/sound/soc/codecs/wcd-clsh-v2.c
+++ b/sound/soc/codecs/wcd-clsh-v2.c
@@ -480,7 +480,6 @@ static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state,
 	case WCD_CLSH_STATE_HPHR:
 		wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode);
 		break;
-		break;
 	case WCD_CLSH_STATE_LO:
 		wcd_clsh_state_lo(ctrl, req_state, is_enable, mode);
 		break;
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 4d2b1ec7c03b..9ddfed797b7e 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -3979,7 +3979,7 @@ static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
 	}
 
 	for_each_set_bit(j, &status, 32) {
-		tx = (j >= 16 ? true : false);
+		tx = (j >= 16);
 		port_id = (tx ? j - 16 : j);
 		regmap_read(wcd->if_regmap,
 				WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0 + j, &val);
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index c56b9329240f..d8ced4559bf2 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -311,7 +311,6 @@ static int wl1273_startup(struct snd_pcm_substream *substream,
 		break;
 	default:
 		return -EINVAL;
-		break;
 	}
 
 	return 0;
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 2ed3fa67027d..70d353b63fe0 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -682,9 +682,7 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
 	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 
 	mutex_lock(&arizona->dac_comp_lock);
-	memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data,
-	       sizeof(arizona->dac_comp_coeff));
-	arizona->dac_comp_coeff = be16_to_cpu(arizona->dac_comp_coeff);
+	arizona->dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data);
 	mutex_unlock(&arizona->dac_comp_lock);
 
 	return 0;
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index a6aa212fa0c8..15d42ce3b21d 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -218,7 +218,8 @@ static void wm8350_pga_work(struct work_struct *work)
 
 	/* PGA volumes have 6 bits of resolution to ramp */
 	for (i = 0; i <= 63; i++) {
-		out1_complete = 1, out2_complete = 1;
+		out1_complete = 1;
+		out2_complete = 1;
 		if (out1->ramp != WM8350_RAMP_NONE)
 			out1_complete = wm8350_out1_ramp_step(wm8350_data);
 		if (out2->ramp != WM8350_RAMP_NONE)
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 0bd3bbc2aacf..3af456010b9c 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -3203,6 +3203,7 @@ static int wm8962_beep_event(struct input_dev *dev, unsigned int type,
 	case SND_BELL:
 		if (hz)
 			hz = 1000;
+		fallthrough;
 	case SND_TONE:
 		break;
 	default:
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index fc9ea198ac79..f57884113406 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -4645,8 +4645,12 @@ static int wm8994_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_idle(&pdev->dev);
 
-	return devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8994,
+	ret = devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8994,
 			wm8994_dai, ARRAY_SIZE(wm8994_dai));
+	if (ret < 0)
+		pm_runtime_disable(&pdev->dev);
+
+	return ret;
 }
 
 static int wm8994_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index 37e4bb3dbd8a..229f2986cd96 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -1177,6 +1177,8 @@ static int wm8997_probe(struct platform_device *pdev)
 		goto err_spk_irqs;
 	}
 
+	return ret;
+
 err_spk_irqs:
 	arizona_free_spk_irqs(arizona);
 
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
index f6c5cc80c970..5413254295b7 100644
--- a/sound/soc/codecs/wm8998.c
+++ b/sound/soc/codecs/wm8998.c
@@ -1375,7 +1375,7 @@ static int wm8998_probe(struct platform_device *pdev)
 
 	ret = arizona_init_spk_irqs(arizona);
 	if (ret < 0)
-		return ret;
+		goto err_pm_disable;
 
 	ret = devm_snd_soc_register_component(&pdev->dev,
 					      &soc_component_dev_wm8998,
@@ -1390,6 +1390,8 @@ static int wm8998_probe(struct platform_device *pdev)
 
 err_spk_irqs:
 	arizona_free_spk_irqs(arizona);
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
 
 	return ret;
 }
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index e61d00486c65..dec8716aa8ef 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -1519,7 +1519,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
 	ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
 	if (!ctl_work) {
 		ret = -ENOMEM;
-		goto err_ctl_cache;
+		goto err_list_del;
 	}
 
 	ctl_work->dsp = dsp;
@@ -1529,7 +1529,8 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
 
 	return 0;
 
-err_ctl_cache:
+err_list_del:
+	list_del(&ctl->list);
 	kfree(ctl->cache);
 err_ctl_subname:
 	kfree(ctl->subname);
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 3f76ff71ea47..84db0b7b9d59 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -95,6 +95,22 @@ config SND_SOC_FSL_EASRC
 	  destination sample rate. It is a new design module compare with the
 	  old ASRC.
 
+config SND_SOC_FSL_XCVR
+	tristate "NXP Audio Transceiver (XCVR) module support"
+	select REGMAP_MMIO
+	select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	help
+	  Say Y if you want to add Audio Transceiver (XCVR) support for NXP
+	  iMX CPUs. XCVR is a digital module that supports HDMI2.1 eARC,
+	  HDMI1.4 ARC and SPDIF.
+
+config SND_SOC_FSL_AUD2HTX
+	tristate "AUDIO TO HDMI TX module support"
+	depends on ARCH_MXC || COMPILE_TEST
+	help
+	  Say Y if you want to add AUDIO TO HDMI TX support for NXP.
+
 config SND_SOC_FSL_UTILS
 	tristate
 
@@ -213,57 +229,18 @@ endif # SND_POWERPC_SOC
 
 config SND_SOC_IMX_PCM_FIQ
 	tristate
-	default y if SND_SOC_IMX_SSI=y && (SND_SOC_FSL_SSI=m || SND_SOC_FSL_SPDIF=m) && (MXC_TZIC || MXC_AVIC)
+	default y if (SND_SOC_FSL_SSI=m || SND_SOC_FSL_SPDIF=m) && (MXC_TZIC || MXC_AVIC)
 	select FIQ
 
 if SND_IMX_SOC
 
-config SND_SOC_IMX_SSI
-	tristate
-	select SND_SOC_FSL_UTILS
-
 comment "SoC Audio support for Freescale i.MX boards:"
 
-config SND_MXC_SOC_WM1133_EV1
-	tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted"
-	depends on MACH_MX31ADS_WM1133_EV1
-	select SND_SOC_WM8350
-	select SND_SOC_IMX_PCM_FIQ
-	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_IMX_SSI
-	help
-	  Enable support for audio on the i.MX31ADS with the WM1133-EV1
-	  PMIC board with WM8835x fitted.
-
-config SND_SOC_MX27VIS_AIC32X4
-	tristate "SoC audio support for Visstrim M10 boards"
-	depends on MACH_IMX27_VISSTRIM_M10 && I2C
-	select SND_SOC_TLV320AIC32X4
-	select SND_SOC_IMX_PCM_DMA
-	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_IMX_SSI
-	help
-	  Say Y if you want to add support for SoC audio on Visstrim SM10
-	  board with TLV320AIC32X4 codec.
-
-config SND_SOC_PHYCORE_AC97
-	tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
-	depends on MACH_PCM043 || MACH_PCA100
-	select SND_SOC_AC97_BUS
-	select SND_SOC_WM9712
-	select SND_SOC_IMX_PCM_FIQ
-	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_IMX_SSI
-	help
-	  Say Y if you want to add support for SoC audio on Phytec phyCORE
-	  and phyCARD boards in AC97 mode
-
 config SND_SOC_EUKREA_TLV320
 	tristate "Eukrea TLV320"
 	depends on ARCH_MXC && !ARM64 && I2C
 	select SND_SOC_TLV320AIC23_I2C
 	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_IMX_SSI
 	select SND_SOC_FSL_SSI
 	select SND_SOC_IMX_PCM_DMA
 	help
@@ -302,14 +279,6 @@ config SND_SOC_IMX_SPDIF
 	  Say Y if you want to add support for SoC audio on an i.MX board with
 	  a S/DPDIF.
 
-config SND_SOC_IMX_MC13783
-	tristate "SoC Audio support for I.MX boards with mc13783"
-	depends on MFD_MC13XXX && ARM
-	select SND_SOC_IMX_SSI
-	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_MC13783
-	select SND_SOC_IMX_PCM_DMA
-
 config SND_SOC_FSL_ASOC_CARD
 	tristate "Generic ASoC Sound Card with ASRC support"
 	depends on OF && I2C
@@ -336,6 +305,18 @@ config SND_SOC_IMX_AUDMIX
 	  Say Y if you want to add support for SoC audio on an i.MX board with
 	  an Audio Mixer.
 
+config SND_SOC_IMX_HDMI
+	tristate "SoC Audio support for i.MX boards with HDMI port"
+	select SND_SOC_FSL_SAI
+	select SND_SOC_FSL_AUD2HTX
+	select SND_SOC_HDMI_CODEC
+	help
+	  ALSA SoC Audio support with HDMI feature for Freescale SoCs that have
+	  SAI/AUD2HTX and connect with internal HDMI IP or external module
+	  SII902X.
+	  Say Y if you want to add support for SoC audio on an i.MX board with
+	  IMX HDMI.
+
 endif # SND_IMX_SOC
 
 endmenu
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index b835eebf8825..8c5fa8a859c0 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -25,6 +25,8 @@ snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
 snd-soc-fsl-mqs-objs := fsl_mqs.o
 snd-soc-fsl-easrc-objs := fsl_easrc.o
+snd-soc-fsl-xcvr-objs := fsl_xcvr.o
+snd-soc-fsl-aud2htx-objs := fsl_aud2htx.o
 
 obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
 obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
@@ -38,6 +40,8 @@ obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
 obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o
 obj-$(CONFIG_SND_SOC_FSL_EASRC) += snd-soc-fsl-easrc.o
 obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
+obj-$(CONFIG_SND_SOC_FSL_XCVR) += snd-soc-fsl-xcvr.o
+obj-$(CONFIG_SND_SOC_FSL_AUD2HTX) += snd-soc-fsl-aud2htx.o
 
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
@@ -49,9 +53,7 @@ obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
 obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
 
 # i.MX Platform Support
-snd-soc-imx-ssi-objs := imx-ssi.o
 snd-soc-imx-audmux-objs := imx-audmux.o
-obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
 obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
 
 obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o
@@ -59,21 +61,15 @@ obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o
 
 # i.MX Machine Support
 snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
-snd-soc-phycore-ac97-objs := phycore-ac97.o
-snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
-snd-soc-wm1133-ev1-objs := wm1133-ev1.o
 snd-soc-imx-es8328-objs := imx-es8328.o
 snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
 snd-soc-imx-spdif-objs := imx-spdif.o
-snd-soc-imx-mc13783-objs := imx-mc13783.o
 snd-soc-imx-audmix-objs := imx-audmix.o
+snd-soc-imx-hdmi-objs := imx-hdmi.o
 
 obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
-obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
-obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
-obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
 obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o
 obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
 obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
-obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
 obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o
+obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index a2dd3b6b7fec..f62f81ceab0d 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -131,6 +131,13 @@ static const struct snd_soc_dapm_route audio_map_tx[] = {
 	{"CPU-Playback",  NULL, "ASRC-Playback"},
 };
 
+static const struct snd_soc_dapm_route audio_map_rx[] = {
+	/* 1st half -- Normal DAPM routes */
+	{"CPU-Capture",  NULL, "Capture"},
+	/* 2nd half -- ASRC DAPM routes */
+	{"ASRC-Capture",  NULL, "CPU-Capture"},
+};
+
 /* Add all possible widgets into here without being redundant */
 static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
 	SND_SOC_DAPM_LINE("Line Out Jack", NULL),
@@ -653,6 +660,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 		priv->cpu_priv.slot_width = 32;
 		priv->card.dapm_routes = audio_map_tx;
 		priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
+	} else if (of_device_is_compatible(np, "fsl,imx-audio-si476x")) {
+		codec_dai_name = "si476x-codec";
+		priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+		priv->card.dapm_routes = audio_map_rx;
+		priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx);
 	} else {
 		dev_err(&pdev->dev, "unknown Device Tree compatible\n");
 		ret = -EINVAL;
@@ -869,6 +881,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = {
 	{ .compatible = "fsl,imx-audio-wm8960", },
 	{ .compatible = "fsl,imx-audio-mqs", },
 	{ .compatible = "fsl,imx-audio-wm8524", },
+	{ .compatible = "fsl,imx-audio-si476x", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids);
diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c
new file mode 100644
index 000000000000..d70d5e75a30c
--- /dev/null
+++ b/sound/soc/fsl/fsl_aud2htx.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2020 NXP
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/pm_qos.h>
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/dma-mapping.h>
+
+#include "fsl_aud2htx.h"
+#include "imx-pcm.h"
+
+static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
+{
+	struct fsl_aud2htx *aud2htx = snd_soc_dai_get_drvdata(dai);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL,
+				   AUD2HTX_CTRL_EN, AUD2HTX_CTRL_EN);
+		regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+				   AUD2HTX_CTRE_DE, AUD2HTX_CTRE_DE);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+				   AUD2HTX_CTRE_DE, 0);
+		regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL,
+				   AUD2HTX_CTRL_EN, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = {
+	.trigger	= fsl_aud2htx_trigger,
+};
+
+static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+	struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev);
+
+	/* DMA request when number of entries < WTMK_LOW */
+	regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+			   AUD2HTX_CTRE_DT_MASK, 0);
+
+	/* Disable interrupts*/
+	regmap_update_bits(aud2htx->regmap, AUD2HTX_IRQ_MASK,
+			   AUD2HTX_WM_HIGH_IRQ_MASK |
+			   AUD2HTX_WM_LOW_IRQ_MASK |
+			   AUD2HTX_OVF_MASK,
+			   AUD2HTX_WM_HIGH_IRQ_MASK |
+			   AUD2HTX_WM_LOW_IRQ_MASK |
+			   AUD2HTX_OVF_MASK);
+
+	/* Configure watermark */
+	regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+			   AUD2HTX_CTRE_WL_MASK,
+			   AUD2HTX_WTMK_LOW << AUD2HTX_CTRE_WL_SHIFT);
+	regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+			   AUD2HTX_CTRE_WH_MASK,
+			   AUD2HTX_WTMK_HIGH << AUD2HTX_CTRE_WH_SHIFT);
+
+	snd_soc_dai_init_dma_data(cpu_dai, &aud2htx->dma_params_tx,
+				  &aud2htx->dma_params_rx);
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver fsl_aud2htx_dai = {
+	.probe = fsl_aud2htx_dai_probe,
+	.playback = {
+		.stream_name = "CPU-Playback",
+		.channels_min = 1,
+		.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 = FSL_AUD2HTX_FORMATS,
+	},
+	.ops = &fsl_aud2htx_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_aud2htx_component = {
+	.name	= "fsl-aud2htx",
+};
+
+static const struct reg_default fsl_aud2htx_reg_defaults[] = {
+	{AUD2HTX_CTRL,		0x00000000},
+	{AUD2HTX_CTRL_EXT,	0x00000000},
+	{AUD2HTX_WR,		0x00000000},
+	{AUD2HTX_STATUS,	0x00000000},
+	{AUD2HTX_IRQ_NOMASK,	0x00000000},
+	{AUD2HTX_IRQ_MASKED,	0x00000000},
+	{AUD2HTX_IRQ_MASK,	0x00000000},
+};
+
+static bool fsl_aud2htx_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AUD2HTX_CTRL:
+	case AUD2HTX_CTRL_EXT:
+	case AUD2HTX_STATUS:
+	case AUD2HTX_IRQ_NOMASK:
+	case AUD2HTX_IRQ_MASKED:
+	case AUD2HTX_IRQ_MASK:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool fsl_aud2htx_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AUD2HTX_CTRL:
+	case AUD2HTX_CTRL_EXT:
+	case AUD2HTX_WR:
+	case AUD2HTX_IRQ_NOMASK:
+	case AUD2HTX_IRQ_MASKED:
+	case AUD2HTX_IRQ_MASK:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool fsl_aud2htx_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AUD2HTX_STATUS:
+	case AUD2HTX_IRQ_NOMASK:
+	case AUD2HTX_IRQ_MASKED:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config fsl_aud2htx_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+
+	.max_register = AUD2HTX_IRQ_MASK,
+	.reg_defaults = fsl_aud2htx_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(fsl_aud2htx_reg_defaults),
+	.readable_reg = fsl_aud2htx_readable_reg,
+	.volatile_reg = fsl_aud2htx_volatile_reg,
+	.writeable_reg = fsl_aud2htx_writeable_reg,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const struct of_device_id fsl_aud2htx_dt_ids[] = {
+	{ .compatible = "fsl,imx8mp-aud2htx",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, fsl_aud2htx_dt_ids);
+
+static irqreturn_t fsl_aud2htx_isr(int irq, void *dev_id)
+{
+	return IRQ_HANDLED;
+}
+
+static int fsl_aud2htx_probe(struct platform_device *pdev)
+{
+	struct fsl_aud2htx *aud2htx;
+	struct resource *res;
+	void __iomem *regs;
+	int ret, irq;
+
+	aud2htx = devm_kzalloc(&pdev->dev, sizeof(*aud2htx), GFP_KERNEL);
+	if (!aud2htx)
+		return -ENOMEM;
+
+	aud2htx->pdev = pdev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(regs)) {
+		dev_err(&pdev->dev, "failed ioremap\n");
+		return PTR_ERR(regs);
+	}
+
+	aud2htx->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+						&fsl_aud2htx_regmap_config);
+	if (IS_ERR(aud2htx->regmap)) {
+		dev_err(&pdev->dev, "failed to init regmap");
+		return PTR_ERR(aud2htx->regmap);
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	ret = devm_request_irq(&pdev->dev, irq, fsl_aud2htx_isr, 0,
+			       dev_name(&pdev->dev), aud2htx);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret);
+		return ret;
+	}
+
+	aud2htx->bus_clk = devm_clk_get(&pdev->dev, "bus");
+	if (IS_ERR(aud2htx->bus_clk)) {
+		dev_err(&pdev->dev, "failed to get mem clock\n");
+		return PTR_ERR(aud2htx->bus_clk);
+	}
+
+	aud2htx->dma_params_tx.chan_name = "tx";
+	aud2htx->dma_params_tx.maxburst = AUD2HTX_MAXBURST;
+	aud2htx->dma_params_tx.addr = res->start + AUD2HTX_WR;
+
+	platform_set_drvdata(pdev, aud2htx);
+	pm_runtime_enable(&pdev->dev);
+
+	regcache_cache_only(aud2htx->regmap, true);
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &fsl_aud2htx_component,
+					      &fsl_aud2htx_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register ASoC DAI\n");
+		return ret;
+	}
+
+	ret = imx_pcm_dma_init(pdev, IMX_DEFAULT_DMABUF_SIZE);
+	if (ret)
+		dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
+
+	return ret;
+}
+
+static int fsl_aud2htx_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static int __maybe_unused fsl_aud2htx_runtime_suspend(struct device *dev)
+{
+	struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
+
+	regcache_cache_only(aud2htx->regmap, true);
+	clk_disable_unprepare(aud2htx->bus_clk);
+
+	return 0;
+}
+
+static int __maybe_unused fsl_aud2htx_runtime_resume(struct device *dev)
+{
+	struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(aud2htx->bus_clk);
+	if (ret)
+		return ret;
+
+	regcache_cache_only(aud2htx->regmap, false);
+	regcache_mark_dirty(aud2htx->regmap);
+	regcache_sync(aud2htx->regmap);
+
+	return 0;
+}
+
+static const struct dev_pm_ops fsl_aud2htx_pm_ops = {
+	SET_RUNTIME_PM_OPS(fsl_aud2htx_runtime_suspend,
+			   fsl_aud2htx_runtime_resume,
+			   NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_aud2htx_driver = {
+	.probe = fsl_aud2htx_probe,
+	.remove = fsl_aud2htx_remove,
+	.driver = {
+		.name = "fsl-aud2htx",
+		.pm = &fsl_aud2htx_pm_ops,
+		.of_match_table = fsl_aud2htx_dt_ids,
+	},
+};
+module_platform_driver(fsl_aud2htx_driver);
+
+MODULE_AUTHOR("Shengjiu Wang <Shengjiu.Wang@nxp.com>");
+MODULE_DESCRIPTION("NXP AUD2HTX driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_aud2htx.h b/sound/soc/fsl/fsl_aud2htx.h
new file mode 100644
index 000000000000..ad70d6a7694c
--- /dev/null
+++ b/sound/soc/fsl/fsl_aud2htx.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2020 NXP
+ */
+
+#ifndef _FSL_AUD2HTX_H
+#define _FSL_AUD2HTX_H
+
+#define FSL_AUD2HTX_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \
+			     SNDRV_PCM_FMTBIT_S32_LE)
+
+/* AUD2HTX Register Map */
+#define AUD2HTX_CTRL          0x0   /* AUD2HTX Control Register */
+#define AUD2HTX_CTRL_EXT      0x4   /* AUD2HTX Control Extended Register */
+#define AUD2HTX_WR            0x8   /* AUD2HTX Write Register */
+#define AUD2HTX_STATUS        0xC   /* AUD2HTX Status Register */
+#define AUD2HTX_IRQ_NOMASK    0x10  /* AUD2HTX Nonmasked Interrupt Flags Register */
+#define AUD2HTX_IRQ_MASKED    0x14  /* AUD2HTX Masked Interrupt Flags Register */
+#define AUD2HTX_IRQ_MASK      0x18  /* AUD2HTX IRQ Masks Register */
+
+/* AUD2HTX Control Register */
+#define AUD2HTX_CTRL_EN          BIT(0)
+
+/* AUD2HTX Control Extended Register */
+#define AUD2HTX_CTRE_DE          BIT(0)
+#define AUD2HTX_CTRE_DT_SHIFT    0x1
+#define AUD2HTX_CTRE_DT_WIDTH    0x2
+#define AUD2HTX_CTRE_DT_MASK     ((BIT(AUD2HTX_CTRE_DT_WIDTH) - 1) \
+				 << AUD2HTX_CTRE_DT_SHIFT)
+#define AUD2HTX_CTRE_WL_SHIFT    16
+#define AUD2HTX_CTRE_WL_WIDTH    5
+#define AUD2HTX_CTRE_WL_MASK     ((BIT(AUD2HTX_CTRE_WL_WIDTH) - 1) \
+				 << AUD2HTX_CTRE_WL_SHIFT)
+#define AUD2HTX_CTRE_WH_SHIFT    24
+#define AUD2HTX_CTRE_WH_WIDTH    5
+#define AUD2HTX_CTRE_WH_MASK     ((BIT(AUD2HTX_CTRE_WH_WIDTH) - 1) \
+				 << AUD2HTX_CTRE_WH_SHIFT)
+
+/* AUD2HTX IRQ Masks Register */
+#define AUD2HTX_WM_HIGH_IRQ_MASK BIT(2)
+#define AUD2HTX_WM_LOW_IRQ_MASK  BIT(1)
+#define AUD2HTX_OVF_MASK         BIT(0)
+
+#define AUD2HTX_FIFO_DEPTH       0x20
+#define AUD2HTX_WTMK_LOW         0x10
+#define AUD2HTX_WTMK_HIGH        0x10
+#define AUD2HTX_MAXBURST         0x10
+
+/**
+ * fsl_aud2htx: AUD2HTX private data
+ *
+ * @pdev: platform device pointer
+ * @regmap: regmap handler
+ * @bus_clk: clock source to access register
+ * @dma_params_rx: DMA parameters for receive channel
+ * @dma_params_tx: DMA parameters for transmit channel
+ */
+struct fsl_aud2htx {
+	struct platform_device *pdev;
+	struct regmap *regmap;
+	struct clk *bus_clk;
+
+	struct snd_dmaengine_dai_dma_data dma_params_rx;
+	struct snd_dmaengine_dai_dma_data dma_params_tx;
+};
+
+#endif /* _FSL_AUD2HTX_H */
diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
index 7ad5925772e8..8dc44dec7956 100644
--- a/sound/soc/fsl/fsl_audmix.c
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -455,7 +455,6 @@ static const struct regmap_config fsl_audmix_regmap_config = {
 static const struct of_device_id fsl_audmix_ids[] = {
 	{
 		.compatible = "fsl,imx8qm-audmix",
-		.data = "imx-audmix",
 	},
 	{ /* sentinel */ }
 };
@@ -465,17 +464,9 @@ static int fsl_audmix_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct fsl_audmix *priv;
-	const char *mdrv;
-	const struct of_device_id *of_id;
 	void __iomem *regs;
 	int ret;
 
-	of_id = of_match_device(fsl_audmix_ids, dev);
-	if (!of_id || !of_id->data)
-		return -EINVAL;
-
-	mdrv = of_id->data;
-
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
@@ -510,10 +501,10 @@ static int fsl_audmix_probe(struct platform_device *pdev)
 		goto err_disable_pm;
 	}
 
-	priv->pdev = platform_device_register_data(dev, mdrv, 0, NULL, 0);
+	priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0);
 	if (IS_ERR(priv->pdev)) {
 		ret = PTR_ERR(priv->pdev);
-		dev_err(dev, "failed to register platform %s: %d\n", mdrv, ret);
+		dev_err(dev, "failed to register platform: %d\n", ret);
 		goto err_disable_pm;
 	}
 
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 3e5c1eaccd5e..f3d3d20d35d7 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -359,7 +359,14 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
 	if (sai->is_slave_mode)
 		return 0;
 
-	for (id = 0; id < FSL_SAI_MCLK_MAX; id++) {
+	/*
+	 * There is no point in polling MCLK0 if it is identical to MCLK1.
+	 * And given that MQS use case has to use MCLK1 though two clocks
+	 * are the same, we simply skip MCLK0 and start to find from MCLK1.
+	 */
+	id = sai->soc_data->mclk0_is_mclk1 ? 1 : 0;
+
+	for (; id < FSL_SAI_MCLK_MAX; id++) {
 		clk_rate = clk_get_rate(sai->mclk_clk[id]);
 		if (!clk_rate)
 			continue;
@@ -1040,7 +1047,6 @@ static int fsl_sai_probe(struct platform_device *pdev)
 		sai->bus_clk = NULL;
 	}
 
-	sai->mclk_clk[0] = sai->bus_clk;
 	for (i = 1; i < FSL_SAI_MCLK_MAX; i++) {
 		sprintf(tmp, "mclk%d", i);
 		sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
@@ -1051,6 +1057,11 @@ static int fsl_sai_probe(struct platform_device *pdev)
 		}
 	}
 
+	if (sai->soc_data->mclk0_is_mclk1)
+		sai->mclk_clk[0] = sai->mclk_clk[1];
+	else
+		sai->mclk_clk[0] = sai->bus_clk;
+
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
 		return irq;
@@ -1165,6 +1176,7 @@ static const struct fsl_sai_soc_data fsl_sai_vf610_data = {
 	.use_edma = false,
 	.fifo_depth = 32,
 	.reg_offset = 0,
+	.mclk0_is_mclk1 = false,
 };
 
 static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
@@ -1172,6 +1184,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
 	.use_edma = false,
 	.fifo_depth = 32,
 	.reg_offset = 0,
+	.mclk0_is_mclk1 = true,
 };
 
 static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = {
@@ -1179,6 +1192,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = {
 	.use_edma = false,
 	.fifo_depth = 16,
 	.reg_offset = 8,
+	.mclk0_is_mclk1 = false,
 };
 
 static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = {
@@ -1186,6 +1200,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = {
 	.use_edma = false,
 	.fifo_depth = 128,
 	.reg_offset = 8,
+	.mclk0_is_mclk1 = false,
 };
 
 static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = {
@@ -1193,6 +1208,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = {
 	.use_edma = true,
 	.fifo_depth = 64,
 	.reg_offset = 0,
+	.mclk0_is_mclk1 = false,
 };
 
 static const struct of_device_id fsl_sai_ids[] = {
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index 4bbcd0dbe8f1..ff2619f1b214 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -219,6 +219,7 @@
 struct fsl_sai_soc_data {
 	bool use_imx_pcm;
 	bool use_edma;
+	bool mclk0_is_mclk1;
 	unsigned int fifo_depth;
 	unsigned int reg_offset;
 };
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index b0f643fefe1e..5fa178f3f497 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -49,10 +49,18 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
  * @imx: for imx platform
  * @shared_root_clock: flag of sharing a clock source with others;
  *                     so the driver shouldn't set root clock rate
+ * @interrupts: interrupt number
+ * @tx_burst: tx maxburst size
+ * @rx_burst: rx maxburst size
+ * @tx_formats: tx supported data format
  */
 struct fsl_spdif_soc_data {
 	bool imx;
 	bool shared_root_clock;
+	u32 interrupts;
+	u32 tx_burst;
+	u32 rx_burst;
+	u64 tx_formats;
 };
 
 /*
@@ -128,16 +136,38 @@ struct fsl_spdif_priv {
 static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
 	.imx = false,
 	.shared_root_clock = false,
+	.interrupts = 1,
+	.tx_burst = FSL_SPDIF_TXFIFO_WML,
+	.rx_burst = FSL_SPDIF_RXFIFO_WML,
+	.tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
 };
 
 static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
 	.imx = true,
 	.shared_root_clock = false,
+	.interrupts = 1,
+	.tx_burst = FSL_SPDIF_TXFIFO_WML,
+	.rx_burst = FSL_SPDIF_RXFIFO_WML,
+	.tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
 };
 
 static struct fsl_spdif_soc_data fsl_spdif_imx6sx = {
 	.imx = true,
 	.shared_root_clock = true,
+	.interrupts = 1,
+	.tx_burst = FSL_SPDIF_TXFIFO_WML,
+	.rx_burst = FSL_SPDIF_RXFIFO_WML,
+	.tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
+
+};
+
+static struct fsl_spdif_soc_data fsl_spdif_imx8qm = {
+	.imx = true,
+	.shared_root_clock = true,
+	.interrupts = 2,
+	.tx_burst = 2,		/* Applied for EDMA */
+	.rx_burst = 2,		/* Applied for EDMA */
+	.tx_formats = SNDRV_PCM_FMTBIT_S24_LE,  /* Applied for EDMA */
 };
 
 /* Check if clk is a root clock that does not share clock source with others */
@@ -429,10 +459,18 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
 		rate = SPDIF_TXRATE_48000;
 		csfs = IEC958_AES3_CON_FS_48000;
 		break;
+	case 88200:
+		rate = SPDIF_TXRATE_88200;
+		csfs = IEC958_AES3_CON_FS_88200;
+		break;
 	case 96000:
 		rate = SPDIF_TXRATE_96000;
 		csfs = IEC958_AES3_CON_FS_96000;
 		break;
+	case 176400:
+		rate = SPDIF_TXRATE_176400;
+		csfs = IEC958_AES3_CON_FS_176400;
+		break;
 	case 192000:
 		rate = SPDIF_TXRATE_192000;
 		csfs = IEC958_AES3_CON_FS_192000;
@@ -827,7 +865,7 @@ static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol,
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 1;
 	uinfo->value.integer.min = 16000;
-	uinfo->value.integer.max = 96000;
+	uinfo->value.integer.max = 192000;
 
 	return 0;
 }
@@ -1145,7 +1183,8 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
 				struct clk *clk, u64 savesub,
 				enum spdif_txrate index, bool round)
 {
-	static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
+	static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400,
+				    192000, };
 	bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk);
 	u64 rate_ideal, rate_actual, sub;
 	u32 arate;
@@ -1205,7 +1244,8 @@ out:
 static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
 				enum spdif_txrate index)
 {
-	static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
+	static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400,
+				    192000, };
 	struct platform_device *pdev = spdif_priv->pdev;
 	struct device *dev = &pdev->dev;
 	u64 savesub = 100000, ret;
@@ -1273,6 +1313,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
 	/* Initialize this copy of the CPU DAI driver structure */
 	memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
 	spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev);
+	spdif_priv->cpu_dai_drv.playback.formats =
+				spdif_priv->soc->tx_formats;
 
 	/* Get the addresses and IRQ */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1287,15 +1329,19 @@ static int fsl_spdif_probe(struct platform_device *pdev)
 		return PTR_ERR(spdif_priv->regmap);
 	}
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
+	for (i = 0; i < spdif_priv->soc->interrupts; i++) {
+		irq = platform_get_irq(pdev, i);
+		if (irq < 0) {
+			dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+			return irq;
+		}
 
-	ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
-			       dev_name(&pdev->dev), spdif_priv);
-	if (ret) {
-		dev_err(&pdev->dev, "could not claim irq %u\n", irq);
-		return ret;
+		ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
+				       dev_name(&pdev->dev), spdif_priv);
+		if (ret) {
+			dev_err(&pdev->dev, "could not claim irq %u\n", irq);
+			return ret;
+		}
 	}
 
 	/* Get system clock for rx clock rate calculation */
@@ -1344,8 +1390,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
 
 	spdif_priv->dpll_locked = false;
 
-	spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML;
-	spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML;
+	spdif_priv->dma_params_tx.maxburst = spdif_priv->soc->tx_burst;
+	spdif_priv->dma_params_rx.maxburst = spdif_priv->soc->rx_burst;
 	spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL;
 	spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL;
 
@@ -1458,6 +1504,7 @@ static const struct of_device_id fsl_spdif_dt_ids[] = {
 	{ .compatible = "fsl,imx35-spdif", .data = &fsl_spdif_imx35, },
 	{ .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, },
 	{ .compatible = "fsl,imx6sx-spdif", .data = &fsl_spdif_imx6sx, },
+	{ .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, },
 	{}
 };
 MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h
index e6c61e07bc1a..d5f1dfd58740 100644
--- a/sound/soc/fsl/fsl_spdif.h
+++ b/sound/soc/fsl/fsl_spdif.h
@@ -163,7 +163,9 @@ enum spdif_txrate {
 	SPDIF_TXRATE_32000 = 0,
 	SPDIF_TXRATE_44100,
 	SPDIF_TXRATE_48000,
+	SPDIF_TXRATE_88200,
 	SPDIF_TXRATE_96000,
+	SPDIF_TXRATE_176400,
 	SPDIF_TXRATE_192000,
 };
 #define SPDIF_TXRATE_MAX		(SPDIF_TXRATE_192000 + 1)
@@ -177,15 +179,20 @@ enum spdif_txrate {
 #define FSL_SPDIF_RATES_PLAYBACK	(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)
 
 #define FSL_SPDIF_RATES_CAPTURE		(SNDRV_PCM_RATE_16000 | \
 					 SNDRV_PCM_RATE_32000 |	\
 					 SNDRV_PCM_RATE_44100 | \
 					 SNDRV_PCM_RATE_48000 |	\
+					 SNDRV_PCM_RATE_88200 | \
 					 SNDRV_PCM_RATE_64000 | \
-					 SNDRV_PCM_RATE_96000)
+					 SNDRV_PCM_RATE_96000 | \
+					 SNDRV_PCM_RATE_176400 | \
+					 SNDRV_PCM_RATE_192000)
 
 #define FSL_SPDIF_FORMATS_PLAYBACK	(SNDRV_PCM_FMTBIT_S16_LE | \
 					 SNDRV_PCM_FMTBIT_S20_3LE | \
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
new file mode 100644
index 000000000000..3d58c88ea603
--- /dev/null
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -0,0 +1,1360 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2019 NXP
+
+#include <linux/bitrev.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_iec958.h>
+#include <sound/pcm_params.h>
+
+#include "fsl_xcvr.h"
+#include "imx-pcm.h"
+
+#define FSL_XCVR_CAPDS_SIZE	256
+
+struct fsl_xcvr_soc_data {
+	const char *fw_name;
+};
+
+struct fsl_xcvr {
+	const struct fsl_xcvr_soc_data *soc_data;
+	struct platform_device *pdev;
+	struct regmap *regmap;
+	struct clk *ipg_clk;
+	struct clk *pll_ipg_clk;
+	struct clk *phy_clk;
+	struct clk *spba_clk;
+	struct reset_control *reset;
+	u8 streams;
+	u32 mode;
+	u32 arc_mode;
+	void __iomem *ram_addr;
+	struct snd_dmaengine_dai_dma_data dma_prms_rx;
+	struct snd_dmaengine_dai_dma_data dma_prms_tx;
+	struct snd_aes_iec958 rx_iec958;
+	struct snd_aes_iec958 tx_iec958;
+	u8 cap_ds[FSL_XCVR_CAPDS_SIZE];
+};
+
+static const struct fsl_xcvr_pll_conf {
+	u8 mfi;   /* min=0x18, max=0x38 */
+	u32 mfn;  /* signed int, 2's compl., min=0x3FFF0000, max=0x00010000 */
+	u32 mfd;  /* unsigned int */
+	u32 fout; /* Fout = Fref*(MFI + MFN/MFD), Fref is 24MHz */
+} fsl_xcvr_pll_cfg[] = {
+	{ .mfi = 54, .mfn = 1,  .mfd = 6,   .fout = 1300000000, }, /* 1.3 GHz */
+	{ .mfi = 32, .mfn = 96, .mfd = 125, .fout = 786432000, },  /* 8000 Hz */
+	{ .mfi = 30, .mfn = 66, .mfd = 625, .fout = 722534400, },  /* 11025 Hz */
+	{ .mfi = 29, .mfn = 1,  .mfd = 6,   .fout = 700000000, },  /* 700 MHz */
+};
+
+/*
+ * HDMI2.1 spec defines 6- and 12-channels layout for one bit audio
+ * stream. Todo: to check how this case can be considered below
+ */
+static const u32 fsl_xcvr_earc_channels[] = { 1, 2, 8, 16, 32, };
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_earc_channels_constr = {
+	.count = ARRAY_SIZE(fsl_xcvr_earc_channels),
+	.list = fsl_xcvr_earc_channels,
+};
+
+static const u32 fsl_xcvr_earc_rates[] = {
+	32000, 44100, 48000, 64000, 88200, 96000,
+	128000, 176400, 192000, 256000, 352800, 384000,
+	512000, 705600, 768000, 1024000, 1411200, 1536000,
+};
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_earc_rates_constr = {
+	.count = ARRAY_SIZE(fsl_xcvr_earc_rates),
+	.list = fsl_xcvr_earc_rates,
+};
+
+static const u32 fsl_xcvr_spdif_channels[] = { 2, };
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_spdif_channels_constr = {
+	.count = ARRAY_SIZE(fsl_xcvr_spdif_channels),
+	.list = fsl_xcvr_spdif_channels,
+};
+
+static const u32 fsl_xcvr_spdif_rates[] = {
+	32000, 44100, 48000, 88200, 96000, 176400, 192000,
+};
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_spdif_rates_constr = {
+	.count = ARRAY_SIZE(fsl_xcvr_spdif_rates),
+	.list = fsl_xcvr_spdif_rates,
+};
+
+static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int *item = ucontrol->value.enumerated.item;
+
+	xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]);
+
+	return 0;
+}
+
+static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	ucontrol->value.enumerated.item[0] = xcvr->arc_mode;
+
+	return 0;
+}
+
+static const u32 fsl_xcvr_phy_arc_cfg[] = {
+	FSL_XCVR_PHY_CTRL_ARC_MODE_SE_EN, FSL_XCVR_PHY_CTRL_ARC_MODE_CM_EN,
+};
+
+static const char * const fsl_xcvr_arc_mode[] = { "Single Ended", "Common", };
+static const struct soc_enum fsl_xcvr_arc_mode_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fsl_xcvr_arc_mode), fsl_xcvr_arc_mode);
+static struct snd_kcontrol_new fsl_xcvr_arc_mode_kctl =
+	SOC_ENUM_EXT("ARC Mode", fsl_xcvr_arc_mode_enum,
+		     fsl_xcvr_arc_mode_get, fsl_xcvr_arc_mode_put);
+
+/* Capabilities data structure, bytes */
+static int fsl_xcvr_type_capds_bytes_info(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = FSL_XCVR_CAPDS_SIZE;
+
+	return 0;
+}
+
+static int fsl_xcvr_capds_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	memcpy(ucontrol->value.bytes.data, xcvr->cap_ds, FSL_XCVR_CAPDS_SIZE);
+
+	return 0;
+}
+
+static int fsl_xcvr_capds_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	memcpy(xcvr->cap_ds, ucontrol->value.bytes.data, FSL_XCVR_CAPDS_SIZE);
+
+	return 0;
+}
+
+static struct snd_kcontrol_new fsl_xcvr_earc_capds_kctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+	.name = "Capabilities Data Structure",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = fsl_xcvr_type_capds_bytes_info,
+	.get = fsl_xcvr_capds_get,
+	.put = fsl_xcvr_capds_put,
+};
+
+static int fsl_xcvr_activate_ctl(struct snd_soc_dai *dai, const char *name,
+				 bool active)
+{
+	struct snd_soc_card *card = dai->component->card;
+	struct snd_kcontrol *kctl;
+	bool enabled;
+
+	kctl = snd_soc_card_get_kcontrol(card, name);
+	if (kctl == NULL)
+		return -ENOENT;
+
+	enabled = ((kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_WRITE) != 0);
+	if (active == enabled)
+		return 0; /* nothing to do */
+
+	if (active)
+		kctl->vd[0].access |=  SNDRV_CTL_ELEM_ACCESS_WRITE;
+	else
+		kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE;
+
+	snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
+
+	return 1;
+}
+
+static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int *item = ucontrol->value.enumerated.item;
+	struct snd_soc_card *card = dai->component->card;
+	struct snd_soc_pcm_runtime *rtd;
+
+	xcvr->mode = snd_soc_enum_item_to_val(e, item[0]);
+
+	fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
+			      (xcvr->mode == FSL_XCVR_MODE_ARC));
+	fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
+			      (xcvr->mode == FSL_XCVR_MODE_EARC));
+	/* Allow playback for SPDIF only */
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link);
+	rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count =
+		(xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0);
+	return 0;
+}
+
+static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	ucontrol->value.enumerated.item[0] = xcvr->mode;
+
+	return 0;
+}
+
+static const char * const fsl_xcvr_mode[] = { "SPDIF", "ARC RX", "eARC", };
+static const struct soc_enum fsl_xcvr_mode_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fsl_xcvr_mode), fsl_xcvr_mode);
+static struct snd_kcontrol_new fsl_xcvr_mode_kctl =
+	SOC_ENUM_EXT("XCVR Mode", fsl_xcvr_mode_enum,
+		     fsl_xcvr_mode_get, fsl_xcvr_mode_put);
+
+/** phy: true => phy, false => pll */
+static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy)
+{
+	struct device *dev = &xcvr->pdev->dev;
+	u32 val, idx, tidx;
+	int ret;
+
+	idx  = BIT(phy ? 26 : 24);
+	tidx = BIT(phy ? 27 : 25);
+
+	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_CLR, 0xFF);
+	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, reg);
+	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_WDATA, data);
+	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_TOG, idx);
+
+	ret = regmap_read_poll_timeout(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, val,
+				       (val & idx) == ((val & tidx) >> 1),
+				       10, 10000);
+	if (ret)
+		dev_err(dev, "AI timeout: failed to set %s reg 0x%02x=0x%08x\n",
+			phy ? "PHY" : "PLL", reg, data);
+	return ret;
+}
+
+static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx)
+{
+	struct device *dev = &xcvr->pdev->dev;
+	u32 i, div = 0, log2;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) {
+		if (fsl_xcvr_pll_cfg[i].fout % freq == 0) {
+			div = fsl_xcvr_pll_cfg[i].fout / freq;
+			break;
+		}
+	}
+
+	if (!div || i >= ARRAY_SIZE(fsl_xcvr_pll_cfg))
+		return -EINVAL;
+
+	log2 = ilog2(div);
+
+	/* Release AI interface from reset */
+	ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
+			   FSL_XCVR_PHY_AI_CTRL_AI_RESETN);
+	if (ret < 0) {
+		dev_err(dev, "Error while setting IER0: %d\n", ret);
+		return ret;
+	}
+
+	/* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */
+	fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET,
+			  FSL_XCVR_PLL_BANDGAP_EN_VBG, 0);
+
+	/* PLL: CTRL0: DIV_INTEGER */
+	fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0);
+	/* PLL: NUMERATOR: MFN */
+	fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0);
+	/* PLL: DENOMINATOR: MFD */
+	fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0);
+	/* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */
+	fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+			  FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0);
+	udelay(25);
+	/* PLL: CTRL0: Clear Hold Ring Off */
+	fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR,
+			  FSL_XCVR_PLL_CTRL0_HROFF, 0);
+	udelay(100);
+	if (tx) { /* TX is enabled for SPDIF only */
+		/* PLL: POSTDIV: PDIV0 */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
+				  FSL_XCVR_PLL_PDIVx(log2, 0), 0);
+		/* PLL: CTRL_SET: CLKMUX0_EN */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+				  FSL_XCVR_PLL_CTRL0_CM0_EN, 0);
+	} else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */
+		/* PLL: POSTDIV: PDIV1 */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
+				  FSL_XCVR_PLL_PDIVx(log2, 1), 0);
+		/* PLL: CTRL_SET: CLKMUX1_EN */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+				  FSL_XCVR_PLL_CTRL0_CM1_EN, 0);
+	} else { /* SPDIF / ARC RX */
+		/* PLL: POSTDIV: PDIV2 */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
+				  FSL_XCVR_PLL_PDIVx(log2, 2), 0);
+		/* PLL: CTRL_SET: CLKMUX2_EN */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+				  FSL_XCVR_PLL_CTRL0_CM2_EN, 0);
+	}
+
+	if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
+		/* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+				  FSL_XCVR_PHY_CTRL_TSDIFF_OE |
+				  FSL_XCVR_PHY_CTRL_PHY_EN, 1);
+		/* PHY: CTRL2_SET: EARC_TX_MODE */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET,
+				  FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1);
+	} else if (!tx) { /* SPDIF / ARC RX mode */
+		if (xcvr->mode == FSL_XCVR_MODE_SPDIF)
+			/* PHY: CTRL_SET: SPDIF_EN */
+			fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+					  FSL_XCVR_PHY_CTRL_SPDIF_EN, 1);
+		else	/* PHY: CTRL_SET: ARC RX setup */
+			fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+					  FSL_XCVR_PHY_CTRL_PHY_EN |
+					  FSL_XCVR_PHY_CTRL_RX_CM_EN |
+					  fsl_xcvr_phy_arc_cfg[xcvr->arc_mode], 1);
+	}
+
+	dev_dbg(dev, "PLL Fexp: %u, Fout: %u, mfi: %u, mfn: %u, mfd: %d, div: %u, pdiv0: %u\n",
+		freq, fsl_xcvr_pll_cfg[i].fout, fsl_xcvr_pll_cfg[i].mfi,
+		fsl_xcvr_pll_cfg[i].mfn, fsl_xcvr_pll_cfg[i].mfd, div, log2);
+	return 0;
+}
+
+static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)
+{
+	struct device *dev = &xcvr->pdev->dev;
+	int ret;
+
+	clk_disable_unprepare(xcvr->phy_clk);
+	ret = clk_set_rate(xcvr->phy_clk, freq);
+	if (ret < 0) {
+		dev_err(dev, "Error while setting AUD PLL rate: %d\n", ret);
+		return ret;
+	}
+	ret = clk_prepare_enable(xcvr->phy_clk);
+	if (ret) {
+		dev_err(dev, "failed to start PHY clock: %d\n", ret);
+		return ret;
+	}
+
+	/* Release AI interface from reset */
+	ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
+			   FSL_XCVR_PHY_AI_CTRL_AI_RESETN);
+	if (ret < 0) {
+		dev_err(dev, "Error while setting IER0: %d\n", ret);
+		return ret;
+	}
+
+	if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
+		/* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+				  FSL_XCVR_PHY_CTRL_TSDIFF_OE |
+				  FSL_XCVR_PHY_CTRL_PHY_EN, 1);
+		/* PHY: CTRL2_SET: EARC_TX_MODE */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET,
+				  FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1);
+	} else { /* SPDIF mode */
+		/* PHY: CTRL_SET: TX_CLK_AUD_SS | SPDIF_EN */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+				  FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS |
+				  FSL_XCVR_PHY_CTRL_SPDIF_EN, 1);
+	}
+
+	dev_dbg(dev, "PLL Fexp: %u\n", freq);
+
+	return 0;
+}
+
+#define FSL_XCVR_SPDIF_RX_FREQ	175000000
+static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	u32 m_ctl = 0, v_ctl = 0;
+	u32 r = substream->runtime->rate, ch = substream->runtime->channels;
+	u32 fout = 32 * r * ch * 10 * 2;
+	int ret = 0;
+
+	switch (xcvr->mode) {
+	case FSL_XCVR_MODE_SPDIF:
+	case FSL_XCVR_MODE_ARC:
+		if (tx) {
+			ret = fsl_xcvr_en_aud_pll(xcvr, fout);
+			if (ret < 0) {
+				dev_err(dai->dev, "Failed to set TX freq %u: %d\n",
+					fout, ret);
+				return ret;
+			}
+
+			ret = regmap_write(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL_SET,
+					   FSL_XCVR_TX_DPTH_CTRL_FRM_FMT);
+			if (ret < 0) {
+				dev_err(dai->dev, "Failed to set TX_DPTH: %d\n", ret);
+				return ret;
+			}
+
+			/**
+			 * set SPDIF MODE - this flag is used to gate
+			 * SPDIF output, useless for SPDIF RX
+			 */
+			m_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
+			v_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
+		} else {
+			/**
+			 * Clear RX FIFO, flip RX FIFO bits,
+			 * disable eARC related HW mode detects
+			 */
+			ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET,
+					   FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
+					   FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO |
+					   FSL_XCVR_RX_DPTH_CTRL_COMP |
+					   FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
+			if (ret < 0) {
+				dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret);
+				return ret;
+			}
+
+			ret = fsl_xcvr_en_phy_pll(xcvr, FSL_XCVR_SPDIF_RX_FREQ, tx);
+			if (ret < 0) {
+				dev_err(dai->dev, "Failed to set RX freq %u: %d\n",
+					FSL_XCVR_SPDIF_RX_FREQ, ret);
+				return ret;
+			}
+		}
+		break;
+	case FSL_XCVR_MODE_EARC:
+		if (!tx) {
+			/** Clear RX FIFO, flip RX FIFO bits */
+			ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET,
+					   FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
+					   FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO);
+			if (ret < 0) {
+				dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret);
+				return ret;
+			}
+
+			/** Enable eARC related HW mode detects */
+			ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_CLR,
+					   FSL_XCVR_RX_DPTH_CTRL_COMP |
+					   FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
+			if (ret < 0) {
+				dev_err(dai->dev, "Failed to clr TX_DPTH: %d\n", ret);
+				return ret;
+			}
+		}
+
+		/* clear CMDC RESET */
+		m_ctl |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
+		/* set TX_RX_MODE */
+		m_ctl |= FSL_XCVR_EXT_CTRL_TX_RX_MODE;
+		v_ctl |= (tx ? FSL_XCVR_EXT_CTRL_TX_RX_MODE : 0);
+		break;
+	}
+
+	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
+				 FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL);
+	if (ret < 0) {
+		dev_err(dai->dev, "Error while setting IER0: %d\n", ret);
+		return ret;
+	}
+
+	/* clear DPATH RESET */
+	m_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
+	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, m_ctl, v_ctl);
+	if (ret < 0) {
+		dev_err(dai->dev, "Error while setting EXT_CTRL: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int fsl_xcvr_constr(const struct snd_pcm_substream *substream,
+			   const struct snd_pcm_hw_constraint_list *channels,
+			   const struct snd_pcm_hw_constraint_list *rates)
+{
+	struct snd_pcm_runtime *rt = substream->runtime;
+	int ret;
+
+	ret = snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+					 channels);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE,
+					 rates);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int fsl_xcvr_startup(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	int ret = 0;
+
+	if (xcvr->streams & BIT(substream->stream)) {
+		dev_err(dai->dev, "%sX busy\n", tx ? "T" : "R");
+		return -EBUSY;
+	}
+
+	switch (xcvr->mode) {
+	case FSL_XCVR_MODE_SPDIF:
+	case FSL_XCVR_MODE_ARC:
+		ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
+				      &fsl_xcvr_spdif_rates_constr);
+		break;
+	case FSL_XCVR_MODE_EARC:
+		ret = fsl_xcvr_constr(substream, &fsl_xcvr_earc_channels_constr,
+				      &fsl_xcvr_earc_rates_constr);
+		break;
+	}
+	if (ret < 0)
+		return ret;
+
+	xcvr->streams |= BIT(substream->stream);
+
+	/* Disable XCVR controls if there is stream started */
+	fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, false);
+	fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, false);
+	fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, false);
+
+	return 0;
+}
+
+static void fsl_xcvr_shutdown(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	u32 mask = 0, val = 0;
+	int ret;
+
+	xcvr->streams &= ~BIT(substream->stream);
+
+	/* Enable XCVR controls if there is no stream started */
+	if (!xcvr->streams) {
+		fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, true);
+		fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
+				      (xcvr->mode == FSL_XCVR_MODE_ARC));
+		fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
+				      (xcvr->mode == FSL_XCVR_MODE_EARC));
+
+		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
+					 FSL_XCVR_IRQ_EARC_ALL, 0);
+		if (ret < 0) {
+			dev_err(dai->dev, "Failed to set IER0: %d\n", ret);
+			return;
+		}
+
+		/* clear SPDIF MODE */
+		if (xcvr->mode == FSL_XCVR_MODE_SPDIF)
+			mask |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
+	}
+
+	if (xcvr->mode == FSL_XCVR_MODE_EARC) {
+		/* set CMDC RESET */
+		mask |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
+		val  |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
+	}
+
+	/* set DPATH RESET */
+	mask |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
+	val  |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
+
+	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val);
+	if (ret < 0) {
+		dev_err(dai->dev, "Err setting DPATH RESET: %d\n", ret);
+		return;
+	}
+}
+
+static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
+			    struct snd_soc_dai *dai)
+{
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	int ret;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (tx) {
+			switch (xcvr->mode) {
+			case FSL_XCVR_MODE_EARC:
+				/* set isr_cmdc_tx_en, w1c */
+				ret = regmap_write(xcvr->regmap,
+						   FSL_XCVR_ISR_SET,
+						   FSL_XCVR_ISR_CMDC_TX_EN);
+				if (ret < 0) {
+					dev_err(dai->dev, "err updating isr %d\n", ret);
+					return ret;
+				}
+				fallthrough;
+			case FSL_XCVR_MODE_SPDIF:
+				ret = regmap_write(xcvr->regmap,
+					 FSL_XCVR_TX_DPTH_CTRL_SET,
+					 FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
+				if (ret < 0) {
+					dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret);
+					return ret;
+				}
+				break;
+			}
+		}
+
+		/* enable DMA RD/WR */
+		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+					 FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0);
+		if (ret < 0) {
+			dev_err(dai->dev, "Failed to enable DMA: %d\n", ret);
+			return ret;
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		/* disable DMA RD/WR */
+		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+					 FSL_XCVR_EXT_CTRL_DMA_DIS(tx),
+					 FSL_XCVR_EXT_CTRL_DMA_DIS(tx));
+		if (ret < 0) {
+			dev_err(dai->dev, "Failed to disable DMA: %d\n", ret);
+			return ret;
+		}
+
+		if (tx) {
+			switch (xcvr->mode) {
+			case FSL_XCVR_MODE_SPDIF:
+				ret = regmap_write(xcvr->regmap,
+					 FSL_XCVR_TX_DPTH_CTRL_CLR,
+					 FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
+				if (ret < 0) {
+					dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret);
+					return ret;
+				}
+				fallthrough;
+			case FSL_XCVR_MODE_EARC:
+				/* clear ISR_CMDC_TX_EN, W1C */
+				ret = regmap_write(xcvr->regmap,
+						   FSL_XCVR_ISR_CLR,
+						   FSL_XCVR_ISR_CMDC_TX_EN);
+				if (ret < 0) {
+					dev_err(dai->dev,
+						"Err updating ISR %d\n", ret);
+					return ret;
+				}
+				break;
+			}
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr)
+{
+	struct device *dev = &xcvr->pdev->dev;
+	const struct firmware *fw;
+	int ret = 0, rem, off, out, page = 0, size = FSL_XCVR_REG_OFFSET;
+	u32 mask, val;
+
+	ret = request_firmware(&fw, xcvr->soc_data->fw_name, dev);
+	if (ret) {
+		dev_err(dev, "failed to request firmware.\n");
+		return ret;
+	}
+
+	rem = fw->size;
+
+	/* RAM is 20KiB = 16KiB code + 4KiB data => max 10 pages 2KiB each */
+	if (rem > 16384) {
+		dev_err(dev, "FW size %d is bigger than 16KiB.\n", rem);
+		release_firmware(fw);
+		return -ENOMEM;
+	}
+
+	for (page = 0; page < 10; page++) {
+		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+					 FSL_XCVR_EXT_CTRL_PAGE_MASK,
+					 FSL_XCVR_EXT_CTRL_PAGE(page));
+		if (ret < 0) {
+			dev_err(dev, "FW: failed to set page %d, err=%d\n",
+				page, ret);
+			goto err_firmware;
+		}
+
+		off = page * size;
+		out = min(rem, size);
+		/* IPG clock is assumed to be running, otherwise it will hang */
+		if (out > 0) {
+			/* write firmware into code memory */
+			memcpy_toio(xcvr->ram_addr, fw->data + off, out);
+			rem -= out;
+			if (rem == 0) {
+				/* last part of firmware written */
+				/* clean remaining part of code memory page */
+				memset_io(xcvr->ram_addr + out, 0, size - out);
+			}
+		} else {
+			/* clean current page, including data memory */
+			memset_io(xcvr->ram_addr, 0, size);
+		}
+	};
+
+err_firmware:
+	release_firmware(fw);
+	if (ret < 0)
+		return ret;
+
+	/* configure watermarks */
+	mask = FSL_XCVR_EXT_CTRL_RX_FWM_MASK | FSL_XCVR_EXT_CTRL_TX_FWM_MASK;
+	val  = FSL_XCVR_EXT_CTRL_RX_FWM(FSL_XCVR_FIFO_WMK_RX);
+	val |= FSL_XCVR_EXT_CTRL_TX_FWM(FSL_XCVR_FIFO_WMK_TX);
+	/* disable DMA RD/WR */
+	mask |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS;
+	val  |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS;
+	/* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
+	mask |= FSL_XCVR_EXT_CTRL_PAGE_MASK;
+	val  |= FSL_XCVR_EXT_CTRL_PAGE(8);
+
+	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set watermarks: %d\n", ret);
+		return ret;
+	}
+
+	/* Store Capabilities Data Structure into Data RAM */
+	memcpy_toio(xcvr->ram_addr + FSL_XCVR_CAP_DATA_STR, xcvr->cap_ds,
+		    FSL_XCVR_CAPDS_SIZE);
+	return 0;
+}
+
+static int fsl_xcvr_type_iec958_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+
+	return 0;
+}
+
+static int fsl_xcvr_type_iec958_bytes_info(struct snd_kcontrol *kcontrol,
+					   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = sizeof_field(struct snd_aes_iec958, status);
+
+	return 0;
+}
+
+static int fsl_xcvr_rx_cs_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	memcpy(ucontrol->value.iec958.status, xcvr->rx_iec958.status, 24);
+
+	return 0;
+}
+
+static int fsl_xcvr_tx_cs_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	memcpy(ucontrol->value.iec958.status, xcvr->tx_iec958.status, 24);
+
+	return 0;
+}
+
+static int fsl_xcvr_tx_cs_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	memcpy(xcvr->tx_iec958.status, ucontrol->value.iec958.status, 24);
+
+	return 0;
+}
+
+static struct snd_kcontrol_new fsl_xcvr_rx_ctls[] = {
+	/* Channel status controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.info = fsl_xcvr_type_iec958_info,
+		.get = fsl_xcvr_rx_cs_get,
+	},
+	/* Capture channel status, bytes */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "Capture Channel Status",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.info = fsl_xcvr_type_iec958_bytes_info,
+		.get = fsl_xcvr_rx_cs_get,
+	},
+};
+
+static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = {
+	/* Channel status controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = fsl_xcvr_type_iec958_info,
+		.get = fsl_xcvr_tx_cs_get,
+		.put = fsl_xcvr_tx_cs_put,
+	},
+	/* Playback channel status, bytes */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "Playback Channel Status",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = fsl_xcvr_type_iec958_bytes_info,
+		.get = fsl_xcvr_tx_cs_get,
+		.put = fsl_xcvr_tx_cs_put,
+	},
+};
+
+static struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
+	.prepare = fsl_xcvr_prepare,
+	.startup = fsl_xcvr_startup,
+	.shutdown = fsl_xcvr_shutdown,
+	.trigger = fsl_xcvr_trigger,
+};
+
+static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai)
+{
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, &xcvr->dma_prms_tx, &xcvr->dma_prms_rx);
+	snd_soc_dai_set_drvdata(dai, xcvr);
+
+	snd_soc_add_dai_controls(dai, &fsl_xcvr_mode_kctl, 1);
+	snd_soc_add_dai_controls(dai, &fsl_xcvr_arc_mode_kctl, 1);
+	snd_soc_add_dai_controls(dai, &fsl_xcvr_earc_capds_kctl, 1);
+	snd_soc_add_dai_controls(dai, fsl_xcvr_tx_ctls,
+				 ARRAY_SIZE(fsl_xcvr_tx_ctls));
+	snd_soc_add_dai_controls(dai, fsl_xcvr_rx_ctls,
+				 ARRAY_SIZE(fsl_xcvr_rx_ctls));
+	return 0;
+}
+
+static struct snd_soc_dai_driver fsl_xcvr_dai = {
+	.probe  = fsl_xcvr_dai_probe,
+	.ops = &fsl_xcvr_dai_ops,
+	.playback = {
+		.stream_name = "CPU-Playback",
+		.channels_min = 1,
+		.channels_max = 32,
+		.rate_min = 32000,
+		.rate_max = 1536000,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+	},
+	.capture = {
+		.stream_name = "CPU-Capture",
+		.channels_min = 1,
+		.channels_max = 32,
+		.rate_min = 32000,
+		.rate_max = 1536000,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+	},
+};
+
+static const struct snd_soc_component_driver fsl_xcvr_comp = {
+	.name = "fsl-xcvr-dai",
+};
+
+static const struct reg_default fsl_xcvr_reg_defaults[] = {
+	{ FSL_XCVR_VERSION,	0x00000000 },
+	{ FSL_XCVR_EXT_CTRL,	0xF8204040 },
+	{ FSL_XCVR_EXT_STATUS,	0x00000000 },
+	{ FSL_XCVR_EXT_IER0,	0x00000000 },
+	{ FSL_XCVR_EXT_IER1,	0x00000000 },
+	{ FSL_XCVR_EXT_ISR,	0x00000000 },
+	{ FSL_XCVR_EXT_ISR_SET,	0x00000000 },
+	{ FSL_XCVR_EXT_ISR_CLR,	0x00000000 },
+	{ FSL_XCVR_EXT_ISR_TOG,	0x00000000 },
+	{ FSL_XCVR_IER,		0x00000000 },
+	{ FSL_XCVR_ISR,		0x00000000 },
+	{ FSL_XCVR_ISR_SET,	0x00000000 },
+	{ FSL_XCVR_ISR_CLR,	0x00000000 },
+	{ FSL_XCVR_ISR_TOG,	0x00000000 },
+	{ FSL_XCVR_RX_DPTH_CTRL,	0x00002C89 },
+	{ FSL_XCVR_RX_DPTH_CTRL_SET,	0x00002C89 },
+	{ FSL_XCVR_RX_DPTH_CTRL_CLR,	0x00002C89 },
+	{ FSL_XCVR_RX_DPTH_CTRL_TOG,	0x00002C89 },
+	{ FSL_XCVR_TX_DPTH_CTRL,	0x00000000 },
+	{ FSL_XCVR_TX_DPTH_CTRL_SET,	0x00000000 },
+	{ FSL_XCVR_TX_DPTH_CTRL_CLR,	0x00000000 },
+	{ FSL_XCVR_TX_DPTH_CTRL_TOG,	0x00000000 },
+	{ FSL_XCVR_TX_CS_DATA_0,	0x00000000 },
+	{ FSL_XCVR_TX_CS_DATA_1,	0x00000000 },
+	{ FSL_XCVR_TX_CS_DATA_2,	0x00000000 },
+	{ FSL_XCVR_TX_CS_DATA_3,	0x00000000 },
+	{ FSL_XCVR_TX_CS_DATA_4,	0x00000000 },
+	{ FSL_XCVR_TX_CS_DATA_5,	0x00000000 },
+	{ FSL_XCVR_DEBUG_REG_0,		0x00000000 },
+	{ FSL_XCVR_DEBUG_REG_1,		0x00000000 },
+};
+
+static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case FSL_XCVR_VERSION:
+	case FSL_XCVR_EXT_CTRL:
+	case FSL_XCVR_EXT_STATUS:
+	case FSL_XCVR_EXT_IER0:
+	case FSL_XCVR_EXT_IER1:
+	case FSL_XCVR_EXT_ISR:
+	case FSL_XCVR_EXT_ISR_SET:
+	case FSL_XCVR_EXT_ISR_CLR:
+	case FSL_XCVR_EXT_ISR_TOG:
+	case FSL_XCVR_IER:
+	case FSL_XCVR_ISR:
+	case FSL_XCVR_ISR_SET:
+	case FSL_XCVR_ISR_CLR:
+	case FSL_XCVR_ISR_TOG:
+	case FSL_XCVR_PHY_AI_CTRL:
+	case FSL_XCVR_PHY_AI_CTRL_SET:
+	case FSL_XCVR_PHY_AI_CTRL_CLR:
+	case FSL_XCVR_PHY_AI_CTRL_TOG:
+	case FSL_XCVR_PHY_AI_RDATA:
+	case FSL_XCVR_CLK_CTRL:
+	case FSL_XCVR_RX_DPTH_CTRL:
+	case FSL_XCVR_RX_DPTH_CTRL_SET:
+	case FSL_XCVR_RX_DPTH_CTRL_CLR:
+	case FSL_XCVR_RX_DPTH_CTRL_TOG:
+	case FSL_XCVR_TX_DPTH_CTRL:
+	case FSL_XCVR_TX_DPTH_CTRL_SET:
+	case FSL_XCVR_TX_DPTH_CTRL_CLR:
+	case FSL_XCVR_TX_DPTH_CTRL_TOG:
+	case FSL_XCVR_TX_CS_DATA_0:
+	case FSL_XCVR_TX_CS_DATA_1:
+	case FSL_XCVR_TX_CS_DATA_2:
+	case FSL_XCVR_TX_CS_DATA_3:
+	case FSL_XCVR_TX_CS_DATA_4:
+	case FSL_XCVR_TX_CS_DATA_5:
+	case FSL_XCVR_DEBUG_REG_0:
+	case FSL_XCVR_DEBUG_REG_1:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case FSL_XCVR_EXT_CTRL:
+	case FSL_XCVR_EXT_IER0:
+	case FSL_XCVR_EXT_IER1:
+	case FSL_XCVR_EXT_ISR:
+	case FSL_XCVR_EXT_ISR_SET:
+	case FSL_XCVR_EXT_ISR_CLR:
+	case FSL_XCVR_EXT_ISR_TOG:
+	case FSL_XCVR_IER:
+	case FSL_XCVR_ISR_SET:
+	case FSL_XCVR_ISR_CLR:
+	case FSL_XCVR_ISR_TOG:
+	case FSL_XCVR_PHY_AI_CTRL:
+	case FSL_XCVR_PHY_AI_CTRL_SET:
+	case FSL_XCVR_PHY_AI_CTRL_CLR:
+	case FSL_XCVR_PHY_AI_CTRL_TOG:
+	case FSL_XCVR_PHY_AI_WDATA:
+	case FSL_XCVR_CLK_CTRL:
+	case FSL_XCVR_RX_DPTH_CTRL:
+	case FSL_XCVR_RX_DPTH_CTRL_SET:
+	case FSL_XCVR_RX_DPTH_CTRL_CLR:
+	case FSL_XCVR_RX_DPTH_CTRL_TOG:
+	case FSL_XCVR_TX_DPTH_CTRL_SET:
+	case FSL_XCVR_TX_DPTH_CTRL_CLR:
+	case FSL_XCVR_TX_DPTH_CTRL_TOG:
+	case FSL_XCVR_TX_CS_DATA_0:
+	case FSL_XCVR_TX_CS_DATA_1:
+	case FSL_XCVR_TX_CS_DATA_2:
+	case FSL_XCVR_TX_CS_DATA_3:
+	case FSL_XCVR_TX_CS_DATA_4:
+	case FSL_XCVR_TX_CS_DATA_5:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool fsl_xcvr_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return fsl_xcvr_readable_reg(dev, reg);
+}
+
+static const struct regmap_config fsl_xcvr_regmap_cfg = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = FSL_XCVR_MAX_REG,
+	.reg_defaults = fsl_xcvr_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(fsl_xcvr_reg_defaults),
+	.readable_reg = fsl_xcvr_readable_reg,
+	.volatile_reg = fsl_xcvr_volatile_reg,
+	.writeable_reg = fsl_xcvr_writeable_reg,
+	.cache_type = REGCACHE_FLAT,
+};
+
+static irqreturn_t irq0_isr(int irq, void *devid)
+{
+	struct fsl_xcvr *xcvr = (struct fsl_xcvr *)devid;
+	struct device *dev = &xcvr->pdev->dev;
+	struct regmap *regmap = xcvr->regmap;
+	void __iomem *reg_ctrl, *reg_buff;
+	u32 isr, isr_clr = 0, val, i;
+
+	regmap_read(regmap, FSL_XCVR_EXT_ISR, &isr);
+
+	if (isr & FSL_XCVR_IRQ_NEW_CS) {
+		dev_dbg(dev, "Received new CS block\n");
+		isr_clr |= FSL_XCVR_IRQ_NEW_CS;
+		/* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
+		regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+				   FSL_XCVR_EXT_CTRL_PAGE_MASK,
+				   FSL_XCVR_EXT_CTRL_PAGE(8));
+
+		/* Find updated CS buffer */
+		reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_0;
+		reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_0;
+		memcpy_fromio(&val, reg_ctrl, sizeof(val));
+		if (!val) {
+			reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_1;
+			reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_1;
+			memcpy_fromio(&val, reg_ctrl, sizeof(val));
+		}
+
+		if (val) {
+			/* copy CS buffer */
+			memcpy_fromio(&xcvr->rx_iec958.status, reg_buff,
+				      sizeof(xcvr->rx_iec958.status));
+			for (i = 0; i < 6; i++) {
+				val = *(u32 *)(xcvr->rx_iec958.status + i*4);
+				*(u32 *)(xcvr->rx_iec958.status + i*4) =
+					bitrev32(val);
+			}
+			/* clear CS control register */
+			memset_io(reg_ctrl, 0, sizeof(val));
+		}
+	}
+	if (isr & FSL_XCVR_IRQ_NEW_UD) {
+		dev_dbg(dev, "Received new UD block\n");
+		isr_clr |= FSL_XCVR_IRQ_NEW_UD;
+	}
+	if (isr & FSL_XCVR_IRQ_MUTE) {
+		dev_dbg(dev, "HW mute bit detected\n");
+		isr_clr |= FSL_XCVR_IRQ_MUTE;
+	}
+	if (isr & FSL_XCVR_IRQ_FIFO_UOFL_ERR) {
+		dev_dbg(dev, "RX/TX FIFO full/empty\n");
+		isr_clr |= FSL_XCVR_IRQ_FIFO_UOFL_ERR;
+	}
+	if (isr & FSL_XCVR_IRQ_ARC_MODE) {
+		dev_dbg(dev, "CMDC SM falls out of eARC mode\n");
+		isr_clr |= FSL_XCVR_IRQ_ARC_MODE;
+	}
+	if (isr & FSL_XCVR_IRQ_DMA_RD_REQ) {
+		dev_dbg(dev, "DMA read request\n");
+		isr_clr |= FSL_XCVR_IRQ_DMA_RD_REQ;
+	}
+	if (isr & FSL_XCVR_IRQ_DMA_WR_REQ) {
+		dev_dbg(dev, "DMA write request\n");
+		isr_clr |= FSL_XCVR_IRQ_DMA_WR_REQ;
+	}
+
+	if (isr_clr) {
+		regmap_write(regmap, FSL_XCVR_EXT_ISR_CLR, isr_clr);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static const struct fsl_xcvr_soc_data fsl_xcvr_imx8mp_data = {
+	.fw_name = "imx/xcvr/xcvr-imx8mp.bin",
+};
+
+static const struct of_device_id fsl_xcvr_dt_ids[] = {
+	{ .compatible = "fsl,imx8mp-xcvr", .data = &fsl_xcvr_imx8mp_data },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids);
+
+static int fsl_xcvr_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *of_id;
+	struct fsl_xcvr *xcvr;
+	struct resource *ram_res, *regs_res, *rx_res, *tx_res;
+	void __iomem *regs;
+	int ret, irq;
+
+	of_id = of_match_device(fsl_xcvr_dt_ids, dev);
+	if (!of_id)
+		return -EINVAL;
+
+	xcvr = devm_kzalloc(dev, sizeof(*xcvr), GFP_KERNEL);
+	if (!xcvr)
+		return -ENOMEM;
+
+	xcvr->pdev = pdev;
+	xcvr->soc_data = of_device_get_match_data(&pdev->dev);
+
+	xcvr->ipg_clk = devm_clk_get(dev, "ipg");
+	if (IS_ERR(xcvr->ipg_clk)) {
+		dev_err(dev, "failed to get ipg clock\n");
+		return PTR_ERR(xcvr->ipg_clk);
+	}
+
+	xcvr->phy_clk = devm_clk_get(dev, "phy");
+	if (IS_ERR(xcvr->phy_clk)) {
+		dev_err(dev, "failed to get phy clock\n");
+		return PTR_ERR(xcvr->phy_clk);
+	}
+
+	xcvr->spba_clk = devm_clk_get(dev, "spba");
+	if (IS_ERR(xcvr->spba_clk)) {
+		dev_err(dev, "failed to get spba clock\n");
+		return PTR_ERR(xcvr->spba_clk);
+	}
+
+	xcvr->pll_ipg_clk = devm_clk_get(dev, "pll_ipg");
+	if (IS_ERR(xcvr->pll_ipg_clk)) {
+		dev_err(dev, "failed to get pll_ipg clock\n");
+		return PTR_ERR(xcvr->pll_ipg_clk);
+	}
+
+	ram_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ram");
+	xcvr->ram_addr = devm_ioremap_resource(dev, ram_res);
+	if (IS_ERR(xcvr->ram_addr))
+		return PTR_ERR(xcvr->ram_addr);
+
+	regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+	regs = devm_ioremap_resource(dev, regs_res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	xcvr->regmap = devm_regmap_init_mmio_clk(dev, NULL, regs,
+						 &fsl_xcvr_regmap_cfg);
+	if (IS_ERR(xcvr->regmap)) {
+		dev_err(dev, "failed to init XCVR regmap: %ld\n",
+			PTR_ERR(xcvr->regmap));
+		return PTR_ERR(xcvr->regmap);
+	}
+
+	xcvr->reset = devm_reset_control_get_exclusive(dev, NULL);
+	if (IS_ERR(xcvr->reset)) {
+		dev_err(dev, "failed to get XCVR reset control\n");
+		return PTR_ERR(xcvr->reset);
+	}
+
+	/* get IRQs */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "no irq[0]: %d\n", irq);
+		return irq;
+	}
+
+	ret = devm_request_irq(dev, irq, irq0_isr, 0, pdev->name, xcvr);
+	if (ret) {
+		dev_err(dev, "failed to claim IRQ0: %i\n", ret);
+		return ret;
+	}
+
+	rx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rxfifo");
+	tx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "txfifo");
+	xcvr->dma_prms_rx.chan_name = "rx";
+	xcvr->dma_prms_tx.chan_name = "tx";
+	xcvr->dma_prms_rx.addr = rx_res->start;
+	xcvr->dma_prms_tx.addr = tx_res->start;
+	xcvr->dma_prms_rx.maxburst = FSL_XCVR_MAXBURST_RX;
+	xcvr->dma_prms_tx.maxburst = FSL_XCVR_MAXBURST_TX;
+
+	platform_set_drvdata(pdev, xcvr);
+	pm_runtime_enable(dev);
+	regcache_cache_only(xcvr->regmap, true);
+
+	ret = devm_snd_soc_register_component(dev, &fsl_xcvr_comp,
+					      &fsl_xcvr_dai, 1);
+	if (ret) {
+		dev_err(dev, "failed to register component %s\n",
+			fsl_xcvr_comp.name);
+		return ret;
+	}
+
+	ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
+	if (ret)
+		dev_err(dev, "failed to pcm register\n");
+
+	return ret;
+}
+
+static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev)
+{
+	struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
+	int ret;
+
+	/* Assert M0+ reset */
+	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+				 FSL_XCVR_EXT_CTRL_CORE_RESET,
+				 FSL_XCVR_EXT_CTRL_CORE_RESET);
+	if (ret < 0)
+		dev_err(dev, "Failed to assert M0+ core: %d\n", ret);
+
+	ret = reset_control_assert(xcvr->reset);
+	if (ret < 0)
+		dev_err(dev, "Failed to assert M0+ reset: %d\n", ret);
+
+	regcache_cache_only(xcvr->regmap, true);
+
+	clk_disable_unprepare(xcvr->spba_clk);
+	clk_disable_unprepare(xcvr->phy_clk);
+	clk_disable_unprepare(xcvr->pll_ipg_clk);
+	clk_disable_unprepare(xcvr->ipg_clk);
+
+	return 0;
+}
+
+static __maybe_unused int fsl_xcvr_runtime_resume(struct device *dev)
+{
+	struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(xcvr->ipg_clk);
+	if (ret) {
+		dev_err(dev, "failed to start IPG clock.\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(xcvr->pll_ipg_clk);
+	if (ret) {
+		dev_err(dev, "failed to start PLL IPG clock.\n");
+		goto stop_ipg_clk;
+	}
+
+	ret = clk_prepare_enable(xcvr->phy_clk);
+	if (ret) {
+		dev_err(dev, "failed to start PHY clock: %d\n", ret);
+		goto stop_pll_ipg_clk;
+	}
+
+	ret = clk_prepare_enable(xcvr->spba_clk);
+	if (ret) {
+		dev_err(dev, "failed to start SPBA clock.\n");
+		goto stop_phy_clk;
+	}
+
+	regcache_cache_only(xcvr->regmap, false);
+	regcache_mark_dirty(xcvr->regmap);
+	ret = regcache_sync(xcvr->regmap);
+
+	if (ret) {
+		dev_err(dev, "failed to sync regcache.\n");
+		goto stop_spba_clk;
+	}
+
+	ret = reset_control_deassert(xcvr->reset);
+	if (ret) {
+		dev_err(dev, "failed to deassert M0+ reset.\n");
+		goto stop_spba_clk;
+	}
+
+	ret = fsl_xcvr_load_firmware(xcvr);
+	if (ret) {
+		dev_err(dev, "failed to load firmware.\n");
+		goto stop_spba_clk;
+	}
+
+	/* Release M0+ reset */
+	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+				 FSL_XCVR_EXT_CTRL_CORE_RESET, 0);
+	if (ret < 0) {
+		dev_err(dev, "M0+ core release failed: %d\n", ret);
+		goto stop_spba_clk;
+	}
+
+	/* Let M0+ core complete firmware initialization */
+	msleep(50);
+
+	return 0;
+
+stop_spba_clk:
+	clk_disable_unprepare(xcvr->spba_clk);
+stop_phy_clk:
+	clk_disable_unprepare(xcvr->phy_clk);
+stop_pll_ipg_clk:
+	clk_disable_unprepare(xcvr->pll_ipg_clk);
+stop_ipg_clk:
+	clk_disable_unprepare(xcvr->ipg_clk);
+
+	return ret;
+}
+
+static const struct dev_pm_ops fsl_xcvr_pm_ops = {
+	SET_RUNTIME_PM_OPS(fsl_xcvr_runtime_suspend,
+			   fsl_xcvr_runtime_resume,
+			   NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_xcvr_driver = {
+	.probe = fsl_xcvr_probe,
+	.driver = {
+		.name = "fsl,imx8mp-audio-xcvr",
+		.pm = &fsl_xcvr_pm_ops,
+		.of_match_table = fsl_xcvr_dt_ids,
+	},
+};
+module_platform_driver(fsl_xcvr_driver);
+
+MODULE_AUTHOR("Viorel Suman <viorel.suman@nxp.com>");
+MODULE_DESCRIPTION("NXP Audio Transceiver (XCVR) driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h
new file mode 100644
index 000000000000..7f2853c60085
--- /dev/null
+++ b/sound/soc/fsl/fsl_xcvr.h
@@ -0,0 +1,266 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * NXP XCVR ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright 2019 NXP
+ */
+
+#ifndef __FSL_XCVR_H
+#define __FSL_XCVR_H
+
+#define FSL_XCVR_MODE_SPDIF	0
+#define FSL_XCVR_MODE_ARC	1
+#define FSL_XCVR_MODE_EARC	2
+
+/* XCVR Registers */
+#define FSL_XCVR_REG_OFFSET		0x800 /* regs offset */
+#define FSL_XCVR_FIFO_SIZE		0x80  /* 128 */
+#define FSL_XCVR_FIFO_WMK_RX		(FSL_XCVR_FIFO_SIZE >> 1)   /* 64 */
+#define FSL_XCVR_FIFO_WMK_TX		(FSL_XCVR_FIFO_SIZE >> 1)   /* 64 */
+#define FSL_XCVR_MAXBURST_RX		(FSL_XCVR_FIFO_WMK_RX >> 2) /* 16 */
+#define FSL_XCVR_MAXBURST_TX		(FSL_XCVR_FIFO_WMK_TX >> 2) /* 16 */
+
+#define FSL_XCVR_RX_FIFO_ADDR		0x0C00
+#define FSL_XCVR_TX_FIFO_ADDR		0x0E00
+
+#define FSL_XCVR_VERSION		0x00  /* Version */
+#define FSL_XCVR_EXT_CTRL		0x10  /* Control */
+#define FSL_XCVR_EXT_STATUS		0x20  /* Status */
+#define FSL_XCVR_EXT_IER0		0x30  /* Interrupt en 0 */
+#define FSL_XCVR_EXT_IER1		0x40  /* Interrupt en 1 */
+#define FSL_XCVR_EXT_ISR		0x50  /* Interrupt status */
+#define FSL_XCVR_EXT_ISR_SET		0x54  /* Interrupt status */
+#define FSL_XCVR_EXT_ISR_CLR		0x58  /* Interrupt status */
+#define FSL_XCVR_EXT_ISR_TOG		0x5C  /* Interrupt status */
+#define FSL_XCVR_IER			0x70  /* Interrupt en for M0+ */
+#define FSL_XCVR_ISR			0x80  /* Interrupt status */
+#define FSL_XCVR_ISR_SET		0x84  /* Interrupt status set */
+#define FSL_XCVR_ISR_CLR		0x88  /* Interrupt status clear */
+#define FSL_XCVR_ISR_TOG		0x8C  /* Interrupt status toggle */
+#define FSL_XCVR_PHY_AI_CTRL		0x90
+#define FSL_XCVR_PHY_AI_CTRL_SET	0x94
+#define FSL_XCVR_PHY_AI_CTRL_CLR	0x98
+#define FSL_XCVR_PHY_AI_CTRL_TOG	0x9C
+#define FSL_XCVR_PHY_AI_WDATA		0xA0
+#define FSL_XCVR_PHY_AI_RDATA		0xA4
+#define FSL_XCVR_CLK_CTRL		0xB0
+#define FSL_XCVR_RX_DPTH_CTRL		0x180 /* RX datapath ctrl reg */
+#define FSL_XCVR_RX_DPTH_CTRL_SET	0x184
+#define FSL_XCVR_RX_DPTH_CTRL_CLR	0x188
+#define FSL_XCVR_RX_DPTH_CTRL_TOG	0x18c
+
+#define FSL_XCVR_TX_DPTH_CTRL		0x220 /* TX datapath ctrl reg */
+#define FSL_XCVR_TX_DPTH_CTRL_SET	0x224
+#define FSL_XCVR_TX_DPTH_CTRL_CLR	0x228
+#define FSL_XCVR_TX_DPTH_CTRL_TOG	0x22C
+#define FSL_XCVR_TX_CS_DATA_0		0x230 /* TX channel status bits regs */
+#define FSL_XCVR_TX_CS_DATA_1		0x234
+#define FSL_XCVR_TX_CS_DATA_2		0x238
+#define FSL_XCVR_TX_CS_DATA_3		0x23C
+#define FSL_XCVR_TX_CS_DATA_4		0x240
+#define FSL_XCVR_TX_CS_DATA_5		0x244
+#define FSL_XCVR_DEBUG_REG_0		0x2E0
+#define FSL_XCVR_DEBUG_REG_1		0x2F0
+
+#define FSL_XCVR_MAX_REG		FSL_XCVR_DEBUG_REG_1
+
+#define FSL_XCVR_EXT_CTRL_CORE_RESET	BIT(31)
+
+#define FSL_XCVR_EXT_CTRL_RX_CMDC_RESET	BIT(30)
+#define FSL_XCVR_EXT_CTRL_TX_CMDC_RESET	BIT(29)
+#define FSL_XCVR_EXT_CTRL_CMDC_RESET(t) (t ? BIT(29) : BIT(30))
+
+#define FSL_XCVR_EXT_CTRL_RX_DPTH_RESET	BIT(28)
+#define FSL_XCVR_EXT_CTRL_TX_DPTH_RESET	BIT(27)
+#define FSL_XCVR_EXT_CTRL_DPTH_RESET(t) (t ? BIT(27) : BIT(28))
+
+#define FSL_XCVR_EXT_CTRL_TX_RX_MODE	BIT(26)
+#define FSL_XCVR_EXT_CTRL_DMA_RD_DIS	BIT(25)
+#define FSL_XCVR_EXT_CTRL_DMA_WR_DIS	BIT(24)
+#define FSL_XCVR_EXT_CTRL_DMA_DIS(t)	(t ? BIT(24) : BIT(25))
+#define FSL_XCVR_EXT_CTRL_SPDIF_MODE	BIT(23)
+#define FSL_XCVR_EXT_CTRL_SLEEP_MODE	BIT(21)
+
+#define FSL_XCVR_EXT_CTRL_TX_FWM_SHFT	0
+#define FSL_XCVR_EXT_CTRL_TX_FWM_MASK	GENMASK(6, 0)
+#define FSL_XCVR_EXT_CTRL_TX_FWM(i)	(((i) << FSL_XCVR_EXT_CTRL_TX_FWM_SHFT) \
+					  & FSL_XCVR_EXT_CTRL_TX_FWM_MASK)
+#define FSL_XCVR_EXT_CTRL_RX_FWM_SHFT	8
+#define FSL_XCVR_EXT_CTRL_RX_FWM_MASK	GENMASK(14, 8)
+#define FSL_XCVR_EXT_CTRL_RX_FWM(i)	(((i) << FSL_XCVR_EXT_CTRL_RX_FWM_SHFT) \
+					  & FSL_XCVR_EXT_CTRL_RX_FWM_MASK)
+#define FSL_XCVR_EXT_CTRL_PAGE_SHFT	16
+#define FSL_XCVR_EXT_CTRL_PAGE_MASK	GENMASK(19, 16)
+#define FSL_XCVR_EXT_CTRL_PAGE(i)	(((i) << FSL_XCVR_EXT_CTRL_PAGE_SHFT) \
+					  & FSL_XCVR_EXT_CTRL_PAGE_MASK)
+
+#define FSL_XCVR_EXT_STUS_NT_FIFO_ENTR	GENMASK(7, 0)
+#define FSL_XCVR_EXT_STUS_NR_FIFO_ENTR	GENMASK(15, 8)
+#define FSL_XCVR_EXT_STUS_CM0_SLEEPING	BIT(16)
+#define FSL_XCVR_EXT_STUS_CM0_DEEP_SLP	BIT(17)
+#define FSL_XCVR_EXT_STUS_CM0_SLP_HACK	BIT(18)
+#define FSL_XCVR_EXT_STUS_RX_CMDC_RSTO	BIT(23)
+#define FSL_XCVR_EXT_STUS_TX_CMDC_RSTO	BIT(24)
+#define FSL_XCVR_EXT_STUS_RX_CMDC_COTO	BIT(25)
+#define FSL_XCVR_EXT_STUS_TX_CMDC_COTO	BIT(26)
+#define FSL_XCVR_EXT_STUS_HB_STATUS	BIT(27)
+#define FSL_XCVR_EXT_STUS_NEW_UD4_REC	BIT(28)
+#define FSL_XCVR_EXT_STUS_NEW_UD5_REC	BIT(29)
+#define FSL_XCVR_EXT_STUS_NEW_UD6_REC	BIT(30)
+#define FSL_XCVR_EXT_STUS_HPD_INPUT	BIT(31)
+
+#define FSL_XCVR_IRQ_NEW_CS		BIT(0)
+#define FSL_XCVR_IRQ_NEW_UD		BIT(1)
+#define FSL_XCVR_IRQ_MUTE		BIT(2)
+#define FSL_XCVR_IRQ_CMDC_RESP_TO	BIT(3)
+#define FSL_XCVR_IRQ_ECC_ERR		BIT(4)
+#define FSL_XCVR_IRQ_PREAMBLE_MISMATCH	BIT(5)
+#define FSL_XCVR_IRQ_FIFO_UOFL_ERR	BIT(6)
+#define FSL_XCVR_IRQ_HOST_WAKEUP	BIT(7)
+#define FSL_XCVR_IRQ_HOST_OHPD		BIT(8)
+#define FSL_XCVR_IRQ_DMAC_NO_DATA_REC	BIT(9)
+#define FSL_XCVR_IRQ_DMAC_FMT_CHG_DET	BIT(10)
+#define FSL_XCVR_IRQ_HB_STATE_CHG	BIT(11)
+#define FSL_XCVR_IRQ_CMDC_STATUS_UPD	BIT(12)
+#define FSL_XCVR_IRQ_TEMP_UPD		BIT(13)
+#define FSL_XCVR_IRQ_DMA_RD_REQ		BIT(14)
+#define FSL_XCVR_IRQ_DMA_WR_REQ		BIT(15)
+#define FSL_XCVR_IRQ_DMAC_BME_BIT_ERR	BIT(16)
+#define FSL_XCVR_IRQ_PREAMBLE_MATCH	BIT(17)
+#define FSL_XCVR_IRQ_M_W_PRE_MISMATCH	BIT(18)
+#define FSL_XCVR_IRQ_B_PRE_MISMATCH	BIT(19)
+#define FSL_XCVR_IRQ_UNEXP_PRE_REC	BIT(20)
+#define FSL_XCVR_IRQ_ARC_MODE		BIT(21)
+#define FSL_XCVR_IRQ_CH_UD_OFLOW	BIT(22)
+#define FSL_XCVR_IRQ_EARC_ALL		(FSL_XCVR_IRQ_NEW_CS | \
+					 FSL_XCVR_IRQ_NEW_UD | \
+					 FSL_XCVR_IRQ_MUTE | \
+					 FSL_XCVR_IRQ_FIFO_UOFL_ERR | \
+					 FSL_XCVR_IRQ_HOST_WAKEUP | \
+					 FSL_XCVR_IRQ_ARC_MODE)
+
+#define FSL_XCVR_ISR_CMDC_TX_EN		BIT(3)
+#define FSL_XCVR_ISR_HPD_TGL		BIT(15)
+#define FSL_XCVR_ISR_DMAC_SPARE_INT	BIT(19)
+#define FSL_XCVR_ISR_SET_SPDIF_RX_INT	BIT(20)
+#define FSL_XCVR_ISR_SET_SPDIF_TX_INT	BIT(21)
+#define FSL_XCVR_ISR_SET_SPDIF_MODE(t)	(t ? BIT(21) : BIT(20))
+#define FSL_XCVR_ISR_SET_ARC_CM_INT	BIT(22)
+#define FSL_XCVR_ISR_SET_ARC_SE_INT	BIT(23)
+
+#define FSL_XCVR_PHY_AI_ADDR_MASK	GENMASK(7, 0)
+#define FSL_XCVR_PHY_AI_RESETN		BIT(15)
+#define FSL_XCVR_PHY_AI_TOG_PLL		BIT(24)
+#define FSL_XCVR_PHY_AI_TOG_DONE_PLL	BIT(25)
+#define FSL_XCVR_PHY_AI_TOG_PHY		BIT(26)
+#define FSL_XCVR_PHY_AI_TOG_DONE_PHY	BIT(27)
+#define FSL_XCVR_PHY_AI_RW_MASK		BIT(31)
+
+#define FSL_XCVR_RX_DPTH_CTRL_PAPB_FIFO_STATUS	BIT(0)
+#define FSL_XCVR_RX_DPTH_CTRL_DIS_PRE_ERR_CHK	BIT(1)
+#define FSL_XCVR_RX_DPTH_CTRL_DIS_NOD_REC_CHK	BIT(2)
+#define FSL_XCVR_RX_DPTH_CTRL_ECC_VUC_BIT_CHK	BIT(3)
+#define FSL_XCVR_RX_DPTH_CTRL_EN_CMP_PAR_CALC	BIT(4)
+#define FSL_XCVR_RX_DPTH_CTRL_RST_PKT_CNT_FIFO	BIT(5)
+#define FSL_XCVR_RX_DPTH_CTRL_STORE_FMT		BIT(6)
+#define FSL_XCVR_RX_DPTH_CTRL_EN_PAR_CALC	BIT(7)
+#define FSL_XCVR_RX_DPTH_CTRL_UDR		BIT(8)
+#define FSL_XCVR_RX_DPTH_CTRL_CSR		BIT(9)
+#define FSL_XCVR_RX_DPTH_CTRL_UDA		BIT(10)
+#define FSL_XCVR_RX_DPTH_CTRL_CSA		BIT(11)
+#define FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO	BIT(12)
+#define FSL_XCVR_RX_DPTH_CTRL_DIS_B_PRE_ERR_CHK	BIT(13)
+#define FSL_XCVR_RX_DPTH_CTRL_PABS		BIT(19)
+#define FSL_XCVR_RX_DPTH_CTRL_DTS_CDS		BIT(20)
+#define FSL_XCVR_RX_DPTH_CTRL_BLKC		BIT(21)
+#define FSL_XCVR_RX_DPTH_CTRL_MUTE_CTRL		BIT(22)
+#define FSL_XCVR_RX_DPTH_CTRL_MUTE_MODE		BIT(23)
+#define FSL_XCVR_RX_DPTH_CTRL_FMT_CHG_CTRL	BIT(24)
+#define FSL_XCVR_RX_DPTH_CTRL_FMT_CHG_MODE	BIT(25)
+#define FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL		BIT(26)
+#define FSL_XCVR_RX_DPTH_CTRL_LAYB_MODE		BIT(27)
+#define FSL_XCVR_RX_DPTH_CTRL_PRC		BIT(28)
+#define FSL_XCVR_RX_DPTH_CTRL_COMP		BIT(29)
+#define FSL_XCVR_RX_DPTH_CTRL_FSM		GENMASK(31, 30)
+
+#define FSL_XCVR_TX_DPTH_CTRL_CS_ACK		BIT(0)
+#define FSL_XCVR_TX_DPTH_CTRL_UD_ACK		BIT(1)
+#define FSL_XCVR_TX_DPTH_CTRL_CS_MOD		BIT(2)
+#define FSL_XCVR_TX_DPTH_CTRL_UD_MOD		BIT(3)
+#define FSL_XCVR_TX_DPTH_CTRL_VLD_MOD		BIT(4)
+#define FSL_XCVR_TX_DPTH_CTRL_FRM_VLD		BIT(5)
+#define FSL_XCVR_TX_DPTH_CTRL_EN_PARITY		BIT(6)
+#define FSL_XCVR_TX_DPTH_CTRL_EN_PREAMBLE	BIT(7)
+#define FSL_XCVR_TX_DPTH_CTRL_EN_ECC_INTER	BIT(8)
+#define FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM	BIT(10)
+#define FSL_XCVR_TX_DPTH_CTRL_FRM_FMT		BIT(11)
+#define FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX	BIT(14)
+#define FSL_XCVR_TX_DPTH_CTRL_ADD_CYC_TX_OE_STR	BIT(15)
+#define FSL_XCVR_TX_DPTH_CTRL_ADD_CYC_TX_OE_END	BIT(16)
+#define FSL_XCVR_TX_DPTH_CTRL_CLK_RATIO		BIT(29)
+#define FSL_XCVR_TX_DPTH_CTRL_TM_NO_PRE_BME	GENMASK(31, 30)
+
+#define FSL_XCVR_PHY_AI_CTRL_AI_RESETN		BIT(15)
+
+#define FSL_XCVR_PLL_CTRL0			0x00
+#define FSL_XCVR_PLL_CTRL0_SET			0x04
+#define FSL_XCVR_PLL_CTRL0_CLR			0x08
+#define FSL_XCVR_PLL_NUM			0x20
+#define FSL_XCVR_PLL_DEN			0x30
+#define FSL_XCVR_PLL_PDIV			0x40
+#define FSL_XCVR_PLL_BANDGAP_SET		0x54
+#define FSL_XCVR_PHY_CTRL			0x00
+#define FSL_XCVR_PHY_CTRL_SET			0x04
+#define FSL_XCVR_PHY_CTRL_CLR			0x08
+#define FSL_XCVR_PHY_CTRL2			0x70
+#define FSL_XCVR_PHY_CTRL2_SET			0x74
+#define FSL_XCVR_PHY_CTRL2_CLR			0x78
+
+#define FSL_XCVR_PLL_BANDGAP_EN_VBG		BIT(0)
+#define FSL_XCVR_PLL_CTRL0_HROFF		BIT(13)
+#define FSL_XCVR_PLL_CTRL0_PWP			BIT(14)
+#define FSL_XCVR_PLL_CTRL0_CM0_EN		BIT(24)
+#define FSL_XCVR_PLL_CTRL0_CM1_EN		BIT(25)
+#define FSL_XCVR_PLL_CTRL0_CM2_EN		BIT(26)
+#define FSL_XCVR_PLL_PDIVx(v, i)		((v & 0x7) << (4 * i))
+
+#define FSL_XCVR_PHY_CTRL_PHY_EN		BIT(0)
+#define FSL_XCVR_PHY_CTRL_RX_CM_EN		BIT(1)
+#define FSL_XCVR_PHY_CTRL_TSDIFF_OE		BIT(5)
+#define FSL_XCVR_PHY_CTRL_SPDIF_EN		BIT(8)
+#define FSL_XCVR_PHY_CTRL_ARC_MODE_SE_EN	BIT(9)
+#define FSL_XCVR_PHY_CTRL_ARC_MODE_CM_EN	BIT(10)
+#define FSL_XCVR_PHY_CTRL_TX_CLK_MASK		GENMASK(26, 25)
+#define FSL_XCVR_PHY_CTRL_TX_CLK_HDMI_SS	BIT(25)
+#define FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS		BIT(26)
+#define FSL_XCVR_PHY_CTRL2_EARC_TXMS		BIT(14)
+
+#define FSL_XCVR_CS_DATA_0_FS_MASK		GENMASK(31, 24)
+#define FSL_XCVR_CS_DATA_0_FS_32000		0x3000000
+#define FSL_XCVR_CS_DATA_0_FS_44100		0x0000000
+#define FSL_XCVR_CS_DATA_0_FS_48000		0x2000000
+#define FSL_XCVR_CS_DATA_0_FS_64000		0xB000000
+#define FSL_XCVR_CS_DATA_0_FS_88200		0x8000000
+#define FSL_XCVR_CS_DATA_0_FS_96000		0xA000000
+#define FSL_XCVR_CS_DATA_0_FS_176400		0xC000000
+#define FSL_XCVR_CS_DATA_0_FS_192000		0xE000000
+
+#define FSL_XCVR_CS_DATA_0_CH_MASK		0x3A
+#define FSL_XCVR_CS_DATA_0_CH_U2LPCM		0x00
+#define FSL_XCVR_CS_DATA_0_CH_UMLPCM		0x20
+#define FSL_XCVR_CS_DATA_0_CH_U1BAUD		0x30
+
+#define FSL_XCVR_CS_DATA_1_CH_MASK		0xF000
+#define FSL_XCVR_CS_DATA_1_CH_2			0x0000
+#define FSL_XCVR_CS_DATA_1_CH_8			0x7000
+#define FSL_XCVR_CS_DATA_1_CH_16		0xB000
+#define FSL_XCVR_CS_DATA_1_CH_32		0x3000
+
+/* Data memory structures */
+#define FSL_XCVR_RX_CS_CTRL_0		0x20 /* First  RX CS control register */
+#define FSL_XCVR_RX_CS_CTRL_1		0x24 /* Second RX CS control register */
+#define FSL_XCVR_RX_CS_BUFF_0		0x80 /* First  RX CS buffer */
+#define FSL_XCVR_RX_CS_BUFF_1		0xA0 /* Second RX CS buffer */
+#define FSL_XCVR_CAP_DATA_STR		0x300 /* Capabilities data structure */
+
+#endif /* __FSL_XCVR_H */
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index 25c18b9e348f..dfa05d40b276 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -170,22 +170,9 @@ static enum imx_audmux_type {
 	IMX31_AUDMUX,
 } audmux_type;
 
-static const struct platform_device_id imx_audmux_ids[] = {
-	{
-		.name = "imx21-audmux",
-		.driver_data = IMX21_AUDMUX,
-	}, {
-		.name = "imx31-audmux",
-		.driver_data = IMX31_AUDMUX,
-	}, {
-		/* sentinel */
-	}
-};
-MODULE_DEVICE_TABLE(platform, imx_audmux_ids);
-
 static const struct of_device_id imx_audmux_dt_ids[] = {
-	{ .compatible = "fsl,imx21-audmux", .data = &imx_audmux_ids[0], },
-	{ .compatible = "fsl,imx31-audmux", .data = &imx_audmux_ids[1], },
+	{ .compatible = "fsl,imx21-audmux", .data = (void *)IMX21_AUDMUX, },
+	{ .compatible = "fsl,imx31-audmux", .data = (void *)IMX31_AUDMUX, },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, imx_audmux_dt_ids);
@@ -300,9 +287,6 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev,
 
 static int imx_audmux_probe(struct platform_device *pdev)
 {
-	const struct of_device_id *of_id =
-			of_match_device(imx_audmux_dt_ids, &pdev->dev);
-
 	audmux_base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(audmux_base))
 		return PTR_ERR(audmux_base);
@@ -314,9 +298,7 @@ static int imx_audmux_probe(struct platform_device *pdev)
 		audmux_clk = NULL;
 	}
 
-	if (of_id)
-		pdev->id_entry = of_id->data;
-	audmux_type = pdev->id_entry->driver_data;
+	audmux_type = (enum imx_audmux_type)of_device_get_match_data(&pdev->dev);
 
 	switch (audmux_type) {
 	case IMX31_AUDMUX:
@@ -335,8 +317,7 @@ static int imx_audmux_probe(struct platform_device *pdev)
 	if (!regcache)
 		return -ENOMEM;
 
-	if (of_id)
-		imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node);
+	imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node);
 
 	return 0;
 }
@@ -386,7 +367,6 @@ static const struct dev_pm_ops imx_audmux_pm = {
 static struct platform_driver imx_audmux_driver = {
 	.probe		= imx_audmux_probe,
 	.remove		= imx_audmux_remove,
-	.id_table	= imx_audmux_ids,
 	.driver	= {
 		.name	= DRIVER_NAME,
 		.pm = &imx_audmux_pm,
diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c
new file mode 100644
index 000000000000..2c2a76a71940
--- /dev/null
+++ b/sound/soc/fsl/imx-hdmi.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2017-2020 NXP
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/hdmi-codec.h>
+#include "fsl_sai.h"
+
+/**
+ * struct cpu_priv - CPU private data
+ * @sysclk_freq: SYSCLK rates for set_sysclk()
+ * @sysclk_dir: SYSCLK directions for set_sysclk()
+ * @sysclk_id: SYSCLK ids for set_sysclk()
+ * @slot_width: Slot width of each frame
+ *
+ * Note: [1] for tx and [0] for rx
+ */
+struct cpu_priv {
+	unsigned long sysclk_freq[2];
+	u32 sysclk_dir[2];
+	u32 sysclk_id[2];
+	u32 slot_width;
+};
+
+struct imx_hdmi_data {
+	struct snd_soc_dai_link dai;
+	struct snd_soc_card card;
+	struct snd_soc_jack hdmi_jack;
+	struct snd_soc_jack_pin hdmi_jack_pin;
+	struct cpu_priv cpu_priv;
+	u32 dai_fmt;
+};
+
+static int imx_hdmi_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct imx_hdmi_data *data = snd_soc_card_get_drvdata(rtd->card);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct snd_soc_card *card = rtd->card;
+	struct device *dev = card->dev;
+	u32 slot_width = data->cpu_priv.slot_width;
+	int ret;
+
+	/* MCLK always is (256 or 192) * rate. */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, data->cpu_priv.sysclk_id[tx],
+				     8 * slot_width * params_rate(params),
+				     tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN);
+	if (ret && ret != -ENOTSUPP) {
+		dev_err(dev, "failed to set cpu sysclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0, 2, slot_width);
+	if (ret && ret != -ENOTSUPP) {
+		dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops imx_hdmi_ops = {
+	.hw_params = imx_hdmi_hw_params,
+};
+
+static const struct snd_soc_dapm_widget imx_hdmi_widgets[] = {
+	SND_SOC_DAPM_LINE("HDMI Jack", NULL),
+};
+
+static int imx_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+	struct snd_soc_component *component = codec_dai->component;
+	struct imx_hdmi_data *data = snd_soc_card_get_drvdata(card);
+	int ret;
+
+	data->hdmi_jack_pin.pin = "HDMI Jack";
+	data->hdmi_jack_pin.mask = SND_JACK_LINEOUT;
+	/* enable jack detection */
+	ret = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT,
+				    &data->hdmi_jack, &data->hdmi_jack_pin, 1);
+	if (ret) {
+		dev_err(card->dev, "Can't new HDMI Jack %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_set_jack(component, &data->hdmi_jack, NULL);
+	if (ret && ret != -EOPNOTSUPP) {
+		dev_err(card->dev, "Can't set HDMI Jack %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+};
+
+static int imx_hdmi_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	bool hdmi_out = of_property_read_bool(np, "hdmi-out");
+	bool hdmi_in = of_property_read_bool(np, "hdmi-in");
+	struct snd_soc_dai_link_component *dlc;
+	struct platform_device *cpu_pdev;
+	struct device_node *cpu_np;
+	struct imx_hdmi_data *data;
+	int ret;
+
+	dlc = devm_kzalloc(&pdev->dev, 3 * sizeof(*dlc), GFP_KERNEL);
+	if (!dlc)
+		return -ENOMEM;
+
+	cpu_np = of_parse_phandle(np, "audio-cpu", 0);
+	if (!cpu_np) {
+		dev_err(&pdev->dev, "cpu dai phandle missing or invalid\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	cpu_pdev = of_find_device_by_node(cpu_np);
+	if (!cpu_pdev) {
+		dev_err(&pdev->dev, "failed to find SAI platform device\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	data->dai.cpus = &dlc[0];
+	data->dai.num_cpus = 1;
+	data->dai.platforms = &dlc[1];
+	data->dai.num_platforms = 1;
+	data->dai.codecs = &dlc[2];
+	data->dai.num_codecs = 1;
+
+	data->dai.name = "i.MX HDMI";
+	data->dai.stream_name = "i.MX HDMI";
+	data->dai.cpus->dai_name = dev_name(&cpu_pdev->dev);
+	data->dai.platforms->of_node = cpu_np;
+	data->dai.ops = &imx_hdmi_ops;
+	data->dai.playback_only = true;
+	data->dai.capture_only = false;
+	data->dai.init = imx_hdmi_init;
+
+	if (of_node_name_eq(cpu_np, "sai")) {
+		data->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
+		data->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
+	}
+
+	if (of_device_is_compatible(np, "fsl,imx-audio-sii902x")) {
+		data->dai_fmt = SND_SOC_DAIFMT_LEFT_J;
+		data->cpu_priv.slot_width = 24;
+	} else {
+		data->dai_fmt = SND_SOC_DAIFMT_I2S;
+		data->cpu_priv.slot_width = 32;
+	}
+
+	if ((hdmi_out && hdmi_in) || (!hdmi_out && !hdmi_in)) {
+		dev_err(&pdev->dev, "Invalid HDMI DAI link\n");
+		goto fail;
+	}
+
+	if (hdmi_out) {
+		data->dai.playback_only = true;
+		data->dai.capture_only = false;
+		data->dai.codecs->dai_name = "i2s-hifi";
+		data->dai.codecs->name = "hdmi-audio-codec.1";
+		data->dai.dai_fmt = data->dai_fmt |
+				    SND_SOC_DAIFMT_NB_NF |
+				    SND_SOC_DAIFMT_CBS_CFS;
+	}
+
+	if (hdmi_in) {
+		data->dai.playback_only = false;
+		data->dai.capture_only = true;
+		data->dai.codecs->dai_name = "i2s-hifi";
+		data->dai.codecs->name = "hdmi-audio-codec.2";
+		data->dai.dai_fmt = data->dai_fmt |
+				    SND_SOC_DAIFMT_NB_NF |
+				    SND_SOC_DAIFMT_CBM_CFM;
+	}
+
+	data->card.dapm_widgets = imx_hdmi_widgets;
+	data->card.num_dapm_widgets = ARRAY_SIZE(imx_hdmi_widgets);
+	data->card.dev = &pdev->dev;
+	data->card.owner = THIS_MODULE;
+	ret = snd_soc_of_parse_card_name(&data->card, "model");
+	if (ret)
+		goto fail;
+
+	data->card.num_links = 1;
+	data->card.dai_link = &data->dai;
+
+	snd_soc_card_set_drvdata(&data->card, data);
+	ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+		goto fail;
+	}
+
+fail:
+	if (cpu_np)
+		of_node_put(cpu_np);
+
+	return ret;
+}
+
+static const struct of_device_id imx_hdmi_dt_ids[] = {
+	{ .compatible = "fsl,imx-audio-hdmi", },
+	{ .compatible = "fsl,imx-audio-sii902x", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
+
+static struct platform_driver imx_hdmi_driver = {
+	.driver = {
+		.name = "imx-hdmi",
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = imx_hdmi_dt_ids,
+	},
+	.probe = imx_hdmi_probe,
+};
+module_platform_driver(imx_hdmi_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale i.MX hdmi audio ASoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-hdmi");
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c
deleted file mode 100644
index d9dca7bbcae3..000000000000
--- a/sound/soc/fsl/imx-mc13783.c
+++ /dev/null
@@ -1,156 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// imx-mc13783.c  --  SoC audio for imx based boards with mc13783 codec
-//
-// Copyright 2012 Philippe Retornaz, <philippe.retornaz@epfl.ch>
-//
-// Heavly based on phycore-mc13783:
-// Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <asm/mach-types.h>
-
-#include "../codecs/mc13783.h"
-#include "imx-ssi.h"
-#include "imx-audmux.h"
-
-#define FMT_SSI (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \
-		SND_SOC_DAIFMT_CBM_CFM)
-
-static int imx_mc13783_hifi_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);
-	int ret;
-
-	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 4, 16);
-	if (ret)
-		return ret;
-
-	ret = snd_soc_dai_set_sysclk(codec_dai, MC13783_CLK_CLIA, 26000000, 0);
-	if (ret)
-		return ret;
-
-	return snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16);
-}
-
-static const struct snd_soc_ops imx_mc13783_hifi_ops = {
-	.hw_params = imx_mc13783_hifi_hw_params,
-};
-
-SND_SOC_DAILINK_DEFS(hifi,
-	DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")),
-	DAILINK_COMP_ARRAY(COMP_CODEC("mc13783-codec", "mc13783-hifi")),
-	DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0")));
-
-static struct snd_soc_dai_link imx_mc13783_dai_mc13783[] = {
-	{
-		.name = "MC13783",
-		.stream_name	 = "Sound",
-		.ops		 = &imx_mc13783_hifi_ops,
-		.symmetric_rates = 1,
-		.dai_fmt 	 = FMT_SSI,
-		SND_SOC_DAILINK_REG(hifi),
-	},
-};
-
-static const struct snd_soc_dapm_widget imx_mc13783_widget[] = {
-	SND_SOC_DAPM_MIC("Mic", NULL),
-	SND_SOC_DAPM_HP("Headphone", NULL),
-	SND_SOC_DAPM_SPK("Speaker", NULL),
-};
-
-static const struct snd_soc_dapm_route imx_mc13783_routes[] = {
-	{"Speaker", NULL, "LSP"},
-	{"Headphone", NULL, "HSL"},
-	{"Headphone", NULL, "HSR"},
-
-	{"MC1LIN", NULL, "MC1 Bias"},
-	{"MC2IN", NULL, "MC2 Bias"},
-	{"MC1 Bias", NULL, "Mic"},
-	{"MC2 Bias", NULL, "Mic"},
-};
-
-static struct snd_soc_card imx_mc13783 = {
-	.name		= "imx_mc13783",
-	.owner		= THIS_MODULE,
-	.dai_link	= imx_mc13783_dai_mc13783,
-	.num_links	= ARRAY_SIZE(imx_mc13783_dai_mc13783),
-	.dapm_widgets	= imx_mc13783_widget,
-	.num_dapm_widgets = ARRAY_SIZE(imx_mc13783_widget),
-	.dapm_routes	= imx_mc13783_routes,
-	.num_dapm_routes = ARRAY_SIZE(imx_mc13783_routes),
-};
-
-static int imx_mc13783_probe(struct platform_device *pdev)
-{
-	int ret;
-
-	imx_mc13783.dev = &pdev->dev;
-
-	ret = devm_snd_soc_register_card(&pdev->dev, &imx_mc13783);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
-		return ret;
-	}
-
-	if (machine_is_mx31_3ds() || machine_is_mx31moboard()) {
-		imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4,
-			IMX_AUDMUX_V2_PTCR_SYN,
-			IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) |
-			IMX_AUDMUX_V2_PDCR_MODE(1) |
-			IMX_AUDMUX_V2_PDCR_INMMASK(0xfc));
-		imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0,
-			IMX_AUDMUX_V2_PTCR_SYN |
-			IMX_AUDMUX_V2_PTCR_TFSDIR |
-			IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
-			IMX_AUDMUX_V2_PTCR_TCLKDIR |
-			IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
-			IMX_AUDMUX_V2_PTCR_RFSDIR |
-			IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
-			IMX_AUDMUX_V2_PTCR_RCLKDIR |
-			IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4),
-			IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4));
-	} else if (machine_is_mx27_3ds()) {
-		imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
-			IMX_AUDMUX_V1_PCR_SYN |
-			IMX_AUDMUX_V1_PCR_TFSDIR |
-			IMX_AUDMUX_V1_PCR_TCLKDIR |
-			IMX_AUDMUX_V1_PCR_RFSDIR |
-			IMX_AUDMUX_V1_PCR_RCLKDIR |
-			IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
-			IMX_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
-			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4)
-		);
-		imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4,
-			IMX_AUDMUX_V1_PCR_SYN |
-			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
-		);
-	}
-
-	return ret;
-}
-
-static struct platform_driver imx_mc13783_audio_driver = {
-	.driver = {
-		.name = "imx_mc13783",
-	},
-	.probe = imx_mc13783_probe,
-};
-
-module_platform_driver(imx_mc13783_audio_driver);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch");
-MODULE_DESCRIPTION("imx with mc13783 codec ALSA SoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx_mc13783");
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
deleted file mode 100644
index f8488e8f5f5b..000000000000
--- a/sound/soc/fsl/imx-ssi.c
+++ /dev/null
@@ -1,651 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// imx-ssi.c  --  ALSA Soc Audio Layer
-//
-// Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
-//
-// This code is based on code copyrighted by Freescale,
-// Liam Girdwood, Javier Martin and probably others.
-//
-// The i.MX SSI core has some nasty limitations in AC97 mode. While most
-// sane processor vendors have a FIFO per AC97 slot, the i.MX has only
-// one FIFO which combines all valid receive slots. We cannot even select
-// which slots we want to receive. The WM9712 with which this driver
-// was developed with always sends GPIO status data in slot 12 which
-// we receive in our (PCM-) data stream. The only chance we have is to
-// manually skip this data in the FIQ handler. With sampling rates different
-// from 48000Hz not every frame has valid receive data, so the ratio
-// between pcm data and GPIO status data changes. Our FIQ handler is not
-// able to handle this, hence this driver only works with 48000Hz sampling
-// rate.
-// Reading and writing AC97 registers is another challenge. The core
-// provides us status bits when the read register is updated with *another*
-// value. When we read the same register two times (and the register still
-// contains the same value) these status bits are not set. We work
-// around this by not polling these bits but only wait a fixed delay.
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <linux/platform_data/asoc-imx-ssi.h>
-
-#include "imx-ssi.h"
-#include "fsl_utils.h"
-
-#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
-
-/*
- * SSI Network Mode or TDM slots configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
-	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
-{
-	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-	u32 sccr;
-
-	sccr = readl(ssi->base + SSI_STCCR);
-	sccr &= ~SSI_STCCR_DC_MASK;
-	sccr |= SSI_STCCR_DC(slots - 1);
-	writel(sccr, ssi->base + SSI_STCCR);
-
-	sccr = readl(ssi->base + SSI_SRCCR);
-	sccr &= ~SSI_STCCR_DC_MASK;
-	sccr |= SSI_STCCR_DC(slots - 1);
-	writel(sccr, ssi->base + SSI_SRCCR);
-
-	writel(~tx_mask, ssi->base + SSI_STMSK);
-	writel(~rx_mask, ssi->base + SSI_SRMSK);
-
-	return 0;
-}
-
-/*
- * SSI DAI format configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
-{
-	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-	u32 strcr = 0, scr;
-
-	scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
-
-	/* DAI mode */
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_I2S:
-		/* data on rising edge of bclk, frame low 1clk before data */
-		strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSI |
-			SSI_STCR_TEFS;
-		scr |= SSI_SCR_NET;
-		if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) {
-			scr &= ~SSI_I2S_MODE_MASK;
-			scr |= SSI_SCR_I2S_MODE_SLAVE;
-		}
-		break;
-	case SND_SOC_DAIFMT_LEFT_J:
-		/* data on rising edge of bclk, frame high with data */
-		strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP;
-		break;
-	case SND_SOC_DAIFMT_DSP_B:
-		/* data on rising edge of bclk, frame high with data */
-		strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSL;
-		break;
-	case SND_SOC_DAIFMT_DSP_A:
-		/* data on rising edge of bclk, frame high 1clk before data */
-		strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSL |
-			SSI_STCR_TEFS;
-		break;
-	}
-
-	/* DAI clock inversion */
-	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_IB_IF:
-		strcr ^= SSI_STCR_TSCKP | SSI_STCR_TFSI;
-		break;
-	case SND_SOC_DAIFMT_IB_NF:
-		strcr ^= SSI_STCR_TSCKP;
-		break;
-	case SND_SOC_DAIFMT_NB_IF:
-		strcr ^= SSI_STCR_TFSI;
-		break;
-	case SND_SOC_DAIFMT_NB_NF:
-		break;
-	}
-
-	/* DAI clock master masks */
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBM_CFM:
-		break;
-	default:
-		/* Master mode not implemented, needs handling of clocks. */
-		return -EINVAL;
-	}
-
-	strcr |= SSI_STCR_TFEN0;
-
-	if (ssi->flags & IMX_SSI_NET)
-		scr |= SSI_SCR_NET;
-	if (ssi->flags & IMX_SSI_SYN)
-		scr |= SSI_SCR_SYN;
-
-	writel(strcr, ssi->base + SSI_STCR);
-	writel(strcr, ssi->base + SSI_SRCR);
-	writel(scr, ssi->base + SSI_SCR);
-
-	return 0;
-}
-
-/*
- * SSI system clock configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
-				  int clk_id, unsigned int freq, int dir)
-{
-	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-	u32 scr;
-
-	scr = readl(ssi->base + SSI_SCR);
-
-	switch (clk_id) {
-	case IMX_SSP_SYS_CLK:
-		if (dir == SND_SOC_CLOCK_OUT)
-			scr |= SSI_SCR_SYS_CLK_EN;
-		else
-			scr &= ~SSI_SCR_SYS_CLK_EN;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	writel(scr, ssi->base + SSI_SCR);
-
-	return 0;
-}
-
-/*
- * SSI Clock dividers
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
-				  int div_id, int div)
-{
-	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-	u32 stccr, srccr;
-
-	stccr = readl(ssi->base + SSI_STCCR);
-	srccr = readl(ssi->base + SSI_SRCCR);
-
-	switch (div_id) {
-	case IMX_SSI_TX_DIV_2:
-		stccr &= ~SSI_STCCR_DIV2;
-		stccr |= div;
-		break;
-	case IMX_SSI_TX_DIV_PSR:
-		stccr &= ~SSI_STCCR_PSR;
-		stccr |= div;
-		break;
-	case IMX_SSI_TX_DIV_PM:
-		stccr &= ~0xff;
-		stccr |= SSI_STCCR_PM(div);
-		break;
-	case IMX_SSI_RX_DIV_2:
-		stccr &= ~SSI_STCCR_DIV2;
-		stccr |= div;
-		break;
-	case IMX_SSI_RX_DIV_PSR:
-		stccr &= ~SSI_STCCR_PSR;
-		stccr |= div;
-		break;
-	case IMX_SSI_RX_DIV_PM:
-		stccr &= ~0xff;
-		stccr |= SSI_STCCR_PM(div);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	writel(stccr, ssi->base + SSI_STCCR);
-	writel(srccr, ssi->base + SSI_SRCCR);
-
-	return 0;
-}
-
-/*
- * Should only be called when port is inactive (i.e. SSIEN = 0),
- * although can be called multiple times by upper layers.
- */
-static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
-			     struct snd_pcm_hw_params *params,
-			     struct snd_soc_dai *cpu_dai)
-{
-	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-	u32 reg, sccr;
-
-	/* Tx/Rx config */
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		reg = SSI_STCCR;
-	else
-		reg = SSI_SRCCR;
-
-	if (ssi->flags & IMX_SSI_SYN)
-		reg = SSI_STCCR;
-
-	sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK;
-
-	/* DAI data (word) size */
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		sccr |= SSI_SRCCR_WL(16);
-		break;
-	case SNDRV_PCM_FORMAT_S20_3LE:
-		sccr |= SSI_SRCCR_WL(20);
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		sccr |= SSI_SRCCR_WL(24);
-		break;
-	}
-
-	writel(sccr, ssi->base + reg);
-
-	return 0;
-}
-
-static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
-		struct snd_soc_dai *dai)
-{
-	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
-	unsigned int sier_bits, sier;
-	unsigned int scr;
-
-	scr = readl(ssi->base + SSI_SCR);
-	sier = readl(ssi->base + SSI_SIER);
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		if (ssi->flags & IMX_SSI_DMA)
-			sier_bits = SSI_SIER_TDMAE;
-		else
-			sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN;
-	} else {
-		if (ssi->flags & IMX_SSI_DMA)
-			sier_bits = SSI_SIER_RDMAE;
-		else
-			sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN;
-	}
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			scr |= SSI_SCR_TE;
-		else
-			scr |= SSI_SCR_RE;
-		sier |= sier_bits;
-
-		scr |= SSI_SCR_SSIEN;
-
-		break;
-
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			scr &= ~SSI_SCR_TE;
-		else
-			scr &= ~SSI_SCR_RE;
-		sier &= ~sier_bits;
-
-		if (!(scr & (SSI_SCR_TE | SSI_SCR_RE)))
-			scr &= ~SSI_SCR_SSIEN;
-
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (!(ssi->flags & IMX_SSI_USE_AC97))
-		/* rx/tx are always enabled to access ac97 registers */
-		writel(scr, ssi->base + SSI_SCR);
-
-	writel(sier, ssi->base + SSI_SIER);
-
-	return 0;
-}
-
-static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
-	.hw_params	= imx_ssi_hw_params,
-	.set_fmt	= imx_ssi_set_dai_fmt,
-	.set_clkdiv	= imx_ssi_set_dai_clkdiv,
-	.set_sysclk	= imx_ssi_set_dai_sysclk,
-	.set_tdm_slot	= imx_ssi_set_dai_tdm_slot,
-	.trigger	= imx_ssi_trigger,
-};
-
-static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
-{
-	struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
-	uint32_t val;
-
-	snd_soc_dai_set_drvdata(dai, ssi);
-
-	val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.maxburst) |
-		SSI_SFCSR_RFWM0(ssi->dma_params_rx.maxburst);
-	writel(val, ssi->base + SSI_SFCSR);
-
-	/* Tx/Rx config */
-	dai->playback_dma_data = &ssi->dma_params_tx;
-	dai->capture_dma_data = &ssi->dma_params_rx;
-
-	return 0;
-}
-
-static struct snd_soc_dai_driver imx_ssi_dai = {
-	.probe = imx_ssi_dai_probe,
-	.playback = {
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_96000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.capture = {
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_96000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.ops = &imx_ssi_pcm_dai_ops,
-};
-
-static struct snd_soc_dai_driver imx_ac97_dai = {
-	.probe = imx_ssi_dai_probe,
-	.playback = {
-		.stream_name = "AC97 Playback",
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.capture = {
-		.stream_name = "AC97 Capture",
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.ops = &imx_ssi_pcm_dai_ops,
-};
-
-static const struct snd_soc_component_driver imx_component = {
-	.name		= DRV_NAME,
-};
-
-static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
-{
-	void __iomem *base = imx_ssi->base;
-
-	writel(0x0, base + SSI_SCR);
-	writel(0x0, base + SSI_STCR);
-	writel(0x0, base + SSI_SRCR);
-
-	writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR);
-
-	writel(SSI_SFCSR_RFWM0(8) |
-		SSI_SFCSR_TFWM0(8) |
-		SSI_SFCSR_RFWM1(8) |
-		SSI_SFCSR_TFWM1(8), base + SSI_SFCSR);
-
-	writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR);
-	writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR);
-
-	writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR);
-	writel(SSI_SOR_WAIT(3), base + SSI_SOR);
-
-	writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN |
-			SSI_SCR_TE | SSI_SCR_RE,
-			base + SSI_SCR);
-
-	writel(SSI_SACNT_DEFAULT, base + SSI_SACNT);
-	writel(0xff, base + SSI_SACCDIS);
-	writel(0x300, base + SSI_SACCEN);
-}
-
-static struct imx_ssi *ac97_ssi;
-
-static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
-		unsigned short val)
-{
-	struct imx_ssi *imx_ssi = ac97_ssi;
-	void __iomem *base = imx_ssi->base;
-	unsigned int lreg;
-	unsigned int lval;
-
-	if (reg > 0x7f)
-		return;
-
-	pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
-
-	lreg = reg <<  12;
-	writel(lreg, base + SSI_SACADD);
-
-	lval = val << 4;
-	writel(lval , base + SSI_SACDAT);
-
-	writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT);
-	udelay(100);
-}
-
-static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97,
-		unsigned short reg)
-{
-	struct imx_ssi *imx_ssi = ac97_ssi;
-	void __iomem *base = imx_ssi->base;
-
-	unsigned short val = -1;
-	unsigned int lreg;
-
-	lreg = (reg & 0x7f) <<  12 ;
-	writel(lreg, base + SSI_SACADD);
-	writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT);
-
-	udelay(100);
-
-	val = (readl(base + SSI_SACDAT) >> 4) & 0xffff;
-
-	pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
-
-	return val;
-}
-
-static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
-{
-	struct imx_ssi *imx_ssi = ac97_ssi;
-
-	if (imx_ssi->ac97_reset)
-		imx_ssi->ac97_reset(ac97);
-	/* First read sometimes fails, do a dummy read */
-	imx_ssi_ac97_read(ac97, 0);
-}
-
-static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
-{
-	struct imx_ssi *imx_ssi = ac97_ssi;
-
-	if (imx_ssi->ac97_warm_reset)
-		imx_ssi->ac97_warm_reset(ac97);
-
-	/* First read sometimes fails, do a dummy read */
-	imx_ssi_ac97_read(ac97, 0);
-}
-
-static struct snd_ac97_bus_ops imx_ssi_ac97_ops = {
-	.read		= imx_ssi_ac97_read,
-	.write		= imx_ssi_ac97_write,
-	.reset		= imx_ssi_ac97_reset,
-	.warm_reset	= imx_ssi_ac97_warm_reset
-};
-
-static int imx_ssi_probe(struct platform_device *pdev)
-{
-	struct resource *res;
-	struct imx_ssi *ssi;
-	struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
-	int ret = 0;
-	struct snd_soc_dai_driver *dai;
-
-	ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL);
-	if (!ssi)
-		return -ENOMEM;
-	dev_set_drvdata(&pdev->dev, ssi);
-
-	if (pdata) {
-		ssi->ac97_reset = pdata->ac97_reset;
-		ssi->ac97_warm_reset = pdata->ac97_warm_reset;
-		ssi->flags = pdata->flags;
-	}
-
-	ssi->irq = platform_get_irq(pdev, 0);
-	if (ssi->irq < 0)
-		return ssi->irq;
-
-	ssi->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(ssi->clk)) {
-		ret = PTR_ERR(ssi->clk);
-		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
-			ret);
-		goto failed_clk;
-	}
-	ret = clk_prepare_enable(ssi->clk);
-	if (ret)
-		goto failed_clk;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	ssi->base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(ssi->base)) {
-		ret = PTR_ERR(ssi->base);
-		goto failed_register;
-	}
-
-	if (ssi->flags & IMX_SSI_USE_AC97) {
-		if (ac97_ssi) {
-			dev_err(&pdev->dev, "AC'97 SSI already registered\n");
-			ret = -EBUSY;
-			goto failed_register;
-		}
-		ac97_ssi = ssi;
-		setup_channel_to_ac97(ssi);
-		dai = &imx_ac97_dai;
-	} else
-		dai = &imx_ssi_dai;
-
-	writel(0x0, ssi->base + SSI_SIER);
-
-	ssi->dma_params_rx.addr = res->start + SSI_SRX0;
-	ssi->dma_params_tx.addr = res->start + SSI_STX0;
-
-	ssi->dma_params_tx.maxburst = 6;
-	ssi->dma_params_rx.maxburst = 4;
-
-	ssi->dma_params_tx.filter_data = &ssi->filter_data_tx;
-	ssi->dma_params_rx.filter_data = &ssi->filter_data_rx;
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
-	if (res) {
-		imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
-			IMX_DMATYPE_SSI);
-	}
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
-	if (res) {
-		imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
-			IMX_DMATYPE_SSI);
-	}
-
-	platform_set_drvdata(pdev, ssi);
-
-	ret = snd_soc_set_ac97_ops(&imx_ssi_ac97_ops);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
-		goto failed_register;
-	}
-
-	ret = snd_soc_register_component(&pdev->dev, &imx_component,
-					 dai, 1);
-	if (ret) {
-		dev_err(&pdev->dev, "register DAI failed\n");
-		goto failed_register;
-	}
-
-	ssi->fiq_params.irq = ssi->irq;
-	ssi->fiq_params.base = ssi->base;
-	ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx;
-	ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx;
-
-	ssi->fiq_init = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
-	ssi->dma_init = imx_pcm_dma_init(pdev, IMX_SSI_DMABUF_SIZE);
-
-	if (ssi->fiq_init && ssi->dma_init) {
-		ret = ssi->fiq_init;
-		goto failed_pcm;
-	}
-
-	return 0;
-
-failed_pcm:
-	snd_soc_unregister_component(&pdev->dev);
-failed_register:
-	clk_disable_unprepare(ssi->clk);
-failed_clk:
-	snd_soc_set_ac97_ops(NULL);
-
-	return ret;
-}
-
-static int imx_ssi_remove(struct platform_device *pdev)
-{
-	struct imx_ssi *ssi = platform_get_drvdata(pdev);
-
-	if (!ssi->fiq_init)
-		imx_pcm_fiq_exit(pdev);
-
-	snd_soc_unregister_component(&pdev->dev);
-
-	if (ssi->flags & IMX_SSI_USE_AC97)
-		ac97_ssi = NULL;
-
-	clk_disable_unprepare(ssi->clk);
-	snd_soc_set_ac97_ops(NULL);
-
-	return 0;
-}
-
-static struct platform_driver imx_ssi_driver = {
-	.probe = imx_ssi_probe,
-	.remove = imx_ssi_remove,
-
-	.driver = {
-		.name = "imx-ssi",
-	},
-};
-
-module_platform_driver(imx_ssi_driver);
-
-/* Module information */
-MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-ssi");
diff --git a/sound/soc/fsl/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c
deleted file mode 100644
index 8d3b1897370b..000000000000
--- a/sound/soc/fsl/mx27vis-aic32x4.c
+++ /dev/null
@@ -1,214 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// mx27vis-aic32x4.c
-//
-// Copyright 2011 Vista Silicon S.L.
-//
-// Author: Javier Martin <javier.martin@vista-silicon.com>
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/platform_data/asoc-mx27vis.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/tlv.h>
-#include <asm/mach-types.h>
-
-#include "../codecs/tlv320aic32x4.h"
-#include "imx-ssi.h"
-#include "imx-audmux.h"
-
-#define MX27VIS_AMP_GAIN	0
-#define MX27VIS_AMP_MUTE	1
-
-static int mx27vis_amp_gain;
-static int mx27vis_amp_mute;
-static int mx27vis_amp_gain0_gpio;
-static int mx27vis_amp_gain1_gpio;
-static int mx27vis_amp_mutel_gpio;
-static int mx27vis_amp_muter_gpio;
-
-static int mx27vis_aic32x4_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);
-	int ret;
-
-	ret = snd_soc_dai_set_sysclk(codec_dai, 0,
-				     25000000, SND_SOC_CLOCK_OUT);
-	if (ret) {
-		pr_err("%s: failed setting codec sysclk\n", __func__);
-		return ret;
-	}
-
-	ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
-				SND_SOC_CLOCK_IN);
-	if (ret) {
-		pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-static const struct snd_soc_ops mx27vis_aic32x4_snd_ops = {
-	.hw_params	= mx27vis_aic32x4_hw_params,
-};
-
-static int mx27vis_amp_set(struct snd_kcontrol *kcontrol,
-			    struct snd_ctl_elem_value *ucontrol)
-{
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
-	int value = ucontrol->value.integer.value[0];
-	unsigned int reg = mc->reg;
-	int max = mc->max;
-
-	if (value > max)
-		return -EINVAL;
-
-	switch (reg) {
-	case MX27VIS_AMP_GAIN:
-		gpio_set_value(mx27vis_amp_gain0_gpio, value & 1);
-		gpio_set_value(mx27vis_amp_gain1_gpio, value >> 1);
-		mx27vis_amp_gain = value;
-		break;
-	case MX27VIS_AMP_MUTE:
-		gpio_set_value(mx27vis_amp_mutel_gpio, value & 1);
-		gpio_set_value(mx27vis_amp_muter_gpio, value >> 1);
-		mx27vis_amp_mute = value;
-		break;
-	}
-	return 0;
-}
-
-static int mx27vis_amp_get(struct snd_kcontrol *kcontrol,
-			    struct snd_ctl_elem_value *ucontrol)
-{
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
-	unsigned int reg = mc->reg;
-
-	switch (reg) {
-	case MX27VIS_AMP_GAIN:
-		ucontrol->value.integer.value[0] = mx27vis_amp_gain;
-		break;
-	case MX27VIS_AMP_MUTE:
-		ucontrol->value.integer.value[0] = mx27vis_amp_mute;
-		break;
-	}
-	return 0;
-}
-
-/* From 6dB to 24dB in steps of 6dB */
-static const DECLARE_TLV_DB_SCALE(mx27vis_amp_tlv, 600, 600, 0);
-
-static const struct snd_kcontrol_new mx27vis_aic32x4_controls[] = {
-	SOC_DAPM_PIN_SWITCH("External Mic"),
-	SOC_SINGLE_EXT_TLV("LO Ext Boost", MX27VIS_AMP_GAIN, 0, 3, 0,
-		       mx27vis_amp_get, mx27vis_amp_set, mx27vis_amp_tlv),
-	SOC_DOUBLE_EXT("LO Ext Mute Switch", MX27VIS_AMP_MUTE, 0, 1, 1, 0,
-		       mx27vis_amp_get, mx27vis_amp_set),
-};
-
-static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
-	SND_SOC_DAPM_MIC("External Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
-	{"Mic Bias", NULL, "External Mic"},
-	{"IN1_R", NULL, "Mic Bias"},
-	{"IN2_R", NULL, "Mic Bias"},
-	{"IN3_R", NULL, "Mic Bias"},
-	{"IN1_L", NULL, "Mic Bias"},
-	{"IN2_L", NULL, "Mic Bias"},
-	{"IN3_L", NULL, "Mic Bias"},
-};
-
-SND_SOC_DAILINK_DEFS(hifi,
-	DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")),
-	DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic32x4.0-0018",
-				      "tlv320aic32x4-hifi")),
-	DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0")));
-
-static struct snd_soc_dai_link mx27vis_aic32x4_dai = {
-	.name		= "tlv320aic32x4",
-	.stream_name	= "TLV320AIC32X4",
-	.dai_fmt	= SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
-			  SND_SOC_DAIFMT_CBM_CFM,
-	.ops		= &mx27vis_aic32x4_snd_ops,
-	SND_SOC_DAILINK_REG(hifi),
-};
-
-static struct snd_soc_card mx27vis_aic32x4 = {
-	.name		= "visstrim_m10-audio",
-	.owner		= THIS_MODULE,
-	.dai_link	= &mx27vis_aic32x4_dai,
-	.num_links	= 1,
-	.controls	= mx27vis_aic32x4_controls,
-	.num_controls	= ARRAY_SIZE(mx27vis_aic32x4_controls),
-	.dapm_widgets	= aic32x4_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets),
-	.dapm_routes	= aic32x4_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),
-};
-
-static int mx27vis_aic32x4_probe(struct platform_device *pdev)
-{
-	struct snd_mx27vis_platform_data *pdata = pdev->dev.platform_data;
-	int ret;
-
-	if (!pdata) {
-		dev_err(&pdev->dev, "No platform data supplied\n");
-		return -EINVAL;
-	}
-
-	mx27vis_amp_gain0_gpio = pdata->amp_gain0_gpio;
-	mx27vis_amp_gain1_gpio = pdata->amp_gain1_gpio;
-	mx27vis_amp_mutel_gpio = pdata->amp_mutel_gpio;
-	mx27vis_amp_muter_gpio = pdata->amp_muter_gpio;
-
-	mx27vis_aic32x4.dev = &pdev->dev;
-	ret = devm_snd_soc_register_card(&pdev->dev, &mx27vis_aic32x4);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
-		return ret;
-	}
-
-	/* Connect SSI0 as clock slave to SSI1 external pins */
-	imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
-			IMX_AUDMUX_V1_PCR_SYN |
-			IMX_AUDMUX_V1_PCR_TFSDIR |
-			IMX_AUDMUX_V1_PCR_TCLKDIR |
-			IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) |
-			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1)
-	);
-	imx_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1,
-			IMX_AUDMUX_V1_PCR_SYN |
-			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
-	);
-
-	return ret;
-}
-
-static struct platform_driver mx27vis_aic32x4_audio_driver = {
-	.driver = {
-		.name = "mx27vis",
-	},
-	.probe = mx27vis_aic32x4_probe,
-};
-
-module_platform_driver(mx27vis_aic32x4_audio_driver);
-
-MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
-MODULE_DESCRIPTION("ALSA SoC AIC32X4 mx27 visstrim");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mx27vis");
diff --git a/sound/soc/fsl/phycore-ac97.c b/sound/soc/fsl/phycore-ac97.c
deleted file mode 100644
index e561f7ff1699..000000000000
--- a/sound/soc/fsl/phycore-ac97.c
+++ /dev/null
@@ -1,121 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// phycore-ac97.c  --  SoC audio for imx_phycore in AC97 mode
-//
-// Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <asm/mach-types.h>
-
-#include "imx-audmux.h"
-
-static struct snd_soc_card imx_phycore;
-
-static const struct snd_soc_ops imx_phycore_hifi_ops = {
-};
-
-SND_SOC_DAILINK_DEFS(hifi,
-	DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")),
-	DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")),
-	DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0")));
-
-static struct snd_soc_dai_link imx_phycore_dai_ac97[] = {
-	{
-		.name		= "HiFi",
-		.stream_name	= "HiFi",
-		.ops		= &imx_phycore_hifi_ops,
-		SND_SOC_DAILINK_REG(hifi),
-	},
-};
-
-static struct snd_soc_card imx_phycore = {
-	.name		= "PhyCORE-ac97-audio",
-	.owner		= THIS_MODULE,
-	.dai_link	= imx_phycore_dai_ac97,
-	.num_links	= ARRAY_SIZE(imx_phycore_dai_ac97),
-};
-
-static struct platform_device *imx_phycore_snd_ac97_device;
-static struct platform_device *imx_phycore_snd_device;
-
-static int __init imx_phycore_init(void)
-{
-	int ret;
-
-	if (machine_is_pca100()) {
-		imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
-			IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */
-			IMX_AUDMUX_V1_PCR_TFCSEL(3) |
-			IMX_AUDMUX_V1_PCR_TCLKDIR | /* clock is output */
-			IMX_AUDMUX_V1_PCR_RXDSEL(3));
-		imx_audmux_v1_configure_port(3,
-			IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */
-			IMX_AUDMUX_V1_PCR_TFCSEL(0) |
-			IMX_AUDMUX_V1_PCR_TFSDIR |
-			IMX_AUDMUX_V1_PCR_RXDSEL(0));
-	} else if (machine_is_pcm043()) {
-		imx_audmux_v2_configure_port(3,
-			IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
-			IMX_AUDMUX_V2_PTCR_TFSEL(0) |
-			IMX_AUDMUX_V2_PTCR_TFSDIR,
-			IMX_AUDMUX_V2_PDCR_RXDSEL(0));
-		imx_audmux_v2_configure_port(0,
-			IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
-			IMX_AUDMUX_V2_PTCR_TCSEL(3) |
-			IMX_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */
-			IMX_AUDMUX_V2_PDCR_RXDSEL(3));
-	} else {
-		/* return happy. We might run on a totally different machine */
-		return 0;
-	}
-
-	imx_phycore_snd_ac97_device = platform_device_alloc("soc-audio", -1);
-	if (!imx_phycore_snd_ac97_device)
-		return -ENOMEM;
-
-	platform_set_drvdata(imx_phycore_snd_ac97_device, &imx_phycore);
-	ret = platform_device_add(imx_phycore_snd_ac97_device);
-	if (ret)
-		goto fail1;
-
-	imx_phycore_snd_device = platform_device_alloc("wm9712-codec", -1);
-	if (!imx_phycore_snd_device) {
-		ret = -ENOMEM;
-		goto fail2;
-	}
-	ret = platform_device_add(imx_phycore_snd_device);
-
-	if (ret) {
-		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
-		goto fail3;
-	}
-
-	return 0;
-
-fail3:
-	platform_device_put(imx_phycore_snd_device);
-fail2:
-	platform_device_del(imx_phycore_snd_ac97_device);
-fail1:
-	platform_device_put(imx_phycore_snd_ac97_device);
-	return ret;
-}
-
-static void __exit imx_phycore_exit(void)
-{
-	platform_device_unregister(imx_phycore_snd_device);
-	platform_device_unregister(imx_phycore_snd_ac97_device);
-}
-
-late_initcall(imx_phycore_init);
-module_exit(imx_phycore_exit);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION("PhyCORE ALSA SoC driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c
deleted file mode 100644
index 99611a037ada..000000000000
--- a/sound/soc/fsl/wm1133-ev1.c
+++ /dev/null
@@ -1,289 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-//  wm1133-ev1.c - Audio for WM1133-EV1 on i.MX31ADS
-//
-//  Copyright (c) 2010 Wolfson Microelectronics plc
-//  Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
-//
-//  Based on an earlier driver for the same hardware by Liam Girdwood.
-
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "imx-ssi.h"
-#include "../codecs/wm8350.h"
-#include "imx-audmux.h"
-
-/* There is a silicon mic on the board optionally connected via a solder pad
- * SP1.  Define this to enable it.
- */
-#undef USE_SIMIC
-
-struct _wm8350_audio {
-	unsigned int channels;
-	snd_pcm_format_t format;
-	unsigned int rate;
-	unsigned int sysclk;
-	unsigned int bclkdiv;
-	unsigned int clkdiv;
-	unsigned int lr_rate;
-};
-
-/* in order of power consumption per rate (lowest first) */
-static const struct _wm8350_audio wm8350_audio[] = {
-	/* 16bit mono modes */
-	{1, SNDRV_PCM_FORMAT_S16_LE, 8000, 12288000 >> 1,
-	 WM8350_BCLK_DIV_48, WM8350_DACDIV_3, 16,},
-
-	/* 16 bit stereo modes */
-	{2, SNDRV_PCM_FORMAT_S16_LE, 8000, 12288000,
-	 WM8350_BCLK_DIV_48, WM8350_DACDIV_6, 32,},
-	{2, SNDRV_PCM_FORMAT_S16_LE, 16000, 12288000,
-	 WM8350_BCLK_DIV_24, WM8350_DACDIV_3, 32,},
-	{2, SNDRV_PCM_FORMAT_S16_LE, 32000, 12288000,
-	 WM8350_BCLK_DIV_12, WM8350_DACDIV_1_5, 32,},
-	{2, SNDRV_PCM_FORMAT_S16_LE, 48000, 12288000,
-	 WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
-	{2, SNDRV_PCM_FORMAT_S16_LE, 96000, 24576000,
-	 WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
-	{2, SNDRV_PCM_FORMAT_S16_LE, 11025, 11289600,
-	 WM8350_BCLK_DIV_32, WM8350_DACDIV_4, 32,},
-	{2, SNDRV_PCM_FORMAT_S16_LE, 22050, 11289600,
-	 WM8350_BCLK_DIV_16, WM8350_DACDIV_2, 32,},
-	{2, SNDRV_PCM_FORMAT_S16_LE, 44100, 11289600,
-	 WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
-	{2, SNDRV_PCM_FORMAT_S16_LE, 88200, 22579200,
-	 WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
-
-	/* 24bit stereo modes */
-	{2, SNDRV_PCM_FORMAT_S24_LE, 48000, 12288000,
-	 WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
-	{2, SNDRV_PCM_FORMAT_S24_LE, 96000, 24576000,
-	 WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
-	{2, SNDRV_PCM_FORMAT_S24_LE, 44100, 11289600,
-	 WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
-	{2, SNDRV_PCM_FORMAT_S24_LE, 88200, 22579200,
-	 WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
-};
-
-static int wm1133_ev1_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);
-	int i, found = 0;
-	snd_pcm_format_t format = params_format(params);
-	unsigned int rate = params_rate(params);
-	unsigned int channels = params_channels(params);
-
-	/* find the correct audio parameters */
-	for (i = 0; i < ARRAY_SIZE(wm8350_audio); i++) {
-		if (rate == wm8350_audio[i].rate &&
-		    format == wm8350_audio[i].format &&
-		    channels == wm8350_audio[i].channels) {
-			found = 1;
-			break;
-		}
-	}
-	if (!found)
-		return -EINVAL;
-
-	/* codec FLL input is 14.75 MHz from MCLK */
-	snd_soc_dai_set_pll(codec_dai, 0, 0, 14750000, wm8350_audio[i].sysclk);
-
-	/* TODO: The SSI driver should figure this out for us */
-	switch (channels) {
-	case 2:
-		snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 0);
-		break;
-	case 1:
-		snd_soc_dai_set_tdm_slot(cpu_dai, 0x1, 0x1, 1, 0);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* set MCLK as the codec system clock for DAC and ADC */
-	snd_soc_dai_set_sysclk(codec_dai, WM8350_MCLK_SEL_PLL_MCLK,
-			       wm8350_audio[i].sysclk, SND_SOC_CLOCK_IN);
-
-	/* set codec BCLK division for sample rate */
-	snd_soc_dai_set_clkdiv(codec_dai, WM8350_BCLK_CLKDIV,
-			       wm8350_audio[i].bclkdiv);
-
-	/* DAI is synchronous and clocked with DAC LRCLK & ADC LRC */
-	snd_soc_dai_set_clkdiv(codec_dai,
-			       WM8350_DACLR_CLKDIV, wm8350_audio[i].lr_rate);
-	snd_soc_dai_set_clkdiv(codec_dai,
-			       WM8350_ADCLR_CLKDIV, wm8350_audio[i].lr_rate);
-
-	/* now configure DAC and ADC clocks */
-	snd_soc_dai_set_clkdiv(codec_dai,
-			       WM8350_DAC_CLKDIV, wm8350_audio[i].clkdiv);
-
-	snd_soc_dai_set_clkdiv(codec_dai,
-			       WM8350_ADC_CLKDIV, wm8350_audio[i].clkdiv);
-
-	return 0;
-}
-
-static const struct snd_soc_ops wm1133_ev1_ops = {
-	.hw_params = wm1133_ev1_hw_params,
-};
-
-static const struct snd_soc_dapm_widget wm1133_ev1_widgets[] = {
-#ifdef USE_SIMIC
-	SND_SOC_DAPM_MIC("SiMIC", NULL),
-#endif
-	SND_SOC_DAPM_MIC("Mic1 Jack", NULL),
-	SND_SOC_DAPM_MIC("Mic2 Jack", NULL),
-	SND_SOC_DAPM_LINE("Line In Jack", NULL),
-	SND_SOC_DAPM_LINE("Line Out Jack", NULL),
-	SND_SOC_DAPM_HP("Headphone Jack", NULL),
-};
-
-/* imx32ads soc_card audio map */
-static const struct snd_soc_dapm_route wm1133_ev1_map[] = {
-
-#ifdef USE_SIMIC
-	/* SiMIC --> IN1LN (with automatic bias) via SP1 */
-	{ "IN1LN", NULL, "Mic Bias" },
-	{ "Mic Bias", NULL, "SiMIC" },
-#endif
-
-	/* Mic 1 Jack --> IN1LN and IN1LP (with automatic bias) */
-	{ "IN1LN", NULL, "Mic Bias" },
-	{ "IN1LP", NULL, "Mic1 Jack" },
-	{ "Mic Bias", NULL, "Mic1 Jack" },
-
-	/* Mic 2 Jack --> IN1RN and IN1RP (with automatic bias) */
-	{ "IN1RN", NULL, "Mic Bias" },
-	{ "IN1RP", NULL, "Mic2 Jack" },
-	{ "Mic Bias", NULL, "Mic2 Jack" },
-
-	/* Line in Jack --> AUX (L+R) */
-	{ "IN3R", NULL, "Line In Jack" },
-	{ "IN3L", NULL, "Line In Jack" },
-
-	/* Out1 --> Headphone Jack */
-	{ "Headphone Jack", NULL, "OUT1R" },
-	{ "Headphone Jack", NULL, "OUT1L" },
-
-	/* Out1 --> Line Out Jack */
-	{ "Line Out Jack", NULL, "OUT2R" },
-	{ "Line Out Jack", NULL, "OUT2L" },
-};
-
-static struct snd_soc_jack hp_jack;
-
-static struct snd_soc_jack_pin hp_jack_pins[] = {
-	{ .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE },
-};
-
-static struct snd_soc_jack mic_jack;
-
-static struct snd_soc_jack_pin mic_jack_pins[] = {
-	{ .pin = "Mic1 Jack", .mask = SND_JACK_MICROPHONE },
-	{ .pin = "Mic2 Jack", .mask = SND_JACK_MICROPHONE },
-};
-
-static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
-
-	/* Headphone jack detection */
-	snd_soc_card_jack_new(rtd->card, "Headphone", SND_JACK_HEADPHONE,
-			      &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
-	wm8350_hp_jack_detect(component, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
-
-	/* Microphone jack detection */
-	snd_soc_card_jack_new(rtd->card, "Microphone",
-			      SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack,
-			      mic_jack_pins, ARRAY_SIZE(mic_jack_pins));
-	wm8350_mic_jack_detect(component, &mic_jack, SND_JACK_MICROPHONE,
-			       SND_JACK_BTN_0);
-
-	snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias");
-
-	return 0;
-}
-
-
-SND_SOC_DAILINK_DEFS(ev1,
-	DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")),
-	DAILINK_COMP_ARRAY(COMP_CODEC("wm8350-codec.0-0x1a", "wm8350-hifi")),
-	DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0")));
-
-static struct snd_soc_dai_link wm1133_ev1_dai = {
-	.name = "WM1133-EV1",
-	.stream_name = "Audio",
-	.init = wm1133_ev1_init,
-	.ops = &wm1133_ev1_ops,
-	.symmetric_rates = 1,
-	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-		   SND_SOC_DAIFMT_CBM_CFM,
-	SND_SOC_DAILINK_REG(ev1),
-};
-
-static struct snd_soc_card wm1133_ev1 = {
-	.name = "WM1133-EV1",
-	.owner = THIS_MODULE,
-	.dai_link = &wm1133_ev1_dai,
-	.num_links = 1,
-
-	.dapm_widgets = wm1133_ev1_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm1133_ev1_widgets),
-	.dapm_routes = wm1133_ev1_map,
-	.num_dapm_routes = ARRAY_SIZE(wm1133_ev1_map),
-};
-
-static struct platform_device *wm1133_ev1_snd_device;
-
-static int __init wm1133_ev1_audio_init(void)
-{
-	int ret;
-	unsigned int ptcr, pdcr;
-
-	/* SSI0 mastered by port 5 */
-	ptcr = IMX_AUDMUX_V2_PTCR_SYN |
-		IMX_AUDMUX_V2_PTCR_TFSDIR |
-		IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT5_SSI_PINS_5) |
-		IMX_AUDMUX_V2_PTCR_TCLKDIR |
-		IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT5_SSI_PINS_5);
-	pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT5_SSI_PINS_5);
-	imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, ptcr, pdcr);
-
-	ptcr = IMX_AUDMUX_V2_PTCR_SYN;
-	pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0);
-	imx_audmux_v2_configure_port(MX31_AUDMUX_PORT5_SSI_PINS_5, ptcr, pdcr);
-
-	wm1133_ev1_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!wm1133_ev1_snd_device)
-		return -ENOMEM;
-
-	platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1);
-	ret = platform_device_add(wm1133_ev1_snd_device);
-
-	if (ret)
-		platform_device_put(wm1133_ev1_snd_device);
-
-	return ret;
-}
-module_init(wm1133_ev1_audio_init);
-
-static void __exit wm1133_ev1_audio_exit(void)
-{
-	platform_device_unregister(wm1133_ev1_snd_device);
-}
-module_exit(wm1133_ev1_audio_exit);
-
-MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
-MODULE_DESCRIPTION("Audio for WM1133-EV1 on i.MX31ADS");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
index a90c3b28bce5..4cafcf0e2bbf 100644
--- a/sound/soc/generic/Kconfig
+++ b/sound/soc/generic/Kconfig
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config SND_SIMPLE_CARD_UTILS
-       tristate
+	tristate
 
 config SND_SIMPLE_CARD
 	tristate "ASoC Simple sound card support"
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 97b4f5480a31..16a04a678828 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -18,7 +18,7 @@
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
-#include <sound/simple_card_utils.h>
+#include <sound/graph_card.h>
 
 #define DPCM_SELECTABLE 1
 
@@ -111,6 +111,17 @@ static int graph_get_dai_id(struct device_node *ep)
 	return id;
 }
 
+static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
+{
+	struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc);
+
+	if (dai && (dai->component->driver->pcm_construct ||
+		    dai->driver->pcm_new))
+		return true;
+
+	return false;
+}
+
 static int asoc_simple_parse_dai(struct device_node *ep,
 				 struct snd_soc_dai_link_component *dlc,
 				 int *is_single_link)
@@ -205,6 +216,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 				  int dup_codec)
 {
 	struct device *dev = simple_priv_to_dev(priv);
+	struct snd_soc_card *card = simple_priv_to_card(priv);
 	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
 	struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
 	struct device_node *top = dev->of_node;
@@ -217,6 +229,14 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	struct snd_soc_dai_link_component *codecs = dai_link->codecs;
 	int ret;
 
+	/*
+	 * Codec endpoint can be NULL for pluggable audio HW.
+	 * Platform DT can populate the Codec endpoint depending on the
+	 * plugged HW.
+	 */
+	if (!li->cpu && !codec_ep)
+		return 0;
+
 	/* Do it all CPU endpoint, and 1st Codec endpoint */
 	if (!li->cpu && dup_codec)
 		return 0;
@@ -253,11 +273,25 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 			goto out_put_node;
 
 		ret = asoc_simple_set_dailink_name(dev, dai_link,
-						   "fe.%s",
+						   "fe.%pOFP.%s",
+						   cpus->of_node,
 						   cpus->dai_name);
 		if (ret < 0)
 			goto out_put_node;
 
+		/*
+		 * In BE<->BE connections it is not required to create
+		 * PCM devices at CPU end of the dai link and thus 'no_pcm'
+		 * flag needs to be set. It is useful when there are many
+		 * BE components and some of these have to be connected to
+		 * form a valid audio path.
+		 *
+		 * For example: FE <-> BE1 <-> BE2 <-> ... <-> BEn where
+		 * there are 'n' BE components in the path.
+		 */
+		if (card->component_chaining && !soc_component_is_pcm(cpus))
+			dai_link->no_pcm = 1;
+
 		/* card->num_links includes Codec */
 		asoc_simple_canonicalize_cpu(dai_link, is_single_links);
 	} else {
@@ -287,7 +321,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 			goto out_put_node;
 
 		ret = asoc_simple_set_dailink_name(dev, dai_link,
-						   "be.%s",
+						   "be.%pOFP.%s",
+						   codecs->of_node,
 						   codecs->dai_name);
 		if (ret < 0)
 			goto out_put_node;
@@ -320,6 +355,11 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	snd_soc_dai_link_set_capabilities(dai_link);
 
 	dai_link->ops			= &graph_ops;
+
+	/* Use custom snd_soc_ops callbacks if available */
+	if (priv->ops)
+		dai_link->ops = priv->ops;
+
 	dai_link->init			= asoc_simple_dai_init;
 
 out_put_node:
@@ -404,6 +444,28 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv,
 	return 0;
 }
 
+static inline bool parse_as_dpcm_link(struct asoc_simple_priv *priv,
+				      struct device_node *codec_port,
+				      struct asoc_simple_data *adata)
+{
+	if (priv->force_dpcm)
+		return true;
+
+	if (!priv->dpcm_selectable)
+		return false;
+
+	/*
+	 * It is DPCM
+	 * if Codec port has many endpoints,
+	 * or has convert-xxx property
+	 */
+	if ((of_get_child_count(codec_port) > 1) ||
+	    (adata->convert_rate || adata->convert_channels))
+		return true;
+
+	return false;
+}
+
 static int graph_for_each_link(struct asoc_simple_priv *priv,
 			struct link_info *li,
 			int (*func_noml)(struct asoc_simple_priv *priv,
@@ -424,7 +486,6 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
 	struct device_node *codec_port;
 	struct device_node *codec_port_old = NULL;
 	struct asoc_simple_data adata;
-	uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
 	int rc, ret;
 
 	/* loop for all listed CPU port */
@@ -447,14 +508,8 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
 			graph_parse_convert(dev, codec_ep, &adata);
 			graph_parse_convert(dev, cpu_ep,   &adata);
 
-			/*
-			 * It is DPCM
-			 * if Codec port has many endpoints,
-			 * or has convert-xxx property
-			 */
-			if (dpcm_selectable &&
-			    ((of_get_child_count(codec_port) > 1) ||
-			     adata.convert_rate || adata.convert_channels))
+			/* check if link requires DPCM parsing */
+			if (parse_as_dpcm_link(priv, codec_port, &adata))
 				ret = func_dpcm(priv, cpu_ep, codec_ep, li,
 						(codec_port_old == codec_port));
 			/* else normal sound */
@@ -474,12 +529,34 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
 	return 0;
 }
 
-static int graph_parse_of(struct asoc_simple_priv *priv)
+static void graph_get_dais_count(struct asoc_simple_priv *priv,
+				 struct link_info *li);
+
+int graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
 {
 	struct snd_soc_card *card = simple_priv_to_card(priv);
 	struct link_info li;
 	int ret;
 
+	card->owner = THIS_MODULE;
+	card->dev = dev;
+
+	memset(&li, 0, sizeof(li));
+	graph_get_dais_count(priv, &li);
+	if (!li.link || !li.dais)
+		return -EINVAL;
+
+	ret = asoc_simple_init_priv(priv, &li);
+	if (ret < 0)
+		return ret;
+
+	priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
+	if (IS_ERR(priv->pa_gpio)) {
+		ret = PTR_ERR(priv->pa_gpio);
+		dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
+		return ret;
+	}
+
 	ret = asoc_simple_parse_widgets(card, NULL);
 	if (ret < 0)
 		return ret;
@@ -506,11 +583,32 @@ static int graph_parse_of(struct asoc_simple_priv *priv)
 					  graph_dai_link_of,
 					  graph_dai_link_of_dpcm);
 		if (ret < 0)
-			return ret;
+			goto err;
 	}
 
-	return asoc_simple_parse_card_name(card, NULL);
+	ret = asoc_simple_parse_card_name(card, NULL);
+	if (ret < 0)
+		goto err;
+
+	snd_soc_card_set_drvdata(card, priv);
+
+	asoc_simple_debug_info(priv);
+
+	ret = devm_snd_soc_register_card(dev, card);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+
+err:
+	asoc_simple_clean_reference(card);
+
+	if (ret != -EPROBE_DEFER)
+		dev_err(dev, "parse error %d\n", ret);
+
+	return ret;
 }
+EXPORT_SYMBOL_GPL(graph_parse_of);
 
 static int graph_count_noml(struct asoc_simple_priv *priv,
 			    struct device_node *cpu_ep,
@@ -538,7 +636,7 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv,
 	li->link++; /* 1xCPU-dummy */
 	li->dais++; /* 1xCPU */
 
-	if (!dup_codec) {
+	if (!dup_codec && codec_ep) {
 		li->link++; /* 1xdummy-Codec */
 		li->conf++; /* 1xdummy-Codec */
 		li->dais++; /* 1xCodec */
@@ -607,7 +705,7 @@ static void graph_get_dais_count(struct asoc_simple_priv *priv,
 		li->link, li->dais, li->conf);
 }
 
-static int graph_card_probe(struct snd_soc_card *card)
+int graph_card_probe(struct snd_soc_card *card)
 {
 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
 	int ret;
@@ -622,14 +720,13 @@ static int graph_card_probe(struct snd_soc_card *card)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(graph_card_probe);
 
 static int graph_probe(struct platform_device *pdev)
 {
 	struct asoc_simple_priv *priv;
 	struct device *dev = &pdev->dev;
 	struct snd_soc_card *card;
-	struct link_info li;
-	int ret;
 
 	/* Allocate the private data and the DAI link array */
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -637,48 +734,14 @@ static int graph_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	card = simple_priv_to_card(priv);
-	card->owner		= THIS_MODULE;
-	card->dev		= dev;
 	card->dapm_widgets	= graph_dapm_widgets;
 	card->num_dapm_widgets	= ARRAY_SIZE(graph_dapm_widgets);
 	card->probe		= graph_card_probe;
 
-	memset(&li, 0, sizeof(li));
-	graph_get_dais_count(priv, &li);
-	if (!li.link || !li.dais)
-		return -EINVAL;
-
-	ret = asoc_simple_init_priv(priv, &li);
-	if (ret < 0)
-		return ret;
+	if (of_device_get_match_data(dev))
+		priv->dpcm_selectable = 1;
 
-	priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
-	if (IS_ERR(priv->pa_gpio)) {
-		ret = PTR_ERR(priv->pa_gpio);
-		dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
-		return ret;
-	}
-
-	ret = graph_parse_of(priv);
-	if (ret < 0) {
-		if (ret != -EPROBE_DEFER)
-			dev_err(dev, "parse error %d\n", ret);
-		goto err;
-	}
-
-	snd_soc_card_set_drvdata(card, priv);
-
-	asoc_simple_debug_info(priv);
-
-	ret = devm_snd_soc_register_card(dev, card);
-	if (ret < 0)
-		goto err;
-
-	return 0;
-err:
-	asoc_simple_clean_reference(card);
-
-	return ret;
+	return graph_parse_of(priv, dev);
 }
 
 static int graph_remove(struct platform_device *pdev)
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index a5b446d5af19..0c6404fc12b3 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -24,6 +24,8 @@ config SND_SOC_INTEL_CATPT
 	depends on DMADEVICES && SND_DMA_SGBUF
 	select DW_DMAC_CORE
 	select SND_SOC_ACPI_INTEL_MATCH
+	select WANT_DEV_COREDUMP
+	select SND_INTEL_DSP_CONFIG
 	help
 	  Enable support for Intel(R) Haswell and Broadwell platforms
 	  with I2S codec present. This is a recommended option.
@@ -55,6 +57,7 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI
 	depends on X86 && ACPI && PCI
 	select SND_SST_ATOM_HIFI2_PLATFORM
 	select SND_SOC_ACPI_INTEL_MATCH
+	select SND_INTEL_DSP_CONFIG
 	select IOSF_MBI
 	help
 	  If you have a Intel Baytrail or Cherrytrail platform with an I2S
@@ -198,7 +201,7 @@ endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
 
 config SND_SOC_INTEL_KEEMBAY
 	tristate "Keembay Platforms"
-	depends on ARM64 || COMPILE_TEST
+	depends on ARCH_KEEMBAY || COMPILE_TEST
 	depends on COMMON_CLK
 	help
 	  If you have a Intel Keembay platform then enable this option
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index 6b5a34a15acb..335c32732994 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -827,14 +827,14 @@ static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	int format;
 
-	format = (fmt & SND_SOC_DAIFMT_MASTER_MASK);
+	format = (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
 	dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format);
 
 	switch (format) {
-	case SND_SOC_DAIFMT_CBS_CFS:
-		return SSP_MODE_MASTER;
-	case SND_SOC_DAIFMT_CBM_CFM:
-		return SSP_MODE_SLAVE;
+	case SND_SOC_DAIFMT_CBC_CFC:
+		return SSP_MODE_PROVIDER;
+	case SND_SOC_DAIFMT_CBP_CFP:
+		return SSP_MODE_CONSUMER;
 	default:
 		dev_err(dai->dev, "Invalid ssp protocol: %d\n", format);
 	}
@@ -905,7 +905,7 @@ static const struct sst_ssp_config sst_ssp_configs = {
 	.ssp_id = SSP_CODEC,
 	.bits_per_slot = 24,
 	.slots = 4,
-	.ssp_mode = SSP_MODE_MASTER,
+	.ssp_mode = SSP_MODE_PROVIDER,
 	.pcm_mode = SSP_PCM_MODE_NETWORK,
 	.duplex = SSP_DUPLEX,
 	.ssp_protocol = SSP_MODE_PCM,
diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h
index 620b48d2a064..23bf37544a8d 100644
--- a/sound/soc/intel/atom/sst-atom-controls.h
+++ b/sound/soc/intel/atom/sst-atom-controls.h
@@ -439,8 +439,8 @@ struct sst_cmd_tone_stop {
 } __packed;
 
 enum sst_ssp_mode {
-	SSP_MODE_MASTER = 0,
-	SSP_MODE_SLAVE = 1,
+	SSP_MODE_PROVIDER = 0,
+	SSP_MODE_CONSUMER = 1,
 };
 
 enum sst_ssp_pcm_mode {
diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c
index e90590559185..e21e11dac000 100644
--- a/sound/soc/intel/atom/sst/sst.c
+++ b/sound/soc/intel/atom/sst/sst.c
@@ -186,7 +186,7 @@ int sst_driver_ops(struct intel_sst_drv *sst)
 			"SST Driver capabilities missing for dev_id: %x",
 			sst->dev_id);
 		return -EINVAL;
-	};
+	}
 }
 
 void sst_process_pending_msg(struct work_struct *work)
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index f943a0884976..2c1b8a2e3506 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -21,6 +21,7 @@
 #include <linux/acpi.h>
 #include <asm/platform_sst_audio.h>
 #include <sound/core.h>
+#include <sound/intel-dsp-config.h>
 #include <sound/soc.h>
 #include <sound/compress_driver.h>
 #include <acpi/acbuffer.h>
@@ -246,6 +247,13 @@ static int sst_acpi_probe(struct platform_device *pdev)
 	id = acpi_match_device(dev->driver->acpi_match_table, dev);
 	if (!id)
 		return -ENODEV;
+
+	ret = snd_intel_acpi_dsp_driver_probe(dev, id->id);
+	if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SST) {
+		dev_dbg(dev, "SST ACPI driver not selected, aborting probe\n");
+		return -ENODEV;
+	}
+
 	dev_dbg(dev, "for %s\n", id->id);
 
 	mach = (struct snd_soc_acpi_mach *)id->driver_data;
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index c10c37803c67..b58b9b60d37e 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -443,6 +443,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH
 		    (MFD_INTEL_LPSS || COMPILE_TEST)) ||\
 		   (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST))
 	select SND_SOC_MAX98373_I2C
+	select SND_SOC_RT1011
 	select SND_SOC_RT1015
 	select SND_SOC_RT5682_I2C
 	select SND_SOC_DMIC
@@ -552,7 +553,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
 	select SND_SOC_RT715_SDCA_SDW
 	select SND_SOC_RT5682_SDW
 	select SND_SOC_DMIC
-        help
+	help
 	  Add support for Intel SoundWire-based platforms connected to
 	  MAX98373, RT700, RT711, RT1308 and RT715
 	  If unsure select "N".
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index a58e4d22e9c8..5f03e484b215 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -18,7 +18,7 @@ snd-soc-sst-byt-cht-cx2072x-objs := bytcht_cx2072x.o
 snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o
 snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o
 snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o
-snd-soc-sof_rt5682-objs := sof_rt5682.o hda_dsp_common.o sof_maxim_common.o
+snd-soc-sof_rt5682-objs := sof_rt5682.o hda_dsp_common.o sof_maxim_common.o sof_realtek_common.o
 snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o hda_dsp_common.o
 snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o
 snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o
diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c
index aa420b201848..c5122d3b0e6c 100644
--- a/sound/soc/intel/boards/bdw-rt5650.c
+++ b/sound/soc/intel/boards/bdw-rt5650.c
@@ -262,14 +262,12 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
 	},
 };
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bdw rt5650" /* card name will be 'sof-bdw rt5650' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bdw rt5650" /* card name will be 'sof-bdw rt5650' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bdw-rt5650"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* ASoC machine driver for Broadwell DSP + RT5650 */
 static struct snd_soc_card bdw_rt5650_card = {
@@ -309,6 +307,15 @@ static int bdw_rt5650_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	/* set card and driver name */
+	if (snd_soc_acpi_sof_parent(&pdev->dev)) {
+		bdw_rt5650_card.name = SOF_CARD_NAME;
+		bdw_rt5650_card.driver_name = SOF_DRIVER_NAME;
+	} else {
+		bdw_rt5650_card.name = CARD_NAME;
+		bdw_rt5650_card.driver_name = DRIVER_NAME;
+	}
+
 	snd_soc_card_set_drvdata(&bdw_rt5650_card, bdw_rt5650);
 
 	return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5650_card);
diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
index 7a3e773d0a1c..021bc59aac80 100644
--- a/sound/soc/intel/boards/bdw-rt5677.c
+++ b/sound/soc/intel/boards/bdw-rt5677.c
@@ -387,14 +387,12 @@ static int bdw_rt5677_resume_post(struct snd_soc_card *card)
 	return 0;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bdw rt5677" /* card name will be 'sof-bdw rt5677' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bdw rt5677" /* card name will be 'sof-bdw rt5677' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bdw-rt5677"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* ASoC machine driver for Broadwell DSP + RT5677 */
 static struct snd_soc_card bdw_rt5677_card = {
@@ -437,6 +435,15 @@ static int bdw_rt5677_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	/* set card and driver name */
+	if (snd_soc_acpi_sof_parent(&pdev->dev)) {
+		bdw_rt5677_card.name = SOF_CARD_NAME;
+		bdw_rt5677_card.driver_name = SOF_DRIVER_NAME;
+	} else {
+		bdw_rt5677_card.name = CARD_NAME;
+		bdw_rt5677_card.driver_name = DRIVER_NAME;
+	}
+
 	snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677);
 
 	return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card);
@@ -446,6 +453,7 @@ static struct platform_driver bdw_rt5677_audio = {
 	.probe = bdw_rt5677_probe,
 	.driver = {
 		.name = "bdw-rt5677",
+		.pm = &snd_soc_pm_ops
 	},
 };
 
diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c
index 77c85f17aca6..3c3aff9c61cc 100644
--- a/sound/soc/intel/boards/broadwell.c
+++ b/sound/soc/intel/boards/broadwell.c
@@ -262,19 +262,15 @@ static int broadwell_resume(struct snd_soc_card *card){
 	return 0;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "broadwell-rt286"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* broadwell audio machine driver for WPT + RT286S */
 static struct snd_soc_card broadwell_rt286 = {
-	.name = CARD_NAME,
-	.driver_name = DRIVER_NAME,
 	.owner = THIS_MODULE,
 	.dai_link = broadwell_rt286_dais,
 	.num_links = ARRAY_SIZE(broadwell_rt286_dais),
@@ -303,6 +299,15 @@ static int broadwell_audio_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	/* set card and driver name */
+	if (snd_soc_acpi_sof_parent(&pdev->dev)) {
+		broadwell_rt286.name = SOF_CARD_NAME;
+		broadwell_rt286.driver_name = SOF_DRIVER_NAME;
+	} else {
+		broadwell_rt286.name = CARD_NAME;
+		broadwell_rt286.driver_name = DRIVER_NAME;
+	}
+
 	return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
 }
 
@@ -318,6 +323,7 @@ static struct platform_driver broadwell_audio = {
 	.remove = broadwell_audio_remove,
 	.driver = {
 		.name = "broadwell-audio",
+		.pm = &snd_soc_pm_ops
 	},
 };
 
diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c
index 0b50b3646d55..2bfe3e4c696f 100644
--- a/sound/soc/intel/boards/bytcht_cx2072x.c
+++ b/sound/soc/intel/boards/bytcht_cx2072x.c
@@ -205,14 +205,12 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = {
 	},
 };
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht cx2072x" /* card name will be 'sof-bytcht cx2072x' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht cx2072x" /* card name will be 'sof-bytcht cx2072x' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bytcht-cx2072x"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* SoC card */
 static struct snd_soc_card byt_cht_cx2072x_card = {
@@ -236,6 +234,7 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev)
 	struct snd_soc_acpi_mach *mach;
 	struct acpi_device *adev;
 	int dai_index = 0;
+	bool sof_parent;
 	int i, ret;
 
 	byt_cht_cx2072x_card.dev = &pdev->dev;
@@ -265,15 +264,27 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+	/* set card and driver name */
+	if (sof_parent) {
+		byt_cht_cx2072x_card.name = SOF_CARD_NAME;
+		byt_cht_cx2072x_card.driver_name = SOF_DRIVER_NAME;
+	} else {
+		byt_cht_cx2072x_card.name = CARD_NAME;
+		byt_cht_cx2072x_card.driver_name = DRIVER_NAME;
+	}
+
+	/* set pm ops */
+	if (sof_parent)
+		pdev->dev.driver->pm = &snd_soc_pm_ops;
+
 	return devm_snd_soc_register_card(&pdev->dev, &byt_cht_cx2072x_card);
 }
 
 static struct platform_driver snd_byt_cht_cx2072x_driver = {
 	.driver = {
 		.name = "bytcht_cx2072x",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-		.pm = &snd_soc_pm_ops,
-#endif
 	},
 	.probe = snd_byt_cht_cx2072x_probe,
 };
diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c
index e1e46b4bbac5..cfeba27252ba 100644
--- a/sound/soc/intel/boards/bytcht_da7213.c
+++ b/sound/soc/intel/boards/bytcht_da7213.c
@@ -205,14 +205,12 @@ static struct snd_soc_dai_link dailink[] = {
 	},
 };
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht da7213" /* card name will be 'sof-bytcht da7213' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht da7213" /* card name will be 'sof-bytcht da7213' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bytcht-da7213"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* SoC card */
 static struct snd_soc_card bytcht_da7213_card = {
@@ -237,6 +235,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
 	struct snd_soc_acpi_mach *mach;
 	const char *platform_name;
 	struct acpi_device *adev;
+	bool sof_parent;
 	int dai_index = 0;
 	int ret_val = 0;
 	int i;
@@ -269,6 +268,21 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
 	if (ret_val)
 		return ret_val;
 
+	sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+	/* set card and driver name */
+	if (sof_parent) {
+		bytcht_da7213_card.name = SOF_CARD_NAME;
+		bytcht_da7213_card.driver_name = SOF_DRIVER_NAME;
+	} else {
+		bytcht_da7213_card.name = CARD_NAME;
+		bytcht_da7213_card.driver_name = DRIVER_NAME;
+	}
+
+	/* set pm ops */
+	if (sof_parent)
+		pdev->dev.driver->pm = &snd_soc_pm_ops;
+
 	ret_val = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret_val) {
 		dev_err(&pdev->dev,
@@ -282,9 +296,6 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
 static struct platform_driver bytcht_da7213_driver = {
 	.driver = {
 		.name = "bytcht_da7213",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-		.pm = &snd_soc_pm_ops,
-#endif
 	},
 	.probe = bytcht_da7213_probe,
 };
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
index 7ed869bf1a92..892cf684216e 100644
--- a/sound/soc/intel/boards/bytcht_es8316.c
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -406,18 +406,14 @@ static int byt_cht_es8316_resume(struct snd_soc_card *card)
 	return 0;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht es8316" /* card name will be 'sof-bytcht es8316' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht es8316" /* card name will be 'sof-bytcht es8316' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bytcht-es8316"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 static struct snd_soc_card byt_cht_es8316_card = {
-	.name = CARD_NAME,
-	.driver_name = DRIVER_NAME,
 	.owner = THIS_MODULE,
 	.dai_link = byt_cht_es8316_dais,
 	.num_links = ARRAY_SIZE(byt_cht_es8316_dais),
@@ -472,6 +468,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
 	const char *platform_name;
 	struct acpi_device *adev;
 	struct device *codec_dev;
+	bool sof_parent;
 	unsigned int cnt = 0;
 	int dai_index = 0;
 	int i;
@@ -590,6 +587,21 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
 	byt_cht_es8316_card.long_name = long_name;
 #endif
 
+	sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+	/* set card and driver name */
+	if (sof_parent) {
+		byt_cht_es8316_card.name = SOF_CARD_NAME;
+		byt_cht_es8316_card.driver_name = SOF_DRIVER_NAME;
+	} else {
+		byt_cht_es8316_card.name = CARD_NAME;
+		byt_cht_es8316_card.driver_name = DRIVER_NAME;
+	}
+
+	/* set pm ops */
+	if (sof_parent)
+		dev->driver->pm = &snd_soc_pm_ops;
+
 	/* register the soc card */
 	snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv);
 
@@ -615,9 +627,6 @@ static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev)
 static struct platform_driver snd_byt_cht_es8316_mc_driver = {
 	.driver = {
 		.name = "bytcht_es8316",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-		.pm = &snd_soc_pm_ops,
-#endif
 	},
 	.probe = snd_byt_cht_es8316_mc_probe,
 	.remove = snd_byt_cht_es8316_mc_remove,
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index f790514a147d..5520d7c80019 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -423,6 +423,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
 	},
 	{
 		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 140 CESIUM"),
+		},
+		.driver_data = (void *)(BYT_RT5640_IN1_MAP |
+					BYT_RT5640_JD_SRC_JD2_IN4N |
+					BYT_RT5640_OVCD_TH_2000UA |
+					BYT_RT5640_OVCD_SF_0P75 |
+					BYT_RT5640_SSP0_AIF1 |
+					BYT_RT5640_MCLK_EN),
+	},
+	{
+		.matches = {
 			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"),
 		},
@@ -1147,18 +1159,14 @@ static int byt_rt5640_resume(struct snd_soc_card *card)
 	return 0;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht rt5640" /* card name will be 'sof-bytcht rt5640' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht rt5640" /* card name will be 'sof-bytcht rt5640' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bytcr-rt5640"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 static struct snd_soc_card byt_rt5640_card = {
-	.name = CARD_NAME,
-	.driver_name = DRIVER_NAME,
 	.owner = THIS_MODULE,
 	.dai_link = byt_rt5640_dais,
 	.num_links = ARRAY_SIZE(byt_rt5640_dais),
@@ -1178,12 +1186,14 @@ struct acpi_chan_package {   /* ACPICA seems to require 64 bit integers */
 
 static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
 	static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" };
 	const struct dmi_system_id *dmi_id;
 	struct byt_rt5640_private *priv;
 	struct snd_soc_acpi_mach *mach;
 	const char *platform_name;
 	struct acpi_device *adev;
+	bool sof_parent;
 	int ret_val = 0;
 	int dai_index = 0;
 	int i;
@@ -1347,6 +1357,21 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 	if (ret_val)
 		return ret_val;
 
+	sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+	/* set card and driver name */
+	if (sof_parent) {
+		byt_rt5640_card.name = SOF_CARD_NAME;
+		byt_rt5640_card.driver_name = SOF_DRIVER_NAME;
+	} else {
+		byt_rt5640_card.name = CARD_NAME;
+		byt_rt5640_card.driver_name = DRIVER_NAME;
+	}
+
+	/* set pm ops */
+	if (sof_parent)
+		dev->driver->pm = &snd_soc_pm_ops;
+
 	ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
 
 	if (ret_val) {
@@ -1361,9 +1386,6 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 static struct platform_driver snd_byt_rt5640_mc_driver = {
 	.driver = {
 		.name = "bytcr_rt5640",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-		.pm = &snd_soc_pm_ops,
-#endif
 	},
 	.probe = snd_byt_rt5640_mc_probe,
 };
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index 688b5e0a49e3..f289ec8563a1 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -143,7 +143,7 @@ static int byt_rt5651_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai,
 
 	/* Configure the PLL before selecting it */
 	if (!(byt_rt5651_quirk & BYT_RT5651_MCLK_EN)) {
-		clk_id = RT5651_PLL1_S_BCLK1,
+		clk_id = RT5651_PLL1_S_BCLK1;
 		clk_freq = rate * bclk_ratio;
 	} else {
 		clk_id = RT5651_PLL1_S_MCLK;
@@ -827,14 +827,12 @@ static int byt_rt5651_resume(struct snd_soc_card *card)
 	return 0;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht rt5651" /* card name will be 'sof-bytcht rt5651' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht rt5651" /* card name will be 'sof-bytcht rt5651' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "bytcr-rt5651"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 static struct snd_soc_card byt_rt5651_card = {
 	.name = CARD_NAME,
@@ -876,6 +874,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
 	const char *platform_name;
 	struct acpi_device *adev;
 	struct device *codec_dev;
+	bool sof_parent;
 	bool is_bytcr = false;
 	int ret_val = 0;
 	int dai_index = 0;
@@ -1093,6 +1092,21 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
 	if (ret_val)
 		return ret_val;
 
+	sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+	/* set card and driver name */
+	if (sof_parent) {
+		byt_rt5651_card.name = SOF_CARD_NAME;
+		byt_rt5651_card.driver_name = SOF_DRIVER_NAME;
+	} else {
+		byt_rt5651_card.name = CARD_NAME;
+		byt_rt5651_card.driver_name = DRIVER_NAME;
+	}
+
+	/* set pm ops */
+	if (sof_parent)
+		pdev->dev.driver->pm = &snd_soc_pm_ops;
+
 	ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card);
 
 	if (ret_val) {
@@ -1107,9 +1121,6 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
 static struct platform_driver snd_byt_rt5651_mc_driver = {
 	.driver = {
 		.name = "bytcr_rt5651",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-		.pm = &snd_soc_pm_ops,
-#endif
 	},
 	.probe = snd_byt_rt5651_mc_probe,
 };
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index 835e9bd6b52d..131882378a59 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -382,19 +382,15 @@ static struct snd_soc_dai_link cht_dailink[] = {
 	},
 };
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht max98090" /* card name will be 'sof-bytcht max98090 */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht max98090" /* card name will be 'sof-bytcht max98090 */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "chtmax98090"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* SoC card */
 static struct snd_soc_card snd_soc_card_cht = {
-	.name = CARD_NAME,
-	.driver_name = DRIVER_NAME,
 	.owner = THIS_MODULE,
 	.dai_link = cht_dailink,
 	.num_links = ARRAY_SIZE(cht_dailink),
@@ -540,6 +536,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 	const char *mclk_name;
 	struct snd_soc_acpi_mach *mach;
 	const char *platform_name;
+	bool sof_parent;
 
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
@@ -602,6 +599,21 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 		}
 	}
 
+	sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+	/* set card and driver name */
+	if (sof_parent) {
+		snd_soc_card_cht.name = SOF_CARD_NAME;
+		snd_soc_card_cht.driver_name = SOF_DRIVER_NAME;
+	} else {
+		snd_soc_card_cht.name = CARD_NAME;
+		snd_soc_card_cht.driver_name = DRIVER_NAME;
+	}
+
+	/* set pm ops */
+	if (sof_parent)
+		dev->driver->pm = &snd_soc_pm_ops;
+
 	ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
 	if (ret_val) {
 		dev_err(&pdev->dev,
@@ -626,9 +638,6 @@ static int snd_cht_mc_remove(struct platform_device *pdev)
 static struct platform_driver snd_cht_mc_driver = {
 	.driver = {
 		.name = "cht-bsw-max98090",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-		.pm = &snd_soc_pm_ops,
-#endif
 	},
 	.probe = snd_cht_mc_probe,
 	.remove = snd_cht_mc_remove,
diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c
index 3e12bff15fed..fd5e25ca05f7 100644
--- a/sound/soc/intel/boards/cht_bsw_nau8824.c
+++ b/sound/soc/intel/boards/cht_bsw_nau8824.c
@@ -176,9 +176,6 @@ SND_SOC_DAILINK_DEF(media,
 SND_SOC_DAILINK_DEF(deepbuffer,
 	DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
 
-SND_SOC_DAILINK_DEF(compress,
-	DAILINK_COMP_ARRAY(COMP_CPU("compress-cpu-dai")));
-
 SND_SOC_DAILINK_DEF(ssp2_port,
 	DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
 SND_SOC_DAILINK_DEF(ssp2_codec,
@@ -209,16 +206,11 @@ static struct snd_soc_dai_link cht_dailink[] = {
 		.ops = &cht_aif1_ops,
 		SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
 	},
-	[MERR_DPCM_COMPR] = {
-		.name = "Compressed Port",
-		.stream_name = "Compress",
-		SND_SOC_DAILINK_REG(compress, dummy, platform),
-	},
 	/* Back End DAI links */
 	{
 		/* SSP2 - Codec */
 		.name = "SSP2-Codec",
-		.id = 1,
+		.id = 0,
 		.no_pcm = 1,
 		.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
 			| SND_SOC_DAIFMT_CBS_CFS,
@@ -231,19 +223,15 @@ static struct snd_soc_dai_link cht_dailink[] = {
 	},
 };
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht nau8824" /* card name will be 'sof-bytcht nau8824 */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht nau8824" /* card name will be 'sof-bytcht nau8824 */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "chtnau8824"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* SoC card */
 static struct snd_soc_card snd_soc_card_cht = {
-	.name = CARD_NAME,
-	.driver_name = DRIVER_NAME,
 	.owner = THIS_MODULE,
 	.dai_link = cht_dailink,
 	.num_links = ARRAY_SIZE(cht_dailink),
@@ -260,6 +248,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 	struct cht_mc_private *drv;
 	struct snd_soc_acpi_mach *mach;
 	const char *platform_name;
+	bool sof_parent;
 	int ret_val;
 
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
@@ -277,6 +266,21 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 	if (ret_val)
 		return ret_val;
 
+	sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+	/* set card and driver name */
+	if (sof_parent) {
+		snd_soc_card_cht.name = SOF_CARD_NAME;
+		snd_soc_card_cht.driver_name = SOF_DRIVER_NAME;
+	} else {
+		snd_soc_card_cht.name = CARD_NAME;
+		snd_soc_card_cht.driver_name = DRIVER_NAME;
+	}
+
+	/* set pm ops */
+	if (sof_parent)
+		pdev->dev.driver->pm = &snd_soc_pm_ops;
+
 	/* register the soc card */
 	ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
 	if (ret_val) {
@@ -292,9 +296,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 static struct platform_driver snd_cht_mc_driver = {
 	.driver = {
 		.name = "cht-bsw-nau8824",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-		.pm = &snd_soc_pm_ops,
-#endif
 	},
 	.probe = snd_cht_mc_probe,
 };
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index b53c02481749..6fea554cfed5 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -479,21 +479,17 @@ static struct snd_soc_dai_link cht_dailink[] = {
 	},
 };
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_RT5645_NAME "bytcht rt5645" /* card name 'sof-bytcht rt5645' */
-#define CARD_RT5650_NAME "bytcht rt5650" /* card name 'sof-bytcht rt5650' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_RT5645_NAME "bytcht rt5645" /* card name 'sof-bytcht rt5645' */
+#define SOF_CARD_RT5650_NAME "bytcht rt5650" /* card name 'sof-bytcht rt5650' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_RT5645_NAME "chtrt5645"
 #define CARD_RT5650_NAME "chtrt5650"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* SoC card */
 static struct snd_soc_card snd_soc_card_chtrt5645 = {
-	.name = CARD_RT5645_NAME,
-	.driver_name = DRIVER_NAME,
 	.owner = THIS_MODULE,
 	.dai_link = cht_dailink,
 	.num_links = ARRAY_SIZE(cht_dailink),
@@ -506,8 +502,6 @@ static struct snd_soc_card snd_soc_card_chtrt5645 = {
 };
 
 static struct snd_soc_card snd_soc_card_chtrt5650 = {
-	.name = CARD_RT5650_NAME,
-	.driver_name = DRIVER_NAME,
 	.owner = THIS_MODULE,
 	.dai_link = cht_dailink,
 	.num_links = ARRAY_SIZE(cht_dailink),
@@ -541,6 +535,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 	const char *platform_name;
 	struct cht_mc_private *drv;
 	struct acpi_device *adev;
+	bool sof_parent;
 	bool found = false;
 	bool is_bytcr = false;
 	int dai_index = 0;
@@ -680,6 +675,26 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 	}
 
 	snd_soc_card_set_drvdata(card, drv);
+
+	sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+	/* set card and driver name */
+	if (sof_parent) {
+		snd_soc_card_chtrt5645.name = SOF_CARD_RT5645_NAME;
+		snd_soc_card_chtrt5645.driver_name = SOF_DRIVER_NAME;
+		snd_soc_card_chtrt5650.name = SOF_CARD_RT5650_NAME;
+		snd_soc_card_chtrt5650.driver_name = SOF_DRIVER_NAME;
+	} else {
+		snd_soc_card_chtrt5645.name = CARD_RT5645_NAME;
+		snd_soc_card_chtrt5645.driver_name = DRIVER_NAME;
+		snd_soc_card_chtrt5650.name = CARD_RT5650_NAME;
+		snd_soc_card_chtrt5650.driver_name = DRIVER_NAME;
+	}
+
+	/* set pm ops */
+	if (sof_parent)
+		pdev->dev.driver->pm = &snd_soc_pm_ops;
+
 	ret_val = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret_val) {
 		dev_err(&pdev->dev,
@@ -693,9 +708,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 static struct platform_driver snd_cht_mc_driver = {
 	.driver = {
 		.name = "cht-bsw-rt5645",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-		.pm = &snd_soc_pm_ops,
-#endif
 	},
 	.probe = snd_cht_mc_probe,
 };
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index 8442be93eb1c..10c88ef2f85d 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -382,19 +382,15 @@ static int cht_resume_post(struct snd_soc_card *card)
 	return 0;
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 /* use space before codec name to simplify card ID, and simplify driver name */
-#define CARD_NAME "bytcht rt5672" /* card name will be 'sof-bytcht rt5672' */
-#define DRIVER_NAME "SOF"
-#else
+#define SOF_CARD_NAME "bytcht rt5672" /* card name will be 'sof-bytcht rt5672' */
+#define SOF_DRIVER_NAME "SOF"
+
 #define CARD_NAME "cht-bsw-rt5672"
 #define DRIVER_NAME NULL /* card name will be used for driver name */
-#endif
 
 /* SoC card */
 static struct snd_soc_card snd_soc_card_cht = {
-	.name = CARD_NAME,
-	.driver_name = DRIVER_NAME,
 	.owner = THIS_MODULE,
 	.dai_link = cht_dailink,
 	.num_links = ARRAY_SIZE(cht_dailink),
@@ -417,6 +413,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 	struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
 	const char *platform_name;
 	struct acpi_device *adev;
+	bool sof_parent;
 	int i;
 
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
@@ -458,6 +455,21 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 	}
 	snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
 
+	sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
+
+	/* set card and driver name */
+	if (sof_parent) {
+		snd_soc_card_cht.name = SOF_CARD_NAME;
+		snd_soc_card_cht.driver_name = SOF_DRIVER_NAME;
+	} else {
+		snd_soc_card_cht.name = CARD_NAME;
+		snd_soc_card_cht.driver_name = DRIVER_NAME;
+	}
+
+	/* set pm ops */
+	if (sof_parent)
+		pdev->dev.driver->pm = &snd_soc_pm_ops;
+
 	/* register the soc card */
 	ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
 	if (ret_val) {
@@ -472,9 +484,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 static struct platform_driver snd_cht_mc_driver = {
 	.driver = {
 		.name = "cht-bsw-rt5672",
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
-		.pm = &snd_soc_pm_ops,
-#endif
 	},
 	.probe = snd_cht_mc_probe,
 };
diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c
index b6e63ea13d64..c2a9757181fe 100644
--- a/sound/soc/intel/boards/sof_maxim_common.c
+++ b/sound/soc/intel/boards/sof_maxim_common.c
@@ -49,11 +49,11 @@ static int max98373_hw_params(struct snd_pcm_substream *substream,
 	for_each_rtd_codec_dais(rtd, j, codec_dai) {
 		if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) {
 			/* DEV0 tdm slot configuration */
-			snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 24);
+			snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32);
 		}
 		if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) {
 			/* DEV1 tdm slot configuration */
-			snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 24);
+			snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32);
 		}
 	}
 	return 0;
diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c
new file mode 100644
index 000000000000..f3cf73c620ba
--- /dev/null
+++ b/sound/soc/intel/boards/sof_realtek_common.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+#include <uapi/sound/asound.h>
+#include "../../codecs/rt1011.h"
+#include "sof_realtek_common.h"
+
+/*
+ * Current only 2-amp configuration is supported for rt1011
+ */
+static const struct snd_soc_dapm_route rt1011_dapm_routes[] = {
+	/* speaker */
+	{ "Left Spk", NULL, "Left SPO" },
+	{ "Right Spk", NULL, "Right SPO" },
+};
+
+/*
+ * Make sure device's Unique ID follows this configuration:
+ *
+ * Two speakers:
+ *         0: left, 1: right
+ * Four speakers:
+ *         0: Woofer left, 1: Woofer right
+ *         2: Tweeter left, 3: Tweeter right
+ */
+static struct snd_soc_codec_conf rt1011_codec_confs[] = {
+	{
+		.dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME),
+		.name_prefix = "Left",
+	},
+	{
+		.dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME),
+		.name_prefix = "Right",
+	},
+};
+
+static struct snd_soc_dai_link_component rt1011_dai_link_components[] = {
+	{
+		.name = RT1011_DEV0_NAME,
+		.dai_name = RT1011_CODEC_DAI,
+	},
+	{
+		.name = RT1011_DEV1_NAME,
+		.dai_name = RT1011_CODEC_DAI,
+	},
+};
+
+static const struct {
+	unsigned int tx;
+	unsigned int rx;
+} rt1011_tdm_mask[] = {
+	{.tx = 0x4, .rx = 0x1},
+	{.tx = 0x8, .rx = 0x2},
+};
+
+static int rt1011_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 srate, i, ret = 0;
+
+	srate = params_rate(params);
+
+	for_each_rtd_codec_dais(rtd, i, codec_dai) {
+		/* 100 Fs to drive 24 bit data */
+		ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK,
+					  100 * srate, 256 * srate);
+		if (ret < 0) {
+			dev_err(codec_dai->dev, "fail to set pll, ret %d\n",
+				ret);
+			return ret;
+		}
+
+		ret = snd_soc_dai_set_sysclk(codec_dai, RT1011_FS_SYS_PRE_S_PLL1,
+					     256 * srate, SND_SOC_CLOCK_IN);
+		if (ret < 0) {
+			dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n",
+				ret);
+			return ret;
+		}
+
+		if (i >= ARRAY_SIZE(rt1011_tdm_mask)) {
+			dev_err(codec_dai->dev, "invalid codec index %d\n",
+				i);
+			return -ENODEV;
+		}
+
+		ret = snd_soc_dai_set_tdm_slot(codec_dai, rt1011_tdm_mask[i].tx,
+					       rt1011_tdm_mask[i].rx, 4,
+					       params_width(params));
+		if (ret < 0) {
+			dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_ops rt1011_ops = {
+	.hw_params = rt1011_hw_params,
+};
+
+static int rt1011_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_card *card = rtd->card;
+	int ret;
+
+	ret = snd_soc_dapm_add_routes(&card->dapm, rt1011_dapm_routes,
+				      ARRAY_SIZE(rt1011_dapm_routes));
+	if (ret)
+		dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
+	return ret;
+}
+
+void sof_rt1011_dai_link(struct snd_soc_dai_link *link)
+{
+	link->codecs = rt1011_dai_link_components;
+	link->num_codecs = ARRAY_SIZE(rt1011_dai_link_components);
+	link->init = rt1011_init;
+	link->ops = &rt1011_ops;
+}
+
+void sof_rt1011_codec_conf(struct snd_soc_card *card)
+{
+	card->codec_conf = rt1011_codec_confs;
+	card->num_configs = ARRAY_SIZE(rt1011_codec_confs);
+}
diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h
new file mode 100644
index 000000000000..87cb3812b926
--- /dev/null
+++ b/sound/soc/intel/boards/sof_realtek_common.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2020 Intel Corporation.
+ */
+
+/*
+ * This file defines data structures used in Machine Driver for Intel
+ * platforms with Realtek Codecs.
+ */
+#ifndef __SOF_REALTEK_COMMON_H
+#define __SOF_REALTEK_COMMON_H
+
+#include <sound/soc.h>
+
+#define RT1011_CODEC_DAI	"rt1011-aif"
+#define RT1011_DEV0_NAME	"i2c-10EC1011:00"
+#define RT1011_DEV1_NAME	"i2c-10EC1011:01"
+#define RT1011_DEV2_NAME	"i2c-10EC1011:02"
+#define RT1011_DEV3_NAME	"i2c-10EC1011:03"
+
+void sof_rt1011_dai_link(struct snd_soc_dai_link *link);
+void sof_rt1011_codec_conf(struct snd_soc_card *card);
+
+#endif /* __SOF_REALTEK_COMMON_H */
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index ddbb9fe7cc06..8b1ca2da9bb9 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -24,6 +24,7 @@
 #include "../common/soc-intel-quirks.h"
 #include "hda_dsp_common.h"
 #include "sof_maxim_common.h"
+#include "sof_realtek_common.h"
 
 #define NAME_SIZE 32
 
@@ -41,9 +42,11 @@
 #define SOF_RT5682_NUM_HDMIDEV_MASK		(GENMASK(12, 10))
 #define SOF_RT5682_NUM_HDMIDEV(quirk)	\
 	((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK)
-#define SOF_RT1015_SPEAKER_AMP_PRESENT		BIT(13)
-#define SOF_MAX98373_SPEAKER_AMP_PRESENT	BIT(14)
-#define SOF_MAX98360A_SPEAKER_AMP_PRESENT	BIT(15)
+#define SOF_RT1011_SPEAKER_AMP_PRESENT		BIT(13)
+#define SOF_RT1015_SPEAKER_AMP_PRESENT		BIT(14)
+#define SOF_RT1015_SPEAKER_AMP_100FS		BIT(15)
+#define SOF_MAX98373_SPEAKER_AMP_PRESENT	BIT(16)
+#define SOF_MAX98360A_SPEAKER_AMP_PRESENT	BIT(17)
 
 /* Default: MCLK on, MCLK 19.2M, SSP0  */
 static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
@@ -100,6 +103,24 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
 					SOF_RT5682_SSP_CODEC(1)),
 	},
 	{
+		/*
+		 * Dooly is hatch family but using rt1015 amp so it
+		 * requires a quirk before "Google_Hatch".
+		 */
+		.callback = sof_rt5682_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Dooly"),
+		},
+		.driver_data = (void *)(SOF_RT5682_MCLK_EN |
+					SOF_RT5682_MCLK_24MHZ |
+					SOF_RT5682_SSP_CODEC(0) |
+					SOF_SPEAKER_AMP_PRESENT |
+					SOF_RT1015_SPEAKER_AMP_PRESENT |
+					SOF_RT1015_SPEAKER_AMP_100FS |
+					SOF_RT5682_SSP_AMP(1)),
+	},
+	{
 		.callback = sof_rt5682_quirk_cb,
 		.matches = {
 			DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Hatch"),
@@ -291,21 +312,26 @@ static int sof_rt1015_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_soc_card *card = rtd->card;
 	struct snd_soc_dai *codec_dai;
-	int i, ret;
+	int i, fs, ret;
 
 	if (!snd_soc_card_get_codec_dai(card, "rt1015-aif"))
 		return 0;
 
+	if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_100FS)
+		fs = 100;
+	else
+		fs = 64;
+
 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
 		/* Set tdm/i2s1 master bclk ratio */
-		ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
+		ret = snd_soc_dai_set_bclk_ratio(codec_dai, fs);
 		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,
-					  params_rate(params) * 64,
+					  params_rate(params) * fs,
 					  params_rate(params) * 256);
 		if (ret < 0) {
 			dev_err(card->dev, "failed to set pll\n");
@@ -319,6 +345,26 @@ static int sof_rt1015_hw_params(struct snd_pcm_substream *substream,
 			dev_err(card->dev, "failed to set sysclk\n");
 			return ret;
 		}
+
+		if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_100FS) {
+			if (!strcmp(codec_dai->component->name, "i2c-10EC1015:00")) {
+				ret = snd_soc_dai_set_tdm_slot(codec_dai,
+							       0x0, 0x1, 4, 24);
+				if (ret < 0) {
+					dev_err(card->dev, "failed to set tdm slot\n");
+					return ret;
+				}
+			}
+
+			if (!strcmp(codec_dai->component->name, "i2c-10EC1015:01")) {
+				ret = snd_soc_dai_set_tdm_slot(codec_dai,
+							       0x0, 0x2, 4, 24);
+				if (ret < 0) {
+					dev_err(card->dev, "failed to set tdm slot\n");
+					return ret;
+				}
+			}
+		}
 	}
 
 	return 0;
@@ -690,11 +736,16 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
 			links[id].num_codecs = ARRAY_SIZE(max_98373_components);
 			links[id].init = max98373_spk_codec_init;
 			links[id].ops = &max_98373_ops;
+			/* feedback stream */
+			links[id].dpcm_capture = 1;
 		} else if (sof_rt5682_quirk &
 				SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
 			links[id].codecs = max98360a_component;
 			links[id].num_codecs = ARRAY_SIZE(max98360a_component);
 			links[id].init = speaker_codec_init;
+		} else if (sof_rt5682_quirk &
+				SOF_RT1011_SPEAKER_AMP_PRESENT) {
+			sof_rt1011_dai_link(&links[id]);
 		} else {
 			links[id].codecs = max98357a_component;
 			links[id].num_codecs = ARRAY_SIZE(max98357a_component);
@@ -805,6 +856,8 @@ static int sof_audio_probe(struct platform_device *pdev)
 
 	if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT)
 		sof_max98373_codec_conf(&sof_audio_card_rt5682);
+	else if (sof_rt5682_quirk & SOF_RT1011_SPEAKER_AMP_PRESENT)
+		sof_rt1011_codec_conf(&sof_audio_card_rt5682);
 
 	dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
 					      dmic_be_num, hdmi_num);
@@ -875,6 +928,25 @@ static const struct platform_device_id board_ids[] = {
 					SOF_MAX98360A_SPEAKER_AMP_PRESENT |
 					SOF_RT5682_SSP_AMP(1)),
 	},
+	{
+		.name = "cml_rt1015_rt5682",
+		.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+					SOF_RT5682_MCLK_24MHZ |
+					SOF_RT5682_SSP_CODEC(0) |
+					SOF_SPEAKER_AMP_PRESENT |
+					SOF_RT1015_SPEAKER_AMP_PRESENT |
+					SOF_RT1015_SPEAKER_AMP_100FS |
+					SOF_RT5682_SSP_AMP(1)),
+	},
+	{
+		.name = "tgl_rt1011_rt5682",
+		.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+					SOF_RT5682_SSP_CODEC(0) |
+					SOF_SPEAKER_AMP_PRESENT |
+					SOF_RT1011_SPEAKER_AMP_PRESENT |
+					SOF_RT5682_SSP_AMP(1) |
+					SOF_RT5682_NUM_HDMIDEV(4)),
+	},
 	{ }
 };
 
@@ -892,9 +964,12 @@ module_platform_driver(sof_audio)
 MODULE_DESCRIPTION("SOF Audio Machine driver");
 MODULE_AUTHOR("Bard Liao <bard.liao@intel.com>");
 MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
+MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:sof_rt5682");
 MODULE_ALIAS("platform:tgl_max98357a_rt5682");
 MODULE_ALIAS("platform:jsl_rt5682_rt1015");
 MODULE_ALIAS("platform:tgl_max98373_rt5682");
 MODULE_ALIAS("platform:jsl_rt5682_max98360a");
+MODULE_ALIAS("platform:cml_rt1015_rt5682");
+MODULE_ALIAS("platform:tgl_rt1011_rt5682");
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index b29946eb4355..ca968901ac96 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -52,6 +52,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
 		.callback = sof_sdw_quirk_cb,
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
+		},
+		.driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
+					SOF_RT715_DAI_ID_FIX |
+					SOF_SDW_FOUR_SPK),
+	},
+	{
+		.callback = sof_sdw_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
 		},
 		.driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h
index 88dc3fb6306f..0f53a0d43254 100644
--- a/sound/soc/intel/catpt/core.h
+++ b/sound/soc/intel/catpt/core.h
@@ -80,9 +80,9 @@ struct catpt_spec {
 	u32 host_ssp_offset[CATPT_SSP_COUNT];
 	u32 dram_mask;
 	u32 iram_mask;
+	u32 d3srampgd_bit;
+	u32 d3pgd_bit;
 	void (*pll_shutdown)(struct catpt_dev *cdev, bool enable);
-	int (*power_up)(struct catpt_dev *cdev);
-	int (*power_down)(struct catpt_dev *cdev);
 };
 
 struct catpt_dev {
@@ -126,10 +126,8 @@ int catpt_dma_memcpy_fromdsp(struct catpt_dev *cdev, struct dma_chan *chan,
 
 void lpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable);
 void wpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable);
-int lpt_dsp_power_up(struct catpt_dev *cdev);
-int lpt_dsp_power_down(struct catpt_dev *cdev);
-int wpt_dsp_power_up(struct catpt_dev *cdev);
-int wpt_dsp_power_down(struct catpt_dev *cdev);
+int catpt_dsp_power_up(struct catpt_dev *cdev);
+int catpt_dsp_power_down(struct catpt_dev *cdev);
 int catpt_dsp_stall(struct catpt_dev *cdev, bool stall);
 void catpt_dsp_update_srampge(struct catpt_dev *cdev, struct resource *sram,
 			      unsigned long mask);
diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c
index a70179959795..85a34e37316d 100644
--- a/sound/soc/intel/catpt/device.c
+++ b/sound/soc/intel/catpt/device.c
@@ -19,6 +19,7 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <sound/intel-dsp-config.h>
 #include <sound/soc.h>
 #include <sound/soc-acpi.h>
 #include <sound/soc-acpi-intel-match.h>
@@ -69,7 +70,7 @@ release_dma_chan:
 	dma_release_channel(chan);
 	if (ret)
 		return ret;
-	return cdev->spec->power_down(cdev);
+	return catpt_dsp_power_down(cdev);
 }
 
 static int __maybe_unused catpt_resume(struct device *dev)
@@ -77,7 +78,7 @@ static int __maybe_unused catpt_resume(struct device *dev)
 	struct catpt_dev *cdev = dev_get_drvdata(dev);
 	int ret, i;
 
-	ret = cdev->spec->power_up(cdev);
+	ret = catpt_dsp_power_up(cdev);
 	if (ret)
 		return ret;
 
@@ -162,7 +163,7 @@ static int catpt_probe_components(struct catpt_dev *cdev)
 {
 	int ret;
 
-	ret = cdev->spec->power_up(cdev);
+	ret = catpt_dsp_power_up(cdev);
 	if (ret)
 		return ret;
 
@@ -204,7 +205,7 @@ err_reg_board:
 err_boot_fw:
 	catpt_dmac_remove(cdev);
 err_dmac_probe:
-	cdev->spec->power_down(cdev);
+	catpt_dsp_power_down(cdev);
 
 	return ret;
 }
@@ -239,9 +240,20 @@ static int catpt_acpi_probe(struct platform_device *pdev)
 	const struct catpt_spec *spec;
 	struct catpt_dev *cdev;
 	struct device *dev = &pdev->dev;
+	const struct acpi_device_id *id;
 	struct resource *res;
 	int ret;
 
+	id = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (!id)
+		return -ENODEV;
+
+	ret = snd_intel_acpi_dsp_driver_probe(dev, id->id);
+	if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SST) {
+		dev_dbg(dev, "CATPT ACPI driver not selected, aborting probe\n");
+		return -ENODEV;
+	}
+
 	spec = device_get_match_data(dev);
 	if (!spec)
 		return -ENODEV;
@@ -293,7 +305,7 @@ static int catpt_acpi_remove(struct platform_device *pdev)
 
 	snd_soc_unregister_component(cdev->dev);
 	catpt_dmac_remove(cdev);
-	cdev->spec->power_down(cdev);
+	catpt_dsp_power_down(cdev);
 
 	catpt_sram_free(&cdev->iram);
 	catpt_sram_free(&cdev->dram);
@@ -311,9 +323,9 @@ static struct catpt_spec lpt_desc = {
 	.host_ssp_offset = { 0x0E8000, 0x0E9000 },
 	.dram_mask = LPT_VDRTCTL0_DSRAMPGE_MASK,
 	.iram_mask = LPT_VDRTCTL0_ISRAMPGE_MASK,
+	.d3srampgd_bit = LPT_VDRTCTL0_D3SRAMPGD,
+	.d3pgd_bit = LPT_VDRTCTL0_D3PGD,
 	.pll_shutdown = lpt_dsp_pll_shutdown,
-	.power_up = lpt_dsp_power_up,
-	.power_down = lpt_dsp_power_down,
 };
 
 static struct catpt_spec wpt_desc = {
@@ -326,9 +338,9 @@ static struct catpt_spec wpt_desc = {
 	.host_ssp_offset = { 0x0FC000, 0x0FD000 },
 	.dram_mask = WPT_VDRTCTL0_DSRAMPGE_MASK,
 	.iram_mask = WPT_VDRTCTL0_ISRAMPGE_MASK,
+	.d3srampgd_bit = WPT_VDRTCTL0_D3SRAMPGD,
+	.d3pgd_bit = WPT_VDRTCTL0_D3PGD,
 	.pll_shutdown = wpt_dsp_pll_shutdown,
-	.power_up = wpt_dsp_power_up,
-	.power_down = wpt_dsp_power_down,
 };
 
 static const struct acpi_device_id catpt_ids[] = {
diff --git a/sound/soc/intel/catpt/dsp.c b/sound/soc/intel/catpt/dsp.c
index 9e807b941732..9c5fd18f2600 100644
--- a/sound/soc/intel/catpt/dsp.c
+++ b/sound/soc/intel/catpt/dsp.c
@@ -344,53 +344,7 @@ static void catpt_dsp_set_regs_defaults(struct catpt_dev *cdev)
 	}
 }
 
-int lpt_dsp_power_down(struct catpt_dev *cdev)
-{
-	catpt_dsp_reset(cdev, true);
-
-	/* set 24Mhz clock for both SSPs */
-	catpt_updatel_shim(cdev, CS1, CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1),
-			   CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1));
-	catpt_dsp_select_lpclock(cdev, true, false);
-
-	/* DRAM power gating all */
-	catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask,
-			      cdev->spec->dram_mask);
-	catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask,
-			      cdev->spec->iram_mask);
-
-	catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D3hot);
-	/* give hw time to drop off */
-	udelay(50);
-
-	return 0;
-}
-
-int lpt_dsp_power_up(struct catpt_dev *cdev)
-{
-	/* SRAM power gating none */
-	catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask, 0);
-	catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask, 0);
-
-	catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D0);
-	/* give hw time to wake up */
-	udelay(100);
-
-	catpt_dsp_select_lpclock(cdev, false, false);
-	catpt_updatel_shim(cdev, CS1,
-			   CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1),
-			   CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1));
-	/* stagger DSP reset after clock selection */
-	udelay(50);
-
-	catpt_dsp_reset(cdev, false);
-	/* generate int deassert msg to fix inversed int logic */
-	catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCDB | CATPT_IMC_IPCCD, 0);
-
-	return 0;
-}
-
-int wpt_dsp_power_down(struct catpt_dev *cdev)
+int catpt_dsp_power_down(struct catpt_dev *cdev)
 {
 	u32 mask, val;
 
@@ -420,8 +374,8 @@ int wpt_dsp_power_down(struct catpt_dev *cdev)
 			      cdev->spec->dram_mask);
 	catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask,
 			      cdev->spec->iram_mask);
-	mask = WPT_VDRTCTL0_D3SRAMPGD | WPT_VDRTCTL0_D3PGD;
-	catpt_updatel_pci(cdev, VDRTCTL0, mask, WPT_VDRTCTL0_D3PGD);
+	mask = cdev->spec->d3srampgd_bit | cdev->spec->d3pgd_bit;
+	catpt_updatel_pci(cdev, VDRTCTL0, mask, cdev->spec->d3pgd_bit);
 
 	catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D3hot);
 	/* give hw time to drop off */
@@ -435,7 +389,7 @@ int wpt_dsp_power_down(struct catpt_dev *cdev)
 	return 0;
 }
 
-int wpt_dsp_power_up(struct catpt_dev *cdev)
+int catpt_dsp_power_up(struct catpt_dev *cdev)
 {
 	u32 mask, val;
 
@@ -450,7 +404,7 @@ int wpt_dsp_power_up(struct catpt_dev *cdev)
 	catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D0);
 
 	/* SRAM power gating none */
-	mask = WPT_VDRTCTL0_D3SRAMPGD | WPT_VDRTCTL0_D3PGD;
+	mask = cdev->spec->d3srampgd_bit | cdev->spec->d3pgd_bit;
 	catpt_updatel_pci(cdev, VDRTCTL0, mask, mask);
 	catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask, 0);
 	catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask, 0);
diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c
index 8a5f20abcadb..40c22e4bb263 100644
--- a/sound/soc/intel/catpt/loader.c
+++ b/sound/soc/intel/catpt/loader.c
@@ -304,7 +304,7 @@ static int catpt_load_block(struct catpt_dev *cdev,
 	default:
 		sram = &cdev->dram;
 		break;
-	};
+	}
 
 	dst_addr = sram->start + blk->ram_offset;
 	if (alloc) {
diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c
index 408e64e3b5fb..e5d54bb1c42a 100644
--- a/sound/soc/intel/catpt/pcm.c
+++ b/sound/soc/intel/catpt/pcm.c
@@ -92,7 +92,7 @@ catpt_get_stream_template(struct snd_pcm_substream *substream)
 		break;
 	default:
 		break;
-	};
+	}
 
 	return catpt_topology[type];
 }
@@ -324,6 +324,54 @@ static void catpt_dai_shutdown(struct snd_pcm_substream *substream,
 	snd_soc_dai_set_dma_data(dai, substream, NULL);
 }
 
+static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol);
+
+static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
+				     struct catpt_stream_runtime *stream)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
+	struct snd_soc_component *component = dai->component;
+	struct snd_kcontrol *pos, *kctl = NULL;
+	const char *name;
+	int ret;
+	u32 id = stream->info.stream_hw_id;
+
+	/* only selected streams have individual controls */
+	switch (id) {
+	case CATPT_PIN_ID_OFFLOAD1:
+		name = "Media0 Playback Volume";
+		break;
+	case CATPT_PIN_ID_OFFLOAD2:
+		name = "Media1 Playback Volume";
+		break;
+	case CATPT_PIN_ID_CAPTURE1:
+		name = "Mic Capture Volume";
+		break;
+	case CATPT_PIN_ID_REFERENCE:
+		name = "Loopback Mute";
+		break;
+	default:
+		return 0;
+	};
+
+	list_for_each_entry(pos, &component->card->snd_card->controls, list) {
+		if (pos->private_data == component &&
+		    !strncmp(name, pos->id.name, sizeof(pos->id.name))) {
+			kctl = pos;
+			break;
+		}
+	}
+	if (!kctl)
+		return -ENOENT;
+
+	if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK)
+		return catpt_set_dspvol(cdev, id, (long *)kctl->private_value);
+	ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)kctl->private_value);
+	if (ret)
+		return CATPT_IPC_ERROR(ret);
+	return 0;
+}
+
 static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
 			       struct snd_pcm_hw_params *params,
 			       struct snd_soc_dai *dai)
@@ -370,6 +418,10 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
 	if (ret)
 		return CATPT_IPC_ERROR(ret);
 
+	ret = catpt_dai_apply_usettings(dai, stream);
+	if (ret)
+		return ret;
+
 	stream->allocated = true;
 	return 0;
 }
@@ -391,54 +443,6 @@ static int catpt_dai_hw_free(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol);
-
-static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
-				     struct catpt_stream_runtime *stream)
-{
-	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
-	struct snd_soc_component *component = dai->component;
-	struct snd_kcontrol *pos, *kctl = NULL;
-	const char *name;
-	int ret;
-	u32 id = stream->info.stream_hw_id;
-
-	/* only selected streams have individual controls */
-	switch (id) {
-	case CATPT_PIN_ID_OFFLOAD1:
-		name = "Media0 Playback Volume";
-		break;
-	case CATPT_PIN_ID_OFFLOAD2:
-		name = "Media1 Playback Volume";
-		break;
-	case CATPT_PIN_ID_CAPTURE1:
-		name = "Mic Capture Volume";
-		break;
-	case CATPT_PIN_ID_REFERENCE:
-		name = "Loopback Mute";
-		break;
-	default:
-		return 0;
-	};
-
-	list_for_each_entry(pos, &component->card->snd_card->controls, list) {
-		if (pos->private_data == component &&
-		    !strncmp(name, pos->id.name, sizeof(pos->id.name))) {
-			kctl = pos;
-			break;
-		}
-	}
-	if (!kctl)
-		return -ENOENT;
-
-	if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK)
-		return catpt_set_dspvol(cdev, id, (long *)kctl->private_value);
-	ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)kctl->private_value);
-	if (ret)
-		return CATPT_IPC_ERROR(ret);
-	return 0;
-}
-
 static int catpt_dai_prepare(struct snd_pcm_substream *substream,
 			     struct snd_soc_dai *dai)
 {
@@ -458,10 +462,6 @@ static int catpt_dai_prepare(struct snd_pcm_substream *substream,
 	if (ret)
 		return CATPT_IPC_ERROR(ret);
 
-	ret = catpt_dai_apply_usettings(dai, stream);
-	if (ret)
-		return ret;
-
 	stream->prepared = true;
 	return 0;
 }
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index 64468fe9c513..12a205ccdeeb 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -8,7 +8,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m
 	soc-acpi-intel-cnl-match.o soc-acpi-intel-cfl-match.o \
 	soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \
 	soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \
-	soc-acpi-intel-jsl-match.o \
+	soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \
 	soc-acpi-intel-hda-match.o
 
 obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
new file mode 100644
index 000000000000..06b233d63b73
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * soc-apci-intel-adl-match.c - tables and support for ADL ACPI enumeration.
+ *
+ * Copyright (c) 2020, Intel Corporation.
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+
+static const struct snd_soc_acpi_endpoint single_endpoint = {
+	.num = 0,
+	.aggregated = 0,
+	.group_position = 0,
+	.group_id = 0,
+};
+
+static const struct snd_soc_acpi_adr_device rt711_0_adr[] = {
+	{
+		.adr = 0x000020025D071100,
+		.num_endpoints = 1,
+		.endpoints = &single_endpoint,
+		.name_prefix = "rt711"
+	}
+};
+
+static const struct snd_soc_acpi_link_adr adl_rvp[] = {
+	{
+		.mask = BIT(0),
+		.num_adr = ARRAY_SIZE(rt711_0_adr),
+		.adr_d = rt711_0_adr,
+	},
+	{}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
+	{},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines);
+
+/* this table is used when there is no I2S codec present */
+struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
+	{
+		.link_mask = 0x1, /* link0 required */
+		.links = adl_rvp,
+		.drv_name = "sof_sdw",
+		.sof_fw_filename = "sof-adl.ri",
+		.sof_tplg_filename = "sof-adl-rt711.tplg",
+	},
+	{},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_sdw_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
index 26dde88bb227..adddc91918df 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
@@ -14,6 +14,11 @@ static struct snd_soc_acpi_codecs rt1011_spk_codecs = {
 	.codecs = {"10EC1011"}
 };
 
+static struct snd_soc_acpi_codecs rt1015_spk_codecs = {
+	.num_codecs = 1,
+	.codecs = {"10EC1015"}
+};
+
 static struct snd_soc_acpi_codecs max98357a_spk_codecs = {
 	.num_codecs = 1,
 	.codecs = {"MX98357A"}
@@ -40,6 +45,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = {
 	},
 	{
 		.id = "10EC5682",
+		.drv_name = "cml_rt1015_rt5682",
+		.machine_quirk = snd_soc_acpi_codec_list,
+		.quirk_data = &rt1015_spk_codecs,
+		.sof_fw_filename = "sof-cml.ri",
+		.sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg",
+	},
+	{
+		.id = "10EC5682",
 		.drv_name = "sof_rt5682",
 		.machine_quirk = snd_soc_acpi_codec_list,
 		.quirk_data = &max98357a_spk_codecs,
diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
index 9f243e60b95c..98196e9fad62 100644
--- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
@@ -9,7 +9,7 @@
 #include <sound/soc-acpi.h>
 #include <sound/soc-acpi-intel-match.h>
 
-static struct snd_soc_acpi_codecs tgl_codecs = {
+static const struct snd_soc_acpi_codecs tgl_codecs = {
 	.num_codecs = 1,
 	.codecs = {"MX98357A"}
 };
@@ -305,11 +305,16 @@ static const struct snd_soc_acpi_link_adr tgl_3_in_1_sdca[] = {
 	{}
 };
 
-static struct snd_soc_acpi_codecs tgl_max98373_amp = {
+static const struct snd_soc_acpi_codecs tgl_max98373_amp = {
 	.num_codecs = 1,
 	.codecs = {"MX98373"}
 };
 
+static const struct snd_soc_acpi_codecs tgl_rt1011_amp = {
+	.num_codecs = 1,
+	.codecs = {"10EC1011"}
+};
+
 struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
 	{
 		.id = "10EC1308",
@@ -335,6 +340,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
 		.sof_fw_filename = "sof-tgl.ri",
 		.sof_tplg_filename = "sof-tgl-max98373-rt5682.tplg",
 	},
+	{
+		.id = "10EC5682",
+		.drv_name = "tgl_rt1011_rt5682",
+		.machine_quirk = snd_soc_acpi_codec_list,
+		.quirk_data = &tgl_rt1011_amp,
+		.sof_fw_filename = "sof-tgl.ri",
+		.sof_tplg_filename = "sof-tgl-rt1011-rt5682.tplg",
+	},
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines);
diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c
index 291a686568c2..1c3748f33136 100644
--- a/sound/soc/intel/keembay/kmb_platform.c
+++ b/sound/soc/intel/keembay/kmb_platform.c
@@ -358,7 +358,7 @@ static void kmb_i2s_start(struct kmb_i2s_info *kmb_i2s,
 
 	kmb_i2s_irq_trigger(kmb_i2s, substream->stream, config->chan_nr, true);
 
-	if (kmb_i2s->master)
+	if (kmb_i2s->clock_provider)
 		writel(1, kmb_i2s->i2s_base + CER);
 	else
 		writel(0, kmb_i2s->i2s_base + CER);
@@ -393,13 +393,13 @@ static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
 	int ret;
 
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBM_CFM:
-		kmb_i2s->master = false;
+	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+	case SND_SOC_DAIFMT_CBP_CFP:
+		kmb_i2s->clock_provider = false;
 		ret = 0;
 		break;
-	case SND_SOC_DAIFMT_CBS_CFS:
-		writel(MASTER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0);
+	case SND_SOC_DAIFMT_CBC_CFC:
+		writel(CLOCK_PROVIDER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0);
 
 		ret = clk_prepare_enable(kmb_i2s->clk_i2s);
 		if (ret < 0)
@@ -410,7 +410,7 @@ static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		if (ret)
 			return ret;
 
-		kmb_i2s->master = true;
+		kmb_i2s->clock_provider = true;
 		break;
 	default:
 		return -EINVAL;
@@ -510,7 +510,7 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream,
 		 * Platform is not capable of providing clocks for
 		 * multi channel audio
 		 */
-		if (kmb_i2s->master)
+		if (kmb_i2s->clock_provider)
 			return -EINVAL;
 
 		write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) |
@@ -524,12 +524,12 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream,
 		 * Platform is only capable of providing clocks need for
 		 * 2 channel master mode
 		 */
-		if (!(kmb_i2s->master))
+		if (!(kmb_i2s->clock_provider))
 			return -EINVAL;
 
 		write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) |
 				(config->data_width << DATA_WIDTH_CONFIG_BIT) |
-				MASTER_MODE | I2S_OPERATION;
+				CLOCK_PROVIDER_MODE | I2S_OPERATION;
 
 		writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0);
 		break;
@@ -544,7 +544,7 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream,
 
 	config->sample_rate = params_rate(hw_params);
 
-	if (kmb_i2s->master) {
+	if (kmb_i2s->clock_provider) {
 		/* Only 2 ch supported in Master mode */
 		u32 bitclk = config->sample_rate * config->data_width * 2;
 
diff --git a/sound/soc/intel/keembay/kmb_platform.h b/sound/soc/intel/keembay/kmb_platform.h
index 9756b132c12f..0c393e5916b6 100644
--- a/sound/soc/intel/keembay/kmb_platform.h
+++ b/sound/soc/intel/keembay/kmb_platform.h
@@ -58,7 +58,7 @@
 #define PSS_CPR_CLK_CLR		0x000
 #define PSS_CPR_AUX_RST_EN	0x070
 
-#define MASTER_MODE		BIT(13)
+#define CLOCK_PROVIDER_MODE	BIT(13)
 
 /* Interrupt Flag */
 #define TX_INT_FLAG		GENMASK(5, 4)
@@ -99,8 +99,8 @@
 
 #define DWC_I2S_PLAY	BIT(0)
 #define DWC_I2S_RECORD	BIT(1)
-#define DW_I2S_SLAVE	BIT(2)
-#define DW_I2S_MASTER	BIT(3)
+#define DW_I2S_CONSUMER	BIT(2)
+#define DW_I2S_PROVIDER	BIT(3)
 
 #define I2S_RXDMA	0x01C0
 #define I2S_TXDMA	0x01C8
@@ -130,7 +130,7 @@ struct kmb_i2s_info {
 	u32 ccr;
 	u32 xfer_resolution;
 	u32 fifo_th;
-	bool master;
+	bool clock_provider;
 
 	struct i2s_clk_config_data config;
 	int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index bbe8d782e0af..b1ca64d2f7ea 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -502,7 +502,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
 		if (ret < 0)
 			return ret;
 		return skl_run_pipe(skl, mconfig->pipe);
-		break;
 
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 40bee10b0c65..ae466cd59292 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -3742,12 +3742,7 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
 	}
 
 component_load:
-
-	/*
-	 * The complete tplg for SKL is loaded as index 0, we don't use
-	 * any other index
-	 */
-	ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw, 0);
+	ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw);
 	if (ret < 0) {
 		dev_err(bus->dev, "tplg component load failed%d\n", ret);
 		goto err;
@@ -3777,5 +3772,5 @@ void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus)
 		list_del(&ppl->node);
 
 	/* clean up topology */
-	snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
+	snd_soc_tplg_component_remove(component);
 }
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index c7bd20104b20..0a68f4c3d15a 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -26,9 +26,6 @@
 
 #include "jz4740-i2s.h"
 
-#define JZ4740_DMA_TYPE_AIC_TRANSMIT 24
-#define JZ4740_DMA_TYPE_AIC_RECEIVE 25
-
 #define JZ_REG_AIC_CONF		0x00
 #define JZ_REG_AIC_CTRL		0x04
 #define JZ_REG_AIC_I2S_FMT	0x10
@@ -312,10 +309,14 @@ static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	switch (clk_id) {
 	case JZ4740_I2S_CLKSRC_EXT:
 		parent = clk_get(NULL, "ext");
+		if (IS_ERR(parent))
+			return PTR_ERR(parent);
 		clk_set_parent(i2s->clk_i2s, parent);
 		break;
 	case JZ4740_I2S_CLKSRC_PLL:
 		parent = clk_get(NULL, "pll half");
+		if (IS_ERR(parent))
+			return PTR_ERR(parent);
 		clk_set_parent(i2s->clk_i2s, parent);
 		ret = clk_set_rate(i2s->clk_i2s, freq);
 		break;
@@ -377,13 +378,11 @@ static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
 	/* Playback */
 	dma_data = &i2s->playback_dma_data;
 	dma_data->maxburst = 16;
-	dma_data->slave_id = JZ4740_DMA_TYPE_AIC_TRANSMIT;
 	dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
 
 	/* Capture */
 	dma_data = &i2s->capture_dma_data;
 	dma_data->maxburst = 16;
-	dma_data->slave_id = JZ4740_DMA_TYPE_AIC_RECEIVE;
 	dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
 }
 
diff --git a/sound/soc/kirkwood/armada-370-db.c b/sound/soc/kirkwood/armada-370-db.c
index 8e44ae37ad1e..81326426da33 100644
--- a/sound/soc/kirkwood/armada-370-db.c
+++ b/sound/soc/kirkwood/armada-370-db.c
@@ -134,7 +134,7 @@ static int a370db_probe(struct platform_device *pdev)
 	return devm_snd_soc_register_card(card->dev, card);
 }
 
-static const struct of_device_id a370db_dt_ids[] = {
+static const struct of_device_id a370db_dt_ids[] __maybe_unused = {
 	{ .compatible = "marvell,a370db-audio" },
 	{ },
 };
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 76e055d1dfb2..8d3dcfb6a580 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -158,3 +158,28 @@ config SND_SOC_MTK_BTCVSD
 	  BT encoded data to/from BT firmware.
 	  Select Y if you have such device.
 	  If unsure select "N".
+
+config SND_SOC_MT8192
+	tristate "ASoC support for Mediatek MT8192 chip"
+	depends on ARCH_MEDIATEK
+	select SND_SOC_MEDIATEK
+	help
+	  This adds ASoC platform driver support for Mediatek MT8192 chip
+	  that can be used with other codecs.
+	  Select Y if you have such device.
+	  If unsure select "N".
+
+config SND_SOC_MT8192_MT6359_RT1015_RT5682
+	tristate "ASoC Audio driver for MT8192 with MT6359 RT1015 RT5682 codec"
+	depends on I2C
+	depends on SND_SOC_MT8192
+	select SND_SOC_MT6359
+	select SND_SOC_RT1015
+	select SND_SOC_RT1015P
+	select SND_SOC_RT5682_I2C
+	select SND_SOC_DMIC
+	help
+	  This adds ASoC driver for Mediatek MT8192 boards
+	  with the MT6359 RT1015 RT5682 audio codec.
+	  Select Y if you have such device.
+	  If unsure select "N".
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
index 76032cae6d51..f6cb6b8508e3 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
 obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
 obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
 obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
+obj-$(CONFIG_SND_SOC_MT8192) += mt8192/
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
index 882cdf86c8bf..3cb2adf420bb 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
@@ -542,8 +542,13 @@ int mtk_memif_set_format(struct mtk_base_afe *afe,
 		break;
 	case SNDRV_PCM_FORMAT_S32_LE:
 	case SNDRV_PCM_FORMAT_U32_LE:
-		hd_audio = 1;
-		hd_align = 1;
+		if (afe->memif_32bit_supported) {
+			hd_audio = 2;
+			hd_align = 0;
+		} else {
+			hd_audio = 1;
+			hd_align = 1;
+		}
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
 	case SNDRV_PCM_FORMAT_U24_LE:
@@ -556,10 +561,10 @@ int mtk_memif_set_format(struct mtk_base_afe *afe,
 	}
 
 	mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
-			       1, hd_audio, memif->data->hd_shift);
+			       0x3, 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);
+			       0x1, hd_align, memif->data->hd_align_mshift);
 
 	return 0;
 }
diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h
index a8cf44d98244..a6f68c68581c 100644
--- a/sound/soc/mediatek/common/mtk-base-afe.h
+++ b/sound/soc/mediatek/common/mtk-base-afe.h
@@ -91,6 +91,7 @@ struct mtk_base_afe {
 	int memif_size;
 	struct mtk_base_afe_irq *irqs;
 	int irqs_size;
+	int memif_32bit_supported;
 
 	struct list_head sub_dais;
 	struct snd_soc_dai_driver *dai_drivers;
diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c
index 668fef3e319a..a554c57b6460 100644
--- a/sound/soc/mediatek/common/mtk-btcvsd.c
+++ b/sound/soc/mediatek/common/mtk-btcvsd.c
@@ -808,7 +808,7 @@ static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt,
 		spin_unlock_irqrestore(&bt->tx_lock, flags);
 
 		if (!avail) {
-			int ret = wait_for_bt_irq(bt, bt->rx);
+			int ret = wait_for_bt_irq(bt, bt->tx);
 
 			if (ret)
 				return written_size;
diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-clk.c b/sound/soc/mediatek/mt8183/mt8183-afe-clk.c
index 48e81c5d52fc..cc4f8f4d3dab 100644
--- a/sound/soc/mediatek/mt8183/mt8183-afe-clk.c
+++ b/sound/soc/mediatek/mt8183/mt8183-afe-clk.c
@@ -584,7 +584,6 @@ int mt8183_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
 			__func__, aud_clks[div_clk_id],
 			rate, ret);
 		goto ERR_SET_MCLK_RATE;
-		return ret;
 	}
 
 	return 0;
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
index 26e7d9a7198f..078e58f1ad0b 100644
--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -811,6 +811,7 @@ static struct platform_driver mt8183_da7219_max98357_driver = {
 #ifdef CONFIG_OF
 		.of_match_table = mt8183_da7219_max98357_dt_match,
 #endif
+		.pm = &snd_soc_pm_ops,
 	},
 	.probe = mt8183_da7219_max98357_dev_probe,
 };
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
index 327dfad41e31..8c8340854859 100644
--- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
@@ -744,6 +744,7 @@ static struct platform_driver mt8183_mt6358_ts3a227_max98357_driver = {
 #ifdef CONFIG_OF
 		.of_match_table = mt8183_mt6358_ts3a227_max98357_dt_match,
 #endif
+		.pm = &snd_soc_pm_ops,
 	},
 	.probe = mt8183_mt6358_ts3a227_max98357_dev_probe,
 };
diff --git a/sound/soc/mediatek/mt8192/Makefile b/sound/soc/mediatek/mt8192/Makefile
new file mode 100644
index 000000000000..8b27d82626ea
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/Makefile
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# platform driver
+snd-soc-mt8192-afe-objs := \
+	mt8192-afe-pcm.o \
+	mt8192-afe-clk.o \
+	mt8192-afe-gpio.o \
+	mt8192-dai-adda.o \
+	mt8192-afe-control.o \
+	mt8192-dai-i2s.o \
+	mt8192-dai-pcm.o \
+	mt8192-dai-tdm.o
+
+obj-$(CONFIG_SND_SOC_MT8192) += snd-soc-mt8192-afe.o
+obj-$(CONFIG_SND_SOC_MT8192_MT6359_RT1015_RT5682) += \
+	mt8192-mt6359-rt1015-rt5682.o
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-clk.c b/sound/soc/mediatek/mt8192/mt8192-afe-clk.c
new file mode 100644
index 000000000000..bba5f3056e8f
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-clk.c
@@ -0,0 +1,669 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8192-afe-clk.c  --  Mediatek 8192 afe clock ctrl
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/arm-smccc.h>
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include "mt8192-afe-clk.h"
+#include "mt8192-afe-common.h"
+
+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_NLE] = "aud_nle",
+	[CLK_INFRA_SYS_AUDIO] = "aud_infra_clk",
+	[CLK_INFRA_AUDIO_26M] = "aud_infra_26m_clk",
+	[CLK_MUX_AUDIO] = "top_mux_audio",
+	[CLK_MUX_AUDIOINTBUS] = "top_mux_audio_int",
+	[CLK_TOP_MAINPLL_D4_D4] = "top_mainpll_d4_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_D4] = "top_apll1_d4",
+	[CLK_TOP_MUX_AUD_ENG2] = "top_mux_aud_eng2",
+	[CLK_TOP_APLL2_D4] = "top_apll2_d4",
+	[CLK_TOP_MUX_AUDIO_H] = "top_mux_audio_h",
+	[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_I2S6_M_SEL] = "top_i2s6_m_sel",
+	[CLK_TOP_I2S7_M_SEL] = "top_i2s7_m_sel",
+	[CLK_TOP_I2S8_M_SEL] = "top_i2s8_m_sel",
+	[CLK_TOP_I2S9_M_SEL] = "top_i2s9_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_TOP_APLL12_DIV5] = "top_apll12_div5",
+	[CLK_TOP_APLL12_DIV6] = "top_apll12_div6",
+	[CLK_TOP_APLL12_DIV7] = "top_apll12_div7",
+	[CLK_TOP_APLL12_DIV8] = "top_apll12_div8",
+	[CLK_TOP_APLL12_DIV9] = "top_apll12_div9",
+	[CLK_CLK26M] = "top_clk26m_clk",
+};
+
+int mt8192_set_audio_int_bus_parent(struct mtk_base_afe *afe,
+				    int clk_id)
+{
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIOINTBUS],
+			     afe_priv->clk[clk_id]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+			__func__, aud_clks[CLK_MUX_AUDIOINTBUS],
+			aud_clks[clk_id], ret);
+	}
+
+	return ret;
+}
+
+static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+	struct mt8192_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 EXIT;
+		}
+		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 EXIT;
+		}
+
+		/* 180.6336 / 4 = 45.1584MHz */
+		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 EXIT;
+		}
+		ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
+				     afe_priv->clk[CLK_TOP_APLL1_D4]);
+		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_D4], ret);
+			goto EXIT;
+		}
+	} 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]);
+	}
+
+EXIT:
+	return ret;
+}
+
+static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+	struct mt8192_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 EXIT;
+		}
+		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 EXIT;
+		}
+
+		/* 196.608 / 4 = 49.152MHz */
+		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 EXIT;
+		}
+		ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
+				     afe_priv->clk[CLK_TOP_APLL2_D4]);
+		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_D4], ret);
+			goto EXIT;
+		}
+	} 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]);
+	}
+
+EXIT:
+	return ret;
+}
+
+int mt8192_afe_enable_clock(struct mtk_base_afe *afe)
+{
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	dev_info(afe->dev, "%s()\n", __func__);
+
+	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 EXIT;
+	}
+
+	ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[CLK_INFRA_AUDIO_26M], ret);
+		goto EXIT;
+	}
+
+	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 EXIT;
+	}
+	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 EXIT;
+	}
+
+	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 EXIT;
+	}
+
+	ret = mt8192_set_audio_int_bus_parent(afe, CLK_CLK26M);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+			__func__, aud_clks[CLK_MUX_AUDIOINTBUS],
+			aud_clks[CLK_CLK26M], ret);
+		goto EXIT;
+	}
+
+	ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUDIO_H],
+			     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_AUDIO_H],
+			aud_clks[CLK_TOP_APLL2_CK], ret);
+		goto EXIT;
+	}
+
+	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 EXIT;
+	}
+
+EXIT:
+	return ret;
+}
+
+void mt8192_afe_disable_clock(struct mtk_base_afe *afe)
+{
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+	dev_info(afe->dev, "%s()\n", __func__);
+
+	clk_disable_unprepare(afe_priv->clk[CLK_AFE]);
+	mt8192_set_audio_int_bus_parent(afe, CLK_CLK26M);
+	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_AUDIO_26M]);
+	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+}
+
+int mt8192_apll1_enable(struct mtk_base_afe *afe)
+{
+	struct mt8192_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 EXIT;
+	}
+
+	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 EXIT;
+	}
+
+	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);
+
+EXIT:
+	return ret;
+}
+
+void mt8192_apll1_disable(struct mtk_base_afe *afe)
+{
+	struct mt8192_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 mt8192_apll2_enable(struct mtk_base_afe *afe)
+{
+	struct mt8192_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 EXIT;
+	}
+
+	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 EXIT;
+	}
+
+	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);
+
+EXIT:
+	return ret;
+}
+
+void mt8192_apll2_disable(struct mtk_base_afe *afe)
+{
+	struct mt8192_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 mt8192_get_apll_rate(struct mtk_base_afe *afe, int apll)
+{
+	return (apll == MT8192_APLL1) ? 180633600 : 196608000;
+}
+
+int mt8192_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
+{
+	return ((rate % 8000) == 0) ? MT8192_APLL2 : MT8192_APLL1;
+}
+
+int mt8192_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
+{
+	if (strcmp(name, APLL1_W_NAME) == 0)
+		return MT8192_APLL1;
+	else
+		return MT8192_APLL2;
+}
+
+/* mck */
+struct mt8192_mck_div {
+	int m_sel_id;
+	int div_clk_id;
+	/* below will be deprecated */
+	int div_pdn_reg;
+	int div_pdn_mask_sft;
+	int div_reg;
+	int div_mask_sft;
+	int div_mask;
+	int div_sft;
+	int div_apll_sel_reg;
+	int div_apll_sel_mask_sft;
+	int div_apll_sel_sft;
+};
+
+static const struct mt8192_mck_div mck_div[MT8192_MCK_NUM] = {
+	[MT8192_I2S0_MCK] = {
+		.m_sel_id = CLK_TOP_I2S0_M_SEL,
+		.div_clk_id = CLK_TOP_APLL12_DIV0,
+		.div_pdn_reg = CLK_AUDDIV_0,
+		.div_pdn_mask_sft = APLL12_DIV0_PDN_MASK_SFT,
+		.div_reg = CLK_AUDDIV_2,
+		.div_mask_sft = APLL12_CK_DIV0_MASK_SFT,
+		.div_mask = APLL12_CK_DIV0_MASK,
+		.div_sft = APLL12_CK_DIV0_SFT,
+		.div_apll_sel_reg = CLK_AUDDIV_0,
+		.div_apll_sel_mask_sft = APLL_I2S0_MCK_SEL_MASK_SFT,
+		.div_apll_sel_sft = APLL_I2S0_MCK_SEL_SFT,
+	},
+	[MT8192_I2S1_MCK] = {
+		.m_sel_id = CLK_TOP_I2S1_M_SEL,
+		.div_clk_id = CLK_TOP_APLL12_DIV1,
+		.div_pdn_reg = CLK_AUDDIV_0,
+		.div_pdn_mask_sft = APLL12_DIV1_PDN_MASK_SFT,
+		.div_reg = CLK_AUDDIV_2,
+		.div_mask_sft = APLL12_CK_DIV1_MASK_SFT,
+		.div_mask = APLL12_CK_DIV1_MASK,
+		.div_sft = APLL12_CK_DIV1_SFT,
+		.div_apll_sel_reg = CLK_AUDDIV_0,
+		.div_apll_sel_mask_sft = APLL_I2S1_MCK_SEL_MASK_SFT,
+		.div_apll_sel_sft = APLL_I2S1_MCK_SEL_SFT,
+	},
+	[MT8192_I2S2_MCK] = {
+		.m_sel_id = CLK_TOP_I2S2_M_SEL,
+		.div_clk_id = CLK_TOP_APLL12_DIV2,
+		.div_pdn_reg = CLK_AUDDIV_0,
+		.div_pdn_mask_sft = APLL12_DIV2_PDN_MASK_SFT,
+		.div_reg = CLK_AUDDIV_2,
+		.div_mask_sft = APLL12_CK_DIV2_MASK_SFT,
+		.div_mask = APLL12_CK_DIV2_MASK,
+		.div_sft = APLL12_CK_DIV2_SFT,
+		.div_apll_sel_reg = CLK_AUDDIV_0,
+		.div_apll_sel_mask_sft = APLL_I2S2_MCK_SEL_MASK_SFT,
+		.div_apll_sel_sft = APLL_I2S2_MCK_SEL_SFT,
+	},
+	[MT8192_I2S3_MCK] = {
+		.m_sel_id = CLK_TOP_I2S3_M_SEL,
+		.div_clk_id = CLK_TOP_APLL12_DIV3,
+		.div_pdn_reg = CLK_AUDDIV_0,
+		.div_pdn_mask_sft = APLL12_DIV3_PDN_MASK_SFT,
+		.div_reg = CLK_AUDDIV_2,
+		.div_mask_sft = APLL12_CK_DIV3_MASK_SFT,
+		.div_mask = APLL12_CK_DIV3_MASK,
+		.div_sft = APLL12_CK_DIV3_SFT,
+		.div_apll_sel_reg = CLK_AUDDIV_0,
+		.div_apll_sel_mask_sft = APLL_I2S3_MCK_SEL_MASK_SFT,
+		.div_apll_sel_sft = APLL_I2S3_MCK_SEL_SFT,
+	},
+	[MT8192_I2S4_MCK] = {
+		.m_sel_id = CLK_TOP_I2S4_M_SEL,
+		.div_clk_id = CLK_TOP_APLL12_DIV4,
+		.div_pdn_reg = CLK_AUDDIV_0,
+		.div_pdn_mask_sft = APLL12_DIV4_PDN_MASK_SFT,
+		.div_reg = CLK_AUDDIV_3,
+		.div_mask_sft = APLL12_CK_DIV4_MASK_SFT,
+		.div_mask = APLL12_CK_DIV4_MASK,
+		.div_sft = APLL12_CK_DIV4_SFT,
+		.div_apll_sel_reg = CLK_AUDDIV_0,
+		.div_apll_sel_mask_sft = APLL_I2S4_MCK_SEL_MASK_SFT,
+		.div_apll_sel_sft = APLL_I2S4_MCK_SEL_SFT,
+	},
+	[MT8192_I2S4_BCK] = {
+		.m_sel_id = -1,
+		.div_clk_id = CLK_TOP_APLL12_DIVB,
+		.div_pdn_reg = CLK_AUDDIV_0,
+		.div_pdn_mask_sft = APLL12_DIVB_PDN_MASK_SFT,
+		.div_reg = CLK_AUDDIV_2,
+		.div_mask_sft = APLL12_CK_DIVB_MASK_SFT,
+		.div_mask = APLL12_CK_DIVB_MASK,
+		.div_sft = APLL12_CK_DIVB_SFT,
+	},
+	[MT8192_I2S5_MCK] = {
+		.m_sel_id = CLK_TOP_I2S5_M_SEL,
+		.div_clk_id = CLK_TOP_APLL12_DIV5,
+		.div_pdn_reg = CLK_AUDDIV_0,
+		.div_pdn_mask_sft = APLL12_DIV5_PDN_MASK_SFT,
+		.div_reg = CLK_AUDDIV_3,
+		.div_mask_sft = APLL12_CK_DIV5_MASK_SFT,
+		.div_mask = APLL12_CK_DIV5_MASK,
+		.div_sft = APLL12_CK_DIV5_SFT,
+		.div_apll_sel_reg = CLK_AUDDIV_0,
+		.div_apll_sel_mask_sft = APLL_I2S5_MCK_SEL_MASK_SFT,
+		.div_apll_sel_sft = APLL_I2S5_MCK_SEL_SFT,
+	},
+	[MT8192_I2S6_MCK] = {
+		.m_sel_id = CLK_TOP_I2S6_M_SEL,
+		.div_clk_id = CLK_TOP_APLL12_DIV6,
+		.div_pdn_reg = CLK_AUDDIV_0,
+		.div_pdn_mask_sft = APLL12_DIV6_PDN_MASK_SFT,
+		.div_reg = CLK_AUDDIV_3,
+		.div_mask_sft = APLL12_CK_DIV6_MASK_SFT,
+		.div_mask = APLL12_CK_DIV6_MASK,
+		.div_sft = APLL12_CK_DIV6_SFT,
+		.div_apll_sel_reg = CLK_AUDDIV_0,
+		.div_apll_sel_mask_sft = APLL_I2S6_MCK_SEL_MASK_SFT,
+		.div_apll_sel_sft = APLL_I2S6_MCK_SEL_SFT,
+	},
+	[MT8192_I2S7_MCK] = {
+		.m_sel_id = CLK_TOP_I2S7_M_SEL,
+		.div_clk_id = CLK_TOP_APLL12_DIV7,
+		.div_pdn_reg = CLK_AUDDIV_0,
+		.div_pdn_mask_sft = APLL12_DIV7_PDN_MASK_SFT,
+		.div_reg = CLK_AUDDIV_4,
+		.div_mask_sft = APLL12_CK_DIV7_MASK_SFT,
+		.div_mask = APLL12_CK_DIV7_MASK,
+		.div_sft = APLL12_CK_DIV7_SFT,
+		.div_apll_sel_reg = CLK_AUDDIV_0,
+		.div_apll_sel_mask_sft = APLL_I2S7_MCK_SEL_MASK_SFT,
+		.div_apll_sel_sft = APLL_I2S7_MCK_SEL_SFT,
+	},
+	[MT8192_I2S8_MCK] = {
+		.m_sel_id = CLK_TOP_I2S8_M_SEL,
+		.div_clk_id = CLK_TOP_APLL12_DIV8,
+		.div_pdn_reg = CLK_AUDDIV_0,
+		.div_pdn_mask_sft = APLL12_DIV8_PDN_MASK_SFT,
+		.div_reg = CLK_AUDDIV_4,
+		.div_mask_sft = APLL12_CK_DIV8_MASK_SFT,
+		.div_mask = APLL12_CK_DIV8_MASK,
+		.div_sft = APLL12_CK_DIV8_SFT,
+		.div_apll_sel_reg = CLK_AUDDIV_0,
+		.div_apll_sel_mask_sft = APLL_I2S8_MCK_SEL_MASK_SFT,
+		.div_apll_sel_sft = APLL_I2S8_MCK_SEL_SFT,
+	},
+	[MT8192_I2S9_MCK] = {
+		.m_sel_id = CLK_TOP_I2S9_M_SEL,
+		.div_clk_id = CLK_TOP_APLL12_DIV9,
+		.div_pdn_reg = CLK_AUDDIV_0,
+		.div_pdn_mask_sft = APLL12_DIV9_PDN_MASK_SFT,
+		.div_reg = CLK_AUDDIV_4,
+		.div_mask_sft = APLL12_CK_DIV9_MASK_SFT,
+		.div_mask = APLL12_CK_DIV9_MASK,
+		.div_sft = APLL12_CK_DIV9_SFT,
+		.div_apll_sel_reg = CLK_AUDDIV_0,
+		.div_apll_sel_mask_sft = APLL_I2S9_MCK_SEL_MASK_SFT,
+		.div_apll_sel_sft = APLL_I2S9_MCK_SEL_SFT,
+	},
+};
+
+int mt8192_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
+{
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	int apll = mt8192_get_apll_by_rate(afe, rate);
+	int apll_clk_id = apll == MT8192_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;
+
+	/* select apll */
+	if (m_sel_id >= 0) {
+		ret = clk_prepare_enable(afe_priv->clk[m_sel_id]);
+		if (ret) {
+			dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+				__func__, aud_clks[m_sel_id], ret);
+			return ret;
+		}
+		ret = clk_set_parent(afe_priv->clk[m_sel_id],
+				     afe_priv->clk[apll_clk_id]);
+		if (ret) {
+			dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n",
+				__func__, aud_clks[m_sel_id],
+				aud_clks[apll_clk_id], ret);
+			return ret;
+		}
+	}
+
+	/* enable div, set rate */
+	ret = clk_prepare_enable(afe_priv->clk[div_clk_id]);
+	if (ret) {
+		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[div_clk_id], ret);
+		return ret;
+	}
+	ret = clk_set_rate(afe_priv->clk[div_clk_id], rate);
+	if (ret) {
+		dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n",
+			__func__, aud_clks[div_clk_id],
+			rate, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+void mt8192_mck_disable(struct mtk_base_afe *afe, int mck_id)
+{
+	struct mt8192_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;
+
+	clk_disable_unprepare(afe_priv->clk[div_clk_id]);
+	if (m_sel_id >= 0)
+		clk_disable_unprepare(afe_priv->clk[m_sel_id]);
+}
+
+int mt8192_init_clock(struct mtk_base_afe *afe)
+{
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	struct device_node *of_node = afe->dev->of_node;
+	int i = 0;
+
+	afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk),
+				     GFP_KERNEL);
+	if (!afe_priv->clk)
+		return -ENOMEM;
+
+	for (i = 0; i < CLK_NUM; i++) {
+		afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
+		if (IS_ERR(afe_priv->clk[i])) {
+			dev_warn(afe->dev, "%s devm_clk_get %s fail, ret %ld\n",
+				 __func__,
+				 aud_clks[i], PTR_ERR(afe_priv->clk[i]));
+			afe_priv->clk[i] = NULL;
+		}
+	}
+
+	afe_priv->apmixedsys = syscon_regmap_lookup_by_phandle(of_node,
+							       "mediatek,apmixedsys");
+	if (IS_ERR(afe_priv->apmixedsys)) {
+		dev_err(afe->dev, "%s() Cannot find apmixedsys controller: %ld\n",
+			__func__, PTR_ERR(afe_priv->apmixedsys));
+		return PTR_ERR(afe_priv->apmixedsys);
+	}
+
+	afe_priv->topckgen = syscon_regmap_lookup_by_phandle(of_node,
+							     "mediatek,topckgen");
+	if (IS_ERR(afe_priv->topckgen)) {
+		dev_err(afe->dev, "%s() Cannot find topckgen controller: %ld\n",
+			__func__, PTR_ERR(afe_priv->topckgen));
+		return PTR_ERR(afe_priv->topckgen);
+	}
+
+	afe_priv->infracfg = syscon_regmap_lookup_by_phandle(of_node,
+							     "mediatek,infracfg");
+	if (IS_ERR(afe_priv->infracfg)) {
+		dev_err(afe->dev, "%s() Cannot find infracfg: %ld\n",
+			__func__, PTR_ERR(afe_priv->infracfg));
+		return PTR_ERR(afe_priv->infracfg);
+	}
+
+	return 0;
+}
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-clk.h b/sound/soc/mediatek/mt8192/mt8192-afe-clk.h
new file mode 100644
index 000000000000..3adaf027af83
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-clk.h
@@ -0,0 +1,244 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8192-afe-clk.h  --  Mediatek 8192 afe clock ctrl definition
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Shane Chien <shane.chien@mediatek.com>
+ */
+
+#ifndef _MT8192_AFE_CLOCK_CTRL_H_
+#define _MT8192_AFE_CLOCK_CTRL_H_
+
+#define AP_PLL_CON3 0x0014
+#define APLL1_CON0 0x0318
+#define APLL1_CON1 0x031c
+#define APLL1_CON2 0x0320
+#define APLL1_CON4 0x0328
+#define APLL1_TUNER_CON0 0x0040
+
+#define APLL2_CON0 0x032c
+#define APLL2_CON1 0x0330
+#define APLL2_CON2 0x0334
+#define APLL2_CON4 0x033c
+#define APLL2_TUNER_CON0 0x0044
+
+#define CLK_CFG_7 0x0080
+#define CLK_CFG_8 0x0090
+#define CLK_CFG_11 0x00c0
+#define CLK_CFG_12 0x00d0
+#define CLK_CFG_13 0x00e0
+#define CLK_CFG_15 0x0100
+
+#define CLK_AUDDIV_0 0x0320
+#define CLK_AUDDIV_2 0x0328
+#define CLK_AUDDIV_3 0x0334
+#define CLK_AUDDIV_4 0x0338
+#define CKSYS_AUD_TOP_CFG 0x032c
+#define CKSYS_AUD_TOP_MON 0x0330
+
+#define PERI_BUS_DCM_CTRL 0x0074
+#define MODULE_SW_CG_1_STA 0x0094
+#define MODULE_SW_CG_2_STA 0x00ac
+
+/* CLK_AUDDIV_0 */
+#define APLL12_DIV0_PDN_SFT                0
+#define APLL12_DIV0_PDN_MASK               0x1
+#define APLL12_DIV0_PDN_MASK_SFT           (0x1 << 0)
+#define APLL12_DIV1_PDN_SFT                1
+#define APLL12_DIV1_PDN_MASK               0x1
+#define APLL12_DIV1_PDN_MASK_SFT           (0x1 << 1)
+#define APLL12_DIV2_PDN_SFT                2
+#define APLL12_DIV2_PDN_MASK               0x1
+#define APLL12_DIV2_PDN_MASK_SFT           (0x1 << 2)
+#define APLL12_DIV3_PDN_SFT                3
+#define APLL12_DIV3_PDN_MASK               0x1
+#define APLL12_DIV3_PDN_MASK_SFT           (0x1 << 3)
+#define APLL12_DIV4_PDN_SFT                4
+#define APLL12_DIV4_PDN_MASK               0x1
+#define APLL12_DIV4_PDN_MASK_SFT           (0x1 << 4)
+#define APLL12_DIVB_PDN_SFT                5
+#define APLL12_DIVB_PDN_MASK               0x1
+#define APLL12_DIVB_PDN_MASK_SFT           (0x1 << 5)
+#define APLL12_DIV5_PDN_SFT                6
+#define APLL12_DIV5_PDN_MASK               0x1
+#define APLL12_DIV5_PDN_MASK_SFT           (0x1 << 6)
+#define APLL12_DIV6_PDN_SFT                7
+#define APLL12_DIV6_PDN_MASK               0x1
+#define APLL12_DIV6_PDN_MASK_SFT           (0x1 << 7)
+#define APLL12_DIV7_PDN_SFT                8
+#define APLL12_DIV7_PDN_MASK               0x1
+#define APLL12_DIV7_PDN_MASK_SFT           (0x1 << 8)
+#define APLL12_DIV8_PDN_SFT                9
+#define APLL12_DIV8_PDN_MASK               0x1
+#define APLL12_DIV8_PDN_MASK_SFT           (0x1 << 9)
+#define APLL12_DIV9_PDN_SFT                10
+#define APLL12_DIV9_PDN_MASK               0x1
+#define APLL12_DIV9_PDN_MASK_SFT           (0x1 << 10)
+#define APLL_I2S0_MCK_SEL_SFT              16
+#define APLL_I2S0_MCK_SEL_MASK             0x1
+#define APLL_I2S0_MCK_SEL_MASK_SFT         (0x1 << 16)
+#define APLL_I2S1_MCK_SEL_SFT              17
+#define APLL_I2S1_MCK_SEL_MASK             0x1
+#define APLL_I2S1_MCK_SEL_MASK_SFT         (0x1 << 17)
+#define APLL_I2S2_MCK_SEL_SFT              18
+#define APLL_I2S2_MCK_SEL_MASK             0x1
+#define APLL_I2S2_MCK_SEL_MASK_SFT         (0x1 << 18)
+#define APLL_I2S3_MCK_SEL_SFT              19
+#define APLL_I2S3_MCK_SEL_MASK             0x1
+#define APLL_I2S3_MCK_SEL_MASK_SFT         (0x1 << 19)
+#define APLL_I2S4_MCK_SEL_SFT              20
+#define APLL_I2S4_MCK_SEL_MASK             0x1
+#define APLL_I2S4_MCK_SEL_MASK_SFT         (0x1 << 20)
+#define APLL_I2S5_MCK_SEL_SFT              21
+#define APLL_I2S5_MCK_SEL_MASK             0x1
+#define APLL_I2S5_MCK_SEL_MASK_SFT         (0x1 << 21)
+#define APLL_I2S6_MCK_SEL_SFT              22
+#define APLL_I2S6_MCK_SEL_MASK             0x1
+#define APLL_I2S6_MCK_SEL_MASK_SFT         (0x1 << 22)
+#define APLL_I2S7_MCK_SEL_SFT              23
+#define APLL_I2S7_MCK_SEL_MASK             0x1
+#define APLL_I2S7_MCK_SEL_MASK_SFT         (0x1 << 23)
+#define APLL_I2S8_MCK_SEL_SFT              24
+#define APLL_I2S8_MCK_SEL_MASK             0x1
+#define APLL_I2S8_MCK_SEL_MASK_SFT         (0x1 << 24)
+#define APLL_I2S9_MCK_SEL_SFT              25
+#define APLL_I2S9_MCK_SEL_MASK             0x1
+#define APLL_I2S9_MCK_SEL_MASK_SFT         (0x1 << 25)
+
+/* CLK_AUDDIV_2 */
+#define APLL12_CK_DIV0_SFT                 0
+#define APLL12_CK_DIV0_MASK                0xff
+#define APLL12_CK_DIV0_MASK_SFT            (0xff << 0)
+#define APLL12_CK_DIV1_SFT                 8
+#define APLL12_CK_DIV1_MASK                0xff
+#define APLL12_CK_DIV1_MASK_SFT            (0xff << 8)
+#define APLL12_CK_DIV2_SFT                 16
+#define APLL12_CK_DIV2_MASK                0xff
+#define APLL12_CK_DIV2_MASK_SFT            (0xff << 16)
+#define APLL12_CK_DIV3_SFT                 24
+#define APLL12_CK_DIV3_MASK                0xff
+#define APLL12_CK_DIV3_MASK_SFT            (0xff << 24)
+
+/* CLK_AUDDIV_3 */
+#define APLL12_CK_DIV4_SFT                 0
+#define APLL12_CK_DIV4_MASK                0xff
+#define APLL12_CK_DIV4_MASK_SFT            (0xff << 0)
+#define APLL12_CK_DIVB_SFT                 8
+#define APLL12_CK_DIVB_MASK                0xff
+#define APLL12_CK_DIVB_MASK_SFT            (0xff << 8)
+#define APLL12_CK_DIV5_SFT                 16
+#define APLL12_CK_DIV5_MASK                0xff
+#define APLL12_CK_DIV5_MASK_SFT            (0xff << 16)
+#define APLL12_CK_DIV6_SFT                 24
+#define APLL12_CK_DIV6_MASK                0xff
+#define APLL12_CK_DIV6_MASK_SFT            (0xff << 24)
+
+/* CLK_AUDDIV_4 */
+#define APLL12_CK_DIV7_SFT                 0
+#define APLL12_CK_DIV7_MASK                0xff
+#define APLL12_CK_DIV7_MASK_SFT            (0xff << 0)
+#define APLL12_CK_DIV8_SFT                 8
+#define APLL12_CK_DIV8_MASK                0xff
+#define APLL12_CK_DIV8_MASK_SFT            (0xff << 0)
+#define APLL12_CK_DIV9_SFT                 16
+#define APLL12_CK_DIV9_MASK                0xff
+#define APLL12_CK_DIV9_MASK_SFT            (0xff << 0)
+
+/* AUD_TOP_CFG */
+#define AUD_TOP_CFG_SFT                    0
+#define AUD_TOP_CFG_MASK                   0xffffffff
+#define AUD_TOP_CFG_MASK_SFT               (0xffffffff << 0)
+
+/* AUD_TOP_MON */
+#define AUD_TOP_MON_SFT                    0
+#define AUD_TOP_MON_MASK                   0xffffffff
+#define AUD_TOP_MON_MASK_SFT               (0xffffffff << 0)
+
+/* CLK_AUDDIV_3 */
+#define APLL12_CK_DIV5_MSB_SFT             0
+#define APLL12_CK_DIV5_MSB_MASK            0xf
+#define APLL12_CK_DIV5_MSB_MASK_SFT        (0xf << 0)
+#define RESERVED0_SFT                      4
+#define RESERVED0_MASK                     0xfffffff
+#define RESERVED0_MASK_SFT                 (0xfffffff << 4)
+
+/* APLL */
+#define APLL1_W_NAME "APLL1"
+#define APLL2_W_NAME "APLL2"
+enum {
+	MT8192_APLL1 = 0,
+	MT8192_APLL2,
+};
+
+enum {
+	CLK_AFE = 0,
+	CLK_TML,
+	CLK_APLL22M,
+	CLK_APLL24M,
+	CLK_APLL1_TUNER,
+	CLK_APLL2_TUNER,
+	CLK_NLE,
+	CLK_INFRA_SYS_AUDIO,
+	CLK_INFRA_AUDIO_26M,
+	CLK_MUX_AUDIO,
+	CLK_MUX_AUDIOINTBUS,
+	CLK_TOP_MAINPLL_D4_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_D4,
+	CLK_TOP_MUX_AUD_ENG2,
+	CLK_TOP_APLL2_D4,
+	CLK_TOP_MUX_AUDIO_H,
+	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_I2S6_M_SEL,
+	CLK_TOP_I2S7_M_SEL,
+	CLK_TOP_I2S8_M_SEL,
+	CLK_TOP_I2S9_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_TOP_APLL12_DIV5,
+	CLK_TOP_APLL12_DIV6,
+	CLK_TOP_APLL12_DIV7,
+	CLK_TOP_APLL12_DIV8,
+	CLK_TOP_APLL12_DIV9,
+	CLK_CLK26M,
+	CLK_NUM
+};
+
+struct mtk_base_afe;
+
+int mt8192_init_clock(struct mtk_base_afe *afe);
+int mt8192_afe_enable_clock(struct mtk_base_afe *afe);
+void mt8192_afe_disable_clock(struct mtk_base_afe *afe);
+
+int mt8192_apll1_enable(struct mtk_base_afe *afe);
+void mt8192_apll1_disable(struct mtk_base_afe *afe);
+
+int mt8192_apll2_enable(struct mtk_base_afe *afe);
+void mt8192_apll2_disable(struct mtk_base_afe *afe);
+
+int mt8192_get_apll_rate(struct mtk_base_afe *afe, int apll);
+int mt8192_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
+int mt8192_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
+
+/* these will be replaced by using CCF */
+int mt8192_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate);
+void mt8192_mck_disable(struct mtk_base_afe *afe, int mck_id);
+
+int mt8192_set_audio_int_bus_parent(struct mtk_base_afe *afe,
+				    int clk_id);
+
+#endif
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-common.h b/sound/soc/mediatek/mt8192/mt8192-afe-common.h
new file mode 100644
index 000000000000..d55eff46cc7f
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-common.h
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8192-afe-common.h  --  Mediatek 8192 audio driver definitions
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Shane Chien <shane.chien@mediatek.com>
+ */
+
+#ifndef _MT_8192_AFE_COMMON_H_
+#define _MT_8192_AFE_COMMON_H_
+
+#include <linux/list.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "../common/mtk-base-afe.h"
+#include "mt8192-reg.h"
+
+enum {
+	MT8192_MEMIF_DL1,
+	MT8192_MEMIF_DL12,
+	MT8192_MEMIF_DL2,
+	MT8192_MEMIF_DL3,
+	MT8192_MEMIF_DL4,
+	MT8192_MEMIF_DL5,
+	MT8192_MEMIF_DL6,
+	MT8192_MEMIF_DL7,
+	MT8192_MEMIF_DL8,
+	MT8192_MEMIF_DL9,
+	MT8192_MEMIF_DAI,
+	MT8192_MEMIF_DAI2,
+	MT8192_MEMIF_MOD_DAI,
+	MT8192_MEMIF_VUL12,
+	MT8192_MEMIF_VUL2,
+	MT8192_MEMIF_VUL3,
+	MT8192_MEMIF_VUL4,
+	MT8192_MEMIF_VUL5,
+	MT8192_MEMIF_VUL6,
+	MT8192_MEMIF_AWB,
+	MT8192_MEMIF_AWB2,
+	MT8192_MEMIF_HDMI,
+	MT8192_MEMIF_NUM,
+	MT8192_DAI_ADDA = MT8192_MEMIF_NUM,
+	MT8192_DAI_ADDA_CH34,
+	MT8192_DAI_AP_DMIC,
+	MT8192_DAI_AP_DMIC_CH34,
+	MT8192_DAI_VOW,
+	MT8192_DAI_CONNSYS_I2S,
+	MT8192_DAI_I2S_0,
+	MT8192_DAI_I2S_1,
+	MT8192_DAI_I2S_2,
+	MT8192_DAI_I2S_3,
+	MT8192_DAI_I2S_5,
+	MT8192_DAI_I2S_6,
+	MT8192_DAI_I2S_7,
+	MT8192_DAI_I2S_8,
+	MT8192_DAI_I2S_9,
+	MT8192_DAI_HW_GAIN_1,
+	MT8192_DAI_HW_GAIN_2,
+	MT8192_DAI_SRC_1,
+	MT8192_DAI_SRC_2,
+	MT8192_DAI_PCM_1,
+	MT8192_DAI_PCM_2,
+	MT8192_DAI_TDM,
+	MT8192_DAI_NUM,
+};
+
+enum {
+	MT8192_IRQ_0,
+	MT8192_IRQ_1,
+	MT8192_IRQ_2,
+	MT8192_IRQ_3,
+	MT8192_IRQ_4,
+	MT8192_IRQ_5,
+	MT8192_IRQ_6,
+	MT8192_IRQ_7,
+	MT8192_IRQ_8,
+	MT8192_IRQ_9,
+	MT8192_IRQ_10,
+	MT8192_IRQ_11,
+	MT8192_IRQ_12,
+	MT8192_IRQ_13,
+	MT8192_IRQ_14,
+	MT8192_IRQ_15,
+	MT8192_IRQ_16,
+	MT8192_IRQ_17,
+	MT8192_IRQ_18,
+	MT8192_IRQ_19,
+	MT8192_IRQ_20,
+	MT8192_IRQ_21,
+	MT8192_IRQ_22,
+	MT8192_IRQ_23,
+	MT8192_IRQ_24,
+	MT8192_IRQ_25,
+	MT8192_IRQ_26,
+	MT8192_IRQ_31,	/* used only for TDM */
+	MT8192_IRQ_NUM,
+};
+
+enum {
+	MTKAIF_PROTOCOL_1 = 0,
+	MTKAIF_PROTOCOL_2,
+	MTKAIF_PROTOCOL_2_CLK_P2,
+};
+
+enum {
+	MTK_AFE_ADDA_DL_GAIN_MUTE = 0,
+	MTK_AFE_ADDA_DL_GAIN_NORMAL = 0xf74f,
+	/* SA suggest apply -0.3db to audio/speech path */
+};
+
+/* MCLK */
+enum {
+	MT8192_I2S0_MCK = 0,
+	MT8192_I2S1_MCK,
+	MT8192_I2S2_MCK,
+	MT8192_I2S3_MCK,
+	MT8192_I2S4_MCK,
+	MT8192_I2S4_BCK,
+	MT8192_I2S5_MCK,
+	MT8192_I2S6_MCK,
+	MT8192_I2S7_MCK,
+	MT8192_I2S8_MCK,
+	MT8192_I2S9_MCK,
+	MT8192_MCK_NUM,
+};
+
+struct clk;
+
+struct mt8192_afe_private {
+	struct clk **clk;
+	struct regmap *topckgen;
+	struct regmap *apmixedsys;
+	struct regmap *infracfg;
+	int stf_positive_gain_db;
+	int pm_runtime_bypass_reg_ctl;
+
+	/* dai */
+	bool dai_on[MT8192_DAI_NUM];
+	void *dai_priv[MT8192_DAI_NUM];
+
+	/* adda */
+	int mtkaif_protocol;
+	int mtkaif_chosen_phase[4];
+	int mtkaif_phase_cycle[4];
+	int mtkaif_calibration_num_phase;
+	int mtkaif_dmic;
+	int mtkaif_dmic_ch34;
+	int mtkaif_adda6_only;
+
+	/* mck */
+	int mck_rate[MT8192_MCK_NUM];
+};
+
+int mt8192_dai_adda_register(struct mtk_base_afe *afe);
+int mt8192_dai_i2s_register(struct mtk_base_afe *afe);
+int mt8192_dai_hw_gain_register(struct mtk_base_afe *afe);
+int mt8192_dai_src_register(struct mtk_base_afe *afe);
+int mt8192_dai_pcm_register(struct mtk_base_afe *afe);
+int mt8192_dai_tdm_register(struct mtk_base_afe *afe);
+
+unsigned int mt8192_general_rate_transform(struct device *dev,
+					   unsigned int rate);
+unsigned int mt8192_rate_transform(struct device *dev,
+				   unsigned int rate, int aud_blk);
+
+int mt8192_dai_set_priv(struct mtk_base_afe *afe, int id,
+			int priv_size, const void *priv_data);
+
+#endif
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-control.c b/sound/soc/mediatek/mt8192/mt8192-afe-control.c
new file mode 100644
index 000000000000..9163e05e54e1
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-control.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio Control
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/pm_runtime.h>
+
+#include "mt8192-afe-common.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_352K = 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 mt8192_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 176400:
+		return MTK_AFE_RATE_176K;
+	case 192000:
+		return MTK_AFE_RATE_192K;
+	case 260000:
+		return MTK_AFE_RATE_260K;
+	case 352800:
+		return MTK_AFE_RATE_352K;
+	case 384000:
+		return MTK_AFE_RATE_384K;
+	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;
+	}
+}
+
+static unsigned int pcm_rate_transform(struct device *dev,
+				       unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return MTK_AFE_PCM_RATE_8K;
+	case 16000:
+		return MTK_AFE_PCM_RATE_16K;
+	case 32000:
+		return MTK_AFE_PCM_RATE_32K;
+	case 48000:
+		return MTK_AFE_PCM_RATE_48K;
+	default:
+		dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
+			 __func__,
+			 rate, MTK_AFE_PCM_RATE_32K);
+		return MTK_AFE_PCM_RATE_32K;
+	}
+}
+
+unsigned int mt8192_rate_transform(struct device *dev,
+				   unsigned int rate, int aud_blk)
+{
+	switch (aud_blk) {
+	case MT8192_MEMIF_DAI:
+	case MT8192_MEMIF_MOD_DAI:
+		return dai_memif_rate_transform(dev, rate);
+	case MT8192_DAI_PCM_1:
+	case MT8192_DAI_PCM_2:
+		return pcm_rate_transform(dev, rate);
+	default:
+		return mt8192_general_rate_transform(dev, rate);
+	}
+}
+
+int mt8192_dai_set_priv(struct mtk_base_afe *afe, int id,
+			int priv_size, const void *priv_data)
+{
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	void *temp_data;
+
+	temp_data = devm_kzalloc(afe->dev,
+				 priv_size,
+				 GFP_KERNEL);
+	if (!temp_data)
+		return -ENOMEM;
+
+	if (priv_data)
+		memcpy(temp_data, priv_data, priv_size);
+
+	afe_priv->dai_priv[id] = temp_data;
+
+	return 0;
+}
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c
new file mode 100644
index 000000000000..165663a78e36
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8192-afe-gpio.c  --  Mediatek 8192 afe gpio ctrl
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "mt8192-afe-common.h"
+#include "mt8192-afe-gpio.h"
+
+static struct pinctrl *aud_pinctrl;
+
+enum mt8192_afe_gpio {
+	MT8192_AFE_GPIO_DAT_MISO_OFF,
+	MT8192_AFE_GPIO_DAT_MISO_ON,
+	MT8192_AFE_GPIO_DAT_MOSI_OFF,
+	MT8192_AFE_GPIO_DAT_MOSI_ON,
+	MT8192_AFE_GPIO_DAT_MISO_CH34_OFF,
+	MT8192_AFE_GPIO_DAT_MISO_CH34_ON,
+	MT8192_AFE_GPIO_DAT_MOSI_CH34_OFF,
+	MT8192_AFE_GPIO_DAT_MOSI_CH34_ON,
+	MT8192_AFE_GPIO_I2S0_OFF,
+	MT8192_AFE_GPIO_I2S0_ON,
+	MT8192_AFE_GPIO_I2S1_OFF,
+	MT8192_AFE_GPIO_I2S1_ON,
+	MT8192_AFE_GPIO_I2S2_OFF,
+	MT8192_AFE_GPIO_I2S2_ON,
+	MT8192_AFE_GPIO_I2S3_OFF,
+	MT8192_AFE_GPIO_I2S3_ON,
+	MT8192_AFE_GPIO_I2S5_OFF,
+	MT8192_AFE_GPIO_I2S5_ON,
+	MT8192_AFE_GPIO_I2S6_OFF,
+	MT8192_AFE_GPIO_I2S6_ON,
+	MT8192_AFE_GPIO_I2S7_OFF,
+	MT8192_AFE_GPIO_I2S7_ON,
+	MT8192_AFE_GPIO_I2S8_OFF,
+	MT8192_AFE_GPIO_I2S8_ON,
+	MT8192_AFE_GPIO_I2S9_OFF,
+	MT8192_AFE_GPIO_I2S9_ON,
+	MT8192_AFE_GPIO_VOW_DAT_OFF,
+	MT8192_AFE_GPIO_VOW_DAT_ON,
+	MT8192_AFE_GPIO_VOW_CLK_OFF,
+	MT8192_AFE_GPIO_VOW_CLK_ON,
+	MT8192_AFE_GPIO_CLK_MOSI_OFF,
+	MT8192_AFE_GPIO_CLK_MOSI_ON,
+	MT8192_AFE_GPIO_TDM_OFF,
+	MT8192_AFE_GPIO_TDM_ON,
+	MT8192_AFE_GPIO_GPIO_NUM
+};
+
+struct audio_gpio_attr {
+	const char *name;
+	bool gpio_prepare;
+	struct pinctrl_state *gpioctrl;
+};
+
+static struct audio_gpio_attr aud_gpios[MT8192_AFE_GPIO_GPIO_NUM] = {
+	[MT8192_AFE_GPIO_DAT_MISO_OFF] = {"aud_dat_miso_off", false, NULL},
+	[MT8192_AFE_GPIO_DAT_MISO_ON] = {"aud_dat_miso_on", false, NULL},
+	[MT8192_AFE_GPIO_DAT_MOSI_OFF] = {"aud_dat_mosi_off", false, NULL},
+	[MT8192_AFE_GPIO_DAT_MOSI_ON] = {"aud_dat_mosi_on", false, NULL},
+	[MT8192_AFE_GPIO_I2S0_OFF] = {"aud_gpio_i2s0_off", false, NULL},
+	[MT8192_AFE_GPIO_I2S0_ON] = {"aud_gpio_i2s0_on", false, NULL},
+	[MT8192_AFE_GPIO_I2S1_OFF] = {"aud_gpio_i2s1_off", false, NULL},
+	[MT8192_AFE_GPIO_I2S1_ON] = {"aud_gpio_i2s1_on", false, NULL},
+	[MT8192_AFE_GPIO_I2S2_OFF] = {"aud_gpio_i2s2_off", false, NULL},
+	[MT8192_AFE_GPIO_I2S2_ON] = {"aud_gpio_i2s2_on", false, NULL},
+	[MT8192_AFE_GPIO_I2S3_OFF] = {"aud_gpio_i2s3_off", false, NULL},
+	[MT8192_AFE_GPIO_I2S3_ON] = {"aud_gpio_i2s3_on", false, NULL},
+	[MT8192_AFE_GPIO_I2S5_OFF] = {"aud_gpio_i2s5_off", false, NULL},
+	[MT8192_AFE_GPIO_I2S5_ON] = {"aud_gpio_i2s5_on", false, NULL},
+	[MT8192_AFE_GPIO_I2S6_OFF] = {"aud_gpio_i2s6_off", false, NULL},
+	[MT8192_AFE_GPIO_I2S6_ON] = {"aud_gpio_i2s6_on", false, NULL},
+	[MT8192_AFE_GPIO_I2S7_OFF] = {"aud_gpio_i2s7_off", false, NULL},
+	[MT8192_AFE_GPIO_I2S7_ON] = {"aud_gpio_i2s7_on", false, NULL},
+	[MT8192_AFE_GPIO_I2S8_OFF] = {"aud_gpio_i2s8_off", false, NULL},
+	[MT8192_AFE_GPIO_I2S8_ON] = {"aud_gpio_i2s8_on", false, NULL},
+	[MT8192_AFE_GPIO_I2S9_OFF] = {"aud_gpio_i2s9_off", false, NULL},
+	[MT8192_AFE_GPIO_I2S9_ON] = {"aud_gpio_i2s9_on", false, NULL},
+	[MT8192_AFE_GPIO_TDM_OFF] = {"aud_gpio_tdm_off", false, NULL},
+	[MT8192_AFE_GPIO_TDM_ON] = {"aud_gpio_tdm_on", false, NULL},
+	[MT8192_AFE_GPIO_VOW_DAT_OFF] = {"vow_dat_miso_off", false, NULL},
+	[MT8192_AFE_GPIO_VOW_DAT_ON] = {"vow_dat_miso_on", false, NULL},
+	[MT8192_AFE_GPIO_VOW_CLK_OFF] = {"vow_clk_miso_off", false, NULL},
+	[MT8192_AFE_GPIO_VOW_CLK_ON] = {"vow_clk_miso_on", false, NULL},
+	[MT8192_AFE_GPIO_DAT_MISO_CH34_OFF] = {"aud_dat_miso_ch34_off",
+					       false, NULL},
+	[MT8192_AFE_GPIO_DAT_MISO_CH34_ON] = {"aud_dat_miso_ch34_on",
+					      false, NULL},
+	[MT8192_AFE_GPIO_DAT_MOSI_CH34_OFF] = {"aud_dat_mosi_ch34_off",
+					       false, NULL},
+	[MT8192_AFE_GPIO_DAT_MOSI_CH34_ON] = {"aud_dat_mosi_ch34_on",
+					      false, NULL},
+	[MT8192_AFE_GPIO_CLK_MOSI_OFF] = {"aud_clk_mosi_off", false, NULL},
+	[MT8192_AFE_GPIO_CLK_MOSI_ON] = {"aud_clk_mosi_on", false, NULL},
+};
+
+static DEFINE_MUTEX(gpio_request_mutex);
+
+static int mt8192_afe_gpio_select(struct device *dev,
+				  enum mt8192_afe_gpio type)
+{
+	int ret;
+
+	if (type < 0 || type >= MT8192_AFE_GPIO_GPIO_NUM) {
+		dev_err(dev, "%s(), error, invalid gpio type %d\n",
+			__func__, type);
+		return -EINVAL;
+	}
+
+	if (!aud_gpios[type].gpio_prepare) {
+		dev_warn(dev, "%s(), error, gpio type %d not prepared\n",
+			 __func__, type);
+		return -EIO;
+	}
+
+	ret = pinctrl_select_state(aud_pinctrl,
+				   aud_gpios[type].gpioctrl);
+	if (ret) {
+		dev_dbg(dev, "%s(), error, can not set gpio type %d\n",
+			__func__, type);
+	}
+
+	return ret;
+}
+
+int mt8192_afe_gpio_init(struct device *dev)
+{
+	int i, ret;
+
+	aud_pinctrl = devm_pinctrl_get(dev);
+	if (IS_ERR(aud_pinctrl)) {
+		ret = PTR_ERR(aud_pinctrl);
+		dev_err(dev, "%s(), ret %d, cannot get aud_pinctrl!\n",
+			__func__, ret);
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(aud_gpios); i++) {
+		aud_gpios[i].gpioctrl = pinctrl_lookup_state(aud_pinctrl,
+							     aud_gpios[i].name);
+		if (IS_ERR(aud_gpios[i].gpioctrl)) {
+			ret = PTR_ERR(aud_gpios[i].gpioctrl);
+			dev_dbg(dev, "%s(), pinctrl_lookup_state %s fail, ret %d\n",
+				__func__, aud_gpios[i].name, ret);
+		} else {
+			aud_gpios[i].gpio_prepare = true;
+		}
+	}
+
+	mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_CLK_MOSI_ON);
+
+	/* gpio status init */
+	mt8192_afe_gpio_request(dev, false, MT8192_DAI_ADDA, 0);
+	mt8192_afe_gpio_request(dev, false, MT8192_DAI_ADDA, 1);
+
+	return 0;
+}
+EXPORT_SYMBOL(mt8192_afe_gpio_init);
+
+static int mt8192_afe_gpio_adda_dl(struct device *dev, bool enable)
+{
+	if (enable) {
+		return mt8192_afe_gpio_select(dev,
+					      MT8192_AFE_GPIO_DAT_MOSI_ON);
+	} else {
+		return mt8192_afe_gpio_select(dev,
+					      MT8192_AFE_GPIO_DAT_MOSI_OFF);
+	}
+}
+
+static int mt8192_afe_gpio_adda_ul(struct device *dev, bool enable)
+{
+	if (enable) {
+		return mt8192_afe_gpio_select(dev,
+					      MT8192_AFE_GPIO_DAT_MISO_ON);
+	} else {
+		return mt8192_afe_gpio_select(dev,
+					      MT8192_AFE_GPIO_DAT_MISO_OFF);
+	}
+}
+
+static int mt8192_afe_gpio_adda_ch34_dl(struct device *dev, bool enable)
+{
+	if (enable) {
+		return mt8192_afe_gpio_select(dev,
+			MT8192_AFE_GPIO_DAT_MOSI_CH34_ON);
+	} else {
+		return mt8192_afe_gpio_select(dev,
+			MT8192_AFE_GPIO_DAT_MOSI_CH34_OFF);
+	}
+}
+
+static int mt8192_afe_gpio_adda_ch34_ul(struct device *dev, bool enable)
+{
+	if (enable) {
+		return mt8192_afe_gpio_select(dev,
+			MT8192_AFE_GPIO_DAT_MISO_CH34_ON);
+	} else {
+		return mt8192_afe_gpio_select(dev,
+			MT8192_AFE_GPIO_DAT_MISO_CH34_OFF);
+	}
+}
+
+int mt8192_afe_gpio_request(struct device *dev, bool enable,
+			    int dai, int uplink)
+{
+	mutex_lock(&gpio_request_mutex);
+	switch (dai) {
+	case MT8192_DAI_ADDA:
+		if (uplink)
+			mt8192_afe_gpio_adda_ul(dev, enable);
+		else
+			mt8192_afe_gpio_adda_dl(dev, enable);
+		break;
+	case MT8192_DAI_ADDA_CH34:
+		if (uplink)
+			mt8192_afe_gpio_adda_ch34_ul(dev, enable);
+		else
+			mt8192_afe_gpio_adda_ch34_dl(dev, enable);
+		break;
+	case MT8192_DAI_I2S_0:
+		if (enable)
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S0_ON);
+		else
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S0_OFF);
+		break;
+	case MT8192_DAI_I2S_1:
+		if (enable)
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S1_ON);
+		else
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S1_OFF);
+		break;
+	case MT8192_DAI_I2S_2:
+		if (enable)
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S2_ON);
+		else
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S2_OFF);
+		break;
+	case MT8192_DAI_I2S_3:
+		if (enable)
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S3_ON);
+		else
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S3_OFF);
+		break;
+	case MT8192_DAI_I2S_5:
+		if (enable)
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S5_ON);
+		else
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S5_OFF);
+		break;
+	case MT8192_DAI_I2S_6:
+		if (enable)
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S6_ON);
+		else
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S6_OFF);
+		break;
+	case MT8192_DAI_I2S_7:
+		if (enable)
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S7_ON);
+		else
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S7_OFF);
+		break;
+	case MT8192_DAI_I2S_8:
+		if (enable)
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S8_ON);
+		else
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S8_OFF);
+		break;
+	case MT8192_DAI_I2S_9:
+		if (enable)
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S9_ON);
+		else
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S9_OFF);
+		break;
+	case MT8192_DAI_TDM:
+		if (enable)
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_TDM_ON);
+		else
+			mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_TDM_OFF);
+		break;
+	case MT8192_DAI_VOW:
+		if (enable) {
+			mt8192_afe_gpio_select(dev,
+					       MT8192_AFE_GPIO_VOW_CLK_ON);
+			mt8192_afe_gpio_select(dev,
+					       MT8192_AFE_GPIO_VOW_DAT_ON);
+		} else {
+			mt8192_afe_gpio_select(dev,
+					       MT8192_AFE_GPIO_VOW_CLK_OFF);
+			mt8192_afe_gpio_select(dev,
+					       MT8192_AFE_GPIO_VOW_DAT_OFF);
+		}
+		break;
+	default:
+		mutex_unlock(&gpio_request_mutex);
+		dev_warn(dev, "%s(), invalid dai %d\n", __func__, dai);
+		return -EINVAL;
+	}
+	mutex_unlock(&gpio_request_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(mt8192_afe_gpio_request);
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-gpio.h b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.h
new file mode 100644
index 000000000000..5d29469da1c1
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8192-afe-gpio.h  --  Mediatek 8192 afe gpio ctrl definition
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Shane Chien <shane.chien@mediatek.com>
+ */
+
+#ifndef _MT8192_AFE_GPIO_H_
+#define _MT8192_AFE_GPIO_H_
+
+struct device;
+
+int mt8192_afe_gpio_init(struct device *dev);
+
+int mt8192_afe_gpio_request(struct device *dev, bool enable,
+			    int dai, int uplink);
+
+#endif
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
new file mode 100644
index 000000000000..e7fec2d75e3d
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
@@ -0,0 +1,2389 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Mediatek ALSA SoC AFE platform driver for 8192
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.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 <sound/soc.h>
+
+#include "../common/mtk-afe-fe-dai.h"
+#include "../common/mtk-afe-platform-driver.h"
+
+#include "mt8192-afe-common.h"
+#include "mt8192-afe-clk.h"
+#include "mt8192-afe-gpio.h"
+#include "mt8192-interconnection.h"
+
+static const struct snd_pcm_hardware mt8192_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 = 96,
+	.period_bytes_max = 4 * 48 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
+	.buffer_bytes_max = 4 * 48 * 1024,
+	.fifo_size = 0,
+};
+
+static int mt8192_memif_fs(struct snd_pcm_substream *substream,
+			   unsigned int rate)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	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 mt8192_rate_transform(afe->dev, rate, id);
+}
+
+static int mt8192_get_dai_fs(struct mtk_base_afe *afe,
+			     int dai_id, unsigned int rate)
+{
+	return mt8192_rate_transform(afe->dev, rate, dai_id);
+}
+
+static int mt8192_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	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 mt8192_general_rate_transform(afe->dev, rate);
+}
+
+static int mt8192_get_memif_pbuf_size(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if ((runtime->period_size * 1000) / runtime->rate > 10)
+		return MT8192_MEMIF_PBUF_SIZE_256_BYTES;
+	else
+		return MT8192_MEMIF_PBUF_SIZE_32_BYTES;
+}
+
+#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 mt8192_memif_dai_driver[] = {
+	/* FE DAIs: memory intefaces to CPU */
+	{
+		.name = "DL1",
+		.id = MT8192_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 = "DL12",
+		.id = MT8192_MEMIF_DL12,
+		.playback = {
+			.stream_name = "DL12",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "DL2",
+		.id = MT8192_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 = MT8192_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 = "DL4",
+		.id = MT8192_MEMIF_DL4,
+		.playback = {
+			.stream_name = "DL4",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "DL5",
+		.id = MT8192_MEMIF_DL5,
+		.playback = {
+			.stream_name = "DL5",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "DL6",
+		.id = MT8192_MEMIF_DL6,
+		.playback = {
+			.stream_name = "DL6",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "DL7",
+		.id = MT8192_MEMIF_DL7,
+		.playback = {
+			.stream_name = "DL7",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "DL8",
+		.id = MT8192_MEMIF_DL8,
+		.playback = {
+			.stream_name = "DL8",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "DL9",
+		.id = MT8192_MEMIF_DL9,
+		.playback = {
+			.stream_name = "DL9",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL1",
+		.id = MT8192_MEMIF_VUL12,
+		.capture = {
+			.stream_name = "UL1",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL2",
+		.id = MT8192_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 = MT8192_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 = MT8192_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 = "UL5",
+		.id = MT8192_MEMIF_VUL3,
+		.capture = {
+			.stream_name = "UL5",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL6",
+		.id = MT8192_MEMIF_VUL4,
+		.capture = {
+			.stream_name = "UL6",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL7",
+		.id = MT8192_MEMIF_VUL5,
+		.capture = {
+			.stream_name = "UL7",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL8",
+		.id = MT8192_MEMIF_VUL6,
+		.capture = {
+			.stream_name = "UL8",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL_MONO_1",
+		.id = MT8192_MEMIF_MOD_DAI,
+		.capture = {
+			.stream_name = "UL_MONO_1",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_DAI_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL_MONO_2",
+		.id = MT8192_MEMIF_DAI,
+		.capture = {
+			.stream_name = "UL_MONO_2",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_DAI_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL_MONO_3",
+		.id = MT8192_MEMIF_DAI2,
+		.capture = {
+			.stream_name = "UL_MONO_3",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_DAI_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "HDMI",
+		.id = MT8192_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,
+	},
+};
+
+static int ul_tinyconn_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);
+	unsigned int reg_shift;
+	unsigned int reg_mask_shift;
+
+	dev_info(afe->dev, "%s(), event 0x%x\n", __func__, event);
+
+	if (strstr(w->name, "UL1")) {
+		reg_shift = VUL1_USE_TINY_SFT;
+		reg_mask_shift = VUL1_USE_TINY_MASK_SFT;
+	} else if (strstr(w->name, "UL2")) {
+		reg_shift = VUL2_USE_TINY_SFT;
+		reg_mask_shift = VUL2_USE_TINY_MASK_SFT;
+	} else if (strstr(w->name, "UL3")) {
+		reg_shift = VUL12_USE_TINY_SFT;
+		reg_mask_shift = VUL12_USE_TINY_MASK_SFT;
+	} else if (strstr(w->name, "UL4")) {
+		reg_shift = AWB2_USE_TINY_SFT;
+		reg_mask_shift = AWB2_USE_TINY_MASK_SFT;
+	} else {
+		reg_shift = AWB2_USE_TINY_SFT;
+		reg_mask_shift = AWB2_USE_TINY_MASK_SFT;
+		dev_warn(afe->dev, "%s(), err widget name %s, default use UL4",
+			 __func__, w->name);
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(afe->regmap, AFE_MEMIF_CONN, reg_mask_shift,
+				   0x1 << reg_shift);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_update_bits(afe->regmap, AFE_MEMIF_CONN, reg_mask_shift,
+				   0x0 << reg_shift);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/* 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("ADDA_UL_CH2", AFE_CONN21,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN21,
+				    I_ADDA_UL_CH3, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN22,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN22,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN22,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN22,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch3_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN9,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN9,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN9,
+				    I_ADDA_UL_CH3, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch4_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN10,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN10,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN10,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN10,
+				    I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN5,
+				    I_I2S0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN5,
+				    I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN5,
+				    I_DL12_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("DL4_CH1", AFE_CONN5_1,
+				    I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN5_1,
+				    I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN5_1,
+				    I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN5,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN5,
+				    I_PCM_2_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN5,
+				    I_I2S2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S6_CH1", AFE_CONN5_1,
+				    I_I2S6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S8_CH1", AFE_CONN5_1,
+				    I_I2S8_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1", AFE_CONN5_1,
+				    I_CONNSYS_I2S_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1", AFE_CONN5_1,
+				    I_SRC_1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN6,
+				    I_I2S0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN6,
+				    I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN6,
+				    I_DL12_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("DL4_CH2", AFE_CONN6_1,
+				    I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN6_1,
+				    I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN6_1,
+				    I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN6,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN6,
+				    I_PCM_2_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN6,
+				    I_I2S2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S6_CH2", AFE_CONN6_1,
+				    I_I2S6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S8_CH2", AFE_CONN6_1,
+				    I_I2S8_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2", AFE_CONN6_1,
+				    I_CONNSYS_I2S_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2", AFE_CONN6_1,
+				    I_SRC_1_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1", AFE_CONN32_1,
+				    I_CONNSYS_I2S_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN32,
+				    I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN32,
+				    I_DL2_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2", AFE_CONN33_1,
+				    I_CONNSYS_I2S_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),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN38,
+				    I_I2S0_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),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN39,
+				    I_I2S0_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul5_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN44,
+				    I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul5_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN45,
+				    I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul6_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN46,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN46,
+				    I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN46,
+				    I_DL12_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN46_1,
+				    I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN46,
+				    I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN46,
+				    I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN46_1,
+				    I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN46,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN46,
+				    I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul6_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN47,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN47,
+				    I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN47,
+				    I_DL12_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN47_1,
+				    I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN47,
+				    I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN47,
+				    I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN47_1,
+				    I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN47,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN47,
+				    I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul7_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN48,
+				    I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul7_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN49,
+				    I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul8_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN50,
+				    I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul8_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN51,
+				    I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_mono_1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN12,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN12,
+				    I_PCM_2_CAP_CH1, 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),
+};
+
+static const struct snd_kcontrol_new memif_ul_mono_3_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN35,
+				    I_ADDA_UL_CH1, 1, 0),
+};
+
+/* TINYCONN MUX */
+enum {
+	TINYCONN_CH1_MUX_I2S0 = 0x14,
+	TINYCONN_CH2_MUX_I2S0 = 0x15,
+	TINYCONN_CH1_MUX_I2S6 = 0x1a,
+	TINYCONN_CH2_MUX_I2S6 = 0x1b,
+	TINYCONN_CH1_MUX_I2S8 = 0x1c,
+	TINYCONN_CH2_MUX_I2S8 = 0x1d,
+	TINYCONN_MUX_NONE = 0x1f,
+};
+
+static const char * const tinyconn_mux_map[] = {
+	"NONE",
+	"I2S0_CH1",
+	"I2S0_CH2",
+	"I2S6_CH1",
+	"I2S6_CH2",
+	"I2S8_CH1",
+	"I2S8_CH2",
+};
+
+static int tinyconn_mux_map_value[] = {
+	TINYCONN_MUX_NONE,
+	TINYCONN_CH1_MUX_I2S0,
+	TINYCONN_CH2_MUX_I2S0,
+	TINYCONN_CH1_MUX_I2S6,
+	TINYCONN_CH2_MUX_I2S6,
+	TINYCONN_CH1_MUX_I2S8,
+	TINYCONN_CH2_MUX_I2S8,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(ul4_tinyconn_ch1_mux_map_enum,
+				  AFE_TINY_CONN0,
+				  O_2_CFG_SFT,
+				  O_2_CFG_MASK,
+				  tinyconn_mux_map,
+				  tinyconn_mux_map_value);
+static SOC_VALUE_ENUM_SINGLE_DECL(ul4_tinyconn_ch2_mux_map_enum,
+				  AFE_TINY_CONN0,
+				  O_3_CFG_SFT,
+				  O_3_CFG_MASK,
+				  tinyconn_mux_map,
+				  tinyconn_mux_map_value);
+
+static const struct snd_kcontrol_new ul4_tinyconn_ch1_mux_control =
+	SOC_DAPM_ENUM("UL4_TINYCONN_CH1_MUX", ul4_tinyconn_ch1_mux_map_enum);
+static const struct snd_kcontrol_new ul4_tinyconn_ch2_mux_control =
+	SOC_DAPM_ENUM("UL4_TINYCONN_CH2_MUX", ul4_tinyconn_ch2_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mt8192_memif_widgets[] = {
+	/* inter-connections */
+	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("UL1_CH3", SND_SOC_NOPM, 0, 0,
+			   memif_ul1_ch3_mix, ARRAY_SIZE(memif_ul1_ch3_mix)),
+	SND_SOC_DAPM_MIXER("UL1_CH4", SND_SOC_NOPM, 0, 0,
+			   memif_ul1_ch4_mix, ARRAY_SIZE(memif_ul1_ch4_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_MUX_E("UL4_TINYCONN_CH1_MUX", SND_SOC_NOPM, 0, 0,
+			   &ul4_tinyconn_ch1_mux_control,
+			   ul_tinyconn_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MUX_E("UL4_TINYCONN_CH2_MUX", SND_SOC_NOPM, 0, 0,
+			   &ul4_tinyconn_ch2_mux_control,
+			   ul_tinyconn_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MIXER("UL5_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul5_ch1_mix, ARRAY_SIZE(memif_ul5_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL5_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul5_ch2_mix, ARRAY_SIZE(memif_ul5_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL6_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul6_ch1_mix, ARRAY_SIZE(memif_ul6_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL6_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul6_ch2_mix, ARRAY_SIZE(memif_ul6_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL7_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul7_ch1_mix, ARRAY_SIZE(memif_ul7_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL7_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul7_ch2_mix, ARRAY_SIZE(memif_ul7_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL8_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul8_ch1_mix, ARRAY_SIZE(memif_ul8_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL8_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul8_ch2_mix, ARRAY_SIZE(memif_ul8_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("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)),
+
+	SND_SOC_DAPM_MIXER("UL_MONO_3_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul_mono_3_mix,
+			   ARRAY_SIZE(memif_ul_mono_3_mix)),
+
+	SND_SOC_DAPM_INPUT("UL1_VIRTUAL_INPUT"),
+	SND_SOC_DAPM_INPUT("UL2_VIRTUAL_INPUT"),
+	SND_SOC_DAPM_INPUT("UL6_VIRTUAL_INPUT"),
+};
+
+static const struct snd_soc_dapm_route mt8192_memif_routes[] = {
+	{"UL1", NULL, "UL1_CH1"},
+	{"UL1", NULL, "UL1_CH2"},
+	{"UL1", NULL, "UL1_CH3"},
+	{"UL1", NULL, "UL1_CH4"},
+	{"UL1_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL1_CH1", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+	{"UL1_CH1", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+	{"UL1_CH2", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL1_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+	{"UL1_CH2", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+	{"UL1_CH2", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+	{"UL1_CH3", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL1_CH3", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+	{"UL1_CH3", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+	{"UL1_CH4", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL1_CH4", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+	{"UL1_CH4", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+	{"UL1_CH4", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+
+	{"UL2", NULL, "UL2_CH1"},
+	{"UL2", NULL, "UL2_CH2"},
+	{"UL2_CH1", "I2S0_CH1", "I2S0"},
+	{"UL2_CH2", "I2S0_CH2", "I2S0"},
+	{"UL2_CH1", "I2S2_CH1", "I2S2"},
+	{"UL2_CH2", "I2S2_CH2", "I2S2"},
+	{"UL2_CH1", "I2S6_CH1", "I2S6"},
+	{"UL2_CH2", "I2S6_CH2", "I2S6"},
+	{"UL2_CH1", "I2S8_CH1", "I2S8"},
+	{"UL2_CH2", "I2S8_CH2", "I2S8"},
+
+	{"UL2_CH1", "PCM_1_CAP_CH1", "PCM 1 Capture"},
+	{"UL2_CH2", "PCM_1_CAP_CH1", "PCM 1 Capture"},
+	{"UL2_CH1", "PCM_2_CAP_CH1", "PCM 2 Capture"},
+	{"UL2_CH2", "PCM_2_CAP_CH1", "PCM 2 Capture"},
+
+	{"UL_MONO_1", NULL, "UL_MONO_1_CH1"},
+	{"UL_MONO_1_CH1", "PCM_1_CAP_CH1", "PCM 1 Capture"},
+	{"UL_MONO_1_CH1", "PCM_2_CAP_CH1", "PCM 2 Capture"},
+
+	{"UL_MONO_2", NULL, "UL_MONO_2_CH1"},
+	{"UL_MONO_2_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+
+	{"UL_MONO_3", NULL, "UL_MONO_3_CH1"},
+	{"UL_MONO_3_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+
+	{"UL2_CH1", "CONNSYS_I2S_CH1", "Connsys I2S"},
+	{"UL2_CH2", "CONNSYS_I2S_CH2", "Connsys I2S"},
+
+	{"UL3", NULL, "UL3_CH1"},
+	{"UL3", NULL, "UL3_CH2"},
+	{"UL3_CH1", "CONNSYS_I2S_CH1", "Connsys I2S"},
+	{"UL3_CH2", "CONNSYS_I2S_CH2", "Connsys I2S"},
+
+	{"UL4", NULL, "UL4_CH1"},
+	{"UL4", NULL, "UL4_CH2"},
+	{"UL4", NULL, "UL4_TINYCONN_CH1_MUX"},
+	{"UL4", NULL, "UL4_TINYCONN_CH2_MUX"},
+	{"UL4_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL4_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+	{"UL4_CH1", "I2S0_CH1", "I2S0"},
+	{"UL4_CH2", "I2S0_CH2", "I2S0"},
+	{"UL4_TINYCONN_CH1_MUX", "I2S0_CH1", "I2S0"},
+	{"UL4_TINYCONN_CH2_MUX", "I2S0_CH2", "I2S0"},
+
+	{"UL5", NULL, "UL5_CH1"},
+	{"UL5", NULL, "UL5_CH2"},
+	{"UL5_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL5_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+
+	{"UL6", NULL, "UL6_CH1"},
+	{"UL6", NULL, "UL6_CH2"},
+
+	{"UL6_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL6_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+	{"UL6_CH1", "PCM_1_CAP_CH1", "PCM 1 Capture"},
+	{"UL6_CH2", "PCM_1_CAP_CH1", "PCM 1 Capture"},
+	{"UL6_CH1", "PCM_2_CAP_CH1", "PCM 2 Capture"},
+	{"UL6_CH2", "PCM_2_CAP_CH1", "PCM 2 Capture"},
+
+	{"UL7", NULL, "UL7_CH1"},
+	{"UL7", NULL, "UL7_CH2"},
+	{"UL7_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL7_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+
+	{"UL8", NULL, "UL8_CH1"},
+	{"UL8", NULL, "UL8_CH2"},
+	{"UL8_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+	{"UL8_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+};
+
+static const struct mtk_base_memif_data memif_data[MT8192_MEMIF_NUM] = {
+	[MT8192_MEMIF_DL1] = {
+		.name = "DL1",
+		.id = MT8192_MEMIF_DL1,
+		.reg_ofs_base = AFE_DL1_BASE,
+		.reg_ofs_cur = AFE_DL1_CUR,
+		.reg_ofs_end = AFE_DL1_END,
+		.reg_ofs_base_msb = AFE_DL1_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DL1_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DL1_END_MSB,
+		.fs_reg = AFE_DL1_CON0,
+		.fs_shift = DL1_MODE_SFT,
+		.fs_maskbit = DL1_MODE_MASK,
+		.mono_reg = AFE_DL1_CON0,
+		.mono_shift = DL1_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL1_ON_SFT,
+		.hd_reg = AFE_DL1_CON0,
+		.hd_shift = DL1_HD_MODE_SFT,
+		.hd_align_reg = AFE_DL1_CON0,
+		.hd_align_mshift = DL1_HALIGN_SFT,
+		.pbuf_reg = AFE_DL1_CON0,
+		.pbuf_shift = DL1_PBUF_SIZE_SFT,
+		.minlen_reg = AFE_DL1_CON0,
+		.minlen_shift = DL1_MINLEN_SFT,
+	},
+	[MT8192_MEMIF_DL12] = {
+		.name = "DL12",
+		.id = MT8192_MEMIF_DL12,
+		.reg_ofs_base = AFE_DL12_BASE,
+		.reg_ofs_cur = AFE_DL12_CUR,
+		.reg_ofs_end = AFE_DL12_END,
+		.reg_ofs_base_msb = AFE_DL12_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DL12_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DL12_END_MSB,
+		.fs_reg = AFE_DL12_CON0,
+		.fs_shift = DL12_MODE_SFT,
+		.fs_maskbit = DL12_MODE_MASK,
+		.mono_reg = AFE_DL12_CON0,
+		.mono_shift = DL12_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL12_ON_SFT,
+		.hd_reg = AFE_DL12_CON0,
+		.hd_shift = DL12_HD_MODE_SFT,
+		.hd_align_reg = AFE_DL12_CON0,
+		.hd_align_mshift = DL12_HALIGN_SFT,
+		.pbuf_reg = AFE_DL12_CON0,
+		.pbuf_shift = DL12_PBUF_SIZE_SFT,
+		.minlen_reg = AFE_DL12_CON0,
+		.minlen_shift = DL12_MINLEN_SFT,
+	},
+	[MT8192_MEMIF_DL2] = {
+		.name = "DL2",
+		.id = MT8192_MEMIF_DL2,
+		.reg_ofs_base = AFE_DL2_BASE,
+		.reg_ofs_cur = AFE_DL2_CUR,
+		.reg_ofs_end = AFE_DL2_END,
+		.reg_ofs_base_msb = AFE_DL2_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DL2_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DL2_END_MSB,
+		.fs_reg = AFE_DL2_CON0,
+		.fs_shift = DL2_MODE_SFT,
+		.fs_maskbit = DL2_MODE_MASK,
+		.mono_reg = AFE_DL2_CON0,
+		.mono_shift = DL2_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL2_ON_SFT,
+		.hd_reg = AFE_DL2_CON0,
+		.hd_shift = DL2_HD_MODE_SFT,
+		.hd_align_reg = AFE_DL2_CON0,
+		.hd_align_mshift = DL2_HALIGN_SFT,
+		.pbuf_reg = AFE_DL2_CON0,
+		.pbuf_shift = DL2_PBUF_SIZE_SFT,
+		.minlen_reg = AFE_DL2_CON0,
+		.minlen_shift = DL2_MINLEN_SFT,
+	},
+	[MT8192_MEMIF_DL3] = {
+		.name = "DL3",
+		.id = MT8192_MEMIF_DL3,
+		.reg_ofs_base = AFE_DL3_BASE,
+		.reg_ofs_cur = AFE_DL3_CUR,
+		.reg_ofs_end = AFE_DL3_END,
+		.reg_ofs_base_msb = AFE_DL3_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DL3_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DL3_END_MSB,
+		.fs_reg = AFE_DL3_CON0,
+		.fs_shift = DL3_MODE_SFT,
+		.fs_maskbit = DL3_MODE_MASK,
+		.mono_reg = AFE_DL3_CON0,
+		.mono_shift = DL3_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL3_ON_SFT,
+		.hd_reg = AFE_DL3_CON0,
+		.hd_shift = DL3_HD_MODE_SFT,
+		.hd_align_reg = AFE_DL3_CON0,
+		.hd_align_mshift = DL3_HALIGN_SFT,
+		.pbuf_reg = AFE_DL3_CON0,
+		.pbuf_shift = DL3_PBUF_SIZE_SFT,
+		.minlen_reg = AFE_DL3_CON0,
+		.minlen_shift = DL3_MINLEN_SFT,
+	},
+	[MT8192_MEMIF_DL4] = {
+		.name = "DL4",
+		.id = MT8192_MEMIF_DL4,
+		.reg_ofs_base = AFE_DL4_BASE,
+		.reg_ofs_cur = AFE_DL4_CUR,
+		.reg_ofs_end = AFE_DL4_END,
+		.reg_ofs_base_msb = AFE_DL4_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DL4_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DL4_END_MSB,
+		.fs_reg = AFE_DL4_CON0,
+		.fs_shift = DL4_MODE_SFT,
+		.fs_maskbit = DL4_MODE_MASK,
+		.mono_reg = AFE_DL4_CON0,
+		.mono_shift = DL4_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL4_ON_SFT,
+		.hd_reg = AFE_DL4_CON0,
+		.hd_shift = DL4_HD_MODE_SFT,
+		.hd_align_reg = AFE_DL4_CON0,
+		.hd_align_mshift = DL4_HALIGN_SFT,
+		.pbuf_reg = AFE_DL4_CON0,
+		.pbuf_shift = DL4_PBUF_SIZE_SFT,
+		.minlen_reg = AFE_DL4_CON0,
+		.minlen_shift = DL4_MINLEN_SFT,
+	},
+	[MT8192_MEMIF_DL5] = {
+		.name = "DL5",
+		.id = MT8192_MEMIF_DL5,
+		.reg_ofs_base = AFE_DL5_BASE,
+		.reg_ofs_cur = AFE_DL5_CUR,
+		.reg_ofs_end = AFE_DL5_END,
+		.reg_ofs_base_msb = AFE_DL5_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DL5_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DL5_END_MSB,
+		.fs_reg = AFE_DL5_CON0,
+		.fs_shift = DL5_MODE_SFT,
+		.fs_maskbit = DL5_MODE_MASK,
+		.mono_reg = AFE_DL5_CON0,
+		.mono_shift = DL5_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL5_ON_SFT,
+		.hd_reg = AFE_DL5_CON0,
+		.hd_shift = DL5_HD_MODE_SFT,
+		.hd_align_reg = AFE_DL5_CON0,
+		.hd_align_mshift = DL5_HALIGN_SFT,
+		.pbuf_reg = AFE_DL5_CON0,
+		.pbuf_shift = DL5_PBUF_SIZE_SFT,
+		.minlen_reg = AFE_DL5_CON0,
+		.minlen_shift = DL5_MINLEN_SFT,
+	},
+	[MT8192_MEMIF_DL6] = {
+		.name = "DL6",
+		.id = MT8192_MEMIF_DL6,
+		.reg_ofs_base = AFE_DL6_BASE,
+		.reg_ofs_cur = AFE_DL6_CUR,
+		.reg_ofs_end = AFE_DL6_END,
+		.reg_ofs_base_msb = AFE_DL6_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DL6_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DL6_END_MSB,
+		.fs_reg = AFE_DL6_CON0,
+		.fs_shift = DL6_MODE_SFT,
+		.fs_maskbit = DL6_MODE_MASK,
+		.mono_reg = AFE_DL6_CON0,
+		.mono_shift = DL6_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL6_ON_SFT,
+		.hd_reg = AFE_DL6_CON0,
+		.hd_shift = DL6_HD_MODE_SFT,
+		.hd_align_reg = AFE_DL6_CON0,
+		.hd_align_mshift = DL6_HALIGN_SFT,
+		.pbuf_reg = AFE_DL6_CON0,
+		.pbuf_shift = DL6_PBUF_SIZE_SFT,
+		.minlen_reg = AFE_DL6_CON0,
+		.minlen_shift = DL6_MINLEN_SFT,
+	},
+	[MT8192_MEMIF_DL7] = {
+		.name = "DL7",
+		.id = MT8192_MEMIF_DL7,
+		.reg_ofs_base = AFE_DL7_BASE,
+		.reg_ofs_cur = AFE_DL7_CUR,
+		.reg_ofs_end = AFE_DL7_END,
+		.reg_ofs_base_msb = AFE_DL7_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DL7_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DL7_END_MSB,
+		.fs_reg = AFE_DL7_CON0,
+		.fs_shift = DL7_MODE_SFT,
+		.fs_maskbit = DL7_MODE_MASK,
+		.mono_reg = AFE_DL7_CON0,
+		.mono_shift = DL7_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL7_ON_SFT,
+		.hd_reg = AFE_DL7_CON0,
+		.hd_shift = DL7_HD_MODE_SFT,
+		.hd_align_reg = AFE_DL7_CON0,
+		.hd_align_mshift = DL7_HALIGN_SFT,
+		.pbuf_reg = AFE_DL7_CON0,
+		.pbuf_shift = DL7_PBUF_SIZE_SFT,
+		.minlen_reg = AFE_DL7_CON0,
+		.minlen_shift = DL7_MINLEN_SFT,
+	},
+	[MT8192_MEMIF_DL8] = {
+		.name = "DL8",
+		.id = MT8192_MEMIF_DL8,
+		.reg_ofs_base = AFE_DL8_BASE,
+		.reg_ofs_cur = AFE_DL8_CUR,
+		.reg_ofs_end = AFE_DL8_END,
+		.reg_ofs_base_msb = AFE_DL8_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DL8_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DL8_END_MSB,
+		.fs_reg = AFE_DL8_CON0,
+		.fs_shift = DL8_MODE_SFT,
+		.fs_maskbit = DL8_MODE_MASK,
+		.mono_reg = AFE_DL8_CON0,
+		.mono_shift = DL8_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL8_ON_SFT,
+		.hd_reg = AFE_DL8_CON0,
+		.hd_shift = DL8_HD_MODE_SFT,
+		.hd_align_reg = AFE_DL8_CON0,
+		.hd_align_mshift = DL8_HALIGN_SFT,
+		.pbuf_reg = AFE_DL8_CON0,
+		.pbuf_shift = DL8_PBUF_SIZE_SFT,
+		.minlen_reg = AFE_DL8_CON0,
+		.minlen_shift = DL8_MINLEN_SFT,
+	},
+	[MT8192_MEMIF_DL9] = {
+		.name = "DL9",
+		.id = MT8192_MEMIF_DL9,
+		.reg_ofs_base = AFE_DL9_BASE,
+		.reg_ofs_cur = AFE_DL9_CUR,
+		.reg_ofs_end = AFE_DL9_END,
+		.reg_ofs_base_msb = AFE_DL9_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DL9_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DL9_END_MSB,
+		.fs_reg = AFE_DL9_CON0,
+		.fs_shift = DL9_MODE_SFT,
+		.fs_maskbit = DL9_MODE_MASK,
+		.mono_reg = AFE_DL9_CON0,
+		.mono_shift = DL9_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL9_ON_SFT,
+		.hd_reg = AFE_DL9_CON0,
+		.hd_shift = DL9_HD_MODE_SFT,
+		.hd_align_reg = AFE_DL9_CON0,
+		.hd_align_mshift = DL9_HALIGN_SFT,
+		.pbuf_reg = AFE_DL9_CON0,
+		.pbuf_shift = DL9_PBUF_SIZE_SFT,
+		.minlen_reg = AFE_DL9_CON0,
+		.minlen_shift = DL9_MINLEN_SFT,
+	},
+	[MT8192_MEMIF_DAI] = {
+		.name = "DAI",
+		.id = MT8192_MEMIF_DAI,
+		.reg_ofs_base = AFE_DAI_BASE,
+		.reg_ofs_cur = AFE_DAI_CUR,
+		.reg_ofs_end = AFE_DAI_END,
+		.reg_ofs_base_msb = AFE_DAI_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DAI_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DAI_END_MSB,
+		.fs_reg = AFE_DAI_CON0,
+		.fs_shift = DAI_MODE_SFT,
+		.fs_maskbit = DAI_MODE_MASK,
+		.mono_reg = AFE_DAI_CON0,
+		.mono_shift = DAI_DUPLICATE_WR_SFT,
+		.mono_invert = 1,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DAI_ON_SFT,
+		.hd_reg = AFE_DAI_CON0,
+		.hd_shift = DAI_HD_MODE_SFT,
+		.hd_align_reg = AFE_DAI_CON0,
+		.hd_align_mshift = DAI_HALIGN_SFT,
+	},
+	[MT8192_MEMIF_MOD_DAI] = {
+		.name = "MOD_DAI",
+		.id = MT8192_MEMIF_MOD_DAI,
+		.reg_ofs_base = AFE_MOD_DAI_BASE,
+		.reg_ofs_cur = AFE_MOD_DAI_CUR,
+		.reg_ofs_end = AFE_MOD_DAI_END,
+		.reg_ofs_base_msb = AFE_MOD_DAI_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_MOD_DAI_CUR_MSB,
+		.reg_ofs_end_msb = AFE_MOD_DAI_END_MSB,
+		.fs_reg = AFE_MOD_DAI_CON0,
+		.fs_shift = MOD_DAI_MODE_SFT,
+		.fs_maskbit = MOD_DAI_MODE_MASK,
+		.mono_reg = AFE_MOD_DAI_CON0,
+		.mono_shift = MOD_DAI_DUPLICATE_WR_SFT,
+		.mono_invert = 1,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = MOD_DAI_ON_SFT,
+		.hd_reg = AFE_MOD_DAI_CON0,
+		.hd_shift = MOD_DAI_HD_MODE_SFT,
+		.hd_align_reg = AFE_MOD_DAI_CON0,
+		.hd_align_mshift = MOD_DAI_HALIGN_SFT,
+	},
+	[MT8192_MEMIF_DAI2] = {
+		.name = "DAI2",
+		.id = MT8192_MEMIF_DAI2,
+		.reg_ofs_base = AFE_DAI2_BASE,
+		.reg_ofs_cur = AFE_DAI2_CUR,
+		.reg_ofs_end = AFE_DAI2_END,
+		.reg_ofs_base_msb = AFE_DAI2_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DAI2_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DAI2_END_MSB,
+		.fs_reg = AFE_DAI2_CON0,
+		.fs_shift = DAI2_MODE_SFT,
+		.fs_maskbit = DAI2_MODE_MASK,
+		.mono_reg = AFE_DAI2_CON0,
+		.mono_shift = DAI2_DUPLICATE_WR_SFT,
+		.mono_invert = 1,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DAI2_ON_SFT,
+		.hd_reg = AFE_DAI2_CON0,
+		.hd_shift = DAI2_HD_MODE_SFT,
+		.hd_align_reg = AFE_DAI2_CON0,
+		.hd_align_mshift = DAI2_HALIGN_SFT,
+	},
+	[MT8192_MEMIF_VUL12] = {
+		.name = "VUL12",
+		.id = MT8192_MEMIF_VUL12,
+		.reg_ofs_base = AFE_VUL12_BASE,
+		.reg_ofs_cur = AFE_VUL12_CUR,
+		.reg_ofs_end = AFE_VUL12_END,
+		.reg_ofs_base_msb = AFE_VUL12_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_VUL12_CUR_MSB,
+		.reg_ofs_end_msb = AFE_VUL12_END_MSB,
+		.fs_reg = AFE_VUL12_CON0,
+		.fs_shift = VUL12_MODE_SFT,
+		.fs_maskbit = VUL12_MODE_MASK,
+		.mono_reg = AFE_VUL12_CON0,
+		.mono_shift = VUL12_MONO_SFT,
+		.quad_ch_reg = AFE_VUL12_CON0,
+		.quad_ch_shift = VUL12_4CH_EN_SFT,
+		.quad_ch_mask = VUL12_4CH_EN_MASK,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = VUL12_ON_SFT,
+		.hd_reg = AFE_VUL12_CON0,
+		.hd_shift = VUL12_HD_MODE_SFT,
+		.hd_align_reg = AFE_VUL12_CON0,
+		.hd_align_mshift = VUL12_HALIGN_SFT,
+	},
+	[MT8192_MEMIF_VUL2] = {
+		.name = "VUL2",
+		.id = MT8192_MEMIF_VUL2,
+		.reg_ofs_base = AFE_VUL2_BASE,
+		.reg_ofs_cur = AFE_VUL2_CUR,
+		.reg_ofs_end = AFE_VUL2_END,
+		.reg_ofs_base_msb = AFE_VUL2_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_VUL2_CUR_MSB,
+		.reg_ofs_end_msb = AFE_VUL2_END_MSB,
+		.fs_reg = AFE_VUL2_CON0,
+		.fs_shift = VUL2_MODE_SFT,
+		.fs_maskbit = VUL2_MODE_MASK,
+		.mono_reg = AFE_VUL2_CON0,
+		.mono_shift = VUL2_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = VUL2_ON_SFT,
+		.hd_reg = AFE_VUL2_CON0,
+		.hd_shift = VUL2_HD_MODE_SFT,
+		.hd_align_reg = AFE_VUL2_CON0,
+		.hd_align_mshift = VUL2_HALIGN_SFT,
+	},
+	[MT8192_MEMIF_AWB] = {
+		.name = "AWB",
+		.id = MT8192_MEMIF_AWB,
+		.reg_ofs_base = AFE_AWB_BASE,
+		.reg_ofs_cur = AFE_AWB_CUR,
+		.reg_ofs_end = AFE_AWB_END,
+		.reg_ofs_base_msb = AFE_AWB_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_AWB_CUR_MSB,
+		.reg_ofs_end_msb = AFE_AWB_END_MSB,
+		.fs_reg = AFE_AWB_CON0,
+		.fs_shift = AWB_MODE_SFT,
+		.fs_maskbit = AWB_MODE_MASK,
+		.mono_reg = AFE_AWB_CON0,
+		.mono_shift = AWB_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = AWB_ON_SFT,
+		.hd_reg = AFE_AWB_CON0,
+		.hd_shift = AWB_HD_MODE_SFT,
+		.hd_align_reg = AFE_AWB_CON0,
+		.hd_align_mshift = AWB_HALIGN_SFT,
+	},
+	[MT8192_MEMIF_AWB2] = {
+		.name = "AWB2",
+		.id = MT8192_MEMIF_AWB2,
+		.reg_ofs_base = AFE_AWB2_BASE,
+		.reg_ofs_cur = AFE_AWB2_CUR,
+		.reg_ofs_end = AFE_AWB2_END,
+		.reg_ofs_base_msb = AFE_AWB2_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_AWB2_CUR_MSB,
+		.reg_ofs_end_msb = AFE_AWB2_END_MSB,
+		.fs_reg = AFE_AWB2_CON0,
+		.fs_shift = AWB2_MODE_SFT,
+		.fs_maskbit = AWB2_MODE_MASK,
+		.mono_reg = AFE_AWB2_CON0,
+		.mono_shift = AWB2_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = AWB2_ON_SFT,
+		.hd_reg = AFE_AWB2_CON0,
+		.hd_shift = AWB2_HD_MODE_SFT,
+		.hd_align_reg = AFE_AWB2_CON0,
+		.hd_align_mshift = AWB2_HALIGN_SFT,
+	},
+	[MT8192_MEMIF_VUL3] = {
+		.name = "VUL3",
+		.id = MT8192_MEMIF_VUL3,
+		.reg_ofs_base = AFE_VUL3_BASE,
+		.reg_ofs_cur = AFE_VUL3_CUR,
+		.reg_ofs_end = AFE_VUL3_END,
+		.reg_ofs_base_msb = AFE_VUL3_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_VUL3_CUR_MSB,
+		.reg_ofs_end_msb = AFE_VUL3_END_MSB,
+		.fs_reg = AFE_VUL3_CON0,
+		.fs_shift = VUL3_MODE_SFT,
+		.fs_maskbit = VUL3_MODE_MASK,
+		.mono_reg = AFE_VUL3_CON0,
+		.mono_shift = VUL3_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = VUL3_ON_SFT,
+		.hd_reg = AFE_VUL3_CON0,
+		.hd_shift = VUL3_HD_MODE_SFT,
+		.hd_align_reg = AFE_VUL3_CON0,
+		.hd_align_mshift = VUL3_HALIGN_SFT,
+	},
+	[MT8192_MEMIF_VUL4] = {
+		.name = "VUL4",
+		.id = MT8192_MEMIF_VUL4,
+		.reg_ofs_base = AFE_VUL4_BASE,
+		.reg_ofs_cur = AFE_VUL4_CUR,
+		.reg_ofs_end = AFE_VUL4_END,
+		.reg_ofs_base_msb = AFE_VUL4_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_VUL4_CUR_MSB,
+		.reg_ofs_end_msb = AFE_VUL4_END_MSB,
+		.fs_reg = AFE_VUL4_CON0,
+		.fs_shift = VUL4_MODE_SFT,
+		.fs_maskbit = VUL4_MODE_MASK,
+		.mono_reg = AFE_VUL4_CON0,
+		.mono_shift = VUL4_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = VUL4_ON_SFT,
+		.hd_reg = AFE_VUL4_CON0,
+		.hd_shift = VUL4_HD_MODE_SFT,
+		.hd_align_reg = AFE_VUL4_CON0,
+		.hd_align_mshift = VUL4_HALIGN_SFT,
+	},
+	[MT8192_MEMIF_VUL5] = {
+		.name = "VUL5",
+		.id = MT8192_MEMIF_VUL5,
+		.reg_ofs_base = AFE_VUL5_BASE,
+		.reg_ofs_cur = AFE_VUL5_CUR,
+		.reg_ofs_end = AFE_VUL5_END,
+		.reg_ofs_base_msb = AFE_VUL5_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_VUL5_CUR_MSB,
+		.reg_ofs_end_msb = AFE_VUL5_END_MSB,
+		.fs_reg = AFE_VUL5_CON0,
+		.fs_shift = VUL5_MODE_SFT,
+		.fs_maskbit = VUL5_MODE_MASK,
+		.mono_reg = AFE_VUL5_CON0,
+		.mono_shift = VUL5_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = VUL5_ON_SFT,
+		.hd_reg = AFE_VUL5_CON0,
+		.hd_shift = VUL5_HD_MODE_SFT,
+		.hd_align_reg = AFE_VUL5_CON0,
+		.hd_align_mshift = VUL5_HALIGN_SFT,
+	},
+	[MT8192_MEMIF_VUL6] = {
+		.name = "VUL6",
+		.id = MT8192_MEMIF_VUL6,
+		.reg_ofs_base = AFE_VUL6_BASE,
+		.reg_ofs_cur = AFE_VUL6_CUR,
+		.reg_ofs_end = AFE_VUL6_END,
+		.reg_ofs_base_msb = AFE_VUL6_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_VUL6_CUR_MSB,
+		.reg_ofs_end_msb = AFE_VUL6_END_MSB,
+		.fs_reg = AFE_VUL6_CON0,
+		.fs_shift = VUL6_MODE_SFT,
+		.fs_maskbit = VUL6_MODE_MASK,
+		.mono_reg = AFE_VUL6_CON0,
+		.mono_shift = VUL6_MONO_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = VUL6_ON_SFT,
+		.hd_reg = AFE_VUL6_CON0,
+		.hd_shift = VUL6_HD_MODE_SFT,
+		.hd_align_reg = AFE_VUL6_CON0,
+		.hd_align_mshift = VUL6_HALIGN_SFT,
+	},
+	[MT8192_MEMIF_HDMI] = {
+		.name = "HDMI",
+		.id = MT8192_MEMIF_HDMI,
+		.reg_ofs_base = AFE_HDMI_OUT_BASE,
+		.reg_ofs_cur = AFE_HDMI_OUT_CUR,
+		.reg_ofs_end = AFE_HDMI_OUT_END,
+		.reg_ofs_base_msb = AFE_HDMI_OUT_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_HDMI_OUT_CUR_MSB,
+		.reg_ofs_end_msb = AFE_HDMI_OUT_END_MSB,
+		.fs_reg = -1,
+		.fs_shift = -1,
+		.fs_maskbit = -1,
+		.mono_reg = -1,
+		.mono_shift = -1,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = HDMI_OUT_ON_SFT,
+		.hd_reg = AFE_HDMI_OUT_CON0,
+		.hd_shift = HDMI_OUT_HD_MODE_SFT,
+		.hd_align_reg = AFE_HDMI_OUT_CON0,
+		.hd_align_mshift = HDMI_OUT_HALIGN_SFT,
+		.pbuf_reg = AFE_HDMI_OUT_CON0,
+		.minlen_reg = AFE_HDMI_OUT_CON0,
+		.minlen_shift = HDMI_OUT_MINLEN_SFT,
+	},
+};
+
+static const struct mtk_base_irq_data irq_data[MT8192_IRQ_NUM] = {
+	[MT8192_IRQ_0] = {
+		.id = MT8192_IRQ_0,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT0,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.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,
+	},
+	[MT8192_IRQ_1] = {
+		.id = MT8192_IRQ_1,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT1,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.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,
+	},
+	[MT8192_IRQ_2] = {
+		.id = MT8192_IRQ_2,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT2,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.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,
+	},
+	[MT8192_IRQ_3] = {
+		.id = MT8192_IRQ_3,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT3,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.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,
+	},
+	[MT8192_IRQ_4] = {
+		.id = MT8192_IRQ_4,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT4,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.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,
+	},
+	[MT8192_IRQ_5] = {
+		.id = MT8192_IRQ_5,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT5,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.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,
+	},
+	[MT8192_IRQ_6] = {
+		.id = MT8192_IRQ_6,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT6,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.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,
+	},
+	[MT8192_IRQ_7] = {
+		.id = MT8192_IRQ_7,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT7,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.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,
+	},
+	[MT8192_IRQ_8] = {
+		.id = MT8192_IRQ_8,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT8,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON2,
+		.irq_fs_shift = IRQ8_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ8_MCU_MODE_MASK,
+		.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,
+	},
+	[MT8192_IRQ_9] = {
+		.id = MT8192_IRQ_9,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT9,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON2,
+		.irq_fs_shift = IRQ9_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ9_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ9_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ9_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_10] = {
+		.id = MT8192_IRQ_10,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT10,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON2,
+		.irq_fs_shift = IRQ10_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ10_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ10_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ10_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_11] = {
+		.id = MT8192_IRQ_11,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT11,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.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,
+	},
+	[MT8192_IRQ_12] = {
+		.id = MT8192_IRQ_12,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT12,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.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,
+	},
+	[MT8192_IRQ_13] = {
+		.id = MT8192_IRQ_13,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT13,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON2,
+		.irq_fs_shift = IRQ13_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ13_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ13_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ13_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_14] = {
+		.id = MT8192_IRQ_14,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT14,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON2,
+		.irq_fs_shift = IRQ14_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ14_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ14_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ14_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_15] = {
+		.id = MT8192_IRQ_15,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT15,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON2,
+		.irq_fs_shift = IRQ15_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ15_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ15_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ15_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_16] = {
+		.id = MT8192_IRQ_16,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT16,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON3,
+		.irq_fs_shift = IRQ16_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ16_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ16_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ16_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_17] = {
+		.id = MT8192_IRQ_17,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT17,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON3,
+		.irq_fs_shift = IRQ17_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ17_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ17_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ17_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_18] = {
+		.id = MT8192_IRQ_18,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT18,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON3,
+		.irq_fs_shift = IRQ18_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ18_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ18_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ18_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_19] = {
+		.id = MT8192_IRQ_19,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT19,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON3,
+		.irq_fs_shift = IRQ19_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ19_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ19_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ19_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_20] = {
+		.id = MT8192_IRQ_20,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT20,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON3,
+		.irq_fs_shift = IRQ20_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ20_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ20_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ20_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_21] = {
+		.id = MT8192_IRQ_21,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT21,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON3,
+		.irq_fs_shift = IRQ21_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ21_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ21_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ21_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_22] = {
+		.id = MT8192_IRQ_22,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT22,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON3,
+		.irq_fs_shift = IRQ22_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ22_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ22_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ22_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_23] = {
+		.id = MT8192_IRQ_23,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT23,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON3,
+		.irq_fs_shift = IRQ23_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ23_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ23_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ23_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_24] = {
+		.id = MT8192_IRQ_24,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT24,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON4,
+		.irq_fs_shift = IRQ24_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ24_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ24_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ24_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_25] = {
+		.id = MT8192_IRQ_25,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT25,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON4,
+		.irq_fs_shift = IRQ25_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ25_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ25_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ25_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_26] = {
+		.id = MT8192_IRQ_26,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT26,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON4,
+		.irq_fs_shift = IRQ26_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ26_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ26_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ26_MCU_CLR_SFT,
+	},
+	[MT8192_IRQ_31] = {
+		.id = MT8192_IRQ_31,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT31,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = -1,
+		.irq_fs_shift = -1,
+		.irq_fs_maskbit = -1,
+		.irq_en_reg = AFE_IRQ_MCU_CON0,
+		.irq_en_shift = IRQ31_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ31_MCU_CLR_SFT,
+	},
+};
+
+static const int memif_irq_usage[MT8192_MEMIF_NUM] = {
+	[MT8192_MEMIF_DL1] = MT8192_IRQ_0,
+	[MT8192_MEMIF_DL2] = MT8192_IRQ_1,
+	[MT8192_MEMIF_DL3] = MT8192_IRQ_2,
+	[MT8192_MEMIF_DL4] = MT8192_IRQ_3,
+	[MT8192_MEMIF_DL5] = MT8192_IRQ_4,
+	[MT8192_MEMIF_DL6] = MT8192_IRQ_5,
+	[MT8192_MEMIF_DL7] = MT8192_IRQ_6,
+	[MT8192_MEMIF_DL8] = MT8192_IRQ_7,
+	[MT8192_MEMIF_DL9] = MT8192_IRQ_8,
+	[MT8192_MEMIF_DL12] = MT8192_IRQ_9,
+	[MT8192_MEMIF_DAI] = MT8192_IRQ_10,
+	[MT8192_MEMIF_MOD_DAI] = MT8192_IRQ_11,
+	[MT8192_MEMIF_DAI2] = MT8192_IRQ_12,
+	[MT8192_MEMIF_VUL12] = MT8192_IRQ_13,
+	[MT8192_MEMIF_VUL2] = MT8192_IRQ_14,
+	[MT8192_MEMIF_AWB] = MT8192_IRQ_15,
+	[MT8192_MEMIF_AWB2] = MT8192_IRQ_16,
+	[MT8192_MEMIF_VUL3] = MT8192_IRQ_17,
+	[MT8192_MEMIF_VUL4] = MT8192_IRQ_18,
+	[MT8192_MEMIF_VUL5] = MT8192_IRQ_19,
+	[MT8192_MEMIF_VUL6] = MT8192_IRQ_20,
+	[MT8192_MEMIF_HDMI] = MT8192_IRQ_31,
+};
+
+static bool mt8192_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_CON2:
+	case AUDIO_TOP_CON3:
+	case AFE_DL1_CUR_MSB:
+	case AFE_DL1_CUR:
+	case AFE_DL1_END:
+	case AFE_DL2_CUR_MSB:
+	case AFE_DL2_CUR:
+	case AFE_DL2_END:
+	case AFE_DL3_CUR_MSB:
+	case AFE_DL3_CUR:
+	case AFE_DL3_END:
+	case AFE_DL4_CUR_MSB:
+	case AFE_DL4_CUR:
+	case AFE_DL4_END:
+	case AFE_DL12_CUR_MSB:
+	case AFE_DL12_CUR:
+	case AFE_DL12_END:
+	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_SECURE_CON0:
+	case AFE_SRAM_BOUND:
+	case AFE_SECURE_CON1:
+	case AFE_VUL_CUR_MSB:
+	case AFE_VUL_CUR:
+	case AFE_VUL_END:
+	case AFE_ADDA_3RD_DAC_DL_SDM_FIFO_MON:
+	case AFE_ADDA_3RD_DAC_DL_SRC_LCH_MON:
+	case AFE_ADDA_3RD_DAC_DL_SRC_RCH_MON:
+	case AFE_ADDA_3RD_DAC_DL_SDM_OUT_MON:
+	case AFE_SIDETONE_MON:
+	case AFE_SIDETONE_CON0:
+	case AFE_SIDETONE_COEFF:
+	case AFE_VUL2_CUR_MSB:
+	case AFE_VUL2_CUR:
+	case AFE_VUL2_END:
+	case AFE_VUL3_CUR_MSB:
+	case AFE_VUL3_CUR:
+	case AFE_VUL3_END:
+	case AFE_I2S_MON:
+	case AFE_DAC_MON:
+	case AFE_IRQ0_MCU_CNT_MON:
+	case AFE_IRQ6_MCU_CNT_MON:
+	case AFE_VUL4_CUR_MSB:
+	case AFE_VUL4_CUR:
+	case AFE_VUL4_END:
+	case AFE_VUL12_CUR_MSB:
+	case AFE_VUL12_CUR:
+	case AFE_VUL12_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_IRQ5_MCU_CNT_MON:
+	case AFE_IRQ7_MCU_CNT_MON:
+	case AFE_IRQ_MCU_MISS_CLR:
+	case AFE_GAIN1_CUR:
+	case AFE_GAIN2_CUR:
+	case AFE_SRAM_DELSEL_CON1:
+	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_IRQ9_MCU_CNT_MON:
+	case AFE_IRQ10_MCU_CNT_MON:
+	case AFE_IRQ13_MCU_CNT_MON:
+	case AFE_IRQ14_MCU_CNT_MON:
+	case AFE_IRQ15_MCU_CNT_MON:
+	case AFE_IRQ16_MCU_CNT_MON:
+	case AFE_IRQ17_MCU_CNT_MON:
+	case AFE_IRQ18_MCU_CNT_MON:
+	case AFE_IRQ19_MCU_CNT_MON:
+	case AFE_IRQ20_MCU_CNT_MON:
+	case AFE_IRQ21_MCU_CNT_MON:
+	case AFE_IRQ22_MCU_CNT_MON:
+	case AFE_IRQ23_MCU_CNT_MON:
+	case AFE_IRQ24_MCU_CNT_MON:
+	case AFE_IRQ25_MCU_CNT_MON:
+	case AFE_IRQ26_MCU_CNT_MON:
+	case AFE_IRQ31_MCU_CNT_MON:
+	case AFE_CBIP_MON0:
+	case AFE_CBIP_SLV_MUX_MON0:
+	case AFE_CBIP_SLV_DECODER_MON0:
+	case AFE_ADDA6_MTKAIF_MON0:
+	case AFE_ADDA6_MTKAIF_MON1:
+	case AFE_AWB_CUR_MSB:
+	case AFE_AWB_CUR:
+	case AFE_AWB_END:
+	case AFE_AWB2_CUR_MSB:
+	case AFE_AWB2_CUR:
+	case AFE_AWB2_END:
+	case AFE_DAI_CUR_MSB:
+	case AFE_DAI_CUR:
+	case AFE_DAI_END:
+	case AFE_DAI2_CUR_MSB:
+	case AFE_DAI2_CUR:
+	case AFE_DAI2_END:
+	case AFE_ADDA6_SRC_DEBUG_MON0:
+	case AFE_ADD6A_UL_SRC_MON0:
+	case AFE_ADDA6_UL_SRC_MON1:
+	case AFE_MOD_DAI_CUR_MSB:
+	case AFE_MOD_DAI_CUR:
+	case AFE_MOD_DAI_END:
+	case AFE_HDMI_OUT_CUR_MSB:
+	case AFE_HDMI_OUT_CUR:
+	case AFE_HDMI_OUT_END:
+	case AFE_AWB_RCH_MON:
+	case AFE_AWB_LCH_MON:
+	case AFE_VUL_RCH_MON:
+	case AFE_VUL_LCH_MON:
+	case AFE_VUL12_RCH_MON:
+	case AFE_VUL12_LCH_MON:
+	case AFE_VUL2_RCH_MON:
+	case AFE_VUL2_LCH_MON:
+	case AFE_DAI_DATA_MON:
+	case AFE_MOD_DAI_DATA_MON:
+	case AFE_DAI2_DATA_MON:
+	case AFE_AWB2_RCH_MON:
+	case AFE_AWB2_LCH_MON:
+	case AFE_VUL3_RCH_MON:
+	case AFE_VUL3_LCH_MON:
+	case AFE_VUL4_RCH_MON:
+	case AFE_VUL4_LCH_MON:
+	case AFE_VUL5_RCH_MON:
+	case AFE_VUL5_LCH_MON:
+	case AFE_VUL6_RCH_MON:
+	case AFE_VUL6_LCH_MON:
+	case AFE_DL1_RCH_MON:
+	case AFE_DL1_LCH_MON:
+	case AFE_DL2_RCH_MON:
+	case AFE_DL2_LCH_MON:
+	case AFE_DL12_RCH1_MON:
+	case AFE_DL12_LCH1_MON:
+	case AFE_DL12_RCH2_MON:
+	case AFE_DL12_LCH2_MON:
+	case AFE_DL3_RCH_MON:
+	case AFE_DL3_LCH_MON:
+	case AFE_DL4_RCH_MON:
+	case AFE_DL4_LCH_MON:
+	case AFE_DL5_RCH_MON:
+	case AFE_DL5_LCH_MON:
+	case AFE_DL6_RCH_MON:
+	case AFE_DL6_LCH_MON:
+	case AFE_DL7_RCH_MON:
+	case AFE_DL7_LCH_MON:
+	case AFE_DL8_RCH_MON:
+	case AFE_DL8_LCH_MON:
+	case AFE_VUL5_CUR_MSB:
+	case AFE_VUL5_CUR:
+	case AFE_VUL5_END:
+	case AFE_VUL6_CUR_MSB:
+	case AFE_VUL6_CUR:
+	case AFE_VUL6_END:
+	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_ASRC_2CH_CON12:
+	case AFE_ASRC_2CH_CON13:
+	case AFE_DL9_CUR_MSB:
+	case AFE_DL9_CUR:
+	case AFE_DL9_END:
+	case AFE_ADDA_MTKAIF_MON0:
+	case AFE_ADDA_MTKAIF_MON1:
+	case AFE_DL_NLE_R_MON0:
+	case AFE_DL_NLE_R_MON1:
+	case AFE_DL_NLE_R_MON2:
+	case AFE_DL_NLE_L_MON0:
+	case AFE_DL_NLE_L_MON1:
+	case AFE_DL_NLE_L_MON2:
+	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:
+	case AFE_DL9_RCH_MON:
+	case AFE_DL9_LCH_MON:
+	case AFE_DL5_CUR_MSB:
+	case AFE_DL5_CUR:
+	case AFE_DL5_END:
+	case AFE_DL6_CUR_MSB:
+	case AFE_DL6_CUR:
+	case AFE_DL6_END:
+	case AFE_DL7_CUR_MSB:
+	case AFE_DL7_CUR:
+	case AFE_DL7_END:
+	case AFE_DL8_CUR_MSB:
+	case AFE_DL8_CUR:
+	case AFE_DL8_END:
+	case AFE_PROT_SIDEBAND_MON:
+	case AFE_DOMAIN_SIDEBAND0_MON:
+	case AFE_DOMAIN_SIDEBAND1_MON:
+	case AFE_DOMAIN_SIDEBAND2_MON:
+	case AFE_DOMAIN_SIDEBAND3_MON:
+	case AFE_APLL1_TUNER_CFG:	/* [20:31] is monitor */
+	case AFE_APLL2_TUNER_CFG:	/* [20:31] is monitor */
+	case AFE_DAC_CON0:
+	case AFE_IRQ_MCU_CON0:
+	case AFE_IRQ_MCU_EN:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config mt8192_afe_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.volatile_reg = mt8192_is_volatile_reg,
+	.max_register = AFE_MAX_REGISTER,
+	.num_reg_defaults_raw = AFE_MAX_REGISTER,
+	.cache_type = REGCACHE_FLAT,
+};
+
+static irqreturn_t mt8192_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;
+
+	/* 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);
+
+		goto err_irq;
+	}
+
+	for (i = 0; i < MT8192_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_HANDLED;
+}
+
+static int mt8192_afe_runtime_suspend(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	unsigned int value;
+	int ret;
+
+	dev_info(afe->dev, "%s()\n", __func__);
+
+	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 */
+	regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, 0xffffffff);
+	regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, 0xffffffff);
+
+	/* reset sgen */
+	regmap_write(afe->regmap, AFE_SINEGEN_CON0, 0x0);
+	regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2,
+			   INNER_LOOP_BACK_MODE_MASK_SFT,
+			   0x3f << INNER_LOOP_BACK_MODE_SFT);
+
+	/* cache only */
+	regcache_cache_only(afe->regmap, true);
+	regcache_mark_dirty(afe->regmap);
+
+skip_regmap:
+	mt8192_afe_disable_clock(afe);
+	return 0;
+}
+
+static int mt8192_afe_runtime_resume(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	dev_info(afe->dev, "%s()\n", __func__);
+
+	ret = mt8192_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_priv->infracfg,
+			   PERI_BUS_DCM_CTRL, 0x1 << 29, 0x1 << 29);
+	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_CON0,
+			   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, AFE_ON_MASK_SFT, 0x1);
+
+skip_regmap:
+	return 0;
+}
+
+static int mt8192_afe_component_probe(struct snd_soc_component *component)
+{
+	return mtk_afe_add_sub_dai_control(component);
+}
+
+static const struct snd_soc_component_driver mt8192_afe_component = {
+	.name = AFE_PCM_NAME,
+	.probe = mt8192_afe_component_probe,
+	.pointer = mtk_afe_pcm_pointer,
+	.pcm_construct = mtk_afe_pcm_new,
+};
+
+static const struct snd_soc_component_driver mt8192_afe_pcm_component = {
+	.name = "mt8192-afe-pcm-dai",
+};
+
+static int mt8192_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 = mt8192_memif_dai_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mt8192_memif_dai_driver);
+
+	dai->dapm_widgets = mt8192_memif_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mt8192_memif_widgets);
+	dai->dapm_routes = mt8192_memif_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mt8192_memif_routes);
+	return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+	mt8192_dai_adda_register,
+	mt8192_dai_i2s_register,
+	mt8192_dai_pcm_register,
+	mt8192_dai_tdm_register,
+	mt8192_dai_memif_register,
+};
+
+static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+	struct mtk_base_afe *afe;
+	struct mt8192_afe_private *afe_priv;
+	struct device *dev;
+	struct reset_control *rstc;
+	int i, ret, irq_id;
+
+	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
+	if (ret)
+		return ret;
+
+	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+	if (!afe)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, afe);
+
+	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+					  GFP_KERNEL);
+	if (!afe->platform_priv)
+		return -ENOMEM;
+	afe_priv = afe->platform_priv;
+
+	afe->dev = &pdev->dev;
+	dev = afe->dev;
+
+	/* init audio related clock */
+	ret = mt8192_init_clock(afe);
+	if (ret) {
+		dev_err(dev, "init clock error\n");
+		return ret;
+	}
+
+	/* reset controller to reset audio regs before regmap cache */
+	rstc = devm_reset_control_get_exclusive(dev, "audiosys");
+	if (IS_ERR(rstc)) {
+		ret = PTR_ERR(rstc);
+		dev_err(dev, "could not get audiosys reset:%d\n", ret);
+		return ret;
+	}
+
+	ret = reset_control_reset(rstc);
+	if (ret) {
+		dev_err(dev, "failed to trigger audio reset:%d\n", ret);
+		return ret;
+	}
+
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev))
+		goto err_pm_disable;
+
+	/* 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");
+		return PTR_ERR(afe->regmap);
+	}
+	ret = regmap_attach_dev(dev, afe->regmap, &mt8192_afe_regmap_config);
+	if (ret) {
+		dev_warn(dev, "regmap_attach_dev fail, ret %d\n", ret);
+		return ret;
+	}
+
+	/* 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, &mt8192_afe_regmap_config);
+	if (ret) {
+		dev_err(dev, "regmap_reinit_cache fail, ret %d\n", ret);
+		return ret;
+	}
+
+	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 = MT8192_MEMIF_NUM;
+	afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+				  GFP_KERNEL);
+	if (!afe->memif)
+		return -ENOMEM;
+
+	for (i = 0; i < afe->memif_size; i++) {
+		afe->memif[i].data = &memif_data[i];
+		afe->memif[i].irq_usage = memif_irq_usage[i];
+		afe->memif[i].const_irq = 1;
+	}
+
+	mutex_init(&afe->irq_alloc_lock);	/* needed when dynamic irq */
+
+	/* init irq */
+	afe->irqs_size = MT8192_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, mt8192_afe_irq_handler,
+			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+	if (ret) {
+		dev_err(dev, "could not request_irq for Afe_ISR_Handle\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);
+			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;
+	}
+
+	/* others */
+	afe->mtk_afe_hardware = &mt8192_afe_hardware;
+	afe->memif_fs = mt8192_memif_fs;
+	afe->irq_fs = mt8192_irq_fs;
+	afe->get_dai_fs = mt8192_get_dai_fs;
+	afe->get_memif_pbuf_size = mt8192_get_memif_pbuf_size;
+	afe->memif_32bit_supported = 1;
+
+	afe->runtime_resume = mt8192_afe_runtime_resume;
+	afe->runtime_suspend = mt8192_afe_runtime_suspend;
+
+	/* register platform */
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &mt8192_afe_component, NULL, 0);
+	if (ret) {
+		dev_warn(dev, "err_platform\n");
+		goto err_pm_disable;
+	}
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &mt8192_afe_pcm_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(&pdev->dev);
+
+	return ret;
+}
+
+static int mt8192_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+	struct mtk_base_afe *afe = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		mt8192_afe_runtime_suspend(&pdev->dev);
+
+	/* disable afe clock */
+	mt8192_afe_disable_clock(afe);
+	return 0;
+}
+
+static const struct of_device_id mt8192_afe_pcm_dt_match[] = {
+	{ .compatible = "mediatek,mt8192-audio", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mt8192_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt8192_afe_pm_ops = {
+	SET_RUNTIME_PM_OPS(mt8192_afe_runtime_suspend,
+			   mt8192_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt8192_afe_pcm_driver = {
+	.driver = {
+		   .name = "mt8192-audio",
+		   .of_match_table = mt8192_afe_pcm_dt_match,
+#ifdef CONFIG_PM
+		   .pm = &mt8192_afe_pm_ops,
+#endif
+	},
+	.probe = mt8192_afe_pcm_dev_probe,
+	.remove = mt8192_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt8192_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 8192");
+MODULE_AUTHOR("Shane Chien <shane.chien@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-adda.c b/sound/soc/mediatek/mt8192/mt8192-dai-adda.c
new file mode 100644
index 000000000000..f040dce85da5
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-dai-adda.c
@@ -0,0 +1,1471 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI ADDA Control
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/delay.h>
+#include <linux/regmap.h>
+
+#include "mt8192-afe-clk.h"
+#include "mt8192-afe-common.h"
+#include "mt8192-afe-gpio.h"
+#include "mt8192-interconnection.h"
+
+enum {
+	UL_IIR_SW = 0,
+	UL_IIR_5HZ,
+	UL_IIR_10HZ,
+	UL_IIR_25HZ,
+	UL_IIR_50HZ,
+	UL_IIR_75HZ,
+};
+
+enum {
+	AUDIO_SDM_LEVEL_MUTE = 0,
+	AUDIO_SDM_LEVEL_NORMAL = 0x1d,
+	/* if you change level normal */
+	/* you need to change formula of hp impedance and dc trim too */
+};
+
+enum {
+	AUDIO_SDM_2ND = 0,
+	AUDIO_SDM_3RD,
+};
+
+enum {
+	DELAY_DATA_MISO1 = 0,
+	DELAY_DATA_MISO2,
+};
+
+enum {
+	MTK_AFE_ADDA_DL_RATE_8K = 0,
+	MTK_AFE_ADDA_DL_RATE_11K = 1,
+	MTK_AFE_ADDA_DL_RATE_12K = 2,
+	MTK_AFE_ADDA_DL_RATE_16K = 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,
+};
+
+#define SDM_AUTO_RESET_THRESHOLD 0x190000
+
+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("DL12_CH1", AFE_CONN3, I_DL12_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("DL4_CH1", AFE_CONN3_1, I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN3_1, I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN3_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN3_1, I_DL8_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN3,
+				    I_ADDA_UL_CH3, 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("GAIN1_OUT_CH1", AFE_CONN3,
+				    I_GAIN1_OUT_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),
+	SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1", AFE_CONN3_1,
+				    I_SRC_1_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH1", AFE_CONN3_1,
+				    I_SRC_2_OUT_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("DL12_CH2", AFE_CONN4, I_DL12_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("DL4_CH2", AFE_CONN4_1, I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN4_1, I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN4_1, I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN4_1, I_DL8_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN4,
+				    I_ADDA_UL_CH3, 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("GAIN1_OUT_CH2", AFE_CONN4,
+				    I_GAIN1_OUT_CH2, 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),
+	SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2", AFE_CONN4_1,
+				    I_SRC_1_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH2", AFE_CONN4_1,
+				    I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch3_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN52, I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN52, I_DL12_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN52, I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN52, I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN52_1, I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN52_1, I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN52_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN52,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN52,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN52,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN52,
+				    I_GAIN1_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN52,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN52,
+				    I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch4_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN53, I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN53, I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN53, I_DL12_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN53, I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN53, I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN53, I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN53, I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN53_1, I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN53_1, I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN53_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN53,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN53,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN53,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN53,
+				    I_GAIN1_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN53,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN53,
+				    I_PCM_2_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN53,
+				    I_PCM_1_CAP_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN53,
+				    I_PCM_2_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_stf_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN19,
+				    I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_stf_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN20,
+				    I_ADDA_UL_CH2, 1, 0),
+};
+
+enum {
+	SUPPLY_SEQ_ADDA_AFE_ON,
+	SUPPLY_SEQ_ADDA_DL_ON,
+	SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+	SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+	SUPPLY_SEQ_ADDA6_MTKAIF_CFG,
+	SUPPLY_SEQ_ADDA_FIFO,
+	SUPPLY_SEQ_ADDA_AP_DMIC,
+	SUPPLY_SEQ_ADDA_UL_ON,
+};
+
+static int mtk_adda_ul_src_dmic(struct mtk_base_afe *afe, int id)
+{
+	unsigned int reg;
+
+	switch (id) {
+	case MT8192_DAI_ADDA:
+	case MT8192_DAI_AP_DMIC:
+		reg = AFE_ADDA_UL_SRC_CON0;
+		break;
+	case MT8192_DAI_ADDA_CH34:
+	case MT8192_DAI_AP_DMIC_CH34:
+		reg = AFE_ADDA6_UL_SRC_CON0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* dmic mode, 3.25M*/
+	regmap_update_bits(afe->regmap, reg,
+			   DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT,
+			   0x0);
+	regmap_update_bits(afe->regmap, reg,
+			   DMIC_LOW_POWER_MODE_CTL_MASK_SFT,
+			   0x0);
+
+	/* turn on dmic, ch1, ch2 */
+	regmap_update_bits(afe->regmap, reg,
+			   UL_SDM_3_LEVEL_CTL_MASK_SFT,
+			   0x1 << UL_SDM_3_LEVEL_CTL_SFT);
+	regmap_update_bits(afe->regmap, reg,
+			   UL_MODE_3P25M_CH1_CTL_MASK_SFT,
+			   0x1 << UL_MODE_3P25M_CH1_CTL_SFT);
+	regmap_update_bits(afe->regmap, reg,
+			   UL_MODE_3P25M_CH2_CTL_MASK_SFT,
+			   0x1 << UL_MODE_3P25M_CH2_CTL_SFT);
+	return 0;
+}
+
+static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol,
+			     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	int mtkaif_dmic = afe_priv->mtkaif_dmic;
+
+	dev_info(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n",
+		 __func__, w->name, event, mtkaif_dmic);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 1);
+
+		/* update setting to dmic */
+		if (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,
+					   MTKAIF_RXIF_VOICE_MODE_MASK_SFT,
+					   0x0);
+			mtk_adda_ul_src_dmic(afe, MT8192_DAI_ADDA);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+		usleep_range(125, 135);
+		mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 1);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_adda_ch34_ul_event(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol,
+				  int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	int mtkaif_dmic = afe_priv->mtkaif_dmic_ch34;
+	int mtkaif_adda6_only = afe_priv->mtkaif_adda6_only;
+
+	dev_info(afe->dev,
+		 "%s(), name %s, event 0x%x, mtkaif_dmic %d, mtkaif_adda6_only %d\n",
+		 __func__, w->name, event, mtkaif_dmic, mtkaif_adda6_only);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34,
+					1);
+
+		/* update setting to dmic */
+		if (mtkaif_dmic) {
+			/* mtkaif_rxif_data_mode = 1, dmic */
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA6_MTKAIF_RX_CFG0,
+					   0x1, 0x1);
+
+			/* dmic mode, 3.25M*/
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA6_MTKAIF_RX_CFG0,
+					   MTKAIF_RXIF_VOICE_MODE_MASK_SFT,
+					   0x0);
+			mtk_adda_ul_src_dmic(afe, MT8192_DAI_ADDA_CH34);
+		}
+
+		/* when using adda6 without adda enabled,
+		 * RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_SFT need to be set or
+		 * data cannot be received.
+		 */
+		if (mtkaif_adda6_only) {
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_MTKAIF_SYNCWORD_CFG,
+					   0x1 << 23, 0x1 << 23);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+		usleep_range(125, 135);
+		mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34,
+					1);
+
+		/* reset dmic */
+		afe_priv->mtkaif_dmic_ch34 = 0;
+
+		if (mtkaif_adda6_only) {
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_MTKAIF_SYNCWORD_CFG,
+					   0x1 << 23, 0x0 << 23);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol,
+				  int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2)
+			regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x38);
+		else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2)
+			regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x30);
+		else
+			regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x30);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	int delay_data;
+	int delay_cycle;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) {
+			/* set protocol 2 */
+			regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
+				     0x00010000);
+			regmap_write(afe->regmap, AFE_ADDA6_MTKAIF_CFG0,
+				     0x00010000);
+
+			if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0 &&
+			    (afe_priv->mtkaif_chosen_phase[0] < 0 ||
+			     afe_priv->mtkaif_chosen_phase[1] < 0)) {
+				dev_warn(afe->dev,
+					 "%s(), mtkaif_chosen_phase[0/1]:%d/%d\n",
+					 __func__,
+					 afe_priv->mtkaif_chosen_phase[0],
+					 afe_priv->mtkaif_chosen_phase[1]);
+				break;
+			} else if (strcmp(w->name, "ADDA6_MTKAIF_CFG") == 0 &&
+				   afe_priv->mtkaif_chosen_phase[2] < 0) {
+				dev_warn(afe->dev,
+					 "%s(), mtkaif_chosen_phase[2]:%d\n",
+					 __func__,
+					 afe_priv->mtkaif_chosen_phase[2]);
+				break;
+			}
+
+			/* mtkaif_rxif_clkinv_adc inverse for calibration */
+			regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
+					   MTKAIF_RXIF_CLKINV_ADC_MASK_SFT,
+					   0x1 << MTKAIF_RXIF_CLKINV_ADC_SFT);
+			regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIF_CFG0,
+					   MTKAIF_RXIF_CLKINV_ADC_MASK_SFT,
+					   0x1 << MTKAIF_RXIF_CLKINV_ADC_SFT);
+
+			/* set delay for ch12 */
+			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);
+
+			/* set delay between ch3 and ch2 */
+			if (afe_priv->mtkaif_phase_cycle[2] >=
+			    afe_priv->mtkaif_phase_cycle[1]) {
+				delay_data = DELAY_DATA_MISO1;	/* ch3 */
+				delay_cycle = afe_priv->mtkaif_phase_cycle[2] -
+					      afe_priv->mtkaif_phase_cycle[1];
+			} else {
+				delay_data = DELAY_DATA_MISO2;	/* ch2 */
+				delay_cycle = afe_priv->mtkaif_phase_cycle[1] -
+					      afe_priv->mtkaif_phase_cycle[2];
+			}
+
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA6_MTKAIF_RX_CFG2,
+					   MTKAIF_RXIF_DELAY_DATA_MASK_SFT,
+					   delay_data <<
+					   MTKAIF_RXIF_DELAY_DATA_SFT);
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA6_MTKAIF_RX_CFG2,
+					   MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT,
+					   delay_cycle <<
+					   MTKAIF_RXIF_DELAY_CYCLE_SFT);
+		} else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) {
+			regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
+				     0x00010000);
+			regmap_write(afe->regmap, AFE_ADDA6_MTKAIF_CFG0,
+				     0x00010000);
+		} else {
+			regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x0);
+			regmap_write(afe->regmap, AFE_ADDA6_MTKAIF_CFG0, 0x0);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol,
+			     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+	dev_info(afe->dev, "%s(), name %s, event 0x%x\n",
+		 __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+		usleep_range(125, 135);
+		mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 0);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_adda_ch34_dl_event(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol,
+				  int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+	dev_info(afe->dev, "%s(), name %s, event 0x%x\n",
+		 __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34,
+					0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+		usleep_range(125, 135);
+		mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34,
+					0);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/* stf */
+static int stf_positive_gain_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+	ucontrol->value.integer.value[0] = afe_priv->stf_positive_gain_db;
+	return 0;
+}
+
+static int stf_positive_gain_set(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	int gain_db = ucontrol->value.integer.value[0];
+
+	afe_priv->stf_positive_gain_db = gain_db;
+
+	if (gain_db >= 0 && gain_db <= 24) {
+		regmap_update_bits(afe->regmap,
+				   AFE_SIDETONE_GAIN,
+				   POSITIVE_GAIN_MASK_SFT,
+				   (gain_db / 6) << POSITIVE_GAIN_SFT);
+	} else {
+		dev_warn(afe->dev, "%s(), gain_db %d invalid\n",
+			 __func__, gain_db);
+	}
+	return 0;
+}
+
+static int mt8192_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 mt8192_afe_private *afe_priv = afe->platform_priv;
+
+	ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic;
+	return 0;
+}
+
+static int mt8192_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 mt8192_afe_private *afe_priv = afe->platform_priv;
+	int dmic_on;
+
+	dmic_on = ucontrol->value.integer.value[0];
+
+	dev_info(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n",
+		 __func__, kcontrol->id.name, dmic_on);
+
+	afe_priv->mtkaif_dmic = dmic_on;
+	afe_priv->mtkaif_dmic_ch34 = dmic_on;
+	return 0;
+}
+
+static int mt8192_adda6_only_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+	ucontrol->value.integer.value[0] = afe_priv->mtkaif_adda6_only;
+	return 0;
+}
+
+static int mt8192_adda6_only_set(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	int mtkaif_adda6_only;
+
+	mtkaif_adda6_only = ucontrol->value.integer.value[0];
+
+	dev_info(afe->dev, "%s(), kcontrol name %s, mtkaif_adda6_only %d\n",
+		 __func__, kcontrol->id.name, mtkaif_adda6_only);
+
+	afe_priv->mtkaif_adda6_only = mtkaif_adda6_only;
+	return 0;
+}
+
+static const struct snd_kcontrol_new mtk_adda_controls[] = {
+	SOC_SINGLE("Sidetone_Gain", AFE_SIDETONE_GAIN,
+		   SIDE_TONE_GAIN_SFT, SIDE_TONE_GAIN_MASK, 0),
+	SOC_SINGLE_EXT("Sidetone_Positive_Gain_dB", SND_SOC_NOPM, 0, 100, 0,
+		       stf_positive_gain_get, stf_positive_gain_set),
+	SOC_SINGLE("ADDA_DL_GAIN", AFE_ADDA_DL_SRC2_CON1,
+		   DL_2_GAIN_CTL_PRE_SFT, DL_2_GAIN_CTL_PRE_MASK, 0),
+	SOC_SINGLE_BOOL_EXT("MTKAIF_DMIC Switch", 0,
+			    mt8192_adda_dmic_get, mt8192_adda_dmic_set),
+	SOC_SINGLE_BOOL_EXT("MTKAIF_ADDA6_ONLY Switch", 0,
+			    mt8192_adda6_only_get, mt8192_adda6_only_set),
+};
+
+static const struct snd_kcontrol_new stf_ctl =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const u16 stf_coeff_table_16k[] = {
+	0x049C, 0x09E8, 0x09E0, 0x089C,
+	0xFF54, 0xF488, 0xEAFC, 0xEBAC,
+	0xfA40, 0x17AC, 0x3D1C, 0x6028,
+	0x7538
+};
+
+static const u16 stf_coeff_table_32k[] = {
+	0xFE52, 0x0042, 0x00C5, 0x0194,
+	0x029A, 0x03B7, 0x04BF, 0x057D,
+	0x05BE, 0x0555, 0x0426, 0x0230,
+	0xFF92, 0xFC89, 0xF973, 0xF6C6,
+	0xF500, 0xF49D, 0xF603, 0xF970,
+	0xFEF3, 0x065F, 0x0F4F, 0x1928,
+	0x2329, 0x2C80, 0x345E, 0x3A0D,
+	0x3D08
+};
+
+static const u16 stf_coeff_table_48k[] = {
+	0x0401, 0xFFB0, 0xFF5A, 0xFECE,
+	0xFE10, 0xFD28, 0xFC21, 0xFB08,
+	0xF9EF, 0xF8E8, 0xF80A, 0xF76C,
+	0xF724, 0xF746, 0xF7E6, 0xF90F,
+	0xFACC, 0xFD1E, 0xFFFF, 0x0364,
+	0x0737, 0x0B62, 0x0FC1, 0x1431,
+	0x188A, 0x1CA4, 0x2056, 0x237D,
+	0x25F9, 0x27B0, 0x2890
+};
+
+static int mtk_stf_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol,
+			 int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+	size_t half_tap_num;
+	const u16 *stf_coeff_table;
+	unsigned int ul_rate, reg_value;
+	size_t coef_addr;
+
+	regmap_read(afe->regmap, AFE_ADDA_UL_SRC_CON0, &ul_rate);
+	ul_rate = ul_rate >> UL_VOICE_MODE_CH1_CH2_CTL_SFT;
+	ul_rate = ul_rate & UL_VOICE_MODE_CH1_CH2_CTL_MASK;
+
+	if (ul_rate == MTK_AFE_ADDA_UL_RATE_48K) {
+		half_tap_num = ARRAY_SIZE(stf_coeff_table_48k);
+		stf_coeff_table = stf_coeff_table_48k;
+	} else if (ul_rate == MTK_AFE_ADDA_UL_RATE_32K) {
+		half_tap_num = ARRAY_SIZE(stf_coeff_table_32k);
+		stf_coeff_table = stf_coeff_table_32k;
+	} else {
+		half_tap_num = ARRAY_SIZE(stf_coeff_table_16k);
+		stf_coeff_table = stf_coeff_table_16k;
+	}
+
+	regmap_read(afe->regmap, AFE_SIDETONE_CON1, &reg_value);
+
+	dev_info(afe->dev, "%s(), name %s, event 0x%x, ul_rate 0x%x, AFE_SIDETONE_CON1 0x%x\n",
+		 __func__, w->name, event, ul_rate, reg_value);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* set side tone gain = 0 */
+		regmap_update_bits(afe->regmap,
+				   AFE_SIDETONE_GAIN,
+				   SIDE_TONE_GAIN_MASK_SFT,
+				   0);
+		regmap_update_bits(afe->regmap,
+				   AFE_SIDETONE_GAIN,
+				   POSITIVE_GAIN_MASK_SFT,
+				   0);
+		/* don't bypass stf */
+		regmap_update_bits(afe->regmap,
+				   AFE_SIDETONE_CON1,
+				   0x1f << 27,
+				   0x0);
+		/* set stf half tap num */
+		regmap_update_bits(afe->regmap,
+				   AFE_SIDETONE_CON1,
+				   SIDE_TONE_HALF_TAP_NUM_MASK_SFT,
+				   half_tap_num << SIDE_TONE_HALF_TAP_NUM_SFT);
+
+		/* set side tone coefficient */
+		regmap_read(afe->regmap, AFE_SIDETONE_CON0, &reg_value);
+		for (coef_addr = 0; coef_addr < half_tap_num; coef_addr++) {
+			bool old_w_ready = (reg_value >> W_RDY_SFT) & 0x1;
+			bool new_w_ready = 0;
+			int try_cnt = 0;
+
+			regmap_update_bits(afe->regmap,
+					   AFE_SIDETONE_CON0,
+					   0x39FFFFF,
+					   (1 << R_W_EN_SFT) |
+					   (1 << R_W_SEL_SFT) |
+					   (0 << SEL_CH2_SFT) |
+					   (coef_addr <<
+					   SIDE_TONE_COEFFICIENT_ADDR_SFT) |
+					   stf_coeff_table[coef_addr]);
+
+			/* wait until flag write_ready changed */
+			for (try_cnt = 0; try_cnt < 10; try_cnt++) {
+				regmap_read(afe->regmap,
+					    AFE_SIDETONE_CON0, &reg_value);
+				new_w_ready = (reg_value >> W_RDY_SFT) & 0x1;
+
+				/* flip => ok */
+				if (new_w_ready == old_w_ready) {
+					udelay(3);
+					if (try_cnt == 9) {
+						dev_warn(afe->dev,
+							 "%s(), write coeff not ready",
+							 __func__);
+					}
+				} else {
+					break;
+				}
+			}
+			/* need write -> read -> write to write next coeff */
+			regmap_update_bits(afe->regmap,
+					   AFE_SIDETONE_CON0,
+					   R_W_SEL_MASK_SFT,
+					   0x0);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* bypass stf */
+		regmap_update_bits(afe->regmap,
+				   AFE_SIDETONE_CON1,
+				   0x1f << 27,
+				   0x1f << 27);
+
+		/* set side tone gain = 0 */
+		regmap_update_bits(afe->regmap,
+				   AFE_SIDETONE_GAIN,
+				   SIDE_TONE_GAIN_MASK_SFT,
+				   0);
+		regmap_update_bits(afe->regmap,
+				   AFE_SIDETONE_GAIN,
+				   POSITIVE_GAIN_MASK_SFT,
+				   0);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/* stf mux */
+enum {
+	STF_SRC_ADDA_ADDA6 = 0,
+	STF_SRC_O19O20,
+};
+
+static const char *const stf_o19o20_mux_map[] = {
+	"ADDA_ADDA6",
+	"O19O20",
+};
+
+static int stf_o19o20_mux_map_value[] = {
+	STF_SRC_ADDA_ADDA6,
+	STF_SRC_O19O20,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(stf_o19o20_mux_map_enum,
+				  AFE_SIDETONE_CON1,
+				  STF_SOURCE_FROM_O19O20_SFT,
+				  STF_SOURCE_FROM_O19O20_MASK,
+				  stf_o19o20_mux_map,
+				  stf_o19o20_mux_map_value);
+
+static const struct snd_kcontrol_new stf_o19O20_mux_control =
+	SOC_DAPM_ENUM("STF_O19O20_MUX", stf_o19o20_mux_map_enum);
+
+enum {
+	STF_SRC_ADDA = 0,
+	STF_SRC_ADDA6,
+};
+
+static const char *const stf_adda_mux_map[] = {
+	"ADDA",
+	"ADDA6",
+};
+
+static int stf_adda_mux_map_value[] = {
+	STF_SRC_ADDA,
+	STF_SRC_ADDA6,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(stf_adda_mux_map_enum,
+				  AFE_SIDETONE_CON1,
+				  STF_O19O20_OUT_EN_SEL_SFT,
+				  STF_O19O20_OUT_EN_SEL_MASK,
+				  stf_adda_mux_map,
+				  stf_adda_mux_map_value);
+
+static const struct snd_kcontrol_new stf_adda_mux_control =
+	SOC_DAPM_ENUM("STF_ADDA_MUX", stf_adda_mux_map_enum);
+
+/* ADDA UL MUX */
+enum {
+	ADDA_UL_MUX_MTKAIF = 0,
+	ADDA_UL_MUX_AP_DMIC,
+	ADDA_UL_MUX_MASK = 0x1,
+};
+
+static const char * const adda_ul_mux_map[] = {
+	"MTKAIF", "AP_DMIC"
+};
+
+static int adda_ul_map_value[] = {
+	ADDA_UL_MUX_MTKAIF,
+	ADDA_UL_MUX_AP_DMIC,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum,
+				  SND_SOC_NOPM,
+				  0,
+				  ADDA_UL_MUX_MASK,
+				  adda_ul_mux_map,
+				  adda_ul_map_value);
+
+static const struct snd_kcontrol_new adda_ul_mux_control =
+	SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_kcontrol_new adda_ch34_ul_mux_control =
+	SOC_DAPM_ENUM("ADDA_CH34_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+	/* inter-connections */
+	SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_adda_dl_ch1_mix,
+			   ARRAY_SIZE(mtk_adda_dl_ch1_mix)),
+	SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_adda_dl_ch2_mix,
+			   ARRAY_SIZE(mtk_adda_dl_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("ADDA_DL_CH3", SND_SOC_NOPM, 0, 0,
+			   mtk_adda_dl_ch3_mix,
+			   ARRAY_SIZE(mtk_adda_dl_ch3_mix)),
+	SND_SOC_DAPM_MIXER("ADDA_DL_CH4", SND_SOC_NOPM, 0, 0,
+			   mtk_adda_dl_ch4_mix,
+			   ARRAY_SIZE(mtk_adda_dl_ch4_mix)),
+
+	SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
+			      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,
+			      mtk_adda_dl_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("ADDA CH34 Playback Enable",
+			      SUPPLY_SEQ_ADDA_DL_ON,
+			      AFE_ADDA_3RD_DAC_DL_SRC2_CON0,
+			      DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0,
+			      mtk_adda_ch34_dl_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+			      AFE_ADDA_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_SUPPLY_S("ADDA CH34 Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+			      AFE_ADDA6_UL_SRC_CON0,
+			      UL_SRC_ON_TMP_CTL_SFT, 0,
+			      mtk_adda_ch34_ul_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+			      AFE_AUD_PAD_TOP,
+			      RG_RX_FIFO_ON_SFT, 0,
+			      mtk_adda_pad_top_event,
+			      SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_adda_mtkaif_cfg_event,
+			      SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY_S("ADDA6_MTKAIF_CFG", SUPPLY_SEQ_ADDA6_MTKAIF_CFG,
+			      SND_SOC_NOPM, 0, 0,
+			      mtk_adda_mtkaif_cfg_event,
+			      SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+			      AFE_ADDA_UL_SRC_CON0,
+			      UL_AP_DMIC_ON_SFT, 0,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AP_DMIC_CH34_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+			      AFE_ADDA6_UL_SRC_CON0,
+			      UL_AP_DMIC_ON_SFT, 0,
+			      NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+			      AFE_ADDA_UL_DL_CON0,
+			      AFE_ADDA_FIFO_AUTO_RST_SFT, 1,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADDA_CH34_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+			      AFE_ADDA_UL_DL_CON0,
+			      AFE_ADDA6_FIFO_AUTO_RST_SFT, 1,
+			      NULL, 0),
+
+	SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0,
+			 &adda_ul_mux_control),
+	SND_SOC_DAPM_MUX("ADDA_CH34_UL_Mux", SND_SOC_NOPM, 0, 0,
+			 &adda_ch34_ul_mux_control),
+
+	SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"),
+	SND_SOC_DAPM_INPUT("AP_DMIC_CH34_INPUT"),
+
+	/* stf */
+	SND_SOC_DAPM_SWITCH_E("Sidetone Filter",
+			      AFE_SIDETONE_CON1, SIDE_TONE_ON_SFT, 0,
+			      &stf_ctl,
+			      mtk_stf_event,
+			      SND_SOC_DAPM_PRE_PMU |
+			      SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("STF_O19O20_MUX", SND_SOC_NOPM, 0, 0,
+			 &stf_o19O20_mux_control),
+	SND_SOC_DAPM_MUX("STF_ADDA_MUX", SND_SOC_NOPM, 0, 0,
+			 &stf_adda_mux_control),
+	SND_SOC_DAPM_MIXER("STF_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_stf_ch1_mix,
+			   ARRAY_SIZE(mtk_stf_ch1_mix)),
+	SND_SOC_DAPM_MIXER("STF_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_stf_ch2_mix,
+			   ARRAY_SIZE(mtk_stf_ch2_mix)),
+	SND_SOC_DAPM_OUTPUT("STF_OUTPUT"),
+
+	/* clock */
+	SND_SOC_DAPM_CLOCK_SUPPLY("top_mux_audio_h"),
+
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_clk"),
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_predis_clk"),
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_3rd_dac_clk"),
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_3rd_dac_predis_clk"),
+
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_clk"),
+	SND_SOC_DAPM_CLOCK_SUPPLY("aud_adda6_adc_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", "DL12_CH1", "DL12"},
+	{"ADDA_DL_CH2", "DL12_CH2", "DL12"},
+
+	{"ADDA_DL_CH1", "DL6_CH1", "DL6"},
+	{"ADDA_DL_CH2", "DL6_CH2", "DL6"},
+
+	{"ADDA_DL_CH1", "DL8_CH1", "DL8"},
+	{"ADDA_DL_CH2", "DL8_CH2", "DL8"},
+
+	{"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_DL_CH1", "DL4_CH1", "DL4"},
+	{"ADDA_DL_CH2", "DL4_CH2", "DL4"},
+
+	{"ADDA_DL_CH1", "DL5_CH1", "DL5"},
+	{"ADDA_DL_CH2", "DL5_CH2", "DL5"},
+
+	{"ADDA Playback", NULL, "ADDA_DL_CH1"},
+	{"ADDA Playback", NULL, "ADDA_DL_CH2"},
+
+	{"ADDA Playback", NULL, "ADDA Enable"},
+	{"ADDA Playback", NULL, "ADDA Playback Enable"},
+
+	{"ADDA_DL_CH3", "DL1_CH1", "DL1"},
+	{"ADDA_DL_CH4", "DL1_CH1", "DL1"},
+	{"ADDA_DL_CH4", "DL1_CH2", "DL1"},
+
+	{"ADDA_DL_CH3", "DL12_CH1", "DL12"},
+	{"ADDA_DL_CH4", "DL12_CH2", "DL12"},
+
+	{"ADDA_DL_CH3", "DL6_CH1", "DL6"},
+	{"ADDA_DL_CH4", "DL6_CH2", "DL6"},
+
+	{"ADDA_DL_CH3", "DL2_CH1", "DL2"},
+	{"ADDA_DL_CH4", "DL2_CH1", "DL2"},
+	{"ADDA_DL_CH4", "DL2_CH2", "DL2"},
+
+	{"ADDA_DL_CH3", "DL3_CH1", "DL3"},
+	{"ADDA_DL_CH4", "DL3_CH1", "DL3"},
+	{"ADDA_DL_CH4", "DL3_CH2", "DL3"},
+
+	{"ADDA_DL_CH3", "DL4_CH1", "DL4"},
+	{"ADDA_DL_CH4", "DL4_CH2", "DL4"},
+
+	{"ADDA_DL_CH3", "DL5_CH1", "DL5"},
+	{"ADDA_DL_CH4", "DL5_CH2", "DL5"},
+
+	{"ADDA CH34 Playback", NULL, "ADDA_DL_CH3"},
+	{"ADDA CH34 Playback", NULL, "ADDA_DL_CH4"},
+
+	{"ADDA CH34 Playback", NULL, "ADDA Enable"},
+	{"ADDA CH34 Playback", NULL, "ADDA CH34 Playback Enable"},
+
+	/* capture */
+	{"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"},
+	{"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"},
+
+	{"ADDA_CH34_UL_Mux", "MTKAIF", "ADDA CH34 Capture"},
+	{"ADDA_CH34_UL_Mux", "AP_DMIC", "AP DMIC CH34 Capture"},
+
+	{"ADDA Capture", NULL, "ADDA Enable"},
+	{"ADDA Capture", NULL, "ADDA Capture Enable"},
+	{"ADDA Capture", NULL, "AUD_PAD_TOP"},
+	{"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"},
+
+	{"AP DMIC Capture", NULL, "ADDA Enable"},
+	{"AP DMIC Capture", NULL, "ADDA Capture Enable"},
+	{"AP DMIC Capture", NULL, "ADDA_FIFO"},
+	{"AP DMIC Capture", NULL, "AP_DMIC_EN"},
+
+	{"ADDA CH34 Capture", NULL, "ADDA Enable"},
+	{"ADDA CH34 Capture", NULL, "ADDA CH34 Capture Enable"},
+	{"ADDA CH34 Capture", NULL, "AUD_PAD_TOP"},
+	{"ADDA CH34 Capture", NULL, "ADDA6_MTKAIF_CFG"},
+
+	{"AP DMIC CH34 Capture", NULL, "ADDA Enable"},
+	{"AP DMIC CH34 Capture", NULL, "ADDA CH34 Capture Enable"},
+	{"AP DMIC CH34 Capture", NULL, "ADDA_CH34_FIFO"},
+	{"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_EN"},
+
+	{"AP DMIC Capture", NULL, "AP_DMIC_INPUT"},
+	{"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_INPUT"},
+
+	/* sidetone filter */
+	{"STF_ADDA_MUX", "ADDA", "ADDA_UL_Mux"},
+	{"STF_ADDA_MUX", "ADDA6", "ADDA_CH34_UL_Mux"},
+
+	{"STF_O19O20_MUX", "ADDA_ADDA6", "STF_ADDA_MUX"},
+	{"STF_O19O20_MUX", "O19O20", "STF_CH1"},
+	{"STF_O19O20_MUX", "O19O20", "STF_CH2"},
+
+	{"Sidetone Filter", "Switch", "STF_O19O20_MUX"},
+	{"STF_OUTPUT", NULL, "Sidetone Filter"},
+	{"ADDA Playback", NULL, "Sidetone Filter"},
+	{"ADDA CH34 Playback", NULL, "Sidetone Filter"},
+
+	/* clk */
+	{"ADDA Playback", NULL, "aud_dac_clk"},
+	{"ADDA Playback", NULL, "aud_dac_predis_clk"},
+
+	{"ADDA CH34 Playback", NULL, "aud_3rd_dac_clk"},
+	{"ADDA CH34 Playback", NULL, "aud_3rd_dac_predis_clk"},
+
+	{"ADDA Capture Enable", NULL, "aud_adc_clk"},
+	{"ADDA CH34 Capture Enable", NULL, "aud_adda6_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);
+	int id = dai->id;
+
+	dev_info(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+		 __func__,
+		 id,
+		 substream->stream,
+		 rate);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		unsigned int dl_src2_con0 = 0;
+		unsigned int dl_src2_con1 = 0;
+
+		/* set sampling rate */
+		dl_src2_con0 = adda_dl_rate_transform(afe, rate) <<
+			       DL_2_INPUT_MODE_CTL_SFT;
+
+		/* set output mode, UP_SAMPLING_RATE_X8 */
+		dl_src2_con0 |= (0x3 << DL_2_OUTPUT_SEL_CTL_SFT);
+
+		/* turn off mute function */
+		dl_src2_con0 |= (0x01 << DL_2_MUTE_CH2_OFF_CTL_PRE_SFT);
+		dl_src2_con0 |= (0x01 << DL_2_MUTE_CH1_OFF_CTL_PRE_SFT);
+
+		/* set voice input data if input sample rate is 8k or 16k */
+		if (rate == 8000 || rate == 16000)
+			dl_src2_con0 |= 0x01 << DL_2_VOICE_MODE_CTL_PRE_SFT;
+
+		/* SA suggest apply -0.3db to audio/speech path */
+		dl_src2_con1 = MTK_AFE_ADDA_DL_GAIN_NORMAL <<
+			       DL_2_GAIN_CTL_PRE_SFT;
+
+		/* turn on down-link gain */
+		dl_src2_con0 |= (0x01 << DL_2_GAIN_ON_CTL_PRE_SFT);
+
+		if (id == MT8192_DAI_ADDA) {
+			/* clean predistortion */
+			regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0);
+			regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0);
+
+			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);
+
+			/* 2nd sdm */
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_DL_SDM_DCCOMP_CON,
+					   USE_3RD_SDM_MASK_SFT,
+					   AUDIO_SDM_2ND << USE_3RD_SDM_SFT);
+
+			/* sdm auto reset */
+			regmap_write(afe->regmap,
+				     AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+				     SDM_AUTO_RESET_THRESHOLD);
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+					   ADDA_SDM_AUTO_RESET_ONOFF_MASK_SFT,
+					   0x1 << ADDA_SDM_AUTO_RESET_ONOFF_SFT);
+		} else {
+			/* clean predistortion */
+			regmap_write(afe->regmap,
+				     AFE_ADDA_3RD_DAC_PREDIS_CON0, 0);
+			regmap_write(afe->regmap,
+				     AFE_ADDA_3RD_DAC_PREDIS_CON1, 0);
+
+			regmap_write(afe->regmap, AFE_ADDA_3RD_DAC_DL_SRC2_CON0,
+				     dl_src2_con0);
+			regmap_write(afe->regmap, AFE_ADDA_3RD_DAC_DL_SRC2_CON1,
+				     dl_src2_con1);
+
+			/* set sdm gain */
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_3RD_DAC_DL_SDM_DCCOMP_CON,
+					   ATTGAIN_CTL_MASK_SFT,
+					   AUDIO_SDM_LEVEL_NORMAL <<
+					   ATTGAIN_CTL_SFT);
+
+			/* 2nd sdm */
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_3RD_DAC_DL_SDM_DCCOMP_CON,
+					   USE_3RD_SDM_MASK_SFT,
+					   AUDIO_SDM_2ND << USE_3RD_SDM_SFT);
+
+			/* sdm auto reset */
+			regmap_write(afe->regmap,
+				     AFE_ADDA_3RD_DAC_DL_SDM_AUTO_RESET_CON,
+				     SDM_AUTO_RESET_THRESHOLD);
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_3RD_DAC_DL_SDM_AUTO_RESET_CON,
+					   ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_MASK_SFT,
+					   0x1 << ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_SFT);
+		}
+	} else {
+		unsigned int voice_mode = 0;
+		unsigned int ul_src_con0 = 0;	/* default value */
+
+		voice_mode = adda_ul_rate_transform(afe, rate);
+
+		ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
+
+		/* enable iir */
+		ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) &
+			       UL_IIR_ON_TMP_CTL_MASK_SFT;
+		ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) &
+			       UL_IIRMODE_CTL_MASK_SFT;
+
+		switch (id) {
+		case MT8192_DAI_ADDA:
+		case MT8192_DAI_AP_DMIC:
+			/* 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);
+
+			/* Using Internal ADC */
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_TOP_CON0,
+					   0x1 << 0,
+					   0x0 << 0);
+
+			/* mtkaif_rxif_data_mode = 0, amic */
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_MTKAIF_RX_CFG0,
+					   0x1 << 0,
+					   0x0 << 0);
+			break;
+		case MT8192_DAI_ADDA_CH34:
+		case MT8192_DAI_AP_DMIC_CH34:
+			/* 35Hz @ 48k */
+			regmap_write(afe->regmap,
+				     AFE_ADDA6_IIR_COEF_02_01, 0x00000000);
+			regmap_write(afe->regmap,
+				     AFE_ADDA6_IIR_COEF_04_03, 0x00003FB8);
+			regmap_write(afe->regmap,
+				     AFE_ADDA6_IIR_COEF_06_05, 0x3FB80000);
+			regmap_write(afe->regmap,
+				     AFE_ADDA6_IIR_COEF_08_07, 0x3FB80000);
+			regmap_write(afe->regmap,
+				     AFE_ADDA6_IIR_COEF_10_09, 0x0000C048);
+
+			regmap_write(afe->regmap,
+				     AFE_ADDA6_UL_SRC_CON0, ul_src_con0);
+
+			/* Using Internal ADC */
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA6_TOP_CON0,
+					   0x1 << 0,
+					   0x0 << 0);
+
+			/* mtkaif_rxif_data_mode = 0, amic */
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA6_MTKAIF_RX_CFG0,
+					   0x1 << 0,
+					   0x0 << 0);
+			break;
+		default:
+			break;
+		}
+
+		/* ap dmic */
+		switch (id) {
+		case MT8192_DAI_AP_DMIC:
+		case MT8192_DAI_AP_DMIC_CH34:
+			mtk_adda_ul_src_dmic(afe, id);
+			break;
+		default:
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_adda_ops = {
+	.hw_params = mtk_dai_adda_hw_params,
+};
+
+/* dai driver */
+#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\
+				 SNDRV_PCM_RATE_96000 |\
+				 SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+				SNDRV_PCM_RATE_16000 |\
+				SNDRV_PCM_RATE_32000 |\
+				SNDRV_PCM_RATE_48000 |\
+				SNDRV_PCM_RATE_96000 |\
+				SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			  SNDRV_PCM_FMTBIT_S24_LE |\
+			  SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
+	{
+		.name = "ADDA",
+		.id = MT8192_DAI_ADDA,
+		.playback = {
+			.stream_name = "ADDA Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_PLAYBACK_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.capture = {
+			.stream_name = "ADDA Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_CAPTURE_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.ops = &mtk_dai_adda_ops,
+	},
+	{
+		.name = "ADDA_CH34",
+		.id = MT8192_DAI_ADDA_CH34,
+		.playback = {
+			.stream_name = "ADDA CH34 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_PLAYBACK_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.capture = {
+			.stream_name = "ADDA CH34 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_CAPTURE_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.ops = &mtk_dai_adda_ops,
+	},
+	{
+		.name = "AP_DMIC",
+		.id = MT8192_DAI_AP_DMIC,
+		.capture = {
+			.stream_name = "AP DMIC Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_CAPTURE_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.ops = &mtk_dai_adda_ops,
+	},
+	{
+		.name = "AP_DMIC_CH34",
+		.id = MT8192_DAI_AP_DMIC_CH34,
+		.capture = {
+			.stream_name = "AP DMIC CH34 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_CAPTURE_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.ops = &mtk_dai_adda_ops,
+	},
+};
+
+int mt8192_dai_adda_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+	dev_info(afe->dev, "%s()\n", __func__);
+
+	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+
+	list_add(&dai->list, &afe->sub_dais);
+
+	dai->dai_drivers = mtk_dai_adda_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+
+	dai->controls = mtk_adda_controls;
+	dai->num_controls = ARRAY_SIZE(mtk_adda_controls);
+	dai->dapm_widgets = mtk_dai_adda_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+	dai->dapm_routes = mtk_dai_adda_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+
+	/* ap dmic priv share with adda */
+	afe_priv->dai_priv[MT8192_DAI_AP_DMIC] =
+		afe_priv->dai_priv[MT8192_DAI_ADDA];
+	afe_priv->dai_priv[MT8192_DAI_AP_DMIC_CH34] =
+		afe_priv->dai_priv[MT8192_DAI_ADDA_CH34];
+
+	return 0;
+}
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c
new file mode 100644
index 000000000000..5b29340f9516
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c
@@ -0,0 +1,2110 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI I2S Control
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+
+#include "mt8192-afe-clk.h"
+#include "mt8192-afe-common.h"
+#include "mt8192-afe-gpio.h"
+#include "mt8192-interconnection.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;
+};
+
+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 MTK_AFE_I2S6_KCONTROL_NAME "I2S6_HD_Mux"
+#define MTK_AFE_I2S7_KCONTROL_NAME "I2S7_HD_Mux"
+#define MTK_AFE_I2S8_KCONTROL_NAME "I2S8_HD_Mux"
+#define MTK_AFE_I2S9_KCONTROL_NAME "I2S9_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 I2S6_HD_EN_W_NAME "I2S6_HD_EN"
+#define I2S7_HD_EN_W_NAME "I2S7_HD_EN"
+#define I2S8_HD_EN_W_NAME "I2S8_HD_EN"
+#define I2S9_HD_EN_W_NAME "I2S9_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"
+#define I2S6_MCLK_EN_W_NAME "I2S6_MCLK_EN"
+#define I2S7_MCLK_EN_W_NAME "I2S7_MCLK_EN"
+#define I2S8_MCLK_EN_W_NAME "I2S8_MCLK_EN"
+#define I2S9_MCLK_EN_W_NAME "I2S9_MCLK_EN"
+
+static int get_i2s_id_by_name(struct mtk_base_afe *afe,
+			      const char *name)
+{
+	if (strncmp(name, "I2S0", 4) == 0)
+		return MT8192_DAI_I2S_0;
+	else if (strncmp(name, "I2S1", 4) == 0)
+		return MT8192_DAI_I2S_1;
+	else if (strncmp(name, "I2S2", 4) == 0)
+		return MT8192_DAI_I2S_2;
+	else if (strncmp(name, "I2S3", 4) == 0)
+		return MT8192_DAI_I2S_3;
+	else if (strncmp(name, "I2S5", 4) == 0)
+		return MT8192_DAI_I2S_5;
+	else if (strncmp(name, "I2S6", 4) == 0)
+		return MT8192_DAI_I2S_6;
+	else if (strncmp(name, "I2S7", 4) == 0)
+		return MT8192_DAI_I2S_7;
+	else if (strncmp(name, "I2S8", 4) == 0)
+		return MT8192_DAI_I2S_8;
+	else if (strncmp(name, "I2S9", 4) == 0)
+		return MT8192_DAI_I2S_9;
+	else
+		return -EINVAL;
+}
+
+static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe,
+						     const char *name)
+{
+	struct mt8192_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 mt8192_i2s_hd_str[] = {
+	"Normal", "Low_Jitter"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(mt8192_i2s_enum, mt8192_i2s_hd_str);
+
+static int mt8192_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 mt8192_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_dbg(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, mt8192_i2s_enum,
+		     mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+	SOC_ENUM_EXT(MTK_AFE_I2S1_KCONTROL_NAME, mt8192_i2s_enum,
+		     mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+	SOC_ENUM_EXT(MTK_AFE_I2S2_KCONTROL_NAME, mt8192_i2s_enum,
+		     mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+	SOC_ENUM_EXT(MTK_AFE_I2S3_KCONTROL_NAME, mt8192_i2s_enum,
+		     mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+	SOC_ENUM_EXT(MTK_AFE_I2S5_KCONTROL_NAME, mt8192_i2s_enum,
+		     mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+	SOC_ENUM_EXT(MTK_AFE_I2S6_KCONTROL_NAME, mt8192_i2s_enum,
+		     mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+	SOC_ENUM_EXT(MTK_AFE_I2S7_KCONTROL_NAME, mt8192_i2s_enum,
+		     mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+	SOC_ENUM_EXT(MTK_AFE_I2S8_KCONTROL_NAME, mt8192_i2s_enum,
+		     mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+	SOC_ENUM_EXT(MTK_AFE_I2S9_KCONTROL_NAME, mt8192_i2s_enum,
+		     mt8192_i2s_hd_get, mt8192_i2s_hd_set),
+};
+
+/* dai component */
+/* i2s virtual mux to output widget */
+static const char * const i2s_mux_map[] = {
+	"Normal", "Dummy_Widget",
+};
+
+static int i2s_mux_map_value[] = {
+	0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s_mux_map_enum,
+					      SND_SOC_NOPM,
+					      0,
+					      1,
+					      i2s_mux_map,
+					      i2s_mux_map_value);
+
+static const struct snd_kcontrol_new i2s0_in_mux_control =
+	SOC_DAPM_ENUM("I2S0 In Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s8_in_mux_control =
+	SOC_DAPM_ENUM("I2S8 In Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s1_out_mux_control =
+	SOC_DAPM_ENUM("I2S1 Out Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s3_out_mux_control =
+	SOC_DAPM_ENUM("I2S3 Out Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s5_out_mux_control =
+	SOC_DAPM_ENUM("I2S5 Out Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s7_out_mux_control =
+	SOC_DAPM_ENUM("I2S7 Out Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s9_out_mux_control =
+	SOC_DAPM_ENUM("I2S9 Out Select", i2s_mux_map_enum);
+
+/* Tinyconn Mux */
+enum {
+	TINYCONN_CH1_MUX_DL1 = 0x0,
+	TINYCONN_CH2_MUX_DL1 = 0x1,
+	TINYCONN_CH1_MUX_DL12 = 0x2,
+	TINYCONN_CH2_MUX_DL12 = 0x3,
+	TINYCONN_CH1_MUX_DL2 = 0x4,
+	TINYCONN_CH2_MUX_DL2 = 0x5,
+	TINYCONN_CH1_MUX_DL3 = 0x6,
+	TINYCONN_CH2_MUX_DL3 = 0x7,
+	TINYCONN_MUX_NONE = 0x1f,
+};
+
+static const char * const tinyconn_mux_map[] = {
+	"NONE",
+	"DL1_CH1",
+	"DL1_CH2",
+	"DL12_CH1",
+	"DL12_CH2",
+	"DL2_CH1",
+	"DL2_CH2",
+	"DL3_CH1",
+	"DL3_CH2",
+};
+
+static int tinyconn_mux_map_value[] = {
+	TINYCONN_MUX_NONE,
+	TINYCONN_CH1_MUX_DL1,
+	TINYCONN_CH2_MUX_DL1,
+	TINYCONN_CH1_MUX_DL12,
+	TINYCONN_CH2_MUX_DL12,
+	TINYCONN_CH1_MUX_DL2,
+	TINYCONN_CH2_MUX_DL2,
+	TINYCONN_CH1_MUX_DL3,
+	TINYCONN_CH2_MUX_DL3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(i2s1_tinyconn_ch1_mux_map_enum,
+				  AFE_TINY_CONN5,
+				  O_20_CFG_SFT,
+				  O_20_CFG_MASK,
+				  tinyconn_mux_map,
+				  tinyconn_mux_map_value);
+static const struct snd_kcontrol_new i2s1_tinyconn_ch1_mux_control =
+	SOC_DAPM_ENUM("i2s1 ch1 tinyconn Select",
+		      i2s1_tinyconn_ch1_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(i2s1_tinyconn_ch2_mux_map_enum,
+				  AFE_TINY_CONN5,
+				  O_21_CFG_SFT,
+				  O_21_CFG_MASK,
+				  tinyconn_mux_map,
+				  tinyconn_mux_map_value);
+static const struct snd_kcontrol_new i2s1_tinyconn_ch2_mux_control =
+	SOC_DAPM_ENUM("i2s1 ch2 tinyconn Select",
+		      i2s1_tinyconn_ch2_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(i2s3_tinyconn_ch1_mux_map_enum,
+				  AFE_TINY_CONN5,
+				  O_22_CFG_SFT,
+				  O_22_CFG_MASK,
+				  tinyconn_mux_map,
+				  tinyconn_mux_map_value);
+static const struct snd_kcontrol_new i2s3_tinyconn_ch1_mux_control =
+	SOC_DAPM_ENUM("i2s3 ch1 tinyconn Select",
+		      i2s3_tinyconn_ch1_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(i2s3_tinyconn_ch2_mux_map_enum,
+				  AFE_TINY_CONN5,
+				  O_23_CFG_SFT,
+				  O_23_CFG_MASK,
+				  tinyconn_mux_map,
+				  tinyconn_mux_map_value);
+static const struct snd_kcontrol_new i2s3_tinyconn_ch2_mux_control =
+	SOC_DAPM_ENUM("i2s3 ch2 tinyconn Select",
+		      i2s3_tinyconn_ch2_mux_map_enum);
+
+/* i2s in lpbk */
+static const char * const i2s_lpbk_mux_map[] = {
+	"Normal", "Lpbk",
+};
+
+static int i2s_lpbk_mux_map_value[] = {
+	0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s0_lpbk_mux_map_enum,
+					      AFE_I2S_CON,
+					      I2S_LOOPBACK_SFT,
+					      1,
+					      i2s_lpbk_mux_map,
+					      i2s_lpbk_mux_map_value);
+
+static const struct snd_kcontrol_new i2s0_lpbk_mux_control =
+	SOC_DAPM_ENUM("I2S Lpbk Select", i2s0_lpbk_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s2_lpbk_mux_map_enum,
+					      AFE_I2S_CON2,
+					      I2S3_LOOPBACK_SFT,
+					      1,
+					      i2s_lpbk_mux_map,
+					      i2s_lpbk_mux_map_value);
+
+static const struct snd_kcontrol_new i2s2_lpbk_mux_control =
+	SOC_DAPM_ENUM("I2S Lpbk Select", i2s2_lpbk_mux_map_enum);
+
+/* 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("DL12_CH1", AFE_CONN0, I_DL12_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN0_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN0_1, I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN0_1, I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN0_1, I_DL8_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN0_1, I_DL9_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN0,
+				    I_GAIN1_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN0,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN0,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN0,
+				    I_ADDA_UL_CH3, 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("DL12_CH2", AFE_CONN1, I_DL12_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN1_1, I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN1_1, I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN1_1, I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN1_1, I_DL8_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN1_1, I_DL9_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN1,
+				    I_GAIN1_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN1,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN1,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN1,
+				    I_ADDA_UL_CH3, 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("DL12_CH1", AFE_CONN28, I_DL12_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN28_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN28_1, I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN28_1, I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN28_1, I_DL8_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN28_1, I_DL9_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN28,
+				    I_GAIN1_OUT_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("DL12_CH2", AFE_CONN29, I_DL12_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN29_1, I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN29_1, I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN29_1, I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN29_1, I_DL8_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN29_1, I_DL9_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN29,
+				    I_GAIN1_OUT_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("DL12_CH1", AFE_CONN30, I_DL12_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN30_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN30_1, I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN30_1, I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN30_1, I_DL8_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN30_1, I_DL9_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN30,
+				    I_GAIN1_OUT_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("DL12_CH2", AFE_CONN31, I_DL12_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN31_1, I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN31_1, I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN31_1, I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN31_1, I_DL8_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN31_1, I_DL9_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN31,
+				    I_GAIN1_OUT_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),
+};
+
+static const struct snd_kcontrol_new mtk_i2s7_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN54, I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN54, I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN54, I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN54, I_DL12_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN54_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN54_1, I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN54_1, I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN54_1, I_DL9_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN54,
+				    I_GAIN1_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN54,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN54,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN54,
+				    I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s7_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN55, I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN55, I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN55, I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN55, I_DL12_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN55_1, I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN55_1, I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN55_1, I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN55_1, I_DL9_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN55,
+				    I_GAIN1_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN55,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN55,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN55,
+				    I_PCM_2_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN55,
+				    I_PCM_1_CAP_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN55,
+				    I_PCM_2_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s9_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN56, I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN56, I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN56, I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN56, I_DL12_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN56_1, I_DL6_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN56_1, I_DL4_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN56_1, I_DL5_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN56_1, I_DL8_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN56_1, I_DL9_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN56,
+				    I_GAIN1_OUT_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN56,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN56,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN56,
+				    I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s9_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN57, I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN57, I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN57, I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN57, I_DL12_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN57_1, I_DL6_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN57_1, I_DL4_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN57_1, I_DL5_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN57_1, I_DL8_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN57_1, I_DL9_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN57,
+				    I_GAIN1_OUT_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN57,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN57,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN57,
+				    I_PCM_2_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN57,
+				    I_PCM_1_CAP_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN57,
+				    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_i2s_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;
+
+	i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+	if (!i2s_priv) {
+		dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+		return -EINVAL;
+	}
+
+	dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+		__func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8192_afe_gpio_request(afe->dev, true, i2s_priv->id, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		mt8192_afe_gpio_request(afe->dev, false, i2s_priv->id, 0);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_apll_event(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol,
+			  int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+	dev_dbg(cmpnt->dev, "%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)
+			mt8192_apll1_enable(afe);
+		else
+			mt8192_apll2_enable(afe);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (strcmp(w->name, APLL1_W_NAME) == 0)
+			mt8192_apll1_disable(afe);
+		else
+			mt8192_apll2_disable(afe);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int i2s_out_tinyconn_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);
+	unsigned int reg;
+	unsigned int reg_shift;
+	unsigned int reg_mask_shift;
+
+	dev_dbg(afe->dev, "%s(), event 0x%x\n", __func__, event);
+
+	if (strstr(w->name, "I2S1")) {
+		reg = AFE_I2S_CON1;
+		reg_shift = I2S2_32BIT_EN_SFT;
+		reg_mask_shift = I2S2_32BIT_EN_MASK_SFT;
+	} else if (strstr(w->name, "I2S3")) {
+		reg = AFE_I2S_CON3;
+		reg_shift = I2S4_32BIT_EN_SFT;
+		reg_mask_shift = I2S4_32BIT_EN_MASK_SFT;
+	} else if (strstr(w->name, "I2S5")) {
+		reg = AFE_I2S_CON4;
+		reg_shift = I2S5_32BIT_EN_SFT;
+		reg_mask_shift = I2S5_32BIT_EN_MASK_SFT;
+	} else if (strstr(w->name, "I2S7")) {
+		reg = AFE_I2S_CON7;
+		reg_shift = I2S7_32BIT_EN_SFT;
+		reg_mask_shift = I2S7_32BIT_EN_MASK_SFT;
+	} else if (strstr(w->name, "I2S9")) {
+		reg = AFE_I2S_CON9;
+		reg_shift = I2S9_32BIT_EN_SFT;
+		reg_mask_shift = I2S9_32BIT_EN_MASK_SFT;
+	} else {
+		reg = AFE_I2S_CON1;
+		reg_shift = I2S2_32BIT_EN_SFT;
+		reg_mask_shift = I2S2_32BIT_EN_MASK_SFT;
+		dev_warn(afe->dev, "%s(), error widget name %s, use i2s1\n",
+			 __func__, w->name);
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(afe->regmap, reg, reg_mask_shift,
+				   0x1 << reg_shift);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_update_bits(afe->regmap, reg, reg_mask_shift,
+				   0x0 << reg_shift);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol,
+			     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+	struct mtk_afe_i2s_priv *i2s_priv;
+
+	dev_dbg(cmpnt->dev, "%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:
+		mt8192_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		i2s_priv->mclk_rate = 0;
+		mt8192_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_INPUT("CONNSYS"),
+
+	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)),
+
+	SND_SOC_DAPM_MIXER("I2S7_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_i2s7_ch1_mix,
+			   ARRAY_SIZE(mtk_i2s7_ch1_mix)),
+	SND_SOC_DAPM_MIXER("I2S7_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_i2s7_ch2_mix,
+			   ARRAY_SIZE(mtk_i2s7_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("I2S9_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_i2s9_ch1_mix,
+			   ARRAY_SIZE(mtk_i2s9_ch1_mix)),
+	SND_SOC_DAPM_MIXER("I2S9_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_i2s9_ch2_mix,
+			   ARRAY_SIZE(mtk_i2s9_ch2_mix)),
+
+	SND_SOC_DAPM_MUX_E("I2S1_TINYCONN_CH1_MUX", SND_SOC_NOPM, 0, 0,
+			   &i2s1_tinyconn_ch1_mux_control,
+			   i2s_out_tinyconn_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MUX_E("I2S1_TINYCONN_CH2_MUX", SND_SOC_NOPM, 0, 0,
+			   &i2s1_tinyconn_ch2_mux_control,
+			   i2s_out_tinyconn_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MUX_E("I2S3_TINYCONN_CH1_MUX", SND_SOC_NOPM, 0, 0,
+			   &i2s3_tinyconn_ch1_mux_control,
+			   i2s_out_tinyconn_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MUX_E("I2S3_TINYCONN_CH2_MUX", SND_SOC_NOPM, 0, 0,
+			   &i2s3_tinyconn_ch2_mux_control,
+			   i2s_out_tinyconn_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* i2s en*/
+	SND_SOC_DAPM_SUPPLY_S("I2S0_EN", SUPPLY_SEQ_I2S_EN,
+			      AFE_I2S_CON, I2S_EN_SFT, 0,
+			      mtk_i2s_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("I2S1_EN", SUPPLY_SEQ_I2S_EN,
+			      AFE_I2S_CON1, I2S_EN_SFT, 0,
+			      mtk_i2s_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("I2S2_EN", SUPPLY_SEQ_I2S_EN,
+			      AFE_I2S_CON2, I2S_EN_SFT, 0,
+			      mtk_i2s_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("I2S3_EN", SUPPLY_SEQ_I2S_EN,
+			      AFE_I2S_CON3, I2S_EN_SFT, 0,
+			      mtk_i2s_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("I2S5_EN", SUPPLY_SEQ_I2S_EN,
+			      AFE_I2S_CON4, I2S5_EN_SFT, 0,
+			      mtk_i2s_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("I2S6_EN", SUPPLY_SEQ_I2S_EN,
+			      AFE_I2S_CON6, I2S6_EN_SFT, 0,
+			      mtk_i2s_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("I2S7_EN", SUPPLY_SEQ_I2S_EN,
+			      AFE_I2S_CON7, I2S7_EN_SFT, 0,
+			      mtk_i2s_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("I2S8_EN", SUPPLY_SEQ_I2S_EN,
+			      AFE_I2S_CON8, I2S8_EN_SFT, 0,
+			      mtk_i2s_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("I2S9_EN", SUPPLY_SEQ_I2S_EN,
+			      AFE_I2S_CON9, I2S9_EN_SFT, 0,
+			      mtk_i2s_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	/* 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),
+	SND_SOC_DAPM_SUPPLY_S(I2S6_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+			      AFE_I2S_CON6, I2S6_HD_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S(I2S7_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+			      AFE_I2S_CON7, I2S7_HD_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S(I2S8_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+			      AFE_I2S_CON8, I2S8_HD_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S(I2S9_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+			      AFE_I2S_CON9, I2S9_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),
+	SND_SOC_DAPM_SUPPLY_S(I2S6_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(I2S7_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(I2S8_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(I2S9_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),
+
+	/* allow i2s on without codec on */
+	SND_SOC_DAPM_OUTPUT("I2S_DUMMY_OUT"),
+	SND_SOC_DAPM_MUX("I2S1_Out_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s1_out_mux_control),
+	SND_SOC_DAPM_MUX("I2S3_Out_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s3_out_mux_control),
+	SND_SOC_DAPM_MUX("I2S5_Out_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s5_out_mux_control),
+	SND_SOC_DAPM_MUX("I2S7_Out_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s7_out_mux_control),
+	SND_SOC_DAPM_MUX("I2S9_Out_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s9_out_mux_control),
+
+	SND_SOC_DAPM_INPUT("I2S_DUMMY_IN"),
+	SND_SOC_DAPM_MUX("I2S0_In_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s0_in_mux_control),
+	SND_SOC_DAPM_MUX("I2S8_In_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s8_in_mux_control),
+
+	/* i2s in lpbk */
+	SND_SOC_DAPM_MUX("I2S0_Lpbk_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s0_lpbk_mux_control),
+	SND_SOC_DAPM_MUX("I2S2_Lpbk_Mux",
+			 SND_SOC_NOPM, 0, 0, &i2s2_lpbk_mux_control),
+};
+
+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 = mt8192_get_apll_by_name(afe, source->name);
+
+	/* choose APLL from i2s rate */
+	i2s_need_apll = mt8192_get_apll_by_rate(afe, i2s_priv->rate);
+
+	if (i2s_need_apll == cur_apll)
+		return 1;
+
+	return 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 = mt8192_get_apll_by_name(afe, source->name);
+
+	if (i2s_priv->mclk_apll == cur_apll)
+		return 1;
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = {
+	{"Connsys I2S", NULL, "CONNSYS"},
+
+	/* 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, "I2S6_EN", mtk_afe_i2s_share_connect},
+	{"I2S0", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+	{"I2S0", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+	{"I2S0", NULL, "I2S9_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", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S0", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S0", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S0", NULL, I2S9_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", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S0", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S0", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S0", NULL, I2S9_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_TINYCONN_CH1_MUX", "DL1_CH1", "DL1"},
+	{"I2S1_TINYCONN_CH2_MUX", "DL1_CH2", "DL1"},
+
+	{"I2S1_CH1", "DL2_CH1", "DL2"},
+	{"I2S1_CH2", "DL2_CH2", "DL2"},
+	{"I2S1_TINYCONN_CH1_MUX", "DL2_CH1", "DL2"},
+	{"I2S1_TINYCONN_CH2_MUX", "DL2_CH2", "DL2"},
+
+	{"I2S1_CH1", "DL3_CH1", "DL3"},
+	{"I2S1_CH2", "DL3_CH2", "DL3"},
+	{"I2S1_TINYCONN_CH1_MUX", "DL3_CH1", "DL3"},
+	{"I2S1_TINYCONN_CH2_MUX", "DL3_CH2", "DL3"},
+
+	{"I2S1_CH1", "DL12_CH1", "DL12"},
+	{"I2S1_CH2", "DL12_CH2", "DL12"},
+	{"I2S1_TINYCONN_CH1_MUX", "DL12_CH1", "DL12"},
+	{"I2S1_TINYCONN_CH2_MUX", "DL12_CH2", "DL12"},
+
+	{"I2S1_CH1", "DL4_CH1", "DL4"},
+	{"I2S1_CH2", "DL4_CH2", "DL4"},
+
+	{"I2S1_CH1", "DL5_CH1", "DL5"},
+	{"I2S1_CH2", "DL5_CH2", "DL5"},
+
+	{"I2S1_CH1", "DL6_CH1", "DL6"},
+	{"I2S1_CH2", "DL6_CH2", "DL6"},
+
+	{"I2S1_CH1", "DL8_CH1", "DL8"},
+	{"I2S1_CH2", "DL8_CH2", "DL8"},
+
+	{"I2S1", NULL, "I2S1_CH1"},
+	{"I2S1", NULL, "I2S1_CH2"},
+	{"I2S1", NULL, "I2S3_TINYCONN_CH1_MUX"},
+	{"I2S1", NULL, "I2S3_TINYCONN_CH2_MUX"},
+
+	{"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, "I2S6_EN", mtk_afe_i2s_share_connect},
+	{"I2S1", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+	{"I2S1", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+	{"I2S1", NULL, "I2S9_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", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S1", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S1", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S1", NULL, I2S9_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", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S1", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S1", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S1", NULL, I2S9_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, "I2S6_EN", mtk_afe_i2s_share_connect},
+	{"I2S2", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+	{"I2S2", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+	{"I2S2", NULL, "I2S9_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", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S2", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S2", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S2", NULL, I2S9_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", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S2", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S2", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S2", NULL, I2S9_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_TINYCONN_CH1_MUX", "DL1_CH1", "DL1"},
+	{"I2S3_TINYCONN_CH2_MUX", "DL1_CH2", "DL1"},
+
+	{"I2S3_CH1", "DL2_CH1", "DL2"},
+	{"I2S3_CH2", "DL2_CH2", "DL2"},
+	{"I2S3_TINYCONN_CH1_MUX", "DL2_CH1", "DL2"},
+	{"I2S3_TINYCONN_CH2_MUX", "DL2_CH2", "DL2"},
+
+	{"I2S3_CH1", "DL3_CH1", "DL3"},
+	{"I2S3_CH2", "DL3_CH2", "DL3"},
+	{"I2S3_TINYCONN_CH1_MUX", "DL3_CH1", "DL3"},
+	{"I2S3_TINYCONN_CH2_MUX", "DL3_CH2", "DL3"},
+
+	{"I2S3_CH1", "DL12_CH1", "DL12"},
+	{"I2S3_CH2", "DL12_CH2", "DL12"},
+	{"I2S3_TINYCONN_CH1_MUX", "DL12_CH1", "DL12"},
+	{"I2S3_TINYCONN_CH2_MUX", "DL12_CH2", "DL12"},
+
+	{"I2S3_CH1", "DL4_CH1", "DL4"},
+	{"I2S3_CH2", "DL4_CH2", "DL4"},
+
+	{"I2S3_CH1", "DL5_CH1", "DL5"},
+	{"I2S3_CH2", "DL5_CH2", "DL5"},
+
+	{"I2S3_CH1", "DL6_CH1", "DL6"},
+	{"I2S3_CH2", "DL6_CH2", "DL6"},
+
+	{"I2S3_CH1", "DL8_CH1", "DL8"},
+	{"I2S3_CH2", "DL8_CH2", "DL8"},
+
+	{"I2S3", NULL, "I2S3_CH1"},
+	{"I2S3", NULL, "I2S3_CH2"},
+	{"I2S3", NULL, "I2S3_TINYCONN_CH1_MUX"},
+	{"I2S3", NULL, "I2S3_TINYCONN_CH2_MUX"},
+
+	{"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, "I2S6_EN", mtk_afe_i2s_share_connect},
+	{"I2S3", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+	{"I2S3", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+	{"I2S3", NULL, "I2S9_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", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S3", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S3", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S3", NULL, I2S9_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", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S3", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S3", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S3", NULL, I2S9_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_CH1", "DL12_CH1", "DL12"},
+	{"I2S5_CH2", "DL12_CH2", "DL12"},
+
+	{"I2S5_CH1", "DL4_CH1", "DL4"},
+	{"I2S5_CH2", "DL4_CH2", "DL4"},
+
+	{"I2S5_CH1", "DL5_CH1", "DL5"},
+	{"I2S5_CH2", "DL5_CH2", "DL5"},
+
+	{"I2S5_CH1", "DL6_CH1", "DL6"},
+	{"I2S5_CH2", "DL6_CH2", "DL6"},
+
+	{"I2S5_CH1", "DL8_CH1", "DL8"},
+	{"I2S5_CH2", "DL8_CH2", "DL8"},
+
+	{"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, "I2S6_EN", mtk_afe_i2s_share_connect},
+	{"I2S5", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+	{"I2S5", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+	{"I2S5", NULL, "I2S9_EN", mtk_afe_i2s_share_connect},
+
+	{"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", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S5", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S5", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S5", NULL, I2S9_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", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S5", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S5", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S5", NULL, I2S9_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},
+
+	/* i2s6 */
+	{"I2S6", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+	{"I2S6", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+	{"I2S6", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+	{"I2S6", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+	{"I2S6", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+	{"I2S6", NULL, "I2S6_EN"},
+	{"I2S6", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+	{"I2S6", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+	{"I2S6", NULL, "I2S9_EN", mtk_afe_i2s_share_connect},
+
+	{"I2S6", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S6", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S6", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S6", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S6", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S6", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S6", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S6", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S6", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{I2S6_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+	{I2S6_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+	{"I2S6", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S6", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S6", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S6", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S6", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S6", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S6", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S6", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S6", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{I2S6_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+	{I2S6_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+	/* i2s7 */
+	{"I2S7", NULL, "I2S7_CH1"},
+	{"I2S7", NULL, "I2S7_CH2"},
+
+	{"I2S7", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+	{"I2S7", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+	{"I2S7", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+	{"I2S7", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+	{"I2S7", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+	{"I2S7", NULL, "I2S6_EN", mtk_afe_i2s_share_connect},
+	{"I2S7", NULL, "I2S7_EN"},
+	{"I2S7", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+	{"I2S7", NULL, "I2S9_EN", mtk_afe_i2s_share_connect},
+
+	{"I2S7", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S7", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S7", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S7", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S7", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S7", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S7", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S7", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S7", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{I2S7_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+	{I2S7_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+	{"I2S7", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S7", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S7", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S7", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S7", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S7", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S7", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S7", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S7", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{I2S7_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+	{I2S7_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+	/* i2s8 */
+	{"I2S8", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+	{"I2S8", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+	{"I2S8", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+	{"I2S8", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+	{"I2S8", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+	{"I2S8", NULL, "I2S6_EN", mtk_afe_i2s_share_connect},
+	{"I2S8", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+	{"I2S8", NULL, "I2S8_EN"},
+	{"I2S8", NULL, "I2S9_EN", mtk_afe_i2s_share_connect},
+
+	{"I2S8", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S8", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S8", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S8", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S8", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S8", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S8", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S8", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S8", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{I2S8_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+	{I2S8_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+	{"I2S8", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S8", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S8", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S8", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S8", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S8", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S8", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S8", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S8", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{I2S8_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+	{I2S8_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+	/* i2s9 */
+	{"I2S9_CH1", "DL1_CH1", "DL1"},
+	{"I2S9_CH2", "DL1_CH2", "DL1"},
+
+	{"I2S9_CH1", "DL2_CH1", "DL2"},
+	{"I2S9_CH2", "DL2_CH2", "DL2"},
+
+	{"I2S9_CH1", "DL3_CH1", "DL3"},
+	{"I2S9_CH2", "DL3_CH2", "DL3"},
+
+	{"I2S9_CH1", "DL12_CH1", "DL12"},
+	{"I2S9_CH2", "DL12_CH2", "DL12"},
+
+	{"I2S9_CH1", "DL4_CH1", "DL4"},
+	{"I2S9_CH2", "DL4_CH2", "DL4"},
+
+	{"I2S9_CH1", "DL5_CH1", "DL5"},
+	{"I2S9_CH2", "DL5_CH2", "DL5"},
+
+	{"I2S9_CH1", "DL6_CH1", "DL6"},
+	{"I2S9_CH2", "DL6_CH2", "DL6"},
+
+	{"I2S9_CH1", "DL8_CH1", "DL8"},
+	{"I2S9_CH2", "DL8_CH2", "DL8"},
+
+	{"I2S9_CH1", "DL9_CH1", "DL9"},
+	{"I2S9_CH2", "DL9_CH2", "DL9"},
+
+	{"I2S9", NULL, "I2S9_CH1"},
+	{"I2S9", NULL, "I2S9_CH2"},
+
+	{"I2S9", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+	{"I2S9", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+	{"I2S9", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+	{"I2S9", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+	{"I2S9", NULL, "I2S5_EN", mtk_afe_i2s_share_connect},
+	{"I2S9", NULL, "I2S6_EN", mtk_afe_i2s_share_connect},
+	{"I2S9", NULL, "I2S7_EN", mtk_afe_i2s_share_connect},
+	{"I2S9", NULL, "I2S8_EN", mtk_afe_i2s_share_connect},
+	{"I2S9", NULL, "I2S9_EN"},
+
+	{"I2S9", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S9", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S9", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S9", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S9", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S9", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S9", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S9", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{"I2S9", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+	{I2S9_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+	{I2S9_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+	{"I2S9", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S9", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S9", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S9", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S9", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S9", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S9", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S9", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{"I2S9", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+	{I2S9_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+	{I2S9_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+	/* allow i2s on without codec on */
+	{"I2S0", NULL, "I2S0_In_Mux"},
+	{"I2S0_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"},
+
+	{"I2S8", NULL, "I2S8_In_Mux"},
+	{"I2S8_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"},
+
+	{"I2S1_Out_Mux", "Dummy_Widget", "I2S1"},
+	{"I2S_DUMMY_OUT", NULL, "I2S1_Out_Mux"},
+
+	{"I2S3_Out_Mux", "Dummy_Widget", "I2S3"},
+	{"I2S_DUMMY_OUT", NULL, "I2S3_Out_Mux"},
+
+	{"I2S5_Out_Mux", "Dummy_Widget", "I2S5"},
+	{"I2S_DUMMY_OUT", NULL, "I2S5_Out_Mux"},
+
+	{"I2S7_Out_Mux", "Dummy_Widget", "I2S7"},
+	{"I2S_DUMMY_OUT", NULL, "I2S7_Out_Mux"},
+
+	{"I2S9_Out_Mux", "Dummy_Widget", "I2S9"},
+	{"I2S_DUMMY_OUT", NULL, "I2S9_Out_Mux"},
+
+	/* i2s in lpbk */
+	{"I2S0_Lpbk_Mux", "Lpbk", "I2S3"},
+	{"I2S2_Lpbk_Mux", "Lpbk", "I2S1"},
+	{"I2S0", NULL, "I2S0_Lpbk_Mux"},
+	{"I2S2", NULL, "I2S2_Lpbk_Mux"},
+};
+
+/* dai ops */
+static int mtk_dai_connsys_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);
+	unsigned int rate = params_rate(params);
+	unsigned int rate_reg = mt8192_rate_transform(afe->dev,
+						      rate, dai->id);
+	unsigned int i2s_con = 0;
+
+	dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+		__func__, dai->id, substream->stream, rate);
+
+	/* non-inverse, i2s mode, proxy mode, 16bits, from connsys */
+	i2s_con |= 0 << INV_PAD_CTRL_SFT;
+	i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT;
+	i2s_con |= 1 << I2S_SRC_SFT;
+	i2s_con |= get_i2s_wlen(SNDRV_PCM_FORMAT_S16_LE) << I2S_WLEN_SFT;
+	i2s_con |= 0 << I2SIN_PAD_SEL_SFT;
+	regmap_write(afe->regmap, AFE_CONNSYS_I2S_CON, i2s_con);
+
+	/* use asrc */
+	regmap_update_bits(afe->regmap,
+			   AFE_CONNSYS_I2S_CON,
+			   I2S_BYPSRC_MASK_SFT,
+			   0x0 << I2S_BYPSRC_SFT);
+
+	/* proxy mode, set i2s for asrc */
+	regmap_update_bits(afe->regmap,
+			   AFE_CONNSYS_I2S_CON,
+			   I2S_MODE_MASK_SFT,
+			   rate_reg << I2S_MODE_SFT);
+
+	switch (rate) {
+	case 32000:
+		regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x140000);
+		break;
+	case 44100:
+		regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x001B9000);
+		break;
+	default:
+		regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x001E0000);
+		break;
+	}
+
+	/* Calibration setting */
+	regmap_write(afe->regmap, AFE_ASRC_2CH_CON4, 0x00140000);
+	regmap_write(afe->regmap, AFE_ASRC_2CH_CON9, 0x00036000);
+	regmap_write(afe->regmap, AFE_ASRC_2CH_CON10, 0x0002FC00);
+	regmap_write(afe->regmap, AFE_ASRC_2CH_CON6, 0x00007EF4);
+	regmap_write(afe->regmap, AFE_ASRC_2CH_CON5, 0x00FF5986);
+
+	/* 0:Stereo 1:Mono */
+	regmap_update_bits(afe->regmap,
+			   AFE_ASRC_2CH_CON2,
+			   CHSET_IS_MONO_MASK_SFT,
+			   0x0 << CHSET_IS_MONO_SFT);
+
+	return 0;
+}
+
+static int mtk_dai_connsys_i2s_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 mt8192_afe_private *afe_priv = afe->platform_priv;
+
+	dev_dbg(afe->dev, "%s(), cmd %d, stream %d\n",
+		__func__, cmd, substream->stream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		/* i2s enable */
+		regmap_update_bits(afe->regmap,
+				   AFE_CONNSYS_I2S_CON,
+				   I2S_EN_MASK_SFT,
+				   0x1 << I2S_EN_SFT);
+
+		/* calibrator enable */
+		regmap_update_bits(afe->regmap,
+				   AFE_ASRC_2CH_CON5,
+				   CALI_EN_MASK_SFT,
+				   0x1 << CALI_EN_SFT);
+
+		/* asrc enable */
+		regmap_update_bits(afe->regmap,
+				   AFE_ASRC_2CH_CON0,
+				   CON0_CHSET_STR_CLR_MASK_SFT,
+				   0x1 << CON0_CHSET_STR_CLR_SFT);
+		regmap_update_bits(afe->regmap,
+				   AFE_ASRC_2CH_CON0,
+				   CON0_ASM_ON_MASK_SFT,
+				   0x1 << CON0_ASM_ON_SFT);
+
+		afe_priv->dai_on[dai->id] = true;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		regmap_update_bits(afe->regmap,
+				   AFE_ASRC_2CH_CON0,
+				   CON0_ASM_ON_MASK_SFT,
+				   0 << CON0_ASM_ON_SFT);
+		regmap_update_bits(afe->regmap,
+				   AFE_ASRC_2CH_CON5,
+				   CALI_EN_MASK_SFT,
+				   0 << CALI_EN_SFT);
+
+		/* i2s disable */
+		regmap_update_bits(afe->regmap,
+				   AFE_CONNSYS_I2S_CON,
+				   I2S_EN_MASK_SFT,
+				   0x0 << I2S_EN_SFT);
+
+		/* bypass asrc */
+		regmap_update_bits(afe->regmap,
+				   AFE_CONNSYS_I2S_CON,
+				   I2S_BYPSRC_MASK_SFT,
+				   0x1 << I2S_BYPSRC_SFT);
+
+		afe_priv->dai_on[dai->id] = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_connsys_i2s_ops = {
+	.hw_params = mtk_dai_connsys_i2s_hw_params,
+	.trigger = mtk_dai_connsys_i2s_trigger,
+};
+
+/* i2s */
+static int mtk_dai_i2s_config(struct mtk_base_afe *afe,
+			      struct snd_pcm_hw_params *params,
+			      int i2s_id)
+{
+	struct mt8192_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 = mt8192_rate_transform(afe->dev,
+						      rate, i2s_id);
+	snd_pcm_format_t format = params_format(params);
+	unsigned int i2s_con = 0;
+	int ret = 0;
+
+	dev_dbg(afe->dev, "%s(), id %d, rate %d, format %d\n",
+		__func__, i2s_id, rate, format);
+
+	if (i2s_priv)
+		i2s_priv->rate = rate;
+	else
+		dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__);
+
+	switch (i2s_id) {
+	case MT8192_DAI_I2S_0:
+		i2s_con = I2S_IN_PAD_IO_MUX << I2SIN_PAD_SEL_SFT;
+		i2s_con |= rate_reg << I2S_OUT_MODE_SFT;
+		i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT;
+		i2s_con |= get_i2s_wlen(format) << I2S_WLEN_SFT;
+		regmap_update_bits(afe->regmap, AFE_I2S_CON,
+				   0xffffeffe, i2s_con);
+		break;
+	case MT8192_DAI_I2S_1:
+		i2s_con = I2S1_SEL_O28_O29 << I2S2_SEL_O03_O04_SFT;
+		i2s_con |= rate_reg << I2S2_OUT_MODE_SFT;
+		i2s_con |= I2S_FMT_I2S << I2S2_FMT_SFT;
+		i2s_con |= get_i2s_wlen(format) << I2S2_WLEN_SFT;
+		regmap_update_bits(afe->regmap, AFE_I2S_CON1,
+				   0xffffeffe, i2s_con);
+		break;
+	case MT8192_DAI_I2S_2:
+		i2s_con = 8 << I2S3_UPDATE_WORD_SFT;
+		i2s_con |= rate_reg << I2S3_OUT_MODE_SFT;
+		i2s_con |= I2S_FMT_I2S << I2S3_FMT_SFT;
+		i2s_con |= get_i2s_wlen(format) << I2S3_WLEN_SFT;
+		regmap_update_bits(afe->regmap, AFE_I2S_CON2,
+				   0xffffeffe, i2s_con);
+		break;
+	case MT8192_DAI_I2S_3:
+		i2s_con = rate_reg << I2S4_OUT_MODE_SFT;
+		i2s_con |= I2S_FMT_I2S << I2S4_FMT_SFT;
+		i2s_con |= get_i2s_wlen(format) << I2S4_WLEN_SFT;
+		regmap_update_bits(afe->regmap, AFE_I2S_CON3,
+				   0xffffeffe, i2s_con);
+		break;
+	case MT8192_DAI_I2S_5:
+		i2s_con = rate_reg << I2S5_OUT_MODE_SFT;
+		i2s_con |= I2S_FMT_I2S << I2S5_FMT_SFT;
+		i2s_con |= get_i2s_wlen(format) << I2S5_WLEN_SFT;
+		regmap_update_bits(afe->regmap, AFE_I2S_CON4,
+				   0xffffeffe, i2s_con);
+		break;
+	case MT8192_DAI_I2S_6:
+		i2s_con = rate_reg << I2S6_OUT_MODE_SFT;
+		i2s_con |= I2S_FMT_I2S << I2S6_FMT_SFT;
+		i2s_con |= get_i2s_wlen(format) << I2S6_WLEN_SFT;
+		regmap_update_bits(afe->regmap, AFE_I2S_CON6,
+				   0xffffeffe, i2s_con);
+		break;
+	case MT8192_DAI_I2S_7:
+		i2s_con = rate_reg << I2S7_OUT_MODE_SFT;
+		i2s_con |= I2S_FMT_I2S << I2S7_FMT_SFT;
+		i2s_con |= get_i2s_wlen(format) << I2S7_WLEN_SFT;
+		regmap_update_bits(afe->regmap, AFE_I2S_CON7,
+				   0xffffeffe, i2s_con);
+		break;
+	case MT8192_DAI_I2S_8:
+		i2s_con = rate_reg << I2S8_OUT_MODE_SFT;
+		i2s_con |= I2S_FMT_I2S << I2S8_FMT_SFT;
+		i2s_con |= get_i2s_wlen(format) << I2S8_WLEN_SFT;
+		regmap_update_bits(afe->regmap, AFE_I2S_CON8,
+				   0xffffeffe, i2s_con);
+		break;
+	case MT8192_DAI_I2S_9:
+		i2s_con = rate_reg << I2S9_OUT_MODE_SFT;
+		i2s_con |= I2S_FMT_I2S << I2S9_FMT_SFT;
+		i2s_con |= get_i2s_wlen(format) << I2S9_WLEN_SFT;
+		regmap_update_bits(afe->regmap, AFE_I2S_CON9,
+				   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 mt8192_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_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+	apll = mt8192_get_apll_by_rate(afe, freq);
+	apll_rate = mt8192_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 can't gen 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 const struct snd_soc_dai_ops mtk_dai_i2s_ops = {
+	.hw_params = mtk_dai_i2s_hw_params,
+	.set_sysclk = mtk_dai_i2s_set_sysclk,
+};
+
+/* dai driver */
+#define MTK_CONNSYS_I2S_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#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 = "CONNSYS_I2S",
+		.id = MT8192_DAI_CONNSYS_I2S,
+		.capture = {
+			.stream_name = "Connsys I2S",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_CONNSYS_I2S_RATES,
+			.formats = MTK_I2S_FORMATS,
+		},
+		.ops = &mtk_dai_connsys_i2s_ops,
+	},
+	{
+		.name = "I2S0",
+		.id = MT8192_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 = MT8192_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 = MT8192_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 = MT8192_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 = MT8192_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,
+	},
+	{
+		.name = "I2S6",
+		.id = MT8192_DAI_I2S_6,
+		.capture = {
+			.stream_name = "I2S6",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_I2S_RATES,
+			.formats = MTK_I2S_FORMATS,
+		},
+		.ops = &mtk_dai_i2s_ops,
+	},
+	{
+		.name = "I2S7",
+		.id = MT8192_DAI_I2S_7,
+		.playback = {
+			.stream_name = "I2S7",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_I2S_RATES,
+			.formats = MTK_I2S_FORMATS,
+		},
+		.ops = &mtk_dai_i2s_ops,
+	},
+	{
+		.name = "I2S8",
+		.id = MT8192_DAI_I2S_8,
+		.capture = {
+			.stream_name = "I2S8",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_I2S_RATES,
+			.formats = MTK_I2S_FORMATS,
+		},
+		.ops = &mtk_dai_i2s_ops,
+	},
+	{
+		.name = "I2S9",
+		.id = MT8192_DAI_I2S_9,
+		.playback = {
+			.stream_name = "I2S9",
+			.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_I2S6,
+	DAI_I2S7,
+	DAI_I2S8,
+	DAI_I2S9,
+	DAI_I2S_NUM,
+};
+
+static const struct mtk_afe_i2s_priv mt8192_i2s_priv[DAI_I2S_NUM] = {
+	[DAI_I2S0] = {
+		.id = MT8192_DAI_I2S_0,
+		.mclk_id = MT8192_I2S0_MCK,
+		.share_property_name = "i2s0-share",
+		.share_i2s_id = -1,
+	},
+	[DAI_I2S1] = {
+		.id = MT8192_DAI_I2S_1,
+		.mclk_id = MT8192_I2S1_MCK,
+		.share_property_name = "i2s1-share",
+		.share_i2s_id = -1,
+	},
+	[DAI_I2S2] = {
+		.id = MT8192_DAI_I2S_2,
+		.mclk_id = MT8192_I2S2_MCK,
+		.share_property_name = "i2s2-share",
+		.share_i2s_id = -1,
+	},
+	[DAI_I2S3] = {
+		.id = MT8192_DAI_I2S_3,
+		.mclk_id = MT8192_I2S3_MCK,
+		.share_property_name = "i2s3-share",
+		.share_i2s_id = -1,
+	},
+	[DAI_I2S5] = {
+		.id = MT8192_DAI_I2S_5,
+		.mclk_id = MT8192_I2S5_MCK,
+		.share_property_name = "i2s5-share",
+		.share_i2s_id = -1,
+	},
+	[DAI_I2S6] = {
+		.id = MT8192_DAI_I2S_6,
+		.mclk_id = MT8192_I2S6_MCK,
+		.share_property_name = "i2s6-share",
+		.share_i2s_id = -1,
+	},
+	[DAI_I2S7] = {
+		.id = MT8192_DAI_I2S_7,
+		.mclk_id = MT8192_I2S7_MCK,
+		.share_property_name = "i2s7-share",
+		.share_i2s_id = -1,
+	},
+	[DAI_I2S8] = {
+		.id = MT8192_DAI_I2S_8,
+		.mclk_id = MT8192_I2S8_MCK,
+		.share_property_name = "i2s8-share",
+		.share_i2s_id = -1,
+	},
+	[DAI_I2S9] = {
+		.id = MT8192_DAI_I2S_9,
+		.mclk_id = MT8192_I2S9_MCK,
+		.share_property_name = "i2s9-share",
+		.share_i2s_id = -1,
+	},
+};
+
+static int mt8192_dai_i2s_get_share(struct mtk_base_afe *afe)
+{
+	struct mt8192_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[mt8192_i2s_priv[i].id];
+		property_name = mt8192_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 mt8192_dai_i2s_set_priv(struct mtk_base_afe *afe)
+{
+	int i;
+	int ret;
+
+	for (i = 0; i < DAI_I2S_NUM; i++) {
+		ret = mt8192_dai_set_priv(afe, mt8192_i2s_priv[i].id,
+					  sizeof(struct mtk_afe_i2s_priv),
+					  &mt8192_i2s_priv[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int mt8192_dai_i2s_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+	int ret;
+
+	dev_dbg(afe->dev, "%s()\n", __func__);
+
+	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+
+	list_add(&dai->list, &afe->sub_dais);
+
+	dai->dai_drivers = mtk_dai_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 = mt8192_dai_i2s_set_priv(afe);
+	if (ret)
+		return ret;
+
+	/* parse share i2s */
+	ret = mt8192_dai_i2s_get_share(afe);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c b/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c
new file mode 100644
index 000000000000..6e94cfdf06fc
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI I2S Control
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+//
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+
+#include "mt8192-afe-common.h"
+#include "mt8192-interconnection.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),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN7_1,
+				    I_DL4_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),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN8_1,
+				    I_DL4_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch4_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN27,
+				    I_I2S0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN27,
+				    I_I2S0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN27,
+				    I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN27,
+				    I_I2S2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN27,
+				    I_I2S2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN27_1,
+				    I_DL4_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("ADDA_UL_CH2", AFE_CONN17,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN17,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN17,
+				    I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN17_1,
+				    I_DL4_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN18,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN18,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN18,
+				    I_ADDA_UL_CH3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN18,
+				    I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN18_1,
+				    I_DL4_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch3_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN23,
+				    I_ADDA_UL_CH3, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch4_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN24,
+				    I_I2S0_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN24,
+				    I_I2S0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN24,
+				    I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN24,
+				    I_I2S2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN24,
+				    I_I2S2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN24_1,
+				    I_DL4_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch5_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN25,
+				    I_I2S0_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN25,
+				    I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN25,
+				    I_I2S2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN25_1,
+				    I_DL4_CH2, 1, 0),
+};
+
+static int mtk_pcm_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);
+
+	dev_info(afe->dev, "%s(), name %s, event 0x%x\n",
+		 __func__, w->name, event);
+	return 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_CH3", SND_SOC_NOPM, 0, 0,
+			   mtk_pcm_2_playback_ch3_mix,
+			   ARRAY_SIZE(mtk_pcm_2_playback_ch3_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_MIXER("PCM_2_PB_CH5", SND_SOC_NOPM, 0, 0,
+			   mtk_pcm_2_playback_ch5_mix,
+			   ARRAY_SIZE(mtk_pcm_2_playback_ch5_mix)),
+
+	SND_SOC_DAPM_SUPPLY("PCM_1_EN",
+			    PCM_INTF_CON1, PCM_EN_SFT, 0,
+			    mtk_pcm_en_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("PCM_2_EN",
+			    PCM2_INTF_CON, PCM2_EN_SFT, 0,
+			    mtk_pcm_en_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	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_CH3"},
+	{"PCM 2 Playback", NULL, "PCM_2_PB_CH4"},
+	{"PCM 2 Playback", NULL, "PCM_2_PB_CH5"},
+
+	{"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"},
+
+	{"PCM_1_PB_CH1", "DL4_CH1", "DL4"},
+	{"PCM_1_PB_CH2", "DL4_CH2", "DL4"},
+	{"PCM_1_PB_CH4", "DL4_CH1", "DL4"},
+	{"PCM_2_PB_CH1", "DL4_CH1", "DL4"},
+	{"PCM_2_PB_CH2", "DL4_CH2", "DL4"},
+	{"PCM_2_PB_CH4", "DL4_CH1", "DL4"},
+	{"PCM_1_PB_CH4", "I2S0_CH1", "I2S0"},
+	{"PCM_2_PB_CH4", "I2S2_CH1", "I2S2"},
+	{"PCM_2_PB_CH5", "DL1_CH2", "DL1"},
+	{"PCM_2_PB_CH5", "DL4_CH2", "DL4"},
+	{"PCM_2_PB_CH5", "I2S0_CH2", "I2S0"},
+	{"PCM_2_PB_CH5", "I2S2_CH2", "I2S2"},
+};
+
+/* 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 = mt8192_rate_transform(afe->dev, rate, dai->id);
+	unsigned int pcm_con = 0;
+
+	dev_info(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 MT8192_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 MT8192_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 = MT8192_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 = MT8192_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 mt8192_dai_pcm_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+
+	dev_info(afe->dev, "%s()\n", __func__);
+
+	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+
+	list_add(&dai->list, &afe->sub_dais);
+
+	dai->dai_drivers = mtk_dai_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/mt8192/mt8192-dai-tdm.c b/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c
new file mode 100644
index 000000000000..8383536b7ae0
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c
@@ -0,0 +1,778 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI TDM Control
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Shane Chien <shane.chien@mediatek.com>
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+
+#include "mt8192-afe-clk.h"
+#include "mt8192-afe-common.h"
+#include "mt8192-afe-gpio.h"
+#include "mt8192-interconnection.h"
+
+struct mtk_afe_tdm_priv {
+	int id;
+	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_DSP_A = 1,
+	TDM_OUT_DSP_B = 2,
+};
+
+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,
+};
+
+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_DSP_A || mode == TDM_OUT_DSP_B)
+		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,
+	SUPPLY_SEQ_TDM_EN,
+};
+
+static int get_tdm_id_by_name(const char *name)
+{
+	return MT8192_DAI_TDM;
+}
+
+static int mtk_tdm_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 mt8192_afe_private *afe_priv = afe->platform_priv;
+	int dai_id = get_tdm_id_by_name(w->name);
+	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+	if (!tdm_priv) {
+		dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
+		return -EINVAL;
+	}
+
+	dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+		 __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8192_afe_gpio_request(afe->dev, true, tdm_priv->id, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		mt8192_afe_gpio_request(afe->dev, false, tdm_priv->id, 0);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+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 mt8192_afe_private *afe_priv = afe->platform_priv;
+	int dai_id = get_tdm_id_by_name(w->name);
+	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+	if (!tdm_priv) {
+		dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
+		return -EINVAL;
+	}
+
+	dev_info(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n",
+		 __func__, w->name, event, dai_id);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8192_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		mt8192_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 mt8192_afe_private *afe_priv = afe->platform_priv;
+	int dai_id = get_tdm_id_by_name(w->name);
+	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+	if (!tdm_priv) {
+		dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
+		return -EINVAL;
+	}
+
+	dev_info(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n",
+		 __func__, w->name, event, dai_id);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mt8192_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tdm_priv->mclk_rate = 0;
+		mt8192_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_EN", SUPPLY_SEQ_TDM_EN,
+			      AFE_TDM_CON1, TDM_EN_SFT, 0,
+			      mtk_tdm_en_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	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 mt8192_afe_private *afe_priv = afe->platform_priv;
+	int dai_id = get_tdm_id_by_name(w->name);
+	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+	int cur_apll;
+
+	/* which apll */
+	cur_apll = mt8192_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", NULL, "TDM_EN"},
+	{"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 = mt8192_get_apll_by_rate(afe, freq);
+	apll_rate = mt8192_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 mt8192_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)
+		tdm_con |= 1 << 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_DSP_A) {
+		tdm_con |= 0 << DELAY_DATA_SFT;
+		tdm_con |= 0 << LRCK_TDM_WIDTH_SFT;
+	} else if (tdm_priv->tdm_out_mode == TDM_OUT_DSP_B) {
+		tdm_con |= 1 << 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,
+			   HDMI_CH_NUM_MASK_SFT,
+			   channels << HDMI_CH_NUM_SFT);
+	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 mt8192_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 mt8192_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_DSP_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		tdm_priv->tdm_out_mode = TDM_OUT_DSP_B;
+		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,
+	.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 = MT8192_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,
+	},
+};
+
+static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe)
+{
+	struct mtk_afe_tdm_priv *tdm_priv;
+
+	tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
+				GFP_KERNEL);
+	if (!tdm_priv)
+		return NULL;
+
+	tdm_priv->mclk_multiple = 128;
+	tdm_priv->bck_id = MT8192_I2S4_BCK;
+	tdm_priv->mclk_id = MT8192_I2S4_MCK;
+	tdm_priv->id = MT8192_DAI_TDM;
+
+	return tdm_priv;
+}
+
+int mt8192_dai_tdm_register(struct mtk_base_afe *afe)
+{
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_tdm_priv *tdm_priv;
+	struct mtk_base_afe_dai *dai;
+
+	dev_info(afe->dev, "%s()\n", __func__);
+
+	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+
+	list_add(&dai->list, &afe->sub_dais);
+
+	dai->dai_drivers = mtk_dai_tdm_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
+
+	dai->dapm_widgets = mtk_dai_tdm_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
+	dai->dapm_routes = mtk_dai_tdm_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
+
+	tdm_priv = init_tdm_priv_data(afe);
+	if (!tdm_priv)
+		return -ENOMEM;
+
+	afe_priv->dai_priv[MT8192_DAI_TDM] = tdm_priv;
+
+	return 0;
+}
diff --git a/sound/soc/mediatek/mt8192/mt8192-interconnection.h b/sound/soc/mediatek/mt8192/mt8192-interconnection.h
new file mode 100644
index 000000000000..6a1bc7c1a862
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-interconnection.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Mediatek MT8192 audio driver interconnection definition
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Shane Chien <shane.chien@mediatek.com>
+ */
+
+#ifndef _MT8192_INTERCONNECTION_H_
+#define _MT8192_INTERCONNECTION_H_
+
+/* in port define */
+#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_ADDA_UL_CH3 17
+#define I_ADDA_UL_CH4 18
+#define I_DL12_CH1 19
+#define I_DL12_CH2 20
+#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
+#define I_I2S2_CH3 27
+#define I_I2S2_CH4 28
+
+/* in port define >= 32 */
+#define I_32_OFFSET 32
+#define I_CONNSYS_I2S_CH1 (34 - I_32_OFFSET)
+#define I_CONNSYS_I2S_CH2 (35 - I_32_OFFSET)
+#define I_SRC_1_OUT_CH1 (36 - I_32_OFFSET)
+#define I_SRC_1_OUT_CH2 (37 - I_32_OFFSET)
+#define I_SRC_2_OUT_CH1 (38 - I_32_OFFSET)
+#define I_SRC_2_OUT_CH2 (39 - I_32_OFFSET)
+#define I_DL4_CH1 (40 - I_32_OFFSET)
+#define I_DL4_CH2 (41 - I_32_OFFSET)
+#define I_DL5_CH1 (42 - I_32_OFFSET)
+#define I_DL5_CH2 (43 - I_32_OFFSET)
+#define I_DL6_CH1 (44 - I_32_OFFSET)
+#define I_DL6_CH2 (45 - I_32_OFFSET)
+#define I_DL7_CH1 (46 - I_32_OFFSET)
+#define I_DL7_CH2 (47 - I_32_OFFSET)
+#define I_DL8_CH1 (48 - I_32_OFFSET)
+#define I_DL8_CH2 (49 - I_32_OFFSET)
+#define I_DL9_CH1 (50 - I_32_OFFSET)
+#define I_DL9_CH2 (51 - I_32_OFFSET)
+#define I_I2S6_CH1 (52 - I_32_OFFSET)
+#define I_I2S6_CH2 (53 - I_32_OFFSET)
+#define I_I2S8_CH1 (54 - I_32_OFFSET)
+#define I_I2S8_CH2 (55 - I_32_OFFSET)
+
+#endif
diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
new file mode 100644
index 000000000000..716fbb4126b5
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
@@ -0,0 +1,1137 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8192-mt6359-rt1015-rt5682.c  --
+//	MT8192-MT6359-RT1015-RT6358 ALSA SoC machine driver
+//
+// Copyright (c) 2020 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+//
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/rt5682.h>
+#include <sound/soc.h>
+
+#include "../../codecs/mt6359.h"
+#include "../../codecs/rt1015.h"
+#include "../../codecs/rt5682.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "mt8192-afe-common.h"
+#include "mt8192-afe-clk.h"
+#include "mt8192-afe-gpio.h"
+
+#define RT1015_CODEC_DAI	"rt1015-aif"
+#define RT1015_DEV0_NAME	"rt1015.1-0028"
+#define RT1015_DEV1_NAME	"rt1015.1-0029"
+
+#define RT5682_CODEC_DAI	"rt5682-aif1"
+#define RT5682_DEV0_NAME	"rt5682.1-001a"
+
+static struct snd_soc_jack headset_jack;
+
+static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
+				       struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct snd_soc_dai *codec_dai;
+	unsigned int rate = params_rate(params);
+	unsigned int mclk_fs_ratio = 128;
+	unsigned int mclk_fs = rate * mclk_fs_ratio;
+	int ret, i;
+
+	for_each_rtd_codec_dais(rtd, i, codec_dai) {
+		ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
+		if (ret) {
+			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,
+					  params_rate(params) * 64,
+					  params_rate(params) * 256);
+		if (ret) {
+			dev_err(card->dev, "failed to set pll\n");
+			return ret;
+		}
+
+		ret = snd_soc_dai_set_sysclk(codec_dai,
+					     RT1015_SCLK_S_PLL,
+					     params_rate(params) * 256,
+					     SND_SOC_CLOCK_IN);
+		if (ret) {
+			dev_err(card->dev, "failed to set sysclk\n");
+			return ret;
+		}
+	}
+
+	return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static int mt8192_rt5682_i2s_hw_params(struct snd_pcm_substream *substream,
+				       struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+	unsigned int rate = params_rate(params);
+	unsigned int mclk_fs_ratio = 128;
+	unsigned int mclk_fs = rate * mclk_fs_ratio;
+	int bitwidth;
+	int ret;
+
+	bitwidth = snd_pcm_format_width(params_format(params));
+	if (bitwidth < 0) {
+		dev_err(card->dev, "invalid bit width: %d\n", bitwidth);
+		return bitwidth;
+	}
+
+	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth);
+	if (ret) {
+		dev_err(card->dev, "failed to set tdm slot\n");
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1,
+				  RT5682_PLL1_S_BCLK1,
+				  params_rate(params) * 64,
+				  params_rate(params) * 512);
+	if (ret) {
+		dev_err(card->dev, "failed to set pll\n");
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai,
+				     RT5682_SCLK_S_PLL1,
+				     params_rate(params) * 512,
+				     SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(card->dev, "failed to set sysclk\n");
+		return ret;
+	}
+
+	return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8192_rt1015_i2s_ops = {
+	.hw_params = mt8192_rt1015_i2s_hw_params,
+};
+
+static const struct snd_soc_ops mt8192_rt5682_i2s_ops = {
+	.hw_params = mt8192_rt5682_i2s_hw_params,
+};
+
+static int mt8192_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_component *cmpnt_afe =
+		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct snd_soc_component *cmpnt_codec =
+		asoc_rtd_to_codec(rtd, 0)->component;
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+	int phase;
+	unsigned int monitor;
+	int test_done_1, test_done_2, test_done_3;
+	int cycle_1, cycle_2, cycle_3;
+	int prev_cycle_1, prev_cycle_2, prev_cycle_3;
+	int chosen_phase_1, chosen_phase_2, chosen_phase_3;
+	int counter;
+	int mtkaif_calib_ok;
+
+	dev_info(afe->dev, "%s(), start\n", __func__);
+
+	pm_runtime_get_sync(afe->dev);
+	mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 1);
+	mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 0);
+	mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34, 1);
+	mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34, 0);
+
+	mt6359_mtkaif_calibration_enable(cmpnt_codec);
+
+	/* set clock protocol 2 */
+	regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, 0xff, 0x38);
+	regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, 0xff, 0x39);
+
+	/* set test type to synchronizer pulse */
+	regmap_update_bits(afe_priv->topckgen,
+			   CKSYS_AUD_TOP_CFG, 0xffff, 0x4);
+
+	mtkaif_calib_ok = true;
+	afe_priv->mtkaif_calibration_num_phase = 42;	/* mt6359: 0 ~ 42 */
+	afe_priv->mtkaif_chosen_phase[0] = -1;
+	afe_priv->mtkaif_chosen_phase[1] = -1;
+	afe_priv->mtkaif_chosen_phase[2] = -1;
+
+	for (phase = 0;
+	     phase <= afe_priv->mtkaif_calibration_num_phase &&
+	     mtkaif_calib_ok;
+	     phase++) {
+		mt6359_set_mtkaif_calibration_phase(cmpnt_codec,
+						    phase, phase, phase);
+
+		regmap_update_bits(afe_priv->topckgen,
+				   CKSYS_AUD_TOP_CFG, 0x1, 0x1);
+
+		test_done_1 = 0;
+		test_done_2 = 0;
+		test_done_3 = 0;
+		cycle_1 = -1;
+		cycle_2 = -1;
+		cycle_3 = -1;
+		counter = 0;
+		while (test_done_1 == 0 ||
+		       test_done_2 == 0 ||
+		       test_done_3 == 0) {
+			regmap_read(afe_priv->topckgen,
+				    CKSYS_AUD_TOP_MON, &monitor);
+
+			test_done_1 = (monitor >> 28) & 0x1;
+			test_done_2 = (monitor >> 29) & 0x1;
+			test_done_3 = (monitor >> 30) & 0x1;
+			if (test_done_1 == 1)
+				cycle_1 = monitor & 0xf;
+
+			if (test_done_2 == 1)
+				cycle_2 = (monitor >> 4) & 0xf;
+
+			if (test_done_3 == 1)
+				cycle_3 = (monitor >> 8) & 0xf;
+
+			/* handle if never test done */
+			if (++counter > 10000) {
+				dev_err(afe->dev, "%s(), test fail, cycle_1 %d, cycle_2 %d, cycle_3 %d, monitor 0x%x\n",
+					__func__,
+					cycle_1, cycle_2, cycle_3, monitor);
+				mtkaif_calib_ok = false;
+				break;
+			}
+		}
+
+		if (phase == 0) {
+			prev_cycle_1 = cycle_1;
+			prev_cycle_2 = cycle_2;
+			prev_cycle_3 = cycle_3;
+		}
+
+		if (cycle_1 != prev_cycle_1 &&
+		    afe_priv->mtkaif_chosen_phase[0] < 0) {
+			afe_priv->mtkaif_chosen_phase[0] = phase - 1;
+			afe_priv->mtkaif_phase_cycle[0] = prev_cycle_1;
+		}
+
+		if (cycle_2 != prev_cycle_2 &&
+		    afe_priv->mtkaif_chosen_phase[1] < 0) {
+			afe_priv->mtkaif_chosen_phase[1] = phase - 1;
+			afe_priv->mtkaif_phase_cycle[1] = prev_cycle_2;
+		}
+
+		if (cycle_3 != prev_cycle_3 &&
+		    afe_priv->mtkaif_chosen_phase[2] < 0) {
+			afe_priv->mtkaif_chosen_phase[2] = phase - 1;
+			afe_priv->mtkaif_phase_cycle[2] = prev_cycle_3;
+		}
+
+		regmap_update_bits(afe_priv->topckgen,
+				   CKSYS_AUD_TOP_CFG, 0x1, 0x0);
+
+		if (afe_priv->mtkaif_chosen_phase[0] >= 0 &&
+		    afe_priv->mtkaif_chosen_phase[1] >= 0 &&
+		    afe_priv->mtkaif_chosen_phase[2] >= 0)
+			break;
+	}
+
+	if (afe_priv->mtkaif_chosen_phase[0] < 0)
+		chosen_phase_1 = 0;
+	else
+		chosen_phase_1 = afe_priv->mtkaif_chosen_phase[0];
+
+	if (afe_priv->mtkaif_chosen_phase[1] < 0)
+		chosen_phase_2 = 0;
+	else
+		chosen_phase_2 = afe_priv->mtkaif_chosen_phase[1];
+
+	if (afe_priv->mtkaif_chosen_phase[2] < 0)
+		chosen_phase_3 = 0;
+	else
+		chosen_phase_3 = afe_priv->mtkaif_chosen_phase[2];
+
+	mt6359_set_mtkaif_calibration_phase(cmpnt_codec,
+					    chosen_phase_1,
+					    chosen_phase_2,
+					    chosen_phase_3);
+
+	/* disable rx fifo */
+	regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, 0xff, 0x38);
+
+	mt6359_mtkaif_calibration_disable(cmpnt_codec);
+
+	mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 1);
+	mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 0);
+	mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34, 1);
+	mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34, 0);
+	pm_runtime_put(afe->dev);
+
+	dev_info(afe->dev, "%s(), mtkaif_chosen_phase[0/1/2]:%d/%d/%d\n",
+		 __func__,
+		 afe_priv->mtkaif_chosen_phase[0],
+		 afe_priv->mtkaif_chosen_phase[1],
+		 afe_priv->mtkaif_chosen_phase[2]);
+
+	return 0;
+}
+
+static int mt8192_mt6359_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_component *cmpnt_afe =
+		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct snd_soc_component *cmpnt_codec =
+		asoc_rtd_to_codec(rtd, 0)->component;
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
+	struct mt8192_afe_private *afe_priv = afe->platform_priv;
+
+	/* set mtkaif protocol */
+	mt6359_set_mtkaif_protocol(cmpnt_codec,
+				   MT6359_MTKAIF_PROTOCOL_2_CLK_P2);
+	afe_priv->mtkaif_protocol = MTKAIF_PROTOCOL_2_CLK_P2;
+
+	/* mtkaif calibration */
+	mt8192_mt6359_mtkaif_calibration(rtd);
+
+	return 0;
+}
+
+static int mt8192_rt5682_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_component *cmpnt_codec =
+		asoc_rtd_to_codec(rtd, 0)->component;
+	struct snd_soc_jack *jack = &headset_jack;
+	int ret;
+
+	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+				    SND_JACK_HEADSET | SND_JACK_BTN_0 |
+				    SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+				    SND_JACK_BTN_3,
+				    jack, NULL, 0);
+	if (ret) {
+		dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+		return ret;
+	}
+
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+	ret = snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
+	if (ret) {
+		dev_err(rtd->dev, "Headset Jack set failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+};
+
+static int mt8192_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
+mt8192_mt6359_rt1015_rt5682_cap1_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	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 ret;
+
+	static const unsigned int channels[] = {
+		1, 2, 4
+	};
+	static const struct snd_pcm_hw_constraint_list constraints_channels = {
+		.count = ARRAY_SIZE(channels),
+		.list = channels,
+		.mask = 0,
+	};
+	static const unsigned int rates[] = {
+		8000, 16000, 32000, 48000, 96000, 192000
+	};
+	static const struct snd_pcm_hw_constraint_list constraints_rates = {
+		.count = ARRAY_SIZE(rates),
+		.list  = rates,
+		.mask = 0,
+	};
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+					 SNDRV_PCM_HW_PARAM_CHANNELS,
+					 &constraints_channels);
+	if (ret < 0) {
+		dev_err(afe->dev, "hw_constraint_list channels failed\n");
+		return ret;
+	}
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+					 SNDRV_PCM_HW_PARAM_RATE,
+					 &constraints_rates);
+	if (ret < 0) {
+		dev_err(afe->dev, "hw_constraint_list rate failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_ops mt8192_mt6359_rt1015_rt5682_capture1_ops = {
+	.startup = mt8192_mt6359_rt1015_rt5682_cap1_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(playback12,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL12")),
+		     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(playback4,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL4")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback5,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL5")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback6,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL6")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback7,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL7")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback8,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL8")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback9,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL9")),
+		     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(capture4,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL4")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture5,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL5")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture6,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL6")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture7,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL7")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture8,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL8")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture_mono1,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_1")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture_mono2,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_2")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture_mono3,
+		     DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_3")),
+		     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("mt6359-sound",
+						   "mt6359-snd-codec-aif1"),
+					COMP_CODEC("dmic-codec",
+						   "dmic-hifi")),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(primary_codec_ch34,
+		     DAILINK_COMP_ARRAY(COMP_CPU("ADDA_CH34")),
+		     DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound",
+						   "mt6359-snd-codec-aif2")),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(ap_dmic,
+		     DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(ap_dmic_ch34,
+		     DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_CH34")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s0,
+		     DAILINK_COMP_ARRAY(COMP_CPU("I2S0")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     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_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(i2s3_rt1015p,
+		     DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
+		     DAILINK_COMP_ARRAY(COMP_CODEC("rt1015p", "HiFi")),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s5,
+		     DAILINK_COMP_ARRAY(COMP_CPU("I2S5")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s6,
+		     DAILINK_COMP_ARRAY(COMP_CPU("I2S6")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s7,
+		     DAILINK_COMP_ARRAY(COMP_CPU("I2S7")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s8,
+		     DAILINK_COMP_ARRAY(COMP_CPU("I2S8")),
+		     DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME,
+						   RT5682_CODEC_DAI)),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s9,
+		     DAILINK_COMP_ARRAY(COMP_CPU("I2S9")),
+		     DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME,
+						   RT5682_CODEC_DAI)),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(connsys_i2s,
+		     DAILINK_COMP_ARRAY(COMP_CPU("CONNSYS_I2S")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     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(tdm,
+		     DAILINK_COMP_ARRAY(COMP_CPU("TDM")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
+	/* Front End DAI links */
+	{
+		.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_12",
+		.stream_name = "Playback_12",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback12),
+	},
+	{
+		.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(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 = "Playback_4",
+		.stream_name = "Playback_4",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback4),
+	},
+	{
+		.name = "Playback_5",
+		.stream_name = "Playback_5",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback5),
+	},
+	{
+		.name = "Playback_6",
+		.stream_name = "Playback_6",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback6),
+	},
+	{
+		.name = "Playback_7",
+		.stream_name = "Playback_7",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback7),
+	},
+	{
+		.name = "Playback_8",
+		.stream_name = "Playback_8",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback8),
+	},
+	{
+		.name = "Playback_9",
+		.stream_name = "Playback_9",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback9),
+	},
+	{
+		.name = "Capture_1",
+		.stream_name = "Capture_1",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		.ops = &mt8192_mt6359_rt1015_rt5682_capture1_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_4",
+		.stream_name = "Capture_4",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture4),
+	},
+	{
+		.name = "Capture_5",
+		.stream_name = "Capture_5",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture5),
+	},
+	{
+		.name = "Capture_6",
+		.stream_name = "Capture_6",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture6),
+	},
+	{
+		.name = "Capture_7",
+		.stream_name = "Capture_7",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture7),
+	},
+	{
+		.name = "Capture_8",
+		.stream_name = "Capture_8",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture8),
+	},
+	{
+		.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_mono1),
+	},
+	{
+		.name = "Capture_Mono_2",
+		.stream_name = "Capture_Mono_2",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture_mono2),
+	},
+	{
+		.name = "Capture_Mono_3",
+		.stream_name = "Capture_Mono_3",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture_mono3),
+	},
+	{
+		.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),
+	},
+	/* Back End DAI links */
+	{
+		.name = "Primary Codec",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+		.init = mt8192_mt6359_init,
+		SND_SOC_DAILINK_REG(primary_codec),
+	},
+	{
+		.name = "Primary Codec CH34",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(primary_codec_ch34),
+	},
+	{
+		.name = "AP_DMIC",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(ap_dmic),
+	},
+	{
+		.name = "AP_DMIC_CH34",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(ap_dmic_ch34),
+	},
+	{
+		.name = "I2S0",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+		.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+		SND_SOC_DAILINK_REG(i2s0),
+	},
+	{
+		.name = "I2S1",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.ignore_suspend = 1,
+		.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+		SND_SOC_DAILINK_REG(i2s1),
+	},
+	{
+		.name = "I2S2",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+		.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+		SND_SOC_DAILINK_REG(i2s2),
+	},
+	{
+		.name = "I2S3",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.ignore_suspend = 1,
+		.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+	},
+	{
+		.name = "I2S5",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.ignore_suspend = 1,
+		.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+		SND_SOC_DAILINK_REG(i2s5),
+	},
+	{
+		.name = "I2S6",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+		.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+		SND_SOC_DAILINK_REG(i2s6),
+	},
+	{
+		.name = "I2S7",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.ignore_suspend = 1,
+		.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+		SND_SOC_DAILINK_REG(i2s7),
+	},
+	{
+		.name = "I2S8",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+		.init = mt8192_rt5682_init,
+		.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+		SND_SOC_DAILINK_REG(i2s8),
+		.ops = &mt8192_rt5682_i2s_ops,
+	},
+	{
+		.name = "I2S9",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.ignore_suspend = 1,
+		.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
+		SND_SOC_DAILINK_REG(i2s9),
+		.ops = &mt8192_rt5682_i2s_ops,
+	},
+	{
+		.name = "CONNSYS_I2S",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(connsys_i2s),
+	},
+	{
+		.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 = "TDM",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(tdm),
+	},
+};
+
+static const struct snd_soc_dapm_widget
+mt8192_mt6359_rt1015_rt5682_widgets[] = {
+	SND_SOC_DAPM_SPK("Left Spk", NULL),
+	SND_SOC_DAPM_SPK("Right Spk", NULL),
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mt8192_mt6359_rt1015_rt5682_routes[] = {
+	/* speaker */
+	{ "Left Spk", NULL, "Left SPO" },
+	{ "Right Spk", NULL, "Right SPO" },
+	/* headset */
+	{ "Headphone Jack", NULL, "HPOL" },
+	{ "Headphone Jack", NULL, "HPOR" },
+	{ "IN1P", NULL, "Headset Mic" },
+};
+
+static const struct snd_kcontrol_new mt8192_mt6359_rt1015_rt5682_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Left Spk"),
+	SOC_DAPM_PIN_SWITCH("Right Spk"),
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static struct snd_soc_codec_conf 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 mt8192_mt6359_rt1015_rt5682_card = {
+	.name = "mt8192_mt6359_rt1015_rt5682",
+	.owner = THIS_MODULE,
+	.dai_link = mt8192_mt6359_dai_links,
+	.num_links = ARRAY_SIZE(mt8192_mt6359_dai_links),
+	.controls = mt8192_mt6359_rt1015_rt5682_controls,
+	.num_controls = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_controls),
+	.dapm_widgets = mt8192_mt6359_rt1015_rt5682_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_widgets),
+	.dapm_routes = mt8192_mt6359_rt1015_rt5682_routes,
+	.num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_routes),
+	.codec_conf = rt1015_amp_conf,
+	.num_configs = ARRAY_SIZE(rt1015_amp_conf),
+};
+
+static const struct snd_soc_dapm_widget
+mt8192_mt6359_rt1015p_rt5682_widgets[] = {
+	SND_SOC_DAPM_SPK("Speakers", NULL),
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mt8192_mt6359_rt1015p_rt5682_routes[] = {
+	/* speaker */
+	{ "Speakers", NULL, "Speaker" },
+	/* headset */
+	{ "Headphone Jack", NULL, "HPOL" },
+	{ "Headphone Jack", NULL, "HPOR" },
+	{ "IN1P", NULL, "Headset Mic" },
+};
+
+static const struct snd_kcontrol_new mt8192_mt6359_rt1015p_rt5682_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Speakers"),
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682_card = {
+	.name = "mt8192_mt6359_rt1015p_rt5682",
+	.owner = THIS_MODULE,
+	.dai_link = mt8192_mt6359_dai_links,
+	.num_links = ARRAY_SIZE(mt8192_mt6359_dai_links),
+	.controls = mt8192_mt6359_rt1015p_rt5682_controls,
+	.num_controls = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682_controls),
+	.dapm_widgets = mt8192_mt6359_rt1015p_rt5682_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682_widgets),
+	.dapm_routes = mt8192_mt6359_rt1015p_rt5682_routes,
+	.num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682_routes),
+};
+
+static int mt8192_mt6359_dev_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card;
+	struct device_node *platform_node;
+	int ret, i;
+	struct snd_soc_dai_link *dai_link;
+	const struct of_device_id *match;
+
+	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;
+
+	for_each_card_prelinks(card, i, dai_link) {
+		if (strcmp(dai_link->name, "I2S3") == 0) {
+			if (card == &mt8192_mt6359_rt1015_rt5682_card) {
+				dai_link->ops = &mt8192_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 == &mt8192_mt6359_rt1015p_rt5682_card) {
+				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 (!dai_link->platforms->name)
+			dai_link->platforms->of_node = platform_node;
+	}
+
+	ret = mt8192_afe_gpio_init(&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "init gpio error %d\n", ret);
+		return ret;
+	}
+
+	return devm_snd_soc_register_card(&pdev->dev, card);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt8192_mt6359_dt_match[] = {
+	{
+		.compatible = "mediatek,mt8192_mt6359_rt1015_rt5682",
+		.data = &mt8192_mt6359_rt1015_rt5682_card,
+	},
+	{
+		.compatible = "mediatek,mt8192_mt6359_rt1015p_rt5682",
+		.data = &mt8192_mt6359_rt1015p_rt5682_card,
+	},
+	{}
+};
+#endif
+
+static const struct dev_pm_ops mt8192_mt6359_pm_ops = {
+	.poweroff = snd_soc_poweroff,
+	.restore = snd_soc_resume,
+};
+
+static struct platform_driver mt8192_mt6359_driver = {
+	.driver = {
+		.name = "mt8192_mt6359",
+#ifdef CONFIG_OF
+		.of_match_table = mt8192_mt6359_dt_match,
+#endif
+		.pm = &mt8192_mt6359_pm_ops,
+	},
+	.probe = mt8192_mt6359_dev_probe,
+};
+
+module_platform_driver(mt8192_mt6359_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8192-MT6359 ALSA SoC machine driver");
+MODULE_AUTHOR("Jiaxin Yu <jiaxin.yu@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt8192_mt6359 soc card");
diff --git a/sound/soc/mediatek/mt8192/mt8192-reg.h b/sound/soc/mediatek/mt8192/mt8192-reg.h
new file mode 100644
index 000000000000..562f25c79c34
--- /dev/null
+++ b/sound/soc/mediatek/mt8192/mt8192-reg.h
@@ -0,0 +1,3131 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8192-reg.h  --  Mediatek 8192 audio driver reg definition
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Shane Chien <shane.chien@mediatek.com>
+ */
+
+#ifndef _MT8192_REG_H_
+#define _MT8192_REG_H_
+
+/* reg bit enum */
+enum {
+	MT8192_MEMIF_PBUF_SIZE_32_BYTES,
+	MT8192_MEMIF_PBUF_SIZE_64_BYTES,
+	MT8192_MEMIF_PBUF_SIZE_128_BYTES,
+	MT8192_MEMIF_PBUF_SIZE_256_BYTES,
+	MT8192_MEMIF_PBUF_SIZE_NUM,
+};
+
+/*****************************************************************************
+ *                  R E G I S T E R       D E F I N I T I O N
+ *****************************************************************************/
+/* AFE_DAC_CON0 */
+#define VUL12_ON_SFT                                   31
+#define VUL12_ON_MASK                                  0x1
+#define VUL12_ON_MASK_SFT                              (0x1 << 31)
+#define MOD_DAI_ON_SFT                                 30
+#define MOD_DAI_ON_MASK                                0x1
+#define MOD_DAI_ON_MASK_SFT                            (0x1 << 30)
+#define DAI_ON_SFT                                     29
+#define DAI_ON_MASK                                    0x1
+#define DAI_ON_MASK_SFT                                (0x1 << 29)
+#define DAI2_ON_SFT                                    28
+#define DAI2_ON_MASK                                   0x1
+#define DAI2_ON_MASK_SFT                               (0x1 << 28)
+#define VUL6_ON_SFT                                    23
+#define VUL6_ON_MASK                                   0x1
+#define VUL6_ON_MASK_SFT                               (0x1 << 23)
+#define VUL5_ON_SFT                                    22
+#define VUL5_ON_MASK                                   0x1
+#define VUL5_ON_MASK_SFT                               (0x1 << 22)
+#define VUL4_ON_SFT                                    21
+#define VUL4_ON_MASK                                   0x1
+#define VUL4_ON_MASK_SFT                               (0x1 << 21)
+#define VUL3_ON_SFT                                    20
+#define VUL3_ON_MASK                                   0x1
+#define VUL3_ON_MASK_SFT                               (0x1 << 20)
+#define VUL2_ON_SFT                                    19
+#define VUL2_ON_MASK                                   0x1
+#define VUL2_ON_MASK_SFT                               (0x1 << 19)
+#define VUL_ON_SFT                                     18
+#define VUL_ON_MASK                                    0x1
+#define VUL_ON_MASK_SFT                                (0x1 << 18)
+#define AWB2_ON_SFT                                    17
+#define AWB2_ON_MASK                                   0x1
+#define AWB2_ON_MASK_SFT                               (0x1 << 17)
+#define AWB_ON_SFT                                     16
+#define AWB_ON_MASK                                    0x1
+#define AWB_ON_MASK_SFT                                (0x1 << 16)
+#define DL12_ON_SFT                                    15
+#define DL12_ON_MASK                                   0x1
+#define DL12_ON_MASK_SFT                               (0x1 << 15)
+#define DL9_ON_SFT                                     12
+#define DL9_ON_MASK                                    0x1
+#define DL9_ON_MASK_SFT                                (0x1 << 12)
+#define DL8_ON_SFT                                     11
+#define DL8_ON_MASK                                    0x1
+#define DL8_ON_MASK_SFT                                (0x1 << 11)
+#define DL7_ON_SFT                                     10
+#define DL7_ON_MASK                                    0x1
+#define DL7_ON_MASK_SFT                                (0x1 << 10)
+#define DL6_ON_SFT                                     9
+#define DL6_ON_MASK                                    0x1
+#define DL6_ON_MASK_SFT                                (0x1 << 9)
+#define DL5_ON_SFT                                     8
+#define DL5_ON_MASK                                    0x1
+#define DL5_ON_MASK_SFT                                (0x1 << 8)
+#define DL4_ON_SFT                                     7
+#define DL4_ON_MASK                                    0x1
+#define DL4_ON_MASK_SFT                                (0x1 << 7)
+#define DL3_ON_SFT                                     6
+#define DL3_ON_MASK                                    0x1
+#define DL3_ON_MASK_SFT                                (0x1 << 6)
+#define DL2_ON_SFT                                     5
+#define DL2_ON_MASK                                    0x1
+#define DL2_ON_MASK_SFT                                (0x1 << 5)
+#define DL1_ON_SFT                                     4
+#define DL1_ON_MASK                                    0x1
+#define DL1_ON_MASK_SFT                                (0x1 << 4)
+#define HDMI_OUT_ON_SFT                                1
+#define HDMI_OUT_ON_MASK                               0x1
+#define HDMI_OUT_ON_MASK_SFT                           (0x1 << 1)
+#define AFE_ON_SFT                                     0
+#define AFE_ON_MASK                                    0x1
+#define AFE_ON_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 I2S_OUT_MODE_SFT                               8
+#define I2S_OUT_MODE_MASK                              0xf
+#define I2S_OUT_MODE_MASK_SFT                          (0xf << 8)
+#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_CONNSYS_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 I2S_MODE_SFT                                   8
+#define I2S_MODE_MASK                                  0xf
+#define I2S_MODE_MASK_SFT                              (0xf << 8)
+#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_CON6 */
+#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 I2S6_LOOPBACK_SFT                              20
+#define I2S6_LOOPBACK_MASK                             0x1
+#define I2S6_LOOPBACK_MASK_SFT                         (0x1 << 20)
+#define I2S6_ONOFF_NOT_RESET_CK_ENABLE_SFT             17
+#define I2S6_ONOFF_NOT_RESET_CK_ENABLE_MASK            0x1
+#define I2S6_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT        (0x1 << 17)
+#define I2S6_HD_EN_SFT                                 12
+#define I2S6_HD_EN_MASK                                0x1
+#define I2S6_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S6_OUT_MODE_SFT                              8
+#define I2S6_OUT_MODE_MASK                             0xf
+#define I2S6_OUT_MODE_MASK_SFT                         (0xf << 8)
+#define I2S6_BYPSRC_SFT                                6
+#define I2S6_BYPSRC_MASK                               0x1
+#define I2S6_BYPSRC_MASK_SFT                           (0x1 << 6)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S6_FMT_SFT                                   3
+#define I2S6_FMT_MASK                                  0x1
+#define I2S6_FMT_MASK_SFT                              (0x1 << 3)
+#define I2S6_SRC_SFT                                   2
+#define I2S6_SRC_MASK                                  0x1
+#define I2S6_SRC_MASK_SFT                              (0x1 << 2)
+#define I2S6_WLEN_SFT                                  1
+#define I2S6_WLEN_MASK                                 0x1
+#define I2S6_WLEN_MASK_SFT                             (0x1 << 1)
+#define I2S6_EN_SFT                                    0
+#define I2S6_EN_MASK                                   0x1
+#define I2S6_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_I2S_CON7 */
+#define I2S7_LR_SWAP_SFT                               31
+#define I2S7_LR_SWAP_MASK                              0x1
+#define I2S7_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 I2S7_32BIT_EN_SFT                              13
+#define I2S7_32BIT_EN_MASK                             0x1
+#define I2S7_32BIT_EN_MASK_SFT                         (0x1 << 13)
+#define I2S7_HD_EN_SFT                                 12
+#define I2S7_HD_EN_MASK                                0x1
+#define I2S7_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S7_OUT_MODE_SFT                              8
+#define I2S7_OUT_MODE_MASK                             0xf
+#define I2S7_OUT_MODE_MASK_SFT                         (0xf << 8)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S7_FMT_SFT                                   3
+#define I2S7_FMT_MASK                                  0x1
+#define I2S7_FMT_MASK_SFT                              (0x1 << 3)
+#define I2S7_WLEN_SFT                                  1
+#define I2S7_WLEN_MASK                                 0x1
+#define I2S7_WLEN_MASK_SFT                             (0x1 << 1)
+#define I2S7_EN_SFT                                    0
+#define I2S7_EN_MASK                                   0x1
+#define I2S7_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_I2S_CON8 */
+#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 I2S8_LOOPBACK_SFT                              20
+#define I2S8_LOOPBACK_MASK                             0x1
+#define I2S8_LOOPBACK_MASK_SFT                         (0x1 << 20)
+#define I2S8_ONOFF_NOT_RESET_CK_ENABLE_SFT             17
+#define I2S8_ONOFF_NOT_RESET_CK_ENABLE_MASK            0x1
+#define I2S8_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT        (0x1 << 17)
+#define I2S8_HD_EN_SFT                                 12
+#define I2S8_HD_EN_MASK                                0x1
+#define I2S8_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S8_OUT_MODE_SFT                              8
+#define I2S8_OUT_MODE_MASK                             0xf
+#define I2S8_OUT_MODE_MASK_SFT                         (0xf << 8)
+#define I2S8_BYPSRC_SFT                                6
+#define I2S8_BYPSRC_MASK                               0x1
+#define I2S8_BYPSRC_MASK_SFT                           (0x1 << 6)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S8_FMT_SFT                                   3
+#define I2S8_FMT_MASK                                  0x1
+#define I2S8_FMT_MASK_SFT                              (0x1 << 3)
+#define I2S8_SRC_SFT                                   2
+#define I2S8_SRC_MASK                                  0x1
+#define I2S8_SRC_MASK_SFT                              (0x1 << 2)
+#define I2S8_WLEN_SFT                                  1
+#define I2S8_WLEN_MASK                                 0x1
+#define I2S8_WLEN_MASK_SFT                             (0x1 << 1)
+#define I2S8_EN_SFT                                    0
+#define I2S8_EN_MASK                                   0x1
+#define I2S8_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_I2S_CON9 */
+#define I2S9_LR_SWAP_SFT                               31
+#define I2S9_LR_SWAP_MASK                              0x1
+#define I2S9_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 I2S9_32BIT_EN_SFT                              13
+#define I2S9_32BIT_EN_MASK                             0x1
+#define I2S9_32BIT_EN_MASK_SFT                         (0x1 << 13)
+#define I2S9_HD_EN_SFT                                 12
+#define I2S9_HD_EN_MASK                                0x1
+#define I2S9_HD_EN_MASK_SFT                            (0x1 << 12)
+#define I2S9_OUT_MODE_SFT                              8
+#define I2S9_OUT_MODE_MASK                             0xf
+#define I2S9_OUT_MODE_MASK_SFT                         (0xf << 8)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              (0x1 << 5)
+#define I2S9_FMT_SFT                                   3
+#define I2S9_FMT_MASK                                  0x1
+#define I2S9_FMT_MASK_SFT                              (0x1 << 3)
+#define I2S9_WLEN_SFT                                  1
+#define I2S9_WLEN_MASK                                 0x1
+#define I2S9_WLEN_MASK_SFT                             (0x1 << 1)
+#define I2S9_EN_SFT                                    0
+#define I2S9_EN_MASK                                   0x1
+#define I2S9_EN_MASK_SFT                               (0x1 << 0)
+
+/* AFE_ASRC_2CH_CON2 */
+#define CHSET_O16BIT_SFT                               19
+#define CHSET_O16BIT_MASK                              0x1
+#define CHSET_O16BIT_MASK_SFT                          (0x1 << 19)
+#define CHSET_CLR_IIR_HISTORY_SFT                      17
+#define CHSET_CLR_IIR_HISTORY_MASK                     0x1
+#define CHSET_CLR_IIR_HISTORY_MASK_SFT                 (0x1 << 17)
+#define CHSET_IS_MONO_SFT                              16
+#define CHSET_IS_MONO_MASK                             0x1
+#define CHSET_IS_MONO_MASK_SFT                         (0x1 << 16)
+#define CHSET_IIR_EN_SFT                               11
+#define CHSET_IIR_EN_MASK                              0x1
+#define CHSET_IIR_EN_MASK_SFT                          (0x1 << 11)
+#define CHSET_IIR_STAGE_SFT                            8
+#define CHSET_IIR_STAGE_MASK                           0x7
+#define CHSET_IIR_STAGE_MASK_SFT                       (0x7 << 8)
+#define CHSET_STR_CLR_SFT                              5
+#define CHSET_STR_CLR_MASK                             0x1
+#define CHSET_STR_CLR_MASK_SFT                         (0x1 << 5)
+#define CHSET_ON_SFT                                   2
+#define CHSET_ON_MASK                                  0x1
+#define CHSET_ON_MASK_SFT                              (0x1 << 2)
+#define COEFF_SRAM_CTRL_SFT                            1
+#define COEFF_SRAM_CTRL_MASK                           0x1
+#define COEFF_SRAM_CTRL_MASK_SFT                       (0x1 << 1)
+#define ASM_ON_SFT                                     0
+#define ASM_ON_MASK                                    0x1
+#define ASM_ON_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                              0xfffffff
+#define GAIN1_TARGET_MASK_SFT                          (0xfffffff << 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                              0xfffffff
+#define GAIN2_TARGET_MASK_SFT                          (0xfffffff << 0)
+
+/* AFE_GAIN1_CUR */
+#define AFE_GAIN1_CUR_SFT                              0
+#define AFE_GAIN1_CUR_MASK                             0xfffffff
+#define AFE_GAIN1_CUR_MASK_SFT                         (0xfffffff << 0)
+
+/* AFE_GAIN2_CUR */
+#define AFE_GAIN2_CUR_SFT                              0
+#define AFE_GAIN2_CUR_MASK                             0xfffffff
+#define AFE_GAIN2_CUR_MASK_SFT                         (0xfffffff << 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_DMIC_PHASE_SEL_CH1_SFT                      27
+#define UL_DMIC_PHASE_SEL_CH1_MASK                     0x7
+#define UL_DMIC_PHASE_SEL_CH1_MASK_SFT                 (0x7 << 27)
+#define UL_DMIC_PHASE_SEL_CH2_SFT                      24
+#define UL_DMIC_PHASE_SEL_CH2_MASK                     0x7
+#define UL_DMIC_PHASE_SEL_CH2_MASK_SFT                 (0x7 << 24)
+#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 UL_AP_DMIC_ON_SFT                              16
+#define UL_AP_DMIC_ON_MASK                             0x1
+#define UL_AP_DMIC_ON_MASK_SFT                         (0x1 << 16)
+#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_4P33M_SEL_SFT                           6
+#define DIGMIC_4P33M_SEL_MASK                          0x1
+#define DIGMIC_4P33M_SEL_MASK_SFT                      (0x1 << 6)
+#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 ADDA_UL_GAIN_MODE_SFT                          8
+#define ADDA_UL_GAIN_MODE_MASK                         0x3
+#define ADDA_UL_GAIN_MODE_MASK_SFT                     (0x3 << 8)
+#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_ADDA_UL_LR_SWAP_SFT                        31
+#define AFE_ADDA_UL_LR_SWAP_MASK                       0x1
+#define AFE_ADDA_UL_LR_SWAP_MASK_SFT                   (0x1 << 31)
+#define AFE_ADDA_CKDIV_RST_SFT                         30
+#define AFE_ADDA_CKDIV_RST_MASK                        0x1
+#define AFE_ADDA_CKDIV_RST_MASK_SFT                    (0x1 << 30)
+#define AFE_ADDA_FIFO_AUTO_RST_SFT                     29
+#define AFE_ADDA_FIFO_AUTO_RST_MASK                    0x1
+#define AFE_ADDA_FIFO_AUTO_RST_MASK_SFT                (0x1 << 29)
+#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_SFT             21
+#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_MASK            0x3
+#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_MASK_SFT        (0x3 << 21)
+#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_SFT       20
+#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK      0x1
+#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT  (0x1 << 20)
+#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 AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_SFT            5
+#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_MASK           0x3
+#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_MASK_SFT       (0x3 << 5)
+#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_SFT      4
+#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK     0x1
+#define AFE_ADDA6_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_BYPASS_MODE_DL3_SFT                        27
+#define STF_BYPASS_MODE_DL3_MASK                       0x1
+#define STF_BYPASS_MODE_DL3_MASK_SFT                   (0x1 << 27)
+#define STF_BYPASS_MODE_I2S7_SFT                       26
+#define STF_BYPASS_MODE_I2S7_MASK                      0x1
+#define STF_BYPASS_MODE_I2S7_MASK_SFT                  (0x1 << 26)
+#define STF_BYPASS_MODE_I2S9_SFT                       25
+#define STF_BYPASS_MODE_I2S9_MASK                      0x1
+#define STF_BYPASS_MODE_I2S9_MASK_SFT                  (0x1 << 25)
+#define STF_O19O20_OUT_EN_SEL_SFT                      13
+#define STF_O19O20_OUT_EN_SEL_MASK                     0x1
+#define STF_O19O20_OUT_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 USE_3RD_SDM_SFT                                28
+#define USE_3RD_SDM_MASK                               0x1
+#define USE_3RD_SDM_MASK_SFT                           (0x1 << 28)
+#define DL_FIFO_START_POINT_SFT                        24
+#define DL_FIFO_START_POINT_MASK                       0x7
+#define DL_FIFO_START_POINT_MASK_SFT                   (0x7 << 24)
+#define DL_FIFO_SWAP_SFT                               20
+#define DL_FIFO_SWAP_MASK                              0x1
+#define DL_FIFO_SWAP_MASK_SFT                          (0x1 << 20)
+#define C_AUDSDM1ORDSELECT_CTL_SFT                     19
+#define C_AUDSDM1ORDSELECT_CTL_MASK                    0x1
+#define C_AUDSDM1ORDSELECT_CTL_MASK_SFT                (0x1 << 19)
+#define C_SDM7BITSEL_CTL_SFT                           18
+#define C_SDM7BITSEL_CTL_MASK                          0x1
+#define C_SDM7BITSEL_CTL_MASK_SFT                      (0x1 << 18)
+#define GAIN_AT_SDM_RST_PRE_CTL_SFT                    15
+#define GAIN_AT_SDM_RST_PRE_CTL_MASK                   0x1
+#define GAIN_AT_SDM_RST_PRE_CTL_MASK_SFT               (0x1 << 15)
+#define DL_DCM_AUTO_IDLE_EN_SFT                        14
+#define DL_DCM_AUTO_IDLE_EN_MASK                       0x1
+#define DL_DCM_AUTO_IDLE_EN_MASK_SFT                   (0x1 << 14)
+#define AFE_DL_SRC_DCM_EN_SFT                          13
+#define AFE_DL_SRC_DCM_EN_MASK                         0x1
+#define AFE_DL_SRC_DCM_EN_MASK_SFT                     (0x1 << 13)
+#define AFE_DL_POST_SRC_DCM_EN_SFT                     12
+#define AFE_DL_POST_SRC_DCM_EN_MASK                    0x1
+#define AFE_DL_POST_SRC_DCM_EN_MASK_SFT                (0x1 << 12)
+#define AUD_SDM_MONO_SFT                               9
+#define AUD_SDM_MONO_MASK                              0x1
+#define AUD_SDM_MONO_MASK_SFT                          (0x1 << 9)
+#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_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_ADDA_DL_NLE_FIFO_MON */
+#define DL_NLE_FIFO_WBIN_SFT                           8
+#define DL_NLE_FIFO_WBIN_MASK                          0xf
+#define DL_NLE_FIFO_WBIN_MASK_SFT                      (0xf << 8)
+#define DL_NLE_FIFO_RBIN_SFT                           4
+#define DL_NLE_FIFO_RBIN_MASK                          0xf
+#define DL_NLE_FIFO_RBIN_MASK_SFT                      (0xf << 4)
+#define DL_NLE_FIFO_RDACTIVE_SFT                       3
+#define DL_NLE_FIFO_RDACTIVE_MASK                      0x1
+#define DL_NLE_FIFO_RDACTIVE_MASK_SFT                  (0x1 << 3)
+#define DL_NLE_FIFO_STARTRD_SFT                        2
+#define DL_NLE_FIFO_STARTRD_MASK                       0x1
+#define DL_NLE_FIFO_STARTRD_MASK_SFT                   (0x1 << 2)
+#define DL_NLE_FIFO_RD_EMPTY_SFT                       1
+#define DL_NLE_FIFO_RD_EMPTY_MASK                      0x1
+#define DL_NLE_FIFO_RD_EMPTY_MASK_SFT                  (0x1 << 1)
+#define DL_NLE_FIFO_WR_FULL_SFT                        0
+#define DL_NLE_FIFO_WR_FULL_MASK                       0x1
+#define DL_NLE_FIFO_WR_FULL_MASK_SFT                   (0x1 << 0)
+
+/* AFE_DL1_CON0 */
+#define DL1_MODE_SFT                                   24
+#define DL1_MODE_MASK                                  0xf
+#define DL1_MODE_MASK_SFT                              (0xf << 24)
+#define DL1_MINLEN_SFT                                 20
+#define DL1_MINLEN_MASK                                0xf
+#define DL1_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL1_MAXLEN_SFT                                 16
+#define DL1_MAXLEN_MASK                                0xf
+#define DL1_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL1_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL1_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL1_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL1_PBUF_SIZE_SFT                              12
+#define DL1_PBUF_SIZE_MASK                             0x3
+#define DL1_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL1_MONO_SFT                                   8
+#define DL1_MONO_MASK                                  0x1
+#define DL1_MONO_MASK_SFT                              (0x1 << 8)
+#define DL1_NORMAL_MODE_SFT                            5
+#define DL1_NORMAL_MODE_MASK                           0x1
+#define DL1_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL1_HALIGN_SFT                                 4
+#define DL1_HALIGN_MASK                                0x1
+#define DL1_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL1_HD_MODE_SFT                                0
+#define DL1_HD_MODE_MASK                               0x3
+#define DL1_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL2_CON0 */
+#define DL2_MODE_SFT                                   24
+#define DL2_MODE_MASK                                  0xf
+#define DL2_MODE_MASK_SFT                              (0xf << 24)
+#define DL2_MINLEN_SFT                                 20
+#define DL2_MINLEN_MASK                                0xf
+#define DL2_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL2_MAXLEN_SFT                                 16
+#define DL2_MAXLEN_MASK                                0xf
+#define DL2_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL2_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL2_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL2_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL2_PBUF_SIZE_SFT                              12
+#define DL2_PBUF_SIZE_MASK                             0x3
+#define DL2_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL2_MONO_SFT                                   8
+#define DL2_MONO_MASK                                  0x1
+#define DL2_MONO_MASK_SFT                              (0x1 << 8)
+#define DL2_NORMAL_MODE_SFT                            5
+#define DL2_NORMAL_MODE_MASK                           0x1
+#define DL2_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL2_HALIGN_SFT                                 4
+#define DL2_HALIGN_MASK                                0x1
+#define DL2_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL2_HD_MODE_SFT                                0
+#define DL2_HD_MODE_MASK                               0x3
+#define DL2_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL3_CON0 */
+#define DL3_MODE_SFT                                   24
+#define DL3_MODE_MASK                                  0xf
+#define DL3_MODE_MASK_SFT                              (0xf << 24)
+#define DL3_MINLEN_SFT                                 20
+#define DL3_MINLEN_MASK                                0xf
+#define DL3_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL3_MAXLEN_SFT                                 16
+#define DL3_MAXLEN_MASK                                0xf
+#define DL3_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL3_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL3_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL3_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL3_PBUF_SIZE_SFT                              12
+#define DL3_PBUF_SIZE_MASK                             0x3
+#define DL3_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL3_MONO_SFT                                   8
+#define DL3_MONO_MASK                                  0x1
+#define DL3_MONO_MASK_SFT                              (0x1 << 8)
+#define DL3_NORMAL_MODE_SFT                            5
+#define DL3_NORMAL_MODE_MASK                           0x1
+#define DL3_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL3_HALIGN_SFT                                 4
+#define DL3_HALIGN_MASK                                0x1
+#define DL3_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL3_HD_MODE_SFT                                0
+#define DL3_HD_MODE_MASK                               0x3
+#define DL3_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL4_CON0 */
+#define DL4_MODE_SFT                                   24
+#define DL4_MODE_MASK                                  0xf
+#define DL4_MODE_MASK_SFT                              (0xf << 24)
+#define DL4_MINLEN_SFT                                 20
+#define DL4_MINLEN_MASK                                0xf
+#define DL4_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL4_MAXLEN_SFT                                 16
+#define DL4_MAXLEN_MASK                                0xf
+#define DL4_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL4_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL4_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL4_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL4_PBUF_SIZE_SFT                              12
+#define DL4_PBUF_SIZE_MASK                             0x3
+#define DL4_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL4_MONO_SFT                                   8
+#define DL4_MONO_MASK                                  0x1
+#define DL4_MONO_MASK_SFT                              (0x1 << 8)
+#define DL4_NORMAL_MODE_SFT                            5
+#define DL4_NORMAL_MODE_MASK                           0x1
+#define DL4_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL4_HALIGN_SFT                                 4
+#define DL4_HALIGN_MASK                                0x1
+#define DL4_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL4_HD_MODE_SFT                                0
+#define DL4_HD_MODE_MASK                               0x3
+#define DL4_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL5_CON0 */
+#define DL5_MODE_SFT                                   24
+#define DL5_MODE_MASK                                  0xf
+#define DL5_MODE_MASK_SFT                              (0xf << 24)
+#define DL5_MINLEN_SFT                                 20
+#define DL5_MINLEN_MASK                                0xf
+#define DL5_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL5_MAXLEN_SFT                                 16
+#define DL5_MAXLEN_MASK                                0xf
+#define DL5_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL5_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL5_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL5_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL5_PBUF_SIZE_SFT                              12
+#define DL5_PBUF_SIZE_MASK                             0x3
+#define DL5_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL5_MONO_SFT                                   8
+#define DL5_MONO_MASK                                  0x1
+#define DL5_MONO_MASK_SFT                              (0x1 << 8)
+#define DL5_NORMAL_MODE_SFT                            5
+#define DL5_NORMAL_MODE_MASK                           0x1
+#define DL5_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL5_HALIGN_SFT                                 4
+#define DL5_HALIGN_MASK                                0x1
+#define DL5_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL5_HD_MODE_SFT                                0
+#define DL5_HD_MODE_MASK                               0x3
+#define DL5_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL6_CON0 */
+#define DL6_MODE_SFT                                   24
+#define DL6_MODE_MASK                                  0xf
+#define DL6_MODE_MASK_SFT                              (0xf << 24)
+#define DL6_MINLEN_SFT                                 20
+#define DL6_MINLEN_MASK                                0xf
+#define DL6_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL6_MAXLEN_SFT                                 16
+#define DL6_MAXLEN_MASK                                0xf
+#define DL6_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL6_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL6_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL6_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL6_PBUF_SIZE_SFT                              12
+#define DL6_PBUF_SIZE_MASK                             0x3
+#define DL6_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL6_MONO_SFT                                   8
+#define DL6_MONO_MASK                                  0x1
+#define DL6_MONO_MASK_SFT                              (0x1 << 8)
+#define DL6_NORMAL_MODE_SFT                            5
+#define DL6_NORMAL_MODE_MASK                           0x1
+#define DL6_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL6_HALIGN_SFT                                 4
+#define DL6_HALIGN_MASK                                0x1
+#define DL6_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL6_HD_MODE_SFT                                0
+#define DL6_HD_MODE_MASK                               0x3
+#define DL6_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL7_CON0 */
+#define DL7_MODE_SFT                                   24
+#define DL7_MODE_MASK                                  0xf
+#define DL7_MODE_MASK_SFT                              (0xf << 24)
+#define DL7_MINLEN_SFT                                 20
+#define DL7_MINLEN_MASK                                0xf
+#define DL7_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL7_MAXLEN_SFT                                 16
+#define DL7_MAXLEN_MASK                                0xf
+#define DL7_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL7_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL7_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL7_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL7_PBUF_SIZE_SFT                              12
+#define DL7_PBUF_SIZE_MASK                             0x3
+#define DL7_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL7_MONO_SFT                                   8
+#define DL7_MONO_MASK                                  0x1
+#define DL7_MONO_MASK_SFT                              (0x1 << 8)
+#define DL7_NORMAL_MODE_SFT                            5
+#define DL7_NORMAL_MODE_MASK                           0x1
+#define DL7_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL7_HALIGN_SFT                                 4
+#define DL7_HALIGN_MASK                                0x1
+#define DL7_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL7_HD_MODE_SFT                                0
+#define DL7_HD_MODE_MASK                               0x3
+#define DL7_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL8_CON0 */
+#define DL8_MODE_SFT                                   24
+#define DL8_MODE_MASK                                  0xf
+#define DL8_MODE_MASK_SFT                              (0xf << 24)
+#define DL8_MINLEN_SFT                                 20
+#define DL8_MINLEN_MASK                                0xf
+#define DL8_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL8_MAXLEN_SFT                                 16
+#define DL8_MAXLEN_MASK                                0xf
+#define DL8_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL8_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL8_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL8_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL8_PBUF_SIZE_SFT                              12
+#define DL8_PBUF_SIZE_MASK                             0x3
+#define DL8_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL8_MONO_SFT                                   8
+#define DL8_MONO_MASK                                  0x1
+#define DL8_MONO_MASK_SFT                              (0x1 << 8)
+#define DL8_NORMAL_MODE_SFT                            5
+#define DL8_NORMAL_MODE_MASK                           0x1
+#define DL8_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL8_HALIGN_SFT                                 4
+#define DL8_HALIGN_MASK                                0x1
+#define DL8_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL8_HD_MODE_SFT                                0
+#define DL8_HD_MODE_MASK                               0x3
+#define DL8_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL9_CON0 */
+#define DL9_MODE_SFT                                   24
+#define DL9_MODE_MASK                                  0xf
+#define DL9_MODE_MASK_SFT                              (0xf << 24)
+#define DL9_MINLEN_SFT                                 20
+#define DL9_MINLEN_MASK                                0xf
+#define DL9_MINLEN_MASK_SFT                            (0xf << 20)
+#define DL9_MAXLEN_SFT                                 16
+#define DL9_MAXLEN_MASK                                0xf
+#define DL9_MAXLEN_MASK_SFT                            (0xf << 16)
+#define DL9_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL9_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL9_SW_CLEAR_BUF_EMPTY_MASK_SFT                (0x1 << 15)
+#define DL9_PBUF_SIZE_SFT                              12
+#define DL9_PBUF_SIZE_MASK                             0x3
+#define DL9_PBUF_SIZE_MASK_SFT                         (0x3 << 12)
+#define DL9_MONO_SFT                                   8
+#define DL9_MONO_MASK                                  0x1
+#define DL9_MONO_MASK_SFT                              (0x1 << 8)
+#define DL9_NORMAL_MODE_SFT                            5
+#define DL9_NORMAL_MODE_MASK                           0x1
+#define DL9_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DL9_HALIGN_SFT                                 4
+#define DL9_HALIGN_MASK                                0x1
+#define DL9_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DL9_HD_MODE_SFT                                0
+#define DL9_HD_MODE_MASK                               0x3
+#define DL9_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_DL12_CON0 */
+#define DL12_MODE_SFT                                  24
+#define DL12_MODE_MASK                                 0xf
+#define DL12_MODE_MASK_SFT                             (0xf << 24)
+#define DL12_MINLEN_SFT                                20
+#define DL12_MINLEN_MASK                               0xf
+#define DL12_MINLEN_MASK_SFT                           (0xf << 20)
+#define DL12_MAXLEN_SFT                                16
+#define DL12_MAXLEN_MASK                               0xf
+#define DL12_MAXLEN_MASK_SFT                           (0xf << 16)
+#define DL12_SW_CLEAR_BUF_EMPTY_SFT                    15
+#define DL12_SW_CLEAR_BUF_EMPTY_MASK                   0x1
+#define DL12_SW_CLEAR_BUF_EMPTY_MASK_SFT               (0x1 << 15)
+#define DL12_PBUF_SIZE_SFT                             12
+#define DL12_PBUF_SIZE_MASK                            0x3
+#define DL12_PBUF_SIZE_MASK_SFT                        (0x3 << 12)
+#define DL12_4CH_EN_SFT                                11
+#define DL12_4CH_EN_MASK                               0x1
+#define DL12_4CH_EN_MASK_SFT                           (0x1 << 11)
+#define DL12_MONO_SFT                                  8
+#define DL12_MONO_MASK                                 0x1
+#define DL12_MONO_MASK_SFT                             (0x1 << 8)
+#define DL12_NORMAL_MODE_SFT                           5
+#define DL12_NORMAL_MODE_MASK                          0x1
+#define DL12_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define DL12_HALIGN_SFT                                4
+#define DL12_HALIGN_MASK                               0x1
+#define DL12_HALIGN_MASK_SFT                           (0x1 << 4)
+#define DL12_HD_MODE_SFT                               0
+#define DL12_HD_MODE_MASK                              0x3
+#define DL12_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_AWB_CON0 */
+#define AWB_MODE_SFT                                   24
+#define AWB_MODE_MASK                                  0xf
+#define AWB_MODE_MASK_SFT                              (0xf << 24)
+#define AWB_SW_CLEAR_BUF_FULL_SFT                      15
+#define AWB_SW_CLEAR_BUF_FULL_MASK                     0x1
+#define AWB_SW_CLEAR_BUF_FULL_MASK_SFT                 (0x1 << 15)
+#define AWB_R_MONO_SFT                                 9
+#define AWB_R_MONO_MASK                                0x1
+#define AWB_R_MONO_MASK_SFT                            (0x1 << 9)
+#define AWB_MONO_SFT                                   8
+#define AWB_MONO_MASK                                  0x1
+#define AWB_MONO_MASK_SFT                              (0x1 << 8)
+#define AWB_WR_SIGN_SFT                                6
+#define AWB_WR_SIGN_MASK                               0x1
+#define AWB_WR_SIGN_MASK_SFT                           (0x1 << 6)
+#define AWB_NORMAL_MODE_SFT                            5
+#define AWB_NORMAL_MODE_MASK                           0x1
+#define AWB_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define AWB_HALIGN_SFT                                 4
+#define AWB_HALIGN_MASK                                0x1
+#define AWB_HALIGN_MASK_SFT                            (0x1 << 4)
+#define AWB_HD_MODE_SFT                                0
+#define AWB_HD_MODE_MASK                               0x3
+#define AWB_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_AWB2_CON0 */
+#define AWB2_MODE_SFT                                  24
+#define AWB2_MODE_MASK                                 0xf
+#define AWB2_MODE_MASK_SFT                             (0xf << 24)
+#define AWB2_SW_CLEAR_BUF_FULL_SFT                     15
+#define AWB2_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define AWB2_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define AWB2_R_MONO_SFT                                9
+#define AWB2_R_MONO_MASK                               0x1
+#define AWB2_R_MONO_MASK_SFT                           (0x1 << 9)
+#define AWB2_MONO_SFT                                  8
+#define AWB2_MONO_MASK                                 0x1
+#define AWB2_MONO_MASK_SFT                             (0x1 << 8)
+#define AWB2_WR_SIGN_SFT                               6
+#define AWB2_WR_SIGN_MASK                              0x1
+#define AWB2_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define AWB2_NORMAL_MODE_SFT                           5
+#define AWB2_NORMAL_MODE_MASK                          0x1
+#define AWB2_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define AWB2_HALIGN_SFT                                4
+#define AWB2_HALIGN_MASK                               0x1
+#define AWB2_HALIGN_MASK_SFT                           (0x1 << 4)
+#define AWB2_HD_MODE_SFT                               0
+#define AWB2_HD_MODE_MASK                              0x3
+#define AWB2_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_VUL_CON0 */
+#define VUL_MODE_SFT                                   24
+#define VUL_MODE_MASK                                  0xf
+#define VUL_MODE_MASK_SFT                              (0xf << 24)
+#define VUL_SW_CLEAR_BUF_FULL_SFT                      15
+#define VUL_SW_CLEAR_BUF_FULL_MASK                     0x1
+#define VUL_SW_CLEAR_BUF_FULL_MASK_SFT                 (0x1 << 15)
+#define VUL_R_MONO_SFT                                 9
+#define VUL_R_MONO_MASK                                0x1
+#define VUL_R_MONO_MASK_SFT                            (0x1 << 9)
+#define VUL_MONO_SFT                                   8
+#define VUL_MONO_MASK                                  0x1
+#define VUL_MONO_MASK_SFT                              (0x1 << 8)
+#define VUL_WR_SIGN_SFT                                6
+#define VUL_WR_SIGN_MASK                               0x1
+#define VUL_WR_SIGN_MASK_SFT                           (0x1 << 6)
+#define VUL_NORMAL_MODE_SFT                            5
+#define VUL_NORMAL_MODE_MASK                           0x1
+#define VUL_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define VUL_HALIGN_SFT                                 4
+#define VUL_HALIGN_MASK                                0x1
+#define VUL_HALIGN_MASK_SFT                            (0x1 << 4)
+#define VUL_HD_MODE_SFT                                0
+#define VUL_HD_MODE_MASK                               0x3
+#define VUL_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_VUL12_CON0 */
+#define VUL12_MODE_SFT                                 24
+#define VUL12_MODE_MASK                                0xf
+#define VUL12_MODE_MASK_SFT                            (0xf << 24)
+#define VUL12_SW_CLEAR_BUF_FULL_SFT                    15
+#define VUL12_SW_CLEAR_BUF_FULL_MASK                   0x1
+#define VUL12_SW_CLEAR_BUF_FULL_MASK_SFT               (0x1 << 15)
+#define VUL12_4CH_EN_SFT                               11
+#define VUL12_4CH_EN_MASK                              0x1
+#define VUL12_4CH_EN_MASK_SFT                          (0x1 << 11)
+#define VUL12_R_MONO_SFT                               9
+#define VUL12_R_MONO_MASK                              0x1
+#define VUL12_R_MONO_MASK_SFT                          (0x1 << 9)
+#define VUL12_MONO_SFT                                 8
+#define VUL12_MONO_MASK                                0x1
+#define VUL12_MONO_MASK_SFT                            (0x1 << 8)
+#define VUL12_WR_SIGN_SFT                              6
+#define VUL12_WR_SIGN_MASK                             0x1
+#define VUL12_WR_SIGN_MASK_SFT                         (0x1 << 6)
+#define VUL12_NORMAL_MODE_SFT                          5
+#define VUL12_NORMAL_MODE_MASK                         0x1
+#define VUL12_NORMAL_MODE_MASK_SFT                     (0x1 << 5)
+#define VUL12_HALIGN_SFT                               4
+#define VUL12_HALIGN_MASK                              0x1
+#define VUL12_HALIGN_MASK_SFT                          (0x1 << 4)
+#define VUL12_HD_MODE_SFT                              0
+#define VUL12_HD_MODE_MASK                             0x3
+#define VUL12_HD_MODE_MASK_SFT                         (0x3 << 0)
+
+/* AFE_VUL2_CON0 */
+#define VUL2_MODE_SFT                                  24
+#define VUL2_MODE_MASK                                 0xf
+#define VUL2_MODE_MASK_SFT                             (0xf << 24)
+#define VUL2_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL2_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL2_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define VUL2_R_MONO_SFT                                9
+#define VUL2_R_MONO_MASK                               0x1
+#define VUL2_R_MONO_MASK_SFT                           (0x1 << 9)
+#define VUL2_MONO_SFT                                  8
+#define VUL2_MONO_MASK                                 0x1
+#define VUL2_MONO_MASK_SFT                             (0x1 << 8)
+#define VUL2_WR_SIGN_SFT                               6
+#define VUL2_WR_SIGN_MASK                              0x1
+#define VUL2_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define VUL2_NORMAL_MODE_SFT                           5
+#define VUL2_NORMAL_MODE_MASK                          0x1
+#define VUL2_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define VUL2_HALIGN_SFT                                4
+#define VUL2_HALIGN_MASK                               0x1
+#define VUL2_HALIGN_MASK_SFT                           (0x1 << 4)
+#define VUL2_HD_MODE_SFT                               0
+#define VUL2_HD_MODE_MASK                              0x3
+#define VUL2_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_VUL3_CON0 */
+#define VUL3_MODE_SFT                                  24
+#define VUL3_MODE_MASK                                 0xf
+#define VUL3_MODE_MASK_SFT                             (0xf << 24)
+#define VUL3_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL3_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL3_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define VUL3_R_MONO_SFT                                9
+#define VUL3_R_MONO_MASK                               0x1
+#define VUL3_R_MONO_MASK_SFT                           (0x1 << 9)
+#define VUL3_MONO_SFT                                  8
+#define VUL3_MONO_MASK                                 0x1
+#define VUL3_MONO_MASK_SFT                             (0x1 << 8)
+#define VUL3_WR_SIGN_SFT                               6
+#define VUL3_WR_SIGN_MASK                              0x1
+#define VUL3_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define VUL3_NORMAL_MODE_SFT                           5
+#define VUL3_NORMAL_MODE_MASK                          0x1
+#define VUL3_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define VUL3_HALIGN_SFT                                4
+#define VUL3_HALIGN_MASK                               0x1
+#define VUL3_HALIGN_MASK_SFT                           (0x1 << 4)
+#define VUL3_HD_MODE_SFT                               0
+#define VUL3_HD_MODE_MASK                              0x3
+#define VUL3_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_VUL4_CON0 */
+#define VUL4_MODE_SFT                                  24
+#define VUL4_MODE_MASK                                 0xf
+#define VUL4_MODE_MASK_SFT                             (0xf << 24)
+#define VUL4_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL4_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL4_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define VUL4_R_MONO_SFT                                9
+#define VUL4_R_MONO_MASK                               0x1
+#define VUL4_R_MONO_MASK_SFT                           (0x1 << 9)
+#define VUL4_MONO_SFT                                  8
+#define VUL4_MONO_MASK                                 0x1
+#define VUL4_MONO_MASK_SFT                             (0x1 << 8)
+#define VUL4_WR_SIGN_SFT                               6
+#define VUL4_WR_SIGN_MASK                              0x1
+#define VUL4_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define VUL4_NORMAL_MODE_SFT                           5
+#define VUL4_NORMAL_MODE_MASK                          0x1
+#define VUL4_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define VUL4_HALIGN_SFT                                4
+#define VUL4_HALIGN_MASK                               0x1
+#define VUL4_HALIGN_MASK_SFT                           (0x1 << 4)
+#define VUL4_HD_MODE_SFT                               0
+#define VUL4_HD_MODE_MASK                              0x3
+#define VUL4_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_VUL5_CON0 */
+#define VUL5_MODE_SFT                                  24
+#define VUL5_MODE_MASK                                 0xf
+#define VUL5_MODE_MASK_SFT                             (0xf << 24)
+#define VUL5_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL5_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL5_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define VUL5_R_MONO_SFT                                9
+#define VUL5_R_MONO_MASK                               0x1
+#define VUL5_R_MONO_MASK_SFT                           (0x1 << 9)
+#define VUL5_MONO_SFT                                  8
+#define VUL5_MONO_MASK                                 0x1
+#define VUL5_MONO_MASK_SFT                             (0x1 << 8)
+#define VUL5_WR_SIGN_SFT                               6
+#define VUL5_WR_SIGN_MASK                              0x1
+#define VUL5_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define VUL5_NORMAL_MODE_SFT                           5
+#define VUL5_NORMAL_MODE_MASK                          0x1
+#define VUL5_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define VUL5_HALIGN_SFT                                4
+#define VUL5_HALIGN_MASK                               0x1
+#define VUL5_HALIGN_MASK_SFT                           (0x1 << 4)
+#define VUL5_HD_MODE_SFT                               0
+#define VUL5_HD_MODE_MASK                              0x3
+#define VUL5_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_VUL6_CON0 */
+#define VUL6_MODE_SFT                                  24
+#define VUL6_MODE_MASK                                 0xf
+#define VUL6_MODE_MASK_SFT                             (0xf << 24)
+#define VUL6_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL6_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL6_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define VUL6_R_MONO_SFT                                9
+#define VUL6_R_MONO_MASK                               0x1
+#define VUL6_R_MONO_MASK_SFT                           (0x1 << 9)
+#define VUL6_MONO_SFT                                  8
+#define VUL6_MONO_MASK                                 0x1
+#define VUL6_MONO_MASK_SFT                             (0x1 << 8)
+#define VUL6_WR_SIGN_SFT                               6
+#define VUL6_WR_SIGN_MASK                              0x1
+#define VUL6_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define VUL6_NORMAL_MODE_SFT                           5
+#define VUL6_NORMAL_MODE_MASK                          0x1
+#define VUL6_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define VUL6_HALIGN_SFT                                4
+#define VUL6_HALIGN_MASK                               0x1
+#define VUL6_HALIGN_MASK_SFT                           (0x1 << 4)
+#define VUL6_HD_MODE_SFT                               0
+#define VUL6_HD_MODE_MASK                              0x3
+#define VUL6_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_DAI_CON0 */
+#define DAI_MODE_SFT                                   24
+#define DAI_MODE_MASK                                  0x3
+#define DAI_MODE_MASK_SFT                              (0x3 << 24)
+#define DAI_SW_CLEAR_BUF_FULL_SFT                      15
+#define DAI_SW_CLEAR_BUF_FULL_MASK                     0x1
+#define DAI_SW_CLEAR_BUF_FULL_MASK_SFT                 (0x1 << 15)
+#define DAI_DUPLICATE_WR_SFT                           10
+#define DAI_DUPLICATE_WR_MASK                          0x1
+#define DAI_DUPLICATE_WR_MASK_SFT                      (0x1 << 10)
+#define DAI_MONO_SFT                                   8
+#define DAI_MONO_MASK                                  0x1
+#define DAI_MONO_MASK_SFT                              (0x1 << 8)
+#define DAI_WR_SIGN_SFT                                6
+#define DAI_WR_SIGN_MASK                               0x1
+#define DAI_WR_SIGN_MASK_SFT                           (0x1 << 6)
+#define DAI_NORMAL_MODE_SFT                            5
+#define DAI_NORMAL_MODE_MASK                           0x1
+#define DAI_NORMAL_MODE_MASK_SFT                       (0x1 << 5)
+#define DAI_HALIGN_SFT                                 4
+#define DAI_HALIGN_MASK                                0x1
+#define DAI_HALIGN_MASK_SFT                            (0x1 << 4)
+#define DAI_HD_MODE_SFT                                0
+#define DAI_HD_MODE_MASK                               0x3
+#define DAI_HD_MODE_MASK_SFT                           (0x3 << 0)
+
+/* AFE_MOD_DAI_CON0 */
+#define MOD_DAI_MODE_SFT                               24
+#define MOD_DAI_MODE_MASK                              0x3
+#define MOD_DAI_MODE_MASK_SFT                          (0x3 << 24)
+#define MOD_DAI_SW_CLEAR_BUF_FULL_SFT                  15
+#define MOD_DAI_SW_CLEAR_BUF_FULL_MASK                 0x1
+#define MOD_DAI_SW_CLEAR_BUF_FULL_MASK_SFT             (0x1 << 15)
+#define MOD_DAI_DUPLICATE_WR_SFT                       10
+#define MOD_DAI_DUPLICATE_WR_MASK                      0x1
+#define MOD_DAI_DUPLICATE_WR_MASK_SFT                  (0x1 << 10)
+#define MOD_DAI_MONO_SFT                               8
+#define MOD_DAI_MONO_MASK                              0x1
+#define MOD_DAI_MONO_MASK_SFT                          (0x1 << 8)
+#define MOD_DAI_WR_SIGN_SFT                            6
+#define MOD_DAI_WR_SIGN_MASK                           0x1
+#define MOD_DAI_WR_SIGN_MASK_SFT                       (0x1 << 6)
+#define MOD_DAI_NORMAL_MODE_SFT                        5
+#define MOD_DAI_NORMAL_MODE_MASK                       0x1
+#define MOD_DAI_NORMAL_MODE_MASK_SFT                   (0x1 << 5)
+#define MOD_DAI_HALIGN_SFT                             4
+#define MOD_DAI_HALIGN_MASK                            0x1
+#define MOD_DAI_HALIGN_MASK_SFT                        (0x1 << 4)
+#define MOD_DAI_HD_MODE_SFT                            0
+#define MOD_DAI_HD_MODE_MASK                           0x3
+#define MOD_DAI_HD_MODE_MASK_SFT                       (0x3 << 0)
+
+/* AFE_DAI2_CON0 */
+#define DAI2_MODE_SFT                                  24
+#define DAI2_MODE_MASK                                 0xf
+#define DAI2_MODE_MASK_SFT                             (0xf << 24)
+#define DAI2_SW_CLEAR_BUF_FULL_SFT                     15
+#define DAI2_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define DAI2_SW_CLEAR_BUF_FULL_MASK_SFT                (0x1 << 15)
+#define DAI2_DUPLICATE_WR_SFT                          10
+#define DAI2_DUPLICATE_WR_MASK                         0x1
+#define DAI2_DUPLICATE_WR_MASK_SFT                     (0x1 << 10)
+#define DAI2_MONO_SFT                                  8
+#define DAI2_MONO_MASK                                 0x1
+#define DAI2_MONO_MASK_SFT                             (0x1 << 8)
+#define DAI2_WR_SIGN_SFT                               6
+#define DAI2_WR_SIGN_MASK                              0x1
+#define DAI2_WR_SIGN_MASK_SFT                          (0x1 << 6)
+#define DAI2_NORMAL_MODE_SFT                           5
+#define DAI2_NORMAL_MODE_MASK                          0x1
+#define DAI2_NORMAL_MODE_MASK_SFT                      (0x1 << 5)
+#define DAI2_HALIGN_SFT                                4
+#define DAI2_HALIGN_MASK                               0x1
+#define DAI2_HALIGN_MASK_SFT                           (0x1 << 4)
+#define DAI2_HD_MODE_SFT                               0
+#define DAI2_HD_MODE_MASK                              0x3
+#define DAI2_HD_MODE_MASK_SFT                          (0x3 << 0)
+
+/* AFE_MEMIF_CON0 */
+#define CPU_COMPACT_MODE_SFT                           2
+#define CPU_COMPACT_MODE_MASK                          0x1
+#define CPU_COMPACT_MODE_MASK_SFT                      (0x1 << 2)
+#define CPU_HD_ALIGN_SFT                               1
+#define CPU_HD_ALIGN_MASK                              0x1
+#define CPU_HD_ALIGN_MASK_SFT                          (0x1 << 1)
+#define SYSRAM_SIGN_SFT                                0
+#define SYSRAM_SIGN_MASK                               0x1
+#define SYSRAM_SIGN_MASK_SFT                           (0x1 << 0)
+
+/* AFE_HDMI_OUT_CON0 */
+#define HDMI_CH_NUM_SFT                                24
+#define HDMI_CH_NUM_MASK                               0xf
+#define HDMI_CH_NUM_MASK_SFT                           (0xf << 24)
+#define HDMI_OUT_MINLEN_SFT                            20
+#define HDMI_OUT_MINLEN_MASK                           0xf
+#define HDMI_OUT_MINLEN_MASK_SFT                       (0xf << 20)
+#define HDMI_OUT_MAXLEN_SFT                            16
+#define HDMI_OUT_MAXLEN_MASK                           0xf
+#define HDMI_OUT_MAXLEN_MASK_SFT                       (0xf << 16)
+#define HDMI_OUT_SW_CLEAR_BUF_EMPTY_SFT                15
+#define HDMI_OUT_SW_CLEAR_BUF_EMPTY_MASK               0x1
+#define HDMI_OUT_SW_CLEAR_BUF_EMPTY_MASK_SFT           (0x1 << 15)
+#define HDMI_OUT_PBUF_SIZE_SFT                         12
+#define HDMI_OUT_PBUF_SIZE_MASK                        0x3
+#define HDMI_OUT_PBUF_SIZE_MASK_SFT                    (0x3 << 12)
+#define HDMI_OUT_NORMAL_MODE_SFT                       5
+#define HDMI_OUT_NORMAL_MODE_MASK                      0x1
+#define HDMI_OUT_NORMAL_MODE_MASK_SFT                  (0x1 << 5)
+#define HDMI_OUT_HALIGN_SFT                            4
+#define HDMI_OUT_HALIGN_MASK                           0x1
+#define HDMI_OUT_HALIGN_MASK_SFT                       (0x1 << 4)
+#define HDMI_OUT_HD_MODE_SFT                           0
+#define HDMI_OUT_HD_MODE_MASK                          0x3
+#define HDMI_OUT_HD_MODE_MASK_SFT                      (0x3 << 0)
+
+/* AFE_IRQ_MCU_CON0 */
+#define IRQ31_MCU_ON_SFT                               31
+#define IRQ31_MCU_ON_MASK                              0x1
+#define IRQ31_MCU_ON_MASK_SFT                          (0x1 << 31)
+#define IRQ26_MCU_ON_SFT                               26
+#define IRQ26_MCU_ON_MASK                              0x1
+#define IRQ26_MCU_ON_MASK_SFT                          (0x1 << 26)
+#define IRQ25_MCU_ON_SFT                               25
+#define IRQ25_MCU_ON_MASK                              0x1
+#define IRQ25_MCU_ON_MASK_SFT                          (0x1 << 25)
+#define IRQ24_MCU_ON_SFT                               24
+#define IRQ24_MCU_ON_MASK                              0x1
+#define IRQ24_MCU_ON_MASK_SFT                          (0x1 << 24)
+#define IRQ23_MCU_ON_SFT                               23
+#define IRQ23_MCU_ON_MASK                              0x1
+#define IRQ23_MCU_ON_MASK_SFT                          (0x1 << 23)
+#define IRQ22_MCU_ON_SFT                               22
+#define IRQ22_MCU_ON_MASK                              0x1
+#define IRQ22_MCU_ON_MASK_SFT                          (0x1 << 22)
+#define IRQ21_MCU_ON_SFT                               21
+#define IRQ21_MCU_ON_MASK                              0x1
+#define IRQ21_MCU_ON_MASK_SFT                          (0x1 << 21)
+#define IRQ20_MCU_ON_SFT                               20
+#define IRQ20_MCU_ON_MASK                              0x1
+#define IRQ20_MCU_ON_MASK_SFT                          (0x1 << 20)
+#define IRQ19_MCU_ON_SFT                               19
+#define IRQ19_MCU_ON_MASK                              0x1
+#define IRQ19_MCU_ON_MASK_SFT                          (0x1 << 19)
+#define IRQ18_MCU_ON_SFT                               18
+#define IRQ18_MCU_ON_MASK                              0x1
+#define IRQ18_MCU_ON_MASK_SFT                          (0x1 << 18)
+#define IRQ17_MCU_ON_SFT                               17
+#define IRQ17_MCU_ON_MASK                              0x1
+#define IRQ17_MCU_ON_MASK_SFT                          (0x1 << 17)
+#define IRQ16_MCU_ON_SFT                               16
+#define IRQ16_MCU_ON_MASK                              0x1
+#define IRQ16_MCU_ON_MASK_SFT                          (0x1 << 16)
+#define IRQ15_MCU_ON_SFT                               15
+#define IRQ15_MCU_ON_MASK                              0x1
+#define IRQ15_MCU_ON_MASK_SFT                          (0x1 << 15)
+#define IRQ14_MCU_ON_SFT                               14
+#define IRQ14_MCU_ON_MASK                              0x1
+#define IRQ14_MCU_ON_MASK_SFT                          (0x1 << 14)
+#define IRQ13_MCU_ON_SFT                               13
+#define IRQ13_MCU_ON_MASK                              0x1
+#define IRQ13_MCU_ON_MASK_SFT                          (0x1 << 13)
+#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 IRQ15_MCU_MODE_SFT                             28
+#define IRQ15_MCU_MODE_MASK                            0xf
+#define IRQ15_MCU_MODE_MASK_SFT                        (0xf << 28)
+#define IRQ14_MCU_MODE_SFT                             24
+#define IRQ14_MCU_MODE_MASK                            0xf
+#define IRQ14_MCU_MODE_MASK_SFT                        (0xf << 24)
+#define IRQ13_MCU_MODE_SFT                             20
+#define IRQ13_MCU_MODE_MASK                            0xf
+#define IRQ13_MCU_MODE_MASK_SFT                        (0xf << 20)
+#define IRQ12_MCU_MODE_SFT                             16
+#define IRQ12_MCU_MODE_MASK                            0xf
+#define IRQ12_MCU_MODE_MASK_SFT                        (0xf << 16)
+#define IRQ11_MCU_MODE_SFT                             12
+#define IRQ11_MCU_MODE_MASK                            0xf
+#define IRQ11_MCU_MODE_MASK_SFT                        (0xf << 12)
+#define IRQ10_MCU_MODE_SFT                             8
+#define IRQ10_MCU_MODE_MASK                            0xf
+#define IRQ10_MCU_MODE_MASK_SFT                        (0xf << 8)
+#define IRQ9_MCU_MODE_SFT                              4
+#define IRQ9_MCU_MODE_MASK                             0xf
+#define IRQ9_MCU_MODE_MASK_SFT                         (0xf << 4)
+#define IRQ8_MCU_MODE_SFT                              0
+#define IRQ8_MCU_MODE_MASK                             0xf
+#define IRQ8_MCU_MODE_MASK_SFT                         (0xf << 0)
+
+/* AFE_IRQ_MCU_CON3 */
+#define IRQ23_MCU_MODE_SFT                             28
+#define IRQ23_MCU_MODE_MASK                            0xf
+#define IRQ23_MCU_MODE_MASK_SFT                        (0xf << 28)
+#define IRQ22_MCU_MODE_SFT                             24
+#define IRQ22_MCU_MODE_MASK                            0xf
+#define IRQ22_MCU_MODE_MASK_SFT                        (0xf << 24)
+#define IRQ21_MCU_MODE_SFT                             20
+#define IRQ21_MCU_MODE_MASK                            0xf
+#define IRQ21_MCU_MODE_MASK_SFT                        (0xf << 20)
+#define IRQ20_MCU_MODE_SFT                             16
+#define IRQ20_MCU_MODE_MASK                            0xf
+#define IRQ20_MCU_MODE_MASK_SFT                        (0xf << 16)
+#define IRQ19_MCU_MODE_SFT                             12
+#define IRQ19_MCU_MODE_MASK                            0xf
+#define IRQ19_MCU_MODE_MASK_SFT                        (0xf << 12)
+#define IRQ18_MCU_MODE_SFT                             8
+#define IRQ18_MCU_MODE_MASK                            0xf
+#define IRQ18_MCU_MODE_MASK_SFT                        (0xf << 8)
+#define IRQ17_MCU_MODE_SFT                             4
+#define IRQ17_MCU_MODE_MASK                            0xf
+#define IRQ17_MCU_MODE_MASK_SFT                        (0xf << 4)
+#define IRQ16_MCU_MODE_SFT                             0
+#define IRQ16_MCU_MODE_MASK                            0xf
+#define IRQ16_MCU_MODE_MASK_SFT                        (0xf << 0)
+
+/* AFE_IRQ_MCU_CON4 */
+#define IRQ26_MCU_MODE_SFT                             8
+#define IRQ26_MCU_MODE_MASK                            0xf
+#define IRQ26_MCU_MODE_MASK_SFT                        (0xf << 8)
+#define IRQ25_MCU_MODE_SFT                             4
+#define IRQ25_MCU_MODE_MASK                            0xf
+#define IRQ25_MCU_MODE_MASK_SFT                        (0xf << 4)
+#define IRQ24_MCU_MODE_SFT                             0
+#define IRQ24_MCU_MODE_MASK                            0xf
+#define IRQ24_MCU_MODE_MASK_SFT                        (0xf << 0)
+
+/* AFE_IRQ_MCU_CLR */
+#define IRQ31_MCU_CLR_SFT                              31
+#define IRQ31_MCU_CLR_MASK                             0x1
+#define IRQ31_MCU_CLR_MASK_SFT                         (0x1 << 31)
+#define IRQ26_MCU_CLR_SFT                              26
+#define IRQ26_MCU_CLR_MASK                             0x1
+#define IRQ26_MCU_CLR_MASK_SFT                         (0x1 << 26)
+#define IRQ25_MCU_CLR_SFT                              25
+#define IRQ25_MCU_CLR_MASK                             0x1
+#define IRQ25_MCU_CLR_MASK_SFT                         (0x1 << 25)
+#define IRQ24_MCU_CLR_SFT                              24
+#define IRQ24_MCU_CLR_MASK                             0x1
+#define IRQ24_MCU_CLR_MASK_SFT                         (0x1 << 24)
+#define IRQ23_MCU_CLR_SFT                              23
+#define IRQ23_MCU_CLR_MASK                             0x1
+#define IRQ23_MCU_CLR_MASK_SFT                         (0x1 << 23)
+#define IRQ22_MCU_CLR_SFT                              22
+#define IRQ22_MCU_CLR_MASK                             0x1
+#define IRQ22_MCU_CLR_MASK_SFT                         (0x1 << 22)
+#define IRQ21_MCU_CLR_SFT                              21
+#define IRQ21_MCU_CLR_MASK                             0x1
+#define IRQ21_MCU_CLR_MASK_SFT                         (0x1 << 21)
+#define IRQ20_MCU_CLR_SFT                              20
+#define IRQ20_MCU_CLR_MASK                             0x1
+#define IRQ20_MCU_CLR_MASK_SFT                         (0x1 << 20)
+#define IRQ19_MCU_CLR_SFT                              19
+#define IRQ19_MCU_CLR_MASK                             0x1
+#define IRQ19_MCU_CLR_MASK_SFT                         (0x1 << 19)
+#define IRQ18_MCU_CLR_SFT                              18
+#define IRQ18_MCU_CLR_MASK                             0x1
+#define IRQ18_MCU_CLR_MASK_SFT                         (0x1 << 18)
+#define IRQ17_MCU_CLR_SFT                              17
+#define IRQ17_MCU_CLR_MASK                             0x1
+#define IRQ17_MCU_CLR_MASK_SFT                         (0x1 << 17)
+#define IRQ16_MCU_CLR_SFT                              16
+#define IRQ16_MCU_CLR_MASK                             0x1
+#define IRQ16_MCU_CLR_MASK_SFT                         (0x1 << 16)
+#define IRQ15_MCU_CLR_SFT                              15
+#define IRQ15_MCU_CLR_MASK                             0x1
+#define IRQ15_MCU_CLR_MASK_SFT                         (0x1 << 15)
+#define IRQ14_MCU_CLR_SFT                              14
+#define IRQ14_MCU_CLR_MASK                             0x1
+#define IRQ14_MCU_CLR_MASK_SFT                         (0x1 << 14)
+#define IRQ13_MCU_CLR_SFT                              13
+#define IRQ13_MCU_CLR_MASK                             0x1
+#define IRQ13_MCU_CLR_MASK_SFT                         (0x1 << 13)
+#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_IRQ_MCU_EN */
+#define IRQ31_MCU_EN_SFT                               31
+#define IRQ30_MCU_EN_SFT                               30
+#define IRQ29_MCU_EN_SFT                               29
+#define IRQ28_MCU_EN_SFT                               28
+#define IRQ27_MCU_EN_SFT                               27
+#define IRQ26_MCU_EN_SFT                               26
+#define IRQ25_MCU_EN_SFT                               25
+#define IRQ24_MCU_EN_SFT                               24
+#define IRQ23_MCU_EN_SFT                               23
+#define IRQ22_MCU_EN_SFT                               22
+#define IRQ21_MCU_EN_SFT                               21
+#define IRQ20_MCU_EN_SFT                               20
+#define IRQ19_MCU_EN_SFT                               19
+#define IRQ18_MCU_EN_SFT                               18
+#define IRQ17_MCU_EN_SFT                               17
+#define IRQ16_MCU_EN_SFT                               16
+#define IRQ15_MCU_EN_SFT                               15
+#define IRQ14_MCU_EN_SFT                               14
+#define IRQ13_MCU_EN_SFT                               13
+#define IRQ12_MCU_EN_SFT                               12
+#define IRQ11_MCU_EN_SFT                               11
+#define IRQ10_MCU_EN_SFT                               10
+#define IRQ9_MCU_EN_SFT                                9
+#define IRQ8_MCU_EN_SFT                                8
+#define IRQ7_MCU_EN_SFT                                7
+#define IRQ6_MCU_EN_SFT                                6
+#define IRQ5_MCU_EN_SFT                                5
+#define IRQ4_MCU_EN_SFT                                4
+#define IRQ3_MCU_EN_SFT                                3
+#define IRQ2_MCU_EN_SFT                                2
+#define IRQ1_MCU_EN_SFT                                1
+#define IRQ0_MCU_EN_SFT                                0
+
+/* AFE_IRQ_MCU_SCP_EN */
+#define IRQ31_MCU_SCP_EN_SFT                           31
+#define IRQ30_MCU_SCP_EN_SFT                           30
+#define IRQ29_MCU_SCP_EN_SFT                           29
+#define IRQ28_MCU_SCP_EN_SFT                           28
+#define IRQ27_MCU_SCP_EN_SFT                           27
+#define IRQ26_MCU_SCP_EN_SFT                           26
+#define IRQ25_MCU_SCP_EN_SFT                           25
+#define IRQ24_MCU_SCP_EN_SFT                           24
+#define IRQ23_MCU_SCP_EN_SFT                           23
+#define IRQ22_MCU_SCP_EN_SFT                           22
+#define IRQ21_MCU_SCP_EN_SFT                           21
+#define IRQ20_MCU_SCP_EN_SFT                           20
+#define IRQ19_MCU_SCP_EN_SFT                           19
+#define IRQ18_MCU_SCP_EN_SFT                           18
+#define IRQ17_MCU_SCP_EN_SFT                           17
+#define IRQ16_MCU_SCP_EN_SFT                           16
+#define IRQ15_MCU_SCP_EN_SFT                           15
+#define IRQ14_MCU_SCP_EN_SFT                           14
+#define IRQ13_MCU_SCP_EN_SFT                           13
+#define IRQ12_MCU_SCP_EN_SFT                           12
+#define IRQ11_MCU_SCP_EN_SFT                           11
+#define IRQ10_MCU_SCP_EN_SFT                           10
+#define IRQ9_MCU_SCP_EN_SFT                            9
+#define IRQ8_MCU_SCP_EN_SFT                            8
+#define IRQ7_MCU_SCP_EN_SFT                            7
+#define IRQ6_MCU_SCP_EN_SFT                            6
+#define IRQ5_MCU_SCP_EN_SFT                            5
+#define IRQ4_MCU_SCP_EN_SFT                            4
+#define IRQ3_MCU_SCP_EN_SFT                            3
+#define IRQ2_MCU_SCP_EN_SFT                            2
+#define IRQ1_MCU_SCP_EN_SFT                            1
+#define IRQ0_MCU_SCP_EN_SFT                            0
+
+/* AFE_TDM_CON1 */
+#define TDM_EN_SFT                                     0
+#define TDM_EN_MASK                                    0x1
+#define TDM_EN_MASK_SFT                                (0x1 << 0)
+#define BCK_INVERSE_SFT                                1
+#define BCK_INVERSE_MASK                               0x1
+#define BCK_INVERSE_MASK_SFT                           (0x1 << 1)
+#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_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_AUD_PAD_TOP */
+#define AUD_PAD_TOP_MON_SFT                            15
+#define AUD_PAD_TOP_MON_MASK                           0x1ffff
+#define AUD_PAD_TOP_MON_MASK_SFT                       (0x1ffff << 15)
+#define AUD_PAD_TOP_FIFO_RSP_SFT                       4
+#define AUD_PAD_TOP_FIFO_RSP_MASK                      0xf
+#define AUD_PAD_TOP_FIFO_RSP_MASK_SFT                  (0xf << 4)
+#define RG_RX_PROTOCOL2_SFT                            3
+#define RG_RX_PROTOCOL2_MASK                           0x1
+#define RG_RX_PROTOCOL2_MASK_SFT                       (0x1 << 3)
+#define RESERVDED_01_SFT                               1
+#define RESERVDED_01_MASK                              0x3
+#define RESERVDED_01_MASK_SFT                          (0x3 << 1)
+#define RG_RX_FIFO_ON_SFT                              0
+#define RG_RX_FIFO_ON_MASK                             0x1
+#define RG_RX_FIFO_ON_MASK_SFT                         (0x1 << 0)
+
+/* AFE_ADDA_MTKAIF_SYNCWORD_CFG */
+#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_SFT      23
+#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_MASK     0x1
+#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_MASK_SFT (0x1 << 23)
+
+/* AFE_ADDA_MTKAIF_RX_CFG0 */
+#define MTKAIF_RXIF_VOICE_MODE_SFT                     20
+#define MTKAIF_RXIF_VOICE_MODE_MASK                    0xf
+#define MTKAIF_RXIF_VOICE_MODE_MASK_SFT                (0xf << 20)
+#define MTKAIF_RXIF_DETECT_ON_SFT                      16
+#define MTKAIF_RXIF_DETECT_ON_MASK                     0x1
+#define MTKAIF_RXIF_DETECT_ON_MASK_SFT                 (0x1 << 16)
+#define MTKAIF_RXIF_DATA_BIT_SFT                       8
+#define MTKAIF_RXIF_DATA_BIT_MASK                      0x7
+#define MTKAIF_RXIF_DATA_BIT_MASK_SFT                  (0x7 << 8)
+#define MTKAIF_RXIF_FIFO_RSP_SFT                       4
+#define MTKAIF_RXIF_FIFO_RSP_MASK                      0x7
+#define MTKAIF_RXIF_FIFO_RSP_MASK_SFT                  (0x7 << 4)
+#define MTKAIF_RXIF_DATA_MODE_SFT                      0
+#define MTKAIF_RXIF_DATA_MODE_MASK                     0x1
+#define MTKAIF_RXIF_DATA_MODE_MASK_SFT                 (0x1 << 0)
+
+/* GENERAL_ASRC_MODE */
+#define GENERAL2_ASRCOUT_MODE_SFT                      12
+#define GENERAL2_ASRCOUT_MODE_MASK                     0xf
+#define GENERAL2_ASRCOUT_MODE_MASK_SFT                 (0xf << 12)
+#define GENERAL2_ASRCIN_MODE_SFT                       8
+#define GENERAL2_ASRCIN_MODE_MASK                      0xf
+#define GENERAL2_ASRCIN_MODE_MASK_SFT                  (0xf << 8)
+#define GENERAL1_ASRCOUT_MODE_SFT                      4
+#define GENERAL1_ASRCOUT_MODE_MASK                     0xf
+#define GENERAL1_ASRCOUT_MODE_MASK_SFT                 (0xf << 4)
+#define GENERAL1_ASRCIN_MODE_SFT                       0
+#define GENERAL1_ASRCIN_MODE_MASK                      0xf
+#define GENERAL1_ASRCIN_MODE_MASK_SFT                  (0xf << 0)
+
+/* GENERAL_ASRC_EN_ON */
+#define GENERAL2_ASRC_EN_ON_SFT                        1
+#define GENERAL2_ASRC_EN_ON_MASK                       0x1
+#define GENERAL2_ASRC_EN_ON_MASK_SFT                   (0x1 << 1)
+#define GENERAL1_ASRC_EN_ON_SFT                        0
+#define GENERAL1_ASRC_EN_ON_MASK                       0x1
+#define GENERAL1_ASRC_EN_ON_MASK_SFT                   (0x1 << 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON0 */
+#define G_SRC_CHSET_STR_CLR_SFT                        4
+#define G_SRC_CHSET_STR_CLR_MASK                       0x1
+#define G_SRC_CHSET_STR_CLR_MASK_SFT                   (0x1 << 4)
+#define G_SRC_CHSET_ON_SFT                             2
+#define G_SRC_CHSET_ON_MASK                            0x1
+#define G_SRC_CHSET_ON_MASK_SFT                        (0x1 << 2)
+#define G_SRC_COEFF_SRAM_CTRL_SFT                      1
+#define G_SRC_COEFF_SRAM_CTRL_MASK                     0x1
+#define G_SRC_COEFF_SRAM_CTRL_MASK_SFT                 (0x1 << 1)
+#define G_SRC_ASM_ON_SFT                               0
+#define G_SRC_ASM_ON_MASK                              0x1
+#define G_SRC_ASM_ON_MASK_SFT                          (0x1 << 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON3 */
+#define G_SRC_ASM_FREQ_4_SFT                           0
+#define G_SRC_ASM_FREQ_4_MASK                          0xffffff
+#define G_SRC_ASM_FREQ_4_MASK_SFT                      (0xffffff << 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON4 */
+#define G_SRC_ASM_FREQ_5_SFT                           0
+#define G_SRC_ASM_FREQ_5_MASK                          0xffffff
+#define G_SRC_ASM_FREQ_5_MASK_SFT                      (0xffffff << 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON13 */
+#define G_SRC_COEFF_SRAM_ADR_SFT                       0
+#define G_SRC_COEFF_SRAM_ADR_MASK                      0x3f
+#define G_SRC_COEFF_SRAM_ADR_MASK_SFT                  (0x3f << 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON2 */
+#define G_SRC_CHSET_O16BIT_SFT                         19
+#define G_SRC_CHSET_O16BIT_MASK                        0x1
+#define G_SRC_CHSET_O16BIT_MASK_SFT                    (0x1 << 19)
+#define G_SRC_CHSET_CLR_IIR_HISTORY_SFT                17
+#define G_SRC_CHSET_CLR_IIR_HISTORY_MASK               0x1
+#define G_SRC_CHSET_CLR_IIR_HISTORY_MASK_SFT           (0x1 << 17)
+#define G_SRC_CHSET_IS_MONO_SFT                        16
+#define G_SRC_CHSET_IS_MONO_MASK                       0x1
+#define G_SRC_CHSET_IS_MONO_MASK_SFT                   (0x1 << 16)
+#define G_SRC_CHSET_IIR_EN_SFT                         11
+#define G_SRC_CHSET_IIR_EN_MASK                        0x1
+#define G_SRC_CHSET_IIR_EN_MASK_SFT                    (0x1 << 11)
+#define G_SRC_CHSET_IIR_STAGE_SFT                      8
+#define G_SRC_CHSET_IIR_STAGE_MASK                     0x7
+#define G_SRC_CHSET_IIR_STAGE_MASK_SFT                 (0x7 << 8)
+#define G_SRC_CHSET_STR_CLR_RU_SFT                     5
+#define G_SRC_CHSET_STR_CLR_RU_MASK                    0x1
+#define G_SRC_CHSET_STR_CLR_RU_MASK_SFT                (0x1 << 5)
+#define G_SRC_CHSET_ON_SFT                             2
+#define G_SRC_CHSET_ON_MASK                            0x1
+#define G_SRC_CHSET_ON_MASK_SFT                        (0x1 << 2)
+#define G_SRC_COEFF_SRAM_CTRL_SFT                      1
+#define G_SRC_COEFF_SRAM_CTRL_MASK                     0x1
+#define G_SRC_COEFF_SRAM_CTRL_MASK_SFT                 (0x1 << 1)
+#define G_SRC_ASM_ON_SFT                               0
+#define G_SRC_ASM_ON_MASK                              0x1
+#define G_SRC_ASM_ON_MASK_SFT                          (0x1 << 0)
+
+/* AFE_ADDA_DL_SDM_AUTO_RESET_CON */
+#define ADDA_SDM_AUTO_RESET_ONOFF_SFT                  31
+#define ADDA_SDM_AUTO_RESET_ONOFF_MASK                 0x1
+#define ADDA_SDM_AUTO_RESET_ONOFF_MASK_SFT             (0x1 << 31)
+
+/* AFE_ADDA_3RD_DAC_DL_SDM_AUTO_RESET_CON */
+#define ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_SFT          31
+#define ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_MASK         0x1
+#define ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_MASK_SFT     (0x1 << 31)
+
+/* AFE_TINY_CONN0 */
+#define O_3_CFG_SFT                                    24
+#define O_3_CFG_MASK                                   0x1f
+#define O_3_CFG_MASK_SFT                               (0x1f << 24)
+#define O_2_CFG_SFT                                    16
+#define O_2_CFG_MASK                                   0x1f
+#define O_2_CFG_MASK_SFT                               (0x1f << 16)
+#define O_1_CFG_SFT                                    8
+#define O_1_CFG_MASK                                   0x1f
+#define O_1_CFG_MASK_SFT                               (0x1f << 8)
+#define O_0_CFG_SFT                                    0
+#define O_0_CFG_MASK                                   0x1f
+#define O_0_CFG_MASK_SFT                               (0x1f << 0)
+
+/* AFE_TINY_CONN5 */
+#define O_23_CFG_SFT                                    24
+#define O_23_CFG_MASK                                   0x1f
+#define O_23_CFG_MASK_SFT                               (0x1f << 24)
+#define O_22_CFG_SFT                                    16
+#define O_22_CFG_MASK                                   0x1f
+#define O_22_CFG_MASK_SFT                               (0x1f << 16)
+#define O_21_CFG_SFT                                    8
+#define O_21_CFG_MASK                                   0x1f
+#define O_21_CFG_MASK_SFT                               (0x1f << 8)
+#define O_20_CFG_SFT                                    0
+#define O_20_CFG_MASK                                   0x1f
+#define O_20_CFG_MASK_SFT                               (0x1f << 0)
+
+/* AFE_MEMIF_CONN */
+#define VUL6_USE_TINY_SFT                              8
+#define VUL6_USE_TINY_MASK                             1
+#define VUL6_USE_TINY_MASK_SFT                         (0x1 << 8)
+#define VUL5_USE_TINY_SFT                              7
+#define VUL5_USE_TINY_MASK                             1
+#define VUL5_USE_TINY_MASK_SFT                         (0x1 << 7)
+#define VUL4_USE_TINY_SFT                              6
+#define VUL4_USE_TINY_MASK                             1
+#define VUL4_USE_TINY_MASK_SFT                         (0x1 << 6)
+#define VUL3_USE_TINY_SFT                              5
+#define VUL3_USE_TINY_MASK                             1
+#define VUL3_USE_TINY_MASK_SFT                         (0x1 << 5)
+#define AWB2_USE_TINY_SFT                              4
+#define AWB2_USE_TINY_MASK                             1
+#define AWB2_USE_TINY_MASK_SFT                         (0x1 << 4)
+#define AWB_USE_TINY_SFT                               3
+#define AWB_USE_TINY_MASK                              1
+#define AWB_USE_TINY_MASK_SFT                          (0x1 << 3)
+#define VUL12_USE_TINY_SFT                             2
+#define VUL12_USE_TINY_MASK                            1
+#define VUL12_USE_TINY_MASK_SFT                        (0x1 << 2)
+#define VUL2_USE_TINY_SFT                              1
+#define VUL2_USE_TINY_MASK                             1
+#define VUL2_USE_TINY_MASK_SFT                         (0x1 << 1)
+#define VUL1_USE_TINY_SFT                              0
+#define VUL1_USE_TINY_MASK                             1
+#define VUL1_USE_TINY_MASK_SFT                         (0x1 << 0)
+
+/* AFE_ASRC_2CH_CON0 */
+#define CON0_CHSET_STR_CLR_SFT                         4
+#define CON0_CHSET_STR_CLR_MASK                        1
+#define CON0_CHSET_STR_CLR_MASK_SFT                    (0x1 << 4)
+#define CON0_ASM_ON_SFT                                0
+#define CON0_ASM_ON_MASK                               1
+#define CON0_ASM_ON_MASK_SFT                           (0x1 << 0)
+
+/* AFE_ASRC_2CH_CON5 */
+#define CALI_EN_SFT                                    0
+#define CALI_EN_MASK                                   1
+#define CALI_EN_MASK_SFT                               (0x1 << 0)
+
+#define AUDIO_TOP_CON0                                 0x0000
+#define AUDIO_TOP_CON1                                 0x0004
+#define AUDIO_TOP_CON2                                 0x0008
+#define AUDIO_TOP_CON3                                 0x000c
+#define AFE_DAC_CON0                                   0x0010
+#define AFE_I2S_CON                                    0x0018
+#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_I2S_CON3                                   0x0040
+#define AFE_CONN5                                      0x0044
+#define AFE_CONN_24BIT                                 0x0048
+#define AFE_DL1_CON0                                   0x004c
+#define AFE_DL1_BASE_MSB                               0x0050
+#define AFE_DL1_BASE                                   0x0054
+#define AFE_DL1_CUR_MSB                                0x0058
+#define AFE_DL1_CUR                                    0x005c
+#define AFE_DL1_END_MSB                                0x0060
+#define AFE_DL1_END                                    0x0064
+#define AFE_DL2_CON0                                   0x0068
+#define AFE_DL2_BASE_MSB                               0x006c
+#define AFE_DL2_BASE                                   0x0070
+#define AFE_DL2_CUR_MSB                                0x0074
+#define AFE_DL2_CUR                                    0x0078
+#define AFE_DL2_END_MSB                                0x007c
+#define AFE_DL2_END                                    0x0080
+#define AFE_DL3_CON0                                   0x0084
+#define AFE_DL3_BASE_MSB                               0x0088
+#define AFE_DL3_BASE                                   0x008c
+#define AFE_DL3_CUR_MSB                                0x0090
+#define AFE_DL3_CUR                                    0x0094
+#define AFE_DL3_END_MSB                                0x0098
+#define AFE_DL3_END                                    0x009c
+#define AFE_CONN6                                      0x00bc
+#define AFE_DL4_CON0                                   0x00cc
+#define AFE_DL4_BASE_MSB                               0x00d0
+#define AFE_DL4_BASE                                   0x00d4
+#define AFE_DL4_CUR_MSB                                0x00d8
+#define AFE_DL4_CUR                                    0x00dc
+#define AFE_DL4_END_MSB                                0x00e0
+#define AFE_DL4_END                                    0x00e4
+#define AFE_DL12_CON0                                  0x00e8
+#define AFE_DL12_BASE_MSB                              0x00ec
+#define AFE_DL12_BASE                                  0x00f0
+#define AFE_DL12_CUR_MSB                               0x00f4
+#define AFE_DL12_CUR                                   0x00f8
+#define AFE_DL12_END_MSB                               0x00fc
+#define AFE_DL12_END                                   0x0100
+#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_SECURE_CON0                                0x0150
+#define AFE_SRAM_BOUND                                 0x0154
+#define AFE_SECURE_CON1                                0x0158
+#define AFE_SECURE_CONN0                               0x015c
+#define AFE_VUL_CON0                                   0x0170
+#define AFE_VUL_BASE_MSB                               0x0174
+#define AFE_VUL_BASE                                   0x0178
+#define AFE_VUL_CUR_MSB                                0x017c
+#define AFE_VUL_CUR                                    0x0180
+#define AFE_VUL_END_MSB                                0x0184
+#define AFE_VUL_END                                    0x0188
+#define AFE_ADDA_3RD_DAC_DL_SDM_AUTO_RESET_CON         0x018c
+#define AFE_ADDA_3RD_DAC_DL_SRC2_CON0                  0x0190
+#define AFE_ADDA_3RD_DAC_DL_SRC2_CON1                  0x0194
+#define AFE_ADDA_3RD_DAC_PREDIS_CON0                   0x01a0
+#define AFE_ADDA_3RD_DAC_PREDIS_CON1                   0x01a4
+#define AFE_ADDA_3RD_DAC_PREDIS_CON2                   0x01a8
+#define AFE_ADDA_3RD_DAC_PREDIS_CON3                   0x01ac
+#define AFE_ADDA_3RD_DAC_DL_SDM_DCCOMP_CON             0x01b0
+#define AFE_ADDA_3RD_DAC_DL_SDM_TEST                   0x01b4
+#define AFE_ADDA_3RD_DAC_DL_DC_COMP_CFG0               0x01b8
+#define AFE_ADDA_3RD_DAC_DL_DC_COMP_CFG1               0x01bc
+#define AFE_ADDA_3RD_DAC_DL_SDM_FIFO_MON               0x01c0
+#define AFE_ADDA_3RD_DAC_DL_SRC_LCH_MON                0x01c4
+#define AFE_ADDA_3RD_DAC_DL_SRC_RCH_MON                0x01c8
+#define AFE_ADDA_3RD_DAC_DL_SDM_OUT_MON                0x01cc
+#define AFE_SIDETONE_DEBUG                             0x01d0
+#define AFE_SIDETONE_MON                               0x01d4
+#define AFE_ADDA_3RD_DAC_DL_SDM_DITHER_CON             0x01d8
+#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_I2S_MON2                                   0x01f8
+#define AFE_SINEGEN_CON_TDM                            0x01fc
+#define AFE_TOP_CON0                                   0x0200
+#define AFE_VUL2_CON0                                  0x020c
+#define AFE_VUL2_BASE_MSB                              0x0210
+#define AFE_VUL2_BASE                                  0x0214
+#define AFE_VUL2_CUR_MSB                               0x0218
+#define AFE_VUL2_CUR                                   0x021c
+#define AFE_VUL2_END_MSB                               0x0220
+#define AFE_VUL2_END                                   0x0224
+#define AFE_VUL3_CON0                                  0x0228
+#define AFE_VUL3_BASE_MSB                              0x022c
+#define AFE_VUL3_BASE                                  0x0230
+#define AFE_VUL3_CUR_MSB                               0x0234
+#define AFE_VUL3_CUR                                   0x0238
+#define AFE_VUL3_END_MSB                               0x023c
+#define AFE_VUL3_END                                   0x0240
+#define AFE_BUSY                                       0x0244
+#define AFE_BUS_CFG                                    0x0250
+#define AFE_ADDA_PREDIS_CON0                           0x0260
+#define AFE_ADDA_PREDIS_CON1                           0x0264
+#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_IRQ_MCU_CON1                               0x02e4
+#define AFE_IRQ_MCU_CON2                               0x02e8
+#define AFE_DAC_MON                                    0x02ec
+#define AFE_IRQ_MCU_CON3                               0x02f0
+#define AFE_IRQ_MCU_CON4                               0x02f4
+#define AFE_IRQ_MCU_CNT0                               0x0300
+#define AFE_IRQ_MCU_CNT6                               0x0304
+#define AFE_IRQ_MCU_CNT8                               0x0308
+#define AFE_IRQ_MCU_DSP2_EN                            0x030c
+#define AFE_IRQ0_MCU_CNT_MON                           0x0310
+#define AFE_IRQ6_MCU_CNT_MON                           0x0314
+#define AFE_VUL4_CON0                                  0x0358
+#define AFE_VUL4_BASE_MSB                              0x035c
+#define AFE_VUL4_BASE                                  0x0360
+#define AFE_VUL4_CUR_MSB                               0x0364
+#define AFE_VUL4_CUR                                   0x0368
+#define AFE_VUL4_END_MSB                               0x036c
+#define AFE_VUL4_END                                   0x0370
+#define AFE_VUL12_CON0                                 0x0374
+#define AFE_VUL12_BASE_MSB                             0x0378
+#define AFE_VUL12_BASE                                 0x037c
+#define AFE_VUL12_CUR_MSB                              0x0380
+#define AFE_VUL12_CUR                                  0x0384
+#define AFE_VUL12_END_MSB                              0x0388
+#define AFE_VUL12_END                                  0x038c
+#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_IRQ5_MCU_CNT_MON                           0x03cc
+#define AFE_IRQ_MCU_DSP_EN                             0x03d0
+#define AFE_IRQ_MCU_SCP_EN                             0x03d4
+#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_IRQ_MCU_MISS_CLR                           0x03f8
+#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_CON1                           0x04f4
+#define AFE_CONN56                                     0x0500
+#define AFE_CONN57                                     0x0504
+#define AFE_CONN56_1                                   0x0510
+#define AFE_CONN57_1                                   0x0514
+#define AFE_TINY_CONN2                                 0x0520
+#define AFE_TINY_CONN3                                 0x0524
+#define AFE_TINY_CONN4                                 0x0528
+#define AFE_TINY_CONN5                                 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_I2S_CON6                                   0x0564
+#define AFE_I2S_CON7                                   0x0568
+#define AFE_I2S_CON8                                   0x056c
+#define AFE_I2S_CON9                                   0x0570
+#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_IRQ_MCU_CNT9                               0x0600
+#define AFE_IRQ_MCU_CNT10                              0x0604
+#define AFE_IRQ_MCU_CNT13                              0x0608
+#define AFE_IRQ_MCU_CNT14                              0x060c
+#define AFE_IRQ_MCU_CNT15                              0x0610
+#define AFE_IRQ_MCU_CNT16                              0x0614
+#define AFE_IRQ_MCU_CNT17                              0x0618
+#define AFE_IRQ_MCU_CNT18                              0x061c
+#define AFE_IRQ_MCU_CNT19                              0x0620
+#define AFE_IRQ_MCU_CNT20                              0x0624
+#define AFE_IRQ_MCU_CNT21                              0x0628
+#define AFE_IRQ_MCU_CNT22                              0x062c
+#define AFE_IRQ_MCU_CNT23                              0x0630
+#define AFE_IRQ_MCU_CNT24                              0x0634
+#define AFE_IRQ_MCU_CNT25                              0x0638
+#define AFE_IRQ_MCU_CNT26                              0x063c
+#define AFE_IRQ_MCU_CNT31                              0x0640
+#define AFE_TINY_CONN6                                 0x0650
+#define AFE_TINY_CONN7                                 0x0654
+#define AFE_IRQ9_MCU_CNT_MON                           0x0660
+#define AFE_IRQ10_MCU_CNT_MON                          0x0664
+#define AFE_IRQ13_MCU_CNT_MON                          0x0668
+#define AFE_IRQ14_MCU_CNT_MON                          0x066c
+#define AFE_IRQ15_MCU_CNT_MON                          0x0670
+#define AFE_IRQ16_MCU_CNT_MON                          0x0674
+#define AFE_IRQ17_MCU_CNT_MON                          0x0678
+#define AFE_IRQ18_MCU_CNT_MON                          0x067c
+#define AFE_IRQ19_MCU_CNT_MON                          0x0680
+#define AFE_IRQ20_MCU_CNT_MON                          0x0684
+#define AFE_IRQ21_MCU_CNT_MON                          0x0688
+#define AFE_IRQ22_MCU_CNT_MON                          0x068c
+#define AFE_IRQ23_MCU_CNT_MON                          0x0690
+#define AFE_IRQ24_MCU_CNT_MON                          0x0694
+#define AFE_IRQ25_MCU_CNT_MON                          0x0698
+#define AFE_IRQ26_MCU_CNT_MON                          0x069c
+#define AFE_IRQ31_MCU_CNT_MON                          0x06a0
+#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_ADDA6_MTKAIF_MON0                          0x0854
+#define AFE_ADDA6_MTKAIF_MON1                          0x0858
+#define AFE_AWB_CON0                                   0x085c
+#define AFE_AWB_BASE_MSB                               0x0860
+#define AFE_AWB_BASE                                   0x0864
+#define AFE_AWB_CUR_MSB                                0x0868
+#define AFE_AWB_CUR                                    0x086c
+#define AFE_AWB_END_MSB                                0x0870
+#define AFE_AWB_END                                    0x0874
+#define AFE_AWB2_CON0                                  0x0878
+#define AFE_AWB2_BASE_MSB                              0x087c
+#define AFE_AWB2_BASE                                  0x0880
+#define AFE_AWB2_CUR_MSB                               0x0884
+#define AFE_AWB2_CUR                                   0x0888
+#define AFE_AWB2_END_MSB                               0x088c
+#define AFE_AWB2_END                                   0x0890
+#define AFE_DAI_CON0                                   0x0894
+#define AFE_DAI_BASE_MSB                               0x0898
+#define AFE_DAI_BASE                                   0x089c
+#define AFE_DAI_CUR_MSB                                0x08a0
+#define AFE_DAI_CUR                                    0x08a4
+#define AFE_DAI_END_MSB                                0x08a8
+#define AFE_DAI_END                                    0x08ac
+#define AFE_DAI2_CON0                                  0x08b0
+#define AFE_DAI2_BASE_MSB                              0x08b4
+#define AFE_DAI2_BASE                                  0x08b8
+#define AFE_DAI2_CUR_MSB                               0x08bc
+#define AFE_DAI2_CUR                                   0x08c0
+#define AFE_DAI2_END_MSB                               0x08c4
+#define AFE_DAI2_END                                   0x08c8
+#define AFE_MEMIF_CON0                                 0x08cc
+#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_SGEN_CON_SGEN32                            0x09d0
+#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_ADDA6_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_TINY_CONN0                                 0x0af0
+#define AFE_TINY_CONN1                                 0x0af4
+#define AFE_CONN43                                     0x0af8
+#define AFE_CONN43_1                                   0x0afc
+#define AFE_MOD_DAI_CON0                               0x0b00
+#define AFE_MOD_DAI_BASE_MSB                           0x0b04
+#define AFE_MOD_DAI_BASE                               0x0b08
+#define AFE_MOD_DAI_CUR_MSB                            0x0b0c
+#define AFE_MOD_DAI_CUR                                0x0b10
+#define AFE_MOD_DAI_END_MSB                            0x0b14
+#define AFE_MOD_DAI_END                                0x0b18
+#define AFE_HDMI_OUT_CON0                              0x0b1c
+#define AFE_HDMI_OUT_BASE_MSB                          0x0b20
+#define AFE_HDMI_OUT_BASE                              0x0b24
+#define AFE_HDMI_OUT_CUR_MSB                           0x0b28
+#define AFE_HDMI_OUT_CUR                               0x0b2c
+#define AFE_HDMI_OUT_END_MSB                           0x0b30
+#define AFE_HDMI_OUT_END                               0x0b34
+#define AFE_AWB_RCH_MON                                0x0b70
+#define AFE_AWB_LCH_MON                                0x0b74
+#define AFE_VUL_RCH_MON                                0x0b78
+#define AFE_VUL_LCH_MON                                0x0b7c
+#define AFE_VUL12_RCH_MON                              0x0b80
+#define AFE_VUL12_LCH_MON                              0x0b84
+#define AFE_VUL2_RCH_MON                               0x0b88
+#define AFE_VUL2_LCH_MON                               0x0b8c
+#define AFE_DAI_DATA_MON                               0x0b90
+#define AFE_MOD_DAI_DATA_MON                           0x0b94
+#define AFE_DAI2_DATA_MON                              0x0b98
+#define AFE_AWB2_RCH_MON                               0x0b9c
+#define AFE_AWB2_LCH_MON                               0x0ba0
+#define AFE_VUL3_RCH_MON                               0x0ba4
+#define AFE_VUL3_LCH_MON                               0x0ba8
+#define AFE_VUL4_RCH_MON                               0x0bac
+#define AFE_VUL4_LCH_MON                               0x0bb0
+#define AFE_VUL5_RCH_MON                               0x0bb4
+#define AFE_VUL5_LCH_MON                               0x0bb8
+#define AFE_VUL6_RCH_MON                               0x0bbc
+#define AFE_VUL6_LCH_MON                               0x0bc0
+#define AFE_DL1_RCH_MON                                0x0bc4
+#define AFE_DL1_LCH_MON                                0x0bc8
+#define AFE_DL2_RCH_MON                                0x0bcc
+#define AFE_DL2_LCH_MON                                0x0bd0
+#define AFE_DL12_RCH1_MON                              0x0bd4
+#define AFE_DL12_LCH1_MON                              0x0bd8
+#define AFE_DL12_RCH2_MON                              0x0bdc
+#define AFE_DL12_LCH2_MON                              0x0be0
+#define AFE_DL3_RCH_MON                                0x0be4
+#define AFE_DL3_LCH_MON                                0x0be8
+#define AFE_DL4_RCH_MON                                0x0bec
+#define AFE_DL4_LCH_MON                                0x0bf0
+#define AFE_DL5_RCH_MON                                0x0bf4
+#define AFE_DL5_LCH_MON                                0x0bf8
+#define AFE_DL6_RCH_MON                                0x0bfc
+#define AFE_DL6_LCH_MON                                0x0c00
+#define AFE_DL7_RCH_MON                                0x0c04
+#define AFE_DL7_LCH_MON                                0x0c08
+#define AFE_DL8_RCH_MON                                0x0c0c
+#define AFE_DL8_LCH_MON                                0x0c10
+#define AFE_VUL5_CON0                                  0x0c14
+#define AFE_VUL5_BASE_MSB                              0x0c18
+#define AFE_VUL5_BASE                                  0x0c1c
+#define AFE_VUL5_CUR_MSB                               0x0c20
+#define AFE_VUL5_CUR                                   0x0c24
+#define AFE_VUL5_END_MSB                               0x0c28
+#define AFE_VUL5_END                                   0x0c2c
+#define AFE_VUL6_CON0                                  0x0c30
+#define AFE_VUL6_BASE_MSB                              0x0c34
+#define AFE_VUL6_BASE                                  0x0c38
+#define AFE_VUL6_CUR_MSB                               0x0c3c
+#define AFE_VUL6_CUR                                   0x0c40
+#define AFE_VUL6_END_MSB                               0x0c44
+#define AFE_VUL6_END                                   0x0c48
+#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_ADDA_DL_SDM_DITHER_CON                     0x0c70
+#define AFE_ADDA_DL_SDM_AUTO_RESET_CON                 0x0c74
+#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_ASRC_2CH_CON12                             0x0cb0
+#define AFE_ASRC_2CH_CON13                             0x0cb4
+#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_SE_PROT_SIDEBAND                           0x0d38
+#define AFE_SE_DOMAIN_SIDEBAND0                        0x0d3c
+#define AFE_ADDA_PREDIS_CON2                           0x0d40
+#define AFE_ADDA_PREDIS_CON3                           0x0d44
+#define AFE_MEMIF_CONN                                 0x0d50
+#define AFE_SE_DOMAIN_SIDEBAND1                        0x0d54
+#define AFE_SE_DOMAIN_SIDEBAND2                        0x0d58
+#define AFE_SE_DOMAIN_SIDEBAND3                        0x0d5c
+#define AFE_CONN44                                     0x0d70
+#define AFE_CONN45                                     0x0d74
+#define AFE_CONN46                                     0x0d78
+#define AFE_CONN47                                     0x0d7c
+#define AFE_CONN44_1                                   0x0d80
+#define AFE_CONN45_1                                   0x0d84
+#define AFE_CONN46_1                                   0x0d88
+#define AFE_CONN47_1                                   0x0d8c
+#define AFE_DL9_CUR_MSB                                0x0dc0
+#define AFE_DL9_CUR                                    0x0dc4
+#define AFE_DL9_END_MSB                                0x0dc8
+#define AFE_DL9_END                                    0x0dcc
+#define AFE_HD_ENGEN_ENABLE                            0x0dd0
+#define AFE_ADDA_DL_NLE_FIFO_MON                       0x0dfc
+#define AFE_ADDA_MTKAIF_CFG0                           0x0e00
+#define AFE_ADDA_MTKAIF_SYNCWORD_CFG                   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_DL_NLE_R_CFG0                              0x0e44
+#define AFE_DL_NLE_R_CFG1                              0x0e48
+#define AFE_DL_NLE_L_CFG0                              0x0e4c
+#define AFE_DL_NLE_L_CFG1                              0x0e50
+#define AFE_DL_NLE_R_MON0                              0x0e54
+#define AFE_DL_NLE_R_MON1                              0x0e58
+#define AFE_DL_NLE_R_MON2                              0x0e5c
+#define AFE_DL_NLE_L_MON0                              0x0e60
+#define AFE_DL_NLE_L_MON1                              0x0e64
+#define AFE_DL_NLE_L_MON2                              0x0e68
+#define AFE_DL_NLE_GAIN_CFG0                           0x0e6c
+#define AFE_ADDA6_MTKAIF_CFG0                          0x0e70
+#define AFE_ADDA6_MTKAIF_RX_CFG0                       0x0e74
+#define AFE_ADDA6_MTKAIF_RX_CFG1                       0x0e78
+#define AFE_ADDA6_MTKAIF_RX_CFG2                       0x0e7c
+#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_CONN48                                     0x0ec0
+#define AFE_CONN49                                     0x0ec4
+#define AFE_CONN50                                     0x0ec8
+#define AFE_CONN51                                     0x0ecc
+#define AFE_CONN52                                     0x0ed0
+#define AFE_CONN53                                     0x0ed4
+#define AFE_CONN54                                     0x0ed8
+#define AFE_CONN55                                     0x0edc
+#define AFE_CONN48_1                                   0x0ee0
+#define AFE_CONN49_1                                   0x0ee4
+#define AFE_CONN50_1                                   0x0ee8
+#define AFE_CONN51_1                                   0x0eec
+#define AFE_CONN52_1                                   0x0ef0
+#define AFE_CONN53_1                                   0x0ef4
+#define AFE_CONN54_1                                   0x0ef8
+#define AFE_CONN55_1                                   0x0efc
+#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_DL9_RCH_MON                                0x0f38
+#define AFE_DL9_LCH_MON                                0x0f3c
+#define AFE_DL5_CON0                                   0x0f4c
+#define AFE_DL5_BASE_MSB                               0x0f50
+#define AFE_DL5_BASE                                   0x0f54
+#define AFE_DL5_CUR_MSB                                0x0f58
+#define AFE_DL5_CUR                                    0x0f5c
+#define AFE_DL5_END_MSB                                0x0f60
+#define AFE_DL5_END                                    0x0f64
+#define AFE_DL6_CON0                                   0x0f68
+#define AFE_DL6_BASE_MSB                               0x0f6c
+#define AFE_DL6_BASE                                   0x0f70
+#define AFE_DL6_CUR_MSB                                0x0f74
+#define AFE_DL6_CUR                                    0x0f78
+#define AFE_DL6_END_MSB                                0x0f7c
+#define AFE_DL6_END                                    0x0f80
+#define AFE_DL7_CON0                                   0x0f84
+#define AFE_DL7_BASE_MSB                               0x0f88
+#define AFE_DL7_BASE                                   0x0f8c
+#define AFE_DL7_CUR_MSB                                0x0f90
+#define AFE_DL7_CUR                                    0x0f94
+#define AFE_DL7_END_MSB                                0x0f98
+#define AFE_DL7_END                                    0x0f9c
+#define AFE_DL8_CON0                                   0x0fa0
+#define AFE_DL8_BASE_MSB                               0x0fa4
+#define AFE_DL8_BASE                                   0x0fa8
+#define AFE_DL8_CUR_MSB                                0x0fac
+#define AFE_DL8_CUR                                    0x0fb0
+#define AFE_DL8_END_MSB                                0x0fb4
+#define AFE_DL8_END                                    0x0fb8
+#define AFE_DL9_CON0                                   0x0fbc
+#define AFE_DL9_BASE_MSB                               0x0fc0
+#define AFE_DL9_BASE                                   0x0fc4
+#define AFE_SE_SECURE_CON                              0x1004
+#define AFE_PROT_SIDEBAND_MON                          0x1008
+#define AFE_DOMAIN_SIDEBAND0_MON                       0x100c
+#define AFE_DOMAIN_SIDEBAND1_MON                       0x1010
+#define AFE_DOMAIN_SIDEBAND2_MON                       0x1014
+#define AFE_DOMAIN_SIDEBAND3_MON                       0x1018
+#define AFE_SECURE_MASK_CONN0                          0x1020
+#define AFE_SECURE_MASK_CONN1                          0x1024
+#define AFE_SECURE_MASK_CONN2                          0x1028
+#define AFE_SECURE_MASK_CONN3                          0x102c
+#define AFE_SECURE_MASK_CONN4                          0x1030
+#define AFE_SECURE_MASK_CONN5                          0x1034
+#define AFE_SECURE_MASK_CONN6                          0x1038
+#define AFE_SECURE_MASK_CONN7                          0x103c
+#define AFE_SECURE_MASK_CONN8                          0x1040
+#define AFE_SECURE_MASK_CONN9                          0x1044
+#define AFE_SECURE_MASK_CONN10                         0x1048
+#define AFE_SECURE_MASK_CONN11                         0x104c
+#define AFE_SECURE_MASK_CONN12                         0x1050
+#define AFE_SECURE_MASK_CONN13                         0x1054
+#define AFE_SECURE_MASK_CONN14                         0x1058
+#define AFE_SECURE_MASK_CONN15                         0x105c
+#define AFE_SECURE_MASK_CONN16                         0x1060
+#define AFE_SECURE_MASK_CONN17                         0x1064
+#define AFE_SECURE_MASK_CONN18                         0x1068
+#define AFE_SECURE_MASK_CONN19                         0x106c
+#define AFE_SECURE_MASK_CONN20                         0x1070
+#define AFE_SECURE_MASK_CONN21                         0x1074
+#define AFE_SECURE_MASK_CONN22                         0x1078
+#define AFE_SECURE_MASK_CONN23                         0x107c
+#define AFE_SECURE_MASK_CONN24                         0x1080
+#define AFE_SECURE_MASK_CONN25                         0x1084
+#define AFE_SECURE_MASK_CONN26                         0x1088
+#define AFE_SECURE_MASK_CONN27                         0x108c
+#define AFE_SECURE_MASK_CONN28                         0x1090
+#define AFE_SECURE_MASK_CONN29                         0x1094
+#define AFE_SECURE_MASK_CONN30                         0x1098
+#define AFE_SECURE_MASK_CONN31                         0x109c
+#define AFE_SECURE_MASK_CONN32                         0x10a0
+#define AFE_SECURE_MASK_CONN33                         0x10a4
+#define AFE_SECURE_MASK_CONN34                         0x10a8
+#define AFE_SECURE_MASK_CONN35                         0x10ac
+#define AFE_SECURE_MASK_CONN36                         0x10b0
+#define AFE_SECURE_MASK_CONN37                         0x10b4
+#define AFE_SECURE_MASK_CONN38                         0x10b8
+#define AFE_SECURE_MASK_CONN39                         0x10bc
+#define AFE_SECURE_MASK_CONN40                         0x10c0
+#define AFE_SECURE_MASK_CONN41                         0x10c4
+#define AFE_SECURE_MASK_CONN42                         0x10c8
+#define AFE_SECURE_MASK_CONN43                         0x10cc
+#define AFE_SECURE_MASK_CONN44                         0x10d0
+#define AFE_SECURE_MASK_CONN45                         0x10d4
+#define AFE_SECURE_MASK_CONN46                         0x10d8
+#define AFE_SECURE_MASK_CONN47                         0x10dc
+#define AFE_SECURE_MASK_CONN48                         0x10e0
+#define AFE_SECURE_MASK_CONN49                         0x10e4
+#define AFE_SECURE_MASK_CONN50                         0x10e8
+#define AFE_SECURE_MASK_CONN51                         0x10ec
+#define AFE_SECURE_MASK_CONN52                         0x10f0
+#define AFE_SECURE_MASK_CONN53                         0x10f4
+#define AFE_SECURE_MASK_CONN54                         0x10f8
+#define AFE_SECURE_MASK_CONN55                         0x10fc
+#define AFE_SECURE_MASK_CONN56                         0x1100
+#define AFE_SECURE_MASK_CONN57                         0x1104
+#define AFE_SECURE_MASK_CONN0_1                        0x1108
+#define AFE_SECURE_MASK_CONN1_1                        0x110c
+#define AFE_SECURE_MASK_CONN2_1                        0x1110
+#define AFE_SECURE_MASK_CONN3_1                        0x1114
+#define AFE_SECURE_MASK_CONN4_1                        0x1118
+#define AFE_SECURE_MASK_CONN5_1                        0x111c
+#define AFE_SECURE_MASK_CONN6_1                        0x1120
+#define AFE_SECURE_MASK_CONN7_1                        0x1124
+#define AFE_SECURE_MASK_CONN8_1                        0x1128
+#define AFE_SECURE_MASK_CONN9_1                        0x112c
+#define AFE_SECURE_MASK_CONN10_1                       0x1130
+#define AFE_SECURE_MASK_CONN11_1                       0x1134
+#define AFE_SECURE_MASK_CONN12_1                       0x1138
+#define AFE_SECURE_MASK_CONN13_1                       0x113c
+#define AFE_SECURE_MASK_CONN14_1                       0x1140
+#define AFE_SECURE_MASK_CONN15_1                       0x1144
+#define AFE_SECURE_MASK_CONN16_1                       0x1148
+#define AFE_SECURE_MASK_CONN17_1                       0x114c
+#define AFE_SECURE_MASK_CONN18_1                       0x1150
+#define AFE_SECURE_MASK_CONN19_1                       0x1154
+#define AFE_SECURE_MASK_CONN20_1                       0x1158
+#define AFE_SECURE_MASK_CONN21_1                       0x115c
+#define AFE_SECURE_MASK_CONN22_1                       0x1160
+#define AFE_SECURE_MASK_CONN23_1                       0x1164
+#define AFE_SECURE_MASK_CONN24_1                       0x1168
+#define AFE_SECURE_MASK_CONN25_1                       0x116c
+#define AFE_SECURE_MASK_CONN26_1                       0x1170
+#define AFE_SECURE_MASK_CONN27_1                       0x1174
+#define AFE_SECURE_MASK_CONN28_1                       0x1178
+#define AFE_SECURE_MASK_CONN29_1                       0x117c
+#define AFE_SECURE_MASK_CONN30_1                       0x1180
+#define AFE_SECURE_MASK_CONN31_1                       0x1184
+#define AFE_SECURE_MASK_CONN32_1                       0x1188
+#define AFE_SECURE_MASK_CONN33_1                       0x118c
+#define AFE_SECURE_MASK_CONN34_1                       0x1190
+#define AFE_SECURE_MASK_CONN35_1                       0x1194
+#define AFE_SECURE_MASK_CONN36_1                       0x1198
+#define AFE_SECURE_MASK_CONN37_1                       0x119c
+#define AFE_SECURE_MASK_CONN38_1                       0x11a0
+#define AFE_SECURE_MASK_CONN39_1                       0x11a4
+#define AFE_SECURE_MASK_CONN40_1                       0x11a8
+#define AFE_SECURE_MASK_CONN41_1                       0x11ac
+#define AFE_SECURE_MASK_CONN42_1                       0x11b0
+#define AFE_SECURE_MASK_CONN43_1                       0x11b4
+#define AFE_SECURE_MASK_CONN44_1                       0x11b8
+#define AFE_SECURE_MASK_CONN45_1                       0x11bc
+#define AFE_SECURE_MASK_CONN46_1                       0x11c0
+#define AFE_SECURE_MASK_CONN47_1                       0x11c4
+#define AFE_SECURE_MASK_CONN48_1                       0x11c8
+#define AFE_SECURE_MASK_CONN49_1                       0x11cc
+#define AFE_SECURE_MASK_CONN50_1                       0x11d0
+#define AFE_SECURE_MASK_CONN51_1                       0x11d4
+#define AFE_SECURE_MASK_CONN52_1                       0x11d8
+#define AFE_SECURE_MASK_CONN53_1                       0x11dc
+#define AFE_SECURE_MASK_CONN54_1                       0x11e0
+#define AFE_SECURE_MASK_CONN55_1                       0x11e4
+#define AFE_SECURE_MASK_CONN56_1                       0x11e8
+#define AFE_SECURE_MASK_TINY_CONN0                     0x1200
+#define AFE_SECURE_MASK_TINY_CONN1                     0x1204
+#define AFE_SECURE_MASK_TINY_CONN2                     0x1208
+#define AFE_SECURE_MASK_TINY_CONN3                     0x120c
+#define AFE_SECURE_MASK_TINY_CONN4                     0x1210
+#define AFE_SECURE_MASK_TINY_CONN5                     0x1214
+#define AFE_SECURE_MASK_TINY_CONN6                     0x1218
+#define AFE_SECURE_MASK_TINY_CONN7                     0x121c
+
+#define AFE_MAX_REGISTER AFE_SECURE_MASK_TINY_CONN7
+
+#define AFE_IRQ_STATUS_BITS 0x87FFFFFF
+#define AFE_IRQ_CNT_SHIFT 0
+#define AFE_IRQ_CNT_MASK 0x3ffff
+
+#endif
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
index 363dc3b1bbe4..b93ea33739f2 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menu "ASoC support for Amlogic platforms"
-	depends on ARCH_MESON || COMPILE_TEST
+	depends on ARCH_MESON || (COMPILE_TEST && COMMON_CLK)
 
 config SND_MESON_AIU
 	tristate "Amlogic AIU"
@@ -98,7 +98,7 @@ config SND_MESON_AXG_PDM
 	  in the Amlogic AXG SoC family
 
 config SND_MESON_CARD_UTILS
-       tristate
+	tristate
 
 config SND_MESON_CODEC_GLUE
 	tristate
diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c
index 56d2592c16d5..4c1349dd1e06 100644
--- a/sound/soc/meson/t9015.c
+++ b/sound/soc/meson/t9015.c
@@ -312,7 +312,7 @@ static int t9015_probe(struct platform_device *pdev)
 					       &t9015_dai, 1);
 }
 
-static const struct of_device_id t9015_ids[] = {
+static const struct of_device_id t9015_ids[] __maybe_unused = {
 	{ .compatible = "amlogic,t9015", },
 	{ }
 };
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 0ac85eada75c..9d40e8a206d1 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -221,13 +221,13 @@ config SND_PXA2XX_SOC_MIOA701
 	  MIO A701.
 
 config SND_PXA2XX_SOC_IMOTE2
-       tristate "SoC Audio support for IMote 2"
-       depends on SND_PXA2XX_SOC && MACH_INTELMOTE2 && I2C
-       select SND_PXA2XX_SOC_I2S
-       select SND_SOC_WM8940
-       help
-	 Say Y if you want to add support for SoC audio on the
-	 IMote 2.
+	tristate "SoC Audio support for IMote 2"
+	depends on SND_PXA2XX_SOC && MACH_INTELMOTE2 && I2C
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_WM8940
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  IMote 2.
 
 config SND_MMP_SOC_BROWNSTONE
 	tristate "SoC Audio support for Marvell Brownstone"
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c
index 4255851c71c1..4803972ee655 100644
--- a/sound/soc/pxa/mmp-sspa.c
+++ b/sound/soc/pxa/mmp-sspa.c
@@ -239,12 +239,16 @@ static int mmp_sspa_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
+	sspa_ctrl &= ~SSPA_CTL_XPH;
 	if (dev->of_node || params_channels(params) == 2)
 		sspa_ctrl |= SSPA_CTL_XPH;
 
 	sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK;
 	sspa_ctrl |= SSPA_CTL_XWDLEN1(bitval);
 
+	sspa_ctrl &= ~SSPA_CTL_XWDLEN2_MASK;
+	sspa_ctrl |= SSPA_CTL_XWDLEN2(bitval);
+
 	sspa_ctrl &= ~SSPA_CTL_XSSZ1_MASK;
 	sspa_ctrl |= SSPA_CTL_XSSZ1(bitval);
 
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index c4e7307a4437..b941adcbb8f9 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -99,8 +99,7 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
 		pxa_ssp_disable(ssp);
 	}
 
-	if (priv->extclk)
-		clk_prepare_enable(priv->extclk);
+	clk_prepare_enable(priv->extclk);
 
 	dma = kzalloc(sizeof(struct snd_dmaengine_dai_dma_data), GFP_KERNEL);
 	if (!dma)
@@ -124,8 +123,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
 		clk_disable_unprepare(ssp->clk);
 	}
 
-	if (priv->extclk)
-		clk_disable_unprepare(priv->extclk);
+	clk_disable_unprepare(priv->extclk);
 
 	kfree(snd_soc_dai_get_dma_data(cpu_dai, substream));
 	snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 2696ffcba880..cc7c1de2f1d9 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -106,6 +106,7 @@ config SND_SOC_QDSP6
 config SND_SOC_MSM8996
 	tristate "SoC Machine driver for MSM8996 and APQ8096 boards"
 	depends on QCOM_APR
+	depends on COMMON_CLK
 	select SND_SOC_QDSP6
 	select SND_SOC_QCOM_COMMON
 	help
@@ -127,4 +128,28 @@ config SND_SOC_SDM845
 	  SDM845 SoC-based systems.
 	  Say Y if you want to use audio device on this SoCs.
 
+config SND_SOC_SM8250
+	tristate "SoC Machine driver for SM8250 boards"
+	depends on QCOM_APR && SOUNDWIRE
+	depends on COMMON_CLK
+	select SND_SOC_QDSP6
+	select SND_SOC_QCOM_COMMON
+	help
+	  To add support for audio on Qualcomm Technologies Inc.
+	  SM8250 SoC-based systems.
+	  Say Y if you want to use audio device on this SoCs.
+
+config SND_SOC_SC7180
+	tristate "SoC Machine driver for SC7180 boards"
+	depends on I2C
+	select SND_SOC_QCOM_COMMON
+	select SND_SOC_LPASS_SC7180
+	select SND_SOC_MAX98357A
+	select SND_SOC_RT5682_I2C
+	select SND_SOC_ADAU7002
+	help
+	  To add support for audio on Qualcomm Technologies Inc.
+	  SC7180 SoC-based systems.
+	  Say Y if you want to use audio device on this SoCs.
+
 endif #SND_SOC_QCOM
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index 0bd90d74e3db..1600ae55bd34 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -18,13 +18,17 @@ obj-$(CONFIG_SND_SOC_LPASS_SC7180) += snd-soc-lpass-sc7180.o
 snd-soc-storm-objs := storm.o
 snd-soc-apq8016-sbc-objs := apq8016_sbc.o
 snd-soc-apq8096-objs := apq8096.o
+snd-soc-sc7180-objs := sc7180.o
 snd-soc-sdm845-objs := sdm845.o
+snd-soc-sm8250-objs := sm8250.o
 snd-soc-qcom-common-objs := common.o
 
 obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
 obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
 obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-apq8096.o
+obj-$(CONFIG_SND_SOC_SC7180) += snd-soc-sc7180.o
 obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
+obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o
 obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
 
 #DSP lib
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
index 575e2aefefe3..270986b2f102 100644
--- a/sound/soc/qcom/apq8016_sbc.c
+++ b/sound/soc/qcom/apq8016_sbc.c
@@ -167,7 +167,7 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev)
 	return devm_snd_soc_register_card(&pdev->dev, card);
 }
 
-static const struct of_device_id apq8016_sbc_device_id[]  = {
+static const struct of_device_id apq8016_sbc_device_id[] __maybe_unused = {
 	{ .compatible = "qcom,apq8016-sbc-sndcard" },
 	{},
 };
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index 54660f126d09..09af00700700 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -58,7 +58,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
 		dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL);
 		if (!dlc) {
 			ret = -ENOMEM;
-			goto err;
+			goto err_put_np;
 		}
 
 		link->cpus	= &dlc[0];
@@ -70,7 +70,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
 		ret = of_property_read_string(np, "link-name", &link->name);
 		if (ret) {
 			dev_err(card->dev, "error getting codec dai_link name\n");
-			goto err;
+			goto err_put_np;
 		}
 
 		cpu = of_get_child_by_name(np, "cpu");
@@ -130,8 +130,10 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
 		} else {
 			/* DPCM frontend */
 			dlc = devm_kzalloc(dev, sizeof(*dlc), GFP_KERNEL);
-			if (!dlc)
-				return -ENOMEM;
+			if (!dlc) {
+				ret = -ENOMEM;
+				goto err;
+			}
 
 			link->codecs	 = dlc;
 			link->num_codecs = 1;
@@ -158,10 +160,11 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
 
 	return 0;
 err:
-	of_node_put(np);
 	of_node_put(cpu);
 	of_node_put(codec);
 	of_node_put(platform);
+err_put_np:
+	of_node_put(np);
 	return ret;
 }
 EXPORT_SYMBOL(qcom_snd_parse_of);
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
index 0aedb3a0a798..8507ef8f6679 100644
--- a/sound/soc/qcom/lpass-apq8016.c
+++ b/sound/soc/qcom/lpass-apq8016.c
@@ -291,7 +291,7 @@ static struct lpass_variant apq8016_data = {
 	.free_dma_channel	= apq8016_lpass_free_dma_channel,
 };
 
-static const struct of_device_id apq8016_lpass_cpu_device_id[] = {
+static const struct of_device_id apq8016_lpass_cpu_device_id[] __maybe_unused = {
 	{ .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data },
 	{}
 };
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 426235a217ec..af684fd19ab9 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -673,7 +673,7 @@ static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
 	return false;
 }
 
-struct regmap_config lpass_hdmi_regmap_config = {
+static struct regmap_config lpass_hdmi_regmap_config = {
 	.reg_bits = 32,
 	.reg_stride = 4,
 	.val_bits = 32,
@@ -914,5 +914,15 @@ int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
 
+void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+
+	if (drvdata->variant->exit)
+		drvdata->variant->exit(pdev);
+
+}
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_shutdown);
+
 MODULE_DESCRIPTION("QTi LPASS CPU Driver");
 MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/lpass-hdmi.c b/sound/soc/qcom/lpass-hdmi.c
index 172952d3a5d6..abfb8737a89f 100644
--- a/sound/soc/qcom/lpass-hdmi.c
+++ b/sound/soc/qcom/lpass-hdmi.c
@@ -24,7 +24,7 @@ static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream,
 	unsigned int rate = params_rate(params);
 	unsigned int channels = params_channels(params);
 	unsigned int ret;
-	unsigned int bitwidth;
+	int bitwidth;
 	unsigned int word_length;
 	unsigned int ch_sts_buf0;
 	unsigned int ch_sts_buf1;
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index 832a9161484e..92f98b4df47f 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -161,7 +161,7 @@ static struct lpass_variant ipq806x_data = {
 	.free_dma_channel	= ipq806x_lpass_free_dma_channel,
 };
 
-static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
+static const struct of_device_id ipq806x_lpass_cpu_device_id[] __maybe_unused = {
 	{ .compatible = "qcom,lpass-cpu", .data = &ipq806x_data },
 	{}
 };
diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c
index bc998d501600..85db650c2169 100644
--- a/sound/soc/qcom/lpass-sc7180.c
+++ b/sound/soc/qcom/lpass-sc7180.c
@@ -34,7 +34,8 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = {
 		},
 		.capture = {
 			.stream_name = "Primary Capture",
-			.formats = SNDRV_PCM_FMTBIT_S16,
+			.formats = SNDRV_PCM_FMTBIT_S16 |
+				SNDRV_PCM_FMTBIT_S32,
 			.rates = SNDRV_PCM_RATE_48000,
 			.rate_min	= 48000,
 			.rate_max	= 48000,
@@ -96,8 +97,8 @@ static int sc7180_lpass_alloc_dma_channel(struct lpass_data *drvdata,
 			chan = find_first_zero_bit(&drvdata->dma_ch_bit_map,
 						v->rdma_channels);
 
-		if (chan >= v->rdma_channels)
-			return -EBUSY;
+			if (chan >= v->rdma_channels)
+				return -EBUSY;
 		} else {
 			chan = find_next_zero_bit(&drvdata->dma_ch_bit_map,
 					v->wrdma_channel_start +
@@ -284,7 +285,7 @@ static struct lpass_variant sc7180_data = {
 	.free_dma_channel	= sc7180_lpass_free_dma_channel,
 };
 
-static const struct of_device_id sc7180_lpass_cpu_device_id[] = {
+static const struct of_device_id sc7180_lpass_cpu_device_id[] __maybe_unused = {
 	{.compatible = "qcom,sc7180-lpass-cpu", .data = &sc7180_data},
 	{}
 };
@@ -297,6 +298,7 @@ static struct platform_driver sc7180_lpass_cpu_platform_driver = {
 	},
 	.probe = asoc_qcom_lpass_cpu_platform_probe,
 	.remove = asoc_qcom_lpass_cpu_platform_remove,
+	.shutdown = asoc_qcom_lpass_cpu_platform_shutdown,
 };
 
 module_platform_driver(sc7180_lpass_cpu_platform_driver);
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index bccd1a05d771..0195372905ed 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -256,6 +256,7 @@ struct lpass_variant {
 /* register the platform driver from the CPU DAI driver */
 int asoc_qcom_lpass_platform_register(struct platform_device *);
 int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
+void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev);
 int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev);
 int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
 extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c
index 72f29720398c..1855b805eba2 100644
--- a/sound/soc/qcom/qdsp6/q6adm.c
+++ b/sound/soc/qcom/qdsp6/q6adm.c
@@ -601,14 +601,7 @@ static int q6adm_probe(struct apr_device *adev)
 	INIT_LIST_HEAD(&adm->copps_list);
 	spin_lock_init(&adm->copps_list_lock);
 
-	return of_platform_populate(dev->of_node, NULL, NULL, dev);
-}
-
-static int q6adm_remove(struct apr_device *adev)
-{
-	of_platform_depopulate(&adev->dev);
-
-	return 0;
+	return devm_of_platform_populate(dev);
 }
 
 #ifdef CONFIG_OF
@@ -621,7 +614,6 @@ MODULE_DEVICE_TABLE(of, q6adm_device_id);
 
 static struct apr_driver qcom_q6adm_driver = {
 	.probe = q6adm_probe,
-	.remove = q6adm_remove,
 	.callback = q6adm_callback,
 	.driver = {
 		.name = "qcom-q6adm",
diff --git a/sound/soc/qcom/qdsp6/q6afe-clocks.c b/sound/soc/qcom/qdsp6/q6afe-clocks.c
index 2efc2eaa0424..f0362f061652 100644
--- a/sound/soc/qcom/qdsp6/q6afe-clocks.c
+++ b/sound/soc/qcom/qdsp6/q6afe-clocks.c
@@ -16,6 +16,7 @@
 		.afe_clk_id	= Q6AFE_##id,		\
 		.name = #id,				\
 		.attributes = LPASS_CLK_ATTRIBUTE_COUPLE_NO, \
+		.rate = 19200000,			\
 		.hw.init = &(struct clk_init_data) {	\
 			.ops = &clk_q6afe_ops,		\
 			.name = #id,			\
@@ -119,7 +120,7 @@ static const struct clk_ops clk_vote_q6afe_ops = {
 	.unprepare	= clk_unvote_q6afe_block,
 };
 
-struct q6afe_clk *q6afe_clks[Q6AFE_MAX_CLK_ID] = {
+static struct q6afe_clk *q6afe_clks[Q6AFE_MAX_CLK_ID] = {
 	[LPASS_CLK_ID_PRI_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_IBIT),
 	[LPASS_CLK_ID_PRI_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_EBIT),
 	[LPASS_CLK_ID_SEC_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_IBIT),
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index 0ca1e4aae518..daa58b5f941e 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -1740,14 +1740,7 @@ static int q6afe_probe(struct apr_device *adev)
 
 	dev_set_drvdata(dev, afe);
 
-	return of_platform_populate(dev->of_node, NULL, NULL, dev);
-}
-
-static int q6afe_remove(struct apr_device *adev)
-{
-	of_platform_depopulate(&adev->dev);
-
-	return 0;
+	return devm_of_platform_populate(dev);
 }
 
 #ifdef CONFIG_OF
@@ -1760,7 +1753,6 @@ MODULE_DEVICE_TABLE(of, q6afe_device_id);
 
 static struct apr_driver qcom_q6afe_driver = {
 	.probe = q6afe_probe,
-	.remove = q6afe_remove,
 	.callback = q6afe_callback,
 	.driver = {
 		.name = "qcom-q6afe",
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index c547c560cb24..a6618efe22f2 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -1727,14 +1727,7 @@ static int q6asm_probe(struct apr_device *adev)
 	spin_lock_init(&q6asm->slock);
 	dev_set_drvdata(dev, q6asm);
 
-	return of_platform_populate(dev->of_node, NULL, NULL, dev);
-}
-
-static int q6asm_remove(struct apr_device *adev)
-{
-	of_platform_depopulate(&adev->dev);
-
-	return 0;
+	return devm_of_platform_populate(dev);
 }
 
 #ifdef CONFIG_OF
@@ -1747,7 +1740,6 @@ MODULE_DEVICE_TABLE(of, q6asm_device_id);
 
 static struct apr_driver qcom_q6asm_driver = {
 	.probe = q6asm_probe,
-	.remove = q6asm_remove,
 	.callback = q6asm_srvc_callback,
 	.driver = {
 		.name = "qcom-q6asm",
diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c
new file mode 100644
index 000000000000..768566bb57a5
--- /dev/null
+++ b/sound/soc/qcom/sc7180.c
@@ -0,0 +1,391 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright (c) 2020, The Linux Foundation. All rights reserved.
+//
+// sc7180.c -- ALSA SoC Machine driver for SC7180
+
+#include <dt-bindings/sound/sc7180-lpass.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <uapi/linux/input-event-codes.h>
+
+#include "../codecs/rt5682.h"
+#include "common.h"
+#include "lpass.h"
+
+#define DEFAULT_MCLK_RATE		19200000
+#define RT5682_PLL1_FREQ (48000 * 512)
+
+#define DRIVER_NAME "SC7180"
+
+struct sc7180_snd_data {
+	struct snd_soc_card card;
+	u32 pri_mi2s_clk_count;
+	struct snd_soc_jack hs_jack;
+	struct snd_soc_jack hdmi_jack;
+	struct gpio_desc *dmic_sel;
+	int dmic_switch;
+};
+
+static void sc7180_jack_free(struct snd_jack *jack)
+{
+	struct snd_soc_component *component = jack->private_data;
+
+	snd_soc_component_set_jack(component, NULL, NULL);
+}
+
+static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_card *card = rtd->card;
+	struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card);
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+	struct snd_soc_component *component = codec_dai->component;
+	struct snd_jack *jack;
+	int rval;
+
+	rval = snd_soc_card_jack_new(
+			card, "Headset Jack",
+			SND_JACK_HEADSET |
+			SND_JACK_HEADPHONE |
+			SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			SND_JACK_BTN_2 | SND_JACK_BTN_3,
+			&pdata->hs_jack, NULL, 0);
+
+	if (rval < 0) {
+		dev_err(card->dev, "Unable to add Headset Jack\n");
+		return rval;
+	}
+
+	jack = pdata->hs_jack.jack;
+
+	snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+	snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+	snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+	snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+	jack->private_data = component;
+	jack->private_free = sc7180_jack_free;
+
+	return snd_soc_component_set_jack(component, &pdata->hs_jack, NULL);
+}
+
+static int sc7180_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_card *card = rtd->card;
+	struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card);
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+	struct snd_soc_component *component = codec_dai->component;
+	struct snd_jack *jack;
+	int rval;
+
+	rval = snd_soc_card_jack_new(
+			card, "HDMI Jack",
+			SND_JACK_LINEOUT,
+			&pdata->hdmi_jack, NULL, 0);
+
+	if (rval < 0) {
+		dev_err(card->dev, "Unable to add HDMI Jack\n");
+		return rval;
+	}
+
+	jack = pdata->hdmi_jack.jack;
+	jack->private_data = component;
+	jack->private_free = sc7180_jack_free;
+
+	return snd_soc_component_set_jack(component, &pdata->hdmi_jack, NULL);
+}
+
+static int sc7180_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+
+	switch (cpu_dai->id) {
+	case MI2S_PRIMARY:
+		return sc7180_headset_init(rtd);
+	case MI2S_SECONDARY:
+		return 0;
+	case LPASS_DP_RX:
+		return sc7180_hdmi_init(rtd);
+	default:
+		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+			cpu_dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int sc7180_snd_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+	int ret;
+
+	switch (cpu_dai->id) {
+	case MI2S_PRIMARY:
+		if (++data->pri_mi2s_clk_count == 1) {
+			snd_soc_dai_set_sysclk(cpu_dai,
+					       LPASS_MCLK0,
+					       DEFAULT_MCLK_RATE,
+					       SNDRV_PCM_STREAM_PLAYBACK);
+		}
+
+		snd_soc_dai_set_fmt(codec_dai,
+				    SND_SOC_DAIFMT_CBS_CFS |
+				    SND_SOC_DAIFMT_NB_NF |
+				    SND_SOC_DAIFMT_I2S);
+
+		/* Configure PLL1 for codec */
+		ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK,
+					  DEFAULT_MCLK_RATE, RT5682_PLL1_FREQ);
+		if (ret) {
+			dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+			return ret;
+		}
+
+		/* Configure sysclk for codec */
+		ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
+					     RT5682_PLL1_FREQ,
+					     SND_SOC_CLOCK_IN);
+		if (ret)
+			dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n",
+				ret);
+
+		break;
+	case MI2S_SECONDARY:
+		break;
+	case LPASS_DP_RX:
+		break;
+	default:
+		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+			cpu_dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int dmic_get(struct snd_kcontrol *kcontrol,
+		    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct sc7180_snd_data *data = snd_soc_card_get_drvdata(dapm->card);
+
+	ucontrol->value.integer.value[0] = data->dmic_switch;
+	return 0;
+}
+
+static int dmic_set(struct snd_kcontrol *kcontrol,
+		    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct sc7180_snd_data *data = snd_soc_card_get_drvdata(dapm->card);
+
+	data->dmic_switch = ucontrol->value.integer.value[0];
+	gpiod_set_value(data->dmic_sel, data->dmic_switch);
+	return 0;
+}
+
+static void sc7180_snd_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+
+	switch (cpu_dai->id) {
+	case MI2S_PRIMARY:
+		if (--data->pri_mi2s_clk_count == 0) {
+			snd_soc_dai_set_sysclk(cpu_dai,
+					       LPASS_MCLK0,
+					       0,
+					       SNDRV_PCM_STREAM_PLAYBACK);
+		}
+		break;
+	case MI2S_SECONDARY:
+		break;
+	case LPASS_DP_RX:
+		break;
+	default:
+		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+			cpu_dai->id);
+		break;
+	}
+}
+
+static int sc7180_adau7002_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+
+	switch (cpu_dai->id) {
+	case MI2S_PRIMARY:
+		return 0;
+	case MI2S_SECONDARY:
+		return 0;
+	case LPASS_DP_RX:
+		return sc7180_hdmi_init(rtd);
+	default:
+		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+			cpu_dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	switch (cpu_dai->id) {
+	case MI2S_PRIMARY:
+		snd_soc_dai_set_fmt(codec_dai,
+				    SND_SOC_DAIFMT_CBS_CFS |
+				    SND_SOC_DAIFMT_NB_NF |
+				    SND_SOC_DAIFMT_I2S);
+		runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
+		snd_pcm_hw_constraint_msbits(runtime, 0, 32, 32);
+
+		break;
+	case MI2S_SECONDARY:
+		break;
+	case LPASS_DP_RX:
+		break;
+	default:
+		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+			cpu_dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct snd_soc_ops sc7180_ops = {
+	.startup = sc7180_snd_startup,
+	.shutdown = sc7180_snd_shutdown,
+};
+
+static const struct snd_soc_ops sc7180_adau7002_ops = {
+	.startup = sc7180_adau7002_snd_startup,
+};
+
+static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_widget sc7180_adau7002_snd_widgets[] = {
+	SND_SOC_DAPM_MIC("DMIC", NULL),
+};
+
+static const char * const dmic_mux_text[] = {
+	"Front Mic",
+	"Rear Mic",
+};
+
+static SOC_ENUM_SINGLE_DECL(sc7180_dmic_enum,
+			    SND_SOC_NOPM, 0, dmic_mux_text);
+
+static const struct snd_kcontrol_new sc7180_dmic_mux_control =
+	SOC_DAPM_ENUM_EXT("DMIC Select Mux", sc7180_dmic_enum,
+			  dmic_get, dmic_set);
+
+static const struct snd_soc_dapm_widget sc7180_snd_dual_mic_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("DMIC", NULL),
+	SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &sc7180_dmic_mux_control),
+};
+
+static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route[] = {
+	{"Dmic Mux", "Front Mic", "DMIC"},
+	{"Dmic Mux", "Rear Mic", "DMIC"},
+};
+
+static int sc7180_snd_platform_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card;
+	struct sc7180_snd_data *data;
+	struct device *dev = &pdev->dev;
+	struct snd_soc_dai_link *link;
+	int ret;
+	int i;
+	bool no_headphone = false;
+
+	/* Allocate the private data */
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	card = &data->card;
+	snd_soc_card_set_drvdata(card, data);
+
+	card->owner = THIS_MODULE;
+	card->driver_name = DRIVER_NAME;
+	card->dev = dev;
+	card->dapm_widgets = sc7180_snd_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_widgets);
+
+	if (of_property_read_bool(dev->of_node, "dmic-gpios")) {
+		card->dapm_widgets = sc7180_snd_dual_mic_widgets,
+		card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_dual_mic_widgets),
+		card->dapm_routes = sc7180_snd_dual_mic_audio_route,
+		card->num_dapm_routes = ARRAY_SIZE(sc7180_snd_dual_mic_audio_route),
+		data->dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW);
+		if (IS_ERR(data->dmic_sel)) {
+			dev_err(&pdev->dev, "DMIC gpio failed err=%ld\n", PTR_ERR(data->dmic_sel));
+			return PTR_ERR(data->dmic_sel);
+		}
+	}
+
+	if (of_device_is_compatible(dev->of_node, "google,sc7180-coachz")) {
+		no_headphone = true;
+		card->dapm_widgets = sc7180_adau7002_snd_widgets;
+		card->num_dapm_widgets = ARRAY_SIZE(sc7180_adau7002_snd_widgets);
+	}
+
+	ret = qcom_snd_parse_of(card);
+	if (ret)
+		return ret;
+
+	for_each_card_prelinks(card, i, link) {
+		if (no_headphone) {
+			link->ops = &sc7180_adau7002_ops;
+			link->init = sc7180_adau7002_init;
+		} else {
+			link->ops = &sc7180_ops;
+			link->init = sc7180_init;
+		}
+	}
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static const struct of_device_id sc7180_snd_device_id[]  = {
+	{.compatible = "google,sc7180-trogdor"},
+	{.compatible = "google,sc7180-coachz"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, sc7180_snd_device_id);
+
+static struct platform_driver sc7180_snd_driver = {
+	.probe = sc7180_snd_platform_probe,
+	.driver = {
+		.name = "msm-snd-sc7180",
+		.of_match_table = sc7180_snd_device_id,
+		.pm = &snd_soc_pm_ops,
+	},
+};
+module_platform_driver(sc7180_snd_driver);
+
+MODULE_DESCRIPTION("sc7180 ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
new file mode 100644
index 000000000000..fe8fd7367e21
--- /dev/null
+++ b/sound/soc/qcom/sm8250.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2020, Linaro Limited
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <linux/soundwire/sdw.h>
+#include "qdsp6/q6afe.h"
+#include "common.h"
+
+#define DRIVER_NAME		"sm8250"
+#define MI2S_BCLK_RATE		1536000
+
+struct sm8250_snd_data {
+	bool stream_prepared[AFE_PORT_MAX];
+	struct snd_soc_card *card;
+	struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
+};
+
+static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+				     struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	return 0;
+}
+
+static int sm8250_snd_startup(struct snd_pcm_substream *substream)
+{
+	unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+	unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+
+	switch (cpu_dai->id) {
+	case TERTIARY_MI2S_RX:
+		codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
+		snd_soc_dai_set_sysclk(cpu_dai,
+			Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
+			MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+		snd_soc_dai_set_fmt(cpu_dai, fmt);
+		snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int sm8250_snd_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
+	struct sdw_stream_runtime *sruntime;
+	int i;
+
+	switch (cpu_dai->id) {
+	case WSA_CODEC_DMA_RX_0:
+		for_each_rtd_codec_dais(rtd, i, codec_dai) {
+			sruntime = snd_soc_dai_get_sdw_stream(codec_dai,
+						      substream->stream);
+			if (sruntime != ERR_PTR(-ENOTSUPP))
+				pdata->sruntime[cpu_dai->id] = sruntime;
+		}
+		break;
+	}
+
+	return 0;
+
+}
+
+static int sm8250_snd_wsa_dma_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+	struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
+	int ret;
+
+	if (!sruntime)
+		return 0;
+
+	if (data->stream_prepared[cpu_dai->id]) {
+		sdw_disable_stream(sruntime);
+		sdw_deprepare_stream(sruntime);
+		data->stream_prepared[cpu_dai->id] = false;
+	}
+
+	ret = sdw_prepare_stream(sruntime);
+	if (ret)
+		return ret;
+
+	/**
+	 * NOTE: there is a strict hw requirement about the ordering of port
+	 * enables and actual WSA881x PA enable. PA enable should only happen
+	 * after soundwire ports are enabled if not DC on the line is
+	 * accumulated resulting in Click/Pop Noise
+	 * PA enable/mute are handled as part of codec DAPM and digital mute.
+	 */
+
+	ret = sdw_enable_stream(sruntime);
+	if (ret) {
+		sdw_deprepare_stream(sruntime);
+		return ret;
+	}
+	data->stream_prepared[cpu_dai->id]  = true;
+
+	return ret;
+}
+
+static int sm8250_snd_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+
+	switch (cpu_dai->id) {
+	case WSA_CODEC_DMA_RX_0:
+	case WSA_CODEC_DMA_RX_1:
+		return sm8250_snd_wsa_dma_prepare(substream);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int sm8250_snd_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
+
+	switch (cpu_dai->id) {
+	case WSA_CODEC_DMA_RX_0:
+	case WSA_CODEC_DMA_RX_1:
+		if (sruntime && data->stream_prepared[cpu_dai->id]) {
+			sdw_disable_stream(sruntime);
+			sdw_deprepare_stream(sruntime);
+			data->stream_prepared[cpu_dai->id] = false;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_ops sm8250_be_ops = {
+	.startup = sm8250_snd_startup,
+	.hw_params = sm8250_snd_hw_params,
+	.hw_free = sm8250_snd_hw_free,
+	.prepare = sm8250_snd_prepare,
+};
+
+static void sm8250_add_be_ops(struct snd_soc_card *card)
+{
+	struct snd_soc_dai_link *link;
+	int i;
+
+	for_each_card_prelinks(card, i, link) {
+		if (link->no_pcm == 1) {
+			link->be_hw_params_fixup = sm8250_be_hw_params_fixup;
+			link->ops = &sm8250_be_ops;
+		}
+	}
+}
+
+static int sm8250_platform_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card;
+	struct sm8250_snd_data *data;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
+
+	/* Allocate the private data */
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	card->dev = dev;
+	dev_set_drvdata(dev, card);
+	snd_soc_card_set_drvdata(card, data);
+	ret = qcom_snd_parse_of(card);
+	if (ret)
+		return ret;
+
+	card->driver_name = DRIVER_NAME;
+	sm8250_add_be_ops(card);
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static const struct of_device_id snd_sm8250_dt_match[] = {
+	{.compatible = "qcom,sm8250-sndcard"},
+	{.compatible = "qcom,qrb5165-rb5-sndcard"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, snd_sm8250_dt_match);
+
+static struct platform_driver snd_sm8250_driver = {
+	.probe  = sm8250_platform_probe,
+	.driver = {
+		.name = "snd-sm8250",
+		.of_match_table = snd_sm8250_dt_match,
+	},
+};
+module_platform_driver(snd_sm8250_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_DESCRIPTION("SM8250 ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 593299675b8c..eae287d905eb 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -566,7 +566,7 @@ static const struct rk_i2s_pins rk3399_i2s_pins = {
 	.shift = 11,
 };
 
-static const struct of_device_id rockchip_i2s_match[] = {
+static const struct of_device_id rockchip_i2s_match[] __maybe_unused = {
 	{ .compatible = "rockchip,rk3066-i2s", },
 	{ .compatible = "rockchip,rk3188-i2s", },
 	{ .compatible = "rockchip,rk3288-i2s", },
diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index 5adb293d0435..e5f732747f71 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -460,7 +460,7 @@ static const struct regmap_config rockchip_pdm_regmap_config = {
 	.cache_type = REGCACHE_FLAT,
 };
 
-static const struct of_device_id rockchip_pdm_match[] = {
+static const struct of_device_id rockchip_pdm_match[] __maybe_unused = {
 	{ .compatible = "rockchip,pdm",
 	  .data = (void *)RK_PDM_RK3229 },
 	{ .compatible = "rockchip,px30-pdm",
diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index 674810851fbc..ffb4ec306441 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -41,7 +41,7 @@ struct rk_spdif_dev {
 	struct regmap *regmap;
 };
 
-static const struct of_device_id rk_spdif_match[] = {
+static const struct of_device_id rk_spdif_match[] __maybe_unused = {
 	{ .compatible = "rockchip,rk3066-spdif",
 	  .data = (void *)RK_SPDIF_RK3066 },
 	{ .compatible = "rockchip,rk3188-spdif",
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index df53d4ea808f..4bdc268fd981 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -1212,8 +1212,7 @@ static int i2s_runtime_suspend(struct device *dev)
 	priv->suspend_i2scon = readl(priv->addr + I2SCON);
 	priv->suspend_i2spsr = readl(priv->addr + I2SPSR);
 
-	if (priv->op_clk)
-		clk_disable_unprepare(priv->op_clk);
+	clk_disable_unprepare(priv->op_clk);
 	clk_disable_unprepare(priv->clk);
 
 	return 0;
@@ -1622,28 +1621,28 @@ static const struct samsung_i2s_dai_data i2sv3_dai_type = {
 	.i2s_variant_regs = &i2sv3_regs,
 };
 
-static const struct samsung_i2s_dai_data i2sv5_dai_type = {
+static const struct samsung_i2s_dai_data i2sv5_dai_type __maybe_unused = {
 	.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
 			QUIRK_SUPPORTS_IDMA,
 	.pcm_rates = SNDRV_PCM_RATE_8000_96000,
 	.i2s_variant_regs = &i2sv3_regs,
 };
 
-static const struct samsung_i2s_dai_data i2sv6_dai_type = {
+static const struct samsung_i2s_dai_data i2sv6_dai_type __maybe_unused = {
 	.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
 			QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA,
 	.pcm_rates = SNDRV_PCM_RATE_8000_96000,
 	.i2s_variant_regs = &i2sv6_regs,
 };
 
-static const struct samsung_i2s_dai_data i2sv7_dai_type = {
+static const struct samsung_i2s_dai_data i2sv7_dai_type __maybe_unused = {
 	.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
 			QUIRK_SUPPORTS_TDM,
 	.pcm_rates = SNDRV_PCM_RATE_8000_192000,
 	.i2s_variant_regs = &i2sv7_regs,
 };
 
-static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = {
+static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 __maybe_unused = {
 	.quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR,
 	.pcm_rates = SNDRV_PCM_RATE_8000_96000,
 	.i2s_variant_regs = &i2sv5_i2s1_regs,
diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c
index d03340ce49a2..1f9a553edf19 100644
--- a/sound/soc/samsung/midas_wm1811.c
+++ b/sound/soc/samsung/midas_wm1811.c
@@ -531,7 +531,6 @@ static struct platform_driver midas_driver = {
 	.driver = {
 		.name = "midas-audio",
 		.of_match_table = midas_of_match,
-		.owner = THIS_MODULE,
 		.pm = &snd_soc_pm_ops,
 	},
 	.probe = midas_probe,
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c
index 64a1a64656ab..681b244d5312 100644
--- a/sound/soc/samsung/smdk_wm8994.c
+++ b/sound/soc/samsung/smdk_wm8994.c
@@ -136,7 +136,7 @@ static struct snd_soc_card smdk = {
 	.num_links = ARRAY_SIZE(smdk_dai),
 };
 
-static const struct of_device_id samsung_wm8994_of_match[] = {
+static const struct of_device_id samsung_wm8994_of_match[] __maybe_unused = {
 	{ .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data },
 	{},
 };
@@ -170,7 +170,7 @@ static int smdk_audio_probe(struct platform_device *pdev)
 		smdk_dai[0].platforms->of_node = smdk_dai[0].cpus->of_node;
 	}
 
-	id = of_match_device(of_match_ptr(samsung_wm8994_of_match), &pdev->dev);
+	id = of_match_device(samsung_wm8994_of_match, &pdev->dev);
 	if (id)
 		*board = *((struct smdk_wm8994_data *)id->data);
 
diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c
index 07163f07c6d5..989af624dd11 100644
--- a/sound/soc/samsung/snow.c
+++ b/sound/soc/samsung/snow.c
@@ -189,7 +189,7 @@ static int snow_probe(struct platform_device *pdev)
 			return PTR_ERR(priv->clk_i2s_bus);
 		}
 	} else {
-		link->codecs->dai_name = "HiFi",
+		link->codecs->dai_name = "HiFi";
 
 		link->cpus->of_node = of_parse_phandle(dev->of_node,
 						"samsung,i2s-controller", 0);
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index ef8a29b9f641..346c806ba390 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -23,6 +23,7 @@ config SND_SOC_SH4_SSI
 
 config SND_SOC_SH4_FSI
 	tristate "SH4 FSI support"
+	depends on SUPERH || COMMON_CLK
 	select SND_SIMPLE_CARD
 	help
 	  This option enables FSI sound support
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index 728e93f35ffb..760523382f3c 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -421,6 +421,260 @@ EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap);
 
 #endif
 
+int snd_soc_component_compr_open(struct snd_compr_stream *cstream)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_component *component;
+	int i, ret;
+
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->compress_ops &&
+		    component->driver->compress_ops->open) {
+			ret = component->driver->compress_ops->open(component, cstream);
+			if (ret < 0)
+				return soc_component_ret(component, ret);
+		}
+		soc_component_mark_push(component, cstream, compr_open);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_open);
+
+void snd_soc_component_compr_free(struct snd_compr_stream *cstream,
+				  int rollback)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_component *component;
+	int i;
+
+	for_each_rtd_components(rtd, i, component) {
+		if (rollback && !soc_component_mark_match(component, cstream, compr_open))
+			continue;
+
+		if (component->driver->compress_ops &&
+		    component->driver->compress_ops->free)
+			component->driver->compress_ops->free(component, cstream);
+
+		soc_component_mark_pop(component, cstream, compr_open);
+	}
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_free);
+
+int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_component *component;
+	int i, ret;
+
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->compress_ops &&
+		    component->driver->compress_ops->trigger) {
+			ret = component->driver->compress_ops->trigger(
+				component, cstream, cmd);
+			if (ret < 0)
+				return soc_component_ret(component, ret);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_trigger);
+
+int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream,
+				       struct snd_compr_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_component *component;
+	int i, ret;
+
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->compress_ops &&
+		    component->driver->compress_ops->set_params) {
+			ret = component->driver->compress_ops->set_params(
+				component, cstream, params);
+			if (ret < 0)
+				return soc_component_ret(component, ret);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_set_params);
+
+int snd_soc_component_compr_get_params(struct snd_compr_stream *cstream,
+				       struct snd_codec *params)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_component *component;
+	int i, ret;
+
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->compress_ops &&
+		    component->driver->compress_ops->get_params) {
+			ret = component->driver->compress_ops->get_params(
+				component, cstream, params);
+			return soc_component_ret(component, ret);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_params);
+
+int snd_soc_component_compr_get_caps(struct snd_compr_stream *cstream,
+				     struct snd_compr_caps *caps)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_component *component;
+	int i, ret = 0;
+
+	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
+
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->compress_ops &&
+		    component->driver->compress_ops->get_caps) {
+			ret = component->driver->compress_ops->get_caps(
+				component, cstream, caps);
+			break;
+		}
+	}
+
+	mutex_unlock(&rtd->card->pcm_mutex);
+
+	return soc_component_ret(component, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_caps);
+
+int snd_soc_component_compr_get_codec_caps(struct snd_compr_stream *cstream,
+					   struct snd_compr_codec_caps *codec)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_component *component;
+	int i, ret = 0;
+
+	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
+
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->compress_ops &&
+		    component->driver->compress_ops->get_codec_caps) {
+			ret = component->driver->compress_ops->get_codec_caps(
+				component, cstream, codec);
+			break;
+		}
+	}
+
+	mutex_unlock(&rtd->card->pcm_mutex);
+
+	return soc_component_ret(component, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_codec_caps);
+
+int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_component *component;
+	int i, ret;
+
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->compress_ops &&
+		    component->driver->compress_ops->ack) {
+			ret = component->driver->compress_ops->ack(
+				component, cstream, bytes);
+			if (ret < 0)
+				return soc_component_ret(component, ret);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_ack);
+
+int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream,
+				    struct snd_compr_tstamp *tstamp)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_component *component;
+	int i, ret;
+
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->compress_ops &&
+		    component->driver->compress_ops->pointer) {
+			ret = component->driver->compress_ops->pointer(
+				component, cstream, tstamp);
+			return soc_component_ret(component, ret);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_pointer);
+
+int snd_soc_component_compr_copy(struct snd_compr_stream *cstream,
+				 char __user *buf, size_t count)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_component *component;
+	int i, ret = 0;
+
+	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
+
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->compress_ops &&
+		    component->driver->compress_ops->copy) {
+			ret = component->driver->compress_ops->copy(
+				component, cstream, buf, count);
+			break;
+		}
+	}
+
+	mutex_unlock(&rtd->card->pcm_mutex);
+
+	return soc_component_ret(component, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_copy);
+
+int snd_soc_component_compr_set_metadata(struct snd_compr_stream *cstream,
+					 struct snd_compr_metadata *metadata)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_component *component;
+	int i, ret;
+
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->compress_ops &&
+		    component->driver->compress_ops->set_metadata) {
+			ret = component->driver->compress_ops->set_metadata(
+				component, cstream, metadata);
+			if (ret < 0)
+				return soc_component_ret(component, ret);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_set_metadata);
+
+int snd_soc_component_compr_get_metadata(struct snd_compr_stream *cstream,
+					 struct snd_compr_metadata *metadata)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_component *component;
+	int i, ret;
+
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->compress_ops &&
+		    component->driver->compress_ops->get_metadata) {
+			ret = component->driver->compress_ops->get_metadata(
+				component, cstream, metadata);
+			return soc_component_ret(component, ret);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_metadata);
+
 static unsigned int soc_component_read_no_lock(
 	struct snd_soc_component *component,
 	unsigned int reg)
@@ -779,8 +1033,7 @@ int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream)
 }
 
 int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
-				    struct snd_pcm_hw_params *params,
-				    struct snd_soc_component **last)
+				    struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_soc_component *component;
@@ -790,52 +1043,83 @@ int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
 		if (component->driver->hw_params) {
 			ret = component->driver->hw_params(component,
 							   substream, params);
-			if (ret < 0) {
-				*last = component;
+			if (ret < 0)
 				return soc_component_ret(component, ret);
-			}
 		}
+		/* mark substream if succeeded */
+		soc_component_mark_push(component, substream, hw_params);
 	}
 
-	*last = NULL;
 	return 0;
 }
 
 void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream,
-				   struct snd_soc_component *last)
+				   int rollback)
 {
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_soc_component *component;
 	int i, ret;
 
 	for_each_rtd_components(rtd, i, component) {
-		if (component == last)
-			break;
+		if (rollback && !soc_component_mark_match(component, substream, hw_params))
+			continue;
 
 		if (component->driver->hw_free) {
 			ret = component->driver->hw_free(component, substream);
 			if (ret < 0)
 				soc_component_ret(component, ret);
 		}
+
+		/* remove marked substream */
+		soc_component_mark_pop(component, substream, hw_params);
 	}
 }
 
+static int soc_component_trigger(struct snd_soc_component *component,
+				 struct snd_pcm_substream *substream,
+				 int cmd)
+{
+	int ret = 0;
+
+	if (component->driver->trigger)
+		ret = component->driver->trigger(component, substream, cmd);
+
+	return soc_component_ret(component, ret);
+}
+
 int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream,
-				  int cmd)
+				  int cmd, int rollback)
 {
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_soc_component *component;
-	int i, ret;
-
-	for_each_rtd_components(rtd, i, component) {
-		if (component->driver->trigger) {
-			ret = component->driver->trigger(component, substream, cmd);
+	int i, r, ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		for_each_rtd_components(rtd, i, component) {
+			ret = soc_component_trigger(component, substream, cmd);
 			if (ret < 0)
-				return soc_component_ret(component, ret);
+				break;
+			soc_component_mark_push(component, substream, trigger);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		for_each_rtd_components(rtd, i, component) {
+			if (rollback && !soc_component_mark_match(component, substream, trigger))
+				continue;
+
+			r = soc_component_trigger(component, substream, cmd);
+			if (r < 0)
+				ret = r; /* use last ret */
+			soc_component_mark_pop(component, substream, trigger);
 		}
 	}
 
-	return 0;
+	return ret;
 }
 
 int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd,
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 3a6a60215e81..246a5e32e22a 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -22,93 +22,78 @@
 #include <sound/soc-link.h>
 #include <linux/pm_runtime.h>
 
-static int soc_compr_components_open(struct snd_compr_stream *cstream,
-				     struct snd_soc_component **last)
+static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component;
-	int i, ret;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
 
-	for_each_rtd_components(rtd, i, component) {
-		if (!component->driver->compress_ops ||
-		    !component->driver->compress_ops->open)
-			continue;
+	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 
-		ret = component->driver->compress_ops->open(component, cstream);
-		if (ret < 0) {
-			dev_err(component->dev,
-				"Compress ASoC: can't open platform %s: %d\n",
-				component->name, ret);
+	if (!rollback)
+		snd_soc_runtime_deactivate(rtd, stream);
 
-			*last = component;
-			return ret;
-		}
-	}
+	snd_soc_dai_digital_mute(codec_dai, 1, stream);
 
-	*last = NULL;
-	return 0;
-}
+	if (!snd_soc_dai_active(cpu_dai))
+		cpu_dai->rate = 0;
 
-static int soc_compr_components_free(struct snd_compr_stream *cstream,
-				     struct snd_soc_component *last)
-{
-	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component;
-	int i;
+	if (!snd_soc_dai_active(codec_dai))
+		codec_dai->rate = 0;
 
-	for_each_rtd_components(rtd, i, component) {
-		if (component == last)
-			break;
+	snd_soc_link_compr_shutdown(cstream, rollback);
 
-		if (!component->driver->compress_ops ||
-		    !component->driver->compress_ops->free)
-			continue;
+	snd_soc_component_compr_free(cstream, rollback);
 
-		component->driver->compress_ops->free(component, cstream);
-	}
+	snd_soc_dai_compr_shutdown(cpu_dai, cstream, rollback);
+
+	if (!rollback)
+		snd_soc_dapm_stream_stop(rtd, stream);
+
+	mutex_unlock(&rtd->card->pcm_mutex);
+
+	snd_soc_pcm_component_pm_runtime_put(rtd, cstream, rollback);
 
 	return 0;
 }
 
+static int soc_compr_free(struct snd_compr_stream *cstream)
+{
+	return soc_compr_clean(cstream, 0);
+}
+
 static int soc_compr_open(struct snd_compr_stream *cstream)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component = NULL;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
 	int ret;
 
 	ret = snd_soc_pcm_component_pm_runtime_get(rtd, cstream);
 	if (ret < 0)
-		goto pm_err;
+		goto err_no_lock;
 
 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 
 	ret = snd_soc_dai_compr_startup(cpu_dai, cstream);
 	if (ret < 0)
-		goto out;
+		goto err;
 
-	ret = soc_compr_components_open(cstream, &component);
+	ret = snd_soc_component_compr_open(cstream);
 	if (ret < 0)
-		goto machine_err;
+		goto err;
 
 	ret = snd_soc_link_compr_startup(cstream);
 	if (ret < 0)
-		goto machine_err;
-
-	snd_soc_runtime_activate(rtd, cstream->direction);
-
-	mutex_unlock(&rtd->card->pcm_mutex);
-
-	return 0;
-
-machine_err:
-	soc_compr_components_free(cstream, component);
+		goto err;
 
-	snd_soc_dai_compr_shutdown(cpu_dai, cstream);
-out:
+	snd_soc_runtime_activate(rtd, stream);
+err:
 	mutex_unlock(&rtd->card->pcm_mutex);
-pm_err:
-	snd_soc_pcm_component_pm_runtime_put(rtd, cstream, 1);
+err_no_lock:
+	if (ret < 0)
+		soc_compr_clean(cstream, 1);
 
 	return ret;
 }
@@ -118,18 +103,12 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
 	struct snd_pcm_substream *fe_substream =
 		 fe->pcm->streams[cstream->direction].substream;
-	struct snd_soc_component *component;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
 	struct snd_soc_dpcm *dpcm;
 	struct snd_soc_dapm_widget_list *list;
-	int stream;
+	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
 	int ret;
 
-	if (cstream->direction == SND_COMPRESS_PLAYBACK)
-		stream = SNDRV_PCM_STREAM_PLAYBACK;
-	else
-		stream = SNDRV_PCM_STREAM_CAPTURE;
-
 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 	fe->dpcm[stream].runtime = fe_substream->runtime;
 
@@ -160,7 +139,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 	if (ret < 0)
 		goto out;
 
-	ret = soc_compr_components_open(cstream, &component);
+	ret = snd_soc_component_compr_open(cstream);
 	if (ret < 0)
 		goto open_err;
 
@@ -181,9 +160,9 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 	return 0;
 
 machine_err:
-	soc_compr_components_free(cstream, component);
+	snd_soc_component_compr_free(cstream, 1);
 open_err:
-	snd_soc_dai_compr_shutdown(cpu_dai, cstream);
+	snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1);
 out:
 	dpcm_path_put(&list);
 be_err:
@@ -192,59 +171,16 @@ be_err:
 	return ret;
 }
 
-static int soc_compr_free(struct snd_compr_stream *cstream)
-{
-	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
-	int stream;
-
-	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
-
-	if (cstream->direction == SND_COMPRESS_PLAYBACK)
-		stream = SNDRV_PCM_STREAM_PLAYBACK;
-	else
-		stream = SNDRV_PCM_STREAM_CAPTURE;
-
-	snd_soc_runtime_deactivate(rtd, stream);
-
-	snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
-
-	if (!snd_soc_dai_active(cpu_dai))
-		cpu_dai->rate = 0;
-
-	if (!snd_soc_dai_active(codec_dai))
-		codec_dai->rate = 0;
-
-	snd_soc_link_compr_shutdown(cstream);
-
-	soc_compr_components_free(cstream, NULL);
-
-	snd_soc_dai_compr_shutdown(cpu_dai, cstream);
-
-	snd_soc_dapm_stream_stop(rtd, stream);
-
-	mutex_unlock(&rtd->card->pcm_mutex);
-
-	snd_soc_pcm_component_pm_runtime_put(rtd, cstream, 0);
-
-	return 0;
-}
-
 static int soc_compr_free_fe(struct snd_compr_stream *cstream)
 {
 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
 	struct snd_soc_dpcm *dpcm;
-	int stream, ret;
+	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
+	int ret;
 
 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
-	if (cstream->direction == SND_COMPRESS_PLAYBACK)
-		stream = SNDRV_PCM_STREAM_PLAYBACK;
-	else
-		stream = SNDRV_PCM_STREAM_CAPTURE;
-
 	snd_soc_runtime_deactivate(fe, stream);
 
 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
@@ -268,47 +204,27 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
 
 	fe->dpcm[stream].runtime = NULL;
 
-	snd_soc_link_compr_shutdown(cstream);
+	snd_soc_link_compr_shutdown(cstream, 0);
 
-	soc_compr_components_free(cstream, NULL);
+	snd_soc_component_compr_free(cstream, 0);
 
-	snd_soc_dai_compr_shutdown(cpu_dai, cstream);
+	snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0);
 
 	mutex_unlock(&fe->card->mutex);
 	return 0;
 }
 
-static int soc_compr_components_trigger(struct snd_compr_stream *cstream,
-					int cmd)
-{
-	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component;
-	int i, ret;
-
-	for_each_rtd_components(rtd, i, component) {
-		if (!component->driver->compress_ops ||
-		    !component->driver->compress_ops->trigger)
-			continue;
-
-		ret = component->driver->compress_ops->trigger(
-			component, cstream, cmd);
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
-}
-
 static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
 	int ret;
 
 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 
-	ret = soc_compr_components_trigger(cstream, cmd);
+	ret = snd_soc_component_compr_trigger(cstream, cmd);
 	if (ret < 0)
 		goto out;
 
@@ -318,10 +234,10 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-		snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
+		snd_soc_dai_digital_mute(codec_dai, 0, stream);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
+		snd_soc_dai_digital_mute(codec_dai, 1, stream);
 		break;
 	}
 
@@ -334,16 +250,12 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
 {
 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
-	int ret, stream;
+	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
+	int ret;
 
 	if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
 	    cmd == SND_COMPR_TRIGGER_DRAIN)
-		return soc_compr_components_trigger(cstream, cmd);
-
-	if (cstream->direction == SND_COMPRESS_PLAYBACK)
-		stream = SNDRV_PCM_STREAM_PLAYBACK;
-	else
-		stream = SNDRV_PCM_STREAM_CAPTURE;
+		return snd_soc_component_compr_trigger(cstream, cmd);
 
 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
@@ -351,7 +263,7 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
 	if (ret < 0)
 		goto out;
 
-	ret = soc_compr_components_trigger(cstream, cmd);
+	ret = snd_soc_component_compr_trigger(cstream, cmd);
 	if (ret < 0)
 		goto out;
 
@@ -380,32 +292,12 @@ out:
 	return ret;
 }
 
-static int soc_compr_components_set_params(struct snd_compr_stream *cstream,
-					   struct snd_compr_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component;
-	int i, ret;
-
-	for_each_rtd_components(rtd, i, component) {
-		if (!component->driver->compress_ops ||
-		    !component->driver->compress_ops->set_params)
-			continue;
-
-		ret = component->driver->compress_ops->set_params(
-			component, cstream, params);
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
-}
-
 static int soc_compr_set_params(struct snd_compr_stream *cstream,
 				struct snd_compr_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
 	int ret;
 
 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
@@ -421,7 +313,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
 	if (ret < 0)
 		goto err;
 
-	ret = soc_compr_components_set_params(cstream, params);
+	ret = snd_soc_component_compr_set_params(cstream, params);
 	if (ret < 0)
 		goto err;
 
@@ -429,12 +321,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
 	if (ret < 0)
 		goto err;
 
-	if (cstream->direction == SND_COMPRESS_PLAYBACK)
-		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
-					  SND_SOC_DAPM_STREAM_START);
-	else
-		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
-					  SND_SOC_DAPM_STREAM_START);
+	snd_soc_dapm_stream_event(rtd, stream, SND_SOC_DAPM_STREAM_START);
 
 	/* cancel any delayed stream shutdown that is pending */
 	rtd->pop_wait = 0;
@@ -456,12 +343,8 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
 	struct snd_pcm_substream *fe_substream =
 		 fe->pcm->streams[cstream->direction].substream;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
-	int ret, stream;
-
-	if (cstream->direction == SND_COMPRESS_PLAYBACK)
-		stream = SNDRV_PCM_STREAM_PLAYBACK;
-	else
-		stream = SNDRV_PCM_STREAM_CAPTURE;
+	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
+	int ret;
 
 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
@@ -487,7 +370,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
 	if (ret < 0)
 		goto out;
 
-	ret = soc_compr_components_set_params(cstream, params);
+	ret = snd_soc_component_compr_set_params(cstream, params);
 	if (ret < 0)
 		goto out;
 
@@ -508,9 +391,8 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream,
 				struct snd_codec *params)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-	int i, ret = 0;
+	int ret = 0;
 
 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 
@@ -518,73 +400,17 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream,
 	if (ret < 0)
 		goto err;
 
-	for_each_rtd_components(rtd, i, component) {
-		if (!component->driver->compress_ops ||
-		    !component->driver->compress_ops->get_params)
-			continue;
-
-		ret = component->driver->compress_ops->get_params(
-			component, cstream, params);
-		break;
-	}
-
+	ret = snd_soc_component_compr_get_params(cstream, params);
 err:
 	mutex_unlock(&rtd->card->pcm_mutex);
 	return ret;
 }
 
-static int soc_compr_get_caps(struct snd_compr_stream *cstream,
-			      struct snd_compr_caps *caps)
-{
-	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component;
-	int i, ret = 0;
-
-	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
-
-	for_each_rtd_components(rtd, i, component) {
-		if (!component->driver->compress_ops ||
-		    !component->driver->compress_ops->get_caps)
-			continue;
-
-		ret = component->driver->compress_ops->get_caps(
-			component, cstream, caps);
-		break;
-	}
-
-	mutex_unlock(&rtd->card->pcm_mutex);
-	return ret;
-}
-
-static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
-				    struct snd_compr_codec_caps *codec)
-{
-	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component;
-	int i, ret = 0;
-
-	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
-
-	for_each_rtd_components(rtd, i, component) {
-		if (!component->driver->compress_ops ||
-		    !component->driver->compress_ops->get_codec_caps)
-			continue;
-
-		ret = component->driver->compress_ops->get_codec_caps(
-			component, cstream, codec);
-		break;
-	}
-
-	mutex_unlock(&rtd->card->pcm_mutex);
-	return ret;
-}
-
 static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-	int i, ret = 0;
+	int ret;
 
 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 
@@ -592,17 +418,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
 	if (ret < 0)
 		goto err;
 
-	for_each_rtd_components(rtd, i, component) {
-		if (!component->driver->compress_ops ||
-		    !component->driver->compress_ops->ack)
-			continue;
-
-		ret = component->driver->compress_ops->ack(
-			component, cstream, bytes);
-		if (ret < 0)
-			goto err;
-	}
-
+	ret = snd_soc_component_compr_ack(cstream, bytes);
 err:
 	mutex_unlock(&rtd->card->pcm_mutex);
 	return ret;
@@ -612,8 +428,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,
 			     struct snd_compr_tstamp *tstamp)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component;
-	int i, ret = 0;
+	int ret;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 
 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
@@ -622,91 +437,38 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,
 	if (ret < 0)
 		goto out;
 
-	for_each_rtd_components(rtd, i, component) {
-		if (!component->driver->compress_ops ||
-		    !component->driver->compress_ops->pointer)
-			continue;
-
-		ret = component->driver->compress_ops->pointer(
-			component, cstream, tstamp);
-		break;
-	}
+	ret = snd_soc_component_compr_pointer(cstream, tstamp);
 out:
 	mutex_unlock(&rtd->card->pcm_mutex);
 	return ret;
 }
 
-static int soc_compr_copy(struct snd_compr_stream *cstream,
-			  char __user *buf, size_t count)
-{
-	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component;
-	int i, ret = 0;
-
-	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
-
-	for_each_rtd_components(rtd, i, component) {
-		if (!component->driver->compress_ops ||
-		    !component->driver->compress_ops->copy)
-			continue;
-
-		ret = component->driver->compress_ops->copy(
-			component, cstream, buf, count);
-		break;
-	}
-
-	mutex_unlock(&rtd->card->pcm_mutex);
-	return ret;
-}
-
 static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
 				  struct snd_compr_metadata *metadata)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-	int i, ret;
+	int ret;
 
 	ret = snd_soc_dai_compr_set_metadata(cpu_dai, cstream, metadata);
 	if (ret < 0)
 		return ret;
 
-	for_each_rtd_components(rtd, i, component) {
-		if (!component->driver->compress_ops ||
-		    !component->driver->compress_ops->set_metadata)
-			continue;
-
-		ret = component->driver->compress_ops->set_metadata(
-			component, cstream, metadata);
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
+	return snd_soc_component_compr_set_metadata(cstream, metadata);
 }
 
 static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
 				  struct snd_compr_metadata *metadata)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_component *component;
 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-	int i, ret;
+	int ret;
 
 	ret = snd_soc_dai_compr_get_metadata(cpu_dai, cstream, metadata);
 	if (ret < 0)
 		return ret;
 
-	for_each_rtd_components(rtd, i, component) {
-		if (!component->driver->compress_ops ||
-		    !component->driver->compress_ops->get_metadata)
-			continue;
-
-		return component->driver->compress_ops->get_metadata(
-			component, cstream, metadata);
-	}
-
-	return 0;
+	return snd_soc_component_compr_get_metadata(cstream, metadata);
 }
 
 /* ASoC Compress operations */
@@ -720,8 +482,8 @@ static struct snd_compr_ops soc_compr_ops = {
 	.trigger	= soc_compr_trigger,
 	.pointer	= soc_compr_pointer,
 	.ack		= soc_compr_ack,
-	.get_caps	= soc_compr_get_caps,
-	.get_codec_caps = soc_compr_get_codec_caps
+	.get_caps	= snd_soc_component_compr_get_caps,
+	.get_codec_caps = snd_soc_component_compr_get_codec_caps,
 };
 
 /* ASoC Dynamic Compress operations */
@@ -735,8 +497,8 @@ static struct snd_compr_ops soc_compr_dyn_ops = {
 	.trigger	= soc_compr_trigger_fe,
 	.pointer	= soc_compr_pointer,
 	.ack		= soc_compr_ack,
-	.get_caps	= soc_compr_get_caps,
-	.get_codec_caps = soc_compr_get_codec_caps
+	.get_caps	= snd_soc_component_compr_get_caps,
+	.get_codec_caps = snd_soc_component_compr_get_codec_caps,
 };
 
 /**
@@ -759,6 +521,13 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 	int playback = 0, capture = 0;
 	int i;
 
+	/*
+	 * make sure these are same value,
+	 * and then use these as equally
+	 */
+	BUILD_BUG_ON((int)SNDRV_PCM_STREAM_PLAYBACK != (int)SND_COMPRESS_PLAYBACK);
+	BUILD_BUG_ON((int)SNDRV_PCM_STREAM_CAPTURE  != (int)SND_COMPRESS_CAPTURE);
+
 	if (rtd->num_cpus > 1 ||
 	    rtd->num_codecs > 1) {
 		dev_err(rtd->card->dev,
@@ -832,7 +601,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 		    !component->driver->compress_ops->copy)
 			continue;
 
-		compr->ops->copy = soc_compr_copy;
+		compr->ops->copy = snd_soc_component_compr_copy;
 		break;
 	}
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 05a085f6dc7c..f6d4e99b590c 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -32,7 +32,6 @@
 #include <linux/of_graph.h>
 #include <linux/dmi.h>
 #include <sound/core.h>
-#include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -520,13 +519,46 @@ static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card)
 }
 
 #ifdef CONFIG_PM_SLEEP
+static void soc_playback_digital_mute(struct snd_soc_card *card, int mute)
+{
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *dai;
+	int playback = SNDRV_PCM_STREAM_PLAYBACK;
+	int i;
+
+	for_each_card_rtds(card, rtd) {
+
+		if (rtd->dai_link->ignore_suspend)
+			continue;
+
+		for_each_rtd_dais(rtd, i, dai) {
+			if (snd_soc_dai_stream_active(dai, playback))
+				snd_soc_dai_digital_mute(dai, mute, playback);
+		}
+	}
+}
+
+static void soc_dapm_suspend_resume(struct snd_soc_card *card, int event)
+{
+	struct snd_soc_pcm_runtime *rtd;
+	int stream;
+
+	for_each_card_rtds(card, rtd) {
+
+		if (rtd->dai_link->ignore_suspend)
+			continue;
+
+		for_each_pcm_streams(stream)
+			snd_soc_dapm_stream_event(rtd, stream, event);
+	}
+}
+
 /* powers down audio subsystem for suspend */
 int snd_soc_suspend(struct device *dev)
 {
 	struct snd_soc_card *card = dev_get_drvdata(dev);
 	struct snd_soc_component *component;
 	struct snd_soc_pcm_runtime *rtd;
-	int playback = SNDRV_PCM_STREAM_PLAYBACK;
 	int i;
 
 	/* If the card is not initialized yet there is nothing to do */
@@ -543,17 +575,7 @@ int snd_soc_suspend(struct device *dev)
 	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
 
 	/* mute any active DACs */
-	for_each_card_rtds(card, rtd) {
-		struct snd_soc_dai *dai;
-
-		if (rtd->dai_link->ignore_suspend)
-			continue;
-
-		for_each_rtd_dais(rtd, i, dai) {
-			if (snd_soc_dai_stream_active(dai, playback))
-				snd_soc_dai_digital_mute(dai, 1, playback);
-		}
-	}
+	soc_playback_digital_mute(card, 1);
 
 	/* suspend all pcms */
 	for_each_card_rtds(card, rtd) {
@@ -568,16 +590,7 @@ int snd_soc_suspend(struct device *dev)
 	/* close any waiting streams */
 	snd_soc_flush_all_delayed_work(card);
 
-	for_each_card_rtds(card, rtd) {
-		int stream;
-
-		if (rtd->dai_link->ignore_suspend)
-			continue;
-
-		for_each_pcm_streams(stream)
-			snd_soc_dapm_stream_event(rtd, stream,
-						  SND_SOC_DAPM_STREAM_SUSPEND);
-	}
+	soc_dapm_suspend_resume(card, SND_SOC_DAPM_STREAM_SUSPEND);
 
 	/* Recheck all endpoints too, their state is affected by suspend */
 	dapm_mark_endpoints_dirty(card);
@@ -648,9 +661,7 @@ static void soc_resume_deferred(struct work_struct *work)
 	struct snd_soc_card *card =
 			container_of(work, struct snd_soc_card,
 				     deferred_resume_work);
-	struct snd_soc_pcm_runtime *rtd;
 	struct snd_soc_component *component;
-	int i;
 
 	/*
 	 * our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
@@ -669,30 +680,10 @@ static void soc_resume_deferred(struct work_struct *work)
 			snd_soc_component_resume(component);
 	}
 
-	for_each_card_rtds(card, rtd) {
-		int stream;
-
-		if (rtd->dai_link->ignore_suspend)
-			continue;
-
-		for_each_pcm_streams(stream)
-			snd_soc_dapm_stream_event(rtd, stream,
-						  SND_SOC_DAPM_STREAM_RESUME);
-	}
+	soc_dapm_suspend_resume(card, SND_SOC_DAPM_STREAM_RESUME);
 
 	/* unmute any active DACs */
-	for_each_card_rtds(card, rtd) {
-		struct snd_soc_dai *dai;
-		int playback = SNDRV_PCM_STREAM_PLAYBACK;
-
-		if (rtd->dai_link->ignore_suspend)
-			continue;
-
-		for_each_rtd_dais(rtd, i, dai) {
-			if (snd_soc_dai_stream_active(dai, playback))
-				snd_soc_dai_digital_mute(dai, 0, playback);
-		}
-	}
+	soc_playback_digital_mute(card, 0);
 
 	snd_soc_card_resume_post(card);
 
@@ -1124,7 +1115,8 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
 	for (i = 0; i < card->num_configs; i++) {
 		struct snd_soc_codec_conf *map = &card->codec_conf[i];
 
-		if (snd_soc_is_matching_component(&map->dlc, component)) {
+		if (snd_soc_is_matching_component(&map->dlc, component) &&
+		    map->name_prefix) {
 			component->name_prefix = map->name_prefix;
 			return;
 		}
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 4705c3da6280..cd3bb9a7983f 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -335,16 +335,27 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
 	if (dai->driver->ops &&
 	    dai->driver->ops->hw_params)
 		ret = dai->driver->ops->hw_params(substream, params, dai);
+
+	/* mark substream if succeeded */
+	if (ret == 0)
+		soc_dai_mark_push(dai, substream, hw_params);
 end:
 	return soc_dai_ret(dai, ret);
 }
 
 void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
-			 struct snd_pcm_substream *substream)
+			 struct snd_pcm_substream *substream,
+			 int rollback)
 {
+	if (rollback && !soc_dai_mark_match(dai, substream, hw_params))
+		return;
+
 	if (dai->driver->ops &&
 	    dai->driver->ops->hw_free)
 		dai->driver->ops->hw_free(substream, dai);
+
+	/* remove marked substream */
+	soc_dai_mark_pop(dai, substream, hw_params);
 }
 
 int snd_soc_dai_startup(struct snd_soc_dai *dai,
@@ -553,23 +564,51 @@ int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
 	return 0;
 }
 
+static int soc_dai_trigger(struct snd_soc_dai *dai,
+			   struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+
+	if (dai->driver->ops &&
+	    dai->driver->ops->trigger)
+		ret = dai->driver->ops->trigger(substream, cmd, dai);
+
+	return soc_dai_ret(dai, ret);
+}
+
 int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
-			    int cmd)
+			    int cmd, int rollback)
 {
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	struct snd_soc_dai *dai;
-	int i, ret;
+	int i, r, ret = 0;
 
-	for_each_rtd_dais(rtd, i, dai) {
-		if (dai->driver->ops &&
-		    dai->driver->ops->trigger) {
-			ret = dai->driver->ops->trigger(substream, cmd, dai);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		for_each_rtd_dais(rtd, i, dai) {
+			ret = soc_dai_trigger(dai, substream, cmd);
 			if (ret < 0)
-				return soc_dai_ret(dai, ret);
+				break;
+			soc_dai_mark_push(dai, substream, trigger);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		for_each_rtd_dais(rtd, i, dai) {
+			if (rollback && !soc_dai_mark_match(dai, substream, trigger))
+				continue;
+
+			r = soc_dai_trigger(dai, substream, cmd);
+			if (r < 0)
+				ret = r; /* use last ret */
+			soc_dai_mark_pop(dai, substream, trigger);
 		}
 	}
 
-	return 0;
+	return ret;
 }
 
 int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
@@ -601,16 +640,27 @@ int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
 	    dai->driver->cops->startup)
 		ret = dai->driver->cops->startup(cstream, dai);
 
+	/* mark cstream if succeeded */
+	if (ret == 0)
+		soc_dai_mark_push(dai, cstream, compr_startup);
+
 	return soc_dai_ret(dai, ret);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
 
 void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
-				struct snd_compr_stream *cstream)
+				struct snd_compr_stream *cstream,
+				int rollback)
 {
+	if (rollback && !soc_dai_mark_match(dai, cstream, compr_startup))
+		return;
+
 	if (dai->driver->cops &&
 	    dai->driver->cops->shutdown)
 		dai->driver->cops->shutdown(cstream, dai);
+
+	/* remove marked cstream */
+	soc_dai_mark_pop(dai, cstream, compr_startup);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
 
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7f87b449f950..9f0c86cbdcca 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -3955,13 +3955,13 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 		substream->stream = SNDRV_PCM_STREAM_CAPTURE;
 		snd_soc_dapm_widget_for_each_source_path(w, path) {
 			source = path->source->priv;
-			snd_soc_dai_hw_free(source, substream);
+			snd_soc_dai_hw_free(source, substream, 0);
 		}
 
 		substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
 		snd_soc_dapm_widget_for_each_sink_path(w, path) {
 			sink = path->sink->priv;
-			snd_soc_dai_hw_free(sink, substream);
+			snd_soc_dai_hw_free(sink, substream, 0);
 		}
 
 		substream->stream = SNDRV_PCM_STREAM_CAPTURE;
@@ -4764,7 +4764,7 @@ void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm,
 
 	if (component) {
 		dapm->dev		= component->dev;
-		dapm->idle_bias_off	= !component->driver->idle_bias_on,
+		dapm->idle_bias_off	= !component->driver->idle_bias_on;
 		dapm->suspend_bias_off	= component->driver->suspend_bias_off;
 	} else {
 		dapm->dev		= card->dev;
diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c
index 2a8881978930..619664cc9ab9 100644
--- a/sound/soc/soc-link.c
+++ b/sound/soc/soc-link.c
@@ -119,19 +119,29 @@ int snd_soc_link_hw_params(struct snd_pcm_substream *substream,
 	    rtd->dai_link->ops->hw_params)
 		ret = rtd->dai_link->ops->hw_params(substream, params);
 
+	/* mark substream if succeeded */
+	if (ret == 0)
+		soc_link_mark_push(rtd, substream, hw_params);
+
 	return soc_link_ret(rtd, ret);
 }
 
-void snd_soc_link_hw_free(struct snd_pcm_substream *substream)
+void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback)
 {
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 
+	if (rollback && !soc_link_mark_match(rtd, substream, hw_params))
+		return;
+
 	if (rtd->dai_link->ops &&
 	    rtd->dai_link->ops->hw_free)
 		rtd->dai_link->ops->hw_free(substream);
+
+	/* remove marked substream */
+	soc_link_mark_pop(rtd, substream, hw_params);
 }
 
-int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
+static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 	int ret = 0;
@@ -143,6 +153,34 @@ int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
 	return soc_link_ret(rtd, ret);
 }
 
+int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd,
+			 int rollback)
+{
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = soc_link_trigger(substream, cmd);
+		if (ret < 0)
+			break;
+		soc_link_mark_push(rtd, substream, trigger);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (rollback && !soc_link_mark_match(rtd, substream, trigger))
+			break;
+
+		ret = soc_link_trigger(substream, cmd);
+		soc_link_mark_pop(rtd, substream, startup);
+	}
+
+	return ret;
+}
+
 int snd_soc_link_compr_startup(struct snd_compr_stream *cstream)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -152,17 +190,26 @@ int snd_soc_link_compr_startup(struct snd_compr_stream *cstream)
 	    rtd->dai_link->compr_ops->startup)
 		ret = rtd->dai_link->compr_ops->startup(cstream);
 
+	if (ret == 0)
+		soc_link_mark_push(rtd, cstream, compr_startup);
+
 	return soc_link_ret(rtd, ret);
 }
 EXPORT_SYMBOL_GPL(snd_soc_link_compr_startup);
 
-void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream)
+void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream,
+				 int rollback)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 
+	if (rollback && !soc_link_mark_match(rtd, cstream, compr_startup))
+		return;
+
 	if (rtd->dai_link->compr_ops &&
 	    rtd->dai_link->compr_ops->shutdown)
 		rtd->dai_link->compr_ops->shutdown(cstream);
+
+	soc_link_mark_pop(rtd, cstream, compr_startup);
 }
 EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown);
 
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index dcab9527ba3d..ee51dc7fd893 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -662,8 +662,6 @@ static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback)
 
 	soc_pcm_components_close(substream, rollback);
 
-	if (!rollback)
-		snd_soc_dapm_stream_stop(rtd, substream->stream);
 
 	mutex_unlock(&rtd->card->pcm_mutex);
 
@@ -860,6 +858,57 @@ static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
 	interval->max = channels;
 }
 
+static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback)
+{
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *dai;
+	int i;
+
+	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
+
+	/* clear the corresponding DAIs parameters when going to be inactive */
+	for_each_rtd_dais(rtd, i, dai) {
+		int active = snd_soc_dai_stream_active(dai, substream->stream);
+
+		if (snd_soc_dai_active(dai) == 1) {
+			dai->rate = 0;
+			dai->channels = 0;
+			dai->sample_bits = 0;
+		}
+
+		if (active == 1)
+			snd_soc_dai_digital_mute(dai, 1, substream->stream);
+	}
+
+	/* run the stream event */
+	snd_soc_dapm_stream_stop(rtd, substream->stream);
+
+	/* free any machine hw params */
+	snd_soc_link_hw_free(substream, rollback);
+
+	/* free any component resources */
+	snd_soc_pcm_component_hw_free(substream, rollback);
+
+	/* now free hw params for the DAIs  */
+	for_each_rtd_dais(rtd, i, dai) {
+		if (!snd_soc_dai_stream_valid(dai, substream->stream))
+			continue;
+
+		snd_soc_dai_hw_free(dai, substream, rollback);
+	}
+
+	mutex_unlock(&rtd->card->pcm_mutex);
+	return 0;
+}
+
+/*
+ * Frees resources allocated by hw_params, can be called multiple times
+ */
+static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return soc_pcm_hw_clean(substream, 0);
+}
+
 /*
  * Called by ALSA when the hardware params are set by application. This
  * function can also be called multiple times and can allocate buffers
@@ -869,7 +918,6 @@ static int soc_pcm_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_component *component;
 	struct snd_soc_dai *cpu_dai;
 	struct snd_soc_dai *codec_dai;
 	int i, ret = 0;
@@ -921,7 +969,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 		ret = snd_soc_dai_hw_params(codec_dai, substream,
 					    &codec_params);
 		if(ret < 0)
-			goto codec_err;
+			goto out;
 
 		codec_dai->rate = params_rate(&codec_params);
 		codec_dai->channels = params_channels(&codec_params);
@@ -941,7 +989,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 
 		ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
 		if (ret < 0)
-			goto interface_err;
+			goto out;
 
 		/* store the parameters for each DAI */
 		cpu_dai->rate = params_rate(params);
@@ -952,121 +1000,73 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 		snd_soc_dapm_update_dai(substream, params, cpu_dai);
 	}
 
-	ret = snd_soc_pcm_component_hw_params(substream, params, &component);
-	if (ret < 0)
-		goto component_err;
-
+	ret = snd_soc_pcm_component_hw_params(substream, params);
 out:
 	mutex_unlock(&rtd->card->pcm_mutex);
-	return ret;
 
-component_err:
-	snd_soc_pcm_component_hw_free(substream, component);
-
-	i = rtd->num_cpus;
-
-interface_err:
-	for_each_rtd_cpu_dais_rollback(rtd, i, cpu_dai) {
-		if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
-			continue;
-
-		snd_soc_dai_hw_free(cpu_dai, substream);
-		cpu_dai->rate = 0;
-	}
-
-	i = rtd->num_codecs;
-
-codec_err:
-	for_each_rtd_codec_dais_rollback(rtd, i, codec_dai) {
-		if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
-			continue;
-
-		snd_soc_dai_hw_free(codec_dai, substream);
-		codec_dai->rate = 0;
-	}
-
-	snd_soc_link_hw_free(substream);
+	if (ret < 0)
+		soc_pcm_hw_clean(substream, 1);
 
-	mutex_unlock(&rtd->card->pcm_mutex);
 	return ret;
 }
 
-/*
- * Frees resources allocated by hw_params, can be called multiple times
- */
-static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-	struct snd_soc_dai *dai;
-	int i;
-
-	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
-
-	/* clear the corresponding DAIs parameters when going to be inactive */
-	for_each_rtd_dais(rtd, i, dai) {
-		int active = snd_soc_dai_stream_active(dai, substream->stream);
-
-		if (snd_soc_dai_active(dai) == 1) {
-			dai->rate = 0;
-			dai->channels = 0;
-			dai->sample_bits = 0;
-		}
-
-		if (active == 1)
-			snd_soc_dai_digital_mute(dai, 1, substream->stream);
-	}
-
-	/* free any machine hw params */
-	snd_soc_link_hw_free(substream);
-
-	/* free any component resources */
-	snd_soc_pcm_component_hw_free(substream, NULL);
-
-	/* now free hw params for the DAIs  */
-	for_each_rtd_dais(rtd, i, dai) {
-		if (!snd_soc_dai_stream_valid(dai, substream->stream))
-			continue;
-
-		snd_soc_dai_hw_free(dai, substream);
-	}
-
-	mutex_unlock(&rtd->card->pcm_mutex);
-	return 0;
-}
-
 static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-	int ret = -EINVAL;
+	int ret = -EINVAL, _ret = 0;
+	int rollback = 0;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		ret = snd_soc_link_trigger(substream, cmd);
+		ret = snd_soc_link_trigger(substream, cmd, 0);
 		if (ret < 0)
-			break;
+			goto start_err;
 
-		ret = snd_soc_pcm_component_trigger(substream, cmd);
+		ret = snd_soc_pcm_component_trigger(substream, cmd, 0);
 		if (ret < 0)
+			goto start_err;
+
+		ret = snd_soc_pcm_dai_trigger(substream, cmd, 0);
+start_err:
+		if (ret < 0)
+			rollback = 1;
+	}
+
+	if (rollback) {
+		_ret = ret;
+		switch (cmd) {
+		case SNDRV_PCM_TRIGGER_START:
+			cmd = SNDRV_PCM_TRIGGER_STOP;
+			break;
+		case SNDRV_PCM_TRIGGER_RESUME:
+			cmd = SNDRV_PCM_TRIGGER_SUSPEND;
 			break;
+		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+			cmd = SNDRV_PCM_TRIGGER_PAUSE_PUSH;
+			break;
+		}
+	}
 
-		ret = snd_soc_pcm_dai_trigger(substream, cmd);
-		break;
+	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		ret = snd_soc_pcm_dai_trigger(substream, cmd);
+		ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback);
 		if (ret < 0)
 			break;
 
-		ret = snd_soc_pcm_component_trigger(substream, cmd);
+		ret = snd_soc_pcm_component_trigger(substream, cmd, rollback);
 		if (ret < 0)
 			break;
 
-		ret = snd_soc_link_trigger(substream, cmd);
+		ret = snd_soc_link_trigger(substream, cmd, rollback);
 		break;
 	}
 
+	if (_ret)
+		ret = _ret;
+
 	return ret;
 }
 
@@ -1284,7 +1284,8 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
 
 	/* get number of valid DAI paths and their widgets */
 	paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
-			dpcm_end_walk_at_be);
+			fe->card->component_chaining ?
+				NULL : dpcm_end_walk_at_be);
 
 	dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
 			stream ? "capture" : "playback");
@@ -1883,7 +1884,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
 	/* now shutdown the frontend */
 	soc_pcm_close(substream);
 
-	/* run the stream event for each BE */
+	/* run the stream stop event */
 	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 
 	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
@@ -2073,21 +2074,6 @@ out:
 	return ret;
 }
 
-static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
-		struct snd_pcm_substream *substream, int cmd)
-{
-	int ret;
-
-	dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
-			dpcm->be->dai_link->name, cmd);
-
-	ret = soc_pcm_trigger(substream, cmd);
-	if (ret < 0)
-		dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
-
-	return ret;
-}
-
 int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
 			       int cmd)
 {
@@ -2104,6 +2090,9 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
 		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
 			continue;
 
+		dev_dbg(be->dev, "ASoC: trigger BE %s cmd %d\n",
+			be->dai_link->name, cmd);
+
 		switch (cmd) {
 		case SNDRV_PCM_TRIGGER_START:
 			if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
@@ -2111,7 +2100,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
 			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
 				continue;
 
-			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+			ret = soc_pcm_trigger(be_substream, cmd);
 			if (ret)
 				return ret;
 
@@ -2121,7 +2110,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
 			if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
 				continue;
 
-			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+			ret = soc_pcm_trigger(be_substream, cmd);
 			if (ret)
 				return ret;
 
@@ -2131,7 +2120,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
 			if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
 				continue;
 
-			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+			ret = soc_pcm_trigger(be_substream, cmd);
 			if (ret)
 				return ret;
 
@@ -2145,7 +2134,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
 			if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
 				continue;
 
-			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+			ret = soc_pcm_trigger(be_substream, cmd);
 			if (ret)
 				return ret;
 
@@ -2158,7 +2147,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
 			if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
 				continue;
 
-			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+			ret = soc_pcm_trigger(be_substream, cmd);
 			if (ret)
 				return ret;
 
@@ -2171,7 +2160,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
 			if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
 				continue;
 
-			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+			ret = soc_pcm_trigger(be_substream, cmd);
 			if (ret)
 				return ret;
 
@@ -2231,6 +2220,7 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
 		case SNDRV_PCM_TRIGGER_START:
 		case SNDRV_PCM_TRIGGER_RESUME:
 		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		case SNDRV_PCM_TRIGGER_DRAIN:
 			ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
 			break;
 		case SNDRV_PCM_TRIGGER_STOP:
@@ -2248,6 +2238,7 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
 		case SNDRV_PCM_TRIGGER_START:
 		case SNDRV_PCM_TRIGGER_RESUME:
 		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		case SNDRV_PCM_TRIGGER_DRAIN:
 			ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
 			break;
 		case SNDRV_PCM_TRIGGER_STOP:
@@ -2385,8 +2376,6 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
 		goto out;
 	}
 
-	/* run the stream event for each BE */
-	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
 	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
 
 out:
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index c5ef432a023b..950c45008e24 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -64,7 +64,6 @@ struct soc_tplg {
 	struct device *dev;
 	struct snd_soc_component *comp;
 	u32 index;	/* current block index */
-	u32 req_index;	/* required index, only loaded/free matching blocks */
 
 	/* vendor specific kcontrol operations */
 	const struct snd_soc_tplg_kcontrol_ops *io_ops;
@@ -80,8 +79,6 @@ struct soc_tplg {
 
 static int soc_tplg_process_headers(struct soc_tplg *tplg);
 static void soc_tplg_complete(struct soc_tplg *tplg);
-static void soc_tplg_denum_remove_texts(struct soc_enum *se);
-static void soc_tplg_denum_remove_values(struct soc_enum *se);
 
 /* check we dont overflow the data for this control chunk */
 static int soc_tplg_check_elem_count(struct soc_tplg *tplg, size_t elem_size,
@@ -360,9 +357,6 @@ static void remove_mixer(struct snd_soc_component *comp,
 	struct snd_soc_dobj *dobj, int pass)
 {
 	struct snd_card *card = comp->card->snd_card;
-	struct soc_mixer_control *sm =
-		container_of(dobj, struct soc_mixer_control, dobj);
-	const unsigned int *p = NULL;
 
 	if (pass != SOC_TPLG_PASS_MIXER)
 		return;
@@ -370,12 +364,8 @@ static void remove_mixer(struct snd_soc_component *comp,
 	if (dobj->ops && dobj->ops->control_unload)
 		dobj->ops->control_unload(comp, dobj);
 
-	if (dobj->control.kcontrol->tlv.p)
-		p = dobj->control.kcontrol->tlv.p;
 	snd_ctl_remove(card, dobj->control.kcontrol);
 	list_del(&dobj->list);
-	kfree(sm);
-	kfree(p);
 }
 
 /* remove an enum kcontrol */
@@ -383,7 +373,6 @@ static void remove_enum(struct snd_soc_component *comp,
 	struct snd_soc_dobj *dobj, int pass)
 {
 	struct snd_card *card = comp->card->snd_card;
-	struct soc_enum *se = container_of(dobj, struct soc_enum, dobj);
 
 	if (pass != SOC_TPLG_PASS_MIXER)
 		return;
@@ -393,10 +382,6 @@ static void remove_enum(struct snd_soc_component *comp,
 
 	snd_ctl_remove(card, dobj->control.kcontrol);
 	list_del(&dobj->list);
-
-	soc_tplg_denum_remove_values(se);
-	soc_tplg_denum_remove_texts(se);
-	kfree(se);
 }
 
 /* remove a byte kcontrol */
@@ -404,8 +389,6 @@ static void remove_bytes(struct snd_soc_component *comp,
 	struct snd_soc_dobj *dobj, int pass)
 {
 	struct snd_card *card = comp->card->snd_card;
-	struct soc_bytes_ext *sb =
-		container_of(dobj, struct soc_bytes_ext, dobj);
 
 	if (pass != SOC_TPLG_PASS_MIXER)
 		return;
@@ -415,16 +398,12 @@ static void remove_bytes(struct snd_soc_component *comp,
 
 	snd_ctl_remove(card, dobj->control.kcontrol);
 	list_del(&dobj->list);
-	kfree(sb);
 }
 
 /* remove a route */
 static void remove_route(struct snd_soc_component *comp,
 			 struct snd_soc_dobj *dobj, int pass)
 {
-	struct snd_soc_dapm_route *route =
-		container_of(dobj, struct snd_soc_dapm_route, dobj);
-
 	if (pass != SOC_TPLG_PASS_GRAPH)
 		return;
 
@@ -432,7 +411,6 @@ static void remove_route(struct snd_soc_component *comp,
 		dobj->ops->dapm_route_unload(comp, dobj);
 
 	list_del(&dobj->list);
-	kfree(route);
 }
 
 /* remove a widget and it's kcontrols - routes must be removed first */
@@ -453,47 +431,10 @@ static void remove_widget(struct snd_soc_component *comp,
 	if (!w->kcontrols)
 		goto free_news;
 
-	/*
-	 * Dynamic Widgets either have 1..N enum kcontrols or mixers.
-	 * The enum may either have an array of values or strings.
-	 */
-	if (dobj->widget.kcontrol_type == SND_SOC_TPLG_TYPE_ENUM) {
-		/* enumerated widget mixer */
-		for (i = 0; w->kcontrols != NULL && i < w->num_kcontrols; i++) {
-			struct snd_kcontrol *kcontrol = w->kcontrols[i];
-			struct soc_enum *se =
-				(struct soc_enum *)kcontrol->private_value;
-
-			snd_ctl_remove(card, kcontrol);
-
-			/* free enum kcontrol's dvalues and dtexts */
-			soc_tplg_denum_remove_values(se);
-			soc_tplg_denum_remove_texts(se);
-
-			kfree(se);
-			kfree(w->kcontrol_news[i].name);
-		}
-	} else {
-		/* volume mixer or bytes controls */
-		for (i = 0; w->kcontrols != NULL && i < w->num_kcontrols; i++) {
-			struct snd_kcontrol *kcontrol = w->kcontrols[i];
-
-			if (dobj->widget.kcontrol_type
-			    == SND_SOC_TPLG_TYPE_MIXER)
-				kfree(kcontrol->tlv.p);
-
-			/* Private value is used as struct soc_mixer_control
-			 * for volume mixers or soc_bytes_ext for bytes
-			 * controls.
-			 */
-			kfree((void *)kcontrol->private_value);
-			snd_ctl_remove(card, kcontrol);
-			kfree(w->kcontrol_news[i].name);
-		}
-	}
+	for (i = 0; w->kcontrols && i < w->num_kcontrols; i++)
+		snd_ctl_remove(card, w->kcontrols[i]);
 
 free_news:
-	kfree(w->kcontrol_news);
 
 	list_del(&dobj->list);
 
@@ -518,11 +459,7 @@ static void remove_dai(struct snd_soc_component *comp,
 		if (dai->driver == dai_drv)
 			dai->driver = NULL;
 
-	kfree(dai_drv->playback.stream_name);
-	kfree(dai_drv->capture.stream_name);
-	kfree(dai_drv->name);
 	list_del(&dobj->list);
-	kfree(dai_drv);
 }
 
 /* remove link configurations */
@@ -541,11 +478,6 @@ static void remove_link(struct snd_soc_component *comp,
 	list_del(&dobj->list);
 	snd_soc_remove_pcm_runtime(comp->card,
 			snd_soc_get_pcm_runtime(comp->card, link));
-
-	kfree(link->name);
-	kfree(link->stream_name);
-	kfree(link->cpus->dai_name);
-	kfree(link);
 }
 
 /* unload dai link */
@@ -700,7 +632,7 @@ static int soc_tplg_create_tlv_db_scale(struct soc_tplg *tplg,
 	unsigned int item_len = 2 * sizeof(unsigned int);
 	unsigned int *p;
 
-	p = kzalloc(item_len + 2 * sizeof(unsigned int), GFP_KERNEL);
+	p = devm_kzalloc(tplg->dev, item_len + 2 * sizeof(unsigned int), GFP_KERNEL);
 	if (!p)
 		return -ENOMEM;
 
@@ -741,12 +673,6 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg,
 	return 0;
 }
 
-static inline void soc_tplg_free_tlv(struct soc_tplg *tplg,
-	struct snd_kcontrol_new *kc)
-{
-	kfree(kc->tlv.p);
-}
-
 static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
 	size_t size)
 {
@@ -772,7 +698,7 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
 			SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
 			return -EINVAL;
 
-		sbe = kzalloc(sizeof(*sbe), GFP_KERNEL);
+		sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL);
 		if (sbe == NULL)
 			return -ENOMEM;
 
@@ -798,7 +724,6 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
 		err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg);
 		if (err) {
 			soc_control_err(tplg, &be->hdr, be->hdr.name);
-			kfree(sbe);
 			break;
 		}
 
@@ -808,7 +733,6 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
 		if (err < 0) {
 			dev_err(tplg->dev, "ASoC: failed to init %s\n",
 				be->hdr.name);
-			kfree(sbe);
 			break;
 		}
 
@@ -818,7 +742,6 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
 		if (err < 0) {
 			dev_err(tplg->dev, "ASoC: failed to add %s\n",
 				be->hdr.name);
-			kfree(sbe);
 			break;
 		}
 
@@ -854,7 +777,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
 			SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
 			return -EINVAL;
 
-		sm = kzalloc(sizeof(*sm), GFP_KERNEL);
+		sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL);
 		if (sm == NULL)
 			return -ENOMEM;
 		tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
@@ -893,7 +816,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
 		err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg);
 		if (err) {
 			soc_control_err(tplg, &mc->hdr, mc->hdr.name);
-			kfree(sm);
 			break;
 		}
 
@@ -902,7 +824,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
 		if (err < 0) {
 			dev_err(tplg->dev, "ASoC: failed to create TLV %s\n",
 				mc->hdr.name);
-			kfree(sm);
 			break;
 		}
 
@@ -912,8 +833,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
 		if (err < 0) {
 			dev_err(tplg->dev, "ASoC: failed to init %s\n",
 				mc->hdr.name);
-			soc_tplg_free_tlv(tplg, &kc);
-			kfree(sm);
 			break;
 		}
 
@@ -923,8 +842,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
 		if (err < 0) {
 			dev_err(tplg->dev, "ASoC: failed to add %s\n",
 				mc->hdr.name);
-			soc_tplg_free_tlv(tplg, &kc);
-			kfree(sm);
 			break;
 		}
 
@@ -934,13 +851,16 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
 	return err;
 }
 
-static int soc_tplg_denum_create_texts(struct soc_enum *se,
-	struct snd_soc_tplg_enum_control *ec)
+static int soc_tplg_denum_create_texts(struct soc_tplg *tplg, struct soc_enum *se,
+				       struct snd_soc_tplg_enum_control *ec)
 {
 	int i, ret;
 
+	if (le32_to_cpu(ec->items) > ARRAY_SIZE(ec->texts))
+		return -EINVAL;
+
 	se->dobj.control.dtexts =
-		kcalloc(le32_to_cpu(ec->items), sizeof(char *), GFP_KERNEL);
+		devm_kcalloc(tplg->dev, le32_to_cpu(ec->items), sizeof(char *), GFP_KERNEL);
 	if (se->dobj.control.dtexts == NULL)
 		return -ENOMEM;
 
@@ -952,7 +872,7 @@ static int soc_tplg_denum_create_texts(struct soc_enum *se,
 			goto err;
 		}
 
-		se->dobj.control.dtexts[i] = kstrdup(ec->texts[i], GFP_KERNEL);
+		se->dobj.control.dtexts[i] = devm_kstrdup(tplg->dev, ec->texts[i], GFP_KERNEL);
 		if (!se->dobj.control.dtexts[i]) {
 			ret = -ENOMEM;
 			goto err;
@@ -964,29 +884,24 @@ static int soc_tplg_denum_create_texts(struct soc_enum *se,
 	return 0;
 
 err:
-	se->items = i;
-	soc_tplg_denum_remove_texts(se);
 	return ret;
 }
 
-static inline void soc_tplg_denum_remove_texts(struct soc_enum *se)
-{
-	int i = se->items;
-
-	for (--i; i >= 0; i--)
-		kfree(se->dobj.control.dtexts[i]);
-	kfree(se->dobj.control.dtexts);
-}
-
-static int soc_tplg_denum_create_values(struct soc_enum *se,
-	struct snd_soc_tplg_enum_control *ec)
+static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum *se,
+					struct snd_soc_tplg_enum_control *ec)
 {
 	int i;
 
-	if (le32_to_cpu(ec->items) > sizeof(*ec->values))
+	/*
+	 * Following "if" checks if we have at most SND_SOC_TPLG_NUM_TEXTS
+	 * values instead of using ARRAY_SIZE(ec->values) due to the fact that
+	 * it is oversized for its purpose. Additionally it is done so because
+	 * it is defined in UAPI header where it can't be easily changed.
+	 */
+	if (le32_to_cpu(ec->items) > SND_SOC_TPLG_NUM_TEXTS)
 		return -EINVAL;
 
-	se->dobj.control.dvalues = kzalloc(le32_to_cpu(ec->items) *
+	se->dobj.control.dvalues = devm_kcalloc(tplg->dev, le32_to_cpu(ec->items),
 					   sizeof(u32),
 					   GFP_KERNEL);
 	if (!se->dobj.control.dvalues)
@@ -1000,11 +915,6 @@ static int soc_tplg_denum_create_values(struct soc_enum *se,
 	return 0;
 }
 
-static inline void soc_tplg_denum_remove_values(struct soc_enum *se)
-{
-	kfree(se->dobj.control.dvalues);
-}
-
 static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
 	size_t size)
 {
@@ -1031,7 +941,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
 			SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
 			return -EINVAL;
 
-		se = kzalloc((sizeof(*se)), GFP_KERNEL);
+		se = devm_kzalloc(tplg->dev, (sizeof(*se)), GFP_KERNEL);
 		if (se == NULL)
 			return -ENOMEM;
 
@@ -1062,7 +972,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
 		switch (le32_to_cpu(ec->hdr.ops.info)) {
 		case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
 		case SND_SOC_TPLG_CTL_ENUM_VALUE:
-			err = soc_tplg_denum_create_values(se, ec);
+			err = soc_tplg_denum_create_values(tplg, se, ec);
 			if (err < 0) {
 				dev_err(tplg->dev,
 					"ASoC: could not create values for %s\n",
@@ -1073,7 +983,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
 		case SND_SOC_TPLG_CTL_ENUM:
 		case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
 		case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
-			err = soc_tplg_denum_create_texts(se, ec);
+			err = soc_tplg_denum_create_texts(tplg, se, ec);
 			if (err < 0) {
 				dev_err(tplg->dev,
 					"ASoC: could not create texts for %s\n",
@@ -1119,7 +1029,6 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
 	return 0;
 
 err_denum:
-	kfree(se);
 	return err;
 }
 
@@ -1196,7 +1105,7 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
 	struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
 	struct snd_soc_tplg_dapm_graph_elem *elem;
 	struct snd_soc_dapm_route **routes;
-	int count, i, j;
+	int count, i;
 	int ret = 0;
 
 	count = le32_to_cpu(hdr->count);
@@ -1225,15 +1134,9 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
 	 * each route can be freed when it is removed in remove_route().
 	 */
 	for (i = 0; i < count; i++) {
-		routes[i] = kzalloc(sizeof(*routes[i]), GFP_KERNEL);
-		if (!routes[i]) {
-			/* free previously allocated memory */
-			for (j = 0; j < i; j++)
-				kfree(routes[j]);
-
-			kfree(routes);
+		routes[i] = devm_kzalloc(tplg->dev, sizeof(*routes[i]), GFP_KERNEL);
+		if (!routes[i])
 			return -ENOMEM;
-		}
 	}
 
 	for (i = 0; i < count; i++) {
@@ -1291,15 +1194,6 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
 	}
 
 	/*
-	 * free memory allocated for all dapm routes not added to the
-	 * list in case of error
-	 */
-	if (ret < 0) {
-		while (i < count)
-			kfree(routes[i++]);
-	}
-
-	/*
 	 * free pointer to array of dapm routes as this is no longer needed.
 	 * The memory allocated for each dapm route will be freed
 	 * when it is removed in remove_route().
@@ -1317,7 +1211,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
 	struct snd_soc_tplg_mixer_control *mc;
 	int i, err;
 
-	kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
+	kc = devm_kcalloc(tplg->dev, num_kcontrols, sizeof(*kc), GFP_KERNEL);
 	if (kc == NULL)
 		return NULL;
 
@@ -1329,7 +1223,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
 			SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
 			goto err_sm;
 
-		sm = kzalloc(sizeof(*sm), GFP_KERNEL);
+		sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL);
 		if (sm == NULL)
 			goto err_sm;
 
@@ -1340,7 +1234,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
 			mc->hdr.name, i);
 
 		kc[i].private_value = (long)sm;
-		kc[i].name = kstrdup(mc->hdr.name, GFP_KERNEL);
+		kc[i].name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL);
 		if (kc[i].name == NULL)
 			goto err_sm;
 		kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
@@ -1390,14 +1284,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
 	return kc;
 
 err_sm:
-	for (; i >= 0; i--) {
-		soc_tplg_free_tlv(tplg, &kc[i]);
-		sm = (struct soc_mixer_control *)kc[i].private_value;
-		kfree(sm);
-		kfree(kc[i].name);
-	}
-	kfree(kc);
-
 	return NULL;
 }
 
@@ -1409,7 +1295,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
 	struct soc_enum *se;
 	int i, err;
 
-	kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
+	kc = devm_kcalloc(tplg->dev, num_kcontrols, sizeof(*kc), GFP_KERNEL);
 	if (kc == NULL)
 		return NULL;
 
@@ -1420,7 +1306,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
 			    SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
 			goto err_se;
 
-		se = kzalloc(sizeof(*se), GFP_KERNEL);
+		se = devm_kzalloc(tplg->dev, sizeof(*se), GFP_KERNEL);
 		if (se == NULL)
 			goto err_se;
 
@@ -1431,7 +1317,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
 			ec->hdr.name);
 
 		kc[i].private_value = (long)se;
-		kc[i].name = kstrdup(ec->hdr.name, GFP_KERNEL);
+		kc[i].name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL);
 		if (kc[i].name == NULL)
 			goto err_se;
 		kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
@@ -1451,7 +1337,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
 		switch (le32_to_cpu(ec->hdr.ops.info)) {
 		case SND_SOC_TPLG_CTL_ENUM_VALUE:
 		case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
-			err = soc_tplg_denum_create_values(se, ec);
+			err = soc_tplg_denum_create_values(tplg, se, ec);
 			if (err < 0) {
 				dev_err(tplg->dev, "ASoC: could not create values for %s\n",
 					ec->hdr.name);
@@ -1461,7 +1347,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
 		case SND_SOC_TPLG_CTL_ENUM:
 		case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
 		case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
-			err = soc_tplg_denum_create_texts(se, ec);
+			err = soc_tplg_denum_create_texts(tplg, se, ec);
 			if (err < 0) {
 				dev_err(tplg->dev, "ASoC: could not create texts for %s\n",
 					ec->hdr.name);
@@ -1494,20 +1380,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
 	return kc;
 
 err_se:
-	for (; i >= 0; i--) {
-		/* free values and texts */
-		se = (struct soc_enum *)kc[i].private_value;
-
-		if (se) {
-			soc_tplg_denum_remove_values(se);
-			soc_tplg_denum_remove_texts(se);
-		}
-
-		kfree(se);
-		kfree(kc[i].name);
-	}
-	kfree(kc);
-
 	return NULL;
 }
 
@@ -1519,7 +1391,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
 	struct snd_kcontrol_new *kc;
 	int i, err;
 
-	kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
+	kc = devm_kcalloc(tplg->dev, num_kcontrols, sizeof(*kc), GFP_KERNEL);
 	if (!kc)
 		return NULL;
 
@@ -1531,7 +1403,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
 			SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
 			goto err_sbe;
 
-		sbe = kzalloc(sizeof(*sbe), GFP_KERNEL);
+		sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL);
 		if (sbe == NULL)
 			goto err_sbe;
 
@@ -1543,7 +1415,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
 			be->hdr.name, be->hdr.access);
 
 		kc[i].private_value = (long)sbe;
-		kc[i].name = kstrdup(be->hdr.name, GFP_KERNEL);
+		kc[i].name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL);
 		if (kc[i].name == NULL)
 			goto err_sbe;
 		kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
@@ -1572,12 +1444,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
 	return kc;
 
 err_sbe:
-	for (; i >= 0; i--) {
-		sbe = (struct soc_bytes_ext *)kc[i].private_value;
-		kfree(sbe);
-		kfree(kc[i].name);
-	}
-	kfree(kc);
 
 	return NULL;
 }
@@ -1725,7 +1591,7 @@ widget:
 	return 0;
 
 ready_err:
-	snd_soc_tplg_widget_remove(widget);
+	remove_widget(widget->dapm->component, &widget->dobj, SOC_TPLG_PASS_WIDGET);
 	snd_soc_dapm_free_widget(widget);
 hdr_err:
 	kfree(template.sname);
@@ -1784,10 +1650,10 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
 	return 0;
 }
 
-static int set_stream_info(struct snd_soc_pcm_stream *stream,
-	struct snd_soc_tplg_stream_caps *caps)
+static int set_stream_info(struct soc_tplg *tplg, struct snd_soc_pcm_stream *stream,
+			   struct snd_soc_tplg_stream_caps *caps)
 {
-	stream->stream_name = kstrdup(caps->name, GFP_KERNEL);
+	stream->stream_name = devm_kstrdup(tplg->dev, caps->name, GFP_KERNEL);
 	if (!stream->stream_name)
 		return -ENOMEM;
 
@@ -1831,12 +1697,12 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
 		snd_soc_component_get_dapm(tplg->comp);
 	int ret;
 
-	dai_drv = kzalloc(sizeof(struct snd_soc_dai_driver), GFP_KERNEL);
+	dai_drv = devm_kzalloc(tplg->dev, sizeof(struct snd_soc_dai_driver), GFP_KERNEL);
 	if (dai_drv == NULL)
 		return -ENOMEM;
 
 	if (strlen(pcm->dai_name)) {
-		dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL);
+		dai_drv->name = devm_kstrdup(tplg->dev, pcm->dai_name, GFP_KERNEL);
 		if (!dai_drv->name) {
 			ret = -ENOMEM;
 			goto err;
@@ -1847,7 +1713,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
 	if (pcm->playback) {
 		stream = &dai_drv->playback;
 		caps = &pcm->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
-		ret = set_stream_info(stream, caps);
+		ret = set_stream_info(tplg, stream, caps);
 		if (ret < 0)
 			goto err;
 	}
@@ -1855,7 +1721,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
 	if (pcm->capture) {
 		stream = &dai_drv->capture;
 		caps = &pcm->caps[SND_SOC_TPLG_STREAM_CAPTURE];
-		ret = set_stream_info(stream, caps);
+		ret = set_stream_info(tplg, stream, caps);
 		if (ret < 0)
 			goto err;
 	}
@@ -1866,7 +1732,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
 	/* pass control to component driver for optional further init */
 	ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL);
 	if (ret < 0) {
-		dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
+		dev_err(tplg->dev, "ASoC: DAI loading failed\n");
 		goto err;
 	}
 
@@ -1876,7 +1742,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
 	list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list);
 
 	/* register the DAI to the component */
-	dai = devm_snd_soc_register_dai(tplg->comp->dev, tplg->comp, dai_drv, false);
+	dai = devm_snd_soc_register_dai(tplg->dev, tplg->comp, dai_drv, false);
 	if (!dai)
 		return -ENOMEM;
 
@@ -1890,11 +1756,6 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
 	return 0;
 
 err:
-	kfree(dai_drv->playback.stream_name);
-	kfree(dai_drv->capture.stream_name);
-	kfree(dai_drv->name);
-	kfree(dai_drv);
-
 	return ret;
 }
 
@@ -1930,7 +1791,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
 	int ret;
 
 	/* link + cpu + codec + platform */
-	link = kzalloc(sizeof(*link) + (3 * sizeof(*dlc)), GFP_KERNEL);
+	link = devm_kzalloc(tplg->dev, sizeof(*link) + (3 * sizeof(*dlc)), GFP_KERNEL);
 	if (link == NULL)
 		return -ENOMEM;
 
@@ -1949,8 +1810,8 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
 	link->dobj.type = SND_SOC_DOBJ_DAI_LINK;
 
 	if (strlen(pcm->pcm_name)) {
-		link->name = kstrdup(pcm->pcm_name, GFP_KERNEL);
-		link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL);
+		link->name = devm_kstrdup(tplg->dev, pcm->pcm_name, GFP_KERNEL);
+		link->stream_name = devm_kstrdup(tplg->dev, pcm->pcm_name, GFP_KERNEL);
 		if (!link->name || !link->stream_name) {
 			ret = -ENOMEM;
 			goto err;
@@ -1959,7 +1820,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
 	link->id = le32_to_cpu(pcm->pcm_id);
 
 	if (strlen(pcm->dai_name)) {
-		link->cpus->dai_name = kstrdup(pcm->dai_name, GFP_KERNEL);
+		link->cpus->dai_name = devm_kstrdup(tplg->dev, pcm->dai_name, GFP_KERNEL);
 		if (!link->cpus->dai_name) {
 			ret = -ENOMEM;
 			goto err;
@@ -1983,13 +1844,13 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
 	/* pass control to component driver for optional further init */
 	ret = soc_tplg_dai_link_load(tplg, link, NULL);
 	if (ret < 0) {
-		dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n");
+		dev_err(tplg->dev, "ASoC: FE link loading failed\n");
 		goto err;
 	}
 
 	ret = snd_soc_add_pcm_runtime(tplg->comp->card, link);
 	if (ret < 0) {
-		dev_err(tplg->comp->dev, "ASoC: adding FE link failed\n");
+		dev_err(tplg->dev, "ASoC: adding FE link failed\n");
 		goto err;
 	}
 
@@ -1997,10 +1858,6 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
 
 	return 0;
 err:
-	kfree(link->name);
-	kfree(link->stream_name);
-	kfree(link->cpus->dai_name);
-	kfree(link);
 	return ret;
 }
 
@@ -2169,7 +2026,7 @@ static void set_link_hw_format(struct snd_soc_dai_link *link,
 			struct snd_soc_tplg_link_config *cfg)
 {
 	struct snd_soc_tplg_hw_config *hw_config;
-	unsigned char bclk_master, fsync_master;
+	unsigned char bclk_provider, fsync_provider;
 	unsigned char invert_bclk, invert_fsync;
 	int i;
 
@@ -2209,18 +2066,18 @@ static void set_link_hw_format(struct snd_soc_dai_link *link,
 			link->dai_fmt |= SND_SOC_DAIFMT_IB_IF;
 
 		/* clock masters */
-		bclk_master = (hw_config->bclk_master ==
-			       SND_SOC_TPLG_BCLK_CM);
-		fsync_master = (hw_config->fsync_master ==
-				SND_SOC_TPLG_FSYNC_CM);
-		if (bclk_master && fsync_master)
-			link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
-		else if (!bclk_master && fsync_master)
-			link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
-		else if (bclk_master && !fsync_master)
-			link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
+		bclk_provider = (hw_config->bclk_provider ==
+			       SND_SOC_TPLG_BCLK_CP);
+		fsync_provider = (hw_config->fsync_provider ==
+				SND_SOC_TPLG_FSYNC_CP);
+		if (bclk_provider && fsync_provider)
+			link->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
+		else if (!bclk_provider && fsync_provider)
+			link->dai_fmt |= SND_SOC_DAIFMT_CBC_CFP;
+		else if (bclk_provider && !fsync_provider)
+			link->dai_fmt |= SND_SOC_DAIFMT_CBP_CFC;
 		else
-			link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+			link->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
 	}
 }
 
@@ -2473,7 +2330,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
 	if (d->playback) {
 		stream = &dai_drv->playback;
 		caps = &d->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
-		ret = set_stream_info(stream, caps);
+		ret = set_stream_info(tplg, stream, caps);
 		if (ret < 0)
 			goto err;
 	}
@@ -2481,7 +2338,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
 	if (d->capture) {
 		stream = &dai_drv->capture;
 		caps = &d->caps[SND_SOC_TPLG_STREAM_CAPTURE];
-		ret = set_stream_info(stream, caps);
+		ret = set_stream_info(tplg, stream, caps);
 		if (ret < 0)
 			goto err;
 	}
@@ -2494,15 +2351,13 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
 	/* pass control to component driver for optional further init */
 	ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai);
 	if (ret < 0) {
-		dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
+		dev_err(tplg->dev, "ASoC: DAI loading failed\n");
 		goto err;
 	}
 
 	return 0;
 
 err:
-	kfree(dai_drv->playback.stream_name);
-	kfree(dai_drv->capture.stream_name);
 	return ret;
 }
 
@@ -2680,11 +2535,6 @@ static int soc_tplg_load_header(struct soc_tplg *tplg,
 
 	tplg->pos = tplg->hdr_pos + sizeof(struct snd_soc_tplg_hdr);
 
-	/* check for matching ID */
-	if (le32_to_cpu(hdr->index) != tplg->req_index &&
-		tplg->req_index != SND_SOC_TPLG_INDEX_ALL)
-		return 0;
-
 	tplg->index = le32_to_cpu(hdr->index);
 
 	switch (le32_to_cpu(hdr->type)) {
@@ -2804,7 +2654,7 @@ static int soc_tplg_load(struct soc_tplg *tplg)
 
 /* load audio component topology from "firmware" file */
 int snd_soc_tplg_component_load(struct snd_soc_component *comp,
-	struct snd_soc_tplg_ops *ops, const struct firmware *fw, u32 id)
+	struct snd_soc_tplg_ops *ops, const struct firmware *fw)
 {
 	struct soc_tplg tplg;
 	int ret;
@@ -2819,7 +2669,6 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp,
 	tplg.dev = comp->dev;
 	tplg.comp = comp;
 	tplg.ops = ops;
-	tplg.req_index = id;
 	tplg.io_ops = ops->io_ops;
 	tplg.io_ops_count = ops->io_ops_count;
 	tplg.bytes_ext_ops = ops->bytes_ext_ops;
@@ -2828,49 +2677,14 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp,
 	ret = soc_tplg_load(&tplg);
 	/* free the created components if fail to load topology */
 	if (ret)
-		snd_soc_tplg_component_remove(comp, SND_SOC_TPLG_INDEX_ALL);
+		snd_soc_tplg_component_remove(comp);
 
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load);
 
-/* remove this dynamic widget */
-void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w)
-{
-	/* make sure we are a widget */
-	if (w->dobj.type != SND_SOC_DOBJ_WIDGET)
-		return;
-
-	remove_widget(w->dapm->component, &w->dobj, SOC_TPLG_PASS_WIDGET);
-}
-EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove);
-
-/* remove all dynamic widgets from this DAPM context */
-void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
-	u32 index)
-{
-	struct snd_soc_dapm_widget *w, *next_w;
-
-	for_each_card_widgets_safe(dapm->card, w, next_w) {
-
-		/* make sure we are a widget with correct context */
-		if (w->dobj.type != SND_SOC_DOBJ_WIDGET || w->dapm != dapm)
-			continue;
-
-		/* match ID */
-		if (w->dobj.index != index &&
-			w->dobj.index != SND_SOC_TPLG_INDEX_ALL)
-			continue;
-		/* check and free and dynamic widget kcontrols */
-		snd_soc_tplg_widget_remove(w);
-		snd_soc_dapm_free_widget(w);
-	}
-	snd_soc_dapm_reset_cache(dapm);
-}
-EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all);
-
 /* remove dynamic controls from the component driver */
-int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index)
+int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
 {
 	struct snd_soc_dobj *dobj, *next_dobj;
 	int pass = SOC_TPLG_PASS_END;
@@ -2882,11 +2696,6 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index)
 		list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list,
 			list) {
 
-			/* match index */
-			if (dobj->index != index &&
-				index != SND_SOC_TPLG_INDEX_ALL)
-				continue;
-
 			switch (dobj->type) {
 			case SND_SOC_DOBJ_MIXER:
 				remove_mixer(comp, dobj, pass);
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig
index 8c1f0829de40..031dad5fc4c7 100644
--- a/sound/soc/sof/Kconfig
+++ b/sound/soc/sof/Kconfig
@@ -2,7 +2,7 @@
 config SND_SOC_SOF_TOPLEVEL
 	bool "Sound Open Firmware Support"
 	help
-	  This adds support for Sound Open Firmware (SOF). SOF is a free and
+	  This adds support for Sound Open Firmware (SOF). SOF is free and
 	  generic open source audio DSP firmware for multiple devices.
 	  Say Y if you have such a device that is supported by SOF.
 	  If unsure select "N".
@@ -16,8 +16,8 @@ config SND_SOC_SOF_PCI
 	select SND_SOC_ACPI if ACPI
 	help
 	  This adds support for PCI enumeration. This option is
-	  required to enable Intel Skylake+ devices
-	  Say Y if you need this option
+	  required to enable Intel Skylake+ devices.
+	  Say Y if you need this option.
 	  If unsure select "N".
 
 config SND_SOC_SOF_ACPI
@@ -28,8 +28,8 @@ config SND_SOC_SOF_ACPI
 	select IOSF_MBI if X86 && PCI
 	help
 	  This adds support for ACPI enumeration. This option is required
-	  to enable Intel Broadwell/Baytrail/Cherrytrail devices
-	  Say Y if you need this option
+	  to enable Intel Broadwell/Baytrail/Cherrytrail devices.
+	  Say Y if you need this option.
 	  If unsure select "N".
 
 config SND_SOC_SOF_OF
@@ -54,12 +54,12 @@ config SND_SOC_SOF_DEVELOPER_SUPPORT
 	bool "SOF developer options support"
 	depends on EXPERT
 	help
-	  This option unlock SOF developer options for debug/performance/
+	  This option unlocks SOF developer options for debug/performance/
 	  code hardening.
 	  Distributions should not select this option, only SOF development
 	  teams should select it.
-	  Say Y if you are involved in SOF development and need this option
-	  If not, select N
+	  Say Y if you are involved in SOF development and need this option.
+	  If not, select N.
 
 if SND_SOC_SOF_DEVELOPER_SUPPORT
 
@@ -72,13 +72,13 @@ config SND_SOC_SOF_NOCODEC_SUPPORT
 	  This adds support for a dummy/nocodec machine driver fallback
 	  option if no known codec is detected. This is typically only
 	  enabled for developers or devices where the sound card is
-	  controlled externally
-	  This option is mutually exclusive with the Intel HDAudio support,
-	  selecting it may have negative impacts and prevent e.g. microphone
+	  controlled externally.
+	  This option is mutually exclusive with the Intel HDAudio support.
+	  Selecting it may have negative impacts and prevent e.g. microphone
 	  functionality from being enabled on Intel CoffeeLake and later
 	  platforms.
 	  Distributions should not select this option!
-	  Say Y if you need this nocodec fallback option
+	  Say Y if you need this nocodec fallback option.
 	  If unsure select "N".
 
 config SND_SOC_SOF_STRICT_ABI_CHECKS
@@ -92,8 +92,8 @@ config SND_SOC_SOF_STRICT_ABI_CHECKS
 	  is invoked.
 	  This option will stop topology creation and firmware load upfront.
 	  It is intended for SOF CI/releases and not for users or distros.
-	  Say Y if you want strict ABI checks for an SOF release
-	  If you are not involved in SOF releases and CI development
+	  Say Y if you want strict ABI checks for an SOF release.
+	  If you are not involved in SOF releases and CI development,
 	  select "N".
 
 config SND_SOC_SOF_DEBUG
@@ -114,8 +114,8 @@ config SND_SOC_SOF_FORCE_NOCODEC_MODE
 	  though there is a codec detected on the real platform. This is
 	  typically only enabled for developers for debug purposes, before
 	  codec/machine driver is ready, or to exclude the impact of those
-	  drivers
-	  Say Y if you need this force nocodec mode option
+	  drivers.
+	  Say Y if you need this force nocodec mode option.
 	  If unsure select "N".
 
 config SND_SOC_SOF_DEBUG_XRUN_STOP
@@ -137,12 +137,12 @@ config SND_SOC_SOF_DEBUG_VERBOSE_IPC
 config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION
 	bool "SOF force to use IPC for position update on SKL+"
 	help
-	  This option force to handle stream position update IPCs and run pcm
+	  This option forces to handle stream position update IPCs and run PCM
 	  elapse to inform ALSA about that, on platforms (e.g. Intel SKL+) that
 	  with other approach (e.g. HDAC DPIB/posbuf) to elapse PCM.
 	  On platforms (e.g. Intel SKL-) where position update IPC is the only
 	  one choice, this setting won't impact anything.
-	  if you are trying to debug pointer update with position IPCs or where
+	  If you are trying to debug pointer update with position IPCs or where
 	  DPIB/posbuf is not ready, select "Y".
 	  If unsure select "N".
 
@@ -161,7 +161,7 @@ config SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE
 	help
 	  The firmware trace can be enabled either at build-time with
 	  this option, or dynamically by setting flags in the SOF core
-	  module parameter (similar to dynamic debug)
+	  module parameter (similar to dynamic debug).
 	  If unsure, select "N".
 
 config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST
@@ -190,7 +190,7 @@ config SND_SOC_SOF
 	select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 	  The selection is made at the top level and does not exactly follow
 	  module dependencies but since the module or built-in type is decided
 	  at the top level it doesn't matter.
@@ -199,7 +199,7 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE
 	bool
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 	  When selected, the probe is handled in two steps, for example to
 	  avoid lockdeps if request_module is used in the probe.
 
diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c
index 0352d2b61358..a5dd728c580a 100644
--- a/sound/soc/sof/control.c
+++ b/sound/soc/sof/control.c
@@ -114,6 +114,28 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
 	return change;
 }
 
+int snd_sof_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_sof_control *scontrol = sm->dobj.private;
+	unsigned int channels = scontrol->num_channels;
+	int platform_max;
+
+	if (!sm->platform_max)
+		sm->platform_max = sm->max;
+	platform_max = sm->platform_max;
+
+	if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume"))
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	else
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+
+	uinfo->count = channels;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = platform_max - sm->min;
+	return 0;
+}
+
 int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_value *ucontrol)
 {
@@ -309,7 +331,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
 	 * the length (as bytes) is needed to know the correct copy
 	 * length of data from tlvd->tlv.
 	 */
-	if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv)))
+	if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv)))
 		return -EFAULT;
 
 	/* make sure TLV info is consistent */
@@ -351,7 +373,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
 	}
 
 	/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
-	if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) {
+	if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) {
 		dev_err_ratelimited(scomp->dev, "error: Mismatch in ABI data size (truncated?).\n");
 		return -EINVAL;
 	}
@@ -405,15 +427,15 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
 		goto out;
 
 	/* check data size doesn't exceed max coming from topology */
-	if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) {
+	if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) {
 		dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %zu.\n",
 				    cdata->data->size,
-				    be->max - sizeof(const struct sof_abi_hdr));
+				    be->max - sizeof(struct sof_abi_hdr));
 		ret = -EINVAL;
 		goto out;
 	}
 
-	data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
+	data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
 
 	/* make sure we don't exceed size provided by user space for data */
 	if (data_size > size) {
@@ -423,7 +445,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
 
 	header.numid = scontrol->cmd;
 	header.length = data_size;
-	if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) {
+	if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) {
 		ret = -EFAULT;
 		goto out;
 	}
@@ -466,14 +488,14 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
 	cdata->data->abi = SOF_ABI_VERSION;
 
 	/* check data size doesn't exceed max coming from topology */
-	if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) {
+	if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) {
 		dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %zu.\n",
 				    cdata->data->size,
-				    be->max - sizeof(const struct sof_abi_hdr));
+				    be->max - sizeof(struct sof_abi_hdr));
 		return -EINVAL;
 	}
 
-	data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
+	data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
 
 	/* make sure we don't exceed size provided by user space for data */
 	if (data_size > size)
@@ -481,7 +503,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
 
 	header.numid = scontrol->cmd;
 	header.length = data_size;
-	if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv)))
+	if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
 		return -EFAULT;
 
 	if (copy_to_user(tlvd->tlv, cdata->data, data_size))
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
index 9419a99bab53..30213a1beaaa 100644
--- a/sound/soc/sof/debug.c
+++ b/sound/soc/sof/debug.c
@@ -14,6 +14,8 @@
 #include <linux/debugfs.h>
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
+#include <sound/sof/ext_manifest.h>
+#include <sound/sof/debug.h>
 #include "sof-priv.h"
 #include "ops.h"
 
@@ -626,6 +628,121 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev,
 }
 EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item);
 
+static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_size)
+{
+	struct sof_ipc_cmd_hdr msg = {
+		.size = sizeof(struct sof_ipc_cmd_hdr),
+		.cmd = SOF_IPC_GLB_DEBUG | SOF_IPC_DEBUG_MEM_USAGE,
+	};
+	struct sof_ipc_dbg_mem_usage *reply;
+	int len;
+	int ret;
+	int i;
+
+	reply = kmalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
+	if (!reply)
+		return -ENOMEM;
+
+	ret = pm_runtime_get_sync(sdev->dev);
+	if (ret < 0 && ret != -EACCES) {
+		pm_runtime_put_noidle(sdev->dev);
+		dev_err(sdev->dev, "error: enabling device failed: %d\n", ret);
+		goto error;
+	}
+
+	ret = sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
+	pm_runtime_mark_last_busy(sdev->dev);
+	pm_runtime_put_autosuspend(sdev->dev);
+	if (ret < 0 || reply->rhdr.error < 0) {
+		ret = min(ret, reply->rhdr.error);
+		dev_err(sdev->dev, "error: reading memory info failed, %d\n", ret);
+		goto error;
+	}
+
+	if (struct_size(reply, elems, reply->num_elems) != reply->rhdr.hdr.size) {
+		dev_err(sdev->dev, "error: invalid memory info ipc struct size, %d\n",
+			reply->rhdr.hdr.size);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	for (i = 0, len = 0; i < reply->num_elems; i++) {
+		ret = snprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n",
+			       reply->elems[i].zone, reply->elems[i].id,
+			       reply->elems[i].used, reply->elems[i].free);
+		if (ret < 0)
+			goto error;
+		len += ret;
+	}
+
+	ret = len;
+error:
+	kfree(reply);
+	return ret;
+}
+
+static ssize_t memory_info_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+	struct snd_sof_dfsentry *dfse = file->private_data;
+	struct snd_sof_dev *sdev = dfse->sdev;
+	int data_length;
+
+	/* read memory info from FW only once for each file read */
+	if (!*ppos) {
+		dfse->buf_data_size = 0;
+		data_length = memory_info_update(sdev, dfse->buf, dfse->size);
+		if (data_length < 0)
+			return data_length;
+		dfse->buf_data_size = data_length;
+	}
+
+	return simple_read_from_buffer(to, count, ppos, dfse->buf, dfse->buf_data_size);
+}
+
+static int memory_info_open(struct inode *inode, struct file *file)
+{
+	struct snd_sof_dfsentry *dfse = inode->i_private;
+	struct snd_sof_dev *sdev = dfse->sdev;
+
+	file->private_data = dfse;
+
+	/* allocate buffer memory only in first open run, to save memory when unused */
+	if (!dfse->buf) {
+		dfse->buf = devm_kmalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL);
+		if (!dfse->buf)
+			return -ENOMEM;
+		dfse->size = PAGE_SIZE;
+	}
+
+	return 0;
+}
+
+static const struct file_operations memory_info_fops = {
+	.open = memory_info_open,
+	.read = memory_info_read,
+	.llseek = default_llseek,
+};
+
+int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev)
+{
+	struct snd_sof_dfsentry *dfse;
+
+	dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
+	if (!dfse)
+		return -ENOMEM;
+
+	/* don't allocate buffer before first usage, to save memory when unused */
+	dfse->type = SOF_DFSENTRY_TYPE_BUF;
+	dfse->sdev = sdev;
+
+	debugfs_create_file("memory_info", 0444, sdev->debugfs_root, dfse, &memory_info_fops);
+
+	/* add to dfsentry list */
+	list_add(&dfse->list, &sdev->dfsentry_list);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init);
+
 int snd_sof_dbg_init(struct snd_sof_dev *sdev)
 {
 	const struct snd_sof_dsp_ops *ops = sof_ops(sdev);
@@ -700,7 +817,7 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev)
 	}
 
 	/* dump vital information to the logs */
-	snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
+	snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
 	snd_sof_ipc_dump(sdev);
 	snd_sof_trace_notify_for_error(sdev);
 }
diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig
index 48f998a19ddb..49d605cb09a5 100644
--- a/sound/soc/sof/imx/Kconfig
+++ b/sound/soc/sof/imx/Kconfig
@@ -17,7 +17,7 @@ config SND_SOC_SOF_IMX_OF
 	select SND_SOC_SOF_IMX8M if SND_SOC_SOF_IMX8M_SUPPORT
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_IMX_COMMON
 	tristate
@@ -30,7 +30,7 @@ config SND_SOC_SOF_IMX8_SUPPORT
 	depends on IMX_SCU=y || IMX_SCU=SND_SOC_SOF_IMX_OF
 	depends on IMX_DSP=y || IMX_DSP=SND_SOC_SOF_IMX_OF
 	help
-	  This adds support for Sound Open Firmware for NXP i.MX8 platforms
+	  This adds support for Sound Open Firmware for NXP i.MX8 platforms.
 	  Say Y if you have such a device.
 	  If unsure select "N".
 
@@ -40,13 +40,13 @@ config SND_SOC_SOF_IMX8
 	select SND_SOC_SOF_XTENSA
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_IMX8M_SUPPORT
 	bool "SOF support for i.MX8M"
 	depends on IMX_DSP=y || IMX_DSP=SND_SOC_SOF_OF
 	help
-	  This adds support for Sound Open Firmware for NXP i.MX8M platforms
+	  This adds support for Sound Open Firmware for NXP i.MX8M platforms.
 	  Say Y if you have such a device.
 	  If unsure select "N".
 
@@ -56,6 +56,6 @@ config SND_SOC_SOF_IMX8M
 	select SND_SOC_SOF_XTENSA
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL
diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c
index 5fee637834c2..8826ef94f04a 100644
--- a/sound/soc/sof/imx/imx-common.c
+++ b/sound/soc/sof/imx/imx-common.c
@@ -47,6 +47,8 @@ void imx8_get_registers(struct snd_sof_dev *sdev,
 /**
  * imx8_dump() - This function is called when a panic message is
  * received from the firmware.
+ * @sdev: SOF device
+ * @flags: parameter not used but required by ops prototype
  */
 void imx8_dump(struct snd_sof_dev *sdev, u32 flags)
 {
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
index a066e08860cb..d306c370e5d1 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -15,7 +15,7 @@ config SND_SOC_SOF_INTEL_ACPI
 	select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_INTEL_PCI
 	def_tristate SND_SOC_SOF_PCI
@@ -29,15 +29,16 @@ config SND_SOC_SOF_INTEL_PCI
 	select SND_SOC_SOF_TIGERLAKE   if SND_SOC_SOF_TIGERLAKE_SUPPORT
 	select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT
 	select SND_SOC_SOF_JASPERLAKE  if SND_SOC_SOF_JASPERLAKE_SUPPORT
+	select SND_SOC_SOF_ALDERLAKE   if SND_SOC_SOF_ALDERLAKE_SUPPORT
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_INTEL_HIFI_EP_IPC
 	tristate
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_INTEL_ATOM_HIFI_EP
 	tristate
@@ -45,7 +46,7 @@ config SND_SOC_SOF_INTEL_ATOM_HIFI_EP
 	select SND_SOC_SOF_INTEL_HIFI_EP_IPC
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_INTEL_COMMON
 	tristate
@@ -55,47 +56,48 @@ config SND_SOC_SOF_INTEL_COMMON
 	select SND_SOC_ACPI if ACPI
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 if SND_SOC_SOF_INTEL_ACPI
 
 config SND_SOC_SOF_BAYTRAIL_SUPPORT
 	bool "SOF support for Baytrail, Braswell and Cherrytrail"
-	depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI=n
 	help
 	  This adds support for Sound Open Firmware for Intel(R) platforms
 	  using the Baytrail, Braswell or Cherrytrail processors.
-	  This option is mutually exclusive with the Atom/SST and Baytrail
-	  legacy drivers. If you want to enable SOF on Baytrail/Cherrytrail,
-	  you need to deselect those options first.
-	  SOF does not support Baytrail-CR for now, so this option is not
-	  recommended for distros. At some point all legacy drivers will be
-	  deprecated but not before all userspace firmware/topology/UCM files
-	  are made available to downstream distros.
-	  Say Y if you want to enable SOF on Baytrail/Cherrytrail
+	  This option can coexist in the same build with the Atom legacy
+	  drivers, currently the default but which will be deprecated
+	  at some point.
+	  Existing firmware/topology binaries and UCM configurations
+	  typically located in the root file system are already
+	  compatible with both SOF or Atom/SST legacy drivers.
+	  This is a recommended option for distributions.
+	  Say Y if you want to enable SOF on Baytrail/Cherrytrail.
 	  If unsure select "N".
 
 config SND_SOC_SOF_BAYTRAIL
 	tristate
 	select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
+	select SND_INTEL_DSP_CONFIG
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_BROADWELL_SUPPORT
 	bool "SOF support for Broadwell"
-	depends on SND_SOC_INTEL_HASWELL=n
+	select SND_INTEL_DSP_CONFIG
 	help
 	  This adds support for Sound Open Firmware for Intel(R) platforms
 	  using the Broadwell processors.
-	  This option is mutually exclusive with the Haswell/Broadwell legacy
-	  driver. If you want to enable SOF on Broadwell you need to deselect
-	  the legacy driver first.
-	  SOF does fully support Broadwell yet, so this option is not
-	  recommended for distros. At some point all legacy drivers will be
-	  deprecated but not before all userspace firmware/topology/UCM files
-	  are made available to downstream distros.
-	  Say Y if you want to enable SOF on Broadwell
+	  This option can coexist in the same build with the default 'catpt'
+	  driver.
+	  Existing firmware/topology binaries and UCM configurations typically
+	  located in the root file system are already compatible with both SOF
+	  or catpt drivers.
+	  SOF does not fully support Broadwell and has limitations related to
+	  DMA and suspend-resume, this is not a recommended option for
+	  distributions.
+	  Say Y if you want to enable SOF on Broadwell.
 	  If unsure select "N".
 
 config SND_SOC_SOF_BROADWELL
@@ -104,7 +106,7 @@ config SND_SOC_SOF_BROADWELL
 	select SND_SOC_SOF_INTEL_HIFI_EP_IPC
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 endif ## SND_SOC_SOF_INTEL_ACPI
 
@@ -123,7 +125,7 @@ config SND_SOC_SOF_MERRIFIELD
 	select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_APOLLOLAKE_SUPPORT
 	bool "SOF support for Apollolake"
@@ -138,7 +140,7 @@ config SND_SOC_SOF_APOLLOLAKE
 	select SND_SOC_SOF_HDA_COMMON
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_GEMINILAKE_SUPPORT
 	bool "SOF support for GeminiLake"
@@ -153,7 +155,7 @@ config SND_SOC_SOF_GEMINILAKE
 	select SND_SOC_SOF_HDA_COMMON
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_CANNONLAKE_SUPPORT
 	bool "SOF support for Cannonlake"
@@ -169,7 +171,7 @@ config SND_SOC_SOF_CANNONLAKE
 	select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_COFFEELAKE_SUPPORT
 	bool "SOF support for CoffeeLake"
@@ -185,7 +187,7 @@ config SND_SOC_SOF_COFFEELAKE
 	select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_ICELAKE_SUPPORT
 	bool "SOF support for Icelake"
@@ -201,7 +203,7 @@ config SND_SOC_SOF_ICELAKE
 	select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_COMETLAKE
 	tristate
@@ -209,7 +211,7 @@ config SND_SOC_SOF_COMETLAKE
 	select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_COMETLAKE_SUPPORT
 	bool
@@ -236,7 +238,7 @@ config SND_SOC_SOF_TIGERLAKE
 	select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_ELKHARTLAKE_SUPPORT
 	bool "SOF support for ElkhartLake"
@@ -252,7 +254,7 @@ config SND_SOC_SOF_ELKHARTLAKE
 	select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_JASPERLAKE_SUPPORT
 	bool "SOF support for JasperLake"
@@ -267,15 +269,32 @@ config SND_SOC_SOF_JASPERLAKE
 	select SND_SOC_SOF_HDA_COMMON
 	help
 	  This option is not user-selectable but automagically handled by
+	  'select' statements at a higher level.
+
+config SND_SOC_SOF_ALDERLAKE_SUPPORT
+	bool "SOF support for Alderlake"
+	help
+	  This adds support for Sound Open Firmware for Intel(R) platforms
+	  using the Alderlake processors.
+	  Say Y if you have such a device.
+	  If unsure select "N".
+
+config SND_SOC_SOF_ALDERLAKE
+	tristate
+	select SND_SOC_SOF_HDA_COMMON
+	select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+	help
+	  This option is not user-selectable but automagically handled by
 	  'select' statements at a higher level
 
 config SND_SOC_SOF_HDA_COMMON
 	tristate
+	select SND_INTEL_DSP_CONFIG
 	select SND_SOC_SOF_INTEL_COMMON
 	select SND_SOC_SOF_HDA_LINK_BASELINE
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 if SND_SOC_SOF_HDA_COMMON
 
@@ -285,7 +304,7 @@ config SND_SOC_SOF_HDA_LINK
 	select SND_SOC_SOF_PROBE_WORK_QUEUE
 	help
 	  This adds support for HDA links(HDA/HDMI) with Sound Open Firmware
-		  for Intel(R) platforms.
+	  for Intel(R) platforms.
 	  Say Y if you want to enable HDA links with SOF.
 	  If unsure select "N".
 
@@ -294,7 +313,7 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC
 	depends on SND_SOC_SOF_HDA_LINK
 	help
 	  This adds support for HDAudio codecs with Sound Open Firmware
-		  for Intel(R) platforms.
+	  for Intel(R) platforms.
 	  Say Y if you want to enable HDAudio codecs with SOF.
 	  If unsure select "N".
 
@@ -302,8 +321,8 @@ config SND_SOC_SOF_HDA_PROBES
 	bool "SOF enable probes over HDA"
 	depends on SND_SOC_SOF_DEBUG_PROBES
 	help
-	  This option enables the data probing for Intel(R).
-		  Intel(R) Skylake and newer platforms.
+	  This option enables the data probing for Intel(R)
+	  Skylake and newer platforms.
 	  Say Y if you want to enable probes.
 	  If unsure, select "N".
 
@@ -314,7 +333,7 @@ config SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1
 	  and disables known workarounds for specific HDAudio platforms.
 	  Only use to look into power optimizations on platforms not
 	  affected by DMI L1 issues. This option is not recommended.
-	  Say Y if you want to enable DMI Link L1
+	  Say Y if you want to enable DMI Link L1.
 	  If unsure, select "N".
 
 endif ## SND_SOC_SOF_HDA_COMMON
@@ -324,23 +343,22 @@ config SND_SOC_SOF_HDA_LINK_BASELINE
 	select SND_SOC_SOF_HDA if SND_SOC_SOF_HDA_LINK
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_HDA
 	tristate
 	select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK
 	select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC
-	select SND_INTEL_DSP_CONFIG
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK
 	bool "SOF support for SoundWire"
 	depends on SOUNDWIRE && ACPI
 	help
 	  This adds support for SoundWire with Sound Open Firmware
-		  for Intel(R) platforms.
+	  for Intel(R) platforms.
 	  Say Y if you want to enable SoundWire links with SOF.
 	  If unsure select "N".
 
@@ -349,14 +367,14 @@ config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
 	select SND_SOC_SOF_INTEL_SOUNDWIRE if SND_SOC_SOF_INTEL_SOUNDWIRE_LINK
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 config SND_SOC_SOF_INTEL_SOUNDWIRE
 	tristate
 	select SOUNDWIRE_INTEL
 	help
 	  This option is not user-selectable but automagically handled by
-	  'select' statements at a higher level
+	  'select' statements at a higher level.
 
 endif ## SND_SOC_SOF_INTEL_PCI
 
diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile
index 72d85b25df7d..2589111c2fae 100644
--- a/sound/soc/sof/intel/Makefile
+++ b/sound/soc/sof/intel/Makefile
@@ -8,7 +8,7 @@ snd-sof-intel-ipc-objs := intel-ipc.o
 snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
 				 hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
 				 hda-dai.o hda-bus.o \
-				 apl.o cnl.o tgl.o
+				 apl.o cnl.o tgl.o icl.o
 snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-compress.o
 
 snd-sof-intel-hda-objs := hda-codec.o
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index 4eeade2e77f7..fc29b91b8932 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -92,6 +92,9 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
 	.pre_fw_run = hda_dsp_pre_fw_run,
 	.post_fw_run = hda_dsp_post_fw_run,
 
+	/* parse platform specific extended manifest */
+	.parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
+
 	/* dsp core power up/down */
 	.core_power_up = hda_dsp_enable_core,
 	.core_power_down = hda_dsp_core_reset_power_down,
diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c
index 186736ee5fc2..19260dbecac5 100644
--- a/sound/soc/sof/intel/byt.c
+++ b/sound/soc/sof/intel/byt.c
@@ -336,7 +336,7 @@ static int byt_run(struct snd_sof_dev *sdev)
 	}
 	if (tries < 0) {
 		dev_err(sdev->dev, "error:  unable to run DSP firmware\n");
-		byt_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
+		byt_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
 		return -ENODEV;
 	}
 
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index a5d3258104c0..e38db519f38d 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -294,6 +294,9 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
 	.pre_fw_run = hda_dsp_pre_fw_run,
 	.post_fw_run = hda_dsp_post_fw_run,
 
+	/* parse platform specific extended manifest */
+	.parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
+
 	/* dsp core power up/down */
 	.core_power_up = hda_dsp_enable_core,
 	.core_power_down = hda_dsp_core_reset_power_down,
@@ -346,22 +349,6 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
 };
 EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
 
-const struct sof_intel_dsp_desc icl_chip_info = {
-	/* Icelake */
-	.cores_num = 4,
-	.init_core_mask = 1,
-	.host_managed_cores_mask = GENMASK(3, 0),
-	.ipc_req = CNL_DSP_REG_HIPCIDR,
-	.ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
-	.ipc_ack = CNL_DSP_REG_HIPCIDA,
-	.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
-	.ipc_ctl = CNL_DSP_REG_HIPCCTL,
-	.rom_init_timeout	= 300,
-	.ssp_count = ICL_SSP_COUNT,
-	.ssp_base_offset = CNL_SSP_BASE_OFFSET,
-};
-EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
-
 const struct sof_intel_dsp_desc ehl_chip_info = {
 	/* Elkhartlake */
 	.cores_num = 4,
diff --git a/sound/soc/sof/intel/ext_manifest.h b/sound/soc/sof/intel/ext_manifest.h
new file mode 100644
index 000000000000..2dfae9285d3c
--- /dev/null
+++ b/sound/soc/sof/intel/ext_manifest.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ */
+
+/*
+ * Intel extended manifest is a extra place to store Intel cavs specific
+ * metadata about firmware, for example LPRO/HPRO configuration is
+ * Intel cavs specific. This part of output binary is not signed.
+ */
+
+#ifndef __INTEL_CAVS_EXT_MANIFEST_H__
+#define __INTEL_CAVS_EXT_MANIFEST_H__
+
+#include <sound/sof/ext_manifest.h>
+
+/* EXT_MAN_ELEM_PLATFORM_CONFIG_DATA elements identificators */
+enum sof_cavs_config_elem_type {
+	SOF_EXT_MAN_CAVS_CONFIG_EMPTY		= 0,
+	SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO	= 1,
+	SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE	= 2,
+	SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE	= 3,
+};
+
+/* EXT_MAN_ELEM_PLATFORM_CONFIG_DATA elements */
+struct sof_ext_man_cavs_config_data {
+	struct sof_ext_man_elem_header hdr;
+
+	struct sof_config_elem elems[];
+} __packed;
+
+#endif /* __INTEL_CAVS_EXT_MANIFEST_H__ */
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index 18ff1c2f5376..2b001151fe37 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -44,7 +44,7 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask)
 	reset = HDA_DSP_ADSPCS_CRST_MASK(core_mask);
 	snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
 					 HDA_DSP_REG_ADSPCS,
-					 reset, reset),
+					 reset, reset);
 
 	/* poll with timeout to check if operation successful */
 	ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 2707a16c6a4d..ed773696b495 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -19,6 +19,7 @@
 #include <sound/hdaudio_ext.h>
 #include <sound/hda_register.h>
 #include <sound/sof.h>
+#include "ext_manifest.h"
 #include "../ops.h"
 #include "hda.h"
 
@@ -87,6 +88,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
 	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
 	const struct sof_intel_dsp_desc *chip = hda->desc;
 	unsigned int status;
+	u32 flags;
 	int ret;
 	int i;
 
@@ -174,7 +176,13 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
 			__func__);
 
 err:
-	hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX);
+	flags = SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX;
+
+	/* force error log level after max boot attempts */
+	if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
+		flags |= SOF_DBG_DUMP_FORCE_ERR_LEVEL;
+
+	hda_dsp_dump(sdev, flags);
 	hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
 
 	return ret;
@@ -407,10 +415,13 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
 	 * should be ready for code loading and firmware boot
 	 */
 	ret = cl_copy_fw(sdev, stream);
-	if (!ret)
+	if (!ret) {
 		dev_dbg(sdev->dev, "Firmware download successful, booting...\n");
-	else
+	} else {
+		hda_dsp_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX |
+			     SOF_DBG_DUMP_FORCE_ERR_LEVEL);
 		dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret);
+	}
 
 cleanup:
 	/*
@@ -434,9 +445,6 @@ cleanup:
 	if (!ret)
 		return chip_info->init_core_mask;
 
-	/* dump dsp registers and disable DSP upon error */
-	hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX);
-
 	/* disable DSP */
 	snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR,
 				SOF_HDA_REG_PP_PPCTL,
@@ -470,3 +478,102 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev)
 	/* re-enable clock gating and power gating */
 	return hda_dsp_ctrl_clock_power_gating(sdev, true);
 }
+
+/*
+ * post fw run operations for ICL,
+ * Core 3 will be powered up and in stall when HPRO is enabled
+ */
+int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev)
+{
+	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+	int ret;
+
+	if (sdev->first_boot) {
+		ret = hda_sdw_startup(sdev);
+		if (ret < 0) {
+			dev_err(sdev->dev,
+				"error: could not startup SoundWire links\n");
+			return ret;
+		}
+	}
+
+	hda_sdw_int_enable(sdev, true);
+
+	/*
+	 * The recommended HW programming sequence for ICL is to
+	 * power up core 3 and keep it in stall if HPRO is enabled.
+	 * Major difference between ICL and TGL, on ICL core 3 is managed by
+	 * the host whereas on TGL it is handled by the firmware.
+	 */
+	if (!hda->clk_config_lpro) {
+		ret = snd_sof_dsp_core_power_up(sdev, BIT(3));
+		if (ret < 0) {
+			dev_err(sdev->dev, "error: dsp core power up failed on core 3\n");
+			return ret;
+		}
+
+		snd_sof_dsp_stall(sdev, BIT(3));
+	}
+
+	/* re-enable clock gating and power gating */
+	return hda_dsp_ctrl_clock_power_gating(sdev, true);
+}
+
+int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,
+					 const struct sof_ext_man_elem_header *hdr)
+{
+	const struct sof_ext_man_cavs_config_data *config_data =
+		container_of(hdr, struct sof_ext_man_cavs_config_data, hdr);
+	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+	int i, elem_num;
+
+	/* calculate total number of config data elements */
+	elem_num = (hdr->size - sizeof(struct sof_ext_man_elem_header))
+		   / sizeof(struct sof_config_elem);
+	if (elem_num <= 0) {
+		dev_err(sdev->dev, "cavs config data is inconsistent: %d\n", elem_num);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < elem_num; i++)
+		switch (config_data->elems[i].token) {
+		case SOF_EXT_MAN_CAVS_CONFIG_EMPTY:
+			/* skip empty token */
+			break;
+		case SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO:
+			hda->clk_config_lpro = config_data->elems[i].value;
+			dev_dbg(sdev->dev, "FW clock config: %s\n",
+				hda->clk_config_lpro ? "LPRO" : "HPRO");
+			break;
+		case SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE:
+		case SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE:
+			/* These elements are defined but not being used yet. No warn is required */
+			break;
+		default:
+			dev_info(sdev->dev, "unsupported token type: %d\n",
+				 config_data->elems[i].token);
+		}
+
+	return 0;
+}
+
+int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask)
+{
+	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+	const struct sof_intel_dsp_desc *chip = hda->desc;
+
+	/* make sure core_mask in host managed cores */
+	core_mask &= chip->host_managed_cores_mask;
+	if (!core_mask) {
+		dev_err(sdev->dev, "error: core_mask is not in host managed cores\n");
+		return -EINVAL;
+	}
+
+	/* stall core */
+	snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
+					 HDA_DSP_REG_ADSPCS,
+					 HDA_DSP_ADSPCS_CSTALL_MASK(core_mask),
+					 HDA_DSP_ADSPCS_CSTALL_MASK(core_mask));
+
+	return 0;
+}
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index b527d5958ae5..5d35bb18660a 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -225,6 +225,13 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
 		return -ENODEV;
 	}
 
+	/* minimum as per HDA spec */
+	snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
+
+	/* avoid circular buffer wrap in middle of period */
+	snd_pcm_hw_constraint_integer(substream->runtime,
+				      SNDRV_PCM_HW_PARAM_PERIODS);
+
 	/* binding pcm substream to hda stream */
 	substream->runtime->private_data = &dsp_stream->hstream;
 	return 0;
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index bb4128a72a42..509a9b256423 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -416,9 +416,8 @@ void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags)
 }
 
 /* dump the first 8 dwords representing the extended ROM status */
-static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev)
+static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, u32 flags)
 {
-	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
 	char msg[128];
 	int len = 0;
 	u32 value;
@@ -429,14 +428,13 @@ static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev)
 		len += snprintf(msg + len, sizeof(msg) - len, " 0x%x", value);
 	}
 
-	sof_dev_dbg_or_err(sdev->dev, hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS,
+	sof_dev_dbg_or_err(sdev->dev, flags & SOF_DBG_DUMP_FORCE_ERR_LEVEL,
 			   "extended rom status: %s", msg);
 
 }
 
 void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
 {
-	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
 	struct sof_ipc_dsp_oops_xtensa xoops;
 	struct sof_ipc_panic_info panic_info;
 	u32 stack[HDA_DSP_STACK_DUMP_SIZE];
@@ -456,11 +454,11 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
 		snd_sof_get_status(sdev, status, panic, &xoops, &panic_info,
 				   stack, HDA_DSP_STACK_DUMP_SIZE);
 	} else {
-		sof_dev_dbg_or_err(sdev->dev, hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS,
+		sof_dev_dbg_or_err(sdev->dev, flags & SOF_DBG_DUMP_FORCE_ERR_LEVEL,
 				   "status = 0x%8.8x panic = 0x%8.8x\n",
 				   status, panic);
 
-		hda_dsp_dump_ext_rom_status(sdev);
+		hda_dsp_dump_ext_rom_status(sdev, flags);
 		hda_dsp_get_status(sdev);
 	}
 }
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 1bc4dabdd394..9ec8ae0fd649 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -447,6 +447,9 @@ struct sof_intel_hda_dev {
 
 	/* sdw context allocated by SoundWire driver */
 	struct sdw_intel_ctx *sdw;
+
+	/* FW clock config, 0:HPRO, 1:LPRO */
+	bool clk_config_lpro;
 };
 
 static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s)
@@ -612,11 +615,18 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
  */
 int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev);
 int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev);
+int hda_dsp_cl_boot_firmware_iccmax_icl(struct snd_sof_dev *sdev);
 int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev);
 
 /* pre and post fw run ops */
 int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev);
 int hda_dsp_post_fw_run(struct snd_sof_dev *sdev);
+int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev);
+int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask);
+
+/* parse platform specific ext manifest ops */
+int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,
+					 const struct sof_ext_man_elem_header *hdr);
 
 /*
  * HDA Controller Operations.
@@ -733,6 +743,7 @@ extern struct snd_soc_dai_driver skl_dai[];
 extern const struct snd_sof_dsp_ops sof_apl_ops;
 extern const struct snd_sof_dsp_ops sof_cnl_ops;
 extern const struct snd_sof_dsp_ops sof_tgl_ops;
+extern const struct snd_sof_dsp_ops sof_icl_ops;
 
 extern const struct sof_intel_dsp_desc apl_chip_info;
 extern const struct sof_intel_dsp_desc cnl_chip_info;
@@ -742,6 +753,7 @@ extern const struct sof_intel_dsp_desc tgl_chip_info;
 extern const struct sof_intel_dsp_desc tglh_chip_info;
 extern const struct sof_intel_dsp_desc ehl_chip_info;
 extern const struct sof_intel_dsp_desc jsl_chip_info;
+extern const struct sof_intel_dsp_desc adls_chip_info;
 
 /* machine driver select */
 void hda_machine_select(struct snd_sof_dev *sdev);
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
new file mode 100644
index 000000000000..e9d5a0a58504
--- /dev/null
+++ b/sound/soc/sof/intel/icl.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+//
+// Author: Fred Oh <fred.oh@linux.intel.com>
+//
+
+/*
+ * Hardware interface for audio DSP on IceLake.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kconfig.h>
+#include <linux/export.h>
+#include <linux/bits.h>
+#include "../ops.h"
+#include "hda.h"
+#include "hda-ipc.h"
+#include "../sof-audio.h"
+
+static const struct snd_sof_debugfs_map icl_dsp_debugfs[] = {
+	{"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
+	{"pp", HDA_DSP_PP_BAR,  0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
+	{"dsp", HDA_DSP_BAR,  0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
+};
+
+/* Icelake ops */
+const struct snd_sof_dsp_ops sof_icl_ops = {
+	/* probe and remove */
+	.probe		= hda_dsp_probe,
+	.remove		= hda_dsp_remove,
+
+	/* Register IO */
+	.write		= sof_io_write,
+	.read		= sof_io_read,
+	.write64	= sof_io_write64,
+	.read64		= sof_io_read64,
+
+	/* Block IO */
+	.block_read	= sof_block_read,
+	.block_write	= sof_block_write,
+
+	/* doorbell */
+	.irq_thread	= cnl_ipc_irq_thread,
+
+	/* ipc */
+	.send_msg	= cnl_ipc_send_msg,
+	.fw_ready	= sof_fw_ready,
+	.get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset,
+	.get_window_offset = hda_dsp_ipc_get_window_offset,
+
+	.ipc_msg_data	= hda_ipc_msg_data,
+	.ipc_pcm_params	= hda_ipc_pcm_params,
+
+	/* machine driver */
+	.machine_select = hda_machine_select,
+	.machine_register = sof_machine_register,
+	.machine_unregister = sof_machine_unregister,
+	.set_mach_params = hda_set_mach_params,
+
+	/* debug */
+	.debug_map	= icl_dsp_debugfs,
+	.debug_map_count	= ARRAY_SIZE(icl_dsp_debugfs),
+	.dbg_dump	= hda_dsp_dump,
+	.ipc_dump	= cnl_ipc_dump,
+
+	/* stream callbacks */
+	.pcm_open	= hda_dsp_pcm_open,
+	.pcm_close	= hda_dsp_pcm_close,
+	.pcm_hw_params	= hda_dsp_pcm_hw_params,
+	.pcm_hw_free	= hda_dsp_stream_hw_free,
+	.pcm_trigger	= hda_dsp_pcm_trigger,
+	.pcm_pointer	= hda_dsp_pcm_pointer,
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
+	/* probe callbacks */
+	.probe_assign	= hda_probe_compr_assign,
+	.probe_free	= hda_probe_compr_free,
+	.probe_set_params	= hda_probe_compr_set_params,
+	.probe_trigger	= hda_probe_compr_trigger,
+	.probe_pointer	= hda_probe_compr_pointer,
+#endif
+
+	/* firmware loading */
+	.load_firmware = snd_sof_load_firmware_raw,
+
+	/* pre/post fw run */
+	.pre_fw_run = hda_dsp_pre_fw_run,
+	.post_fw_run = hda_dsp_post_fw_run_icl,
+
+	/* parse platform specific extended manifest */
+	.parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
+
+	/* dsp core power up/down */
+	.core_power_up = hda_dsp_enable_core,
+	.core_power_down = hda_dsp_core_reset_power_down,
+
+	/* firmware run */
+	.run = hda_dsp_cl_boot_firmware_iccmax,
+	.stall = hda_dsp_core_stall_icl,
+
+	/* trace callback */
+	.trace_init = hda_dsp_trace_init,
+	.trace_release = hda_dsp_trace_release,
+	.trace_trigger = hda_dsp_trace_trigger,
+
+	/* DAI drivers */
+	.drv		= skl_dai,
+	.num_drv	= SOF_SKL_NUM_DAIS,
+
+	/* PM */
+	.suspend		= hda_dsp_suspend,
+	.resume			= hda_dsp_resume,
+	.runtime_suspend	= hda_dsp_runtime_suspend,
+	.runtime_resume		= hda_dsp_runtime_resume,
+	.runtime_idle		= hda_dsp_runtime_idle,
+	.set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume,
+	.set_power_state	= hda_dsp_set_power_state,
+
+	/* ALSA HW info flags */
+	.hw_info =	SNDRV_PCM_INFO_MMAP |
+			SNDRV_PCM_INFO_MMAP_VALID |
+			SNDRV_PCM_INFO_INTERLEAVED |
+			SNDRV_PCM_INFO_PAUSE |
+			SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+
+	.arch_ops = &sof_xtensa_arch_ops,
+};
+EXPORT_SYMBOL_NS(sof_icl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+const struct sof_intel_dsp_desc icl_chip_info = {
+	/* Icelake */
+	.cores_num = 4,
+	.init_core_mask = 1,
+	.host_managed_cores_mask = GENMASK(3, 0),
+	.ipc_req = CNL_DSP_REG_HIPCIDR,
+	.ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
+	.ipc_ack = CNL_DSP_REG_HIPCIDA,
+	.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
+	.ipc_ctl = CNL_DSP_REG_HIPCCTL,
+	.rom_init_timeout	= 300,
+	.ssp_count = ICL_SSP_COUNT,
+	.ssp_base_offset = CNL_SSP_BASE_OFFSET,
+};
+EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/intel/intel-ipc.c b/sound/soc/sof/intel/intel-ipc.c
index 310f9168c124..de66f8a82a07 100644
--- a/sound/soc/sof/intel/intel-ipc.c
+++ b/sound/soc/sof/intel/intel-ipc.c
@@ -73,6 +73,13 @@ int intel_pcm_open(struct snd_sof_dev *sdev,
 	/* binding pcm substream to hda stream */
 	substream->runtime->private_data = stream;
 
+	/* align to DMA minimum transfer size */
+	snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
+
+	/* avoid circular buffer wrap in middle of period */
+	snd_pcm_hw_constraint_integer(substream->runtime,
+				      SNDRV_PCM_HW_PARAM_PERIODS);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS(intel_pcm_open, SND_SOC_SOF_INTEL_HIFI_EP_IPC);
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index 0278b67de1ec..2252ca38ff4b 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -84,6 +84,9 @@ const struct snd_sof_dsp_ops sof_tgl_ops = {
 	.pre_fw_run = hda_dsp_pre_fw_run,
 	.post_fw_run = hda_dsp_post_fw_run,
 
+	/* parse platform specific extended manifest */
+	.parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
+
 	/* dsp core power up/down */
 	.core_power_up = hda_dsp_enable_core,
 	.core_power_down = hda_dsp_core_reset_power_down,
@@ -151,3 +154,19 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
 	.ssp_base_offset = CNL_SSP_BASE_OFFSET,
 };
 EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+const struct sof_intel_dsp_desc adls_chip_info = {
+	/* Alderlake-S */
+	.cores_num = 2,
+	.init_core_mask = BIT(0),
+	.host_managed_cores_mask = BIT(0),
+	.ipc_req = CNL_DSP_REG_HIPCIDR,
+	.ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
+	.ipc_ack = CNL_DSP_REG_HIPCIDA,
+	.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
+	.ipc_ctl = CNL_DSP_REG_HIPCCTL,
+	.rom_init_timeout	= 300,
+	.ssp_count = ICL_SSP_COUNT,
+	.ssp_base_offset = CNL_SSP_BASE_OFFSET,
+};
+EXPORT_SYMBOL_NS(adls_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
index fd2b96ae4943..fc13bb06dbf3 100644
--- a/sound/soc/sof/ipc.c
+++ b/sound/soc/sof/ipc.c
@@ -181,6 +181,15 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
 			str2 = "unknown type"; break;
 		}
 		break;
+	case SOF_IPC_GLB_DEBUG:
+		str = "GLB_DEBUG";
+		switch (type) {
+		case SOF_IPC_DEBUG_MEM_USAGE:
+			str2 = "MEM_USAGE"; break;
+		default:
+			str2 = "unknown type"; break;
+		}
+		break;
 	default:
 		str = "unknown GLB command"; break;
 	}
diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c
index ba9ed66f98bc..08a17abb63ff 100644
--- a/sound/soc/sof/loader.c
+++ b/sound/soc/sof/loader.c
@@ -124,7 +124,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
 			/* They are supported but we don't do anything here */
 			break;
 		default:
-			dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n",
+			dev_info(sdev->dev, "unknown ext header type %d size 0x%x\n",
 				 ext_hdr->type, ext_hdr->hdr.size);
 			ret = 0;
 			break;
@@ -197,6 +197,54 @@ static int ext_man_get_dbg_abi_info(struct snd_sof_dev *sdev,
 	return 0;
 }
 
+static int ext_man_get_config_data(struct snd_sof_dev *sdev,
+				   const struct sof_ext_man_elem_header *hdr)
+{
+	const struct sof_ext_man_config_data *config =
+		container_of(hdr, struct sof_ext_man_config_data, hdr);
+	const struct sof_config_elem *elem;
+	int elems_counter;
+	int elems_size;
+	int ret = 0;
+	int i;
+
+	/* calculate elements counter */
+	elems_size = config->hdr.size - sizeof(struct sof_ext_man_elem_header);
+	elems_counter = elems_size / sizeof(struct sof_config_elem);
+
+	dev_dbg(sdev->dev, "%s can hold up to %d config elements\n",
+		__func__, elems_counter);
+
+	for (i = 0; i < elems_counter; ++i) {
+		elem = &config->elems[i];
+		dev_dbg(sdev->dev, "%s get index %d token %d val %d\n",
+			__func__, i, elem->token, elem->value);
+		switch (elem->token) {
+		case SOF_EXT_MAN_CONFIG_EMPTY:
+			/* unused memory space is zero filled - mapped to EMPTY elements */
+			break;
+		case SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE:
+			/* TODO: use ipc msg size from config data */
+			break;
+		case SOF_EXT_MAN_CONFIG_MEMORY_USAGE_SCAN:
+			if (sdev->first_boot && elem->value)
+				ret = snd_sof_dbg_memory_info_init(sdev);
+			break;
+		default:
+			dev_info(sdev->dev, "Unknown firmware configuration token %d value %d",
+				 elem->token, elem->value);
+			break;
+		}
+		if (ret < 0) {
+			dev_err(sdev->dev, "error: processing sof_ext_man_config_data failed for token %d value 0x%x, %d\n",
+				elem->token, elem->value, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 static ssize_t snd_sof_ext_man_size(const struct firmware *fw)
 {
 	const struct sof_ext_man_header *head;
@@ -279,8 +327,14 @@ static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev,
 		case SOF_EXT_MAN_ELEM_DBG_ABI:
 			ret = ext_man_get_dbg_abi_info(sdev, elem_hdr);
 			break;
+		case SOF_EXT_MAN_ELEM_CONFIG_DATA:
+			ret = ext_man_get_config_data(sdev, elem_hdr);
+			break;
+		case SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA:
+			ret = snd_sof_dsp_parse_platform_ext_manifest(sdev, elem_hdr);
+			break;
 		default:
-			dev_warn(sdev->dev, "warning: unknown sof_ext_man header type %d size 0x%X\n",
+			dev_info(sdev->dev, "unknown sof_ext_man header type %d size 0x%X\n",
 				 elem_hdr->type, elem_hdr->size);
 			break;
 		}
@@ -802,8 +856,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
 				 msecs_to_jiffies(sdev->boot_timeout));
 	if (ret == 0) {
 		dev_err(sdev->dev, "error: firmware boot failure\n");
-		snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
-			SOF_DBG_TEXT | SOF_DBG_PCI);
+		snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX |
+			SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_FORCE_ERR_LEVEL);
 		sdev->fw_state = SOF_FW_BOOT_FAILED;
 		return -EIO;
 	}
diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c
index 9e922df6a710..3b9bb2e83a86 100644
--- a/sound/soc/sof/nocodec.c
+++ b/sound/soc/sof/nocodec.c
@@ -10,17 +10,21 @@
 
 #include <linux/module.h>
 #include <sound/sof.h>
+#include "sof-audio.h"
 #include "sof-priv.h"
 
 static struct snd_soc_card sof_nocodec_card = {
 	.name = "nocodec", /* the sof- prefix is added by the core */
+	.topology_shortname = "sof-nocodec",
 	.owner = THIS_MODULE
 };
 
 static int sof_nocodec_bes_setup(struct device *dev,
 				 const struct snd_sof_dsp_ops *ops,
 				 struct snd_soc_dai_link *links,
-				 int link_num, struct snd_soc_card *card)
+				 int link_num, struct snd_soc_card *card,
+				 int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd,
+							   struct snd_pcm_hw_params *params))
 {
 	struct snd_soc_dai_link_component *dlc;
 	int i;
@@ -39,6 +43,8 @@ static int sof_nocodec_bes_setup(struct device *dev,
 		if (!links[i].name)
 			return -ENOMEM;
 
+		links[i].stream_name = links[i].name;
+
 		links[i].cpus = &dlc[0];
 		links[i].codecs = &dlc[1];
 		links[i].platforms = &dlc[2];
@@ -57,6 +63,8 @@ static int sof_nocodec_bes_setup(struct device *dev,
 			links[i].dpcm_playback = 1;
 		if (ops->drv[i].capture.channels_min)
 			links[i].dpcm_capture = 1;
+
+		links[i].be_hw_params_fixup = pcm_dai_link_fixup;
 	}
 
 	card->dai_link = links;
@@ -65,8 +73,9 @@ static int sof_nocodec_bes_setup(struct device *dev,
 	return 0;
 }
 
-int sof_nocodec_setup(struct device *dev,
-		      const struct snd_sof_dsp_ops *ops)
+int sof_nocodec_setup(struct device *dev, const struct snd_sof_dsp_ops *ops,
+		      int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd,
+						struct snd_pcm_hw_params *params))
 {
 	struct snd_soc_dai_link *links;
 
@@ -77,7 +86,7 @@ int sof_nocodec_setup(struct device *dev,
 		return -ENOMEM;
 
 	return sof_nocodec_bes_setup(dev, ops, links, ops->num_drv,
-				     &sof_nocodec_card);
+				     &sof_nocodec_card, pcm_dai_link_fixup);
 }
 EXPORT_SYMBOL(sof_nocodec_setup);
 
@@ -86,6 +95,7 @@ static int sof_nocodec_probe(struct platform_device *pdev)
 	struct snd_soc_card *card = &sof_nocodec_card;
 
 	card->dev = &pdev->dev;
+	card->topology_shortname_created = true;
 
 	return devm_snd_soc_register_card(&pdev->dev, card);
 }
diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c
index 1a394b4c6a2f..11ecebd07907 100644
--- a/sound/soc/sof/ops.c
+++ b/sound/soc/sof/ops.c
@@ -157,7 +157,7 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset)
 		dev_dbg(sdev->dev, "panic: dsp_oops_offset %zu offset %d\n",
 			sdev->dsp_oops_offset, offset);
 
-	snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
+	snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
 	snd_sof_trace_notify_for_error(sdev);
 }
 EXPORT_SYMBOL(snd_sof_dsp_panic);
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
index b21632f5511a..95e748b36903 100644
--- a/sound/soc/sof/ops.h
+++ b/sound/soc/sof/ops.h
@@ -48,10 +48,10 @@ static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev)
 	return sof_ops(sdev)->run(sdev);
 }
 
-static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev)
+static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev, unsigned int core_mask)
 {
 	if (sof_ops(sdev)->stall)
-		return sof_ops(sdev)->stall(sdev);
+		return sof_ops(sdev)->stall(sdev, core_mask);
 
 	return 0;
 }
@@ -100,6 +100,16 @@ static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev)
 	return 0;
 }
 
+/* parse platform specific extended manifest */
+static inline int snd_sof_dsp_parse_platform_ext_manifest(struct snd_sof_dev *sdev,
+							  const struct sof_ext_man_elem_header *hdr)
+{
+	if (sof_ops(sdev)->parse_platform_ext_manifest)
+		return sof_ops(sdev)->parse_platform_ext_manifest(sdev, hdr);
+
+	return 0;
+}
+
 /* misc */
 
 /**
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index cbac6f17c52f..0dc39fbcd81d 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -478,17 +478,10 @@ static int sof_pcm_open(struct snd_soc_component *component,
 
 	caps = &spcm->pcm.caps[substream->stream];
 
-	/* set any runtime constraints based on topology */
-	snd_pcm_hw_constraint_step(substream->runtime, 0,
-				   SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
-				   le32_to_cpu(caps->period_size_min));
-	snd_pcm_hw_constraint_step(substream->runtime, 0,
-				   SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
-				   le32_to_cpu(caps->period_size_min));
-
 	/* set runtime config */
 	runtime->hw.info = ops->hw_info; /* platform-specific */
 
+	/* set any runtime constraints based on topology */
 	runtime->hw.formats = le64_to_cpu(caps->formats);
 	runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min);
 	runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max);
@@ -627,8 +620,7 @@ capture:
 }
 
 /* fixup the BE DAI link to match any values from topology */
-static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
-				  struct snd_pcm_hw_params *params)
+int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params)
 {
 	struct snd_interval *rate = hw_param_interval(params,
 			SNDRV_PCM_HW_PARAM_RATE);
@@ -780,7 +772,7 @@ static int sof_pcm_probe(struct snd_soc_component *component)
 static void sof_pcm_remove(struct snd_soc_component *component)
 {
 	/* remove topology */
-	snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
+	snd_soc_tplg_component_remove(component);
 }
 
 void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c
index a78b76ef37b2..2a369c2c6551 100644
--- a/sound/soc/sof/sof-acpi-dev.c
+++ b/sound/soc/sof/sof-acpi-dev.c
@@ -12,6 +12,7 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <sound/intel-dsp-config.h>
 #include <sound/soc-acpi.h>
 #include <sound/soc-acpi-intel-match.h>
 #include <sound/sof.h>
@@ -120,12 +121,23 @@ static void sof_acpi_probe_complete(struct device *dev)
 static int sof_acpi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	const struct acpi_device_id *id;
 	const struct sof_dev_desc *desc;
 	struct snd_sof_pdata *sof_pdata;
 	const struct snd_sof_dsp_ops *ops;
 	int ret;
 
-	dev_dbg(&pdev->dev, "ACPI DSP detected");
+	id = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (!id)
+		return -ENODEV;
+
+	ret = snd_intel_acpi_dsp_driver_probe(dev, id->id);
+	if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) {
+		dev_dbg(dev, "SOF ACPI driver not selected, aborting probe\n");
+		return -ENODEV;
+	}
+
+	dev_dbg(dev, "ACPI DSP detected");
 
 	sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
 	if (!sof_pdata)
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index afe7e503bf66..3277489fee5e 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -443,11 +443,7 @@ int sof_machine_check(struct snd_sof_dev *sdev)
 	struct snd_soc_acpi_mach *mach;
 	int ret;
 
-	/* force nocodec mode */
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
-		dev_warn(sdev->dev, "Force to use nocodec mode\n");
-		goto nocodec;
-#endif
+#if !IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
 
 	/* find machine */
 	snd_sof_machine_select(sdev);
@@ -460,8 +456,8 @@ int sof_machine_check(struct snd_sof_dev *sdev)
 	dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
 	return -ENODEV;
 #endif
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
-nocodec:
+#else
+	dev_warn(sdev->dev, "Force to use nocodec mode\n");
 #endif
 	/* select nocodec mode */
 	dev_warn(sdev->dev, "Using nocodec machine driver\n");
@@ -472,7 +468,7 @@ nocodec:
 	mach->drv_name = "sof-nocodec";
 	sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
 
-	ret = sof_nocodec_setup(sdev->dev, desc->ops);
+	ret = sof_nocodec_setup(sdev->dev, desc->ops, sof_pcm_dai_link_fixup);
 	if (ret < 0)
 		return ret;
 
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 9f645a2e5a6c..dc930fc2f4b5 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -124,6 +124,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_value *ucontrol);
 int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_value *ucontrol);
+int snd_sof_volume_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo);
 int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_value *ucontrol);
 int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
@@ -212,6 +214,9 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
 				  enum sof_ipc_ctrl_cmd ctrl_cmd,
 				  bool send);
 
+/* DAI link fixup */
+int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params);
+
 /* PM */
 int sof_restore_pipelines(struct device *dev);
 int sof_set_hw_params_upon_resume(struct device *dev);
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index 8f62e3487dc1..63b989e3ec40 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -209,7 +209,7 @@ static const struct sof_dev_desc icl_desc = {
 	.default_tplg_path = "intel/sof-tplg",
 	.default_fw_filename = "sof-icl.ri",
 	.nocodec_tplg_filename = "sof-icl-nocodec.tplg",
-	.ops = &sof_cnl_ops,
+	.ops = &sof_icl_ops,
 };
 #endif
 
@@ -284,6 +284,24 @@ static const struct sof_dev_desc jsl_desc = {
 };
 #endif
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
+static const struct sof_dev_desc adls_desc = {
+	.machines               = snd_soc_acpi_intel_adl_machines,
+	.alt_machines           = snd_soc_acpi_intel_adl_sdw_machines,
+	.resindex_lpe_base      = 0,
+	.resindex_pcicfg_base   = -1,
+	.resindex_imr_base      = -1,
+	.irqindex_host_ipc      = -1,
+	.resindex_dma_base      = -1,
+	.chip_info = &adls_chip_info,
+	.default_fw_path = "intel/sof",
+	.default_tplg_path = "intel/sof-tplg",
+	.default_fw_filename = "sof-adl-s.ri",
+	.nocodec_tplg_filename = "sof-adl-nocodec.tplg",
+	.ops = &sof_tgl_ops,
+};
+#endif
+
 static const struct dev_pm_ops sof_pci_pm = {
 	.prepare = snd_sof_prepare,
 	.complete = snd_sof_complete,
@@ -491,6 +509,10 @@ static const struct pci_device_id sof_pci_ids[] = {
 	{ PCI_DEVICE(0x8086, 0x4b58),
 		.driver_data = (unsigned long)&ehl_desc},
 #endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
+	{ PCI_DEVICE(0x8086, 0x7ad0),
+		.driver_data = (unsigned long)&adls_desc},
+#endif
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, sof_pci_ids);
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index 0aed2a7ab858..68da8f797403 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -18,14 +18,18 @@
 #include <sound/sof/pm.h>
 #include <sound/sof/trace.h>
 #include <uapi/sound/sof/fw.h>
+#include <sound/sof/ext_manifest.h>
 
 /* debug flags */
 #define SOF_DBG_ENABLE_TRACE	BIT(0)
-#define SOF_DBG_REGS		BIT(1)
-#define SOF_DBG_MBOX		BIT(2)
-#define SOF_DBG_TEXT		BIT(3)
-#define SOF_DBG_PCI		BIT(4)
-#define SOF_DBG_RETAIN_CTX	BIT(5)	/* prevent DSP D3 on FW exception */
+#define SOF_DBG_RETAIN_CTX	BIT(1)	/* prevent DSP D3 on FW exception */
+
+#define SOF_DBG_DUMP_REGS		BIT(0)
+#define SOF_DBG_DUMP_MBOX		BIT(1)
+#define SOF_DBG_DUMP_TEXT		BIT(2)
+#define SOF_DBG_DUMP_PCI		BIT(3)
+#define SOF_DBG_DUMP_FORCE_ERR_LEVEL	BIT(4) /* used to dump dsp status with error log level */
+
 
 /* global debug state set by SOF_DBG_ flags */
 extern int sof_core_debug;
@@ -100,7 +104,7 @@ struct snd_sof_dsp_ops {
 
 	/* DSP core boot / reset */
 	int (*run)(struct snd_sof_dev *sof_dev); /* mandatory */
-	int (*stall)(struct snd_sof_dev *sof_dev); /* optional */
+	int (*stall)(struct snd_sof_dev *sof_dev, unsigned int core_mask); /* optional */
 	int (*reset)(struct snd_sof_dev *sof_dev); /* optional */
 	int (*core_power_up)(struct snd_sof_dev *sof_dev,
 			     unsigned int core_mask); /* optional */
@@ -208,6 +212,10 @@ struct snd_sof_dsp_ops {
 	int (*pre_fw_run)(struct snd_sof_dev *sof_dev); /* optional */
 	int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */
 
+	/* parse platform specific extended manifest, optional */
+	int (*parse_platform_ext_manifest)(struct snd_sof_dev *sof_dev,
+					   const struct sof_ext_man_elem_header *hdr);
+
 	/* DSP PM */
 	int (*suspend)(struct snd_sof_dev *sof_dev,
 		       u32 target_state); /* optional */
@@ -290,6 +298,7 @@ enum sof_debugfs_access_type {
 /* FS entry for debug files that can expose DSP memories, registers */
 struct snd_sof_dfsentry {
 	size_t size;
+	size_t buf_data_size;  /* length of buffered data for file read operation */
 	enum sof_dfsentry_type type;
 	/*
 	 * access_type specifies if the
@@ -523,6 +532,7 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code,
 			void *stack, size_t stack_words);
 int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev);
 void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev);
+int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev);
 
 /*
  * Platform specific ops.
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 69313fbdb636..b6b32a7a91f8 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -1041,6 +1041,15 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
 		goto out;
 	}
 
+	/*
+	 * If control has more than 2 channels we need to override the info. This is because even if
+	 * ASoC layer has defined topology's max channel count to SND_SOC_TPLG_MAX_CHAN = 8, the
+	 * pre-defined dapm control types (and related functions) creating the actual control
+	 * restrict the channels only to mono or stereo.
+	 */
+	if (le32_to_cpu(mc->num_channels) > 2)
+		kc->info = snd_sof_volume_info;
+
 	/* init the volume get/put data */
 	scontrol->size = struct_size(scontrol->control_data, chanv,
 				     le32_to_cpu(mc->num_channels));
@@ -1201,7 +1210,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp,
 			ret = -EINVAL;
 			goto out_free;
 		}
-		if (cdata->data->size + sizeof(const struct sof_abi_hdr) !=
+		if (cdata->data->size + sizeof(struct sof_abi_hdr) !=
 		    le32_to_cpu(control->priv.size)) {
 			dev_err(scomp->dev,
 				"error: Conflict in bytes vs. priv size.\n");
@@ -2777,18 +2786,18 @@ static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config,
 			       struct sof_ipc_dai_config *config)
 {
 	/* clock directions wrt codec */
-	if (hw_config->bclk_master == SND_SOC_TPLG_BCLK_CM) {
-		/* codec is bclk master */
-		if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM)
-			config->format |= SOF_DAI_FMT_CBM_CFM;
+	if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CP) {
+		/* codec is bclk provider */
+		if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
+			config->format |= SOF_DAI_FMT_CBP_CFP;
 		else
-			config->format |= SOF_DAI_FMT_CBM_CFS;
+			config->format |= SOF_DAI_FMT_CBP_CFC;
 	} else {
-		/* codec is bclk slave */
-		if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM)
-			config->format |= SOF_DAI_FMT_CBS_CFM;
+		/* codec is bclk consumer */
+		if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
+			config->format |= SOF_DAI_FMT_CBC_CFP;
 		else
-			config->format |= SOF_DAI_FMT_CBS_CFS;
+			config->format |= SOF_DAI_FMT_CBC_CFC;
 	}
 
 	/* inverted clocks ? */
@@ -3734,9 +3743,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
 		return ret;
 	}
 
-	ret = snd_soc_tplg_component_load(scomp,
-					  &sof_tplg_ops, fw,
-					  SND_SOC_TPLG_INDEX_ALL);
+	ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw);
 	if (ret < 0) {
 		dev_err(scomp->dev, "error: tplg component load failed %d\n",
 			ret);
diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c
index 69889241a092..f72a6e83e6af 100644
--- a/sound/soc/sof/trace.c
+++ b/sound/soc/sof/trace.c
@@ -13,6 +13,225 @@
 #include "sof-priv.h"
 #include "ops.h"
 
+#define TRACE_FILTER_ELEMENTS_PER_ENTRY 4
+#define TRACE_FILTER_MAX_CONFIG_STRING_LENGTH 1024
+
+static int trace_filter_append_elem(struct snd_sof_dev *sdev, uint32_t key, uint32_t value,
+				    struct sof_ipc_trace_filter_elem *elem_list,
+				    int capacity, int *counter)
+{
+	if (*counter >= capacity)
+		return -ENOMEM;
+
+	elem_list[*counter].key = key;
+	elem_list[*counter].value = value;
+	++*counter;
+
+	return 0;
+}
+
+static int trace_filter_parse_entry(struct snd_sof_dev *sdev, const char *line,
+				    struct sof_ipc_trace_filter_elem *elem,
+				    int capacity, int *counter)
+{
+	int len = strlen(line);
+	int cnt = *counter;
+	uint32_t uuid_id;
+	int log_level;
+	int pipe_id;
+	int comp_id;
+	int read;
+	int ret;
+
+	/* ignore empty content */
+	ret = sscanf(line, " %n", &read);
+	if (!ret && read == len)
+		return len;
+
+	ret = sscanf(line, " %d %x %d %d %n", &log_level, &uuid_id, &pipe_id, &comp_id, &read);
+	if (ret != TRACE_FILTER_ELEMENTS_PER_ENTRY || read != len) {
+		dev_err(sdev->dev, "error: invalid trace filter entry '%s'\n", line);
+		return -EINVAL;
+	}
+
+	if (uuid_id > 0) {
+		ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_UUID,
+					       uuid_id, elem, capacity, &cnt);
+		if (ret)
+			return ret;
+	}
+	if (pipe_id >= 0) {
+		ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_PIPE,
+					       pipe_id, elem, capacity, &cnt);
+		if (ret)
+			return ret;
+	}
+	if (comp_id >= 0) {
+		ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_COMP,
+					       comp_id, elem, capacity, &cnt);
+		if (ret)
+			return ret;
+	}
+
+	ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_SET_LEVEL |
+				       SOF_IPC_TRACE_FILTER_ELEM_FIN,
+				       log_level, elem, capacity, &cnt);
+	if (ret)
+		return ret;
+
+	/* update counter only when parsing whole entry passed */
+	*counter = cnt;
+
+	return len;
+}
+
+static int trace_filter_parse(struct snd_sof_dev *sdev, char *string,
+			      int *out_elem_cnt,
+			      struct sof_ipc_trace_filter_elem **out)
+{
+	static const char entry_delimiter[] = ";";
+	char *entry = string;
+	int capacity = 0;
+	int entry_len;
+	int cnt = 0;
+
+	/*
+	 * Each entry contains at least 1, up to TRACE_FILTER_ELEMENTS_PER_ENTRY
+	 * IPC elements, depending on content. Calculate IPC elements capacity
+	 * for the input string where each element is set.
+	 */
+	while (entry) {
+		capacity += TRACE_FILTER_ELEMENTS_PER_ENTRY;
+		entry = strchr(entry + 1, entry_delimiter[0]);
+	}
+	*out = kmalloc(capacity * sizeof(**out), GFP_KERNEL);
+	if (!*out)
+		return -ENOMEM;
+
+	/* split input string by ';', and parse each entry separately in trace_filter_parse_entry */
+	while ((entry = strsep(&string, entry_delimiter))) {
+		entry_len = trace_filter_parse_entry(sdev, entry, *out, capacity, &cnt);
+		if (entry_len < 0) {
+			dev_err(sdev->dev, "error: %s failed for '%s', %d\n", __func__, entry,
+				entry_len);
+			return -EINVAL;
+		}
+	}
+
+	*out_elem_cnt = cnt;
+
+	return 0;
+}
+
+static int sof_ipc_trace_update_filter(struct snd_sof_dev *sdev, int num_elems,
+				       struct sof_ipc_trace_filter_elem *elems)
+{
+	struct sof_ipc_trace_filter *msg;
+	struct sof_ipc_reply reply;
+	size_t size;
+	int ret;
+
+	size = struct_size(msg, elems, num_elems);
+	if (size > SOF_IPC_MSG_MAX_SIZE)
+		return -EINVAL;
+
+	msg = kmalloc(size, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	msg->hdr.size = size;
+	msg->hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_FILTER_UPDATE;
+	msg->elem_cnt = num_elems;
+	memcpy(&msg->elems[0], elems, num_elems * sizeof(*elems));
+
+	ret = pm_runtime_get_sync(sdev->dev);
+	if (ret < 0 && ret != -EACCES) {
+		pm_runtime_put_noidle(sdev->dev);
+		dev_err(sdev->dev, "error: enabling device failed: %d\n", ret);
+		goto error;
+	}
+	ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
+				 &reply, sizeof(reply));
+	pm_runtime_mark_last_busy(sdev->dev);
+	pm_runtime_put_autosuspend(sdev->dev);
+
+error:
+	kfree(msg);
+	return ret ? ret : reply.error;
+}
+
+static ssize_t sof_dfsentry_trace_filter_write(struct file *file, const char __user *from,
+					       size_t count, loff_t *ppos)
+{
+	struct snd_sof_dfsentry *dfse = file->private_data;
+	struct sof_ipc_trace_filter_elem *elems = NULL;
+	struct snd_sof_dev *sdev = dfse->sdev;
+	loff_t pos = 0;
+	int num_elems;
+	char *string;
+	int ret;
+
+	if (count > TRACE_FILTER_MAX_CONFIG_STRING_LENGTH) {
+		dev_err(sdev->dev, "%s too long input, %zu > %d\n", __func__, count,
+			TRACE_FILTER_MAX_CONFIG_STRING_LENGTH);
+		return -EINVAL;
+	}
+
+	string = kmalloc(count + 1, GFP_KERNEL);
+	if (!string)
+		return -ENOMEM;
+
+	/* assert null termination */
+	string[count] = 0;
+	ret = simple_write_to_buffer(string, count, &pos, from, count);
+	if (ret < 0)
+		goto error;
+
+	ret = trace_filter_parse(sdev, string, &num_elems, &elems);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: fail in trace_filter_parse, %d\n", ret);
+		goto error;
+	}
+
+	if (num_elems) {
+		ret = sof_ipc_trace_update_filter(sdev, num_elems, elems);
+		if (ret < 0) {
+			dev_err(sdev->dev, "error: fail in sof_ipc_trace_update_filter %d\n", ret);
+			goto error;
+		}
+	}
+	ret = count;
+error:
+	kfree(string);
+	kfree(elems);
+	return ret;
+}
+
+static const struct file_operations sof_dfs_trace_filter_fops = {
+	.open = simple_open,
+	.write = sof_dfsentry_trace_filter_write,
+	.llseek = default_llseek,
+};
+
+static int trace_debugfs_filter_create(struct snd_sof_dev *sdev)
+{
+	struct snd_sof_dfsentry *dfse;
+
+	dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
+	if (!dfse)
+		return -ENOMEM;
+
+	dfse->sdev = sdev;
+	dfse->type = SOF_DFSENTRY_TYPE_BUF;
+
+	debugfs_create_file("filter", 0200, sdev->debugfs_root, dfse,
+			    &sof_dfs_trace_filter_fops);
+	/* add to dfsentry list */
+	list_add(&dfse->list, &sdev->dfsentry_list);
+
+	return 0;
+}
+
 static size_t sof_trace_avail(struct snd_sof_dev *sdev,
 			      loff_t pos, size_t buffer_size)
 {
@@ -135,10 +354,15 @@ static const struct file_operations sof_dfs_trace_fops = {
 static int trace_debugfs_create(struct snd_sof_dev *sdev)
 {
 	struct snd_sof_dfsentry *dfse;
+	int ret;
 
 	if (!sdev)
 		return -EINVAL;
 
+	ret = trace_debugfs_filter_create(sdev);
+	if (ret < 0)
+		dev_err(sdev->dev, "error: fail in %s, %d", __func__, ret);
+
 	dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
 	if (!dfse)
 		return -ENOMEM;
diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig
index bbade257fe89..da1f7a16605b 100644
--- a/sound/soc/stm/Kconfig
+++ b/sound/soc/stm/Kconfig
@@ -15,6 +15,7 @@ config SND_SOC_STM32_SAI
 config SND_SOC_STM32_I2S
 	tristate "STM32 I2S interface (SPI/I2S block) support"
 	depends on (ARCH_STM32 && OF) || COMPILE_TEST
+	depends on COMMON_CLK
 	depends on SND_SOC
 	select SND_SOC_GENERIC_DMAENGINE_PCM
 	select REGMAP_MMIO
diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 9cd7009cb570..ddcaaa98d3cb 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -14,6 +14,7 @@ config SND_SUN8I_CODEC
 	tristate "Allwinner SUN8I audio codec"
 	depends on OF
 	depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+	depends on COMMON_CLK
 	select REGMAP_MMIO
 	help
 	  This option enables the digital part of the internal audio codec for
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index f23ff29e7c1d..4b8ca5be0a29 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -48,6 +48,9 @@
 #define SUN4I_I2S_FMT0_FMT_I2S				(0 << 0)
 
 #define SUN4I_I2S_FMT1_REG		0x08
+#define SUN4I_I2S_FMT1_REG_SEXT_MASK		BIT(8)
+#define SUN4I_I2S_FMT1_REG_SEXT(sext)			((sext) << 8)
+
 #define SUN4I_I2S_FIFO_TX_REG		0x0c
 #define SUN4I_I2S_FIFO_RX_REG		0x10
 
@@ -105,6 +108,9 @@
 #define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED		(1 << 7)
 #define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL		(0 << 7)
 
+#define SUN8I_I2S_FMT1_REG_SEXT_MASK		GENMASK(5, 4)
+#define SUN8I_I2S_FMT1_REG_SEXT(sext)			((sext) << 4)
+
 #define SUN8I_I2S_INT_STA_REG		0x0c
 #define SUN8I_I2S_FIFO_TX_REG		0x20
 
@@ -124,6 +130,21 @@
 #define SUN8I_I2S_RX_CHAN_SEL_REG	0x54
 #define SUN8I_I2S_RX_CHAN_MAP_REG	0x58
 
+/* Defines required for sun50i-h6 support */
+#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK	GENMASK(21, 20)
+#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset)	((offset) << 20)
+#define SUN50I_H6_I2S_TX_CHAN_SEL_MASK		GENMASK(19, 16)
+#define SUN50I_H6_I2S_TX_CHAN_SEL(chan)		((chan - 1) << 16)
+#define SUN50I_H6_I2S_TX_CHAN_EN_MASK		GENMASK(15, 0)
+#define SUN50I_H6_I2S_TX_CHAN_EN(num_chan)	(((1 << num_chan) - 1))
+
+#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG	0x44
+#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG	0x48
+
+#define SUN50I_H6_I2S_RX_CHAN_SEL_REG	0x64
+#define SUN50I_H6_I2S_RX_CHAN_MAP0_REG	0x68
+#define SUN50I_H6_I2S_RX_CHAN_MAP1_REG	0x6C
+
 struct sun4i_i2s;
 
 /**
@@ -159,12 +180,19 @@ struct sun4i_i2s_quirks {
 	const struct sun4i_i2s_clk_div	*mclk_dividers;
 	unsigned int			num_mclk_dividers;
 
-	unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *);
-	s8	(*get_sr)(const struct sun4i_i2s *, int);
-	s8	(*get_wss)(const struct sun4i_i2s *, int);
-	int	(*set_chan_cfg)(const struct sun4i_i2s *,
-				const struct snd_pcm_hw_params *);
-	int	(*set_fmt)(const struct sun4i_i2s *, unsigned int);
+	unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *i2s);
+	int	(*get_sr)(unsigned int width);
+	int	(*get_wss)(unsigned int width);
+
+	/*
+	 * In the set_chan_cfg() function pointer:
+	 * @slots: channels per frame + padding slots, regardless of format
+	 * @slot_width: bits per sample + padding bits, regardless of format
+	 */
+	int	(*set_chan_cfg)(const struct sun4i_i2s *i2s,
+				unsigned int channels,	unsigned int slots,
+				unsigned int slot_width);
+	int	(*set_fmt)(const struct sun4i_i2s *i2s, unsigned int fmt);
 };
 
 struct sun4i_i2s {
@@ -365,44 +393,62 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
 	return 0;
 }
 
-static s8 sun4i_i2s_get_sr(const struct sun4i_i2s *i2s, int width)
+static int sun4i_i2s_get_sr(unsigned int width)
 {
-	if (width < 16 || width > 24)
-		return -EINVAL;
-
-	if (width % 4)
-		return -EINVAL;
+	switch (width) {
+	case 16:
+		return 0;
+	case 20:
+		return 1;
+	case 24:
+		return 2;
+	}
 
-	return (width - 16) / 4;
+	return -EINVAL;
 }
 
-static s8 sun4i_i2s_get_wss(const struct sun4i_i2s *i2s, int width)
+static int sun4i_i2s_get_wss(unsigned int width)
 {
-	if (width < 16 || width > 32)
-		return -EINVAL;
-
-	if (width % 4)
-		return -EINVAL;
+	switch (width) {
+	case 16:
+		return 0;
+	case 20:
+		return 1;
+	case 24:
+		return 2;
+	case 32:
+		return 3;
+	}
 
-	return (width - 16) / 4;
+	return -EINVAL;
 }
 
-static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width)
+static int sun8i_i2s_get_sr_wss(unsigned int width)
 {
-	if (width % 4)
-		return -EINVAL;
-
-	if (width < 8 || width > 32)
-		return -EINVAL;
+	switch (width) {
+	case 8:
+		return 1;
+	case 12:
+		return 2;
+	case 16:
+		return 3;
+	case 20:
+		return 4;
+	case 24:
+		return 5;
+	case 28:
+		return 6;
+	case 32:
+		return 7;
+	}
 
-	return (width - 8) / 4 + 1;
+	return -EINVAL;
 }
 
 static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
-				  const struct snd_pcm_hw_params *params)
+				  unsigned int channels, unsigned int slots,
+				  unsigned int slot_width)
 {
-	unsigned int channels = params_channels(params);
-
 	/* Map the channels for playback and capture */
 	regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210);
 	regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210);
@@ -419,15 +465,11 @@ static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
 }
 
 static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
-				  const struct snd_pcm_hw_params *params)
+				  unsigned int channels, unsigned int slots,
+				  unsigned int slot_width)
 {
-	unsigned int channels = params_channels(params);
-	unsigned int slots = channels;
 	unsigned int lrck_period;
 
-	if (i2s->slots)
-		slots = i2s->slots;
-
 	/* Map the channels for playback and capture */
 	regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
 	regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);
@@ -450,13 +492,13 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
 	switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_DSP_A:
 	case SND_SOC_DAIFMT_DSP_B:
-	case SND_SOC_DAIFMT_LEFT_J:
-	case SND_SOC_DAIFMT_RIGHT_J:
-		lrck_period = params_physical_width(params) * slots;
+		lrck_period = slot_width * slots;
 		break;
 
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
 	case SND_SOC_DAIFMT_I2S:
-		lrck_period = params_physical_width(params);
+		lrck_period = slot_width;
 		break;
 
 	default:
@@ -474,6 +516,60 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
 	return 0;
 }
 
+static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
+				      unsigned int channels, unsigned int slots,
+				      unsigned int slot_width)
+{
+	unsigned int lrck_period;
+
+	/* Map the channels for playback and capture */
+	regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0xFEDCBA98);
+	regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x76543210);
+	regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98);
+	regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210);
+
+	/* Configure the channels */
+	regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+			   SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
+			   SUN50I_H6_I2S_TX_CHAN_SEL(channels));
+	regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
+			   SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
+			   SUN50I_H6_I2S_TX_CHAN_SEL(channels));
+
+	regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+			   SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
+			   SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));
+	regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+			   SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
+			   SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
+
+	switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		lrck_period = slot_width * slots;
+		break;
+
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_I2S:
+		lrck_period = slot_width;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
+			   SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
+			   SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));
+
+	regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+			   SUN50I_H6_I2S_TX_CHAN_EN_MASK,
+			   SUN50I_H6_I2S_TX_CHAN_EN(channels));
+
+	return 0;
+}
+
 static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
 			       struct snd_pcm_hw_params *params,
 			       struct snd_soc_dai *dai)
@@ -482,7 +578,9 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
 	unsigned int word_size = params_width(params);
 	unsigned int slot_width = params_physical_width(params);
 	unsigned int channels = params_channels(params);
+
 	unsigned int slots = channels;
+
 	int ret, sr, wss;
 	u32 width;
 
@@ -492,16 +590,26 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
 	if (i2s->slot_width)
 		slot_width = i2s->slot_width;
 
-	ret = i2s->variant->set_chan_cfg(i2s, params);
+	ret = i2s->variant->set_chan_cfg(i2s, channels, slots, slot_width);
 	if (ret < 0) {
 		dev_err(dai->dev, "Invalid channel configuration\n");
 		return ret;
 	}
 
+	/* Set significant bits in our FIFOs */
+	regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
+			   SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
+			   SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
+			   SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
+			   SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
+
 	switch (params_physical_width(params)) {
 	case 16:
 		width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 		break;
+	case 32:
+		width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		break;
 	default:
 		dev_err(dai->dev, "Unsupported physical sample width: %d\n",
 			params_physical_width(params));
@@ -509,11 +617,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
 	}
 	i2s->playback_dma_data.addr_width = width;
 
-	sr = i2s->variant->get_sr(i2s, word_size);
+	sr = i2s->variant->get_sr(word_size);
 	if (sr < 0)
 		return -EINVAL;
 
-	wss = i2s->variant->get_wss(i2s, slot_width);
+	wss = i2s->variant->get_wss(slot_width);
 	if (wss < 0)
 		return -EINVAL;
 
@@ -594,6 +702,7 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
 	}
 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
 			   SUN4I_I2S_CTRL_MODE_MASK, val);
+
 	return 0;
 }
 
@@ -696,6 +805,118 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
 			   SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT,
 			   val);
 
+	/* Set sign extension to pad out LSB with 0 */
+	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,
+			   SUN8I_I2S_FMT1_REG_SEXT_MASK,
+			   SUN8I_I2S_FMT1_REG_SEXT(0));
+
+	return 0;
+}
+
+static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
+				     unsigned int fmt)
+{
+	u32 mode, val;
+	u8 offset;
+
+	/*
+	 * DAI clock polarity
+	 *
+	 * The setup for LRCK contradicts the datasheet, but under a
+	 * scope it's clear that the LRCK polarity is reversed
+	 * compared to the expected polarity on the bus.
+	 */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_IF:
+		/* Invert both clocks */
+		val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		/* Invert bit clock */
+		val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED |
+		      SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		/* Invert frame clock */
+		val = 0;
+		break;
+	case SND_SOC_DAIFMT_NB_NF:
+		val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
+			   SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |
+			   SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,
+			   val);
+
+	/* DAI Mode */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		mode = SUN8I_I2S_CTRL_MODE_PCM;
+		offset = 1;
+		break;
+
+	case SND_SOC_DAIFMT_DSP_B:
+		mode = SUN8I_I2S_CTRL_MODE_PCM;
+		offset = 0;
+		break;
+
+	case SND_SOC_DAIFMT_I2S:
+		mode = SUN8I_I2S_CTRL_MODE_LEFT;
+		offset = 1;
+		break;
+
+	case SND_SOC_DAIFMT_LEFT_J:
+		mode = SUN8I_I2S_CTRL_MODE_LEFT;
+		offset = 0;
+		break;
+
+	case SND_SOC_DAIFMT_RIGHT_J:
+		mode = SUN8I_I2S_CTRL_MODE_RIGHT;
+		offset = 0;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+			   SUN8I_I2S_CTRL_MODE_MASK, mode);
+	regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+			   SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
+			   SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
+	regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
+			   SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
+			   SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
+
+	/* DAI clock master masks */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* BCLK and LRCLK master */
+		val = SUN8I_I2S_CTRL_BCLK_OUT |	SUN8I_I2S_CTRL_LRCK_OUT;
+		break;
+
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* BCLK and LRCLK slave */
+		val = 0;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+			   SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT,
+			   val);
+
+	/* Set sign extension to pad out LSB with 0 */
+	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,
+			   SUN8I_I2S_FMT1_REG_SEXT_MASK,
+			   SUN8I_I2S_FMT1_REG_SEXT(0));
+
 	return 0;
 }
 
@@ -710,13 +931,6 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return ret;
 	}
 
-	/* Set significant bits in our FIFOs */
-	regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
-			   SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
-			   SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
-			   SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
-			   SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
-
 	i2s->format = fmt;
 
 	return 0;
@@ -870,6 +1084,10 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
+#define SUN4I_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
+			 SNDRV_PCM_FMTBIT_S20_LE | \
+			 SNDRV_PCM_FMTBIT_S24_LE)
+
 static struct snd_soc_dai_driver sun4i_i2s_dai = {
 	.probe = sun4i_i2s_dai_probe,
 	.capture = {
@@ -877,14 +1095,14 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = {
 		.channels_min = 1,
 		.channels_max = 8,
 		.rates = SNDRV_PCM_RATE_8000_192000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.formats = SUN4I_FORMATS,
 	},
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 1,
 		.channels_max = 8,
 		.rates = SNDRV_PCM_RATE_8000_192000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.formats = SUN4I_FORMATS,
 	},
 	.ops = &sun4i_i2s_dai_ops,
 	.symmetric_rates = 1,
@@ -944,12 +1162,19 @@ static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg)
 
 static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg)
 {
-	if (reg == SUN8I_I2S_INT_STA_REG)
+	switch (reg) {
+	case SUN4I_I2S_FIFO_CTRL_REG:
+	case SUN4I_I2S_FIFO_RX_REG:
+	case SUN4I_I2S_FIFO_STA_REG:
+	case SUN4I_I2S_RX_CNT_REG:
+	case SUN4I_I2S_TX_CNT_REG:
+	case SUN8I_I2S_FIFO_TX_REG:
+	case SUN8I_I2S_INT_STA_REG:
 		return true;
-	if (reg == SUN8I_I2S_FIFO_TX_REG)
-		return false;
 
-	return sun4i_i2s_volatile_reg(dev, reg);
+	default:
+		return false;
+	}
 }
 
 static const struct reg_default sun4i_i2s_reg_defaults[] = {
@@ -979,6 +1204,22 @@ static const struct reg_default sun8i_i2s_reg_defaults[] = {
 	{ SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 },
 };
 
+static const struct reg_default sun50i_h6_i2s_reg_defaults[] = {
+	{ SUN4I_I2S_CTRL_REG, 0x00060000 },
+	{ SUN4I_I2S_FMT0_REG, 0x00000033 },
+	{ SUN4I_I2S_FMT1_REG, 0x00000030 },
+	{ SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },
+	{ SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
+	{ SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
+	{ SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },
+	{ SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 },
+	{ SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0x00000000 },
+	{ SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x00000000 },
+	{ SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 },
+	{ SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 },
+	{ SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 },
+};
+
 static const struct regmap_config sun4i_i2s_regmap_config = {
 	.reg_bits	= 32,
 	.reg_stride	= 4,
@@ -1006,6 +1247,19 @@ static const struct regmap_config sun8i_i2s_regmap_config = {
 	.volatile_reg	= sun8i_i2s_volatile_reg,
 };
 
+static const struct regmap_config sun50i_h6_i2s_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register	= SUN50I_H6_I2S_RX_CHAN_MAP1_REG,
+	.cache_type	= REGCACHE_FLAT,
+	.reg_defaults	= sun50i_h6_i2s_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(sun50i_h6_i2s_reg_defaults),
+	.writeable_reg	= sun4i_i2s_wr_reg,
+	.readable_reg	= sun8i_i2s_rd_reg,
+	.volatile_reg	= sun8i_i2s_volatile_reg,
+};
+
 static int sun4i_i2s_runtime_resume(struct device *dev)
 {
 	struct sun4i_i2s *i2s = dev_get_drvdata(dev);
@@ -1164,6 +1418,24 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
 	.set_fmt		= sun4i_i2s_set_soc_fmt,
 };
 
+static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = {
+	.has_reset		= true,
+	.reg_offset_txdata	= SUN8I_I2S_FIFO_TX_REG,
+	.sun4i_i2s_regmap	= &sun50i_h6_i2s_regmap_config,
+	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
+	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
+	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
+	.bclk_dividers		= sun8i_i2s_clk_div,
+	.num_bclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),
+	.mclk_dividers		= sun8i_i2s_clk_div,
+	.num_mclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),
+	.get_bclk_parent_rate	= sun8i_i2s_get_bclk_parent_rate,
+	.get_sr			= sun8i_i2s_get_sr_wss,
+	.get_wss		= sun8i_i2s_get_sr_wss,
+	.set_chan_cfg		= sun50i_h6_i2s_set_chan_cfg,
+	.set_fmt		= sun50i_h6_i2s_set_soc_fmt,
+};
+
 static int sun4i_i2s_init_regmap_fields(struct device *dev,
 					struct sun4i_i2s *i2s)
 {
@@ -1333,6 +1605,10 @@ static const struct of_device_id sun4i_i2s_match[] = {
 		.compatible = "allwinner,sun50i-a64-codec-i2s",
 		.data = &sun50i_a64_codec_i2s_quirks,
 	},
+	{
+		.compatible = "allwinner,sun50i-h6-i2s",
+		.data = &sun50i_h6_i2s_quirks,
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 7590c4b04d14..180442c62be1 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -33,24 +33,26 @@
 #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF2CLK		(0x1 << 0)
 #define SUN8I_MOD_CLK_ENA				0x010
 #define SUN8I_MOD_CLK_ENA_AIF1				15
+#define SUN8I_MOD_CLK_ENA_AIF2				14
+#define SUN8I_MOD_CLK_ENA_AIF3				13
 #define SUN8I_MOD_CLK_ENA_ADC				3
 #define SUN8I_MOD_CLK_ENA_DAC				2
 #define SUN8I_MOD_RST_CTL				0x014
 #define SUN8I_MOD_RST_CTL_AIF1				15
+#define SUN8I_MOD_RST_CTL_AIF2				14
+#define SUN8I_MOD_RST_CTL_AIF3				13
 #define SUN8I_MOD_RST_CTL_ADC				3
 #define SUN8I_MOD_RST_CTL_DAC				2
 #define SUN8I_SYS_SR_CTRL				0x018
 #define SUN8I_SYS_SR_CTRL_AIF1_FS			12
 #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
-#define SUN8I_AIF1CLK_CTRL				0x040
-#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD		15
-#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV		14
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV		13
-#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV		9
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV		6
-#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ		4
-#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16		(1 << 4)
-#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT		2
+#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
+#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
+#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
+#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
+#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
+#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
+#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
 #define SUN8I_AIF1_ADCDAT_CTRL				0x044
 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA		15
 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
@@ -70,6 +72,32 @@
 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR	10
 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR		9
 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL	8
+#define SUN8I_AIF2_ADCDAT_CTRL				0x084
+#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA		15
+#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA		14
+#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC		10
+#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC		8
+#define SUN8I_AIF2_DACDAT_CTRL				0x088
+#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA		15
+#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA		14
+#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC		10
+#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC		8
+#define SUN8I_AIF2_MXR_SRC				0x08c
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L	15
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L	14
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR	13
+#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL		12
+#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R	11
+#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R	10
+#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL	9
+#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR		8
+#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1		(0x0 << 0)
+#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2		(0x1 << 0)
+#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1CLK	(0x2 << 0)
+#define SUN8I_AIF3_PATH_CTRL				0x0cc
+#define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC		10
+#define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC		8
+#define SUN8I_AIF3_PATH_CTRL_AIF3_PINS_TRI		7
 #define SUN8I_ADC_DIG_CTRL				0x100
 #define SUN8I_ADC_DIG_CTRL_ENAD				15
 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS			2
@@ -90,10 +118,44 @@
 #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK	GENMASK(5, 4)
 #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK		GENMASK(15, 12)
 #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK		GENMASK(11, 8)
-#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK	GENMASK(12, 9)
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK	GENMASK(8, 6)
-#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK	GENMASK(5, 4)
-#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK	GENMASK(3, 2)
+#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
+#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
+#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
+#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
+#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
+#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK	GENMASK(1, 0)
+
+#define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
+
+#define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
+				 SNDRV_PCM_FMTBIT_S16_LE |\
+				 SNDRV_PCM_FMTBIT_S20_LE |\
+				 SNDRV_PCM_FMTBIT_S24_LE |\
+				 SNDRV_PCM_FMTBIT_S20_3LE|\
+				 SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define SUN8I_CODEC_PCM_RATES	(SNDRV_PCM_RATE_8000_48000|\
+				 SNDRV_PCM_RATE_88200     |\
+				 SNDRV_PCM_RATE_96000     |\
+				 SNDRV_PCM_RATE_176400    |\
+				 SNDRV_PCM_RATE_192000    |\
+				 SNDRV_PCM_RATE_KNOT)
+
+enum {
+	SUN8I_CODEC_AIF1,
+	SUN8I_CODEC_AIF2,
+	SUN8I_CODEC_AIF3,
+	SUN8I_CODEC_NAIFS
+};
+
+struct sun8i_codec_aif {
+	unsigned int	lrck_div_order;
+	unsigned int	sample_rate;
+	unsigned int	slots;
+	unsigned int	slot_width;
+	unsigned int	active_streams	: 2;
+	unsigned int	open_streams	: 2;
+};
 
 struct sun8i_codec_quirks {
 	bool legacy_widgets	: 1;
@@ -104,8 +166,13 @@ struct sun8i_codec {
 	struct regmap			*regmap;
 	struct clk			*clk_module;
 	const struct sun8i_codec_quirks	*quirks;
+	struct sun8i_codec_aif		aifs[SUN8I_CODEC_NAIFS];
+	unsigned int			sysclk_rate;
+	int				sysclk_refcnt;
 };
 
+static struct snd_soc_dai_driver sun8i_codec_dais[];
+
 static int sun8i_codec_runtime_resume(struct device *dev)
 {
 	struct sun8i_codec *scodec = dev_get_drvdata(dev);
@@ -132,32 +199,34 @@ static int sun8i_codec_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
+static int sun8i_codec_get_hw_rate(unsigned int sample_rate)
 {
-	unsigned int rate = params_rate(params);
-
-	switch (rate) {
-	case 8000:
+	switch (sample_rate) {
 	case 7350:
+	case 8000:
 		return 0x0;
 	case 11025:
 		return 0x1;
 	case 12000:
 		return 0x2;
+	case 14700:
 	case 16000:
 		return 0x3;
 	case 22050:
 		return 0x4;
 	case 24000:
 		return 0x5;
+	case 29400:
 	case 32000:
 		return 0x6;
 	case 44100:
 		return 0x7;
 	case 48000:
 		return 0x8;
+	case 88200:
 	case 96000:
 		return 0x9;
+	case 176400:
 	case 192000:
 		return 0xa;
 	default:
@@ -165,10 +234,37 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 	}
 }
 
-static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
+{
+	unsigned int max_rate = 0;
+	int hw_rate, i;
+
+	for (i = SUN8I_CODEC_AIF1; i < SUN8I_CODEC_NAIFS; ++i) {
+		struct sun8i_codec_aif *aif = &scodec->aifs[i];
+
+		if (aif->active_streams)
+			max_rate = max(max_rate, aif->sample_rate);
+	}
+
+	/* Set the sample rate for ADC->DAC passthrough when no AIF is active. */
+	if (!max_rate)
+		max_rate = SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE;
+
+	hw_rate = sun8i_codec_get_hw_rate(max_rate);
+	if (hw_rate < 0)
+		return hw_rate;
+
+	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
+			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
+			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
+
+	return 0;
+}
+
+static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
-	u32 value;
+	u32 dsp_format, format, invert, value;
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -181,65 +277,162 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	default:
 		return -EINVAL;
 	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
 
-	/* clock inversion */
-	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_NB_NF: /* Normal */
-		value = 0x0;
-		break;
-	case SND_SOC_DAIFMT_IB_IF: /* Inversion */
-		value = 0x1;
-		break;
-	default:
-		return -EINVAL;
+	if (dai->id == SUN8I_CODEC_AIF3) {
+		/* AIF3 only supports master mode. */
+		if (value)
+			return -EINVAL;
+
+		/* Use the AIF2 BCLK and LRCK for AIF3. */
+		regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
+				   SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK,
+				   SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2);
+	} else {
+		regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
+				   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
+				   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
 	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
-
-	/*
-	 * It appears that the DAI and the codec in the A33 SoC don't
-	 * share the same polarity for the LRCK signal when they mean
-	 * 'normal' and 'inverted' in the datasheet.
-	 *
-	 * Since the DAI here is our regular i2s driver that have been
-	 * tested with way more codecs than just this one, it means
-	 * that the codec probably gets it backward, and we have to
-	 * invert the value here.
-	 */
-	value ^= scodec->quirks->lrck_inversion;
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV),
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV);
 
 	/* DAI format */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
-		value = 0x0;
+		format = 0x0;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
-		value = 0x1;
+		format = 0x1;
 		break;
 	case SND_SOC_DAIFMT_RIGHT_J:
-		value = 0x2;
+		format = 0x2;
 		break;
 	case SND_SOC_DAIFMT_DSP_A:
+		format = 0x3;
+		dsp_format = 0x0; /* Set LRCK_INV to 0 */
+		break;
 	case SND_SOC_DAIFMT_DSP_B:
-		value = 0x3;
+		format = 0x3;
+		dsp_format = 0x1; /* Set LRCK_INV to 1 */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (dai->id == SUN8I_CODEC_AIF3) {
+		/* AIF3 only supports DSP mode. */
+		if (format != 3)
+			return -EINVAL;
+	} else {
+		regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
+				   SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
+				   format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF: /* Normal */
+		invert = 0x0;
+		break;
+	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
+		invert = 0x1;
+		break;
+	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
+		invert = 0x2;
+		break;
+	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
+		invert = 0x3;
 		break;
 	default:
 		return -EINVAL;
 	}
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
-			   value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
+
+	if (format == 0x3) {
+		/* Inverted LRCK is not available in DSP mode. */
+		if (invert & BIT(0))
+			return -EINVAL;
+
+		/* Instead, the bit selects between DSP A/B formats. */
+		invert |= dsp_format;
+	} else {
+		/*
+		 * It appears that the DAI and the codec in the A33 SoC don't
+		 * share the same polarity for the LRCK signal when they mean
+		 * 'normal' and 'inverted' in the datasheet.
+		 *
+		 * Since the DAI here is our regular i2s driver that have been
+		 * tested with way more codecs than just this one, it means
+		 * that the codec probably gets it backward, and we have to
+		 * invert the value here.
+		 */
+		invert ^= scodec->quirks->lrck_inversion;
+	}
+
+	regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
+			   SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
+			   invert << SUN8I_AIF_CLK_CTRL_CLK_INV);
 
 	return 0;
 }
 
+static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
+				    unsigned int tx_mask, unsigned int rx_mask,
+				    int slots, int slot_width)
+{
+	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+
+	if (slot_width && !is_power_of_2(slot_width))
+		return -EINVAL;
+
+	aif->slots = slots;
+	aif->slot_width = slot_width;
+
+	return 0;
+}
+
+static const unsigned int sun8i_codec_rates[] = {
+	  7350,   8000,  11025,  12000,  14700,  16000,  22050,  24000,
+	 29400,  32000,  44100,  48000,  88200,  96000, 176400, 192000,
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_all_rates = {
+	.list	= sun8i_codec_rates,
+	.count	= ARRAY_SIZE(sun8i_codec_rates),
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_22M_rates = {
+	.list	= sun8i_codec_rates,
+	.count	= ARRAY_SIZE(sun8i_codec_rates),
+	.mask	= 0x5555,
+};
+
+static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
+	.list	= sun8i_codec_rates,
+	.count	= ARRAY_SIZE(sun8i_codec_rates),
+	.mask	= 0xaaaa,
+};
+
+static int sun8i_codec_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	const struct snd_pcm_hw_constraint_list *list;
+
+	/* hw_constraints is not relevant for codec2codec DAIs. */
+	if (dai->id != SUN8I_CODEC_AIF1)
+		return 0;
+
+	if (!scodec->sysclk_refcnt)
+		list = &sun8i_codec_all_rates;
+	else if (scodec->sysclk_rate == 22579200)
+		list = &sun8i_codec_22M_rates;
+	else if (scodec->sysclk_rate == 24576000)
+		list = &sun8i_codec_24M_rates;
+	else
+		return -EINVAL;
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE, list);
+}
+
 struct sun8i_codec_clk_div {
 	u8	div;
 	u8	val;
@@ -262,37 +455,37 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 	{ .div = 192,	.val = 13 },
 };
 
-static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
-				   unsigned int rate,
-				   unsigned int word_size)
+static int sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
+				    unsigned int lrck_div_order,
+				    unsigned int sample_rate)
 {
-	unsigned long clk_rate = clk_get_rate(scodec->clk_module);
-	unsigned int div = clk_rate / rate / word_size / 2;
-	unsigned int best_val = 0, best_diff = ~0;
+	unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
 		const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
-		unsigned int diff = abs(bdiv->div - div);
 
-		if (diff < best_diff) {
-			best_diff = diff;
-			best_val = bdiv->val;
-		}
+		if (bdiv->div == div)
+			return bdiv->val;
 	}
 
-	return best_val;
+	return -EINVAL;
 }
 
-static int sun8i_codec_get_lrck_div(unsigned int channels,
-				    unsigned int word_size)
+static int sun8i_codec_get_lrck_div_order(unsigned int slots,
+					  unsigned int slot_width)
 {
-	unsigned int div = word_size * channels;
+	unsigned int div = slots * slot_width;
 
 	if (div < 16 || div > 256)
 		return -EINVAL;
 
-	return ilog2(div) - 4;
+	return order_base_2(div);
+}
+
+static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
+{
+	return sample_rate % 4000 ? 22579200 : 24576000;
 }
 
 static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
@@ -300,42 +493,225 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
-	int sample_rate, lrck_div;
-	u8 bclk_div;
+	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
+	unsigned int sample_rate = params_rate(params);
+	unsigned int slots = aif->slots ?: params_channels(params);
+	unsigned int slot_width = aif->slot_width ?: params_width(params);
+	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
+	int bclk_div, lrck_div_order, ret, word_size;
+	u32 clk_reg;
+
+	/* word size */
+	switch (params_width(params)) {
+	case 8:
+		word_size = 0x0;
+		break;
+	case 16:
+		word_size = 0x1;
+		break;
+	case 20:
+		word_size = 0x2;
+		break;
+	case 24:
+		word_size = 0x3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
+			   SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
+			   word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
+
+	/* LRCK divider (BCLK/LRCK ratio) */
+	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
+	if (lrck_div_order < 0)
+		return lrck_div_order;
+
+	if (dai->id == SUN8I_CODEC_AIF2 || dai->id == SUN8I_CODEC_AIF3) {
+		/* AIF2 and AIF3 share AIF2's BCLK and LRCK generation circuitry. */
+		int partner = (SUN8I_CODEC_AIF2 + SUN8I_CODEC_AIF3) - dai->id;
+		const struct sun8i_codec_aif *partner_aif = &scodec->aifs[partner];
+		const char *partner_name = sun8i_codec_dais[partner].name;
+
+		if (partner_aif->open_streams &&
+		    (lrck_div_order != partner_aif->lrck_div_order ||
+		     sample_rate != partner_aif->sample_rate)) {
+			dev_err(dai->dev,
+				"%s sample and bit rates must match %s when both are used\n",
+				dai->name, partner_name);
+			return -EBUSY;
+		}
+
+		clk_reg = SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF2);
+	} else {
+		clk_reg = SUN8I_AIF_CLK_CTRL(dai->id);
+	}
+
+	regmap_update_bits(scodec->regmap, clk_reg,
+			   SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
+			   (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
+
+	/* BCLK divider (SYSCLK/BCLK ratio) */
+	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
+	if (bclk_div < 0)
+		return bclk_div;
+
+	regmap_update_bits(scodec->regmap, clk_reg,
+			   SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
+			   bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
 
 	/*
-	 * The CPU DAI handles only a sample of 16 bits. Configure the
-	 * codec to handle this type of sample resolution.
+	 * SYSCLK rate
+	 *
+	 * Clock rate protection is reference counted; but hw_params may be
+	 * called many times per substream, without matching calls to hw_free.
+	 * Protect the clock rate once per AIF, on the first hw_params call
+	 * for the first substream. clk_set_rate() will allow clock rate
+	 * changes on subsequent calls if only one AIF has open streams.
 	 */
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
-			   SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16);
+	ret = (aif->open_streams ? clk_set_rate : clk_set_rate_exclusive)(scodec->clk_module,
+									  sysclk_rate);
+	if (ret == -EBUSY)
+		dev_err(dai->dev,
+			"%s sample rate (%u Hz) conflicts with other audio streams\n",
+			dai->name, sample_rate);
+	if (ret < 0)
+		return ret;
 
-	bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
-			   bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
+	if (!aif->open_streams)
+		scodec->sysclk_refcnt++;
+	scodec->sysclk_rate = sysclk_rate;
 
-	lrck_div = sun8i_codec_get_lrck_div(params_channels(params),
-					    params_physical_width(params));
-	if (lrck_div < 0)
-		return lrck_div;
+	aif->lrck_div_order = lrck_div_order;
+	aif->sample_rate = sample_rate;
+	aif->open_streams |= BIT(substream->stream);
 
-	regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
-			   SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
-			   lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
+	return sun8i_codec_update_sample_rate(scodec);
+}
 
-	sample_rate = sun8i_codec_get_hw_rate(params);
-	if (sample_rate < 0)
-		return sample_rate;
+static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
+	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
 
-	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
-			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
-			   sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
+	/* Drop references when the last substream for the AIF is freed. */
+	if (aif->open_streams != BIT(substream->stream))
+		goto done;
 
+	clk_rate_exclusive_put(scodec->clk_module);
+	scodec->sysclk_refcnt--;
+	aif->lrck_div_order = 0;
+	aif->sample_rate = 0;
+
+done:
+	aif->open_streams &= ~BIT(substream->stream);
 	return 0;
 }
 
+static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
+	.set_fmt	= sun8i_codec_set_fmt,
+	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
+	.startup	= sun8i_codec_startup,
+	.hw_params	= sun8i_codec_hw_params,
+	.hw_free	= sun8i_codec_hw_free,
+};
+
+static struct snd_soc_dai_driver sun8i_codec_dais[] = {
+	{
+		.name	= "sun8i-codec-aif1",
+		.id	= SUN8I_CODEC_AIF1,
+		.ops	= &sun8i_codec_dai_ops,
+		/* capture capabilities */
+		.capture = {
+			.stream_name	= "AIF1 Capture",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+			.sig_bits	= 24,
+		},
+		/* playback capabilities */
+		.playback = {
+			.stream_name	= "AIF1 Playback",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+		},
+		.symmetric_rates	= true,
+		.symmetric_channels	= true,
+		.symmetric_samplebits	= true,
+	},
+	{
+		.name	= "sun8i-codec-aif2",
+		.id	= SUN8I_CODEC_AIF2,
+		.ops	= &sun8i_codec_dai_ops,
+		/* capture capabilities */
+		.capture = {
+			.stream_name	= "AIF2 Capture",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+			.sig_bits	= 24,
+		},
+		/* playback capabilities */
+		.playback = {
+			.stream_name	= "AIF2 Playback",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+		},
+		.symmetric_rates	= true,
+		.symmetric_channels	= true,
+		.symmetric_samplebits	= true,
+	},
+	{
+		.name	= "sun8i-codec-aif3",
+		.id	= SUN8I_CODEC_AIF3,
+		.ops	= &sun8i_codec_dai_ops,
+		/* capture capabilities */
+		.capture = {
+			.stream_name	= "AIF3 Capture",
+			.channels_min	= 1,
+			.channels_max	= 1,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+			.sig_bits	= 24,
+		},
+		/* playback capabilities */
+		.playback = {
+			.stream_name	= "AIF3 Playback",
+			.channels_min	= 1,
+			.channels_max	= 1,
+			.rates		= SUN8I_CODEC_PCM_RATES,
+			.formats	= SUN8I_CODEC_PCM_FORMATS,
+		},
+		.symmetric_rates	= true,
+		.symmetric_channels	= true,
+		.symmetric_samplebits	= true,
+	},
+};
+
+static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
+	struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
+	int stream = w->id == snd_soc_dapm_aif_out;
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		aif->active_streams |= BIT(stream);
+	else
+		aif->active_streams &= ~BIT(stream);
+
+	return sun8i_codec_update_sample_rate(scodec);
+}
+
 static const char *const sun8i_aif_stereo_mux_enum_values[] = {
 	"Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono"
 };
@@ -350,6 +726,29 @@ static const struct snd_kcontrol_new sun8i_aif1_ad0_stereo_mux_control =
 	SOC_DAPM_ENUM("AIF1 AD0 Stereo Capture Route",
 		      sun8i_aif1_ad0_stereo_mux_enum);
 
+static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_adc_stereo_mux_enum,
+			    SUN8I_AIF2_ADCDAT_CTRL,
+			    SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC,
+			    SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC,
+			    sun8i_aif_stereo_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif2_adc_stereo_mux_control =
+	SOC_DAPM_ENUM("AIF2 ADC Stereo Capture Route",
+		      sun8i_aif2_adc_stereo_mux_enum);
+
+static const char *const sun8i_aif3_adc_mux_enum_values[] = {
+	"None", "AIF2 ADCL", "AIF2 ADCR"
+};
+
+static SOC_ENUM_SINGLE_DECL(sun8i_aif3_adc_mux_enum,
+			    SUN8I_AIF3_PATH_CTRL,
+			    SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC,
+			    sun8i_aif3_adc_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif3_adc_mux_control =
+	SOC_DAPM_ENUM("AIF3 ADC Source Capture Route",
+		      sun8i_aif3_adc_mux_enum);
+
 static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
 			SUN8I_AIF1_MXR_SRC,
@@ -369,6 +768,38 @@ static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
 			SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
 };
 
+static const struct snd_kcontrol_new sun8i_aif2_adc_mixer_controls[] = {
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA0 Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R, 1, 0),
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA1 Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R, 1, 0),
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF2 DAC Rev Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL, 1, 0),
+	SOC_DAPM_DOUBLE("AIF2 ADC Mixer ADC Capture Switch",
+			SUN8I_AIF2_MXR_SRC,
+			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL,
+			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR, 1, 0),
+};
+
+static const char *const sun8i_aif2_dac_mux_enum_values[] = {
+	"AIF2", "AIF3+2", "AIF2+3"
+};
+
+static SOC_ENUM_SINGLE_DECL(sun8i_aif2_dac_mux_enum,
+			    SUN8I_AIF3_PATH_CTRL,
+			    SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC,
+			    sun8i_aif2_dac_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif2_dac_mux_control =
+	SOC_DAPM_ENUM("AIF2 DAC Source Playback Route",
+		      sun8i_aif2_dac_mux_enum);
+
 static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_da0_stereo_mux_enum,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC,
@@ -379,6 +810,16 @@ static const struct snd_kcontrol_new sun8i_aif1_da0_stereo_mux_control =
 	SOC_DAPM_ENUM("AIF1 DA0 Stereo Playback Route",
 		      sun8i_aif1_da0_stereo_mux_enum);
 
+static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_dac_stereo_mux_enum,
+			    SUN8I_AIF2_DACDAT_CTRL,
+			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC,
+			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC,
+			    sun8i_aif_stereo_mux_enum_values);
+
+static const struct snd_kcontrol_new sun8i_aif2_dac_stereo_mux_control =
+	SOC_DAPM_ENUM("AIF2 DAC Stereo Playback Route",
+		      sun8i_aif2_dac_stereo_mux_enum);
+
 static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
 			SUN8I_DAC_MXR_SRC,
@@ -403,6 +844,9 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("AIF1CLK",
 			    SUN8I_SYSCLK_CTL,
 			    SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AIF2CLK",
+			    SUN8I_SYSCLK_CTL,
+			    SUN8I_SYSCLK_CTL_AIF2CLK_ENA, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("SYSCLK",
 			    SUN8I_SYSCLK_CTL,
 			    SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
@@ -411,6 +855,12 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("CLK AIF1",
 			    SUN8I_MOD_CLK_ENA,
 			    SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLK AIF2",
+			    SUN8I_MOD_CLK_ENA,
+			    SUN8I_MOD_CLK_ENA_AIF2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLK AIF3",
+			    SUN8I_MOD_CLK_ENA,
+			    SUN8I_MOD_CLK_ENA_AIF3, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("CLK ADC",
 			    SUN8I_MOD_CLK_ENA,
 			    SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
@@ -422,6 +872,12 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("RST AIF1",
 			    SUN8I_MOD_RST_CTL,
 			    SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RST AIF2",
+			    SUN8I_MOD_RST_CTL,
+			    SUN8I_MOD_RST_CTL_AIF2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RST AIF3",
+			    SUN8I_MOD_RST_CTL,
+			    SUN8I_MOD_RST_CTL_AIF3, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("RST ADC",
 			    SUN8I_MOD_RST_CTL,
 			    SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
@@ -438,39 +894,96 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 			    SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0),
 
 	/* AIF "ADC" Outputs */
-	SND_SOC_DAPM_AIF_OUT("AIF1 AD0L", "Capture", 0,
-			     SUN8I_AIF1_ADCDAT_CTRL,
-			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
-	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1,
+	SND_SOC_DAPM_AIF_OUT_E("AIF1 AD0L", "AIF1 Capture", 0,
+			       SUN8I_AIF1_ADCDAT_CTRL,
+			       SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
+			       sun8i_codec_aif_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 Capture", 1,
 			     SUN8I_AIF1_ADCDAT_CTRL,
 			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
 
+	SND_SOC_DAPM_AIF_OUT_E("AIF2 ADCL", "AIF2 Capture", 0,
+			       SUN8I_AIF2_ADCDAT_CTRL,
+			       SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA, 0,
+			       sun8i_codec_aif_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1,
+			     SUN8I_AIF2_ADCDAT_CTRL,
+			     SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA, 0),
+
+	SND_SOC_DAPM_AIF_OUT_E("AIF3 ADC", "AIF3 Capture", 0,
+			       SND_SOC_NOPM, 0, 0,
+			       sun8i_codec_aif_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
 	/* AIF "ADC" Mono/Stereo Muxes */
 	SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0,
 			 &sun8i_aif1_ad0_stereo_mux_control),
 	SND_SOC_DAPM_MUX("AIF1 AD0R Stereo Mux", SND_SOC_NOPM, 0, 0,
 			 &sun8i_aif1_ad0_stereo_mux_control),
 
+	SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_adc_stereo_mux_control),
+	SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_adc_stereo_mux_control),
+
+	/* AIF "ADC" Output Muxes */
+	SND_SOC_DAPM_MUX("AIF3 ADC Source Capture Route", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif3_adc_mux_control),
+
 	/* AIF "ADC" Mixers */
 	SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0,
 			sun8i_aif1_ad0_mixer_controls),
 	SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0,
 			sun8i_aif1_ad0_mixer_controls),
 
+	SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif2_adc_mixer_controls),
+	SOC_MIXER_ARRAY("AIF2 ADCR Mixer", SND_SOC_NOPM, 0, 0,
+			sun8i_aif2_adc_mixer_controls),
+
+	/* AIF "DAC" Input Muxes */
+	SND_SOC_DAPM_MUX("AIF2 DACL Source", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_mux_control),
+	SND_SOC_DAPM_MUX("AIF2 DACR Source", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_mux_control),
+
 	/* AIF "DAC" Mono/Stereo Muxes */
 	SND_SOC_DAPM_MUX("AIF1 DA0L Stereo Mux", SND_SOC_NOPM, 0, 0,
 			 &sun8i_aif1_da0_stereo_mux_control),
 	SND_SOC_DAPM_MUX("AIF1 DA0R Stereo Mux", SND_SOC_NOPM, 0, 0,
 			 &sun8i_aif1_da0_stereo_mux_control),
 
+	SND_SOC_DAPM_MUX("AIF2 DACL Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_stereo_mux_control),
+	SND_SOC_DAPM_MUX("AIF2 DACR Stereo Mux", SND_SOC_NOPM, 0, 0,
+			 &sun8i_aif2_dac_stereo_mux_control),
+
 	/* AIF "DAC" Inputs */
-	SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0,
-			    SUN8I_AIF1_DACDAT_CTRL,
-			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
-	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1,
+	SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
+			      SUN8I_AIF1_DACDAT_CTRL,
+			      SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
+			      sun8i_codec_aif_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
 			    SUN8I_AIF1_DACDAT_CTRL,
 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
 
+	SND_SOC_DAPM_AIF_IN_E("AIF2 DACL", "AIF2 Playback", 0,
+			      SUN8I_AIF2_DACDAT_CTRL,
+			      SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA, 0,
+			      sun8i_codec_aif_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1,
+			    SUN8I_AIF2_DACDAT_CTRL,
+			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA, 0),
+
+	SND_SOC_DAPM_AIF_IN_E("AIF3 DAC", "AIF3 Playback", 0,
+			      SND_SOC_NOPM, 0, 0,
+			      sun8i_codec_aif_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
 	/* ADC Inputs (connected to analog codec DAPM context) */
 	SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
@@ -500,6 +1013,20 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "AIF1 DA0L", NULL, "RST AIF1" },
 	{ "AIF1 DA0R", NULL, "RST AIF1" },
 
+	{ "CLK AIF2", NULL, "AIF2CLK" },
+	{ "CLK AIF2", NULL, "SYSCLK" },
+	{ "RST AIF2", NULL, "CLK AIF2" },
+	{ "AIF2 ADCL", NULL, "RST AIF2" },
+	{ "AIF2 ADCR", NULL, "RST AIF2" },
+	{ "AIF2 DACL", NULL, "RST AIF2" },
+	{ "AIF2 DACR", NULL, "RST AIF2" },
+
+	{ "CLK AIF3", NULL, "AIF1CLK" },
+	{ "CLK AIF3", NULL, "SYSCLK" },
+	{ "RST AIF3", NULL, "CLK AIF3" },
+	{ "AIF3 ADC", NULL, "RST AIF3" },
+	{ "AIF3 DAC", NULL, "RST AIF3" },
+
 	{ "CLK ADC", NULL, "SYSCLK" },
 	{ "RST ADC", NULL, "CLK ADC" },
 	{ "ADC", NULL, "RST ADC" },
@@ -516,6 +1043,11 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" },
 	{ "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" },
 
+	{ "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" },
+	{ "AIF2 ADCR", NULL, "AIF2 ADCR Stereo Mux" },
+
+	{ "AIF3 ADC", NULL, "AIF3 ADC Source Capture Route" },
+
 	/* AIF "ADC" Mono/Stereo Mux Routes */
 	{ "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" },
 	{ "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" },
@@ -531,12 +1063,51 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
 	{ "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
 
+	{ "AIF2 ADCL Stereo Mux", "Stereo", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Reverse Stereo", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
+
+	{ "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
+	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
+
+	/* AIF "ADC" Output Mux Routes */
+	{ "AIF3 ADC Source Capture Route", "AIF2 ADCL", "AIF2 ADCL Mixer" },
+	{ "AIF3 ADC Source Capture Route", "AIF2 ADCR", "AIF2 ADCR Mixer" },
+
 	/* AIF "ADC" Mixer Routes */
 	{ "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
+	{ "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" },
 	{ "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
+	{ "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" },
 
 	{ "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
+	{ "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" },
 	{ "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
+	{ "AIF1 AD0R Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACL Source" },
+
+	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0L Stereo Mux" },
+	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACR Source" },
+	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" },
+
+	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" },
+	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" },
+	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" },
+
+	/* AIF "DAC" Input Mux Routes */
+	{ "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" },
+	{ "AIF2 DACL Source", "AIF3+2", "AIF3 DAC" },
+	{ "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" },
+
+	{ "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" },
+	{ "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" },
+	{ "AIF2 DACR Source", "AIF2+3", "AIF3 DAC" },
 
 	/* AIF "DAC" Mono/Stereo Mux Routes */
 	{ "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" },
@@ -553,15 +1124,31 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 	{ "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0L" },
 	{ "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0R" },
 
+	{ "AIF2 DACL Stereo Mux", "Stereo", "AIF2 DACL" },
+	{ "AIF2 DACL Stereo Mux", "Reverse Stereo", "AIF2 DACR" },
+	{ "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACL" },
+	{ "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACR" },
+	{ "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACL" },
+	{ "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACR" },
+
+	{ "AIF2 DACR Stereo Mux", "Stereo", "AIF2 DACR" },
+	{ "AIF2 DACR Stereo Mux", "Reverse Stereo", "AIF2 DACL" },
+	{ "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACL" },
+	{ "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACR" },
+	{ "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACL" },
+	{ "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACR" },
+
 	/* DAC Output Routes */
 	{ "DACL", NULL, "DACL Mixer" },
 	{ "DACR", NULL, "DACR Mixer" },
 
 	/* DAC Mixer Routes */
 	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
+	{ "DACL Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACL Source" },
 	{ "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
 
 	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
+	{ "DACR Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACR Source" },
 	{ "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
 };
 
@@ -621,37 +1208,12 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
 			   BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC),
 			   SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK);
 
+	/* Program the default sample rate. */
+	sun8i_codec_update_sample_rate(scodec);
+
 	return 0;
 }
 
-static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
-	.hw_params = sun8i_codec_hw_params,
-	.set_fmt = sun8i_set_fmt,
-};
-
-static struct snd_soc_dai_driver sun8i_codec_dai = {
-	.name = "sun8i",
-	/* playback capabilities */
-	.playback = {
-		.stream_name = "Playback",
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_192000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	/* capture capabilities */
-	.capture = {
-		.stream_name = "Capture",
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_192000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-		.sig_bits = 24,
-	},
-	/* pcm operations */
-	.ops = &sun8i_codec_dai_ops,
-};
-
 static const struct snd_soc_component_driver sun8i_soc_component = {
 	.dapm_widgets		= sun8i_codec_dapm_widgets,
 	.num_dapm_widgets	= ARRAY_SIZE(sun8i_codec_dapm_widgets),
@@ -659,7 +1221,6 @@ static const struct snd_soc_component_driver sun8i_soc_component = {
 	.num_dapm_routes	= ARRAY_SIZE(sun8i_codec_dapm_routes),
 	.probe			= sun8i_codec_component_probe,
 	.idle_bias_on		= 1,
-	.use_pmdown_time	= 1,
 	.endianness		= 1,
 	.non_legacy_dai_naming	= 1,
 };
@@ -714,7 +1275,8 @@ static int sun8i_codec_probe(struct platform_device *pdev)
 	}
 
 	ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
-				     &sun8i_codec_dai, 1);
+					      sun8i_codec_dais,
+					      ARRAY_SIZE(sun8i_codec_dais));
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register codec\n");
 		goto err_suspend;
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 3d91bd3e59cd..a62cc87551ac 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -39,7 +39,6 @@ config SND_SOC_TEGRA20_I2S
 config SND_SOC_TEGRA20_SPDIF
 	tristate "Tegra20 SPDIF interface"
 	depends on SND_SOC_TEGRA
-	default m
 	help
 	  Say Y or M if you want to add support for the Tegra20 SPDIF interface.
 	  You will also need to select the individual machine drivers to support
diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c
index 0cbe31e2c7e9..7d9948fb2ca7 100644
--- a/sound/soc/tegra/tegra186_dspk.c
+++ b/sound/soc/tegra/tegra186_dspk.c
@@ -310,7 +310,7 @@ static bool tegra186_dspk_wr_reg(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg)
@@ -326,7 +326,7 @@ static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg)
@@ -339,7 +339,7 @@ static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static const struct regmap_config tegra186_dspk_regmap = {
diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c
index a661f40bc41c..ead2c99bf72e 100644
--- a/sound/soc/tegra/tegra210_dmic.c
+++ b/sound/soc/tegra/tegra210_dmic.c
@@ -322,7 +322,7 @@ static bool tegra210_dmic_wr_reg(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static bool tegra210_dmic_rd_reg(struct device *dev, unsigned int reg)
@@ -338,7 +338,7 @@ static bool tegra210_dmic_rd_reg(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static bool tegra210_dmic_volatile_reg(struct device *dev, unsigned int reg)
@@ -353,7 +353,7 @@ static bool tegra210_dmic_volatile_reg(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static const struct regmap_config tegra210_dmic_regmap_config = {
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
index a383bd5c51cd..ca31ec92e508 100644
--- a/sound/soc/tegra/tegra210_i2s.c
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -662,7 +662,7 @@ static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg)
@@ -682,7 +682,7 @@ static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
@@ -701,7 +701,7 @@ static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
 		return true;
 	default:
 		return false;
-	};
+	}
 }
 
 static const struct regmap_config tegra210_i2s_regmap_config = {
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index 8661877bf4c6..0a0efd24e4b0 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -203,8 +203,8 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
 
 	ret = snd_soc_register_card(card);
 	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
+		dev_err_probe(&pdev->dev, ret,
+			      "snd_soc_register_card failed\n");
 		goto err_put_cpu_of_node;
 	}
 
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c
index 9d8e16473ab9..00c19704057b 100644
--- a/sound/soc/tegra/tegra_max98090.c
+++ b/sound/soc/tegra/tegra_max98090.c
@@ -247,11 +247,9 @@ static int tegra_max98090_probe(struct platform_device *pdev)
 		return ret;
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "snd_soc_register_card failed\n");
 
 	return 0;
 }
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
index c73bd23b3d67..9afba37a3b08 100644
--- a/sound/soc/tegra/tegra_rt5640.c
+++ b/sound/soc/tegra/tegra_rt5640.c
@@ -193,11 +193,9 @@ static int tegra_rt5640_probe(struct platform_device *pdev)
 		return ret;
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "snd_soc_register_card failed\n");
 
 	return 0;
 }
diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c
index 7504507dd8b8..d30f8b6deda4 100644
--- a/sound/soc/tegra/tegra_rt5677.c
+++ b/sound/soc/tegra/tegra_rt5677.c
@@ -268,8 +268,8 @@ static int tegra_rt5677_probe(struct platform_device *pdev)
 
 	ret = snd_soc_register_card(card);
 	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
+		dev_err_probe(&pdev->dev, ret,
+			      "snd_soc_register_card failed\n");
 		goto err_put_cpu_of_node;
 	}
 
diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c
index e1dc8e7d337a..885332170c77 100644
--- a/sound/soc/tegra/tegra_sgtl5000.c
+++ b/sound/soc/tegra/tegra_sgtl5000.c
@@ -154,8 +154,8 @@ static int tegra_sgtl5000_driver_probe(struct platform_device *pdev)
 
 	ret = snd_soc_register_card(card);
 	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
+		dev_err_probe(&pdev->dev, ret,
+			      "snd_soc_register_card failed\n");
 		goto err_put_cpu_of_node;
 	}
 
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
index fa41fa366daf..efd793886689 100644
--- a/sound/soc/tegra/tegra_wm8753.c
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -156,11 +156,9 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
 		return ret;
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "snd_soc_register_card failed\n");
 
 	return 0;
 }
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index ef6652aaac9b..e4863fa37b0c 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -352,11 +352,9 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
 		return ret;
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
-	if (ret) {
-		dev_err(&pdev->dev, "devm_snd_soc_register_card failed (%d)\n",
-			ret);
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "snd_soc_register_card failed\n");
 
 	return 0;
 }
diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c
index 726edfa21a29..4f09a178049d 100644
--- a/sound/soc/tegra/tegra_wm9712.c
+++ b/sound/soc/tegra/tegra_wm9712.c
@@ -117,8 +117,8 @@ static int tegra_wm9712_driver_probe(struct platform_device *pdev)
 
 	ret = snd_soc_register_card(card);
 	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
+		dev_err_probe(&pdev->dev, ret,
+			      "snd_soc_register_card failed\n");
 		goto codec_unregister;
 	}
 
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
index baae4cce7fc6..6c1cc3d0ac33 100644
--- a/sound/soc/tegra/trimslice.c
+++ b/sound/soc/tegra/trimslice.c
@@ -144,11 +144,9 @@ static int tegra_snd_trimslice_probe(struct platform_device *pdev)
 		return ret;
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "snd_soc_register_card failed\n");
 
 	return 0;
 }
diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig
index 9775393d46b6..698d7bc84dcf 100644
--- a/sound/soc/ti/Kconfig
+++ b/sound/soc/ti/Kconfig
@@ -26,6 +26,7 @@ config SND_SOC_DAVINCI_ASP
 
 config SND_SOC_DAVINCI_MCASP
 	tristate "Multichannel Audio Serial Port (McASP) support"
+	depends on COMMON_CLK
 	select SND_SOC_TI_EDMA_PCM
 	select SND_SOC_TI_SDMA_PCM
 	select SND_SOC_TI_UDMA_PCM
@@ -47,7 +48,7 @@ config SND_SOC_DAVINCI_VCIF
 
 config SND_SOC_OMAP_DMIC
 	tristate "Digital Microphone Module (DMIC) support"
-	depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST
+	depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST && COMMON_CLK
 	select SND_SOC_TI_SDMA_PCM
 	help
 	  Say Y or M here if you want to have support for DMIC IP found in
@@ -55,7 +56,7 @@ config SND_SOC_OMAP_DMIC
 
 config SND_SOC_OMAP_MCBSP
 	tristate "Multichannel Buffered Serial Port (McBSP) support"
-	depends on ARCH_OMAP || ARCH_OMAP1 || COMPILE_TEST
+	depends on ARCH_OMAP || ARCH_OMAP1 || COMPILE_TEST && COMMON_CLK
 	select SND_SOC_TI_SDMA_PCM
 	help
 	  Say Y or M here if you want to have support for McBSP IP found in
@@ -99,7 +100,7 @@ config SND_SOC_OMAP3_PANDORA
 
 config SND_SOC_OMAP3_TWL4030
 	tristate "SoC Audio support for OMAP3 based boards with twl4030 codec"
-	depends on ARCH_OMAP3 || COMPILE_TEST
+	depends on ARCH_OMAP3 || COMPILE_TEST && COMMON_CLK
 	depends on TWL4030_CORE
 	select SND_SOC_OMAP_MCBSP
 	select SND_SOC_TWL4030
@@ -221,7 +222,7 @@ config SND_SOC_DM365_VOICE_CODEC_MODULE
 
 config SND_SOC_J721E_EVM
 	tristate "SoC Audio support for j721e EVM"
-	depends on ARCH_K3 || COMPILE_TEST
+	depends on ARCH_K3 || COMPILE_TEST && COMMON_CLK
 	depends on I2C
 	select SND_SOC_PCM3168A_I2C
 	select SND_SOC_DAVINCI_MCASP
diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c
index 105e56ab9cdc..b043a0070d20 100644
--- a/sound/soc/ti/davinci-evm.c
+++ b/sound/soc/ti/davinci-evm.c
@@ -46,8 +46,7 @@ static void evm_shutdown(struct snd_pcm_substream *substream)
 	struct snd_soc_card_drvdata_davinci *drvdata =
 		snd_soc_card_get_drvdata(soc_card);
 
-	if (drvdata->mclk)
-		clk_disable_unprepare(drvdata->mclk);
+	clk_disable_unprepare(drvdata->mclk);
 }
 
 static int evm_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c
index dd34504c09ba..6dca51862dd7 100644
--- a/sound/soc/ti/davinci-i2s.c
+++ b/sound/soc/ti/davinci-i2s.c
@@ -747,7 +747,7 @@ static int davinci_i2s_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id davinci_i2s_match[] = {
+static const struct of_device_id davinci_i2s_match[] __maybe_unused = {
 	{ .compatible = "ti,da850-mcbsp" },
 	{},
 };
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index a6b72ad53b43..6247ec3d3a09 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -76,12 +76,16 @@ struct davinci_mcasp_ruledata {
 
 struct davinci_mcasp {
 	struct snd_dmaengine_dai_dma_data dma_data[2];
+	struct davinci_mcasp_pdata *pdata;
 	void __iomem *base;
 	u32 fifo_base;
 	struct device *dev;
 	struct snd_pcm_substream *substreams[2];
 	unsigned int dai_fmt;
 
+	/* Audio can not be enabled due to missing parameter(s) */
+	bool	missing_audio_param;
+
 	/* McASP specific data */
 	int	tdm_slots;
 	u32	tdm_mask[2];
@@ -94,7 +98,6 @@ struct davinci_mcasp {
 	u8	bclk_div;
 	int	streams;
 	u32	irq_request[2];
-	int	dma_request[2];
 
 	int	sysclk_freq;
 	bool	bclk_master;
@@ -1748,48 +1751,58 @@ err1:
 	return ret;
 }
 
-static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
-						struct platform_device *pdev)
+static bool davinci_mcasp_have_gpiochip(struct davinci_mcasp *mcasp)
 {
+#ifdef CONFIG_OF_GPIO
+	if (mcasp->dev->of_node &&
+	    of_property_read_bool(mcasp->dev->of_node, "gpio-controller"))
+		return true;
+#endif
+
+	return false;
+}
+
+static int davinci_mcasp_get_config(struct davinci_mcasp *mcasp,
+				    struct platform_device *pdev)
+{
+	const struct of_device_id *match = of_match_device(mcasp_dt_ids, &pdev->dev);
 	struct device_node *np = pdev->dev.of_node;
 	struct davinci_mcasp_pdata *pdata = NULL;
-	const struct of_device_id *match =
-			of_match_device(mcasp_dt_ids, &pdev->dev);
-	struct of_phandle_args dma_spec;
-
 	const u32 *of_serial_dir32;
 	u32 val;
-	int i, ret = 0;
+	int i;
 
 	if (pdev->dev.platform_data) {
 		pdata = pdev->dev.platform_data;
 		pdata->dismod = DISMOD_LOW;
-		return pdata;
+		goto out;
 	} else if (match) {
 		pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
 				     GFP_KERNEL);
 		if (!pdata)
-			return NULL;
+			return -ENOMEM;
 	} else {
-		/* control shouldn't reach here. something is wrong */
-		ret = -EINVAL;
-		goto nodata;
+		dev_err(&pdev->dev, "No compatible match found\n");
+		return -EINVAL;
 	}
 
-	ret = of_property_read_u32(np, "op-mode", &val);
-	if (ret >= 0)
+	if (of_property_read_u32(np, "op-mode", &val) == 0) {
 		pdata->op_mode = val;
+	} else {
+		mcasp->missing_audio_param = true;
+		goto out;
+	}
 
-	ret = of_property_read_u32(np, "tdm-slots", &val);
-	if (ret >= 0) {
+	if (of_property_read_u32(np, "tdm-slots", &val) == 0) {
 		if (val < 2 || val > 32) {
-			dev_err(&pdev->dev,
-				"tdm-slots must be in rage [2-32]\n");
-			ret = -EINVAL;
-			goto nodata;
+			dev_err(&pdev->dev, "tdm-slots must be in rage [2-32]\n");
+			return -EINVAL;
 		}
 
 		pdata->tdm_slots = val;
+	} else if (pdata->op_mode == DAVINCI_MCASP_IIS_MODE) {
+		mcasp->missing_audio_param = true;
+		goto out;
 	}
 
 	of_serial_dir32 = of_get_property(np, "serial-dir", &val);
@@ -1798,61 +1811,29 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
 		u8 *of_serial_dir = devm_kzalloc(&pdev->dev,
 						 (sizeof(*of_serial_dir) * val),
 						 GFP_KERNEL);
-		if (!of_serial_dir) {
-			ret = -ENOMEM;
-			goto nodata;
-		}
+		if (!of_serial_dir)
+			return -ENOMEM;
 
 		for (i = 0; i < val; i++)
 			of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
 
 		pdata->num_serializer = val;
 		pdata->serial_dir = of_serial_dir;
+	} else {
+		mcasp->missing_audio_param = true;
+		goto out;
 	}
 
-	ret = of_property_match_string(np, "dma-names", "tx");
-	if (ret < 0)
-		goto nodata;
-
-	ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
-					 &dma_spec);
-	if (ret < 0)
-		goto nodata;
-
-	pdata->tx_dma_channel = dma_spec.args[0];
-
-	/* RX is not valid in DIT mode */
-	if (pdata->op_mode != DAVINCI_MCASP_DIT_MODE) {
-		ret = of_property_match_string(np, "dma-names", "rx");
-		if (ret < 0)
-			goto nodata;
-
-		ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
-						 &dma_spec);
-		if (ret < 0)
-			goto nodata;
-
-		pdata->rx_dma_channel = dma_spec.args[0];
-	}
-
-	ret = of_property_read_u32(np, "tx-num-evt", &val);
-	if (ret >= 0)
+	if (of_property_read_u32(np, "tx-num-evt", &val) == 0)
 		pdata->txnumevt = val;
 
-	ret = of_property_read_u32(np, "rx-num-evt", &val);
-	if (ret >= 0)
+	if (of_property_read_u32(np, "rx-num-evt", &val) == 0)
 		pdata->rxnumevt = val;
 
-	ret = of_property_read_u32(np, "sram-size-playback", &val);
-	if (ret >= 0)
-		pdata->sram_size_playback = val;
-
-	ret = of_property_read_u32(np, "sram-size-capture", &val);
-	if (ret >= 0)
-		pdata->sram_size_capture = val;
+	if (of_property_read_u32(np, "auxclk-fs-ratio", &val) == 0)
+		mcasp->auxclk_fs_ratio = val;
 
-	ret = of_property_read_u32(np, "dismod", &val);
-	if (ret >= 0) {
+	if (of_property_read_u32(np, "dismod", &val) == 0) {
 		if (val == 0 || val == 2 || val == 3) {
 			pdata->dismod = DISMOD_VAL(val);
 		} else {
@@ -1863,15 +1844,50 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
 		pdata->dismod = DISMOD_LOW;
 	}
 
-	return  pdata;
+out:
+	mcasp->pdata = pdata;
+
+	if (mcasp->missing_audio_param) {
+		if (davinci_mcasp_have_gpiochip(mcasp)) {
+			dev_dbg(&pdev->dev, "Missing DT parameter(s) for audio\n");
+			return 0;
+		}
 
-nodata:
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Error populating platform data, err %d\n",
-			ret);
-		pdata = NULL;
+		dev_err(&pdev->dev, "Insufficient DT parameter(s)\n");
+		return -ENODEV;
 	}
-	return  pdata;
+
+	mcasp->op_mode = pdata->op_mode;
+	/* sanity check for tdm slots parameter */
+	if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
+		if (pdata->tdm_slots < 2) {
+			dev_warn(&pdev->dev, "invalid tdm slots: %d\n",
+				 pdata->tdm_slots);
+			mcasp->tdm_slots = 2;
+		} else if (pdata->tdm_slots > 32) {
+			dev_warn(&pdev->dev, "invalid tdm slots: %d\n",
+				 pdata->tdm_slots);
+			mcasp->tdm_slots = 32;
+		} else {
+			mcasp->tdm_slots = pdata->tdm_slots;
+		}
+	}
+
+	mcasp->num_serializer = pdata->num_serializer;
+#ifdef CONFIG_PM
+	mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
+						mcasp->num_serializer, sizeof(u32),
+						GFP_KERNEL);
+	if (!mcasp->context.xrsr_regs)
+		return -ENOMEM;
+#endif
+	mcasp->serial_dir = pdata->serial_dir;
+	mcasp->version = pdata->version;
+	mcasp->txnumevt = pdata->txnumevt;
+	mcasp->rxnumevt = pdata->rxnumevt;
+	mcasp->dismod = pdata->dismod;
+
+	return 0;
 }
 
 enum {
@@ -2090,7 +2106,7 @@ static const struct gpio_chip davinci_mcasp_template_chip = {
 
 static int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
 {
-	if (!of_property_read_bool(mcasp->dev->of_node, "gpio-controller"))
+	if (!davinci_mcasp_have_gpiochip(mcasp))
 		return 0;
 
 	mcasp->gpio_chip = davinci_mcasp_template_chip;
@@ -2110,30 +2126,12 @@ static inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
 }
 #endif /* CONFIG_GPIOLIB */
 
-static int davinci_mcasp_get_dt_params(struct davinci_mcasp *mcasp)
-{
-	struct device_node *np = mcasp->dev->of_node;
-	int ret;
-	u32 val;
-
-	if (!np)
-		return 0;
-
-	ret = of_property_read_u32(np, "auxclk-fs-ratio", &val);
-	if (ret >= 0)
-		mcasp->auxclk_fs_ratio = val;
-
-	return 0;
-}
-
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
 	struct snd_dmaengine_dai_dma_data *dma_data;
-	struct resource *mem, *res, *dat;
-	struct davinci_mcasp_pdata *pdata;
+	struct resource *mem, *dat;
 	struct davinci_mcasp *mcasp;
 	char *irq_name;
-	int *dma;
 	int irq;
 	int ret;
 
@@ -2147,12 +2145,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 	if (!mcasp)
 		return	-ENOMEM;
 
-	pdata = davinci_mcasp_set_pdata_from_of(pdev);
-	if (!pdata) {
-		dev_err(&pdev->dev, "no platform data\n");
-		return -EINVAL;
-	}
-
 	mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
 	if (!mem) {
 		dev_warn(&pdev->dev,
@@ -2168,44 +2160,25 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 	if (IS_ERR(mcasp->base))
 		return PTR_ERR(mcasp->base);
 
+	dev_set_drvdata(&pdev->dev, mcasp);
 	pm_runtime_enable(&pdev->dev);
 
-	mcasp->op_mode = pdata->op_mode;
-	/* sanity check for tdm slots parameter */
-	if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
-		if (pdata->tdm_slots < 2) {
-			dev_err(&pdev->dev, "invalid tdm slots: %d\n",
-				pdata->tdm_slots);
-			mcasp->tdm_slots = 2;
-		} else if (pdata->tdm_slots > 32) {
-			dev_err(&pdev->dev, "invalid tdm slots: %d\n",
-				pdata->tdm_slots);
-			mcasp->tdm_slots = 32;
-		} else {
-			mcasp->tdm_slots = pdata->tdm_slots;
-		}
-	}
-
-	mcasp->num_serializer = pdata->num_serializer;
-#ifdef CONFIG_PM
-	mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
-					mcasp->num_serializer, sizeof(u32),
-					GFP_KERNEL);
-	if (!mcasp->context.xrsr_regs) {
-		ret = -ENOMEM;
+	mcasp->dev = &pdev->dev;
+	ret = davinci_mcasp_get_config(mcasp, pdev);
+	if (ret)
 		goto err;
-	}
-#endif
-	mcasp->serial_dir = pdata->serial_dir;
-	mcasp->version = pdata->version;
-	mcasp->txnumevt = pdata->txnumevt;
-	mcasp->rxnumevt = pdata->rxnumevt;
-	mcasp->dismod = pdata->dismod;
 
-	mcasp->dev = &pdev->dev;
+	/* All PINS as McASP */
+	pm_runtime_get_sync(mcasp->dev);
+	mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
+	pm_runtime_put(mcasp->dev);
+
+	/* Skip audio related setup code if the configuration is not adequat */
+	if (mcasp->missing_audio_param)
+		goto no_audio;
 
-	irq = platform_get_irq_byname(pdev, "common");
-	if (irq >= 0) {
+	irq = platform_get_irq_byname_optional(pdev, "common");
+	if (irq > 0) {
 		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common",
 					  dev_name(&pdev->dev));
 		if (!irq_name) {
@@ -2225,8 +2198,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 		mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
 	}
 
-	irq = platform_get_irq_byname(pdev, "rx");
-	if (irq >= 0) {
+	irq = platform_get_irq_byname_optional(pdev, "rx");
+	if (irq > 0) {
 		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx",
 					  dev_name(&pdev->dev));
 		if (!irq_name) {
@@ -2244,8 +2217,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 		mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
 	}
 
-	irq = platform_get_irq_byname(pdev, "tx");
-	if (irq >= 0) {
+	irq = platform_get_irq_byname_optional(pdev, "tx");
+	if (irq > 0) {
 		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx",
 					  dev_name(&pdev->dev));
 		if (!irq_name) {
@@ -2268,45 +2241,22 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 		mcasp->dat_port = true;
 
 	dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+	dma_data->filter_data = "tx";
 	if (dat)
 		dma_data->addr = dat->start;
 	else
-		dma_data->addr = mem->start + davinci_mcasp_txdma_offset(pdata);
+		dma_data->addr = mem->start + davinci_mcasp_txdma_offset(mcasp->pdata);
 
-	dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
-	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (res)
-		*dma = res->start;
-	else
-		*dma = pdata->tx_dma_channel;
-
-	/* dmaengine filter data for DT and non-DT boot */
-	if (pdev->dev.of_node)
-		dma_data->filter_data = "tx";
-	else
-		dma_data->filter_data = dma;
 
 	/* RX is not valid in DIT mode */
 	if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
 		dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+		dma_data->filter_data = "rx";
 		if (dat)
 			dma_data->addr = dat->start;
 		else
 			dma_data->addr =
-				mem->start + davinci_mcasp_rxdma_offset(pdata);
-
-		dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE];
-		res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-		if (res)
-			*dma = res->start;
-		else
-			*dma = pdata->rx_dma_channel;
-
-		/* dmaengine filter data for DT and non-DT boot */
-		if (pdev->dev.of_node)
-			dma_data->filter_data = "rx";
-		else
-			dma_data->filter_data = dma;
+				mem->start + davinci_mcasp_rxdma_offset(mcasp->pdata);
 	}
 
 	if (mcasp->version < MCASP_VERSION_3) {
@@ -2346,26 +2296,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 	if (ret)
 		goto err;
 
-	dev_set_drvdata(&pdev->dev, mcasp);
-
 	mcasp_reparent_fck(pdev);
 
-	/* All PINS as McASP */
-	pm_runtime_get_sync(mcasp->dev);
-	mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
-	pm_runtime_put(mcasp->dev);
-
-	ret = davinci_mcasp_init_gpiochip(mcasp);
-	if (ret)
-		goto err;
-
-	ret = davinci_mcasp_get_dt_params(mcasp);
-	if (ret)
-		return -EINVAL;
-
-	ret = devm_snd_soc_register_component(&pdev->dev,
-					&davinci_mcasp_component,
-					&davinci_mcasp_dai[pdata->op_mode], 1);
+	ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
+					      &davinci_mcasp_dai[mcasp->op_mode], 1);
 
 	if (ret != 0)
 		goto err;
@@ -2385,7 +2319,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret);
 	case -EPROBE_DEFER:
 		goto err;
-		break;
 	}
 
 	if (ret) {
@@ -2393,8 +2326,14 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 		goto err;
 	}
 
-	return 0;
+no_audio:
+	ret = davinci_mcasp_init_gpiochip(mcasp);
+	if (ret) {
+		dev_err(&pdev->dev, "gpiochip registration failed: %d\n", ret);
+		goto err;
+	}
 
+	return 0;
 err:
 	pm_runtime_disable(&pdev->dev);
 	return ret;
diff --git a/sound/soc/uniphier/aio-ld11.c b/sound/soc/uniphier/aio-ld11.c
index 8b44f8dc4970..7b3cf5d751f6 100644
--- a/sound/soc/uniphier/aio-ld11.c
+++ b/sound/soc/uniphier/aio-ld11.c
@@ -372,7 +372,7 @@ static const struct uniphier_aio_chip_spec uniphier_aio_ld20_spec = {
 	.addr_ext  = 1,
 };
 
-static const struct of_device_id uniphier_aio_of_match[] = {
+static const struct of_device_id uniphier_aio_of_match[] __maybe_unused = {
 	{
 		.compatible = "socionext,uniphier-ld11-aio",
 		.data = &uniphier_aio_ld11_spec,
diff --git a/sound/soc/uniphier/aio-pxs2.c b/sound/soc/uniphier/aio-pxs2.c
index a1d05fe9d3c2..899904f7ffd6 100644
--- a/sound/soc/uniphier/aio-pxs2.c
+++ b/sound/soc/uniphier/aio-pxs2.c
@@ -282,7 +282,7 @@ static const struct uniphier_aio_chip_spec uniphier_aio_pxs2_spec = {
 	.addr_ext  = 0,
 };
 
-static const struct of_device_id uniphier_aio_of_match[] = {
+static const struct of_device_id uniphier_aio_of_match[] __maybe_unused = {
 	{
 		.compatible = "socionext,uniphier-pxs2-aio",
 		.data = &uniphier_aio_pxs2_spec,
diff --git a/sound/soc/uniphier/evea.c b/sound/soc/uniphier/evea.c
index d27e9ca07856..96343d19a1e0 100644
--- a/sound/soc/uniphier/evea.c
+++ b/sound/soc/uniphier/evea.c
@@ -551,7 +551,7 @@ static int evea_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id evea_of_match[] = {
+static const struct of_device_id evea_of_match[] __maybe_unused = {
 	{ .compatible = "socionext,uniphier-evea", },
 	{}
 };