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/Makefile2
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c90
-rw-r--r--sound/soc/amd/acp-pcm-dma.c623
-rw-r--r--sound/soc/amd/acp.h97
-rw-r--r--sound/soc/atmel/Kconfig9
-rw-r--r--sound/soc/atmel/Makefile2
-rw-r--r--sound/soc/atmel/atmel-i2s.c765
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c8
-rw-r--r--sound/soc/bcm/Kconfig3
-rw-r--r--sound/soc/cirrus/Kconfig17
-rw-r--r--sound/soc/cirrus/edb93xx.c2
-rw-r--r--sound/soc/cirrus/ep93xx-i2s.c106
-rw-r--r--sound/soc/cirrus/snappercl15.c2
-rw-r--r--sound/soc/codecs/Kconfig33
-rw-r--r--sound/soc/codecs/Makefile10
-rw-r--r--sound/soc/codecs/adau17x1.c9
-rw-r--r--sound/soc/codecs/cs35l35.c1
-rw-r--r--sound/soc/codecs/cs43130.c8
-rw-r--r--sound/soc/codecs/max98088.c13
-rw-r--r--sound/soc/codecs/max98095.c13
-rw-r--r--sound/soc/codecs/max9860.c44
-rw-r--r--sound/soc/codecs/max9860.h10
-rw-r--r--sound/soc/codecs/mt6351.c1505
-rw-r--r--sound/soc/codecs/mt6351.h105
-rw-r--r--sound/soc/codecs/nau8810.c19
-rw-r--r--sound/soc/codecs/nau8824.c13
-rw-r--r--sound/soc/codecs/pcm1789.c2
-rw-r--r--sound/soc/codecs/pcm512x-i2c.c17
-rw-r--r--sound/soc/codecs/rt1305.c1191
-rw-r--r--sound/soc/codecs/rt1305.h276
-rw-r--r--sound/soc/codecs/rt5640.c553
-rw-r--r--sound/soc/codecs/rt5640.h46
-rw-r--r--sound/soc/codecs/rt5645.c23
-rw-r--r--sound/soc/codecs/rt5663.c55
-rw-r--r--sound/soc/codecs/rt5663.h2
-rw-r--r--sound/soc/codecs/rt5668.c2639
-rw-r--r--sound/soc/codecs/rt5668.h1318
-rw-r--r--sound/soc/codecs/rt5670.c2
-rw-r--r--sound/soc/codecs/rt5677.c13
-rw-r--r--sound/soc/codecs/sgtl5000.c18
-rw-r--r--sound/soc/codecs/sgtl5000.h5
-rw-r--r--sound/soc/codecs/ssm2305.c104
-rw-r--r--sound/soc/codecs/tas6424.c72
-rw-r--r--sound/soc/codecs/tas6424.h4
-rw-r--r--sound/soc/codecs/tfa9879.c48
-rw-r--r--sound/soc/codecs/tfa9879.h7
-rw-r--r--sound/soc/codecs/tscs42xx.c203
-rw-r--r--sound/soc/codecs/tscs42xx.h2
-rw-r--r--sound/soc/codecs/tscs454.c3497
-rw-r--r--sound/soc/codecs/tscs454.h2323
-rw-r--r--sound/soc/codecs/wm2200.c4
-rw-r--r--sound/soc/codecs/wm5100.c8
-rw-r--r--sound/soc/codecs/wm8782.c9
-rw-r--r--sound/soc/codecs/wm8904.c2
-rw-r--r--sound/soc/codecs/wm_adsp.c19
-rw-r--r--sound/soc/davinci/Kconfig2
-rw-r--r--sound/soc/davinci/davinci-mcasp.c10
-rw-r--r--sound/soc/fsl/fsl_esai.c20
-rw-r--r--sound/soc/fsl/fsl_esai.h5
-rw-r--r--sound/soc/fsl/fsl_sai.c16
-rw-r--r--sound/soc/fsl/fsl_sai.h5
-rw-r--r--sound/soc/fsl/fsl_spdif.c24
-rw-r--r--sound/soc/fsl/fsl_spdif.h5
-rw-r--r--sound/soc/fsl/fsl_ssi.c60
-rw-r--r--sound/soc/fsl/fsl_ssi.h6
-rw-r--r--sound/soc/fsl/fsl_ssi_dbg.c20
-rw-r--r--sound/soc/generic/simple-card.c21
-rw-r--r--sound/soc/hisilicon/hi6210-i2s.c2
-rw-r--r--sound/soc/intel/Kconfig2
-rw-r--r--sound/soc/intel/boards/bxt_da7219_max98357a.c2
-rw-r--r--sound/soc/intel/boards/bxt_rt298.c2
-rw-r--r--sound/soc/intel/boards/byt-max98090.c2
-rw-r--r--sound/soc/intel/boards/bytcht_es8316.c2
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c568
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c18
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c2
-rw-r--r--sound/soc/intel/boards/cht_bsw_nau8824.c4
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c2
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c30
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98357a.c19
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c5
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c4
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c2
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c2
-rw-r--r--sound/soc/intel/boards/skl_rt286.c2
-rw-r--r--sound/soc/intel/skylake/skl-debug.c6
-rw-r--r--sound/soc/intel/skylake/skl-messages.c4
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c36
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.h3
-rw-r--r--sound/soc/intel/skylake/skl-sst.c34
-rw-r--r--sound/soc/intel/skylake/skl-topology.c171
-rw-r--r--sound/soc/intel/skylake/skl-topology.h2
-rw-r--r--sound/soc/intel/skylake/skl-tplg-interface.h172
-rw-r--r--sound/soc/intel/skylake/skl.c7
-rw-r--r--sound/soc/kirkwood/Kconfig1
-rw-r--r--sound/soc/mediatek/Kconfig20
-rw-r--r--sound/soc/mediatek/Makefile2
-rw-r--r--sound/soc/mediatek/common/Makefile14
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.c30
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.h10
-rw-r--r--sound/soc/mediatek/common/mtk-afe-platform-driver.c103
-rw-r--r--sound/soc/mediatek/common/mtk-afe-platform-driver.h22
-rw-r--r--sound/soc/mediatek/common/mtk-base-afe.h30
-rw-r--r--sound/soc/mediatek/mt2701/Makefile14
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c66
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h23
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-common.h38
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-pcm.c349
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-cs42448.c13
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-reg.h11
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-wm8960.c10
-rw-r--r--sound/soc/mediatek/mt6797/Makefile14
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-clk.c123
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-clk.h17
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-common.h58
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-pcm.c914
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-dai-adda.c396
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-dai-hostless.c112
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-dai-pcm.c312
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-interconnection.h33
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-mt6351.c223
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-reg.h1015
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-afe-common.h10
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-afe-pcm.c38
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-max98090.c10
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c10
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c10
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c10
-rw-r--r--sound/soc/omap/Kconfig28
-rw-r--r--sound/soc/omap/Makefile4
-rw-r--r--sound/soc/omap/n810.c21
-rw-r--r--sound/soc/omap/omap-dmic.c4
-rw-r--r--sound/soc/omap/omap-hdmi-audio.c5
-rw-r--r--sound/soc/omap/omap-mcbsp.c4
-rw-r--r--sound/soc/omap/omap-mcpdm.c4
-rw-r--r--sound/soc/omap/omap-pcm.c262
-rw-r--r--sound/soc/omap/sdma-pcm.c74
-rw-r--r--sound/soc/omap/sdma-pcm.h21
-rw-r--r--sound/soc/pxa/Kconfig1
-rw-r--r--sound/soc/pxa/pxa-ssp.c88
-rw-r--r--sound/soc/qcom/Kconfig57
-rw-r--r--sound/soc/qcom/Makefile5
-rw-r--r--sound/soc/qcom/apq8016_sbc.c3
-rw-r--r--sound/soc/qcom/apq8096.c255
-rw-r--r--sound/soc/qcom/qdsp6/Makefile8
-rw-r--r--sound/soc/qcom/qdsp6/q6adm.c646
-rw-r--r--sound/soc/qcom/qdsp6/q6adm.h27
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-dai.c1303
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.c1495
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.h211
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c624
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.c1399
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.h69
-rw-r--r--sound/soc/qcom/qdsp6/q6core.c380
-rw-r--r--sound/soc/qcom/qdsp6/q6core.h15
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-common.c66
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-common.h24
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-errno.h51
-rw-r--r--sound/soc/qcom/qdsp6/q6routing.c1006
-rw-r--r--sound/soc/qcom/qdsp6/q6routing.h9
-rw-r--r--sound/soc/rockchip/rk3399_gru_sound.c46
-rw-r--r--sound/soc/sh/Kconfig6
-rw-r--r--sound/soc/sh/rcar/cmd.c15
-rw-r--r--sound/soc/sh/rcar/core.c49
-rw-r--r--sound/soc/sh/rcar/dma.c11
-rw-r--r--sound/soc/sh/rcar/gen.c3
-rw-r--r--sound/soc/sh/rcar/rsnd.h4
-rw-r--r--sound/soc/sh/rcar/ssi.c13
-rw-r--r--sound/soc/soc-cache.c53
-rw-r--r--sound/soc/soc-compress.c385
-rw-r--r--sound/soc/soc-core.c794
-rw-r--r--sound/soc/soc-dapm.c22
-rw-r--r--sound/soc/soc-devres.c35
-rw-r--r--sound/soc/soc-io.c83
-rw-r--r--sound/soc/soc-jack.c22
-rw-r--r--sound/soc/soc-pcm.c147
-rw-r--r--sound/soc/soc-topology.c93
-rw-r--r--sound/soc/uniphier/aio-compress.c13
-rw-r--r--sound/soc/uniphier/aio-core.c71
-rw-r--r--sound/soc/uniphier/aio-cpu.c153
-rw-r--r--sound/soc/uniphier/aio-dma.c13
-rw-r--r--sound/soc/uniphier/aio-ld11.c13
-rw-r--r--sound/soc/uniphier/aio-reg.h46
-rw-r--r--sound/soc/uniphier/aio.h20
-rw-r--r--sound/soc/uniphier/evea.c55
-rw-r--r--sound/soc/zte/zx-i2s.c5
186 files changed, 28060 insertions, 3610 deletions
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 8d92492183d2..06389a5385d7 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
+snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o
 snd-soc-core-objs += soc-pcm.o soc-io.o soc-devres.o soc-ops.o
 snd-soc-core-$(CONFIG_SND_SOC_COMPRESS) += soc-compress.o
 
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index f41560ecbcd1..ccddc6650b9c 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -33,17 +33,19 @@
 #include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
+#include <linux/input.h>
 #include <linux/acpi.h>
 
+#include "acp.h"
 #include "../codecs/da7219.h"
 #include "../codecs/da7219-aad.h"
 
-#define CZ_PLAT_CLK 24000000
-#define MCLK_RATE 24576000
+#define CZ_PLAT_CLK 25000000
 #define DUAL_CHANNEL		2
 
 static struct snd_soc_jack cz_jack;
 static struct clk *da7219_dai_clk;
+extern int bt_uart_enable;
 
 static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
 {
@@ -62,7 +64,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
 	}
 
 	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL,
-				  CZ_PLAT_CLK, MCLK_RATE);
+				  CZ_PLAT_CLK, DA7219_PLL_FREQ_OUT_98304);
 	if (ret < 0) {
 		dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
 		return ret;
@@ -80,13 +82,17 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
 		return ret;
 	}
 
+	snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+	snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+	snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+	snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+
 	da7219_aad_jack_det(component, &cz_jack);
 
 	return 0;
 }
 
-static int cz_da7219_hw_params(struct snd_pcm_substream *substream,
-			     struct snd_pcm_hw_params *params)
+static int da7219_clk_enable(struct snd_pcm_substream *substream)
 {
 	int ret = 0;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -100,11 +106,9 @@ static int cz_da7219_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static int cz_da7219_hw_free(struct snd_pcm_substream *substream)
+static void da7219_clk_disable(void)
 {
 	clk_disable_unprepare(da7219_dai_clk);
-
-	return 0;
 }
 
 static const unsigned int channels[] = {
@@ -127,9 +131,12 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
 	.mask = 0,
 };
 
-static int cz_fe_startup(struct snd_pcm_substream *substream)
+static int cz_da7219_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 
 	/*
 	 * On this platform for PCM device we support stereo
@@ -141,23 +148,58 @@ static int cz_fe_startup(struct snd_pcm_substream *substream)
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 				   &constraints_rates);
 
-	return 0;
+	machine->i2s_instance = I2S_BT_INSTANCE;
+	return da7219_clk_enable(substream);
+}
+
+static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
+{
+	da7219_clk_disable();
+}
+
+static int cz_max_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
+
+	machine->i2s_instance = I2S_SP_INSTANCE;
+	return da7219_clk_enable(substream);
+}
+
+static void cz_max_shutdown(struct snd_pcm_substream *substream)
+{
+	da7219_clk_disable();
+}
+
+static int cz_dmic_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
+
+	machine->i2s_instance = I2S_SP_INSTANCE;
+	return da7219_clk_enable(substream);
+}
+
+static void cz_dmic_shutdown(struct snd_pcm_substream *substream)
+{
+	da7219_clk_disable();
 }
 
-static struct snd_soc_ops cz_da7219_cap_ops = {
-	.hw_params = cz_da7219_hw_params,
-	.hw_free = cz_da7219_hw_free,
-	.startup = cz_fe_startup,
+static const struct snd_soc_ops cz_da7219_cap_ops = {
+	.startup = cz_da7219_startup,
+	.shutdown = cz_da7219_shutdown,
 };
 
-static struct snd_soc_ops cz_max_play_ops = {
-	.hw_params = cz_da7219_hw_params,
-	.hw_free = cz_da7219_hw_free,
+static const struct snd_soc_ops cz_max_play_ops = {
+	.startup = cz_max_startup,
+	.shutdown = cz_max_shutdown,
 };
 
-static struct snd_soc_ops cz_dmic_cap_ops = {
-	.hw_params = cz_da7219_hw_params,
-	.hw_free = cz_da7219_hw_free,
+static const struct snd_soc_ops cz_dmic_cap_ops = {
+	.startup = cz_dmic_startup,
+	.shutdown = cz_dmic_shutdown,
 };
 
 static struct snd_soc_dai_link cz_dai_7219_98357[] = {
@@ -240,10 +282,16 @@ static int cz_probe(struct platform_device *pdev)
 {
 	int ret;
 	struct snd_soc_card *card;
+	struct acp_platform_info *machine;
 
+	machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info),
+			       GFP_KERNEL);
+	if (!machine)
+		return -ENOMEM;
 	card = &cz_card;
 	cz_card.dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
+	snd_soc_card_set_drvdata(card, machine);
 	ret = devm_snd_soc_register_card(&pdev->dev, &cz_card);
 	if (ret) {
 		dev_err(&pdev->dev,
@@ -251,6 +299,8 @@ static int cz_probe(struct platform_device *pdev)
 				cz_card.name, ret);
 		return ret;
 	}
+	bt_uart_enable = !device_property_read_bool(&pdev->dev,
+						    "bt-pad-enable");
 	return 0;
 }
 
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index 540088d317f2..77203841c535 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -37,12 +37,14 @@
 #define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
 #define MIN_BUFFER MAX_BUFFER
 
-#define ST_PLAYBACK_MAX_PERIOD_SIZE 8192
+#define ST_PLAYBACK_MAX_PERIOD_SIZE 4096
 #define ST_CAPTURE_MAX_PERIOD_SIZE  ST_PLAYBACK_MAX_PERIOD_SIZE
 #define ST_MAX_BUFFER (ST_PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
 #define ST_MIN_BUFFER ST_MAX_BUFFER
 
 #define DRV_NAME "acp_audio_dma"
+bool bt_uart_enable = true;
+EXPORT_SYMBOL(bt_uart_enable);
 
 static const struct snd_pcm_hardware acp_pcm_hardware_playback = {
 	.info = SNDRV_PCM_INFO_INTERLEAVED |
@@ -130,7 +132,8 @@ static void acp_reg_write(u32 val, void __iomem *acp_mmio, u32 reg)
 	writel(val, acp_mmio + (reg * 4));
 }
 
-/* Configure a given dma channel parameters - enable/disable,
+/*
+ * Configure a given dma channel parameters - enable/disable,
  * number of descriptors, priority
  */
 static void config_acp_dma_channel(void __iomem *acp_mmio, u8 ch_num,
@@ -149,11 +152,12 @@ static void config_acp_dma_channel(void __iomem *acp_mmio, u8 ch_num,
 			& dscr_strt_idx),
 			acp_mmio, mmACP_DMA_DSCR_STRT_IDX_0 + ch_num);
 
-	/* program a DMA channel with the number of descriptors to be
+	/*
+	 * program a DMA channel with the number of descriptors to be
 	 * processed in the transfer
-	*/
+	 */
 	acp_reg_write(ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK & num_dscrs,
-		acp_mmio, mmACP_DMA_DSCR_CNT_0 + ch_num);
+		      acp_mmio, mmACP_DMA_DSCR_CNT_0 + ch_num);
 
 	/* set DMA channel priority */
 	acp_reg_write(priority_level, acp_mmio, mmACP_DMA_PRIO_0 + ch_num);
@@ -180,13 +184,15 @@ static void config_dma_descriptor_in_sram(void __iomem *acp_mmio,
 	acp_reg_write(descr_info->xfer_val, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
 }
 
-/* Initialize the DMA descriptor information for transfer between
+/*
+ * Initialize the DMA descriptor information for transfer between
  * system memory <-> ACP SRAM
  */
 static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
-					u32 size, int direction, u32 pte_offset,
-					u16 ch, u32 sram_bank,
-					u16 dma_dscr_idx, u32 asic_type)
+					   u32 size, int direction,
+					   u32 pte_offset, u16 ch,
+					   u32 sram_bank, u16 dma_dscr_idx,
+					   u32 asic_type)
 {
 	u16 i;
 	acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
@@ -195,58 +201,58 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
 		dmadscr[i].xfer_val = 0;
 		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
 			dma_dscr_idx = dma_dscr_idx + i;
-			dmadscr[i].dest = sram_bank + (i * (size/2));
+			dmadscr[i].dest = sram_bank + (i * (size / 2));
 			dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
-				+ (pte_offset * SZ_4K) + (i * (size/2));
+				+ (pte_offset * SZ_4K) + (i * (size / 2));
 			switch (asic_type) {
 			case CHIP_STONEY:
 				dmadscr[i].xfer_val |=
-				(ACP_DMA_ATTRIBUTES_DAGB_GARLIC_TO_SHAREDMEM  << 16) |
+				(ACP_DMA_ATTR_DAGB_GARLIC_TO_SHAREDMEM  << 16) |
 				(size / 2);
 				break;
 			default:
 				dmadscr[i].xfer_val |=
-				(ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM  << 16) |
+				(ACP_DMA_ATTR_DAGB_ONION_TO_SHAREDMEM  << 16) |
 				(size / 2);
 			}
 		} else {
 			dma_dscr_idx = dma_dscr_idx + i;
-			dmadscr[i].src = sram_bank + (i * (size/2));
+			dmadscr[i].src = sram_bank + (i * (size / 2));
 			dmadscr[i].dest =
 			ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
-			(pte_offset * SZ_4K) + (i * (size/2));
+			(pte_offset * SZ_4K) + (i * (size / 2));
 			switch (asic_type) {
 			case CHIP_STONEY:
 				dmadscr[i].xfer_val |=
 				BIT(22) |
-				(ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC << 16) |
+				(ACP_DMA_ATTR_SHARED_MEM_TO_DAGB_GARLIC << 16) |
 				(size / 2);
 				break;
 			default:
 				dmadscr[i].xfer_val |=
 				BIT(22) |
-				(ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) |
+				(ACP_DMA_ATTR_SHAREDMEM_TO_DAGB_ONION << 16) |
 				(size / 2);
 			}
 		}
 		config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
-						&dmadscr[i]);
+					      &dmadscr[i]);
 	}
 	config_acp_dma_channel(acp_mmio, ch,
-				dma_dscr_idx - 1,
-				NUM_DSCRS_PER_CHANNEL,
-				ACP_DMA_PRIORITY_LEVEL_NORMAL);
+			       dma_dscr_idx - 1,
+			       NUM_DSCRS_PER_CHANNEL,
+			       ACP_DMA_PRIORITY_LEVEL_NORMAL);
 }
 
-/* Initialize the DMA descriptor information for transfer between
+/*
+ * Initialize the DMA descriptor information for transfer between
  * ACP SRAM <-> I2S
  */
 static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size,
-						int direction, u32 sram_bank,
-						u16 destination, u16 ch,
-						u16 dma_dscr_idx, u32 asic_type)
+					   int direction, u32 sram_bank,
+					   u16 destination, u16 ch,
+					   u16 dma_dscr_idx, u32 asic_type)
 {
-
 	u16 i;
 	acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
 
@@ -254,7 +260,7 @@ static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size,
 		dmadscr[i].xfer_val = 0;
 		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
 			dma_dscr_idx = dma_dscr_idx + i;
-			dmadscr[i].src = sram_bank  + (i * (size/2));
+			dmadscr[i].src = sram_bank  + (i * (size / 2));
 			/* dmadscr[i].dest is unused by hardware. */
 			dmadscr[i].dest = 0;
 			dmadscr[i].xfer_val |= BIT(22) | (destination << 16) |
@@ -269,12 +275,12 @@ static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size,
 				(destination << 16) | (size / 2);
 		}
 		config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
-						&dmadscr[i]);
+					      &dmadscr[i]);
 	}
 	/* Configure the DMA channel with the above descriptore */
 	config_acp_dma_channel(acp_mmio, ch, dma_dscr_idx - 1,
-				NUM_DSCRS_PER_CHANNEL,
-				ACP_DMA_PRIORITY_LEVEL_NORMAL);
+			       NUM_DSCRS_PER_CHANNEL,
+			       ACP_DMA_PRIORITY_LEVEL_NORMAL);
 }
 
 /* Create page table entries in ACP SRAM for the allocated memory */
@@ -291,7 +297,7 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
 	for (page_idx = 0; page_idx < (num_of_pages); page_idx++) {
 		/* Load the low address of page int ACP SRAM through SRBM */
 		acp_reg_write((offset + (page_idx * 8)),
-			acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+			      acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
 		addr = page_to_phys(pg);
 
 		low = lower_32_bits(addr);
@@ -301,7 +307,7 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
 
 		/* Load the High address of page int ACP SRAM through SRBM */
 		acp_reg_write((offset + (page_idx * 8) + 4),
-			acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+			      acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
 
 		/* page enable in ACP */
 		high |= BIT(31);
@@ -313,59 +319,25 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
 }
 
 static void config_acp_dma(void __iomem *acp_mmio,
-			struct audio_substream_data *audio_config,
-			u32 asic_type)
+			   struct audio_substream_data *rtd,
+			   u32 asic_type)
 {
-	u32 pte_offset, sram_bank;
-	u16 ch1, ch2, destination, dma_dscr_idx;
-
-	if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK) {
-		pte_offset = ACP_PLAYBACK_PTE_OFFSET;
-		ch1 = SYSRAM_TO_ACP_CH_NUM;
-		ch2 = ACP_TO_I2S_DMA_CH_NUM;
-		sram_bank = ACP_SHARED_RAM_BANK_1_ADDRESS;
-		destination = TO_ACP_I2S_1;
-
-	} else {
-		pte_offset = ACP_CAPTURE_PTE_OFFSET;
-		ch1 = SYSRAM_TO_ACP_CH_NUM;
-		ch2 = ACP_TO_I2S_DMA_CH_NUM;
-		switch (asic_type) {
-		case CHIP_STONEY:
-			sram_bank = ACP_SHARED_RAM_BANK_3_ADDRESS;
-			break;
-		default:
-			sram_bank = ACP_SHARED_RAM_BANK_5_ADDRESS;
-		}
-		destination = FROM_ACP_I2S_1;
-	}
-
-	acp_pte_config(acp_mmio, audio_config->pg, audio_config->num_of_pages,
-			pte_offset);
-	if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
-		dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
-	else
-		dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
-
+	acp_pte_config(acp_mmio, rtd->pg, rtd->num_of_pages,
+		       rtd->pte_offset);
 	/* Configure System memory <-> ACP SRAM DMA descriptors */
-	set_acp_sysmem_dma_descriptors(acp_mmio, audio_config->size,
-				       audio_config->direction, pte_offset,
-					ch1, sram_bank, dma_dscr_idx, asic_type);
-
-	if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
-		dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13;
-	else
-		dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15;
+	set_acp_sysmem_dma_descriptors(acp_mmio, rtd->size,
+				       rtd->direction, rtd->pte_offset,
+				       rtd->ch1, rtd->sram_bank,
+				       rtd->dma_dscr_idx_1, asic_type);
 	/* Configure ACP SRAM <-> I2S DMA descriptors */
-	set_acp_to_i2s_dma_descriptors(acp_mmio, audio_config->size,
-					audio_config->direction, sram_bank,
-					destination, ch2, dma_dscr_idx,
-					asic_type);
+	set_acp_to_i2s_dma_descriptors(acp_mmio, rtd->size,
+				       rtd->direction, rtd->sram_bank,
+				       rtd->destination, rtd->ch2,
+				       rtd->dma_dscr_idx_2, asic_type);
 }
 
 /* Start a given DMA channel transfer */
-static void acp_dma_start(void __iomem *acp_mmio,
-			 u16 ch_num, bool is_circular)
+static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
 {
 	u32 dma_ctrl;
 
@@ -375,7 +347,8 @@ static void acp_dma_start(void __iomem *acp_mmio,
 	/* Invalidating the DAGB cache */
 	acp_reg_write(1, acp_mmio, mmACP_DAGB_ATU_CTRL);
 
-	/* configure the DMA channel and start the DMA transfer
+	/*
+	 * configure the DMA channel and start the DMA transfer
 	 * set dmachrun bit to start the transfer and enable the
 	 * interrupt on completion of the dma transfer
 	 */
@@ -385,6 +358,9 @@ static void acp_dma_start(void __iomem *acp_mmio,
 	case ACP_TO_I2S_DMA_CH_NUM:
 	case ACP_TO_SYSRAM_CH_NUM:
 	case I2S_TO_ACP_DMA_CH_NUM:
+	case ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM:
+	case ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM:
+	case I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM:
 		dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
 		break;
 	default:
@@ -392,11 +368,8 @@ static void acp_dma_start(void __iomem *acp_mmio,
 		break;
 	}
 
-	/* enable  for ACP SRAM to/from I2S DMA channel */
-	if (is_circular == true)
-		dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
-	else
-		dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
+	/* circular for both DMA channel */
+	dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
 
 	acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
 }
@@ -410,9 +383,10 @@ static int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num)
 
 	dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
 
-	/* clear the dma control register fields before writing zero
+	/*
+	 * clear the dma control register fields before writing zero
 	 * in reset bit
-	*/
+	 */
 	dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK;
 	dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
 
@@ -420,9 +394,10 @@ static int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num)
 	dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS);
 
 	if (dma_ch_sts & BIT(ch_num)) {
-		/* set the reset bit for this channel to stop the dma
-		*  transfer
-		*/
+		/*
+		 * set the reset bit for this channel to stop the dma
+		 *  transfer
+		 */
 		dma_ctrl |= ACP_DMA_CNTL_0__DMAChRst_MASK;
 		acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
 	}
@@ -431,13 +406,14 @@ static int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num)
 	while (true) {
 		dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS);
 		if (!(dma_ch_sts & BIT(ch_num))) {
-			/* clear the reset flag after successfully stopping
-			* the dma transfer and break from the loop
-			*/
+			/*
+			 * clear the reset flag after successfully stopping
+			 * the dma transfer and break from the loop
+			 */
 			dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRst_MASK;
 
 			acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0
-								+ ch_num);
+				      + ch_num);
 			break;
 		}
 		if (--count == 0) {
@@ -450,7 +426,7 @@ static int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num)
 }
 
 static void acp_set_sram_bank_state(void __iomem *acp_mmio, u16 bank,
-					bool power_on)
+				    bool power_on)
 {
 	u32 val, req_reg, sts_reg, sts_reg_mask;
 	u32 loops = 1000;
@@ -530,7 +506,7 @@ static int acp_init(void __iomem *acp_mmio, u32 asic_type)
 
 	while (true) {
 		val = acp_reg_read(acp_mmio, mmACP_STATUS);
-		if (val & (u32) 0x1)
+		if (val & (u32)0x1)
 			break;
 		if (--count == 0) {
 			pr_err("Failed to reset ACP\n");
@@ -544,13 +520,20 @@ static int acp_init(void __iomem *acp_mmio, u32 asic_type)
 	val &= ~ACP_SOFT_RESET__SoftResetAud_MASK;
 	acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET);
 
+	/* For BT instance change pins from UART to BT */
+	if (!bt_uart_enable) {
+		val = acp_reg_read(acp_mmio, mmACP_BT_UART_PAD_SEL);
+		val |= ACP_BT_UART_PAD_SELECT_MASK;
+		acp_reg_write(val, acp_mmio, mmACP_BT_UART_PAD_SEL);
+	}
+
 	/* initiailize Onion control DAGB register */
 	acp_reg_write(ACP_ONION_CNTL_DEFAULT, acp_mmio,
-			mmACP_AXI2DAGB_ONION_CNTL);
+		      mmACP_AXI2DAGB_ONION_CNTL);
 
 	/* initiailize Garlic control DAGB registers */
 	acp_reg_write(ACP_GARLIC_CNTL_DEFAULT, acp_mmio,
-			mmACP_AXI2DAGB_GARLIC_CNTL);
+		      mmACP_AXI2DAGB_GARLIC_CNTL);
 
 	sram_pte_offset = ACP_DAGB_GRP_SRAM_BASE_ADDRESS |
 			ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK |
@@ -558,17 +541,18 @@ static int acp_init(void __iomem *acp_mmio, u32 asic_type)
 			ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK;
 	acp_reg_write(sram_pte_offset,  acp_mmio, mmACP_DAGB_BASE_ADDR_GRP_1);
 	acp_reg_write(ACP_PAGE_SIZE_4K_ENABLE, acp_mmio,
-			mmACP_DAGB_PAGE_SIZE_GRP_1);
+		      mmACP_DAGB_PAGE_SIZE_GRP_1);
 
 	acp_reg_write(ACP_SRAM_BASE_ADDRESS, acp_mmio,
-			mmACP_DMA_DESC_BASE_ADDR);
+		      mmACP_DMA_DESC_BASE_ADDR);
 
 	/* Num of descriptiors in SRAM 0x4, means 256 descriptors;(64 * 4) */
 	acp_reg_write(0x4, acp_mmio, mmACP_DMA_DESC_MAX_NUM_DSCR);
 	acp_reg_write(ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK,
-		acp_mmio, mmACP_EXTERNAL_INTR_CNTL);
+		      acp_mmio, mmACP_EXTERNAL_INTR_CNTL);
 
-       /* When ACP_TILE_P1 is turned on, all SRAM banks get turned on.
+       /*
+	* When ACP_TILE_P1 is turned on, all SRAM banks get turned on.
 	* Now, turn off all of them. This can't be done in 'poweron' of
 	* ACP pm domain, as this requires ACP to be initialized.
 	* For Stoney, Memory gating is disabled,i.e SRAM Banks
@@ -606,7 +590,7 @@ static int acp_deinit(void __iomem *acp_mmio)
 		}
 		udelay(100);
 	}
-	/** Disable ACP clock */
+	/* Disable ACP clock */
 	val = acp_reg_read(acp_mmio, mmACP_CONTROL);
 	val &= ~ACP_CONTROL__ClkEn_MASK;
 	acp_reg_write(val, acp_mmio, mmACP_CONTROL);
@@ -615,7 +599,7 @@ static int acp_deinit(void __iomem *acp_mmio)
 
 	while (true) {
 		val = acp_reg_read(acp_mmio, mmACP_STATUS);
-		if (!(val & (u32) 0x1))
+		if (!(val & (u32)0x1))
 			break;
 		if (--count == 0) {
 			pr_err("Failed to reset ACP\n");
@@ -629,7 +613,6 @@ static int acp_deinit(void __iomem *acp_mmio)
 /* ACP DMA irq handler routine for playback, capture usecases */
 static irqreturn_t dma_irq_handler(int irq, void *arg)
 {
-	u16 dscr_idx;
 	u32 intr_flag, ext_intr_status;
 	struct audio_drv_data *irq_data;
 	void __iomem *acp_mmio;
@@ -646,41 +629,45 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
 
 	if ((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) != 0) {
 		valid_irq = true;
-		if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_13) ==
-				PLAYBACK_START_DMA_DESCR_CH13)
-			dscr_idx = PLAYBACK_END_DMA_DESCR_CH12;
-		else
-			dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
-		config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM, dscr_idx,
-				       1, 0);
-		acp_dma_start(acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
-
 		snd_pcm_period_elapsed(irq_data->play_i2ssp_stream);
-
 		acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) << 16,
-				acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+			      acp_mmio, mmACP_EXTERNAL_INTR_STAT);
 	}
 
-	if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) {
+	if ((intr_flag & BIT(ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM)) != 0) {
 		valid_irq = true;
-		if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_15) ==
-				CAPTURE_START_DMA_DESCR_CH15)
-			dscr_idx = CAPTURE_END_DMA_DESCR_CH14;
-		else
-			dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
-		config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, dscr_idx,
-				       1, 0);
-		acp_dma_start(acp_mmio, ACP_TO_SYSRAM_CH_NUM, false);
+		snd_pcm_period_elapsed(irq_data->play_i2sbt_stream);
+		acp_reg_write((intr_flag &
+			      BIT(ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM)) << 16,
+			      acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+	}
 
+	if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) {
+		valid_irq = true;
+		snd_pcm_period_elapsed(irq_data->capture_i2ssp_stream);
 		acp_reg_write((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) << 16,
-				acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+			      acp_mmio, mmACP_EXTERNAL_INTR_STAT);
 	}
 
 	if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) {
 		valid_irq = true;
-		snd_pcm_period_elapsed(irq_data->capture_i2ssp_stream);
 		acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16,
-				acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+			      acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+	}
+
+	if ((intr_flag & BIT(I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM)) != 0) {
+		valid_irq = true;
+		snd_pcm_period_elapsed(irq_data->capture_i2sbt_stream);
+		acp_reg_write((intr_flag &
+			      BIT(I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM)) << 16,
+			      acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+	}
+
+	if ((intr_flag & BIT(ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM)) != 0) {
+		valid_irq = true;
+		acp_reg_write((intr_flag &
+			      BIT(ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM)) << 16,
+			      acp_mmio, mmACP_EXTERNAL_INTR_STAT);
 	}
 
 	if (valid_irq)
@@ -695,11 +682,12 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
 	int ret = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *prtd = substream->private_data;
-	struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
+								    DRV_NAME);
 	struct audio_drv_data *intr_data = dev_get_drvdata(component->dev);
 	struct audio_substream_data *adata =
 		kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL);
-	if (adata == NULL)
+	if (!adata)
 		return -ENOMEM;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -731,17 +719,19 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
 	adata->acp_mmio = intr_data->acp_mmio;
 	runtime->private_data = adata;
 
-	/* Enable ACP irq, when neither playback or capture streams are
+	/*
+	 * Enable ACP irq, when neither playback or capture streams are
 	 * active by the time when a new stream is being opened.
 	 * This enablement is not required for another stream, if current
 	 * stream is not closed
-	*/
-	if (!intr_data->play_i2ssp_stream && !intr_data->capture_i2ssp_stream)
+	 */
+	if (!intr_data->play_i2ssp_stream && !intr_data->capture_i2ssp_stream &&
+	    !intr_data->play_i2sbt_stream && !intr_data->capture_i2sbt_stream)
 		acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		intr_data->play_i2ssp_stream = substream;
-		/* For Stoney, Memory gating is disabled,i.e SRAM Banks
+		/*
+		 * For Stoney, Memory gating is disabled,i.e SRAM Banks
 		 * won't be turned off. The default state for SRAM banks is ON.
 		 * Setting SRAM bank state code skipped for STONEY platform.
 		 */
@@ -751,7 +741,6 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
 							bank, true);
 		}
 	} else {
-		intr_data->capture_i2ssp_stream = substream;
 		if (intr_data->asic_type != CHIP_STONEY) {
 			for (bank = 5; bank <= 8; bank++)
 				acp_set_sram_bank_state(intr_data->acp_mmio,
@@ -772,8 +761,11 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_runtime *runtime;
 	struct audio_substream_data *rtd;
 	struct snd_soc_pcm_runtime *prtd = substream->private_data;
-	struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
+								    DRV_NAME);
 	struct audio_drv_data *adata = dev_get_drvdata(component->dev);
+	struct snd_soc_card *card = prtd->card;
+	struct acp_platform_info *pinfo = snd_soc_card_get_drvdata(card);
 
 	runtime = substream->runtime;
 	rtd = runtime->private_data;
@@ -781,14 +773,111 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
 	if (WARN_ON(!rtd))
 		return -EINVAL;
 
+	rtd->i2s_instance = pinfo->i2s_instance;
 	if (adata->asic_type == CHIP_STONEY) {
-		val = acp_reg_read(adata->acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			val |= ACP_I2S_SP_16BIT_RESOLUTION_EN;
-		else
-			val |= ACP_I2S_MIC_16BIT_RESOLUTION_EN;
-		acp_reg_write(val, adata->acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
+		val = acp_reg_read(adata->acp_mmio,
+				   mmACP_I2S_16BIT_RESOLUTION_EN);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			switch (rtd->i2s_instance) {
+			case I2S_BT_INSTANCE:
+				val |= ACP_I2S_BT_16BIT_RESOLUTION_EN;
+				break;
+			case I2S_SP_INSTANCE:
+			default:
+				val |= ACP_I2S_SP_16BIT_RESOLUTION_EN;
+			}
+		} else {
+			switch (rtd->i2s_instance) {
+			case I2S_BT_INSTANCE:
+				val |= ACP_I2S_BT_16BIT_RESOLUTION_EN;
+				break;
+			case I2S_SP_INSTANCE:
+			default:
+				val |= ACP_I2S_MIC_16BIT_RESOLUTION_EN;
+			}
+		}
+		acp_reg_write(val, adata->acp_mmio,
+			      mmACP_I2S_16BIT_RESOLUTION_EN);
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		switch (rtd->i2s_instance) {
+		case I2S_BT_INSTANCE:
+			rtd->pte_offset = ACP_ST_BT_PLAYBACK_PTE_OFFSET;
+			rtd->ch1 = SYSRAM_TO_ACP_BT_INSTANCE_CH_NUM;
+			rtd->ch2 = ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM;
+			rtd->sram_bank = ACP_SRAM_BANK_3_ADDRESS;
+			rtd->destination = TO_BLUETOOTH;
+			rtd->dma_dscr_idx_1 = PLAYBACK_START_DMA_DESCR_CH8;
+			rtd->dma_dscr_idx_2 = PLAYBACK_START_DMA_DESCR_CH9;
+			rtd->byte_cnt_high_reg_offset =
+					mmACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH;
+			rtd->byte_cnt_low_reg_offset =
+					mmACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW;
+			adata->play_i2sbt_stream = substream;
+			break;
+		case I2S_SP_INSTANCE:
+		default:
+			switch (adata->asic_type) {
+			case CHIP_STONEY:
+				rtd->pte_offset = ACP_ST_PLAYBACK_PTE_OFFSET;
+				break;
+			default:
+				rtd->pte_offset = ACP_PLAYBACK_PTE_OFFSET;
+			}
+			rtd->ch1 = SYSRAM_TO_ACP_CH_NUM;
+			rtd->ch2 = ACP_TO_I2S_DMA_CH_NUM;
+			rtd->sram_bank = ACP_SRAM_BANK_1_ADDRESS;
+			rtd->destination = TO_ACP_I2S_1;
+			rtd->dma_dscr_idx_1 = PLAYBACK_START_DMA_DESCR_CH12;
+			rtd->dma_dscr_idx_2 = PLAYBACK_START_DMA_DESCR_CH13;
+			rtd->byte_cnt_high_reg_offset =
+					mmACP_I2S_TRANSMIT_BYTE_CNT_HIGH;
+			rtd->byte_cnt_low_reg_offset =
+					mmACP_I2S_TRANSMIT_BYTE_CNT_LOW;
+			adata->play_i2ssp_stream = substream;
+		}
+	} else {
+		switch (rtd->i2s_instance) {
+		case I2S_BT_INSTANCE:
+			rtd->pte_offset = ACP_ST_BT_CAPTURE_PTE_OFFSET;
+			rtd->ch1 = ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM;
+			rtd->ch2 = I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM;
+			rtd->sram_bank = ACP_SRAM_BANK_4_ADDRESS;
+			rtd->destination = FROM_BLUETOOTH;
+			rtd->dma_dscr_idx_1 = CAPTURE_START_DMA_DESCR_CH10;
+			rtd->dma_dscr_idx_2 = CAPTURE_START_DMA_DESCR_CH11;
+			rtd->byte_cnt_high_reg_offset =
+					mmACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH;
+			rtd->byte_cnt_low_reg_offset =
+					mmACP_I2S_BT_RECEIVE_BYTE_CNT_LOW;
+			adata->capture_i2sbt_stream = substream;
+			break;
+		case I2S_SP_INSTANCE:
+		default:
+			rtd->pte_offset = ACP_CAPTURE_PTE_OFFSET;
+			rtd->ch1 = ACP_TO_SYSRAM_CH_NUM;
+			rtd->ch2 = I2S_TO_ACP_DMA_CH_NUM;
+			switch (adata->asic_type) {
+			case CHIP_STONEY:
+				rtd->pte_offset = ACP_ST_CAPTURE_PTE_OFFSET;
+				rtd->sram_bank = ACP_SRAM_BANK_2_ADDRESS;
+				break;
+			default:
+				rtd->pte_offset = ACP_CAPTURE_PTE_OFFSET;
+				rtd->sram_bank = ACP_SRAM_BANK_5_ADDRESS;
+			}
+			rtd->destination = FROM_ACP_I2S_1;
+			rtd->dma_dscr_idx_1 = CAPTURE_START_DMA_DESCR_CH14;
+			rtd->dma_dscr_idx_2 = CAPTURE_START_DMA_DESCR_CH15;
+			rtd->byte_cnt_high_reg_offset =
+					mmACP_I2S_RECEIVED_BYTE_CNT_HIGH;
+			rtd->byte_cnt_low_reg_offset =
+					mmACP_I2S_RECEIVED_BYTE_CNT_LOW;
+			adata->capture_i2ssp_stream = substream;
+		}
 	}
+
 	size = params_buffer_bytes(params);
 	status = snd_pcm_lib_malloc_pages(substream, size);
 	if (status < 0)
@@ -797,7 +886,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
 	memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
 	pg = virt_to_page(substream->dma_buffer.area);
 
-	if (pg != NULL) {
+	if (pg) {
 		acp_set_sram_bank_state(rtd->acp_mmio, 0, true);
 		/* Save for runtime private data */
 		rtd->pg = pg;
@@ -822,26 +911,15 @@ static int acp_dma_hw_free(struct snd_pcm_substream *substream)
 	return snd_pcm_lib_free_pages(substream);
 }
 
-static u64 acp_get_byte_count(void __iomem *acp_mmio, int stream)
+static u64 acp_get_byte_count(struct audio_substream_data *rtd)
 {
-	union acp_dma_count playback_dma_count;
-	union acp_dma_count capture_dma_count;
-	u64 bytescount = 0;
+	union acp_dma_count byte_count;
 
-	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		playback_dma_count.bcount.high = acp_reg_read(acp_mmio,
-					mmACP_I2S_TRANSMIT_BYTE_CNT_HIGH);
-		playback_dma_count.bcount.low  = acp_reg_read(acp_mmio,
-					mmACP_I2S_TRANSMIT_BYTE_CNT_LOW);
-		bytescount = playback_dma_count.bytescount;
-	} else {
-		capture_dma_count.bcount.high = acp_reg_read(acp_mmio,
-					mmACP_I2S_RECEIVED_BYTE_CNT_HIGH);
-		capture_dma_count.bcount.low  = acp_reg_read(acp_mmio,
-					mmACP_I2S_RECEIVED_BYTE_CNT_LOW);
-		bytescount = capture_dma_count.bytescount;
-	}
-	return bytescount;
+	byte_count.bcount.high = acp_reg_read(rtd->acp_mmio,
+					      rtd->byte_cnt_high_reg_offset);
+	byte_count.bcount.low  = acp_reg_read(rtd->acp_mmio,
+					      rtd->byte_cnt_low_reg_offset);
+	return byte_count.bytescount;
 }
 
 static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
@@ -857,15 +935,10 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
 		return -EINVAL;
 
 	buffersize = frames_to_bytes(runtime, runtime->buffer_size);
-	bytescount = acp_get_byte_count(rtd->acp_mmio, substream->stream);
+	bytescount = acp_get_byte_count(rtd);
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		if (bytescount > rtd->i2ssp_renderbytescount)
-			bytescount = bytescount - rtd->i2ssp_renderbytescount;
-	} else {
-		if (bytescount > rtd->i2ssp_capturebytescount)
-			bytescount = bytescount - rtd->i2ssp_capturebytescount;
-	}
+	if (bytescount > rtd->bytescount)
+		bytescount -= rtd->bytescount;
 	pos = do_div(bytescount, buffersize);
 	return bytes_to_frames(runtime, pos);
 }
@@ -883,34 +956,25 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
 
 	if (!rtd)
 		return -EINVAL;
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM,
-					PLAYBACK_START_DMA_DESCR_CH12,
-					NUM_DSCRS_PER_CHANNEL, 0);
-		config_acp_dma_channel(rtd->acp_mmio, ACP_TO_I2S_DMA_CH_NUM,
-					PLAYBACK_START_DMA_DESCR_CH13,
-					NUM_DSCRS_PER_CHANNEL, 0);
-	} else {
-		config_acp_dma_channel(rtd->acp_mmio, ACP_TO_SYSRAM_CH_NUM,
-					CAPTURE_START_DMA_DESCR_CH14,
-					NUM_DSCRS_PER_CHANNEL, 0);
-		config_acp_dma_channel(rtd->acp_mmio, I2S_TO_ACP_DMA_CH_NUM,
-					CAPTURE_START_DMA_DESCR_CH15,
-					NUM_DSCRS_PER_CHANNEL, 0);
-	}
+
+	config_acp_dma_channel(rtd->acp_mmio,
+			       rtd->ch1,
+			       rtd->dma_dscr_idx_1,
+			       NUM_DSCRS_PER_CHANNEL, 0);
+	config_acp_dma_channel(rtd->acp_mmio,
+			       rtd->ch2,
+			       rtd->dma_dscr_idx_2,
+			       NUM_DSCRS_PER_CHANNEL, 0);
 	return 0;
 }
 
 static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	int ret;
-	u32 loops = 4000;
 	u64 bytescount = 0;
 
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *prtd = substream->private_data;
 	struct audio_substream_data *rtd = runtime->private_data;
-	struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
 
 	if (!rtd)
 		return -EINVAL;
@@ -918,59 +982,40 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 	case SNDRV_PCM_TRIGGER_RESUME:
-		bytescount = acp_get_byte_count(rtd->acp_mmio,
-						substream->stream);
+		bytescount = acp_get_byte_count(rtd);
+		if (rtd->bytescount == 0)
+			rtd->bytescount = bytescount;
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			if (rtd->i2ssp_renderbytescount == 0)
-				rtd->i2ssp_renderbytescount = bytescount;
-			acp_dma_start(rtd->acp_mmio,
-						SYSRAM_TO_ACP_CH_NUM, false);
-			while (acp_reg_read(rtd->acp_mmio, mmACP_DMA_CH_STS) &
-						BIT(SYSRAM_TO_ACP_CH_NUM)) {
-				if (!loops--) {
-					dev_err(component->dev,
-						"acp dma start timeout\n");
-					return -ETIMEDOUT;
-				}
-				cpu_relax();
-			}
-
-			acp_dma_start(rtd->acp_mmio,
-					ACP_TO_I2S_DMA_CH_NUM, true);
-
+			acp_dma_start(rtd->acp_mmio, rtd->ch1);
+			acp_dma_start(rtd->acp_mmio, rtd->ch2);
 		} else {
-			if (rtd->i2ssp_capturebytescount == 0)
-				rtd->i2ssp_capturebytescount = bytescount;
-			acp_dma_start(rtd->acp_mmio,
-					    I2S_TO_ACP_DMA_CH_NUM, true);
+			acp_dma_start(rtd->acp_mmio, rtd->ch2);
+			acp_dma_start(rtd->acp_mmio, rtd->ch1);
 		}
 		ret = 0;
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
-		/* Need to stop only circular DMA channels :
-		 * ACP_TO_I2S_DMA_CH_NUM / I2S_TO_ACP_DMA_CH_NUM. Non-circular
-		 * channels will stopped automatically after its transfer
-		 * completes : SYSRAM_TO_ACP_CH_NUM / ACP_TO_SYSRAM_CH_NUM
+		/* For playback, non circular dma should be stopped first
+		 * i.e Sysram to acp dma transfer channel(rtd->ch1) should be
+		 * stopped before stopping cirular dma which is acp sram to i2s
+		 * fifo dma transfer channel(rtd->ch2). Where as in Capture
+		 * scenario, i2s fifo to acp sram dma channel(rtd->ch2) stopped
+		 * first before stopping acp sram to sysram which is circular
+		 * dma(rtd->ch1).
 		 */
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			ret = acp_dma_stop(rtd->acp_mmio,
-						SYSRAM_TO_ACP_CH_NUM);
-			ret = acp_dma_stop(rtd->acp_mmio,
-					ACP_TO_I2S_DMA_CH_NUM);
-			rtd->i2ssp_renderbytescount = 0;
+			acp_dma_stop(rtd->acp_mmio, rtd->ch1);
+			ret =  acp_dma_stop(rtd->acp_mmio, rtd->ch2);
 		} else {
-			ret = acp_dma_stop(rtd->acp_mmio,
-					I2S_TO_ACP_DMA_CH_NUM);
-			ret = acp_dma_stop(rtd->acp_mmio,
-						ACP_TO_SYSRAM_CH_NUM);
-			rtd->i2ssp_capturebytescount = 0;
+			acp_dma_stop(rtd->acp_mmio, rtd->ch2);
+			ret = acp_dma_stop(rtd->acp_mmio, rtd->ch1);
 		}
+		rtd->bytescount = 0;
 		break;
 	default:
 		ret = -EINVAL;
-
 	}
 	return ret;
 }
@@ -978,26 +1023,27 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret;
-	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd,
+								    DRV_NAME);
 	struct audio_drv_data *adata = dev_get_drvdata(component->dev);
 
 	switch (adata->asic_type) {
 	case CHIP_STONEY:
 		ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
-							SNDRV_DMA_TYPE_DEV,
-							NULL, ST_MIN_BUFFER,
-							ST_MAX_BUFFER);
+							    SNDRV_DMA_TYPE_DEV,
+							    NULL, ST_MIN_BUFFER,
+							    ST_MAX_BUFFER);
 		break;
 	default:
 		ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
-							SNDRV_DMA_TYPE_DEV,
-							NULL, MIN_BUFFER,
-							MAX_BUFFER);
+							    SNDRV_DMA_TYPE_DEV,
+							    NULL, MIN_BUFFER,
+							    MAX_BUFFER);
 		break;
 	}
 	if (ret < 0)
 		dev_err(component->dev,
-				"buffer preallocation failer error:%d\n", ret);
+			"buffer preallocation failure error:%d\n", ret);
 	return ret;
 }
 
@@ -1007,38 +1053,55 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct audio_substream_data *rtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *prtd = substream->private_data;
-	struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
+								    DRV_NAME);
 	struct audio_drv_data *adata = dev_get_drvdata(component->dev);
 
-	kfree(rtd);
-
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		adata->play_i2ssp_stream = NULL;
-		/* For Stoney, Memory gating is disabled,i.e SRAM Banks
-		 * won't be turned off. The default state for SRAM banks is ON.
-		 * Setting SRAM bank state code skipped for STONEY platform.
-		 * added condition checks for Carrizo platform only
-		 */
-		if (adata->asic_type != CHIP_STONEY) {
-			for (bank = 1; bank <= 4; bank++)
-				acp_set_sram_bank_state(adata->acp_mmio, bank,
-				false);
+		switch (rtd->i2s_instance) {
+		case I2S_BT_INSTANCE:
+			adata->play_i2sbt_stream = NULL;
+			break;
+		case I2S_SP_INSTANCE:
+		default:
+			adata->play_i2ssp_stream = NULL;
+			/*
+			 * For Stoney, Memory gating is disabled,i.e SRAM Banks
+			 * won't be turned off. The default state for SRAM banks
+			 * is ON.Setting SRAM bank state code skipped for STONEY
+			 * platform. Added condition checks for Carrizo platform
+			 * only.
+			 */
+			if (adata->asic_type != CHIP_STONEY) {
+				for (bank = 1; bank <= 4; bank++)
+					acp_set_sram_bank_state(adata->acp_mmio,
+								bank, false);
+			}
 		}
 	} else  {
-		adata->capture_i2ssp_stream = NULL;
-		if (adata->asic_type != CHIP_STONEY) {
-			for (bank = 5; bank <= 8; bank++)
-				acp_set_sram_bank_state(adata->acp_mmio, bank,
-						     false);
+		switch (rtd->i2s_instance) {
+		case I2S_BT_INSTANCE:
+			adata->capture_i2sbt_stream = NULL;
+			break;
+		case I2S_SP_INSTANCE:
+		default:
+			adata->capture_i2ssp_stream = NULL;
+			if (adata->asic_type != CHIP_STONEY) {
+				for (bank = 5; bank <= 8; bank++)
+					acp_set_sram_bank_state(adata->acp_mmio,
+								bank, false);
+			}
 		}
 	}
 
-	/* Disable ACP irq, when the current stream is being closed and
+	/*
+	 * Disable ACP irq, when the current stream is being closed and
 	 * another stream is also not active.
-	*/
-	if (!adata->play_i2ssp_stream && !adata->capture_i2ssp_stream)
+	 */
+	if (!adata->play_i2ssp_stream && !adata->capture_i2ssp_stream &&
+	    !adata->play_i2sbt_stream && !adata->capture_i2sbt_stream)
 		acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
-
+	kfree(rtd);
 	return 0;
 }
 
@@ -1054,7 +1117,7 @@ static const struct snd_pcm_ops acp_dma_ops = {
 	.prepare = acp_dma_prepare,
 };
 
-static struct snd_soc_component_driver acp_asoc_platform = {
+static const struct snd_soc_component_driver acp_asoc_platform = {
 	.name = DRV_NAME,
 	.ops = &acp_dma_ops,
 	.pcm_new = acp_dma_new,
@@ -1073,8 +1136,8 @@ static int acp_audio_probe(struct platform_device *pdev)
 	}
 
 	audio_drv_data = devm_kzalloc(&pdev->dev, sizeof(struct audio_drv_data),
-					GFP_KERNEL);
-	if (audio_drv_data == NULL)
+				      GFP_KERNEL);
+	if (!audio_drv_data)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1082,13 +1145,16 @@ static int acp_audio_probe(struct platform_device *pdev)
 	if (IS_ERR(audio_drv_data->acp_mmio))
 		return PTR_ERR(audio_drv_data->acp_mmio);
 
-	/* The following members gets populated in device 'open'
+	/*
+	 * The following members gets populated in device 'open'
 	 * function. Till then interrupts are disabled in 'acp_init'
 	 * and device doesn't generate any interrupts.
 	 */
 
 	audio_drv_data->play_i2ssp_stream = NULL;
 	audio_drv_data->capture_i2ssp_stream = NULL;
+	audio_drv_data->play_i2sbt_stream = NULL;
+	audio_drv_data->capture_i2sbt_stream = NULL;
 
 	audio_drv_data->asic_type =  *pdata;
 
@@ -1099,7 +1165,7 @@ static int acp_audio_probe(struct platform_device *pdev)
 	}
 
 	status = devm_request_irq(&pdev->dev, res->start, dma_irq_handler,
-					0, "ACP_IRQ", &pdev->dev);
+				  0, "ACP_IRQ", &pdev->dev);
 	if (status) {
 		dev_err(&pdev->dev, "ACP IRQ request failed\n");
 		return status;
@@ -1115,7 +1181,7 @@ static int acp_audio_probe(struct platform_device *pdev)
 	}
 
 	status = devm_snd_soc_register_component(&pdev->dev,
-						&acp_asoc_platform, NULL, 0);
+						 &acp_asoc_platform, NULL, 0);
 	if (status != 0) {
 		dev_err(&pdev->dev, "Fail to register ALSA platform device\n");
 		return status;
@@ -1145,6 +1211,7 @@ static int acp_pcm_resume(struct device *dev)
 {
 	u16 bank;
 	int status;
+	struct audio_substream_data *rtd;
 	struct audio_drv_data *adata = dev_get_drvdata(dev);
 
 	status = acp_init(adata->acp_mmio, adata->asic_type);
@@ -1154,28 +1221,40 @@ static int acp_pcm_resume(struct device *dev)
 	}
 
 	if (adata->play_i2ssp_stream && adata->play_i2ssp_stream->runtime) {
-		/* For Stoney, Memory gating is disabled,i.e SRAM Banks
+		/*
+		 * For Stoney, Memory gating is disabled,i.e SRAM Banks
 		 * won't be turned off. The default state for SRAM banks is ON.
 		 * Setting SRAM bank state code skipped for STONEY platform.
 		 */
 		if (adata->asic_type != CHIP_STONEY) {
 			for (bank = 1; bank <= 4; bank++)
 				acp_set_sram_bank_state(adata->acp_mmio, bank,
-						true);
+							true);
 		}
-		config_acp_dma(adata->acp_mmio,
-			adata->play_i2ssp_stream->runtime->private_data,
-			adata->asic_type);
+		rtd = adata->play_i2ssp_stream->runtime->private_data;
+		config_acp_dma(adata->acp_mmio, rtd, adata->asic_type);
 	}
-	if (adata->capture_i2ssp_stream && adata->capture_i2ssp_stream->runtime) {
+	if (adata->capture_i2ssp_stream &&
+	    adata->capture_i2ssp_stream->runtime) {
 		if (adata->asic_type != CHIP_STONEY) {
 			for (bank = 5; bank <= 8; bank++)
 				acp_set_sram_bank_state(adata->acp_mmio, bank,
-						true);
+							true);
+		}
+		rtd =  adata->capture_i2ssp_stream->runtime->private_data;
+		config_acp_dma(adata->acp_mmio, rtd, adata->asic_type);
+	}
+	if (adata->asic_type != CHIP_CARRIZO) {
+		if (adata->play_i2sbt_stream &&
+		    adata->play_i2sbt_stream->runtime) {
+			rtd = adata->play_i2sbt_stream->runtime->private_data;
+			config_acp_dma(adata->acp_mmio, rtd, adata->asic_type);
+		}
+		if (adata->capture_i2sbt_stream &&
+		    adata->capture_i2sbt_stream->runtime) {
+			rtd = adata->capture_i2sbt_stream->runtime->private_data;
+			config_acp_dma(adata->acp_mmio, rtd, adata->asic_type);
 		}
-		config_acp_dma(adata->acp_mmio,
-			adata->capture_i2ssp_stream->runtime->private_data,
-			adata->asic_type);
 	}
 	acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
 	return 0;
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
index ba01510eb818..9cd3e96c84d4 100644
--- a/sound/soc/amd/acp.h
+++ b/sound/soc/amd/acp.h
@@ -10,17 +10,30 @@
 #define ACP_PLAYBACK_PTE_OFFSET			10
 #define ACP_CAPTURE_PTE_OFFSET			0
 
+/* Playback and Capture Offset for Stoney */
+#define ACP_ST_PLAYBACK_PTE_OFFSET	0x04
+#define ACP_ST_CAPTURE_PTE_OFFSET	0x00
+#define ACP_ST_BT_PLAYBACK_PTE_OFFSET	0x08
+#define ACP_ST_BT_CAPTURE_PTE_OFFSET	0x0c
+
 #define ACP_GARLIC_CNTL_DEFAULT			0x00000FB4
 #define ACP_ONION_CNTL_DEFAULT			0x00000FB4
 
 #define ACP_PHYSICAL_BASE			0x14000
 
-/* Playback SRAM address (as a destination in dma descriptor) */
-#define ACP_SHARED_RAM_BANK_1_ADDRESS		0x4002000
-
-/* Capture SRAM address (as a source in dma descriptor) */
-#define ACP_SHARED_RAM_BANK_5_ADDRESS		0x400A000
-#define ACP_SHARED_RAM_BANK_3_ADDRESS		0x4006000
+/*
+ * In case of I2S SP controller instance, Stoney uses SRAM bank 1 for
+ * playback and SRAM Bank 2 for capture where as in case of BT I2S
+ * Instance, Stoney uses SRAM Bank 3 for playback & SRAM Bank 4 will
+ * be used for capture. Carrizo uses I2S SP controller instance. SRAM Banks
+ * 1, 2, 3, 4 will be used for playback & SRAM Banks 5, 6, 7, 8 will be used
+ * for capture scenario.
+ */
+#define ACP_SRAM_BANK_1_ADDRESS		0x4002000
+#define ACP_SRAM_BANK_2_ADDRESS		0x4004000
+#define ACP_SRAM_BANK_3_ADDRESS		0x4006000
+#define ACP_SRAM_BANK_4_ADDRESS		0x4008000
+#define ACP_SRAM_BANK_5_ADDRESS		0x400A000
 
 #define ACP_DMA_RESET_TIME			10000
 #define ACP_CLOCK_EN_TIME_OUT_VALUE		0x000000FF
@@ -35,8 +48,13 @@
 
 #define TO_ACP_I2S_1   0x2
 #define TO_ACP_I2S_2   0x4
+#define TO_BLUETOOTH   0x3
 #define FROM_ACP_I2S_1 0xa
 #define FROM_ACP_I2S_2 0xb
+#define FROM_BLUETOOTH 0xb
+
+#define I2S_SP_INSTANCE                 0x01
+#define I2S_BT_INSTANCE                 0x02
 
 #define ACP_TILE_ON_MASK                0x03
 #define ACP_TILE_OFF_MASK               0x02
@@ -57,6 +75,14 @@
 #define ACP_TO_SYSRAM_CH_NUM 14
 #define I2S_TO_ACP_DMA_CH_NUM 15
 
+/* Playback DMA Channels for I2S BT instance */
+#define SYSRAM_TO_ACP_BT_INSTANCE_CH_NUM  8
+#define ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM 9
+
+/* Capture DMA Channels for I2S BT Instance */
+#define ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM 10
+#define I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM 11
+
 #define NUM_DSCRS_PER_CHANNEL 2
 
 #define PLAYBACK_START_DMA_DESCR_CH12 0
@@ -69,9 +95,23 @@
 #define CAPTURE_START_DMA_DESCR_CH15 6
 #define CAPTURE_END_DMA_DESCR_CH15 7
 
+/* I2S BT Instance DMA Descriptors */
+#define PLAYBACK_START_DMA_DESCR_CH8 8
+#define PLAYBACK_END_DMA_DESCR_CH8 9
+#define PLAYBACK_START_DMA_DESCR_CH9 10
+#define PLAYBACK_END_DMA_DESCR_CH9 11
+
+#define CAPTURE_START_DMA_DESCR_CH10 12
+#define CAPTURE_END_DMA_DESCR_CH10 13
+#define CAPTURE_START_DMA_DESCR_CH11 14
+#define CAPTURE_END_DMA_DESCR_CH11 15
+
 #define mmACP_I2S_16BIT_RESOLUTION_EN       0x5209
 #define ACP_I2S_MIC_16BIT_RESOLUTION_EN 0x01
 #define ACP_I2S_SP_16BIT_RESOLUTION_EN	0x02
+#define ACP_I2S_BT_16BIT_RESOLUTION_EN	0x04
+#define ACP_BT_UART_PAD_SELECT_MASK	0x1
+
 enum acp_dma_priority_level {
 	/* 0x0 Specifies the DMA channel is given normal priority */
 	ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0,
@@ -84,20 +124,39 @@ struct audio_substream_data {
 	struct page *pg;
 	unsigned int order;
 	u16 num_of_pages;
+	u16 i2s_instance;
 	u16 direction;
+	u16 ch1;
+	u16 ch2;
+	u16 destination;
+	u16 dma_dscr_idx_1;
+	u16 dma_dscr_idx_2;
+	u32 pte_offset;
+	u32 sram_bank;
+	u32 byte_cnt_high_reg_offset;
+	u32 byte_cnt_low_reg_offset;
 	uint64_t size;
-	u64 i2ssp_renderbytescount;
-	u64 i2ssp_capturebytescount;
+	u64 bytescount;
 	void __iomem *acp_mmio;
 };
 
 struct audio_drv_data {
 	struct snd_pcm_substream *play_i2ssp_stream;
 	struct snd_pcm_substream *capture_i2ssp_stream;
+	struct snd_pcm_substream *play_i2sbt_stream;
+	struct snd_pcm_substream *capture_i2sbt_stream;
 	void __iomem *acp_mmio;
 	u32 asic_type;
 };
 
+/*
+ * this structure used for platform data transfer between machine driver
+ * and dma driver
+ */
+struct acp_platform_info {
+	u16 i2s_instance;
+};
+
 union acp_dma_count {
 	struct {
 	u32 low;
@@ -115,23 +174,25 @@ enum {
 };
 
 enum {
-	ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION = 0x0,
-	ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC = 0x1,
-	ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM = 0x8,
-	ACP_DMA_ATTRIBUTES_DAGB_GARLIC_TO_SHAREDMEM = 0x9,
-	ACP_DMA_ATTRIBUTES_FORCE_SIZE = 0xF
+	ACP_DMA_ATTR_SHAREDMEM_TO_DAGB_ONION = 0x0,
+	ACP_DMA_ATTR_SHARED_MEM_TO_DAGB_GARLIC = 0x1,
+	ACP_DMA_ATTR_DAGB_ONION_TO_SHAREDMEM = 0x8,
+	ACP_DMA_ATTR_DAGB_GARLIC_TO_SHAREDMEM = 0x9,
+	ACP_DMA_ATTR_FORCE_SIZE = 0xF
 };
 
 typedef struct acp_dma_dscr_transfer {
 	/* Specifies the source memory location for the DMA data transfer. */
 	u32 src;
-	/* Specifies the destination memory location to where the data will
+	/*
+	 * Specifies the destination memory location to where the data will
 	 * be transferred.
-	*/
+	 */
 	u32 dest;
-	/* Specifies the number of bytes need to be transferred
-	* from source to destination memory.Transfer direction & IOC enable
-	*/
+	/*
+	 * Specifies the number of bytes need to be transferred
+	 * from source to destination memory.Transfer direction & IOC enable
+	 */
 	u32 xfer_val;
 	/* Reserved for future use */
 	u32 reserved;
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index dcee145dd179..64b784e96f84 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -88,4 +88,13 @@ config SND_ATMEL_SOC_TSE850_PCM5142
 	help
 	  Say Y if you want to add support for the ASoC driver for the
 	  Axentia TSE-850 with a PCM5142 codec.
+
+config SND_ATMEL_SOC_I2S
+	tristate "Atmel ASoC driver for boards using I2S"
+	depends on OF && (ARCH_AT91 || COMPILE_TEST)
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	select REGMAP_MMIO
+	help
+	  Say Y or M if you want to add support for Atmel ASoc driver for boards
+	  using I2S.
 endif
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
index 4440646416e8..cd87cb4bcff5 100644
--- a/sound/soc/atmel/Makefile
+++ b/sound/soc/atmel/Makefile
@@ -3,10 +3,12 @@
 snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o
 snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o
 snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o
+snd-soc-atmel-i2s-objs := atmel-i2s.o
 
 obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o
 obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o
 obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
+obj-$(CONFIG_SND_ATMEL_SOC_I2S) += snd-soc-atmel-i2s.o
 
 # AT91 Machine Support
 snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c
new file mode 100644
index 000000000000..5d3b5af9fd92
--- /dev/null
+++ b/sound/soc/atmel/atmel-i2s.c
@@ -0,0 +1,765 @@
+/*
+ * Driver for Atmel I2S controller
+ *
+ * Copyright (C) 2015 Atmel Corporation
+ *
+ * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#define ATMEL_I2SC_MAX_TDM_CHANNELS	8
+
+/*
+ * ---- I2S Controller Register map ----
+ */
+#define ATMEL_I2SC_CR		0x0000	/* Control Register */
+#define ATMEL_I2SC_MR		0x0004	/* Mode Register */
+#define ATMEL_I2SC_SR		0x0008	/* Status Register */
+#define ATMEL_I2SC_SCR		0x000c	/* Status Clear Register */
+#define ATMEL_I2SC_SSR		0x0010	/* Status Set Register */
+#define ATMEL_I2SC_IER		0x0014	/* Interrupt Enable Register */
+#define ATMEL_I2SC_IDR		0x0018	/* Interrupt Disable Register */
+#define ATMEL_I2SC_IMR		0x001c	/* Interrupt Mask Register */
+#define ATMEL_I2SC_RHR		0x0020	/* Receiver Holding Register */
+#define ATMEL_I2SC_THR		0x0024	/* Transmitter Holding Register */
+#define ATMEL_I2SC_VERSION	0x0028	/* Version Register */
+
+/*
+ * ---- Control Register (Write-only) ----
+ */
+#define ATMEL_I2SC_CR_RXEN	BIT(0)	/* Receiver Enable */
+#define ATMEL_I2SC_CR_RXDIS	BIT(1)	/* Receiver Disable */
+#define ATMEL_I2SC_CR_CKEN	BIT(2)	/* Clock Enable */
+#define ATMEL_I2SC_CR_CKDIS	BIT(3)	/* Clock Disable */
+#define ATMEL_I2SC_CR_TXEN	BIT(4)	/* Transmitter Enable */
+#define ATMEL_I2SC_CR_TXDIS	BIT(5)	/* Transmitter Disable */
+#define ATMEL_I2SC_CR_SWRST	BIT(7)	/* Software Reset */
+
+/*
+ * ---- Mode Register (Read/Write) ----
+ */
+#define ATMEL_I2SC_MR_MODE_MASK		GENMASK(0, 0)
+#define ATMEL_I2SC_MR_MODE_SLAVE	(0 << 0)
+#define ATMEL_I2SC_MR_MODE_MASTER	(1 << 0)
+
+#define ATMEL_I2SC_MR_DATALENGTH_MASK		GENMASK(4, 2)
+#define ATMEL_I2SC_MR_DATALENGTH_32_BITS	(0 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_24_BITS	(1 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_20_BITS	(2 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_18_BITS	(3 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_16_BITS	(4 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_16_BITS_COMPACT	(5 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_8_BITS		(6 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_8_BITS_COMPACT	(7 << 2)
+
+#define ATMEL_I2SC_MR_FORMAT_MASK	GENMASK(7, 6)
+#define ATMEL_I2SC_MR_FORMAT_I2S	(0 << 6)
+#define ATMEL_I2SC_MR_FORMAT_LJ		(1 << 6)  /* Left Justified */
+#define ATMEL_I2SC_MR_FORMAT_TDM	(2 << 6)
+#define ATMEL_I2SC_MR_FORMAT_TDMLJ	(3 << 6)
+
+/* Left audio samples duplicated to right audio channel */
+#define ATMEL_I2SC_MR_RXMONO		BIT(8)
+
+/* Receiver uses one DMA channel ... */
+#define ATMEL_I2SC_MR_RXDMA_MASK	GENMASK(9, 9)
+#define ATMEL_I2SC_MR_RXDMA_SINGLE	(0 << 9)  /* for all audio channels */
+#define ATMEL_I2SC_MR_RXDMA_MULTIPLE	(1 << 9)  /* per audio channel */
+
+/* I2SDO output of I2SC is internally connected to I2SDI input */
+#define ATMEL_I2SC_MR_RXLOOP		BIT(10)
+
+/* Left audio samples duplicated to right audio channel */
+#define ATMEL_I2SC_MR_TXMONO		BIT(12)
+
+/* Transmitter uses one DMA channel ... */
+#define ATMEL_I2SC_MR_TXDMA_MASK	GENMASK(13, 13)
+#define ATMEL_I2SC_MR_TXDMA_SINGLE	(0 << 13)  /* for all audio channels */
+#define ATMEL_I2SC_MR_TXDME_MULTIPLE	(1 << 13)  /* per audio channel */
+
+/* x sample transmitted when underrun */
+#define ATMEL_I2SC_MR_TXSAME_MASK	GENMASK(14, 14)
+#define ATMEL_I2SC_MR_TXSAME_ZERO	(0 << 14)  /* Zero sample */
+#define ATMEL_I2SC_MR_TXSAME_PREVIOUS	(1 << 14)  /* Previous sample */
+
+/* Audio Clock to I2SC Master Clock ratio */
+#define ATMEL_I2SC_MR_IMCKDIV_MASK	GENMASK(21, 16)
+#define ATMEL_I2SC_MR_IMCKDIV(div) \
+	(((div) << 16) & ATMEL_I2SC_MR_IMCKDIV_MASK)
+
+/* Master Clock to fs ratio */
+#define ATMEL_I2SC_MR_IMCKFS_MASK	GENMASK(29, 24)
+#define ATMEL_I2SC_MR_IMCKFS(fs) \
+	(((fs) << 24) & ATMEL_I2SC_MR_IMCKFS_MASK)
+
+/* Master Clock mode */
+#define ATMEL_I2SC_MR_IMCKMODE_MASK	GENMASK(30, 30)
+/* 0: No master clock generated (selected clock drives I2SCK pin) */
+#define ATMEL_I2SC_MR_IMCKMODE_I2SCK	(0 << 30)
+/* 1: master clock generated (internally generated clock drives I2SMCK pin) */
+#define ATMEL_I2SC_MR_IMCKMODE_I2SMCK	(1 << 30)
+
+/* Slot Width */
+/* 0: slot is 32 bits wide for DATALENGTH = 18/20/24 bits. */
+/* 1: slot is 24 bits wide for DATALENGTH = 18/20/24 bits. */
+#define ATMEL_I2SC_MR_IWS		BIT(31)
+
+/*
+ * ---- Status Registers ----
+ */
+#define ATMEL_I2SC_SR_RXEN	BIT(0)	/* Receiver Enabled */
+#define ATMEL_I2SC_SR_RXRDY	BIT(1)	/* Receive Ready */
+#define ATMEL_I2SC_SR_RXOR	BIT(2)	/* Receive Overrun */
+
+#define ATMEL_I2SC_SR_TXEN	BIT(4)	/* Transmitter Enabled */
+#define ATMEL_I2SC_SR_TXRDY	BIT(5)	/* Transmit Ready */
+#define ATMEL_I2SC_SR_TXUR	BIT(6)	/* Transmit Underrun */
+
+/* Receive Overrun Channel */
+#define ATMEL_I2SC_SR_RXORCH_MASK	GENMASK(15, 8)
+#define ATMEL_I2SC_SR_RXORCH(ch)	(1 << (((ch) & 0x7) + 8))
+
+/* Transmit Underrun Channel */
+#define ATMEL_I2SC_SR_TXURCH_MASK	GENMASK(27, 20)
+#define ATMEL_I2SC_SR_TXURCH(ch)	(1 << (((ch) & 0x7) + 20))
+
+/*
+ * ---- Interrupt Enable/Disable/Mask Registers ----
+ */
+#define ATMEL_I2SC_INT_RXRDY	ATMEL_I2SC_SR_RXRDY
+#define ATMEL_I2SC_INT_RXOR	ATMEL_I2SC_SR_RXOR
+#define ATMEL_I2SC_INT_TXRDY	ATMEL_I2SC_SR_TXRDY
+#define ATMEL_I2SC_INT_TXUR	ATMEL_I2SC_SR_TXUR
+
+static const struct regmap_config atmel_i2s_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = ATMEL_I2SC_VERSION,
+};
+
+struct atmel_i2s_gck_param {
+	int		fs;
+	unsigned long	mck;
+	int		imckdiv;
+	int		imckfs;
+};
+
+#define I2S_MCK_12M288		12288000UL
+#define I2S_MCK_11M2896		11289600UL
+
+/* mck = (32 * (imckfs+1) / (imckdiv+1)) * fs */
+static const struct atmel_i2s_gck_param gck_params[] = {
+	/* mck = 12.288MHz */
+	{  8000, I2S_MCK_12M288, 0, 47},	/* mck = 1536 fs */
+	{ 16000, I2S_MCK_12M288, 1, 47},	/* mck =  768 fs */
+	{ 24000, I2S_MCK_12M288, 3, 63},	/* mck =  512 fs */
+	{ 32000, I2S_MCK_12M288, 3, 47},	/* mck =  384 fs */
+	{ 48000, I2S_MCK_12M288, 7, 63},	/* mck =  256 fs */
+	{ 64000, I2S_MCK_12M288, 7, 47},	/* mck =  192 fs */
+	{ 96000, I2S_MCK_12M288, 7, 31},	/* mck =  128 fs */
+	{192000, I2S_MCK_12M288, 7, 15},	/* mck =   64 fs */
+
+	/* mck = 11.2896MHz */
+	{ 11025, I2S_MCK_11M2896, 1, 63},	/* mck = 1024 fs */
+	{ 22050, I2S_MCK_11M2896, 3, 63},	/* mck =  512 fs */
+	{ 44100, I2S_MCK_11M2896, 7, 63},	/* mck =  256 fs */
+	{ 88200, I2S_MCK_11M2896, 7, 31},	/* mck =  128 fs */
+	{176400, I2S_MCK_11M2896, 7, 15},	/* mck =   64 fs */
+};
+
+struct atmel_i2s_dev;
+
+struct atmel_i2s_caps {
+	int	(*mck_init)(struct atmel_i2s_dev *, struct device_node *np);
+};
+
+struct atmel_i2s_dev {
+	struct device				*dev;
+	struct regmap				*regmap;
+	struct clk				*pclk;
+	struct clk				*gclk;
+	struct clk				*aclk;
+	struct snd_dmaengine_dai_dma_data	playback;
+	struct snd_dmaengine_dai_dma_data	capture;
+	unsigned int				fmt;
+	const struct atmel_i2s_gck_param	*gck_param;
+	const struct atmel_i2s_caps		*caps;
+};
+
+static irqreturn_t atmel_i2s_interrupt(int irq, void *dev_id)
+{
+	struct atmel_i2s_dev *dev = dev_id;
+	unsigned int sr, imr, pending, ch, mask;
+	irqreturn_t ret = IRQ_NONE;
+
+	regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr);
+	regmap_read(dev->regmap, ATMEL_I2SC_IMR, &imr);
+	pending = sr & imr;
+
+	if (!pending)
+		return IRQ_NONE;
+
+	if (pending & ATMEL_I2SC_INT_RXOR) {
+		mask = ATMEL_I2SC_SR_RXOR;
+
+		for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) {
+			if (sr & ATMEL_I2SC_SR_RXORCH(ch)) {
+				mask |= ATMEL_I2SC_SR_RXORCH(ch);
+				dev_err(dev->dev,
+					"RX overrun on channel %d\n", ch);
+			}
+		}
+		regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask);
+		ret = IRQ_HANDLED;
+	}
+
+	if (pending & ATMEL_I2SC_INT_TXUR) {
+		mask = ATMEL_I2SC_SR_TXUR;
+
+		for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) {
+			if (sr & ATMEL_I2SC_SR_TXURCH(ch)) {
+				mask |= ATMEL_I2SC_SR_TXURCH(ch);
+				dev_err(dev->dev,
+					"TX underrun on channel %d\n", ch);
+			}
+		}
+		regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask);
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+#define ATMEL_I2S_RATES		SNDRV_PCM_RATE_8000_192000
+
+#define ATMEL_I2S_FORMATS	(SNDRV_PCM_FMTBIT_S8 |		\
+				 SNDRV_PCM_FMTBIT_S16_LE |	\
+				 SNDRV_PCM_FMTBIT_S18_3LE |	\
+				 SNDRV_PCM_FMTBIT_S20_3LE |	\
+				 SNDRV_PCM_FMTBIT_S24_3LE |	\
+				 SNDRV_PCM_FMTBIT_S24_LE |	\
+				 SNDRV_PCM_FMTBIT_S32_LE)
+
+static int atmel_i2s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+	dev->fmt = fmt;
+	return 0;
+}
+
+static int atmel_i2s_prepare(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+	bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+	unsigned int rhr, sr = 0;
+
+	if (is_playback) {
+		regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr);
+		if (sr & ATMEL_I2SC_SR_RXRDY) {
+			/*
+			 * The RX Ready flag should not be set. However if here,
+			 * we flush (read) the Receive Holding Register to start
+			 * from a clean state.
+			 */
+			dev_dbg(dev->dev, "RXRDY is set\n");
+			regmap_read(dev->regmap, ATMEL_I2SC_RHR, &rhr);
+		}
+	}
+
+	return 0;
+}
+
+static int atmel_i2s_get_gck_param(struct atmel_i2s_dev *dev, int fs)
+{
+	int i, best;
+
+	if (!dev->gclk || !dev->aclk) {
+		dev_err(dev->dev, "cannot generate the I2S Master Clock\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Find the best possible settings to generate the I2S Master Clock
+	 * from the PLL Audio.
+	 */
+	dev->gck_param = NULL;
+	best = INT_MAX;
+	for (i = 0; i < ARRAY_SIZE(gck_params); ++i) {
+		const struct atmel_i2s_gck_param *gck_param = &gck_params[i];
+		int val = abs(fs - gck_param->fs);
+
+		if (val < best) {
+			best = val;
+			dev->gck_param = gck_param;
+		}
+	}
+
+	return 0;
+}
+
+static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *params,
+			       struct snd_soc_dai *dai)
+{
+	struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+	bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+	unsigned int mr = 0;
+	int ret;
+
+	switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		mr |= ATMEL_I2SC_MR_FORMAT_I2S;
+		break;
+
+	default:
+		dev_err(dev->dev, "unsupported bus format\n");
+		return -EINVAL;
+	}
+
+	switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* codec is slave, so cpu is master */
+		mr |= ATMEL_I2SC_MR_MODE_MASTER;
+		ret = atmel_i2s_get_gck_param(dev, params_rate(params));
+		if (ret)
+			return ret;
+		break;
+
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* codec is master, so cpu is slave */
+		mr |= ATMEL_I2SC_MR_MODE_SLAVE;
+		dev->gck_param = NULL;
+		break;
+
+	default:
+		dev_err(dev->dev, "unsupported master/slave mode\n");
+		return -EINVAL;
+	}
+
+	switch (params_channels(params)) {
+	case 1:
+		if (is_playback)
+			mr |= ATMEL_I2SC_MR_TXMONO;
+		else
+			mr |= ATMEL_I2SC_MR_RXMONO;
+		break;
+	case 2:
+		break;
+	default:
+		dev_err(dev->dev, "unsupported number of audio channels\n");
+		return -EINVAL;
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		mr |= ATMEL_I2SC_MR_DATALENGTH_8_BITS;
+		break;
+
+	case SNDRV_PCM_FORMAT_S16_LE:
+		mr |= ATMEL_I2SC_MR_DATALENGTH_16_BITS;
+		break;
+
+	case SNDRV_PCM_FORMAT_S18_3LE:
+		mr |= ATMEL_I2SC_MR_DATALENGTH_18_BITS | ATMEL_I2SC_MR_IWS;
+		break;
+
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		mr |= ATMEL_I2SC_MR_DATALENGTH_20_BITS | ATMEL_I2SC_MR_IWS;
+		break;
+
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		mr |= ATMEL_I2SC_MR_DATALENGTH_24_BITS | ATMEL_I2SC_MR_IWS;
+		break;
+
+	case SNDRV_PCM_FORMAT_S24_LE:
+		mr |= ATMEL_I2SC_MR_DATALENGTH_24_BITS;
+		break;
+
+	case SNDRV_PCM_FORMAT_S32_LE:
+		mr |= ATMEL_I2SC_MR_DATALENGTH_32_BITS;
+		break;
+
+	default:
+		dev_err(dev->dev, "unsupported size/endianness for audio samples\n");
+		return -EINVAL;
+	}
+
+	return regmap_write(dev->regmap, ATMEL_I2SC_MR, mr);
+}
+
+static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev,
+					  bool enabled)
+{
+	unsigned int mr, mr_mask;
+	unsigned long aclk_rate;
+	int ret;
+
+	mr = 0;
+	mr_mask = (ATMEL_I2SC_MR_IMCKDIV_MASK |
+		   ATMEL_I2SC_MR_IMCKFS_MASK |
+		   ATMEL_I2SC_MR_IMCKMODE_MASK);
+
+	if (!enabled) {
+		/* Disable the I2S Master Clock generator. */
+		ret = regmap_write(dev->regmap, ATMEL_I2SC_CR,
+				   ATMEL_I2SC_CR_CKDIS);
+		if (ret)
+			return ret;
+
+		/* Reset the I2S Master Clock generator settings. */
+		ret = regmap_update_bits(dev->regmap, ATMEL_I2SC_MR,
+					 mr_mask, mr);
+		if (ret)
+			return ret;
+
+		/* Disable/unprepare the PMC generated clock. */
+		clk_disable_unprepare(dev->gclk);
+
+		/* Disable/unprepare the PLL audio clock. */
+		clk_disable_unprepare(dev->aclk);
+		return 0;
+	}
+
+	if (!dev->gck_param)
+		return -EINVAL;
+
+	aclk_rate = dev->gck_param->mck * (dev->gck_param->imckdiv + 1);
+
+	/* Fist change the PLL audio clock frequency ... */
+	ret = clk_set_rate(dev->aclk, aclk_rate);
+	if (ret)
+		return ret;
+
+	/*
+	 * ... then set the PMC generated clock rate to the very same frequency
+	 * to set the gclk parent to aclk.
+	 */
+	ret = clk_set_rate(dev->gclk, aclk_rate);
+	if (ret)
+		return ret;
+
+	/* Prepare and enable the PLL audio clock first ... */
+	ret = clk_prepare_enable(dev->aclk);
+	if (ret)
+		return ret;
+
+	/* ... then prepare and enable the PMC generated clock. */
+	ret = clk_prepare_enable(dev->gclk);
+	if (ret)
+		return ret;
+
+	/* Update the Mode Register to generate the I2S Master Clock. */
+	mr |= ATMEL_I2SC_MR_IMCKDIV(dev->gck_param->imckdiv);
+	mr |= ATMEL_I2SC_MR_IMCKFS(dev->gck_param->imckfs);
+	mr |= ATMEL_I2SC_MR_IMCKMODE_I2SMCK;
+	ret = regmap_update_bits(dev->regmap, ATMEL_I2SC_MR, mr_mask, mr);
+	if (ret)
+		return ret;
+
+	/* Finally enable the I2S Master Clock generator. */
+	return regmap_write(dev->regmap, ATMEL_I2SC_CR,
+			    ATMEL_I2SC_CR_CKEN);
+}
+
+static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			     struct snd_soc_dai *dai)
+{
+	struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+	bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+	bool is_master, mck_enabled;
+	unsigned int cr, mr;
+	int err;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		cr = is_playback ? ATMEL_I2SC_CR_TXEN : ATMEL_I2SC_CR_RXEN;
+		mck_enabled = true;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		cr = is_playback ? ATMEL_I2SC_CR_TXDIS : ATMEL_I2SC_CR_RXDIS;
+		mck_enabled = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Read the Mode Register to retrieve the master/slave state. */
+	err = regmap_read(dev->regmap, ATMEL_I2SC_MR, &mr);
+	if (err)
+		return err;
+	is_master = (mr & ATMEL_I2SC_MR_MODE_MASK) == ATMEL_I2SC_MR_MODE_MASTER;
+
+	/* If master starts, enable the audio clock. */
+	if (is_master && mck_enabled)
+		err = atmel_i2s_switch_mck_generator(dev, true);
+	if (err)
+		return err;
+
+	err = regmap_write(dev->regmap, ATMEL_I2SC_CR, cr);
+	if (err)
+		return err;
+
+	/* If master stops, disable the audio clock. */
+	if (is_master && !mck_enabled)
+		err = atmel_i2s_switch_mck_generator(dev, false);
+
+	return err;
+}
+
+static const struct snd_soc_dai_ops atmel_i2s_dai_ops = {
+	.prepare	= atmel_i2s_prepare,
+	.trigger	= atmel_i2s_trigger,
+	.hw_params	= atmel_i2s_hw_params,
+	.set_fmt	= atmel_i2s_set_dai_fmt,
+};
+
+static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+	struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, &dev->playback, &dev->capture);
+	return 0;
+}
+
+static struct snd_soc_dai_driver atmel_i2s_dai = {
+	.probe	= atmel_i2s_dai_probe,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ATMEL_I2S_RATES,
+		.formats = ATMEL_I2S_FORMATS,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ATMEL_I2S_RATES,
+		.formats = ATMEL_I2S_FORMATS,
+	},
+	.ops = &atmel_i2s_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static const struct snd_soc_component_driver atmel_i2s_component = {
+	.name	= "atmel-i2s",
+};
+
+static int atmel_i2s_sama5d2_mck_init(struct atmel_i2s_dev *dev,
+				      struct device_node *np)
+{
+	struct clk *muxclk;
+	int err;
+
+	if (!dev->gclk)
+		return 0;
+
+	/* muxclk is optional, so we return error for probe defer only */
+	muxclk = devm_clk_get(dev->dev, "muxclk");
+	if (IS_ERR(muxclk)) {
+		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);
+		return 0;
+	}
+
+	return clk_set_parent(muxclk, dev->gclk);
+}
+
+static const struct atmel_i2s_caps atmel_i2s_sama5d2_caps = {
+	.mck_init = atmel_i2s_sama5d2_mck_init,
+};
+
+static const struct of_device_id atmel_i2s_dt_ids[] = {
+	{
+		.compatible = "atmel,sama5d2-i2s",
+		.data = (void *)&atmel_i2s_sama5d2_caps,
+	},
+
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_i2s_dt_ids);
+
+static int atmel_i2s_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *match;
+	struct atmel_i2s_dev *dev;
+	struct resource *mem;
+	struct regmap *regmap;
+	void __iomem *base;
+	int irq;
+	int err = -ENXIO;
+	unsigned int pcm_flags = 0;
+	unsigned int version;
+
+	/* Get memory for driver data. */
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	/* Get hardware capabilities. */
+	match = of_match_node(atmel_i2s_dt_ids, np);
+	if (match)
+		dev->caps = match->data;
+
+	/* Map I/O registers. */
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	regmap = devm_regmap_init_mmio(&pdev->dev, base,
+				       &atmel_i2s_regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	/* Request IRQ. */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	err = devm_request_irq(&pdev->dev, irq, atmel_i2s_interrupt, 0,
+			       dev_name(&pdev->dev), dev);
+	if (err)
+		return err;
+
+	/* Get the peripheral clock. */
+	dev->pclk = devm_clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(dev->pclk)) {
+		err = PTR_ERR(dev->pclk);
+		dev_err(&pdev->dev,
+			"failed to get the peripheral clock: %d\n", err);
+		return err;
+	}
+
+	/* Get audio clocks to generate the I2S Master Clock (I2S_MCK) */
+	dev->aclk = devm_clk_get(&pdev->dev, "aclk");
+	dev->gclk = devm_clk_get(&pdev->dev, "gclk");
+	if (IS_ERR(dev->aclk) && IS_ERR(dev->gclk)) {
+		if (PTR_ERR(dev->aclk) == -EPROBE_DEFER ||
+		    PTR_ERR(dev->gclk) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		/* Master Mode not supported */
+		dev->aclk = NULL;
+		dev->gclk = NULL;
+	} else if (IS_ERR(dev->gclk)) {
+		err = PTR_ERR(dev->gclk);
+		dev_err(&pdev->dev,
+			"failed to get the PMC generated clock: %d\n", err);
+		return err;
+	} else if (IS_ERR(dev->aclk)) {
+		err = PTR_ERR(dev->aclk);
+		dev_err(&pdev->dev,
+			"failed to get the PLL audio clock: %d\n", err);
+		return err;
+	}
+
+	dev->dev = &pdev->dev;
+	dev->regmap = regmap;
+	platform_set_drvdata(pdev, dev);
+
+	/* Do hardware specific settings to initialize I2S_MCK generator */
+	if (dev->caps && dev->caps->mck_init) {
+		err = dev->caps->mck_init(dev, np);
+		if (err)
+			return err;
+	}
+
+	/* Enable the peripheral clock. */
+	err = clk_prepare_enable(dev->pclk);
+	if (err)
+		return err;
+
+	/* Get IP version. */
+	regmap_read(dev->regmap, ATMEL_I2SC_VERSION, &version);
+	dev_info(&pdev->dev, "hw version: %#x\n", version);
+
+	/* Enable error interrupts. */
+	regmap_write(dev->regmap, ATMEL_I2SC_IER,
+		     ATMEL_I2SC_INT_RXOR | ATMEL_I2SC_INT_TXUR);
+
+	err = devm_snd_soc_register_component(&pdev->dev,
+					      &atmel_i2s_component,
+					      &atmel_i2s_dai, 1);
+	if (err) {
+		dev_err(&pdev->dev, "failed to register DAI: %d\n", err);
+		clk_disable_unprepare(dev->pclk);
+		return err;
+	}
+
+	/* Prepare DMA config. */
+	dev->playback.addr	= (dma_addr_t)mem->start + ATMEL_I2SC_THR;
+	dev->playback.maxburst	= 1;
+	dev->capture.addr	= (dma_addr_t)mem->start + ATMEL_I2SC_RHR;
+	dev->capture.maxburst	= 1;
+
+	if (of_property_match_string(np, "dma-names", "rx-tx") == 0)
+		pcm_flags |= SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX;
+	err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, pcm_flags);
+	if (err) {
+		dev_err(&pdev->dev, "failed to register PCM: %d\n", err);
+		clk_disable_unprepare(dev->pclk);
+		return err;
+	}
+
+	return 0;
+}
+
+static int atmel_i2s_remove(struct platform_device *pdev)
+{
+	struct atmel_i2s_dev *dev = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(dev->pclk);
+
+	return 0;
+}
+
+static struct platform_driver atmel_i2s_driver = {
+	.driver		= {
+		.name	= "atmel_i2s",
+		.of_match_table	= of_match_ptr(atmel_i2s_dt_ids),
+	},
+	.probe		= atmel_i2s_probe,
+	.remove		= atmel_i2s_remove,
+};
+module_platform_driver(atmel_i2s_driver);
+
+MODULE_DESCRIPTION("Atmel I2S Controller driver");
+MODULE_AUTHOR("Cyrille Pitchen <cyrille.pitchen@atmel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index a1e2c5682dcd..d3b69682d9c2 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -820,7 +820,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 		if (ret < 0) {
 			printk(KERN_WARNING
 					"atmel_ssc_dai: request_irq failure\n");
-			pr_debug("Atmel_ssc_dai: Stoping clock\n");
+			pr_debug("Atmel_ssc_dai: Stopping clock\n");
 			clk_disable(ssc_p->ssc->clk);
 			return ret;
 		}
@@ -1002,8 +1002,7 @@ static const struct snd_soc_component_driver atmel_ssc_component = {
 
 static int asoc_ssc_init(struct device *dev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct ssc_device *ssc = platform_get_drvdata(pdev);
+	struct ssc_device *ssc = dev_get_drvdata(dev);
 	int ret;
 
 	ret = snd_soc_register_component(dev, &atmel_ssc_component,
@@ -1033,8 +1032,7 @@ err:
 
 static void asoc_ssc_exit(struct device *dev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct ssc_device *ssc = platform_get_drvdata(pdev);
+	struct ssc_device *ssc = dev_get_drvdata(dev);
 
 	if (ssc->pdata->use_dma)
 		atmel_pcm_dma_platform_unregister(dev);
diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig
index edf367100ebd..02f50b7a966f 100644
--- a/sound/soc/bcm/Kconfig
+++ b/sound/soc/bcm/Kconfig
@@ -11,9 +11,8 @@ config SND_BCM2835_SOC_I2S
 config SND_SOC_CYGNUS
 	tristate "SoC platform audio for Broadcom Cygnus chips"
 	depends on ARCH_BCM_CYGNUS || COMPILE_TEST
-	depends on HAS_DMA
 	help
 	  Say Y if you want to add support for ASoC audio on Broadcom
 	  Cygnus chips (bcm958300, bcm958305, bcm911360)
 
-	  If you don't know what to do here, say N.
\ No newline at end of file
+	  If you don't know what to do here, say N.
diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig
index c7cd60f009e9..e09199124c36 100644
--- a/sound/soc/cirrus/Kconfig
+++ b/sound/soc/cirrus/Kconfig
@@ -9,6 +9,23 @@ config SND_EP93XX_SOC
 config SND_EP93XX_SOC_I2S
 	tristate
 
+if SND_EP93XX_SOC_I2S
+
+config SND_EP93XX_SOC_I2S_WATCHDOG
+	bool "IRQ based underflow watchdog workaround"
+	default y
+	help
+	  I2S controller on EP93xx seems to have undocumented HW issue.
+	  Underflow of internal I2S controller FIFO could confuse the
+	  state machine and the whole stream can be shifted by one byte
+	  until I2S is disabled. This option enables IRQ based watchdog
+	  which disables and re-enables I2S in case of underflow and
+	  fills FIFO with zeroes.
+
+	  If you are unsure how to answer this question, answer Y.
+
+endif # if SND_EP93XX_SOC_I2S
+
 config SND_EP93XX_SOC_AC97
 	tristate
 	select AC97_BUS
diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c
index c53bd6f2c2d7..3d011abaa266 100644
--- a/sound/soc/cirrus/edb93xx.c
+++ b/sound/soc/cirrus/edb93xx.c
@@ -67,7 +67,7 @@ static struct snd_soc_dai_link edb93xx_dai = {
 	.cpu_dai_name	= "ep93xx-i2s",
 	.codec_name	= "spi0.0",
 	.codec_dai_name	= "cs4271-hifi",
-	.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
+	.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 			  SND_SOC_DAIFMT_CBS_CFS,
 	.ops		= &edb93xx_ops,
 };
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
index 934f8aefdd90..0918c5da575a 100644
--- a/sound/soc/cirrus/ep93xx-i2s.c
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -35,8 +35,12 @@
 
 #define EP93XX_I2S_TXCLKCFG		0x00
 #define EP93XX_I2S_RXCLKCFG		0x04
+#define EP93XX_I2S_GLSTS		0x08
 #define EP93XX_I2S_GLCTRL		0x0C
 
+#define EP93XX_I2S_I2STX0LFT		0x10
+#define EP93XX_I2S_I2STX0RT		0x14
+
 #define EP93XX_I2S_TXLINCTRLDATA	0x28
 #define EP93XX_I2S_TXCTRL		0x2C
 #define EP93XX_I2S_TXWRDLEN		0x30
@@ -51,7 +55,17 @@
 #define EP93XX_I2S_WRDLEN_24		(1 << 0)
 #define EP93XX_I2S_WRDLEN_32		(2 << 0)
 
-#define EP93XX_I2S_LINCTRLDATA_R_JUST	(1 << 2) /* Right justify */
+#define EP93XX_I2S_RXLINCTRLDATA_R_JUST	BIT(1) /* Right justify */
+
+#define EP93XX_I2S_TXLINCTRLDATA_R_JUST	BIT(2) /* Right justify */
+
+/*
+ * Transmit empty interrupt level select:
+ * 0 - Generate interrupt when FIFO is half empty
+ * 1 - Generate interrupt when FIFO is empty
+ */
+#define EP93XX_I2S_TXCTRL_TXEMPTY_LVL	BIT(0)
+#define EP93XX_I2S_TXCTRL_TXUFIE	BIT(1) /* Transmit interrupt enable */
 
 #define EP93XX_I2S_CLKCFG_LRS		(1 << 0) /* lrclk polarity */
 #define EP93XX_I2S_CLKCFG_CKP		(1 << 1) /* Bit clock polarity */
@@ -59,6 +73,8 @@
 #define EP93XX_I2S_CLKCFG_MASTER	(1 << 3) /* Master mode */
 #define EP93XX_I2S_CLKCFG_NBCG		(1 << 4) /* Not bit clock gating */
 
+#define EP93XX_I2S_GLSTS_TX0_FIFO_FULL	BIT(12)
+
 struct ep93xx_i2s_info {
 	struct clk			*mclk;
 	struct clk			*sclk;
@@ -96,7 +112,6 @@ static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
 static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
 {
 	unsigned base_reg;
-	int i;
 
 	if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
 	    (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
@@ -109,27 +124,36 @@ static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
 		ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
 	}
 
-	/* Enable fifos */
+	/* Enable fifo */
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
 		base_reg = EP93XX_I2S_TX0EN;
 	else
 		base_reg = EP93XX_I2S_RX0EN;
-	for (i = 0; i < 3; i++)
-		ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1);
+	ep93xx_i2s_write_reg(info, base_reg, 1);
+
+	/* Enable TX IRQs (FIFO empty or underflow) */
+	if (IS_ENABLED(CONFIG_SND_EP93XX_SOC_I2S_WATCHDOG) &&
+	    stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCTRL,
+				     EP93XX_I2S_TXCTRL_TXEMPTY_LVL |
+				     EP93XX_I2S_TXCTRL_TXUFIE);
 }
 
 static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
 {
 	unsigned base_reg;
-	int i;
 
-	/* Disable fifos */
+	/* Disable IRQs */
+	if (IS_ENABLED(CONFIG_SND_EP93XX_SOC_I2S_WATCHDOG) &&
+	    stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCTRL, 0);
+
+	/* Disable fifo */
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
 		base_reg = EP93XX_I2S_TX0EN;
 	else
 		base_reg = EP93XX_I2S_RX0EN;
-	for (i = 0; i < 3; i++)
-		ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0);
+	ep93xx_i2s_write_reg(info, base_reg, 0);
 
 	if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
 	    (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
@@ -143,6 +167,37 @@ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
 	}
 }
 
+/*
+ * According to documentation I2S controller can handle underflow conditions
+ * just fine, but in reality the state machine is sometimes confused so that
+ * the whole stream is shifted by one byte. The watchdog below disables the TX
+ * FIFO, fills the buffer with zeroes and re-enables the FIFO. State machine
+ * is being reset and by filling the buffer we get some time before next
+ * underflow happens.
+ */
+static irqreturn_t ep93xx_i2s_interrupt(int irq, void *dev_id)
+{
+	struct ep93xx_i2s_info *info = dev_id;
+
+	/* Disable FIFO */
+	ep93xx_i2s_write_reg(info, EP93XX_I2S_TX0EN, 0);
+	/*
+	 * Fill TX FIFO with zeroes, this way we can defer next IRQs as much as
+	 * possible and get more time for DMA to catch up. Actually there are
+	 * only 8 samples in this FIFO, so even on 8kHz maximum deferral here is
+	 * 1ms.
+	 */
+	while (!(ep93xx_i2s_read_reg(info, EP93XX_I2S_GLSTS) &
+		 EP93XX_I2S_GLSTS_TX0_FIFO_FULL)) {
+		ep93xx_i2s_write_reg(info, EP93XX_I2S_I2STX0LFT, 0);
+		ep93xx_i2s_write_reg(info, EP93XX_I2S_I2STX0RT, 0);
+	}
+	/* Re-enable FIFO */
+	ep93xx_i2s_write_reg(info, EP93XX_I2S_TX0EN, 1);
+
+	return IRQ_HANDLED;
+}
+
 static int ep93xx_i2s_dai_probe(struct snd_soc_dai *dai)
 {
 	struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
@@ -170,25 +225,25 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 				  unsigned int fmt)
 {
 	struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
-	unsigned int clk_cfg, lin_ctrl;
+	unsigned int clk_cfg;
+	unsigned int txlin_ctrl = 0;
+	unsigned int rxlin_ctrl = 0;
 
 	clk_cfg  = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
-	lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA);
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 		clk_cfg |= EP93XX_I2S_CLKCFG_REL;
-		lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
 		break;
 
 	case SND_SOC_DAIFMT_LEFT_J:
 		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
-		lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
 		break;
 
 	case SND_SOC_DAIFMT_RIGHT_J:
 		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
-		lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST;
+		rxlin_ctrl |= EP93XX_I2S_RXLINCTRLDATA_R_JUST;
+		txlin_ctrl |= EP93XX_I2S_TXLINCTRLDATA_R_JUST;
 		break;
 
 	default:
@@ -213,32 +268,32 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF:
 		/* Negative bit clock, lrclk low on left word */
-		clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL);
+		clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_LRS);
 		break;
 
 	case SND_SOC_DAIFMT_NB_IF:
 		/* Negative bit clock, lrclk low on right word */
 		clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP;
-		clk_cfg |= EP93XX_I2S_CLKCFG_REL;
+		clk_cfg |= EP93XX_I2S_CLKCFG_LRS;
 		break;
 
 	case SND_SOC_DAIFMT_IB_NF:
 		/* Positive bit clock, lrclk low on left word */
 		clk_cfg |= EP93XX_I2S_CLKCFG_CKP;
-		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+		clk_cfg &= ~EP93XX_I2S_CLKCFG_LRS;
 		break;
 
 	case SND_SOC_DAIFMT_IB_IF:
 		/* Positive bit clock, lrclk low on right word */
-		clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL;
+		clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_LRS;
 		break;
 	}
 
 	/* Write new register values */
 	ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg);
 	ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg);
-	ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl);
-	ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl);
+	ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, rxlin_ctrl);
+	ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, txlin_ctrl);
 	return 0;
 }
 
@@ -392,6 +447,17 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
 	if (IS_ERR(info->regs))
 		return PTR_ERR(info->regs);
 
+	if (IS_ENABLED(CONFIG_SND_EP93XX_SOC_I2S_WATCHDOG)) {
+		int irq = platform_get_irq(pdev, 0);
+		if (irq <= 0)
+			return irq < 0 ? irq : -ENODEV;
+
+		err = devm_request_irq(&pdev->dev, irq, ep93xx_i2s_interrupt, 0,
+				       pdev->name, info);
+		if (err)
+			return err;
+	}
+
 	info->mclk = clk_get(&pdev->dev, "mclk");
 	if (IS_ERR(info->mclk)) {
 		err = PTR_ERR(info->mclk);
diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c
index 2334ec19e7eb..11ff7b2672b2 100644
--- a/sound/soc/cirrus/snappercl15.c
+++ b/sound/soc/cirrus/snappercl15.c
@@ -72,7 +72,7 @@ static struct snd_soc_dai_link snappercl15_dai = {
 	.codec_dai_name	= "tlv320aic23-hifi",
 	.codec_name	= "tlv320aic23-codec.0-001a",
 	.platform_name	= "ep93xx-i2s",
-	.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
+	.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 			  SND_SOC_DAIFMT_CBS_CFS,
 	.ops		= &snappercl15_ops,
 };
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9548f63ca531..63cf62e9c9aa 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -106,6 +106,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_MC13783 if MFD_MC13XXX
 	select SND_SOC_ML26124 if I2C
+	select SND_SOC_MT6351 if MTK_PMIC_WRAP
 	select SND_SOC_NAU8540 if I2C
 	select SND_SOC_NAU8810 if I2C
 	select SND_SOC_NAU8824 if I2C
@@ -126,6 +127,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_RT274 if I2C
 	select SND_SOC_RT286 if I2C
 	select SND_SOC_RT298 if I2C
+	select SND_SOC_RT1305 if I2C
 	select SND_SOC_RT5514 if I2C
 	select SND_SOC_RT5616 if I2C
 	select SND_SOC_RT5631 if I2C
@@ -136,12 +138,14 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_RT5660 if I2C
 	select SND_SOC_RT5663 if I2C
 	select SND_SOC_RT5665 if I2C
+	select SND_SOC_RT5668 if I2C
 	select SND_SOC_RT5670 if I2C
 	select SND_SOC_RT5677 if I2C && SPI_MASTER
 	select SND_SOC_SGTL5000 if I2C
 	select SND_SOC_SI476X if MFD_SI476X_CORE
 	select SND_SOC_SIRF_AUDIO_CODEC
 	select SND_SOC_SPDIF
+	select SND_SOC_SSM2305
 	select SND_SOC_SSM2518 if I2C
 	select SND_SOC_SSM2602_SPI if SPI_MASTER
 	select SND_SOC_SSM2602_I2C if I2C
@@ -168,6 +172,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_TPA6130A2 if I2C
 	select SND_SOC_TLV320DAC33 if I2C
 	select SND_SOC_TSCS42XX if I2C
+	select SND_SOC_TSCS454 if I2C
 	select SND_SOC_TS3A227E if I2C
 	select SND_SOC_TWL4030 if TWL4030_CORE
 	select SND_SOC_TWL6040 if TWL6040_CORE
@@ -770,8 +775,10 @@ config SND_SOC_RL6231
 	default y if SND_SOC_RT5660=y
 	default y if SND_SOC_RT5663=y
 	default y if SND_SOC_RT5665=y
+	default y if SND_SOC_RT5668=y
 	default y if SND_SOC_RT5670=y
 	default y if SND_SOC_RT5677=y
+	default y if SND_SOC_RT1305=y
 	default m if SND_SOC_RT5514=m
 	default m if SND_SOC_RT5616=m
 	default m if SND_SOC_RT5640=m
@@ -781,8 +788,10 @@ config SND_SOC_RL6231
 	default m if SND_SOC_RT5660=m
 	default m if SND_SOC_RT5663=m
 	default m if SND_SOC_RT5665=m
+	default m if SND_SOC_RT5668=m
 	default m if SND_SOC_RT5670=m
 	default m if SND_SOC_RT5677=m
+	default m if SND_SOC_RT1305=m
 
 config SND_SOC_RL6347A
 	tristate
@@ -805,6 +814,9 @@ config SND_SOC_RT298
 	tristate
 	depends on I2C
 
+config SND_SOC_RT1305
+	tristate
+
 config SND_SOC_RT5514
 	tristate
 
@@ -844,6 +856,9 @@ config SND_SOC_RT5663
 config SND_SOC_RT5665
 	tristate
 
+config SND_SOC_RT5668
+	tristate
+
 config SND_SOC_RT5670
 	tristate
 
@@ -883,6 +898,12 @@ config SND_SOC_SIRF_AUDIO_CODEC
 config SND_SOC_SPDIF
 	tristate "S/PDIF CODEC"
 
+config SND_SOC_SSM2305
+	tristate "Analog Devices SSM2305 Class-D Amplifier"
+	help
+	  Enable support for Analog Devices SSM2305 filterless
+	  high-efficiency mono Class-D audio power amplifiers.
+
 config SND_SOC_SSM2518
 	tristate
 
@@ -1011,6 +1032,13 @@ config SND_SOC_TSCS42XX
 	help
 	  Add support for Tempo Semiconductor's TSCS42xx audio CODEC.
 
+config SND_SOC_TSCS454
+	tristate "Tempo Semiconductor TSCS454 CODEC"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  Add support for Tempo Semiconductor's TSCS454 audio CODEC.
+
 config SND_SOC_TWL4030
 	select MFD_TWL4030_AUDIO
 	tristate
@@ -1111,7 +1139,7 @@ config SND_SOC_WM8776
 	depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8782
-	tristate
+	tristate "Wolfson Microelectronics WM8782 ADC"
 
 config SND_SOC_WM8804
 	tristate
@@ -1247,6 +1275,9 @@ config SND_SOC_MC13783
 config SND_SOC_ML26124
 	tristate
 
+config SND_SOC_MT6351
+	tristate "MediaTek MT6351 Codec"
+
 config SND_SOC_NAU8540
        tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
        depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index e849d1495308..e023fdf85221 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -102,6 +102,7 @@ snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
 snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
 snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
+snd-soc-mt6351-objs := mt6351.o
 snd-soc-nau8540-objs := nau8540.o
 snd-soc-nau8810-objs := nau8810.o
 snd-soc-nau8824-objs := nau8824.o
@@ -126,6 +127,7 @@ snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
 snd-soc-pcm512x-spi-objs := pcm512x-spi.o
 snd-soc-rl6231-objs := rl6231.o
 snd-soc-rl6347a-objs := rl6347a.o
+snd-soc-rt1305-objs := rt1305.o
 snd-soc-rt274-objs := rt274.o
 snd-soc-rt286-objs := rt286.o
 snd-soc-rt298-objs := rt298.o
@@ -140,6 +142,7 @@ snd-soc-rt5659-objs := rt5659.o
 snd-soc-rt5660-objs := rt5660.o
 snd-soc-rt5663-objs := rt5663.o
 snd-soc-rt5665-objs := rt5665.o
+snd-soc-rt5668-objs := rt5668.o
 snd-soc-rt5670-objs := rt5670.o
 snd-soc-rt5677-objs := rt5677.o
 snd-soc-rt5677-spi-objs := rt5677-spi.o
@@ -153,6 +156,7 @@ snd-soc-si476x-objs := si476x.o
 snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
 snd-soc-spdif-tx-objs := spdif_transmitter.o
 snd-soc-spdif-rx-objs := spdif_receiver.o
+snd-soc-ssm2305-objs := ssm2305.o
 snd-soc-ssm2518-objs := ssm2518.o
 snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-ssm2602-spi-objs := ssm2602-spi.o
@@ -180,6 +184,7 @@ snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-tlv320dac33-objs := tlv320dac33.o
 snd-soc-tscs42xx-objs := tscs42xx.o
+snd-soc-tscs454-objs := tscs454.o
 snd-soc-ts3a227e-objs := ts3a227e.o
 snd-soc-twl4030-objs := twl4030.o
 snd-soc-twl6040-objs := twl6040.o
@@ -355,6 +360,7 @@ obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
 obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
 obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
+obj-$(CONFIG_SND_SOC_MT6351)	+= snd-soc-mt6351.o
 obj-$(CONFIG_SND_SOC_NAU8540)   += snd-soc-nau8540.o
 obj-$(CONFIG_SND_SOC_NAU8810)   += snd-soc-nau8810.o
 obj-$(CONFIG_SND_SOC_NAU8824)   += snd-soc-nau8824.o
@@ -379,6 +385,7 @@ obj-$(CONFIG_SND_SOC_PCM512x_I2C)	+= snd-soc-pcm512x-i2c.o
 obj-$(CONFIG_SND_SOC_PCM512x_SPI)	+= snd-soc-pcm512x-spi.o
 obj-$(CONFIG_SND_SOC_RL6231)	+= snd-soc-rl6231.o
 obj-$(CONFIG_SND_SOC_RL6347A)	+= snd-soc-rl6347a.o
+obj-$(CONFIG_SND_SOC_RT1305)	+= snd-soc-rt1305.o
 obj-$(CONFIG_SND_SOC_RT274)	+= snd-soc-rt274.o
 obj-$(CONFIG_SND_SOC_RT286)	+= snd-soc-rt286.o
 obj-$(CONFIG_SND_SOC_RT298)	+= snd-soc-rt298.o
@@ -394,6 +401,7 @@ obj-$(CONFIG_SND_SOC_RT5659)	+= snd-soc-rt5659.o
 obj-$(CONFIG_SND_SOC_RT5660)	+= snd-soc-rt5660.o
 obj-$(CONFIG_SND_SOC_RT5663)	+= snd-soc-rt5663.o
 obj-$(CONFIG_SND_SOC_RT5665)	+= snd-soc-rt5665.o
+obj-$(CONFIG_SND_SOC_RT5668)	+= snd-soc-rt5668.o
 obj-$(CONFIG_SND_SOC_RT5670)	+= snd-soc-rt5670.o
 obj-$(CONFIG_SND_SOC_RT5677)	+= snd-soc-rt5677.o
 obj-$(CONFIG_SND_SOC_RT5677_SPI)	+= snd-soc-rt5677-spi.o
@@ -404,6 +412,7 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP)	+= snd-soc-sigmadsp-regmap.o
 obj-$(CONFIG_SND_SOC_SI476X)	+= snd-soc-si476x.o
 obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif-rx.o snd-soc-spdif-tx.o
 obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o
+obj-$(CONFIG_SND_SOC_SSM2305)	+= snd-soc-ssm2305.o
 obj-$(CONFIG_SND_SOC_SSM2518)	+= snd-soc-ssm2518.o
 obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_SSM2602_SPI)	+= snd-soc-ssm2602-spi.o
@@ -432,6 +441,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI)	+= snd-soc-tlv320aic32x4-spi.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TLV320DAC33)	+= snd-soc-tlv320dac33.o
 obj-$(CONFIG_SND_SOC_TSCS42XX)	+= snd-soc-tscs42xx.o
+obj-$(CONFIG_SND_SOC_TSCS454)	+= snd-soc-tscs454.o
 obj-$(CONFIG_SND_SOC_TS3A227E)	+= snd-soc-ts3a227e.o
 obj-$(CONFIG_SND_SOC_TWL4030)	+= snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index 12bf24c26818..ae41edd1c406 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -843,6 +843,15 @@ int adau17x1_setup_firmware(struct snd_soc_component *component,
 	struct adau *adau = snd_soc_component_get_drvdata(component);
 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
+	/* Check if sample rate is the same as before. If it is there is no
+	 * point in performing the below steps as the call to
+	 * sigmadsp_setup(...) will return directly when it finds the sample
+	 * rate to be the same as before. By checking this we can prevent an
+	 * audiable popping noise which occours when toggling DSP_RUN.
+	 */
+	if (adau->sigmadsp->current_samplerate == rate)
+		return 0;
+
 	snd_soc_dapm_mutex_lock(dapm);
 
 	ret = regmap_read(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, &dspsr);
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index a4a2cb171bdf..bd6226bde45f 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -1105,6 +1105,7 @@ static struct regmap_config cs35l35_regmap = {
 	.readable_reg = cs35l35_readable_register,
 	.precious_reg = cs35l35_precious_register,
 	.cache_type = REGCACHE_RBTREE,
+	.use_single_rw = true,
 };
 
 static irqreturn_t cs35l35_irq(int irq, void *data)
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
index feca0a672976..80dc42197154 100644
--- a/sound/soc/codecs/cs43130.c
+++ b/sound/soc/codecs/cs43130.c
@@ -1733,10 +1733,10 @@ static ssize_t cs43130_show_ac_r(struct device *dev,
 	return cs43130_show_ac(dev, buf, HP_RIGHT);
 }
 
-static DEVICE_ATTR(hpload_dc_l, S_IRUGO, cs43130_show_dc_l, NULL);
-static DEVICE_ATTR(hpload_dc_r, S_IRUGO, cs43130_show_dc_r, NULL);
-static DEVICE_ATTR(hpload_ac_l, S_IRUGO, cs43130_show_ac_l, NULL);
-static DEVICE_ATTR(hpload_ac_r, S_IRUGO, cs43130_show_ac_r, NULL);
+static DEVICE_ATTR(hpload_dc_l, 0444, cs43130_show_dc_l, NULL);
+static DEVICE_ATTR(hpload_dc_r, 0444, cs43130_show_dc_r, NULL);
+static DEVICE_ATTR(hpload_ac_l, 0444, cs43130_show_ac_l, NULL);
+static DEVICE_ATTR(hpload_ac_r, 0444, cs43130_show_ac_r, NULL);
 
 static struct reg_sequence hp_en_cal_seq[] = {
 	{CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 865f64c40b79..fb515aaa54fc 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -1382,15 +1382,12 @@ static const char *eq_mode_name[] = {"EQ1 Mode", "EQ2 Mode"};
 
 static int max98088_get_channel(struct snd_soc_component *component, const char *name)
 {
-	int i;
+	int ret;
 
-	for (i = 0; i < ARRAY_SIZE(eq_mode_name); i++)
-		if (strcmp(name, eq_mode_name[i]) == 0)
-			return i;
-
-	/* Shouldn't happen */
-	dev_err(component->dev, "Bad EQ channel name '%s'\n", name);
-	return -EINVAL;
+	ret = match_string(eq_mode_name, ARRAY_SIZE(eq_mode_name), name);
+	if (ret < 0)
+		dev_err(component->dev, "Bad EQ channel name '%s'\n", name);
+	return ret;
 }
 
 static void max98088_setup_eq1(struct snd_soc_component *component)
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 6bf2d0ba864f..3b3a10da7f40 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -1634,15 +1634,12 @@ static const char *bq_mode_name[] = {"Biquad1 Mode", "Biquad2 Mode"};
 static int max98095_get_bq_channel(struct snd_soc_component *component,
 				   const char *name)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(bq_mode_name); i++)
-		if (strcmp(name, bq_mode_name[i]) == 0)
-			return i;
+	int ret;
 
-	/* Shouldn't happen */
-	dev_err(component->dev, "Bad biquad channel name '%s'\n", name);
-	return -EINVAL;
+	ret = match_string(bq_mode_name, ARRAY_SIZE(bq_mode_name), name);
+	if (ret < 0)
+		dev_err(component->dev, "Bad biquad channel name '%s'\n", name);
+	return ret;
 }
 
 static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index 5bbf889ad98e..de3d44e9199b 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -1,23 +1,14 @@
-/*
- * Driver for the MAX9860 Mono Audio Voice Codec
- *
- * https://datasheets.maximintegrated.com/en/ds/MAX9860.pdf
- *
- * The driver does not support sidetone since the DVST register field is
- * backwards with the mute near the maximum level instead of the minimum.
- *
- * Author: Peter Rosin <peda@axentia.s>
- *         Copyright 2016 Axentia Technologies
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Driver for the MAX9860 Mono Audio Voice Codec
+//
+// https://datasheets.maximintegrated.com/en/ds/MAX9860.pdf
+//
+// The driver does not support sidetone since the DVST register field is
+// backwards with the mute near the maximum level instead of the minimum.
+//
+// Author: Peter Rosin <peda@axentia.s>
+//         Copyright 2016 Axentia Technologies
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -443,7 +434,8 @@ static int max9860_hw_params(struct snd_pcm_substream *substream,
 		ret = regmap_update_bits(max9860->regmap, MAX9860_AUDIOCLKHIGH,
 					 MAX9860_PLL, MAX9860_PLL);
 		if (ret) {
-			dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
+			dev_err(component->dev, "Failed to enable PLL: %d\n",
+				ret);
 			return ret;
 		}
 	}
@@ -515,7 +507,8 @@ static int max9860_set_bias_level(struct snd_soc_component *component,
 		ret = regmap_update_bits(max9860->regmap, MAX9860_PWRMAN,
 					 MAX9860_SHDN, MAX9860_SHDN);
 		if (ret) {
-			dev_err(component->dev, "Failed to remove SHDN: %d\n", ret);
+			dev_err(component->dev, "Failed to remove SHDN: %d\n",
+				ret);
 			return ret;
 		}
 		break;
@@ -598,8 +591,7 @@ static const struct dev_pm_ops max9860_pm_ops = {
 	SET_RUNTIME_PM_OPS(max9860_suspend, max9860_resume, NULL)
 };
 
-static int max9860_probe(struct i2c_client *i2c,
-			 const struct i2c_device_id *id)
+static int max9860_probe(struct i2c_client *i2c)
 {
 	struct device *dev = &i2c->dev;
 	struct max9860_priv *max9860;
@@ -698,7 +690,7 @@ static int max9860_probe(struct i2c_client *i2c,
 	pm_runtime_idle(dev);
 
 	ret = devm_snd_soc_register_component(dev, &max9860_component_driver,
-				     &max9860_dai, 1);
+					      &max9860_dai, 1);
 	if (ret) {
 		dev_err(dev, "Failed to register CODEC: %d\n", ret);
 		goto err_pm;
@@ -736,7 +728,7 @@ static const struct of_device_id max9860_of_match[] = {
 MODULE_DEVICE_TABLE(of, max9860_of_match);
 
 static struct i2c_driver max9860_i2c_driver = {
-	.probe	        = max9860_probe,
+	.probe_new      = max9860_probe,
 	.remove         = max9860_remove,
 	.id_table       = max9860_i2c_id,
 	.driver         = {
diff --git a/sound/soc/codecs/max9860.h b/sound/soc/codecs/max9860.h
index 22041bd67a7d..e07b905eaf50 100644
--- a/sound/soc/codecs/max9860.h
+++ b/sound/soc/codecs/max9860.h
@@ -1,17 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Driver for the MAX9860 Mono Audio Voice Codec
  *
  * Author: Peter Rosin <peda@axentia.s>
  *         Copyright 2016 Axentia Technologies
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
  */
 
 #ifndef _SND_SOC_MAX9860
diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c
new file mode 100644
index 000000000000..f73dcd753584
--- /dev/null
+++ b/sound/soc/codecs/mt6351.c
@@ -0,0 +1,1505 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt6351.c  --  mt6351 ALSA SoC audio codec driver
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "mt6351.h"
+
+/* MT6351_TOP_CLKSQ */
+#define RG_CLKSQ_EN_AUD_BIT (0)
+
+/* MT6351_TOP_CKPDN_CON0 */
+#define RG_AUDNCP_CK_PDN_BIT (12)
+#define RG_AUDIF_CK_PDN_BIT (13)
+#define RG_AUD_CK_PDN_BIT (14)
+#define RG_ZCD13M_CK_PDN_BIT (15)
+
+/* MT6351_AUDDEC_ANA_CON0 */
+#define RG_AUDDACLPWRUP_VAUDP32_BIT (0)
+#define RG_AUDDACRPWRUP_VAUDP32_BIT (1)
+#define RG_AUD_DAC_PWR_UP_VA32_BIT (2)
+#define RG_AUD_DAC_PWL_UP_VA32_BIT (3)
+
+#define RG_AUDHSPWRUP_VAUDP32_BIT (4)
+
+#define RG_AUDHPLPWRUP_VAUDP32_BIT (5)
+#define RG_AUDHPRPWRUP_VAUDP32_BIT (6)
+
+#define RG_AUDHSMUXINPUTSEL_VAUDP32_SFT (7)
+#define RG_AUDHSMUXINPUTSEL_VAUDP32_MASK (0x3)
+
+#define RG_AUDHPLMUXINPUTSEL_VAUDP32_SFT (9)
+#define RG_AUDHPLMUXINPUTSEL_VAUDP32_MASK (0x3)
+
+#define RG_AUDHPRMUXINPUTSEL_VAUDP32_SFT (11)
+#define RG_AUDHPRMUXINPUTSEL_VAUDP32_MASK (0x3)
+
+#define RG_AUDHSSCDISABLE_VAUDP32 (13)
+#define RG_AUDHPLSCDISABLE_VAUDP32_BIT (14)
+#define RG_AUDHPRSCDISABLE_VAUDP32_BIT (15)
+
+/* MT6351_AUDDEC_ANA_CON1 */
+#define RG_HSOUTPUTSTBENH_VAUDP32_BIT (8)
+
+/* MT6351_AUDDEC_ANA_CON3 */
+#define RG_AUDLOLPWRUP_VAUDP32_BIT (2)
+
+#define RG_AUDLOLMUXINPUTSEL_VAUDP32_SFT (3)
+#define RG_AUDLOLMUXINPUTSEL_VAUDP32_MASK (0x3)
+
+#define RG_AUDLOLSCDISABLE_VAUDP32_BIT (5)
+#define RG_LOOUTPUTSTBENH_VAUDP32_BIT (9)
+
+/* MT6351_AUDDEC_ANA_CON6 */
+#define RG_ABIDEC_RSVD0_VAUDP32_HPL_BIT (8)
+#define RG_ABIDEC_RSVD0_VAUDP32_HPR_BIT (9)
+#define RG_ABIDEC_RSVD0_VAUDP32_HS_BIT (10)
+#define RG_ABIDEC_RSVD0_VAUDP32_LOL_BIT (11)
+
+/* MT6351_AUDDEC_ANA_CON9 */
+#define RG_AUDIBIASPWRDN_VAUDP32_BIT (8)
+#define RG_RSTB_DECODER_VA32_BIT (9)
+#define RG_AUDGLB_PWRDN_VA32_BIT (12)
+
+#define RG_LCLDO_DEC_EN_VA32_BIT (13)
+#define RG_LCLDO_DEC_REMOTE_SENSE_VA18_BIT (15)
+/* MT6351_AUDDEC_ANA_CON10 */
+#define RG_NVREG_EN_VAUDP32_BIT (8)
+
+#define RG_AUDGLB_LP2_VOW_EN_VA32 10
+
+/* MT6351_AFE_UL_DL_CON0 */
+#define RG_AFE_ON_BIT (0)
+
+/* MT6351_AFE_DL_SRC2_CON0_L */
+#define RG_DL_2_SRC_ON_TMP_CTL_PRE_BIT (0)
+
+/* MT6351_AFE_UL_SRC_CON0_L */
+#define UL_SRC_ON_TMP_CTL (0)
+
+/* MT6351_AFE_TOP_CON0 */
+#define RG_DL_SINE_ON_SFT (0)
+#define RG_DL_SINE_ON_MASK (0x1)
+
+#define RG_UL_SINE_ON_SFT (1)
+#define RG_UL_SINE_ON_MASK (0x1)
+
+/* MT6351_AUDIO_TOP_CON0 */
+#define AUD_TOP_PDN_RESERVED_BIT 0
+#define AUD_TOP_PWR_CLK_DIS_CTL_BIT 2
+#define AUD_TOP_PDN_ADC_CTL_BIT 5
+#define AUD_TOP_PDN_DAC_CTL_BIT 6
+#define AUD_TOP_PDN_AFE_CTL_BIT 7
+
+/* MT6351_AFE_SGEN_CFG0 */
+#define SGEN_C_MUTE_SW_CTL_BIT 6
+#define SGEN_C_DAC_EN_CTL_BIT 7
+
+/* MT6351_AFE_NCP_CFG0 */
+#define RG_NCP_ON_BIT 0
+
+/* MT6351_LDO_VUSB33_CON0 */
+#define RG_VUSB33_EN 1
+#define RG_VUSB33_ON_CTRL 3
+
+/* MT6351_LDO_VA18_CON0 */
+#define RG_VA18_EN 1
+#define RG_VA18_ON_CTRL 3
+
+/* MT6351_AUDENC_ANA_CON0 */
+#define RG_AUDPREAMPLON 0
+#define RG_AUDPREAMPLDCCEN 1
+#define RG_AUDPREAMPLDCPRECHARGE 2
+
+#define RG_AUDPREAMPLINPUTSEL_SFT (4)
+#define RG_AUDPREAMPLINPUTSEL_MASK (0x3)
+
+#define RG_AUDADCLPWRUP 12
+
+#define RG_AUDADCLINPUTSEL_SFT (13)
+#define RG_AUDADCLINPUTSEL_MASK (0x3)
+
+/* MT6351_AUDENC_ANA_CON1 */
+#define RG_AUDPREAMPRON 0
+#define RG_AUDPREAMPRDCCEN 1
+#define RG_AUDPREAMPRDCPRECHARGE 2
+
+#define RG_AUDPREAMPRINPUTSEL_SFT (4)
+#define RG_AUDPREAMPRINPUTSEL_MASK (0x3)
+
+#define RG_AUDADCRPWRUP 12
+
+#define RG_AUDADCRINPUTSEL_SFT (13)
+#define RG_AUDADCRINPUTSEL_MASK (0x3)
+
+/* MT6351_AUDENC_ANA_CON3 */
+#define RG_AUDADCCLKRSTB 6
+
+/* MT6351_AUDENC_ANA_CON9 */
+#define RG_AUDPWDBMICBIAS0 0
+#define RG_AUDMICBIAS0VREF 4
+#define RG_AUDMICBIAS0LOWPEN 7
+
+#define RG_AUDPWDBMICBIAS2 8
+#define RG_AUDMICBIAS2VREF 12
+#define RG_AUDMICBIAS2LOWPEN 15
+
+/* MT6351_AUDENC_ANA_CON10 */
+#define RG_AUDPWDBMICBIAS1 0
+#define RG_AUDMICBIAS1DCSW1NEN 2
+#define RG_AUDMICBIAS1VREF 4
+#define RG_AUDMICBIAS1LOWPEN 7
+
+enum {
+	AUDIO_ANALOG_VOLUME_HSOUTL,
+	AUDIO_ANALOG_VOLUME_HSOUTR,
+	AUDIO_ANALOG_VOLUME_HPOUTL,
+	AUDIO_ANALOG_VOLUME_HPOUTR,
+	AUDIO_ANALOG_VOLUME_LINEOUTL,
+	AUDIO_ANALOG_VOLUME_LINEOUTR,
+	AUDIO_ANALOG_VOLUME_MICAMP1,
+	AUDIO_ANALOG_VOLUME_MICAMP2,
+	AUDIO_ANALOG_VOLUME_TYPE_MAX
+};
+
+/* Supply subseq */
+enum {
+	SUPPLY_SUBSEQ_SETTING,
+	SUPPLY_SUBSEQ_ENABLE,
+	SUPPLY_SUBSEQ_MICBIAS,
+};
+
+#define REG_STRIDE 2
+
+struct mt6351_priv {
+	struct device *dev;
+	struct regmap *regmap;
+
+	unsigned int dl_rate;
+	unsigned int ul_rate;
+
+	int ana_gain[AUDIO_ANALOG_VOLUME_TYPE_MAX];
+
+	int hp_en_counter;
+};
+
+static void set_hp_gain_zero(struct snd_soc_component *cmpnt)
+{
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON2,
+			   0x1f << 7, 0x8 << 7);
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON2,
+			   0x1f << 0, 0x8 << 0);
+}
+
+static unsigned int get_cap_reg_val(struct snd_soc_component *cmpnt,
+				    unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return 0;
+	case 16000:
+		return 1;
+	case 32000:
+		return 2;
+	case 48000:
+		return 3;
+	case 96000:
+		return 4;
+	case 192000:
+		return 5;
+	default:
+		dev_warn(cmpnt->dev, "%s(), error rate %d, return 3",
+			 __func__, rate);
+		return 3;
+	}
+}
+
+static unsigned int get_play_reg_val(struct snd_soc_component *cmpnt,
+				     unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return 0;
+	case 11025:
+		return 1;
+	case 12000:
+		return 2;
+	case 16000:
+		return 3;
+	case 22050:
+		return 4;
+	case 24000:
+		return 5;
+	case 32000:
+		return 6;
+	case 44100:
+		return 7;
+	case 48000:
+	case 96000:
+	case 192000:
+		return 8;
+	default:
+		dev_warn(cmpnt->dev, "%s(), error rate %d, return 8",
+			 __func__, rate);
+		return 8;
+	}
+}
+
+static int mt6351_codec_dai_hw_params(struct snd_pcm_substream *substream,
+				      struct snd_pcm_hw_params *params,
+				      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *cmpnt = dai->component;
+	struct mt6351_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int rate = params_rate(params);
+
+	dev_dbg(priv->dev, "%s(), substream->stream %d, rate %d\n",
+		__func__, substream->stream, rate);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		priv->dl_rate = rate;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		priv->ul_rate = rate;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mt6351_codec_dai_ops = {
+	.hw_params = mt6351_codec_dai_hw_params,
+};
+
+#define MT6351_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\
+			SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
+			SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\
+			SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\
+			SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE)
+
+static struct snd_soc_dai_driver mt6351_dai_driver[] = {
+	{
+		.name = "mt6351-snd-codec-aif1",
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000 |
+				 SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = MT6351_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.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,
+			.formats = MT6351_FORMATS,
+		},
+		.ops = &mt6351_codec_dai_ops,
+	},
+};
+
+enum {
+	HP_GAIN_SET_ZERO,
+	HP_GAIN_RESTORE,
+};
+
+static void hp_gain_ramp_set(struct snd_soc_component *cmpnt, int hp_gain_ctl)
+{
+	struct mt6351_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+	int idx, old_idx, offset, reg_idx;
+
+	if (hp_gain_ctl == HP_GAIN_SET_ZERO) {
+		idx = 8;	/* 0dB */
+		old_idx = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL];
+	} else {
+		idx = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL];
+		old_idx = 8;	/* 0dB */
+	}
+	dev_dbg(priv->dev, "%s(), idx %d, old_idx %d\n",
+		__func__, idx, old_idx);
+
+	if (idx > old_idx)
+		offset = idx - old_idx;
+	else
+		offset = old_idx - idx;
+
+	reg_idx = old_idx;
+
+	while (offset > 0) {
+		reg_idx = idx > old_idx ? reg_idx + 1 : reg_idx - 1;
+
+		/* check valid range, and set value */
+		if ((reg_idx >= 0 && reg_idx <= 0x12) || reg_idx == 0x1f) {
+			regmap_update_bits(cmpnt->regmap,
+					   MT6351_ZCD_CON2,
+					   0xf9f,
+					   (reg_idx << 7) | reg_idx);
+			usleep_range(100, 120);
+		}
+		offset--;
+	}
+}
+
+static void hp_zcd_enable(struct snd_soc_component *cmpnt)
+{
+	/* Enable ZCD, for minimize pop noise */
+	/* when adjust gain during HP buffer on */
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON0, 0x7 << 8, 0x1 << 8);
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON0, 0x1 << 7, 0x0 << 7);
+
+	/* timeout, 1=5ms, 0=30ms */
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON0, 0x1 << 6, 0x1 << 6);
+
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON0, 0x3 << 4, 0x0 << 4);
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON0, 0x7 << 1, 0x5 << 1);
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON0, 0x1 << 0, 0x1 << 0);
+}
+
+static void hp_zcd_disable(struct snd_soc_component *cmpnt)
+{
+	regmap_write(cmpnt->regmap, MT6351_ZCD_CON0, 0x0000);
+}
+
+static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
+static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new mt6351_snd_controls[] = {
+	/* dl pga gain */
+	SOC_DOUBLE_TLV("Headphone Volume",
+		       MT6351_ZCD_CON2, 0, 7, 0x12, 1,
+		       playback_tlv),
+	SOC_DOUBLE_TLV("Lineout Volume",
+		       MT6351_ZCD_CON1, 0, 7, 0x12, 1,
+		       playback_tlv),
+	SOC_SINGLE_TLV("Handset Volume",
+		       MT6351_ZCD_CON3, 0, 0x12, 1,
+		       playback_tlv),
+       /* ul pga gain */
+	SOC_DOUBLE_R_TLV("PGA Volume",
+			 MT6351_AUDENC_ANA_CON0, MT6351_AUDENC_ANA_CON1,
+			 8, 4, 0,
+			 pga_tlv),
+};
+
+/* MUX */
+
+/* LOL MUX */
+static const char *const lo_in_mux_map[] = {
+	"Open", "Mute", "Playback", "Test Mode",
+};
+
+static int lo_in_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(lo_in_mux_map_enum,
+				  MT6351_AUDDEC_ANA_CON3,
+				  RG_AUDLOLMUXINPUTSEL_VAUDP32_SFT,
+				  RG_AUDLOLMUXINPUTSEL_VAUDP32_MASK,
+				  lo_in_mux_map,
+				  lo_in_mux_map_value);
+
+static const struct snd_kcontrol_new lo_in_mux_control =
+	SOC_DAPM_ENUM("In Select", lo_in_mux_map_enum);
+
+/*HP MUX */
+static const char *const hp_in_mux_map[] = {
+	"Open", "LoudSPK Playback", "Audio Playback", "Test Mode",
+};
+
+static int hp_in_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hpl_in_mux_map_enum,
+				  MT6351_AUDDEC_ANA_CON0,
+				  RG_AUDHPLMUXINPUTSEL_VAUDP32_SFT,
+				  RG_AUDHPLMUXINPUTSEL_VAUDP32_MASK,
+				  hp_in_mux_map,
+				  hp_in_mux_map_value);
+
+static const struct snd_kcontrol_new hpl_in_mux_control =
+	SOC_DAPM_ENUM("HPL Select", hpl_in_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hpr_in_mux_map_enum,
+				  MT6351_AUDDEC_ANA_CON0,
+				  RG_AUDHPRMUXINPUTSEL_VAUDP32_SFT,
+				  RG_AUDHPRMUXINPUTSEL_VAUDP32_MASK,
+				  hp_in_mux_map,
+				  hp_in_mux_map_value);
+
+static const struct snd_kcontrol_new hpr_in_mux_control =
+	SOC_DAPM_ENUM("HPR Select", hpr_in_mux_map_enum);
+
+/* RCV MUX */
+static const char *const rcv_in_mux_map[] = {
+	"Open", "Mute", "Voice Playback", "Test Mode",
+};
+
+static int rcv_in_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rcv_in_mux_map_enum,
+				  MT6351_AUDDEC_ANA_CON0,
+				  RG_AUDHSMUXINPUTSEL_VAUDP32_SFT,
+				  RG_AUDHSMUXINPUTSEL_VAUDP32_MASK,
+				  rcv_in_mux_map,
+				  rcv_in_mux_map_value);
+
+static const struct snd_kcontrol_new rcv_in_mux_control =
+	SOC_DAPM_ENUM("RCV Select", rcv_in_mux_map_enum);
+
+/* DAC In MUX */
+static const char *const dac_in_mux_map[] = {
+	"Normal Path", "Sgen",
+};
+
+static int dac_in_mux_map_value[] = {
+	0x0, 0x1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(dac_in_mux_map_enum,
+				  MT6351_AFE_TOP_CON0,
+				  RG_DL_SINE_ON_SFT,
+				  RG_DL_SINE_ON_MASK,
+				  dac_in_mux_map,
+				  dac_in_mux_map_value);
+
+static const struct snd_kcontrol_new dac_in_mux_control =
+	SOC_DAPM_ENUM("DAC Select", dac_in_mux_map_enum);
+
+/* AIF Out MUX */
+static SOC_VALUE_ENUM_SINGLE_DECL(aif_out_mux_map_enum,
+				  MT6351_AFE_TOP_CON0,
+				  RG_UL_SINE_ON_SFT,
+				  RG_UL_SINE_ON_MASK,
+				  dac_in_mux_map,
+				  dac_in_mux_map_value);
+
+static const struct snd_kcontrol_new aif_out_mux_control =
+	SOC_DAPM_ENUM("AIF Out Select", aif_out_mux_map_enum);
+
+/* ADC L MUX */
+static const char *const adc_left_mux_map[] = {
+	"Idle", "AIN0", "Left Preamplifier", "Idle_1",
+};
+
+static int adc_left_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adc_left_mux_map_enum,
+				  MT6351_AUDENC_ANA_CON0,
+				  RG_AUDADCLINPUTSEL_SFT,
+				  RG_AUDADCLINPUTSEL_MASK,
+				  adc_left_mux_map,
+				  adc_left_mux_map_value);
+
+static const struct snd_kcontrol_new adc_left_mux_control =
+	SOC_DAPM_ENUM("ADC L Select", adc_left_mux_map_enum);
+
+/* ADC R MUX */
+static const char *const adc_right_mux_map[] = {
+	"Idle", "AIN0", "Right Preamplifier", "Idle_1",
+};
+
+static int adc_right_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adc_right_mux_map_enum,
+				  MT6351_AUDENC_ANA_CON1,
+				  RG_AUDADCRINPUTSEL_SFT,
+				  RG_AUDADCRINPUTSEL_MASK,
+				  adc_right_mux_map,
+				  adc_right_mux_map_value);
+
+static const struct snd_kcontrol_new adc_right_mux_control =
+	SOC_DAPM_ENUM("ADC R Select", adc_right_mux_map_enum);
+
+/* PGA L MUX */
+static const char *const pga_left_mux_map[] = {
+	"None", "AIN0", "AIN1", "AIN2",
+};
+
+static int pga_left_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(pga_left_mux_map_enum,
+				  MT6351_AUDENC_ANA_CON0,
+				  RG_AUDPREAMPLINPUTSEL_SFT,
+				  RG_AUDPREAMPLINPUTSEL_MASK,
+				  pga_left_mux_map,
+				  pga_left_mux_map_value);
+
+static const struct snd_kcontrol_new pga_left_mux_control =
+	SOC_DAPM_ENUM("PGA L Select", pga_left_mux_map_enum);
+
+/* PGA R MUX */
+static const char *const pga_right_mux_map[] = {
+	"None", "AIN0", "AIN3", "AIN2",
+};
+
+static int pga_right_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(pga_right_mux_map_enum,
+				  MT6351_AUDENC_ANA_CON1,
+				  RG_AUDPREAMPRINPUTSEL_SFT,
+				  RG_AUDPREAMPRINPUTSEL_MASK,
+				  pga_right_mux_map,
+				  pga_right_mux_map_value);
+
+static const struct snd_kcontrol_new pga_right_mux_control =
+	SOC_DAPM_ENUM("PGA R Select", pga_right_mux_map_enum);
+
+static int mt_reg_set_clr_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (w->on_val) {
+			/* SET REG */
+			regmap_update_bits(cmpnt->regmap,
+					   w->reg + REG_STRIDE,
+					   0x1 << w->shift,
+					   0x1 << w->shift);
+		} else {
+			/* CLR REG */
+			regmap_update_bits(cmpnt->regmap,
+					   w->reg + REG_STRIDE * 2,
+					   0x1 << w->shift,
+					   0x1 << w->shift);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if (w->off_val) {
+			/* SET REG */
+			regmap_update_bits(cmpnt->regmap,
+					   w->reg + REG_STRIDE,
+					   0x1 << w->shift,
+					   0x1 << w->shift);
+		} else {
+			/* CLR REG */
+			regmap_update_bits(cmpnt->regmap,
+					   w->reg + REG_STRIDE * 2,
+					   0x1 << w->shift,
+					   0x1 << w->shift);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_ncp_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_NCP_CFG1,
+				   0xffff, 0x1515);
+		/* NCP: ck1 and ck2 clock frequecy adjust configure */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_NCP_CFG0,
+				   0xfffe, 0x8C00);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(250, 270);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_sgen_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_SGEN_CFG0,
+				   0xffef, 0x0008);
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_SGEN_CFG1,
+				   0xffff, 0x0101);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_aif_in_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 mt6351_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	dev_dbg(priv->dev, "%s(), event 0x%x, rate %d\n",
+		__func__, event, priv->dl_rate);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* sdm audio fifo clock power on */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFUNC_AUD_CON2,
+				   0xffff, 0x0006);
+		/* scrambler clock on enable */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFUNC_AUD_CON0,
+				   0xffff, 0xC3A1);
+		/* sdm power on */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFUNC_AUD_CON2,
+				   0xffff, 0x0003);
+		/* sdm fifo enable */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFUNC_AUD_CON2,
+				   0xffff, 0x000B);
+		/* set attenuation gain */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_DL_SDM_CON1,
+				   0xffff, 0x001E);
+
+		regmap_write(cmpnt->regmap, MT6351_AFE_PMIC_NEWIF_CFG0,
+			     (get_play_reg_val(cmpnt, priv->dl_rate) << 12) |
+			     0x330);
+		regmap_write(cmpnt->regmap, MT6351_AFE_DL_SRC2_CON0_H,
+			     (get_play_reg_val(cmpnt, priv->dl_rate) << 12) |
+			     0x300);
+
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_PMIC_NEWIF_CFG2,
+				   0x8000, 0x8000);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_hp_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 mt6351_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+	int reg;
+
+	dev_dbg(priv->dev, "%s(), event 0x%x, hp_en_counter %d\n",
+		__func__, event, priv->hp_en_counter);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		priv->hp_en_counter++;
+		if (priv->hp_en_counter > 1)
+			break;	/* already enabled, do nothing */
+		else if (priv->hp_en_counter <= 0)
+			dev_err(priv->dev, "%s(), hp_en_counter %d <= 0\n",
+				__func__,
+				priv->hp_en_counter);
+
+		hp_zcd_disable(cmpnt);
+
+		/* from yoyo HQA script */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON6,
+				   0x0700, 0x0700);
+
+		/* save target gain to restore after hardware open complete */
+		regmap_read(cmpnt->regmap, MT6351_ZCD_CON2, &reg);
+		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] = reg & 0x1f;
+		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] = (reg >> 7) & 0x1f;
+
+		/* Set HPR/HPL gain as minimum (~ -40dB) */
+		regmap_update_bits(cmpnt->regmap,
+				   MT6351_ZCD_CON2, 0xffff, 0x0F9F);
+		/* Set HS gain as minimum (~ -40dB) */
+		regmap_update_bits(cmpnt->regmap,
+				   MT6351_ZCD_CON3, 0xffff, 0x001F);
+		/* De_OSC of HP */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON2,
+				   0x0001, 0x0001);
+		/* enable output STBENH */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON1,
+				   0xffff, 0x2000);
+		/* De_OSC of voice, enable output STBENH */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON1,
+				   0xffff, 0x2100);
+		/* Enable voice driver */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON0,
+				   0x0010, 0xE090);
+		/* Enable pre-charge buffer  */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON1,
+				   0xffff, 0x2140);
+
+		usleep_range(50, 60);
+
+		/* Apply digital DC compensation value to DAC */
+		set_hp_gain_zero(cmpnt);
+
+		/* Enable HPR/HPL */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON1,
+				   0xffff, 0x2100);
+		/* Disable pre-charge buffer */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON1,
+				   0xffff, 0x2000);
+		/* Disable De_OSC of voice */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON0,
+				   0x0010, 0xF4EF);
+		/* Disable voice buffer */
+
+		/* from yoyo HQ */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON6,
+				   0x0700, 0x0300);
+
+		/* Enable ZCD, for minimize pop noise */
+		/* when adjust gain during HP buffer on */
+		hp_zcd_enable(cmpnt);
+
+		/* apply volume setting */
+		hp_gain_ramp_set(cmpnt, HP_GAIN_RESTORE);
+
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		priv->hp_en_counter--;
+		if (priv->hp_en_counter > 0)
+			break;	/* still being used, don't close */
+		else if (priv->hp_en_counter < 0)
+			dev_err(priv->dev, "%s(), hp_en_counter %d <= 0\n",
+				__func__,
+				priv->hp_en_counter);
+
+		/* Disable AUD_ZCD */
+		hp_zcd_disable(cmpnt);
+
+		/* Set HPR/HPL gain as -1dB, step by step */
+		hp_gain_ramp_set(cmpnt, HP_GAIN_SET_ZERO);
+
+		set_hp_gain_zero(cmpnt);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (priv->hp_en_counter > 0)
+			break;	/* still being used, don't close */
+		else if (priv->hp_en_counter < 0)
+			dev_err(priv->dev, "%s(), hp_en_counter %d <= 0\n",
+				__func__,
+				priv->hp_en_counter);
+
+		/* reset*/
+		regmap_update_bits(cmpnt->regmap,
+				   MT6351_AUDDEC_ANA_CON6,
+				   0x0700,
+				   0x0000);
+		/* De_OSC of HP */
+		regmap_update_bits(cmpnt->regmap,
+				   MT6351_AUDDEC_ANA_CON2,
+				   0x0001,
+				   0x0000);
+
+		/* apply volume setting */
+		hp_gain_ramp_set(cmpnt, HP_GAIN_RESTORE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_aif_out_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 mt6351_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	dev_dbg(priv->dev, "%s(), event 0x%x, rate %d\n",
+		__func__, event, priv->ul_rate);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* dcclk_div=11'b00100000011, dcclk_ref_ck_sel=2'b00 */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_DCCLK_CFG0,
+				   0xffff, 0x2062);
+		/* dcclk_pdn=1'b0 */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_DCCLK_CFG0,
+				   0xffff, 0x2060);
+		/* dcclk_gen_on=1'b1 */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_DCCLK_CFG0,
+				   0xffff, 0x2061);
+
+		/* UL sample rate and mode configure */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_UL_SRC_CON0_H,
+				   0x000E,
+				   get_cap_reg_val(cmpnt, priv->ul_rate) << 1);
+
+		/* fixed 260k path for 8/16/32/48 */
+		if (priv->ul_rate <= 48000) {
+			/* anc ul path src on */
+			regmap_update_bits(cmpnt->regmap,
+					   MT6351_AFE_HPANC_CFG0,
+					   0x1 << 1,
+					   0x1 << 1);
+			/* ANC clk pdn release */
+			regmap_update_bits(cmpnt->regmap,
+					   MT6351_AFE_HPANC_CFG0,
+					   0x1 << 0,
+					   0x0 << 0);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* fixed 260k path for 8/16/32/48 */
+		if (priv->ul_rate <= 48000) {
+			/* anc ul path src on */
+			regmap_update_bits(cmpnt->regmap,
+					   MT6351_AFE_HPANC_CFG0,
+					   0x1 << 1,
+					   0x0 << 1);
+			/* ANC clk pdn release */
+			regmap_update_bits(cmpnt->regmap,
+					   MT6351_AFE_HPANC_CFG0,
+					   0x1 << 0,
+					   0x1 << 0);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_adc_clkgen_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Audio ADC clock gen. mode: 00_divided by 2 (Normal) */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON3,
+				   0x3 << 4, 0x0);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* ADC CLK from: 00_13MHz from CLKSQ (Default) */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON3,
+				   0x3 << 2, 0x0);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int mt_pga_left_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Audio L PGA precharge on */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON0,
+				   0x3 << RG_AUDPREAMPLDCPRECHARGE,
+				   0x1 << RG_AUDPREAMPLDCPRECHARGE);
+		/* Audio L PGA mode: 1_DCC */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON0,
+				   0x3 << RG_AUDPREAMPLDCCEN,
+				   0x1 << RG_AUDPREAMPLDCCEN);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(100, 120);
+		/* Audio L PGA precharge off */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON0,
+				   0x3 << RG_AUDPREAMPLDCPRECHARGE,
+				   0x0 << RG_AUDPREAMPLDCPRECHARGE);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int mt_pga_right_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Audio R PGA precharge on */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON1,
+				   0x3 << RG_AUDPREAMPRDCPRECHARGE,
+				   0x1 << RG_AUDPREAMPRDCPRECHARGE);
+		/* Audio R PGA mode: 1_DCC */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON1,
+				   0x3 << RG_AUDPREAMPRDCCEN,
+				   0x1 << RG_AUDPREAMPRDCCEN);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(100, 120);
+		/* Audio R PGA precharge off */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON1,
+				   0x3 << RG_AUDPREAMPRDCPRECHARGE,
+				   0x0 << RG_AUDPREAMPRDCPRECHARGE);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int mt_mic_bias_0_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* MIC Bias 0 LowPower: 0_Normal */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON9,
+				   0x3 << RG_AUDMICBIAS0LOWPEN, 0x0);
+		/* MISBIAS0 = 1P9V */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON9,
+				   0x7 << RG_AUDMICBIAS0VREF,
+				   0x2 << RG_AUDMICBIAS0VREF);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* MISBIAS0 = 1P97 */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON9,
+				   0x7 << RG_AUDMICBIAS0VREF,
+				   0x0 << RG_AUDMICBIAS0VREF);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int mt_mic_bias_1_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* MIC Bias 1 LowPower: 0_Normal */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON10,
+				   0x3 << RG_AUDMICBIAS1LOWPEN, 0x0);
+		/* MISBIAS1 = 2P7V */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON10,
+				   0x7 << RG_AUDMICBIAS1VREF,
+				   0x7 << RG_AUDMICBIAS1VREF);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* MISBIAS1 = 1P7V */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON10,
+				   0x7 << RG_AUDMICBIAS1VREF,
+				   0x0 << RG_AUDMICBIAS1VREF);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int mt_mic_bias_2_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* MIC Bias 2 LowPower: 0_Normal */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON9,
+				   0x3 << RG_AUDMICBIAS2LOWPEN, 0x0);
+		/* MISBIAS2 = 1P9V */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON9,
+				   0x7 << RG_AUDMICBIAS2VREF,
+				   0x2 << RG_AUDMICBIAS2VREF);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* MISBIAS2 = 1P97 */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON9,
+				   0x7 << RG_AUDMICBIAS2VREF,
+				   0x0 << RG_AUDMICBIAS2VREF);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* DAPM Kcontrols */
+static const struct snd_kcontrol_new mt_lineout_control =
+	SOC_DAPM_SINGLE("Switch", MT6351_AUDDEC_ANA_CON3,
+			RG_AUDLOLPWRUP_VAUDP32_BIT, 1, 0);
+
+/* DAPM Widgets */
+static const struct snd_soc_dapm_widget mt6351_dapm_widgets[] = {
+	/* Digital Clock */
+	SND_SOC_DAPM_SUPPLY("AUDIO_TOP_AFE_CTL", MT6351_AUDIO_TOP_CON0,
+			    AUD_TOP_PDN_AFE_CTL_BIT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AUDIO_TOP_DAC_CTL", MT6351_AUDIO_TOP_CON0,
+			    AUD_TOP_PDN_DAC_CTL_BIT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AUDIO_TOP_ADC_CTL", MT6351_AUDIO_TOP_CON0,
+			    AUD_TOP_PDN_ADC_CTL_BIT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AUDIO_TOP_PWR_CLK", MT6351_AUDIO_TOP_CON0,
+			    AUD_TOP_PWR_CLK_DIS_CTL_BIT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AUDIO_TOP_PDN_RESERVED", MT6351_AUDIO_TOP_CON0,
+			    AUD_TOP_PDN_RESERVED_BIT, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("NCP", MT6351_AFE_NCP_CFG0,
+			    RG_NCP_ON_BIT, 0,
+			    mt_ncp_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SUPPLY("DL Digital Clock", SND_SOC_NOPM,
+			    0, 0, NULL, 0),
+
+	/* Global Supply*/
+	SND_SOC_DAPM_SUPPLY("AUDGLB", MT6351_AUDDEC_ANA_CON9,
+			    RG_AUDGLB_PWRDN_VA32_BIT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKSQ Audio", MT6351_TOP_CLKSQ,
+			    RG_CLKSQ_EN_AUD_BIT, 0,
+			    mt_reg_set_clr_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("ZCD13M_CK", MT6351_TOP_CKPDN_CON0,
+			    RG_ZCD13M_CK_PDN_BIT, 1,
+			    mt_reg_set_clr_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("AUD_CK", MT6351_TOP_CKPDN_CON0,
+			    RG_AUD_CK_PDN_BIT, 1,
+			    mt_reg_set_clr_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("AUDIF_CK", MT6351_TOP_CKPDN_CON0,
+			    RG_AUDIF_CK_PDN_BIT, 1,
+			    mt_reg_set_clr_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("AUDNCP_CK", MT6351_TOP_CKPDN_CON0,
+			    RG_AUDNCP_CK_PDN_BIT, 1,
+			    mt_reg_set_clr_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SUPPLY("AFE_ON", MT6351_AFE_UL_DL_CON0, RG_AFE_ON_BIT, 0,
+			    NULL, 0),
+
+	/* AIF Rx*/
+	SND_SOC_DAPM_AIF_IN_E("AIF_RX", "AIF1 Playback", 0,
+			      MT6351_AFE_DL_SRC2_CON0_L,
+			      RG_DL_2_SRC_ON_TMP_CTL_PRE_BIT, 0,
+			      mt_aif_in_event, SND_SOC_DAPM_PRE_PMU),
+
+	/* DL Supply */
+	SND_SOC_DAPM_SUPPLY("DL Power Supply", SND_SOC_NOPM,
+			    0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("NV Regulator", MT6351_AUDDEC_ANA_CON10,
+			    RG_NVREG_EN_VAUDP32_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AUD_CLK", MT6351_AUDDEC_ANA_CON9,
+			    RG_RSTB_DECODER_VA32_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("IBIST", MT6351_AUDDEC_ANA_CON9,
+			    RG_AUDIBIASPWRDN_VAUDP32_BIT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO", MT6351_AUDDEC_ANA_CON9,
+			    RG_LCLDO_DEC_EN_VA32_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO_REMOTE_SENSE", MT6351_AUDDEC_ANA_CON9,
+			    RG_LCLDO_DEC_REMOTE_SENSE_VA18_BIT, 0, NULL, 0),
+
+	/* DAC */
+	SND_SOC_DAPM_MUX("DAC In Mux", SND_SOC_NOPM, 0, 0, &dac_in_mux_control),
+
+	SND_SOC_DAPM_DAC("DACL", NULL, MT6351_AUDDEC_ANA_CON0,
+			 RG_AUDDACLPWRUP_VAUDP32_BIT, 0),
+	SND_SOC_DAPM_SUPPLY("DACL_BIASGEN", MT6351_AUDDEC_ANA_CON0,
+			    RG_AUD_DAC_PWL_UP_VA32_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("DACR", NULL, MT6351_AUDDEC_ANA_CON0,
+			 RG_AUDDACRPWRUP_VAUDP32_BIT, 0),
+	SND_SOC_DAPM_SUPPLY("DACR_BIASGEN", MT6351_AUDDEC_ANA_CON0,
+			    RG_AUD_DAC_PWR_UP_VA32_BIT, 0, NULL, 0),
+	/* LOL */
+	SND_SOC_DAPM_MUX("LOL Mux", SND_SOC_NOPM, 0, 0, &lo_in_mux_control),
+
+	SND_SOC_DAPM_SUPPLY("LO Stability Enh", MT6351_AUDDEC_ANA_CON3,
+			    RG_LOOUTPUTSTBENH_VAUDP32_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LOL Bias Gen", MT6351_AUDDEC_ANA_CON6,
+			    RG_ABIDEC_RSVD0_VAUDP32_LOL_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUT_DRV("LOL Buffer", MT6351_AUDDEC_ANA_CON3,
+			     RG_AUDLOLPWRUP_VAUDP32_BIT, 0, NULL, 0),
+
+	/* Headphone */
+	SND_SOC_DAPM_MUX("HPL Mux", SND_SOC_NOPM, 0, 0, &hpl_in_mux_control),
+	SND_SOC_DAPM_MUX("HPR Mux", SND_SOC_NOPM, 0, 0, &hpr_in_mux_control),
+
+	SND_SOC_DAPM_OUT_DRV_E("HPL Power", MT6351_AUDDEC_ANA_CON0,
+			       RG_AUDHPLPWRUP_VAUDP32_BIT, 0, NULL, 0,
+			       mt_hp_event,
+			       SND_SOC_DAPM_PRE_PMU |
+			       SND_SOC_DAPM_PRE_PMD |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_OUT_DRV_E("HPR Power", MT6351_AUDDEC_ANA_CON0,
+			       RG_AUDHPRPWRUP_VAUDP32_BIT, 0, NULL, 0,
+			       mt_hp_event,
+			       SND_SOC_DAPM_PRE_PMU |
+			       SND_SOC_DAPM_PRE_PMD |
+			       SND_SOC_DAPM_POST_PMD),
+
+	/* Receiver */
+	SND_SOC_DAPM_MUX("RCV Mux", SND_SOC_NOPM, 0, 0, &rcv_in_mux_control),
+
+	SND_SOC_DAPM_SUPPLY("RCV Stability Enh", MT6351_AUDDEC_ANA_CON1,
+			    RG_HSOUTPUTSTBENH_VAUDP32_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RCV Bias Gen", MT6351_AUDDEC_ANA_CON6,
+			    RG_ABIDEC_RSVD0_VAUDP32_HS_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUT_DRV("RCV Buffer", MT6351_AUDDEC_ANA_CON0,
+			     RG_AUDHSPWRUP_VAUDP32_BIT, 0, NULL, 0),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("Receiver"),
+	SND_SOC_DAPM_OUTPUT("Headphone L"),
+	SND_SOC_DAPM_OUTPUT("Headphone R"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT L"),
+
+	/* SGEN */
+	SND_SOC_DAPM_SUPPLY("SGEN DL Enable", MT6351_AFE_SGEN_CFG0,
+			    SGEN_C_DAC_EN_CTL_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SGEN MUTE", MT6351_AFE_SGEN_CFG0,
+			    SGEN_C_MUTE_SW_CTL_BIT, 1,
+			    mt_sgen_event, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("SGEN DL SRC", MT6351_AFE_DL_SRC2_CON0_L,
+			    RG_DL_2_SRC_ON_TMP_CTL_PRE_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_INPUT("SGEN DL"),
+
+	/* Uplinks */
+	SND_SOC_DAPM_AIF_OUT_E("AIF1TX", "AIF1 Capture", 0,
+			       MT6351_AFE_UL_SRC_CON0_L,
+			       UL_SRC_ON_TMP_CTL, 0,
+			       mt_aif_out_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("VUSB33_LDO", SUPPLY_SUBSEQ_ENABLE,
+			      MT6351_LDO_VUSB33_CON0, RG_VUSB33_EN, 0,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("VUSB33_LDO_CTRL", SUPPLY_SUBSEQ_SETTING,
+			      MT6351_LDO_VUSB33_CON0, RG_VUSB33_ON_CTRL, 1,
+			      NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("VA18_LDO", SUPPLY_SUBSEQ_ENABLE,
+			      MT6351_LDO_VA18_CON0, RG_VA18_EN, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("VA18_LDO_CTRL", SUPPLY_SUBSEQ_SETTING,
+			      MT6351_LDO_VA18_CON0, RG_VA18_ON_CTRL, 1,
+			      NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("ADC CLKGEN", SUPPLY_SUBSEQ_ENABLE,
+			      MT6351_AUDENC_ANA_CON3, RG_AUDADCCLKRSTB, 0,
+			      mt_adc_clkgen_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+	/* Uplinks MUX */
+	SND_SOC_DAPM_MUX("AIF Out Mux", SND_SOC_NOPM, 0, 0,
+			 &aif_out_mux_control),
+
+	SND_SOC_DAPM_MUX("ADC L Mux", SND_SOC_NOPM, 0, 0,
+			 &adc_left_mux_control),
+	SND_SOC_DAPM_MUX("ADC R Mux", SND_SOC_NOPM, 0, 0,
+			 &adc_right_mux_control),
+
+	SND_SOC_DAPM_ADC("ADC L", NULL,
+			 MT6351_AUDENC_ANA_CON0, RG_AUDADCLPWRUP, 0),
+	SND_SOC_DAPM_ADC("ADC R", NULL,
+			 MT6351_AUDENC_ANA_CON1, RG_AUDADCRPWRUP, 0),
+
+	SND_SOC_DAPM_MUX("PGA L Mux", SND_SOC_NOPM, 0, 0,
+			 &pga_left_mux_control),
+	SND_SOC_DAPM_MUX("PGA R Mux", SND_SOC_NOPM, 0, 0,
+			 &pga_right_mux_control),
+
+	SND_SOC_DAPM_PGA_E("PGA L", MT6351_AUDENC_ANA_CON0, RG_AUDPREAMPLON, 0,
+			   NULL, 0,
+			   mt_pga_left_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("PGA R", MT6351_AUDENC_ANA_CON1, RG_AUDPREAMPRON, 0,
+			   NULL, 0,
+			   mt_pga_right_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+	/* main mic mic bias */
+	SND_SOC_DAPM_SUPPLY_S("Mic Bias 0", SUPPLY_SUBSEQ_MICBIAS,
+			      MT6351_AUDENC_ANA_CON9, RG_AUDPWDBMICBIAS0, 0,
+			      mt_mic_bias_0_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	/* ref mic mic bias */
+	SND_SOC_DAPM_SUPPLY_S("Mic Bias 2", SUPPLY_SUBSEQ_MICBIAS,
+			      MT6351_AUDENC_ANA_CON9, RG_AUDPWDBMICBIAS2, 0,
+			      mt_mic_bias_2_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	/* headset mic1/2 mic bias */
+	SND_SOC_DAPM_SUPPLY_S("Mic Bias 1", SUPPLY_SUBSEQ_MICBIAS,
+			      MT6351_AUDENC_ANA_CON10, RG_AUDPWDBMICBIAS1, 0,
+			      mt_mic_bias_1_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("Mic Bias 1 DCC pull high", SUPPLY_SUBSEQ_MICBIAS,
+			      MT6351_AUDENC_ANA_CON10,
+			      RG_AUDMICBIAS1DCSW1NEN, 0,
+			      NULL, 0),
+
+	/* UL input */
+	SND_SOC_DAPM_INPUT("AIN0"),
+	SND_SOC_DAPM_INPUT("AIN1"),
+	SND_SOC_DAPM_INPUT("AIN2"),
+	SND_SOC_DAPM_INPUT("AIN3"),
+};
+
+static const struct snd_soc_dapm_route mt6351_dapm_routes[] = {
+	/* Capture */
+	{"AIF1TX", NULL, "AIF Out Mux"},
+	{"AIF1TX", NULL, "VUSB33_LDO"},
+	{"VUSB33_LDO", NULL, "VUSB33_LDO_CTRL"},
+	{"AIF1TX", NULL, "VA18_LDO"},
+	{"VA18_LDO", NULL, "VA18_LDO_CTRL"},
+
+	{"AIF1TX", NULL, "AUDGLB"},
+	{"AIF1TX", NULL, "CLKSQ Audio"},
+
+	{"AIF1TX", NULL, "AFE_ON"},
+
+	{"AIF1TX", NULL, "AUDIO_TOP_AFE_CTL"},
+	{"AIF1TX", NULL, "AUDIO_TOP_ADC_CTL"},
+	{"AIF1TX", NULL, "AUDIO_TOP_PWR_CLK"},
+	{"AIF1TX", NULL, "AUDIO_TOP_PDN_RESERVED"},
+
+	{"AIF Out Mux", "Normal Path", "ADC L"},
+	{"AIF Out Mux", "Normal Path", "ADC R"},
+
+	{"ADC L", NULL, "ADC L Mux"},
+	{"ADC L", NULL, "AUD_CK"},
+	{"ADC L", NULL, "AUDIF_CK"},
+	{"ADC L", NULL, "ADC CLKGEN"},
+	{"ADC R", NULL, "ADC R Mux"},
+	{"ADC R", NULL, "AUD_CK"},
+	{"ADC R", NULL, "AUDIF_CK"},
+	{"ADC R", NULL, "ADC CLKGEN"},
+
+	{"ADC L Mux", "AIN0", "AIN0"},
+	{"ADC L Mux", "Left Preamplifier", "PGA L"},
+
+	{"ADC R Mux", "AIN0", "AIN0"},
+	{"ADC R Mux", "Right Preamplifier", "PGA R"},
+
+	{"PGA L", NULL, "PGA L Mux"},
+	{"PGA R", NULL, "PGA R Mux"},
+
+	{"PGA L Mux", "AIN0", "AIN0"},
+	{"PGA L Mux", "AIN1", "AIN1"},
+	{"PGA L Mux", "AIN2", "AIN2"},
+
+	{"PGA R Mux", "AIN0", "AIN0"},
+	{"PGA R Mux", "AIN3", "AIN3"},
+	{"PGA R Mux", "AIN2", "AIN2"},
+
+	{"AIN0", NULL, "Mic Bias 0"},
+	{"AIN2", NULL, "Mic Bias 2"},
+
+	{"AIN1", NULL, "Mic Bias 1"},
+	{"AIN1", NULL, "Mic Bias 1 DCC pull high"},
+
+	/* DL Supply */
+	{"DL Power Supply", NULL, "AUDGLB"},
+	{"DL Power Supply", NULL, "CLKSQ Audio"},
+	{"DL Power Supply", NULL, "ZCD13M_CK"},
+	{"DL Power Supply", NULL, "AUD_CK"},
+	{"DL Power Supply", NULL, "AUDIF_CK"},
+	{"DL Power Supply", NULL, "AUDNCP_CK"},
+
+	{"DL Power Supply", NULL, "NV Regulator"},
+	{"DL Power Supply", NULL, "AUD_CLK"},
+	{"DL Power Supply", NULL, "IBIST"},
+	{"DL Power Supply", NULL, "LDO"},
+	{"LDO", NULL, "LDO_REMOTE_SENSE"},
+
+	/* DL Digital Supply */
+	{"DL Digital Clock", NULL, "AUDIO_TOP_AFE_CTL"},
+	{"DL Digital Clock", NULL, "AUDIO_TOP_DAC_CTL"},
+	{"DL Digital Clock", NULL, "AUDIO_TOP_PWR_CLK"},
+	{"DL Digital Clock", NULL, "AUDIO_TOP_PDN_RESERVED"},
+	{"DL Digital Clock", NULL, "NCP"},
+	{"DL Digital Clock", NULL, "AFE_ON"},
+
+	{"AIF_RX", NULL, "DL Digital Clock"},
+
+	/* DL Path */
+	{"DAC In Mux", "Normal Path", "AIF_RX"},
+
+	{"DAC In Mux", "Sgen", "SGEN DL"},
+	{"SGEN DL", NULL, "SGEN DL SRC"},
+	{"SGEN DL", NULL, "SGEN MUTE"},
+	{"SGEN DL", NULL, "SGEN DL Enable"},
+	{"SGEN DL", NULL, "DL Digital Clock"},
+
+	{"DACL", NULL, "DAC In Mux"},
+	{"DACL", NULL, "DL Power Supply"},
+	{"DACL", NULL, "DACL_BIASGEN"},
+
+	{"DACR", NULL, "DAC In Mux"},
+	{"DACR", NULL, "DL Power Supply"},
+	{"DACR", NULL, "DACR_BIASGEN"},
+
+	{"LOL Mux", "Playback", "DACL"},
+
+	{"LOL Buffer", NULL, "LOL Mux"},
+	{"LOL Buffer", NULL, "LO Stability Enh"},
+	{"LOL Buffer", NULL, "LOL Bias Gen"},
+
+	{"LINEOUT L", NULL, "LOL Buffer"},
+
+	/* Headphone Path */
+	{"HPL Mux", "Audio Playback", "DACL"},
+	{"HPR Mux", "Audio Playback", "DACR"},
+
+	{"HPL Mux", "LoudSPK Playback", "DACL"},
+	{"HPR Mux", "LoudSPK Playback", "DACR"},
+
+	{"HPL Power", NULL, "HPL Mux"},
+	{"HPR Power", NULL, "HPR Mux"},
+
+	{"Headphone L", NULL, "HPL Power"},
+	{"Headphone R", NULL, "HPR Power"},
+
+	/* Receiver Path */
+	{"RCV Mux", "Voice Playback", "DACL"},
+
+	{"RCV Buffer", NULL, "RCV Mux"},
+	{"RCV Buffer", NULL, "RCV Stability Enh"},
+	{"RCV Buffer", NULL, "RCV Bias Gen"},
+
+	{"Receiver", NULL, "RCV Buffer"},
+};
+
+static int mt6351_codec_init_reg(struct snd_soc_component *cmpnt)
+{
+	int ret = 0;
+
+	/* Disable CLKSQ 26MHz */
+	regmap_update_bits(cmpnt->regmap, MT6351_TOP_CLKSQ, 0x0001, 0x0);
+	/* disable AUDGLB */
+	regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON9,
+			   0x1000, 0x1000);
+	/* Turn off AUDNCP_CLKDIV engine clock,Turn off AUD 26M */
+	regmap_update_bits(cmpnt->regmap, MT6351_TOP_CKPDN_CON0_SET,
+			   0x3800, 0x3800);
+	/* Disable HeadphoneL/HeadphoneR/voice short circuit protection */
+	regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON0,
+			   0xe000, 0xe000);
+	/* [5] = 1, disable LO buffer left short circuit protection */
+	regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON3,
+			   0x20, 0x20);
+	/* Reverse the PMIC clock*/
+	regmap_update_bits(cmpnt->regmap, MT6351_AFE_PMIC_NEWIF_CFG2,
+			   0x8000, 0x8000);
+	return ret;
+}
+
+static int mt6351_codec_probe(struct snd_soc_component *cmpnt)
+{
+	struct mt6351_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	snd_soc_component_init_regmap(cmpnt, priv->regmap);
+
+	mt6351_codec_init_reg(cmpnt);
+	return 0;
+}
+
+static const struct snd_soc_component_driver mt6351_soc_component_driver = {
+	.probe = mt6351_codec_probe,
+	.controls = mt6351_snd_controls,
+	.num_controls = ARRAY_SIZE(mt6351_snd_controls),
+	.dapm_widgets = mt6351_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt6351_dapm_widgets),
+	.dapm_routes = mt6351_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(mt6351_dapm_routes),
+};
+
+static int mt6351_codec_driver_probe(struct platform_device *pdev)
+{
+	struct mt6351_priv *priv;
+
+	priv = devm_kzalloc(&pdev->dev,
+			    sizeof(struct mt6351_priv),
+			    GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dev_set_drvdata(&pdev->dev, priv);
+
+	priv->dev = &pdev->dev;
+
+	priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!priv->regmap)
+		return -ENODEV;
+
+	dev_dbg(priv->dev, "%s(), dev name %s\n",
+		__func__, dev_name(&pdev->dev));
+
+	return devm_snd_soc_register_component(&pdev->dev,
+					       &mt6351_soc_component_driver,
+					       mt6351_dai_driver,
+					       ARRAY_SIZE(mt6351_dai_driver));
+}
+
+static const struct of_device_id mt6351_of_match[] = {
+	{.compatible = "mediatek,mt6351-sound",},
+	{}
+};
+
+static struct platform_driver mt6351_codec_driver = {
+	.driver = {
+		.name = "mt6351-sound",
+		.of_match_table = mt6351_of_match,
+	},
+	.probe = mt6351_codec_driver_probe,
+};
+
+module_platform_driver(mt6351_codec_driver)
+
+/* Module information */
+MODULE_DESCRIPTION("MT6351 ALSA SoC codec driver");
+MODULE_AUTHOR("KaiChieh Chuang <kaichieh.chuang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/mt6351.h b/sound/soc/codecs/mt6351.h
new file mode 100644
index 000000000000..04b2ab694ec7
--- /dev/null
+++ b/sound/soc/codecs/mt6351.h
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt6351.h  --  mt6351 ALSA SoC audio codec driver
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef __MT6351_H__
+#define __MT6351_H__
+
+#define MT6351_AFE_UL_DL_CON0               (0x2000 + 0x0000)
+#define MT6351_AFE_DL_SRC2_CON0_H           (0x2000 + 0x0002)
+#define MT6351_AFE_DL_SRC2_CON0_L           (0x2000 + 0x0004)
+#define MT6351_AFE_DL_SDM_CON0              (0x2000 + 0x0006)
+#define MT6351_AFE_DL_SDM_CON1              (0x2000 + 0x0008)
+#define MT6351_AFE_UL_SRC_CON0_H            (0x2000 + 0x000a)
+#define MT6351_AFE_UL_SRC_CON0_L            (0x2000 + 0x000c)
+#define MT6351_AFE_UL_SRC_CON1_H            (0x2000 + 0x000e)
+#define MT6351_AFE_UL_SRC_CON1_L            (0x2000 + 0x0010)
+#define MT6351_AFE_TOP_CON0                 (0x2000 + 0x0012)
+#define MT6351_AUDIO_TOP_CON0               (0x2000 + 0x0014)
+#define MT6351_AFE_DL_SRC_MON0              (0x2000 + 0x0016)
+#define MT6351_AFE_DL_SDM_TEST0             (0x2000 + 0x0018)
+#define MT6351_AFE_MON_DEBUG0               (0x2000 + 0x001a)
+#define MT6351_AFUNC_AUD_CON0               (0x2000 + 0x001c)
+#define MT6351_AFUNC_AUD_CON1               (0x2000 + 0x001e)
+#define MT6351_AFUNC_AUD_CON2               (0x2000 + 0x0020)
+#define MT6351_AFUNC_AUD_CON3               (0x2000 + 0x0022)
+#define MT6351_AFUNC_AUD_CON4               (0x2000 + 0x0024)
+#define MT6351_AFUNC_AUD_MON0               (0x2000 + 0x0026)
+#define MT6351_AFUNC_AUD_MON1               (0x2000 + 0x0028)
+#define MT6351_AFE_UP8X_FIFO_CFG0           (0x2000 + 0x002c)
+#define MT6351_AFE_UP8X_FIFO_LOG_MON0       (0x2000 + 0x002e)
+#define MT6351_AFE_UP8X_FIFO_LOG_MON1       (0x2000 + 0x0030)
+#define MT6351_AFE_DL_DC_COMP_CFG0          (0x2000 + 0x0032)
+#define MT6351_AFE_DL_DC_COMP_CFG1          (0x2000 + 0x0034)
+#define MT6351_AFE_DL_DC_COMP_CFG2          (0x2000 + 0x0036)
+#define MT6351_AFE_PMIC_NEWIF_CFG0          (0x2000 + 0x0038)
+#define MT6351_AFE_PMIC_NEWIF_CFG1          (0x2000 + 0x003a)
+#define MT6351_AFE_PMIC_NEWIF_CFG2          (0x2000 + 0x003c)
+#define MT6351_AFE_PMIC_NEWIF_CFG3          (0x2000 + 0x003e)
+#define MT6351_AFE_SGEN_CFG0                (0x2000 + 0x0040)
+#define MT6351_AFE_SGEN_CFG1                (0x2000 + 0x0042)
+#define MT6351_AFE_ADDA2_UP8X_FIFO_LOG_MON0 (0x2000 + 0x004c)
+#define MT6351_AFE_ADDA2_UP8X_FIFO_LOG_MON1 (0x2000 + 0x004e)
+#define MT6351_AFE_ADDA2_PMIC_NEWIF_CFG0    (0x2000 + 0x0050)
+#define MT6351_AFE_ADDA2_PMIC_NEWIF_CFG1    (0x2000 + 0x0052)
+#define MT6351_AFE_ADDA2_PMIC_NEWIF_CFG2    (0x2000 + 0x0054)
+#define MT6351_AFE_DCCLK_CFG0               (0x2000 + 0x0090)
+#define MT6351_AFE_DCCLK_CFG1               (0x2000 + 0x0092)
+#define MT6351_AFE_HPANC_CFG0               (0x2000 + 0x0094)
+#define MT6351_AFE_NCP_CFG0                 (0x2000 + 0x0096)
+#define MT6351_AFE_NCP_CFG1                 (0x2000 + 0x0098)
+
+#define MT6351_TOP_CKPDN_CON0      0x023A
+#define MT6351_TOP_CKPDN_CON0_SET  0x023C
+#define MT6351_TOP_CKPDN_CON0_CLR  0x023E
+
+#define MT6351_TOP_CLKSQ           0x029A
+#define MT6351_TOP_CLKSQ_SET       0x029C
+#define MT6351_TOP_CLKSQ_CLR       0x029E
+
+#define MT6351_ZCD_CON0            0x0800
+#define MT6351_ZCD_CON1            0x0802
+#define MT6351_ZCD_CON2            0x0804
+#define MT6351_ZCD_CON3            0x0806
+#define MT6351_ZCD_CON4            0x0808
+#define MT6351_ZCD_CON5            0x080A
+
+#define MT6351_LDO_VA18_CON0       0x0A00
+#define MT6351_LDO_VA18_CON1       0x0A02
+#define MT6351_LDO_VUSB33_CON0     0x0A16
+#define MT6351_LDO_VUSB33_CON1     0x0A18
+
+#define MT6351_AUDDEC_ANA_CON0     0x0CF2
+#define MT6351_AUDDEC_ANA_CON1     0x0CF4
+#define MT6351_AUDDEC_ANA_CON2     0x0CF6
+#define MT6351_AUDDEC_ANA_CON3     0x0CF8
+#define MT6351_AUDDEC_ANA_CON4     0x0CFA
+#define MT6351_AUDDEC_ANA_CON5     0x0CFC
+#define MT6351_AUDDEC_ANA_CON6     0x0CFE
+#define MT6351_AUDDEC_ANA_CON7     0x0D00
+#define MT6351_AUDDEC_ANA_CON8     0x0D02
+#define MT6351_AUDDEC_ANA_CON9     0x0D04
+#define MT6351_AUDDEC_ANA_CON10    0x0D06
+
+#define MT6351_AUDENC_ANA_CON0     0x0D08
+#define MT6351_AUDENC_ANA_CON1     0x0D0A
+#define MT6351_AUDENC_ANA_CON2     0x0D0C
+#define MT6351_AUDENC_ANA_CON3     0x0D0E
+#define MT6351_AUDENC_ANA_CON4     0x0D10
+#define MT6351_AUDENC_ANA_CON5     0x0D12
+#define MT6351_AUDENC_ANA_CON6     0x0D14
+#define MT6351_AUDENC_ANA_CON7     0x0D16
+#define MT6351_AUDENC_ANA_CON8     0x0D18
+#define MT6351_AUDENC_ANA_CON9     0x0D1A
+#define MT6351_AUDENC_ANA_CON10    0x0D1C
+#define MT6351_AUDENC_ANA_CON11    0x0D1E
+#define MT6351_AUDENC_ANA_CON12    0x0D20
+#define MT6351_AUDENC_ANA_CON13    0x0D22
+#define MT6351_AUDENC_ANA_CON14    0x0D24
+#define MT6351_AUDENC_ANA_CON15    0x0D26
+#define MT6351_AUDENC_ANA_CON16    0x0D28
+#endif
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
index ca2ba1c7bb9a..bfd74b86c9d2 100644
--- a/sound/soc/codecs/nau8810.c
+++ b/sound/soc/codecs/nau8810.c
@@ -373,9 +373,11 @@ static const struct snd_kcontrol_new nau8810_mono_mixer_controls[] = {
 };
 
 /* PGA Mute */
-static const struct snd_kcontrol_new nau8810_inpga_mute[] = {
+static const struct snd_kcontrol_new nau8810_pgaboost_mixer_controls[] = {
 	SOC_DAPM_SINGLE("PGA Mute Switch", NAU8810_REG_PGAGAIN,
-		NAU8810_PGAMT_SFT, 1, 0),
+		NAU8810_PGAMT_SFT, 1, 1),
+	SOC_DAPM_SINGLE("PMIC PGA Switch", NAU8810_REG_ADCBOOST,
+		NAU8810_PMICBSTGAIN_SFT, 0x7, 0),
 };
 
 /* Input PGA */
@@ -386,11 +388,6 @@ static const struct snd_kcontrol_new nau8810_inpga[] = {
 		NAU8810_PMICPGA_SFT, 1, 0),
 };
 
-/* Mic Input boost vol */
-static const struct snd_kcontrol_new nau8810_mic_boost_controls =
-	SOC_DAPM_SINGLE("Mic Volume", NAU8810_REG_ADCBOOST,
-		NAU8810_PMICBSTGAIN_SFT, 0x7, 0);
-
 /* Loopback Switch */
 static const struct snd_kcontrol_new nau8810_loopback =
 	SOC_DAPM_SINGLE("Switch", NAU8810_REG_COMP,
@@ -429,8 +426,8 @@ static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = {
 		NAU8810_PGA_EN_SFT, 0, nau8810_inpga,
 		ARRAY_SIZE(nau8810_inpga)),
 	SND_SOC_DAPM_MIXER("Input Boost Stage", NAU8810_REG_POWER2,
-		NAU8810_BST_EN_SFT, 0, nau8810_inpga_mute,
-		ARRAY_SIZE(nau8810_inpga_mute)),
+		NAU8810_BST_EN_SFT, 0, nau8810_pgaboost_mixer_controls,
+		ARRAY_SIZE(nau8810_pgaboost_mixer_controls)),
 
 	SND_SOC_DAPM_SUPPLY("Mic Bias", NAU8810_REG_POWER1,
 		NAU8810_MICBIAS_EN_SFT, 0, NULL, 0),
@@ -469,8 +466,8 @@ static const struct snd_soc_dapm_route nau8810_dapm_routes[] = {
 	/* Input Boost Stage */
 	{"ADC", NULL, "Input Boost Stage"},
 	{"ADC", NULL, "PLL", check_mclk_select_pll},
-	{"Input Boost Stage", NULL, "Input PGA"},
-	{"Input Boost Stage", NULL, "MICP"},
+	{"Input Boost Stage", "PGA Mute Switch", "Input PGA"},
+	{"Input Boost Stage", "PMIC PGA Switch", "MICP"},
 
 	/* Input PGA */
 	{"Input PGA", NULL, "Mic Bias"},
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
index 637e9527805f..6bd14453f06e 100644
--- a/sound/soc/codecs/nau8824.c
+++ b/sound/soc/codecs/nau8824.c
@@ -205,11 +205,11 @@ static int nau8824_sema_acquire(struct nau8824 *nau8824, long timeout)
 	if (timeout) {
 		ret = down_timeout(&nau8824->jd_sem, timeout);
 		if (ret < 0)
-			dev_warn(nau8824->dev, "Acquire semaphone timeout\n");
+			dev_warn(nau8824->dev, "Acquire semaphore timeout\n");
 	} else {
 		ret = down_interruptible(&nau8824->jd_sem);
 		if (ret < 0)
-			dev_warn(nau8824->dev, "Acquire semaphone fail\n");
+			dev_warn(nau8824->dev, "Acquire semaphore fail\n");
 	}
 
 	return ret;
@@ -409,6 +409,15 @@ static const struct snd_kcontrol_new nau8824_snd_controls[] = {
 
 	SOC_SINGLE("DACL LR Mix", NAU8824_REG_DAC_MUTE_CTRL, 0, 1, 0),
 	SOC_SINGLE("DACR LR Mix", NAU8824_REG_DAC_MUTE_CTRL, 1, 1, 0),
+
+	SOC_SINGLE("THD for key media",
+		NAU8824_REG_VDET_THRESHOLD_1, 8, 0xff, 0),
+	SOC_SINGLE("THD for key voice command",
+		NAU8824_REG_VDET_THRESHOLD_1, 0, 0xff, 0),
+	SOC_SINGLE("THD for key volume up",
+		NAU8824_REG_VDET_THRESHOLD_2, 8, 0xff, 0),
+	SOC_SINGLE("THD for key volume down",
+		NAU8824_REG_VDET_THRESHOLD_2, 0, 0xff, 0),
 };
 
 static int nau8824_output_dac_event(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/codecs/pcm1789.c b/sound/soc/codecs/pcm1789.c
index 507ac9412d6c..21f15219b3ad 100644
--- a/sound/soc/codecs/pcm1789.c
+++ b/sound/soc/codecs/pcm1789.c
@@ -3,7 +3,7 @@
 // Copyright (C) 2018 Bootlin
 // Mylène Josserand <mylene.josserand@bootlin.com>
 
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/workqueue.h>
 
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
index 5f9c069569d5..0fe5ced841a3 100644
--- a/sound/soc/codecs/pcm512x-i2c.c
+++ b/sound/soc/codecs/pcm512x-i2c.c
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
+#include <linux/acpi.h>
 
 #include "pcm512x.h"
 
@@ -52,6 +53,7 @@ static const struct i2c_device_id pcm512x_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
 
+#if defined(CONFIG_OF)
 static const struct of_device_id pcm512x_of_match[] = {
 	{ .compatible = "ti,pcm5121", },
 	{ .compatible = "ti,pcm5122", },
@@ -60,6 +62,18 @@ static const struct of_device_id pcm512x_of_match[] = {
 	{ }
 };
 MODULE_DEVICE_TABLE(of, pcm512x_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id pcm512x_acpi_match[] = {
+	{ "104C5121", 0 },
+	{ "104C5122", 0 },
+	{ "104C5141", 0 },
+	{ "104C5142", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, pcm512x_acpi_match);
+#endif
 
 static struct i2c_driver pcm512x_i2c_driver = {
 	.probe 		= pcm512x_i2c_probe,
@@ -67,7 +81,8 @@ static struct i2c_driver pcm512x_i2c_driver = {
 	.id_table	= pcm512x_i2c_id,
 	.driver		= {
 		.name	= "pcm512x",
-		.of_match_table = pcm512x_of_match,
+		.of_match_table = of_match_ptr(pcm512x_of_match),
+		.acpi_match_table = ACPI_PTR(pcm512x_acpi_match),
 		.pm     = &pcm512x_pm_ops,
 	},
 };
diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c
new file mode 100644
index 000000000000..f4c8c45f4010
--- /dev/null
+++ b/sound/soc/codecs/rt1305.c
@@ -0,0 +1,1191 @@
+/*
+ * rt1305.c  --  RT1305 ALSA SoC amplifier component driver
+ *
+ * Copyright 2018 Realtek Semiconductor Corp.
+ * Author: Shuming Fan <shumingf@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.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 "rl6231.h"
+#include "rt1305.h"
+
+
+#define RT1305_PR_RANGE_BASE (0xff + 1)
+#define RT1305_PR_SPACING 0x100
+
+#define RT1305_PR_BASE (RT1305_PR_RANGE_BASE + (0 * RT1305_PR_SPACING))
+
+
+static const struct regmap_range_cfg rt1305_ranges[] = {
+	{
+		.name = "PR",
+		.range_min = RT1305_PR_BASE,
+		.range_max = RT1305_PR_BASE + 0xff,
+		.selector_reg = RT1305_PRIV_INDEX,
+		.selector_mask = 0xff,
+		.selector_shift = 0x0,
+		.window_start = RT1305_PRIV_DATA,
+		.window_len = 0x1,
+	},
+};
+
+
+static const struct reg_sequence init_list[] = {
+
+	{ RT1305_PR_BASE + 0xcf, 0x5548 },
+	{ RT1305_PR_BASE + 0x5d, 0x0442 },
+	{ RT1305_PR_BASE + 0xc1, 0x0320 },
+
+	{ RT1305_POWER_STATUS, 0x0000 },
+
+	{ RT1305_SPK_TEMP_PROTECTION_1, 0xd6de },
+	{ RT1305_SPK_TEMP_PROTECTION_2, 0x0707 },
+	{ RT1305_SPK_TEMP_PROTECTION_3, 0x4090 },
+
+	{ RT1305_DAC_SET_1, 0xdfdf },	/* 4 ohm 2W  */
+	{ RT1305_ADC_SET_3, 0x0219 },
+	{ RT1305_ADC_SET_1, 0x170f },	/* 0.2 ohm RSense*/
+
+};
+#define RT1305_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+struct rt1305_priv {
+	struct snd_soc_component *component;
+	struct regmap *regmap;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck;
+	int bclk;
+	int master;
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+};
+
+static const struct reg_default rt1305_reg[] = {
+
+	{ 0x04, 0x0400 },
+	{ 0x05, 0x0880 },
+	{ 0x06, 0x0000 },
+	{ 0x07, 0x3100 },
+	{ 0x08, 0x8000 },
+	{ 0x09, 0x0000 },
+	{ 0x0a, 0x087e },
+	{ 0x0b, 0x0020 },
+	{ 0x0c, 0x0802 },
+	{ 0x0d, 0x0020 },
+	{ 0x10, 0x1d1d },
+	{ 0x11, 0x1d1d },
+	{ 0x12, 0xffff },
+	{ 0x14, 0x000c },
+	{ 0x16, 0x1717 },
+	{ 0x17, 0x4000 },
+	{ 0x18, 0x0019 },
+	{ 0x20, 0x0000 },
+	{ 0x22, 0x0000 },
+	{ 0x24, 0x0000 },
+	{ 0x26, 0x0000 },
+	{ 0x28, 0x0000 },
+	{ 0x2a, 0x4000 },
+	{ 0x2b, 0x3000 },
+	{ 0x2d, 0x6000 },
+	{ 0x2e, 0x0000 },
+	{ 0x2f, 0x8000 },
+	{ 0x32, 0x0000 },
+	{ 0x39, 0x0001 },
+	{ 0x3a, 0x0000 },
+	{ 0x3b, 0x1020 },
+	{ 0x3c, 0x0000 },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x4c00 },
+	{ 0x3f, 0x3000 },
+	{ 0x40, 0x000c },
+	{ 0x42, 0x0400 },
+	{ 0x46, 0xc22c },
+	{ 0x47, 0x0000 },
+	{ 0x4b, 0x0000 },
+	{ 0x4c, 0x0300 },
+	{ 0x4f, 0xf000 },
+	{ 0x50, 0xc200 },
+	{ 0x51, 0x1f1f },
+	{ 0x52, 0x01f0 },
+	{ 0x53, 0x407f },
+	{ 0x54, 0xffff },
+	{ 0x58, 0x4005 },
+	{ 0x5e, 0x0000 },
+	{ 0x5f, 0x0000 },
+	{ 0x60, 0xee13 },
+	{ 0x62, 0x0000 },
+	{ 0x63, 0x5f5f },
+	{ 0x64, 0x0040 },
+	{ 0x65, 0x4000 },
+	{ 0x66, 0x4004 },
+	{ 0x67, 0x0306 },
+	{ 0x68, 0x8c04 },
+	{ 0x69, 0xe021 },
+	{ 0x6a, 0x0000 },
+	{ 0x6c, 0xaaaa },
+	{ 0x70, 0x0333 },
+	{ 0x71, 0x3330 },
+	{ 0x72, 0x3333 },
+	{ 0x73, 0x3300 },
+	{ 0x74, 0x0000 },
+	{ 0x75, 0x0000 },
+	{ 0x76, 0x0000 },
+	{ 0x7a, 0x0003 },
+	{ 0x7c, 0x10ec },
+	{ 0x7e, 0x6251 },
+	{ 0x80, 0x0800 },
+	{ 0x81, 0x4000 },
+	{ 0x82, 0x0000 },
+	{ 0x90, 0x7a01 },
+	{ 0x91, 0x8431 },
+	{ 0x92, 0x0180 },
+	{ 0x93, 0x0000 },
+	{ 0x94, 0x0000 },
+	{ 0x95, 0x0000 },
+	{ 0x96, 0x0000 },
+	{ 0x97, 0x0000 },
+	{ 0x98, 0x0000 },
+	{ 0x99, 0x0000 },
+	{ 0x9a, 0x0000 },
+	{ 0x9b, 0x0000 },
+	{ 0x9c, 0x0000 },
+	{ 0x9d, 0x0000 },
+	{ 0x9e, 0x0000 },
+	{ 0x9f, 0x0000 },
+	{ 0xa0, 0x0000 },
+	{ 0xb0, 0x8200 },
+	{ 0xb1, 0x00ff },
+	{ 0xb2, 0x0008 },
+	{ 0xc0, 0x0200 },
+	{ 0xc1, 0x0000 },
+	{ 0xc2, 0x0000 },
+	{ 0xc3, 0x0000 },
+	{ 0xc4, 0x0000 },
+	{ 0xc5, 0x0000 },
+	{ 0xc6, 0x0000 },
+	{ 0xc7, 0x0000 },
+	{ 0xc8, 0x0000 },
+	{ 0xc9, 0x0000 },
+	{ 0xca, 0x0200 },
+	{ 0xcb, 0x0000 },
+	{ 0xcc, 0x0000 },
+	{ 0xcd, 0x0000 },
+	{ 0xce, 0x0000 },
+	{ 0xcf, 0x0000 },
+	{ 0xd0, 0x0000 },
+	{ 0xd1, 0x0000 },
+	{ 0xd2, 0x0000 },
+	{ 0xd3, 0x0000 },
+	{ 0xd4, 0x0200 },
+	{ 0xd5, 0x0000 },
+	{ 0xd6, 0x0000 },
+	{ 0xd7, 0x0000 },
+	{ 0xd8, 0x0000 },
+	{ 0xd9, 0x0000 },
+	{ 0xda, 0x0000 },
+	{ 0xdb, 0x0000 },
+	{ 0xdc, 0x0000 },
+	{ 0xdd, 0x0000 },
+	{ 0xde, 0x0200 },
+	{ 0xdf, 0x0000 },
+	{ 0xe0, 0x0000 },
+	{ 0xe1, 0x0000 },
+	{ 0xe2, 0x0000 },
+	{ 0xe3, 0x0000 },
+	{ 0xe4, 0x0000 },
+	{ 0xe5, 0x0000 },
+	{ 0xe6, 0x0000 },
+	{ 0xe7, 0x0000 },
+	{ 0xe8, 0x0200 },
+	{ 0xe9, 0x0000 },
+	{ 0xea, 0x0000 },
+	{ 0xeb, 0x0000 },
+	{ 0xec, 0x0000 },
+	{ 0xed, 0x0000 },
+	{ 0xee, 0x0000 },
+	{ 0xef, 0x0000 },
+	{ 0xf0, 0x0000 },
+	{ 0xf1, 0x0000 },
+	{ 0xf2, 0x0200 },
+	{ 0xf3, 0x0000 },
+	{ 0xf4, 0x0000 },
+	{ 0xf5, 0x0000 },
+	{ 0xf6, 0x0000 },
+	{ 0xf7, 0x0000 },
+	{ 0xf8, 0x0000 },
+	{ 0xf9, 0x0000 },
+	{ 0xfa, 0x0000 },
+	{ 0xfb, 0x0000 },
+};
+
+static int rt1305_reg_init(struct snd_soc_component *component)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+
+	regmap_multi_reg_write(rt1305->regmap, init_list, RT1305_INIT_REG_LEN);
+	return 0;
+}
+
+static bool rt1305_volatile_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt1305_ranges); i++) {
+		if (reg >= rt1305_ranges[i].range_min &&
+			reg <= rt1305_ranges[i].range_max) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT1305_RESET:
+	case RT1305_SPDIF_IN_SET_1:
+	case RT1305_SPDIF_IN_SET_2:
+	case RT1305_SPDIF_IN_SET_3:
+	case RT1305_POWER_CTRL_2:
+	case RT1305_CLOCK_DETECT:
+	case RT1305_BIQUAD_SET_1:
+	case RT1305_BIQUAD_SET_2:
+	case RT1305_EQ_SET_2:
+	case RT1305_SPK_TEMP_PROTECTION_0:
+	case RT1305_SPK_TEMP_PROTECTION_2:
+	case RT1305_SPK_DC_DETECT_1:
+	case RT1305_SILENCE_DETECT:
+	case RT1305_VERSION_ID:
+	case RT1305_VENDOR_ID:
+	case RT1305_DEVICE_ID:
+	case RT1305_EFUSE_1:
+	case RT1305_EFUSE_3:
+	case RT1305_DC_CALIB_1:
+	case RT1305_DC_CALIB_3:
+	case RT1305_DAC_OFFSET_1:
+	case RT1305_DAC_OFFSET_2:
+	case RT1305_DAC_OFFSET_3:
+	case RT1305_DAC_OFFSET_4:
+	case RT1305_DAC_OFFSET_5:
+	case RT1305_DAC_OFFSET_6:
+	case RT1305_DAC_OFFSET_7:
+	case RT1305_DAC_OFFSET_8:
+	case RT1305_DAC_OFFSET_9:
+	case RT1305_DAC_OFFSET_10:
+	case RT1305_DAC_OFFSET_11:
+	case RT1305_TRIM_1:
+	case RT1305_TRIM_2:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+static bool rt1305_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt1305_ranges); i++) {
+		if (reg >= rt1305_ranges[i].range_min &&
+			reg <= rt1305_ranges[i].range_max) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT1305_RESET:
+	case RT1305_CLK_1 ... RT1305_CAL_EFUSE_CLOCK:
+	case RT1305_PLL0_1 ... RT1305_PLL1_2:
+	case RT1305_MIXER_CTRL_1:
+	case RT1305_MIXER_CTRL_2:
+	case RT1305_DAC_SET_1:
+	case RT1305_DAC_SET_2:
+	case RT1305_ADC_SET_1:
+	case RT1305_ADC_SET_2:
+	case RT1305_ADC_SET_3:
+	case RT1305_PATH_SET:
+	case RT1305_SPDIF_IN_SET_1:
+	case RT1305_SPDIF_IN_SET_2:
+	case RT1305_SPDIF_IN_SET_3:
+	case RT1305_SPDIF_OUT_SET_1:
+	case RT1305_SPDIF_OUT_SET_2:
+	case RT1305_SPDIF_OUT_SET_3:
+	case RT1305_I2S_SET_1:
+	case RT1305_I2S_SET_2:
+	case RT1305_PBTL_MONO_MODE_SRC:
+	case RT1305_MANUALLY_I2C_DEVICE:
+	case RT1305_POWER_STATUS:
+	case RT1305_POWER_CTRL_1:
+	case RT1305_POWER_CTRL_2:
+	case RT1305_POWER_CTRL_3:
+	case RT1305_POWER_CTRL_4:
+	case RT1305_POWER_CTRL_5:
+	case RT1305_CLOCK_DETECT:
+	case RT1305_BIQUAD_SET_1:
+	case RT1305_BIQUAD_SET_2:
+	case RT1305_ADJUSTED_HPF_1:
+	case RT1305_ADJUSTED_HPF_2:
+	case RT1305_EQ_SET_1:
+	case RT1305_EQ_SET_2:
+	case RT1305_SPK_TEMP_PROTECTION_0:
+	case RT1305_SPK_TEMP_PROTECTION_1:
+	case RT1305_SPK_TEMP_PROTECTION_2:
+	case RT1305_SPK_TEMP_PROTECTION_3:
+	case RT1305_SPK_DC_DETECT_1:
+	case RT1305_SPK_DC_DETECT_2:
+	case RT1305_LOUDNESS:
+	case RT1305_THERMAL_FOLD_BACK_1:
+	case RT1305_THERMAL_FOLD_BACK_2:
+	case RT1305_SILENCE_DETECT ... RT1305_SPK_EXCURSION_LIMITER_7:
+	case RT1305_VERSION_ID:
+	case RT1305_VENDOR_ID:
+	case RT1305_DEVICE_ID:
+	case RT1305_EFUSE_1:
+	case RT1305_EFUSE_2:
+	case RT1305_EFUSE_3:
+	case RT1305_DC_CALIB_1:
+	case RT1305_DC_CALIB_2:
+	case RT1305_DC_CALIB_3:
+	case RT1305_DAC_OFFSET_1 ... RT1305_DAC_OFFSET_14:
+	case RT1305_TRIM_1:
+	case RT1305_TRIM_2:
+	case RT1305_TUNE_INTERNAL_OSC:
+	case RT1305_BIQUAD1_H0_L_28_16 ... RT1305_BIQUAD3_A2_R_15_0:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9435, 37, 0);
+
+static const char * const rt1305_rx_data_ch_select[] = {
+	"LR",
+	"RL",
+	"Copy L",
+	"Copy R",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1305_rx_data_ch_enum, RT1305_I2S_SET_2, 2,
+	rt1305_rx_data_ch_select);
+
+static void rt1305_reset(struct regmap *regmap)
+{
+	regmap_write(regmap, RT1305_RESET, 0);
+}
+
+static const struct snd_kcontrol_new rt1305_snd_controls[] = {
+	SOC_DOUBLE_TLV("DAC Playback Volume", RT1305_DAC_SET_1,
+			8, 0, 0xff, 0, dac_vol_tlv),
+
+	/* I2S Data Channel Selection */
+	SOC_ENUM("RX Channel Select", rt1305_rx_data_ch_enum),
+};
+
+static int rt1305_is_rc_clk_from_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(source->dapm);
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	snd_soc_component_read(component, RT1305_CLK_1, &val);
+
+	if (rt1305->sysclk_src == RT1305_FS_SYS_PRE_S_PLL1 &&
+		(val & RT1305_SEL_PLL_SRC_2_RCCLK))
+		return 1;
+	else
+		return 0;
+}
+
+static int rt1305_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(source->dapm);
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+
+	if (rt1305->sysclk_src == RT1305_FS_SYS_PRE_S_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int rt1305_classd_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT1305_POWER_CTRL_1,
+			RT1305_POW_PDB_JD_MASK, RT1305_POW_PDB_JD);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT1305_POWER_CTRL_1,
+			RT1305_POW_PDB_JD_MASK, 0);
+		usleep_range(150000, 200000);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new rt1305_sto_dac_l =
+	SOC_DAPM_SINGLE("Switch", RT1305_DAC_SET_2,
+		RT1305_DVOL_MUTE_L_EN_SFT, 1, 1);
+
+static const struct snd_kcontrol_new rt1305_sto_dac_r =
+	SOC_DAPM_SINGLE("Switch", RT1305_DAC_SET_2,
+		RT1305_DVOL_MUTE_R_EN_SFT, 1, 1);
+
+static const struct snd_soc_dapm_widget rt1305_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("PLL0", RT1305_POWER_CTRL_1,
+		RT1305_POW_PLL0_EN_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL1", RT1305_POWER_CTRL_1,
+		RT1305_POW_PLL1_EN_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MBIAS", RT1305_POWER_CTRL_1,
+		RT1305_POW_MBIAS_LV_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BG MBIAS", RT1305_POWER_CTRL_1,
+		RT1305_POW_BG_MBIAS_LV_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO2", RT1305_POWER_CTRL_1,
+		RT1305_POW_LDO2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BG2", RT1305_POWER_CTRL_1,
+		RT1305_POW_BG2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO2 IB2", RT1305_POWER_CTRL_1,
+		RT1305_POW_LDO2_IB2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VREF", RT1305_POWER_CTRL_1,
+		RT1305_POW_VREF_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VREF1", RT1305_POWER_CTRL_1,
+		RT1305_POW_VREF1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VREF2", RT1305_POWER_CTRL_1,
+		RT1305_POW_VREF2_BIT, 0, NULL, 0),
+
+
+	SND_SOC_DAPM_SUPPLY("DISC VREF", RT1305_POWER_CTRL_2,
+		RT1305_POW_DISC_VREF_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("FASTB VREF", RT1305_POWER_CTRL_2,
+		RT1305_POW_FASTB_VREF_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ULTRA FAST VREF", RT1305_POWER_CTRL_2,
+		RT1305_POW_ULTRA_FAST_VREF_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CHOP DAC", RT1305_POWER_CTRL_2,
+		RT1305_POW_CKXEN_DAC_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CKGEN DAC", RT1305_POWER_CTRL_2,
+		RT1305_POW_EN_CKGEN_DAC_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLAMP", RT1305_POWER_CTRL_2,
+		RT1305_POW_CLAMP_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BUFL", RT1305_POWER_CTRL_2,
+		RT1305_POW_BUFL_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BUFR", RT1305_POWER_CTRL_2,
+		RT1305_POW_BUFR_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CKGEN ADC", RT1305_POWER_CTRL_2,
+		RT1305_POW_EN_CKGEN_ADC_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC3 L", RT1305_POWER_CTRL_2,
+		RT1305_POW_ADC3_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC3 R", RT1305_POWER_CTRL_2,
+		RT1305_POW_ADC3_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("TRIOSC", RT1305_POWER_CTRL_2,
+		RT1305_POW_TRIOSC_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AVDD1", RT1305_POWER_CTRL_2,
+		RT1305_POR_AVDD1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AVDD2", RT1305_POWER_CTRL_2,
+		RT1305_POR_AVDD2_BIT, 0, NULL, 0),
+
+
+	SND_SOC_DAPM_SUPPLY("VSENSE R", RT1305_POWER_CTRL_3,
+		RT1305_POW_VSENSE_RCH_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VSENSE L", RT1305_POWER_CTRL_3,
+		RT1305_POW_VSENSE_LCH_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ISENSE R", RT1305_POWER_CTRL_3,
+		RT1305_POW_ISENSE_RCH_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ISENSE L", RT1305_POWER_CTRL_3,
+		RT1305_POW_ISENSE_LCH_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("POR AVDD1", RT1305_POWER_CTRL_3,
+		RT1305_POW_POR_AVDD1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("POR AVDD2", RT1305_POWER_CTRL_3,
+		RT1305_POW_POR_AVDD2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VCM 6172", RT1305_POWER_CTRL_3,
+		RT1305_EN_VCM_6172_BIT, 0, NULL, 0),
+
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("DAC L Power", RT1305_POWER_CTRL_2,
+		RT1305_POW_DAC1_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC R Power", RT1305_POWER_CTRL_2,
+		RT1305_POW_DAC1_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SWITCH("DAC L", SND_SOC_NOPM, 0, 0, &rt1305_sto_dac_l),
+	SND_SOC_DAPM_SWITCH("DAC R", SND_SOC_NOPM, 0, 0, &rt1305_sto_dac_r),
+
+	/* Output Lines */
+	SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
+		rt1305_classd_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_OUTPUT("SPOL"),
+	SND_SOC_DAPM_OUTPUT("SPOR"),
+};
+
+static const struct snd_soc_dapm_route rt1305_dapm_routes[] = {
+
+	{ "DAC", NULL, "AIF1RX" },
+
+	{ "DAC", NULL, "PLL0", rt1305_is_rc_clk_from_pll },
+	{ "DAC", NULL, "PLL1", rt1305_is_sys_clk_from_pll },
+
+	{ "DAC", NULL, "MBIAS" },
+	{ "DAC", NULL, "BG MBIAS" },
+	{ "DAC", NULL, "LDO2" },
+	{ "DAC", NULL, "BG2" },
+	{ "DAC", NULL, "LDO2 IB2" },
+	{ "DAC", NULL, "VREF" },
+	{ "DAC", NULL, "VREF1" },
+	{ "DAC", NULL, "VREF2" },
+
+	{ "DAC", NULL, "DISC VREF" },
+	{ "DAC", NULL, "FASTB VREF" },
+	{ "DAC", NULL, "ULTRA FAST VREF" },
+	{ "DAC", NULL, "CHOP DAC" },
+	{ "DAC", NULL, "CKGEN DAC" },
+	{ "DAC", NULL, "CLAMP" },
+	{ "DAC", NULL, "CKGEN ADC" },
+	{ "DAC", NULL, "TRIOSC" },
+	{ "DAC", NULL, "AVDD1" },
+	{ "DAC", NULL, "AVDD2" },
+
+	{ "DAC", NULL, "POR AVDD1" },
+	{ "DAC", NULL, "POR AVDD2" },
+	{ "DAC", NULL, "VCM 6172" },
+
+	{ "DAC L", "Switch", "DAC" },
+	{ "DAC R", "Switch", "DAC" },
+
+	{ "DAC R", NULL, "VSENSE R" },
+	{ "DAC L", NULL, "VSENSE L" },
+	{ "DAC R", NULL, "ISENSE R" },
+	{ "DAC L", NULL, "ISENSE L" },
+	{ "DAC L", NULL, "ADC3 L" },
+	{ "DAC R", NULL, "ADC3 R" },
+	{ "DAC L", NULL, "BUFL" },
+	{ "DAC R", NULL, "BUFR" },
+	{ "DAC L", NULL, "DAC L Power" },
+	{ "DAC R", NULL, "DAC R Power" },
+
+	{ "CLASS D", NULL, "DAC L" },
+	{ "CLASS D", NULL, "DAC R" },
+
+	{ "SPOL", NULL, "CLASS D" },
+	{ "SPOR", NULL, "CLASS D" },
+};
+
+static int rt1305_get_clk_info(int sclk, int rate)
+{
+	int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
+
+	if (sclk <= 0 || rate <= 0)
+		return -EINVAL;
+
+	rate = rate << 8;
+	for (i = 0; i < ARRAY_SIZE(pd); i++)
+		if (sclk == rate * pd[i])
+			return i;
+
+	return -EINVAL;
+}
+
+static int rt1305_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 rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int pre_div, bclk_ms, frame_size;
+
+	rt1305->lrck = params_rate(params);
+	pre_div = rt1305_get_clk_info(rt1305->sysclk, rt1305->lrck);
+	if (pre_div < 0) {
+		dev_warn(component->dev, "Force using PLL ");
+		snd_soc_dai_set_pll(dai, 0, RT1305_PLL1_S_BCLK,
+			rt1305->lrck * 64, rt1305->lrck * 256);
+		snd_soc_dai_set_sysclk(dai, RT1305_FS_SYS_PRE_S_PLL1,
+			rt1305->lrck * 256, SND_SOC_CLOCK_IN);
+		pre_div = 0;
+	}
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n",
+			frame_size);
+		return -EINVAL;
+	}
+
+	bclk_ms = frame_size > 32;
+	rt1305->bclk = rt1305->lrck * (32 << bclk_ms);
+
+	dev_dbg(component->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+				bclk_ms, pre_div, dai->id);
+
+	dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+				rt1305->lrck, pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		val_len |= RT1305_I2S_DL_SEL_16B;
+		break;
+	case 20:
+		val_len |= RT1305_I2S_DL_SEL_20B;
+		break;
+	case 24:
+		val_len |= RT1305_I2S_DL_SEL_24B;
+		break;
+	case 8:
+		val_len |= RT1305_I2S_DL_SEL_8B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT1305_AIF1:
+		mask_clk = RT1305_DIV_FS_SYS_MASK;
+		val_clk = pre_div << RT1305_DIV_FS_SYS_SFT;
+		snd_soc_component_update_bits(component, RT1305_I2S_SET_2,
+			RT1305_I2S_DL_SEL_MASK,
+			val_len);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT1305_CLK_2,
+		mask_clk, val_clk);
+
+	return 0;
+}
+
+static int rt1305_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0, reg1_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		reg_val |= RT1305_SEL_I2S_OUT_MODE_M;
+		rt1305->master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT1305_SEL_I2S_OUT_MODE_S;
+		rt1305->master = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg1_val |= RT1305_I2S_BCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg1_val |= RT1305_I2S_DF_SEL_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg1_val |= RT1305_I2S_DF_SEL_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg1_val |= RT1305_I2S_DF_SEL_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT1305_AIF1:
+		snd_soc_component_update_bits(component, RT1305_I2S_SET_1,
+			RT1305_SEL_I2S_OUT_MODE_MASK, reg_val);
+		snd_soc_component_update_bits(component, RT1305_I2S_SET_2,
+			RT1305_I2S_DF_SEL_MASK | RT1305_I2S_BCLK_MASK,
+			reg1_val);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int rt1305_set_component_sysclk(struct snd_soc_component *component,
+		int clk_id, int source, unsigned int freq, int dir)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	if (freq == rt1305->sysclk && clk_id == rt1305->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT1305_FS_SYS_PRE_S_MCLK:
+		reg_val |= RT1305_SEL_FS_SYS_PRE_MCLK;
+		snd_soc_component_update_bits(component,
+			RT1305_CLOCK_DETECT, RT1305_SEL_CLK_DET_SRC_MASK,
+			RT1305_SEL_CLK_DET_SRC_MCLK);
+		break;
+	case RT1305_FS_SYS_PRE_S_PLL1:
+		reg_val |= RT1305_SEL_FS_SYS_PRE_PLL;
+		break;
+	case RT1305_FS_SYS_PRE_S_RCCLK:
+		reg_val |= RT1305_SEL_FS_SYS_PRE_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT1305_CLK_1,
+		RT1305_SEL_FS_SYS_PRE_MASK, reg_val);
+	rt1305->sysclk = freq;
+	rt1305->sysclk_src = clk_id;
+
+	dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
+		freq, clk_id);
+
+	return 0;
+}
+
+static int rt1305_set_component_pll(struct snd_soc_component *component,
+		int pll_id, int source, unsigned int freq_in,
+		unsigned int freq_out)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt1305->pll_src && freq_in == rt1305->pll_in &&
+	    freq_out == rt1305->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt1305->pll_in = 0;
+		rt1305->pll_out = 0;
+		snd_soc_component_update_bits(component, RT1305_CLK_1,
+			RT1305_SEL_FS_SYS_PRE_MASK | RT1305_SEL_PLL_SRC_1_MASK,
+			RT1305_SEL_FS_SYS_PRE_PLL | RT1305_SEL_PLL_SRC_1_BCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT1305_PLL2_S_MCLK:
+		snd_soc_component_update_bits(component, RT1305_CLK_1,
+			RT1305_SEL_PLL_SRC_2_MASK | RT1305_SEL_PLL_SRC_1_MASK |
+			RT1305_DIV_PLL_SRC_2_MASK,
+			RT1305_SEL_PLL_SRC_2_MCLK | RT1305_SEL_PLL_SRC_1_PLL2);
+		snd_soc_component_update_bits(component,
+			RT1305_CLOCK_DETECT, RT1305_SEL_CLK_DET_SRC_MASK,
+			RT1305_SEL_CLK_DET_SRC_MCLK);
+		break;
+	case RT1305_PLL1_S_BCLK:
+		snd_soc_component_update_bits(component,
+			RT1305_CLK_1, RT1305_SEL_PLL_SRC_1_MASK,
+			RT1305_SEL_PLL_SRC_1_BCLK);
+		break;
+	case RT1305_PLL2_S_RCCLK:
+		snd_soc_component_update_bits(component, RT1305_CLK_1,
+			RT1305_SEL_PLL_SRC_2_MASK | RT1305_SEL_PLL_SRC_1_MASK |
+			RT1305_DIV_PLL_SRC_2_MASK,
+			RT1305_SEL_PLL_SRC_2_RCCLK | RT1305_SEL_PLL_SRC_1_PLL2);
+		freq_in = 98304000;
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL Source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT1305_PLL1_1,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT1305_PLL_1_M_SFT |
+		pll_code.m_bp << RT1305_PLL_1_M_BYPASS_SFT |
+		pll_code.n_code);
+	snd_soc_component_write(component, RT1305_PLL1_2,
+		pll_code.k_code);
+
+	rt1305->pll_in = freq_in;
+	rt1305->pll_out = freq_out;
+	rt1305->pll_src = source;
+
+	return 0;
+}
+
+static int rt1305_probe(struct snd_soc_component *component)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+
+	rt1305->component = component;
+
+	/* initial settings */
+	rt1305_reg_init(component);
+
+	return 0;
+}
+
+static void rt1305_remove(struct snd_soc_component *component)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+
+	rt1305_reset(rt1305->regmap);
+}
+
+#ifdef CONFIG_PM
+static int rt1305_suspend(struct snd_soc_component *component)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt1305->regmap, true);
+	regcache_mark_dirty(rt1305->regmap);
+
+	return 0;
+}
+
+static int rt1305_resume(struct snd_soc_component *component)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt1305->regmap, false);
+	regcache_sync(rt1305->regmap);
+
+	return 0;
+}
+#else
+#define rt1305_suspend NULL
+#define rt1305_resume NULL
+#endif
+
+#define RT1305_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT1305_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops rt1305_aif_dai_ops = {
+	.hw_params = rt1305_hw_params,
+	.set_fmt = rt1305_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver rt1305_dai[] = {
+	{
+		.name = "rt1305-aif",
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT1305_STEREO_RATES,
+			.formats = RT1305_FORMATS,
+		},
+		.ops = &rt1305_aif_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt1305 = {
+	.probe = rt1305_probe,
+	.remove = rt1305_remove,
+	.suspend = rt1305_suspend,
+	.resume = rt1305_resume,
+	.controls = rt1305_snd_controls,
+	.num_controls = ARRAY_SIZE(rt1305_snd_controls),
+	.dapm_widgets = rt1305_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rt1305_dapm_widgets),
+	.dapm_routes = rt1305_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(rt1305_dapm_routes),
+	.set_sysclk = rt1305_set_component_sysclk,
+	.set_pll = rt1305_set_component_pll,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt1305_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.max_register = RT1305_MAX_REG + 1 + (ARRAY_SIZE(rt1305_ranges) *
+					       RT1305_PR_SPACING),
+	.volatile_reg = rt1305_volatile_register,
+	.readable_reg = rt1305_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt1305_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt1305_reg),
+	.ranges = rt1305_ranges,
+	.num_ranges = ARRAY_SIZE(rt1305_ranges),
+	.use_single_rw = true,
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt1305_of_match[] = {
+	{ .compatible = "realtek,rt1305", },
+	{ .compatible = "realtek,rt1306", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt1305_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static struct acpi_device_id rt1305_acpi_match[] = {
+	{"10EC1305", 0,},
+	{"10EC1306", 0,},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt1305_acpi_match);
+#endif
+
+static const struct i2c_device_id rt1305_i2c_id[] = {
+	{ "rt1305", 0 },
+	{ "rt1306", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt1305_i2c_id);
+
+static void rt1305_calibrate(struct rt1305_priv *rt1305)
+{
+	unsigned int valmsb, vallsb, offsetl, offsetr;
+	unsigned int rh, rl, rhl, r0ohm;
+	u64 r0l, r0r;
+
+	regcache_cache_bypass(rt1305->regmap, true);
+
+	rt1305_reset(rt1305->regmap);
+	regmap_write(rt1305->regmap, RT1305_ADC_SET_3, 0x0219);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xcf, 0x5548);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xc1, 0x0320);
+	regmap_write(rt1305->regmap, RT1305_CLOCK_DETECT, 0x1000);
+	regmap_write(rt1305->regmap, RT1305_CLK_1, 0x0600);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xffd0);
+	regmap_write(rt1305->regmap, RT1305_EFUSE_1, 0x0080);
+	regmap_write(rt1305->regmap, RT1305_EFUSE_1, 0x0880);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_1, 0x0dfe);
+
+	/* Sin Gen */
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x5d, 0x0442);
+
+	regmap_write(rt1305->regmap, RT1305_CAL_EFUSE_CLOCK, 0xb000);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xc3, 0xd4a0);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xcc, 0x00cc);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xc1, 0x0320);
+	regmap_write(rt1305->regmap, RT1305_POWER_STATUS, 0x0000);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_2, 0xffff);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfc20);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x06, 0x00c0);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfca0);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfce0);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfcf0);
+
+	/* EFUSE read */
+	regmap_write(rt1305->regmap, RT1305_EFUSE_1, 0x0080);
+	regmap_write(rt1305->regmap, RT1305_EFUSE_1, 0x0880);
+	regmap_write(rt1305->regmap, RT1305_EFUSE_1, 0x0880);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfce0);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfca0);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfc20);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x06, 0x0000);
+	regmap_write(rt1305->regmap, RT1305_EFUSE_1, 0x0000);
+
+	regmap_read(rt1305->regmap, RT1305_DAC_OFFSET_5, &valmsb);
+	regmap_read(rt1305->regmap, RT1305_DAC_OFFSET_6, &vallsb);
+	offsetl = valmsb << 16 | vallsb;
+	regmap_read(rt1305->regmap, RT1305_DAC_OFFSET_7, &valmsb);
+	regmap_read(rt1305->regmap, RT1305_DAC_OFFSET_8, &vallsb);
+	offsetr = valmsb << 16 | vallsb;
+	pr_info("DC offsetl=0x%x, offsetr=0x%x\n", offsetl, offsetr);
+
+	/* R0 calibration */
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x5d, 0x9542);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfcf0);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_2, 0xffff);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_1, 0x1dfe);
+	regmap_write(rt1305->regmap, RT1305_SILENCE_DETECT, 0x0e13);
+	regmap_write(rt1305->regmap, RT1305_CLK_1, 0x0650);
+
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x50, 0x0064);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x51, 0x0770);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x52, 0xc30c);
+	regmap_write(rt1305->regmap, RT1305_SPK_TEMP_PROTECTION_1, 0x8200);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xd4, 0xfb00);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xd4, 0xff80);
+	msleep(2000);
+	regmap_read(rt1305->regmap, RT1305_PR_BASE + 0x55, &rh);
+	regmap_read(rt1305->regmap, RT1305_PR_BASE + 0x56, &rl);
+	rhl = (rh << 16) | rl;
+	r0ohm = (rhl*10) / 33554432;
+
+	pr_debug("Left_rhl = 0x%x rh=0x%x rl=0x%x\n", rhl, rh, rl);
+	pr_info("Left channel %d.%dohm\n", (r0ohm/10), (r0ohm%10));
+
+	r0l = 562949953421312;
+	if (rhl != 0)
+		do_div(r0l, rhl);
+	pr_debug("Left_r0 = 0x%llx\n", r0l);
+
+	regmap_write(rt1305->regmap, RT1305_SPK_TEMP_PROTECTION_1, 0x9200);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xd4, 0xfb00);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xd4, 0xff80);
+	msleep(2000);
+	regmap_read(rt1305->regmap, RT1305_PR_BASE + 0x55, &rh);
+	regmap_read(rt1305->regmap, RT1305_PR_BASE + 0x56, &rl);
+	rhl = (rh << 16) | rl;
+	r0ohm = (rhl*10) / 33554432;
+
+	pr_debug("Right_rhl = 0x%x rh=0x%x rl=0x%x\n", rhl, rh, rl);
+	pr_info("Right channel %d.%dohm\n", (r0ohm/10), (r0ohm%10));
+
+	r0r = 562949953421312;
+	if (rhl != 0)
+		do_div(r0r, rhl);
+	pr_debug("Right_r0 = 0x%llx\n", r0r);
+
+	regmap_write(rt1305->regmap, RT1305_SPK_TEMP_PROTECTION_1, 0xc2ec);
+
+	if ((r0l > R0_UPPER) && (r0l < R0_LOWER) &&
+		(r0r > R0_UPPER) && (r0r < R0_LOWER)) {
+		regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x4e,
+			(r0l >> 16) & 0xffff);
+		regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x4f,
+			r0l & 0xffff);
+		regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xfe,
+			((r0r >> 16) & 0xffff) | 0xf800);
+		regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xfd,
+			r0r & 0xffff);
+	} else {
+		pr_err("R0 calibration failed\n");
+	}
+
+	/* restore some registers */
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_1, 0x0dfe);
+	usleep_range(200000, 400000);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x5d, 0x0442);
+	regmap_write(rt1305->regmap, RT1305_CLOCK_DETECT, 0x3000);
+	regmap_write(rt1305->regmap, RT1305_CLK_1, 0x0400);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_1, 0x0000);
+	regmap_write(rt1305->regmap, RT1305_CAL_EFUSE_CLOCK, 0x8000);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_2, 0x1020);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0x0000);
+
+	regcache_cache_bypass(rt1305->regmap, false);
+}
+
+static int rt1305_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt1305_priv *rt1305;
+	int ret;
+	unsigned int val;
+
+	rt1305 = devm_kzalloc(&i2c->dev, sizeof(struct rt1305_priv),
+				GFP_KERNEL);
+	if (rt1305 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt1305);
+
+	rt1305->regmap = devm_regmap_init_i2c(i2c, &rt1305_regmap);
+	if (IS_ERR(rt1305->regmap)) {
+		ret = PTR_ERR(rt1305->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt1305->regmap, RT1305_DEVICE_ID, &val);
+	if (val != RT1305_DEVICE_ID_NUM) {
+		dev_err(&i2c->dev,
+			"Device with ID register %x is not rt1305\n", val);
+		return -ENODEV;
+	}
+
+	rt1305_reset(rt1305->regmap);
+	rt1305_calibrate(rt1305);
+
+	return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt1305,
+			rt1305_dai, ARRAY_SIZE(rt1305_dai));
+}
+
+static int rt1305_i2c_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_component(&i2c->dev);
+
+	return 0;
+}
+
+static void rt1305_i2c_shutdown(struct i2c_client *client)
+{
+	struct rt1305_priv *rt1305 = i2c_get_clientdata(client);
+
+	rt1305_reset(rt1305->regmap);
+}
+
+
+static struct i2c_driver rt1305_i2c_driver = {
+	.driver = {
+		.name = "rt1305",
+#if defined(CONFIG_OF)
+		.of_match_table = rt1305_of_match,
+#endif
+#if defined(CONFIG_ACPI)
+		.acpi_match_table = ACPI_PTR(rt1305_acpi_match)
+#endif
+	},
+	.probe = rt1305_i2c_probe,
+	.remove   = rt1305_i2c_remove,
+	.shutdown = rt1305_i2c_shutdown,
+	.id_table = rt1305_i2c_id,
+};
+module_i2c_driver(rt1305_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT1305 amplifier driver");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt1305.h b/sound/soc/codecs/rt1305.h
new file mode 100644
index 000000000000..bde86f97729a
--- /dev/null
+++ b/sound/soc/codecs/rt1305.h
@@ -0,0 +1,276 @@
+/*
+ * RT1305.h  --  RT1305 ALSA SoC amplifier component driver
+ *
+ * Copyright 2018 Realtek Semiconductor Corp.
+ * Author: Shuming Fan <shumingf@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _RT1305_H_
+#define _RT1305_H_
+
+#define RT1305_DEVICE_ID_NUM 0x6251
+
+#define RT1305_RESET				0x00
+#define RT1305_CLK_1				0x04
+#define RT1305_CLK_2				0x05
+#define RT1305_CLK_3				0x06
+#define RT1305_DFLL_REG				0x07
+#define RT1305_CAL_EFUSE_CLOCK	0x08
+#define RT1305_PLL0_1				0x0a
+#define RT1305_PLL0_2				0x0b
+#define RT1305_PLL1_1				0x0c
+#define RT1305_PLL1_2				0x0d
+#define RT1305_MIXER_CTRL_1 0x10
+#define RT1305_MIXER_CTRL_2 0x11
+#define RT1305_DAC_SET_1             0x12
+#define RT1305_DAC_SET_2             0x14
+#define RT1305_ADC_SET_1            0x16
+#define RT1305_ADC_SET_2            0x17
+#define RT1305_ADC_SET_3            0x18
+#define RT1305_PATH_SET             0x20
+#define RT1305_SPDIF_IN_SET_1                 0x22
+#define RT1305_SPDIF_IN_SET_2                 0x24
+#define RT1305_SPDIF_IN_SET_3                 0x26
+#define RT1305_SPDIF_OUT_SET_1                 0x28
+#define RT1305_SPDIF_OUT_SET_2                 0x2a
+#define RT1305_SPDIF_OUT_SET_3                 0x2b
+#define RT1305_I2S_SET_1                       0x2d
+#define RT1305_I2S_SET_2                      0x2e
+#define RT1305_PBTL_MONO_MODE_SRC            0x2f
+#define RT1305_MANUALLY_I2C_DEVICE 0x32
+#define RT1305_POWER_STATUS                  0x39
+#define RT1305_POWER_CTRL_1                  0x3a
+#define RT1305_POWER_CTRL_2                  0x3b
+#define RT1305_POWER_CTRL_3                  0x3c
+#define RT1305_POWER_CTRL_4                  0x3d
+#define RT1305_POWER_CTRL_5                  0x3e
+#define RT1305_CLOCK_DETECT                  0x3f
+#define RT1305_BIQUAD_SET_1                  0x40
+#define RT1305_BIQUAD_SET_2                  0x42
+#define RT1305_ADJUSTED_HPF_1             0x46
+#define RT1305_ADJUSTED_HPF_2               0x47
+#define RT1305_EQ_SET_1                  0x4b
+#define RT1305_EQ_SET_2                  0x4c
+#define RT1305_SPK_TEMP_PROTECTION_0 0x4f
+#define RT1305_SPK_TEMP_PROTECTION_1 0x50
+#define RT1305_SPK_TEMP_PROTECTION_2 0x51
+#define RT1305_SPK_TEMP_PROTECTION_3 0x52
+#define RT1305_SPK_DC_DETECT_1                  0x53
+#define RT1305_SPK_DC_DETECT_2                  0x54
+#define RT1305_LOUDNESS 0x58
+#define RT1305_THERMAL_FOLD_BACK_1 0x5e
+#define RT1305_THERMAL_FOLD_BACK_2 0x5f
+#define RT1305_SILENCE_DETECT                  0x60
+#define RT1305_ALC_DRC_1                  0x62
+#define RT1305_ALC_DRC_2                  0x63
+#define RT1305_ALC_DRC_3                  0x64
+#define RT1305_ALC_DRC_4                  0x65
+#define RT1305_PRIV_INDEX			0x6a
+#define RT1305_PRIV_DATA			0x6c
+#define RT1305_SPK_EXCURSION_LIMITER_7 0x76
+#define RT1305_VERSION_ID			0x7a
+#define RT1305_VENDOR_ID			0x7c
+#define RT1305_DEVICE_ID			0x7e
+#define RT1305_EFUSE_1                  0x80
+#define RT1305_EFUSE_2                  0x81
+#define RT1305_EFUSE_3                  0x82
+#define RT1305_DC_CALIB_1                  0x90
+#define RT1305_DC_CALIB_2                  0x91
+#define RT1305_DC_CALIB_3                  0x92
+#define RT1305_DAC_OFFSET_1            0x93
+#define RT1305_DAC_OFFSET_2            0x94
+#define RT1305_DAC_OFFSET_3            0x95
+#define RT1305_DAC_OFFSET_4            0x96
+#define RT1305_DAC_OFFSET_5            0x97
+#define RT1305_DAC_OFFSET_6            0x98
+#define RT1305_DAC_OFFSET_7            0x99
+#define RT1305_DAC_OFFSET_8            0x9a
+#define RT1305_DAC_OFFSET_9            0x9b
+#define RT1305_DAC_OFFSET_10            0x9c
+#define RT1305_DAC_OFFSET_11            0x9d
+#define RT1305_DAC_OFFSET_12            0x9e
+#define RT1305_DAC_OFFSET_13            0x9f
+#define RT1305_DAC_OFFSET_14            0xa0
+#define RT1305_TRIM_1                  0xb0
+#define RT1305_TRIM_2                  0xb1
+#define RT1305_TUNE_INTERNAL_OSC             0xb2
+#define RT1305_BIQUAD1_H0_L_28_16 0xc0
+#define RT1305_BIQUAD3_A2_R_15_0 0xfb
+#define RT1305_MAX_REG	                 0xff
+
+/* CLOCK-1 (0x04) */
+#define RT1305_SEL_PLL_SRC_2_MASK			(0x1 << 15)
+#define RT1305_SEL_PLL_SRC_2_SFT			15
+#define RT1305_SEL_PLL_SRC_2_MCLK			(0x0 << 15)
+#define RT1305_SEL_PLL_SRC_2_RCCLK			(0x1 << 15)
+#define RT1305_DIV_PLL_SRC_2_MASK			(0x3 << 13)
+#define RT1305_DIV_PLL_SRC_2_SFT			13
+#define RT1305_SEL_PLL_SRC_1_MASK			(0x3 << 10)
+#define RT1305_SEL_PLL_SRC_1_SFT			10
+#define RT1305_SEL_PLL_SRC_1_PLL2			(0x0 << 10)
+#define RT1305_SEL_PLL_SRC_1_BCLK			(0x1 << 10)
+#define RT1305_SEL_PLL_SRC_1_DFLL			(0x2 << 10)
+#define RT1305_SEL_FS_SYS_PRE_MASK			(0x3 << 8)
+#define RT1305_SEL_FS_SYS_PRE_SFT			8
+#define RT1305_SEL_FS_SYS_PRE_MCLK			(0x0 << 8)
+#define RT1305_SEL_FS_SYS_PRE_PLL			(0x1 << 8)
+#define RT1305_SEL_FS_SYS_PRE_RCCLK			(0x2 << 8)
+#define RT1305_DIV_FS_SYS_MASK				(0x7 << 4)
+#define RT1305_DIV_FS_SYS_SFT				4
+
+/* PLL1M/N/K Code-1 (0x0c) */
+#define RT1305_PLL_1_M_SFT		12
+#define RT1305_PLL_1_M_BYPASS_MASK			(0x1 << 11)
+#define RT1305_PLL_1_M_BYPASS_SFT		11
+#define RT1305_PLL_1_M_BYPASS			(0x1 << 11)
+#define RT1305_PLL_1_N_MASK			(0x1ff << 0)
+
+/* DAC Setting (0x14) */
+#define RT1305_DVOL_MUTE_L_EN_SFT		15
+#define RT1305_DVOL_MUTE_R_EN_SFT		14
+
+/* I2S Setting-1 (0x2d) */
+#define RT1305_SEL_I2S_OUT_MODE_MASK		(0x1 << 15)
+#define RT1305_SEL_I2S_OUT_MODE_SFT			15
+#define RT1305_SEL_I2S_OUT_MODE_S			(0x0 << 15)
+#define RT1305_SEL_I2S_OUT_MODE_M			(0x1 << 15)
+
+/* I2S Setting-2 (0x2e) */
+#define RT1305_I2S_DF_SEL_MASK			(0x3 << 12)
+#define RT1305_I2S_DF_SEL_SFT			12
+#define RT1305_I2S_DF_SEL_I2S			(0x0 << 12)
+#define RT1305_I2S_DF_SEL_LEFT			(0x1 << 12)
+#define RT1305_I2S_DF_SEL_PCM_A			(0x2 << 12)
+#define RT1305_I2S_DF_SEL_PCM_B			(0x3 << 12)
+#define RT1305_I2S_DL_SEL_MASK			(0x3 << 10)
+#define RT1305_I2S_DL_SEL_SFT			10
+#define RT1305_I2S_DL_SEL_16B			(0x0 << 10)
+#define RT1305_I2S_DL_SEL_20B			(0x1 << 10)
+#define RT1305_I2S_DL_SEL_24B			(0x2 << 10)
+#define RT1305_I2S_DL_SEL_8B			(0x3 << 10)
+#define RT1305_I2S_BCLK_MASK		(0x1 << 9)
+#define RT1305_I2S_BCLK_SFT			9
+#define RT1305_I2S_BCLK_NORMAL		(0x0 << 9)
+#define RT1305_I2S_BCLK_INV			(0x1 << 9)
+
+/* Power Control-1 (0x3a) */
+#define RT1305_POW_PDB_JD_MASK				(0x1 << 12)
+#define RT1305_POW_PDB_JD				(0x1 << 12)
+#define RT1305_POW_PDB_JD_BIT			12
+#define RT1305_POW_PLL0_EN				(0x1 << 11)
+#define RT1305_POW_PLL0_EN_BIT			11
+#define RT1305_POW_PLL1_EN				(0x1 << 10)
+#define RT1305_POW_PLL1_EN_BIT			10
+#define RT1305_POW_PDB_JD_POLARITY				(0x1 << 9)
+#define RT1305_POW_PDB_JD_POLARITY_BIT			9
+#define RT1305_POW_MBIAS_LV				(0x1 << 8)
+#define RT1305_POW_MBIAS_LV_BIT			8
+#define RT1305_POW_BG_MBIAS_LV				(0x1 << 7)
+#define RT1305_POW_BG_MBIAS_LV_BIT			7
+#define RT1305_POW_LDO2				(0x1 << 6)
+#define RT1305_POW_LDO2_BIT			6
+#define RT1305_POW_BG2				(0x1 << 5)
+#define RT1305_POW_BG2_BIT			5
+#define RT1305_POW_LDO2_IB2				(0x1 << 4)
+#define RT1305_POW_LDO2_IB2_BIT			4
+#define RT1305_POW_VREF				(0x1 << 3)
+#define RT1305_POW_VREF_BIT			3
+#define RT1305_POW_VREF1				(0x1 << 2)
+#define RT1305_POW_VREF1_BIT			2
+#define RT1305_POW_VREF2				(0x1 << 1)
+#define RT1305_POW_VREF2_BIT			1
+
+/* Power Control-2 (0x3b) */
+#define RT1305_POW_DISC_VREF           (1 << 15)
+#define RT1305_POW_DISC_VREF_BIT       15
+#define RT1305_POW_FASTB_VREF          (1 << 14)
+#define RT1305_POW_FASTB_VREF_BIT          14
+#define RT1305_POW_ULTRA_FAST_VREF     (1 << 13)
+#define RT1305_POW_ULTRA_FAST_VREF_BIT     13
+#define RT1305_POW_CKXEN_DAC           (1 << 12)
+#define RT1305_POW_CKXEN_DAC_BIT           12
+#define RT1305_POW_EN_CKGEN_DAC        (1 << 11)
+#define RT1305_POW_EN_CKGEN_DAC_BIT        11
+#define RT1305_POW_DAC1_L          (1 << 10)
+#define RT1305_POW_DAC1_L_BIT          10
+#define RT1305_POW_DAC1_R          (1 << 9)
+#define RT1305_POW_DAC1_R_BIT          9
+#define RT1305_POW_CLAMP           (1 << 8)
+#define RT1305_POW_CLAMP_BIT           8
+#define RT1305_POW_BUFL            (1 << 7)
+#define RT1305_POW_BUFL_BIT            7
+#define RT1305_POW_BUFR              (1 << 6)
+#define RT1305_POW_BUFR_BIT              6
+#define RT1305_POW_EN_CKGEN_ADC       (1 << 5)
+#define RT1305_POW_EN_CKGEN_ADC_BIT       5
+#define RT1305_POW_ADC3_L             (1 << 4)
+#define RT1305_POW_ADC3_L_BIT             4
+#define RT1305_POW_ADC3_R             (1 << 3)
+#define RT1305_POW_ADC3_R_BIT             3
+#define RT1305_POW_TRIOSC               (1 << 2)
+#define RT1305_POW_TRIOSC_BIT               2
+#define RT1305_POR_AVDD1              (1 << 1)
+#define RT1305_POR_AVDD1_BIT              1
+#define RT1305_POR_AVDD2           (1 << 0)
+#define RT1305_POR_AVDD2_BIT           0
+
+/* Power Control-3 (0x3c) */
+#define RT1305_POW_VSENSE_RCH           (1 << 15)
+#define RT1305_POW_VSENSE_RCH_BIT        15
+#define RT1305_POW_VSENSE_LCH           (1 << 14)
+#define RT1305_POW_VSENSE_LCH_BIT           14
+#define RT1305_POW_ISENSE_RCH            (1 << 13)
+#define RT1305_POW_ISENSE_RCH_BIT          13
+#define RT1305_POW_ISENSE_LCH            (1 << 12)
+#define RT1305_POW_ISENSE_LCH_BIT            12
+#define RT1305_POW_POR_AVDD1            (1 << 11)
+#define RT1305_POW_POR_AVDD1_BIT          11
+#define RT1305_POW_POR_AVDD2            (1 << 10)
+#define RT1305_POW_POR_AVDD2_BIT            10
+#define RT1305_EN_K_HV            (1 << 9)
+#define RT1305_EN_K_HV_BIT           9
+#define RT1305_EN_PRE_K_HV            (1 << 8)
+#define RT1305_EN_PRE_K_HV_BIT           8
+#define RT1305_EN_EFUSE_1P8V            (1 << 7)
+#define RT1305_EN_EFUSE_1P8V_BIT           7
+#define RT1305_EN_EFUSE_5V             (1 << 6)
+#define RT1305_EN_EFUSE_5V_BIT           6
+#define RT1305_EN_VCM_6172           (1 << 5)
+#define RT1305_EN_VCM_6172_BIT          5
+#define RT1305_POR_EFUSE           (1 << 4)
+#define RT1305_POR_EFUSE_BIT             4
+
+/* Clock Detect (0x3f) */
+#define RT1305_SEL_CLK_DET_SRC_MASK			(0x1 << 12)
+#define RT1305_SEL_CLK_DET_SRC_SFT			12
+#define RT1305_SEL_CLK_DET_SRC_MCLK			(0x0 << 12)
+#define RT1305_SEL_CLK_DET_SRC_BCLK			(0x1 << 12)
+
+
+/* System Clock Source */
+enum {
+	RT1305_FS_SYS_PRE_S_MCLK,
+	RT1305_FS_SYS_PRE_S_PLL1,
+	RT1305_FS_SYS_PRE_S_RCCLK,	/* 98.304M Hz */
+};
+
+/* PLL Source 1/2 */
+enum {
+	RT1305_PLL1_S_BCLK,
+	RT1305_PLL2_S_MCLK,
+	RT1305_PLL2_S_RCCLK,	/* 98.304M Hz */
+};
+
+enum {
+	RT1305_AIF1,
+	RT1305_AIFS
+};
+
+#define R0_UPPER 0x2E8BA2 //5.5 ohm
+#define R0_LOWER 0x666666 //2.5 ohm
+
+#endif		/* end of _RT1305_H_ */
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 05567426f211..8bf8d360c25f 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -24,6 +24,7 @@
 #include <linux/spi/spi.h>
 #include <linux/acpi.h>
 #include <sound/core.h>
+#include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -476,20 +477,6 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	return idx;
 }
 
-static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
-			 struct snd_soc_dapm_widget *sink)
-{
-	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
-	unsigned int val;
-
-	val = snd_soc_component_read32(component, RT5640_GLB_CLK);
-	val &= RT5640_SCLK_SRC_MASK;
-	if (val == RT5640_SCLK_SRC_PLL1)
-		return 1;
-	else
-		return 0;
-}
-
 static int is_using_asrc(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
@@ -1071,9 +1058,6 @@ static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
 }
 
 static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
-	SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
-			RT5640_PWR_PLL_BIT, 0, NULL, 0),
-
 	/* ASRC */
 	SND_SOC_DAPM_SUPPLY_S("Stereo Filter ASRC", 1, RT5640_ASRC_1,
 			 15, 0, NULL, 0),
@@ -1427,22 +1411,18 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
 	{"Stereo ADC MIXL", "ADC1 Switch", "Stereo ADC L1 Mux"},
 	{"Stereo ADC MIXL", "ADC2 Switch", "Stereo ADC L2 Mux"},
 	{"Stereo ADC MIXL", NULL, "Stereo Filter"},
-	{"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},
 
 	{"Stereo ADC MIXR", "ADC1 Switch", "Stereo ADC R1 Mux"},
 	{"Stereo ADC MIXR", "ADC2 Switch", "Stereo ADC R2 Mux"},
 	{"Stereo ADC MIXR", NULL, "Stereo Filter"},
-	{"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},
 
 	{"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"},
 	{"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"},
 	{"Mono ADC MIXL", NULL, "Mono Left Filter"},
-	{"Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll},
 
 	{"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"},
 	{"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"},
 	{"Mono ADC MIXR", NULL, "Mono Right Filter"},
-	{"Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll},
 
 	{"IF2 ADC L", NULL, "Mono ADC MIXL"},
 	{"IF2 ADC R", NULL, "Mono ADC MIXR"},
@@ -1512,10 +1492,8 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
 	{"DIG MIXR", "DAC R1 Switch", "DAC MIXR"},
 
 	{"DAC L1", NULL, "Stereo DAC MIXL"},
-	{"DAC L1", NULL, "PLL1", is_sys_clk_from_pll},
 	{"DAC L1", NULL, "DAC L1 Power"},
 	{"DAC R1", NULL, "Stereo DAC MIXR"},
-	{"DAC R1", NULL, "PLL1", is_sys_clk_from_pll},
 	{"DAC R1", NULL, "DAC R1 Power"},
 
 	{"SPK MIXL", "REC MIXL Switch", "RECMIXL"},
@@ -1622,10 +1600,8 @@ static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = {
 	{"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},
 
 	{"DAC L2", NULL, "Mono DAC MIXL"},
-	{"DAC L2", NULL, "PLL1", is_sys_clk_from_pll},
 	{"DAC L2", NULL, "DAC L2 Power"},
 	{"DAC R2", NULL, "Mono DAC MIXR"},
-	{"DAC R2", NULL, "PLL1", is_sys_clk_from_pll},
 	{"DAC R2", NULL, "DAC R2 Power"},
 
 	{"SPK MIXL", "DAC L2 Switch", "DAC L2"},
@@ -1861,6 +1837,7 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
 	struct snd_soc_component *component = dai->component;
 	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
+	unsigned int pll_bit = 0;
 
 	if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src)
 		return 0;
@@ -1871,6 +1848,7 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
 		break;
 	case RT5640_SCLK_S_PLL1:
 		reg_val |= RT5640_SCLK_SRC_PLL1;
+		pll_bit |= RT5640_PWR_PLL;
 		break;
 	case RT5640_SCLK_S_RCCLK:
 		reg_val |= RT5640_SCLK_SRC_RCCLK;
@@ -1879,6 +1857,8 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
 		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
 	}
+	snd_soc_component_update_bits(component, RT5640_PWR_ANLG2,
+		RT5640_PWR_PLL, pll_bit);
 	snd_soc_component_update_bits(component, RT5640_GLB_CLK,
 		RT5640_SCLK_SRC_MASK, reg_val);
 	rt5640->sysclk = freq;
@@ -2114,10 +2094,376 @@ int rt5640_sel_asrc_clk_src(struct snd_soc_component *component,
 }
 EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
 
+static void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_dapm_mutex_lock(dapm);
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2");
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1");
+	/* OVCD is unreliable when used with RCCLK as sysclk-source */
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "Platform Clock");
+	snd_soc_dapm_sync_unlocked(dapm);
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_dapm_mutex_lock(dapm);
+	snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock");
+	snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1");
+	snd_soc_dapm_disable_pin_unlocked(dapm, "LDO2");
+	snd_soc_dapm_sync_unlocked(dapm);
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static void rt5640_enable_micbias1_ovcd_irq(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
+		RT5640_IRQ_MB1_OC_MASK, RT5640_IRQ_MB1_OC_NOR);
+	rt5640->ovcd_irq_enabled = true;
+}
+
+static void rt5640_disable_micbias1_ovcd_irq(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
+		RT5640_IRQ_MB1_OC_MASK, RT5640_IRQ_MB1_OC_BP);
+	rt5640->ovcd_irq_enabled = false;
+}
+
+static void rt5640_clear_micbias1_ovcd(struct snd_soc_component *component)
+{
+	snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
+		RT5640_MB1_OC_STATUS, 0);
+}
+
+static bool rt5640_micbias1_ovcd(struct snd_soc_component *component)
+{
+	int val;
+
+	val = snd_soc_component_read32(component, RT5640_IRQ_CTRL2);
+	dev_dbg(component->dev, "irq ctrl2 %#04x\n", val);
+
+	return (val & RT5640_MB1_OC_STATUS);
+}
+
+static bool rt5640_jack_inserted(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+	int val;
+
+	val = snd_soc_component_read32(component, RT5640_INT_IRQ_ST);
+	dev_dbg(component->dev, "irq status %#04x\n", val);
+
+	if (rt5640->jd_inverted)
+		return !(val & RT5640_JD_STATUS);
+	else
+		return (val & RT5640_JD_STATUS);
+}
+
+/* Jack detect and button-press timings */
+#define JACK_SETTLE_TIME	100 /* milli seconds */
+#define JACK_DETECT_COUNT	5
+#define JACK_DETECT_MAXCOUNT	20  /* Aprox. 2 seconds worth of tries */
+#define JACK_UNPLUG_TIME	80  /* milli seconds */
+#define BP_POLL_TIME		10  /* milli seconds */
+#define BP_POLL_MAXCOUNT	200 /* assume something is wrong after this */
+#define BP_THRESHOLD		3
+
+static void rt5640_start_button_press_work(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	rt5640->poll_count = 0;
+	rt5640->press_count = 0;
+	rt5640->release_count = 0;
+	rt5640->pressed = false;
+	rt5640->press_reported = false;
+	rt5640_clear_micbias1_ovcd(component);
+	schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME));
+}
+
+static void rt5640_button_press_work(struct work_struct *work)
+{
+	struct rt5640_priv *rt5640 =
+		container_of(work, struct rt5640_priv, bp_work.work);
+	struct snd_soc_component *component = rt5640->component;
+
+	/* Check the jack was not removed underneath us */
+	if (!rt5640_jack_inserted(component))
+		return;
+
+	if (rt5640_micbias1_ovcd(component)) {
+		rt5640->release_count = 0;
+		rt5640->press_count++;
+		/* Remember till after JACK_UNPLUG_TIME wait */
+		if (rt5640->press_count >= BP_THRESHOLD)
+			rt5640->pressed = true;
+		rt5640_clear_micbias1_ovcd(component);
+	} else {
+		rt5640->press_count = 0;
+		rt5640->release_count++;
+	}
+
+	/*
+	 * The pins get temporarily shorted on jack unplug, so we poll for
+	 * at least JACK_UNPLUG_TIME milli-seconds before reporting a press.
+	 */
+	rt5640->poll_count++;
+	if (rt5640->poll_count < (JACK_UNPLUG_TIME / BP_POLL_TIME)) {
+		schedule_delayed_work(&rt5640->bp_work,
+				      msecs_to_jiffies(BP_POLL_TIME));
+		return;
+	}
+
+	if (rt5640->pressed && !rt5640->press_reported) {
+		dev_dbg(component->dev, "headset button press\n");
+		snd_soc_jack_report(rt5640->jack, SND_JACK_BTN_0,
+				    SND_JACK_BTN_0);
+		rt5640->press_reported = true;
+	}
+
+	if (rt5640->release_count >= BP_THRESHOLD) {
+		if (rt5640->press_reported) {
+			dev_dbg(component->dev, "headset button release\n");
+			snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
+		}
+		/* Re-enable OVCD IRQ to detect next press */
+		rt5640_enable_micbias1_ovcd_irq(component);
+		return; /* Stop polling */
+	}
+
+	schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME));
+}
+
+static int rt5640_detect_headset(struct snd_soc_component *component)
+{
+	int i, headset_count = 0, headphone_count = 0;
+
+	/*
+	 * We get the insertion event before the jack is fully inserted at which
+	 * point the second ring on a TRRS connector may short the 2nd ring and
+	 * sleeve contacts, also the overcurrent detection is not entirely
+	 * reliable. So we try several times with a wait in between until we
+	 * detect the same type JACK_DETECT_COUNT times in a row.
+	 */
+	for (i = 0; i < JACK_DETECT_MAXCOUNT; i++) {
+		/* Clear any previous over-current status flag */
+		rt5640_clear_micbias1_ovcd(component);
+
+		msleep(JACK_SETTLE_TIME);
+
+		/* Check the jack is still connected before checking ovcd */
+		if (!rt5640_jack_inserted(component))
+			return 0;
+
+		if (rt5640_micbias1_ovcd(component)) {
+			/*
+			 * Over current detected, there is a short between the
+			 * 2nd ring contact and the ground, so a TRS connector
+			 * without a mic contact and thus plain headphones.
+			 */
+			dev_dbg(component->dev, "jack mic-gnd shorted\n");
+			headset_count = 0;
+			headphone_count++;
+			if (headphone_count == JACK_DETECT_COUNT)
+				return SND_JACK_HEADPHONE;
+		} else {
+			dev_dbg(component->dev, "jack mic-gnd open\n");
+			headphone_count = 0;
+			headset_count++;
+			if (headset_count == JACK_DETECT_COUNT)
+				return SND_JACK_HEADSET;
+		}
+	}
+
+	dev_err(component->dev, "Error detecting headset vs headphones, bad contact?, assuming headphones\n");
+	return SND_JACK_HEADPHONE;
+}
+
+static void rt5640_jack_work(struct work_struct *work)
+{
+	struct rt5640_priv *rt5640 =
+		container_of(work, struct rt5640_priv, jack_work);
+	struct snd_soc_component *component = rt5640->component;
+	int status;
+
+	if (!rt5640_jack_inserted(component)) {
+		/* Jack removed, or spurious IRQ? */
+		if (rt5640->jack->status & SND_JACK_HEADPHONE) {
+			if (rt5640->jack->status & SND_JACK_MICROPHONE) {
+				cancel_delayed_work_sync(&rt5640->bp_work);
+				rt5640_disable_micbias1_ovcd_irq(component);
+				rt5640_disable_micbias1_for_ovcd(component);
+			}
+			snd_soc_jack_report(rt5640->jack, 0,
+					    SND_JACK_HEADSET | SND_JACK_BTN_0);
+			dev_dbg(component->dev, "jack unplugged\n");
+		}
+	} else if (!(rt5640->jack->status & SND_JACK_HEADPHONE)) {
+		/* Jack inserted */
+		WARN_ON(rt5640->ovcd_irq_enabled);
+		rt5640_enable_micbias1_for_ovcd(component);
+		status = rt5640_detect_headset(component);
+		if (status == SND_JACK_HEADSET) {
+			/* Enable ovcd IRQ for button press detect. */
+			rt5640_enable_micbias1_ovcd_irq(component);
+		} else {
+			/* No more need for overcurrent detect. */
+			rt5640_disable_micbias1_for_ovcd(component);
+		}
+		dev_dbg(component->dev, "detect status %#02x\n", status);
+		snd_soc_jack_report(rt5640->jack, status, SND_JACK_HEADSET);
+	} else if (rt5640->ovcd_irq_enabled && rt5640_micbias1_ovcd(component)) {
+		dev_dbg(component->dev, "OVCD IRQ\n");
+
+		/*
+		 * The ovcd IRQ keeps firing while the button is pressed, so
+		 * we disable it and start polling the button until released.
+		 *
+		 * The disable will make the IRQ pin 0 again and since we get
+		 * IRQs on both edges (so as to detect both jack plugin and
+		 * unplug) this means we will immediately get another IRQ.
+		 * The ovcd_irq_enabled check above makes the 2ND IRQ a NOP.
+		 */
+		rt5640_disable_micbias1_ovcd_irq(component);
+		rt5640_start_button_press_work(component);
+
+		/*
+		 * If the jack-detect IRQ flag goes high (unplug) after our
+		 * above rt5640_jack_inserted() check and before we have
+		 * disabled the OVCD IRQ, the IRQ pin will stay high and as
+		 * we react to edges, we miss the unplug event -> recheck.
+		 */
+		queue_work(system_long_wq, &rt5640->jack_work);
+	}
+}
+
+static irqreturn_t rt5640_irq(int irq, void *data)
+{
+	struct rt5640_priv *rt5640 = data;
+
+	if (rt5640->jack)
+		queue_work(system_long_wq, &rt5640->jack_work);
+
+	return IRQ_HANDLED;
+}
+
+static void rt5640_cancel_work(void *data)
+{
+	struct rt5640_priv *rt5640 = data;
+
+	cancel_work_sync(&rt5640->jack_work);
+	cancel_delayed_work_sync(&rt5640->bp_work);
+}
+
+static void rt5640_enable_jack_detect(struct snd_soc_component *component,
+				      struct snd_soc_jack *jack)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	/* Select JD-source */
+	snd_soc_component_update_bits(component, RT5640_JD_CTRL,
+		RT5640_JD_MASK, rt5640->jd_src);
+
+	/* Selecting GPIO01 as an interrupt */
+	snd_soc_component_update_bits(component, RT5640_GPIO_CTRL1,
+		RT5640_GP1_PIN_MASK, RT5640_GP1_PIN_IRQ);
+
+	/* Set GPIO1 output */
+	snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3,
+		RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT);
+
+	/* Enabling jd2 in general control 1 */
+	snd_soc_component_write(component, RT5640_DUMMY1, 0x3f41);
+
+	/* Enabling jd2 in general control 2 */
+	snd_soc_component_write(component, RT5640_DUMMY2, 0x4001);
+
+	snd_soc_component_write(component, RT5640_PR_BASE + RT5640_BIAS_CUR4,
+		0xa800 | rt5640->ovcd_sf);
+
+	snd_soc_component_update_bits(component, RT5640_MICBIAS,
+		RT5640_MIC1_OVTH_MASK | RT5640_MIC1_OVCD_MASK,
+		rt5640->ovcd_th | RT5640_MIC1_OVCD_EN);
+
+	/*
+	 * The over-current-detect is only reliable in detecting the absence
+	 * of over-current, when the mic-contact in the jack is short-circuited,
+	 * the hardware periodically retries if it can apply the bias-current
+	 * leading to the ovcd status flip-flopping 1-0-1 with it being 0 about
+	 * 10% of the time, as we poll the ovcd status bit we might hit that
+	 * 10%, so we enable sticky mode and when checking OVCD we clear the
+	 * status, msleep() a bit and then check to get a reliable reading.
+	 */
+	snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
+		RT5640_MB1_OC_STKY_MASK, RT5640_MB1_OC_STKY_EN);
+
+	/*
+	 * All IRQs get or-ed together, so we need the jack IRQ to report 0
+	 * when a jack is inserted so that the OVCD IRQ then toggles the IRQ
+	 * pin 0/1 instead of it being stuck to 1. So we invert the JD polarity
+	 * on systems where the hardware does not already do this.
+	 */
+	if (rt5640->jd_inverted)
+		snd_soc_component_write(component, RT5640_IRQ_CTRL1,
+					RT5640_IRQ_JD_NOR);
+	else
+		snd_soc_component_write(component, RT5640_IRQ_CTRL1,
+					RT5640_IRQ_JD_NOR | RT5640_JD_P_INV);
+
+	rt5640->jack = jack;
+	if (rt5640->jack->status & SND_JACK_MICROPHONE) {
+		rt5640_enable_micbias1_for_ovcd(component);
+		rt5640_enable_micbias1_ovcd_irq(component);
+	}
+
+	enable_irq(rt5640->irq);
+	/* sync initial jack state */
+	queue_work(system_long_wq, &rt5640->jack_work);
+}
+
+static void rt5640_disable_jack_detect(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	disable_irq(rt5640->irq);
+	rt5640_cancel_work(rt5640);
+
+	if (rt5640->jack->status & SND_JACK_MICROPHONE) {
+		rt5640_disable_micbias1_ovcd_irq(component);
+		rt5640_disable_micbias1_for_ovcd(component);
+		snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
+	}
+
+	rt5640->jack = NULL;
+}
+
+static int rt5640_set_jack(struct snd_soc_component *component,
+			   struct snd_soc_jack *jack, void *data)
+{
+	if (jack)
+		rt5640_enable_jack_detect(component, jack);
+	else
+		rt5640_disable_jack_detect(component);
+
+	return 0;
+}
+
 static int rt5640_probe(struct snd_soc_component *component)
 {
 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+	u32 dmic1_data_pin = 0;
+	u32 dmic2_data_pin = 0;
+	bool dmic_en = false;
+	u32 val;
 
 	/* Check if MCLK provided */
 	rt5640->mclk = devm_clk_get(component->dev, "mclk");
@@ -2159,9 +2505,86 @@ static int rt5640_probe(struct snd_soc_component *component)
 		return -ENODEV;
 	}
 
-	if (rt5640->pdata.dmic_en)
-		rt5640_dmic_enable(component, rt5640->pdata.dmic1_data_pin,
-					  rt5640->pdata.dmic2_data_pin);
+	/*
+	 * Note on some platforms the platform code may need to add device-props
+	 * rather then relying only on properties set by the firmware.
+	 * Therefor the property parsing MUST be done here, rather then from
+	 * rt5640_i2c_probe(), so that the platform-code can attach extra
+	 * properties before calling snd_soc_register_card().
+	 */
+	if (device_property_read_bool(component->dev, "realtek,in1-differential"))
+		snd_soc_component_update_bits(component, RT5640_IN1_IN2,
+					      RT5640_IN_DF1, RT5640_IN_DF1);
+
+	if (device_property_read_bool(component->dev, "realtek,in2-differential"))
+		snd_soc_component_update_bits(component, RT5640_IN3_IN4,
+					      RT5640_IN_DF2, RT5640_IN_DF2);
+
+	if (device_property_read_bool(component->dev, "realtek,in3-differential"))
+		snd_soc_component_update_bits(component, RT5640_IN1_IN2,
+					      RT5640_IN_DF2, RT5640_IN_DF2);
+
+	if (device_property_read_u32(component->dev, "realtek,dmic1-data-pin",
+				     &val) == 0 && val) {
+		dmic1_data_pin = val - 1;
+		dmic_en = true;
+	}
+
+	if (device_property_read_u32(component->dev, "realtek,dmic2-data-pin",
+				     &val) == 0 && val) {
+		dmic2_data_pin = val - 1;
+		dmic_en = true;
+	}
+
+	if (dmic_en)
+		rt5640_dmic_enable(component, dmic1_data_pin, dmic2_data_pin);
+
+	if (device_property_read_u32(component->dev,
+				     "realtek,jack-detect-source", &val) == 0) {
+		if (val <= RT5640_JD_SRC_GPIO4)
+			rt5640->jd_src = val << RT5640_JD_SFT;
+		else
+			dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n",
+				 val);
+	}
+
+	if (!device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted"))
+		rt5640->jd_inverted = true;
+
+	/*
+	 * Testing on various boards has shown that good defaults for the OVCD
+	 * threshold and scale-factor are 2000µA and 0.75. For an effective
+	 * limit of 1500µA, this seems to be more reliable then 1500µA and 1.0.
+	 */
+	rt5640->ovcd_th = RT5640_MIC1_OVTH_2000UA;
+	rt5640->ovcd_sf = RT5640_MIC_OVCD_SF_0P75;
+
+	if (device_property_read_u32(component->dev,
+			"realtek,over-current-threshold-microamp", &val) == 0) {
+		switch (val) {
+		case 600:
+			rt5640->ovcd_th = RT5640_MIC1_OVTH_600UA;
+			break;
+		case 1500:
+			rt5640->ovcd_th = RT5640_MIC1_OVTH_1500UA;
+			break;
+		case 2000:
+			rt5640->ovcd_th = RT5640_MIC1_OVTH_2000UA;
+			break;
+		default:
+			dev_warn(component->dev, "Warning: Invalid over-current-threshold-microamp value: %d, defaulting to 2000uA\n",
+				 val);
+		}
+	}
+
+	if (device_property_read_u32(component->dev,
+			"realtek,over-current-scale-factor", &val) == 0) {
+		if (val <= RT5640_OVCD_SF_1P5)
+			rt5640->ovcd_sf = val << RT5640_MIC_OVCD_SF_SFT;
+		else
+			dev_warn(component->dev, "Warning: Invalid over-current-scale-factor value: %d, defaulting to 0.75\n",
+				 val);
+	}
 
 	return 0;
 }
@@ -2180,8 +2603,8 @@ static int rt5640_suspend(struct snd_soc_component *component)
 	rt5640_reset(component);
 	regcache_cache_only(rt5640->regmap, true);
 	regcache_mark_dirty(rt5640->regmap);
-	if (gpio_is_valid(rt5640->pdata.ldo1_en))
-		gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 0);
+	if (gpio_is_valid(rt5640->ldo1_en))
+		gpio_set_value_cansleep(rt5640->ldo1_en, 0);
 
 	return 0;
 }
@@ -2190,8 +2613,8 @@ static int rt5640_resume(struct snd_soc_component *component)
 {
 	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
-	if (gpio_is_valid(rt5640->pdata.ldo1_en)) {
-		gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 1);
+	if (gpio_is_valid(rt5640->ldo1_en)) {
+		gpio_set_value_cansleep(rt5640->ldo1_en, 1);
 		msleep(400);
 	}
 
@@ -2263,6 +2686,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt5640 = {
 	.suspend		= rt5640_suspend,
 	.resume			= rt5640_resume,
 	.set_bias_level		= rt5640_set_bias_level,
+	.set_jack		= rt5640_set_jack,
 	.controls		= rt5640_snd_controls,
 	.num_controls		= ARRAY_SIZE(rt5640_snd_controls),
 	.dapm_widgets		= rt5640_dapm_widgets,
@@ -2323,22 +2747,16 @@ MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
 
 static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
 {
-	rt5640->pdata.in1_diff = of_property_read_bool(np,
-					"realtek,in1-differential");
-	rt5640->pdata.in2_diff = of_property_read_bool(np,
-					"realtek,in2-differential");
-
-	rt5640->pdata.ldo1_en = of_get_named_gpio(np,
-					"realtek,ldo1-en-gpios", 0);
+	rt5640->ldo1_en = of_get_named_gpio(np, "realtek,ldo1-en-gpios", 0);
 	/*
 	 * LDO1_EN is optional (it may be statically tied on the board).
 	 * -ENOENT means that the property doesn't exist, i.e. there is no
 	 * GPIO, so is not an error. Any other error code means the property
 	 * exists, but could not be parsed.
 	 */
-	if (!gpio_is_valid(rt5640->pdata.ldo1_en) &&
-			(rt5640->pdata.ldo1_en != -ENOENT))
-		return rt5640->pdata.ldo1_en;
+	if (!gpio_is_valid(rt5640->ldo1_en) &&
+			(rt5640->ldo1_en != -ENOENT))
+		return rt5640->ldo1_en;
 
 	return 0;
 }
@@ -2346,7 +2764,6 @@ static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
 static int rt5640_i2c_probe(struct i2c_client *i2c,
 		    const struct i2c_device_id *id)
 {
-	struct rt5640_platform_data *pdata = dev_get_platdata(&i2c->dev);
 	struct rt5640_priv *rt5640;
 	int ret;
 	unsigned int val;
@@ -2358,22 +2775,12 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
 		return -ENOMEM;
 	i2c_set_clientdata(i2c, rt5640);
 
-	if (pdata) {
-		rt5640->pdata = *pdata;
-		/*
-		 * Translate zero'd out (default) pdata value to an invalid
-		 * GPIO ID. This makes the pdata and DT paths consistent in
-		 * terms of the value left in this field when no GPIO is
-		 * specified, but means we can't actually use GPIO 0.
-		 */
-		if (!rt5640->pdata.ldo1_en)
-			rt5640->pdata.ldo1_en = -EINVAL;
-	} else if (i2c->dev.of_node) {
+	if (i2c->dev.of_node) {
 		ret = rt5640_parse_dt(rt5640, i2c->dev.of_node);
 		if (ret)
 			return ret;
 	} else
-		rt5640->pdata.ldo1_en = -EINVAL;
+		rt5640->ldo1_en = -EINVAL;
 
 	rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap);
 	if (IS_ERR(rt5640->regmap)) {
@@ -2383,13 +2790,13 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	if (gpio_is_valid(rt5640->pdata.ldo1_en)) {
-		ret = devm_gpio_request_one(&i2c->dev, rt5640->pdata.ldo1_en,
+	if (gpio_is_valid(rt5640->ldo1_en)) {
+		ret = devm_gpio_request_one(&i2c->dev, rt5640->ldo1_en,
 					    GPIOF_OUT_INIT_HIGH,
 					    "RT5640 LDO1_EN");
 		if (ret < 0) {
 			dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n",
-				rt5640->pdata.ldo1_en, ret);
+				rt5640->ldo1_en, ret);
 			return ret;
 		}
 		msleep(400);
@@ -2412,19 +2819,27 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
 	regmap_update_bits(rt5640->regmap, RT5640_DUMMY1,
 				RT5640_MCLK_DET, RT5640_MCLK_DET);
 
-	if (rt5640->pdata.in1_diff)
-		regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2,
-					RT5640_IN_DF1, RT5640_IN_DF1);
-
-	if (rt5640->pdata.in2_diff)
-		regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
-					RT5640_IN_DF2, RT5640_IN_DF2);
+	rt5640->hp_mute = 1;
+	rt5640->irq = i2c->irq;
+	INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work);
+	INIT_WORK(&rt5640->jack_work, rt5640_jack_work);
 
-	if (rt5640->pdata.in3_diff)
-		regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2,
-					RT5640_IN_DF2, RT5640_IN_DF2);
+	/* Make sure work is stopped on probe-error / remove */
+	ret = devm_add_action_or_reset(&i2c->dev, rt5640_cancel_work, rt5640);
+	if (ret)
+		return ret;
 
-	rt5640->hp_mute = 1;
+	ret = devm_request_irq(&i2c->dev, rt5640->irq, rt5640_irq,
+			       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			       | IRQF_ONESHOT, "rt5640", rt5640);
+	if (ret == 0) {
+		/* Gets re-enabled by rt5640_set_jack() */
+		disable_irq(rt5640->irq);
+	} else {
+		dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n",
+			 rt5640->irq, ret);
+		rt5640->irq = -ENXIO;
+	}
 
 	return devm_snd_soc_register_component(&i2c->dev,
 				      &soc_component_dev_rt5640,
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index c473e8ae2eda..e29e3e7d61b0 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -13,7 +13,8 @@
 #define _RT5640_H
 
 #include <linux/clk.h>
-#include <sound/rt5640.h>
+#include <linux/workqueue.h>
+#include <dt-bindings/sound/rt5640.h>
 
 /* Info */
 #define RT5640_RESET				0x00
@@ -146,6 +147,7 @@
 
 
 /* Index of Codec Private Register definition */
+#define RT5640_BIAS_CUR4			0x15
 #define RT5640_CHPUMP_INT_REG1			0x24
 #define RT5640_MAMP_INT_REG2			0x37
 #define RT5640_3D_SPK				0x63
@@ -1607,10 +1609,17 @@
 #define RT5640_MB2_OC_P_SFT			6
 #define RT5640_MB2_OC_P_NOR			(0x0 << 6)
 #define RT5640_MB2_OC_P_INV			(0x1 << 6)
-#define RT5640_MB1_OC_CLR			(0x1 << 3)
-#define RT5640_MB1_OC_CLR_SFT			3
-#define RT5640_MB2_OC_CLR			(0x1 << 2)
-#define RT5640_MB2_OC_CLR_SFT			2
+#define RT5640_MB1_OC_STATUS			(0x1 << 3)
+#define RT5640_MB1_OC_STATUS_SFT		3
+#define RT5640_MB2_OC_STATUS			(0x1 << 2)
+#define RT5640_MB2_OC_STATUS_SFT		2
+
+/* GPIO and Internal Status (0xbf) */
+#define RT5640_GPIO1_STATUS			(0x1 << 8)
+#define RT5640_GPIO2_STATUS			(0x1 << 7)
+#define RT5640_JD_STATUS			(0x1 << 4)
+#define RT5640_OVT_STATUS			(0x1 << 3)
+#define RT5640_CLS_D_OVCD_STATUS		(0x1 << 0)
 
 /* GPIO Control 1 (0xc0) */
 #define RT5640_GP1_PIN_MASK			(0x1 << 15)
@@ -1978,6 +1987,15 @@
 #define RT5640_MCLK_DET				(0x1 << 11)
 
 /* Codec Private Register definition */
+
+/* MIC Over current threshold scale factor (0x15) */
+#define RT5640_MIC_OVCD_SF_MASK			(0x3 << 8)
+#define RT5640_MIC_OVCD_SF_SFT			8
+#define RT5640_MIC_OVCD_SF_0P5			(0x0 << 8)
+#define RT5640_MIC_OVCD_SF_0P75			(0x1 << 8)
+#define RT5640_MIC_OVCD_SF_1P0			(0x2 << 8)
+#define RT5640_MIC_OVCD_SF_1P5			(0x3 << 8)
+
 /* 3D Speaker Control (0x63) */
 #define RT5640_3D_SPK_MASK			(0x1 << 15)
 #define RT5640_3D_SPK_SFT			15
@@ -2103,10 +2121,11 @@ enum {
 
 struct rt5640_priv {
 	struct snd_soc_component *component;
-	struct rt5640_platform_data pdata;
 	struct regmap *regmap;
 	struct clk *mclk;
 
+	int ldo1_en; /* GPIO for LDO1_EN */
+	int irq;
 	int sysclk;
 	int sysclk_src;
 	int lrck[RT5640_AIFS];
@@ -2119,6 +2138,21 @@ struct rt5640_priv {
 
 	bool hp_mute;
 	bool asrc_en;
+
+	/* Jack and button detect data */
+	bool ovcd_irq_enabled;
+	bool pressed;
+	bool press_reported;
+	int press_count;
+	int release_count;
+	int poll_count;
+	struct delayed_work bp_work;
+	struct work_struct jack_work;
+	struct snd_soc_jack *jack;
+	unsigned int jd_src;
+	bool jd_inverted;
+	unsigned int ovcd_th;
+	unsigned int ovcd_sf;
 };
 
 int rt5640_dmic_enable(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index bc8d829ce45b..712384581ebf 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3652,6 +3652,11 @@ static const struct rt5645_platform_data asus_t100ha_platform_data = {
 	.inv_jd1_1 = true,
 };
 
+static const struct rt5645_platform_data lenovo_ideapad_miix_310_pdata = {
+	.jd_mode = 3,
+	.in2_diff = true,
+};
+
 static const struct rt5645_platform_data jd_mode3_platform_data = {
 	.jd_mode = 3,
 };
@@ -3735,6 +3740,24 @@ static const struct dmi_system_id dmi_platform_data[] = {
 		},
 		.driver_data = (void *)&jd_mode3_platform_data,
 	},
+	{
+		.ident = "Lenovo Ideapad Miix 310",
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80SG"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "MIIX 310-10ICR"),
+		},
+		.driver_data = (void *)&lenovo_ideapad_miix_310_pdata,
+	},
+	{
+		.ident = "Lenovo Ideapad Miix 320",
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
+		},
+		.driver_data = (void *)&intel_braswell_platform_data,
+	},
 	{ }
 };
 
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index 20c0aeea6ca3..9bd24ad42240 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -72,6 +72,8 @@ struct rt5663_priv {
 static const struct reg_sequence rt5663_patch_list[] = {
 	{ 0x002a, 0x8020 },
 	{ 0x0086, 0x0028 },
+	{ 0x0117, 0x0f28 },
+	{ 0x02fb, 0x8089 },
 };
 
 static const struct reg_default rt5663_v2_reg[] = {
@@ -593,7 +595,7 @@ static const struct reg_default rt5663_reg[] = {
 	{ 0x0113, 0x2000 },
 	{ 0x0114, 0x0000 },
 	{ 0x0116, 0x0000 },
-	{ 0x0117, 0x0f00 },
+	{ 0x0117, 0x0f28 },
 	{ 0x0118, 0x0006 },
 	{ 0x0125, 0x2424 },
 	{ 0x0126, 0x5550 },
@@ -693,7 +695,7 @@ static const struct reg_default rt5663_reg[] = {
 	{ 0x0251, 0x0000 },
 	{ 0x0252, 0x028a },
 	{ 0x02fa, 0x0000 },
-	{ 0x02fb, 0x00a4 },
+	{ 0x02fb, 0x8089 },
 	{ 0x02fc, 0x0300 },
 	{ 0x0300, 0x0000 },
 	{ 0x03d0, 0x0000 },
@@ -1556,6 +1558,14 @@ static int rt5663_jack_detect(struct snd_soc_component *component, int jack_inse
 			RT5663_PWR_MB_MASK | RT5663_LDO1_DVO_MASK |
 			RT5663_AMP_HP_MASK, RT5663_PWR_MB |
 			RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X);
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
+			RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
+			RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
+			RT5663_PWR_VREF1 | RT5663_PWR_VREF2);
+		msleep(20);
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
+			RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
+			RT5663_PWR_FV1 | RT5663_PWR_FV2);
 		snd_soc_component_update_bits(component, RT5663_AUTO_1MRC_CLK,
 			RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN);
 		snd_soc_component_update_bits(component, RT5663_IRQ_1,
@@ -1613,7 +1623,10 @@ static int rt5663_jack_detect(struct snd_soc_component *component, int jack_inse
 			break;
 		default:
 			rt5663->jack_type = SND_JACK_HEADPHONE;
-
+			snd_soc_component_update_bits(component,
+				RT5663_PWR_ANLG_1,
+				RT5663_PWR_MB_MASK | RT5663_PWR_VREF1_MASK |
+				RT5663_PWR_VREF2_MASK, 0);
 			if (rt5663->pdata.impedance_sensing_num)
 				break;
 
@@ -1638,6 +1651,9 @@ static int rt5663_jack_detect(struct snd_soc_component *component, int jack_inse
 		if (rt5663->jack_type == SND_JACK_HEADSET)
 			rt5663_enable_push_button_irq(component, false);
 		rt5663->jack_type = 0;
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
+			RT5663_PWR_MB_MASK | RT5663_PWR_VREF1_MASK |
+			RT5663_PWR_VREF2_MASK, 0);
 	}
 
 	dev_dbg(component->dev, "jack_type = %d\n", rt5663->jack_type);
@@ -1840,8 +1856,8 @@ static irqreturn_t rt5663_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-int rt5663_set_jack_detect(struct snd_soc_component *component,
-	struct snd_soc_jack *hs_jack)
+static int rt5663_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hs_jack, void *data)
 {
 	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 
@@ -1851,7 +1867,6 @@ int rt5663_set_jack_detect(struct snd_soc_component *component,
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(rt5663_set_jack_detect);
 
 static bool rt5663_check_jd_status(struct snd_soc_component *component)
 {
@@ -2307,6 +2322,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
 				RT5663_HP_SIG_SRC1_MASK,
 				RT5663_HP_SIG_SRC1_SILENCE);
 		} else {
+			snd_soc_component_update_bits(component,
+				RT5663_DACREF_LDO, 0x3e0e, 0x3a0a);
 			snd_soc_component_write(component, RT5663_DEPOP_2, 0x3003);
 			snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
 				RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_DIS);
@@ -2332,6 +2349,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
 			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000, 0x0);
 			snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
 				RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN);
+			snd_soc_component_update_bits(component,
+				RT5663_DACREF_LDO, 0x3e0e, 0);
 		}
 		break;
 
@@ -3086,9 +3105,17 @@ static int rt5663_set_bias_level(struct snd_soc_component *component,
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
-			RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
-			RT5663_PWR_FV1 | RT5663_PWR_FV2, 0x0);
+		if (rt5663->jack_type != SND_JACK_HEADSET)
+			snd_soc_component_update_bits(component,
+				RT5663_PWR_ANLG_1,
+				RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
+				RT5663_PWR_FV1 | RT5663_PWR_FV2 |
+				RT5663_PWR_MB_MASK, 0);
+		else
+			snd_soc_component_update_bits(component,
+				RT5663_PWR_ANLG_1,
+				RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
+				RT5663_PWR_FV1 | RT5663_PWR_FV2);
 		break;
 
 	default:
@@ -3216,10 +3243,10 @@ static const struct snd_soc_component_driver soc_component_dev_rt5663 = {
 	.num_dapm_widgets	= ARRAY_SIZE(rt5663_dapm_widgets),
 	.dapm_routes		= rt5663_dapm_routes,
 	.num_dapm_routes	= ARRAY_SIZE(rt5663_dapm_routes),
+	.set_jack		= rt5663_set_jack_detect,
 	.use_pmdown_time	= 1,
 	.endianness		= 1,
 	.non_legacy_dai_naming	= 1,
-
 };
 
 static const struct regmap_config rt5663_v2_regmap = {
@@ -3310,6 +3337,7 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663)
 	regmap_write(rt5663->regmap, RT5663_HP_IMP_SEN_19, 0x000c);
 	regmap_write(rt5663->regmap, RT5663_DUMMY_1, 0x0324);
 	regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x8001);
+	regmap_write(rt5663->regmap, RT5663_VREFADJ_OP, 0x0f28);
 	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa23b);
 	msleep(30);
 	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf23b);
@@ -3344,6 +3372,7 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663)
 	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x8003);
 	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x018c);
 	regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32);
+	regmap_write(rt5663->regmap, RT5663_DUMMY_2, 0x8089);
 	regmap_write(rt5663->regmap, RT5663_DACREF_LDO, 0x3b0b);
 	msleep(40);
 	regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x0000);
@@ -3578,15 +3607,9 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
 		regmap_update_bits(rt5663->regmap, RT5663_GPIO_1,
 			RT5663_GPIO1_TYPE_MASK, RT5663_GPIO1_TYPE_EN);
 		regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032);
-		regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be);
-		msleep(20);
-		regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be);
 		regmap_update_bits(rt5663->regmap, RT5663_GPIO_2,
 			RT5663_GP1_PIN_CONF_MASK | RT5663_SEL_GPIO1_MASK,
 			RT5663_GP1_PIN_CONF_OUTPUT | RT5663_SEL_GPIO1_EN);
-		/* DACREF LDO control */
-		regmap_update_bits(rt5663->regmap, RT5663_DACREF_LDO, 0x3e0e,
-			0x3a0a);
 		regmap_update_bits(rt5663->regmap, RT5663_RECMIX,
 			RT5663_RECMIX1_BST1_MASK, RT5663_RECMIX1_BST1_ON);
 		regmap_update_bits(rt5663->regmap, RT5663_TDM_2,
diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h
index 865203cc2034..794cf3fadf31 100644
--- a/sound/soc/codecs/rt5663.h
+++ b/sound/soc/codecs/rt5663.h
@@ -1125,8 +1125,6 @@ enum {
 	RT5663_AD_STEREO_FILTER = 0x2,
 };
 
-int rt5663_set_jack_detect(struct snd_soc_component *component,
-	struct snd_soc_jack *hs_jack);
 int rt5663_sel_asrc_clk_src(struct snd_soc_component *component,
 	unsigned int filter_mask, unsigned int clk_src);
 
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
new file mode 100644
index 000000000000..3c19d03f2446
--- /dev/null
+++ b/sound/soc/codecs/rt5668.c
@@ -0,0 +1,2639 @@
+/*
+ * rt5668.c  --  RT5668B ALSA SoC audio component driver
+ *
+ * Copyright 2018 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt5668.h>
+
+#include "rl6231.h"
+#include "rt5668.h"
+
+#define RT5668_NUM_SUPPLIES 3
+
+static const char *rt5668_supply_names[RT5668_NUM_SUPPLIES] = {
+	"AVDD",
+	"MICVDD",
+	"VBAT",
+};
+
+struct rt5668_priv {
+	struct snd_soc_component *component;
+	struct rt5668_platform_data pdata;
+	struct regmap *regmap;
+	struct snd_soc_jack *hs_jack;
+	struct regulator_bulk_data supplies[RT5668_NUM_SUPPLIES];
+	struct delayed_work jack_detect_work;
+	struct delayed_work jd_check_work;
+	struct mutex calibrate_mutex;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5668_AIFS];
+	int bclk[RT5668_AIFS];
+	int master[RT5668_AIFS];
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	int jack_type;
+};
+
+static const struct reg_default rt5668_reg[] = {
+	{0x0002, 0x8080},
+	{0x0003, 0x8000},
+	{0x0005, 0x0000},
+	{0x0006, 0x0000},
+	{0x0008, 0x800f},
+	{0x000b, 0x0000},
+	{0x0010, 0x4040},
+	{0x0011, 0x0000},
+	{0x0012, 0x1404},
+	{0x0013, 0x1000},
+	{0x0014, 0xa00a},
+	{0x0015, 0x0404},
+	{0x0016, 0x0404},
+	{0x0019, 0xafaf},
+	{0x001c, 0x2f2f},
+	{0x001f, 0x0000},
+	{0x0022, 0x5757},
+	{0x0023, 0x0039},
+	{0x0024, 0x000b},
+	{0x0026, 0xc0c4},
+	{0x0029, 0x8080},
+	{0x002a, 0xa0a0},
+	{0x002b, 0x0300},
+	{0x0030, 0x0000},
+	{0x003c, 0x0080},
+	{0x0044, 0x0c0c},
+	{0x0049, 0x0000},
+	{0x0061, 0x0000},
+	{0x0062, 0x0000},
+	{0x0063, 0x003f},
+	{0x0064, 0x0000},
+	{0x0065, 0x0000},
+	{0x0066, 0x0030},
+	{0x0067, 0x0000},
+	{0x006b, 0x0000},
+	{0x006c, 0x0000},
+	{0x006d, 0x2200},
+	{0x006e, 0x0a10},
+	{0x0070, 0x8000},
+	{0x0071, 0x8000},
+	{0x0073, 0x0000},
+	{0x0074, 0x0000},
+	{0x0075, 0x0002},
+	{0x0076, 0x0001},
+	{0x0079, 0x0000},
+	{0x007a, 0x0000},
+	{0x007b, 0x0000},
+	{0x007c, 0x0100},
+	{0x007e, 0x0000},
+	{0x0080, 0x0000},
+	{0x0081, 0x0000},
+	{0x0082, 0x0000},
+	{0x0083, 0x0000},
+	{0x0084, 0x0000},
+	{0x0085, 0x0000},
+	{0x0086, 0x0005},
+	{0x0087, 0x0000},
+	{0x0088, 0x0000},
+	{0x008c, 0x0003},
+	{0x008d, 0x0000},
+	{0x008e, 0x0060},
+	{0x008f, 0x1000},
+	{0x0091, 0x0c26},
+	{0x0092, 0x0073},
+	{0x0093, 0x0000},
+	{0x0094, 0x0080},
+	{0x0098, 0x0000},
+	{0x009a, 0x0000},
+	{0x009b, 0x0000},
+	{0x009c, 0x0000},
+	{0x009d, 0x0000},
+	{0x009e, 0x100c},
+	{0x009f, 0x0000},
+	{0x00a0, 0x0000},
+	{0x00a3, 0x0002},
+	{0x00a4, 0x0001},
+	{0x00ae, 0x2040},
+	{0x00af, 0x0000},
+	{0x00b6, 0x0000},
+	{0x00b7, 0x0000},
+	{0x00b8, 0x0000},
+	{0x00b9, 0x0002},
+	{0x00be, 0x0000},
+	{0x00c0, 0x0160},
+	{0x00c1, 0x82a0},
+	{0x00c2, 0x0000},
+	{0x00d0, 0x0000},
+	{0x00d1, 0x2244},
+	{0x00d2, 0x3300},
+	{0x00d3, 0x2200},
+	{0x00d4, 0x0000},
+	{0x00d9, 0x0009},
+	{0x00da, 0x0000},
+	{0x00db, 0x0000},
+	{0x00dc, 0x00c0},
+	{0x00dd, 0x2220},
+	{0x00de, 0x3131},
+	{0x00df, 0x3131},
+	{0x00e0, 0x3131},
+	{0x00e2, 0x0000},
+	{0x00e3, 0x4000},
+	{0x00e4, 0x0aa0},
+	{0x00e5, 0x3131},
+	{0x00e6, 0x3131},
+	{0x00e7, 0x3131},
+	{0x00e8, 0x3131},
+	{0x00ea, 0xb320},
+	{0x00eb, 0x0000},
+	{0x00f0, 0x0000},
+	{0x00f1, 0x00d0},
+	{0x00f2, 0x00d0},
+	{0x00f6, 0x0000},
+	{0x00fa, 0x0000},
+	{0x00fb, 0x0000},
+	{0x00fc, 0x0000},
+	{0x00fd, 0x0000},
+	{0x00fe, 0x10ec},
+	{0x00ff, 0x6530},
+	{0x0100, 0xa0a0},
+	{0x010b, 0x0000},
+	{0x010c, 0xae00},
+	{0x010d, 0xaaa0},
+	{0x010e, 0x8aa2},
+	{0x010f, 0x02a2},
+	{0x0110, 0xc000},
+	{0x0111, 0x04a2},
+	{0x0112, 0x2800},
+	{0x0113, 0x0000},
+	{0x0117, 0x0100},
+	{0x0125, 0x0410},
+	{0x0132, 0x6026},
+	{0x0136, 0x5555},
+	{0x0138, 0x3700},
+	{0x013a, 0x2000},
+	{0x013b, 0x2000},
+	{0x013c, 0x2005},
+	{0x013f, 0x0000},
+	{0x0142, 0x0000},
+	{0x0145, 0x0002},
+	{0x0146, 0x0000},
+	{0x0147, 0x0000},
+	{0x0148, 0x0000},
+	{0x0149, 0x0000},
+	{0x0150, 0x79a1},
+	{0x0151, 0x0000},
+	{0x0160, 0x4ec0},
+	{0x0161, 0x0080},
+	{0x0162, 0x0200},
+	{0x0163, 0x0800},
+	{0x0164, 0x0000},
+	{0x0165, 0x0000},
+	{0x0166, 0x0000},
+	{0x0167, 0x000f},
+	{0x0168, 0x000f},
+	{0x0169, 0x0021},
+	{0x0190, 0x413d},
+	{0x0194, 0x0000},
+	{0x0195, 0x0000},
+	{0x0197, 0x0022},
+	{0x0198, 0x0000},
+	{0x0199, 0x0000},
+	{0x01af, 0x0000},
+	{0x01b0, 0x0400},
+	{0x01b1, 0x0000},
+	{0x01b2, 0x0000},
+	{0x01b3, 0x0000},
+	{0x01b4, 0x0000},
+	{0x01b5, 0x0000},
+	{0x01b6, 0x01c3},
+	{0x01b7, 0x02a0},
+	{0x01b8, 0x03e9},
+	{0x01b9, 0x1389},
+	{0x01ba, 0xc351},
+	{0x01bb, 0x0009},
+	{0x01bc, 0x0018},
+	{0x01bd, 0x002a},
+	{0x01be, 0x004c},
+	{0x01bf, 0x0097},
+	{0x01c0, 0x433d},
+	{0x01c1, 0x2800},
+	{0x01c2, 0x0000},
+	{0x01c3, 0x0000},
+	{0x01c4, 0x0000},
+	{0x01c5, 0x0000},
+	{0x01c6, 0x0000},
+	{0x01c7, 0x0000},
+	{0x01c8, 0x40af},
+	{0x01c9, 0x0702},
+	{0x01ca, 0x0000},
+	{0x01cb, 0x0000},
+	{0x01cc, 0x5757},
+	{0x01cd, 0x5757},
+	{0x01ce, 0x5757},
+	{0x01cf, 0x5757},
+	{0x01d0, 0x5757},
+	{0x01d1, 0x5757},
+	{0x01d2, 0x5757},
+	{0x01d3, 0x5757},
+	{0x01d4, 0x5757},
+	{0x01d5, 0x5757},
+	{0x01d6, 0x0000},
+	{0x01d7, 0x0008},
+	{0x01d8, 0x0029},
+	{0x01d9, 0x3333},
+	{0x01da, 0x0000},
+	{0x01db, 0x0004},
+	{0x01dc, 0x0000},
+	{0x01de, 0x7c00},
+	{0x01df, 0x0320},
+	{0x01e0, 0x06a1},
+	{0x01e1, 0x0000},
+	{0x01e2, 0x0000},
+	{0x01e3, 0x0000},
+	{0x01e4, 0x0000},
+	{0x01e6, 0x0001},
+	{0x01e7, 0x0000},
+	{0x01e8, 0x0000},
+	{0x01ea, 0x0000},
+	{0x01eb, 0x0000},
+	{0x01ec, 0x0000},
+	{0x01ed, 0x0000},
+	{0x01ee, 0x0000},
+	{0x01ef, 0x0000},
+	{0x01f0, 0x0000},
+	{0x01f1, 0x0000},
+	{0x01f2, 0x0000},
+	{0x01f3, 0x0000},
+	{0x01f4, 0x0000},
+	{0x0210, 0x6297},
+	{0x0211, 0xa005},
+	{0x0212, 0x824c},
+	{0x0213, 0xf7ff},
+	{0x0214, 0xf24c},
+	{0x0215, 0x0102},
+	{0x0216, 0x00a3},
+	{0x0217, 0x0048},
+	{0x0218, 0xa2c0},
+	{0x0219, 0x0400},
+	{0x021a, 0x00c8},
+	{0x021b, 0x00c0},
+	{0x021c, 0x0000},
+	{0x0250, 0x4500},
+	{0x0251, 0x40b3},
+	{0x0252, 0x0000},
+	{0x0253, 0x0000},
+	{0x0254, 0x0000},
+	{0x0255, 0x0000},
+	{0x0256, 0x0000},
+	{0x0257, 0x0000},
+	{0x0258, 0x0000},
+	{0x0259, 0x0000},
+	{0x025a, 0x0005},
+	{0x0270, 0x0000},
+	{0x02ff, 0x0110},
+	{0x0300, 0x001f},
+	{0x0301, 0x032c},
+	{0x0302, 0x5f21},
+	{0x0303, 0x4000},
+	{0x0304, 0x4000},
+	{0x0305, 0x06d5},
+	{0x0306, 0x8000},
+	{0x0307, 0x0700},
+	{0x0310, 0x4560},
+	{0x0311, 0xa4a8},
+	{0x0312, 0x7418},
+	{0x0313, 0x0000},
+	{0x0314, 0x0006},
+	{0x0315, 0xffff},
+	{0x0316, 0xc400},
+	{0x0317, 0x0000},
+	{0x03c0, 0x7e00},
+	{0x03c1, 0x8000},
+	{0x03c2, 0x8000},
+	{0x03c3, 0x8000},
+	{0x03c4, 0x8000},
+	{0x03c5, 0x8000},
+	{0x03c6, 0x8000},
+	{0x03c7, 0x8000},
+	{0x03c8, 0x8000},
+	{0x03c9, 0x8000},
+	{0x03ca, 0x8000},
+	{0x03cb, 0x8000},
+	{0x03cc, 0x8000},
+	{0x03d0, 0x0000},
+	{0x03d1, 0x0000},
+	{0x03d2, 0x0000},
+	{0x03d3, 0x0000},
+	{0x03d4, 0x2000},
+	{0x03d5, 0x2000},
+	{0x03d6, 0x0000},
+	{0x03d7, 0x0000},
+	{0x03d8, 0x2000},
+	{0x03d9, 0x2000},
+	{0x03da, 0x2000},
+	{0x03db, 0x2000},
+	{0x03dc, 0x0000},
+	{0x03dd, 0x0000},
+	{0x03de, 0x0000},
+	{0x03df, 0x2000},
+	{0x03e0, 0x0000},
+	{0x03e1, 0x0000},
+	{0x03e2, 0x0000},
+	{0x03e3, 0x0000},
+	{0x03e4, 0x0000},
+	{0x03e5, 0x0000},
+	{0x03e6, 0x0000},
+	{0x03e7, 0x0000},
+	{0x03e8, 0x0000},
+	{0x03e9, 0x0000},
+	{0x03ea, 0x0000},
+	{0x03eb, 0x0000},
+	{0x03ec, 0x0000},
+	{0x03ed, 0x0000},
+	{0x03ee, 0x0000},
+	{0x03ef, 0x0000},
+	{0x03f0, 0x0800},
+	{0x03f1, 0x0800},
+	{0x03f2, 0x0800},
+	{0x03f3, 0x0800},
+};
+
+static bool rt5668_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5668_RESET:
+	case RT5668_CBJ_CTRL_2:
+	case RT5668_INT_ST_1:
+	case RT5668_4BTN_IL_CMD_1:
+	case RT5668_AJD1_CTRL:
+	case RT5668_HP_CALIB_CTRL_1:
+	case RT5668_DEVICE_ID:
+	case RT5668_I2C_MODE:
+	case RT5668_HP_CALIB_CTRL_10:
+	case RT5668_EFUSE_CTRL_2:
+	case RT5668_JD_TOP_VC_VTRL:
+	case RT5668_HP_IMP_SENS_CTRL_19:
+	case RT5668_IL_CMD_1:
+	case RT5668_SAR_IL_CMD_2:
+	case RT5668_SAR_IL_CMD_4:
+	case RT5668_SAR_IL_CMD_10:
+	case RT5668_SAR_IL_CMD_11:
+	case RT5668_EFUSE_CTRL_6...RT5668_EFUSE_CTRL_11:
+	case RT5668_HP_CALIB_STA_1...RT5668_HP_CALIB_STA_11:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5668_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5668_RESET:
+	case RT5668_VERSION_ID:
+	case RT5668_VENDOR_ID:
+	case RT5668_DEVICE_ID:
+	case RT5668_HP_CTRL_1:
+	case RT5668_HP_CTRL_2:
+	case RT5668_HPL_GAIN:
+	case RT5668_HPR_GAIN:
+	case RT5668_I2C_CTRL:
+	case RT5668_CBJ_BST_CTRL:
+	case RT5668_CBJ_CTRL_1:
+	case RT5668_CBJ_CTRL_2:
+	case RT5668_CBJ_CTRL_3:
+	case RT5668_CBJ_CTRL_4:
+	case RT5668_CBJ_CTRL_5:
+	case RT5668_CBJ_CTRL_6:
+	case RT5668_CBJ_CTRL_7:
+	case RT5668_DAC1_DIG_VOL:
+	case RT5668_STO1_ADC_DIG_VOL:
+	case RT5668_STO1_ADC_BOOST:
+	case RT5668_HP_IMP_GAIN_1:
+	case RT5668_HP_IMP_GAIN_2:
+	case RT5668_SIDETONE_CTRL:
+	case RT5668_STO1_ADC_MIXER:
+	case RT5668_AD_DA_MIXER:
+	case RT5668_STO1_DAC_MIXER:
+	case RT5668_A_DAC1_MUX:
+	case RT5668_DIG_INF2_DATA:
+	case RT5668_REC_MIXER:
+	case RT5668_CAL_REC:
+	case RT5668_ALC_BACK_GAIN:
+	case RT5668_PWR_DIG_1:
+	case RT5668_PWR_DIG_2:
+	case RT5668_PWR_ANLG_1:
+	case RT5668_PWR_ANLG_2:
+	case RT5668_PWR_ANLG_3:
+	case RT5668_PWR_MIXER:
+	case RT5668_PWR_VOL:
+	case RT5668_CLK_DET:
+	case RT5668_RESET_LPF_CTRL:
+	case RT5668_RESET_HPF_CTRL:
+	case RT5668_DMIC_CTRL_1:
+	case RT5668_I2S1_SDP:
+	case RT5668_I2S2_SDP:
+	case RT5668_ADDA_CLK_1:
+	case RT5668_ADDA_CLK_2:
+	case RT5668_I2S1_F_DIV_CTRL_1:
+	case RT5668_I2S1_F_DIV_CTRL_2:
+	case RT5668_TDM_CTRL:
+	case RT5668_TDM_ADDA_CTRL_1:
+	case RT5668_TDM_ADDA_CTRL_2:
+	case RT5668_DATA_SEL_CTRL_1:
+	case RT5668_TDM_TCON_CTRL:
+	case RT5668_GLB_CLK:
+	case RT5668_PLL_CTRL_1:
+	case RT5668_PLL_CTRL_2:
+	case RT5668_PLL_TRACK_1:
+	case RT5668_PLL_TRACK_2:
+	case RT5668_PLL_TRACK_3:
+	case RT5668_PLL_TRACK_4:
+	case RT5668_PLL_TRACK_5:
+	case RT5668_PLL_TRACK_6:
+	case RT5668_PLL_TRACK_11:
+	case RT5668_SDW_REF_CLK:
+	case RT5668_DEPOP_1:
+	case RT5668_DEPOP_2:
+	case RT5668_HP_CHARGE_PUMP_1:
+	case RT5668_HP_CHARGE_PUMP_2:
+	case RT5668_MICBIAS_1:
+	case RT5668_MICBIAS_2:
+	case RT5668_PLL_TRACK_12:
+	case RT5668_PLL_TRACK_14:
+	case RT5668_PLL2_CTRL_1:
+	case RT5668_PLL2_CTRL_2:
+	case RT5668_PLL2_CTRL_3:
+	case RT5668_PLL2_CTRL_4:
+	case RT5668_RC_CLK_CTRL:
+	case RT5668_I2S_M_CLK_CTRL_1:
+	case RT5668_I2S2_F_DIV_CTRL_1:
+	case RT5668_I2S2_F_DIV_CTRL_2:
+	case RT5668_EQ_CTRL_1:
+	case RT5668_EQ_CTRL_2:
+	case RT5668_IRQ_CTRL_1:
+	case RT5668_IRQ_CTRL_2:
+	case RT5668_IRQ_CTRL_3:
+	case RT5668_IRQ_CTRL_4:
+	case RT5668_INT_ST_1:
+	case RT5668_GPIO_CTRL_1:
+	case RT5668_GPIO_CTRL_2:
+	case RT5668_GPIO_CTRL_3:
+	case RT5668_HP_AMP_DET_CTRL_1:
+	case RT5668_HP_AMP_DET_CTRL_2:
+	case RT5668_MID_HP_AMP_DET:
+	case RT5668_LOW_HP_AMP_DET:
+	case RT5668_DELAY_BUF_CTRL:
+	case RT5668_SV_ZCD_1:
+	case RT5668_SV_ZCD_2:
+	case RT5668_IL_CMD_1:
+	case RT5668_IL_CMD_2:
+	case RT5668_IL_CMD_3:
+	case RT5668_IL_CMD_4:
+	case RT5668_IL_CMD_5:
+	case RT5668_IL_CMD_6:
+	case RT5668_4BTN_IL_CMD_1:
+	case RT5668_4BTN_IL_CMD_2:
+	case RT5668_4BTN_IL_CMD_3:
+	case RT5668_4BTN_IL_CMD_4:
+	case RT5668_4BTN_IL_CMD_5:
+	case RT5668_4BTN_IL_CMD_6:
+	case RT5668_4BTN_IL_CMD_7:
+	case RT5668_ADC_STO1_HP_CTRL_1:
+	case RT5668_ADC_STO1_HP_CTRL_2:
+	case RT5668_AJD1_CTRL:
+	case RT5668_JD1_THD:
+	case RT5668_JD2_THD:
+	case RT5668_JD_CTRL_1:
+	case RT5668_DUMMY_1:
+	case RT5668_DUMMY_2:
+	case RT5668_DUMMY_3:
+	case RT5668_DAC_ADC_DIG_VOL1:
+	case RT5668_BIAS_CUR_CTRL_2:
+	case RT5668_BIAS_CUR_CTRL_3:
+	case RT5668_BIAS_CUR_CTRL_4:
+	case RT5668_BIAS_CUR_CTRL_5:
+	case RT5668_BIAS_CUR_CTRL_6:
+	case RT5668_BIAS_CUR_CTRL_7:
+	case RT5668_BIAS_CUR_CTRL_8:
+	case RT5668_BIAS_CUR_CTRL_9:
+	case RT5668_BIAS_CUR_CTRL_10:
+	case RT5668_VREF_REC_OP_FB_CAP_CTRL:
+	case RT5668_CHARGE_PUMP_1:
+	case RT5668_DIG_IN_CTRL_1:
+	case RT5668_PAD_DRIVING_CTRL:
+	case RT5668_SOFT_RAMP_DEPOP:
+	case RT5668_CHOP_DAC:
+	case RT5668_CHOP_ADC:
+	case RT5668_CALIB_ADC_CTRL:
+	case RT5668_VOL_TEST:
+	case RT5668_SPKVDD_DET_STA:
+	case RT5668_TEST_MODE_CTRL_1:
+	case RT5668_TEST_MODE_CTRL_2:
+	case RT5668_TEST_MODE_CTRL_3:
+	case RT5668_TEST_MODE_CTRL_4:
+	case RT5668_TEST_MODE_CTRL_5:
+	case RT5668_PLL1_INTERNAL:
+	case RT5668_PLL2_INTERNAL:
+	case RT5668_STO_NG2_CTRL_1:
+	case RT5668_STO_NG2_CTRL_2:
+	case RT5668_STO_NG2_CTRL_3:
+	case RT5668_STO_NG2_CTRL_4:
+	case RT5668_STO_NG2_CTRL_5:
+	case RT5668_STO_NG2_CTRL_6:
+	case RT5668_STO_NG2_CTRL_7:
+	case RT5668_STO_NG2_CTRL_8:
+	case RT5668_STO_NG2_CTRL_9:
+	case RT5668_STO_NG2_CTRL_10:
+	case RT5668_STO1_DAC_SIL_DET:
+	case RT5668_SIL_PSV_CTRL1:
+	case RT5668_SIL_PSV_CTRL2:
+	case RT5668_SIL_PSV_CTRL3:
+	case RT5668_SIL_PSV_CTRL4:
+	case RT5668_SIL_PSV_CTRL5:
+	case RT5668_HP_IMP_SENS_CTRL_01:
+	case RT5668_HP_IMP_SENS_CTRL_02:
+	case RT5668_HP_IMP_SENS_CTRL_03:
+	case RT5668_HP_IMP_SENS_CTRL_04:
+	case RT5668_HP_IMP_SENS_CTRL_05:
+	case RT5668_HP_IMP_SENS_CTRL_06:
+	case RT5668_HP_IMP_SENS_CTRL_07:
+	case RT5668_HP_IMP_SENS_CTRL_08:
+	case RT5668_HP_IMP_SENS_CTRL_09:
+	case RT5668_HP_IMP_SENS_CTRL_10:
+	case RT5668_HP_IMP_SENS_CTRL_11:
+	case RT5668_HP_IMP_SENS_CTRL_12:
+	case RT5668_HP_IMP_SENS_CTRL_13:
+	case RT5668_HP_IMP_SENS_CTRL_14:
+	case RT5668_HP_IMP_SENS_CTRL_15:
+	case RT5668_HP_IMP_SENS_CTRL_16:
+	case RT5668_HP_IMP_SENS_CTRL_17:
+	case RT5668_HP_IMP_SENS_CTRL_18:
+	case RT5668_HP_IMP_SENS_CTRL_19:
+	case RT5668_HP_IMP_SENS_CTRL_20:
+	case RT5668_HP_IMP_SENS_CTRL_21:
+	case RT5668_HP_IMP_SENS_CTRL_22:
+	case RT5668_HP_IMP_SENS_CTRL_23:
+	case RT5668_HP_IMP_SENS_CTRL_24:
+	case RT5668_HP_IMP_SENS_CTRL_25:
+	case RT5668_HP_IMP_SENS_CTRL_26:
+	case RT5668_HP_IMP_SENS_CTRL_27:
+	case RT5668_HP_IMP_SENS_CTRL_28:
+	case RT5668_HP_IMP_SENS_CTRL_29:
+	case RT5668_HP_IMP_SENS_CTRL_30:
+	case RT5668_HP_IMP_SENS_CTRL_31:
+	case RT5668_HP_IMP_SENS_CTRL_32:
+	case RT5668_HP_IMP_SENS_CTRL_33:
+	case RT5668_HP_IMP_SENS_CTRL_34:
+	case RT5668_HP_IMP_SENS_CTRL_35:
+	case RT5668_HP_IMP_SENS_CTRL_36:
+	case RT5668_HP_IMP_SENS_CTRL_37:
+	case RT5668_HP_IMP_SENS_CTRL_38:
+	case RT5668_HP_IMP_SENS_CTRL_39:
+	case RT5668_HP_IMP_SENS_CTRL_40:
+	case RT5668_HP_IMP_SENS_CTRL_41:
+	case RT5668_HP_IMP_SENS_CTRL_42:
+	case RT5668_HP_IMP_SENS_CTRL_43:
+	case RT5668_HP_LOGIC_CTRL_1:
+	case RT5668_HP_LOGIC_CTRL_2:
+	case RT5668_HP_LOGIC_CTRL_3:
+	case RT5668_HP_CALIB_CTRL_1:
+	case RT5668_HP_CALIB_CTRL_2:
+	case RT5668_HP_CALIB_CTRL_3:
+	case RT5668_HP_CALIB_CTRL_4:
+	case RT5668_HP_CALIB_CTRL_5:
+	case RT5668_HP_CALIB_CTRL_6:
+	case RT5668_HP_CALIB_CTRL_7:
+	case RT5668_HP_CALIB_CTRL_9:
+	case RT5668_HP_CALIB_CTRL_10:
+	case RT5668_HP_CALIB_CTRL_11:
+	case RT5668_HP_CALIB_STA_1:
+	case RT5668_HP_CALIB_STA_2:
+	case RT5668_HP_CALIB_STA_3:
+	case RT5668_HP_CALIB_STA_4:
+	case RT5668_HP_CALIB_STA_5:
+	case RT5668_HP_CALIB_STA_6:
+	case RT5668_HP_CALIB_STA_7:
+	case RT5668_HP_CALIB_STA_8:
+	case RT5668_HP_CALIB_STA_9:
+	case RT5668_HP_CALIB_STA_10:
+	case RT5668_HP_CALIB_STA_11:
+	case RT5668_SAR_IL_CMD_1:
+	case RT5668_SAR_IL_CMD_2:
+	case RT5668_SAR_IL_CMD_3:
+	case RT5668_SAR_IL_CMD_4:
+	case RT5668_SAR_IL_CMD_5:
+	case RT5668_SAR_IL_CMD_6:
+	case RT5668_SAR_IL_CMD_7:
+	case RT5668_SAR_IL_CMD_8:
+	case RT5668_SAR_IL_CMD_9:
+	case RT5668_SAR_IL_CMD_10:
+	case RT5668_SAR_IL_CMD_11:
+	case RT5668_SAR_IL_CMD_12:
+	case RT5668_SAR_IL_CMD_13:
+	case RT5668_EFUSE_CTRL_1:
+	case RT5668_EFUSE_CTRL_2:
+	case RT5668_EFUSE_CTRL_3:
+	case RT5668_EFUSE_CTRL_4:
+	case RT5668_EFUSE_CTRL_5:
+	case RT5668_EFUSE_CTRL_6:
+	case RT5668_EFUSE_CTRL_7:
+	case RT5668_EFUSE_CTRL_8:
+	case RT5668_EFUSE_CTRL_9:
+	case RT5668_EFUSE_CTRL_10:
+	case RT5668_EFUSE_CTRL_11:
+	case RT5668_JD_TOP_VC_VTRL:
+	case RT5668_DRC1_CTRL_0:
+	case RT5668_DRC1_CTRL_1:
+	case RT5668_DRC1_CTRL_2:
+	case RT5668_DRC1_CTRL_3:
+	case RT5668_DRC1_CTRL_4:
+	case RT5668_DRC1_CTRL_5:
+	case RT5668_DRC1_CTRL_6:
+	case RT5668_DRC1_HARD_LMT_CTRL_1:
+	case RT5668_DRC1_HARD_LMT_CTRL_2:
+	case RT5668_DRC1_PRIV_1:
+	case RT5668_DRC1_PRIV_2:
+	case RT5668_DRC1_PRIV_3:
+	case RT5668_DRC1_PRIV_4:
+	case RT5668_DRC1_PRIV_5:
+	case RT5668_DRC1_PRIV_6:
+	case RT5668_DRC1_PRIV_7:
+	case RT5668_DRC1_PRIV_8:
+	case RT5668_EQ_AUTO_RCV_CTRL1:
+	case RT5668_EQ_AUTO_RCV_CTRL2:
+	case RT5668_EQ_AUTO_RCV_CTRL3:
+	case RT5668_EQ_AUTO_RCV_CTRL4:
+	case RT5668_EQ_AUTO_RCV_CTRL5:
+	case RT5668_EQ_AUTO_RCV_CTRL6:
+	case RT5668_EQ_AUTO_RCV_CTRL7:
+	case RT5668_EQ_AUTO_RCV_CTRL8:
+	case RT5668_EQ_AUTO_RCV_CTRL9:
+	case RT5668_EQ_AUTO_RCV_CTRL10:
+	case RT5668_EQ_AUTO_RCV_CTRL11:
+	case RT5668_EQ_AUTO_RCV_CTRL12:
+	case RT5668_EQ_AUTO_RCV_CTRL13:
+	case RT5668_ADC_L_EQ_LPF1_A1:
+	case RT5668_R_EQ_LPF1_A1:
+	case RT5668_L_EQ_LPF1_H0:
+	case RT5668_R_EQ_LPF1_H0:
+	case RT5668_L_EQ_BPF1_A1:
+	case RT5668_R_EQ_BPF1_A1:
+	case RT5668_L_EQ_BPF1_A2:
+	case RT5668_R_EQ_BPF1_A2:
+	case RT5668_L_EQ_BPF1_H0:
+	case RT5668_R_EQ_BPF1_H0:
+	case RT5668_L_EQ_BPF2_A1:
+	case RT5668_R_EQ_BPF2_A1:
+	case RT5668_L_EQ_BPF2_A2:
+	case RT5668_R_EQ_BPF2_A2:
+	case RT5668_L_EQ_BPF2_H0:
+	case RT5668_R_EQ_BPF2_H0:
+	case RT5668_L_EQ_BPF3_A1:
+	case RT5668_R_EQ_BPF3_A1:
+	case RT5668_L_EQ_BPF3_A2:
+	case RT5668_R_EQ_BPF3_A2:
+	case RT5668_L_EQ_BPF3_H0:
+	case RT5668_R_EQ_BPF3_H0:
+	case RT5668_L_EQ_BPF4_A1:
+	case RT5668_R_EQ_BPF4_A1:
+	case RT5668_L_EQ_BPF4_A2:
+	case RT5668_R_EQ_BPF4_A2:
+	case RT5668_L_EQ_BPF4_H0:
+	case RT5668_R_EQ_BPF4_H0:
+	case RT5668_L_EQ_HPF1_A1:
+	case RT5668_R_EQ_HPF1_A1:
+	case RT5668_L_EQ_HPF1_H0:
+	case RT5668_R_EQ_HPF1_H0:
+	case RT5668_L_EQ_PRE_VOL:
+	case RT5668_R_EQ_PRE_VOL:
+	case RT5668_L_EQ_POST_VOL:
+	case RT5668_R_EQ_POST_VOL:
+	case RT5668_I2C_MODE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5668_data_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5668_if2_adc_enum,
+	RT5668_DIG_INF2_DATA, RT5668_IF2_ADC_SEL_SFT, rt5668_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5668_if1_01_adc_enum,
+	RT5668_TDM_ADDA_CTRL_1, RT5668_IF1_ADC1_SEL_SFT, rt5668_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5668_if1_23_adc_enum,
+	RT5668_TDM_ADDA_CTRL_1, RT5668_IF1_ADC2_SEL_SFT, rt5668_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5668_if1_45_adc_enum,
+	RT5668_TDM_ADDA_CTRL_1, RT5668_IF1_ADC3_SEL_SFT, rt5668_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5668_if1_67_adc_enum,
+	RT5668_TDM_ADDA_CTRL_1, RT5668_IF1_ADC4_SEL_SFT, rt5668_data_select);
+
+static const struct snd_kcontrol_new rt5668_if2_adc_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC Swap Mux", rt5668_if2_adc_enum);
+
+static const struct snd_kcontrol_new rt5668_if1_01_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 01 ADC Swap Mux", rt5668_if1_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5668_if1_23_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 23 ADC Swap Mux", rt5668_if1_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5668_if1_45_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 45 ADC Swap Mux", rt5668_if1_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5668_if1_67_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 67 ADC Swap Mux", rt5668_if1_67_adc_enum);
+
+static void rt5668_reset(struct regmap *regmap)
+{
+	regmap_write(regmap, RT5668_RESET, 0);
+	regmap_write(regmap, RT5668_I2C_MODE, 1);
+}
+/**
+ * rt5668_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @component: SoC audio component device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5668 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the component driver will turn on
+ * ASRC for these filters if ASRC is selected as their clock source.
+ */
+int rt5668_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src)
+{
+
+	switch (clk_src) {
+	case RT5668_CLK_SEL_SYS:
+	case RT5668_CLK_SEL_I2S1_ASRC:
+	case RT5668_CLK_SEL_I2S2_ASRC:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (filter_mask & RT5668_DA_STEREO1_FILTER) {
+		snd_soc_component_update_bits(component, RT5668_PLL_TRACK_2,
+			RT5668_FILTER_CLK_SEL_MASK,
+			clk_src << RT5668_FILTER_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5668_AD_STEREO1_FILTER) {
+		snd_soc_component_update_bits(component, RT5668_PLL_TRACK_3,
+			RT5668_FILTER_CLK_SEL_MASK,
+			clk_src << RT5668_FILTER_CLK_SEL_SFT);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5668_sel_asrc_clk_src);
+
+static int rt5668_button_detect(struct snd_soc_component *component)
+{
+	int btn_type, val;
+
+	val = snd_soc_component_read32(component, RT5668_4BTN_IL_CMD_1);
+	btn_type = val & 0xfff0;
+	snd_soc_component_write(component, RT5668_4BTN_IL_CMD_1, val);
+	pr_debug("%s btn_type=%x\n", __func__, btn_type);
+
+	return btn_type;
+}
+
+static void rt5668_enable_push_button_irq(struct snd_soc_component *component,
+		bool enable)
+{
+	if (enable) {
+		snd_soc_component_update_bits(component, RT5668_SAR_IL_CMD_1,
+			RT5668_SAR_BUTT_DET_MASK, RT5668_SAR_BUTT_DET_EN);
+		snd_soc_component_update_bits(component, RT5668_SAR_IL_CMD_13,
+			RT5668_SAR_SOUR_MASK, RT5668_SAR_SOUR_BTN);
+		snd_soc_component_write(component, RT5668_IL_CMD_1, 0x0040);
+		snd_soc_component_update_bits(component, RT5668_4BTN_IL_CMD_2,
+			RT5668_4BTN_IL_MASK | RT5668_4BTN_IL_RST_MASK,
+			RT5668_4BTN_IL_EN | RT5668_4BTN_IL_NOR);
+		snd_soc_component_update_bits(component, RT5668_IRQ_CTRL_3,
+			RT5668_IL_IRQ_MASK, RT5668_IL_IRQ_EN);
+	} else {
+		snd_soc_component_update_bits(component, RT5668_IRQ_CTRL_3,
+			RT5668_IL_IRQ_MASK, RT5668_IL_IRQ_DIS);
+		snd_soc_component_update_bits(component, RT5668_SAR_IL_CMD_1,
+			RT5668_SAR_BUTT_DET_MASK, RT5668_SAR_BUTT_DET_DIS);
+		snd_soc_component_update_bits(component, RT5668_4BTN_IL_CMD_2,
+			RT5668_4BTN_IL_MASK, RT5668_4BTN_IL_DIS);
+		snd_soc_component_update_bits(component, RT5668_4BTN_IL_CMD_2,
+			RT5668_4BTN_IL_RST_MASK, RT5668_4BTN_IL_RST);
+		snd_soc_component_update_bits(component, RT5668_SAR_IL_CMD_13,
+			RT5668_SAR_SOUR_MASK, RT5668_SAR_SOUR_TYPE);
+	}
+}
+
+/**
+ * rt5668_headset_detect - Detect headset.
+ * @component: SoC audio component device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+static int rt5668_headset_detect(struct snd_soc_component *component,
+		int jack_insert)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_component_get_dapm(component);
+	unsigned int val, count;
+
+	if (jack_insert) {
+		snd_soc_dapm_force_enable_pin(dapm, "CBJ Power");
+		snd_soc_dapm_sync(dapm);
+		snd_soc_component_update_bits(component, RT5668_CBJ_CTRL_1,
+			RT5668_TRIG_JD_MASK, RT5668_TRIG_JD_HIGH);
+
+		count = 0;
+		val = snd_soc_component_read32(component, RT5668_CBJ_CTRL_2)
+			& RT5668_JACK_TYPE_MASK;
+		while (val == 0 && count < 50) {
+			usleep_range(10000, 15000);
+			val = snd_soc_component_read32(component,
+				RT5668_CBJ_CTRL_2) & RT5668_JACK_TYPE_MASK;
+			count++;
+		}
+
+		switch (val) {
+		case 0x1:
+		case 0x2:
+			rt5668->jack_type = SND_JACK_HEADSET;
+			rt5668_enable_push_button_irq(component, true);
+			break;
+		default:
+			rt5668->jack_type = SND_JACK_HEADPHONE;
+		}
+
+	} else {
+		rt5668_enable_push_button_irq(component, false);
+		snd_soc_component_update_bits(component, RT5668_CBJ_CTRL_1,
+			RT5668_TRIG_JD_MASK, RT5668_TRIG_JD_LOW);
+		snd_soc_dapm_disable_pin(dapm, "CBJ Power");
+		snd_soc_dapm_sync(dapm);
+
+		rt5668->jack_type = 0;
+	}
+
+	dev_dbg(component->dev, "jack_type = %d\n", rt5668->jack_type);
+	return rt5668->jack_type;
+}
+
+static irqreturn_t rt5668_irq(int irq, void *data)
+{
+	struct rt5668_priv *rt5668 = data;
+
+	mod_delayed_work(system_power_efficient_wq,
+			&rt5668->jack_detect_work, msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+static void rt5668_jd_check_handler(struct work_struct *work)
+{
+	struct rt5668_priv *rt5668 = container_of(work, struct rt5668_priv,
+		jd_check_work.work);
+
+	if (snd_soc_component_read32(rt5668->component, RT5668_AJD1_CTRL)
+		& RT5668_JDH_RS_MASK) {
+		/* jack out */
+		rt5668->jack_type = rt5668_headset_detect(rt5668->component, 0);
+
+		snd_soc_jack_report(rt5668->hs_jack, rt5668->jack_type,
+				SND_JACK_HEADSET |
+				SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				SND_JACK_BTN_2 | SND_JACK_BTN_3);
+	} else {
+		schedule_delayed_work(&rt5668->jd_check_work, 500);
+	}
+}
+
+static int rt5668_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hs_jack, void *data)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	switch (rt5668->pdata.jd_src) {
+	case RT5668_JD1:
+		snd_soc_component_update_bits(component, RT5668_CBJ_CTRL_2,
+			RT5668_EXT_JD_SRC, RT5668_EXT_JD_SRC_MANUAL);
+		snd_soc_component_write(component, RT5668_CBJ_CTRL_1, 0xd002);
+		snd_soc_component_update_bits(component, RT5668_CBJ_CTRL_3,
+			RT5668_CBJ_IN_BUF_EN, RT5668_CBJ_IN_BUF_EN);
+		snd_soc_component_update_bits(component, RT5668_SAR_IL_CMD_1,
+			RT5668_SAR_POW_MASK, RT5668_SAR_POW_EN);
+		regmap_update_bits(rt5668->regmap, RT5668_GPIO_CTRL_1,
+			RT5668_GP1_PIN_MASK, RT5668_GP1_PIN_IRQ);
+		regmap_update_bits(rt5668->regmap, RT5668_RC_CLK_CTRL,
+				RT5668_POW_IRQ | RT5668_POW_JDH |
+				RT5668_POW_ANA, RT5668_POW_IRQ |
+				RT5668_POW_JDH | RT5668_POW_ANA);
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_ANLG_2,
+			RT5668_PWR_JDH | RT5668_PWR_JDL,
+			RT5668_PWR_JDH | RT5668_PWR_JDL);
+		regmap_update_bits(rt5668->regmap, RT5668_IRQ_CTRL_2,
+			RT5668_JD1_EN_MASK | RT5668_JD1_POL_MASK,
+			RT5668_JD1_EN | RT5668_JD1_POL_NOR);
+		mod_delayed_work(system_power_efficient_wq,
+			   &rt5668->jack_detect_work, msecs_to_jiffies(250));
+		break;
+
+	case RT5668_JD_NULL:
+		regmap_update_bits(rt5668->regmap, RT5668_IRQ_CTRL_2,
+			RT5668_JD1_EN_MASK, RT5668_JD1_DIS);
+		regmap_update_bits(rt5668->regmap, RT5668_RC_CLK_CTRL,
+				RT5668_POW_JDH | RT5668_POW_JDL, 0);
+		break;
+
+	default:
+		dev_warn(component->dev, "Wrong JD source\n");
+		break;
+	}
+
+	rt5668->hs_jack = hs_jack;
+
+	return 0;
+}
+
+static void rt5668_jack_detect_handler(struct work_struct *work)
+{
+	struct rt5668_priv *rt5668 =
+		container_of(work, struct rt5668_priv, jack_detect_work.work);
+	int val, btn_type;
+
+	while (!rt5668->component)
+		usleep_range(10000, 15000);
+
+	while (!rt5668->component->card->instantiated)
+		usleep_range(10000, 15000);
+
+	mutex_lock(&rt5668->calibrate_mutex);
+
+	val = snd_soc_component_read32(rt5668->component, RT5668_AJD1_CTRL)
+		& RT5668_JDH_RS_MASK;
+	if (!val) {
+		/* jack in */
+		if (rt5668->jack_type == 0) {
+			/* jack was out, report jack type */
+			rt5668->jack_type =
+				rt5668_headset_detect(rt5668->component, 1);
+		} else {
+			/* jack is already in, report button event */
+			rt5668->jack_type = SND_JACK_HEADSET;
+			btn_type = rt5668_button_detect(rt5668->component);
+			/**
+			 * rt5668 can report three kinds of button behavior,
+			 * one click, double click and hold. However,
+			 * currently we will report button pressed/released
+			 * event. So all the three button behaviors are
+			 * treated as button pressed.
+			 */
+			switch (btn_type) {
+			case 0x8000:
+			case 0x4000:
+			case 0x2000:
+				rt5668->jack_type |= SND_JACK_BTN_0;
+				break;
+			case 0x1000:
+			case 0x0800:
+			case 0x0400:
+				rt5668->jack_type |= SND_JACK_BTN_1;
+				break;
+			case 0x0200:
+			case 0x0100:
+			case 0x0080:
+				rt5668->jack_type |= SND_JACK_BTN_2;
+				break;
+			case 0x0040:
+			case 0x0020:
+			case 0x0010:
+				rt5668->jack_type |= SND_JACK_BTN_3;
+				break;
+			case 0x0000: /* unpressed */
+				break;
+			default:
+				btn_type = 0;
+				dev_err(rt5668->component->dev,
+					"Unexpected button code 0x%04x\n",
+					btn_type);
+				break;
+			}
+		}
+	} else {
+		/* jack out */
+		rt5668->jack_type = rt5668_headset_detect(rt5668->component, 0);
+	}
+
+	snd_soc_jack_report(rt5668->hs_jack, rt5668->jack_type,
+			SND_JACK_HEADSET |
+			    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			    SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+	if (rt5668->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+		SND_JACK_BTN_2 | SND_JACK_BTN_3))
+		schedule_delayed_work(&rt5668->jd_check_work, 0);
+	else
+		cancel_delayed_work_sync(&rt5668->jd_check_work);
+
+	mutex_unlock(&rt5668->calibrate_mutex);
+}
+
+static const struct snd_kcontrol_new rt5668_snd_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5668_HPL_GAIN,
+		RT5668_HPR_GAIN, RT5668_G_HP_SFT, 15, 1, hp_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5668_DAC1_DIG_VOL,
+		RT5668_L_VOL_SFT, RT5668_R_VOL_SFT, 175, 0, dac_vol_tlv),
+
+	/* IN Boost Volume */
+	SOC_SINGLE_TLV("CBJ Boost Volume", RT5668_CBJ_BST_CTRL,
+		RT5668_BST_CBJ_SFT, 8, 0, bst_tlv),
+
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("STO1 ADC Capture Switch", RT5668_STO1_ADC_DIG_VOL,
+		RT5668_L_MUTE_SFT, RT5668_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5668_STO1_ADC_DIG_VOL,
+		RT5668_L_VOL_SFT, RT5668_R_VOL_SFT, 127, 0, adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5668_STO1_ADC_BOOST,
+		RT5668_STO1_ADC_L_BST_SFT, RT5668_STO1_ADC_R_BST_SFT,
+		3, 0, adc_bst_tlv),
+};
+
+
+static int rt5668_div_sel(struct rt5668_priv *rt5668,
+			  int target, const int div[], int size)
+{
+	int i;
+
+	if (rt5668->sysclk < target) {
+		pr_err("sysclk rate %d is too low\n",
+			rt5668->sysclk);
+		return 0;
+	}
+
+	for (i = 0; i < size - 1; i++) {
+		pr_info("div[%d]=%d\n", i, div[i]);
+		if (target * div[i] == rt5668->sysclk)
+			return i;
+		if (target * div[i + 1] > rt5668->sysclk) {
+			pr_err("can't find div for sysclk %d\n",
+				rt5668->sysclk);
+			return i;
+		}
+	}
+
+	if (target * div[i] < rt5668->sysclk)
+		pr_err("sysclk rate %d is too high\n",
+			rt5668->sysclk);
+
+	return size - 1;
+
+}
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(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 rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	int idx = -EINVAL;
+	static const int div[] = {2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128};
+
+	idx = rt5668_div_sel(rt5668, 1500000, div, ARRAY_SIZE(div));
+
+	snd_soc_component_update_bits(component, RT5668_DMIC_CTRL_1,
+		RT5668_DMIC_CLK_MASK, idx << RT5668_DMIC_CLK_SFT);
+
+	return 0;
+}
+
+static int set_filter_clk(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 rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	int ref, val, reg, idx = -EINVAL;
+	static const int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48};
+
+	val = snd_soc_component_read32(component, RT5668_GPIO_CTRL_1) &
+		RT5668_GP4_PIN_MASK;
+	if (w->shift == RT5668_PWR_ADC_S1F_BIT &&
+		val == RT5668_GP4_PIN_ADCDAT2)
+		ref = 256 * rt5668->lrck[RT5668_AIF2];
+	else
+		ref = 256 * rt5668->lrck[RT5668_AIF1];
+
+	idx = rt5668_div_sel(rt5668, ref, div, ARRAY_SIZE(div));
+
+	if (w->shift == RT5668_PWR_ADC_S1F_BIT)
+		reg = RT5668_PLL_TRACK_3;
+	else
+		reg = RT5668_PLL_TRACK_2;
+
+	snd_soc_component_update_bits(component, reg,
+		RT5668_FILTER_CLK_SEL_MASK, idx << RT5668_FILTER_CLK_SEL_SFT);
+
+	return 0;
+}
+
+static int is_sys_clk_from_pll1(struct snd_soc_dapm_widget *w,
+			 struct snd_soc_dapm_widget *sink)
+{
+	unsigned int val;
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	val = snd_soc_component_read32(component, RT5668_GLB_CLK);
+	val &= RT5668_SCLK_SRC_MASK;
+	if (val == RT5668_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *w,
+			 struct snd_soc_dapm_widget *sink)
+{
+	unsigned int reg, shift, val;
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	switch (w->shift) {
+	case RT5668_ADC_STO1_ASRC_SFT:
+		reg = RT5668_PLL_TRACK_3;
+		shift = RT5668_FILTER_CLK_SEL_SFT;
+		break;
+	case RT5668_DAC_STO1_ASRC_SFT:
+		reg = RT5668_PLL_TRACK_2;
+		shift = RT5668_FILTER_CLK_SEL_SFT;
+		break;
+	default:
+		return 0;
+	}
+
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
+	switch (val) {
+	case RT5668_CLK_SEL_I2S1_ASRC:
+	case RT5668_CLK_SEL_I2S2_ASRC:
+		return 1;
+	default:
+		return 0;
+	}
+
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5668_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5668_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5668_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5668_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5668_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5668_AD_DA_MIXER,
+			RT5668_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5668_AD_DA_MIXER,
+			RT5668_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5668_AD_DA_MIXER,
+			RT5668_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5668_AD_DA_MIXER,
+			RT5668_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_sto1_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5668_STO1_DAC_MIXER,
+			RT5668_M_DAC_L1_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5668_STO1_DAC_MIXER,
+			RT5668_M_DAC_R1_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_sto1_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5668_STO1_DAC_MIXER,
+			RT5668_M_DAC_L1_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5668_STO1_DAC_MIXER,
+			RT5668_M_DAC_R1_STO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5668_rec1_l_mix[] = {
+	SOC_DAPM_SINGLE("CBJ Switch", RT5668_REC_MIXER,
+			RT5668_M_CBJ_RM1_L_SFT, 1, 1),
+};
+
+/* STO1 ADC1 Source */
+/* MX-26 [13] [5] */
+static const char * const rt5668_sto1_adc1_src[] = {
+	"DAC MIX", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_sto1_adc1l_enum, RT5668_STO1_ADC_MIXER,
+	RT5668_STO1_ADC1L_SRC_SFT, rt5668_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adc1l_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5668_sto1_adc1l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_sto1_adc1r_enum, RT5668_STO1_ADC_MIXER,
+	RT5668_STO1_ADC1R_SRC_SFT, rt5668_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adc1r_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5668_sto1_adc1r_enum);
+
+/* STO1 ADC Source */
+/* MX-26 [11:10] [3:2] */
+static const char * const rt5668_sto1_adc_src[] = {
+	"ADC1 L", "ADC1 R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_sto1_adcl_enum, RT5668_STO1_ADC_MIXER,
+	RT5668_STO1_ADCL_SRC_SFT, rt5668_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adcl_mux =
+	SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5668_sto1_adcl_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_sto1_adcr_enum, RT5668_STO1_ADC_MIXER,
+	RT5668_STO1_ADCR_SRC_SFT, rt5668_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adcr_mux =
+	SOC_DAPM_ENUM("Stereo1 ADCR Source", rt5668_sto1_adcr_enum);
+
+/* STO1 ADC2 Source */
+/* MX-26 [12] [4] */
+static const char * const rt5668_sto1_adc2_src[] = {
+	"DAC MIX", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_sto1_adc2l_enum, RT5668_STO1_ADC_MIXER,
+	RT5668_STO1_ADC2L_SRC_SFT, rt5668_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adc2l_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5668_sto1_adc2l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_sto1_adc2r_enum, RT5668_STO1_ADC_MIXER,
+	RT5668_STO1_ADC2R_SRC_SFT, rt5668_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adc2r_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC2R Source", rt5668_sto1_adc2r_enum);
+
+/* MX-79 [6:4] I2S1 ADC data location */
+static const unsigned int rt5668_if1_adc_slot_values[] = {
+	0,
+	2,
+	4,
+	6,
+};
+
+static const char * const rt5668_if1_adc_slot_src[] = {
+	"Slot 0", "Slot 2", "Slot 4", "Slot 6"
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5668_if1_adc_slot_enum,
+	RT5668_TDM_CTRL, RT5668_TDM_ADC_LCA_SFT, RT5668_TDM_ADC_LCA_MASK,
+	rt5668_if1_adc_slot_src, rt5668_if1_adc_slot_values);
+
+static const struct snd_kcontrol_new rt5668_if1_adc_slot_mux =
+	SOC_DAPM_ENUM("IF1 ADC Slot location", rt5668_if1_adc_slot_enum);
+
+/* Analog DAC L1 Source, Analog DAC R1 Source*/
+/* MX-2B [4], MX-2B [0]*/
+static const char * const rt5668_alg_dac1_src[] = {
+	"Stereo1 DAC Mixer", "DAC1"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_alg_dac_l1_enum, RT5668_A_DAC1_MUX,
+	RT5668_A_DACL1_SFT, rt5668_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5668_alg_dac_l1_mux =
+	SOC_DAPM_ENUM("Analog DAC L1 Source", rt5668_alg_dac_l1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_alg_dac_r1_enum, RT5668_A_DAC1_MUX,
+	RT5668_A_DACR1_SFT, rt5668_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5668_alg_dac_r1_mux =
+	SOC_DAPM_ENUM("Analog DAC R1 Source", rt5668_alg_dac_r1_enum);
+
+/* Out Switch */
+static const struct snd_kcontrol_new hpol_switch =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5668_HP_CTRL_1,
+					RT5668_L_MUTE_SFT, 1, 1);
+static const struct snd_kcontrol_new hpor_switch =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5668_HP_CTRL_1,
+					RT5668_R_MUTE_SFT, 1, 1);
+
+static int rt5668_hp_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_write(component,
+			RT5668_HP_LOGIC_CTRL_2, 0x0012);
+		snd_soc_component_write(component,
+			RT5668_HP_CTRL_2, 0x6000);
+		snd_soc_component_update_bits(component, RT5668_STO_NG2_CTRL_1,
+			RT5668_NG2_EN_MASK, RT5668_NG2_EN);
+		snd_soc_component_update_bits(component,
+			RT5668_DEPOP_1, 0x60, 0x60);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component,
+			RT5668_DEPOP_1, 0x60, 0x0);
+		snd_soc_component_write(component,
+			RT5668_HP_CTRL_2, 0x0000);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int set_dmic_power(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/*Add delay to avoid pop noise*/
+		msleep(150);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5655_set_verf(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (w->shift) {
+		case RT5668_PWR_VREF1_BIT:
+			snd_soc_component_update_bits(component,
+				RT5668_PWR_ANLG_1, RT5668_PWR_FV1, 0);
+			break;
+
+		case RT5668_PWR_VREF2_BIT:
+			snd_soc_component_update_bits(component,
+				RT5668_PWR_ANLG_1, RT5668_PWR_FV2, 0);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(15000, 20000);
+		switch (w->shift) {
+		case RT5668_PWR_VREF1_BIT:
+			snd_soc_component_update_bits(component,
+				RT5668_PWR_ANLG_1, RT5668_PWR_FV1,
+				RT5668_PWR_FV1);
+			break;
+
+		case RT5668_PWR_VREF2_BIT:
+			snd_soc_component_update_bits(component,
+				RT5668_PWR_ANLG_1, RT5668_PWR_FV2,
+				RT5668_PWR_FV2);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const unsigned int rt5668_adcdat_pin_values[] = {
+	1,
+	3,
+};
+
+static const char * const rt5668_adcdat_pin_select[] = {
+	"ADCDAT1",
+	"ADCDAT2",
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5668_adcdat_pin_enum,
+	RT5668_GPIO_CTRL_1, RT5668_GP4_PIN_SFT, RT5668_GP4_PIN_MASK,
+	rt5668_adcdat_pin_select, rt5668_adcdat_pin_values);
+
+static const struct snd_kcontrol_new rt5668_adcdat_pin_ctrl =
+	SOC_DAPM_ENUM("ADCDAT", rt5668_adcdat_pin_enum);
+
+static const struct snd_soc_dapm_widget rt5668_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5668_PWR_ANLG_3, RT5668_PWR_LDO2_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5668_PWR_ANLG_3, RT5668_PWR_PLL_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL2B", RT5668_PWR_ANLG_3, RT5668_PWR_PLL2B_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL2F", RT5668_PWR_ANLG_3, RT5668_PWR_PLL2F_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Vref1", RT5668_PWR_ANLG_1, RT5668_PWR_VREF1_BIT, 0,
+		rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("Vref2", RT5668_PWR_ANLG_1, RT5668_PWR_VREF2_BIT, 0,
+		rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5668_PLL_TRACK_1,
+		RT5668_DAC_STO1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5668_PLL_TRACK_1,
+		RT5668_ADC_STO1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AD ASRC", 1, RT5668_PLL_TRACK_1,
+		RT5668_AD_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DA ASRC", 1, RT5668_PLL_TRACK_1,
+		RT5668_DA_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC ASRC", 1, RT5668_PLL_TRACK_1,
+		RT5668_DMIC_ASRC_SFT, 0, NULL, 0),
+
+	/* Input Side */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5668_PWR_ANLG_2, RT5668_PWR_MB1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5668_PWR_ANLG_2, RT5668_PWR_MB2_BIT,
+		0, NULL, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+		set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5668_DMIC_CTRL_1,
+		RT5668_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("CBJ Power", RT5668_PWR_ANLG_3,
+		RT5668_PWR_CBJ_BIT, 0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5668_rec1_l_mix,
+		ARRAY_SIZE(rt5668_rec1_l_mix)),
+	SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5668_PWR_ANLG_2,
+		RT5668_PWR_RM1_L_BIT, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5668_PWR_DIG_1,
+		RT5668_PWR_ADC_L1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5668_PWR_DIG_1,
+		RT5668_PWR_ADC_R1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5668_CHOP_ADC,
+		RT5668_CKGEN_ADC1_SFT, 0, NULL, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adc1l_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adc1r_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adc2l_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adc2r_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adcl_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adcr_mux),
+	SND_SOC_DAPM_MUX("IF1_ADC Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_if1_adc_slot_mux),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5668_PWR_DIG_2,
+		RT5668_PWR_ADC_S1F_BIT, 0, set_filter_clk,
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5668_STO1_ADC_DIG_VOL,
+		RT5668_L_MUTE_SFT, 1, rt5668_sto1_adc_l_mix,
+		ARRAY_SIZE(rt5668_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5668_STO1_ADC_DIG_VOL,
+		RT5668_R_MUTE_SFT, 1, rt5668_sto1_adc_r_mix,
+		ARRAY_SIZE(rt5668_sto1_adc_r_mix)),
+
+	/* ADC PGA */
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5668_PWR_DIG_1, RT5668_PWR_I2S1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S2", RT5668_PWR_DIG_1, RT5668_PWR_I2S2_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface Select */
+	SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5668_if1_01_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5668_if1_23_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5668_if1_45_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5668_if1_67_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5668_if2_adc_swap_mux),
+
+	SND_SOC_DAPM_MUX("ADCDAT Mux", SND_SOC_NOPM, 0, 0,
+			&rt5668_adcdat_pin_ctrl),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0,
+		RT5668_I2S1_SDP, RT5668_SEL_ADCDAT_SFT, 1),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0,
+		RT5668_I2S2_SDP, RT5668_I2S2_PIN_CFG_SFT, 1),
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+		rt5668_dac_l_mix, ARRAY_SIZE(rt5668_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+		rt5668_dac_r_mix, ARRAY_SIZE(rt5668_dac_r_mix)),
+
+	/* DAC channel Mux */
+	SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0,
+		&rt5668_alg_dac_l1_mux),
+	SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0,
+		&rt5668_alg_dac_r1_mux),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5668_PWR_DIG_2,
+		RT5668_PWR_DAC_S1F_BIT, 0, set_filter_clk,
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MIXER("Stereo1 DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5668_sto1_dac_l_mix, ARRAY_SIZE(rt5668_sto1_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5668_sto1_dac_r_mix, ARRAY_SIZE(rt5668_sto1_dac_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC L1", NULL, RT5668_PWR_DIG_1,
+		RT5668_PWR_DAC_L1_BIT, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, RT5668_PWR_DIG_1,
+		RT5668_PWR_DAC_R1_BIT, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC 1 Clock", 3, RT5668_CHOP_DAC,
+		RT5668_CKGEN_DAC1_SFT, 0, NULL, 0),
+
+	/* HPO */
+	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5668_hp_event,
+		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_SUPPLY("HP Amp L", RT5668_PWR_ANLG_1,
+		RT5668_PWR_HA_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HP Amp R", RT5668_PWR_ANLG_1,
+		RT5668_PWR_HA_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, RT5668_DEPOP_1,
+		RT5668_PUMP_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("Capless", 2, RT5668_DEPOP_1,
+		RT5668_CAPLESS_EN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("HPOL Playback", SND_SOC_NOPM, 0, 0,
+		&hpol_switch),
+	SND_SOC_DAPM_SWITCH("HPOR Playback", SND_SOC_NOPM, 0, 0,
+		&hpor_switch),
+
+	/* CLK DET */
+	SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5668_CLK_DET,
+		RT5668_SYS_CLK_DET_SFT,	0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET PLL1", RT5668_CLK_DET,
+		RT5668_PLL1_CLK_DET_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET PLL2", RT5668_CLK_DET,
+		RT5668_PLL2_CLK_DET_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET", RT5668_CLK_DET,
+		RT5668_POW_CLK_DET_SFT, 0, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+
+};
+
+static const struct snd_soc_dapm_route rt5668_dapm_routes[] = {
+	/*PLL*/
+	{"ADC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll1},
+	{"DAC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll1},
+
+	/*ASRC*/
+	{"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc},
+	{"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc},
+	{"ADC STO1 ASRC", NULL, "AD ASRC"},
+	{"DAC STO1 ASRC", NULL, "DA ASRC"},
+
+	/*Vref*/
+	{"MICBIAS1", NULL, "Vref1"},
+	{"MICBIAS1", NULL, "Vref2"},
+	{"MICBIAS2", NULL, "Vref1"},
+	{"MICBIAS2", NULL, "Vref2"},
+
+	{"CLKDET SYS", NULL, "CLKDET"},
+
+	{"IN1P", NULL, "LDO2"},
+
+	{"BST1 CBJ", NULL, "IN1P"},
+	{"BST1 CBJ", NULL, "CBJ Power"},
+	{"CBJ Power", NULL, "Vref2"},
+
+	{"RECMIX1L", "CBJ Switch", "BST1 CBJ"},
+	{"RECMIX1L", NULL, "RECMIX1L Power"},
+
+	{"ADC1 L", NULL, "RECMIX1L"},
+	{"ADC1 L", NULL, "ADC1 L Power"},
+	{"ADC1 L", NULL, "ADC1 clock"},
+
+	{"DMIC L1", NULL, "DMIC CLK"},
+	{"DMIC L1", NULL, "DMIC1 Power"},
+	{"DMIC R1", NULL, "DMIC CLK"},
+	{"DMIC R1", NULL, "DMIC1 Power"},
+	{"DMIC CLK", NULL, "DMIC ASRC"},
+
+	{"Stereo1 ADC L Mux", "ADC1 L", "ADC1 L"},
+	{"Stereo1 ADC L Mux", "ADC1 R", "ADC1 R"},
+	{"Stereo1 ADC R Mux", "ADC1 L", "ADC1 L"},
+	{"Stereo1 ADC R Mux", "ADC1 R", "ADC1 R"},
+
+	{"Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux"},
+	{"Stereo1 ADC L1 Mux", "DAC MIX", "Stereo1 DAC MIXL"},
+	{"Stereo1 ADC L2 Mux", "DMIC", "DMIC L1"},
+	{"Stereo1 ADC L2 Mux", "DAC MIX", "Stereo1 DAC MIXL"},
+
+	{"Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux"},
+	{"Stereo1 ADC R1 Mux", "DAC MIX", "Stereo1 DAC MIXR"},
+	{"Stereo1 ADC R2 Mux", "DMIC", "DMIC R1"},
+	{"Stereo1 ADC R2 Mux", "DAC MIX", "Stereo1 DAC MIXR"},
+
+	{"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"},
+	{"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"},
+	{"Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter"},
+
+	{"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"},
+	{"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"},
+	{"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"},
+
+	{"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"},
+	{"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"},
+
+	{"IF1 01 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF1 01 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF1 01 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF1 01 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+	{"IF1 23 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF1 23 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF1 23 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF1 23 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+	{"IF1 45 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF1 45 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF1 45 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF1 45 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+	{"IF1 67 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF1 67 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF1 67 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF1 67 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+
+	{"IF1_ADC Mux", "Slot 0", "IF1 01 ADC Swap Mux"},
+	{"IF1_ADC Mux", "Slot 2", "IF1 23 ADC Swap Mux"},
+	{"IF1_ADC Mux", "Slot 4", "IF1 45 ADC Swap Mux"},
+	{"IF1_ADC Mux", "Slot 6", "IF1 67 ADC Swap Mux"},
+	{"IF1_ADC Mux", NULL, "I2S1"},
+	{"ADCDAT Mux", "ADCDAT1", "IF1_ADC Mux"},
+	{"AIF1TX", NULL, "ADCDAT Mux"},
+	{"IF2 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF2 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF2 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF2 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+	{"ADCDAT Mux", "ADCDAT2", "IF2 ADC Swap Mux"},
+	{"AIF2TX", NULL, "ADCDAT Mux"},
+
+	{"IF1 DAC1 L", NULL, "AIF1RX"},
+	{"IF1 DAC1 L", NULL, "I2S1"},
+	{"IF1 DAC1 L", NULL, "DAC Stereo1 Filter"},
+	{"IF1 DAC1 R", NULL, "AIF1RX"},
+	{"IF1 DAC1 R", NULL, "I2S1"},
+	{"IF1 DAC1 R", NULL, "DAC Stereo1 Filter"},
+
+	{"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+	{"DAC1 MIXL", "DAC1 Switch", "IF1 DAC1 L"},
+	{"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+	{"DAC1 MIXR", "DAC1 Switch", "IF1 DAC1 R"},
+
+	{"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"},
+	{"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"},
+
+	{"Stereo1 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"},
+	{"Stereo1 DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"},
+
+	{"DAC L1 Source", "DAC1", "DAC1 MIXL"},
+	{"DAC L1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"},
+	{"DAC R1 Source", "DAC1", "DAC1 MIXR"},
+	{"DAC R1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"},
+
+	{"DAC L1", NULL, "DAC L1 Source"},
+	{"DAC R1", NULL, "DAC R1 Source"},
+
+	{"DAC L1", NULL, "DAC 1 Clock"},
+	{"DAC R1", NULL, "DAC 1 Clock"},
+
+	{"HP Amp", NULL, "DAC L1"},
+	{"HP Amp", NULL, "DAC R1"},
+	{"HP Amp", NULL, "HP Amp L"},
+	{"HP Amp", NULL, "HP Amp R"},
+	{"HP Amp", NULL, "Capless"},
+	{"HP Amp", NULL, "Charge Pump"},
+	{"HP Amp", NULL, "CLKDET SYS"},
+	{"HP Amp", NULL, "CBJ Power"},
+	{"HP Amp", NULL, "Vref2"},
+	{"HPOL Playback", "Switch", "HP Amp"},
+	{"HPOR Playback", "Switch", "HP Amp"},
+	{"HPOL", NULL, "HPOL Playback"},
+	{"HPOR", NULL, "HPOR Playback"},
+};
+
+static int rt5668_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;
+
+	switch (slots) {
+	case 4:
+		val |= RT5668_TDM_TX_CH_4;
+		val |= RT5668_TDM_RX_CH_4;
+		break;
+	case 6:
+		val |= RT5668_TDM_TX_CH_6;
+		val |= RT5668_TDM_RX_CH_6;
+		break;
+	case 8:
+		val |= RT5668_TDM_TX_CH_8;
+		val |= RT5668_TDM_RX_CH_8;
+		break;
+	case 2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5668_TDM_CTRL,
+		RT5668_TDM_TX_CH_MASK | RT5668_TDM_RX_CH_MASK, val);
+
+	switch (slot_width) {
+	case 16:
+		val = RT5668_TDM_CL_16;
+		break;
+	case 20:
+		val = RT5668_TDM_CL_20;
+		break;
+	case 24:
+		val = RT5668_TDM_CL_24;
+		break;
+	case 32:
+		val = RT5668_TDM_CL_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5668_TDM_TCON_CTRL,
+		RT5668_TDM_CL_MASK, val);
+
+	return 0;
+}
+
+
+static int rt5668_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 rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	unsigned int len_1 = 0, len_2 = 0;
+	int pre_div, frame_size;
+
+	rt5668->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5668->sysclk, rt5668->lrck[dai->id]);
+
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n",
+			frame_size);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+				rt5668->lrck[dai->id], pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		len_1 |= RT5668_I2S1_DL_20;
+		len_2 |= RT5668_I2S2_DL_20;
+		break;
+	case 24:
+		len_1 |= RT5668_I2S1_DL_24;
+		len_2 |= RT5668_I2S2_DL_24;
+		break;
+	case 32:
+		len_1 |= RT5668_I2S1_DL_32;
+		len_2 |= RT5668_I2S2_DL_24;
+		break;
+	case 8:
+		len_1 |= RT5668_I2S2_DL_8;
+		len_2 |= RT5668_I2S2_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5668_AIF1:
+		snd_soc_component_update_bits(component, RT5668_I2S1_SDP,
+			RT5668_I2S1_DL_MASK, len_1);
+		if (rt5668->master[RT5668_AIF1]) {
+			snd_soc_component_update_bits(component,
+				RT5668_ADDA_CLK_1, RT5668_I2S_M_DIV_MASK,
+				pre_div << RT5668_I2S_M_DIV_SFT);
+		}
+		if (params_channels(params) == 1) /* mono mode */
+			snd_soc_component_update_bits(component,
+				RT5668_I2S1_SDP, RT5668_I2S1_MONO_MASK,
+				RT5668_I2S1_MONO_EN);
+		else
+			snd_soc_component_update_bits(component,
+				RT5668_I2S1_SDP, RT5668_I2S1_MONO_MASK,
+				RT5668_I2S1_MONO_DIS);
+		break;
+	case RT5668_AIF2:
+		snd_soc_component_update_bits(component, RT5668_I2S2_SDP,
+			RT5668_I2S2_DL_MASK, len_2);
+		if (rt5668->master[RT5668_AIF2]) {
+			snd_soc_component_update_bits(component,
+				RT5668_I2S_M_CLK_CTRL_1, RT5668_I2S2_M_PD_MASK,
+				pre_div << RT5668_I2S2_M_PD_SFT);
+		}
+		if (params_channels(params) == 1) /* mono mode */
+			snd_soc_component_update_bits(component,
+				RT5668_I2S2_SDP, RT5668_I2S2_MONO_MASK,
+				RT5668_I2S2_MONO_EN);
+		else
+			snd_soc_component_update_bits(component,
+				RT5668_I2S2_SDP, RT5668_I2S2_MONO_MASK,
+				RT5668_I2S2_MONO_DIS);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5668_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0, tdm_ctrl = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5668->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		rt5668->master[dai->id] = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5668_I2S_BP_INV;
+		tdm_ctrl |= RT5668_TDM_S_BP_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		if (dai->id == RT5668_AIF1)
+			tdm_ctrl |= RT5668_TDM_S_LP_INV | RT5668_TDM_M_BP_INV;
+		else
+			return -EINVAL;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		if (dai->id == RT5668_AIF1)
+			tdm_ctrl |= RT5668_TDM_S_BP_INV | RT5668_TDM_S_LP_INV |
+				    RT5668_TDM_M_BP_INV | RT5668_TDM_M_LP_INV;
+		else
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5668_I2S_DF_LEFT;
+		tdm_ctrl |= RT5668_TDM_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5668_I2S_DF_PCM_A;
+		tdm_ctrl |= RT5668_TDM_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5668_I2S_DF_PCM_B;
+		tdm_ctrl |= RT5668_TDM_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5668_AIF1:
+		snd_soc_component_update_bits(component, RT5668_I2S1_SDP,
+			RT5668_I2S_DF_MASK, reg_val);
+		snd_soc_component_update_bits(component, RT5668_TDM_TCON_CTRL,
+			RT5668_TDM_MS_MASK | RT5668_TDM_S_BP_MASK |
+			RT5668_TDM_DF_MASK | RT5668_TDM_M_BP_MASK |
+			RT5668_TDM_M_LP_MASK | RT5668_TDM_S_LP_MASK,
+			tdm_ctrl | rt5668->master[dai->id]);
+		break;
+	case RT5668_AIF2:
+		if (rt5668->master[dai->id] == 0)
+			reg_val |= RT5668_I2S2_MS_S;
+		snd_soc_component_update_bits(component, RT5668_I2S2_SDP,
+			RT5668_I2S2_MS_MASK | RT5668_I2S_BP_MASK |
+			RT5668_I2S_DF_MASK, reg_val);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int rt5668_set_component_sysclk(struct snd_soc_component *component,
+		int clk_id, int source, unsigned int freq, int dir)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0, src = 0;
+
+	if (freq == rt5668->sysclk && clk_id == rt5668->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5668_SCLK_S_MCLK:
+		reg_val |= RT5668_SCLK_SRC_MCLK;
+		src = RT5668_CLK_SRC_MCLK;
+		break;
+	case RT5668_SCLK_S_PLL1:
+		reg_val |= RT5668_SCLK_SRC_PLL1;
+		src = RT5668_CLK_SRC_PLL1;
+		break;
+	case RT5668_SCLK_S_PLL2:
+		reg_val |= RT5668_SCLK_SRC_PLL2;
+		src = RT5668_CLK_SRC_PLL2;
+		break;
+	case RT5668_SCLK_S_RCCLK:
+		reg_val |= RT5668_SCLK_SRC_RCCLK;
+		src = RT5668_CLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT5668_GLB_CLK,
+		RT5668_SCLK_SRC_MASK, reg_val);
+
+	if (rt5668->master[RT5668_AIF2]) {
+		snd_soc_component_update_bits(component,
+			RT5668_I2S_M_CLK_CTRL_1, RT5668_I2S2_SRC_MASK,
+			src << RT5668_I2S2_SRC_SFT);
+	}
+
+	rt5668->sysclk = freq;
+	rt5668->sysclk_src = clk_id;
+
+	dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
+		freq, clk_id);
+
+	return 0;
+}
+
+static int rt5668_set_component_pll(struct snd_soc_component *component,
+		int pll_id, int source, unsigned int freq_in,
+		unsigned int freq_out)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5668->pll_src && freq_in == rt5668->pll_in &&
+	    freq_out == rt5668->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5668->pll_in = 0;
+		rt5668->pll_out = 0;
+		snd_soc_component_update_bits(component, RT5668_GLB_CLK,
+			RT5668_SCLK_SRC_MASK, RT5668_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5668_PLL1_S_MCLK:
+		snd_soc_component_update_bits(component, RT5668_GLB_CLK,
+			RT5668_PLL1_SRC_MASK, RT5668_PLL1_SRC_MCLK);
+		break;
+	case RT5668_PLL1_S_BCLK1:
+		snd_soc_component_update_bits(component, RT5668_GLB_CLK,
+				RT5668_PLL1_SRC_MASK, RT5668_PLL1_SRC_BCLK1);
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL Source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT5668_PLL_CTRL_1,
+		pll_code.n_code << RT5668_PLL_N_SFT | pll_code.k_code);
+	snd_soc_component_write(component, RT5668_PLL_CTRL_2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SFT |
+		pll_code.m_bp << RT5668_PLL_M_BP_SFT);
+
+	rt5668->pll_in = freq_in;
+	rt5668->pll_out = freq_out;
+	rt5668->pll_src = source;
+
+	return 0;
+}
+
+static int rt5668_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	rt5668->bclk[dai->id] = ratio;
+
+	switch (ratio) {
+	case 64:
+		snd_soc_component_update_bits(component, RT5668_ADDA_CLK_2,
+			RT5668_I2S2_BCLK_MS2_MASK,
+			RT5668_I2S2_BCLK_MS2_64);
+		break;
+	case 32:
+		snd_soc_component_update_bits(component, RT5668_ADDA_CLK_2,
+			RT5668_I2S2_BCLK_MS2_MASK,
+			RT5668_I2S2_BCLK_MS2_32);
+		break;
+	default:
+		dev_err(dai->dev, "Invalid bclk ratio %d\n", ratio);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5668_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_ANLG_1,
+			RT5668_PWR_MB | RT5668_PWR_BG,
+			RT5668_PWR_MB | RT5668_PWR_BG);
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_DIG_1,
+			RT5668_DIG_GATE_CTRL | RT5668_PWR_LDO,
+			RT5668_DIG_GATE_CTRL | RT5668_PWR_LDO);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_ANLG_1,
+			RT5668_PWR_MB, RT5668_PWR_MB);
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_DIG_1,
+			RT5668_DIG_GATE_CTRL, RT5668_DIG_GATE_CTRL);
+		break;
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_DIG_1,
+			RT5668_DIG_GATE_CTRL | RT5668_PWR_LDO, 0);
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_ANLG_1,
+			RT5668_PWR_MB | RT5668_PWR_BG, 0);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5668_probe(struct snd_soc_component *component)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	rt5668->component = component;
+
+	return 0;
+}
+
+static void rt5668_remove(struct snd_soc_component *component)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	rt5668_reset(rt5668->regmap);
+}
+
+#ifdef CONFIG_PM
+static int rt5668_suspend(struct snd_soc_component *component)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5668->regmap, true);
+	regcache_mark_dirty(rt5668->regmap);
+	return 0;
+}
+
+static int rt5668_resume(struct snd_soc_component *component)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5668->regmap, false);
+	regcache_sync(rt5668->regmap);
+
+	return 0;
+}
+#else
+#define rt5668_suspend NULL
+#define rt5668_resume NULL
+#endif
+
+#define RT5668_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5668_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5668_aif1_dai_ops = {
+	.hw_params = rt5668_hw_params,
+	.set_fmt = rt5668_set_dai_fmt,
+	.set_tdm_slot = rt5668_set_tdm_slot,
+};
+
+static const struct snd_soc_dai_ops rt5668_aif2_dai_ops = {
+	.hw_params = rt5668_hw_params,
+	.set_fmt = rt5668_set_dai_fmt,
+	.set_bclk_ratio = rt5668_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5668_dai[] = {
+	{
+		.name = "rt5668-aif1",
+		.id = RT5668_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5668_STEREO_RATES,
+			.formats = RT5668_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5668_STEREO_RATES,
+			.formats = RT5668_FORMATS,
+		},
+		.ops = &rt5668_aif1_dai_ops,
+	},
+	{
+		.name = "rt5668-aif2",
+		.id = RT5668_AIF2,
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5668_STEREO_RATES,
+			.formats = RT5668_FORMATS,
+		},
+		.ops = &rt5668_aif2_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5668 = {
+	.probe = rt5668_probe,
+	.remove = rt5668_remove,
+	.suspend = rt5668_suspend,
+	.resume = rt5668_resume,
+	.set_bias_level = rt5668_set_bias_level,
+	.controls = rt5668_snd_controls,
+	.num_controls = ARRAY_SIZE(rt5668_snd_controls),
+	.dapm_widgets = rt5668_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rt5668_dapm_widgets),
+	.dapm_routes = rt5668_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(rt5668_dapm_routes),
+	.set_sysclk = rt5668_set_component_sysclk,
+	.set_pll = rt5668_set_component_pll,
+	.set_jack = rt5668_set_jack_detect,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt5668_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.max_register = RT5668_I2C_MODE,
+	.volatile_reg = rt5668_volatile_register,
+	.readable_reg = rt5668_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5668_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5668_reg),
+	.use_single_rw = true,
+};
+
+static const struct i2c_device_id rt5668_i2c_id[] = {
+	{"rt5668b", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, rt5668_i2c_id);
+
+static int rt5668_parse_dt(struct rt5668_priv *rt5668, struct device *dev)
+{
+
+	of_property_read_u32(dev->of_node, "realtek,dmic1-data-pin",
+		&rt5668->pdata.dmic1_data_pin);
+	of_property_read_u32(dev->of_node, "realtek,dmic1-clk-pin",
+		&rt5668->pdata.dmic1_clk_pin);
+	of_property_read_u32(dev->of_node, "realtek,jd-src",
+		&rt5668->pdata.jd_src);
+
+	rt5668->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
+		"realtek,ldo1-en-gpios", 0);
+
+	return 0;
+}
+
+static void rt5668_calibrate(struct rt5668_priv *rt5668)
+{
+	int value, count;
+
+	mutex_lock(&rt5668->calibrate_mutex);
+
+	rt5668_reset(rt5668->regmap);
+	regmap_write(rt5668->regmap, RT5668_PWR_ANLG_1, 0xa2bf);
+	usleep_range(15000, 20000);
+	regmap_write(rt5668->regmap, RT5668_PWR_ANLG_1, 0xf2bf);
+	regmap_write(rt5668->regmap, RT5668_MICBIAS_2, 0x0380);
+	regmap_write(rt5668->regmap, RT5668_PWR_DIG_1, 0x8001);
+	regmap_write(rt5668->regmap, RT5668_TEST_MODE_CTRL_1, 0x0000);
+	regmap_write(rt5668->regmap, RT5668_STO1_DAC_MIXER, 0x2080);
+	regmap_write(rt5668->regmap, RT5668_STO1_ADC_MIXER, 0x4040);
+	regmap_write(rt5668->regmap, RT5668_DEPOP_1, 0x0069);
+	regmap_write(rt5668->regmap, RT5668_CHOP_DAC, 0x3000);
+	regmap_write(rt5668->regmap, RT5668_HP_CTRL_2, 0x6000);
+	regmap_write(rt5668->regmap, RT5668_HP_CHARGE_PUMP_1, 0x0f26);
+	regmap_write(rt5668->regmap, RT5668_CALIB_ADC_CTRL, 0x7f05);
+	regmap_write(rt5668->regmap, RT5668_STO1_ADC_MIXER, 0x686c);
+	regmap_write(rt5668->regmap, RT5668_CAL_REC, 0x0d0d);
+	regmap_write(rt5668->regmap, RT5668_HP_CALIB_CTRL_9, 0x000f);
+	regmap_write(rt5668->regmap, RT5668_PWR_DIG_1, 0x8d01);
+	regmap_write(rt5668->regmap, RT5668_HP_CALIB_CTRL_2, 0x0321);
+	regmap_write(rt5668->regmap, RT5668_HP_LOGIC_CTRL_2, 0x0004);
+	regmap_write(rt5668->regmap, RT5668_HP_CALIB_CTRL_1, 0x7c00);
+	regmap_write(rt5668->regmap, RT5668_HP_CALIB_CTRL_3, 0x06a1);
+	regmap_write(rt5668->regmap, RT5668_A_DAC1_MUX, 0x0311);
+	regmap_write(rt5668->regmap, RT5668_RESET_HPF_CTRL, 0x0000);
+	regmap_write(rt5668->regmap, RT5668_ADC_STO1_HP_CTRL_1, 0x3320);
+
+	regmap_write(rt5668->regmap, RT5668_HP_CALIB_CTRL_1, 0xfc00);
+
+	for (count = 0; count < 60; count++) {
+		regmap_read(rt5668->regmap, RT5668_HP_CALIB_STA_1, &value);
+		if (!(value & 0x8000))
+			break;
+
+		usleep_range(10000, 10005);
+	}
+
+	if (count >= 60)
+		pr_err("HP Calibration Failure\n");
+
+	/* restore settings */
+	regmap_write(rt5668->regmap, RT5668_STO1_ADC_MIXER, 0xc0c4);
+	regmap_write(rt5668->regmap, RT5668_PWR_DIG_1, 0x0000);
+
+	mutex_unlock(&rt5668->calibrate_mutex);
+
+}
+
+static int rt5668_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5668_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt5668_priv *rt5668;
+	int i, ret;
+	unsigned int val;
+
+	rt5668 = devm_kzalloc(&i2c->dev, sizeof(struct rt5668_priv),
+		GFP_KERNEL);
+
+	if (rt5668 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5668);
+
+	if (pdata)
+		rt5668->pdata = *pdata;
+	else
+		rt5668_parse_dt(rt5668, &i2c->dev);
+
+	rt5668->regmap = devm_regmap_init_i2c(i2c, &rt5668_regmap);
+	if (IS_ERR(rt5668->regmap)) {
+		ret = PTR_ERR(rt5668->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(rt5668->supplies); i++)
+		rt5668->supplies[i].supply = rt5668_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5668->supplies),
+				      rt5668->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(rt5668->supplies),
+				    rt5668->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	if (gpio_is_valid(rt5668->pdata.ldo1_en)) {
+		if (devm_gpio_request_one(&i2c->dev, rt5668->pdata.ldo1_en,
+					  GPIOF_OUT_INIT_HIGH, "rt5668"))
+			dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+	}
+
+	/* Sleep for 300 ms miniumum */
+	usleep_range(300000, 350000);
+
+	regmap_write(rt5668->regmap, RT5668_I2C_MODE, 0x1);
+	usleep_range(10000, 15000);
+
+	regmap_read(rt5668->regmap, RT5668_DEVICE_ID, &val);
+	if (val != DEVICE_ID) {
+		pr_err("Device with ID register %x is not rt5668\n", val);
+		return -ENODEV;
+	}
+
+	rt5668_reset(rt5668->regmap);
+
+	rt5668_calibrate(rt5668);
+
+	regmap_write(rt5668->regmap, RT5668_DEPOP_1, 0x0000);
+
+	/* DMIC pin*/
+	if (rt5668->pdata.dmic1_data_pin != RT5668_DMIC1_NULL) {
+		switch (rt5668->pdata.dmic1_data_pin) {
+		case RT5668_DMIC1_DATA_GPIO2: /* share with LRCK2 */
+			regmap_update_bits(rt5668->regmap, RT5668_DMIC_CTRL_1,
+				RT5668_DMIC_1_DP_MASK, RT5668_DMIC_1_DP_GPIO2);
+			regmap_update_bits(rt5668->regmap, RT5668_GPIO_CTRL_1,
+				RT5668_GP2_PIN_MASK, RT5668_GP2_PIN_DMIC_SDA);
+			break;
+
+		case RT5668_DMIC1_DATA_GPIO5: /* share with DACDAT1 */
+			regmap_update_bits(rt5668->regmap, RT5668_DMIC_CTRL_1,
+				RT5668_DMIC_1_DP_MASK, RT5668_DMIC_1_DP_GPIO5);
+			regmap_update_bits(rt5668->regmap, RT5668_GPIO_CTRL_1,
+				RT5668_GP5_PIN_MASK, RT5668_GP5_PIN_DMIC_SDA);
+			break;
+
+		default:
+			dev_dbg(&i2c->dev, "invalid DMIC_DAT pin\n");
+			break;
+		}
+
+		switch (rt5668->pdata.dmic1_clk_pin) {
+		case RT5668_DMIC1_CLK_GPIO1: /* share with IRQ */
+			regmap_update_bits(rt5668->regmap, RT5668_GPIO_CTRL_1,
+				RT5668_GP1_PIN_MASK, RT5668_GP1_PIN_DMIC_CLK);
+			break;
+
+		case RT5668_DMIC1_CLK_GPIO3: /* share with BCLK2 */
+			regmap_update_bits(rt5668->regmap, RT5668_GPIO_CTRL_1,
+				RT5668_GP3_PIN_MASK, RT5668_GP3_PIN_DMIC_CLK);
+			break;
+
+		default:
+			dev_dbg(&i2c->dev, "invalid DMIC_CLK pin\n");
+			break;
+		}
+	}
+
+	regmap_update_bits(rt5668->regmap, RT5668_PWR_ANLG_1,
+			RT5668_LDO1_DVO_MASK | RT5668_HP_DRIVER_MASK,
+			RT5668_LDO1_DVO_14 | RT5668_HP_DRIVER_5X);
+	regmap_write(rt5668->regmap, RT5668_MICBIAS_2, 0x0380);
+	regmap_update_bits(rt5668->regmap, RT5668_GPIO_CTRL_1,
+			RT5668_GP4_PIN_MASK | RT5668_GP5_PIN_MASK,
+			RT5668_GP4_PIN_ADCDAT1 | RT5668_GP5_PIN_DACDAT1);
+	regmap_write(rt5668->regmap, RT5668_TEST_MODE_CTRL_1, 0x0000);
+
+	INIT_DELAYED_WORK(&rt5668->jack_detect_work,
+				rt5668_jack_detect_handler);
+	INIT_DELAYED_WORK(&rt5668->jd_check_work,
+				rt5668_jd_check_handler);
+
+	mutex_init(&rt5668->calibrate_mutex);
+
+	if (i2c->irq) {
+		ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+			rt5668_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			| IRQF_ONESHOT, "rt5668", rt5668);
+		if (ret)
+			dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+
+	}
+
+	return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668,
+			rt5668_dai, ARRAY_SIZE(rt5668_dai));
+}
+
+static int rt5668_i2c_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_component(&i2c->dev);
+
+	return 0;
+}
+
+static void rt5668_i2c_shutdown(struct i2c_client *client)
+{
+	struct rt5668_priv *rt5668 = i2c_get_clientdata(client);
+
+	rt5668_reset(rt5668->regmap);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt5668_of_match[] = {
+	{.compatible = "realtek,rt5668b"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5668_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5668_acpi_match[] = {
+	{"10EC5668", 0,},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt5668_acpi_match);
+#endif
+
+static struct i2c_driver rt5668_i2c_driver = {
+	.driver = {
+		.name = "rt5668b",
+		.of_match_table = of_match_ptr(rt5668_of_match),
+		.acpi_match_table = ACPI_PTR(rt5668_acpi_match),
+	},
+	.probe = rt5668_i2c_probe,
+	.remove = rt5668_i2c_remove,
+	.shutdown = rt5668_i2c_shutdown,
+	.id_table = rt5668_i2c_id,
+};
+module_i2c_driver(rt5668_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5668B driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5668.h b/sound/soc/codecs/rt5668.h
new file mode 100644
index 000000000000..3e7bcfd569ec
--- /dev/null
+++ b/sound/soc/codecs/rt5668.h
@@ -0,0 +1,1318 @@
+/*
+ * rt5668.h  --  RT5668/RT5658 ALSA SoC audio driver
+ *
+ * Copyright 2018 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5668_H__
+#define __RT5668_H__
+
+#include <sound/rt5668.h>
+
+#define DEVICE_ID 0x6530
+
+/* Info */
+#define RT5668_RESET				0x0000
+#define RT5668_VERSION_ID			0x00fd
+#define RT5668_VENDOR_ID			0x00fe
+#define RT5668_DEVICE_ID			0x00ff
+/*  I/O - Output */
+#define RT5668_HP_CTRL_1			0x0002
+#define RT5668_HP_CTRL_2			0x0003
+#define RT5668_HPL_GAIN				0x0005
+#define RT5668_HPR_GAIN				0x0006
+
+#define RT5668_I2C_CTRL				0x0008
+
+/* I/O - Input */
+#define RT5668_CBJ_BST_CTRL			0x000b
+#define RT5668_CBJ_CTRL_1			0x0010
+#define RT5668_CBJ_CTRL_2			0x0011
+#define RT5668_CBJ_CTRL_3			0x0012
+#define RT5668_CBJ_CTRL_4			0x0013
+#define RT5668_CBJ_CTRL_5			0x0014
+#define RT5668_CBJ_CTRL_6			0x0015
+#define RT5668_CBJ_CTRL_7			0x0016
+/* I/O - ADC/DAC/DMIC */
+#define RT5668_DAC1_DIG_VOL			0x0019
+#define RT5668_STO1_ADC_DIG_VOL			0x001c
+#define RT5668_STO1_ADC_BOOST			0x001f
+#define RT5668_HP_IMP_GAIN_1			0x0022
+#define RT5668_HP_IMP_GAIN_2			0x0023
+/* Mixer - D-D */
+#define RT5668_SIDETONE_CTRL			0x0024
+#define RT5668_STO1_ADC_MIXER			0x0026
+#define RT5668_AD_DA_MIXER			0x0029
+#define RT5668_STO1_DAC_MIXER			0x002a
+#define RT5668_A_DAC1_MUX			0x002b
+#define RT5668_DIG_INF2_DATA			0x0030
+/* Mixer - ADC */
+#define RT5668_REC_MIXER			0x003c
+#define RT5668_CAL_REC				0x0044
+#define RT5668_ALC_BACK_GAIN			0x0049
+/* Power */
+#define RT5668_PWR_DIG_1			0x0061
+#define RT5668_PWR_DIG_2			0x0062
+#define RT5668_PWR_ANLG_1			0x0063
+#define RT5668_PWR_ANLG_2			0x0064
+#define RT5668_PWR_ANLG_3			0x0065
+#define RT5668_PWR_MIXER			0x0066
+#define RT5668_PWR_VOL				0x0067
+/* Clock Detect */
+#define RT5668_CLK_DET				0x006b
+/* Filter Auto Reset */
+#define RT5668_RESET_LPF_CTRL			0x006c
+#define RT5668_RESET_HPF_CTRL			0x006d
+/* DMIC */
+#define RT5668_DMIC_CTRL_1			0x006e
+/* Format - ADC/DAC */
+#define RT5668_I2S1_SDP				0x0070
+#define RT5668_I2S2_SDP				0x0071
+#define RT5668_ADDA_CLK_1			0x0073
+#define RT5668_ADDA_CLK_2			0x0074
+#define RT5668_I2S1_F_DIV_CTRL_1		0x0075
+#define RT5668_I2S1_F_DIV_CTRL_2		0x0076
+/* Format - TDM Control */
+#define RT5668_TDM_CTRL				0x0079
+#define RT5668_TDM_ADDA_CTRL_1			0x007a
+#define RT5668_TDM_ADDA_CTRL_2			0x007b
+#define RT5668_DATA_SEL_CTRL_1			0x007c
+#define RT5668_TDM_TCON_CTRL			0x007e
+/* Function - Analog */
+#define RT5668_GLB_CLK				0x0080
+#define RT5668_PLL_CTRL_1			0x0081
+#define RT5668_PLL_CTRL_2			0x0082
+#define RT5668_PLL_TRACK_1			0x0083
+#define RT5668_PLL_TRACK_2			0x0084
+#define RT5668_PLL_TRACK_3			0x0085
+#define RT5668_PLL_TRACK_4			0x0086
+#define RT5668_PLL_TRACK_5			0x0087
+#define RT5668_PLL_TRACK_6			0x0088
+#define RT5668_PLL_TRACK_11			0x008c
+#define RT5668_SDW_REF_CLK			0x008d
+#define RT5668_DEPOP_1				0x008e
+#define RT5668_DEPOP_2				0x008f
+#define RT5668_HP_CHARGE_PUMP_1			0x0091
+#define RT5668_HP_CHARGE_PUMP_2			0x0092
+#define RT5668_MICBIAS_1			0x0093
+#define RT5668_MICBIAS_2			0x0094
+#define RT5668_PLL_TRACK_12			0x0098
+#define RT5668_PLL_TRACK_14			0x009a
+#define RT5668_PLL2_CTRL_1			0x009b
+#define RT5668_PLL2_CTRL_2			0x009c
+#define RT5668_PLL2_CTRL_3			0x009d
+#define RT5668_PLL2_CTRL_4			0x009e
+#define RT5668_RC_CLK_CTRL			0x009f
+#define RT5668_I2S_M_CLK_CTRL_1			0x00a0
+#define RT5668_I2S2_F_DIV_CTRL_1		0x00a3
+#define RT5668_I2S2_F_DIV_CTRL_2		0x00a4
+/* Function - Digital */
+#define RT5668_EQ_CTRL_1			0x00ae
+#define RT5668_EQ_CTRL_2			0x00af
+#define RT5668_IRQ_CTRL_1			0x00b6
+#define RT5668_IRQ_CTRL_2			0x00b7
+#define RT5668_IRQ_CTRL_3			0x00b8
+#define RT5668_IRQ_CTRL_4			0x00b9
+#define RT5668_INT_ST_1				0x00be
+#define RT5668_GPIO_CTRL_1			0x00c0
+#define RT5668_GPIO_CTRL_2			0x00c1
+#define RT5668_GPIO_CTRL_3			0x00c2
+#define RT5668_HP_AMP_DET_CTRL_1		0x00d0
+#define RT5668_HP_AMP_DET_CTRL_2		0x00d1
+#define RT5668_MID_HP_AMP_DET			0x00d2
+#define RT5668_LOW_HP_AMP_DET			0x00d3
+#define RT5668_DELAY_BUF_CTRL			0x00d4
+#define RT5668_SV_ZCD_1				0x00d9
+#define RT5668_SV_ZCD_2				0x00da
+#define RT5668_IL_CMD_1				0x00db
+#define RT5668_IL_CMD_2				0x00dc
+#define RT5668_IL_CMD_3				0x00dd
+#define RT5668_IL_CMD_4				0x00de
+#define RT5668_IL_CMD_5				0x00df
+#define RT5668_IL_CMD_6				0x00e0
+#define RT5668_4BTN_IL_CMD_1			0x00e2
+#define RT5668_4BTN_IL_CMD_2			0x00e3
+#define RT5668_4BTN_IL_CMD_3			0x00e4
+#define RT5668_4BTN_IL_CMD_4			0x00e5
+#define RT5668_4BTN_IL_CMD_5			0x00e6
+#define RT5668_4BTN_IL_CMD_6			0x00e7
+#define RT5668_4BTN_IL_CMD_7			0x00e8
+
+#define RT5668_ADC_STO1_HP_CTRL_1		0x00ea
+#define RT5668_ADC_STO1_HP_CTRL_2		0x00eb
+#define RT5668_AJD1_CTRL			0x00f0
+#define RT5668_JD1_THD				0x00f1
+#define RT5668_JD2_THD				0x00f2
+#define RT5668_JD_CTRL_1			0x00f6
+/* General Control */
+#define RT5668_DUMMY_1				0x00fa
+#define RT5668_DUMMY_2				0x00fb
+#define RT5668_DUMMY_3				0x00fc
+
+#define RT5668_DAC_ADC_DIG_VOL1			0x0100
+#define RT5668_BIAS_CUR_CTRL_2			0x010b
+#define RT5668_BIAS_CUR_CTRL_3			0x010c
+#define RT5668_BIAS_CUR_CTRL_4			0x010d
+#define RT5668_BIAS_CUR_CTRL_5			0x010e
+#define RT5668_BIAS_CUR_CTRL_6			0x010f
+#define RT5668_BIAS_CUR_CTRL_7			0x0110
+#define RT5668_BIAS_CUR_CTRL_8			0x0111
+#define RT5668_BIAS_CUR_CTRL_9			0x0112
+#define RT5668_BIAS_CUR_CTRL_10			0x0113
+#define RT5668_VREF_REC_OP_FB_CAP_CTRL		0x0117
+#define RT5668_CHARGE_PUMP_1			0x0125
+#define RT5668_DIG_IN_CTRL_1			0x0132
+#define RT5668_PAD_DRIVING_CTRL			0x0136
+#define RT5668_SOFT_RAMP_DEPOP			0x0138
+#define RT5668_CHOP_DAC				0x013a
+#define RT5668_CHOP_ADC				0x013b
+#define RT5668_CALIB_ADC_CTRL			0x013c
+#define RT5668_VOL_TEST				0x013f
+#define RT5668_SPKVDD_DET_STA			0x0142
+#define RT5668_TEST_MODE_CTRL_1			0x0145
+#define RT5668_TEST_MODE_CTRL_2			0x0146
+#define RT5668_TEST_MODE_CTRL_3			0x0147
+#define RT5668_TEST_MODE_CTRL_4			0x0148
+#define RT5668_TEST_MODE_CTRL_5			0x0149
+#define RT5668_PLL1_INTERNAL			0x0150
+#define RT5668_PLL2_INTERNAL			0x0151
+#define RT5668_STO_NG2_CTRL_1			0x0160
+#define RT5668_STO_NG2_CTRL_2			0x0161
+#define RT5668_STO_NG2_CTRL_3			0x0162
+#define RT5668_STO_NG2_CTRL_4			0x0163
+#define RT5668_STO_NG2_CTRL_5			0x0164
+#define RT5668_STO_NG2_CTRL_6			0x0165
+#define RT5668_STO_NG2_CTRL_7			0x0166
+#define RT5668_STO_NG2_CTRL_8			0x0167
+#define RT5668_STO_NG2_CTRL_9			0x0168
+#define RT5668_STO_NG2_CTRL_10			0x0169
+#define RT5668_STO1_DAC_SIL_DET			0x0190
+#define RT5668_SIL_PSV_CTRL1			0x0194
+#define RT5668_SIL_PSV_CTRL2			0x0195
+#define RT5668_SIL_PSV_CTRL3			0x0197
+#define RT5668_SIL_PSV_CTRL4			0x0198
+#define RT5668_SIL_PSV_CTRL5			0x0199
+#define RT5668_HP_IMP_SENS_CTRL_01		0x01af
+#define RT5668_HP_IMP_SENS_CTRL_02		0x01b0
+#define RT5668_HP_IMP_SENS_CTRL_03		0x01b1
+#define RT5668_HP_IMP_SENS_CTRL_04		0x01b2
+#define RT5668_HP_IMP_SENS_CTRL_05		0x01b3
+#define RT5668_HP_IMP_SENS_CTRL_06		0x01b4
+#define RT5668_HP_IMP_SENS_CTRL_07		0x01b5
+#define RT5668_HP_IMP_SENS_CTRL_08		0x01b6
+#define RT5668_HP_IMP_SENS_CTRL_09		0x01b7
+#define RT5668_HP_IMP_SENS_CTRL_10		0x01b8
+#define RT5668_HP_IMP_SENS_CTRL_11		0x01b9
+#define RT5668_HP_IMP_SENS_CTRL_12		0x01ba
+#define RT5668_HP_IMP_SENS_CTRL_13		0x01bb
+#define RT5668_HP_IMP_SENS_CTRL_14		0x01bc
+#define RT5668_HP_IMP_SENS_CTRL_15		0x01bd
+#define RT5668_HP_IMP_SENS_CTRL_16		0x01be
+#define RT5668_HP_IMP_SENS_CTRL_17		0x01bf
+#define RT5668_HP_IMP_SENS_CTRL_18		0x01c0
+#define RT5668_HP_IMP_SENS_CTRL_19		0x01c1
+#define RT5668_HP_IMP_SENS_CTRL_20		0x01c2
+#define RT5668_HP_IMP_SENS_CTRL_21		0x01c3
+#define RT5668_HP_IMP_SENS_CTRL_22		0x01c4
+#define RT5668_HP_IMP_SENS_CTRL_23		0x01c5
+#define RT5668_HP_IMP_SENS_CTRL_24		0x01c6
+#define RT5668_HP_IMP_SENS_CTRL_25		0x01c7
+#define RT5668_HP_IMP_SENS_CTRL_26		0x01c8
+#define RT5668_HP_IMP_SENS_CTRL_27		0x01c9
+#define RT5668_HP_IMP_SENS_CTRL_28		0x01ca
+#define RT5668_HP_IMP_SENS_CTRL_29		0x01cb
+#define RT5668_HP_IMP_SENS_CTRL_30		0x01cc
+#define RT5668_HP_IMP_SENS_CTRL_31		0x01cd
+#define RT5668_HP_IMP_SENS_CTRL_32		0x01ce
+#define RT5668_HP_IMP_SENS_CTRL_33		0x01cf
+#define RT5668_HP_IMP_SENS_CTRL_34		0x01d0
+#define RT5668_HP_IMP_SENS_CTRL_35		0x01d1
+#define RT5668_HP_IMP_SENS_CTRL_36		0x01d2
+#define RT5668_HP_IMP_SENS_CTRL_37		0x01d3
+#define RT5668_HP_IMP_SENS_CTRL_38		0x01d4
+#define RT5668_HP_IMP_SENS_CTRL_39		0x01d5
+#define RT5668_HP_IMP_SENS_CTRL_40		0x01d6
+#define RT5668_HP_IMP_SENS_CTRL_41		0x01d7
+#define RT5668_HP_IMP_SENS_CTRL_42		0x01d8
+#define RT5668_HP_IMP_SENS_CTRL_43		0x01d9
+#define RT5668_HP_LOGIC_CTRL_1			0x01da
+#define RT5668_HP_LOGIC_CTRL_2			0x01db
+#define RT5668_HP_LOGIC_CTRL_3			0x01dc
+#define RT5668_HP_CALIB_CTRL_1			0x01de
+#define RT5668_HP_CALIB_CTRL_2			0x01df
+#define RT5668_HP_CALIB_CTRL_3			0x01e0
+#define RT5668_HP_CALIB_CTRL_4			0x01e1
+#define RT5668_HP_CALIB_CTRL_5			0x01e2
+#define RT5668_HP_CALIB_CTRL_6			0x01e3
+#define RT5668_HP_CALIB_CTRL_7			0x01e4
+#define RT5668_HP_CALIB_CTRL_9			0x01e6
+#define RT5668_HP_CALIB_CTRL_10			0x01e7
+#define RT5668_HP_CALIB_CTRL_11			0x01e8
+#define RT5668_HP_CALIB_STA_1			0x01ea
+#define RT5668_HP_CALIB_STA_2			0x01eb
+#define RT5668_HP_CALIB_STA_3			0x01ec
+#define RT5668_HP_CALIB_STA_4			0x01ed
+#define RT5668_HP_CALIB_STA_5			0x01ee
+#define RT5668_HP_CALIB_STA_6			0x01ef
+#define RT5668_HP_CALIB_STA_7			0x01f0
+#define RT5668_HP_CALIB_STA_8			0x01f1
+#define RT5668_HP_CALIB_STA_9			0x01f2
+#define RT5668_HP_CALIB_STA_10			0x01f3
+#define RT5668_HP_CALIB_STA_11			0x01f4
+#define RT5668_SAR_IL_CMD_1			0x0210
+#define RT5668_SAR_IL_CMD_2			0x0211
+#define RT5668_SAR_IL_CMD_3			0x0212
+#define RT5668_SAR_IL_CMD_4			0x0213
+#define RT5668_SAR_IL_CMD_5			0x0214
+#define RT5668_SAR_IL_CMD_6			0x0215
+#define RT5668_SAR_IL_CMD_7			0x0216
+#define RT5668_SAR_IL_CMD_8			0x0217
+#define RT5668_SAR_IL_CMD_9			0x0218
+#define RT5668_SAR_IL_CMD_10			0x0219
+#define RT5668_SAR_IL_CMD_11			0x021a
+#define RT5668_SAR_IL_CMD_12			0x021b
+#define RT5668_SAR_IL_CMD_13			0x021c
+#define RT5668_EFUSE_CTRL_1			0x0250
+#define RT5668_EFUSE_CTRL_2			0x0251
+#define RT5668_EFUSE_CTRL_3			0x0252
+#define RT5668_EFUSE_CTRL_4			0x0253
+#define RT5668_EFUSE_CTRL_5			0x0254
+#define RT5668_EFUSE_CTRL_6			0x0255
+#define RT5668_EFUSE_CTRL_7			0x0256
+#define RT5668_EFUSE_CTRL_8			0x0257
+#define RT5668_EFUSE_CTRL_9			0x0258
+#define RT5668_EFUSE_CTRL_10			0x0259
+#define RT5668_EFUSE_CTRL_11			0x025a
+#define RT5668_JD_TOP_VC_VTRL			0x0270
+#define RT5668_DRC1_CTRL_0			0x02ff
+#define RT5668_DRC1_CTRL_1			0x0300
+#define RT5668_DRC1_CTRL_2			0x0301
+#define RT5668_DRC1_CTRL_3			0x0302
+#define RT5668_DRC1_CTRL_4			0x0303
+#define RT5668_DRC1_CTRL_5			0x0304
+#define RT5668_DRC1_CTRL_6			0x0305
+#define RT5668_DRC1_HARD_LMT_CTRL_1		0x0306
+#define RT5668_DRC1_HARD_LMT_CTRL_2		0x0307
+#define RT5668_DRC1_PRIV_1			0x0310
+#define RT5668_DRC1_PRIV_2			0x0311
+#define RT5668_DRC1_PRIV_3			0x0312
+#define RT5668_DRC1_PRIV_4			0x0313
+#define RT5668_DRC1_PRIV_5			0x0314
+#define RT5668_DRC1_PRIV_6			0x0315
+#define RT5668_DRC1_PRIV_7			0x0316
+#define RT5668_DRC1_PRIV_8			0x0317
+#define RT5668_EQ_AUTO_RCV_CTRL1		0x03c0
+#define RT5668_EQ_AUTO_RCV_CTRL2		0x03c1
+#define RT5668_EQ_AUTO_RCV_CTRL3		0x03c2
+#define RT5668_EQ_AUTO_RCV_CTRL4		0x03c3
+#define RT5668_EQ_AUTO_RCV_CTRL5		0x03c4
+#define RT5668_EQ_AUTO_RCV_CTRL6		0x03c5
+#define RT5668_EQ_AUTO_RCV_CTRL7		0x03c6
+#define RT5668_EQ_AUTO_RCV_CTRL8		0x03c7
+#define RT5668_EQ_AUTO_RCV_CTRL9		0x03c8
+#define RT5668_EQ_AUTO_RCV_CTRL10		0x03c9
+#define RT5668_EQ_AUTO_RCV_CTRL11		0x03ca
+#define RT5668_EQ_AUTO_RCV_CTRL12		0x03cb
+#define RT5668_EQ_AUTO_RCV_CTRL13		0x03cc
+#define RT5668_ADC_L_EQ_LPF1_A1			0x03d0
+#define RT5668_R_EQ_LPF1_A1			0x03d1
+#define RT5668_L_EQ_LPF1_H0			0x03d2
+#define RT5668_R_EQ_LPF1_H0			0x03d3
+#define RT5668_L_EQ_BPF1_A1			0x03d4
+#define RT5668_R_EQ_BPF1_A1			0x03d5
+#define RT5668_L_EQ_BPF1_A2			0x03d6
+#define RT5668_R_EQ_BPF1_A2			0x03d7
+#define RT5668_L_EQ_BPF1_H0			0x03d8
+#define RT5668_R_EQ_BPF1_H0			0x03d9
+#define RT5668_L_EQ_BPF2_A1			0x03da
+#define RT5668_R_EQ_BPF2_A1			0x03db
+#define RT5668_L_EQ_BPF2_A2			0x03dc
+#define RT5668_R_EQ_BPF2_A2			0x03dd
+#define RT5668_L_EQ_BPF2_H0			0x03de
+#define RT5668_R_EQ_BPF2_H0			0x03df
+#define RT5668_L_EQ_BPF3_A1			0x03e0
+#define RT5668_R_EQ_BPF3_A1			0x03e1
+#define RT5668_L_EQ_BPF3_A2			0x03e2
+#define RT5668_R_EQ_BPF3_A2			0x03e3
+#define RT5668_L_EQ_BPF3_H0			0x03e4
+#define RT5668_R_EQ_BPF3_H0			0x03e5
+#define RT5668_L_EQ_BPF4_A1			0x03e6
+#define RT5668_R_EQ_BPF4_A1			0x03e7
+#define RT5668_L_EQ_BPF4_A2			0x03e8
+#define RT5668_R_EQ_BPF4_A2			0x03e9
+#define RT5668_L_EQ_BPF4_H0			0x03ea
+#define RT5668_R_EQ_BPF4_H0			0x03eb
+#define RT5668_L_EQ_HPF1_A1			0x03ec
+#define RT5668_R_EQ_HPF1_A1			0x03ed
+#define RT5668_L_EQ_HPF1_H0			0x03ee
+#define RT5668_R_EQ_HPF1_H0			0x03ef
+#define RT5668_L_EQ_PRE_VOL			0x03f0
+#define RT5668_R_EQ_PRE_VOL			0x03f1
+#define RT5668_L_EQ_POST_VOL			0x03f2
+#define RT5668_R_EQ_POST_VOL			0x03f3
+#define RT5668_I2C_MODE				0xffff
+
+
+/* global definition */
+#define RT5668_L_MUTE				(0x1 << 15)
+#define RT5668_L_MUTE_SFT			15
+#define RT5668_VOL_L_MUTE			(0x1 << 14)
+#define RT5668_VOL_L_SFT			14
+#define RT5668_R_MUTE				(0x1 << 7)
+#define RT5668_R_MUTE_SFT			7
+#define RT5668_VOL_R_MUTE			(0x1 << 6)
+#define RT5668_VOL_R_SFT			6
+#define RT5668_L_VOL_MASK			(0x3f << 8)
+#define RT5668_L_VOL_SFT			8
+#define RT5668_R_VOL_MASK			(0x3f)
+#define RT5668_R_VOL_SFT			0
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5668_G_HP				(0xf << 8)
+#define RT5668_G_HP_SFT				8
+#define RT5668_G_STO_DA_DMIX			(0xf)
+#define RT5668_G_STO_DA_SFT			0
+
+/* CBJ Control (0x000b) */
+#define RT5668_BST_CBJ_MASK			(0xf << 8)
+#define RT5668_BST_CBJ_SFT			8
+
+/* Embeeded Jack and Type Detection Control 1 (0x0010) */
+#define RT5668_EMB_JD_EN			(0x1 << 15)
+#define RT5668_EMB_JD_EN_SFT			15
+#define RT5668_EMB_JD_RST			(0x1 << 14)
+#define RT5668_JD_MODE				(0x1 << 13)
+#define RT5668_JD_MODE_SFT			13
+#define RT5668_DET_TYPE				(0x1 << 12)
+#define RT5668_DET_TYPE_SFT			12
+#define RT5668_POLA_EXT_JD_MASK			(0x1 << 11)
+#define RT5668_POLA_EXT_JD_LOW			(0x1 << 11)
+#define RT5668_POLA_EXT_JD_HIGH			(0x0 << 11)
+#define RT5668_EXT_JD_DIG			(0x1 << 9)
+#define RT5668_POL_FAST_OFF_MASK		(0x1 << 8)
+#define RT5668_POL_FAST_OFF_HIGH		(0x1 << 8)
+#define RT5668_POL_FAST_OFF_LOW			(0x0 << 8)
+#define RT5668_FAST_OFF_MASK			(0x1 << 7)
+#define RT5668_FAST_OFF_EN			(0x1 << 7)
+#define RT5668_FAST_OFF_DIS			(0x0 << 7)
+#define RT5668_VREF_POW_MASK			(0x1 << 6)
+#define RT5668_VREF_POW_FSM			(0x0 << 6)
+#define RT5668_VREF_POW_REG			(0x1 << 6)
+#define RT5668_MB1_PATH_MASK			(0x1 << 5)
+#define RT5668_CTRL_MB1_REG			(0x1 << 5)
+#define RT5668_CTRL_MB1_FSM			(0x0 << 5)
+#define RT5668_MB2_PATH_MASK			(0x1 << 4)
+#define RT5668_CTRL_MB2_REG			(0x1 << 4)
+#define RT5668_CTRL_MB2_FSM			(0x0 << 4)
+#define RT5668_TRIG_JD_MASK			(0x1 << 3)
+#define RT5668_TRIG_JD_HIGH			(0x1 << 3)
+#define RT5668_TRIG_JD_LOW			(0x0 << 3)
+#define RT5668_MIC_CAP_MASK			(0x1 << 1)
+#define RT5668_MIC_CAP_HS			(0x1 << 1)
+#define RT5668_MIC_CAP_HP			(0x0 << 1)
+#define RT5668_MIC_CAP_SRC_MASK			(0x1)
+#define RT5668_MIC_CAP_SRC_REG			(0x1)
+#define RT5668_MIC_CAP_SRC_ANA			(0x0)
+
+/* Embeeded Jack and Type Detection Control 2 (0x0011) */
+#define RT5668_EXT_JD_SRC			(0x7 << 4)
+#define RT5668_EXT_JD_SRC_SFT			4
+#define RT5668_EXT_JD_SRC_GPIO_JD1		(0x0 << 4)
+#define RT5668_EXT_JD_SRC_GPIO_JD2		(0x1 << 4)
+#define RT5668_EXT_JD_SRC_JDH			(0x2 << 4)
+#define RT5668_EXT_JD_SRC_JDL			(0x3 << 4)
+#define RT5668_EXT_JD_SRC_MANUAL		(0x4 << 4)
+#define RT5668_JACK_TYPE_MASK			(0x3)
+
+/* Combo Jack and Type Detection Control 3 (0x0012) */
+#define RT5668_CBJ_IN_BUF_EN			(0x1 << 7)
+
+/* Combo Jack and Type Detection Control 4 (0x0013) */
+#define RT5668_SEL_SHT_MID_TON_MASK		(0x3 << 12)
+#define RT5668_SEL_SHT_MID_TON_2		(0x0 << 12)
+#define RT5668_SEL_SHT_MID_TON_3		(0x1 << 12)
+#define RT5668_CBJ_JD_TEST_MASK			(0x1 << 6)
+#define RT5668_CBJ_JD_TEST_NORM			(0x0 << 6)
+#define RT5668_CBJ_JD_TEST_MODE			(0x1 << 6)
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5668_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5668_DAC_L1_VOL_SFT			8
+#define RT5668_DAC_R1_VOL_MASK			(0xff)
+#define RT5668_DAC_R1_VOL_SFT			0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5668_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5668_ADC_L_VOL_SFT			8
+#define RT5668_ADC_R_VOL_MASK			(0x7f)
+#define RT5668_ADC_R_VOL_SFT			0
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5668_STO1_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5668_STO1_ADC_L_BST_SFT		14
+#define RT5668_STO1_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5668_STO1_ADC_R_BST_SFT		12
+
+/* Sidetone Control (0x0024) */
+#define RT5668_ST_SRC_SEL			(0x1 << 8)
+#define RT5668_ST_SRC_SFT			8
+#define RT5668_ST_EN_MASK			(0x1 << 6)
+#define RT5668_ST_DIS				(0x0 << 6)
+#define RT5668_ST_EN				(0x1 << 6)
+#define RT5668_ST_EN_SFT			6
+
+/* Stereo1 ADC Mixer Control (0x0026) */
+#define RT5668_M_STO1_ADC_L1			(0x1 << 15)
+#define RT5668_M_STO1_ADC_L1_SFT		15
+#define RT5668_M_STO1_ADC_L2			(0x1 << 14)
+#define RT5668_M_STO1_ADC_L2_SFT		14
+#define RT5668_STO1_ADC1L_SRC_MASK		(0x1 << 13)
+#define RT5668_STO1_ADC1L_SRC_SFT		13
+#define RT5668_STO1_ADC1_SRC_ADC		(0x1 << 13)
+#define RT5668_STO1_ADC1_SRC_DACMIX		(0x0 << 13)
+#define RT5668_STO1_ADC2L_SRC_MASK		(0x1 << 12)
+#define RT5668_STO1_ADC2L_SRC_SFT		12
+#define RT5668_STO1_ADCL_SRC_MASK		(0x3 << 10)
+#define RT5668_STO1_ADCL_SRC_SFT		10
+#define RT5668_STO1_DD_L_SRC_MASK		(0x1 << 9)
+#define RT5668_STO1_DD_L_SRC_SFT		9
+#define RT5668_STO1_DMIC_SRC_MASK		(0x1 << 8)
+#define RT5668_STO1_DMIC_SRC_SFT		8
+#define RT5668_STO1_DMIC_SRC_DMIC2		(0x1 << 8)
+#define RT5668_STO1_DMIC_SRC_DMIC1		(0x0 << 8)
+#define RT5668_M_STO1_ADC_R1			(0x1 << 7)
+#define RT5668_M_STO1_ADC_R1_SFT		7
+#define RT5668_M_STO1_ADC_R2			(0x1 << 6)
+#define RT5668_M_STO1_ADC_R2_SFT		6
+#define RT5668_STO1_ADC1R_SRC_MASK		(0x1 << 5)
+#define RT5668_STO1_ADC1R_SRC_SFT		5
+#define RT5668_STO1_ADC2R_SRC_MASK		(0x1 << 4)
+#define RT5668_STO1_ADC2R_SRC_SFT		4
+#define RT5668_STO1_ADCR_SRC_MASK		(0x3 << 2)
+#define RT5668_STO1_ADCR_SRC_SFT		2
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5668_M_ADCMIX_L			(0x1 << 15)
+#define RT5668_M_ADCMIX_L_SFT			15
+#define RT5668_M_DAC1_L				(0x1 << 14)
+#define RT5668_M_DAC1_L_SFT			14
+#define RT5668_DAC1_R_SEL_MASK			(0x1 << 10)
+#define RT5668_DAC1_R_SEL_SFT			10
+#define RT5668_DAC1_L_SEL_MASK			(0x1 << 8)
+#define RT5668_DAC1_L_SEL_SFT			8
+#define RT5668_M_ADCMIX_R			(0x1 << 7)
+#define RT5668_M_ADCMIX_R_SFT			7
+#define RT5668_M_DAC1_R				(0x1 << 6)
+#define RT5668_M_DAC1_R_SFT			6
+
+/* Stereo1 DAC Mixer Control (0x002a) */
+#define RT5668_M_DAC_L1_STO_L			(0x1 << 15)
+#define RT5668_M_DAC_L1_STO_L_SFT		15
+#define RT5668_G_DAC_L1_STO_L_MASK		(0x1 << 14)
+#define RT5668_G_DAC_L1_STO_L_SFT		14
+#define RT5668_M_DAC_R1_STO_L			(0x1 << 13)
+#define RT5668_M_DAC_R1_STO_L_SFT		13
+#define RT5668_G_DAC_R1_STO_L_MASK		(0x1 << 12)
+#define RT5668_G_DAC_R1_STO_L_SFT		12
+#define RT5668_M_DAC_L1_STO_R			(0x1 << 7)
+#define RT5668_M_DAC_L1_STO_R_SFT		7
+#define RT5668_G_DAC_L1_STO_R_MASK		(0x1 << 6)
+#define RT5668_G_DAC_L1_STO_R_SFT		6
+#define RT5668_M_DAC_R1_STO_R			(0x1 << 5)
+#define RT5668_M_DAC_R1_STO_R_SFT		5
+#define RT5668_G_DAC_R1_STO_R_MASK		(0x1 << 4)
+#define RT5668_G_DAC_R1_STO_R_SFT		4
+
+/* Analog DAC1 Input Source Control (0x002b) */
+#define RT5668_M_ST_STO_L			(0x1 << 9)
+#define RT5668_M_ST_STO_L_SFT			9
+#define RT5668_M_ST_STO_R			(0x1 << 8)
+#define RT5668_M_ST_STO_R_SFT			8
+#define RT5668_DAC_L1_SRC_MASK			(0x3 << 4)
+#define RT5668_A_DACL1_SFT			4
+#define RT5668_DAC_R1_SRC_MASK			(0x3)
+#define RT5668_A_DACR1_SFT			0
+
+/* Digital Interface Data Control (0x0030) */
+#define RT5668_IF2_ADC_SEL_MASK			(0x3 << 0)
+#define RT5668_IF2_ADC_SEL_SFT			0
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5668_G_CBJ_RM1_L			(0x7 << 10)
+#define RT5668_G_CBJ_RM1_L_SFT			10
+#define RT5668_M_CBJ_RM1_L			(0x1 << 7)
+#define RT5668_M_CBJ_RM1_L_SFT			7
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5668_PWR_I2S1				(0x1 << 15)
+#define RT5668_PWR_I2S1_BIT			15
+#define RT5668_PWR_I2S2				(0x1 << 14)
+#define RT5668_PWR_I2S2_BIT			14
+#define RT5668_PWR_DAC_L1			(0x1 << 11)
+#define RT5668_PWR_DAC_L1_BIT			11
+#define RT5668_PWR_DAC_R1			(0x1 << 10)
+#define RT5668_PWR_DAC_R1_BIT			10
+#define RT5668_PWR_LDO				(0x1 << 8)
+#define RT5668_PWR_LDO_BIT			8
+#define RT5668_PWR_ADC_L1			(0x1 << 4)
+#define RT5668_PWR_ADC_L1_BIT			4
+#define RT5668_PWR_ADC_R1			(0x1 << 3)
+#define RT5668_PWR_ADC_R1_BIT			3
+#define RT5668_DIG_GATE_CTRL			(0x1 << 0)
+#define RT5668_DIG_GATE_CTRL_SFT		0
+
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5668_PWR_ADC_S1F			(0x1 << 15)
+#define RT5668_PWR_ADC_S1F_BIT			15
+#define RT5668_PWR_DAC_S1F			(0x1 << 10)
+#define RT5668_PWR_DAC_S1F_BIT			10
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5668_PWR_VREF1			(0x1 << 15)
+#define RT5668_PWR_VREF1_BIT			15
+#define RT5668_PWR_FV1				(0x1 << 14)
+#define RT5668_PWR_FV1_BIT			14
+#define RT5668_PWR_VREF2			(0x1 << 13)
+#define RT5668_PWR_VREF2_BIT			13
+#define RT5668_PWR_FV2				(0x1 << 12)
+#define RT5668_PWR_FV2_BIT			12
+#define RT5668_LDO1_DBG_MASK			(0x3 << 10)
+#define RT5668_PWR_MB				(0x1 << 9)
+#define RT5668_PWR_MB_BIT			9
+#define RT5668_PWR_BG				(0x1 << 7)
+#define RT5668_PWR_BG_BIT			7
+#define RT5668_LDO1_BYPASS_MASK			(0x1 << 6)
+#define RT5668_LDO1_BYPASS			(0x1 << 6)
+#define RT5668_LDO1_NOT_BYPASS			(0x0 << 6)
+#define RT5668_PWR_MA_BIT			6
+#define RT5668_LDO1_DVO_MASK			(0x3 << 4)
+#define RT5668_LDO1_DVO_09			(0x0 << 4)
+#define RT5668_LDO1_DVO_10			(0x1 << 4)
+#define RT5668_LDO1_DVO_12			(0x2 << 4)
+#define RT5668_LDO1_DVO_14			(0x3 << 4)
+#define RT5668_HP_DRIVER_MASK			(0x3 << 2)
+#define RT5668_HP_DRIVER_1X			(0x0 << 2)
+#define RT5668_HP_DRIVER_3X			(0x1 << 2)
+#define RT5668_HP_DRIVER_5X			(0x3 << 2)
+#define RT5668_PWR_HA_L				(0x1 << 1)
+#define RT5668_PWR_HA_L_BIT			1
+#define RT5668_PWR_HA_R				(0x1 << 0)
+#define RT5668_PWR_HA_R_BIT			0
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5668_PWR_MB1				(0x1 << 11)
+#define RT5668_PWR_MB1_PWR_DOWN			(0x0 << 11)
+#define RT5668_PWR_MB1_BIT			11
+#define RT5668_PWR_MB2				(0x1 << 10)
+#define RT5668_PWR_MB2_PWR_DOWN			(0x0 << 10)
+#define RT5668_PWR_MB2_BIT			10
+#define RT5668_PWR_JDH				(0x1 << 3)
+#define RT5668_PWR_JDH_BIT			3
+#define RT5668_PWR_JDL				(0x1 << 2)
+#define RT5668_PWR_JDL_BIT			2
+#define RT5668_PWR_RM1_L			(0x1 << 1)
+#define RT5668_PWR_RM1_L_BIT			1
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5668_PWR_CBJ				(0x1 << 9)
+#define RT5668_PWR_CBJ_BIT			9
+#define RT5668_PWR_PLL				(0x1 << 6)
+#define RT5668_PWR_PLL_BIT			6
+#define RT5668_PWR_PLL2B			(0x1 << 5)
+#define RT5668_PWR_PLL2B_BIT			5
+#define RT5668_PWR_PLL2F			(0x1 << 4)
+#define RT5668_PWR_PLL2F_BIT			4
+#define RT5668_PWR_LDO2				(0x1 << 2)
+#define RT5668_PWR_LDO2_BIT			2
+#define RT5668_PWR_DET_SPKVDD			(0x1 << 1)
+#define RT5668_PWR_DET_SPKVDD_BIT		1
+
+/* Power Management for Mixer (0x0066) */
+#define RT5668_PWR_STO1_DAC_L			(0x1 << 5)
+#define RT5668_PWR_STO1_DAC_L_BIT		5
+#define RT5668_PWR_STO1_DAC_R			(0x1 << 4)
+#define RT5668_PWR_STO1_DAC_R_BIT		4
+
+/* MCLK and System Clock Detection Control (0x006b) */
+#define RT5668_SYS_CLK_DET			(0x1 << 15)
+#define RT5668_SYS_CLK_DET_SFT			15
+#define RT5668_PLL1_CLK_DET			(0x1 << 14)
+#define RT5668_PLL1_CLK_DET_SFT			14
+#define RT5668_PLL2_CLK_DET			(0x1 << 13)
+#define RT5668_PLL2_CLK_DET_SFT			13
+#define RT5668_POW_CLK_DET2_SFT			8
+#define RT5668_POW_CLK_DET_SFT			0
+
+/* Digital Microphone Control 1 (0x006e) */
+#define RT5668_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5668_DMIC_1_EN_SFT			15
+#define RT5668_DMIC_1_DIS			(0x0 << 15)
+#define RT5668_DMIC_1_EN			(0x1 << 15)
+#define RT5668_DMIC_1_DP_MASK			(0x3 << 4)
+#define RT5668_DMIC_1_DP_SFT			4
+#define RT5668_DMIC_1_DP_GPIO2			(0x0 << 4)
+#define RT5668_DMIC_1_DP_GPIO5			(0x1 << 4)
+#define RT5668_DMIC_CLK_MASK			(0xf << 0)
+#define RT5668_DMIC_CLK_SFT			0
+
+/* I2S1 Audio Serial Data Port Control (0x0070) */
+#define RT5668_SEL_ADCDAT_MASK			(0x1 << 15)
+#define RT5668_SEL_ADCDAT_OUT			(0x0 << 15)
+#define RT5668_SEL_ADCDAT_IN			(0x1 << 15)
+#define RT5668_SEL_ADCDAT_SFT			15
+#define RT5668_I2S1_TX_CHL_MASK			(0x7 << 12)
+#define RT5668_I2S1_TX_CHL_SFT			12
+#define RT5668_I2S1_TX_CHL_16			(0x0 << 12)
+#define RT5668_I2S1_TX_CHL_20			(0x1 << 12)
+#define RT5668_I2S1_TX_CHL_24			(0x2 << 12)
+#define RT5668_I2S1_TX_CHL_32			(0x3 << 12)
+#define RT5668_I2S1_TX_CHL_8			(0x4 << 12)
+#define RT5668_I2S1_RX_CHL_MASK			(0x7 << 8)
+#define RT5668_I2S1_RX_CHL_SFT			8
+#define RT5668_I2S1_RX_CHL_16			(0x0 << 8)
+#define RT5668_I2S1_RX_CHL_20			(0x1 << 8)
+#define RT5668_I2S1_RX_CHL_24			(0x2 << 8)
+#define RT5668_I2S1_RX_CHL_32			(0x3 << 8)
+#define RT5668_I2S1_RX_CHL_8			(0x4 << 8)
+#define RT5668_I2S1_MONO_MASK			(0x1 << 7)
+#define RT5668_I2S1_MONO_EN			(0x1 << 7)
+#define RT5668_I2S1_MONO_DIS			(0x0 << 7)
+#define RT5668_I2S2_MONO_MASK			(0x1 << 6)
+#define RT5668_I2S2_MONO_EN			(0x1 << 6)
+#define RT5668_I2S2_MONO_DIS			(0x0 << 6)
+#define RT5668_I2S1_DL_MASK			(0x7 << 4)
+#define RT5668_I2S1_DL_SFT			4
+#define RT5668_I2S1_DL_16			(0x0 << 4)
+#define RT5668_I2S1_DL_20			(0x1 << 4)
+#define RT5668_I2S1_DL_24			(0x2 << 4)
+#define RT5668_I2S1_DL_32			(0x3 << 4)
+#define RT5668_I2S1_DL_8			(0x4 << 4)
+
+/* I2S1/2 Audio Serial Data Port Control (0x0070)(0x0071) */
+#define RT5668_I2S2_MS_MASK			(0x1 << 15)
+#define RT5668_I2S2_MS_SFT			15
+#define RT5668_I2S2_MS_M			(0x0 << 15)
+#define RT5668_I2S2_MS_S			(0x1 << 15)
+#define RT5668_I2S2_PIN_CFG_MASK		(0x1 << 14)
+#define RT5668_I2S2_PIN_CFG_SFT			14
+#define RT5668_I2S2_CLK_SEL_MASK		(0x1 << 11)
+#define RT5668_I2S2_CLK_SEL_SFT			11
+#define RT5668_I2S2_OUT_MASK			(0x1 << 9)
+#define RT5668_I2S2_OUT_SFT			9
+#define RT5668_I2S2_OUT_UM			(0x0 << 9)
+#define RT5668_I2S2_OUT_M			(0x1 << 9)
+#define RT5668_I2S_BP_MASK			(0x1 << 8)
+#define RT5668_I2S_BP_SFT			8
+#define RT5668_I2S_BP_NOR			(0x0 << 8)
+#define RT5668_I2S_BP_INV			(0x1 << 8)
+#define RT5668_I2S2_MONO_EN			(0x1 << 6)
+#define RT5668_I2S2_MONO_DIS			(0x0 << 6)
+#define RT5668_I2S2_DL_MASK			(0x3 << 4)
+#define RT5668_I2S2_DL_SFT			4
+#define RT5668_I2S2_DL_16			(0x0 << 4)
+#define RT5668_I2S2_DL_20			(0x1 << 4)
+#define RT5668_I2S2_DL_24			(0x2 << 4)
+#define RT5668_I2S2_DL_8			(0x3 << 4)
+#define RT5668_I2S_DF_MASK			(0x7)
+#define RT5668_I2S_DF_SFT			0
+#define RT5668_I2S_DF_I2S			(0x0)
+#define RT5668_I2S_DF_LEFT			(0x1)
+#define RT5668_I2S_DF_PCM_A			(0x2)
+#define RT5668_I2S_DF_PCM_B			(0x3)
+#define RT5668_I2S_DF_PCM_A_N			(0x6)
+#define RT5668_I2S_DF_PCM_B_N			(0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5668_ADC_OSR_MASK			(0xf << 12)
+#define RT5668_ADC_OSR_SFT			12
+#define RT5668_ADC_OSR_D_1			(0x0 << 12)
+#define RT5668_ADC_OSR_D_2			(0x1 << 12)
+#define RT5668_ADC_OSR_D_4			(0x2 << 12)
+#define RT5668_ADC_OSR_D_6			(0x3 << 12)
+#define RT5668_ADC_OSR_D_8			(0x4 << 12)
+#define RT5668_ADC_OSR_D_12			(0x5 << 12)
+#define RT5668_ADC_OSR_D_16			(0x6 << 12)
+#define RT5668_ADC_OSR_D_24			(0x7 << 12)
+#define RT5668_ADC_OSR_D_32			(0x8 << 12)
+#define RT5668_ADC_OSR_D_48			(0x9 << 12)
+#define RT5668_I2S_M_DIV_MASK			(0xf << 12)
+#define RT5668_I2S_M_DIV_SFT			8
+#define RT5668_I2S_M_D_1			(0x0 << 8)
+#define RT5668_I2S_M_D_2			(0x1 << 8)
+#define RT5668_I2S_M_D_3			(0x2 << 8)
+#define RT5668_I2S_M_D_4			(0x3 << 8)
+#define RT5668_I2S_M_D_6			(0x4 << 8)
+#define RT5668_I2S_M_D_8			(0x5 << 8)
+#define RT5668_I2S_M_D_12			(0x6 << 8)
+#define RT5668_I2S_M_D_16			(0x7 << 8)
+#define RT5668_I2S_M_D_24			(0x8 << 8)
+#define RT5668_I2S_M_D_32			(0x9 << 8)
+#define RT5668_I2S_M_D_48			(0x10 << 8)
+#define RT5668_I2S_CLK_SRC_MASK			(0x7 << 4)
+#define RT5668_I2S_CLK_SRC_SFT			4
+#define RT5668_I2S_CLK_SRC_MCLK			(0x0 << 4)
+#define RT5668_I2S_CLK_SRC_PLL1			(0x1 << 4)
+#define RT5668_I2S_CLK_SRC_PLL2			(0x2 << 4)
+#define RT5668_I2S_CLK_SRC_SDW			(0x3 << 4)
+#define RT5668_I2S_CLK_SRC_RCCLK		(0x4 << 4) /* 25M */
+#define RT5668_DAC_OSR_MASK			(0xf << 0)
+#define RT5668_DAC_OSR_SFT			0
+#define RT5668_DAC_OSR_D_1			(0x0 << 0)
+#define RT5668_DAC_OSR_D_2			(0x1 << 0)
+#define RT5668_DAC_OSR_D_4			(0x2 << 0)
+#define RT5668_DAC_OSR_D_6			(0x3 << 0)
+#define RT5668_DAC_OSR_D_8			(0x4 << 0)
+#define RT5668_DAC_OSR_D_12			(0x5 << 0)
+#define RT5668_DAC_OSR_D_16			(0x6 << 0)
+#define RT5668_DAC_OSR_D_24			(0x7 << 0)
+#define RT5668_DAC_OSR_D_32			(0x8 << 0)
+#define RT5668_DAC_OSR_D_48			(0x9 << 0)
+
+/* ADC/DAC Clock Control 2 (0x0074) */
+#define RT5668_I2S2_BCLK_MS2_MASK		(0x1 << 11)
+#define RT5668_I2S2_BCLK_MS2_SFT		11
+#define RT5668_I2S2_BCLK_MS2_32			(0x0 << 11)
+#define RT5668_I2S2_BCLK_MS2_64			(0x1 << 11)
+
+
+/* TDM control 1 (0x0079) */
+#define RT5668_TDM_TX_CH_MASK			(0x3 << 12)
+#define RT5668_TDM_TX_CH_2			(0x0 << 12)
+#define RT5668_TDM_TX_CH_4			(0x1 << 12)
+#define RT5668_TDM_TX_CH_6			(0x2 << 12)
+#define RT5668_TDM_TX_CH_8			(0x3 << 12)
+#define RT5668_TDM_RX_CH_MASK			(0x3 << 8)
+#define RT5668_TDM_RX_CH_2			(0x0 << 8)
+#define RT5668_TDM_RX_CH_4			(0x1 << 8)
+#define RT5668_TDM_RX_CH_6			(0x2 << 8)
+#define RT5668_TDM_RX_CH_8			(0x3 << 8)
+#define RT5668_TDM_ADC_LCA_MASK			(0xf << 4)
+#define RT5668_TDM_ADC_LCA_SFT			4
+#define RT5668_TDM_ADC_DL_SFT			0
+
+/* TDM control 3 (0x007a) */
+#define RT5668_IF1_ADC1_SEL_SFT			14
+#define RT5668_IF1_ADC2_SEL_SFT			12
+#define RT5668_IF1_ADC3_SEL_SFT			10
+#define RT5668_IF1_ADC4_SEL_SFT			8
+#define RT5668_TDM_ADC_SEL_SFT			4
+
+/* TDM/I2S control (0x007e) */
+#define RT5668_TDM_S_BP_MASK			(0x1 << 15)
+#define RT5668_TDM_S_BP_SFT			15
+#define RT5668_TDM_S_BP_NOR			(0x0 << 15)
+#define RT5668_TDM_S_BP_INV			(0x1 << 15)
+#define RT5668_TDM_S_LP_MASK			(0x1 << 14)
+#define RT5668_TDM_S_LP_SFT			14
+#define RT5668_TDM_S_LP_NOR			(0x0 << 14)
+#define RT5668_TDM_S_LP_INV			(0x1 << 14)
+#define RT5668_TDM_DF_MASK			(0x7 << 11)
+#define RT5668_TDM_DF_SFT			11
+#define RT5668_TDM_DF_I2S			(0x0 << 11)
+#define RT5668_TDM_DF_LEFT			(0x1 << 11)
+#define RT5668_TDM_DF_PCM_A			(0x2 << 11)
+#define RT5668_TDM_DF_PCM_B			(0x3 << 11)
+#define RT5668_TDM_DF_PCM_A_N			(0x6 << 11)
+#define RT5668_TDM_DF_PCM_B_N			(0x7 << 11)
+#define RT5668_TDM_CL_MASK			(0x3 << 4)
+#define RT5668_TDM_CL_16			(0x0 << 4)
+#define RT5668_TDM_CL_20			(0x1 << 4)
+#define RT5668_TDM_CL_24			(0x2 << 4)
+#define RT5668_TDM_CL_32			(0x3 << 4)
+#define RT5668_TDM_M_BP_MASK			(0x1 << 2)
+#define RT5668_TDM_M_BP_SFT			2
+#define RT5668_TDM_M_BP_NOR			(0x0 << 2)
+#define RT5668_TDM_M_BP_INV			(0x1 << 2)
+#define RT5668_TDM_M_LP_MASK			(0x1 << 1)
+#define RT5668_TDM_M_LP_SFT			1
+#define RT5668_TDM_M_LP_NOR			(0x0 << 1)
+#define RT5668_TDM_M_LP_INV			(0x1 << 1)
+#define RT5668_TDM_MS_MASK			(0x1 << 0)
+#define RT5668_TDM_MS_SFT			0
+#define RT5668_TDM_MS_M				(0x0 << 0)
+#define RT5668_TDM_MS_S				(0x1 << 0)
+
+/* Global Clock Control (0x0080) */
+#define RT5668_SCLK_SRC_MASK			(0x7 << 13)
+#define RT5668_SCLK_SRC_SFT			13
+#define RT5668_SCLK_SRC_MCLK			(0x0 << 13)
+#define RT5668_SCLK_SRC_PLL1			(0x1 << 13)
+#define RT5668_SCLK_SRC_PLL2			(0x2 << 13)
+#define RT5668_SCLK_SRC_SDW			(0x3 << 13)
+#define RT5668_SCLK_SRC_RCCLK			(0x4 << 13)
+#define RT5668_PLL1_SRC_MASK			(0x3 << 10)
+#define RT5668_PLL1_SRC_SFT			10
+#define RT5668_PLL1_SRC_MCLK			(0x0 << 10)
+#define RT5668_PLL1_SRC_BCLK1			(0x1 << 10)
+#define RT5668_PLL1_SRC_SDW			(0x2 << 10)
+#define RT5668_PLL1_SRC_RC			(0x3 << 10)
+#define RT5668_PLL2_SRC_MASK			(0x3 << 8)
+#define RT5668_PLL2_SRC_SFT			8
+#define RT5668_PLL2_SRC_MCLK			(0x0 << 8)
+#define RT5668_PLL2_SRC_BCLK1			(0x1 << 8)
+#define RT5668_PLL2_SRC_SDW			(0x2 << 8)
+#define RT5668_PLL2_SRC_RC			(0x3 << 8)
+
+
+
+#define RT5668_PLL_INP_MAX			40000000
+#define RT5668_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5668_PLL_N_MAX			0x001ff
+#define RT5668_PLL_N_MASK			(RT5668_PLL_N_MAX << 7)
+#define RT5668_PLL_N_SFT			7
+#define RT5668_PLL_K_MAX			0x001f
+#define RT5668_PLL_K_MASK			(RT5668_PLL_K_MAX)
+#define RT5668_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5668_PLL_M_MAX			0x00f
+#define RT5668_PLL_M_MASK			(RT5668_PLL_M_MAX << 12)
+#define RT5668_PLL_M_SFT			12
+#define RT5668_PLL_M_BP				(0x1 << 11)
+#define RT5668_PLL_M_BP_SFT			11
+#define RT5668_PLL_K_BP				(0x1 << 10)
+#define RT5668_PLL_K_BP_SFT			10
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5668_DA_ASRC_MASK			(0x1 << 13)
+#define RT5668_DA_ASRC_SFT			13
+#define RT5668_DAC_STO1_ASRC_MASK		(0x1 << 12)
+#define RT5668_DAC_STO1_ASRC_SFT		12
+#define RT5668_AD_ASRC_MASK			(0x1 << 8)
+#define RT5668_AD_ASRC_SFT			8
+#define RT5668_AD_ASRC_SEL_MASK			(0x1 << 4)
+#define RT5668_AD_ASRC_SEL_SFT			4
+#define RT5668_DMIC_ASRC_MASK			(0x1 << 3)
+#define RT5668_DMIC_ASRC_SFT			3
+#define RT5668_ADC_STO1_ASRC_MASK		(0x1 << 2)
+#define RT5668_ADC_STO1_ASRC_SFT		2
+#define RT5668_DA_ASRC_SEL_MASK			(0x1 << 0)
+#define RT5668_DA_ASRC_SEL_SFT			0
+
+/* PLL tracking mode 2 3 (0x0084)(0x0085)*/
+#define RT5668_FILTER_CLK_SEL_MASK		(0x7 << 12)
+#define RT5668_FILTER_CLK_SEL_SFT		12
+
+/* ASRC Control 4 (0x0086) */
+#define RT5668_ASRCIN_FTK_N1_MASK		(0x3 << 14)
+#define RT5668_ASRCIN_FTK_N1_SFT		14
+#define RT5668_ASRCIN_FTK_N2_MASK		(0x3 << 12)
+#define RT5668_ASRCIN_FTK_N2_SFT		12
+#define RT5668_ASRCIN_FTK_M1_MASK		(0x7 << 8)
+#define RT5668_ASRCIN_FTK_M1_SFT		8
+#define RT5668_ASRCIN_FTK_M2_MASK		(0x7 << 4)
+#define RT5668_ASRCIN_FTK_M2_SFT		4
+
+/* SoundWire reference clk (0x008d) */
+#define RT5668_PLL2_OUT_MASK			(0x1 << 8)
+#define RT5668_PLL2_OUT_98M			(0x0 << 8)
+#define RT5668_PLL2_OUT_49M			(0x1 << 8)
+#define RT5668_SDW_REF_2_MASK			(0xf << 4)
+#define RT5668_SDW_REF_2_SFT			4
+#define RT5668_SDW_REF_2_48K			(0x0 << 4)
+#define RT5668_SDW_REF_2_96K			(0x1 << 4)
+#define RT5668_SDW_REF_2_192K			(0x2 << 4)
+#define RT5668_SDW_REF_2_32K			(0x3 << 4)
+#define RT5668_SDW_REF_2_24K			(0x4 << 4)
+#define RT5668_SDW_REF_2_16K			(0x5 << 4)
+#define RT5668_SDW_REF_2_12K			(0x6 << 4)
+#define RT5668_SDW_REF_2_8K			(0x7 << 4)
+#define RT5668_SDW_REF_2_44K			(0x8 << 4)
+#define RT5668_SDW_REF_2_88K			(0x9 << 4)
+#define RT5668_SDW_REF_2_176K			(0xa << 4)
+#define RT5668_SDW_REF_2_353K			(0xb << 4)
+#define RT5668_SDW_REF_2_22K			(0xc << 4)
+#define RT5668_SDW_REF_2_384K			(0xd << 4)
+#define RT5668_SDW_REF_2_11K			(0xe << 4)
+#define RT5668_SDW_REF_1_MASK			(0xf << 0)
+#define RT5668_SDW_REF_1_SFT			0
+#define RT5668_SDW_REF_1_48K			(0x0 << 0)
+#define RT5668_SDW_REF_1_96K			(0x1 << 0)
+#define RT5668_SDW_REF_1_192K			(0x2 << 0)
+#define RT5668_SDW_REF_1_32K			(0x3 << 0)
+#define RT5668_SDW_REF_1_24K			(0x4 << 0)
+#define RT5668_SDW_REF_1_16K			(0x5 << 0)
+#define RT5668_SDW_REF_1_12K			(0x6 << 0)
+#define RT5668_SDW_REF_1_8K			(0x7 << 0)
+#define RT5668_SDW_REF_1_44K			(0x8 << 0)
+#define RT5668_SDW_REF_1_88K			(0x9 << 0)
+#define RT5668_SDW_REF_1_176K			(0xa << 0)
+#define RT5668_SDW_REF_1_353K			(0xb << 0)
+#define RT5668_SDW_REF_1_22K			(0xc << 0)
+#define RT5668_SDW_REF_1_384K			(0xd << 0)
+#define RT5668_SDW_REF_1_11K			(0xe << 0)
+
+/* Depop Mode Control 1 (0x008e) */
+#define RT5668_PUMP_EN				(0x1 << 3)
+#define RT5668_PUMP_EN_SFT				3
+#define RT5668_CAPLESS_EN			(0x1 << 0)
+#define RT5668_CAPLESS_EN_SFT			0
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5668_RAMP_MASK			(0x1 << 12)
+#define RT5668_RAMP_SFT				12
+#define RT5668_RAMP_DIS				(0x0 << 12)
+#define RT5668_RAMP_EN				(0x1 << 12)
+#define RT5668_BPS_MASK				(0x1 << 11)
+#define RT5668_BPS_SFT				11
+#define RT5668_BPS_DIS				(0x0 << 11)
+#define RT5668_BPS_EN				(0x1 << 11)
+#define RT5668_FAST_UPDN_MASK			(0x1 << 10)
+#define RT5668_FAST_UPDN_SFT			10
+#define RT5668_FAST_UPDN_DIS			(0x0 << 10)
+#define RT5668_FAST_UPDN_EN			(0x1 << 10)
+#define RT5668_VLO_MASK				(0x1 << 7)
+#define RT5668_VLO_SFT				7
+#define RT5668_VLO_3V				(0x0 << 7)
+#define RT5668_VLO_33V				(0x1 << 7)
+
+/* HPOUT charge pump 1 (0x0091) */
+#define RT5668_OSW_L_MASK			(0x1 << 11)
+#define RT5668_OSW_L_SFT			11
+#define RT5668_OSW_L_DIS			(0x0 << 11)
+#define RT5668_OSW_L_EN				(0x1 << 11)
+#define RT5668_OSW_R_MASK			(0x1 << 10)
+#define RT5668_OSW_R_SFT			10
+#define RT5668_OSW_R_DIS			(0x0 << 10)
+#define RT5668_OSW_R_EN				(0x1 << 10)
+#define RT5668_PM_HP_MASK			(0x3 << 8)
+#define RT5668_PM_HP_SFT			8
+#define RT5668_PM_HP_LV				(0x0 << 8)
+#define RT5668_PM_HP_MV				(0x1 << 8)
+#define RT5668_PM_HP_HV				(0x2 << 8)
+#define RT5668_IB_HP_MASK			(0x3 << 6)
+#define RT5668_IB_HP_SFT			6
+#define RT5668_IB_HP_125IL			(0x0 << 6)
+#define RT5668_IB_HP_25IL			(0x1 << 6)
+#define RT5668_IB_HP_5IL			(0x2 << 6)
+#define RT5668_IB_HP_1IL			(0x3 << 6)
+
+/* Micbias Control1 (0x93) */
+#define RT5668_MIC1_OV_MASK			(0x3 << 14)
+#define RT5668_MIC1_OV_SFT			14
+#define RT5668_MIC1_OV_2V7			(0x0 << 14)
+#define RT5668_MIC1_OV_2V4			(0x1 << 14)
+#define RT5668_MIC1_OV_2V25			(0x3 << 14)
+#define RT5668_MIC1_OV_1V8			(0x4 << 14)
+#define RT5668_MIC1_CLK_MASK			(0x1 << 13)
+#define RT5668_MIC1_CLK_SFT			13
+#define RT5668_MIC1_CLK_DIS			(0x0 << 13)
+#define RT5668_MIC1_CLK_EN			(0x1 << 13)
+#define RT5668_MIC1_OVCD_MASK			(0x1 << 12)
+#define RT5668_MIC1_OVCD_SFT			12
+#define RT5668_MIC1_OVCD_DIS			(0x0 << 12)
+#define RT5668_MIC1_OVCD_EN			(0x1 << 12)
+#define RT5668_MIC1_OVTH_MASK			(0x3 << 10)
+#define RT5668_MIC1_OVTH_SFT			10
+#define RT5668_MIC1_OVTH_768UA			(0x0 << 10)
+#define RT5668_MIC1_OVTH_960UA			(0x1 << 10)
+#define RT5668_MIC1_OVTH_1152UA			(0x2 << 10)
+#define RT5668_MIC1_OVTH_1960UA			(0x3 << 10)
+#define RT5668_MIC2_OV_MASK			(0x3 << 8)
+#define RT5668_MIC2_OV_SFT			8
+#define RT5668_MIC2_OV_2V7			(0x0 << 8)
+#define RT5668_MIC2_OV_2V4			(0x1 << 8)
+#define RT5668_MIC2_OV_2V25			(0x3 << 8)
+#define RT5668_MIC2_OV_1V8			(0x4 << 8)
+#define RT5668_MIC2_CLK_MASK			(0x1 << 7)
+#define RT5668_MIC2_CLK_SFT			7
+#define RT5668_MIC2_CLK_DIS			(0x0 << 7)
+#define RT5668_MIC2_CLK_EN			(0x1 << 7)
+#define RT5668_MIC2_OVTH_MASK			(0x3 << 4)
+#define RT5668_MIC2_OVTH_SFT			4
+#define RT5668_MIC2_OVTH_768UA			(0x0 << 4)
+#define RT5668_MIC2_OVTH_960UA			(0x1 << 4)
+#define RT5668_MIC2_OVTH_1152UA			(0x2 << 4)
+#define RT5668_MIC2_OVTH_1960UA			(0x3 << 4)
+#define RT5668_PWR_MB_MASK			(0x1 << 3)
+#define RT5668_PWR_MB_SFT			3
+#define RT5668_PWR_MB_PD			(0x0 << 3)
+#define RT5668_PWR_MB_PU			(0x1 << 3)
+
+/* Micbias Control2 (0x0094) */
+#define RT5668_PWR_CLK25M_MASK			(0x1 << 9)
+#define RT5668_PWR_CLK25M_SFT			9
+#define RT5668_PWR_CLK25M_PD			(0x0 << 9)
+#define RT5668_PWR_CLK25M_PU			(0x1 << 9)
+#define RT5668_PWR_CLK1M_MASK			(0x1 << 8)
+#define RT5668_PWR_CLK1M_SFT			8
+#define RT5668_PWR_CLK1M_PD			(0x0 << 8)
+#define RT5668_PWR_CLK1M_PU			(0x1 << 8)
+
+/* RC Clock Control (0x009f) */
+#define RT5668_POW_IRQ				(0x1 << 15)
+#define RT5668_POW_JDH				(0x1 << 14)
+#define RT5668_POW_JDL				(0x1 << 13)
+#define RT5668_POW_ANA				(0x1 << 12)
+
+/* I2S Master Mode Clock Control 1 (0x00a0) */
+#define RT5668_CLK_SRC_MCLK			(0x0)
+#define RT5668_CLK_SRC_PLL1			(0x1)
+#define RT5668_CLK_SRC_PLL2			(0x2)
+#define RT5668_CLK_SRC_SDW			(0x3)
+#define RT5668_CLK_SRC_RCCLK			(0x4)
+#define RT5668_I2S_PD_1				(0x0)
+#define RT5668_I2S_PD_2				(0x1)
+#define RT5668_I2S_PD_3				(0x2)
+#define RT5668_I2S_PD_4				(0x3)
+#define RT5668_I2S_PD_6				(0x4)
+#define RT5668_I2S_PD_8				(0x5)
+#define RT5668_I2S_PD_12			(0x6)
+#define RT5668_I2S_PD_16			(0x7)
+#define RT5668_I2S_PD_24			(0x8)
+#define RT5668_I2S_PD_32			(0x9)
+#define RT5668_I2S_PD_48			(0xa)
+#define RT5668_I2S2_SRC_MASK			(0x3 << 4)
+#define RT5668_I2S2_SRC_SFT			4
+#define RT5668_I2S2_M_PD_MASK			(0xf << 0)
+#define RT5668_I2S2_M_PD_SFT			0
+
+/* IRQ Control 1 (0x00b6) */
+#define RT5668_JD1_PULSE_EN_MASK		(0x1 << 10)
+#define RT5668_JD1_PULSE_EN_SFT			10
+#define RT5668_JD1_PULSE_DIS			(0x0 << 10)
+#define RT5668_JD1_PULSE_EN			(0x1 << 10)
+
+/* IRQ Control 2 (0x00b7) */
+#define RT5668_JD1_EN_MASK			(0x1 << 15)
+#define RT5668_JD1_EN_SFT			15
+#define RT5668_JD1_DIS				(0x0 << 15)
+#define RT5668_JD1_EN				(0x1 << 15)
+#define RT5668_JD1_POL_MASK			(0x1 << 13)
+#define RT5668_JD1_POL_NOR			(0x0 << 13)
+#define RT5668_JD1_POL_INV			(0x1 << 13)
+
+/* IRQ Control 3 (0x00b8) */
+#define RT5668_IL_IRQ_MASK			(0x1 << 7)
+#define RT5668_IL_IRQ_DIS			(0x0 << 7)
+#define RT5668_IL_IRQ_EN			(0x1 << 7)
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5668_GP1_PIN_MASK			(0x3 << 14)
+#define RT5668_GP1_PIN_SFT			14
+#define RT5668_GP1_PIN_GPIO1			(0x0 << 14)
+#define RT5668_GP1_PIN_IRQ			(0x1 << 14)
+#define RT5668_GP1_PIN_DMIC_CLK			(0x2 << 14)
+#define RT5668_GP2_PIN_MASK			(0x3 << 12)
+#define RT5668_GP2_PIN_SFT			12
+#define RT5668_GP2_PIN_GPIO2			(0x0 << 12)
+#define RT5668_GP2_PIN_LRCK2			(0x1 << 12)
+#define RT5668_GP2_PIN_DMIC_SDA			(0x2 << 12)
+#define RT5668_GP3_PIN_MASK			(0x3 << 10)
+#define RT5668_GP3_PIN_SFT			10
+#define RT5668_GP3_PIN_GPIO3			(0x0 << 10)
+#define RT5668_GP3_PIN_BCLK2			(0x1 << 10)
+#define RT5668_GP3_PIN_DMIC_CLK			(0x2 << 10)
+#define RT5668_GP4_PIN_MASK			(0x3 << 8)
+#define RT5668_GP4_PIN_SFT			8
+#define RT5668_GP4_PIN_GPIO4			(0x0 << 8)
+#define RT5668_GP4_PIN_ADCDAT1			(0x1 << 8)
+#define RT5668_GP4_PIN_DMIC_CLK			(0x2 << 8)
+#define RT5668_GP4_PIN_ADCDAT2			(0x3 << 8)
+#define RT5668_GP5_PIN_MASK			(0x3 << 6)
+#define RT5668_GP5_PIN_SFT			6
+#define RT5668_GP5_PIN_GPIO5			(0x0 << 6)
+#define RT5668_GP5_PIN_DACDAT1			(0x1 << 6)
+#define RT5668_GP5_PIN_DMIC_SDA			(0x2 << 6)
+#define RT5668_GP6_PIN_MASK			(0x1 << 5)
+#define RT5668_GP6_PIN_SFT			5
+#define RT5668_GP6_PIN_GPIO6			(0x0 << 5)
+#define RT5668_GP6_PIN_LRCK1			(0x1 << 5)
+
+/* GPIO Control 2 (0x00c1)*/
+#define RT5668_GP1_PF_MASK			(0x1 << 15)
+#define RT5668_GP1_PF_IN			(0x0 << 15)
+#define RT5668_GP1_PF_OUT			(0x1 << 15)
+#define RT5668_GP1_OUT_MASK			(0x1 << 14)
+#define RT5668_GP1_OUT_L			(0x0 << 14)
+#define RT5668_GP1_OUT_H			(0x1 << 14)
+#define RT5668_GP2_PF_MASK			(0x1 << 13)
+#define RT5668_GP2_PF_IN			(0x0 << 13)
+#define RT5668_GP2_PF_OUT			(0x1 << 13)
+#define RT5668_GP2_OUT_MASK			(0x1 << 12)
+#define RT5668_GP2_OUT_L			(0x0 << 12)
+#define RT5668_GP2_OUT_H			(0x1 << 12)
+#define RT5668_GP3_PF_MASK			(0x1 << 11)
+#define RT5668_GP3_PF_IN			(0x0 << 11)
+#define RT5668_GP3_PF_OUT			(0x1 << 11)
+#define RT5668_GP3_OUT_MASK			(0x1 << 10)
+#define RT5668_GP3_OUT_L			(0x0 << 10)
+#define RT5668_GP3_OUT_H			(0x1 << 10)
+#define RT5668_GP4_PF_MASK			(0x1 << 9)
+#define RT5668_GP4_PF_IN			(0x0 << 9)
+#define RT5668_GP4_PF_OUT			(0x1 << 9)
+#define RT5668_GP4_OUT_MASK			(0x1 << 8)
+#define RT5668_GP4_OUT_L			(0x0 << 8)
+#define RT5668_GP4_OUT_H			(0x1 << 8)
+#define RT5668_GP5_PF_MASK			(0x1 << 7)
+#define RT5668_GP5_PF_IN			(0x0 << 7)
+#define RT5668_GP5_PF_OUT			(0x1 << 7)
+#define RT5668_GP5_OUT_MASK			(0x1 << 6)
+#define RT5668_GP5_OUT_L			(0x0 << 6)
+#define RT5668_GP5_OUT_H			(0x1 << 6)
+#define RT5668_GP6_PF_MASK			(0x1 << 5)
+#define RT5668_GP6_PF_IN			(0x0 << 5)
+#define RT5668_GP6_PF_OUT			(0x1 << 5)
+#define RT5668_GP6_OUT_MASK			(0x1 << 4)
+#define RT5668_GP6_OUT_L			(0x0 << 4)
+#define RT5668_GP6_OUT_H			(0x1 << 4)
+
+
+/* GPIO Status (0x00c2) */
+#define RT5668_GP6_STA				(0x1 << 6)
+#define RT5668_GP5_STA				(0x1 << 5)
+#define RT5668_GP4_STA				(0x1 << 4)
+#define RT5668_GP3_STA				(0x1 << 3)
+#define RT5668_GP2_STA				(0x1 << 2)
+#define RT5668_GP1_STA				(0x1 << 1)
+
+/* Soft volume and zero cross control 1 (0x00d9) */
+#define RT5668_SV_MASK				(0x1 << 15)
+#define RT5668_SV_SFT				15
+#define RT5668_SV_DIS				(0x0 << 15)
+#define RT5668_SV_EN				(0x1 << 15)
+#define RT5668_ZCD_MASK				(0x1 << 10)
+#define RT5668_ZCD_SFT				10
+#define RT5668_ZCD_PD				(0x0 << 10)
+#define RT5668_ZCD_PU				(0x1 << 10)
+#define RT5668_SV_DLY_MASK			(0xf)
+#define RT5668_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0x00da) */
+#define RT5668_ZCD_BST1_CBJ_MASK		(0x1 << 7)
+#define RT5668_ZCD_BST1_CBJ_SFT			7
+#define RT5668_ZCD_BST1_CBJ_DIS			(0x0 << 7)
+#define RT5668_ZCD_BST1_CBJ_EN			(0x1 << 7)
+#define RT5668_ZCD_RECMIX_MASK			(0x1)
+#define RT5668_ZCD_RECMIX_SFT			0
+#define RT5668_ZCD_RECMIX_DIS			(0x0)
+#define RT5668_ZCD_RECMIX_EN			(0x1)
+
+/* 4 Button Inline Command Control 2 (0x00e3) */
+#define RT5668_4BTN_IL_MASK			(0x1 << 15)
+#define RT5668_4BTN_IL_EN			(0x1 << 15)
+#define RT5668_4BTN_IL_DIS			(0x0 << 15)
+#define RT5668_4BTN_IL_RST_MASK			(0x1 << 14)
+#define RT5668_4BTN_IL_NOR			(0x1 << 14)
+#define RT5668_4BTN_IL_RST			(0x0 << 14)
+
+/* Analog JD Control (0x00f0) */
+#define RT5668_JDH_RS_MASK			(0x1 << 4)
+#define RT5668_JDH_NO_PLUG			(0x1 << 4)
+#define RT5668_JDH_PLUG				(0x0 << 4)
+
+/* Chopper and Clock control for DAC (0x013a)*/
+#define RT5668_CKXEN_DAC1_MASK			(0x1 << 13)
+#define RT5668_CKXEN_DAC1_SFT			13
+#define RT5668_CKGEN_DAC1_MASK			(0x1 << 12)
+#define RT5668_CKGEN_DAC1_SFT			12
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5668_CKXEN_ADC1_MASK			(0x1 << 13)
+#define RT5668_CKXEN_ADC1_SFT			13
+#define RT5668_CKGEN_ADC1_MASK			(0x1 << 12)
+#define RT5668_CKGEN_ADC1_SFT			12
+
+/* Volume test (0x013f)*/
+#define RT5668_SEL_CLK_VOL_MASK			(0x1 << 15)
+#define RT5668_SEL_CLK_VOL_EN			(0x1 << 15)
+#define RT5668_SEL_CLK_VOL_DIS			(0x0 << 15)
+
+/* Test Mode Control 1 (0x0145) */
+#define RT5668_AD2DA_LB_MASK			(0x1 << 10)
+#define RT5668_AD2DA_LB_SFT			10
+
+/* Stereo Noise Gate Control 1 (0x0160) */
+#define RT5668_NG2_EN_MASK			(0x1 << 15)
+#define RT5668_NG2_EN				(0x1 << 15)
+#define RT5668_NG2_DIS				(0x0 << 15)
+
+/* Stereo1 DAC Silence Detection Control (0x0190) */
+#define RT5668_DEB_STO_DAC_MASK			(0x7 << 4)
+#define RT5668_DEB_80_MS			(0x0 << 4)
+
+/* SAR ADC Inline Command Control 1 (0x0210) */
+#define RT5668_SAR_BUTT_DET_MASK		(0x1 << 15)
+#define RT5668_SAR_BUTT_DET_EN			(0x1 << 15)
+#define RT5668_SAR_BUTT_DET_DIS			(0x0 << 15)
+#define RT5668_SAR_BUTDET_MODE_MASK		(0x1 << 14)
+#define RT5668_SAR_BUTDET_POW_SAV		(0x1 << 14)
+#define RT5668_SAR_BUTDET_POW_NORM		(0x0 << 14)
+#define RT5668_SAR_BUTDET_RST_MASK		(0x1 << 13)
+#define RT5668_SAR_BUTDET_RST_NORMAL		(0x1 << 13)
+#define RT5668_SAR_BUTDET_RST			(0x0 << 13)
+#define RT5668_SAR_POW_MASK			(0x1 << 12)
+#define RT5668_SAR_POW_EN			(0x1 << 12)
+#define RT5668_SAR_POW_DIS			(0x0 << 12)
+#define RT5668_SAR_RST_MASK			(0x1 << 11)
+#define RT5668_SAR_RST_NORMAL			(0x1 << 11)
+#define RT5668_SAR_RST				(0x0 << 11)
+#define RT5668_SAR_BYPASS_MASK			(0x1 << 10)
+#define RT5668_SAR_BYPASS_EN			(0x1 << 10)
+#define RT5668_SAR_BYPASS_DIS			(0x0 << 10)
+#define RT5668_SAR_SEL_MB1_MASK			(0x1 << 9)
+#define RT5668_SAR_SEL_MB1_SEL			(0x1 << 9)
+#define RT5668_SAR_SEL_MB1_NOSEL		(0x0 << 9)
+#define RT5668_SAR_SEL_MB2_MASK			(0x1 << 8)
+#define RT5668_SAR_SEL_MB2_SEL			(0x1 << 8)
+#define RT5668_SAR_SEL_MB2_NOSEL		(0x0 << 8)
+#define RT5668_SAR_SEL_MODE_MASK		(0x1 << 7)
+#define RT5668_SAR_SEL_MODE_CMP			(0x1 << 7)
+#define RT5668_SAR_SEL_MODE_ADC			(0x0 << 7)
+#define RT5668_SAR_SEL_MB1_MB2_MASK		(0x1 << 5)
+#define RT5668_SAR_SEL_MB1_MB2_AUTO		(0x1 << 5)
+#define RT5668_SAR_SEL_MB1_MB2_MANU		(0x0 << 5)
+#define RT5668_SAR_SEL_SIGNAL_MASK		(0x1 << 4)
+#define RT5668_SAR_SEL_SIGNAL_AUTO		(0x1 << 4)
+#define RT5668_SAR_SEL_SIGNAL_MANU		(0x0 << 4)
+
+/* SAR ADC Inline Command Control 13 (0x021c) */
+#define RT5668_SAR_SOUR_MASK			(0x3f)
+#define RT5668_SAR_SOUR_BTN			(0x3f)
+#define RT5668_SAR_SOUR_TYPE			(0x0)
+
+
+/* System Clock Source */
+enum {
+	RT5668_SCLK_S_MCLK,
+	RT5668_SCLK_S_PLL1,
+	RT5668_SCLK_S_PLL2,
+	RT5668_SCLK_S_RCCLK,
+};
+
+/* PLL Source */
+enum {
+	RT5668_PLL1_S_MCLK,
+	RT5668_PLL1_S_BCLK1,
+	RT5668_PLL1_S_RCCLK,
+};
+
+enum {
+	RT5668_AIF1,
+	RT5668_AIF2,
+	RT5668_AIFS
+};
+
+/* filter mask */
+enum {
+	RT5668_DA_STEREO1_FILTER = 0x1,
+	RT5668_AD_STEREO1_FILTER = (0x1 << 1),
+};
+
+enum {
+	RT5668_CLK_SEL_SYS,
+	RT5668_CLK_SEL_I2S1_ASRC,
+	RT5668_CLK_SEL_I2S2_ASRC,
+};
+
+int rt5668_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src);
+
+#endif /* __RT5668_H__ */
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index dc7df337d5f8..732ef928b25d 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -71,7 +71,7 @@ static const struct regmap_range_cfg rt5670_ranges[] = {
 
 static const struct reg_sequence init_list[] = {
 	{ RT5670_PR_BASE + 0x14, 0x9a8a },
-	{ RT5670_PR_BASE + 0x38, 0x3ba1 },
+	{ RT5670_PR_BASE + 0x38, 0x1fe1 },
 	{ RT5670_PR_BASE + 0x3d, 0x3640 },
 	{ 0x8a, 0x0123 },
 };
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index bc1a23dd7c2d..8a0181a2db08 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -5006,13 +5006,6 @@ static const struct regmap_config rt5677_regmap = {
 	.num_ranges = ARRAY_SIZE(rt5677_ranges),
 };
 
-static const struct i2c_device_id rt5677_i2c_id[] = {
-	{ "rt5677", RT5677 },
-	{ "rt5676", RT5676 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
-
 static const struct of_device_id rt5677_of_match[] = {
 	{ .compatible = "realtek,rt5677", RT5677 },
 	{ }
@@ -5130,8 +5123,7 @@ static void rt5677_free_irq(struct i2c_client *i2c)
 		regmap_del_irq_chip(i2c->irq, rt5677->irq_data);
 }
 
-static int rt5677_i2c_probe(struct i2c_client *i2c,
-		    const struct i2c_device_id *id)
+static int rt5677_i2c_probe(struct i2c_client *i2c)
 {
 	struct rt5677_priv *rt5677;
 	int ret;
@@ -5278,9 +5270,8 @@ static struct i2c_driver rt5677_i2c_driver = {
 		.of_match_table = rt5677_of_match,
 		.acpi_match_table = ACPI_PTR(rt5677_acpi_match),
 	},
-	.probe = rt5677_i2c_probe,
+	.probe_new = rt5677_i2c_probe,
 	.remove   = rt5677_i2c_remove,
-	.id_table = rt5677_i2c_id,
 };
 module_i2c_driver(rt5677_i2c_driver);
 
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 7c1d65830c05..60764f6201b1 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -1,12 +1,8 @@
-/*
- * sgtl5000.c  --  SGTL5000 ALSA SoC Audio driver
- *
- * Copyright 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// sgtl5000.c  --  SGTL5000 ALSA SoC Audio driver
+//
+// Copyright 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -457,7 +453,7 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
  * avc_put_threshold function: register_value = 10^(dB/20) * 0.636 * 2^15 ==>
  * dB = ( fls(register_value) - 14.347 ) * 6.02
  *
- * As this calculation is expensive and the threshold dB values may not exeed
+ * As this calculation is expensive and the threshold dB values may not exceed
  * 0 to 96 we use pre-calculated values.
  */
 static int avc_get_threshold(struct snd_kcontrol *kcontrol,
@@ -490,7 +486,7 @@ static int avc_get_threshold(struct snd_kcontrol *kcontrol,
  *
  * The register value is calculated by following formula:
  *                                    register_value = 10^(dB/20) * 0.636 * 2^15
- * As this calculation is expensive and the threshold dB values may not exeed
+ * As this calculation is expensive and the threshold dB values may not exceed
  * 0 to 96 we use pre-calculated values.
  */
 static int avc_put_threshold(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h
index 28cf637155bb..18cae08bbd3a 100644
--- a/sound/soc/codecs/sgtl5000.h
+++ b/sound/soc/codecs/sgtl5000.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * sgtl5000.h - SGTL5000 audio codec interface
  *
  * Copyright 2010-2011 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef _SGTL5000_H
diff --git a/sound/soc/codecs/ssm2305.c b/sound/soc/codecs/ssm2305.c
new file mode 100644
index 000000000000..2968959c4b75
--- /dev/null
+++ b/sound/soc/codecs/ssm2305.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Analog Devices SSM2305 Amplifier Driver
+//
+// Copyright (C) 2018 Pengutronix, Marco Felsch <kernel@pengutronix.de>
+//
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "ssm2305"
+
+struct ssm2305 {
+	/* shutdown gpio  */
+	struct gpio_desc *gpiod_shutdown;
+};
+
+static int ssm2305_power_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kctrl, int event)
+{
+	struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+	struct ssm2305 *data = snd_soc_component_get_drvdata(c);
+
+	gpiod_set_value_cansleep(data->gpiod_shutdown,
+				 SND_SOC_DAPM_EVENT_ON(event));
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget ssm2305_dapm_widgets[] = {
+	/* Stereo input/output */
+	SND_SOC_DAPM_INPUT("L_IN"),
+	SND_SOC_DAPM_INPUT("R_IN"),
+	SND_SOC_DAPM_OUTPUT("L_OUT"),
+	SND_SOC_DAPM_OUTPUT("R_OUT"),
+
+	SND_SOC_DAPM_SUPPLY("Power", SND_SOC_NOPM, 0, 0, ssm2305_power_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route ssm2305_dapm_routes[] = {
+	{ "L_OUT", NULL, "L_IN" },
+	{ "R_OUT", NULL, "R_IN" },
+	{ "L_IN", NULL, "Power" },
+	{ "R_IN", NULL, "Power" },
+};
+
+static const struct snd_soc_component_driver ssm2305_component_driver = {
+	.dapm_widgets		= ssm2305_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ssm2305_dapm_widgets),
+	.dapm_routes		= ssm2305_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ssm2305_dapm_routes),
+};
+
+static int ssm2305_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ssm2305 *priv;
+	int err;
+
+	/* Allocate the private data */
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+
+	/* Get shutdown gpio */
+	priv->gpiod_shutdown = devm_gpiod_get(dev, "shutdown",
+					      GPIOD_OUT_LOW);
+	if (IS_ERR(priv->gpiod_shutdown)) {
+		err = PTR_ERR(priv->gpiod_shutdown);
+		if (err != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get 'shutdown' gpio: %d\n",
+				err);
+		return err;
+	}
+
+	return devm_snd_soc_register_component(dev, &ssm2305_component_driver,
+					       NULL, 0);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id ssm2305_of_match[] = {
+	{ .compatible = "adi,ssm2305", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ssm2305_of_match);
+#endif
+
+static struct platform_driver ssm2305_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = of_match_ptr(ssm2305_of_match),
+	},
+	.probe = ssm2305_probe,
+};
+
+module_platform_driver(ssm2305_driver);
+
+MODULE_DESCRIPTION("ASoC SSM2305 amplifier driver");
+MODULE_AUTHOR("Marco Felsch <m.felsch@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c
index 4f3a16c520a2..14999b999fd3 100644
--- a/sound/soc/codecs/tas6424.c
+++ b/sound/soc/codecs/tas6424.c
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/regulator/consumer.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -43,6 +44,8 @@ struct tas6424_data {
 	unsigned int last_fault1;
 	unsigned int last_fault2;
 	unsigned int last_warn;
+	struct gpio_desc *standby_gpio;
+	struct gpio_desc *mute_gpio;
 };
 
 /*
@@ -61,6 +64,8 @@ static const struct snd_kcontrol_new tas6424_snd_controls[] = {
 		       TAS6424_CH3_VOL_CTRL, 0, 0xff, 0, dac_tlv),
 	SOC_SINGLE_TLV("Speaker Driver CH4 Playback Volume",
 		       TAS6424_CH4_VOL_CTRL, 0, 0xff, 0, dac_tlv),
+	SOC_SINGLE_STROBE("Auto Diagnostics Switch", TAS6424_DC_DIAG_CTRL1,
+			  TAS6424_LDGBYPASS_SHIFT, 1),
 };
 
 static int tas6424_dac_event(struct snd_soc_dapm_widget *w,
@@ -249,10 +254,16 @@ static int tas6424_set_dai_tdm_slot(struct snd_soc_dai *dai,
 static int tas6424_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_component *component = dai->component;
+	struct tas6424_data *tas6424 = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	dev_dbg(component->dev, "%s() mute=%d\n", __func__, mute);
 
+	if (tas6424->mute_gpio) {
+		gpiod_set_value_cansleep(tas6424->mute_gpio, mute);
+		return 0;
+	}
+
 	if (mute)
 		val = TAS6424_ALL_STATE_MUTE;
 	else
@@ -287,6 +298,12 @@ static int tas6424_power_on(struct snd_soc_component *component)
 {
 	struct tas6424_data *tas6424 = snd_soc_component_get_drvdata(component);
 	int ret;
+	u8 chan_states;
+	int no_auto_diags = 0;
+	unsigned int reg_val;
+
+	if (!regmap_read(tas6424->regmap, TAS6424_DC_DIAG_CTRL1, &reg_val))
+		no_auto_diags = reg_val & TAS6424_LDGBYPASS_MASK;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(tas6424->supplies),
 				    tas6424->supplies);
@@ -303,12 +320,25 @@ static int tas6424_power_on(struct snd_soc_component *component)
 		return ret;
 	}
 
-	snd_soc_component_write(component, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_MUTE);
+	if (tas6424->mute_gpio) {
+		gpiod_set_value_cansleep(tas6424->mute_gpio, 0);
+		/*
+		 * channels are muted via the mute pin.  Don't also mute
+		 * them via the registers so that subsequent register
+		 * access is not necessary to un-mute the channels
+		 */
+		chan_states = TAS6424_ALL_STATE_PLAY;
+	} else {
+		chan_states = TAS6424_ALL_STATE_MUTE;
+	}
+	snd_soc_component_write(component, TAS6424_CH_STATE_CTRL, chan_states);
 
 	/* any time we come out of HIZ, the output channels automatically run DC
-	 * load diagnostics, wait here until this completes
+	 * load diagnostics if autodiagnotics are enabled. wait here until this
+	 * completes.
 	 */
-	msleep(230);
+	if (!no_auto_diags)
+		msleep(230);
 
 	return 0;
 }
@@ -627,6 +657,38 @@ static int tas6424_i2c_probe(struct i2c_client *client,
 		return ret;
 	}
 
+	/*
+	 * Get control of the standby pin and set it LOW to take the codec
+	 * out of the stand-by mode.
+	 * Note: The actual pin polarity is taken care of in the GPIO lib
+	 * according the polarity specified in the DTS.
+	 */
+	tas6424->standby_gpio = devm_gpiod_get_optional(dev, "standby",
+						      GPIOD_OUT_LOW);
+	if (IS_ERR(tas6424->standby_gpio)) {
+		if (PTR_ERR(tas6424->standby_gpio) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		dev_info(dev, "failed to get standby GPIO: %ld\n",
+			PTR_ERR(tas6424->standby_gpio));
+		tas6424->standby_gpio = NULL;
+	}
+
+	/*
+	 * Get control of the mute pin and set it HIGH in order to start with
+	 * all the output muted.
+	 * Note: The actual pin polarity is taken care of in the GPIO lib
+	 * according the polarity specified in the DTS.
+	 */
+	tas6424->mute_gpio = devm_gpiod_get_optional(dev, "mute",
+						      GPIOD_OUT_HIGH);
+	if (IS_ERR(tas6424->mute_gpio)) {
+		if (PTR_ERR(tas6424->mute_gpio) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		dev_info(dev, "failed to get nmute GPIO: %ld\n",
+			PTR_ERR(tas6424->mute_gpio));
+		tas6424->mute_gpio = NULL;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(tas6424->supplies); i++)
 		tas6424->supplies[i].supply = tas6424_supply_names[i];
 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(tas6424->supplies),
@@ -671,6 +733,10 @@ static int tas6424_i2c_remove(struct i2c_client *client)
 
 	cancel_delayed_work_sync(&tas6424->fault_check_work);
 
+	/* put the codec in stand-by */
+	if (tas6424->standby_gpio)
+		gpiod_set_value_cansleep(tas6424->standby_gpio, 1);
+
 	ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies),
 				     tas6424->supplies);
 	if (ret < 0) {
diff --git a/sound/soc/codecs/tas6424.h b/sound/soc/codecs/tas6424.h
index 430588328a06..b5958c45ed0e 100644
--- a/sound/soc/codecs/tas6424.h
+++ b/sound/soc/codecs/tas6424.h
@@ -111,6 +111,10 @@
 					 TAS6424_CH3_STATE_DIAG | \
 					 TAS6424_CH4_STATE_DIAG)
 
+/* TAS6424_DC_DIAG_CTRL1 */
+#define TAS6424_LDGBYPASS_SHIFT		0
+#define TAS6424_LDGBYPASS_MASK		BIT(TAS6424_LDGBYPASS_SHIFT)
+
 /* TAS6424_GLOB_FAULT1_REG */
 #define TAS6424_FAULT_CLOCK		BIT(4)
 #define TAS6424_FAULT_PVDD_OV		BIT(3)
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
index 6d213c6d3920..abc114a3ae2b 100644
--- a/sound/soc/codecs/tfa9879.c
+++ b/sound/soc/codecs/tfa9879.c
@@ -1,15 +1,9 @@
-/*
- * tfa9879.c  --  driver for NXP Semiconductors TFA9879
- *
- * Copyright (C) 2014 Axentia Technologies AB
- * Author: Peter Rosin <peda@axentia.se>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// tfa9879.c  --  driver for NXP Semiconductors TFA9879
+//
+// Copyright (C) 2014 Axentia Technologies AB
+// Author: Peter Rosin <peda@axentia.se>
 
 #include <linux/module.h>
 #include <linux/init.h>
@@ -88,13 +82,14 @@ static int tfa9879_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (tfa9879->lsb_justified)
-		snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
-				    TFA9879_I2S_SET_MASK,
-				    i2s_set << TFA9879_I2S_SET_SHIFT);
+		snd_soc_component_update_bits(component,
+					      TFA9879_SERIAL_INTERFACE_1,
+					      TFA9879_I2S_SET_MASK,
+					      i2s_set << TFA9879_I2S_SET_SHIFT);
 
 	snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
-			    TFA9879_I2S_FS_MASK,
-			    fs << TFA9879_I2S_FS_SHIFT);
+				      TFA9879_I2S_FS_MASK,
+				      fs << TFA9879_I2S_FS_SHIFT);
 	return 0;
 }
 
@@ -103,8 +98,8 @@ static int tfa9879_digital_mute(struct snd_soc_dai *dai, int mute)
 	struct snd_soc_component *component = dai->component;
 
 	snd_soc_component_update_bits(component, TFA9879_MISC_CONTROL,
-			    TFA9879_S_MUTE_MASK,
-			    !!mute << TFA9879_S_MUTE_SHIFT);
+				      TFA9879_S_MUTE_MASK,
+				      !!mute << TFA9879_S_MUTE_SHIFT);
 
 	return 0;
 }
@@ -152,11 +147,11 @@ static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	}
 
 	snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
-			    TFA9879_SCK_POL_MASK,
-			    sck_pol << TFA9879_SCK_POL_SHIFT);
+				      TFA9879_SCK_POL_MASK,
+				      sck_pol << TFA9879_SCK_POL_SHIFT);
 	snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
-			    TFA9879_I2S_SET_MASK,
-			    i2s_set << TFA9879_I2S_SET_SHIFT);
+				      TFA9879_I2S_SET_MASK,
+				      i2s_set << TFA9879_I2S_SET_SHIFT);
 	return 0;
 }
 
@@ -276,8 +271,7 @@ static struct snd_soc_dai_driver tfa9879_dai = {
 	.ops = &tfa9879_dai_ops,
 };
 
-static int tfa9879_i2c_probe(struct i2c_client *i2c,
-			     const struct i2c_device_id *id)
+static int tfa9879_i2c_probe(struct i2c_client *i2c)
 {
 	struct tfa9879_priv *tfa9879;
 	int i;
@@ -298,7 +292,7 @@ static int tfa9879_i2c_probe(struct i2c_client *i2c,
 			     tfa9879_regs[i].reg, tfa9879_regs[i].def);
 
 	return devm_snd_soc_register_component(&i2c->dev, &tfa9879_component,
-				      &tfa9879_dai, 1);
+					       &tfa9879_dai, 1);
 }
 
 static const struct i2c_device_id tfa9879_i2c_id[] = {
@@ -318,7 +312,7 @@ static struct i2c_driver tfa9879_i2c_driver = {
 		.name = "tfa9879",
 		.of_match_table = tfa9879_of_match,
 	},
-	.probe = tfa9879_i2c_probe,
+	.probe_new = tfa9879_i2c_probe,
 	.id_table = tfa9879_i2c_id,
 };
 
diff --git a/sound/soc/codecs/tfa9879.h b/sound/soc/codecs/tfa9879.h
index 3408c90c4628..66c88d0396fe 100644
--- a/sound/soc/codecs/tfa9879.h
+++ b/sound/soc/codecs/tfa9879.h
@@ -1,14 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * tfa9879.h  --  driver for NXP Semiconductors TFA9879
  *
  * Copyright (C) 2014 Axentia Technologies AB
  * Author: Peter Rosin <peda@axentia.se>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
  */
 
 #ifndef _TFA9879_H
diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c
index bbfc73a79b18..d18ff17719cc 100644
--- a/sound/soc/codecs/tscs42xx.c
+++ b/sound/soc/codecs/tscs42xx.c
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
+#include <linux/clk.h>
 #include <sound/tlv.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -31,7 +32,6 @@ struct tscs42xx {
 
 	int bclk_ratio;
 	int samplerate;
-	unsigned int blrcm;
 	struct mutex audio_params_lock;
 
 	u8 coeff_ram[COEFF_RAM_SIZE];
@@ -42,7 +42,8 @@ struct tscs42xx {
 
 	struct regmap *regmap;
 
-	struct device *dev;
+	struct clk *sysclk;
+	int sysclk_src_id;
 };
 
 struct coeff_ram_ctl {
@@ -204,7 +205,8 @@ static int power_up_audio_plls(struct snd_soc_component *component)
 		break;
 	default:
 		ret = -EINVAL;
-		dev_err(component->dev, "Unrecognized PLL output freq (%d)\n", ret);
+		dev_err(component->dev,
+				"Unrecognized PLL output freq (%d)\n", ret);
 		return ret;
 	}
 
@@ -261,7 +263,8 @@ exit:
 static int coeff_ram_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
 	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
 	struct coeff_ram_ctl *ctl =
 		(struct coeff_ram_ctl *)kcontrol->private_value;
@@ -280,7 +283,8 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol,
 static int coeff_ram_put(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
 	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
 	struct coeff_ram_ctl *ctl =
 		(struct coeff_ram_ctl *)kcontrol->private_value;
@@ -363,7 +367,8 @@ static int dapm_micb_event(struct snd_soc_dapm_widget *w,
 static int pll_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 snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
 	int ret;
 
 	if (SND_SOC_DAPM_EVENT_ON(event))
@@ -377,7 +382,8 @@ static int pll_event(struct snd_soc_dapm_widget *w,
 static int dac_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 snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
 	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
 	int ret;
 
@@ -819,16 +825,19 @@ static int setup_sample_format(struct snd_soc_component *component,
 		dev_err(component->dev, "Unsupported format width (%d)\n", ret);
 		return ret;
 	}
-	ret = snd_soc_component_update_bits(component, R_AIC1, RM_AIC1_WL, width);
+	ret = snd_soc_component_update_bits(component,
+			R_AIC1, RM_AIC1_WL, width);
 	if (ret < 0) {
-		dev_err(component->dev, "Failed to set sample width (%d)\n", ret);
+		dev_err(component->dev,
+				"Failed to set sample width (%d)\n", ret);
 		return ret;
 	}
 
 	return 0;
 }
 
-static int setup_sample_rate(struct snd_soc_component *component, unsigned int rate)
+static int setup_sample_rate(struct snd_soc_component *component,
+		unsigned int rate)
 {
 	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
 	unsigned int br, bm;
@@ -881,24 +890,32 @@ static int setup_sample_rate(struct snd_soc_component *component, unsigned int r
 	}
 
 	/* DAC and ADC share bit and frame clock */
-	ret = snd_soc_component_update_bits(component, R_DACSR, RM_DACSR_DBR, br);
+	ret = snd_soc_component_update_bits(component,
+			R_DACSR, RM_DACSR_DBR, br);
 	if (ret < 0) {
-		dev_err(component->dev, "Failed to update register (%d)\n", ret);
+		dev_err(component->dev,
+				"Failed to update register (%d)\n", ret);
 		return ret;
 	}
-	ret = snd_soc_component_update_bits(component, R_DACSR, RM_DACSR_DBM, bm);
+	ret = snd_soc_component_update_bits(component,
+			R_DACSR, RM_DACSR_DBM, bm);
 	if (ret < 0) {
-		dev_err(component->dev, "Failed to update register (%d)\n", ret);
+		dev_err(component->dev,
+				"Failed to update register (%d)\n", ret);
 		return ret;
 	}
-	ret = snd_soc_component_update_bits(component, R_ADCSR, RM_DACSR_DBR, br);
+	ret = snd_soc_component_update_bits(component,
+			R_ADCSR, RM_DACSR_DBR, br);
 	if (ret < 0) {
-		dev_err(component->dev, "Failed to update register (%d)\n", ret);
+		dev_err(component->dev,
+				"Failed to update register (%d)\n", ret);
 		return ret;
 	}
-	ret = snd_soc_component_update_bits(component, R_ADCSR, RM_DACSR_DBM, bm);
+	ret = snd_soc_component_update_bits(component,
+			R_ADCSR, RM_DACSR_DBM, bm);
 	if (ret < 0) {
-		dev_err(component->dev, "Failed to update register (%d)\n", ret);
+		dev_err(component->dev,
+				"Failed to update register (%d)\n", ret);
 		return ret;
 	}
 
@@ -1076,7 +1093,8 @@ static int tscs42xx_hw_params(struct snd_pcm_substream *substream,
 
 	ret = setup_sample_rate(component, params_rate(params));
 	if (ret < 0) {
-		dev_err(component->dev, "Failed to setup sample rate (%d)\n", ret);
+		dev_err(component->dev,
+				"Failed to setup sample rate (%d)\n", ret);
 		return ret;
 	}
 
@@ -1087,7 +1105,8 @@ static inline int dac_mute(struct snd_soc_component *component)
 {
 	int ret;
 
-	ret = snd_soc_component_update_bits(component, R_CNVRTR1, RM_CNVRTR1_DACMU,
+	ret = snd_soc_component_update_bits(component,
+			R_CNVRTR1, RM_CNVRTR1_DACMU,
 		RV_CNVRTR1_DACMU_ENABLE);
 	if (ret < 0) {
 		dev_err(component->dev, "Failed to mute DAC (%d)\n",
@@ -1102,7 +1121,8 @@ static inline int dac_unmute(struct snd_soc_component *component)
 {
 	int ret;
 
-	ret = snd_soc_component_update_bits(component, R_CNVRTR1, RM_CNVRTR1_DACMU,
+	ret = snd_soc_component_update_bits(component,
+			R_CNVRTR1, RM_CNVRTR1_DACMU,
 		RV_CNVRTR1_DACMU_DISABLE);
 	if (ret < 0) {
 		dev_err(component->dev, "Failed to unmute DAC (%d)\n",
@@ -1117,8 +1137,8 @@ static inline int adc_mute(struct snd_soc_component *component)
 {
 	int ret;
 
-	ret = snd_soc_component_update_bits(component, R_CNVRTR0, RM_CNVRTR0_ADCMU,
-		RV_CNVRTR0_ADCMU_ENABLE);
+	ret = snd_soc_component_update_bits(component,
+			R_CNVRTR0, RM_CNVRTR0_ADCMU, RV_CNVRTR0_ADCMU_ENABLE);
 	if (ret < 0) {
 		dev_err(component->dev, "Failed to mute ADC (%d)\n",
 				ret);
@@ -1132,8 +1152,8 @@ static inline int adc_unmute(struct snd_soc_component *component)
 {
 	int ret;
 
-	ret = snd_soc_component_update_bits(component, R_CNVRTR0, RM_CNVRTR0_ADCMU,
-		RV_CNVRTR0_ADCMU_DISABLE);
+	ret = snd_soc_component_update_bits(component,
+			R_CNVRTR0, RM_CNVRTR0_ADCMU, RV_CNVRTR0_ADCMU_DISABLE);
 	if (ret < 0) {
 		dev_err(component->dev, "Failed to unmute ADC (%d)\n",
 				ret);
@@ -1171,8 +1191,8 @@ static int tscs42xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	/* Slave mode not supported since it needs always-on frame clock */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
-		ret = snd_soc_component_update_bits(component, R_AIC1, RM_AIC1_MS,
-				RV_AIC1_MS_MASTER);
+		ret = snd_soc_component_update_bits(component,
+				R_AIC1, RM_AIC1_MS, RV_AIC1_MS_MASTER);
 		if (ret < 0) {
 			dev_err(component->dev,
 				"Failed to set codec DAI master (%d)\n", ret);
@@ -1211,14 +1231,18 @@ static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	ret = snd_soc_component_update_bits(component, R_DACSR, RM_DACSR_DBCM, value);
+	ret = snd_soc_component_update_bits(component,
+			R_DACSR, RM_DACSR_DBCM, value);
 	if (ret < 0) {
-		dev_err(component->dev, "Failed to set DAC BCLK ratio (%d)\n", ret);
+		dev_err(component->dev,
+				"Failed to set DAC BCLK ratio (%d)\n", ret);
 		return ret;
 	}
-	ret = snd_soc_component_update_bits(component, R_ADCSR, RM_ADCSR_ABCM, value);
+	ret = snd_soc_component_update_bits(component,
+			R_ADCSR, RM_ADCSR_ABCM, value);
 	if (ret < 0) {
-		dev_err(component->dev, "Failed to set ADC BCLK ratio (%d)\n", ret);
+		dev_err(component->dev,
+				"Failed to set ADC BCLK ratio (%d)\n", ret);
 		return ret;
 	}
 
@@ -1231,13 +1255,46 @@ static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static int tscs42xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
-	int clk_id, unsigned int freq, int dir)
+static const struct snd_soc_dai_ops tscs42xx_dai_ops = {
+	.hw_params	= tscs42xx_hw_params,
+	.mute_stream	= tscs42xx_mute_stream,
+	.set_fmt	= tscs42xx_set_dai_fmt,
+	.set_bclk_ratio = tscs42xx_set_dai_bclk_ratio,
+};
+
+static int part_is_valid(struct tscs42xx *tscs42xx)
 {
-	struct snd_soc_component *component = codec_dai->component;
+	int val;
 	int ret;
+	unsigned int reg;
+
+	ret = regmap_read(tscs42xx->regmap, R_DEVIDH, &reg);
+	if (ret < 0)
+		return ret;
+
+	val = reg << 8;
+	ret = regmap_read(tscs42xx->regmap, R_DEVIDL, &reg);
+	if (ret < 0)
+		return ret;
+
+	val |= reg;
+
+	switch (val) {
+	case 0x4A74:
+	case 0x4A73:
+		return true;
+	default:
+		return false;
+	};
+}
 
-	switch (clk_id) {
+static int set_sysclk(struct snd_soc_component *component)
+{
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
+	unsigned long freq;
+	int ret;
+
+	switch (tscs42xx->sysclk_src_id) {
 	case TSCS42XX_PLL_SRC_XTAL:
 	case TSCS42XX_PLL_SRC_MCLK1:
 		ret = snd_soc_component_write(component, R_PLLREFSEL,
@@ -1265,6 +1322,7 @@ static int tscs42xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
+	freq = clk_get_rate(tscs42xx->sysclk);
 	ret = set_pll_ctl_from_input_freq(component, freq);
 	if (ret < 0) {
 		dev_err(component->dev,
@@ -1275,41 +1333,13 @@ static int tscs42xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static const struct snd_soc_dai_ops tscs42xx_dai_ops = {
-	.hw_params	= tscs42xx_hw_params,
-	.mute_stream	= tscs42xx_mute_stream,
-	.set_fmt	= tscs42xx_set_dai_fmt,
-	.set_bclk_ratio = tscs42xx_set_dai_bclk_ratio,
-	.set_sysclk	= tscs42xx_set_dai_sysclk,
-};
-
-static int part_is_valid(struct tscs42xx *tscs42xx)
+static int tscs42xx_probe(struct snd_soc_component *component)
 {
-	int val;
-	int ret;
-	unsigned int reg;
-
-	ret = regmap_read(tscs42xx->regmap, R_DEVIDH, &reg);
-	if (ret < 0)
-		return ret;
-
-	val = reg << 8;
-	ret = regmap_read(tscs42xx->regmap, R_DEVIDL, &reg);
-	if (ret < 0)
-		return ret;
-
-	val |= reg;
-
-	switch (val) {
-	case 0x4A74:
-	case 0x4A73:
-		return true;
-	default:
-		return false;
-	};
+	return set_sysclk(component);
 }
 
-static struct snd_soc_component_driver soc_codec_dev_tscs42xx = {
+static const struct snd_soc_component_driver soc_codec_dev_tscs42xx = {
+	.probe			= tscs42xx_probe,
 	.dapm_widgets		= tscs42xx_dapm_widgets,
 	.num_dapm_widgets	= ARRAY_SIZE(tscs42xx_dapm_widgets),
 	.dapm_routes		= tscs42xx_intercon,
@@ -1367,11 +1397,15 @@ static const struct reg_sequence tscs42xx_patch[] = {
 	{ R_AIC2, RV_AIC2_BLRCM_DAC_BCLK_LRCLK_SHARED },
 };
 
+static char const * const src_names[TSCS42XX_PLL_SRC_CNT] = {
+	"xtal", "mclk1", "mclk2"};
+
 static int tscs42xx_i2c_probe(struct i2c_client *i2c,
 		const struct i2c_device_id *id)
 {
 	struct tscs42xx *tscs42xx;
-	int ret = 0;
+	int src;
+	int ret;
 
 	tscs42xx = devm_kzalloc(&i2c->dev, sizeof(*tscs42xx), GFP_KERNEL);
 	if (!tscs42xx) {
@@ -1381,12 +1415,29 @@ static int tscs42xx_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 	i2c_set_clientdata(i2c, tscs42xx);
-	tscs42xx->dev = &i2c->dev;
+
+	for (src = TSCS42XX_PLL_SRC_XTAL; src < TSCS42XX_PLL_SRC_CNT; src++) {
+		tscs42xx->sysclk = devm_clk_get(&i2c->dev, src_names[src]);
+		if (!IS_ERR(tscs42xx->sysclk)) {
+			break;
+		} else if (PTR_ERR(tscs42xx->sysclk) != -ENOENT) {
+			ret = PTR_ERR(tscs42xx->sysclk);
+			dev_err(&i2c->dev, "Failed to get sysclk (%d)\n", ret);
+			return ret;
+		}
+	}
+	if (src == TSCS42XX_PLL_SRC_CNT) {
+		ret = -EINVAL;
+		dev_err(&i2c->dev, "Failed to get a valid clock name (%d)\n",
+				ret);
+		return ret;
+	}
+	tscs42xx->sysclk_src_id = src;
 
 	tscs42xx->regmap = devm_regmap_init_i2c(i2c, &tscs42xx_regmap);
 	if (IS_ERR(tscs42xx->regmap)) {
 		ret = PTR_ERR(tscs42xx->regmap);
-		dev_err(tscs42xx->dev, "Failed to allocate regmap (%d)\n", ret);
+		dev_err(&i2c->dev, "Failed to allocate regmap (%d)\n", ret);
 		return ret;
 	}
 
@@ -1394,21 +1445,21 @@ static int tscs42xx_i2c_probe(struct i2c_client *i2c,
 
 	ret = part_is_valid(tscs42xx);
 	if (ret <= 0) {
-		dev_err(tscs42xx->dev, "No valid part (%d)\n", ret);
+		dev_err(&i2c->dev, "No valid part (%d)\n", ret);
 		ret = -ENODEV;
 		return ret;
 	}
 
 	ret = regmap_write(tscs42xx->regmap, R_RESET, RV_RESET_ENABLE);
 	if (ret < 0) {
-		dev_err(tscs42xx->dev, "Failed to reset device (%d)\n", ret);
+		dev_err(&i2c->dev, "Failed to reset device (%d)\n", ret);
 		return ret;
 	}
 
 	ret = regmap_register_patch(tscs42xx->regmap, tscs42xx_patch,
 			ARRAY_SIZE(tscs42xx_patch));
 	if (ret < 0) {
-		dev_err(tscs42xx->dev, "Failed to apply patch (%d)\n", ret);
+		dev_err(&i2c->dev, "Failed to apply patch (%d)\n", ret);
 		return ret;
 	}
 
@@ -1416,10 +1467,10 @@ static int tscs42xx_i2c_probe(struct i2c_client *i2c,
 	mutex_init(&tscs42xx->coeff_ram_lock);
 	mutex_init(&tscs42xx->pll_lock);
 
-	ret = devm_snd_soc_register_component(tscs42xx->dev, &soc_codec_dev_tscs42xx,
-			&tscs42xx_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_codec_dev_tscs42xx, &tscs42xx_dai, 1);
 	if (ret) {
-		dev_err(tscs42xx->dev, "Failed to register codec (%d)\n", ret);
+		dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret);
 		return ret;
 	}
 
diff --git a/sound/soc/codecs/tscs42xx.h b/sound/soc/codecs/tscs42xx.h
index d4a30bcbf64b..814c8f3c4a68 100644
--- a/sound/soc/codecs/tscs42xx.h
+++ b/sound/soc/codecs/tscs42xx.h
@@ -7,10 +7,10 @@
 #define __WOOKIE_H__
 
 enum {
-	TSCS42XX_PLL_SRC_NONE,
 	TSCS42XX_PLL_SRC_XTAL,
 	TSCS42XX_PLL_SRC_MCLK1,
 	TSCS42XX_PLL_SRC_MCLK2,
+	TSCS42XX_PLL_SRC_CNT,
 };
 
 #define R_HPVOLL        0x0
diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c
new file mode 100644
index 000000000000..ff85a0bf6170
--- /dev/null
+++ b/sound/soc/codecs/tscs454.c
@@ -0,0 +1,3497 @@
+// SPDX-License-Identifier: GPL-2.0
+// tscs454.c -- TSCS454 ALSA SoC Audio driver
+// Copyright 2018 Tempo Semiconductor, Inc.
+// Author: Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
+#include <sound/tlv.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "tscs454.h"
+
+static const unsigned int PLL_48K_RATE = (48000 * 256);
+static const unsigned int PLL_44_1K_RATE = (44100 * 256);
+
+#define COEFF_SIZE 3
+#define BIQUAD_COEFF_COUNT 5
+#define BIQUAD_SIZE (COEFF_SIZE * BIQUAD_COEFF_COUNT)
+
+#define COEFF_RAM_MAX_ADDR 0xcd
+#define COEFF_RAM_COEFF_COUNT (COEFF_RAM_MAX_ADDR + 1)
+#define COEFF_RAM_SIZE (COEFF_SIZE * COEFF_RAM_COEFF_COUNT)
+
+enum {
+	TSCS454_DAI1_ID,
+	TSCS454_DAI2_ID,
+	TSCS454_DAI3_ID,
+	TSCS454_DAI_COUNT,
+};
+
+struct pll {
+	int id;
+	unsigned int users;
+	struct mutex lock;
+};
+
+static inline void pll_init(struct pll *pll, int id)
+{
+	pll->id = id;
+	mutex_init(&pll->lock);
+}
+
+struct internal_rate {
+	struct pll *pll;
+};
+
+struct aif {
+	unsigned int id;
+	bool master;
+	struct pll *pll;
+};
+
+static inline void aif_init(struct aif *aif, unsigned int id)
+{
+	aif->id = id;
+}
+
+struct coeff_ram {
+	u8 cache[COEFF_RAM_SIZE];
+	bool synced;
+	struct mutex lock;
+};
+
+static inline void init_coeff_ram_cache(u8 *cache)
+{
+	static const u8 norm_addrs[] = { 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19,
+		0x1f, 0x20, 0x25, 0x2a, 0x2f, 0x34, 0x39, 0x3f, 0x40, 0x45,
+		0x4a, 0x4f, 0x54, 0x59, 0x5f, 0x60, 0x65, 0x6a, 0x6f, 0x74,
+		0x79, 0x7f, 0x80, 0x85, 0x8c, 0x91, 0x96, 0x97, 0x9c, 0xa3,
+		0xa8, 0xad, 0xaf, 0xb0, 0xb5, 0xba, 0xbf, 0xc4, 0xc9};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(norm_addrs); i++)
+		cache[((norm_addrs[i] + 1) * COEFF_SIZE) - 1] = 0x40;
+}
+
+static inline void coeff_ram_init(struct coeff_ram *ram)
+{
+	init_coeff_ram_cache(ram->cache);
+	mutex_init(&ram->lock);
+}
+
+struct aifs_status {
+	u8 streams;
+};
+
+static inline void set_aif_status_active(struct aifs_status *status,
+		int aif_id, bool playback)
+{
+	u8 mask = 0x01 << (aif_id * 2 + !playback);
+
+	status->streams |= mask;
+}
+
+static inline void set_aif_status_inactive(struct aifs_status *status,
+		int aif_id, bool playback)
+{
+	u8 mask = ~(0x01 << (aif_id * 2 + !playback));
+
+	status->streams &= mask;
+}
+
+static bool aifs_active(struct aifs_status *status)
+{
+	return status->streams;
+}
+
+static bool aif_active(struct aifs_status *status, int aif_id)
+{
+	return (0x03 << aif_id * 2) & status->streams;
+}
+
+struct tscs454 {
+	struct regmap *regmap;
+	struct aif aifs[TSCS454_DAI_COUNT];
+
+	struct aifs_status aifs_status;
+	struct mutex aifs_status_lock;
+
+	struct pll pll1;
+	struct pll pll2;
+	struct internal_rate internal_rate;
+
+	struct coeff_ram dac_ram;
+	struct coeff_ram spk_ram;
+	struct coeff_ram sub_ram;
+
+	struct clk *sysclk;
+	int sysclk_src_id;
+	unsigned int bclk_freq;
+};
+
+struct coeff_ram_ctl {
+	unsigned int addr;
+	struct soc_bytes_ext bytes_ext;
+};
+
+static const struct reg_sequence tscs454_patch[] = {
+	/* Assign ASRC out of the box so DAI 1 just works */
+	{ R_AUDIOMUX1, FV_ASRCIMUX_I2S1 | FV_I2S2MUX_I2S2 },
+	{ R_AUDIOMUX2, FV_ASRCOMUX_I2S1 | FV_DACMUX_I2S1 | FV_I2S3MUX_I2S3 },
+	{ R_AUDIOMUX3, FV_CLSSDMUX_I2S1 | FV_SUBMUX_I2S1_LR },
+	{ R_TDMCTL0, FV_TDMMD_256 },
+	{ VIRT_ADDR(0x0A, 0x13), 1 << 3 },
+};
+
+static bool tscs454_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case R_PLLSTAT:
+
+	case R_SPKCRRDL:
+	case R_SPKCRRDM:
+	case R_SPKCRRDH:
+	case R_SPKCRS:
+
+	case R_DACCRRDL:
+	case R_DACCRRDM:
+	case R_DACCRRDH:
+	case R_DACCRS:
+
+	case R_SUBCRRDL:
+	case R_SUBCRRDM:
+	case R_SUBCRRDH:
+	case R_SUBCRS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tscs454_writable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case R_SPKCRRDL:
+	case R_SPKCRRDM:
+	case R_SPKCRRDH:
+
+	case R_DACCRRDL:
+	case R_DACCRRDM:
+	case R_DACCRRDH:
+
+	case R_SUBCRRDL:
+	case R_SUBCRRDM:
+	case R_SUBCRRDH:
+		return false;
+	default:
+		return true;
+	};
+}
+
+static bool tscs454_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case R_SPKCRWDL:
+	case R_SPKCRWDM:
+	case R_SPKCRWDH:
+
+	case R_DACCRWDL:
+	case R_DACCRWDM:
+	case R_DACCRWDH:
+
+	case R_SUBCRWDL:
+	case R_SUBCRWDM:
+	case R_SUBCRWDH:
+		return false;
+	default:
+		return true;
+	};
+}
+
+static bool tscs454_precious(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case R_SPKCRWDL:
+	case R_SPKCRWDM:
+	case R_SPKCRWDH:
+	case R_SPKCRRDL:
+	case R_SPKCRRDM:
+	case R_SPKCRRDH:
+
+	case R_DACCRWDL:
+	case R_DACCRWDM:
+	case R_DACCRWDH:
+	case R_DACCRRDL:
+	case R_DACCRRDM:
+	case R_DACCRRDH:
+
+	case R_SUBCRWDL:
+	case R_SUBCRWDM:
+	case R_SUBCRWDH:
+	case R_SUBCRRDL:
+	case R_SUBCRRDM:
+	case R_SUBCRRDH:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_range_cfg tscs454_regmap_range_cfg = {
+	.name = "Pages",
+	.range_min = VIRT_BASE,
+	.range_max = VIRT_ADDR(0xFE, 0x02),
+	.selector_reg = R_PAGESEL,
+	.selector_mask = 0xff,
+	.selector_shift = 0,
+	.window_start = 0,
+	.window_len = 0x100,
+};
+
+static struct regmap_config const tscs454_regmap_cfg = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.writeable_reg = tscs454_writable,
+	.readable_reg = tscs454_readable,
+	.volatile_reg = tscs454_volatile,
+	.precious_reg = tscs454_precious,
+	.ranges = &tscs454_regmap_range_cfg,
+	.num_ranges = 1,
+	.max_register = VIRT_ADDR(0xFE, 0x02),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static inline int tscs454_data_init(struct tscs454 *tscs454,
+		struct i2c_client *i2c)
+{
+	int i;
+	int ret;
+
+	tscs454->regmap = devm_regmap_init_i2c(i2c, &tscs454_regmap_cfg);
+	if (IS_ERR(tscs454->regmap)) {
+		ret = PTR_ERR(tscs454->regmap);
+		return ret;
+	}
+
+	for (i = 0; i < TSCS454_DAI_COUNT; i++)
+		aif_init(&tscs454->aifs[i], i);
+
+	mutex_init(&tscs454->aifs_status_lock);
+	pll_init(&tscs454->pll1, 1);
+	pll_init(&tscs454->pll2, 2);
+
+	coeff_ram_init(&tscs454->dac_ram);
+	coeff_ram_init(&tscs454->spk_ram);
+	coeff_ram_init(&tscs454->sub_ram);
+
+	return 0;
+}
+
+struct reg_setting {
+	unsigned int addr;
+	unsigned int val;
+};
+
+static int coeff_ram_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	struct coeff_ram_ctl *ctl =
+		(struct coeff_ram_ctl *)kcontrol->private_value;
+	struct soc_bytes_ext *params = &ctl->bytes_ext;
+	u8 *coeff_ram;
+	struct mutex *coeff_ram_lock;
+
+	if (strstr(kcontrol->id.name, "DAC")) {
+		coeff_ram = tscs454->dac_ram.cache;
+		coeff_ram_lock = &tscs454->dac_ram.lock;
+	} else if (strstr(kcontrol->id.name, "Speaker")) {
+		coeff_ram = tscs454->spk_ram.cache;
+		coeff_ram_lock = &tscs454->spk_ram.lock;
+	} else if (strstr(kcontrol->id.name, "Sub")) {
+		coeff_ram = tscs454->sub_ram.cache;
+		coeff_ram_lock = &tscs454->sub_ram.lock;
+	} else {
+		return -EINVAL;
+	}
+
+	mutex_lock(coeff_ram_lock);
+
+	memcpy(ucontrol->value.bytes.data,
+		&coeff_ram[ctl->addr * COEFF_SIZE], params->max);
+
+	mutex_unlock(coeff_ram_lock);
+
+	return 0;
+}
+
+#define DACCRSTAT_MAX_TRYS 10
+static int write_coeff_ram(struct snd_soc_component *component, u8 *coeff_ram,
+		unsigned int r_stat, unsigned int r_addr, unsigned int r_wr,
+		unsigned int coeff_addr, unsigned int coeff_cnt)
+{
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+	int cnt;
+	int trys;
+	int ret;
+
+	for (cnt = 0; cnt < coeff_cnt; cnt++, coeff_addr++) {
+
+		for (trys = 0; trys < DACCRSTAT_MAX_TRYS; trys++) {
+			ret = snd_soc_component_read(component, r_stat, &val);
+			if (ret < 0) {
+				dev_err(component->dev,
+					"Failed to read stat (%d)\n", ret);
+				return ret;
+			}
+			if (!val)
+				break;
+		}
+
+		if (trys == DACCRSTAT_MAX_TRYS) {
+			ret = -EIO;
+			dev_err(component->dev,
+				"Coefficient write error (%d)\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(tscs454->regmap, r_addr, coeff_addr);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to write dac ram address (%d)\n", ret);
+			return ret;
+		}
+
+		ret = regmap_bulk_write(tscs454->regmap, r_wr,
+			&coeff_ram[coeff_addr * COEFF_SIZE],
+			COEFF_SIZE);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to write dac ram (%d)\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int coeff_ram_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	struct coeff_ram_ctl *ctl =
+		(struct coeff_ram_ctl *)kcontrol->private_value;
+	struct soc_bytes_ext *params = &ctl->bytes_ext;
+	unsigned int coeff_cnt = params->max / COEFF_SIZE;
+	u8 *coeff_ram;
+	struct mutex *coeff_ram_lock;
+	bool *coeff_ram_synced;
+	unsigned int r_stat;
+	unsigned int r_addr;
+	unsigned int r_wr;
+	unsigned int val;
+	int ret;
+
+	if (strstr(kcontrol->id.name, "DAC")) {
+		coeff_ram = tscs454->dac_ram.cache;
+		coeff_ram_lock = &tscs454->dac_ram.lock;
+		coeff_ram_synced = &tscs454->dac_ram.synced;
+		r_stat = R_DACCRS;
+		r_addr = R_DACCRADD;
+		r_wr = R_DACCRWDL;
+	} else if (strstr(kcontrol->id.name, "Speaker")) {
+		coeff_ram = tscs454->spk_ram.cache;
+		coeff_ram_lock = &tscs454->spk_ram.lock;
+		coeff_ram_synced = &tscs454->spk_ram.synced;
+		r_stat = R_SPKCRS;
+		r_addr = R_SPKCRADD;
+		r_wr = R_SPKCRWDL;
+	} else if (strstr(kcontrol->id.name, "Sub")) {
+		coeff_ram = tscs454->sub_ram.cache;
+		coeff_ram_lock = &tscs454->sub_ram.lock;
+		coeff_ram_synced = &tscs454->sub_ram.synced;
+		r_stat = R_SUBCRS;
+		r_addr = R_SUBCRADD;
+		r_wr = R_SUBCRWDL;
+	} else {
+		return -EINVAL;
+	}
+
+	mutex_lock(coeff_ram_lock);
+
+	*coeff_ram_synced = false;
+
+	memcpy(&coeff_ram[ctl->addr * COEFF_SIZE],
+		ucontrol->value.bytes.data, params->max);
+
+	mutex_lock(&tscs454->pll1.lock);
+	mutex_lock(&tscs454->pll2.lock);
+
+	ret = snd_soc_component_read(component, R_PLLSTAT, &val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to read PLL status (%d)\n",
+				ret);
+		goto exit;
+	}
+	if (val) { /* PLLs locked */
+		ret = write_coeff_ram(component, coeff_ram,
+			r_stat, r_addr, r_wr,
+			ctl->addr, coeff_cnt);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to flush coeff ram cache (%d)\n", ret);
+			goto exit;
+		}
+		*coeff_ram_synced = true;
+	}
+
+	ret = 0;
+exit:
+	mutex_unlock(&tscs454->pll2.lock);
+	mutex_unlock(&tscs454->pll1.lock);
+	mutex_unlock(coeff_ram_lock);
+
+	return ret;
+}
+
+static inline int coeff_ram_sync(struct snd_soc_component *component,
+		struct tscs454 *tscs454)
+{
+	int ret;
+
+	mutex_lock(&tscs454->dac_ram.lock);
+	if (!tscs454->dac_ram.synced) {
+		ret = write_coeff_ram(component, tscs454->dac_ram.cache,
+				R_DACCRS, R_DACCRADD, R_DACCRWDL,
+				0x00, COEFF_RAM_COEFF_COUNT);
+		if (ret < 0) {
+			mutex_unlock(&tscs454->dac_ram.lock);
+			return ret;
+		}
+	}
+	mutex_unlock(&tscs454->dac_ram.lock);
+
+	mutex_lock(&tscs454->spk_ram.lock);
+	if (!tscs454->spk_ram.synced) {
+		ret = write_coeff_ram(component, tscs454->spk_ram.cache,
+				R_SPKCRS, R_SPKCRADD, R_SPKCRWDL,
+				0x00, COEFF_RAM_COEFF_COUNT);
+		if (ret < 0) {
+			mutex_unlock(&tscs454->spk_ram.lock);
+			return ret;
+		}
+	}
+	mutex_unlock(&tscs454->spk_ram.lock);
+
+	mutex_lock(&tscs454->sub_ram.lock);
+	if (!tscs454->sub_ram.synced) {
+		ret = write_coeff_ram(component, tscs454->sub_ram.cache,
+				R_SUBCRS, R_SUBCRADD, R_SUBCRWDL,
+				0x00, COEFF_RAM_COEFF_COUNT);
+		if (ret < 0) {
+			mutex_unlock(&tscs454->sub_ram.lock);
+			return ret;
+		}
+	}
+	mutex_unlock(&tscs454->sub_ram.lock);
+
+	return 0;
+}
+
+#define PLL_REG_SETTINGS_COUNT 11
+struct pll_ctl {
+	int freq_in;
+	struct reg_setting settings[PLL_REG_SETTINGS_COUNT];
+};
+
+#define PLL_CTL(f, t, c1, r1, o1, f1l, f1h, c2, r2, o2, f2l, f2h)	\
+	{								\
+		.freq_in = f,						\
+		.settings = {						\
+			{R_PLL1CTL,	c1},				\
+			{R_PLL1RDIV,	r1},				\
+			{R_PLL1ODIV,	o1},				\
+			{R_PLL1FDIVL,	f1l},				\
+			{R_PLL1FDIVH,	f1h},				\
+			{R_PLL2CTL,	c2},				\
+			{R_PLL2RDIV,	r2},				\
+			{R_PLL2ODIV,	o2},				\
+			{R_PLL2FDIVL,	f2l},				\
+			{R_PLL2FDIVH,	f2h},				\
+			{R_TIMEBASE,	t},				\
+		},							\
+	}
+
+static const struct pll_ctl pll_ctls[] = {
+	PLL_CTL(1411200, 0x05,
+		0xB9, 0x07, 0x02, 0xC3, 0x04,
+		0x5A, 0x02, 0x03, 0xE0, 0x01),
+	PLL_CTL(1536000, 0x05,
+		0x5A, 0x02, 0x03, 0xE0, 0x01,
+		0x5A, 0x02, 0x03, 0xB9, 0x01),
+	PLL_CTL(2822400, 0x0A,
+		0x63, 0x07, 0x04, 0xC3, 0x04,
+		0x62, 0x07, 0x03, 0x48, 0x03),
+	PLL_CTL(3072000, 0x0B,
+		0x62, 0x07, 0x03, 0x48, 0x03,
+		0x5A, 0x04, 0x03, 0xB9, 0x01),
+	PLL_CTL(5644800, 0x15,
+		0x63, 0x0E, 0x04, 0xC3, 0x04,
+		0x5A, 0x08, 0x03, 0xE0, 0x01),
+	PLL_CTL(6144000, 0x17,
+		0x5A, 0x08, 0x03, 0xE0, 0x01,
+		0x5A, 0x08, 0x03, 0xB9, 0x01),
+	PLL_CTL(12000000, 0x2E,
+		0x5B, 0x19, 0x03, 0x00, 0x03,
+		0x6A, 0x19, 0x05, 0x98, 0x04),
+	PLL_CTL(19200000, 0x4A,
+		0x53, 0x14, 0x03, 0x80, 0x01,
+		0x5A, 0x19, 0x03, 0xB9, 0x01),
+	PLL_CTL(22000000, 0x55,
+		0x6A, 0x37, 0x05, 0x00, 0x06,
+		0x62, 0x26, 0x03, 0x49, 0x02),
+	PLL_CTL(22579200, 0x57,
+		0x62, 0x31, 0x03, 0x20, 0x03,
+		0x53, 0x1D, 0x03, 0xB3, 0x01),
+	PLL_CTL(24000000, 0x5D,
+		0x53, 0x19, 0x03, 0x80, 0x01,
+		0x5B, 0x19, 0x05, 0x4C, 0x02),
+	PLL_CTL(24576000, 0x5F,
+		0x53, 0x1D, 0x03, 0xB3, 0x01,
+		0x62, 0x40, 0x03, 0x72, 0x03),
+	PLL_CTL(27000000, 0x68,
+		0x62, 0x4B, 0x03, 0x00, 0x04,
+		0x6A, 0x7D, 0x03, 0x20, 0x06),
+	PLL_CTL(36000000, 0x8C,
+		0x5B, 0x4B, 0x03, 0x00, 0x03,
+		0x6A, 0x7D, 0x03, 0x98, 0x04),
+	PLL_CTL(11289600, 0x2B,
+		0x6A, 0x31, 0x03, 0x40, 0x06,
+		0x5A, 0x12, 0x03, 0x1C, 0x02),
+	PLL_CTL(26000000, 0x65,
+		0x63, 0x41, 0x05, 0x00, 0x06,
+		0x5A, 0x26, 0x03, 0xEF, 0x01),
+	PLL_CTL(12288000, 0x2F,
+		0x5A, 0x12, 0x03, 0x1C, 0x02,
+		0x62, 0x20, 0x03, 0x72, 0x03),
+	PLL_CTL(40000000, 0x9B,
+		0xA2, 0x7D, 0x03, 0x80, 0x04,
+		0x63, 0x7D, 0x05, 0xE4, 0x06),
+	PLL_CTL(512000, 0x01,
+		0x62, 0x01, 0x03, 0xD0, 0x02,
+		0x5B, 0x01, 0x04, 0x72, 0x03),
+	PLL_CTL(705600, 0x02,
+		0x62, 0x02, 0x03, 0x15, 0x04,
+		0x62, 0x01, 0x04, 0x80, 0x02),
+	PLL_CTL(1024000, 0x03,
+		0x62, 0x02, 0x03, 0xD0, 0x02,
+		0x5B, 0x02, 0x04, 0x72, 0x03),
+	PLL_CTL(2048000, 0x07,
+		0x62, 0x04, 0x03, 0xD0, 0x02,
+		0x5B, 0x04, 0x04, 0x72, 0x03),
+	PLL_CTL(2400000, 0x08,
+		0x62, 0x05, 0x03, 0x00, 0x03,
+		0x63, 0x05, 0x05, 0x98, 0x04),
+};
+
+static inline const struct pll_ctl *get_pll_ctl(unsigned long freq_in)
+{
+	int i;
+	struct pll_ctl const *pll_ctl = NULL;
+
+	for (i = 0; i < ARRAY_SIZE(pll_ctls); ++i)
+		if (pll_ctls[i].freq_in == freq_in) {
+			pll_ctl = &pll_ctls[i];
+			break;
+		}
+
+	return pll_ctl;
+}
+
+enum {
+	PLL_INPUT_XTAL = 0,
+	PLL_INPUT_MCLK1,
+	PLL_INPUT_MCLK2,
+	PLL_INPUT_BCLK,
+};
+
+static int set_sysclk(struct snd_soc_component *component)
+{
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	struct pll_ctl const *pll_ctl;
+	unsigned long freq;
+	int i;
+	int ret;
+
+	if (tscs454->sysclk_src_id < PLL_INPUT_BCLK)
+		freq = clk_get_rate(tscs454->sysclk);
+	else
+		freq = tscs454->bclk_freq;
+	pll_ctl = get_pll_ctl(freq);
+	if (!pll_ctl) {
+		ret = -EINVAL;
+		dev_err(component->dev,
+				"Invalid PLL input %lu (%d)\n", freq, ret);
+		return ret;
+	}
+
+	for (i = 0; i < PLL_REG_SETTINGS_COUNT; ++i) {
+		ret = snd_soc_component_write(component,
+				pll_ctl->settings[i].addr,
+				pll_ctl->settings[i].val);
+		if (ret < 0) {
+			dev_err(component->dev,
+					"Failed to set pll setting (%d)\n",
+					ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static inline void reserve_pll(struct pll *pll)
+{
+	mutex_lock(&pll->lock);
+	pll->users++;
+	mutex_unlock(&pll->lock);
+}
+
+static inline void free_pll(struct pll *pll)
+{
+	mutex_lock(&pll->lock);
+	pll->users--;
+	mutex_unlock(&pll->lock);
+}
+
+static int pll_connected(struct snd_soc_dapm_widget *source,
+		struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(source->dapm);
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	int users;
+
+	if (strstr(source->name, "PLL 1")) {
+		mutex_lock(&tscs454->pll1.lock);
+		users = tscs454->pll1.users;
+		mutex_unlock(&tscs454->pll1.lock);
+		dev_dbg(component->dev, "%s(): PLL 1 users = %d\n", __func__,
+				users);
+	} else {
+		mutex_lock(&tscs454->pll2.lock);
+		users = tscs454->pll2.users;
+		mutex_unlock(&tscs454->pll2.lock);
+		dev_dbg(component->dev, "%s(): PLL 2 users = %d\n", __func__,
+				users);
+	}
+
+	return users;
+}
+
+/*
+ * PLL must be enabled after power up and must be disabled before power down
+ * for proper clock switching.
+ */
+static int pll_power_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 tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	bool enable;
+	bool pll1;
+	unsigned int msk;
+	unsigned int val;
+	int ret;
+
+	if (strstr(w->name, "PLL 1"))
+		pll1 = true;
+	else
+		pll1 = false;
+
+	msk = pll1 ? FM_PLLCTL_PLL1CLKEN : FM_PLLCTL_PLL2CLKEN;
+
+	if (event == SND_SOC_DAPM_POST_PMU)
+		enable = true;
+	else
+		enable = false;
+
+	if (enable)
+		val = pll1 ? FV_PLL1CLKEN_ENABLE : FV_PLL2CLKEN_ENABLE;
+	else
+		val = pll1 ? FV_PLL1CLKEN_DISABLE : FV_PLL2CLKEN_DISABLE;
+
+	ret = snd_soc_component_update_bits(component, R_PLLCTL, msk, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to %s PLL %d  (%d)\n",
+				enable ? "enable" : "disable",
+				pll1 ? 1 : 2,
+				ret);
+		return ret;
+	}
+
+	if (enable) {
+		msleep(20); // Wait for lock
+		ret = coeff_ram_sync(component, tscs454);
+		if (ret < 0) {
+			dev_err(component->dev,
+					"Failed to sync coeff ram (%d)\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static inline int aif_set_master(struct snd_soc_component *component,
+		unsigned int aif_id, bool master)
+{
+	unsigned int reg;
+	unsigned int mask;
+	unsigned int val;
+	int ret;
+
+	switch (aif_id) {
+	case TSCS454_DAI1_ID:
+		reg = R_I2SP1CTL;
+		break;
+	case TSCS454_DAI2_ID:
+		reg = R_I2SP2CTL;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_I2SP3CTL;
+		break;
+	default:
+		ret = -ENODEV;
+		dev_err(component->dev, "Unknown DAI %d (%d)\n", aif_id, ret);
+		return ret;
+	}
+	mask = FM_I2SPCTL_PORTMS;
+	val = master ? FV_PORTMS_MASTER : FV_PORTMS_SLAVE;
+
+	ret = snd_soc_component_update_bits(component, reg, mask, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set DAI %d to %s (%d)\n",
+			aif_id, master ? "master" : "slave", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline
+int aif_prepare(struct snd_soc_component *component, struct aif *aif)
+{
+	int ret;
+
+	ret = aif_set_master(component, aif->id, aif->master);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static inline int aif_free(struct snd_soc_component *component,
+		struct aif *aif, bool playback)
+{
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+
+	mutex_lock(&tscs454->aifs_status_lock);
+
+	dev_dbg(component->dev, "%s(): aif %d\n", __func__, aif->id);
+
+	set_aif_status_inactive(&tscs454->aifs_status, aif->id, playback);
+
+	dev_dbg(component->dev, "Set aif %d inactive. Streams status is 0x%x\n",
+		aif->id, tscs454->aifs_status.streams);
+
+	if (!aif_active(&tscs454->aifs_status, aif->id)) {
+		/* Do config in slave mode */
+		aif_set_master(component, aif->id, false);
+		dev_dbg(component->dev, "Freeing pll %d from aif %d\n",
+				aif->pll->id, aif->id);
+		free_pll(aif->pll);
+	}
+
+	if (!aifs_active(&tscs454->aifs_status)) {
+		dev_dbg(component->dev, "Freeing pll %d from ir\n",
+				tscs454->internal_rate.pll->id);
+		free_pll(tscs454->internal_rate.pll);
+	}
+
+	mutex_unlock(&tscs454->aifs_status_lock);
+
+	return 0;
+}
+
+/* R_PLLCTL PG 0 ADDR 0x15 */
+static char const * const bclk_sel_txt[] = {
+		"BCLK 1", "BCLK 2", "BCLK 3"};
+
+static struct soc_enum const bclk_sel_enum =
+		SOC_ENUM_SINGLE(R_PLLCTL, FB_PLLCTL_BCLKSEL,
+				ARRAY_SIZE(bclk_sel_txt), bclk_sel_txt);
+
+/* R_ISRC PG 0 ADDR 0x16 */
+static char const * const isrc_br_txt[] = {
+		"44.1kHz", "48kHz"};
+
+static struct soc_enum const isrc_br_enum =
+		SOC_ENUM_SINGLE(R_ISRC, FB_ISRC_IBR,
+				ARRAY_SIZE(isrc_br_txt), isrc_br_txt);
+
+static char const * const isrc_bm_txt[] = {
+		"0.25x", "0.5x", "1.0x", "2.0x"};
+
+static struct soc_enum const isrc_bm_enum =
+		SOC_ENUM_SINGLE(R_ISRC, FB_ISRC_IBM,
+				ARRAY_SIZE(isrc_bm_txt), isrc_bm_txt);
+
+/* R_SCLKCTL PG 0 ADDR 0x18 */
+static char const * const modular_rate_txt[] = {
+	"Reserved", "Half", "Full", "Auto",};
+
+static struct soc_enum const adc_modular_rate_enum =
+	SOC_ENUM_SINGLE(R_SCLKCTL, FB_SCLKCTL_ASDM,
+			ARRAY_SIZE(modular_rate_txt), modular_rate_txt);
+
+static struct soc_enum const dac_modular_rate_enum =
+	SOC_ENUM_SINGLE(R_SCLKCTL, FB_SCLKCTL_DSDM,
+			ARRAY_SIZE(modular_rate_txt), modular_rate_txt);
+
+/* R_I2SIDCTL PG 0 ADDR 0x38 */
+static char const * const data_ctrl_txt[] = {
+	"L/R", "L/L", "R/R", "R/L"};
+
+static struct soc_enum const data_in_ctrl_enums[] = {
+	SOC_ENUM_SINGLE(R_I2SIDCTL, FB_I2SIDCTL_I2SI1DCTL,
+			ARRAY_SIZE(data_ctrl_txt), data_ctrl_txt),
+	SOC_ENUM_SINGLE(R_I2SIDCTL, FB_I2SIDCTL_I2SI2DCTL,
+			ARRAY_SIZE(data_ctrl_txt), data_ctrl_txt),
+	SOC_ENUM_SINGLE(R_I2SIDCTL, FB_I2SIDCTL_I2SI3DCTL,
+			ARRAY_SIZE(data_ctrl_txt), data_ctrl_txt),
+};
+
+/* R_I2SODCTL PG 0 ADDR 0x39 */
+static struct soc_enum const data_out_ctrl_enums[] = {
+	SOC_ENUM_SINGLE(R_I2SODCTL, FB_I2SODCTL_I2SO1DCTL,
+			ARRAY_SIZE(data_ctrl_txt), data_ctrl_txt),
+	SOC_ENUM_SINGLE(R_I2SODCTL, FB_I2SODCTL_I2SO2DCTL,
+			ARRAY_SIZE(data_ctrl_txt), data_ctrl_txt),
+	SOC_ENUM_SINGLE(R_I2SODCTL, FB_I2SODCTL_I2SO3DCTL,
+			ARRAY_SIZE(data_ctrl_txt), data_ctrl_txt),
+};
+
+/* R_AUDIOMUX1 PG 0 ADDR 0x3A */
+static char const * const asrc_mux_txt[] = {
+		"None", "DAI 1", "DAI 2", "DAI 3"};
+
+static struct soc_enum const asrc_in_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX1, FB_AUDIOMUX1_ASRCIMUX,
+				ARRAY_SIZE(asrc_mux_txt), asrc_mux_txt);
+
+static char const * const dai_mux_txt[] = {
+		"CH 0_1", "CH 2_3", "CH 4_5", "ADC/DMic 1",
+		"DMic 2", "ClassD", "DAC", "Sub"};
+
+static struct soc_enum const dai2_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX1, FB_AUDIOMUX1_I2S2MUX,
+				ARRAY_SIZE(dai_mux_txt), dai_mux_txt);
+
+static struct snd_kcontrol_new const dai2_mux_dapm_enum =
+		SOC_DAPM_ENUM("DAI 2 Mux",  dai2_mux_enum);
+
+static struct soc_enum const dai1_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX1, FB_AUDIOMUX1_I2S1MUX,
+				ARRAY_SIZE(dai_mux_txt), dai_mux_txt);
+
+static struct snd_kcontrol_new const dai1_mux_dapm_enum =
+		SOC_DAPM_ENUM("DAI 1 Mux", dai1_mux_enum);
+
+/* R_AUDIOMUX2 PG 0 ADDR 0x3B */
+static struct soc_enum const asrc_out_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX2, FB_AUDIOMUX2_ASRCOMUX,
+				ARRAY_SIZE(asrc_mux_txt), asrc_mux_txt);
+
+static struct soc_enum const dac_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX2, FB_AUDIOMUX2_DACMUX,
+				ARRAY_SIZE(dai_mux_txt), dai_mux_txt);
+
+static struct snd_kcontrol_new const dac_mux_dapm_enum =
+		SOC_DAPM_ENUM("DAC Mux", dac_mux_enum);
+
+static struct soc_enum const dai3_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX2, FB_AUDIOMUX2_I2S3MUX,
+				ARRAY_SIZE(dai_mux_txt), dai_mux_txt);
+
+static struct snd_kcontrol_new const dai3_mux_dapm_enum =
+		SOC_DAPM_ENUM("DAI 3 Mux", dai3_mux_enum);
+
+/* R_AUDIOMUX3 PG 0 ADDR 0x3C */
+static char const * const sub_mux_txt[] = {
+		"CH 0", "CH 1", "CH 0 + 1",
+		"CH 2", "CH 3", "CH 2 + 3",
+		"CH 4", "CH 5", "CH 4 + 5",
+		"ADC/DMic 1 Left", "ADC/DMic 1 Right",
+		"ADC/DMic 1 Left Plus Right",
+		"DMic 2 Left", "DMic 2 Right", "DMic 2 Left Plus Right",
+		"ClassD Left", "ClassD Right", "ClassD Left Plus Right"};
+
+static struct soc_enum const sub_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX3, FB_AUDIOMUX3_SUBMUX,
+				ARRAY_SIZE(sub_mux_txt), sub_mux_txt);
+
+static struct snd_kcontrol_new const sub_mux_dapm_enum =
+		SOC_DAPM_ENUM("Sub Mux", sub_mux_enum);
+
+static struct soc_enum const classd_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX3, FB_AUDIOMUX3_CLSSDMUX,
+				ARRAY_SIZE(dai_mux_txt), dai_mux_txt);
+
+static struct snd_kcontrol_new const classd_mux_dapm_enum =
+		SOC_DAPM_ENUM("ClassD Mux", classd_mux_enum);
+
+/* R_HSDCTL1 PG 1 ADDR 0x01 */
+static char const * const jack_type_txt[] = {
+		"3 Terminal", "4 Terminal"};
+
+static struct soc_enum const hp_jack_type_enum =
+		SOC_ENUM_SINGLE(R_HSDCTL1, FB_HSDCTL1_HPJKTYPE,
+				ARRAY_SIZE(jack_type_txt), jack_type_txt);
+
+static char const * const hs_det_pol_txt[] = {
+		"Rising", "Falling"};
+
+static struct soc_enum const hs_det_pol_enum =
+		SOC_ENUM_SINGLE(R_HSDCTL1, FB_HSDCTL1_HSDETPOL,
+				ARRAY_SIZE(hs_det_pol_txt), hs_det_pol_txt);
+
+/* R_HSDCTL1 PG 1 ADDR 0x02 */
+static char const * const hs_mic_bias_force_txt[] = {
+		"Off", "Ring", "Sleeve"};
+
+static struct soc_enum const hs_mic_bias_force_enum =
+		SOC_ENUM_SINGLE(R_HSDCTL2, FB_HSDCTL2_FMICBIAS1,
+				ARRAY_SIZE(hs_mic_bias_force_txt),
+				hs_mic_bias_force_txt);
+
+static char const * const plug_type_txt[] = {
+		"OMTP", "CTIA", "Reserved", "Headphone"};
+
+static struct soc_enum const plug_type_force_enum =
+		SOC_ENUM_SINGLE(R_HSDCTL2, FB_HSDCTL2_FPLUGTYPE,
+		ARRAY_SIZE(plug_type_txt), plug_type_txt);
+
+
+/* R_CH0AIC PG 1 ADDR 0x06 */
+static char const * const in_bst_mux_txt[] = {
+		"Input 1", "Input 2", "Input 3", "D2S"};
+
+static struct soc_enum const in_bst_mux_ch0_enum =
+		SOC_ENUM_SINGLE(R_CH0AIC, FB_CH0AIC_INSELL,
+				ARRAY_SIZE(in_bst_mux_txt),
+				in_bst_mux_txt);
+static struct snd_kcontrol_new const in_bst_mux_ch0_dapm_enum =
+		SOC_DAPM_ENUM("Input Boost Channel 0 Enum",
+				in_bst_mux_ch0_enum);
+
+static DECLARE_TLV_DB_SCALE(in_bst_vol_tlv_arr, 0, 1000, 0);
+
+static char const * const adc_mux_txt[] = {
+		"Input 1 Boost Bypass", "Input 2 Boost Bypass",
+		"Input 3 Boost Bypass", "Input Boost"};
+
+static struct soc_enum const adc_mux_ch0_enum =
+		SOC_ENUM_SINGLE(R_CH0AIC, FB_CH0AIC_LADCIN,
+				ARRAY_SIZE(adc_mux_txt), adc_mux_txt);
+static struct snd_kcontrol_new const adc_mux_ch0_dapm_enum =
+		SOC_DAPM_ENUM("ADC Channel 0 Enum", adc_mux_ch0_enum);
+
+static char const * const in_proc_mux_txt[] = {
+		"ADC", "DMic"};
+
+static struct soc_enum const in_proc_ch0_enum =
+		SOC_ENUM_SINGLE(R_CH0AIC, FB_CH0AIC_IPCH0S,
+				ARRAY_SIZE(in_proc_mux_txt), in_proc_mux_txt);
+static struct snd_kcontrol_new const in_proc_mux_ch0_dapm_enum =
+		SOC_DAPM_ENUM("Input Processor Channel 0 Enum",
+				in_proc_ch0_enum);
+
+/* R_CH1AIC PG 1 ADDR 0x07 */
+static struct soc_enum const in_bst_mux_ch1_enum =
+		SOC_ENUM_SINGLE(R_CH1AIC, FB_CH1AIC_INSELR,
+				ARRAY_SIZE(in_bst_mux_txt),
+				in_bst_mux_txt);
+static struct snd_kcontrol_new const in_bst_mux_ch1_dapm_enum =
+		SOC_DAPM_ENUM("Input Boost Channel 1 Enum",
+				in_bst_mux_ch1_enum);
+
+static struct soc_enum const adc_mux_ch1_enum =
+		SOC_ENUM_SINGLE(R_CH1AIC, FB_CH1AIC_RADCIN,
+				ARRAY_SIZE(adc_mux_txt), adc_mux_txt);
+static struct snd_kcontrol_new const adc_mux_ch1_dapm_enum =
+		SOC_DAPM_ENUM("ADC Channel 1 Enum", adc_mux_ch1_enum);
+
+static struct soc_enum const in_proc_ch1_enum =
+		SOC_ENUM_SINGLE(R_CH1AIC, FB_CH1AIC_IPCH1S,
+				ARRAY_SIZE(in_proc_mux_txt), in_proc_mux_txt);
+static struct snd_kcontrol_new const in_proc_mux_ch1_dapm_enum =
+		SOC_DAPM_ENUM("Input Processor Channel 1 Enum",
+				in_proc_ch1_enum);
+
+/* R_ICTL0 PG 1 ADDR 0x0A */
+static char const * const pol_txt[] = {
+		"Normal", "Invert"};
+
+static struct soc_enum const in_pol_ch1_enum =
+		SOC_ENUM_SINGLE(R_ICTL0, FB_ICTL0_IN0POL,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+static struct soc_enum const in_pol_ch0_enum =
+		SOC_ENUM_SINGLE(R_ICTL0, FB_ICTL0_IN1POL,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+static char const * const in_proc_ch_sel_txt[] = {
+		"Normal", "Mono Mix to Channel 0",
+		"Mono Mix to Channel 1", "Add"};
+
+static struct soc_enum const in_proc_ch01_sel_enum =
+		SOC_ENUM_SINGLE(R_ICTL0, FB_ICTL0_INPCH10SEL,
+				ARRAY_SIZE(in_proc_ch_sel_txt),
+				in_proc_ch_sel_txt);
+
+/* R_ICTL1 PG 1 ADDR 0x0B */
+static struct soc_enum const in_pol_ch3_enum =
+		SOC_ENUM_SINGLE(R_ICTL1, FB_ICTL1_IN2POL,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+static struct soc_enum const in_pol_ch2_enum =
+		SOC_ENUM_SINGLE(R_ICTL1, FB_ICTL1_IN3POL,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+static struct soc_enum const in_proc_ch23_sel_enum =
+		SOC_ENUM_SINGLE(R_ICTL1, FB_ICTL1_INPCH32SEL,
+				ARRAY_SIZE(in_proc_ch_sel_txt),
+				in_proc_ch_sel_txt);
+
+/* R_MICBIAS PG 1 ADDR 0x0C */
+static char const * const mic_bias_txt[] = {
+		"2.5V", "2.1V", "1.8V", "Vdd"};
+
+static struct soc_enum const mic_bias_2_enum =
+		SOC_ENUM_SINGLE(R_MICBIAS, FB_MICBIAS_MICBOV2,
+				ARRAY_SIZE(mic_bias_txt), mic_bias_txt);
+
+static struct soc_enum const mic_bias_1_enum =
+		SOC_ENUM_SINGLE(R_MICBIAS, FB_MICBIAS_MICBOV1,
+				ARRAY_SIZE(mic_bias_txt), mic_bias_txt);
+
+/* R_PGACTL0 PG 1 ADDR 0x0D */
+/* R_PGACTL1 PG 1 ADDR 0x0E */
+/* R_PGACTL2 PG 1 ADDR 0x0F */
+/* R_PGACTL3 PG 1 ADDR 0x10 */
+static DECLARE_TLV_DB_SCALE(in_pga_vol_tlv_arr, -1725, 75, 0);
+
+/* R_ICH0VOL PG1 ADDR 0x12 */
+/* R_ICH1VOL PG1 ADDR 0x13 */
+/* R_ICH2VOL PG1 ADDR 0x14 */
+/* R_ICH3VOL PG1 ADDR 0x15 */
+static DECLARE_TLV_DB_MINMAX(in_vol_tlv_arr, -7125, 2400);
+
+/* R_ASRCILVOL PG1 ADDR 0x16 */
+/* R_ASRCIRVOL PG1 ADDR 0x17 */
+/* R_ASRCOLVOL PG1 ADDR 0x18 */
+/* R_ASRCORVOL PG1 ADDR 0x19 */
+static DECLARE_TLV_DB_MINMAX(asrc_vol_tlv_arr, -9562, 600);
+
+/* R_ALCCTL0 PG1 ADDR 0x1D */
+static char const * const alc_mode_txt[] = {
+		"ALC", "Limiter"};
+
+static struct soc_enum const alc_mode_enum =
+		SOC_ENUM_SINGLE(R_ALCCTL0, FB_ALCCTL0_ALCMODE,
+				ARRAY_SIZE(alc_mode_txt), alc_mode_txt);
+
+static char const * const alc_ref_text[] = {
+		"Channel 0", "Channel 1", "Channel 2", "Channel 3", "Peak"};
+
+static struct soc_enum const alc_ref_enum =
+		SOC_ENUM_SINGLE(R_ALCCTL0, FB_ALCCTL0_ALCREF,
+				ARRAY_SIZE(alc_ref_text), alc_ref_text);
+
+/* R_ALCCTL1 PG 1 ADDR 0x1E */
+static DECLARE_TLV_DB_SCALE(alc_max_gain_tlv_arr, -1200, 600, 0);
+static DECLARE_TLV_DB_SCALE(alc_target_tlv_arr, -2850, 150, 0);
+
+/* R_ALCCTL2 PG 1 ADDR 0x1F */
+static DECLARE_TLV_DB_SCALE(alc_min_gain_tlv_arr, -1725, 600, 0);
+
+/* R_NGATE PG 1 ADDR 0x21 */
+static DECLARE_TLV_DB_SCALE(ngth_tlv_arr, -7650, 150, 0);
+
+static char const * const ngate_type_txt[] = {
+		"PGA Constant", "ADC Mute"};
+
+static struct soc_enum const ngate_type_enum =
+		SOC_ENUM_SINGLE(R_NGATE, FB_NGATE_NGG,
+				ARRAY_SIZE(ngate_type_txt), ngate_type_txt);
+
+/* R_DMICCTL PG 1 ADDR 0x22 */
+static char const * const dmic_mono_sel_txt[] = {
+		"Stereo", "Mono"};
+
+static struct soc_enum const dmic_mono_sel_enum =
+		SOC_ENUM_SINGLE(R_DMICCTL, FB_DMICCTL_DMONO,
+			ARRAY_SIZE(dmic_mono_sel_txt), dmic_mono_sel_txt);
+
+/* R_DACCTL PG 2 ADDR 0x01 */
+static struct soc_enum const dac_pol_r_enum =
+		SOC_ENUM_SINGLE(R_DACCTL, FB_DACCTL_DACPOLR,
+			ARRAY_SIZE(pol_txt), pol_txt);
+
+static struct soc_enum const dac_pol_l_enum =
+		SOC_ENUM_SINGLE(R_DACCTL, FB_DACCTL_DACPOLL,
+			ARRAY_SIZE(pol_txt), pol_txt);
+
+static char const * const dac_dith_txt[] = {
+		"Half", "Full", "Disabled", "Static"};
+
+static struct soc_enum const dac_dith_enum =
+		SOC_ENUM_SINGLE(R_DACCTL, FB_DACCTL_DACDITH,
+			ARRAY_SIZE(dac_dith_txt), dac_dith_txt);
+
+/* R_SPKCTL PG 2 ADDR 0x02 */
+static struct soc_enum const spk_pol_r_enum =
+		SOC_ENUM_SINGLE(R_SPKCTL, FB_SPKCTL_SPKPOLR,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+static struct soc_enum const spk_pol_l_enum =
+		SOC_ENUM_SINGLE(R_SPKCTL, FB_SPKCTL_SPKPOLL,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_SUBCTL PG 2 ADDR 0x03 */
+static struct soc_enum const sub_pol_enum =
+		SOC_ENUM_SINGLE(R_SUBCTL, FB_SUBCTL_SUBPOL,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_MVOLL PG 2 ADDR 0x08 */
+/* R_MVOLR PG 2 ADDR 0x09 */
+static DECLARE_TLV_DB_MINMAX(mvol_tlv_arr, -9562, 0);
+
+/* R_HPVOLL PG 2 ADDR 0x0A */
+/* R_HPVOLR PG 2 ADDR 0x0B */
+static DECLARE_TLV_DB_SCALE(hp_vol_tlv_arr, -8850, 75, 0);
+
+/* R_SPKVOLL PG 2 ADDR 0x0C */
+/* R_SPKVOLR PG 2 ADDR 0x0D */
+static DECLARE_TLV_DB_SCALE(spk_vol_tlv_arr, -7725, 75, 0);
+
+/* R_SPKEQFILT PG 3 ADDR 0x01 */
+static char const * const eq_txt[] = {
+	"Pre Scale",
+	"Pre Scale + EQ Band 0",
+	"Pre Scale + EQ Band 0 - 1",
+	"Pre Scale + EQ Band 0 - 2",
+	"Pre Scale + EQ Band 0 - 3",
+	"Pre Scale + EQ Band 0 - 4",
+	"Pre Scale + EQ Band 0 - 5",
+};
+
+static struct soc_enum const spk_eq_enums[] = {
+	SOC_ENUM_SINGLE(R_SPKEQFILT, FB_SPKEQFILT_EQ2BE,
+		ARRAY_SIZE(eq_txt), eq_txt),
+	SOC_ENUM_SINGLE(R_SPKEQFILT, FB_SPKEQFILT_EQ1BE,
+		ARRAY_SIZE(eq_txt), eq_txt),
+};
+
+/* R_SPKMBCCTL PG 3 ADDR 0x0B */
+static char const * const lvl_mode_txt[] = {
+		"Average", "Peak"};
+
+static struct soc_enum const spk_mbc3_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCCTL, FB_SPKMBCCTL_LVLMODE3,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static char const * const win_sel_txt[] = {
+		"512", "64"};
+
+static struct soc_enum const spk_mbc3_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCCTL, FB_SPKMBCCTL_WINSEL3,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+static struct soc_enum const spk_mbc2_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCCTL, FB_SPKMBCCTL_LVLMODE2,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const spk_mbc2_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCCTL, FB_SPKMBCCTL_WINSEL2,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+static struct soc_enum const spk_mbc1_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCCTL, FB_SPKMBCCTL_LVLMODE1,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const spk_mbc1_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCCTL, FB_SPKMBCCTL_WINSEL1,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+/* R_SPKMBCMUG1 PG 3 ADDR 0x0C */
+static struct soc_enum const spk_mbc1_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCMUG1, FB_SPKMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+static DECLARE_TLV_DB_MINMAX(mbc_mug_tlv_arr, -4650, 0);
+
+/* R_SPKMBCTHR1 PG 3 ADDR 0x0D */
+static DECLARE_TLV_DB_MINMAX(thr_tlv_arr, -9562, 0);
+
+/* R_SPKMBCRAT1 PG 3 ADDR 0x0E */
+static char const * const comp_rat_txt[] = {
+		"Reserved", "1.5:1", "2:1", "3:1", "4:1", "5:1", "6:1",
+		"7:1", "8:1", "9:1", "10:1", "11:1", "12:1", "13:1", "14:1",
+		"15:1", "16:1", "17:1", "18:1", "19:1", "20:1"};
+
+static struct soc_enum const spk_mbc1_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCRAT1, FB_SPKMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SPKMBCMUG2 PG 3 ADDR 0x13 */
+static struct soc_enum const spk_mbc2_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCMUG2, FB_SPKMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_SPKMBCRAT2 PG 3 ADDR 0x15 */
+static struct soc_enum const spk_mbc2_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCRAT2, FB_SPKMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SPKMBCMUG3 PG 3 ADDR 0x1A */
+static struct soc_enum const spk_mbc3_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCMUG3, FB_SPKMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_SPKMBCRAT3 PG 3 ADDR 0x1C */
+static struct soc_enum const spk_mbc3_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCRAT3, FB_SPKMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SPKCLECTL PG 3 ADDR 0x21 */
+static struct soc_enum const spk_cle_lvl_mode_enum =
+		SOC_ENUM_SINGLE(R_SPKCLECTL, FB_SPKCLECTL_LVLMODE,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const spk_cle_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SPKCLECTL, FB_SPKCLECTL_WINSEL,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+/* R_SPKCLEMUG PG 3 ADDR 0x22 */
+static DECLARE_TLV_DB_MINMAX(cle_mug_tlv_arr, 0, 4650);
+
+/* R_SPKCOMPRAT PG 3 ADDR 0x24 */
+static struct soc_enum const spk_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SPKCOMPRAT, FB_SPKCOMPRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SPKEXPTHR PG 3 ADDR 0x2F */
+static char const * const exp_rat_txt[] = {
+		"Reserved", "Reserved", "1:2", "1:3",
+		"1:4", "1:5", "1:6", "1:7"};
+
+static struct soc_enum const spk_exp_rat_enum =
+		SOC_ENUM_SINGLE(R_SPKEXPRAT, FB_SPKEXPRAT_RATIO,
+				ARRAY_SIZE(exp_rat_txt), exp_rat_txt);
+
+/* R_DACEQFILT PG 4 ADDR 0x01 */
+static struct soc_enum const dac_eq_enums[] = {
+	SOC_ENUM_SINGLE(R_DACEQFILT, FB_DACEQFILT_EQ2BE,
+		ARRAY_SIZE(eq_txt), eq_txt),
+	SOC_ENUM_SINGLE(R_DACEQFILT, FB_DACEQFILT_EQ1BE,
+		ARRAY_SIZE(eq_txt), eq_txt),
+};
+
+/* R_DACMBCCTL PG 4 ADDR 0x0B */
+static struct soc_enum const dac_mbc3_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE3,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const dac_mbc3_win_sel_enum =
+		SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL3,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+static struct soc_enum const dac_mbc2_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE2,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const dac_mbc2_win_sel_enum =
+		SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL2,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+static struct soc_enum const dac_mbc1_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE1,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const dac_mbc1_win_sel_enum =
+		SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL1,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+/* R_DACMBCMUG1 PG 4 ADDR 0x0C */
+static struct soc_enum const dac_mbc1_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_DACMBCMUG1, FB_DACMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_DACMBCRAT1 PG 4 ADDR 0x0E */
+static struct soc_enum const dac_mbc1_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_DACMBCRAT1, FB_DACMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_DACMBCMUG2 PG 4 ADDR 0x13 */
+static struct soc_enum const dac_mbc2_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_DACMBCMUG2, FB_DACMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_DACMBCRAT2 PG 4 ADDR 0x15 */
+static struct soc_enum const dac_mbc2_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_DACMBCRAT2, FB_DACMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_DACMBCMUG3 PG 4 ADDR 0x1A */
+static struct soc_enum const dac_mbc3_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_DACMBCMUG3, FB_DACMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_DACMBCRAT3 PG 4 ADDR 0x1C */
+static struct soc_enum const dac_mbc3_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_DACMBCRAT3, FB_DACMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_DACCLECTL PG 4 ADDR 0x21 */
+static struct soc_enum const dac_cle_lvl_mode_enum =
+		SOC_ENUM_SINGLE(R_DACCLECTL, FB_DACCLECTL_LVLMODE,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const dac_cle_win_sel_enum =
+		SOC_ENUM_SINGLE(R_DACCLECTL, FB_DACCLECTL_WINSEL,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+/* R_DACCOMPRAT PG 4 ADDR 0x24 */
+static struct soc_enum const dac_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_DACCOMPRAT, FB_DACCOMPRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_DACEXPRAT PG 4 ADDR 0x30 */
+static struct soc_enum const dac_exp_rat_enum =
+		SOC_ENUM_SINGLE(R_DACEXPRAT, FB_DACEXPRAT_RATIO,
+				ARRAY_SIZE(exp_rat_txt), exp_rat_txt);
+
+/* R_SUBEQFILT PG 5 ADDR 0x01 */
+static struct soc_enum const sub_eq_enums[] = {
+	SOC_ENUM_SINGLE(R_SUBEQFILT, FB_SUBEQFILT_EQ2BE,
+		ARRAY_SIZE(eq_txt), eq_txt),
+	SOC_ENUM_SINGLE(R_SUBEQFILT, FB_SUBEQFILT_EQ1BE,
+		ARRAY_SIZE(eq_txt), eq_txt),
+};
+
+/* R_SUBMBCCTL PG 5 ADDR 0x0B */
+static struct soc_enum const sub_mbc3_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCCTL, FB_SUBMBCCTL_LVLMODE3,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const sub_mbc3_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCCTL, FB_SUBMBCCTL_WINSEL3,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+static struct soc_enum const sub_mbc2_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCCTL, FB_SUBMBCCTL_LVLMODE2,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const sub_mbc2_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCCTL, FB_SUBMBCCTL_WINSEL2,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+static struct soc_enum const sub_mbc1_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCCTL, FB_SUBMBCCTL_LVLMODE1,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const sub_mbc1_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCCTL, FB_SUBMBCCTL_WINSEL1,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+/* R_SUBMBCMUG1 PG 5 ADDR 0x0C */
+static struct soc_enum const sub_mbc1_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCMUG1, FB_SUBMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_SUBMBCRAT1 PG 5 ADDR 0x0E */
+static struct soc_enum const sub_mbc1_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCRAT1, FB_SUBMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SUBMBCMUG2 PG 5 ADDR 0x13 */
+static struct soc_enum const sub_mbc2_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCMUG2, FB_SUBMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_SUBMBCRAT2 PG 5 ADDR 0x15 */
+static struct soc_enum const sub_mbc2_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCRAT2, FB_SUBMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SUBMBCMUG3 PG 5 ADDR 0x1A */
+static struct soc_enum const sub_mbc3_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCMUG3, FB_SUBMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_SUBMBCRAT3 PG 5 ADDR 0x1C */
+static struct soc_enum const sub_mbc3_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCRAT3, FB_SUBMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SUBCLECTL PG 5 ADDR 0x21 */
+static struct soc_enum const sub_cle_lvl_mode_enum =
+		SOC_ENUM_SINGLE(R_SUBCLECTL, FB_SUBCLECTL_LVLMODE,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+static struct soc_enum const sub_cle_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SUBCLECTL, FB_SUBCLECTL_WINSEL,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+/* R_SUBCOMPRAT PG 5 ADDR 0x24 */
+static struct soc_enum const sub_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SUBCOMPRAT, FB_SUBCOMPRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SUBEXPRAT PG 5 ADDR 0x30 */
+static struct soc_enum const sub_exp_rat_enum =
+		SOC_ENUM_SINGLE(R_SUBEXPRAT, FB_SUBEXPRAT_RATIO,
+				ARRAY_SIZE(exp_rat_txt), exp_rat_txt);
+
+static int bytes_info_ext(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *ucontrol)
+{
+	struct coeff_ram_ctl *ctl =
+		(struct coeff_ram_ctl *)kcontrol->private_value;
+	struct soc_bytes_ext *params = &ctl->bytes_ext;
+
+	ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	ucontrol->count = params->max;
+
+	return 0;
+}
+
+/* CH 0_1 Input Mux */
+static char const * const ch_0_1_mux_txt[] = {"DAI 1", "TDM 0_1"};
+
+static struct soc_enum const ch_0_1_mux_enum =
+		SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+				ARRAY_SIZE(ch_0_1_mux_txt), ch_0_1_mux_txt);
+
+static struct snd_kcontrol_new const ch_0_1_mux_dapm_enum =
+		SOC_DAPM_ENUM("CH 0_1 Input Mux", ch_0_1_mux_enum);
+
+/* CH 2_3 Input Mux */
+static char const * const ch_2_3_mux_txt[] = {"DAI 2", "TDM 2_3"};
+
+static struct soc_enum const ch_2_3_mux_enum =
+		SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+				ARRAY_SIZE(ch_2_3_mux_txt), ch_2_3_mux_txt);
+
+static struct snd_kcontrol_new const ch_2_3_mux_dapm_enum =
+		SOC_DAPM_ENUM("CH 2_3 Input Mux", ch_2_3_mux_enum);
+
+/* CH 4_5 Input Mux */
+static char const * const ch_4_5_mux_txt[] = {"DAI 3", "TDM 4_5"};
+
+static struct soc_enum const ch_4_5_mux_enum =
+		SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+				ARRAY_SIZE(ch_4_5_mux_txt), ch_4_5_mux_txt);
+
+static struct snd_kcontrol_new const ch_4_5_mux_dapm_enum =
+		SOC_DAPM_ENUM("CH 4_5 Input Mux", ch_4_5_mux_enum);
+
+#define COEFF_RAM_CTL(xname, xcount, xaddr) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = bytes_info_ext, \
+	.get = coeff_ram_get, .put = coeff_ram_put, \
+	.private_value = (unsigned long)&(struct coeff_ram_ctl) { \
+		.addr = xaddr, \
+		.bytes_ext = {.max = xcount, }, \
+	} \
+}
+
+static struct snd_kcontrol_new const tscs454_snd_controls[] = {
+	/* R_PLLCTL PG 0 ADDR 0x15 */
+	SOC_ENUM("PLL BCLK Input", bclk_sel_enum),
+	/* R_ISRC PG 0 ADDR 0x16 */
+	SOC_ENUM("Internal Rate", isrc_br_enum),
+	SOC_ENUM("Internal Rate Multiple", isrc_bm_enum),
+	/* R_SCLKCTL PG 0 ADDR 0x18 */
+	SOC_ENUM("ADC Modular Rate", adc_modular_rate_enum),
+	SOC_ENUM("DAC Modular Rate", dac_modular_rate_enum),
+	/* R_ASRC PG 0 ADDR 0x28 */
+	SOC_SINGLE("ASRC Out High Bandwidth Switch",
+			R_ASRC, FB_ASRC_ASRCOBW, 1, 0),
+	SOC_SINGLE("ASRC In High Bandwidth Switch",
+			R_ASRC, FB_ASRC_ASRCIBW, 1, 0),
+	/* R_I2SIDCTL PG 0 ADDR 0x38 */
+	SOC_ENUM("I2S 1 Data In Control", data_in_ctrl_enums[0]),
+	SOC_ENUM("I2S 2 Data In Control", data_in_ctrl_enums[1]),
+	SOC_ENUM("I2S 3 Data In Control", data_in_ctrl_enums[2]),
+	/* R_I2SODCTL PG 0 ADDR 0x39 */
+	SOC_ENUM("I2S 1 Data Out Control", data_out_ctrl_enums[0]),
+	SOC_ENUM("I2S 2 Data Out Control", data_out_ctrl_enums[1]),
+	SOC_ENUM("I2S 3 Data Out Control", data_out_ctrl_enums[2]),
+	/* R_AUDIOMUX1 PG 0 ADDR 0x3A */
+	SOC_ENUM("ASRC In", asrc_in_mux_enum),
+	/* R_AUDIOMUX2 PG 0 ADDR 0x3B */
+	SOC_ENUM("ASRC Out", asrc_out_mux_enum),
+	/* R_HSDCTL1 PG 1 ADDR 0x01 */
+	SOC_ENUM("Headphone Jack Type", hp_jack_type_enum),
+	SOC_ENUM("Headset Detection Polarity", hs_det_pol_enum),
+	SOC_SINGLE("Headphone Detection Switch",
+			R_HSDCTL1, FB_HSDCTL1_HPID_EN, 1, 0),
+	SOC_SINGLE("Headset OMTP/CTIA Switch",
+			R_HSDCTL1, FB_HSDCTL1_GBLHS_EN, 1, 0),
+	/* R_HSDCTL1 PG 1 ADDR 0x02 */
+	SOC_ENUM("Headset Mic Bias Force", hs_mic_bias_force_enum),
+	SOC_SINGLE("Manual Mic Bias Switch",
+			R_HSDCTL2, FB_HSDCTL2_MB1MODE, 1, 0),
+	SOC_SINGLE("Ring/Sleeve Auto Switch",
+			R_HSDCTL2, FB_HSDCTL2_SWMODE, 1, 0),
+	SOC_ENUM("Manual Mode Plug Type", plug_type_force_enum),
+	/* R_CH0AIC PG 1 ADDR 0x06 */
+	SOC_SINGLE_TLV("Input Boost Channel 0 Volume", R_CH0AIC,
+			FB_CHAIC_MICBST, 0x3, 0, in_bst_vol_tlv_arr),
+	/* R_CH1AIC PG 1 ADDR 0x07 */
+	SOC_SINGLE_TLV("Input Boost Channel 1 Volume", R_CH1AIC,
+			FB_CHAIC_MICBST, 0x3, 0, in_bst_vol_tlv_arr),
+	/* R_CH2AIC PG 1 ADDR 0x08 */
+	SOC_SINGLE_TLV("Input Boost Channel 2 Volume", R_CH2AIC,
+			FB_CHAIC_MICBST, 0x3, 0, in_bst_vol_tlv_arr),
+	/* R_CH3AIC PG 1 ADDR 0x09 */
+	SOC_SINGLE_TLV("Input Boost Channel 3 Volume", R_CH3AIC,
+			FB_CHAIC_MICBST, 0x3, 0, in_bst_vol_tlv_arr),
+	/* R_ICTL0 PG 1 ADDR 0x0A */
+	SOC_ENUM("Input Channel 1 Polarity", in_pol_ch1_enum),
+	SOC_ENUM("Input Channel 0 Polarity", in_pol_ch0_enum),
+	SOC_ENUM("Input Processor Channel 0/1 Operation",
+			in_proc_ch01_sel_enum),
+	SOC_SINGLE("Input Channel 1 Mute Switch",
+			R_ICTL0, FB_ICTL0_IN1MUTE, 1, 0),
+	SOC_SINGLE("Input Channel 0 Mute Switch",
+			R_ICTL0, FB_ICTL0_IN0MUTE, 1, 0),
+	SOC_SINGLE("Input Channel 1 HPF Disable Switch",
+			R_ICTL0, FB_ICTL0_IN1HP, 1, 0),
+	SOC_SINGLE("Input Channel 0 HPF Disable Switch",
+			R_ICTL0, FB_ICTL0_IN0HP, 1, 0),
+	/* R_ICTL1 PG 1 ADDR 0x0B */
+	SOC_ENUM("Input Channel 3 Polarity", in_pol_ch3_enum),
+	SOC_ENUM("Input Channel 2 Polarity", in_pol_ch2_enum),
+	SOC_ENUM("Input Processor Channel 2/3 Operation",
+			in_proc_ch23_sel_enum),
+	SOC_SINGLE("Input Channel 3 Mute Switch",
+			R_ICTL1, FB_ICTL1_IN3MUTE, 1, 0),
+	SOC_SINGLE("Input Channel 2 Mute Switch",
+			R_ICTL1, FB_ICTL1_IN2MUTE, 1, 0),
+	SOC_SINGLE("Input Channel 3 HPF Disable Switch",
+			R_ICTL1, FB_ICTL1_IN3HP, 1, 0),
+	SOC_SINGLE("Input Channel 2 HPF Disable Switch",
+			R_ICTL1, FB_ICTL1_IN2HP, 1, 0),
+	/* R_MICBIAS PG 1 ADDR 0x0C */
+	SOC_ENUM("Mic Bias 2 Voltage", mic_bias_2_enum),
+	SOC_ENUM("Mic Bias 1 Voltage", mic_bias_1_enum),
+	/* R_PGACTL0 PG 1 ADDR 0x0D */
+	SOC_SINGLE("Input Channel 0 PGA Mute Switch",
+			R_PGACTL0, FB_PGACTL_PGAMUTE, 1, 0),
+	SOC_SINGLE_TLV("Input Channel 0 PGA Volume", R_PGACTL0,
+			FB_PGACTL_PGAVOL,
+			FM_PGACTL_PGAVOL, 0, in_pga_vol_tlv_arr),
+	/* R_PGACTL1 PG 1 ADDR 0x0E */
+	SOC_SINGLE("Input Channel 1 PGA Mute Switch",
+			R_PGACTL1, FB_PGACTL_PGAMUTE, 1, 0),
+	SOC_SINGLE_TLV("Input Channel 1 PGA Volume", R_PGACTL1,
+			FB_PGACTL_PGAVOL,
+			FM_PGACTL_PGAVOL, 0, in_pga_vol_tlv_arr),
+	/* R_PGACTL2 PG 1 ADDR 0x0F */
+	SOC_SINGLE("Input Channel 2 PGA Mute Switch",
+			R_PGACTL2, FB_PGACTL_PGAMUTE, 1, 0),
+	SOC_SINGLE_TLV("Input Channel 2 PGA Volume", R_PGACTL2,
+			FB_PGACTL_PGAVOL,
+			FM_PGACTL_PGAVOL, 0, in_pga_vol_tlv_arr),
+	/* R_PGACTL3 PG 1 ADDR 0x10 */
+	SOC_SINGLE("Input Channel 3 PGA Mute Switch",
+			R_PGACTL3, FB_PGACTL_PGAMUTE, 1, 0),
+	SOC_SINGLE_TLV("Input Channel 3 PGA Volume", R_PGACTL3,
+			FB_PGACTL_PGAVOL,
+			FM_PGACTL_PGAVOL, 0, in_pga_vol_tlv_arr),
+	/* R_ICH0VOL PG 1 ADDR 0x12 */
+	SOC_SINGLE_TLV("Input Channel 0 Volume", R_ICH0VOL,
+			FB_ICHVOL_ICHVOL, FM_ICHVOL_ICHVOL, 0, in_vol_tlv_arr),
+	/* R_ICH1VOL PG 1 ADDR 0x13 */
+	SOC_SINGLE_TLV("Input Channel 1 Volume", R_ICH1VOL,
+			FB_ICHVOL_ICHVOL, FM_ICHVOL_ICHVOL, 0, in_vol_tlv_arr),
+	/* R_ICH2VOL PG 1 ADDR 0x14 */
+	SOC_SINGLE_TLV("Input Channel 2 Volume", R_ICH2VOL,
+			FB_ICHVOL_ICHVOL, FM_ICHVOL_ICHVOL, 0, in_vol_tlv_arr),
+	/* R_ICH3VOL PG 1 ADDR 0x15 */
+	SOC_SINGLE_TLV("Input Channel 3 Volume", R_ICH3VOL,
+			FB_ICHVOL_ICHVOL, FM_ICHVOL_ICHVOL, 0, in_vol_tlv_arr),
+	/* R_ASRCILVOL PG 1 ADDR 0x16 */
+	SOC_SINGLE_TLV("ASRC Input Left Volume", R_ASRCILVOL,
+			FB_ASRCILVOL_ASRCILVOL, FM_ASRCILVOL_ASRCILVOL,
+			0, asrc_vol_tlv_arr),
+	/* R_ASRCIRVOL PG 1 ADDR 0x17 */
+	SOC_SINGLE_TLV("ASRC Input Right Volume", R_ASRCIRVOL,
+			FB_ASRCIRVOL_ASRCIRVOL, FM_ASRCIRVOL_ASRCIRVOL,
+			0, asrc_vol_tlv_arr),
+	/* R_ASRCOLVOL PG 1 ADDR 0x18 */
+	SOC_SINGLE_TLV("ASRC Output Left Volume", R_ASRCOLVOL,
+			FB_ASRCOLVOL_ASRCOLVOL, FM_ASRCOLVOL_ASRCOLVOL,
+			0, asrc_vol_tlv_arr),
+	/* R_ASRCORVOL PG 1 ADDR 0x19 */
+	SOC_SINGLE_TLV("ASRC Output Right Volume", R_ASRCORVOL,
+			FB_ASRCORVOL_ASRCOLVOL, FM_ASRCORVOL_ASRCOLVOL,
+			0, asrc_vol_tlv_arr),
+	/* R_IVOLCTLU PG 1 ADDR 0x1C */
+	/* R_ALCCTL0 PG 1 ADDR 0x1D */
+	SOC_ENUM("ALC Mode", alc_mode_enum),
+	SOC_ENUM("ALC Reference", alc_ref_enum),
+	SOC_SINGLE("Input Channel 3 ALC Switch",
+			R_ALCCTL0, FB_ALCCTL0_ALCEN3, 1, 0),
+	SOC_SINGLE("Input Channel 2 ALC Switch",
+			R_ALCCTL0, FB_ALCCTL0_ALCEN2, 1, 0),
+	SOC_SINGLE("Input Channel 1 ALC Switch",
+			R_ALCCTL0, FB_ALCCTL0_ALCEN1, 1, 0),
+	SOC_SINGLE("Input Channel 0 ALC Switch",
+			R_ALCCTL0, FB_ALCCTL0_ALCEN0, 1, 0),
+	/* R_ALCCTL1 PG 1 ADDR 0x1E */
+	SOC_SINGLE_TLV("ALC Max Gain Volume", R_ALCCTL1,
+			FB_ALCCTL1_MAXGAIN, FM_ALCCTL1_MAXGAIN,
+			0, alc_max_gain_tlv_arr),
+	SOC_SINGLE_TLV("ALC Target Volume", R_ALCCTL1,
+			FB_ALCCTL1_ALCL, FM_ALCCTL1_ALCL,
+			0, alc_target_tlv_arr),
+	/* R_ALCCTL2 PG 1 ADDR 0x1F */
+	SOC_SINGLE("ALC Zero Cross Switch",
+			R_ALCCTL2, FB_ALCCTL2_ALCZC, 1, 0),
+	SOC_SINGLE_TLV("ALC Min Gain Volume", R_ALCCTL2,
+			FB_ALCCTL2_MINGAIN, FM_ALCCTL2_MINGAIN,
+			0, alc_min_gain_tlv_arr),
+	SOC_SINGLE_RANGE("ALC Hold", R_ALCCTL2,
+			FB_ALCCTL2_HLD, 0, FM_ALCCTL2_HLD, 0),
+	/* R_ALCCTL3 PG 1 ADDR 0x20 */
+	SOC_SINGLE_RANGE("ALC Decay", R_ALCCTL3,
+			FB_ALCCTL3_DCY, 0, FM_ALCCTL3_DCY, 0),
+	SOC_SINGLE_RANGE("ALC Attack", R_ALCCTL3,
+			FB_ALCCTL3_ATK, 0, FM_ALCCTL3_ATK, 0),
+	/* R_NGATE PG 1 ADDR 0x21 */
+	SOC_SINGLE_TLV("Noise Gate Threshold Volume", R_NGATE,
+			FB_NGATE_NGTH, FM_NGATE_NGTH, 0, ngth_tlv_arr),
+	SOC_ENUM("Noise Gate Type", ngate_type_enum),
+	SOC_SINGLE("Noise Gate Switch", R_NGATE, FB_NGATE_NGAT, 1, 0),
+	/* R_DMICCTL PG 1 ADDR 0x22 */
+	SOC_SINGLE("Digital Mic 2 Switch", R_DMICCTL, FB_DMICCTL_DMIC2EN, 1, 0),
+	SOC_SINGLE("Digital Mic 1 Switch", R_DMICCTL, FB_DMICCTL_DMIC1EN, 1, 0),
+	SOC_ENUM("Digital Mic Mono Select", dmic_mono_sel_enum),
+	/* R_DACCTL PG 2 ADDR 0x01 */
+	SOC_ENUM("DAC Polarity Left", dac_pol_r_enum),
+	SOC_ENUM("DAC Polarity Right", dac_pol_l_enum),
+	SOC_ENUM("DAC Dither", dac_dith_enum),
+	SOC_SINGLE("DAC Mute Switch", R_DACCTL, FB_DACCTL_DACMUTE, 1, 0),
+	SOC_SINGLE("DAC De-Emphasis Switch", R_DACCTL, FB_DACCTL_DACDEM, 1, 0),
+	/* R_SPKCTL PG 2 ADDR 0x02 */
+	SOC_ENUM("Speaker Polarity Right", spk_pol_r_enum),
+	SOC_ENUM("Speaker Polarity Left", spk_pol_l_enum),
+	SOC_SINGLE("Speaker Mute Switch", R_SPKCTL, FB_SPKCTL_SPKMUTE, 1, 0),
+	SOC_SINGLE("Speaker De-Emphasis Switch",
+			R_SPKCTL, FB_SPKCTL_SPKDEM, 1, 0),
+	/* R_SUBCTL PG 2 ADDR 0x03 */
+	SOC_ENUM("Sub Polarity", sub_pol_enum),
+	SOC_SINGLE("SUB Mute Switch", R_SUBCTL, FB_SUBCTL_SUBMUTE, 1, 0),
+	SOC_SINGLE("Sub De-Emphasis Switch", R_SUBCTL, FB_SUBCTL_SUBDEM, 1, 0),
+	/* R_DCCTL PG 2 ADDR 0x04 */
+	SOC_SINGLE("Sub DC Removal Switch", R_DCCTL, FB_DCCTL_SUBDCBYP, 1, 1),
+	SOC_SINGLE("DAC DC Removal Switch", R_DCCTL, FB_DCCTL_DACDCBYP, 1, 1),
+	SOC_SINGLE("Speaker DC Removal Switch",
+			R_DCCTL, FB_DCCTL_SPKDCBYP, 1, 1),
+	SOC_SINGLE("DC Removal Coefficient Switch", R_DCCTL, FB_DCCTL_DCCOEFSEL,
+			FM_DCCTL_DCCOEFSEL, 0),
+	/* R_OVOLCTLU PG 2 ADDR 0x06 */
+	SOC_SINGLE("Output Fade Switch", R_OVOLCTLU, FB_OVOLCTLU_OFADE, 1, 0),
+	/* R_MVOLL PG 2 ADDR 0x08 */
+	/* R_MVOLR PG 2 ADDR 0x09 */
+	SOC_DOUBLE_R_TLV("Master Volume", R_MVOLL, R_MVOLR,
+			FB_MVOLL_MVOL_L, FM_MVOLL_MVOL_L, 0, mvol_tlv_arr),
+	/* R_HPVOLL PG 2 ADDR 0x0A */
+	/* R_HPVOLR PG 2 ADDR 0x0B */
+	SOC_DOUBLE_R_TLV("Headphone Volume", R_HPVOLL, R_HPVOLR,
+			FB_HPVOLL_HPVOL_L, FM_HPVOLL_HPVOL_L, 0,
+			hp_vol_tlv_arr),
+	/* R_SPKVOLL PG 2 ADDR 0x0C */
+	/* R_SPKVOLR PG 2 ADDR 0x0D */
+	SOC_DOUBLE_R_TLV("Speaker Volume", R_SPKVOLL, R_SPKVOLR,
+			FB_SPKVOLL_SPKVOL_L, FM_SPKVOLL_SPKVOL_L, 0,
+			spk_vol_tlv_arr),
+	/* R_SUBVOL PG 2 ADDR 0x10 */
+	SOC_SINGLE_TLV("Sub Volume", R_SUBVOL,
+			FB_SUBVOL_SUBVOL, FM_SUBVOL_SUBVOL, 0, spk_vol_tlv_arr),
+	/* R_SPKEQFILT PG 3 ADDR 0x01 */
+	SOC_SINGLE("Speaker EQ 2 Switch",
+			R_SPKEQFILT, FB_SPKEQFILT_EQ2EN, 1, 0),
+	SOC_ENUM("Speaker EQ 2 Band", spk_eq_enums[0]),
+	SOC_SINGLE("Speaker EQ 1 Switch",
+			R_SPKEQFILT, FB_SPKEQFILT_EQ1EN, 1, 0),
+	SOC_ENUM("Speaker EQ 1 Band", spk_eq_enums[1]),
+	/* R_SPKMBCEN PG 3 ADDR 0x0A */
+	SOC_SINGLE("Speaker MBC 3 Switch",
+			R_SPKMBCEN, FB_SPKMBCEN_MBCEN3, 1, 0),
+	SOC_SINGLE("Speaker MBC 2 Switch",
+			R_SPKMBCEN, FB_SPKMBCEN_MBCEN2, 1, 0),
+	SOC_SINGLE("Speaker MBC 1 Switch",
+			R_SPKMBCEN, FB_SPKMBCEN_MBCEN1, 1, 0),
+	/* R_SPKMBCCTL PG 3 ADDR 0x0B */
+	SOC_ENUM("Speaker MBC 3 Mode", spk_mbc3_lvl_det_mode_enum),
+	SOC_ENUM("Speaker MBC 3 Window", spk_mbc3_win_sel_enum),
+	SOC_ENUM("Speaker MBC 2 Mode", spk_mbc2_lvl_det_mode_enum),
+	SOC_ENUM("Speaker MBC 2 Window", spk_mbc2_win_sel_enum),
+	SOC_ENUM("Speaker MBC 1 Mode", spk_mbc1_lvl_det_mode_enum),
+	SOC_ENUM("Speaker MBC 1 Window", spk_mbc1_win_sel_enum),
+	/* R_SPKMBCMUG1 PG 3 ADDR 0x0C */
+	SOC_ENUM("Speaker MBC 1 Phase Polarity", spk_mbc1_phase_pol_enum),
+	SOC_SINGLE_TLV("Speaker MBC1 Make-Up Gain Volume", R_SPKMBCMUG1,
+			FB_SPKMBCMUG_MUGAIN, FM_SPKMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_SPKMBCTHR1 PG 3 ADDR 0x0D */
+	SOC_SINGLE_TLV("Speaker MBC 1 Compressor Threshold Volume",
+			R_SPKMBCTHR1, FB_SPKMBCTHR_THRESH, FM_SPKMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SPKMBCRAT1 PG 3 ADDR 0x0E */
+	SOC_ENUM("Speaker MBC 1 Compressor Ratio", spk_mbc1_comp_rat_enum),
+	/* R_SPKMBCATK1L PG 3 ADDR 0x0F */
+	/* R_SPKMBCATK1H PG 3 ADDR 0x10 */
+	SND_SOC_BYTES("Speaker MBC 1 Attack", R_SPKMBCATK1L, 2),
+	/* R_SPKMBCREL1L PG 3 ADDR 0x11 */
+	/* R_SPKMBCREL1H PG 3 ADDR 0x12 */
+	SND_SOC_BYTES("Speaker MBC 1 Release", R_SPKMBCREL1L, 2),
+	/* R_SPKMBCMUG2 PG 3 ADDR 0x13 */
+	SOC_ENUM("Speaker MBC 2 Phase Polarity", spk_mbc2_phase_pol_enum),
+	SOC_SINGLE_TLV("Speaker MBC2 Make-Up Gain Volume", R_SPKMBCMUG2,
+			FB_SPKMBCMUG_MUGAIN, FM_SPKMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_SPKMBCTHR2 PG 3 ADDR 0x14 */
+	SOC_SINGLE_TLV("Speaker MBC 2 Compressor Threshold Volume",
+			R_SPKMBCTHR2, FB_SPKMBCTHR_THRESH, FM_SPKMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SPKMBCRAT2 PG 3 ADDR 0x15 */
+	SOC_ENUM("Speaker MBC 2 Compressor Ratio", spk_mbc2_comp_rat_enum),
+	/* R_SPKMBCATK2L PG 3 ADDR 0x16 */
+	/* R_SPKMBCATK2H PG 3 ADDR 0x17 */
+	SND_SOC_BYTES("Speaker MBC 2 Attack", R_SPKMBCATK2L, 2),
+	/* R_SPKMBCREL2L PG 3 ADDR 0x18 */
+	/* R_SPKMBCREL2H PG 3 ADDR 0x19 */
+	SND_SOC_BYTES("Speaker MBC 2 Release", R_SPKMBCREL2L, 2),
+	/* R_SPKMBCMUG3 PG 3 ADDR 0x1A */
+	SOC_ENUM("Speaker MBC 3 Phase Polarity", spk_mbc3_phase_pol_enum),
+	SOC_SINGLE_TLV("Speaker MBC 3 Make-Up Gain Volume", R_SPKMBCMUG3,
+			FB_SPKMBCMUG_MUGAIN, FM_SPKMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_SPKMBCTHR3 PG 3 ADDR 0x1B */
+	SOC_SINGLE_TLV("Speaker MBC 3 Threshold Volume", R_SPKMBCTHR3,
+			FB_SPKMBCTHR_THRESH, FM_SPKMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SPKMBCRAT3 PG 3 ADDR 0x1C */
+	SOC_ENUM("Speaker MBC 3 Compressor Ratio", spk_mbc3_comp_rat_enum),
+	/* R_SPKMBCATK3L PG 3 ADDR 0x1D */
+	/* R_SPKMBCATK3H PG 3 ADDR 0x1E */
+	SND_SOC_BYTES("Speaker MBC 3 Attack", R_SPKMBCATK3L, 3),
+	/* R_SPKMBCREL3L PG 3 ADDR 0x1F */
+	/* R_SPKMBCREL3H PG 3 ADDR 0x20 */
+	SND_SOC_BYTES("Speaker MBC 3 Release", R_SPKMBCREL3L, 3),
+	/* R_SPKCLECTL PG 3 ADDR 0x21 */
+	SOC_ENUM("Speaker CLE Level Mode", spk_cle_lvl_mode_enum),
+	SOC_ENUM("Speaker CLE Window", spk_cle_win_sel_enum),
+	SOC_SINGLE("Speaker CLE Expander Switch",
+			R_SPKCLECTL, FB_SPKCLECTL_EXPEN, 1, 0),
+	SOC_SINGLE("Speaker CLE Limiter Switch",
+			R_SPKCLECTL, FB_SPKCLECTL_LIMEN, 1, 0),
+	SOC_SINGLE("Speaker CLE Compressor Switch",
+			R_SPKCLECTL, FB_SPKCLECTL_COMPEN, 1, 0),
+	/* R_SPKCLEMUG PG 3 ADDR 0x22 */
+	SOC_SINGLE_TLV("Speaker CLE Make-Up Gain Volume", R_SPKCLEMUG,
+			FB_SPKCLEMUG_MUGAIN, FM_SPKCLEMUG_MUGAIN,
+			0, cle_mug_tlv_arr),
+	/* R_SPKCOMPTHR PG 3 ADDR 0x23 */
+	SOC_SINGLE_TLV("Speaker Compressor Threshold Volume", R_SPKCOMPTHR,
+			FB_SPKCOMPTHR_THRESH, FM_SPKCOMPTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SPKCOMPRAT PG 3 ADDR 0x24 */
+	SOC_ENUM("Speaker Compressor Ratio", spk_comp_rat_enum),
+	/* R_SPKCOMPATKL PG 3 ADDR 0x25 */
+	/* R_SPKCOMPATKH PG 3 ADDR 0x26 */
+	SND_SOC_BYTES("Speaker Compressor Attack", R_SPKCOMPATKL, 2),
+	/* R_SPKCOMPRELL PG 3 ADDR 0x27 */
+	/* R_SPKCOMPRELH PG 3 ADDR 0x28 */
+	SND_SOC_BYTES("Speaker Compressor Release", R_SPKCOMPRELL, 2),
+	/* R_SPKLIMTHR PG 3 ADDR 0x29 */
+	SOC_SINGLE_TLV("Speaker Limiter Threshold Volume", R_SPKLIMTHR,
+			FB_SPKLIMTHR_THRESH, FM_SPKLIMTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SPKLIMTGT PG 3 ADDR 0x2A */
+	SOC_SINGLE_TLV("Speaker Limiter Target Volume", R_SPKLIMTGT,
+			FB_SPKLIMTGT_TARGET, FM_SPKLIMTGT_TARGET,
+			0, thr_tlv_arr),
+	/* R_SPKLIMATKL PG 3 ADDR 0x2B */
+	/* R_SPKLIMATKH PG 3 ADDR 0x2C */
+	SND_SOC_BYTES("Speaker Limiter Attack", R_SPKLIMATKL, 2),
+	/* R_SPKLIMRELL PG 3 ADDR 0x2D */
+	/* R_SPKLIMRELR PG 3 ADDR 0x2E */
+	SND_SOC_BYTES("Speaker Limiter Release", R_SPKLIMRELL, 2),
+	/* R_SPKEXPTHR PG 3 ADDR 0x2F */
+	SOC_SINGLE_TLV("Speaker Expander Threshold Volume", R_SPKEXPTHR,
+			FB_SPKEXPTHR_THRESH, FM_SPKEXPTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SPKEXPRAT PG 3 ADDR 0x30 */
+	SOC_ENUM("Speaker Expander Ratio", spk_exp_rat_enum),
+	/* R_SPKEXPATKL PG 3 ADDR 0x31 */
+	/* R_SPKEXPATKR PG 3 ADDR 0x32 */
+	SND_SOC_BYTES("Speaker Expander Attack", R_SPKEXPATKL, 2),
+	/* R_SPKEXPRELL PG 3 ADDR 0x33 */
+	/* R_SPKEXPRELR PG 3 ADDR 0x34 */
+	SND_SOC_BYTES("Speaker Expander Release", R_SPKEXPRELL, 2),
+	/* R_SPKFXCTL PG 3 ADDR 0x35 */
+	SOC_SINGLE("Speaker 3D Switch", R_SPKFXCTL, FB_SPKFXCTL_3DEN, 1, 0),
+	SOC_SINGLE("Speaker Treble Enhancement Switch",
+			R_SPKFXCTL, FB_SPKFXCTL_TEEN, 1, 0),
+	SOC_SINGLE("Speaker Treble NLF Switch",
+			R_SPKFXCTL, FB_SPKFXCTL_TNLFBYP, 1, 1),
+	SOC_SINGLE("Speaker Bass Enhancement Switch",
+			R_SPKFXCTL, FB_SPKFXCTL_BEEN, 1, 0),
+	SOC_SINGLE("Speaker Bass NLF Switch",
+			R_SPKFXCTL, FB_SPKFXCTL_BNLFBYP, 1, 1),
+	/* R_DACEQFILT PG 4 ADDR 0x01 */
+	SOC_SINGLE("DAC EQ 2 Switch",
+			R_DACEQFILT, FB_DACEQFILT_EQ2EN, 1, 0),
+	SOC_ENUM("DAC EQ 2 Band", dac_eq_enums[0]),
+	SOC_SINGLE("DAC EQ 1 Switch", R_DACEQFILT, FB_DACEQFILT_EQ1EN, 1, 0),
+	SOC_ENUM("DAC EQ 1 Band", dac_eq_enums[1]),
+	/* R_DACMBCEN PG 4 ADDR 0x0A */
+	SOC_SINGLE("DAC MBC 3 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN3, 1, 0),
+	SOC_SINGLE("DAC MBC 2 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN2, 1, 0),
+	SOC_SINGLE("DAC MBC 1 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN1, 1, 0),
+	/* R_DACMBCCTL PG 4 ADDR 0x0B */
+	SOC_ENUM("DAC MBC 3 Mode", dac_mbc3_lvl_det_mode_enum),
+	SOC_ENUM("DAC MBC 3 Window", dac_mbc3_win_sel_enum),
+	SOC_ENUM("DAC MBC 2 Mode", dac_mbc2_lvl_det_mode_enum),
+	SOC_ENUM("DAC MBC 2 Window", dac_mbc2_win_sel_enum),
+	SOC_ENUM("DAC MBC 1 Mode", dac_mbc1_lvl_det_mode_enum),
+	SOC_ENUM("DAC MBC 1 Window", dac_mbc1_win_sel_enum),
+	/* R_DACMBCMUG1 PG 4 ADDR 0x0C */
+	SOC_ENUM("DAC MBC 1 Phase Polarity", dac_mbc1_phase_pol_enum),
+	SOC_SINGLE_TLV("DAC MBC 1 Make-Up Gain Volume", R_DACMBCMUG1,
+			FB_DACMBCMUG_MUGAIN, FM_DACMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_DACMBCTHR1 PG 4 ADDR 0x0D */
+	SOC_SINGLE_TLV("DAC MBC 1 Compressor Threshold Volume", R_DACMBCTHR1,
+			FB_DACMBCTHR_THRESH, FM_DACMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_DACMBCRAT1 PG 4 ADDR 0x0E */
+	SOC_ENUM("DAC MBC 1 Compressor Ratio", dac_mbc1_comp_rat_enum),
+	/* R_DACMBCATK1L PG 4 ADDR 0x0F */
+	/* R_DACMBCATK1H PG 4 ADDR 0x10 */
+	SND_SOC_BYTES("DAC MBC 1 Attack", R_DACMBCATK1L, 2),
+	/* R_DACMBCREL1L PG 4 ADDR 0x11 */
+	/* R_DACMBCREL1H PG 4 ADDR 0x12 */
+	SND_SOC_BYTES("DAC MBC 1 Release", R_DACMBCREL1L, 2),
+	/* R_DACMBCMUG2 PG 4 ADDR 0x13 */
+	SOC_ENUM("DAC MBC 2 Phase Polarity", dac_mbc2_phase_pol_enum),
+	SOC_SINGLE_TLV("DAC MBC 2 Make-Up Gain Volume", R_DACMBCMUG2,
+			FB_DACMBCMUG_MUGAIN, FM_DACMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_DACMBCTHR2 PG 4 ADDR 0x14 */
+	SOC_SINGLE_TLV("DAC MBC 2 Compressor Threshold Volume", R_DACMBCTHR2,
+			FB_DACMBCTHR_THRESH, FM_DACMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_DACMBCRAT2 PG 4 ADDR 0x15 */
+	SOC_ENUM("DAC MBC 2 Compressor Ratio", dac_mbc2_comp_rat_enum),
+	/* R_DACMBCATK2L PG 4 ADDR 0x16 */
+	/* R_DACMBCATK2H PG 4 ADDR 0x17 */
+	SND_SOC_BYTES("DAC MBC 2 Attack", R_DACMBCATK2L, 2),
+	/* R_DACMBCREL2L PG 4 ADDR 0x18 */
+	/* R_DACMBCREL2H PG 4 ADDR 0x19 */
+	SND_SOC_BYTES("DAC MBC 2 Release", R_DACMBCREL2L, 2),
+	/* R_DACMBCMUG3 PG 4 ADDR 0x1A */
+	SOC_ENUM("DAC MBC 3 Phase Polarity", dac_mbc3_phase_pol_enum),
+	SOC_SINGLE_TLV("DAC MBC 3 Make-Up Gain Volume", R_DACMBCMUG3,
+			FB_DACMBCMUG_MUGAIN, FM_DACMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_DACMBCTHR3 PG 4 ADDR 0x1B */
+	SOC_SINGLE_TLV("DAC MBC 3 Threshold Volume", R_DACMBCTHR3,
+			FB_DACMBCTHR_THRESH, FM_DACMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_DACMBCRAT3 PG 4 ADDR 0x1C */
+	SOC_ENUM("DAC MBC 3 Compressor Ratio", dac_mbc3_comp_rat_enum),
+	/* R_DACMBCATK3L PG 4 ADDR 0x1D */
+	/* R_DACMBCATK3H PG 4 ADDR 0x1E */
+	SND_SOC_BYTES("DAC MBC 3 Attack", R_DACMBCATK3L, 3),
+	/* R_DACMBCREL3L PG 4 ADDR 0x1F */
+	/* R_DACMBCREL3H PG 4 ADDR 0x20 */
+	SND_SOC_BYTES("DAC MBC 3 Release", R_DACMBCREL3L, 3),
+	/* R_DACCLECTL PG 4 ADDR 0x21 */
+	SOC_ENUM("DAC CLE Level Mode", dac_cle_lvl_mode_enum),
+	SOC_ENUM("DAC CLE Window", dac_cle_win_sel_enum),
+	SOC_SINGLE("DAC CLE Expander Switch",
+			R_DACCLECTL, FB_DACCLECTL_EXPEN, 1, 0),
+	SOC_SINGLE("DAC CLE Limiter Switch",
+			R_DACCLECTL, FB_DACCLECTL_LIMEN, 1, 0),
+	SOC_SINGLE("DAC CLE Compressor Switch",
+			R_DACCLECTL, FB_DACCLECTL_COMPEN, 1, 0),
+	/* R_DACCLEMUG PG 4 ADDR 0x22 */
+	SOC_SINGLE_TLV("DAC CLE Make-Up Gain Volume", R_DACCLEMUG,
+			FB_DACCLEMUG_MUGAIN, FM_DACCLEMUG_MUGAIN,
+			0, cle_mug_tlv_arr),
+	/* R_DACCOMPTHR PG 4 ADDR 0x23 */
+	SOC_SINGLE_TLV("DAC Compressor Threshold Volume", R_DACCOMPTHR,
+			FB_DACCOMPTHR_THRESH, FM_DACCOMPTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_DACCOMPRAT PG 4 ADDR 0x24 */
+	SOC_ENUM("DAC Compressor Ratio", dac_comp_rat_enum),
+	/* R_DACCOMPATKL PG 4 ADDR 0x25 */
+	/* R_DACCOMPATKH PG 4 ADDR 0x26 */
+	SND_SOC_BYTES("DAC Compressor Attack", R_DACCOMPATKL, 2),
+	/* R_DACCOMPRELL PG 4 ADDR 0x27 */
+	/* R_DACCOMPRELH PG 4 ADDR 0x28 */
+	SND_SOC_BYTES("DAC Compressor Release", R_DACCOMPRELL, 2),
+	/* R_DACLIMTHR PG 4 ADDR 0x29 */
+	SOC_SINGLE_TLV("DAC Limiter Threshold Volume", R_DACLIMTHR,
+			FB_DACLIMTHR_THRESH, FM_DACLIMTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_DACLIMTGT PG 4 ADDR 0x2A */
+	SOC_SINGLE_TLV("DAC Limiter Target Volume", R_DACLIMTGT,
+			FB_DACLIMTGT_TARGET, FM_DACLIMTGT_TARGET,
+			0, thr_tlv_arr),
+	/* R_DACLIMATKL PG 4 ADDR 0x2B */
+	/* R_DACLIMATKH PG 4 ADDR 0x2C */
+	SND_SOC_BYTES("DAC Limiter Attack", R_DACLIMATKL, 2),
+	/* R_DACLIMRELL PG 4 ADDR 0x2D */
+	/* R_DACLIMRELR PG 4 ADDR 0x2E */
+	SND_SOC_BYTES("DAC Limiter Release", R_DACLIMRELL, 2),
+	/* R_DACEXPTHR PG 4 ADDR 0x2F */
+	SOC_SINGLE_TLV("DAC Expander Threshold Volume", R_DACEXPTHR,
+			FB_DACEXPTHR_THRESH, FM_DACEXPTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_DACEXPRAT PG 4 ADDR 0x30 */
+	SOC_ENUM("DAC Expander Ratio", dac_exp_rat_enum),
+	/* R_DACEXPATKL PG 4 ADDR 0x31 */
+	/* R_DACEXPATKR PG 4 ADDR 0x32 */
+	SND_SOC_BYTES("DAC Expander Attack", R_DACEXPATKL, 2),
+	/* R_DACEXPRELL PG 4 ADDR 0x33 */
+	/* R_DACEXPRELR PG 4 ADDR 0x34 */
+	SND_SOC_BYTES("DAC Expander Release", R_DACEXPRELL, 2),
+	/* R_DACFXCTL PG 4 ADDR 0x35 */
+	SOC_SINGLE("DAC 3D Switch", R_DACFXCTL, FB_DACFXCTL_3DEN, 1, 0),
+	SOC_SINGLE("DAC Treble Enhancement Switch",
+			R_DACFXCTL, FB_DACFXCTL_TEEN, 1, 0),
+	SOC_SINGLE("DAC Treble NLF Switch",
+			R_DACFXCTL, FB_DACFXCTL_TNLFBYP, 1, 1),
+	SOC_SINGLE("DAC Bass Enhancement Switch",
+			R_DACFXCTL, FB_DACFXCTL_BEEN, 1, 0),
+	SOC_SINGLE("DAC Bass NLF Switch",
+			R_DACFXCTL, FB_DACFXCTL_BNLFBYP, 1, 1),
+	/* R_SUBEQFILT PG 5 ADDR 0x01 */
+	SOC_SINGLE("Sub EQ 2 Switch",
+			R_SUBEQFILT, FB_SUBEQFILT_EQ2EN, 1, 0),
+	SOC_ENUM("Sub EQ 2 Band", sub_eq_enums[0]),
+	SOC_SINGLE("Sub EQ 1 Switch", R_SUBEQFILT, FB_SUBEQFILT_EQ1EN, 1, 0),
+	SOC_ENUM("Sub EQ 1 Band", sub_eq_enums[1]),
+	/* R_SUBMBCEN PG 5 ADDR 0x0A */
+	SOC_SINGLE("Sub MBC 3 Switch", R_SUBMBCEN, FB_SUBMBCEN_MBCEN3, 1, 0),
+	SOC_SINGLE("Sub MBC 2 Switch", R_SUBMBCEN, FB_SUBMBCEN_MBCEN2, 1, 0),
+	SOC_SINGLE("Sub MBC 1 Switch", R_SUBMBCEN, FB_SUBMBCEN_MBCEN1, 1, 0),
+	/* R_SUBMBCCTL PG 5 ADDR 0x0B */
+	SOC_ENUM("Sub MBC 3 Mode", sub_mbc3_lvl_det_mode_enum),
+	SOC_ENUM("Sub MBC 3 Window", sub_mbc3_win_sel_enum),
+	SOC_ENUM("Sub MBC 2 Mode", sub_mbc2_lvl_det_mode_enum),
+	SOC_ENUM("Sub MBC 2 Window", sub_mbc2_win_sel_enum),
+	SOC_ENUM("Sub MBC 1 Mode", sub_mbc1_lvl_det_mode_enum),
+	SOC_ENUM("Sub MBC 1 Window", sub_mbc1_win_sel_enum),
+	/* R_SUBMBCMUG1 PG 5 ADDR 0x0C */
+	SOC_ENUM("Sub MBC 1 Phase Polarity", sub_mbc1_phase_pol_enum),
+	SOC_SINGLE_TLV("Sub MBC 1 Make-Up Gain Volume", R_SUBMBCMUG1,
+			FB_SUBMBCMUG_MUGAIN, FM_SUBMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_SUBMBCTHR1 PG 5 ADDR 0x0D */
+	SOC_SINGLE_TLV("Sub MBC 1 Compressor Threshold Volume", R_SUBMBCTHR1,
+			FB_SUBMBCTHR_THRESH, FM_SUBMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SUBMBCRAT1 PG 5 ADDR 0x0E */
+	SOC_ENUM("Sub MBC 1 Compressor Ratio", sub_mbc1_comp_rat_enum),
+	/* R_SUBMBCATK1L PG 5 ADDR 0x0F */
+	/* R_SUBMBCATK1H PG 5 ADDR 0x10 */
+	SND_SOC_BYTES("Sub MBC 1 Attack", R_SUBMBCATK1L, 2),
+	/* R_SUBMBCREL1L PG 5 ADDR 0x11 */
+	/* R_SUBMBCREL1H PG 5 ADDR 0x12 */
+	SND_SOC_BYTES("Sub MBC 1 Release", R_SUBMBCREL1L, 2),
+	/* R_SUBMBCMUG2 PG 5 ADDR 0x13 */
+	SOC_ENUM("Sub MBC 2 Phase Polarity", sub_mbc2_phase_pol_enum),
+	SOC_SINGLE_TLV("Sub MBC 2 Make-Up Gain Volume", R_SUBMBCMUG2,
+			FB_SUBMBCMUG_MUGAIN, FM_SUBMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_SUBMBCTHR2 PG 5 ADDR 0x14 */
+	SOC_SINGLE_TLV("Sub MBC 2 Compressor Threshold Volume", R_SUBMBCTHR2,
+			FB_SUBMBCTHR_THRESH, FM_SUBMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SUBMBCRAT2 PG 5 ADDR 0x15 */
+	SOC_ENUM("Sub MBC 2 Compressor Ratio", sub_mbc2_comp_rat_enum),
+	/* R_SUBMBCATK2L PG 5 ADDR 0x16 */
+	/* R_SUBMBCATK2H PG 5 ADDR 0x17 */
+	SND_SOC_BYTES("Sub MBC 2 Attack", R_SUBMBCATK2L, 2),
+	/* R_SUBMBCREL2L PG 5 ADDR 0x18 */
+	/* R_SUBMBCREL2H PG 5 ADDR 0x19 */
+	SND_SOC_BYTES("Sub MBC 2 Release", R_SUBMBCREL2L, 2),
+	/* R_SUBMBCMUG3 PG 5 ADDR 0x1A */
+	SOC_ENUM("Sub MBC 3 Phase Polarity", sub_mbc3_phase_pol_enum),
+	SOC_SINGLE_TLV("Sub MBC 3 Make-Up Gain Volume", R_SUBMBCMUG3,
+			FB_SUBMBCMUG_MUGAIN, FM_SUBMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_SUBMBCTHR3 PG 5 ADDR 0x1B */
+	SOC_SINGLE_TLV("Sub MBC 3 Threshold Volume", R_SUBMBCTHR3,
+			FB_SUBMBCTHR_THRESH, FM_SUBMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SUBMBCRAT3 PG 5 ADDR 0x1C */
+	SOC_ENUM("Sub MBC 3 Compressor Ratio", sub_mbc3_comp_rat_enum),
+	/* R_SUBMBCATK3L PG 5 ADDR 0x1D */
+	/* R_SUBMBCATK3H PG 5 ADDR 0x1E */
+	SND_SOC_BYTES("Sub MBC 3 Attack", R_SUBMBCATK3L, 3),
+	/* R_SUBMBCREL3L PG 5 ADDR 0x1F */
+	/* R_SUBMBCREL3H PG 5 ADDR 0x20 */
+	SND_SOC_BYTES("Sub MBC 3 Release", R_SUBMBCREL3L, 3),
+	/* R_SUBCLECTL PG 5 ADDR 0x21 */
+	SOC_ENUM("Sub CLE Level Mode", sub_cle_lvl_mode_enum),
+	SOC_ENUM("Sub CLE Window", sub_cle_win_sel_enum),
+	SOC_SINGLE("Sub CLE Expander Switch",
+			R_SUBCLECTL, FB_SUBCLECTL_EXPEN, 1, 0),
+	SOC_SINGLE("Sub CLE Limiter Switch",
+			R_SUBCLECTL, FB_SUBCLECTL_LIMEN, 1, 0),
+	SOC_SINGLE("Sub CLE Compressor Switch",
+			R_SUBCLECTL, FB_SUBCLECTL_COMPEN, 1, 0),
+	/* R_SUBCLEMUG PG 5 ADDR 0x22 */
+	SOC_SINGLE_TLV("Sub CLE Make-Up Gain Volume", R_SUBCLEMUG,
+			FB_SUBCLEMUG_MUGAIN, FM_SUBCLEMUG_MUGAIN,
+			0, cle_mug_tlv_arr),
+	/* R_SUBCOMPTHR PG 5 ADDR 0x23 */
+	SOC_SINGLE_TLV("Sub Compressor Threshold Volume", R_SUBCOMPTHR,
+			FB_SUBCOMPTHR_THRESH, FM_SUBCOMPTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SUBCOMPRAT PG 5 ADDR 0x24 */
+	SOC_ENUM("Sub Compressor Ratio", sub_comp_rat_enum),
+	/* R_SUBCOMPATKL PG 5 ADDR 0x25 */
+	/* R_SUBCOMPATKH PG 5 ADDR 0x26 */
+	SND_SOC_BYTES("Sub Compressor Attack", R_SUBCOMPATKL, 2),
+	/* R_SUBCOMPRELL PG 5 ADDR 0x27 */
+	/* R_SUBCOMPRELH PG 5 ADDR 0x28 */
+	SND_SOC_BYTES("Sub Compressor Release", R_SUBCOMPRELL, 2),
+	/* R_SUBLIMTHR PG 5 ADDR 0x29 */
+	SOC_SINGLE_TLV("Sub Limiter Threshold Volume", R_SUBLIMTHR,
+			FB_SUBLIMTHR_THRESH, FM_SUBLIMTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SUBLIMTGT PG 5 ADDR 0x2A */
+	SOC_SINGLE_TLV("Sub Limiter Target Volume", R_SUBLIMTGT,
+			FB_SUBLIMTGT_TARGET, FM_SUBLIMTGT_TARGET,
+			0, thr_tlv_arr),
+	/* R_SUBLIMATKL PG 5 ADDR 0x2B */
+	/* R_SUBLIMATKH PG 5 ADDR 0x2C */
+	SND_SOC_BYTES("Sub Limiter Attack", R_SUBLIMATKL, 2),
+	/* R_SUBLIMRELL PG 5 ADDR 0x2D */
+	/* R_SUBLIMRELR PG 5 ADDR 0x2E */
+	SND_SOC_BYTES("Sub Limiter Release", R_SUBLIMRELL, 2),
+	/* R_SUBEXPTHR PG 5 ADDR 0x2F */
+	SOC_SINGLE_TLV("Sub Expander Threshold Volume", R_SUBEXPTHR,
+			FB_SUBEXPTHR_THRESH, FM_SUBEXPTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SUBEXPRAT PG 5 ADDR 0x30 */
+	SOC_ENUM("Sub Expander Ratio", sub_exp_rat_enum),
+	/* R_SUBEXPATKL PG 5 ADDR 0x31 */
+	/* R_SUBEXPATKR PG 5 ADDR 0x32 */
+	SND_SOC_BYTES("Sub Expander Attack", R_SUBEXPATKL, 2),
+	/* R_SUBEXPRELL PG 5 ADDR 0x33 */
+	/* R_SUBEXPRELR PG 5 ADDR 0x34 */
+	SND_SOC_BYTES("Sub Expander Release", R_SUBEXPRELL, 2),
+	/* R_SUBFXCTL PG 5 ADDR 0x35 */
+	SOC_SINGLE("Sub Treble Enhancement Switch",
+			R_SUBFXCTL, FB_SUBFXCTL_TEEN, 1, 0),
+	SOC_SINGLE("Sub Treble NLF Switch",
+			R_SUBFXCTL, FB_SUBFXCTL_TNLFBYP, 1, 1),
+	SOC_SINGLE("Sub Bass Enhancement Switch",
+			R_SUBFXCTL, FB_SUBFXCTL_BEEN, 1, 0),
+	SOC_SINGLE("Sub Bass NLF Switch",
+			R_SUBFXCTL, FB_SUBFXCTL_BNLFBYP, 1, 1),
+	COEFF_RAM_CTL("DAC Cascade 1 Left BiQuad 1", BIQUAD_SIZE, 0x00),
+	COEFF_RAM_CTL("DAC Cascade 1 Left BiQuad 2", BIQUAD_SIZE, 0x05),
+	COEFF_RAM_CTL("DAC Cascade 1 Left BiQuad 3", BIQUAD_SIZE, 0x0a),
+	COEFF_RAM_CTL("DAC Cascade 1 Left BiQuad 4", BIQUAD_SIZE, 0x0f),
+	COEFF_RAM_CTL("DAC Cascade 1 Left BiQuad 5", BIQUAD_SIZE, 0x14),
+	COEFF_RAM_CTL("DAC Cascade 1 Left BiQuad 6", BIQUAD_SIZE, 0x19),
+
+	COEFF_RAM_CTL("DAC Cascade 1 Right BiQuad 1", BIQUAD_SIZE, 0x20),
+	COEFF_RAM_CTL("DAC Cascade 1 Right BiQuad 2", BIQUAD_SIZE, 0x25),
+	COEFF_RAM_CTL("DAC Cascade 1 Right BiQuad 3", BIQUAD_SIZE, 0x2a),
+	COEFF_RAM_CTL("DAC Cascade 1 Right BiQuad 4", BIQUAD_SIZE, 0x2f),
+	COEFF_RAM_CTL("DAC Cascade 1 Right BiQuad 5", BIQUAD_SIZE, 0x34),
+	COEFF_RAM_CTL("DAC Cascade 1 Right BiQuad 6", BIQUAD_SIZE, 0x39),
+
+	COEFF_RAM_CTL("DAC Cascade 1 Left Prescale", COEFF_SIZE, 0x1f),
+	COEFF_RAM_CTL("DAC Cascade 1 Right Prescale", COEFF_SIZE, 0x3f),
+
+	COEFF_RAM_CTL("DAC Cascade 2 Left BiQuad 1", BIQUAD_SIZE, 0x40),
+	COEFF_RAM_CTL("DAC Cascade 2 Left BiQuad 2", BIQUAD_SIZE, 0x45),
+	COEFF_RAM_CTL("DAC Cascade 2 Left BiQuad 3", BIQUAD_SIZE, 0x4a),
+	COEFF_RAM_CTL("DAC Cascade 2 Left BiQuad 4", BIQUAD_SIZE, 0x4f),
+	COEFF_RAM_CTL("DAC Cascade 2 Left BiQuad 5", BIQUAD_SIZE, 0x54),
+	COEFF_RAM_CTL("DAC Cascade 2 Left BiQuad 6", BIQUAD_SIZE, 0x59),
+
+	COEFF_RAM_CTL("DAC Cascade 2 Right BiQuad 1", BIQUAD_SIZE, 0x60),
+	COEFF_RAM_CTL("DAC Cascade 2 Right BiQuad 2", BIQUAD_SIZE, 0x65),
+	COEFF_RAM_CTL("DAC Cascade 2 Right BiQuad 3", BIQUAD_SIZE, 0x6a),
+	COEFF_RAM_CTL("DAC Cascade 2 Right BiQuad 4", BIQUAD_SIZE, 0x6f),
+	COEFF_RAM_CTL("DAC Cascade 2 Right BiQuad 5", BIQUAD_SIZE, 0x74),
+	COEFF_RAM_CTL("DAC Cascade 2 Right BiQuad 6", BIQUAD_SIZE, 0x79),
+
+	COEFF_RAM_CTL("DAC Cascade 2 Left Prescale", COEFF_SIZE, 0x5f),
+	COEFF_RAM_CTL("DAC Cascade 2 Right Prescale", COEFF_SIZE, 0x7f),
+
+	COEFF_RAM_CTL("DAC Bass Extraction BiQuad 1", BIQUAD_SIZE, 0x80),
+	COEFF_RAM_CTL("DAC Bass Extraction BiQuad 2", BIQUAD_SIZE, 0x85),
+
+	COEFF_RAM_CTL("DAC Bass Non Linear Function 1", COEFF_SIZE, 0x8a),
+	COEFF_RAM_CTL("DAC Bass Non Linear Function 2", COEFF_SIZE, 0x8b),
+
+	COEFF_RAM_CTL("DAC Bass Limiter BiQuad", BIQUAD_SIZE, 0x8c),
+
+	COEFF_RAM_CTL("DAC Bass Cut Off BiQuad", BIQUAD_SIZE, 0x91),
+
+	COEFF_RAM_CTL("DAC Bass Mix", COEFF_SIZE, 0x96),
+
+	COEFF_RAM_CTL("DAC Treb Extraction BiQuad 1", BIQUAD_SIZE, 0x97),
+	COEFF_RAM_CTL("DAC Treb Extraction BiQuad 2", BIQUAD_SIZE, 0x9c),
+
+	COEFF_RAM_CTL("DAC Treb Non Linear Function 1", COEFF_SIZE, 0xa1),
+	COEFF_RAM_CTL("DAC Treb Non Linear Function 2", COEFF_SIZE, 0xa2),
+
+	COEFF_RAM_CTL("DAC Treb Limiter BiQuad", BIQUAD_SIZE, 0xa3),
+
+	COEFF_RAM_CTL("DAC Treb Cut Off BiQuad", BIQUAD_SIZE, 0xa8),
+
+	COEFF_RAM_CTL("DAC Treb Mix", COEFF_SIZE, 0xad),
+
+	COEFF_RAM_CTL("DAC 3D", COEFF_SIZE, 0xae),
+
+	COEFF_RAM_CTL("DAC 3D Mix", COEFF_SIZE, 0xaf),
+
+	COEFF_RAM_CTL("DAC MBC 1 BiQuad 1", BIQUAD_SIZE, 0xb0),
+	COEFF_RAM_CTL("DAC MBC 1 BiQuad 2", BIQUAD_SIZE, 0xb5),
+
+	COEFF_RAM_CTL("DAC MBC 2 BiQuad 1", BIQUAD_SIZE, 0xba),
+	COEFF_RAM_CTL("DAC MBC 2 BiQuad 2", BIQUAD_SIZE, 0xbf),
+
+	COEFF_RAM_CTL("DAC MBC 3 BiQuad 1", BIQUAD_SIZE, 0xc4),
+	COEFF_RAM_CTL("DAC MBC 3 BiQuad 2", BIQUAD_SIZE, 0xc9),
+
+	COEFF_RAM_CTL("Speaker Cascade 1 Left BiQuad 1", BIQUAD_SIZE, 0x00),
+	COEFF_RAM_CTL("Speaker Cascade 1 Left BiQuad 2", BIQUAD_SIZE, 0x05),
+	COEFF_RAM_CTL("Speaker Cascade 1 Left BiQuad 3", BIQUAD_SIZE, 0x0a),
+	COEFF_RAM_CTL("Speaker Cascade 1 Left BiQuad 4", BIQUAD_SIZE, 0x0f),
+	COEFF_RAM_CTL("Speaker Cascade 1 Left BiQuad 5", BIQUAD_SIZE, 0x14),
+	COEFF_RAM_CTL("Speaker Cascade 1 Left BiQuad 6", BIQUAD_SIZE, 0x19),
+
+	COEFF_RAM_CTL("Speaker Cascade 1 Right BiQuad 1", BIQUAD_SIZE, 0x20),
+	COEFF_RAM_CTL("Speaker Cascade 1 Right BiQuad 2", BIQUAD_SIZE, 0x25),
+	COEFF_RAM_CTL("Speaker Cascade 1 Right BiQuad 3", BIQUAD_SIZE, 0x2a),
+	COEFF_RAM_CTL("Speaker Cascade 1 Right BiQuad 4", BIQUAD_SIZE, 0x2f),
+	COEFF_RAM_CTL("Speaker Cascade 1 Right BiQuad 5", BIQUAD_SIZE, 0x34),
+	COEFF_RAM_CTL("Speaker Cascade 1 Right BiQuad 6", BIQUAD_SIZE, 0x39),
+
+	COEFF_RAM_CTL("Speaker Cascade 1 Left Prescale", COEFF_SIZE, 0x1f),
+	COEFF_RAM_CTL("Speaker Cascade 1 Right Prescale", COEFF_SIZE, 0x3f),
+
+	COEFF_RAM_CTL("Speaker Cascade 2 Left BiQuad 1", BIQUAD_SIZE, 0x40),
+	COEFF_RAM_CTL("Speaker Cascade 2 Left BiQuad 2", BIQUAD_SIZE, 0x45),
+	COEFF_RAM_CTL("Speaker Cascade 2 Left BiQuad 3", BIQUAD_SIZE, 0x4a),
+	COEFF_RAM_CTL("Speaker Cascade 2 Left BiQuad 4", BIQUAD_SIZE, 0x4f),
+	COEFF_RAM_CTL("Speaker Cascade 2 Left BiQuad 5", BIQUAD_SIZE, 0x54),
+	COEFF_RAM_CTL("Speaker Cascade 2 Left BiQuad 6", BIQUAD_SIZE, 0x59),
+
+	COEFF_RAM_CTL("Speaker Cascade 2 Right BiQuad 1", BIQUAD_SIZE, 0x60),
+	COEFF_RAM_CTL("Speaker Cascade 2 Right BiQuad 2", BIQUAD_SIZE, 0x65),
+	COEFF_RAM_CTL("Speaker Cascade 2 Right BiQuad 3", BIQUAD_SIZE, 0x6a),
+	COEFF_RAM_CTL("Speaker Cascade 2 Right BiQuad 4", BIQUAD_SIZE, 0x6f),
+	COEFF_RAM_CTL("Speaker Cascade 2 Right BiQuad 5", BIQUAD_SIZE, 0x74),
+	COEFF_RAM_CTL("Speaker Cascade 2 Right BiQuad 6", BIQUAD_SIZE, 0x79),
+
+	COEFF_RAM_CTL("Speaker Cascade 2 Left Prescale", COEFF_SIZE, 0x5f),
+	COEFF_RAM_CTL("Speaker Cascade 2 Right Prescale", COEFF_SIZE, 0x7f),
+
+	COEFF_RAM_CTL("Speaker Bass Extraction BiQuad 1", BIQUAD_SIZE, 0x80),
+	COEFF_RAM_CTL("Speaker Bass Extraction BiQuad 2", BIQUAD_SIZE, 0x85),
+
+	COEFF_RAM_CTL("Speaker Bass Non Linear Function 1", COEFF_SIZE, 0x8a),
+	COEFF_RAM_CTL("Speaker Bass Non Linear Function 2", COEFF_SIZE, 0x8b),
+
+	COEFF_RAM_CTL("Speaker Bass Limiter BiQuad", BIQUAD_SIZE, 0x8c),
+
+	COEFF_RAM_CTL("Speaker Bass Cut Off BiQuad", BIQUAD_SIZE, 0x91),
+
+	COEFF_RAM_CTL("Speaker Bass Mix", COEFF_SIZE, 0x96),
+
+	COEFF_RAM_CTL("Speaker Treb Extraction BiQuad 1", BIQUAD_SIZE, 0x97),
+	COEFF_RAM_CTL("Speaker Treb Extraction BiQuad 2", BIQUAD_SIZE, 0x9c),
+
+	COEFF_RAM_CTL("Speaker Treb Non Linear Function 1", COEFF_SIZE, 0xa1),
+	COEFF_RAM_CTL("Speaker Treb Non Linear Function 2", COEFF_SIZE, 0xa2),
+
+	COEFF_RAM_CTL("Speaker Treb Limiter BiQuad", BIQUAD_SIZE, 0xa3),
+
+	COEFF_RAM_CTL("Speaker Treb Cut Off BiQuad", BIQUAD_SIZE, 0xa8),
+
+	COEFF_RAM_CTL("Speaker Treb Mix", COEFF_SIZE, 0xad),
+
+	COEFF_RAM_CTL("Speaker 3D", COEFF_SIZE, 0xae),
+
+	COEFF_RAM_CTL("Speaker 3D Mix", COEFF_SIZE, 0xaf),
+
+	COEFF_RAM_CTL("Speaker MBC 1 BiQuad 1", BIQUAD_SIZE, 0xb0),
+	COEFF_RAM_CTL("Speaker MBC 1 BiQuad 2", BIQUAD_SIZE, 0xb5),
+
+	COEFF_RAM_CTL("Speaker MBC 2 BiQuad 1", BIQUAD_SIZE, 0xba),
+	COEFF_RAM_CTL("Speaker MBC 2 BiQuad 2", BIQUAD_SIZE, 0xbf),
+
+	COEFF_RAM_CTL("Speaker MBC 3 BiQuad 1", BIQUAD_SIZE, 0xc4),
+	COEFF_RAM_CTL("Speaker MBC 3 BiQuad 2", BIQUAD_SIZE, 0xc9),
+
+	COEFF_RAM_CTL("Sub Cascade 1 Left BiQuad 1", BIQUAD_SIZE, 0x00),
+	COEFF_RAM_CTL("Sub Cascade 1 Left BiQuad 2", BIQUAD_SIZE, 0x05),
+	COEFF_RAM_CTL("Sub Cascade 1 Left BiQuad 3", BIQUAD_SIZE, 0x0a),
+	COEFF_RAM_CTL("Sub Cascade 1 Left BiQuad 4", BIQUAD_SIZE, 0x0f),
+	COEFF_RAM_CTL("Sub Cascade 1 Left BiQuad 5", BIQUAD_SIZE, 0x14),
+	COEFF_RAM_CTL("Sub Cascade 1 Left BiQuad 6", BIQUAD_SIZE, 0x19),
+
+	COEFF_RAM_CTL("Sub Cascade 1 Right BiQuad 1", BIQUAD_SIZE, 0x20),
+	COEFF_RAM_CTL("Sub Cascade 1 Right BiQuad 2", BIQUAD_SIZE, 0x25),
+	COEFF_RAM_CTL("Sub Cascade 1 Right BiQuad 3", BIQUAD_SIZE, 0x2a),
+	COEFF_RAM_CTL("Sub Cascade 1 Right BiQuad 4", BIQUAD_SIZE, 0x2f),
+	COEFF_RAM_CTL("Sub Cascade 1 Right BiQuad 5", BIQUAD_SIZE, 0x34),
+	COEFF_RAM_CTL("Sub Cascade 1 Right BiQuad 6", BIQUAD_SIZE, 0x39),
+
+	COEFF_RAM_CTL("Sub Cascade 1 Left Prescale", COEFF_SIZE, 0x1f),
+	COEFF_RAM_CTL("Sub Cascade 1 Right Prescale", COEFF_SIZE, 0x3f),
+
+	COEFF_RAM_CTL("Sub Cascade 2 Left BiQuad 1", BIQUAD_SIZE, 0x40),
+	COEFF_RAM_CTL("Sub Cascade 2 Left BiQuad 2", BIQUAD_SIZE, 0x45),
+	COEFF_RAM_CTL("Sub Cascade 2 Left BiQuad 3", BIQUAD_SIZE, 0x4a),
+	COEFF_RAM_CTL("Sub Cascade 2 Left BiQuad 4", BIQUAD_SIZE, 0x4f),
+	COEFF_RAM_CTL("Sub Cascade 2 Left BiQuad 5", BIQUAD_SIZE, 0x54),
+	COEFF_RAM_CTL("Sub Cascade 2 Left BiQuad 6", BIQUAD_SIZE, 0x59),
+
+	COEFF_RAM_CTL("Sub Cascade 2 Right BiQuad 1", BIQUAD_SIZE, 0x60),
+	COEFF_RAM_CTL("Sub Cascade 2 Right BiQuad 2", BIQUAD_SIZE, 0x65),
+	COEFF_RAM_CTL("Sub Cascade 2 Right BiQuad 3", BIQUAD_SIZE, 0x6a),
+	COEFF_RAM_CTL("Sub Cascade 2 Right BiQuad 4", BIQUAD_SIZE, 0x6f),
+	COEFF_RAM_CTL("Sub Cascade 2 Right BiQuad 5", BIQUAD_SIZE, 0x74),
+	COEFF_RAM_CTL("Sub Cascade 2 Right BiQuad 6", BIQUAD_SIZE, 0x79),
+
+	COEFF_RAM_CTL("Sub Cascade 2 Left Prescale", COEFF_SIZE, 0x5f),
+	COEFF_RAM_CTL("Sub Cascade 2 Right Prescale", COEFF_SIZE, 0x7f),
+
+	COEFF_RAM_CTL("Sub Bass Extraction BiQuad 1", BIQUAD_SIZE, 0x80),
+	COEFF_RAM_CTL("Sub Bass Extraction BiQuad 2", BIQUAD_SIZE, 0x85),
+
+	COEFF_RAM_CTL("Sub Bass Non Linear Function 1", COEFF_SIZE, 0x8a),
+	COEFF_RAM_CTL("Sub Bass Non Linear Function 2", COEFF_SIZE, 0x8b),
+
+	COEFF_RAM_CTL("Sub Bass Limiter BiQuad", BIQUAD_SIZE, 0x8c),
+
+	COEFF_RAM_CTL("Sub Bass Cut Off BiQuad", BIQUAD_SIZE, 0x91),
+
+	COEFF_RAM_CTL("Sub Bass Mix", COEFF_SIZE, 0x96),
+
+	COEFF_RAM_CTL("Sub Treb Extraction BiQuad 1", BIQUAD_SIZE, 0x97),
+	COEFF_RAM_CTL("Sub Treb Extraction BiQuad 2", BIQUAD_SIZE, 0x9c),
+
+	COEFF_RAM_CTL("Sub Treb Non Linear Function 1", COEFF_SIZE, 0xa1),
+	COEFF_RAM_CTL("Sub Treb Non Linear Function 2", COEFF_SIZE, 0xa2),
+
+	COEFF_RAM_CTL("Sub Treb Limiter BiQuad", BIQUAD_SIZE, 0xa3),
+
+	COEFF_RAM_CTL("Sub Treb Cut Off BiQuad", BIQUAD_SIZE, 0xa8),
+
+	COEFF_RAM_CTL("Sub Treb Mix", COEFF_SIZE, 0xad),
+
+	COEFF_RAM_CTL("Sub 3D", COEFF_SIZE, 0xae),
+
+	COEFF_RAM_CTL("Sub 3D Mix", COEFF_SIZE, 0xaf),
+
+	COEFF_RAM_CTL("Sub MBC 1 BiQuad 1", BIQUAD_SIZE, 0xb0),
+	COEFF_RAM_CTL("Sub MBC 1 BiQuad 2", BIQUAD_SIZE, 0xb5),
+
+	COEFF_RAM_CTL("Sub MBC 2 BiQuad 1", BIQUAD_SIZE, 0xba),
+	COEFF_RAM_CTL("Sub MBC 2 BiQuad 2", BIQUAD_SIZE, 0xbf),
+
+	COEFF_RAM_CTL("Sub MBC 3 BiQuad 1", BIQUAD_SIZE, 0xc4),
+	COEFF_RAM_CTL("Sub MBC 3 BiQuad 2", BIQUAD_SIZE, 0xc9),
+};
+
+static struct snd_soc_dapm_widget const tscs454_dapm_widgets[] = {
+	/* R_PLLCTL PG 0 ADDR 0x15 */
+	SND_SOC_DAPM_SUPPLY("PLL 1 Power", R_PLLCTL, FB_PLLCTL_PU_PLL1, 0,
+			pll_power_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("PLL 2 Power", R_PLLCTL, FB_PLLCTL_PU_PLL2, 0,
+			pll_power_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+	/* R_I2SPINC0 PG 0 ADDR 0x22 */
+	SND_SOC_DAPM_AIF_OUT("DAI 3 Out", "DAI 3 Capture", 0,
+			R_I2SPINC0, FB_I2SPINC0_SDO3TRI, 1),
+	SND_SOC_DAPM_AIF_OUT("DAI 2 Out", "DAI 2 Capture", 0,
+			R_I2SPINC0, FB_I2SPINC0_SDO2TRI, 1),
+	SND_SOC_DAPM_AIF_OUT("DAI 1 Out", "DAI 1 Capture", 0,
+			R_I2SPINC0, FB_I2SPINC0_SDO1TRI, 1),
+	/* R_PWRM0 PG 0 ADDR 0x33 */
+	SND_SOC_DAPM_ADC("Input Processor Channel 3", NULL,
+			R_PWRM0, FB_PWRM0_INPROC3PU, 0),
+	SND_SOC_DAPM_ADC("Input Processor Channel 2", NULL,
+			R_PWRM0, FB_PWRM0_INPROC2PU, 0),
+	SND_SOC_DAPM_ADC("Input Processor Channel 1", NULL,
+			R_PWRM0, FB_PWRM0_INPROC1PU, 0),
+	SND_SOC_DAPM_ADC("Input Processor Channel 0", NULL,
+			R_PWRM0, FB_PWRM0_INPROC0PU, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Bias 2",
+			R_PWRM0, FB_PWRM0_MICB2PU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Bias 1", R_PWRM0,
+			FB_PWRM0_MICB1PU, 0, NULL, 0),
+	/* R_PWRM1 PG 0 ADDR 0x34 */
+	SND_SOC_DAPM_SUPPLY("Sub Power", R_PWRM1, FB_PWRM1_SUBPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Left Power",
+			R_PWRM1, FB_PWRM1_HPLPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Right Power",
+			R_PWRM1, FB_PWRM1_HPRPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Speaker Left Power",
+			R_PWRM1, FB_PWRM1_SPKLPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Speaker Right Power",
+			R_PWRM1, FB_PWRM1_SPKRPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Differential Input 2 Power",
+			R_PWRM1, FB_PWRM1_D2S2PU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Differential Input 1 Power",
+			R_PWRM1, FB_PWRM1_D2S1PU, 0, NULL, 0),
+	/* R_PWRM2 PG 0 ADDR 0x35 */
+	SND_SOC_DAPM_SUPPLY("DAI 3 Out Power",
+			R_PWRM2, FB_PWRM2_I2S3OPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAI 2 Out Power",
+			R_PWRM2, FB_PWRM2_I2S2OPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAI 1 Out Power",
+			R_PWRM2, FB_PWRM2_I2S1OPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAI 3 In Power",
+			R_PWRM2, FB_PWRM2_I2S3IPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAI 2 In Power",
+			R_PWRM2, FB_PWRM2_I2S2IPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAI 1 In Power",
+			R_PWRM2, FB_PWRM2_I2S1IPU, 0, NULL, 0),
+	/* R_PWRM3 PG 0 ADDR 0x36 */
+	SND_SOC_DAPM_SUPPLY("Line Out Left Power",
+			R_PWRM3, FB_PWRM3_LLINEPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Line Out Right Power",
+			R_PWRM3, FB_PWRM3_RLINEPU, 0, NULL, 0),
+	/* R_PWRM4 PG 0 ADDR 0x37 */
+	SND_SOC_DAPM_DAC("Sub", NULL, R_PWRM4, FB_PWRM4_OPSUBPU, 0),
+	SND_SOC_DAPM_DAC("DAC Left", NULL, R_PWRM4, FB_PWRM4_OPDACLPU, 0),
+	SND_SOC_DAPM_DAC("DAC Right", NULL, R_PWRM4, FB_PWRM4_OPDACRPU, 0),
+	SND_SOC_DAPM_DAC("ClassD Left", NULL, R_PWRM4, FB_PWRM4_OPSPKLPU, 0),
+	SND_SOC_DAPM_DAC("ClassD Right", NULL, R_PWRM4, FB_PWRM4_OPSPKRPU, 0),
+	/* R_AUDIOMUX1  PG 0 ADDR 0x3A */
+	SND_SOC_DAPM_MUX("DAI 2 Out Mux", SND_SOC_NOPM, 0, 0,
+			&dai2_mux_dapm_enum),
+	SND_SOC_DAPM_MUX("DAI 1 Out Mux", SND_SOC_NOPM, 0, 0,
+			&dai1_mux_dapm_enum),
+	/* R_AUDIOMUX2 PG 0 ADDR 0x3B */
+	SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
+			&dac_mux_dapm_enum),
+	SND_SOC_DAPM_MUX("DAI 3 Out Mux", SND_SOC_NOPM, 0, 0,
+			&dai3_mux_dapm_enum),
+	/* R_AUDIOMUX3 PG 0 ADDR 0x3C */
+	SND_SOC_DAPM_MUX("Sub Mux", SND_SOC_NOPM, 0, 0,
+			&sub_mux_dapm_enum),
+	SND_SOC_DAPM_MUX("Speaker Mux", SND_SOC_NOPM, 0, 0,
+			&classd_mux_dapm_enum),
+	/* R_HSDCTL1 PG 1 ADDR 0x01 */
+	SND_SOC_DAPM_SUPPLY("GHS Detect Power", R_HSDCTL1,
+			FB_HSDCTL1_CON_DET_PWD, 1, NULL, 0),
+	/* R_CH0AIC PG 1 ADDR 0x06 */
+	SND_SOC_DAPM_MUX("Input Boost Channel 0 Mux", SND_SOC_NOPM, 0, 0,
+			&in_bst_mux_ch0_dapm_enum),
+	SND_SOC_DAPM_MUX("ADC Channel 0 Mux", SND_SOC_NOPM, 0, 0,
+			&adc_mux_ch0_dapm_enum),
+	SND_SOC_DAPM_MUX("Input Processor Channel 0 Mux", SND_SOC_NOPM, 0, 0,
+			&in_proc_mux_ch0_dapm_enum),
+	/* R_CH1AIC PG 1 ADDR 0x07 */
+	SND_SOC_DAPM_MUX("Input Boost Channel 1 Mux", SND_SOC_NOPM, 0, 0,
+			&in_bst_mux_ch1_dapm_enum),
+	SND_SOC_DAPM_MUX("ADC Channel 1 Mux", SND_SOC_NOPM, 0, 0,
+			&adc_mux_ch1_dapm_enum),
+	SND_SOC_DAPM_MUX("Input Processor Channel 1 Mux", SND_SOC_NOPM, 0, 0,
+			&in_proc_mux_ch1_dapm_enum),
+	/* Virtual */
+	SND_SOC_DAPM_AIF_IN("DAI 3 In", "DAI 3 Playback", 0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DAI 2 In", "DAI 2 Playback", 0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DAI 1 In", "DAI 1 Playback", 0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SUPPLY("PLLs", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("Sub Out"),
+	SND_SOC_DAPM_OUTPUT("Headphone Left"),
+	SND_SOC_DAPM_OUTPUT("Headphone Right"),
+	SND_SOC_DAPM_OUTPUT("Speaker Left"),
+	SND_SOC_DAPM_OUTPUT("Speaker Right"),
+	SND_SOC_DAPM_OUTPUT("Line Out Left"),
+	SND_SOC_DAPM_OUTPUT("Line Out Right"),
+	SND_SOC_DAPM_INPUT("D2S 2"),
+	SND_SOC_DAPM_INPUT("D2S 1"),
+	SND_SOC_DAPM_INPUT("Line In 1 Left"),
+	SND_SOC_DAPM_INPUT("Line In 1 Right"),
+	SND_SOC_DAPM_INPUT("Line In 2 Left"),
+	SND_SOC_DAPM_INPUT("Line In 2 Right"),
+	SND_SOC_DAPM_INPUT("Line In 3 Left"),
+	SND_SOC_DAPM_INPUT("Line In 3 Right"),
+	SND_SOC_DAPM_INPUT("DMic 1"),
+	SND_SOC_DAPM_INPUT("DMic 2"),
+
+	SND_SOC_DAPM_MUX("CH 0_1 Mux", SND_SOC_NOPM, 0, 0,
+			&ch_0_1_mux_dapm_enum),
+	SND_SOC_DAPM_MUX("CH 2_3 Mux", SND_SOC_NOPM, 0, 0,
+			&ch_2_3_mux_dapm_enum),
+	SND_SOC_DAPM_MUX("CH 4_5 Mux", SND_SOC_NOPM, 0, 0,
+			&ch_4_5_mux_dapm_enum),
+};
+
+static struct snd_soc_dapm_route const tscs454_intercon[] = {
+	/* PLLs */
+	{"PLLs", NULL, "PLL 1 Power", pll_connected},
+	{"PLLs", NULL, "PLL 2 Power", pll_connected},
+	/* Inputs */
+	{"DAI 3 In", NULL, "DAI 3 In Power"},
+	{"DAI 2 In", NULL, "DAI 2 In Power"},
+	{"DAI 1 In", NULL, "DAI 1 In Power"},
+	/* Outputs */
+	{"DAI 3 Out", NULL, "DAI 3 Out Power"},
+	{"DAI 2 Out", NULL, "DAI 2 Out Power"},
+	{"DAI 1 Out", NULL, "DAI 1 Out Power"},
+	/* Ch Muxing */
+	{"CH 0_1 Mux", "DAI 1", "DAI 1 In"},
+	{"CH 0_1 Mux", "TDM 0_1", "DAI 1 In"},
+	{"CH 2_3 Mux", "DAI 2", "DAI 2 In"},
+	{"CH 2_3 Mux", "TDM 2_3", "DAI 1 In"},
+	{"CH 4_5 Mux", "DAI 3", "DAI 2 In"},
+	{"CH 4_5 Mux", "TDM 4_5", "DAI 1 In"},
+	/* In/Out Muxing */
+	{"DAI 1 Out Mux", "CH 0_1", "CH 0_1 Mux"},
+	{"DAI 1 Out Mux", "CH 2_3", "CH 2_3 Mux"},
+	{"DAI 1 Out Mux", "CH 4_5", "CH 4_5 Mux"},
+	{"DAI 2 Out Mux", "CH 0_1", "CH 0_1 Mux"},
+	{"DAI 2 Out Mux", "CH 2_3", "CH 2_3 Mux"},
+	{"DAI 2 Out Mux", "CH 4_5", "CH 4_5 Mux"},
+	{"DAI 3 Out Mux", "CH 0_1", "CH 0_1 Mux"},
+	{"DAI 3 Out Mux", "CH 2_3", "CH 2_3 Mux"},
+	{"DAI 3 Out Mux", "CH 4_5", "CH 4_5 Mux"},
+	/******************
+	 * Playback Paths *
+	 ******************/
+	/* DAC Path */
+	{"DAC Mux", "CH 4_5", "CH 4_5 Mux"},
+	{"DAC Mux", "CH 2_3", "CH 2_3 Mux"},
+	{"DAC Mux", "CH 0_1", "CH 0_1 Mux"},
+	{"DAC Left", NULL, "DAC Mux"},
+	{"DAC Right", NULL, "DAC Mux"},
+	{"DAC Left", NULL, "PLLs"},
+	{"DAC Right", NULL, "PLLs"},
+	{"Headphone Left", NULL, "Headphone Left Power"},
+	{"Headphone Right", NULL, "Headphone Right Power"},
+	{"Headphone Left", NULL, "DAC Left"},
+	{"Headphone Right", NULL, "DAC Right"},
+	/* Line Out */
+	{"Line Out Left", NULL, "Line Out Left Power"},
+	{"Line Out Right", NULL, "Line Out Right Power"},
+	{"Line Out Left", NULL, "DAC Left"},
+	{"Line Out Right", NULL, "DAC Right"},
+	/* ClassD Path */
+	{"Speaker Mux", "CH 4_5", "CH 4_5 Mux"},
+	{"Speaker Mux", "CH 2_3", "CH 2_3 Mux"},
+	{"Speaker Mux", "CH 0_1", "CH 0_1 Mux"},
+	{"ClassD Left", NULL, "Speaker Mux"},
+	{"ClassD Right", NULL, "Speaker Mux"},
+	{"ClassD Left", NULL, "PLLs"},
+	{"ClassD Right", NULL, "PLLs"},
+	{"Speaker Left", NULL, "Speaker Left Power"},
+	{"Speaker Right", NULL, "Speaker Right Power"},
+	{"Speaker Left", NULL, "ClassD Left"},
+	{"Speaker Right", NULL, "ClassD Right"},
+	/* Sub Path */
+	{"Sub Mux", "CH 4", "CH 4_5 Mux"},
+	{"Sub Mux", "CH 5", "CH 4_5 Mux"},
+	{"Sub Mux", "CH 4 + 5", "CH 4_5 Mux"},
+	{"Sub Mux", "CH 2", "CH 2_3 Mux"},
+	{"Sub Mux", "CH 3", "CH 2_3 Mux"},
+	{"Sub Mux", "CH 2 + 3", "CH 2_3 Mux"},
+	{"Sub Mux", "CH 0", "CH 0_1 Mux"},
+	{"Sub Mux", "CH 1", "CH 0_1 Mux"},
+	{"Sub Mux", "CH 0 + 1", "CH 0_1 Mux"},
+	{"Sub Mux", "ADC/DMic 1 Left", "Input Processor Channel 0"},
+	{"Sub Mux", "ADC/DMic 1 Right", "Input Processor Channel 1"},
+	{"Sub Mux", "ADC/DMic 1 Left Plus Right", "Input Processor Channel 0"},
+	{"Sub Mux", "ADC/DMic 1 Left Plus Right", "Input Processor Channel 1"},
+	{"Sub Mux", "DMic 2 Left", "DMic 2"},
+	{"Sub Mux", "DMic 2 Right", "DMic 2"},
+	{"Sub Mux", "DMic 2 Left Plus Right", "DMic 2"},
+	{"Sub Mux", "ClassD Left", "ClassD Left"},
+	{"Sub Mux", "ClassD Right", "ClassD Right"},
+	{"Sub Mux", "ClassD Left Plus Right", "ClassD Left"},
+	{"Sub Mux", "ClassD Left Plus Right", "ClassD Right"},
+	{"Sub", NULL, "Sub Mux"},
+	{"Sub", NULL, "PLLs"},
+	{"Sub Out", NULL, "Sub Power"},
+	{"Sub Out", NULL, "Sub"},
+	/*****************
+	 * Capture Paths *
+	 *****************/
+	{"Input Boost Channel 0 Mux", "Input 3", "Line In 3 Left"},
+	{"Input Boost Channel 0 Mux", "Input 2", "Line In 2 Left"},
+	{"Input Boost Channel 0 Mux", "Input 1", "Line In 1 Left"},
+	{"Input Boost Channel 0 Mux", "D2S", "D2S 1"},
+
+	{"Input Boost Channel 1 Mux", "Input 3", "Line In 3 Right"},
+	{"Input Boost Channel 1 Mux", "Input 2", "Line In 2 Right"},
+	{"Input Boost Channel 1 Mux", "Input 1", "Line In 1 Right"},
+	{"Input Boost Channel 1 Mux", "D2S", "D2S 2"},
+
+	{"ADC Channel 0 Mux", "Input 3 Boost Bypass", "Line In 3 Left"},
+	{"ADC Channel 0 Mux", "Input 2 Boost Bypass", "Line In 2 Left"},
+	{"ADC Channel 0 Mux", "Input 1 Boost Bypass", "Line In 1 Left"},
+	{"ADC Channel 0 Mux", "Input Boost", "Input Boost Channel 0 Mux"},
+
+	{"ADC Channel 1 Mux", "Input 3 Boost Bypass", "Line In 3 Right"},
+	{"ADC Channel 1 Mux", "Input 2 Boost Bypass", "Line In 2 Right"},
+	{"ADC Channel 1 Mux", "Input 1 Boost Bypass", "Line In 1 Right"},
+	{"ADC Channel 1 Mux", "Input Boost", "Input Boost Channel 1 Mux"},
+
+	{"Input Processor Channel 0 Mux", "ADC", "ADC Channel 0 Mux"},
+	{"Input Processor Channel 0 Mux", "DMic", "DMic 1"},
+
+	{"Input Processor Channel 0", NULL, "PLLs"},
+	{"Input Processor Channel 0", NULL, "Input Processor Channel 0 Mux"},
+
+	{"Input Processor Channel 1 Mux", "ADC", "ADC Channel 1 Mux"},
+	{"Input Processor Channel 1 Mux", "DMic", "DMic 1"},
+
+	{"Input Processor Channel 1", NULL, "PLLs"},
+	{"Input Processor Channel 1", NULL, "Input Processor Channel 1 Mux"},
+
+	{"Input Processor Channel 2", NULL, "PLLs"},
+	{"Input Processor Channel 2", NULL, "DMic 2"},
+
+	{"Input Processor Channel 3", NULL, "PLLs"},
+	{"Input Processor Channel 3", NULL, "DMic 2"},
+
+	{"DAI 1 Out Mux", "ADC/DMic 1", "Input Processor Channel 0"},
+	{"DAI 1 Out Mux", "ADC/DMic 1", "Input Processor Channel 1"},
+	{"DAI 1 Out Mux", "DMic 2", "Input Processor Channel 2"},
+	{"DAI 1 Out Mux", "DMic 2", "Input Processor Channel 3"},
+
+	{"DAI 2 Out Mux", "ADC/DMic 1", "Input Processor Channel 0"},
+	{"DAI 2 Out Mux", "ADC/DMic 1", "Input Processor Channel 1"},
+	{"DAI 2 Out Mux", "DMic 2", "Input Processor Channel 2"},
+	{"DAI 2 Out Mux", "DMic 2", "Input Processor Channel 3"},
+
+	{"DAI 3 Out Mux", "ADC/DMic 1", "Input Processor Channel 0"},
+	{"DAI 3 Out Mux", "ADC/DMic 1", "Input Processor Channel 1"},
+	{"DAI 3 Out Mux", "DMic 2", "Input Processor Channel 2"},
+	{"DAI 3 Out Mux", "DMic 2", "Input Processor Channel 3"},
+
+	{"DAI 1 Out", NULL, "DAI 1 Out Mux"},
+	{"DAI 2 Out", NULL, "DAI 2 Out Mux"},
+	{"DAI 3 Out", NULL, "DAI 3 Out Mux"},
+};
+
+/* This is used when BCLK is sourcing the PLLs */
+static int tscs454_set_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+	int bclk_dai;
+	int ret;
+
+	dev_dbg(component->dev, "%s(): freq = %u\n", __func__, freq);
+
+	ret = snd_soc_component_read(component, R_PLLCTL, &val);
+	if (ret < 0)
+		return ret;
+
+	bclk_dai = (val & FM_PLLCTL_BCLKSEL) >> FB_PLLCTL_BCLKSEL;
+	if (bclk_dai != dai->id)
+		return 0;
+
+	tscs454->bclk_freq = freq;
+	return set_sysclk(component);
+}
+
+static int tscs454_set_bclk_ratio(struct snd_soc_dai *dai,
+		unsigned int ratio)
+{
+	unsigned int mask;
+	int ret;
+	struct snd_soc_component *component = dai->component;
+	unsigned int val;
+	int shift;
+
+	dev_dbg(component->dev, "set_bclk_ratio() id = %d ratio = %u\n",
+			dai->id, ratio);
+
+	switch (dai->id) {
+	case TSCS454_DAI1_ID:
+		mask = FM_I2SCMC_BCMP1;
+		shift = FB_I2SCMC_BCMP1;
+		break;
+	case TSCS454_DAI2_ID:
+		mask = FM_I2SCMC_BCMP2;
+		shift = FB_I2SCMC_BCMP2;
+		break;
+	case TSCS454_DAI3_ID:
+		mask = FM_I2SCMC_BCMP3;
+		shift = FB_I2SCMC_BCMP3;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unknown audio interface (%d)\n", ret);
+		return ret;
+	}
+
+	switch (ratio) {
+	case 32:
+		val = I2SCMC_BCMP_32X;
+		break;
+	case 40:
+		val = I2SCMC_BCMP_40X;
+		break;
+	case 64:
+		val = I2SCMC_BCMP_64X;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unsupported bclk ratio (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_update_bits(component,
+			R_I2SCMC, mask, val << shift);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to set DAI BCLK ratio (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int set_aif_master_from_fmt(struct snd_soc_component *component,
+		struct aif *aif, unsigned int fmt)
+{
+	int ret;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif->master = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aif->master = false;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unsupported format (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int set_aif_tdm_delay(struct snd_soc_component *component,
+		unsigned int dai_id, bool delay)
+{
+	unsigned int reg;
+	int ret;
+
+	switch (dai_id) {
+	case TSCS454_DAI1_ID:
+		reg = R_TDMCTL0;
+		break;
+	case TSCS454_DAI2_ID:
+		reg = R_PCMP2CTL0;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_PCMP3CTL0;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev,
+				"DAI %d unknown (%d)\n", dai_id + 1, ret);
+		return ret;
+	}
+	ret = snd_soc_component_update_bits(component,
+			reg, FM_TDMCTL0_BDELAY, delay);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to setup tdm format (%d)\n",
+				ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int set_aif_format_from_fmt(struct snd_soc_component *component,
+		unsigned int dai_id, unsigned int fmt)
+{
+	unsigned int reg;
+	unsigned int val;
+	int ret;
+
+	switch (dai_id) {
+	case TSCS454_DAI1_ID:
+		reg = R_I2SP1CTL;
+		break;
+	case TSCS454_DAI2_ID:
+		reg = R_I2SP2CTL;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_I2SP3CTL;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev,
+				"DAI %d unknown (%d)\n", dai_id + 1, ret);
+		return ret;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val = FV_FORMAT_RIGHT;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val = FV_FORMAT_LEFT;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		val = FV_FORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ret = set_aif_tdm_delay(component, dai_id, true);
+		if (ret < 0)
+			return ret;
+		val = FV_FORMAT_TDM;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		ret = set_aif_tdm_delay(component, dai_id, false);
+		if (ret < 0)
+			return ret;
+		val = FV_FORMAT_TDM;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Format unsupported (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_update_bits(component,
+			reg, FM_I2SPCTL_FORMAT, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set DAI %d format (%d)\n",
+				dai_id + 1, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int
+set_aif_clock_format_from_fmt(struct snd_soc_component *component,
+		unsigned int dai_id, unsigned int fmt)
+{
+	unsigned int reg;
+	unsigned int val;
+	int ret;
+
+	switch (dai_id) {
+	case TSCS454_DAI1_ID:
+		reg = R_I2SP1CTL;
+		break;
+	case TSCS454_DAI2_ID:
+		reg = R_I2SP2CTL;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_I2SP3CTL;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev,
+				"DAI %d unknown (%d)\n", dai_id + 1, ret);
+		return ret;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		val = FV_BCLKP_NOT_INVERTED | FV_LRCLKP_NOT_INVERTED;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		val = FV_BCLKP_NOT_INVERTED | FV_LRCLKP_INVERTED;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		val = FV_BCLKP_INVERTED | FV_LRCLKP_NOT_INVERTED;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		val = FV_BCLKP_INVERTED | FV_LRCLKP_INVERTED;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Format unknown (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_update_bits(component, reg,
+			FM_I2SPCTL_BCLKP | FM_I2SPCTL_LRCLKP, val);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to set clock polarity for DAI%d (%d)\n",
+				dai_id + 1, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tscs454_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	struct aif *aif = &tscs454->aifs[dai->id];
+	int ret;
+
+	ret = set_aif_master_from_fmt(component, aif, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = set_aif_format_from_fmt(component, dai->id, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = set_aif_clock_format_from_fmt(component, dai->id, fmt);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int tscs454_dai1_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;
+	int ret;
+
+	if (!slots)
+		return 0;
+
+	if (tx_mask >= (1 << slots) || rx_mask >= (1 << slots)) {
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid TDM slot mask (%d)\n", ret);
+		return ret;
+	}
+
+	switch (slots) {
+	case 2:
+		val = FV_TDMSO_2 | FV_TDMSI_2;
+		break;
+	case 4:
+		val = FV_TDMSO_4 | FV_TDMSI_4;
+		break;
+	case 6:
+		val = FV_TDMSO_6 | FV_TDMSI_6;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid number of slots (%d)\n", ret);
+		return ret;
+	}
+
+	switch (slot_width) {
+	case 16:
+		val = val | FV_TDMDSS_16;
+		break;
+	case 24:
+		val = val | FV_TDMDSS_24;
+		break;
+	case 32:
+		val = val | FV_TDMDSS_32;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid TDM slot width (%d)\n", ret);
+		return ret;
+	}
+	ret = snd_soc_component_write(component, R_TDMCTL1, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set slots (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tscs454_dai23_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 reg;
+	unsigned int val;
+	int ret;
+
+	if (!slots)
+		return 0;
+
+	if (tx_mask >= (1 << slots) || rx_mask >= (1 << slots)) {
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid TDM slot mask (%d)\n", ret);
+		return ret;
+	}
+
+	switch (dai->id) {
+	case TSCS454_DAI2_ID:
+		reg = R_PCMP2CTL1;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_PCMP3CTL1;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unrecognized interface %d (%d)\n",
+				dai->id, ret);
+		return ret;
+	}
+
+	switch (slots) {
+	case 1:
+		val = FV_PCMSOP_1 | FV_PCMSIP_1;
+		break;
+	case 2:
+		val = FV_PCMSOP_2 | FV_PCMSIP_2;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid number of slots (%d)\n", ret);
+		return ret;
+	}
+
+	switch (slot_width) {
+	case 16:
+		val = val | FV_PCMDSSP_16;
+		break;
+	case 24:
+		val = val | FV_PCMDSSP_24;
+		break;
+	case 32:
+		val = val | FV_PCMDSSP_32;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid TDM slot width (%d)\n", ret);
+		return ret;
+	}
+	ret = snd_soc_component_write(component, reg, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set slots (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int set_aif_fs(struct snd_soc_component *component,
+		unsigned int id,
+		unsigned int rate)
+{
+	unsigned int reg;
+	unsigned int br;
+	unsigned int bm;
+	int ret;
+
+	switch (rate) {
+	case 8000:
+		br = FV_I2SMBR_32;
+		bm = FV_I2SMBM_0PT25;
+		break;
+	case 16000:
+		br = FV_I2SMBR_32;
+		bm = FV_I2SMBM_0PT5;
+		break;
+	case 24000:
+		br = FV_I2SMBR_48;
+		bm = FV_I2SMBM_0PT5;
+		break;
+	case 32000:
+		br = FV_I2SMBR_32;
+		bm = FV_I2SMBM_1;
+		break;
+	case 48000:
+		br = FV_I2SMBR_48;
+		bm = FV_I2SMBM_1;
+		break;
+	case 96000:
+		br = FV_I2SMBR_48;
+		bm = FV_I2SMBM_2;
+		break;
+	case 11025:
+		br = FV_I2SMBR_44PT1;
+		bm = FV_I2SMBM_0PT25;
+		break;
+	case 22050:
+		br = FV_I2SMBR_44PT1;
+		bm = FV_I2SMBM_0PT5;
+		break;
+	case 44100:
+		br = FV_I2SMBR_44PT1;
+		bm = FV_I2SMBM_1;
+		break;
+	case 88200:
+		br = FV_I2SMBR_44PT1;
+		bm = FV_I2SMBM_2;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unsupported sample rate (%d)\n", ret);
+		return ret;
+	}
+
+	switch (id) {
+	case TSCS454_DAI1_ID:
+		reg = R_I2S1MRATE;
+		break;
+	case TSCS454_DAI2_ID:
+		reg = R_I2S2MRATE;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_I2S3MRATE;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "DAI ID not recognized (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_update_bits(component, reg,
+			FM_I2SMRATE_I2SMBR | FM_I2SMRATE_I2SMBM, br|bm);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to update register (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int set_aif_sample_format(struct snd_soc_component *component,
+		snd_pcm_format_t format,
+		int aif_id)
+{
+	unsigned int reg;
+	unsigned int width;
+	int ret;
+
+	switch (format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		width = FV_WL_16;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		width = FV_WL_20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		width = FV_WL_24;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+	case SNDRV_PCM_FORMAT_S32_LE:
+		width = FV_WL_32;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unsupported format width (%d)\n", ret);
+		return ret;
+	}
+
+	switch (aif_id) {
+	case TSCS454_DAI1_ID:
+		reg = R_I2SP1CTL;
+		break;
+	case TSCS454_DAI2_ID:
+		reg = R_I2SP2CTL;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_I2SP3CTL;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "AIF ID not recognized (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_update_bits(component,
+			reg, FM_I2SPCTL_WL, width);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to set sample width (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tscs454_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 tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	unsigned int fs = params_rate(params);
+	struct aif *aif = &tscs454->aifs[dai->id];
+	unsigned int val;
+	int ret;
+
+	mutex_lock(&tscs454->aifs_status_lock);
+
+	dev_dbg(component->dev, "%s(): aif %d fs = %u\n", __func__,
+			aif->id, fs);
+
+	if (!aif_active(&tscs454->aifs_status, aif->id)) {
+		if (PLL_44_1K_RATE % fs)
+			aif->pll = &tscs454->pll1;
+		else
+			aif->pll = &tscs454->pll2;
+
+		dev_dbg(component->dev, "Reserving pll %d for aif %d\n",
+				aif->pll->id, aif->id);
+
+		reserve_pll(aif->pll);
+	}
+
+	if (!aifs_active(&tscs454->aifs_status)) { /* First active aif */
+		ret = snd_soc_component_read(component, R_ISRC, &val);
+		if (ret < 0)
+			goto exit;
+
+		if ((val & FM_ISRC_IBR) == FV_IBR_48)
+			tscs454->internal_rate.pll = &tscs454->pll1;
+		else
+			tscs454->internal_rate.pll = &tscs454->pll2;
+
+		dev_dbg(component->dev, "Reserving pll %d for ir\n",
+				tscs454->internal_rate.pll->id);
+
+		reserve_pll(tscs454->internal_rate.pll);
+	}
+
+	ret = set_aif_fs(component, aif->id, fs);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set aif fs (%d)\n", ret);
+		goto exit;
+	}
+
+	ret = set_aif_sample_format(component, params_format(params), aif->id);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to set aif sample format (%d)\n", ret);
+		goto exit;
+	}
+
+	set_aif_status_active(&tscs454->aifs_status, aif->id,
+			substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+
+	dev_dbg(component->dev, "Set aif %d active. Streams status is 0x%x\n",
+		aif->id, tscs454->aifs_status.streams);
+
+	ret = 0;
+exit:
+	mutex_unlock(&tscs454->aifs_status_lock);
+
+	return ret;
+}
+
+static int tscs454_hw_free(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	struct aif *aif = &tscs454->aifs[dai->id];
+
+	return aif_free(component, aif,
+			substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+}
+
+static int tscs454_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	int ret;
+	struct snd_soc_component *component = dai->component;
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	struct aif *aif = &tscs454->aifs[dai->id];
+
+	ret = aif_prepare(component, aif);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops const tscs454_dai1_ops = {
+	.set_sysclk	= tscs454_set_sysclk,
+	.set_bclk_ratio = tscs454_set_bclk_ratio,
+	.set_fmt	= tscs454_set_dai_fmt,
+	.set_tdm_slot	= tscs454_dai1_set_tdm_slot,
+	.hw_params	= tscs454_hw_params,
+	.hw_free	= tscs454_hw_free,
+	.prepare	= tscs454_prepare,
+};
+
+static struct snd_soc_dai_ops const tscs454_dai23_ops = {
+	.set_sysclk	= tscs454_set_sysclk,
+	.set_bclk_ratio = tscs454_set_bclk_ratio,
+	.set_fmt	= tscs454_set_dai_fmt,
+	.set_tdm_slot	= tscs454_dai23_set_tdm_slot,
+	.hw_params	= tscs454_hw_params,
+	.hw_free	= tscs454_hw_free,
+	.prepare	= tscs454_prepare,
+};
+
+static int tscs454_probe(struct snd_soc_component *component)
+{
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+	int ret = 0;
+
+	switch (tscs454->sysclk_src_id) {
+	case PLL_INPUT_XTAL:
+		val = FV_PLLISEL_XTAL;
+		break;
+	case PLL_INPUT_MCLK1:
+		val = FV_PLLISEL_MCLK1;
+		break;
+	case PLL_INPUT_MCLK2:
+		val = FV_PLLISEL_MCLK2;
+		break;
+	case PLL_INPUT_BCLK:
+		val = FV_PLLISEL_BCLK;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid sysclk src id (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_update_bits(component, R_PLLCTL,
+			FM_PLLCTL_PLLISEL, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set PLL input (%d)\n", ret);
+		return ret;
+	}
+
+	if (tscs454->sysclk_src_id < PLL_INPUT_BCLK)
+		ret = set_sysclk(component);
+
+	return ret;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_tscs454 = {
+	.probe =	tscs454_probe,
+	.dapm_widgets = tscs454_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tscs454_dapm_widgets),
+	.dapm_routes = tscs454_intercon,
+	.num_dapm_routes = ARRAY_SIZE(tscs454_intercon),
+	.controls =	tscs454_snd_controls,
+	.num_controls = ARRAY_SIZE(tscs454_snd_controls),
+};
+
+#define TSCS454_RATES SNDRV_PCM_RATE_8000_96000
+
+#define TSCS454_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+	| SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE \
+	| SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver tscs454_dais[] = {
+	{
+		.name = "tscs454-dai1",
+		.id = TSCS454_DAI1_ID,
+		.playback = {
+			.stream_name = "DAI 1 Playback",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = TSCS454_RATES,
+			.formats = TSCS454_FORMATS,},
+		.capture = {
+			.stream_name = "DAI 1 Capture",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = TSCS454_RATES,
+			.formats = TSCS454_FORMATS,},
+		.ops = &tscs454_dai1_ops,
+		.symmetric_rates = 1,
+		.symmetric_channels = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "tscs454-dai2",
+		.id = TSCS454_DAI2_ID,
+		.playback = {
+			.stream_name = "DAI 2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = TSCS454_RATES,
+			.formats = TSCS454_FORMATS,},
+		.capture = {
+			.stream_name = "DAI 2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = TSCS454_RATES,
+			.formats = TSCS454_FORMATS,},
+		.ops = &tscs454_dai23_ops,
+		.symmetric_rates = 1,
+		.symmetric_channels = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "tscs454-dai3",
+		.id = TSCS454_DAI3_ID,
+		.playback = {
+			.stream_name = "DAI 3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = TSCS454_RATES,
+			.formats = TSCS454_FORMATS,},
+		.capture = {
+			.stream_name = "DAI 3 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = TSCS454_RATES,
+			.formats = TSCS454_FORMATS,},
+		.ops = &tscs454_dai23_ops,
+		.symmetric_rates = 1,
+		.symmetric_channels = 1,
+		.symmetric_samplebits = 1,
+	},
+};
+
+static char const * const src_names[] = {
+	"xtal", "mclk1", "mclk2", "bclk"};
+
+static int tscs454_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	struct tscs454 *tscs454;
+	int src;
+	int ret;
+
+	tscs454 = devm_kzalloc(&i2c->dev, sizeof(*tscs454), GFP_KERNEL);
+	if (!tscs454)
+		return -ENOMEM;
+
+	ret = tscs454_data_init(tscs454, i2c);
+	if (ret < 0)
+		return ret;
+
+	i2c_set_clientdata(i2c, tscs454);
+
+	for (src = PLL_INPUT_XTAL; src < PLL_INPUT_BCLK; src++) {
+		tscs454->sysclk = devm_clk_get(&i2c->dev, src_names[src]);
+		if (!IS_ERR(tscs454->sysclk)) {
+			break;
+		} else if (PTR_ERR(tscs454->sysclk) != -ENOENT) {
+			ret = PTR_ERR(tscs454->sysclk);
+			dev_err(&i2c->dev, "Failed to get sysclk (%d)\n", ret);
+			return ret;
+		}
+	}
+	dev_dbg(&i2c->dev, "PLL input is %s\n", src_names[src]);
+	tscs454->sysclk_src_id = src;
+
+	ret = regmap_write(tscs454->regmap,
+			R_RESET, FV_RESET_PWR_ON_DEFAULTS);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to reset the component (%d)\n", ret);
+		return ret;
+	}
+	regcache_mark_dirty(tscs454->regmap);
+
+	ret = regmap_register_patch(tscs454->regmap, tscs454_patch,
+			ARRAY_SIZE(tscs454_patch));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to apply patch (%d)\n", ret);
+		return ret;
+	}
+	/* Sync pg sel reg with cache */
+	regmap_write(tscs454->regmap, R_PAGESEL, 0x00);
+
+	ret = snd_soc_register_component(&i2c->dev, &soc_component_dev_tscs454,
+			tscs454_dais, ARRAY_SIZE(tscs454_dais));
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to register component (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id tscs454_i2c_id[] = {
+	{ "tscs454", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tscs454_i2c_id);
+
+static const struct of_device_id tscs454_of_match[] = {
+	{ .compatible = "tempo,tscs454", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tscs454_of_match);
+
+static struct i2c_driver tscs454_i2c_driver = {
+	.driver = {
+		.name = "tscs454",
+		.of_match_table = tscs454_of_match,
+	},
+	.probe =    tscs454_i2c_probe,
+	.id_table = tscs454_i2c_id,
+};
+
+module_i2c_driver(tscs454_i2c_driver);
+
+MODULE_AUTHOR("Tempo Semiconductor <steven.eckhoff.opensource@gmail.com");
+MODULE_DESCRIPTION("ASoC TSCS454 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/tscs454.h b/sound/soc/codecs/tscs454.h
new file mode 100644
index 000000000000..1142d73d3168
--- /dev/null
+++ b/sound/soc/codecs/tscs454.h
@@ -0,0 +1,2323 @@
+// SPDX-License-Identifier: GPL-2.0
+// tscs454.h -- TSCS454 ALSA SoC Audio driver
+// Copyright 2018 Tempo Semiconductor, Inc.
+// Author: Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
+
+#ifndef __REDWOODPUBLIC_H__
+#define __REDWOODPUBLIC_H__
+
+#define VIRT_BASE 0x00
+#define PAGE_LEN 0x100
+#define VIRT_PAGE_BASE(page) (VIRT_BASE + (PAGE_LEN * page))
+#define VIRT_ADDR(page, address) (VIRT_PAGE_BASE(page) + address)
+#define ADDR(page, virt_address) (virt_address - VIRT_PAGE_BASE(page))
+
+#define R_PAGESEL                       0x0
+#define R_RESET                         VIRT_ADDR(0x0, 0x1)
+#define R_IRQEN                         VIRT_ADDR(0x0, 0x2)
+#define R_IRQMASK                       VIRT_ADDR(0x0, 0x3)
+#define R_IRQSTAT                       VIRT_ADDR(0x0, 0x4)
+#define R_DEVADD0                       VIRT_ADDR(0x0, 0x6)
+#define R_DEVID                         VIRT_ADDR(0x0, 0x8)
+#define R_DEVREV                        VIRT_ADDR(0x0, 0x9)
+#define R_PLLSTAT                       VIRT_ADDR(0x0, 0x0A)
+#define R_PLL1CTL                       VIRT_ADDR(0x0, 0x0B)
+#define R_PLL1RDIV                      VIRT_ADDR(0x0, 0x0C)
+#define R_PLL1ODIV                      VIRT_ADDR(0x0, 0x0D)
+#define R_PLL1FDIVL                     VIRT_ADDR(0x0, 0x0E)
+#define R_PLL1FDIVH                     VIRT_ADDR(0x0, 0x0F)
+#define R_PLL2CTL                       VIRT_ADDR(0x0, 0x10)
+#define R_PLL2RDIV                      VIRT_ADDR(0x0, 0x11)
+#define R_PLL2ODIV                      VIRT_ADDR(0x0, 0x12)
+#define R_PLL2FDIVL                     VIRT_ADDR(0x0, 0x13)
+#define R_PLL2FDIVH                     VIRT_ADDR(0x0, 0x14)
+#define R_PLLCTL                        VIRT_ADDR(0x0, 0x15)
+#define R_ISRC                          VIRT_ADDR(0x0, 0x16)
+#define R_SCLKCTL                       VIRT_ADDR(0x0, 0x18)
+#define R_TIMEBASE                      VIRT_ADDR(0x0, 0x19)
+#define R_I2SP1CTL                      VIRT_ADDR(0x0, 0x1A)
+#define R_I2SP2CTL                      VIRT_ADDR(0x0, 0x1B)
+#define R_I2SP3CTL                      VIRT_ADDR(0x0, 0x1C)
+#define R_I2S1MRATE                     VIRT_ADDR(0x0, 0x1D)
+#define R_I2S2MRATE                     VIRT_ADDR(0x0, 0x1E)
+#define R_I2S3MRATE                     VIRT_ADDR(0x0, 0x1F)
+#define R_I2SCMC                        VIRT_ADDR(0x0, 0x20)
+#define R_MCLK2PINC                     VIRT_ADDR(0x0, 0x21)
+#define R_I2SPINC0                      VIRT_ADDR(0x0, 0x22)
+#define R_I2SPINC1                      VIRT_ADDR(0x0, 0x23)
+#define R_I2SPINC2                      VIRT_ADDR(0x0, 0x24)
+#define R_GPIOCTL0                      VIRT_ADDR(0x0, 0x25)
+#define R_GPIOCTL1                      VIRT_ADDR(0x0, 0x26)
+#define R_ASRC                          VIRT_ADDR(0x0, 0x28)
+#define R_TDMCTL0                       VIRT_ADDR(0x0, 0x2D)
+#define R_TDMCTL1                       VIRT_ADDR(0x0, 0x2E)
+#define R_PCMP2CTL0                     VIRT_ADDR(0x0, 0x2F)
+#define R_PCMP2CTL1                     VIRT_ADDR(0x0, 0x30)
+#define R_PCMP3CTL0                     VIRT_ADDR(0x0, 0x31)
+#define R_PCMP3CTL1                     VIRT_ADDR(0x0, 0x32)
+#define R_PWRM0                         VIRT_ADDR(0x0, 0x33)
+#define R_PWRM1                         VIRT_ADDR(0x0, 0x34)
+#define R_PWRM2                         VIRT_ADDR(0x0, 0x35)
+#define R_PWRM3                         VIRT_ADDR(0x0, 0x36)
+#define R_PWRM4                         VIRT_ADDR(0x0, 0x37)
+#define R_I2SIDCTL                      VIRT_ADDR(0x0, 0x38)
+#define R_I2SODCTL                      VIRT_ADDR(0x0, 0x39)
+#define R_AUDIOMUX1                     VIRT_ADDR(0x0, 0x3A)
+#define R_AUDIOMUX2                     VIRT_ADDR(0x0, 0x3B)
+#define R_AUDIOMUX3                     VIRT_ADDR(0x0, 0x3C)
+#define R_HSDCTL1                       VIRT_ADDR(0x1, 0x1)
+#define R_HSDCTL2                       VIRT_ADDR(0x1, 0x2)
+#define R_HSDSTAT                       VIRT_ADDR(0x1, 0x3)
+#define R_HSDDELAY                      VIRT_ADDR(0x1, 0x4)
+#define R_BUTCTL                        VIRT_ADDR(0x1, 0x5)
+#define R_CH0AIC                        VIRT_ADDR(0x1, 0x6)
+#define R_CH1AIC                        VIRT_ADDR(0x1, 0x7)
+#define R_CH2AIC                        VIRT_ADDR(0x1, 0x8)
+#define R_CH3AIC                        VIRT_ADDR(0x1, 0x9)
+#define R_ICTL0                         VIRT_ADDR(0x1, 0x0A)
+#define R_ICTL1                         VIRT_ADDR(0x1, 0x0B)
+#define R_MICBIAS                       VIRT_ADDR(0x1, 0x0C)
+#define R_PGACTL0                       VIRT_ADDR(0x1, 0x0D)
+#define R_PGACTL1                       VIRT_ADDR(0x1, 0x0E)
+#define R_PGACTL2                       VIRT_ADDR(0x1, 0x0F)
+#define R_PGACTL3                       VIRT_ADDR(0x1, 0x10)
+#define R_PGAZ                          VIRT_ADDR(0x1, 0x11)
+#define R_ICH0VOL                       VIRT_ADDR(0x1, 0x12)
+#define R_ICH1VOL                       VIRT_ADDR(0x1, 0x13)
+#define R_ICH2VOL                       VIRT_ADDR(0x1, 0x14)
+#define R_ICH3VOL                       VIRT_ADDR(0x1, 0x15)
+#define R_ASRCILVOL                     VIRT_ADDR(0x1, 0x16)
+#define R_ASRCIRVOL                     VIRT_ADDR(0x1, 0x17)
+#define R_ASRCOLVOL                     VIRT_ADDR(0x1, 0x18)
+#define R_ASRCORVOL                     VIRT_ADDR(0x1, 0x19)
+#define R_IVOLCTLU                      VIRT_ADDR(0x1, 0x1C)
+#define R_ALCCTL0                       VIRT_ADDR(0x1, 0x1D)
+#define R_ALCCTL1                       VIRT_ADDR(0x1, 0x1E)
+#define R_ALCCTL2                       VIRT_ADDR(0x1, 0x1F)
+#define R_ALCCTL3                       VIRT_ADDR(0x1, 0x20)
+#define R_NGATE                         VIRT_ADDR(0x1, 0x21)
+#define R_DMICCTL                       VIRT_ADDR(0x1, 0x22)
+#define R_DACCTL                        VIRT_ADDR(0x2, 0x1)
+#define R_SPKCTL                        VIRT_ADDR(0x2, 0x2)
+#define R_SUBCTL                        VIRT_ADDR(0x2, 0x3)
+#define R_DCCTL                         VIRT_ADDR(0x2, 0x4)
+#define R_OVOLCTLU                      VIRT_ADDR(0x2, 0x6)
+#define R_MUTEC                         VIRT_ADDR(0x2, 0x7)
+#define R_MVOLL                         VIRT_ADDR(0x2, 0x8)
+#define R_MVOLR                         VIRT_ADDR(0x2, 0x9)
+#define R_HPVOLL                        VIRT_ADDR(0x2, 0x0A)
+#define R_HPVOLR                        VIRT_ADDR(0x2, 0x0B)
+#define R_SPKVOLL                       VIRT_ADDR(0x2, 0x0C)
+#define R_SPKVOLR                       VIRT_ADDR(0x2, 0x0D)
+#define R_SUBVOL                        VIRT_ADDR(0x2, 0x10)
+#define R_COP0                          VIRT_ADDR(0x2, 0x11)
+#define R_COP1                          VIRT_ADDR(0x2, 0x12)
+#define R_COPSTAT                       VIRT_ADDR(0x2, 0x13)
+#define R_PWM0                          VIRT_ADDR(0x2, 0x14)
+#define R_PWM1                          VIRT_ADDR(0x2, 0x15)
+#define R_PWM2                          VIRT_ADDR(0x2, 0x16)
+#define R_PWM3                          VIRT_ADDR(0x2, 0x17)
+#define R_HPSW                          VIRT_ADDR(0x2, 0x18)
+#define R_THERMTS                       VIRT_ADDR(0x2, 0x19)
+#define R_THERMSPK1                     VIRT_ADDR(0x2, 0x1A)
+#define R_THERMSTAT                     VIRT_ADDR(0x2, 0x1B)
+#define R_SCSTAT                        VIRT_ADDR(0x2, 0x1C)
+#define R_SDMON                         VIRT_ADDR(0x2, 0x1D)
+#define R_SPKEQFILT                     VIRT_ADDR(0x3, 0x1)
+#define R_SPKCRWDL                      VIRT_ADDR(0x3, 0x2)
+#define R_SPKCRWDM                      VIRT_ADDR(0x3, 0x3)
+#define R_SPKCRWDH                      VIRT_ADDR(0x3, 0x4)
+#define R_SPKCRRDL                      VIRT_ADDR(0x3, 0x5)
+#define R_SPKCRRDM                      VIRT_ADDR(0x3, 0x6)
+#define R_SPKCRRDH                      VIRT_ADDR(0x3, 0x7)
+#define R_SPKCRADD                      VIRT_ADDR(0x3, 0x8)
+#define R_SPKCRS                        VIRT_ADDR(0x3, 0x9)
+#define R_SPKMBCEN                      VIRT_ADDR(0x3, 0x0A)
+#define R_SPKMBCCTL                     VIRT_ADDR(0x3, 0x0B)
+#define R_SPKMBCMUG1                    VIRT_ADDR(0x3, 0x0C)
+#define R_SPKMBCTHR1                    VIRT_ADDR(0x3, 0x0D)
+#define R_SPKMBCRAT1                    VIRT_ADDR(0x3, 0x0E)
+#define R_SPKMBCATK1L                   VIRT_ADDR(0x3, 0x0F)
+#define R_SPKMBCATK1H                   VIRT_ADDR(0x3, 0x10)
+#define R_SPKMBCREL1L                   VIRT_ADDR(0x3, 0x11)
+#define R_SPKMBCREL1H                   VIRT_ADDR(0x3, 0x12)
+#define R_SPKMBCMUG2                    VIRT_ADDR(0x3, 0x13)
+#define R_SPKMBCTHR2                    VIRT_ADDR(0x3, 0x14)
+#define R_SPKMBCRAT2                    VIRT_ADDR(0x3, 0x15)
+#define R_SPKMBCATK2L                   VIRT_ADDR(0x3, 0x16)
+#define R_SPKMBCATK2H                   VIRT_ADDR(0x3, 0x17)
+#define R_SPKMBCREL2L                   VIRT_ADDR(0x3, 0x18)
+#define R_SPKMBCREL2H                   VIRT_ADDR(0x3, 0x19)
+#define R_SPKMBCMUG3                    VIRT_ADDR(0x3, 0x1A)
+#define R_SPKMBCTHR3                    VIRT_ADDR(0x3, 0x1B)
+#define R_SPKMBCRAT3                    VIRT_ADDR(0x3, 0x1C)
+#define R_SPKMBCATK3L                   VIRT_ADDR(0x3, 0x1D)
+#define R_SPKMBCATK3H                   VIRT_ADDR(0x3, 0x1E)
+#define R_SPKMBCREL3L                   VIRT_ADDR(0x3, 0x1F)
+#define R_SPKMBCREL3H                   VIRT_ADDR(0x3, 0x20)
+#define R_SPKCLECTL                     VIRT_ADDR(0x3, 0x21)
+#define R_SPKCLEMUG                     VIRT_ADDR(0x3, 0x22)
+#define R_SPKCOMPTHR                    VIRT_ADDR(0x3, 0x23)
+#define R_SPKCOMPRAT                    VIRT_ADDR(0x3, 0x24)
+#define R_SPKCOMPATKL                   VIRT_ADDR(0x3, 0x25)
+#define R_SPKCOMPATKH                   VIRT_ADDR(0x3, 0x26)
+#define R_SPKCOMPRELL                   VIRT_ADDR(0x3, 0x27)
+#define R_SPKCOMPRELH                   VIRT_ADDR(0x3, 0x28)
+#define R_SPKLIMTHR                     VIRT_ADDR(0x3, 0x29)
+#define R_SPKLIMTGT                     VIRT_ADDR(0x3, 0x2A)
+#define R_SPKLIMATKL                    VIRT_ADDR(0x3, 0x2B)
+#define R_SPKLIMATKH                    VIRT_ADDR(0x3, 0x2C)
+#define R_SPKLIMRELL                    VIRT_ADDR(0x3, 0x2D)
+#define R_SPKLIMRELH                    VIRT_ADDR(0x3, 0x2E)
+#define R_SPKEXPTHR                     VIRT_ADDR(0x3, 0x2F)
+#define R_SPKEXPRAT                     VIRT_ADDR(0x3, 0x30)
+#define R_SPKEXPATKL                    VIRT_ADDR(0x3, 0x31)
+#define R_SPKEXPATKH                    VIRT_ADDR(0x3, 0x32)
+#define R_SPKEXPRELL                    VIRT_ADDR(0x3, 0x33)
+#define R_SPKEXPRELH                    VIRT_ADDR(0x3, 0x34)
+#define R_SPKFXCTL                      VIRT_ADDR(0x3, 0x35)
+#define R_DACEQFILT                     VIRT_ADDR(0x4, 0x1)
+#define R_DACCRWDL                      VIRT_ADDR(0x4, 0x2)
+#define R_DACCRWDM                      VIRT_ADDR(0x4, 0x3)
+#define R_DACCRWDH                      VIRT_ADDR(0x4, 0x4)
+#define R_DACCRRDL                      VIRT_ADDR(0x4, 0x5)
+#define R_DACCRRDM                      VIRT_ADDR(0x4, 0x6)
+#define R_DACCRRDH                      VIRT_ADDR(0x4, 0x7)
+#define R_DACCRADD                      VIRT_ADDR(0x4, 0x8)
+#define R_DACCRS                        VIRT_ADDR(0x4, 0x9)
+#define R_DACMBCEN                      VIRT_ADDR(0x4, 0x0A)
+#define R_DACMBCCTL                     VIRT_ADDR(0x4, 0x0B)
+#define R_DACMBCMUG1                    VIRT_ADDR(0x4, 0x0C)
+#define R_DACMBCTHR1                    VIRT_ADDR(0x4, 0x0D)
+#define R_DACMBCRAT1                    VIRT_ADDR(0x4, 0x0E)
+#define R_DACMBCATK1L                   VIRT_ADDR(0x4, 0x0F)
+#define R_DACMBCATK1H                   VIRT_ADDR(0x4, 0x10)
+#define R_DACMBCREL1L                   VIRT_ADDR(0x4, 0x11)
+#define R_DACMBCREL1H                   VIRT_ADDR(0x4, 0x12)
+#define R_DACMBCMUG2                    VIRT_ADDR(0x4, 0x13)
+#define R_DACMBCTHR2                    VIRT_ADDR(0x4, 0x14)
+#define R_DACMBCRAT2                    VIRT_ADDR(0x4, 0x15)
+#define R_DACMBCATK2L                   VIRT_ADDR(0x4, 0x16)
+#define R_DACMBCATK2H                   VIRT_ADDR(0x4, 0x17)
+#define R_DACMBCREL2L                   VIRT_ADDR(0x4, 0x18)
+#define R_DACMBCREL2H                   VIRT_ADDR(0x4, 0x19)
+#define R_DACMBCMUG3                    VIRT_ADDR(0x4, 0x1A)
+#define R_DACMBCTHR3                    VIRT_ADDR(0x4, 0x1B)
+#define R_DACMBCRAT3                    VIRT_ADDR(0x4, 0x1C)
+#define R_DACMBCATK3L                   VIRT_ADDR(0x4, 0x1D)
+#define R_DACMBCATK3H                   VIRT_ADDR(0x4, 0x1E)
+#define R_DACMBCREL3L                   VIRT_ADDR(0x4, 0x1F)
+#define R_DACMBCREL3H                   VIRT_ADDR(0x4, 0x20)
+#define R_DACCLECTL                     VIRT_ADDR(0x4, 0x21)
+#define R_DACCLEMUG                     VIRT_ADDR(0x4, 0x22)
+#define R_DACCOMPTHR                    VIRT_ADDR(0x4, 0x23)
+#define R_DACCOMPRAT                    VIRT_ADDR(0x4, 0x24)
+#define R_DACCOMPATKL                   VIRT_ADDR(0x4, 0x25)
+#define R_DACCOMPATKH                   VIRT_ADDR(0x4, 0x26)
+#define R_DACCOMPRELL                   VIRT_ADDR(0x4, 0x27)
+#define R_DACCOMPRELH                   VIRT_ADDR(0x4, 0x28)
+#define R_DACLIMTHR                     VIRT_ADDR(0x4, 0x29)
+#define R_DACLIMTGT                     VIRT_ADDR(0x4, 0x2A)
+#define R_DACLIMATKL                    VIRT_ADDR(0x4, 0x2B)
+#define R_DACLIMATKH                    VIRT_ADDR(0x4, 0x2C)
+#define R_DACLIMRELL                    VIRT_ADDR(0x4, 0x2D)
+#define R_DACLIMRELH                    VIRT_ADDR(0x4, 0x2E)
+#define R_DACEXPTHR                     VIRT_ADDR(0x4, 0x2F)
+#define R_DACEXPRAT                     VIRT_ADDR(0x4, 0x30)
+#define R_DACEXPATKL                    VIRT_ADDR(0x4, 0x31)
+#define R_DACEXPATKH                    VIRT_ADDR(0x4, 0x32)
+#define R_DACEXPRELL                    VIRT_ADDR(0x4, 0x33)
+#define R_DACEXPRELH                    VIRT_ADDR(0x4, 0x34)
+#define R_DACFXCTL                      VIRT_ADDR(0x4, 0x35)
+#define R_SUBEQFILT                     VIRT_ADDR(0x5, 0x1)
+#define R_SUBCRWDL                      VIRT_ADDR(0x5, 0x2)
+#define R_SUBCRWDM                      VIRT_ADDR(0x5, 0x3)
+#define R_SUBCRWDH                      VIRT_ADDR(0x5, 0x4)
+#define R_SUBCRRDL                      VIRT_ADDR(0x5, 0x5)
+#define R_SUBCRRDM                      VIRT_ADDR(0x5, 0x6)
+#define R_SUBCRRDH                      VIRT_ADDR(0x5, 0x7)
+#define R_SUBCRADD                      VIRT_ADDR(0x5, 0x8)
+#define R_SUBCRS                        VIRT_ADDR(0x5, 0x9)
+#define R_SUBMBCEN                      VIRT_ADDR(0x5, 0x0A)
+#define R_SUBMBCCTL                     VIRT_ADDR(0x5, 0x0B)
+#define R_SUBMBCMUG1                    VIRT_ADDR(0x5, 0x0C)
+#define R_SUBMBCTHR1                    VIRT_ADDR(0x5, 0x0D)
+#define R_SUBMBCRAT1                    VIRT_ADDR(0x5, 0x0E)
+#define R_SUBMBCATK1L                   VIRT_ADDR(0x5, 0x0F)
+#define R_SUBMBCATK1H                   VIRT_ADDR(0x5, 0x10)
+#define R_SUBMBCREL1L                   VIRT_ADDR(0x5, 0x11)
+#define R_SUBMBCREL1H                   VIRT_ADDR(0x5, 0x12)
+#define R_SUBMBCMUG2                    VIRT_ADDR(0x5, 0x13)
+#define R_SUBMBCTHR2                    VIRT_ADDR(0x5, 0x14)
+#define R_SUBMBCRAT2                    VIRT_ADDR(0x5, 0x15)
+#define R_SUBMBCATK2L                   VIRT_ADDR(0x5, 0x16)
+#define R_SUBMBCATK2H                   VIRT_ADDR(0x5, 0x17)
+#define R_SUBMBCREL2L                   VIRT_ADDR(0x5, 0x18)
+#define R_SUBMBCREL2H                   VIRT_ADDR(0x5, 0x19)
+#define R_SUBMBCMUG3                    VIRT_ADDR(0x5, 0x1A)
+#define R_SUBMBCTHR3                    VIRT_ADDR(0x5, 0x1B)
+#define R_SUBMBCRAT3                    VIRT_ADDR(0x5, 0x1C)
+#define R_SUBMBCATK3L                   VIRT_ADDR(0x5, 0x1D)
+#define R_SUBMBCATK3H                   VIRT_ADDR(0x5, 0x1E)
+#define R_SUBMBCREL3L                   VIRT_ADDR(0x5, 0x1F)
+#define R_SUBMBCREL3H                   VIRT_ADDR(0x5, 0x20)
+#define R_SUBCLECTL                     VIRT_ADDR(0x5, 0x21)
+#define R_SUBCLEMUG                     VIRT_ADDR(0x5, 0x22)
+#define R_SUBCOMPTHR                    VIRT_ADDR(0x5, 0x23)
+#define R_SUBCOMPRAT                    VIRT_ADDR(0x5, 0x24)
+#define R_SUBCOMPATKL                   VIRT_ADDR(0x5, 0x25)
+#define R_SUBCOMPATKH                   VIRT_ADDR(0x5, 0x26)
+#define R_SUBCOMPRELL                   VIRT_ADDR(0x5, 0x27)
+#define R_SUBCOMPRELH                   VIRT_ADDR(0x5, 0x28)
+#define R_SUBLIMTHR                     VIRT_ADDR(0x5, 0x29)
+#define R_SUBLIMTGT                     VIRT_ADDR(0x5, 0x2A)
+#define R_SUBLIMATKL                    VIRT_ADDR(0x5, 0x2B)
+#define R_SUBLIMATKH                    VIRT_ADDR(0x5, 0x2C)
+#define R_SUBLIMRELL                    VIRT_ADDR(0x5, 0x2D)
+#define R_SUBLIMRELH                    VIRT_ADDR(0x5, 0x2E)
+#define R_SUBEXPTHR                     VIRT_ADDR(0x5, 0x2F)
+#define R_SUBEXPRAT                     VIRT_ADDR(0x5, 0x30)
+#define R_SUBEXPATKL                    VIRT_ADDR(0x5, 0x31)
+#define R_SUBEXPATKH                    VIRT_ADDR(0x5, 0x32)
+#define R_SUBEXPRELL                    VIRT_ADDR(0x5, 0x33)
+#define R_SUBEXPRELH                    VIRT_ADDR(0x5, 0x34)
+#define R_SUBFXCTL                      VIRT_ADDR(0x5, 0x35)
+
+// *** PLLCTL ***
+#define FB_PLLCTL_VCCI_PLL                                  6
+#define FM_PLLCTL_VCCI_PLL                                  0xC0
+
+#define FB_PLLCTL_RZ_PLL                                    3
+#define FM_PLLCTL_RZ_PLL                                    0x38
+
+#define FB_PLLCTL_CP_PLL                                    0
+#define FM_PLLCTL_CP_PLL                                    0x7
+
+// *** PLLRDIV ***
+#define FB_PLLRDIV_REFDIV_PLL                               0
+#define FM_PLLRDIV_REFDIV_PLL                               0xFF
+
+// *** PLLODIV ***
+#define FB_PLLODIV_OUTDIV_PLL                               0
+#define FM_PLLODIV_OUTDIV_PLL                               0xFF
+
+// *** PLLFDIVL ***
+#define FB_PLLFDIVL_FBDIVL_PLL                              0
+#define FM_PLLFDIVL_FBDIVL_PLL                              0xFF
+
+// *** PLLFDIVH ***
+#define FB_PLLFDIVH_FBDIVH_PLL                              0
+#define FM_PLLFDIVH_FBDIVH_PLL                              0xF
+
+// *** I2SPCTL ***
+#define FB_I2SPCTL_BCLKSTAT                                 7
+#define FM_I2SPCTL_BCLKSTAT                                 0x80
+#define FV_BCLKSTAT_LOST                                    0x80
+#define FV_BCLKSTAT_NOT_LOST                                0x0
+
+#define FB_I2SPCTL_BCLKP                                    6
+#define FM_I2SPCTL_BCLKP                                    0x40
+#define FV_BCLKP_NOT_INVERTED                               0x0
+#define FV_BCLKP_INVERTED                                   0x40
+
+#define FB_I2SPCTL_PORTMS                                   5
+#define FM_I2SPCTL_PORTMS                                   0x20
+#define FV_PORTMS_SLAVE                                     0x0
+#define FV_PORTMS_MASTER                                    0x20
+
+#define FB_I2SPCTL_LRCLKP                                   4
+#define FM_I2SPCTL_LRCLKP                                   0x10
+#define FV_LRCLKP_NOT_INVERTED                              0x0
+#define FV_LRCLKP_INVERTED                                  0x10
+
+#define FB_I2SPCTL_WL                                       2
+#define FM_I2SPCTL_WL                                       0xC
+#define FV_WL_16                                            0x0
+#define FV_WL_20                                            0x4
+#define FV_WL_24                                            0x8
+#define FV_WL_32                                            0xC
+
+#define FB_I2SPCTL_FORMAT                                   0
+#define FM_I2SPCTL_FORMAT                                   0x3
+#define FV_FORMAT_RIGHT                                     0x0
+#define FV_FORMAT_LEFT                                      0x1
+#define FV_FORMAT_I2S                                       0x2
+#define FV_FORMAT_TDM                                       0x3
+
+// *** I2SMRATE ***
+#define FB_I2SMRATE_I2SMCLKHALF                             7
+#define FM_I2SMRATE_I2SMCLKHALF                             0x80
+#define FV_I2SMCLKHALF_I2S1MCLKDIV_DIV_2                    0x0
+#define FV_I2SMCLKHALF_I2S1MCLKDIV_ONLY                     0x80
+
+#define FB_I2SMRATE_I2SMCLKDIV                              5
+#define FM_I2SMRATE_I2SMCLKDIV                              0x60
+#define FV_I2SMCLKDIV_125                                   0x0
+#define FV_I2SMCLKDIV_128                                   0x20
+#define FV_I2SMCLKDIV_136                                   0x40
+#define FV_I2SMCLKDIV_192                                   0x60
+
+#define FB_I2SMRATE_I2SMBR                                  3
+#define FM_I2SMRATE_I2SMBR                                  0x18
+#define FV_I2SMBR_32                                        0x0
+#define FV_I2SMBR_44PT1                                     0x8
+#define FV_I2SMBR_48                                        0x10
+#define FV_I2SMBR_MCLK_MODE                                 0x18
+
+#define FB_I2SMRATE_I2SMBM                                  0
+#define FM_I2SMRATE_I2SMBM                                  0x3
+#define FV_I2SMBM_0PT25                                     0x0
+#define FV_I2SMBM_0PT5                                      0x1
+#define FV_I2SMBM_1                                         0x2
+#define FV_I2SMBM_2                                         0x3
+
+// *** PCMPCTL0 ***
+#define FB_PCMPCTL0_PCMFLENP                                2
+#define FM_PCMPCTL0_PCMFLENP                                0x4
+#define FV_PCMFLENP_128                                     0x0
+#define FV_PCMFLENP_256                                     0x4
+
+#define FB_PCMPCTL0_SLSYNCP                                 1
+#define FM_PCMPCTL0_SLSYNCP                                 0x2
+#define FV_SLSYNCP_SHORT                                    0x0
+#define FV_SLSYNCP_LONG                                     0x2
+
+#define FB_PCMPCTL0_BDELAYP                                 0
+#define FM_PCMPCTL0_BDELAYP                                 0x1
+#define FV_BDELAYP_NO_DELAY                                 0x0
+#define FV_BDELAYP_1BCLK_DELAY                              0x1
+
+// *** PCMPCTL1 ***
+#define FB_PCMPCTL1_PCMMOMP                                 6
+#define FM_PCMPCTL1_PCMMOMP                                 0x40
+
+#define FB_PCMPCTL1_PCMSOP                                  5
+#define FM_PCMPCTL1_PCMSOP                                  0x20
+#define FV_PCMSOP_1                                         0x0
+#define FV_PCMSOP_2                                         0x20
+
+#define FB_PCMPCTL1_PCMDSSP                                 3
+#define FM_PCMPCTL1_PCMDSSP                                 0x18
+#define FV_PCMDSSP_16                                       0x0
+#define FV_PCMDSSP_24                                       0x8
+#define FV_PCMDSSP_32                                       0x10
+
+#define FB_PCMPCTL1_PCMMIMP                                 1
+#define FM_PCMPCTL1_PCMMIMP                                 0x2
+
+#define FB_PCMPCTL1_PCMSIP                                  0
+#define FM_PCMPCTL1_PCMSIP                                  0x1
+#define FV_PCMSIP_1                                         0x0
+#define FV_PCMSIP_2                                         0x1
+
+// *** CHAIC ***
+#define FB_CHAIC_MICBST                                     4
+#define FM_CHAIC_MICBST                                     0x30
+
+// *** PGACTL ***
+#define FB_PGACTL_PGAMUTE                                   7
+#define FM_PGACTL_PGAMUTE                                   0x80
+
+#define FB_PGACTL_PGAVOL                                    0
+#define FM_PGACTL_PGAVOL                                    0x3F
+
+// *** ICHVOL ***
+#define FB_ICHVOL_ICHVOL                                    0
+#define FM_ICHVOL_ICHVOL                                    0xFF
+
+// *** SPKMBCMUG ***
+#define FB_SPKMBCMUG_PHASE                                  5
+#define FM_SPKMBCMUG_PHASE                                  0x20
+
+#define FB_SPKMBCMUG_MUGAIN                                 0
+#define FM_SPKMBCMUG_MUGAIN                                 0x1F
+
+// *** SPKMBCTHR ***
+#define FB_SPKMBCTHR_THRESH                                 0
+#define FM_SPKMBCTHR_THRESH                                 0xFF
+
+// *** SPKMBCRAT ***
+#define FB_SPKMBCRAT_RATIO                                  0
+#define FM_SPKMBCRAT_RATIO                                  0x1F
+
+// *** SPKMBCATKL ***
+#define FB_SPKMBCATKL_TCATKL                                0
+#define FM_SPKMBCATKL_TCATKL                                0xFF
+
+// *** SPKMBCATKH ***
+#define FB_SPKMBCATKH_TCATKH                                0
+#define FM_SPKMBCATKH_TCATKH                                0xFF
+
+// *** SPKMBCRELL ***
+#define FB_SPKMBCRELL_TCRELL                                0
+#define FM_SPKMBCRELL_TCRELL                                0xFF
+
+// *** SPKMBCRELH ***
+#define FB_SPKMBCRELH_TCRELH                                0
+#define FM_SPKMBCRELH_TCRELH                                0xFF
+
+// *** DACMBCMUG ***
+#define FB_DACMBCMUG_PHASE                                  5
+#define FM_DACMBCMUG_PHASE                                  0x20
+
+#define FB_DACMBCMUG_MUGAIN                                 0
+#define FM_DACMBCMUG_MUGAIN                                 0x1F
+
+// *** DACMBCTHR ***
+#define FB_DACMBCTHR_THRESH                                 0
+#define FM_DACMBCTHR_THRESH                                 0xFF
+
+// *** DACMBCRAT ***
+#define FB_DACMBCRAT_RATIO                                  0
+#define FM_DACMBCRAT_RATIO                                  0x1F
+
+// *** DACMBCATKL ***
+#define FB_DACMBCATKL_TCATKL                                0
+#define FM_DACMBCATKL_TCATKL                                0xFF
+
+// *** DACMBCATKH ***
+#define FB_DACMBCATKH_TCATKH                                0
+#define FM_DACMBCATKH_TCATKH                                0xFF
+
+// *** DACMBCRELL ***
+#define FB_DACMBCRELL_TCRELL                                0
+#define FM_DACMBCRELL_TCRELL                                0xFF
+
+// *** DACMBCRELH ***
+#define FB_DACMBCRELH_TCRELH                                0
+#define FM_DACMBCRELH_TCRELH                                0xFF
+
+// *** SUBMBCMUG ***
+#define FB_SUBMBCMUG_PHASE                                  5
+#define FM_SUBMBCMUG_PHASE                                  0x20
+
+#define FB_SUBMBCMUG_MUGAIN                                 0
+#define FM_SUBMBCMUG_MUGAIN                                 0x1F
+
+// *** SUBMBCTHR ***
+#define FB_SUBMBCTHR_THRESH                                 0
+#define FM_SUBMBCTHR_THRESH                                 0xFF
+
+// *** SUBMBCRAT ***
+#define FB_SUBMBCRAT_RATIO                                  0
+#define FM_SUBMBCRAT_RATIO                                  0x1F
+
+// *** SUBMBCATKL ***
+#define FB_SUBMBCATKL_TCATKL                                0
+#define FM_SUBMBCATKL_TCATKL                                0xFF
+
+// *** SUBMBCATKH ***
+#define FB_SUBMBCATKH_TCATKH                                0
+#define FM_SUBMBCATKH_TCATKH                                0xFF
+
+// *** SUBMBCRELL ***
+#define FB_SUBMBCRELL_TCRELL                                0
+#define FM_SUBMBCRELL_TCRELL                                0xFF
+
+// *** SUBMBCRELH ***
+#define FB_SUBMBCRELH_TCRELH                                0
+#define FM_SUBMBCRELH_TCRELH                                0xFF
+
+// *** PAGESEL ***
+#define FB_PAGESEL_PAGESEL                                  0
+#define FM_PAGESEL_PAGESEL                                  0xFF
+
+// *** RESET ***
+#define FB_RESET_RESET                                      0
+#define FM_RESET_RESET                                      0xFF
+#define FV_RESET_PWR_ON_DEFAULTS                            0x85
+
+// *** IRQEN ***
+#define FB_IRQEN_THRMINTEN                                  6
+#define FM_IRQEN_THRMINTEN                                  0x40
+#define FV_THRMINTEN_ENABLED                                0x40
+#define FV_THRMINTEN_DISABLED                               0x0
+
+#define FB_IRQEN_HBPINTEN                                   5
+#define FM_IRQEN_HBPINTEN                                   0x20
+#define FV_HBPINTEN_ENABLED                                 0x20
+#define FV_HBPINTEN_DISABLED                                0x0
+
+#define FB_IRQEN_HSDINTEN                                   4
+#define FM_IRQEN_HSDINTEN                                   0x10
+#define FV_HSDINTEN_ENABLED                                 0x10
+#define FV_HSDINTEN_DISABLED                                0x0
+
+#define FB_IRQEN_HPDINTEN                                   3
+#define FM_IRQEN_HPDINTEN                                   0x8
+#define FV_HPDINTEN_ENABLED                                 0x8
+#define FV_HPDINTEN_DISABLED                                0x0
+
+#define FB_IRQEN_GPIO3INTEN                                 1
+#define FM_IRQEN_GPIO3INTEN                                 0x2
+#define FV_GPIO3INTEN_ENABLED                               0x2
+#define FV_GPIO3INTEN_DISABLED                              0x0
+
+#define FB_IRQEN_GPIO2INTEN                                 0
+#define FM_IRQEN_GPIO2INTEN                                 0x1
+#define FV_GPIO2INTEN_ENABLED                               0x1
+#define FV_GPIO2INTEN_DISABLED                              0x0
+
+#define IRQEN_GPIOINTEN_ENABLED                             0x1
+#define IRQEN_GPIOINTEN_DISABLED                            0x0
+
+// *** IRQMASK ***
+#define FB_IRQMASK_THRMIM                                   6
+#define FM_IRQMASK_THRMIM                                   0x40
+#define FV_THRMIM_MASKED                                    0x0
+#define FV_THRMIM_NOT_MASKED                                0x40
+
+#define FB_IRQMASK_HBPIM                                    5
+#define FM_IRQMASK_HBPIM                                    0x20
+#define FV_HBPIM_MASKED                                     0x0
+#define FV_HBPIM_NOT_MASKED                                 0x20
+
+#define FB_IRQMASK_HSDIM                                    4
+#define FM_IRQMASK_HSDIM                                    0x10
+#define FV_HSDIM_MASKED                                     0x0
+#define FV_HSDIM_NOT_MASKED                                 0x10
+
+#define FB_IRQMASK_HPDIM                                    3
+#define FM_IRQMASK_HPDIM                                    0x8
+#define FV_HPDIM_MASKED                                     0x0
+#define FV_HPDIM_NOT_MASKED                                 0x8
+
+#define FB_IRQMASK_GPIO3M                                   1
+#define FM_IRQMASK_GPIO3M                                   0x2
+#define FV_GPIO3M_MASKED                                    0x0
+#define FV_GPIO3M_NOT_MASKED                                0x2
+
+#define FB_IRQMASK_GPIO2M                                   0
+#define FM_IRQMASK_GPIO2M                                   0x1
+#define FV_GPIO2M_MASKED                                    0x0
+#define FV_GPIO2M_NOT_MASKED                                0x1
+
+#define IRQMASK_GPIOM_MASKED                                0x0
+#define IRQMASK_GPIOM_NOT_MASKED                            0x1
+
+// *** IRQSTAT ***
+#define FB_IRQSTAT_THRMINT                                  6
+#define FM_IRQSTAT_THRMINT                                  0x40
+#define FV_THRMINT_INTERRUPTED                              0x40
+#define FV_THRMINT_NOT_INTERRUPTED                          0x0
+
+#define FB_IRQSTAT_HBPINT                                   5
+#define FM_IRQSTAT_HBPINT                                   0x20
+#define FV_HBPINT_INTERRUPTED                               0x20
+#define FV_HBPINT_NOT_INTERRUPTED                           0x0
+
+#define FB_IRQSTAT_HSDINT                                   4
+#define FM_IRQSTAT_HSDINT                                   0x10
+#define FV_HSDINT_INTERRUPTED                               0x10
+#define FV_HSDINT_NOT_INTERRUPTED                           0x0
+
+#define FB_IRQSTAT_HPDINT                                   3
+#define FM_IRQSTAT_HPDINT                                   0x8
+#define FV_HPDINT_INTERRUPTED                               0x8
+#define FV_HPDINT_NOT_INTERRUPTED                           0x0
+
+#define FB_IRQSTAT_GPIO3INT                                 1
+#define FM_IRQSTAT_GPIO3INT                                 0x2
+#define FV_GPIO3INT_INTERRUPTED                             0x2
+#define FV_GPIO3INT_NOT_INTERRUPTED                         0x0
+
+#define FB_IRQSTAT_GPIO2INT                                 0
+#define FM_IRQSTAT_GPIO2INT                                 0x1
+#define FV_GPIO2INT_INTERRUPTED                             0x1
+#define FV_GPIO2INT_NOT_INTERRUPTED                         0x0
+
+#define IRQSTAT_GPIOINT_INTERRUPTED                         0x1
+#define IRQSTAT_GPIOINT_NOT_INTERRUPTED                     0x0
+
+// *** DEVADD0 ***
+#define FB_DEVADD0_DEVADD0                                  1
+#define FM_DEVADD0_DEVADD0                                  0xFE
+
+#define FB_DEVADD0_I2C_ADDRLK                               0
+#define FM_DEVADD0_I2C_ADDRLK                               0x1
+#define FV_I2C_ADDRLK_LOCK                                  0x1
+
+// *** DEVID ***
+#define FB_DEVID_DEV_ID                                     0
+#define FM_DEVID_DEV_ID                                     0xFF
+
+// *** DEVREV ***
+#define FB_DEVREV_MAJ_REV                                   4
+#define FM_DEVREV_MAJ_REV                                   0xF0
+
+#define FB_DEVREV_MIN_REV                                   0
+#define FM_DEVREV_MIN_REV                                   0xF
+
+// *** PLLSTAT ***
+#define FB_PLLSTAT_PLL2LK                                   1
+#define FM_PLLSTAT_PLL2LK                                   0x2
+#define FV_PLL2LK_LOCKED                                    0x2
+#define FV_PLL2LK_UNLOCKED                                  0x0
+
+#define FB_PLLSTAT_PLL1LK                                   0
+#define FM_PLLSTAT_PLL1LK                                   0x1
+#define FV_PLL1LK_LOCKED                                    0x1
+#define FV_PLL1LK_UNLOCKED                                  0x0
+
+#define PLLSTAT_PLLLK_LOCKED                                0x1
+#define PLLSTAT_PLLLK_UNLOCKED                              0x0
+
+// *** PLLCTL ***
+#define FB_PLLCTL_PU_PLL2                                   7
+#define FM_PLLCTL_PU_PLL2                                   0x80
+#define FV_PU_PLL2_PWR_UP                                   0x80
+#define FV_PU_PLL2_PWR_DWN                                  0x0
+
+#define FB_PLLCTL_PU_PLL1                                   6
+#define FM_PLLCTL_PU_PLL1                                   0x40
+#define FV_PU_PLL1_PWR_UP                                   0x40
+#define FV_PU_PLL1_PWR_DWN                                  0x0
+
+#define FB_PLLCTL_PLL2CLKEN                                 5
+#define FM_PLLCTL_PLL2CLKEN                                 0x20
+#define FV_PLL2CLKEN_ENABLE                                 0x20
+#define FV_PLL2CLKEN_DISABLE                                0x0
+
+#define FB_PLLCTL_PLL1CLKEN                                 4
+#define FM_PLLCTL_PLL1CLKEN                                 0x10
+#define FV_PLL1CLKEN_ENABLE                                 0x10
+#define FV_PLL1CLKEN_DISABLE                                0x0
+
+#define FB_PLLCTL_BCLKSEL                                   2
+#define FM_PLLCTL_BCLKSEL                                   0xC
+#define FV_BCLKSEL_BCLK1                                    0x0
+#define FV_BCLKSEL_BCLK2                                    0x4
+#define FV_BCLKSEL_BCLK3                                    0x8
+
+#define FB_PLLCTL_PLLISEL                                   0
+#define FM_PLLCTL_PLLISEL                                   0x3
+#define FV_PLLISEL_XTAL                                     0x0
+#define FV_PLLISEL_MCLK1                                    0x1
+#define FV_PLLISEL_MCLK2                                    0x2
+#define FV_PLLISEL_BCLK                                     0x3
+
+#define PLLCTL_PU_PLL_PWR_UP                                0x1
+#define PLLCTL_PU_PLL_PWR_DWN                               0x0
+#define PLLCTL_PLLCLKEN_ENABLE                              0x1
+#define PLLCTL_PLLCLKEN_DISABLE                             0x0
+
+// *** ISRC ***
+#define FB_ISRC_IBR                                         2
+#define FM_ISRC_IBR                                         0x4
+#define FV_IBR_44PT1                                        0x0
+#define FV_IBR_48                                           0x4
+
+#define FB_ISRC_IBM                                         0
+#define FM_ISRC_IBM                                         0x3
+#define FV_IBM_0PT25                                        0x0
+#define FV_IBM_0PT5                                         0x1
+#define FV_IBM_1                                            0x2
+#define FV_IBM_2                                            0x3
+
+// *** SCLKCTL ***
+#define FB_SCLKCTL_ASDM                                     6
+#define FM_SCLKCTL_ASDM                                     0xC0
+#define FV_ASDM_HALF                                        0x40
+#define FV_ASDM_FULL                                        0x80
+#define FV_ASDM_AUTO                                        0xC0
+
+#define FB_SCLKCTL_DSDM                                     4
+#define FM_SCLKCTL_DSDM                                     0x30
+#define FV_DSDM_HALF                                        0x10
+#define FV_DSDM_FULL                                        0x20
+#define FV_DSDM_AUTO                                        0x30
+
+// *** TIMEBASE ***
+#define FB_TIMEBASE_TIMEBASE                                0
+#define FM_TIMEBASE_TIMEBASE                                0xFF
+
+// *** I2SCMC ***
+#define FB_I2SCMC_BCMP3                                     4
+#define FM_I2SCMC_BCMP3                                     0x30
+#define FV_BCMP3_AUTO                                       0x0
+#define FV_BCMP3_32X                                        0x10
+#define FV_BCMP3_40X                                        0x20
+#define FV_BCMP3_64X                                        0x30
+
+#define FB_I2SCMC_BCMP2                                     2
+#define FM_I2SCMC_BCMP2                                     0xC
+#define FV_BCMP2_AUTO                                       0x0
+#define FV_BCMP2_32X                                        0x4
+#define FV_BCMP2_40X                                        0x8
+#define FV_BCMP2_64X                                        0xC
+
+#define FB_I2SCMC_BCMP1                                     0
+#define FM_I2SCMC_BCMP1                                     0x3
+#define FV_BCMP1_AUTO                                       0x0
+#define FV_BCMP1_32X                                        0x1
+#define FV_BCMP1_40X                                        0x2
+#define FV_BCMP1_64X                                        0x3
+
+#define I2SCMC_BCMP_AUTO                                    0x0
+#define I2SCMC_BCMP_32X                                     0x1
+#define I2SCMC_BCMP_40X                                     0x2
+#define I2SCMC_BCMP_64X                                     0x3
+
+// *** MCLK2PINC ***
+#define FB_MCLK2PINC_SLEWOUT                                4
+#define FM_MCLK2PINC_SLEWOUT                                0xF0
+
+#define FB_MCLK2PINC_MCLK2IO                                2
+#define FM_MCLK2PINC_MCLK2IO                                0x4
+#define FV_MCLK2IO_INPUT                                    0x0
+#define FV_MCLK2IO_OUTPUT                                   0x4
+
+#define FB_MCLK2PINC_MCLK2OS                                0
+#define FM_MCLK2PINC_MCLK2OS                                0x3
+#define FV_MCLK2OS_24PT576                                  0x0
+#define FV_MCLK2OS_22PT5792                                 0x1
+#define FV_MCLK2OS_PLL2                                     0x2
+
+// *** I2SPINC0 ***
+#define FB_I2SPINC0_SDO3TRI                                 7
+#define FM_I2SPINC0_SDO3TRI                                 0x80
+
+#define FB_I2SPINC0_SDO2TRI                                 6
+#define FM_I2SPINC0_SDO2TRI                                 0x40
+
+#define FB_I2SPINC0_SDO1TRI                                 5
+#define FM_I2SPINC0_SDO1TRI                                 0x20
+
+#define FB_I2SPINC0_PCM3TRI                                 2
+#define FM_I2SPINC0_PCM3TRI                                 0x4
+
+#define FB_I2SPINC0_PCM2TRI                                 1
+#define FM_I2SPINC0_PCM2TRI                                 0x2
+
+#define FB_I2SPINC0_PCM1TRI                                 0
+#define FM_I2SPINC0_PCM1TRI                                 0x1
+
+// *** I2SPINC1 ***
+#define FB_I2SPINC1_SDO3PDD                                 2
+#define FM_I2SPINC1_SDO3PDD                                 0x4
+
+#define FB_I2SPINC1_SDO2PDD                                 1
+#define FM_I2SPINC1_SDO2PDD                                 0x2
+
+#define FB_I2SPINC1_SDO1PDD                                 0
+#define FM_I2SPINC1_SDO1PDD                                 0x1
+
+// *** I2SPINC2 ***
+#define FB_I2SPINC2_LR3PDD                                  5
+#define FM_I2SPINC2_LR3PDD                                  0x20
+
+#define FB_I2SPINC2_BC3PDD                                  4
+#define FM_I2SPINC2_BC3PDD                                  0x10
+
+#define FB_I2SPINC2_LR2PDD                                  3
+#define FM_I2SPINC2_LR2PDD                                  0x8
+
+#define FB_I2SPINC2_BC2PDD                                  2
+#define FM_I2SPINC2_BC2PDD                                  0x4
+
+#define FB_I2SPINC2_LR1PDD                                  1
+#define FM_I2SPINC2_LR1PDD                                  0x2
+
+#define FB_I2SPINC2_BC1PDD                                  0
+#define FM_I2SPINC2_BC1PDD                                  0x1
+
+// *** GPIOCTL0 ***
+#define FB_GPIOCTL0_GPIO3INTP                               7
+#define FM_GPIOCTL0_GPIO3INTP                               0x80
+
+#define FB_GPIOCTL0_GPIO2INTP                               6
+#define FM_GPIOCTL0_GPIO2INTP                               0x40
+
+#define FB_GPIOCTL0_GPIO3CFG                                5
+#define FM_GPIOCTL0_GPIO3CFG                                0x20
+
+#define FB_GPIOCTL0_GPIO2CFG                                4
+#define FM_GPIOCTL0_GPIO2CFG                                0x10
+
+#define FB_GPIOCTL0_GPIO3IO                                 3
+#define FM_GPIOCTL0_GPIO3IO                                 0x8
+
+#define FB_GPIOCTL0_GPIO2IO                                 2
+#define FM_GPIOCTL0_GPIO2IO                                 0x4
+
+#define FB_GPIOCTL0_GPIO1IO                                 1
+#define FM_GPIOCTL0_GPIO1IO                                 0x2
+
+#define FB_GPIOCTL0_GPIO0IO                                 0
+#define FM_GPIOCTL0_GPIO0IO                                 0x1
+
+// *** GPIOCTL1 ***
+#define FB_GPIOCTL1_GPIO3                                   7
+#define FM_GPIOCTL1_GPIO3                                   0x80
+
+#define FB_GPIOCTL1_GPIO2                                   6
+#define FM_GPIOCTL1_GPIO2                                   0x40
+
+#define FB_GPIOCTL1_GPIO1                                   5
+#define FM_GPIOCTL1_GPIO1                                   0x20
+
+#define FB_GPIOCTL1_GPIO0                                   4
+#define FM_GPIOCTL1_GPIO0                                   0x10
+
+#define FB_GPIOCTL1_GPIO3RD                                 3
+#define FM_GPIOCTL1_GPIO3RD                                 0x8
+
+#define FB_GPIOCTL1_GPIO2RD                                 2
+#define FM_GPIOCTL1_GPIO2RD                                 0x4
+
+#define FB_GPIOCTL1_GPIO1RD                                 1
+#define FM_GPIOCTL1_GPIO1RD                                 0x2
+
+#define FB_GPIOCTL1_GPIO0RD                                 0
+#define FM_GPIOCTL1_GPIO0RD                                 0x1
+
+// *** ASRC ***
+#define FB_ASRC_ASRCOBW                                     7
+#define FM_ASRC_ASRCOBW                                     0x80
+
+#define FB_ASRC_ASRCIBW                                     6
+#define FM_ASRC_ASRCIBW                                     0x40
+
+#define FB_ASRC_ASRCOB                                      5
+#define FM_ASRC_ASRCOB                                      0x20
+#define FV_ASRCOB_ACTIVE                                    0x0
+#define FV_ASRCOB_BYPASSED                                  0x20
+
+#define FB_ASRC_ASRCIB                                      4
+#define FM_ASRC_ASRCIB                                      0x10
+#define FV_ASRCIB_ACTIVE                                    0x0
+#define FV_ASRCIB_BYPASSED                                  0x10
+
+#define FB_ASRC_ASRCOL                                      3
+#define FM_ASRC_ASRCOL                                      0x8
+
+#define FB_ASRC_ASRCIL                                      2
+#define FM_ASRC_ASRCIL                                      0x4
+
+// *** TDMCTL0 ***
+#define FB_TDMCTL0_TDMMD                                    2
+#define FM_TDMCTL0_TDMMD                                    0x4
+#define FV_TDMMD_200                                        0x0
+#define FV_TDMMD_256                                        0x4
+
+#define FB_TDMCTL0_SLSYNC                                   1
+#define FM_TDMCTL0_SLSYNC                                   0x2
+#define FV_SLSYNC_SHORT                                     0x0
+#define FV_SLSYNC_LONG                                      0x2
+
+#define FB_TDMCTL0_BDELAY                                   0
+#define FM_TDMCTL0_BDELAY                                   0x1
+#define FV_BDELAY_NO_DELAY                                  0x0
+#define FV_BDELAY_1BCLK_DELAY                               0x1
+
+// *** TDMCTL1 ***
+#define FB_TDMCTL1_TDMSO                                    5
+#define FM_TDMCTL1_TDMSO                                    0x60
+#define FV_TDMSO_2                                          0x0
+#define FV_TDMSO_4                                          0x20
+#define FV_TDMSO_6                                          0x40
+
+#define FB_TDMCTL1_TDMDSS                                   3
+#define FM_TDMCTL1_TDMDSS                                   0x18
+#define FV_TDMDSS_16                                        0x0
+#define FV_TDMDSS_24                                        0x10
+#define FV_TDMDSS_32                                        0x18
+
+#define FB_TDMCTL1_TDMSI                                    0
+#define FM_TDMCTL1_TDMSI                                    0x3
+#define FV_TDMSI_2                                          0x0
+#define FV_TDMSI_4                                          0x1
+#define FV_TDMSI_6                                          0x2
+
+// *** PWRM0 ***
+#define FB_PWRM0_INPROC3PU                                  6
+#define FM_PWRM0_INPROC3PU                                  0x40
+
+#define FB_PWRM0_INPROC2PU                                  5
+#define FM_PWRM0_INPROC2PU                                  0x20
+
+#define FB_PWRM0_INPROC1PU                                  4
+#define FM_PWRM0_INPROC1PU                                  0x10
+
+#define FB_PWRM0_INPROC0PU                                  3
+#define FM_PWRM0_INPROC0PU                                  0x8
+
+#define FB_PWRM0_MICB2PU                                    2
+#define FM_PWRM0_MICB2PU                                    0x4
+
+#define FB_PWRM0_MICB1PU                                    1
+#define FM_PWRM0_MICB1PU                                    0x2
+
+#define FB_PWRM0_MCLKPEN                                    0
+#define FM_PWRM0_MCLKPEN                                    0x1
+
+// *** PWRM1 ***
+#define FB_PWRM1_SUBPU                                      7
+#define FM_PWRM1_SUBPU                                      0x80
+
+#define FB_PWRM1_HPLPU                                      6
+#define FM_PWRM1_HPLPU                                      0x40
+
+#define FB_PWRM1_HPRPU                                      5
+#define FM_PWRM1_HPRPU                                      0x20
+
+#define FB_PWRM1_SPKLPU                                     4
+#define FM_PWRM1_SPKLPU                                     0x10
+
+#define FB_PWRM1_SPKRPU                                     3
+#define FM_PWRM1_SPKRPU                                     0x8
+
+#define FB_PWRM1_D2S2PU                                     2
+#define FM_PWRM1_D2S2PU                                     0x4
+
+#define FB_PWRM1_D2S1PU                                     1
+#define FM_PWRM1_D2S1PU                                     0x2
+
+#define FB_PWRM1_VREFPU                                     0
+#define FM_PWRM1_VREFPU                                     0x1
+
+// *** PWRM2 ***
+#define FB_PWRM2_I2S3OPU                                    5
+#define FM_PWRM2_I2S3OPU                                    0x20
+#define FV_I2S3OPU_PWR_DOWN                                 0x0
+#define FV_I2S3OPU_PWR_UP                                   0x20
+
+#define FB_PWRM2_I2S2OPU                                    4
+#define FM_PWRM2_I2S2OPU                                    0x10
+#define FV_I2S2OPU_PWR_DOWN                                 0x0
+#define FV_I2S2OPU_PWR_UP                                   0x10
+
+#define FB_PWRM2_I2S1OPU                                    3
+#define FM_PWRM2_I2S1OPU                                    0x8
+#define FV_I2S1OPU_PWR_DOWN                                 0x0
+#define FV_I2S1OPU_PWR_UP                                   0x8
+
+#define FB_PWRM2_I2S3IPU                                    2
+#define FM_PWRM2_I2S3IPU                                    0x4
+#define FV_I2S3IPU_PWR_DOWN                                 0x0
+#define FV_I2S3IPU_PWR_UP                                   0x4
+
+#define FB_PWRM2_I2S2IPU                                    1
+#define FM_PWRM2_I2S2IPU                                    0x2
+#define FV_I2S2IPU_PWR_DOWN                                 0x0
+#define FV_I2S2IPU_PWR_UP                                   0x2
+
+#define FB_PWRM2_I2S1IPU                                    0
+#define FM_PWRM2_I2S1IPU                                    0x1
+#define FV_I2S1IPU_PWR_DOWN                                 0x0
+#define FV_I2S1IPU_PWR_UP                                   0x1
+
+#define PWRM2_I2SOPU_PWR_DOWN                               0x0
+#define PWRM2_I2SOPU_PWR_UP                                 0x1
+#define PWRM2_I2SIPU_PWR_DOWN                               0x0
+#define PWRM2_I2SIPU_PWR_UP                                 0x1
+
+// *** PWRM3 ***
+#define FB_PWRM3_BGSBUP                                     6
+#define FM_PWRM3_BGSBUP                                     0x40
+#define FV_BGSBUP_ON                                        0x0
+#define FV_BGSBUP_OFF                                       0x40
+
+#define FB_PWRM3_VGBAPU                                     5
+#define FM_PWRM3_VGBAPU                                     0x20
+#define FV_VGBAPU_ON                                        0x0
+#define FV_VGBAPU_OFF                                       0x20
+
+#define FB_PWRM3_LLINEPU                                    4
+#define FM_PWRM3_LLINEPU                                    0x10
+
+#define FB_PWRM3_RLINEPU                                    3
+#define FM_PWRM3_RLINEPU                                    0x8
+
+// *** PWRM4 ***
+#define FB_PWRM4_OPSUBPU                                    4
+#define FM_PWRM4_OPSUBPU                                    0x10
+
+#define FB_PWRM4_OPDACLPU                                   3
+#define FM_PWRM4_OPDACLPU                                   0x8
+
+#define FB_PWRM4_OPDACRPU                                   2
+#define FM_PWRM4_OPDACRPU                                   0x4
+
+#define FB_PWRM4_OPSPKLPU                                   1
+#define FM_PWRM4_OPSPKLPU                                   0x2
+
+#define FB_PWRM4_OPSPKRPU                                   0
+#define FM_PWRM4_OPSPKRPU                                   0x1
+
+// *** I2SIDCTL ***
+#define FB_I2SIDCTL_I2SI3DCTL                               4
+#define FM_I2SIDCTL_I2SI3DCTL                               0x30
+
+#define FB_I2SIDCTL_I2SI2DCTL                               2
+#define FM_I2SIDCTL_I2SI2DCTL                               0xC
+
+#define FB_I2SIDCTL_I2SI1DCTL                               0
+#define FM_I2SIDCTL_I2SI1DCTL                               0x3
+
+// *** I2SODCTL ***
+#define FB_I2SODCTL_I2SO3DCTL                               4
+#define FM_I2SODCTL_I2SO3DCTL                               0x30
+
+#define FB_I2SODCTL_I2SO2DCTL                               2
+#define FM_I2SODCTL_I2SO2DCTL                               0xC
+
+#define FB_I2SODCTL_I2SO1DCTL                               0
+#define FM_I2SODCTL_I2SO1DCTL                               0x3
+
+// *** AUDIOMUX1 ***
+#define FB_AUDIOMUX1_ASRCIMUX                               6
+#define FM_AUDIOMUX1_ASRCIMUX                               0xC0
+#define FV_ASRCIMUX_NONE                                    0x0
+#define FV_ASRCIMUX_I2S1                                    0x40
+#define FV_ASRCIMUX_I2S2                                    0x80
+#define FV_ASRCIMUX_I2S3                                    0xC0
+
+#define FB_AUDIOMUX1_I2S2MUX                                3
+#define FM_AUDIOMUX1_I2S2MUX                                0x38
+#define FV_I2S2MUX_I2S1                                     0x0
+#define FV_I2S2MUX_I2S2                                     0x8
+#define FV_I2S2MUX_I2S3                                     0x10
+#define FV_I2S2MUX_ADC_DMIC                                 0x18
+#define FV_I2S2MUX_DMIC2                                    0x20
+#define FV_I2S2MUX_CLASSD_DSP                               0x28
+#define FV_I2S2MUX_DAC_DSP                                  0x30
+#define FV_I2S2MUX_SUB_DSP                                  0x38
+
+#define FB_AUDIOMUX1_I2S1MUX                                0
+#define FM_AUDIOMUX1_I2S1MUX                                0x7
+#define FV_I2S1MUX_I2S1                                     0x0
+#define FV_I2S1MUX_I2S2                                     0x1
+#define FV_I2S1MUX_I2S3                                     0x2
+#define FV_I2S1MUX_ADC_DMIC                                 0x3
+#define FV_I2S1MUX_DMIC2                                    0x4
+#define FV_I2S1MUX_CLASSD_DSP                               0x5
+#define FV_I2S1MUX_DAC_DSP                                  0x6
+#define FV_I2S1MUX_SUB_DSP                                  0x7
+
+#define AUDIOMUX1_I2SMUX_I2S1                               0x0
+#define AUDIOMUX1_I2SMUX_I2S2                               0x1
+#define AUDIOMUX1_I2SMUX_I2S3                               0x2
+#define AUDIOMUX1_I2SMUX_ADC_DMIC                           0x3
+#define AUDIOMUX1_I2SMUX_DMIC2                              0x4
+#define AUDIOMUX1_I2SMUX_CLASSD_DSP                         0x5
+#define AUDIOMUX1_I2SMUX_DAC_DSP                            0x6
+#define AUDIOMUX1_I2SMUX_SUB_DSP                            0x7
+
+// *** AUDIOMUX2 ***
+#define FB_AUDIOMUX2_ASRCOMUX                               6
+#define FM_AUDIOMUX2_ASRCOMUX                               0xC0
+#define FV_ASRCOMUX_NONE                                    0x0
+#define FV_ASRCOMUX_I2S1                                    0x40
+#define FV_ASRCOMUX_I2S2                                    0x80
+#define FV_ASRCOMUX_I2S3                                    0xC0
+
+#define FB_AUDIOMUX2_DACMUX                                 3
+#define FM_AUDIOMUX2_DACMUX                                 0x38
+#define FV_DACMUX_I2S1                                      0x0
+#define FV_DACMUX_I2S2                                      0x8
+#define FV_DACMUX_I2S3                                      0x10
+#define FV_DACMUX_ADC_DMIC                                  0x18
+#define FV_DACMUX_DMIC2                                     0x20
+#define FV_DACMUX_CLASSD_DSP                                0x28
+#define FV_DACMUX_DAC_DSP                                   0x30
+#define FV_DACMUX_SUB_DSP                                   0x38
+
+#define FB_AUDIOMUX2_I2S3MUX                                0
+#define FM_AUDIOMUX2_I2S3MUX                                0x7
+#define FV_I2S3MUX_I2S1                                     0x0
+#define FV_I2S3MUX_I2S2                                     0x1
+#define FV_I2S3MUX_I2S3                                     0x2
+#define FV_I2S3MUX_ADC_DMIC                                 0x3
+#define FV_I2S3MUX_DMIC2                                    0x4
+#define FV_I2S3MUX_CLASSD_DSP                               0x5
+#define FV_I2S3MUX_DAC_DSP                                  0x6
+#define FV_I2S3MUX_SUB_DSP                                  0x7
+
+// *** AUDIOMUX3 ***
+#define FB_AUDIOMUX3_SUBMUX                                 3
+#define FM_AUDIOMUX3_SUBMUX                                 0xF8
+#define FV_SUBMUX_I2S1_L                                    0x0
+#define FV_SUBMUX_I2S1_R                                    0x8
+#define FV_SUBMUX_I2S1_LR                                   0x10
+#define FV_SUBMUX_I2S2_L                                    0x18
+#define FV_SUBMUX_I2S2_R                                    0x20
+#define FV_SUBMUX_I2S2_LR                                   0x28
+#define FV_SUBMUX_I2S3_L                                    0x30
+#define FV_SUBMUX_I2S3_R                                    0x38
+#define FV_SUBMUX_I2S3_LR                                   0x40
+#define FV_SUBMUX_ADC_DMIC_L                                0x48
+#define FV_SUBMUX_ADC_DMIC_R                                0x50
+#define FV_SUBMUX_ADC_DMIC_LR                               0x58
+#define FV_SUBMUX_DMIC_L                                    0x60
+#define FV_SUBMUX_DMIC_R                                    0x68
+#define FV_SUBMUX_DMIC_LR                                   0x70
+#define FV_SUBMUX_CLASSD_DSP_L                              0x78
+#define FV_SUBMUX_CLASSD_DSP_R                              0x80
+#define FV_SUBMUX_CLASSD_DSP_LR                             0x88
+
+#define FB_AUDIOMUX3_CLSSDMUX                               0
+#define FM_AUDIOMUX3_CLSSDMUX                               0x7
+#define FV_CLSSDMUX_I2S1                                    0x0
+#define FV_CLSSDMUX_I2S2                                    0x1
+#define FV_CLSSDMUX_I2S3                                    0x2
+#define FV_CLSSDMUX_ADC_DMIC                                0x3
+#define FV_CLSSDMUX_DMIC2                                   0x4
+#define FV_CLSSDMUX_CLASSD_DSP                              0x5
+#define FV_CLSSDMUX_DAC_DSP                                 0x6
+#define FV_CLSSDMUX_SUB_DSP                                 0x7
+
+// *** HSDCTL1 ***
+#define FB_HSDCTL1_HPJKTYPE                                 7
+#define FM_HSDCTL1_HPJKTYPE                                 0x80
+
+#define FB_HSDCTL1_CON_DET_PWD                              6
+#define FM_HSDCTL1_CON_DET_PWD                              0x40
+
+#define FB_HSDCTL1_DETCYC                                   4
+#define FM_HSDCTL1_DETCYC                                   0x30
+
+#define FB_HSDCTL1_HPDLYBYP                                 3
+#define FM_HSDCTL1_HPDLYBYP                                 0x8
+
+#define FB_HSDCTL1_HSDETPOL                                 2
+#define FM_HSDCTL1_HSDETPOL                                 0x4
+
+#define FB_HSDCTL1_HPID_EN                                  1
+#define FM_HSDCTL1_HPID_EN                                  0x2
+
+#define FB_HSDCTL1_GBLHS_EN                                 0
+#define FM_HSDCTL1_GBLHS_EN                                 0x1
+
+// *** HSDCTL2 ***
+#define FB_HSDCTL2_FMICBIAS1                                6
+#define FM_HSDCTL2_FMICBIAS1                                0xC0
+
+#define FB_HSDCTL2_MB1MODE                                  5
+#define FM_HSDCTL2_MB1MODE                                  0x20
+#define FV_MB1MODE_AUTO                                     0x0
+#define FV_MB1MODE_MANUAL                                   0x20
+
+#define FB_HSDCTL2_FORCETRG                                 4
+#define FM_HSDCTL2_FORCETRG                                 0x10
+
+#define FB_HSDCTL2_SWMODE                                   3
+#define FM_HSDCTL2_SWMODE                                   0x8
+
+#define FB_HSDCTL2_GHSHIZ                                   2
+#define FM_HSDCTL2_GHSHIZ                                   0x4
+
+#define FB_HSDCTL2_FPLUGTYPE                                0
+#define FM_HSDCTL2_FPLUGTYPE                                0x3
+
+// *** HSDSTAT ***
+#define FB_HSDSTAT_MBIAS1DRV                                5
+#define FM_HSDSTAT_MBIAS1DRV                                0x60
+
+#define FB_HSDSTAT_HSDETSTAT                                3
+#define FM_HSDSTAT_HSDETSTAT                                0x8
+
+#define FB_HSDSTAT_PLUGTYPE                                 1
+#define FM_HSDSTAT_PLUGTYPE                                 0x6
+
+#define FB_HSDSTAT_HSDETDONE                                0
+#define FM_HSDSTAT_HSDETDONE                                0x1
+
+// *** HSDDELAY ***
+#define FB_HSDDELAY_T_STABLE                                0
+#define FM_HSDDELAY_T_STABLE                                0x7
+
+// *** BUTCTL ***
+#define FB_BUTCTL_BPUSHSTAT                                 7
+#define FM_BUTCTL_BPUSHSTAT                                 0x80
+
+#define FB_BUTCTL_BPUSHDET                                  6
+#define FM_BUTCTL_BPUSHDET                                  0x40
+
+#define FB_BUTCTL_BPUSHEN                                   5
+#define FM_BUTCTL_BPUSHEN                                   0x20
+
+#define FB_BUTCTL_BSTABLE_L                                 3
+#define FM_BUTCTL_BSTABLE_L                                 0x18
+
+#define FB_BUTCTL_BSTABLE_S                                 0
+#define FM_BUTCTL_BSTABLE_S                                 0x7
+
+// *** CH0AIC ***
+#define FB_CH0AIC_INSELL                                    6
+#define FM_CH0AIC_INSELL                                    0xC0
+
+#define FB_CH0AIC_MICBST0                                   4
+#define FM_CH0AIC_MICBST0                                   0x30
+
+#define FB_CH0AIC_LADCIN                                    2
+#define FM_CH0AIC_LADCIN                                    0xC
+
+#define FB_CH0AIC_IN_BYPS_L_SEL                             1
+#define FM_CH0AIC_IN_BYPS_L_SEL                             0x2
+
+#define FB_CH0AIC_IPCH0S                                    0
+#define FM_CH0AIC_IPCH0S                                    0x1
+
+// *** CH1AIC ***
+#define FB_CH1AIC_INSELR                                    6
+#define FM_CH1AIC_INSELR                                    0xC0
+
+#define FB_CH1AIC_MICBST1                                   4
+#define FM_CH1AIC_MICBST1                                   0x30
+
+#define FB_CH1AIC_RADCIN                                    2
+#define FM_CH1AIC_RADCIN                                    0xC
+
+#define FB_CH1AIC_IN_BYPS_R_SEL                             1
+#define FM_CH1AIC_IN_BYPS_R_SEL                             0x2
+
+#define FB_CH1AIC_IPCH1S                                    0
+#define FM_CH1AIC_IPCH1S                                    0x1
+
+// *** ICTL0 ***
+#define FB_ICTL0_IN1POL                                     7
+#define FM_ICTL0_IN1POL                                     0x80
+
+#define FB_ICTL0_IN0POL                                     6
+#define FM_ICTL0_IN0POL                                     0x40
+
+#define FB_ICTL0_INPCH10SEL                                 4
+#define FM_ICTL0_INPCH10SEL                                 0x30
+
+#define FB_ICTL0_IN1MUTE                                    3
+#define FM_ICTL0_IN1MUTE                                    0x8
+
+#define FB_ICTL0_IN0MUTE                                    2
+#define FM_ICTL0_IN0MUTE                                    0x4
+
+#define FB_ICTL0_IN1HP                                      1
+#define FM_ICTL0_IN1HP                                      0x2
+
+#define FB_ICTL0_IN0HP                                      0
+#define FM_ICTL0_IN0HP                                      0x1
+
+// *** ICTL1 ***
+#define FB_ICTL1_IN3POL                                     7
+#define FM_ICTL1_IN3POL                                     0x80
+
+#define FB_ICTL1_IN2POL                                     6
+#define FM_ICTL1_IN2POL                                     0x40
+
+#define FB_ICTL1_INPCH32SEL                                 4
+#define FM_ICTL1_INPCH32SEL                                 0x30
+
+#define FB_ICTL1_IN3MUTE                                    3
+#define FM_ICTL1_IN3MUTE                                    0x8
+
+#define FB_ICTL1_IN2MUTE                                    2
+#define FM_ICTL1_IN2MUTE                                    0x4
+
+#define FB_ICTL1_IN3HP                                      1
+#define FM_ICTL1_IN3HP                                      0x2
+
+#define FB_ICTL1_IN2HP                                      0
+#define FM_ICTL1_IN2HP                                      0x1
+
+// *** MICBIAS ***
+#define FB_MICBIAS_MICBOV2                                  4
+#define FM_MICBIAS_MICBOV2                                  0x30
+
+#define FB_MICBIAS_MICBOV1                                  6
+#define FM_MICBIAS_MICBOV1                                  0xC0
+
+#define FB_MICBIAS_SPARE1                                   2
+#define FM_MICBIAS_SPARE1                                   0xC
+
+#define FB_MICBIAS_SPARE2                                   0
+#define FM_MICBIAS_SPARE2                                   0x3
+
+// *** PGAZ ***
+#define FB_PGAZ_INHPOR                                      1
+#define FM_PGAZ_INHPOR                                      0x2
+
+#define FB_PGAZ_TOEN                                        0
+#define FM_PGAZ_TOEN                                        0x1
+
+// *** ASRCILVOL ***
+#define FB_ASRCILVOL_ASRCILVOL                              0
+#define FM_ASRCILVOL_ASRCILVOL                              0xFF
+
+// *** ASRCIRVOL ***
+#define FB_ASRCIRVOL_ASRCIRVOL                              0
+#define FM_ASRCIRVOL_ASRCIRVOL                              0xFF
+
+// *** ASRCOLVOL ***
+#define FB_ASRCOLVOL_ASRCOLVOL                              0
+#define FM_ASRCOLVOL_ASRCOLVOL                              0xFF
+
+// *** ASRCORVOL ***
+#define FB_ASRCORVOL_ASRCOLVOL                              0
+#define FM_ASRCORVOL_ASRCOLVOL                              0xFF
+
+// *** IVOLCTLU ***
+#define FB_IVOLCTLU_IFADE                                   3
+#define FM_IVOLCTLU_IFADE                                   0x8
+
+#define FB_IVOLCTLU_INPVOLU                                 2
+#define FM_IVOLCTLU_INPVOLU                                 0x4
+
+#define FB_IVOLCTLU_PGAVOLU                                 1
+#define FM_IVOLCTLU_PGAVOLU                                 0x2
+
+#define FB_IVOLCTLU_ASRCVOLU                                0
+#define FM_IVOLCTLU_ASRCVOLU                                0x1
+
+// *** ALCCTL0 ***
+#define FB_ALCCTL0_ALCMODE                                  7
+#define FM_ALCCTL0_ALCMODE                                  0x80
+
+#define FB_ALCCTL0_ALCREF                                   4
+#define FM_ALCCTL0_ALCREF                                   0x70
+
+#define FB_ALCCTL0_ALCEN3                                   3
+#define FM_ALCCTL0_ALCEN3                                   0x8
+
+#define FB_ALCCTL0_ALCEN2                                   2
+#define FM_ALCCTL0_ALCEN2                                   0x4
+
+#define FB_ALCCTL0_ALCEN1                                   1
+#define FM_ALCCTL0_ALCEN1                                   0x2
+
+#define FB_ALCCTL0_ALCEN0                                   0
+#define FM_ALCCTL0_ALCEN0                                   0x1
+
+// *** ALCCTL1 ***
+#define FB_ALCCTL1_MAXGAIN                                  4
+#define FM_ALCCTL1_MAXGAIN                                  0x70
+
+#define FB_ALCCTL1_ALCL                                     0
+#define FM_ALCCTL1_ALCL                                     0xF
+
+// *** ALCCTL2 ***
+#define FB_ALCCTL2_ALCZC                                    7
+#define FM_ALCCTL2_ALCZC                                    0x80
+
+#define FB_ALCCTL2_MINGAIN                                  4
+#define FM_ALCCTL2_MINGAIN                                  0x70
+
+#define FB_ALCCTL2_HLD                                      0
+#define FM_ALCCTL2_HLD                                      0xF
+
+// *** ALCCTL3 ***
+#define FB_ALCCTL3_DCY                                      4
+#define FM_ALCCTL3_DCY                                      0xF0
+
+#define FB_ALCCTL3_ATK                                      0
+#define FM_ALCCTL3_ATK                                      0xF
+
+// *** NGATE ***
+#define FB_NGATE_NGTH                                       3
+#define FM_NGATE_NGTH                                       0xF8
+
+#define FB_NGATE_NGG                                        1
+#define FM_NGATE_NGG                                        0x6
+
+#define FB_NGATE_NGAT                                       0
+#define FM_NGATE_NGAT                                       0x1
+
+// *** DMICCTL ***
+#define FB_DMICCTL_DMIC2EN                                  7
+#define FM_DMICCTL_DMIC2EN                                  0x80
+
+#define FB_DMICCTL_DMIC1EN                                  6
+#define FM_DMICCTL_DMIC1EN                                  0x40
+
+#define FB_DMICCTL_DMONO                                    4
+#define FM_DMICCTL_DMONO                                    0x10
+
+#define FB_DMICCTL_DMDCLK                                   2
+#define FM_DMICCTL_DMDCLK                                   0xC
+
+#define FB_DMICCTL_DMRATE                                   0
+#define FM_DMICCTL_DMRATE                                   0x3
+
+// *** DACCTL ***
+#define FB_DACCTL_DACPOLR                                   7
+#define FM_DACCTL_DACPOLR                                   0x80
+#define FV_DACPOLR_NORMAL                                   0x0
+#define FV_DACPOLR_INVERTED                                 0x80
+
+#define FB_DACCTL_DACPOLL                                   6
+#define FM_DACCTL_DACPOLL                                   0x40
+#define FV_DACPOLL_NORMAL                                   0x0
+#define FV_DACPOLL_INVERTED                                 0x40
+
+#define FB_DACCTL_DACDITH                                   4
+#define FM_DACCTL_DACDITH                                   0x30
+#define FV_DACDITH_DYNAMIC_HALF                             0x0
+#define FV_DACDITH_DYNAMIC_FULL                             0x10
+#define FV_DACDITH_DISABLED                                 0x20
+#define FV_DACDITH_STATIC                                   0x30
+
+#define FB_DACCTL_DACMUTE                                   3
+#define FM_DACCTL_DACMUTE                                   0x8
+#define FV_DACMUTE_ENABLE                                   0x8
+#define FV_DACMUTE_DISABLE                                  0x0
+
+#define FB_DACCTL_DACDEM                                    2
+#define FM_DACCTL_DACDEM                                    0x4
+#define FV_DACDEM_ENABLE                                    0x4
+#define FV_DACDEM_DISABLE                                   0x0
+
+#define FB_DACCTL_ABYPASS                                   0
+#define FM_DACCTL_ABYPASS                                   0x1
+
+// *** SPKCTL ***
+#define FB_SPKCTL_SPKPOLR                                   7
+#define FM_SPKCTL_SPKPOLR                                   0x80
+#define FV_SPKPOLR_NORMAL                                   0x0
+#define FV_SPKPOLR_INVERTED                                 0x80
+
+#define FB_SPKCTL_SPKPOLL                                   6
+#define FM_SPKCTL_SPKPOLL                                   0x40
+#define FV_SPKPOLL_NORMAL                                   0x0
+#define FV_SPKPOLL_INVERTED                                 0x40
+
+#define FB_SPKCTL_SPKMUTE                                   3
+#define FM_SPKCTL_SPKMUTE                                   0x8
+#define FV_SPKMUTE_ENABLE                                   0x8
+#define FV_SPKMUTE_DISABLE                                  0x0
+
+#define FB_SPKCTL_SPKDEM                                    2
+#define FM_SPKCTL_SPKDEM                                    0x4
+#define FV_SPKDEM_ENABLE                                    0x4
+#define FV_SPKDEM_DISABLE                                   0x0
+
+// *** SUBCTL ***
+#define FB_SUBCTL_SUBPOL                                    7
+#define FM_SUBCTL_SUBPOL                                    0x80
+
+#define FB_SUBCTL_SUBMUTE                                   3
+#define FM_SUBCTL_SUBMUTE                                   0x8
+
+#define FB_SUBCTL_SUBDEM                                    2
+#define FM_SUBCTL_SUBDEM                                    0x4
+
+#define FB_SUBCTL_SUBMUX                                    1
+#define FM_SUBCTL_SUBMUX                                    0x2
+
+#define FB_SUBCTL_SUBILMDIS                                 0
+#define FM_SUBCTL_SUBILMDIS                                 0x1
+
+// *** DCCTL ***
+#define FB_DCCTL_SUBDCBYP                                   7
+#define FM_DCCTL_SUBDCBYP                                   0x80
+
+#define FB_DCCTL_DACDCBYP                                   6
+#define FM_DCCTL_DACDCBYP                                   0x40
+
+#define FB_DCCTL_SPKDCBYP                                   5
+#define FM_DCCTL_SPKDCBYP                                   0x20
+
+#define FB_DCCTL_DCCOEFSEL                                  0
+#define FM_DCCTL_DCCOEFSEL                                  0x7
+
+// *** OVOLCTLU ***
+#define FB_OVOLCTLU_OFADE                                   4
+#define FM_OVOLCTLU_OFADE                                   0x10
+
+#define FB_OVOLCTLU_SUBVOLU                                 3
+#define FM_OVOLCTLU_SUBVOLU                                 0x8
+
+#define FB_OVOLCTLU_MVOLU                                   2
+#define FM_OVOLCTLU_MVOLU                                   0x4
+
+#define FB_OVOLCTLU_SPKVOLU                                 1
+#define FM_OVOLCTLU_SPKVOLU                                 0x2
+
+#define FB_OVOLCTLU_HPVOLU                                  0
+#define FM_OVOLCTLU_HPVOLU                                  0x1
+
+// *** MUTEC ***
+#define FB_MUTEC_ZDSTAT                                     7
+#define FM_MUTEC_ZDSTAT                                     0x80
+
+#define FB_MUTEC_ZDLEN                                      4
+#define FM_MUTEC_ZDLEN                                      0x30
+
+#define FB_MUTEC_APWD                                       3
+#define FM_MUTEC_APWD                                       0x8
+
+#define FB_MUTEC_AMUTE                                      2
+#define FM_MUTEC_AMUTE                                      0x4
+
+// *** MVOLL ***
+#define FB_MVOLL_MVOL_L                                     0
+#define FM_MVOLL_MVOL_L                                     0xFF
+
+// *** MVOLR ***
+#define FB_MVOLR_MVOL_R                                     0
+#define FM_MVOLR_MVOL_R                                     0xFF
+
+// *** HPVOLL ***
+#define FB_HPVOLL_HPVOL_L                                   0
+#define FM_HPVOLL_HPVOL_L                                   0x7F
+
+// *** HPVOLR ***
+#define FB_HPVOLR_HPVOL_R                                   0
+#define FM_HPVOLR_HPVOL_R                                   0x7F
+
+// *** SPKVOLL ***
+#define FB_SPKVOLL_SPKVOL_L                                 0
+#define FM_SPKVOLL_SPKVOL_L                                 0x7F
+
+// *** SPKVOLR ***
+#define FB_SPKVOLR_SPKVOL_R                                 0
+#define FM_SPKVOLR_SPKVOL_R                                 0x7F
+
+// *** SUBVOL ***
+#define FB_SUBVOL_SUBVOL                                    0
+#define FM_SUBVOL_SUBVOL                                    0x7F
+
+// *** COP0 ***
+#define FB_COP0_COPATTEN                                    7
+#define FM_COP0_COPATTEN                                    0x80
+
+#define FB_COP0_COPGAIN                                     6
+#define FM_COP0_COPGAIN                                     0x40
+
+#define FB_COP0_HDELTAEN                                    5
+#define FM_COP0_HDELTAEN                                    0x20
+
+#define FB_COP0_COPTARGET                                   0
+#define FM_COP0_COPTARGET                                   0x1F
+
+// *** COP1 ***
+#define FB_COP1_HDCOMPMODE                                  6
+#define FM_COP1_HDCOMPMODE                                  0x40
+
+#define FB_COP1_AVGLENGTH                                   2
+#define FM_COP1_AVGLENGTH                                   0x3C
+
+#define FB_COP1_MONRATE                                     0
+#define FM_COP1_MONRATE                                     0x3
+
+// *** COPSTAT ***
+#define FB_COPSTAT_HDELTADET                                7
+#define FM_COPSTAT_HDELTADET                                0x80
+
+#define FB_COPSTAT_UV                                       6
+#define FM_COPSTAT_UV                                       0x40
+
+#define FB_COPSTAT_COPADJ                                   0
+#define FM_COPSTAT_COPADJ                                   0x3F
+
+// *** PWM0 ***
+#define FB_PWM0_SCTO                                        6
+#define FM_PWM0_SCTO                                        0xC0
+
+#define FB_PWM0_UVLO                                        5
+#define FM_PWM0_UVLO                                        0x20
+
+#define FB_PWM0_BFDIS                                       3
+#define FM_PWM0_BFDIS                                       0x8
+
+#define FB_PWM0_PWMMODE                                     2
+#define FM_PWM0_PWMMODE                                     0x4
+
+#define FB_PWM0_NOOFFSET                                    0
+#define FM_PWM0_NOOFFSET                                    0x1
+
+// *** PWM1 ***
+#define FB_PWM1_DITHPOS                                     4
+#define FM_PWM1_DITHPOS                                     0x70
+
+#define FB_PWM1_DYNDITH                                     1
+#define FM_PWM1_DYNDITH                                     0x2
+
+#define FB_PWM1_DITHDIS                                     0
+#define FM_PWM1_DITHDIS                                     0x1
+
+// *** PWM2 ***
+// *** PWM3 ***
+#define FB_PWM3_PWMMUX                                      6
+#define FM_PWM3_PWMMUX                                      0xC0
+
+#define FB_PWM3_CVALUE                                      0
+#define FM_PWM3_CVALUE                                      0x7
+
+// *** HPSW ***
+#define FB_HPSW_HPDETSTATE                                  4
+#define FM_HPSW_HPDETSTATE                                  0x10
+
+#define FB_HPSW_HPSWEN                                      2
+#define FM_HPSW_HPSWEN                                      0xC
+
+#define FB_HPSW_HPSWPOL                                     1
+#define FM_HPSW_HPSWPOL                                     0x2
+
+#define FB_HPSW_TSDEN                                       0
+#define FM_HPSW_TSDEN                                       0x1
+
+// *** THERMTS ***
+#define FB_THERMTS_TRIPHS                                   7
+#define FM_THERMTS_TRIPHS                                   0x80
+
+#define FB_THERMTS_TRIPLS                                   6
+#define FM_THERMTS_TRIPLS                                   0x40
+
+#define FB_THERMTS_TRIPSPLIT                                4
+#define FM_THERMTS_TRIPSPLIT                                0x30
+
+#define FB_THERMTS_TRIPSHIFT                                2
+#define FM_THERMTS_TRIPSHIFT                                0xC
+
+#define FB_THERMTS_TSPOLL                                   0
+#define FM_THERMTS_TSPOLL                                   0x3
+
+// *** THERMSPK1 ***
+#define FB_THERMSPK1_FORCEPWD                               7
+#define FM_THERMSPK1_FORCEPWD                               0x80
+
+#define FB_THERMSPK1_INSTCUTMODE                            6
+#define FM_THERMSPK1_INSTCUTMODE                            0x40
+
+#define FB_THERMSPK1_INCRATIO                               4
+#define FM_THERMSPK1_INCRATIO                               0x30
+
+#define FB_THERMSPK1_INCSTEP                                2
+#define FM_THERMSPK1_INCSTEP                                0xC
+
+#define FB_THERMSPK1_DECSTEP                                0
+#define FM_THERMSPK1_DECSTEP                                0x3
+
+// *** THERMSTAT ***
+#define FB_THERMSTAT_FPWDS                                  7
+#define FM_THERMSTAT_FPWDS                                  0x80
+
+#define FB_THERMSTAT_VOLSTAT                                0
+#define FM_THERMSTAT_VOLSTAT                                0x7F
+
+// *** SCSTAT ***
+#define FB_SCSTAT_ESDF                                      3
+#define FM_SCSTAT_ESDF                                      0x18
+
+#define FB_SCSTAT_CPF                                       2
+#define FM_SCSTAT_CPF                                       0x4
+
+#define FB_SCSTAT_CLSDF                                     0
+#define FM_SCSTAT_CLSDF                                     0x3
+
+// *** SDMON ***
+#define FB_SDMON_SDFORCE                                    7
+#define FM_SDMON_SDFORCE                                    0x80
+
+#define FB_SDMON_SDVALUE                                    0
+#define FM_SDMON_SDVALUE                                    0x1F
+
+// *** SPKEQFILT ***
+#define FB_SPKEQFILT_EQ2EN                                  7
+#define FM_SPKEQFILT_EQ2EN                                  0x80
+#define FV_EQ2EN_ENABLE                                     0x80
+#define FV_EQ2EN_DISABLE                                    0x0
+
+#define FB_SPKEQFILT_EQ2BE                                  4
+#define FM_SPKEQFILT_EQ2BE                                  0x70
+
+#define FB_SPKEQFILT_EQ1EN                                  3
+#define FM_SPKEQFILT_EQ1EN                                  0x8
+#define FV_EQ1EN_ENABLE                                     0x8
+#define FV_EQ1EN_DISABLE                                    0x0
+
+#define FB_SPKEQFILT_EQ1BE                                  0
+#define FM_SPKEQFILT_EQ1BE                                  0x7
+
+#define SPKEQFILT_EQEN_ENABLE                               0x1
+#define SPKEQFILT_EQEN_DISABLE                              0x0
+
+// *** SPKCRWDL ***
+#define FB_SPKCRWDL_WDATA_L                                 0
+#define FM_SPKCRWDL_WDATA_L                                 0xFF
+
+// *** SPKCRWDM ***
+#define FB_SPKCRWDM_WDATA_M                                 0
+#define FM_SPKCRWDM_WDATA_M                                 0xFF
+
+// *** SPKCRWDH ***
+#define FB_SPKCRWDH_WDATA_H                                 0
+#define FM_SPKCRWDH_WDATA_H                                 0xFF
+
+// *** SPKCRRDL ***
+#define FB_SPKCRRDL_RDATA_L                                 0
+#define FM_SPKCRRDL_RDATA_L                                 0xFF
+
+// *** SPKCRRDM ***
+#define FB_SPKCRRDM_RDATA_M                                 0
+#define FM_SPKCRRDM_RDATA_M                                 0xFF
+
+// *** SPKCRRDH ***
+#define FB_SPKCRRDH_RDATA_H                                 0
+#define FM_SPKCRRDH_RDATA_H                                 0xFF
+
+// *** SPKCRADD ***
+#define FB_SPKCRADD_ADDRESS                                 0
+#define FM_SPKCRADD_ADDRESS                                 0xFF
+
+// *** SPKCRS ***
+#define FB_SPKCRS_ACCSTAT                                   7
+#define FM_SPKCRS_ACCSTAT                                   0x80
+
+// *** SPKMBCEN ***
+#define FB_SPKMBCEN_MBCEN3                                  2
+#define FM_SPKMBCEN_MBCEN3                                  0x4
+#define FV_MBCEN3_ENABLE                                    0x4
+#define FV_MBCEN3_DISABLE                                   0x0
+
+#define FB_SPKMBCEN_MBCEN2                                  1
+#define FM_SPKMBCEN_MBCEN2                                  0x2
+#define FV_MBCEN2_ENABLE                                    0x2
+#define FV_MBCEN2_DISABLE                                   0x0
+
+#define FB_SPKMBCEN_MBCEN1                                  0
+#define FM_SPKMBCEN_MBCEN1                                  0x1
+#define FV_MBCEN1_ENABLE                                    0x1
+#define FV_MBCEN1_DISABLE                                   0x0
+
+#define SPKMBCEN_MBCEN_ENABLE                               0x1
+#define SPKMBCEN_MBCEN_DISABLE                              0x0
+
+// *** SPKMBCCTL ***
+#define FB_SPKMBCCTL_LVLMODE3                               5
+#define FM_SPKMBCCTL_LVLMODE3                               0x20
+
+#define FB_SPKMBCCTL_WINSEL3                                4
+#define FM_SPKMBCCTL_WINSEL3                                0x10
+
+#define FB_SPKMBCCTL_LVLMODE2                               3
+#define FM_SPKMBCCTL_LVLMODE2                               0x8
+
+#define FB_SPKMBCCTL_WINSEL2                                2
+#define FM_SPKMBCCTL_WINSEL2                                0x4
+
+#define FB_SPKMBCCTL_LVLMODE1                               1
+#define FM_SPKMBCCTL_LVLMODE1                               0x2
+
+#define FB_SPKMBCCTL_WINSEL1                                0
+#define FM_SPKMBCCTL_WINSEL1                                0x1
+
+// *** SPKCLECTL ***
+#define FB_SPKCLECTL_LVLMODE                                4
+#define FM_SPKCLECTL_LVLMODE                                0x10
+
+#define FB_SPKCLECTL_WINSEL                                 3
+#define FM_SPKCLECTL_WINSEL                                 0x8
+
+#define FB_SPKCLECTL_EXPEN                                  2
+#define FM_SPKCLECTL_EXPEN                                  0x4
+#define FV_EXPEN_ENABLE                                     0x4
+#define FV_EXPEN_DISABLE                                    0x0
+
+#define FB_SPKCLECTL_LIMEN                                  1
+#define FM_SPKCLECTL_LIMEN                                  0x2
+#define FV_LIMEN_ENABLE                                     0x2
+#define FV_LIMEN_DISABLE                                    0x0
+
+#define FB_SPKCLECTL_COMPEN                                 0
+#define FM_SPKCLECTL_COMPEN                                 0x1
+#define FV_COMPEN_ENABLE                                    0x1
+#define FV_COMPEN_DISABLE                                   0x0
+
+// *** SPKCLEMUG ***
+#define FB_SPKCLEMUG_MUGAIN                                 0
+#define FM_SPKCLEMUG_MUGAIN                                 0x1F
+
+// *** SPKCOMPTHR ***
+#define FB_SPKCOMPTHR_THRESH                                0
+#define FM_SPKCOMPTHR_THRESH                                0xFF
+
+// *** SPKCOMPRAT ***
+#define FB_SPKCOMPRAT_RATIO                                 0
+#define FM_SPKCOMPRAT_RATIO                                 0x1F
+
+// *** SPKCOMPATKL ***
+#define FB_SPKCOMPATKL_TCATKL                               0
+#define FM_SPKCOMPATKL_TCATKL                               0xFF
+
+// *** SPKCOMPATKH ***
+#define FB_SPKCOMPATKH_TCATKH                               0
+#define FM_SPKCOMPATKH_TCATKH                               0xFF
+
+// *** SPKCOMPRELL ***
+#define FB_SPKCOMPRELL_TCRELL                               0
+#define FM_SPKCOMPRELL_TCRELL                               0xFF
+
+// *** SPKCOMPRELH ***
+#define FB_SPKCOMPRELH_TCRELH                               0
+#define FM_SPKCOMPRELH_TCRELH                               0xFF
+
+// *** SPKLIMTHR ***
+#define FB_SPKLIMTHR_THRESH                                 0
+#define FM_SPKLIMTHR_THRESH                                 0xFF
+
+// *** SPKLIMTGT ***
+#define FB_SPKLIMTGT_TARGET                                 0
+#define FM_SPKLIMTGT_TARGET                                 0xFF
+
+// *** SPKLIMATKL ***
+#define FB_SPKLIMATKL_TCATKL                                0
+#define FM_SPKLIMATKL_TCATKL                                0xFF
+
+// *** SPKLIMATKH ***
+#define FB_SPKLIMATKH_TCATKH                                0
+#define FM_SPKLIMATKH_TCATKH                                0xFF
+
+// *** SPKLIMRELL ***
+#define FB_SPKLIMRELL_TCRELL                                0
+#define FM_SPKLIMRELL_TCRELL                                0xFF
+
+// *** SPKLIMRELH ***
+#define FB_SPKLIMRELH_TCRELH                                0
+#define FM_SPKLIMRELH_TCRELH                                0xFF
+
+// *** SPKEXPTHR ***
+#define FB_SPKEXPTHR_THRESH                                 0
+#define FM_SPKEXPTHR_THRESH                                 0xFF
+
+// *** SPKEXPRAT ***
+#define FB_SPKEXPRAT_RATIO                                  0
+#define FM_SPKEXPRAT_RATIO                                  0x7
+
+// *** SPKEXPATKL ***
+#define FB_SPKEXPATKL_TCATKL                                0
+#define FM_SPKEXPATKL_TCATKL                                0xFF
+
+// *** SPKEXPATKH ***
+#define FB_SPKEXPATKH_TCATKH                                0
+#define FM_SPKEXPATKH_TCATKH                                0xFF
+
+// *** SPKEXPRELL ***
+#define FB_SPKEXPRELL_TCRELL                                0
+#define FM_SPKEXPRELL_TCRELL                                0xFF
+
+// *** SPKEXPRELH ***
+#define FB_SPKEXPRELH_TCRELH                                0
+#define FM_SPKEXPRELH_TCRELH                                0xFF
+
+// *** SPKFXCTL ***
+#define FB_SPKFXCTL_3DEN                                    4
+#define FM_SPKFXCTL_3DEN                                    0x10
+
+#define FB_SPKFXCTL_TEEN                                    3
+#define FM_SPKFXCTL_TEEN                                    0x8
+
+#define FB_SPKFXCTL_TNLFBYP                                 2
+#define FM_SPKFXCTL_TNLFBYP                                 0x4
+
+#define FB_SPKFXCTL_BEEN                                    1
+#define FM_SPKFXCTL_BEEN                                    0x2
+
+#define FB_SPKFXCTL_BNLFBYP                                 0
+#define FM_SPKFXCTL_BNLFBYP                                 0x1
+
+// *** DACEQFILT ***
+#define FB_DACEQFILT_EQ2EN                                  7
+#define FM_DACEQFILT_EQ2EN                                  0x80
+#define FV_EQ2EN_ENABLE                                     0x80
+#define FV_EQ2EN_DISABLE                                    0x0
+
+#define FB_DACEQFILT_EQ2BE                                  4
+#define FM_DACEQFILT_EQ2BE                                  0x70
+
+#define FB_DACEQFILT_EQ1EN                                  3
+#define FM_DACEQFILT_EQ1EN                                  0x8
+#define FV_EQ1EN_ENABLE                                     0x8
+#define FV_EQ1EN_DISABLE                                    0x0
+
+#define FB_DACEQFILT_EQ1BE                                  0
+#define FM_DACEQFILT_EQ1BE                                  0x7
+
+#define DACEQFILT_EQEN_ENABLE                               0x1
+#define DACEQFILT_EQEN_DISABLE                              0x0
+
+// *** DACCRWDL ***
+#define FB_DACCRWDL_WDATA_L                                 0
+#define FM_DACCRWDL_WDATA_L                                 0xFF
+
+// *** DACCRWDM ***
+#define FB_DACCRWDM_WDATA_M                                 0
+#define FM_DACCRWDM_WDATA_M                                 0xFF
+
+// *** DACCRWDH ***
+#define FB_DACCRWDH_WDATA_H                                 0
+#define FM_DACCRWDH_WDATA_H                                 0xFF
+
+// *** DACCRRDL ***
+#define FB_DACCRRDL_RDATA_L                                 0
+#define FM_DACCRRDL_RDATA_L                                 0xFF
+
+// *** DACCRRDM ***
+#define FB_DACCRRDM_RDATA_M                                 0
+#define FM_DACCRRDM_RDATA_M                                 0xFF
+
+// *** DACCRRDH ***
+#define FB_DACCRRDH_RDATA_H                                 0
+#define FM_DACCRRDH_RDATA_H                                 0xFF
+
+// *** DACCRADD ***
+#define FB_DACCRADD_ADDRESS                                 0
+#define FM_DACCRADD_ADDRESS                                 0xFF
+
+// *** DACCRS ***
+#define FB_DACCRS_ACCSTAT                                   7
+#define FM_DACCRS_ACCSTAT                                   0x80
+
+// *** DACMBCEN ***
+#define FB_DACMBCEN_MBCEN3                                  2
+#define FM_DACMBCEN_MBCEN3                                  0x4
+#define FV_MBCEN3_ENABLE                                    0x4
+#define FV_MBCEN3_DISABLE                                   0x0
+
+#define FB_DACMBCEN_MBCEN2                                  1
+#define FM_DACMBCEN_MBCEN2                                  0x2
+#define FV_MBCEN2_ENABLE                                    0x2
+#define FV_MBCEN2_DISABLE                                   0x0
+
+#define FB_DACMBCEN_MBCEN1                                  0
+#define FM_DACMBCEN_MBCEN1                                  0x1
+#define FV_MBCEN1_ENABLE                                    0x1
+#define FV_MBCEN1_DISABLE                                   0x0
+
+#define DACMBCEN_MBCEN_ENABLE                               0x1
+#define DACMBCEN_MBCEN_DISABLE                              0x0
+
+// *** DACMBCCTL ***
+#define FB_DACMBCCTL_LVLMODE3                               5
+#define FM_DACMBCCTL_LVLMODE3                               0x20
+
+#define FB_DACMBCCTL_WINSEL3                                4
+#define FM_DACMBCCTL_WINSEL3                                0x10
+
+#define FB_DACMBCCTL_LVLMODE2                               3
+#define FM_DACMBCCTL_LVLMODE2                               0x8
+
+#define FB_DACMBCCTL_WINSEL2                                2
+#define FM_DACMBCCTL_WINSEL2                                0x4
+
+#define FB_DACMBCCTL_LVLMODE1                               1
+#define FM_DACMBCCTL_LVLMODE1                               0x2
+
+#define FB_DACMBCCTL_WINSEL1                                0
+#define FM_DACMBCCTL_WINSEL1                                0x1
+
+// *** DACCLECTL ***
+#define FB_DACCLECTL_LVLMODE                                4
+#define FM_DACCLECTL_LVLMODE                                0x10
+
+#define FB_DACCLECTL_WINSEL                                 3
+#define FM_DACCLECTL_WINSEL                                 0x8
+
+#define FB_DACCLECTL_EXPEN                                  2
+#define FM_DACCLECTL_EXPEN                                  0x4
+#define FV_EXPEN_ENABLE                                     0x4
+#define FV_EXPEN_DISABLE                                    0x0
+
+#define FB_DACCLECTL_LIMEN                                  1
+#define FM_DACCLECTL_LIMEN                                  0x2
+#define FV_LIMEN_ENABLE                                     0x2
+#define FV_LIMEN_DISABLE                                    0x0
+
+#define FB_DACCLECTL_COMPEN                                 0
+#define FM_DACCLECTL_COMPEN                                 0x1
+#define FV_COMPEN_ENABLE                                    0x1
+#define FV_COMPEN_DISABLE                                   0x0
+
+// *** DACCLEMUG ***
+#define FB_DACCLEMUG_MUGAIN                                 0
+#define FM_DACCLEMUG_MUGAIN                                 0x1F
+
+// *** DACCOMPTHR ***
+#define FB_DACCOMPTHR_THRESH                                0
+#define FM_DACCOMPTHR_THRESH                                0xFF
+
+// *** DACCOMPRAT ***
+#define FB_DACCOMPRAT_RATIO                                 0
+#define FM_DACCOMPRAT_RATIO                                 0x1F
+
+// *** DACCOMPATKL ***
+#define FB_DACCOMPATKL_TCATKL                               0
+#define FM_DACCOMPATKL_TCATKL                               0xFF
+
+// *** DACCOMPATKH ***
+#define FB_DACCOMPATKH_TCATKH                               0
+#define FM_DACCOMPATKH_TCATKH                               0xFF
+
+// *** DACCOMPRELL ***
+#define FB_DACCOMPRELL_TCRELL                               0
+#define FM_DACCOMPRELL_TCRELL                               0xFF
+
+// *** DACCOMPRELH ***
+#define FB_DACCOMPRELH_TCRELH                               0
+#define FM_DACCOMPRELH_TCRELH                               0xFF
+
+// *** DACLIMTHR ***
+#define FB_DACLIMTHR_THRESH                                 0
+#define FM_DACLIMTHR_THRESH                                 0xFF
+
+// *** DACLIMTGT ***
+#define FB_DACLIMTGT_TARGET                                 0
+#define FM_DACLIMTGT_TARGET                                 0xFF
+
+// *** DACLIMATKL ***
+#define FB_DACLIMATKL_TCATKL                                0
+#define FM_DACLIMATKL_TCATKL                                0xFF
+
+// *** DACLIMATKH ***
+#define FB_DACLIMATKH_TCATKH                                0
+#define FM_DACLIMATKH_TCATKH                                0xFF
+
+// *** DACLIMRELL ***
+#define FB_DACLIMRELL_TCRELL                                0
+#define FM_DACLIMRELL_TCRELL                                0xFF
+
+// *** DACLIMRELH ***
+#define FB_DACLIMRELH_TCRELH                                0
+#define FM_DACLIMRELH_TCRELH                                0xFF
+
+// *** DACEXPTHR ***
+#define FB_DACEXPTHR_THRESH                                 0
+#define FM_DACEXPTHR_THRESH                                 0xFF
+
+// *** DACEXPRAT ***
+#define FB_DACEXPRAT_RATIO                                  0
+#define FM_DACEXPRAT_RATIO                                  0x7
+
+// *** DACEXPATKL ***
+#define FB_DACEXPATKL_TCATKL                                0
+#define FM_DACEXPATKL_TCATKL                                0xFF
+
+// *** DACEXPATKH ***
+#define FB_DACEXPATKH_TCATKH                                0
+#define FM_DACEXPATKH_TCATKH                                0xFF
+
+// *** DACEXPRELL ***
+#define FB_DACEXPRELL_TCRELL                                0
+#define FM_DACEXPRELL_TCRELL                                0xFF
+
+// *** DACEXPRELH ***
+#define FB_DACEXPRELH_TCRELH                                0
+#define FM_DACEXPRELH_TCRELH                                0xFF
+
+// *** DACFXCTL ***
+#define FB_DACFXCTL_3DEN                                    4
+#define FM_DACFXCTL_3DEN                                    0x10
+
+#define FB_DACFXCTL_TEEN                                    3
+#define FM_DACFXCTL_TEEN                                    0x8
+
+#define FB_DACFXCTL_TNLFBYP                                 2
+#define FM_DACFXCTL_TNLFBYP                                 0x4
+
+#define FB_DACFXCTL_BEEN                                    1
+#define FM_DACFXCTL_BEEN                                    0x2
+
+#define FB_DACFXCTL_BNLFBYP                                 0
+#define FM_DACFXCTL_BNLFBYP                                 0x1
+
+// *** SUBEQFILT ***
+#define FB_SUBEQFILT_EQ2EN                                  7
+#define FM_SUBEQFILT_EQ2EN                                  0x80
+#define FV_EQ2EN_ENABLE                                     0x80
+#define FV_EQ2EN_DISABLE                                    0x0
+
+#define FB_SUBEQFILT_EQ2BE                                  4
+#define FM_SUBEQFILT_EQ2BE                                  0x70
+
+#define FB_SUBEQFILT_EQ1EN                                  3
+#define FM_SUBEQFILT_EQ1EN                                  0x8
+#define FV_EQ1EN_ENABLE                                     0x8
+#define FV_EQ1EN_DISABLE                                    0x0
+
+#define FB_SUBEQFILT_EQ1BE                                  0
+#define FM_SUBEQFILT_EQ1BE                                  0x7
+
+#define SUBEQFILT_EQEN_ENABLE                               0x1
+#define SUBEQFILT_EQEN_DISABLE                              0x0
+
+// *** SUBCRWDL ***
+#define FB_SUBCRWDL_WDATA_L                                 0
+#define FM_SUBCRWDL_WDATA_L                                 0xFF
+
+// *** SUBCRWDM ***
+#define FB_SUBCRWDM_WDATA_M                                 0
+#define FM_SUBCRWDM_WDATA_M                                 0xFF
+
+// *** SUBCRWDH ***
+#define FB_SUBCRWDH_WDATA_H                                 0
+#define FM_SUBCRWDH_WDATA_H                                 0xFF
+
+// *** SUBCRRDL ***
+#define FB_SUBCRRDL_RDATA_L                                 0
+#define FM_SUBCRRDL_RDATA_L                                 0xFF
+
+// *** SUBCRRDM ***
+#define FB_SUBCRRDM_RDATA_M                                 0
+#define FM_SUBCRRDM_RDATA_M                                 0xFF
+
+// *** SUBCRRDH ***
+#define FB_SUBCRRDH_RDATA_H                                 0
+#define FM_SUBCRRDH_RDATA_H                                 0xFF
+
+// *** SUBCRADD ***
+#define FB_SUBCRADD_ADDRESS                                 0
+#define FM_SUBCRADD_ADDRESS                                 0xFF
+
+// *** SUBCRS ***
+#define FB_SUBCRS_ACCSTAT                                   7
+#define FM_SUBCRS_ACCSTAT                                   0x80
+
+// *** SUBMBCEN ***
+#define FB_SUBMBCEN_MBCEN3                                  2
+#define FM_SUBMBCEN_MBCEN3                                  0x4
+#define FV_MBCEN3_ENABLE                                    0x4
+#define FV_MBCEN3_DISABLE                                   0x0
+
+#define FB_SUBMBCEN_MBCEN2                                  1
+#define FM_SUBMBCEN_MBCEN2                                  0x2
+#define FV_MBCEN2_ENABLE                                    0x2
+#define FV_MBCEN2_DISABLE                                   0x0
+
+#define FB_SUBMBCEN_MBCEN1                                  0
+#define FM_SUBMBCEN_MBCEN1                                  0x1
+#define FV_MBCEN1_ENABLE                                    0x1
+#define FV_MBCEN1_DISABLE                                   0x0
+
+#define SUBMBCEN_MBCEN_ENABLE                               0x1
+#define SUBMBCEN_MBCEN_DISABLE                              0x0
+
+// *** SUBMBCCTL ***
+#define FB_SUBMBCCTL_LVLMODE3                               5
+#define FM_SUBMBCCTL_LVLMODE3                               0x20
+
+#define FB_SUBMBCCTL_WINSEL3                                4
+#define FM_SUBMBCCTL_WINSEL3                                0x10
+
+#define FB_SUBMBCCTL_LVLMODE2                               3
+#define FM_SUBMBCCTL_LVLMODE2                               0x8
+
+#define FB_SUBMBCCTL_WINSEL2                                2
+#define FM_SUBMBCCTL_WINSEL2                                0x4
+
+#define FB_SUBMBCCTL_LVLMODE1                               1
+#define FM_SUBMBCCTL_LVLMODE1                               0x2
+
+#define FB_SUBMBCCTL_WINSEL1                                0
+#define FM_SUBMBCCTL_WINSEL1                                0x1
+
+// *** SUBCLECTL ***
+#define FB_SUBCLECTL_LVLMODE                                4
+#define FM_SUBCLECTL_LVLMODE                                0x10
+
+#define FB_SUBCLECTL_WINSEL                                 3
+#define FM_SUBCLECTL_WINSEL                                 0x8
+
+#define FB_SUBCLECTL_EXPEN                                  2
+#define FM_SUBCLECTL_EXPEN                                  0x4
+#define FV_EXPEN_ENABLE                                     0x4
+#define FV_EXPEN_DISABLE                                    0x0
+
+#define FB_SUBCLECTL_LIMEN                                  1
+#define FM_SUBCLECTL_LIMEN                                  0x2
+#define FV_LIMEN_ENABLE                                     0x2
+#define FV_LIMEN_DISABLE                                    0x0
+
+#define FB_SUBCLECTL_COMPEN                                 0
+#define FM_SUBCLECTL_COMPEN                                 0x1
+#define FV_COMPEN_ENABLE                                    0x1
+#define FV_COMPEN_DISABLE                                   0x0
+
+// *** SUBCLEMUG ***
+#define FB_SUBCLEMUG_MUGAIN                                 0
+#define FM_SUBCLEMUG_MUGAIN                                 0x1F
+
+// *** SUBCOMPTHR ***
+#define FB_SUBCOMPTHR_THRESH                                0
+#define FM_SUBCOMPTHR_THRESH                                0xFF
+
+// *** SUBCOMPRAT ***
+#define FB_SUBCOMPRAT_RATIO                                 0
+#define FM_SUBCOMPRAT_RATIO                                 0x1F
+
+// *** SUBCOMPATKL ***
+#define FB_SUBCOMPATKL_TCATKL                               0
+#define FM_SUBCOMPATKL_TCATKL                               0xFF
+
+// *** SUBCOMPATKH ***
+#define FB_SUBCOMPATKH_TCATKH                               0
+#define FM_SUBCOMPATKH_TCATKH                               0xFF
+
+// *** SUBCOMPRELL ***
+#define FB_SUBCOMPRELL_TCRELL                               0
+#define FM_SUBCOMPRELL_TCRELL                               0xFF
+
+// *** SUBCOMPRELH ***
+#define FB_SUBCOMPRELH_TCRELH                               0
+#define FM_SUBCOMPRELH_TCRELH                               0xFF
+
+// *** SUBLIMTHR ***
+#define FB_SUBLIMTHR_THRESH                                 0
+#define FM_SUBLIMTHR_THRESH                                 0xFF
+
+// *** SUBLIMTGT ***
+#define FB_SUBLIMTGT_TARGET                                 0
+#define FM_SUBLIMTGT_TARGET                                 0xFF
+
+// *** SUBLIMATKL ***
+#define FB_SUBLIMATKL_TCATKL                                0
+#define FM_SUBLIMATKL_TCATKL                                0xFF
+
+// *** SUBLIMATKH ***
+#define FB_SUBLIMATKH_TCATKH                                0
+#define FM_SUBLIMATKH_TCATKH                                0xFF
+
+// *** SUBLIMRELL ***
+#define FB_SUBLIMRELL_TCRELL                                0
+#define FM_SUBLIMRELL_TCRELL                                0xFF
+
+// *** SUBLIMRELH ***
+#define FB_SUBLIMRELH_TCRELH                                0
+#define FM_SUBLIMRELH_TCRELH                                0xFF
+
+// *** SUBEXPTHR ***
+#define FB_SUBEXPTHR_THRESH                                 0
+#define FM_SUBEXPTHR_THRESH                                 0xFF
+
+// *** SUBEXPRAT ***
+#define FB_SUBEXPRAT_RATIO                                  0
+#define FM_SUBEXPRAT_RATIO                                  0x7
+
+// *** SUBEXPATKL ***
+#define FB_SUBEXPATKL_TCATKL                                0
+#define FM_SUBEXPATKL_TCATKL                                0xFF
+
+// *** SUBEXPATKH ***
+#define FB_SUBEXPATKH_TCATKH                                0
+#define FM_SUBEXPATKH_TCATKH                                0xFF
+
+// *** SUBEXPRELL ***
+#define FB_SUBEXPRELL_TCRELL                                0
+#define FM_SUBEXPRELL_TCRELL                                0xFF
+
+// *** SUBEXPRELH ***
+#define FB_SUBEXPRELH_TCRELH                                0
+#define FM_SUBEXPRELH_TCRELH                                0xFF
+
+// *** SUBFXCTL ***
+#define FB_SUBFXCTL_TEEN                                    3
+#define FM_SUBFXCTL_TEEN                                    0x8
+
+#define FB_SUBFXCTL_TNLFBYP                                 2
+#define FM_SUBFXCTL_TNLFBYP                                 0x4
+
+#define FB_SUBFXCTL_BEEN                                    1
+#define FM_SUBFXCTL_BEEN                                    0x2
+
+#define FB_SUBFXCTL_BNLFBYP                                 0
+#define FM_SUBFXCTL_BNLFBYP                                 0x1
+
+#endif /* __REDWOODPUBLIC_H__ */
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index d5f4bbf27182..3663b9fd4d65 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1155,8 +1155,8 @@ SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_3L,
 SND_SOC_BYTES_MASK("EQL Coefficients", WM2200_EQL_1, 20, WM2200_EQL_ENA),
 SND_SOC_BYTES_MASK("EQR Coefficients", WM2200_EQR_1, 20, WM2200_EQR_ENA),
 
-SND_SOC_BYTES("LHPF1 Coefficeints", WM2200_HPLPF1_2, 1),
-SND_SOC_BYTES("LHPF2 Coefficeints", WM2200_HPLPF2_2, 1),
+SND_SOC_BYTES("LHPF1 Coefficients", WM2200_HPLPF1_2, 1),
+SND_SOC_BYTES("LHPF2 Coefficients", WM2200_HPLPF2_2, 1),
 
 SOC_SINGLE("OUT1 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
 	   WM2200_OUT1_OSR_SHIFT, 1, 0),
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 87f9a99ce978..ba89d9d711f7 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -573,10 +573,10 @@ SND_SOC_BYTES_MASK("EQ4 Coefficients", WM5100_EQ4_1, 20, WM5100_EQ4_ENA),
 SND_SOC_BYTES_MASK("DRC Coefficients", WM5100_DRC1_CTRL1, 5,
 		   WM5100_DRCL_ENA | WM5100_DRCR_ENA),
 
-SND_SOC_BYTES("LHPF1 Coefficeints", WM5100_HPLPF1_2, 1),
-SND_SOC_BYTES("LHPF2 Coefficeints", WM5100_HPLPF2_2, 1),
-SND_SOC_BYTES("LHPF3 Coefficeints", WM5100_HPLPF3_2, 1),
-SND_SOC_BYTES("LHPF4 Coefficeints", WM5100_HPLPF4_2, 1),
+SND_SOC_BYTES("LHPF1 Coefficients", WM5100_HPLPF1_2, 1),
+SND_SOC_BYTES("LHPF2 Coefficients", WM5100_HPLPF2_2, 1),
+SND_SOC_BYTES("LHPF3 Coefficients", WM5100_HPLPF3_2, 1),
+SND_SOC_BYTES("LHPF4 Coefficients", WM5100_HPLPF4_2, 1),
 
 SOC_SINGLE("HPOUT1 High Performance Switch", WM5100_OUT_VOLUME_1L,
 	   WM5100_OUT1_OSR_SHIFT, 1, 0),
diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c
index 7949703f3d04..317db9a149a7 100644
--- a/sound/soc/codecs/wm8782.c
+++ b/sound/soc/codecs/wm8782.c
@@ -67,9 +67,18 @@ static int wm8782_probe(struct platform_device *pdev)
 			&soc_component_dev_wm8782, &wm8782_dai, 1);
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id wm8782_of_match[] = {
+	{ .compatible = "wlf,wm8782", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8782_of_match);
+#endif
+
 static struct platform_driver wm8782_codec_driver = {
 	.driver = {
 		.name = "wm8782",
+		.of_match_table = of_match_ptr(wm8782_of_match),
 	},
 	.probe = wm8782_probe,
 };
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 20fdcae06c6b..f13ef334c0d7 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -596,7 +596,7 @@ static const struct snd_kcontrol_new wm8904_adc_snd_controls[] = {
 SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8904_ADC_DIGITAL_VOLUME_LEFT,
 		 WM8904_ADC_DIGITAL_VOLUME_RIGHT, 1, 119, 0, digital_tlv),
 
-SOC_ENUM("Left Caputure Mode", lin_mode),
+SOC_ENUM("Left Capture Mode", lin_mode),
 SOC_ENUM("Right Capture Mode", rin_mode),
 
 /* No TLV since it depends on mode */
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 82b0927e6ed7..2175dccdf388 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -627,22 +627,21 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
 	if (!root)
 		goto err;
 
-	if (!debugfs_create_bool("booted", S_IRUGO, root, &dsp->booted))
+	if (!debugfs_create_bool("booted", 0444, root, &dsp->booted))
 		goto err;
 
-	if (!debugfs_create_bool("running", S_IRUGO, root, &dsp->running))
+	if (!debugfs_create_bool("running", 0444, root, &dsp->running))
 		goto err;
 
-	if (!debugfs_create_x32("fw_id", S_IRUGO, root, &dsp->fw_id))
+	if (!debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id))
 		goto err;
 
-	if (!debugfs_create_x32("fw_version", S_IRUGO, root,
-				&dsp->fw_id_version))
+	if (!debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version))
 		goto err;
 
 	for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) {
 		if (!debugfs_create_file(wm_adsp_debugfs_fops[i].name,
-					 S_IRUGO, root, dsp,
+					 0444, root, dsp,
 					 &wm_adsp_debugfs_fops[i].fops))
 			goto err;
 	}
@@ -2666,9 +2665,9 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
 	dsp->preloaded = ucontrol->value.integer.value[0];
 
 	if (ucontrol->value.integer.value[0])
-		snd_soc_dapm_force_enable_pin(dapm, preload);
+		snd_soc_component_force_enable_pin(component, preload);
 	else
-		snd_soc_dapm_disable_pin(dapm, preload);
+		snd_soc_component_disable_pin(component, preload);
 
 	snd_soc_dapm_sync(dapm);
 
@@ -2852,11 +2851,11 @@ EXPORT_SYMBOL_GPL(wm_adsp2_event);
 
 int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	char preload[32];
 
 	snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", dsp->num);
-	snd_soc_dapm_disable_pin(dapm, preload);
+
+	snd_soc_component_disable_pin(component, preload);
 
 	wm_adsp2_init_debugfs(dsp, component);
 
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index 6b732d8e5896..778faff28e0e 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -24,7 +24,7 @@ config SND_DAVINCI_SOC_I2S
 
 config SND_DAVINCI_SOC_MCASP
 	tristate "Multichannel Audio Serial Port (McASP) support"
-	depends on SND_OMAP_SOC || SND_EDMA_SOC
+	depends on SND_SDMA_SOC || SND_EDMA_SOC
 	help
 	  Say Y or M here if you want to have support for McASP IP found in
 	  various Texas Instruments SoCs like:
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 03ba218160ca..1f96c9dbe9c4 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -36,9 +36,9 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
-#include <sound/omap-pcm.h>
 
 #include "edma-pcm.h"
+#include "../omap/sdma-pcm.h"
 #include "davinci-mcasp.h"
 
 #define MCASP_MAX_AFIFO_DEPTH	64
@@ -789,7 +789,7 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
 					rx_ser < max_active_serializers) {
 			mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
 			rx_ser++;
-		} else {
+		} else if (mcasp->serial_dir[i] == INACTIVE_MODE) {
 			mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
 				       SRMOD_INACTIVE, SRMOD_MASK);
 		}
@@ -2048,10 +2048,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 #endif
 		break;
 	case PCM_SDMA:
-#if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \
+#if IS_BUILTIN(CONFIG_SND_SDMA_SOC) || \
 	(IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
-	 IS_MODULE(CONFIG_SND_OMAP_SOC))
-		ret = omap_pcm_platform_register(&pdev->dev);
+	 IS_MODULE(CONFIG_SND_SDMA_SOC))
+		ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
 #else
 		dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n");
 		ret = -EINVAL;
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index da8fd98c7f51..8f43110373b8 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -1,12 +1,8 @@
-/*
- * Freescale ESAI ALSA SoC Digital Audio Interface (DAI) driver
- *
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale ESAI ALSA SoC Digital Audio Interface (DAI) driver
+//
+// Copyright (C) 2014 Freescale Semiconductor, Inc.
 
 #include <linux/clk.h>
 #include <linux/dmaengine.h>
@@ -226,6 +222,12 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 	unsigned long clk_rate;
 	int ret;
 
+	if (freq == 0) {
+		dev_err(dai->dev, "%sput freq of HCK%c should not be 0Hz\n",
+			in ? "in" : "out", tx ? 'T' : 'R');
+		return -EINVAL;
+	}
+
 	/* Bypass divider settings if the requirement doesn't change */
 	if (freq == esai_priv->hck_rate[tx] && dir == esai_priv->hck_dir[tx])
 		return 0;
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h
index 5e793bbb6b02..f873588d9045 100644
--- a/sound/soc/fsl/fsl_esai.h
+++ b/sound/soc/fsl/fsl_esai.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * fsl_esai.h - ALSA ESAI interface for the Freescale i.MX SoC
  *
  * Copyright (C) 2014 Freescale Semiconductor, Inc.
  *
  * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
  */
 
 #ifndef _FSL_ESAI_DAI_H
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 18e5ce81527d..4163f2cfc06f 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -1,14 +1,8 @@
-/*
- * Freescale ALSA SoC Digital Audio Interface (SAI) driver.
- *
- * Copyright 2012-2015 Freescale Semiconductor, Inc.
- *
- * This program is free software, you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation, either version 2 of the License, or(at your
- * option) any later version.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Freescale ALSA SoC Digital Audio Interface (SAI) driver.
+//
+// Copyright 2012-2015 Freescale Semiconductor, Inc.
 
 #include <linux/clk.h>
 #include <linux/delay.h>
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index d9ed7be8cb34..24cb156bf995 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright 2012-2013 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __FSL_SAI_H
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 4f7469c1864c..9b59d87b61bf 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -1,17 +1,13 @@
-/*
- * Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver
- *
- * Copyright (C) 2013 Freescale Semiconductor, Inc.
- *
- * Based on stmp3xxx_spdif_dai.c
- * Vladimir Barinov <vbarinov@embeddedalley.com>
- * Copyright 2008 SigmaTel, Inc
- * Copyright 2008 Embedded Alley Solutions, Inc
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program  is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver
+//
+// Copyright (C) 2013 Freescale Semiconductor, Inc.
+//
+// Based on stmp3xxx_spdif_dai.c
+// Vladimir Barinov <vbarinov@embeddedalley.com>
+// Copyright 2008 SigmaTel, Inc
+// Copyright 2008 Embedded Alley Solutions, Inc
 
 #include <linux/bitrev.h>
 #include <linux/clk.h>
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h
index 00bd3514c610..7666dabaccfd 100644
--- a/sound/soc/fsl/fsl_spdif.h
+++ b/sound/soc/fsl/fsl_spdif.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * fsl_spdif.h - ALSA S/PDIF interface for the Freescale i.MX SoC
  *
@@ -8,10 +9,6 @@
  * Based on fsl_ssi.h
  * Author: Timur Tabi <timur@freescale.com>
  * Copyright 2007-2008 Freescale Semiconductor, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program  is licensed "as is" without any warranty of any
- * kind, whether express or implied.
  */
 
 #ifndef _FSL_SPDIF_DAI_H
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 89df2d9f63d7..0a648229e643 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1,34 +1,29 @@
-/*
- * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
- *
- * Author: Timur Tabi <timur@freescale.com>
- *
- * Copyright 2007-2010 Freescale Semiconductor, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- *
- * Some notes why imx-pcm-fiq is used instead of DMA on some boards:
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
+//
+// Author: Timur Tabi <timur@freescale.com>
+//
+// Copyright 2007-2010 Freescale Semiconductor, Inc.
+//
+// Some notes why imx-pcm-fiq is used instead of DMA on some boards:
+//
+// 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/init.h>
 #include <linux/io.h>
@@ -385,8 +380,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
 {
 	struct fsl_ssi *ssi = dev_id;
 	struct regmap *regs = ssi->regs;
-	__be32 sisr;
-	__be32 sisr2;
+	u32 sisr, sisr2;
 
 	regmap_read(regs, REG_SSI_SISR, &sisr);
 
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index 18f8dd5209d5..0bdda608d414 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -1,12 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * fsl_ssi.h - ALSA SSI interface for the Freescale MPC8610 and i.MX SoC
  *
  * Author: Timur Tabi <timur@freescale.com>
  *
- * Copyright 2007-2008 Freescale Semiconductor, Inc.  This file is licensed
- * under the terms of the GNU General Public License version 2.  This
- * program is licensed "as is" without any warranty of any kind, whether
- * express or implied.
+ * Copyright 2007-2008 Freescale Semiconductor, Inc.
  */
 
 #ifndef _MPC8610_I2S_H
diff --git a/sound/soc/fsl/fsl_ssi_dbg.c b/sound/soc/fsl/fsl_ssi_dbg.c
index 7aac63e2c561..1255dfe19eef 100644
--- a/sound/soc/fsl/fsl_ssi_dbg.c
+++ b/sound/soc/fsl/fsl_ssi_dbg.c
@@ -1,14 +1,10 @@
-/*
- * Freescale SSI ALSA SoC Digital Audio Interface (DAI) debugging functions
- *
- * Copyright 2014 Markus Pargmann <mpa@pengutronix.de>, Pengutronix
- *
- * Splitted from fsl_ssi.c
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale SSI ALSA SoC Digital Audio Interface (DAI) debugging functions
+//
+// Copyright 2014 Markus Pargmann <mpa@pengutronix.de>, Pengutronix
+//
+// Split from fsl_ssi.c
 
 #include <linux/debugfs.h>
 #include <linux/device.h>
@@ -146,7 +142,7 @@ int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
 	if (!ssi_dbg->dbg_dir)
 		return -ENOMEM;
 
-	ssi_dbg->dbg_stats = debugfs_create_file("stats", S_IRUGO,
+	ssi_dbg->dbg_stats = debugfs_create_file("stats", 0444,
 						 ssi_dbg->dbg_dir, ssi_dbg,
 						 &fsl_ssi_stats_ops);
 	if (!ssi_dbg->dbg_stats) {
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 6959a74a6f49..4a516c428b3d 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -135,6 +135,18 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
 	asoc_simple_card_clk_disable(&dai_props->codec_dai);
 }
 
+static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
+				    unsigned long rate)
+{
+	if (!simple_dai->clk)
+		return 0;
+
+	if (clk_get_rate(simple_dai->clk) == rate)
+		return 0;
+
+	return clk_set_rate(simple_dai->clk, rate);
+}
+
 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
 				      struct snd_pcm_hw_params *params)
 {
@@ -154,6 +166,15 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
 
 	if (mclk_fs) {
 		mclk = params_rate(params) * mclk_fs;
+
+		ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk);
+		if (ret < 0)
+			return ret;
+
+		ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk);
+		if (ret < 0)
+			return ret;
+
 		ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
 					     SND_SOC_CLOCK_IN);
 		if (ret && ret != -ENOTSUPP)
diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c
index 07a57209e055..53344a3b7a60 100644
--- a/sound/soc/hisilicon/hi6210-i2s.c
+++ b/sound/soc/hisilicon/hi6210-i2s.c
@@ -498,7 +498,7 @@ static int hi6210_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 			hi6210_i2s_txctrl(cpu_dai, 0);
 		break;
 	default:
-		dev_err(cpu_dai->dev, "uknown cmd\n");
+		dev_err(cpu_dai->dev, "unknown cmd\n");
 		return -EINVAL;
 	}
 	return 0;
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index addac2a8e52a..0caa1f4eb94d 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -61,7 +61,7 @@ config SND_SOC_INTEL_HASWELL
 
 config SND_SOC_INTEL_BAYTRAIL
 	tristate "Baytrail (legacy) Platforms"
-	depends on DMADEVICES && ACPI
+	depends on DMADEVICES && ACPI && SND_SST_ATOM_HIFI2_PLATFORM=n
 	select SND_SOC_INTEL_SST
 	select SND_SOC_INTEL_SST_ACPI
 	select SND_SOC_INTEL_SST_FIRMWARE
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c
index 668c0934e942..40eb979d5ac1 100644
--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
+++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c
@@ -571,7 +571,7 @@ static int broxton_audio_probe(struct platform_device *pdev)
 {
 	struct bxt_card_private *ctx;
 
-	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c
index c7e9024e65ef..b68c289558a8 100644
--- a/sound/soc/intel/boards/bxt_rt298.c
+++ b/sound/soc/intel/boards/bxt_rt298.c
@@ -593,7 +593,7 @@ static int broxton_audio_probe(struct platform_device *pdev)
 		}
 	}
 
-	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
diff --git a/sound/soc/intel/boards/byt-max98090.c b/sound/soc/intel/boards/byt-max98090.c
index 0f8b8209c020..f1283634b22b 100644
--- a/sound/soc/intel/boards/byt-max98090.c
+++ b/sound/soc/intel/boards/byt-max98090.c
@@ -151,7 +151,7 @@ static int byt_max98090_probe(struct platform_device *pdev)
 	struct byt_max98090_private *priv;
 	int ret_val;
 
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv) {
 		dev_err(&pdev->dev, "allocation failed\n");
 		return -ENOMEM;
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
index 305e7f4fe55a..adc26dfc7d65 100644
--- a/sound/soc/intel/boards/bytcht_es8316.c
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -243,7 +243,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
 	int i;
 	int ret = 0;
 
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index a8d8bff788e7..33065ba294a9 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -17,6 +17,7 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
+#include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -25,6 +26,7 @@
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/dmi.h>
+#include <linux/input.h>
 #include <linux/slab.h>
 #include <asm/cpu_device_id.h>
 #include <asm/platform_sst_audio.h>
@@ -33,6 +35,7 @@
 #include <sound/soc.h>
 #include <sound/jack.h>
 #include <sound/soc-acpi.h>
+#include <dt-bindings/sound/rt5640.h>
 #include "../../codecs/rt5640.h"
 #include "../atom/sst-atom-controls.h"
 #include "../common/sst-dsp.h"
@@ -44,17 +47,53 @@ enum {
 	BYT_RT5640_IN3_MAP,
 };
 
-#define BYT_RT5640_MAP(quirk)	((quirk) &  GENMASK(7, 0))
-#define BYT_RT5640_DMIC_EN	BIT(16)
-#define BYT_RT5640_MONO_SPEAKER BIT(17)
-#define BYT_RT5640_DIFF_MIC     BIT(18) /* defaut is single-ended */
-#define BYT_RT5640_SSP2_AIF2    BIT(19) /* default is using AIF1  */
-#define BYT_RT5640_SSP0_AIF1    BIT(20)
-#define BYT_RT5640_SSP0_AIF2    BIT(21)
-#define BYT_RT5640_MCLK_EN	BIT(22)
-#define BYT_RT5640_MCLK_25MHZ	BIT(23)
+enum {
+	BYT_RT5640_JD_SRC_GPIO1		= (RT5640_JD_SRC_GPIO1 << 4),
+	BYT_RT5640_JD_SRC_JD1_IN4P	= (RT5640_JD_SRC_JD1_IN4P << 4),
+	BYT_RT5640_JD_SRC_JD2_IN4N	= (RT5640_JD_SRC_JD2_IN4N << 4),
+	BYT_RT5640_JD_SRC_GPIO2		= (RT5640_JD_SRC_GPIO2 << 4),
+	BYT_RT5640_JD_SRC_GPIO3		= (RT5640_JD_SRC_GPIO3 << 4),
+	BYT_RT5640_JD_SRC_GPIO4		= (RT5640_JD_SRC_GPIO4 << 4),
+};
+
+enum {
+	BYT_RT5640_OVCD_TH_600UA	= (6 << 8),
+	BYT_RT5640_OVCD_TH_1500UA	= (15 << 8),
+	BYT_RT5640_OVCD_TH_2000UA	= (20 << 8),
+};
+
+enum {
+	BYT_RT5640_OVCD_SF_0P5		= (RT5640_OVCD_SF_0P5 << 13),
+	BYT_RT5640_OVCD_SF_0P75		= (RT5640_OVCD_SF_0P75 << 13),
+	BYT_RT5640_OVCD_SF_1P0		= (RT5640_OVCD_SF_1P0 << 13),
+	BYT_RT5640_OVCD_SF_1P5		= (RT5640_OVCD_SF_1P5 << 13),
+};
+
+#define BYT_RT5640_MAP(quirk)		((quirk) &  GENMASK(3, 0))
+#define BYT_RT5640_JDSRC(quirk)		(((quirk) & GENMASK(7, 4)) >> 4)
+#define BYT_RT5640_OVCD_TH(quirk)	(((quirk) & GENMASK(12, 8)) >> 8)
+#define BYT_RT5640_OVCD_SF(quirk)	(((quirk) & GENMASK(14, 13)) >> 13)
+#define BYT_RT5640_JD_NOT_INV		BIT(16)
+#define BYT_RT5640_MONO_SPEAKER		BIT(17)
+#define BYT_RT5640_DIFF_MIC		BIT(18) /* default is single-ended */
+#define BYT_RT5640_SSP2_AIF2		BIT(19) /* default is using AIF1  */
+#define BYT_RT5640_SSP0_AIF1		BIT(20)
+#define BYT_RT5640_SSP0_AIF2		BIT(21)
+#define BYT_RT5640_MCLK_EN		BIT(22)
+#define BYT_RT5640_MCLK_25MHZ		BIT(23)
+
+#define BYTCR_INPUT_DEFAULTS				\
+	(BYT_RT5640_IN3_MAP |				\
+	 BYT_RT5640_JD_SRC_JD1_IN4P |			\
+	 BYT_RT5640_OVCD_TH_2000UA |			\
+	 BYT_RT5640_OVCD_SF_0P75 |			\
+	 BYT_RT5640_DIFF_MIC)
+
+/* in-diff or dmic-pin + jdsrc + ovcd-th + -sf + jd-inv + terminating entry */
+#define MAX_NO_PROPS 6
 
 struct byt_rt5640_private {
+	struct snd_soc_jack jack;
 	struct clk *mclk;
 };
 static bool is_bytcr;
@@ -67,7 +106,6 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override");
 static void log_quirks(struct device *dev)
 {
 	int map;
-	bool has_dmic = false;
 	bool has_mclk = false;
 	bool has_ssp0 = false;
 	bool has_ssp0_aif1 = false;
@@ -78,11 +116,9 @@ static void log_quirks(struct device *dev)
 	switch (map) {
 	case BYT_RT5640_DMIC1_MAP:
 		dev_info(dev, "quirk DMIC1_MAP enabled\n");
-		has_dmic = true;
 		break;
 	case BYT_RT5640_DMIC2_MAP:
 		dev_info(dev, "quirk DMIC2_MAP enabled\n");
-		has_dmic = true;
 		break;
 	case BYT_RT5640_IN1_MAP:
 		dev_info(dev, "quirk IN1_MAP enabled\n");
@@ -94,20 +130,20 @@ static void log_quirks(struct device *dev)
 		dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map);
 		break;
 	}
-	if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
-		if (has_dmic)
-			dev_info(dev, "quirk DMIC enabled\n");
-		else
-			dev_err(dev, "quirk DMIC enabled but no DMIC input set, will be ignored\n");
+	if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) {
+		dev_info(dev, "quirk realtek,jack-detect-source %ld\n",
+			 BYT_RT5640_JDSRC(byt_rt5640_quirk));
+		dev_info(dev, "quirk realtek,over-current-threshold-microamp %ld\n",
+			 BYT_RT5640_OVCD_TH(byt_rt5640_quirk) * 100);
+		dev_info(dev, "quirk realtek,over-current-scale-factor %ld\n",
+			 BYT_RT5640_OVCD_SF(byt_rt5640_quirk));
 	}
+	if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV)
+		dev_info(dev, "quirk JD_NOT_INV enabled\n");
 	if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER)
 		dev_info(dev, "quirk MONO_SPEAKER enabled\n");
-	if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) {
-		if (!has_dmic)
-			dev_info(dev, "quirk DIFF_MIC enabled\n");
-		else
-			dev_info(dev, "quirk DIFF_MIC enabled but DMIC input selected, will be ignored\n");
-	}
+	if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
+		dev_info(dev, "quirk DIFF_MIC enabled\n");
 	if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) {
 		dev_info(dev, "quirk SSP0_AIF1 enabled\n");
 		has_ssp0 = true;
@@ -141,6 +177,52 @@ static void log_quirks(struct device *dev)
 	}
 }
 
+static int byt_rt5640_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai,
+					      int rate)
+{
+	int ret;
+
+	/* Configure the PLL before selecting it */
+	if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) {
+		/* use bitclock as PLL input */
+		if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) ||
+		    (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
+			/* 2x16 bit slots on SSP0 */
+			ret = snd_soc_dai_set_pll(codec_dai, 0,
+						  RT5640_PLL1_S_BCLK1,
+						  rate * 32, rate * 512);
+		} else {
+			/* 2x15 bit slots on SSP2 */
+			ret = snd_soc_dai_set_pll(codec_dai, 0,
+						  RT5640_PLL1_S_BCLK1,
+						  rate * 50, rate * 512);
+		}
+	} else {
+		if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) {
+			ret = snd_soc_dai_set_pll(codec_dai, 0,
+						  RT5640_PLL1_S_MCLK,
+						  25000000, rate * 512);
+		} else {
+			ret = snd_soc_dai_set_pll(codec_dai, 0,
+						  RT5640_PLL1_S_MCLK,
+						  19200000, rate * 512);
+		}
+	}
+
+	if (ret < 0) {
+		dev_err(codec_dai->component->dev, "can't set pll: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
+				     rate * 512, SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(codec_dai->component->dev, "can't set clock %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
 
 #define BYT_CODEC_DAI1	"rt5640-aif1"
 #define BYT_CODEC_DAI2	"rt5640-aif2"
@@ -173,9 +255,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
 				return ret;
 			}
 		}
-		ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
-					     48000 * 512,
-					     SND_SOC_CLOCK_IN);
+		ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000);
 	} else {
 		/*
 		 * Set codec clock source to internal clock before
@@ -295,79 +375,72 @@ static const struct snd_kcontrol_new byt_rt5640_controls[] = {
 	SOC_DAPM_PIN_SWITCH("Speaker"),
 };
 
+static struct snd_soc_jack_pin rt5640_pins[] = {
+	{
+		.pin	= "Headphone",
+		.mask	= SND_JACK_HEADPHONE,
+	},
+	{
+		.pin	= "Headset Mic",
+		.mask	= SND_JACK_MICROPHONE,
+	},
+};
+
 static int byt_rt5640_aif1_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 = rtd->codec_dai;
-	int ret;
+	struct snd_soc_dai *dai = rtd->codec_dai;
 
-	ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
-				     params_rate(params) * 512,
-				     SND_SOC_CLOCK_IN);
-
-	if (ret < 0) {
-		dev_err(rtd->dev, "can't set codec clock %d\n", ret);
-		return ret;
-	}
-
-	if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) {
-		/* use bitclock as PLL input */
-		if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) ||
-			(byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
-
-			/* 2x16 bit slots on SSP0 */
-			ret = snd_soc_dai_set_pll(codec_dai, 0,
-						RT5640_PLL1_S_BCLK1,
-						params_rate(params) * 32,
-						params_rate(params) * 512);
-		} else {
-			/* 2x15 bit slots on SSP2 */
-			ret = snd_soc_dai_set_pll(codec_dai, 0,
-						RT5640_PLL1_S_BCLK1,
-						params_rate(params) * 50,
-						params_rate(params) * 512);
-		}
-	} else {
-		if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) {
-			ret = snd_soc_dai_set_pll(codec_dai, 0,
-						RT5640_PLL1_S_MCLK,
-						25000000,
-						params_rate(params) * 512);
-		} else {
-			ret = snd_soc_dai_set_pll(codec_dai, 0,
-						RT5640_PLL1_S_MCLK,
-						19200000,
-						params_rate(params) * 512);
-		}
-	}
-
-	if (ret < 0) {
-		dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
-static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
-{
-	byt_rt5640_quirk = (unsigned long)id->driver_data;
-	return 1;
+	return byt_rt5640_prepare_and_enable_pll1(dai, params_rate(params));
 }
 
+/* Please keep this list alphabetically sorted */
 static const struct dmi_system_id byt_rt5640_quirk_table[] = {
+	{	/* Acer Iconia Tab 8 W1-810 */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Iconia W1-810"),
+		},
+		.driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
+					BYT_RT5640_JD_SRC_JD1_IN4P |
+					BYT_RT5640_OVCD_TH_2000UA |
+					BYT_RT5640_OVCD_SF_0P75 |
+					BYT_RT5640_SSP0_AIF1 |
+					BYT_RT5640_MCLK_EN),
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
+		},
+		.driver_data = (void *)(BYT_RT5640_IN1_MAP |
+						 BYT_RT5640_MCLK_EN |
+						 BYT_RT5640_SSP0_AIF1),
+
+	},
+	{
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 80 Cesium"),
+		},
+		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+					BYT_RT5640_MONO_SPEAKER |
+					BYT_RT5640_SSP0_AIF1 |
+					BYT_RT5640_MCLK_EN),
+	},
 	{
-		.callback = byt_rt5640_quirk_cb,
 		.matches = {
 			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
 		},
 		.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_MCLK_EN),
 	},
 	{
-		.callback = byt_rt5640_quirk_cb,
 		.matches = {
 			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"),
@@ -378,18 +451,38 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
 					BYT_RT5640_SSP0_AIF2 |
 					BYT_RT5640_MCLK_EN),
 	},
+	{	/* Chuwi Vi8 (CWI506) */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "i86"),
+			/* The above are too generic, also match BIOS info */
+			DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"),
+		},
+		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+					BYT_RT5640_MONO_SPEAKER |
+					BYT_RT5640_SSP0_AIF1 |
+					BYT_RT5640_MCLK_EN),
+	},
 	{
-		.callback = byt_rt5640_quirk_cb,
 		.matches = {
-			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "DellInc."),
+			DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
+		},
+		.driver_data = (void *)(BYT_RT5640_DMIC1_MAP),
+	},
+	{
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
 		},
-		.driver_data = (void *)(BYT_RT5640_DMIC2_MAP |
-					BYT_RT5640_DMIC_EN |
+		.driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
+					BYT_RT5640_JD_SRC_JD2_IN4N |
+					BYT_RT5640_OVCD_TH_2000UA |
+					BYT_RT5640_OVCD_SF_0P75 |
+					BYT_RT5640_MONO_SPEAKER |
 					BYT_RT5640_MCLK_EN),
 	},
 	{
-		.callback = byt_rt5640_quirk_cb,
 		.matches = {
 			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"),
@@ -397,17 +490,112 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
 		.driver_data = (void *)(BYT_RT5640_IN1_MAP |
 					BYT_RT5640_MCLK_EN),
 	},
-	{
-		.callback = byt_rt5640_quirk_cb,
+	{	/* HP Pavilion x2 10-n000nd */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
 		},
 		.driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
-					BYT_RT5640_DMIC_EN),
+					BYT_RT5640_JD_SRC_JD2_IN4N |
+					BYT_RT5640_OVCD_TH_1500UA |
+					BYT_RT5640_OVCD_SF_0P75 |
+					BYT_RT5640_SSP0_AIF1 |
+					BYT_RT5640_MCLK_EN),
+	},
+	{	/* HP Stream 7 */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Stream 7 Tablet"),
+		},
+		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+					BYT_RT5640_MONO_SPEAKER |
+					BYT_RT5640_JD_NOT_INV |
+					BYT_RT5640_SSP0_AIF1 |
+					BYT_RT5640_MCLK_EN),
+	},
+	{	/* I.T.Works TW891 */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "TW891"),
+			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TW891"),
+		},
+		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+					BYT_RT5640_MONO_SPEAKER |
+					BYT_RT5640_SSP0_AIF1 |
+					BYT_RT5640_MCLK_EN),
+	},
+	{	/* Lamina I8270 / T701BR.SE */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Lamina"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "T701BR.SE"),
+		},
+		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+					BYT_RT5640_MONO_SPEAKER |
+					BYT_RT5640_JD_NOT_INV |
+					BYT_RT5640_SSP0_AIF1 |
+					BYT_RT5640_MCLK_EN),
+	},
+	{	/* MSI S100 tablet */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "S100"),
+		},
+		.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_MONO_SPEAKER |
+					BYT_RT5640_DIFF_MIC |
+					BYT_RT5640_MCLK_EN),
+	},
+	{	/* Pipo W4 */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
+			/* The above are too generic, also match BIOS info */
+			DMI_MATCH(DMI_BIOS_VERSION, "V8L_WIN32_CHIPHD"),
+		},
+		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+					BYT_RT5640_MONO_SPEAKER |
+					BYT_RT5640_SSP0_AIF1 |
+					BYT_RT5640_MCLK_EN),
+	},
+	{	/* Point of View Mobii TAB-P800W (V2.0) */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
+			/* The above are too generic, also match BIOS info */
+			DMI_EXACT_MATCH(DMI_BIOS_VERSION, "3BAIR1014"),
+			DMI_EXACT_MATCH(DMI_BIOS_DATE, "10/24/2014"),
+		},
+		.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_MONO_SPEAKER |
+					BYT_RT5640_DIFF_MIC |
+					BYT_RT5640_SSP0_AIF2 |
+					BYT_RT5640_MCLK_EN),
+	},
+	{	/* Point of View Mobii TAB-P800W (V2.1) */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
+			/* The above are too generic, also match BIOS info */
+			DMI_EXACT_MATCH(DMI_BIOS_VERSION, "3BAIR1013"),
+			DMI_EXACT_MATCH(DMI_BIOS_DATE, "08/22/2014"),
+		},
+		.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_MONO_SPEAKER |
+					BYT_RT5640_DIFF_MIC |
+					BYT_RT5640_SSP0_AIF2 |
+					BYT_RT5640_MCLK_EN),
 	},
 	{
-		.callback = byt_rt5640_quirk_cb,
 		.matches = {
 			DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
 			DMI_MATCH(DMI_BOARD_NAME, "tPAD"),
@@ -416,23 +604,23 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
 					BYT_RT5640_MCLK_EN |
 					BYT_RT5640_SSP0_AIF1),
 	},
-	{
-		.callback = byt_rt5640_quirk_cb,
+	{	/* Toshiba Satellite Click Mini L9W-B */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SATELLITE Click Mini L9W-B"),
 		},
-		.driver_data = (void *)(BYT_RT5640_IN1_MAP |
-						 BYT_RT5640_MCLK_EN |
-						 BYT_RT5640_SSP0_AIF1),
-
+		.driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
+					BYT_RT5640_JD_SRC_JD2_IN4N |
+					BYT_RT5640_OVCD_TH_1500UA |
+					BYT_RT5640_OVCD_SF_0P75 |
+					BYT_RT5640_SSP0_AIF1 |
+					BYT_RT5640_MCLK_EN),
 	},
-	{
-		.callback = byt_rt5640_quirk_cb,
+	{	/* Catch-all for generic Insyde tablets, must be last */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
 		},
-		.driver_data = (void *)(BYT_RT5640_IN3_MAP |
+		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
 					BYT_RT5640_MCLK_EN |
 					BYT_RT5640_SSP0_AIF1),
 
@@ -440,6 +628,64 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
 	{}
 };
 
+/*
+ * Note this MUST be called before snd_soc_register_card(), so that the props
+ * are in place before the codec component driver's probe function parses them.
+ */
+static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name)
+{
+	struct property_entry props[MAX_NO_PROPS] = {};
+	struct device *i2c_dev;
+	int ret, cnt = 0;
+
+	i2c_dev = bus_find_device_by_name(&i2c_bus_type, NULL, i2c_dev_name);
+	if (!i2c_dev)
+		return -EPROBE_DEFER;
+
+	switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
+	case BYT_RT5640_DMIC1_MAP:
+		props[cnt++] = PROPERTY_ENTRY_U32("realtek,dmic1-data-pin",
+						  RT5640_DMIC1_DATA_PIN_IN1P);
+		break;
+	case BYT_RT5640_DMIC2_MAP:
+		props[cnt++] = PROPERTY_ENTRY_U32("realtek,dmic2-data-pin",
+						  RT5640_DMIC2_DATA_PIN_IN1N);
+		break;
+	case BYT_RT5640_IN1_MAP:
+		if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
+			props[cnt++] =
+				PROPERTY_ENTRY_BOOL("realtek,in1-differential");
+		break;
+	case BYT_RT5640_IN3_MAP:
+		if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
+			props[cnt++] =
+				PROPERTY_ENTRY_BOOL("realtek,in3-differential");
+		break;
+	}
+
+	if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) {
+		props[cnt++] = PROPERTY_ENTRY_U32(
+				    "realtek,jack-detect-source",
+				    BYT_RT5640_JDSRC(byt_rt5640_quirk));
+
+		props[cnt++] = PROPERTY_ENTRY_U32(
+				    "realtek,over-current-threshold-microamp",
+				    BYT_RT5640_OVCD_TH(byt_rt5640_quirk) * 100);
+
+		props[cnt++] = PROPERTY_ENTRY_U32(
+				    "realtek,over-current-scale-factor",
+				    BYT_RT5640_OVCD_SF(byt_rt5640_quirk));
+	}
+
+	if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV)
+		props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,jack-detect-not-inverted");
+
+	ret = device_add_properties(i2c_dev, props);
+	put_device(i2c_dev);
+
+	return ret;
+}
+
 static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 {
 	struct snd_soc_card *card = runtime->card;
@@ -451,6 +697,11 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 
 	card->dapm.idle_bias_off = true;
 
+	/* Start with RC clk for jack-detect (we disable MCLK below) */
+	if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN)
+		snd_soc_component_update_bits(component, RT5640_GLB_CLK,
+			RT5640_SCLK_SRC_MASK, RT5640_SCLK_SRC_RCCLK);
+
 	rt5640_sel_asrc_clk_src(component,
 				RT5640_DA_STEREO_FILTER |
 				RT5640_DA_MONO_L_FILTER	|
@@ -521,17 +772,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 	if (ret)
 		return ret;
 
-	if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) {
-		snd_soc_component_update_bits(component,  RT5640_IN1_IN2, RT5640_IN_DF1,
-				    RT5640_IN_DF1);
-	}
-
-	if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
-		ret = rt5640_dmic_enable(component, 0, 0);
-		if (ret)
-			return ret;
-	}
-
 	snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
 	snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
 
@@ -555,11 +795,27 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 		else
 			ret = clk_set_rate(priv->mclk, 19200000);
 
-		if (ret)
+		if (ret) {
 			dev_err(card->dev, "unable to set MCLK rate\n");
+			return ret;
+		}
 	}
 
-	return ret;
+	if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) {
+		ret = snd_soc_card_jack_new(card, "Headset",
+					    SND_JACK_HEADSET | SND_JACK_BTN_0,
+					    &priv->jack, rt5640_pins,
+					    ARRAY_SIZE(rt5640_pins));
+		if (ret) {
+			dev_err(card->dev, "Jack creation failed %d\n", ret);
+			return ret;
+		}
+		snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0,
+				 KEY_PLAYPAUSE);
+		snd_soc_component_set_jack(component, &priv->jack, NULL);
+	}
+
+	return 0;
 }
 
 static const struct snd_soc_pcm_stream byt_rt5640_dai_params = {
@@ -701,6 +957,48 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
 };
 
 /* SoC card */
+static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN];
+static char byt_rt5640_codec_aif_name[12]; /*  = "rt5640-aif[1|2]" */
+static char byt_rt5640_cpu_dai_name[10]; /*  = "ssp[0|2]-port" */
+static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */
+
+static int byt_rt5640_suspend(struct snd_soc_card *card)
+{
+	struct snd_soc_component *component;
+
+	if (!BYT_RT5640_JDSRC(byt_rt5640_quirk))
+		return 0;
+
+	list_for_each_entry(component, &card->component_dev_list, card_list) {
+		if (!strcmp(component->name, byt_rt5640_codec_name)) {
+			dev_dbg(component->dev, "disabling jack detect before suspend\n");
+			snd_soc_component_set_jack(component, NULL, NULL);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int byt_rt5640_resume(struct snd_soc_card *card)
+{
+	struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
+	struct snd_soc_component *component;
+
+	if (!BYT_RT5640_JDSRC(byt_rt5640_quirk))
+		return 0;
+
+	list_for_each_entry(component, &card->component_dev_list, card_list) {
+		if (!strcmp(component->name, byt_rt5640_codec_name)) {
+			dev_dbg(component->dev, "re-enabling jack detect after resume\n");
+			snd_soc_component_set_jack(component, &priv->jack, NULL);
+			break;
+		}
+	}
+
+	return 0;
+}
+
 static struct snd_soc_card byt_rt5640_card = {
 	.name = "bytcr-rt5640",
 	.owner = THIS_MODULE,
@@ -711,12 +1009,10 @@ static struct snd_soc_card byt_rt5640_card = {
 	.dapm_routes = byt_rt5640_audio_map,
 	.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
 	.fully_routed = true,
+	.suspend_pre = byt_rt5640_suspend,
+	.resume_post = byt_rt5640_resume,
 };
 
-static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN];
-static char byt_rt5640_codec_aif_name[12]; /*  = "rt5640-aif[1|2]" */
-static char byt_rt5640_cpu_dai_name[10]; /*  = "ssp[0|2]-port" */
-
 static bool is_valleyview(void)
 {
 	static const struct x86_cpu_id cpu_ids[] = {
@@ -736,6 +1032,8 @@ struct acpi_chan_package {   /* ACPICA seems to require 64 bit integers */
 
 static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 {
+	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 *i2c_name = NULL;
@@ -744,7 +1042,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 	int i;
 
 	is_bytcr = false;
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
@@ -829,20 +1127,29 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 		}
 
 		/* change defaults for Baytrail-CR capture */
-		byt_rt5640_quirk |= BYT_RT5640_IN1_MAP;
-		byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC;
+		byt_rt5640_quirk |= BYTCR_INPUT_DEFAULTS;
 	} else {
-		byt_rt5640_quirk |= (BYT_RT5640_DMIC1_MAP |
-				BYT_RT5640_DMIC_EN);
+		byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP |
+				    BYT_RT5640_JD_SRC_JD2_IN4N |
+				    BYT_RT5640_OVCD_TH_2000UA |
+				    BYT_RT5640_OVCD_SF_0P75;
 	}
 
 	/* check quirks before creating card */
-	dmi_check_system(byt_rt5640_quirk_table);
+	dmi_id = dmi_first_match(byt_rt5640_quirk_table);
+	if (dmi_id)
+		byt_rt5640_quirk = (unsigned long)dmi_id->driver_data;
 	if (quirk_override) {
 		dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n",
 			 (unsigned int)byt_rt5640_quirk, quirk_override);
 		byt_rt5640_quirk = quirk_override;
 	}
+
+	/* Must be called before register_card, also see declaration comment. */
+	ret_val = byt_rt5640_add_codec_device_props(byt_rt5640_codec_name);
+	if (ret_val)
+		return ret_val;
+
 	log_quirks(&pdev->dev);
 
 	if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) ||
@@ -889,6 +1196,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 		}
 	}
 
+	snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name),
+		 "bytcr-rt5640-%s-spk-%s-mic",
+		 (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ?
+			"mono" : "stereo",
+		 map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]);
+	byt_rt5640_card.long_name = byt_rt5640_long_name;
+
 	ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
 
 	if (ret_val) {
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index 1b1997f1d60c..987720e203f9 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -706,6 +706,7 @@ static struct snd_soc_card byt_rt5651_card = {
 static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN];
 static char byt_rt5651_codec_aif_name[12]; /*  = "rt5651-aif[1|2]" */
 static char byt_rt5651_cpu_dai_name[10]; /*  = "ssp[0|2]-port" */
+static char byt_rt5651_long_name[40]; /* = "bytcr-rt5651-*-spk-*-mic" */
 
 static bool is_valleyview(void)
 {
@@ -726,6 +727,10 @@ struct acpi_chan_package {   /* ACPICA seems to require 64 bit integers */
 
 static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
 {
+	const char * const intmic_name[] =
+		{ "dmic", "in1", "in2", "in12", "in1", "in2" };
+	const char * const hsmic_name[] =
+		{  "in2", "in2", "in1",  "in3", "in3", "in3" };
 	struct byt_rt5651_private *priv;
 	struct snd_soc_acpi_mach *mach;
 	const char *i2c_name = NULL;
@@ -734,7 +739,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
 	int dai_index = 0;
 	int i;
 
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
@@ -856,9 +861,10 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
 	if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) {
 		priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
 		if (IS_ERR(priv->mclk)) {
+			ret_val = PTR_ERR(priv->mclk);
 			dev_err(&pdev->dev,
-				"Failed to get MCLK from pmc_plt_clk_3: %ld\n",
-				PTR_ERR(priv->mclk));
+				"Failed to get MCLK from pmc_plt_clk_3: %d\n",
+				ret_val);
 			/*
 			 * Fall back to bit clock usage for -ENOENT (clock not
 			 * available likely due to missing dependencies), bail
@@ -870,6 +876,12 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
 		}
 	}
 
+	snprintf(byt_rt5651_long_name, sizeof(byt_rt5651_long_name),
+		 "bytcr-rt5651-%s-intmic-%s-hsmic",
+		 intmic_name[BYT_RT5651_MAP(byt_rt5651_quirk)],
+		 hsmic_name[BYT_RT5651_MAP(byt_rt5651_quirk)]);
+	byt_rt5651_card.long_name = byt_rt5651_long_name;
+
 	ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card);
 
 	if (ret_val) {
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index d3e1c7e12004..db6976f4ddaa 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -391,7 +391,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 	int ret_val = 0;
 	struct cht_mc_private *drv;
 
-	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
 
diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c
index 680f2b3a24f9..30c46977d53c 100644
--- a/sound/soc/intel/boards/cht_bsw_nau8824.c
+++ b/sound/soc/intel/boards/cht_bsw_nau8824.c
@@ -120,7 +120,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 	 * KEY_VOLUMEUP
 	 * KEY_VOLUMEDOWN
 	 */
-	jack_type = SND_JACK_HEADPHONE | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+	jack_type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 		SND_JACK_BTN_2 | SND_JACK_BTN_3;
 	ret = snd_soc_card_jack_new(runtime->card, "Headset", jack_type, jack,
 		cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins));
@@ -248,7 +248,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 	struct cht_mc_private *drv;
 	int ret_val;
 
-	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
 	snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 49ba1a956a06..f5a5ea6a093c 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -539,7 +539,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 	int ret_val = 0;
 	int i;
 
-	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
 
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index e68ec32720a4..e5aa13058dd7 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -189,13 +189,6 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 	if (devm_acpi_dev_add_driver_gpios(component->dev, cht_rt5672_gpios))
 		dev_warn(runtime->dev, "Unable to add GPIO mapping table\n");
 
-	/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
-	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
-	if (ret < 0) {
-		dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
-		return ret;
-	}
-
 	/* Select codec ASRC clock source to track I2S1 clock, because codec
 	 * is in slave mode and 100fs I2S format (BCLK = 100 * LRCLK) cannot
 	 * be supported by RT5672. Otherwise, ASRC will be disabled and cause
@@ -252,6 +245,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
 			SNDRV_PCM_HW_PARAM_RATE);
 	struct snd_interval *channels = hw_param_interval(params,
 						SNDRV_PCM_HW_PARAM_CHANNELS);
+	int ret;
 
 	/* The DSP will covert the FE rate to 48k, stereo, 24bits */
 	rate->min = rate->max = 48000;
@@ -259,6 +253,26 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
 
 	/* set SSP2 to 24-bit */
 	params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+
+	/*
+	 * Default mode for SSP configuration is TDM 4 slot
+	 */
+	ret = snd_soc_dai_set_fmt(rtd->codec_dai,
+				  SND_SOC_DAIFMT_DSP_B |
+				  SND_SOC_DAIFMT_IB_NF |
+				  SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set format to TDM %d\n", ret);
+		return ret;
+	}
+
+	/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+	ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, 0xF, 0xF, 4, 24);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -315,8 +329,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
 		.nonatomic = true,
 		.codec_dai_name = "rt5670-aif1",
 		.codec_name = "i2c-10EC5670:00",
-		.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
-					| SND_SOC_DAIFMT_CBS_CFS,
 		.init = cht_codec_init,
 		.be_hw_params_fixup = cht_codec_fixup,
 		.dpcm_playback = 1,
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
index e84baafd5f63..94294c27d1db 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c
@@ -65,14 +65,6 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
 		return -EIO;
 	}
 
-	/* Configure sysclk for codec */
-	ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000,
-				     SND_SOC_CLOCK_IN);
-	if (ret) {
-		dev_err(card->dev, "can't set codec sysclk configuration\n");
-		return ret;
-	}
-
 	if (SND_SOC_DAPM_EVENT_OFF(event)) {
 		ret = snd_soc_dai_set_pll(codec_dai, 0,
 				     DA7219_SYSCLK_MCLK, 0, 0);
@@ -169,9 +161,18 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
 	struct snd_soc_component *component = rtd->codec_dai->component;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_jack *jack;
 	int ret;
 
+	/* Configure sysclk for codec */
+	ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000,
+						SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(rtd->dev, "can't set codec sysclk configuration\n");
+		return ret;
+	}
+
 	/*
 	 * Headset buttons map to the google Reference headset.
 	 * These can be configured by userspace.
@@ -572,7 +573,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
 {
 	struct kbl_codec_private *ctx;
 
-	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index 0e6b7e79441c..3a61252fe450 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -299,7 +299,8 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
 	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
 	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 
-	rt5663_set_jack_detect(component, &ctx->kabylake_headset);
+	snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
+
 	return ret;
 }
 
@@ -972,7 +973,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
 	struct skl_machine_pdata *pdata;
 	int ret;
 
-	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index 69c3d8446f06..92f5fb2ae0a3 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -200,7 +200,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
 	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
 	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 
-	rt5663_set_jack_detect(component, &ctx->kabylake_headset);
+	snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
 
 	ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC");
 	if (ret)
@@ -651,7 +651,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
 	struct kbl_codec_private *ctx;
 	struct skl_machine_pdata *pdata;
 
-	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
index 9a7a0646bffe..3ff6646cfa21 100644
--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -643,7 +643,7 @@ static int skylake_audio_probe(struct platform_device *pdev)
 	struct skl_nau8825_private *ctx;
 	struct skl_machine_pdata *pdata;
 
-	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
index 212ac8971e55..b0610bba3cfa 100644
--- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -696,7 +696,7 @@ static int skylake_audio_probe(struct platform_device *pdev)
 	struct skl_nau88125_private *ctx;
 	struct skl_machine_pdata *pdata;
 
-	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c
index 737d5615b0ef..38a1495c29cf 100644
--- a/sound/soc/intel/boards/skl_rt286.c
+++ b/sound/soc/intel/boards/skl_rt286.c
@@ -527,7 +527,7 @@ static int skylake_audio_probe(struct platform_device *pdev)
 {
 	struct skl_rt286_private *ctx;
 
-	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c
index a016455a6ddb..5d7ac2ee7a3c 100644
--- a/sound/soc/intel/skylake/skl-debug.c
+++ b/sound/soc/intel/skylake/skl-debug.c
@@ -15,10 +15,10 @@
 
 #include <linux/pci.h>
 #include <linux/debugfs.h>
+#include <uapi/sound/skl-tplg-interface.h>
 #include "skl.h"
 #include "skl-sst-dsp.h"
 #include "skl-sst-ipc.h"
-#include "skl-tplg-interface.h"
 #include "skl-topology.h"
 #include "../common/sst-dsp.h"
 #include "../common/sst-dsp-priv.h"
@@ -142,8 +142,8 @@ static ssize_t module_read(struct file *file, char __user *user_buf,
 			mconfig->max_out_queue, ret, false);
 
 	ret += snprintf(buf + ret, MOD_BUF - ret,
-			"Other:\n\tDomain %d\n\tHomogenous Input %s\n\t"
-			"Homogenous Output %s\n\tIn Queue Mask %d\n\t"
+			"Other:\n\tDomain %d\n\tHomogeneous Input %s\n\t"
+			"Homogeneous Output %s\n\tIn Queue Mask %d\n\t"
 			"Out Queue Mask %d\n\tDMA ID %d\n\tMem Pages %d\n\t"
 			"Module Type %d\n\tModule State %d\n",
 			mconfig->domain,
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 57d4a58522a6..d5f9c30eba32 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -21,6 +21,7 @@
 #include <linux/pci.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
+#include <uapi/sound/skl-tplg-interface.h>
 #include "skl-sst-dsp.h"
 #include "cnl-sst-dsp.h"
 #include "skl-sst-ipc.h"
@@ -28,7 +29,6 @@
 #include "../common/sst-dsp.h"
 #include "../common/sst-dsp-priv.h"
 #include "skl-topology.h"
-#include "skl-tplg-interface.h"
 
 static int skl_alloc_dma_buf(struct device *dev,
 		struct snd_dma_buffer *dmab, size_t size)
@@ -225,7 +225,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
 		.id = 0x9d71,
 		.num_cores = 2,
 		.loader_ops = skl_get_loader_ops,
-		.init = kbl_sst_dsp_init,
+		.init = skl_sst_dsp_init,
 		.init_fw = skl_sst_init_fw,
 		.cleanup = skl_sst_dsp_cleanup
 	},
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 15cb8ac3e374..afa86b9e4dcf 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -268,15 +268,31 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream,
 {
 	struct skl *skl = get_skl_ctx(dai->dev);
 	struct skl_module_cfg *mconfig;
+	int ret;
 
 	dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
 
 	mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
 
-	/* In case of XRUN recovery, reset the FW pipe to clean state */
-	if (mconfig && (substream->runtime->status->state ==
-					SNDRV_PCM_STATE_XRUN))
-		skl_reset_pipe(skl->skl_sst, mconfig->pipe);
+	/*
+	 * In case of XRUN recovery or in the case when the application
+	 * calls prepare another time, reset the FW pipe to clean state
+	 */
+	if (mconfig &&
+		(substream->runtime->status->state == SNDRV_PCM_STATE_XRUN ||
+		 mconfig->pipe->state == SKL_PIPE_CREATED ||
+		 mconfig->pipe->state == SKL_PIPE_PAUSED)) {
+
+		ret = skl_reset_pipe(skl->skl_sst, mconfig->pipe);
+
+		if (ret < 0)
+			return ret;
+
+		ret = skl_pcm_host_dma_prepare(dai->dev,
+					mconfig->pipe->p_params);
+		if (ret < 0)
+			return ret;
+	}
 
 	return 0;
 }
@@ -366,9 +382,21 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
 {
 	struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
 	struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+	struct skl *skl = get_skl_ctx(dai->dev);
+	struct skl_module_cfg *mconfig;
+	int ret;
 
 	dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
 
+	mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
+
+	if (mconfig) {
+		ret = skl_reset_pipe(skl->skl_sst, mconfig->pipe);
+		if (ret < 0)
+			dev_err(dai->dev, "%s:Reset failed ret =%d",
+						__func__, ret);
+	}
+
 	snd_hdac_stream_cleanup(hdac_stream(stream));
 	hdac_stream(stream)->prepared = 0;
 
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
index 12fc9a73dc8a..e1d6f6719f7e 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -231,9 +231,6 @@ int skl_dsp_boot(struct sst_dsp *ctx);
 int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
 		const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
 		struct skl_sst **dsp);
-int kbl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
-		const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
-		struct skl_sst **dsp);
 int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
 		const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
 		struct skl_sst **dsp);
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
index 5a7e41b65ef3..5951bbdf1f1a 100644
--- a/sound/soc/intel/skylake/skl-sst.c
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -390,7 +390,7 @@ out:
 }
 
 static int
-kbl_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
+skl_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
 {
 	struct skl_sst *skl = ctx->thread_context;
 	struct firmware stripped_fw;
@@ -508,16 +508,7 @@ static const struct skl_dsp_fw_ops skl_fw_ops = {
 	.set_state_D3 = skl_set_dsp_D3,
 	.load_fw = skl_load_base_firmware,
 	.get_fw_errcode = skl_get_errorcode,
-	.load_mod = skl_load_module,
-	.unload_mod = skl_unload_module,
-};
-
-static const struct skl_dsp_fw_ops kbl_fw_ops = {
-	.set_state_D0 = skl_set_dsp_D0,
-	.set_state_D3 = skl_set_dsp_D3,
-	.load_fw = skl_load_base_firmware,
-	.get_fw_errcode = skl_get_errorcode,
-	.load_library = kbl_load_library,
+	.load_library = skl_load_library,
 	.load_mod = skl_load_module,
 	.unload_mod = skl_unload_module,
 };
@@ -573,27 +564,6 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
 }
 EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
 
-int kbl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
-		const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
-		struct skl_sst **dsp)
-{
-	struct sst_dsp *sst;
-	int ret;
-
-	ret = skl_sst_dsp_init(dev, mmio_base, irq, fw_name, dsp_ops, dsp);
-	if (ret < 0) {
-		dev_err(dev, "%s: Init failed %d\n", __func__, ret);
-		return ret;
-	}
-
-	sst = (*dsp)->dsp;
-	sst->fw_ops = kbl_fw_ops;
-
-	return 0;
-
-}
-EXPORT_SYMBOL_GPL(kbl_sst_dsp_init);
-
 int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx)
 {
 	int ret;
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 3b1dca419883..2c5129782959 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -19,14 +19,15 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/firmware.h>
+#include <linux/uuid.h>
 #include <sound/soc.h>
 #include <sound/soc-topology.h>
 #include <uapi/sound/snd_sst_tokens.h>
+#include <uapi/sound/skl-tplg-interface.h>
 #include "skl-sst-dsp.h"
 #include "skl-sst-ipc.h"
 #include "skl-topology.h"
 #include "skl.h"
-#include "skl-tplg-interface.h"
 #include "../common/sst-dsp.h"
 #include "../common/sst-dsp-priv.h"
 
@@ -2724,6 +2725,167 @@ static int skl_tplg_get_desc_blocks(struct device *dev,
 	return -EINVAL;
 }
 
+/* Functions to parse private data from configuration file format v4 */
+
+/*
+ * Add pipeline from topology binary into driver pipeline list
+ *
+ * If already added we return that instance
+ * Otherwise we create a new instance and add into driver list
+ */
+static int skl_tplg_add_pipe_v4(struct device *dev,
+				struct skl_module_cfg *mconfig, struct skl *skl,
+				struct skl_dfw_v4_pipe *dfw_pipe)
+{
+	struct skl_pipeline *ppl;
+	struct skl_pipe *pipe;
+	struct skl_pipe_params *params;
+
+	list_for_each_entry(ppl, &skl->ppl_list, node) {
+		if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) {
+			mconfig->pipe = ppl->pipe;
+			return 0;
+		}
+	}
+
+	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
+	if (!ppl)
+		return -ENOMEM;
+
+	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
+	if (!pipe)
+		return -ENOMEM;
+
+	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
+	if (!params)
+		return -ENOMEM;
+
+	pipe->ppl_id = dfw_pipe->pipe_id;
+	pipe->memory_pages = dfw_pipe->memory_pages;
+	pipe->pipe_priority = dfw_pipe->pipe_priority;
+	pipe->conn_type = dfw_pipe->conn_type;
+	pipe->state = SKL_PIPE_INVALID;
+	pipe->p_params = params;
+	INIT_LIST_HEAD(&pipe->w_list);
+
+	ppl->pipe = pipe;
+	list_add(&ppl->node, &skl->ppl_list);
+
+	mconfig->pipe = pipe;
+
+	return 0;
+}
+
+static void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin,
+					struct skl_module_pin *m_pin,
+					bool is_dynamic, int max_pin)
+{
+	int i;
+
+	for (i = 0; i < max_pin; i++) {
+		m_pin[i].id.module_id = dfw_pin[i].module_id;
+		m_pin[i].id.instance_id = dfw_pin[i].instance_id;
+		m_pin[i].in_use = false;
+		m_pin[i].is_dynamic = is_dynamic;
+		m_pin[i].pin_state = SKL_PIN_UNBIND;
+	}
+}
+
+static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt,
+				 struct skl_dfw_v4_module_fmt *src_fmt,
+				 int pins)
+{
+	int i;
+
+	for (i = 0; i < pins; i++) {
+		dst_fmt[i].fmt.channels  = src_fmt[i].channels;
+		dst_fmt[i].fmt.s_freq = src_fmt[i].freq;
+		dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth;
+		dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth;
+		dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg;
+		dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map;
+		dst_fmt[i].fmt.interleaving_style =
+						src_fmt[i].interleaving_style;
+		dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type;
+	}
+}
+
+static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w,
+				    struct skl *skl, struct device *dev,
+				    struct skl_module_cfg *mconfig)
+{
+	struct skl_dfw_v4_module *dfw =
+				(struct skl_dfw_v4_module *)tplg_w->priv.data;
+	int ret;
+
+	dev_dbg(dev, "Parsing Skylake v4 widget topology data\n");
+
+	ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid);
+	if (ret)
+		return ret;
+	mconfig->id.module_id = -1;
+	mconfig->id.instance_id = dfw->instance_id;
+	mconfig->module->resources[0].cps = dfw->max_mcps;
+	mconfig->module->resources[0].ibs = dfw->ibs;
+	mconfig->module->resources[0].obs = dfw->obs;
+	mconfig->core_id = dfw->core_id;
+	mconfig->module->max_input_pins = dfw->max_in_queue;
+	mconfig->module->max_output_pins = dfw->max_out_queue;
+	mconfig->module->loadable = dfw->is_loadable;
+	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt,
+			     MAX_IN_QUEUE);
+	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt,
+			     MAX_OUT_QUEUE);
+
+	mconfig->params_fixup = dfw->params_fixup;
+	mconfig->converter = dfw->converter;
+	mconfig->m_type = dfw->module_type;
+	mconfig->vbus_id = dfw->vbus_id;
+	mconfig->module->resources[0].is_pages = dfw->mem_pages;
+
+	ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe);
+	if (ret)
+		return ret;
+
+	mconfig->dev_type = dfw->dev_type;
+	mconfig->hw_conn_type = dfw->hw_conn_type;
+	mconfig->time_slot = dfw->time_slot;
+	mconfig->formats_config.caps_size = dfw->caps.caps_size;
+
+	mconfig->m_in_pin = devm_kzalloc(dev,
+				MAX_IN_QUEUE * sizeof(*mconfig->m_in_pin),
+				GFP_KERNEL);
+	if (!mconfig->m_in_pin)
+		return -ENOMEM;
+
+	mconfig->m_out_pin = devm_kzalloc(dev,
+				MAX_OUT_QUEUE * sizeof(*mconfig->m_out_pin),
+				GFP_KERNEL);
+	if (!mconfig->m_out_pin)
+		return -ENOMEM;
+
+	skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin,
+				    dfw->is_dynamic_in_pin,
+				    mconfig->module->max_input_pins);
+	skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin,
+				    dfw->is_dynamic_out_pin,
+				    mconfig->module->max_output_pins);
+
+	if (mconfig->formats_config.caps_size) {
+		mconfig->formats_config.set_params = dfw->caps.set_params;
+		mconfig->formats_config.param_id = dfw->caps.param_id;
+		mconfig->formats_config.caps =
+		devm_kzalloc(dev, mconfig->formats_config.caps_size,
+			     GFP_KERNEL);
+		if (!mconfig->formats_config.caps)
+			return -ENOMEM;
+		memcpy(mconfig->formats_config.caps, dfw->caps.caps,
+		       dfw->caps.caps_size);
+	}
+
+	return 0;
+}
+
 /*
  * Parse the private data for the token and corresponding value.
  * The private data can have multiple data blocks. So, a data block
@@ -2739,6 +2901,13 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
 	char *data;
 	int ret;
 
+	/*
+	 * v4 configuration files have a valid UUID at the start of
+	 * the widget's private data.
+	 */
+	if (uuid_is_valid((char *)tplg_w->priv.data))
+		return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig);
+
 	/* Read the NUM_DATA_BLOCKS descriptor */
 	array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
 	ret = skl_tplg_get_desc_blocks(dev, array);
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index b1e0667c0ae0..6d7e0569695f 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -25,8 +25,8 @@
 
 #include <sound/hdaudio_ext.h>
 #include <sound/soc.h>
+#include <uapi/sound/skl-tplg-interface.h>
 #include "skl.h"
-#include "skl-tplg-interface.h"
 
 #define BITS_PER_BYTE 8
 #define MAX_TS_GROUPS 8
diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h
deleted file mode 100644
index f8d1749a2e0c..000000000000
--- a/sound/soc/intel/skylake/skl-tplg-interface.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * skl-tplg-interface.h - Intel DSP FW private data interface
- *
- * Copyright (C) 2015 Intel Corp
- * Author: Jeeja KP <jeeja.kp@intel.com>
- *	    Nilofer, Samreen <samreen.nilofer@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- */
-
-#ifndef __HDA_TPLG_INTERFACE_H__
-#define __HDA_TPLG_INTERFACE_H__
-
-/*
- * Default types range from 0~12. type can range from 0 to 0xff
- * SST types start at higher to avoid any overlapping in future
- */
-#define SKL_CONTROL_TYPE_BYTE_TLV	0x100
-#define SKL_CONTROL_TYPE_MIC_SELECT	0x102
-
-#define HDA_SST_CFG_MAX	900 /* size of copier cfg*/
-#define MAX_IN_QUEUE 8
-#define MAX_OUT_QUEUE 8
-
-#define SKL_UUID_STR_SZ 40
-/* Event types goes here */
-/* Reserve event type 0 for no event handlers */
-enum skl_event_types {
-	SKL_EVENT_NONE = 0,
-	SKL_MIXER_EVENT,
-	SKL_MUX_EVENT,
-	SKL_VMIXER_EVENT,
-	SKL_PGA_EVENT
-};
-
-/**
- * enum skl_ch_cfg - channel configuration
- *
- * @SKL_CH_CFG_MONO:	One channel only
- * @SKL_CH_CFG_STEREO:	L & R
- * @SKL_CH_CFG_2_1:	L, R & LFE
- * @SKL_CH_CFG_3_0:	L, C & R
- * @SKL_CH_CFG_3_1:	L, C, R & LFE
- * @SKL_CH_CFG_QUATRO:	L, R, Ls & Rs
- * @SKL_CH_CFG_4_0:	L, C, R & Cs
- * @SKL_CH_CFG_5_0:	L, C, R, Ls & Rs
- * @SKL_CH_CFG_5_1:	L, C, R, Ls, Rs & LFE
- * @SKL_CH_CFG_DUAL_MONO: One channel replicated in two
- * @SKL_CH_CFG_I2S_DUAL_STEREO_0: Stereo(L,R) in 4 slots, 1st stream:[ L, R, -, - ]
- * @SKL_CH_CFG_I2S_DUAL_STEREO_1: Stereo(L,R) in 4 slots, 2nd stream:[ -, -, L, R ]
- * @SKL_CH_CFG_INVALID:	Invalid
- */
-enum skl_ch_cfg {
-	SKL_CH_CFG_MONO = 0,
-	SKL_CH_CFG_STEREO = 1,
-	SKL_CH_CFG_2_1 = 2,
-	SKL_CH_CFG_3_0 = 3,
-	SKL_CH_CFG_3_1 = 4,
-	SKL_CH_CFG_QUATRO = 5,
-	SKL_CH_CFG_4_0 = 6,
-	SKL_CH_CFG_5_0 = 7,
-	SKL_CH_CFG_5_1 = 8,
-	SKL_CH_CFG_DUAL_MONO = 9,
-	SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10,
-	SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11,
-	SKL_CH_CFG_4_CHANNEL = 12,
-	SKL_CH_CFG_INVALID
-};
-
-enum skl_module_type {
-	SKL_MODULE_TYPE_MIXER = 0,
-	SKL_MODULE_TYPE_COPIER,
-	SKL_MODULE_TYPE_UPDWMIX,
-	SKL_MODULE_TYPE_SRCINT,
-	SKL_MODULE_TYPE_ALGO,
-	SKL_MODULE_TYPE_BASE_OUTFMT,
-	SKL_MODULE_TYPE_KPB,
-	SKL_MODULE_TYPE_MIC_SELECT,
-};
-
-enum skl_core_affinity {
-	SKL_AFFINITY_CORE_0 = 0,
-	SKL_AFFINITY_CORE_1,
-	SKL_AFFINITY_CORE_MAX
-};
-
-enum skl_pipe_conn_type {
-	SKL_PIPE_CONN_TYPE_NONE = 0,
-	SKL_PIPE_CONN_TYPE_FE,
-	SKL_PIPE_CONN_TYPE_BE
-};
-
-enum skl_hw_conn_type {
-	SKL_CONN_NONE = 0,
-	SKL_CONN_SOURCE = 1,
-	SKL_CONN_SINK = 2
-};
-
-enum skl_dev_type {
-	SKL_DEVICE_BT = 0x0,
-	SKL_DEVICE_DMIC = 0x1,
-	SKL_DEVICE_I2S = 0x2,
-	SKL_DEVICE_SLIMBUS = 0x3,
-	SKL_DEVICE_HDALINK = 0x4,
-	SKL_DEVICE_HDAHOST = 0x5,
-	SKL_DEVICE_NONE
-};
-
-/**
- * enum skl_interleaving - interleaving style
- *
- * @SKL_INTERLEAVING_PER_CHANNEL: [s1_ch1...s1_chN,...,sM_ch1...sM_chN]
- * @SKL_INTERLEAVING_PER_SAMPLE: [s1_ch1...sM_ch1,...,s1_chN...sM_chN]
- */
-enum skl_interleaving {
-	SKL_INTERLEAVING_PER_CHANNEL = 0,
-	SKL_INTERLEAVING_PER_SAMPLE = 1,
-};
-
-enum skl_sample_type {
-	SKL_SAMPLE_TYPE_INT_MSB = 0,
-	SKL_SAMPLE_TYPE_INT_LSB = 1,
-	SKL_SAMPLE_TYPE_INT_SIGNED = 2,
-	SKL_SAMPLE_TYPE_INT_UNSIGNED = 3,
-	SKL_SAMPLE_TYPE_FLOAT = 4
-};
-
-enum module_pin_type {
-	/* All pins of the module takes same PCM inputs or outputs
-	* e.g. mixout
-	*/
-	SKL_PIN_TYPE_HOMOGENEOUS,
-	/* All pins of the module takes different PCM inputs or outputs
-	* e.g mux
-	*/
-	SKL_PIN_TYPE_HETEROGENEOUS,
-};
-
-enum skl_module_param_type {
-	SKL_PARAM_DEFAULT = 0,
-	SKL_PARAM_INIT,
-	SKL_PARAM_SET,
-	SKL_PARAM_BIND
-};
-
-struct skl_dfw_algo_data {
-	u32 set_params:2;
-	u32 rsvd:30;
-	u32 param_id;
-	u32 max;
-	char params[0];
-} __packed;
-
-enum skl_tkn_dir {
-	SKL_DIR_IN,
-	SKL_DIR_OUT
-};
-
-enum skl_tuple_type {
-	SKL_TYPE_TUPLE,
-	SKL_TYPE_DATA
-};
-
-#endif
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index abf324747b29..f0d9793f872a 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -127,10 +127,17 @@ static void skl_clock_power_gating(struct device *dev, bool enable)
  */
 static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
 {
+	struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
+	struct hdac_ext_link *hlink;
 	int ret;
 
 	skl_enable_miscbdcge(bus->dev, false);
 	ret = snd_hdac_bus_init_chip(bus, full_reset);
+
+	/* Reset stream-to-link mapping */
+	list_for_each_entry(hlink, &ebus->hlink_list, list)
+		bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
+
 	skl_enable_miscbdcge(bus->dev, true);
 
 	return ret;
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig
index bc3c7b5ac752..132bb83f8e99 100644
--- a/sound/soc/kirkwood/Kconfig
+++ b/sound/soc/kirkwood/Kconfig
@@ -1,7 +1,6 @@
 config SND_KIRKWOOD_SOC
 	tristate "SoC Audio for the Marvell Kirkwood and Dove chips"
 	depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST
-	depends on HAS_DMA
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the Kirkwood I2S interface. You will also need to select the
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 5c68797f36c4..e731d40afcce 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -32,6 +32,26 @@ config SND_SOC_MT2701_WM8960
 	  Select Y if you have such device.
 	  If unsure select "N".
 
+config SND_SOC_MT6797
+	tristate "ASoC support for Mediatek MT6797 chip"
+	depends on ARCH_MEDIATEK
+	select SND_SOC_MEDIATEK
+	help
+	  This adds ASoC driver for Mediatek MT6797 boards
+	  that can be used with other codecs.
+	  Select Y if you have such device.
+	  If unsure select "N".
+
+config SND_SOC_MT6797_MT6351
+	tristate "ASoc Audio driver for MT6797 with MT6351 codec"
+	depends on SND_SOC_MT6797 && MTK_PMIC_WRAP
+	select SND_SOC_MT6351
+	help
+	  This adds ASoC driver for Mediatek MT6797 boards
+	  with the MT6351 codecs.
+	  Select Y if you have such device.
+	  If unsure select "N".
+
 config SND_SOC_MT8173
 	tristate "ASoC support for Mediatek MT8173 chip"
 	depends on ARCH_MEDIATEK
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
index 6bcab35dc828..3bb2c47532f4 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
 obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
+obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
 obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
diff --git a/sound/soc/mediatek/common/Makefile b/sound/soc/mediatek/common/Makefile
index a55d33bc7b01..cdadabc5fd16 100644
--- a/sound/soc/mediatek/common/Makefile
+++ b/sound/soc/mediatek/common/Makefile
@@ -1,16 +1,4 @@
-#
-# Copyright (C) 2015 MediaTek Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-
+# SPDX-License-Identifier: GPL-2.0
 # platform driver
 snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o
 obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
index c91e5f4cd902..cf4978be062f 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * mtk-afe-fe-dais.c  --  Mediatek afe fe dai operator
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Garlic Tseng <garlic.tseng@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/module.h>
@@ -44,8 +36,7 @@ int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
 		       struct snd_soc_dai *dai)
 {
 	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int memif_num = rtd->cpu_dai->id;
 	struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
@@ -107,8 +98,7 @@ void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
 			 struct snd_soc_dai *dai)
 {
 	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
 	int irq_id;
 
@@ -131,8 +121,7 @@ int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
 			 struct snd_soc_dai *dai)
 {
 	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
 	int msb_at_bit33 = 0;
 	int ret, fs = 0;
@@ -196,8 +185,7 @@ int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime * const runtime = substream->runtime;
-	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
-	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
 	struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];
 	const struct mtk_base_irq_data *irq_data = irqs->irq_data;
@@ -260,8 +248,7 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
 		       struct snd_soc_dai *dai)
 {
 	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
 	int hd_audio = 0;
 
@@ -333,7 +320,7 @@ EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release);
 
 int mtk_afe_dai_suspend(struct snd_soc_dai *dai)
 {
-	struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct device *dev = afe->dev;
 	struct regmap *regmap = afe->regmap;
 	int i;
@@ -358,7 +345,7 @@ EXPORT_SYMBOL_GPL(mtk_afe_dai_suspend);
 
 int mtk_afe_dai_resume(struct snd_soc_dai *dai)
 {
-	struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct device *dev = afe->dev;
 	struct regmap *regmap = afe->regmap;
 	int i = 0;
@@ -383,4 +370,3 @@ EXPORT_SYMBOL_GPL(mtk_afe_dai_resume);
 MODULE_DESCRIPTION("Mediatek simple fe dai operator");
 MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
 MODULE_LICENSE("GPL v2");
-
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.h b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
index 28cb17854da1..55074fb9861a 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.h
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
@@ -1,17 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * mtk-afe-fe-dais.h  --  Mediatek afe fe dai operator definition
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Garlic Tseng <garlic.tseng@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #ifndef _MTK_AFE_FE_DAI_H_
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
index 53215b52e4f2..51ec4ff6ed95 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * mtk-afe-platform-driver.c  --  Mediatek afe platform driver
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Garlic Tseng <garlic.tseng@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/module.h>
@@ -21,6 +13,86 @@
 #include "mtk-afe-platform-driver.h"
 #include "mtk-base-afe.h"
 
+int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe)
+{
+	struct snd_soc_dai_driver *sub_dai_drivers;
+	size_t num_dai_drivers = 0, dai_idx = 0;
+	int i;
+
+	if (!afe->sub_dais) {
+		dev_err(afe->dev, "%s(), sub_dais == NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	/* calcualte total dai driver size */
+	for (i = 0; i < afe->num_sub_dais; i++) {
+		if (afe->sub_dais[i].dai_drivers &&
+		    afe->sub_dais[i].num_dai_drivers != 0)
+			num_dai_drivers += afe->sub_dais[i].num_dai_drivers;
+	}
+
+	dev_info(afe->dev, "%s(), num of dai %zd\n", __func__, num_dai_drivers);
+
+	/* combine sub_dais */
+	afe->num_dai_drivers = num_dai_drivers;
+	afe->dai_drivers = devm_kcalloc(afe->dev,
+					num_dai_drivers,
+					sizeof(struct snd_soc_dai_driver),
+					GFP_KERNEL);
+	if (!afe->dai_drivers)
+		return -ENOMEM;
+
+	for (i = 0; i < afe->num_sub_dais; i++) {
+		if (afe->sub_dais[i].dai_drivers &&
+		    afe->sub_dais[i].num_dai_drivers != 0) {
+			sub_dai_drivers = afe->sub_dais[i].dai_drivers;
+			/* dai driver */
+			memcpy(&afe->dai_drivers[dai_idx],
+			       sub_dai_drivers,
+			       afe->sub_dais[i].num_dai_drivers *
+			       sizeof(struct snd_soc_dai_driver));
+			dai_idx += afe->sub_dais[i].num_dai_drivers;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai);
+
+int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
+{
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	int i;
+
+	if (!afe->sub_dais) {
+		dev_err(afe->dev, "%s(), sub_dais == NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < afe->num_sub_dais; i++) {
+		if (afe->sub_dais[i].controls)
+			snd_soc_add_component_controls(component,
+				afe->sub_dais[i].controls,
+				afe->sub_dais[i].num_controls);
+
+		if (afe->sub_dais[i].dapm_widgets)
+			snd_soc_dapm_new_controls(&component->dapm,
+				afe->sub_dais[i].dapm_widgets,
+				afe->sub_dais[i].num_dapm_widgets);
+
+		if (afe->sub_dais[i].dapm_routes)
+			snd_soc_dapm_add_routes(&component->dapm,
+				afe->sub_dais[i].dapm_routes,
+				afe->sub_dais[i].num_dapm_routes);
+	}
+
+	snd_soc_dapm_new_widgets(component->dapm.card);
+
+	return 0;
+
+}
+EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control);
+
 static snd_pcm_uframes_t mtk_afe_pcm_pointer
 			 (struct snd_pcm_substream *substream)
 {
@@ -56,28 +128,31 @@ POINTER_RETURN_FRAMES:
 	return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
 }
 
-static const struct snd_pcm_ops mtk_afe_pcm_ops = {
+const struct snd_pcm_ops mtk_afe_pcm_ops = {
 	.ioctl = snd_pcm_lib_ioctl,
 	.pointer = mtk_afe_pcm_pointer,
 };
+EXPORT_SYMBOL_GPL(mtk_afe_pcm_ops);
 
-static int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
+int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
 	size_t size;
-	struct snd_card *card = rtd->card->snd_card;
 	struct snd_pcm *pcm = rtd->pcm;
 	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 
 	size = afe->mtk_afe_hardware->buffer_bytes_max;
 	return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-						     card->dev, size, size);
+						     afe->dev,
+						     size, size);
 }
+EXPORT_SYMBOL_GPL(mtk_afe_pcm_new);
 
-static void mtk_afe_pcm_free(struct snd_pcm *pcm)
+void mtk_afe_pcm_free(struct snd_pcm *pcm)
 {
 	snd_pcm_lib_preallocate_free_for_all(pcm);
 }
+EXPORT_SYMBOL_GPL(mtk_afe_pcm_free);
 
 const struct snd_soc_component_driver mtk_afe_pcm_platform = {
 	.name = AFE_PCM_NAME,
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.h b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
index 8dcdbed959ea..88df6797732f 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.h
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
@@ -1,24 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * mtk-afe-platform-driver.h  --  Mediatek afe platform driver definition
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Garlic Tseng <garlic.tseng@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #ifndef _MTK_AFE_PLATFORM_DRIVER_H_
 #define _MTK_AFE_PLATFORM_DRIVER_H_
 
 #define AFE_PCM_NAME "mtk-afe-pcm"
+extern const struct snd_pcm_ops mtk_afe_pcm_ops;
 extern const struct snd_soc_component_driver mtk_afe_pcm_platform;
 
+struct mtk_base_afe;
+struct snd_pcm;
+struct snd_soc_component;
+struct snd_soc_pcm_runtime;
+
+
+int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd);
+void mtk_afe_pcm_free(struct snd_pcm *pcm);
+
+int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe);
+int mtk_afe_add_sub_dai_control(struct snd_soc_component *component);
 #endif
 
diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h
index 3a78f6f17195..bcf562f029b6 100644
--- a/sound/soc/mediatek/common/mtk-base-afe.h
+++ b/sound/soc/mediatek/common/mtk-base-afe.h
@@ -1,22 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * mtk-base-afe.h  --  Mediatek base afe structure
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Garlic Tseng <garlic.tseng@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #ifndef _MTK_BASE_AFE_H_
 #define _MTK_BASE_AFE_H_
 
+#define MTK_STREAM_NUM (SNDRV_PCM_STREAM_LAST + 1)
+
 struct mtk_base_memif_data {
 	int id;
 	const char *name;
@@ -54,6 +48,7 @@ struct mtk_base_irq_data {
 struct device;
 struct mtk_base_afe_memif;
 struct mtk_base_afe_irq;
+struct mtk_base_afe_dai;
 struct regmap;
 struct snd_pcm_substream;
 struct snd_soc_dai;
@@ -77,6 +72,11 @@ struct mtk_base_afe {
 	struct mtk_base_afe_irq *irqs;
 	int irqs_size;
 
+	struct mtk_base_afe_dai *sub_dais;
+	int num_sub_dais;
+	struct snd_soc_dai_driver *dai_drivers;
+	unsigned int num_dai_drivers;
+
 	const struct snd_pcm_hardware *mtk_afe_hardware;
 	int (*memif_fs)(struct snd_pcm_substream *substream,
 			unsigned int rate);
@@ -100,5 +100,17 @@ struct mtk_base_afe_irq {
 	int irq_occupyed;
 };
 
+struct mtk_base_afe_dai {
+	struct snd_soc_dai_driver *dai_drivers;
+	unsigned int num_dai_drivers;
+
+	const struct snd_kcontrol_new *controls;
+	unsigned int num_controls;
+	const struct snd_soc_dapm_widget *dapm_widgets;
+	unsigned int num_dapm_widgets;
+	const struct snd_soc_dapm_route *dapm_routes;
+	unsigned int num_dapm_routes;
+};
+
 #endif
 
diff --git a/sound/soc/mediatek/mt2701/Makefile b/sound/soc/mediatek/mt2701/Makefile
index c91deb6aca21..21d5e697cfa7 100644
--- a/sound/soc/mediatek/mt2701/Makefile
+++ b/sound/soc/mediatek/mt2701/Makefile
@@ -1,16 +1,4 @@
-#
-# Copyright (C) 2015 MediaTek Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-
+# SPDX-License-Identifier: GPL-2.0
 # platform driver
 snd-soc-mt2701-afe-objs := mt2701-afe-pcm.o mt2701-afe-clock-ctrl.o
 obj-$(CONFIG_SND_SOC_MT2701) += snd-soc-mt2701-afe.o
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
index 949fc3a1d025..ae620890bb3a 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
@@ -1,17 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * mt2701-afe-clock-ctrl.c  --  Mediatek 2701 afe clock ctrl
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Garlic Tseng <garlic.tseng@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ *	   Ryder Lee <ryder.lee@mediatek.com>
  */
 
 #include "mt2701-afe-common.h"
@@ -43,8 +36,9 @@ int mt2701_init_clock(struct mtk_base_afe *afe)
 	}
 
 	/* Get I2S related clocks */
-	for (i = 0; i < MT2701_I2S_NUM; i++) {
+	for (i = 0; i < afe_priv->soc->i2s_num; i++) {
 		struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i];
+		struct clk *i2s_ck;
 		char name[13];
 
 		snprintf(name, sizeof(name), "i2s%d_src_sel", i);
@@ -69,18 +63,20 @@ int mt2701_init_clock(struct mtk_base_afe *afe)
 		}
 
 		snprintf(name, sizeof(name), "i2so%d_hop_ck", i);
-		i2s_path->hop_ck[I2S_OUT] = devm_clk_get(afe->dev, name);
-		if (IS_ERR(i2s_path->hop_ck[I2S_OUT])) {
+		i2s_ck = devm_clk_get(afe->dev, name);
+		if (IS_ERR(i2s_ck)) {
 			dev_err(afe->dev, "failed to get %s\n", name);
-			return PTR_ERR(i2s_path->hop_ck[I2S_OUT]);
+			return PTR_ERR(i2s_ck);
 		}
+		i2s_path->hop_ck[SNDRV_PCM_STREAM_PLAYBACK] = i2s_ck;
 
 		snprintf(name, sizeof(name), "i2si%d_hop_ck", i);
-		i2s_path->hop_ck[I2S_IN] = devm_clk_get(afe->dev, name);
-		if (IS_ERR(i2s_path->hop_ck[I2S_IN])) {
+		i2s_ck = devm_clk_get(afe->dev, name);
+		if (IS_ERR(i2s_ck)) {
 			dev_err(afe->dev, "failed to get %s\n", name);
-			return PTR_ERR(i2s_path->hop_ck[I2S_IN]);
+			return PTR_ERR(i2s_ck);
 		}
+		i2s_path->hop_ck[SNDRV_PCM_STREAM_CAPTURE] = i2s_ck;
 
 		snprintf(name, sizeof(name), "asrc%d_out_ck", i);
 		i2s_path->asrco_ck = devm_clk_get(afe->dev, name);
@@ -102,10 +98,10 @@ int mt2701_init_clock(struct mtk_base_afe *afe)
 	return 0;
 }
 
-int mt2701_afe_enable_i2s(struct mtk_base_afe *afe, int id, int dir)
+int mt2701_afe_enable_i2s(struct mtk_base_afe *afe,
+			  struct mt2701_i2s_path *i2s_path,
+			  int dir)
 {
-	struct mt2701_afe_private *afe_priv = afe->platform_priv;
-	struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
 	int ret;
 
 	ret = clk_prepare_enable(i2s_path->asrco_ck);
@@ -128,11 +124,10 @@ err_hop_ck:
 	return ret;
 }
 
-void mt2701_afe_disable_i2s(struct mtk_base_afe *afe, int id, int dir)
+void mt2701_afe_disable_i2s(struct mtk_base_afe *afe,
+			    struct mt2701_i2s_path *i2s_path,
+			    int dir)
 {
-	struct mt2701_afe_private *afe_priv = afe->platform_priv;
-	struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
-
 	clk_disable_unprepare(i2s_path->hop_ck[dir]);
 	clk_disable_unprepare(i2s_path->asrco_ck);
 }
@@ -272,27 +267,32 @@ int mt2701_afe_disable_clock(struct mtk_base_afe *afe)
 	return 0;
 }
 
-void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain,
-			       int mclk)
+int mt2701_mclk_configuration(struct mtk_base_afe *afe, int id)
+
 {
 	struct mt2701_afe_private *priv = afe->platform_priv;
 	struct mt2701_i2s_path *i2s_path = &priv->i2s_path[id];
-	int ret;
+	int ret = -EINVAL;
 
 	/* Set mclk source */
-	if (domain == 0)
+	if (!(MT2701_PLL_DOMAIN_0_RATE % i2s_path->mclk_rate))
 		ret = clk_set_parent(i2s_path->sel_ck,
 				     priv->base_ck[MT2701_TOP_AUD_MCLK_SRC0]);
-	else
+	else if (!(MT2701_PLL_DOMAIN_1_RATE % i2s_path->mclk_rate))
 		ret = clk_set_parent(i2s_path->sel_ck,
 				     priv->base_ck[MT2701_TOP_AUD_MCLK_SRC1]);
 
-	if (ret)
-		dev_err(afe->dev, "failed to set domain%d mclk source %d\n",
-			domain, ret);
+	if (ret) {
+		dev_err(afe->dev, "failed to set mclk source\n");
+		return ret;
+	}
 
 	/* Set mclk divider */
-	ret = clk_set_rate(i2s_path->div_ck, mclk);
-	if (ret)
+	ret = clk_set_rate(i2s_path->div_ck, i2s_path->mclk_rate);
+	if (ret) {
 		dev_err(afe->dev, "failed to set mclk divider %d\n", ret);
+		return ret;
+	}
+
+	return 0;
 }
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h
index 15417d9d6597..580fead2ab05 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h
@@ -1,37 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * mt2701-afe-clock-ctrl.h  --  Mediatek 2701 afe clock ctrl definition
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Garlic Tseng <garlic.tseng@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ *	   Ryder Lee <ryder.lee@mediatek.com>
  */
 
 #ifndef _MT2701_AFE_CLOCK_CTRL_H_
 #define _MT2701_AFE_CLOCK_CTRL_H_
 
 struct mtk_base_afe;
+struct mt2701_i2s_path;
 
 int mt2701_init_clock(struct mtk_base_afe *afe);
 int mt2701_afe_enable_clock(struct mtk_base_afe *afe);
 int mt2701_afe_disable_clock(struct mtk_base_afe *afe);
 
-int mt2701_afe_enable_i2s(struct mtk_base_afe *afe, int id, int dir);
-void mt2701_afe_disable_i2s(struct mtk_base_afe *afe, int id, int dir);
+int mt2701_afe_enable_i2s(struct mtk_base_afe *afe,
+			  struct mt2701_i2s_path *path,
+			  int dir);
+void mt2701_afe_disable_i2s(struct mtk_base_afe *afe,
+			    struct mt2701_i2s_path *path,
+			    int dir);
 int mt2701_afe_enable_mclk(struct mtk_base_afe *afe, int id);
 void mt2701_afe_disable_mclk(struct mtk_base_afe *afe, int id);
 
 int mt2701_enable_btmrg_clk(struct mtk_base_afe *afe);
 void mt2701_disable_btmrg_clk(struct mtk_base_afe *afe);
 
-void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain,
-			       int mclk);
+int mt2701_mclk_configuration(struct mtk_base_afe *afe, int id);
 
 #endif
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
index ae8ddeacfbfe..d44faba27d3c 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-common.h
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
@@ -1,17 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * mt2701-afe-common.h  --  Mediatek 2701 audio driver definitions
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Garlic Tseng <garlic.tseng@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #ifndef _MT_2701_AFE_COMMON_H_
@@ -23,10 +15,8 @@
 #include "mt2701-reg.h"
 #include "../common/mtk-base-afe.h"
 
-#define MT2701_STREAM_DIR_NUM (SNDRV_PCM_STREAM_LAST + 1)
 #define MT2701_PLL_DOMAIN_0_RATE	98304000
 #define MT2701_PLL_DOMAIN_1_RATE	90316800
-#define MT2701_I2S_NUM	4
 
 enum {
 	MT2701_MEMIF_DL1,
@@ -100,30 +90,30 @@ struct mt2701_i2s_data {
 	int i2s_asrc_fs_mask;
 };
 
-enum mt2701_i2s_dir {
-	I2S_OUT,
-	I2S_IN,
-	I2S_DIR_NUM,
-};
-
 struct mt2701_i2s_path {
-	int dai_id;
 	int mclk_rate;
-	int on[I2S_DIR_NUM];
-	int occupied[I2S_DIR_NUM];
-	const struct mt2701_i2s_data *i2s_data[I2S_DIR_NUM];
-	struct clk *hop_ck[I2S_DIR_NUM];
+	int on[MTK_STREAM_NUM];
+	int occupied[MTK_STREAM_NUM];
+	const struct mt2701_i2s_data *i2s_data[MTK_STREAM_NUM];
+	struct clk *hop_ck[MTK_STREAM_NUM];
 	struct clk *sel_ck;
 	struct clk *div_ck;
 	struct clk *mclk_ck;
 	struct clk *asrco_ck;
 };
 
+struct mt2701_soc_variants {
+	bool has_one_heart_mode;
+	int i2s_num;
+};
+
 struct mt2701_afe_private {
-	struct mt2701_i2s_path i2s_path[MT2701_I2S_NUM];
+	struct mt2701_i2s_path *i2s_path;
 	struct clk *base_ck[MT2701_BASE_CLK_NUM];
 	struct clk *mrgif_ck;
-	bool mrg_enable[MT2701_STREAM_DIR_NUM];
+	bool mrg_enable[MTK_STREAM_NUM];
+
+	const struct mt2701_soc_variants *soc;
 };
 
 #endif
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index 73cce33fa439..828d11c30c6a 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -1,18 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Mediatek ALSA SoC AFE platform driver for 2701
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Garlic Tseng <garlic.tseng@mediatek.com>
- *             Ir Lian <ir.lian@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ *	   Ir Lian <ir.lian@mediatek.com>
+ *	   Ryder Lee <ryder.lee@mediatek.com>
  */
 
 #include <linux/delay.h>
@@ -20,6 +13,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <linux/pm_runtime.h>
 
 #include "mt2701-afe-common.h"
@@ -36,7 +30,7 @@ static const struct snd_pcm_hardware mt2701_afe_hardware = {
 	.period_bytes_max = 1024 * 256,
 	.periods_min = 4,
 	.periods_max = 1024,
-	.buffer_bytes_max = 1024 * 1024 * 16,
+	.buffer_bytes_max = 1024 * 1024,
 	.fifo_size = 0,
 };
 
@@ -68,9 +62,10 @@ static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = {
 
 static int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
 {
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
 	int val = num - MT2701_IO_I2S;
 
-	if (val < 0 || val >= MT2701_I2S_NUM) {
+	if (val < 0 || val >= afe_priv->soc->i2s_num) {
 		dev_err(afe->dev, "%s, num not available, num %d, val %d\n",
 			__func__, num, val);
 		return -EINVAL;
@@ -92,44 +87,26 @@ static int mt2701_afe_i2s_fs(unsigned int sample_rate)
 static int mt2701_afe_i2s_startup(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai)
 {
-	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
 	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	bool mode = afe_priv->soc->has_one_heart_mode;
 
 	if (i2s_num < 0)
 		return i2s_num;
 
-	return mt2701_afe_enable_mclk(afe, i2s_num);
+	return mt2701_afe_enable_mclk(afe, mode ? 1 : i2s_num);
 }
 
-static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream,
-					struct snd_soc_dai *dai,
-					int i2s_num,
-					int dir_invert)
+static int mt2701_afe_i2s_path_disable(struct mtk_base_afe *afe,
+				       struct mt2701_i2s_path *i2s_path,
+				       int stream_dir)
 {
-	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);
-	struct mt2701_afe_private *afe_priv = afe->platform_priv;
-	struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i2s_num];
-	const struct mt2701_i2s_data *i2s_data;
-	int stream_dir = substream->stream;
-
-	if (dir_invert)	{
-		if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
-			stream_dir = SNDRV_PCM_STREAM_CAPTURE;
-		else
-			stream_dir = SNDRV_PCM_STREAM_PLAYBACK;
-	}
-	i2s_data = i2s_path->i2s_data[stream_dir];
+	const struct mt2701_i2s_data *i2s_data = i2s_path->i2s_data[stream_dir];
 
-	i2s_path->on[stream_dir]--;
-	if (i2s_path->on[stream_dir] < 0) {
-		dev_warn(afe->dev, "i2s_path->on: %d, dir: %d\n",
-			 i2s_path->on[stream_dir], stream_dir);
+	if (--i2s_path->on[stream_dir] < 0)
 		i2s_path->on[stream_dir] = 0;
-	}
+
 	if (i2s_path->on[stream_dir])
 		return 0;
 
@@ -137,7 +114,7 @@ static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream,
 	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
 			   ASYS_I2S_CON_I2S_EN, 0);
 
-	mt2701_afe_disable_i2s(afe, i2s_num, stream_dir);
+	mt2701_afe_disable_i2s(afe, i2s_path, stream_dir);
 
 	return 0;
 }
@@ -145,12 +122,11 @@ static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream,
 static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *dai)
 {
-	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
 	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
 	struct mt2701_i2s_path *i2s_path;
+	bool mode = afe_priv->soc->has_one_heart_mode;
 
 	if (i2s_num < 0)
 		return;
@@ -160,50 +136,33 @@ static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream,
 	if (i2s_path->occupied[substream->stream])
 		i2s_path->occupied[substream->stream] = 0;
 	else
-		goto I2S_UNSTART;
+		goto exit;
 
-	mt2701_afe_i2s_path_shutdown(substream, dai, i2s_num, 0);
+	mt2701_afe_i2s_path_disable(afe, i2s_path, substream->stream);
 
 	/* need to disable i2s-out path when disable i2s-in */
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		mt2701_afe_i2s_path_shutdown(substream, dai, i2s_num, 1);
+		mt2701_afe_i2s_path_disable(afe, i2s_path, !substream->stream);
 
-I2S_UNSTART:
+exit:
 	/* disable mclk */
-	mt2701_afe_disable_mclk(afe, i2s_num);
+	mt2701_afe_disable_mclk(afe, mode ? 1 : i2s_num);
 }
 
-static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream,
-					  struct snd_soc_dai *dai,
-					  int i2s_num,
-					  int dir_invert)
+static int mt2701_i2s_path_enable(struct mtk_base_afe *afe,
+				  struct mt2701_i2s_path *i2s_path,
+				  int stream_dir, 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);
+	const struct mt2701_i2s_data *i2s_data = i2s_path->i2s_data[stream_dir];
 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
-	struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i2s_num];
-	const struct mt2701_i2s_data *i2s_data;
-	struct snd_pcm_runtime * const runtime = substream->runtime;
 	int reg, fs, w_len = 1; /* now we support bck 64bits only */
-	int stream_dir = substream->stream;
-	unsigned int mask = 0, val = 0;
-
-	if (dir_invert) {
-		if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
-			stream_dir = SNDRV_PCM_STREAM_CAPTURE;
-		else
-			stream_dir = SNDRV_PCM_STREAM_PLAYBACK;
-	}
-	i2s_data = i2s_path->i2s_data[stream_dir];
+	unsigned int mask, val;
 
 	/* no need to enable if already done */
-	i2s_path->on[stream_dir]++;
-
-	if (i2s_path->on[stream_dir] != 1)
+	if (++i2s_path->on[stream_dir] != 1)
 		return 0;
 
-	fs = mt2701_afe_i2s_fs(runtime->rate);
+	fs = mt2701_afe_i2s_fs(rate);
 
 	mask = ASYS_I2S_CON_FS |
 	       ASYS_I2S_CON_I2S_COUPLE_MODE | /* 0 */
@@ -217,22 +176,24 @@ static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream,
 	if (stream_dir == SNDRV_PCM_STREAM_CAPTURE) {
 		mask |= ASYS_I2S_IN_PHASE_FIX;
 		val |= ASYS_I2S_IN_PHASE_FIX;
+		reg = ASMI_TIMING_CON1;
+	} else {
+		if (afe_priv->soc->has_one_heart_mode) {
+			mask |= ASYS_I2S_CON_ONE_HEART_MODE;
+			val |= ASYS_I2S_CON_ONE_HEART_MODE;
+		}
+		reg = ASMO_TIMING_CON1;
 	}
 
 	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, mask, val);
 
-	if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
-		reg = ASMO_TIMING_CON1;
-	else
-		reg = ASMI_TIMING_CON1;
-
 	regmap_update_bits(afe->regmap, reg,
 			   i2s_data->i2s_asrc_fs_mask
 			   << i2s_data->i2s_asrc_fs_shift,
 			   fs << i2s_data->i2s_asrc_fs_shift);
 
 	/* enable i2s */
-	mt2701_afe_enable_i2s(afe, i2s_num, stream_dir);
+	mt2701_afe_enable_i2s(afe, i2s_path, stream_dir);
 
 	/* reset i2s hw status before enable */
 	regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
@@ -249,45 +210,33 @@ static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream,
 static int mt2701_afe_i2s_prepare(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai)
 {
-	int clk_domain;
-	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
-	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	int ret, i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
 	struct mt2701_i2s_path *i2s_path;
-	int mclk_rate;
+	bool mode = afe_priv->soc->has_one_heart_mode;
 
 	if (i2s_num < 0)
 		return i2s_num;
 
 	i2s_path = &afe_priv->i2s_path[i2s_num];
-	mclk_rate = i2s_path->mclk_rate;
 
 	if (i2s_path->occupied[substream->stream])
 		return -EBUSY;
+
+	ret = mt2701_mclk_configuration(afe, mode ? 1 : i2s_num);
+	if (ret)
+		return ret;
+
 	i2s_path->occupied[substream->stream] = 1;
 
-	if (MT2701_PLL_DOMAIN_0_RATE % mclk_rate == 0) {
-		clk_domain = 0;
-	} else if (MT2701_PLL_DOMAIN_1_RATE % mclk_rate == 0) {
-		clk_domain = 1;
-	} else {
-		dev_err(dai->dev, "%s() bad mclk rate %d\n",
-			__func__, mclk_rate);
-		return -EINVAL;
-	}
-	mt2701_mclk_configuration(afe, i2s_num, clk_domain, mclk_rate);
+	/* need to enable i2s-out path when enable i2s-in */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		mt2701_i2s_path_enable(afe, i2s_path, !substream->stream,
+				       substream->runtime->rate);
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		mt2701_i2s_path_prepare_enable(substream, dai, i2s_num, 0);
-	} else {
-		/* need to enable i2s-out path when enable i2s-in */
-		/* prepare for another direction "out" */
-		mt2701_i2s_path_prepare_enable(substream, dai, i2s_num, 1);
-		/* prepare for "in" */
-		mt2701_i2s_path_prepare_enable(substream, dai, i2s_num, 0);
-	}
+	mt2701_i2s_path_enable(afe, i2s_path, substream->stream,
+			       substream->runtime->rate);
 
 	return 0;
 }
@@ -295,30 +244,29 @@ static int mt2701_afe_i2s_prepare(struct snd_pcm_substream *substream,
 static int mt2701_afe_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 				     unsigned int freq, int dir)
 {
-	struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
 	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
+	bool mode = afe_priv->soc->has_one_heart_mode;
 
 	if (i2s_num < 0)
 		return i2s_num;
 
 	/* mclk */
 	if (dir == SND_SOC_CLOCK_IN) {
-		dev_warn(dai->dev,
-			 "%s() warning: mt2701 doesn't support mclk input\n",
-			__func__);
+		dev_warn(dai->dev, "The SoCs doesn't support mclk input\n");
 		return -EINVAL;
 	}
-	afe_priv->i2s_path[i2s_num].mclk_rate = freq;
+
+	afe_priv->i2s_path[mode ? 1 : i2s_num].mclk_rate = freq;
+
 	return 0;
 }
 
 static int mt2701_btmrg_startup(struct snd_pcm_substream *substream,
 				struct snd_soc_dai *dai)
 {
-	struct 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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
 	int ret;
 
@@ -327,6 +275,7 @@ static int mt2701_btmrg_startup(struct snd_pcm_substream *substream,
 		return ret;
 
 	afe_priv->mrg_enable[substream->stream] = 1;
+
 	return 0;
 }
 
@@ -334,17 +283,14 @@ static int mt2701_btmrg_hw_params(struct snd_pcm_substream *substream,
 				  struct snd_pcm_hw_params *params,
 				  struct snd_soc_dai *dai)
 {
-	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	int stream_fs;
 	u32 val, msk;
 
 	stream_fs = params_rate(params);
 
-	if ((stream_fs != 8000) && (stream_fs != 16000)) {
-		dev_err(afe->dev, "%s() btmgr not support this stream_fs %d\n",
-			__func__, stream_fs);
+	if (stream_fs != 8000 && stream_fs != 16000) {
+		dev_err(afe->dev, "unsupported rate %d\n", stream_fs);
 		return -EINVAL;
 	}
 
@@ -378,9 +324,7 @@ static int mt2701_btmrg_hw_params(struct snd_pcm_substream *substream,
 static void mt2701_btmrg_shutdown(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai)
 {
-	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
 
 	/* if the other direction stream is not occupied */
@@ -393,28 +337,26 @@ static void mt2701_btmrg_shutdown(struct snd_pcm_substream *substream,
 				   AFE_MRGIF_CON_MRG_I2S_EN, 0);
 		mt2701_disable_btmrg_clk(afe);
 	}
+
 	afe_priv->mrg_enable[substream->stream] = 0;
 }
 
 static int mt2701_simple_fe_startup(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *dai)
 {
-	struct 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 stream_dir = substream->stream;
-	int memif_num = rtd->cpu_dai->id;
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mtk_base_afe_memif *memif_tmp;
+	int stream_dir = substream->stream;
 
 	/* can't run single DL & DLM at the same time */
 	if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) {
 		memif_tmp = &afe->memif[MT2701_MEMIF_DLM];
 		if (memif_tmp->substream) {
-			dev_warn(afe->dev, "%s memif is not available, stream_dir %d, memif_num %d\n",
-				 __func__, stream_dir, memif_num);
+			dev_warn(afe->dev, "memif is not available");
 			return -EBUSY;
 		}
 	}
+
 	return mtk_afe_fe_startup(substream, dai);
 }
 
@@ -422,27 +364,23 @@ static int mt2701_simple_fe_hw_params(struct snd_pcm_substream *substream,
 				      struct snd_pcm_hw_params *params,
 				      struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = 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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	int stream_dir = substream->stream;
 
 	/* single DL use PAIR_INTERLEAVE */
-	if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) {
+	if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
 		regmap_update_bits(afe->regmap,
 				   AFE_MEMIF_PBUF_SIZE,
 				   AFE_MEMIF_PBUF_SIZE_DLM_MASK,
 				   AFE_MEMIF_PBUF_SIZE_PAIR_INTERLEAVE);
-	}
+
 	return mtk_afe_fe_hw_params(substream, params, dai);
 }
 
 static int mt2701_dlm_fe_startup(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
-	struct 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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mtk_base_afe_memif *memif_tmp;
 	const struct mtk_base_memif_data *memif_data;
 	int i;
@@ -468,9 +406,7 @@ static int mt2701_dlm_fe_startup(struct snd_pcm_substream *substream,
 static void mt2701_dlm_fe_shutdown(struct snd_pcm_substream *substream,
 				   struct snd_soc_dai *dai)
 {
-	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	const struct mtk_base_memif_data *memif_data;
 	int i;
 
@@ -481,6 +417,7 @@ static void mt2701_dlm_fe_shutdown(struct snd_pcm_substream *substream,
 				   1 << memif_data->agent_disable_shift,
 				   1 << memif_data->agent_disable_shift);
 	}
+
 	return mtk_afe_fe_shutdown(substream, dai);
 }
 
@@ -488,9 +425,7 @@ static int mt2701_dlm_fe_hw_params(struct snd_pcm_substream *substream,
 				   struct snd_pcm_hw_params *params,
 				   struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = 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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	int channels = params_channels(params);
 
 	regmap_update_bits(afe->regmap,
@@ -512,9 +447,7 @@ static int mt2701_dlm_fe_hw_params(struct snd_pcm_substream *substream,
 static int mt2701_dlm_fe_trigger(struct snd_pcm_substream *substream,
 				 int cmd, struct snd_soc_dai *dai)
 {
-	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mtk_base_afe_memif *memif_tmp = &afe->memif[MT2701_MEMIF_DL1];
 
 	switch (cmd) {
@@ -547,6 +480,7 @@ static int mt2701_memif_fs(struct snd_pcm_substream *substream,
 		fs = mt2701_afe_i2s_fs(rate);
 	else
 		fs = (rate == 16000 ? 1 : 0);
+
 	return fs;
 }
 
@@ -1024,7 +958,17 @@ static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = {
 	{ "O31", "I35 Switch", "I35" },
 };
 
+static int mt2701_afe_pcm_probe(struct snd_soc_component *component)
+{
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_init_regmap(component, afe->regmap);
+
+	return 0;
+}
+
 static const struct snd_soc_component_driver mt2701_afe_pcm_dai_component = {
+	.probe = mt2701_afe_pcm_probe,
 	.name = "mt2701-afe-pcm-dai",
 	.dapm_widgets = mt2701_afe_pcm_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(mt2701_afe_pcm_widgets),
@@ -1324,63 +1268,24 @@ static const struct mtk_base_irq_data irq_data[MT2701_IRQ_ASYS_END] = {
 	}
 };
 
-static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = {
+static const struct mt2701_i2s_data mt2701_i2s_data[][2] = {
 	{
-		{
-			.i2s_ctrl_reg = ASYS_I2SO1_CON,
-			.i2s_asrc_fs_shift = 0,
-			.i2s_asrc_fs_mask = 0x1f,
-
-		},
-		{
-			.i2s_ctrl_reg = ASYS_I2SIN1_CON,
-			.i2s_asrc_fs_shift = 0,
-			.i2s_asrc_fs_mask = 0x1f,
-
-		},
+		{ ASYS_I2SO1_CON, 0, 0x1f },
+		{ ASYS_I2SIN1_CON, 0, 0x1f },
 	},
 	{
-		{
-			.i2s_ctrl_reg = ASYS_I2SO2_CON,
-			.i2s_asrc_fs_shift = 5,
-			.i2s_asrc_fs_mask = 0x1f,
-
-		},
-		{
-			.i2s_ctrl_reg = ASYS_I2SIN2_CON,
-			.i2s_asrc_fs_shift = 5,
-			.i2s_asrc_fs_mask = 0x1f,
-
-		},
+		{ ASYS_I2SO2_CON, 5, 0x1f },
+		{ ASYS_I2SIN2_CON, 5, 0x1f },
 	},
 	{
-		{
-			.i2s_ctrl_reg = ASYS_I2SO3_CON,
-			.i2s_asrc_fs_shift = 10,
-			.i2s_asrc_fs_mask = 0x1f,
-
-		},
-		{
-			.i2s_ctrl_reg = ASYS_I2SIN3_CON,
-			.i2s_asrc_fs_shift = 10,
-			.i2s_asrc_fs_mask = 0x1f,
-
-		},
+		{ ASYS_I2SO3_CON, 10, 0x1f },
+		{ ASYS_I2SIN3_CON, 10, 0x1f },
 	},
 	{
-		{
-			.i2s_ctrl_reg = ASYS_I2SO4_CON,
-			.i2s_asrc_fs_shift = 15,
-			.i2s_asrc_fs_mask = 0x1f,
-
-		},
-		{
-			.i2s_ctrl_reg = ASYS_I2SIN4_CON,
-			.i2s_asrc_fs_shift = 15,
-			.i2s_asrc_fs_mask = 0x1f,
-
-		},
+		{ ASYS_I2SO4_CON, 15, 0x1f },
+		{ ASYS_I2SIN4_CON, 15, 0x1f },
 	},
+	/* TODO - extend control registers supported by newer SoCs */
 };
 
 static irqreturn_t mt2701_asys_isr(int irq_id, void *dev)
@@ -1398,10 +1303,12 @@ static irqreturn_t mt2701_asys_isr(int irq_id, void *dev)
 		memif = &afe->memif[id];
 		if (memif->irq_usage < 0)
 			continue;
+
 		irq = &afe->irqs[memif->irq_usage];
-		if (status & 1 << (irq->irq_data->irq_clr_shift))
+		if (status & 1 << irq->irq_data->irq_clr_shift)
 			snd_pcm_period_elapsed(memif->substream);
 	}
+
 	return IRQ_HANDLED;
 }
 
@@ -1419,22 +1326,6 @@ static int mt2701_afe_runtime_resume(struct device *dev)
 	return mt2701_afe_enable_clock(afe);
 }
 
-static int mt2701_afe_add_component(struct mtk_base_afe *afe)
-{
-	struct snd_soc_component *component;
-
-	component = kzalloc(sizeof(*component), GFP_KERNEL);
-	if (!component)
-		return -ENOMEM;
-
-	component->regmap = afe->regmap;
-
-	return snd_soc_add_component(afe->dev, component,
-				     &mt2701_afe_pcm_dai_component,
-				     mt2701_afe_pcm_dais,
-				     ARRAY_SIZE(mt2701_afe_pcm_dais));
-}
-
 static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
 {
 	struct mtk_base_afe *afe;
@@ -1452,9 +1343,16 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	afe_priv = afe->platform_priv;
+	afe_priv->soc = of_device_get_match_data(&pdev->dev);
 	afe->dev = &pdev->dev;
 	dev = afe->dev;
 
+	afe_priv->i2s_path = devm_kzalloc(dev, afe_priv->soc->i2s_num *
+					  sizeof(struct mt2701_i2s_path),
+					  GFP_KERNEL);
+	if (!afe_priv->i2s_path)
+		return -ENOMEM;
+
 	irq_id = platform_get_irq_byname(pdev, "asys");
 	if (irq_id < 0) {
 		dev_err(dev, "unable to get ASYS IRQ\n");
@@ -1499,11 +1397,11 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
 		afe->irqs[i].irq_data = &irq_data[i];
 
 	/* I2S initialize */
-	for (i = 0; i < MT2701_I2S_NUM; i++) {
-		afe_priv->i2s_path[i].i2s_data[I2S_OUT]
-			= &mt2701_i2s_data[i][I2S_OUT];
-		afe_priv->i2s_path[i].i2s_data[I2S_IN]
-			= &mt2701_i2s_data[i][I2S_IN];
+	for (i = 0; i < afe_priv->soc->i2s_num; i++) {
+		afe_priv->i2s_path[i].i2s_data[SNDRV_PCM_STREAM_PLAYBACK] =
+			&mt2701_i2s_data[i][SNDRV_PCM_STREAM_PLAYBACK];
+		afe_priv->i2s_path[i].i2s_data[SNDRV_PCM_STREAM_CAPTURE] =
+			&mt2701_i2s_data[i][SNDRV_PCM_STREAM_CAPTURE];
 	}
 
 	afe->mtk_afe_hardware = &mt2701_afe_hardware;
@@ -1538,7 +1436,10 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
 		goto err_platform;
 	}
 
-	ret = mt2701_afe_add_component(afe);
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					 &mt2701_afe_pcm_dai_component,
+					 mt2701_afe_pcm_dais,
+					 ARRAY_SIZE(mt2701_afe_pcm_dais));
 	if (ret) {
 		dev_warn(dev, "err_dai_component\n");
 		goto err_platform;
@@ -1564,8 +1465,18 @@ static int mt2701_afe_pcm_dev_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct mt2701_soc_variants mt2701_soc_v1 = {
+	.i2s_num = 4,
+};
+
+static const struct mt2701_soc_variants mt2701_soc_v2 = {
+	.has_one_heart_mode = true,
+	.i2s_num = 4,
+};
+
 static const struct of_device_id mt2701_afe_pcm_dt_match[] = {
-	{ .compatible = "mediatek,mt2701-audio", },
+	{ .compatible = "mediatek,mt2701-audio", .data = &mt2701_soc_v1 },
+	{ .compatible = "mediatek,mt7622-audio", .data = &mt2701_soc_v2 },
 	{},
 };
 MODULE_DEVICE_TABLE(of, mt2701_afe_pcm_dt_match);
diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
index 70f61d53fe05..666282b865a8 100644
--- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c
+++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * mt2701-cs42448.c  --  MT2701 CS42448 ALSA SoC machine driver
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Ir Lian <ir.lian@mediatek.com>
- *              Garlic Tseng <garlic.tseng@mediatek.com>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ *	   Garlic Tseng <garlic.tseng@mediatek.com>
  */
 
 #include <linux/module.h>
diff --git a/sound/soc/mediatek/mt2701/mt2701-reg.h b/sound/soc/mediatek/mt2701/mt2701-reg.h
index 18e676974f22..c84d14cdd7ae 100644
--- a/sound/soc/mediatek/mt2701/mt2701-reg.h
+++ b/sound/soc/mediatek/mt2701/mt2701-reg.h
@@ -1,17 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * mt2701-reg.h  --  Mediatek 2701 audio driver reg definition
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Garlic Tseng <garlic.tseng@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #ifndef _MT2701_REG_H_
@@ -138,6 +130,7 @@
 #define ASYS_I2S_CON_FS_SET(x)		((x) << 8)
 #define ASYS_I2S_CON_RESET		(0x1 << 30)
 #define ASYS_I2S_CON_I2S_EN		(0x1 << 0)
+#define ASYS_I2S_CON_ONE_HEART_MODE	(0x1 << 16)
 #define ASYS_I2S_CON_I2S_COUPLE_MODE	(0x1 << 17)
 /* 0:EIAJ 1:I2S */
 #define ASYS_I2S_CON_I2S_MODE		(0x1 << 3)
diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c
index a08ce2323bdc..89f34efd9747 100644
--- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c
+++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * mt2701-wm8960.c  --  MT2701 WM8960 ALSA SoC machine driver
  *
  * Copyright (c) 2017 MediaTek Inc.
  * Author: Ryder Lee <ryder.lee@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/module.h>
diff --git a/sound/soc/mediatek/mt6797/Makefile b/sound/soc/mediatek/mt6797/Makefile
new file mode 100644
index 000000000000..bf6e179ea93f
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/Makefile
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# platform driver
+snd-soc-mt6797-afe-objs := \
+	mt6797-afe-pcm.o \
+	mt6797-afe-clk.o \
+	mt6797-dai-pcm.o \
+	mt6797-dai-hostless.o \
+	mt6797-dai-adda.o
+
+obj-$(CONFIG_SND_SOC_MT6797) += snd-soc-mt6797-afe.o
+
+# machine driver
+obj-$(CONFIG_SND_SOC_MT6797_MT6351) += mt6797-mt6351.o
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-clk.c b/sound/soc/mediatek/mt6797/mt6797-afe-clk.c
new file mode 100644
index 000000000000..6f3e6acfcfab
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-clk.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt6797-afe-clk.c  --  Mediatek 6797 afe clock ctrl
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/clk.h>
+
+#include "mt6797-afe-common.h"
+#include "mt6797-afe-clk.h"
+
+enum {
+	CLK_INFRA_SYS_AUD,
+	CLK_INFRA_SYS_AUD_26M,
+	CLK_TOP_MUX_AUD,
+	CLK_TOP_MUX_AUD_BUS,
+	CLK_TOP_SYSPLL3_D4,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_CLK26M,
+	CLK_NUM
+};
+
+static const char *aud_clks[CLK_NUM] = {
+	[CLK_INFRA_SYS_AUD] = "infra_sys_audio_clk",
+	[CLK_INFRA_SYS_AUD_26M] = "infra_sys_audio_26m",
+	[CLK_TOP_MUX_AUD] = "top_mux_audio",
+	[CLK_TOP_MUX_AUD_BUS] = "top_mux_aud_intbus",
+	[CLK_TOP_SYSPLL3_D4] = "top_sys_pll3_d4",
+	[CLK_TOP_SYSPLL1_D4] = "top_sys_pll1_d4",
+	[CLK_CLK26M] = "top_clk26m_clk",
+};
+
+int mt6797_init_clock(struct mtk_base_afe *afe)
+{
+	struct mt6797_afe_private *afe_priv = afe->platform_priv;
+	int i;
+
+	afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk),
+				     GFP_KERNEL);
+	if (!afe_priv->clk)
+		return -ENOMEM;
+
+	for (i = 0; i < CLK_NUM; i++) {
+		afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
+		if (IS_ERR(afe_priv->clk[i])) {
+			dev_err(afe->dev, "%s(), devm_clk_get %s fail, ret %ld\n",
+				__func__, aud_clks[i],
+				PTR_ERR(afe_priv->clk[i]));
+			return PTR_ERR(afe_priv->clk[i]);
+		}
+	}
+
+	return 0;
+}
+
+int mt6797_afe_enable_clock(struct mtk_base_afe *afe)
+{
+	struct mt6797_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUD]);
+	if (ret) {
+		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[CLK_INFRA_SYS_AUD], ret);
+		goto CLK_INFRA_SYS_AUDIO_ERR;
+	}
+
+	ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUD_26M]);
+	if (ret) {
+		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[CLK_INFRA_SYS_AUD_26M], ret);
+		goto CLK_INFRA_SYS_AUD_26M_ERR;
+	}
+
+	ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD]);
+	if (ret) {
+		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[CLK_TOP_MUX_AUD], ret);
+		goto CLK_MUX_AUDIO_ERR;
+	}
+
+	ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD],
+			     afe_priv->clk[CLK_CLK26M]);
+	if (ret) {
+		dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n",
+			__func__, aud_clks[CLK_TOP_MUX_AUD],
+			aud_clks[CLK_CLK26M], ret);
+		goto CLK_MUX_AUDIO_ERR;
+	}
+
+	ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_BUS]);
+	if (ret) {
+		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[CLK_TOP_MUX_AUD_BUS], ret);
+		goto CLK_MUX_AUDIO_INTBUS_ERR;
+	}
+
+	return ret;
+
+CLK_MUX_AUDIO_INTBUS_ERR:
+	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_BUS]);
+CLK_MUX_AUDIO_ERR:
+	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD]);
+CLK_INFRA_SYS_AUD_26M_ERR:
+	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD_26M]);
+CLK_INFRA_SYS_AUDIO_ERR:
+	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD]);
+
+	return 0;
+}
+
+int mt6797_afe_disable_clock(struct mtk_base_afe *afe)
+{
+	struct mt6797_afe_private *afe_priv = afe->platform_priv;
+
+	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_BUS]);
+	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD]);
+	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD_26M]);
+	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD]);
+
+	return 0;
+}
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-clk.h b/sound/soc/mediatek/mt6797/mt6797-afe-clk.h
new file mode 100644
index 000000000000..a6f0cb572711
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-clk.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt6797-afe-clk.h  --  Mediatek 6797 afe clock ctrl definition
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef _MT6797_AFE_CLK_H_
+#define _MT6797_AFE_CLK_H_
+
+struct mtk_base_afe;
+
+int mt6797_init_clock(struct mtk_base_afe *afe);
+int mt6797_afe_enable_clock(struct mtk_base_afe *afe);
+int mt6797_afe_disable_clock(struct mtk_base_afe *afe);
+#endif
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-common.h b/sound/soc/mediatek/mt6797/mt6797-afe-common.h
new file mode 100644
index 000000000000..22eb7b455cf1
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-common.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt6797-afe-common.h  --  Mediatek 6797 audio driver definitions
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef _MT_6797_AFE_COMMON_H_
+#define _MT_6797_AFE_COMMON_H_
+
+#include <sound/soc.h>
+#include <linux/regmap.h>
+#include "../common/mtk-base-afe.h"
+
+enum {
+	MT6797_MEMIF_DL1,
+	MT6797_MEMIF_DL2,
+	MT6797_MEMIF_DL3,
+	MT6797_MEMIF_VUL,
+	MT6797_MEMIF_AWB,
+	MT6797_MEMIF_VUL12,
+	MT6797_MEMIF_DAI,
+	MT6797_MEMIF_MOD_DAI,
+	MT6797_MEMIF_NUM,
+	MT6797_DAI_ADDA = MT6797_MEMIF_NUM,
+	MT6797_DAI_PCM_1,
+	MT6797_DAI_PCM_2,
+	MT6797_DAI_HOSTLESS_LPBK,
+	MT6797_DAI_HOSTLESS_SPEECH,
+	MT6797_DAI_NUM,
+};
+
+enum {
+	MT6797_IRQ_1,
+	MT6797_IRQ_2,
+	MT6797_IRQ_3,
+	MT6797_IRQ_4,
+	MT6797_IRQ_7,
+	MT6797_IRQ_NUM,
+};
+
+struct clk;
+
+struct mt6797_afe_private {
+	struct clk **clk;
+};
+
+unsigned int mt6797_general_rate_transform(struct device *dev,
+					   unsigned int rate);
+unsigned int mt6797_rate_transform(struct device *dev,
+				   unsigned int rate, int aud_blk);
+
+/* dai register */
+int mt6797_dai_adda_register(struct mtk_base_afe *afe);
+int mt6797_dai_pcm_register(struct mtk_base_afe *afe);
+int mt6797_dai_hostless_register(struct mtk_base_afe *afe);
+#endif
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
new file mode 100644
index 000000000000..6c5dd9fc9976
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
@@ -0,0 +1,914 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Mediatek ALSA SoC AFE platform driver for 6797
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+
+#include "mt6797-afe-common.h"
+#include "mt6797-afe-clk.h"
+#include "mt6797-interconnection.h"
+#include "mt6797-reg.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+enum {
+	MTK_AFE_RATE_8K = 0,
+	MTK_AFE_RATE_11K = 1,
+	MTK_AFE_RATE_12K = 2,
+	MTK_AFE_RATE_384K = 3,
+	MTK_AFE_RATE_16K = 4,
+	MTK_AFE_RATE_22K = 5,
+	MTK_AFE_RATE_24K = 6,
+	MTK_AFE_RATE_130K = 7,
+	MTK_AFE_RATE_32K = 8,
+	MTK_AFE_RATE_44K = 9,
+	MTK_AFE_RATE_48K = 10,
+	MTK_AFE_RATE_88K = 11,
+	MTK_AFE_RATE_96K = 12,
+	MTK_AFE_RATE_174K = 13,
+	MTK_AFE_RATE_192K = 14,
+	MTK_AFE_RATE_260K = 15,
+};
+
+enum {
+	MTK_AFE_DAI_MEMIF_RATE_8K = 0,
+	MTK_AFE_DAI_MEMIF_RATE_16K = 1,
+	MTK_AFE_DAI_MEMIF_RATE_32K = 2,
+};
+
+enum {
+	MTK_AFE_PCM_RATE_8K = 0,
+	MTK_AFE_PCM_RATE_16K = 1,
+	MTK_AFE_PCM_RATE_32K = 2,
+	MTK_AFE_PCM_RATE_48K = 3,
+};
+
+unsigned int mt6797_general_rate_transform(struct device *dev,
+					   unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return MTK_AFE_RATE_8K;
+	case 11025:
+		return MTK_AFE_RATE_11K;
+	case 12000:
+		return MTK_AFE_RATE_12K;
+	case 16000:
+		return MTK_AFE_RATE_16K;
+	case 22050:
+		return MTK_AFE_RATE_22K;
+	case 24000:
+		return MTK_AFE_RATE_24K;
+	case 32000:
+		return MTK_AFE_RATE_32K;
+	case 44100:
+		return MTK_AFE_RATE_44K;
+	case 48000:
+		return MTK_AFE_RATE_48K;
+	case 88200:
+		return MTK_AFE_RATE_88K;
+	case 96000:
+		return MTK_AFE_RATE_96K;
+	case 130000:
+		return MTK_AFE_RATE_130K;
+	case 176400:
+		return MTK_AFE_RATE_174K;
+	case 192000:
+		return MTK_AFE_RATE_192K;
+	case 260000:
+		return MTK_AFE_RATE_260K;
+	default:
+		dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
+			 __func__, rate, MTK_AFE_RATE_48K);
+		return MTK_AFE_RATE_48K;
+	}
+}
+
+static unsigned int dai_memif_rate_transform(struct device *dev,
+					     unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return MTK_AFE_DAI_MEMIF_RATE_8K;
+	case 16000:
+		return MTK_AFE_DAI_MEMIF_RATE_16K;
+	case 32000:
+		return MTK_AFE_DAI_MEMIF_RATE_32K;
+	default:
+		dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
+			 __func__, rate, MTK_AFE_DAI_MEMIF_RATE_16K);
+		return MTK_AFE_DAI_MEMIF_RATE_16K;
+	}
+}
+
+unsigned int mt6797_rate_transform(struct device *dev,
+				   unsigned int rate, int aud_blk)
+{
+	switch (aud_blk) {
+	case MT6797_MEMIF_DAI:
+	case MT6797_MEMIF_MOD_DAI:
+		return dai_memif_rate_transform(dev, rate);
+	default:
+		return mt6797_general_rate_transform(dev, rate);
+	}
+}
+
+static const struct snd_pcm_hardware mt6797_afe_hardware = {
+	.info = SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE |
+		   SNDRV_PCM_FMTBIT_S24_LE |
+		   SNDRV_PCM_FMTBIT_S32_LE,
+	.period_bytes_min = 256,
+	.period_bytes_max = 4 * 48 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
+	.buffer_bytes_max = 8 * 48 * 1024,
+	.fifo_size = 0,
+};
+
+static int mt6797_memif_fs(struct snd_pcm_substream *substream,
+			   unsigned int rate)
+{
+	struct snd_soc_pcm_runtime *rtd = 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 = rtd->cpu_dai->id;
+
+	return mt6797_rate_transform(afe->dev, rate, id);
+}
+
+static int mt6797_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
+{
+	struct snd_soc_pcm_runtime *rtd = 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 mt6797_general_rate_transform(afe->dev, rate);
+}
+
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+		       SNDRV_PCM_RATE_88200 |\
+		       SNDRV_PCM_RATE_96000 |\
+		       SNDRV_PCM_RATE_176400 |\
+		       SNDRV_PCM_RATE_192000)
+
+#define MTK_PCM_DAI_RATES (SNDRV_PCM_RATE_8000 |\
+			   SNDRV_PCM_RATE_16000 |\
+			   SNDRV_PCM_RATE_32000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mt6797_memif_dai_driver[] = {
+	/* FE DAIs: memory intefaces to CPU */
+	{
+		.name = "DL1",
+		.id = MT6797_MEMIF_DL1,
+		.playback = {
+			.stream_name = "DL1",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "DL2",
+		.id = MT6797_MEMIF_DL2,
+		.playback = {
+			.stream_name = "DL2",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "DL3",
+		.id = MT6797_MEMIF_DL3,
+		.playback = {
+			.stream_name = "DL3",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL1",
+		.id = MT6797_MEMIF_VUL12,
+		.capture = {
+			.stream_name = "UL1",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL2",
+		.id = MT6797_MEMIF_AWB,
+		.capture = {
+			.stream_name = "UL2",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL3",
+		.id = MT6797_MEMIF_VUL,
+		.capture = {
+			.stream_name = "UL3",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL_MONO_1",
+		.id = MT6797_MEMIF_MOD_DAI,
+		.capture = {
+			.stream_name = "UL_MONO_1",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = MTK_PCM_DAI_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL_MONO_2",
+		.id = MT6797_MEMIF_DAI,
+		.capture = {
+			.stream_name = "UL_MONO_2",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = MTK_PCM_DAI_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+};
+
+/* dma widget & routes*/
+static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN21,
+				    I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN22,
+				    I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN5,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN5,
+				    I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN5,
+				    I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN5,
+				    I_DL3_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN6,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN6,
+				    I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN6,
+				    I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN6,
+				    I_DL3_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN9,
+				    I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN10,
+				    I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_mono_1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN12,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN12,
+				    I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_mono_2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN11,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN11,
+				    I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mt6797_memif_widgets[] = {
+	/* memif */
+	SND_SOC_DAPM_MIXER("UL1_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul1_ch1_mix, ARRAY_SIZE(memif_ul1_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL1_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul1_ch2_mix, ARRAY_SIZE(memif_ul1_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL2_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul2_ch1_mix, ARRAY_SIZE(memif_ul2_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL2_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul2_ch2_mix, ARRAY_SIZE(memif_ul2_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL3_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul3_ch1_mix, ARRAY_SIZE(memif_ul3_ch1_mix)),
+	SND_SOC_DAPM_MIXER("UL3_CH2", SND_SOC_NOPM, 0, 0,
+			   memif_ul3_ch2_mix, ARRAY_SIZE(memif_ul3_ch2_mix)),
+
+	SND_SOC_DAPM_MIXER("UL_MONO_1_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul_mono_1_mix,
+			   ARRAY_SIZE(memif_ul_mono_1_mix)),
+
+	SND_SOC_DAPM_MIXER("UL_MONO_2_CH1", SND_SOC_NOPM, 0, 0,
+			   memif_ul_mono_2_mix,
+			   ARRAY_SIZE(memif_ul_mono_2_mix)),
+};
+
+static const struct snd_soc_dapm_route mt6797_memif_routes[] = {
+	/* capture */
+	{"UL1", NULL, "UL1_CH1"},
+	{"UL1", NULL, "UL1_CH2"},
+	{"UL1_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL1_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+	{"UL2", NULL, "UL2_CH1"},
+	{"UL2", NULL, "UL2_CH2"},
+	{"UL2_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL2_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+	{"UL3", NULL, "UL3_CH1"},
+	{"UL3", NULL, "UL3_CH2"},
+	{"UL3_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL3_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+	{"UL_MONO_1", NULL, "UL_MONO_1_CH1"},
+	{"UL_MONO_1_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL_MONO_1_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+
+	{"UL_MONO_2", NULL, "UL_MONO_2_CH1"},
+	{"UL_MONO_2_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+	{"UL_MONO_2_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+};
+
+static const struct snd_soc_component_driver mt6797_afe_pcm_dai_component = {
+	.name = "mt6797-afe-pcm-dai",
+};
+
+static const struct mtk_base_memif_data memif_data[MT6797_MEMIF_NUM] = {
+	[MT6797_MEMIF_DL1] = {
+		.name = "DL1",
+		.id = MT6797_MEMIF_DL1,
+		.reg_ofs_base = AFE_DL1_BASE,
+		.reg_ofs_cur = AFE_DL1_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = DL1_MODE_SFT,
+		.fs_maskbit = DL1_MODE_MASK,
+		.mono_reg = AFE_DAC_CON1,
+		.mono_shift = DL1_DATA_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL1_ON_SFT,
+		.hd_reg = AFE_MEMIF_HD_MODE,
+		.hd_shift = DL1_HD_SFT,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	[MT6797_MEMIF_DL2] = {
+		.name = "DL2",
+		.id = MT6797_MEMIF_DL2,
+		.reg_ofs_base = AFE_DL2_BASE,
+		.reg_ofs_cur = AFE_DL2_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = DL2_MODE_SFT,
+		.fs_maskbit = DL2_MODE_MASK,
+		.mono_reg = AFE_DAC_CON1,
+		.mono_shift = DL2_DATA_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL2_ON_SFT,
+		.hd_reg = AFE_MEMIF_HD_MODE,
+		.hd_shift = DL2_HD_SFT,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	[MT6797_MEMIF_DL3] = {
+		.name = "DL3",
+		.id = MT6797_MEMIF_DL3,
+		.reg_ofs_base = AFE_DL3_BASE,
+		.reg_ofs_cur = AFE_DL3_CUR,
+		.fs_reg = AFE_DAC_CON0,
+		.fs_shift = DL3_MODE_SFT,
+		.fs_maskbit = DL3_MODE_MASK,
+		.mono_reg = AFE_DAC_CON1,
+		.mono_shift = DL3_DATA_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DL3_ON_SFT,
+		.hd_reg = AFE_MEMIF_HD_MODE,
+		.hd_shift = DL3_HD_SFT,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	[MT6797_MEMIF_VUL] = {
+		.name = "VUL",
+		.id = MT6797_MEMIF_VUL,
+		.reg_ofs_base = AFE_VUL_BASE,
+		.reg_ofs_cur = AFE_VUL_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = VUL_MODE_SFT,
+		.fs_maskbit = VUL_MODE_MASK,
+		.mono_reg = AFE_DAC_CON1,
+		.mono_shift = VUL_DATA_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = VUL_ON_SFT,
+		.hd_reg = AFE_MEMIF_HD_MODE,
+		.hd_shift = VUL_HD_SFT,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	[MT6797_MEMIF_AWB] = {
+		.name = "AWB",
+		.id = MT6797_MEMIF_AWB,
+		.reg_ofs_base = AFE_AWB_BASE,
+		.reg_ofs_cur = AFE_AWB_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = AWB_MODE_SFT,
+		.fs_maskbit = AWB_MODE_MASK,
+		.mono_reg = AFE_DAC_CON1,
+		.mono_shift = AWB_DATA_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = AWB_ON_SFT,
+		.hd_reg = AFE_MEMIF_HD_MODE,
+		.hd_shift = AWB_HD_SFT,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	[MT6797_MEMIF_VUL12] = {
+		.name = "VUL12",
+		.id = MT6797_MEMIF_VUL12,
+		.reg_ofs_base = AFE_VUL_D2_BASE,
+		.reg_ofs_cur = AFE_VUL_D2_CUR,
+		.fs_reg = AFE_DAC_CON0,
+		.fs_shift = VUL_DATA2_MODE_SFT,
+		.fs_maskbit = VUL_DATA2_MODE_MASK,
+		.mono_reg = AFE_DAC_CON0,
+		.mono_shift = VUL_DATA2_DATA_SFT,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = VUL_DATA2_ON_SFT,
+		.hd_reg = AFE_MEMIF_HD_MODE,
+		.hd_shift = VUL_DATA2_HD_SFT,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	[MT6797_MEMIF_DAI] = {
+		.name = "DAI",
+		.id = MT6797_MEMIF_DAI,
+		.reg_ofs_base = AFE_DAI_BASE,
+		.reg_ofs_cur = AFE_DAI_CUR,
+		.fs_reg = AFE_DAC_CON0,
+		.fs_shift = DAI_MODE_SFT,
+		.fs_maskbit = DAI_MODE_MASK,
+		.mono_reg = -1,
+		.mono_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = DAI_ON_SFT,
+		.hd_reg = AFE_MEMIF_HD_MODE,
+		.hd_shift = DAI_HD_SFT,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+	[MT6797_MEMIF_MOD_DAI] = {
+		.name = "MOD_DAI",
+		.id = MT6797_MEMIF_MOD_DAI,
+		.reg_ofs_base = AFE_MOD_DAI_BASE,
+		.reg_ofs_cur = AFE_MOD_DAI_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = MOD_DAI_MODE_SFT,
+		.fs_maskbit = MOD_DAI_MODE_MASK,
+		.mono_reg = -1,
+		.mono_shift = 0,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = MOD_DAI_ON_SFT,
+		.hd_reg = AFE_MEMIF_HD_MODE,
+		.hd_shift = MOD_DAI_HD_SFT,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+		.msb_reg = -1,
+		.msb_shift = -1,
+	},
+};
+
+static const struct mtk_base_irq_data irq_data[MT6797_IRQ_NUM] = {
+	[MT6797_IRQ_1] = {
+		.id = MT6797_IRQ_1,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT1,
+		.irq_cnt_shift = AFE_IRQ_MCU_CNT1_SFT,
+		.irq_cnt_maskbit = AFE_IRQ_MCU_CNT1_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = IRQ1_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ1_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = IRQ1_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ1_MCU_CLR_SFT,
+	},
+	[MT6797_IRQ_2] = {
+		.id = MT6797_IRQ_2,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT2,
+		.irq_cnt_shift = AFE_IRQ_MCU_CNT2_SFT,
+		.irq_cnt_maskbit = AFE_IRQ_MCU_CNT2_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = IRQ2_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ2_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = IRQ2_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ2_MCU_CLR_SFT,
+	},
+	[MT6797_IRQ_3] = {
+		.id = MT6797_IRQ_3,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT3,
+		.irq_cnt_shift = AFE_IRQ_MCU_CNT3_SFT,
+		.irq_cnt_maskbit = AFE_IRQ_MCU_CNT3_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = IRQ3_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ3_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = IRQ3_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ3_MCU_CLR_SFT,
+	},
+	[MT6797_IRQ_4] = {
+		.id = MT6797_IRQ_4,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT4,
+		.irq_cnt_shift = AFE_IRQ_MCU_CNT4_SFT,
+		.irq_cnt_maskbit = AFE_IRQ_MCU_CNT4_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = IRQ4_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ4_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = IRQ4_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ4_MCU_CLR_SFT,
+	},
+	[MT6797_IRQ_7] = {
+		.id = MT6797_IRQ_7,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT7,
+		.irq_cnt_shift = AFE_IRQ_MCU_CNT7_SFT,
+		.irq_cnt_maskbit = AFE_IRQ_MCU_CNT7_MASK,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = IRQ7_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ7_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = IRQ7_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ7_MCU_CLR_SFT,
+	},
+};
+
+static const struct regmap_config mt6797_afe_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = AFE_MAX_REGISTER,
+};
+
+static irqreturn_t mt6797_afe_irq_handler(int irq_id, void *dev)
+{
+	struct mtk_base_afe *afe = dev;
+	struct mtk_base_afe_irq *irq;
+	unsigned int status;
+	unsigned int mcu_en;
+	int ret;
+	int i;
+	irqreturn_t irq_ret = IRQ_HANDLED;
+
+	/* get irq that is sent to MCU */
+	regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
+
+	ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
+	if (ret || (status & mcu_en) == 0) {
+		dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n",
+			__func__, ret, status, mcu_en);
+
+		/* only clear IRQ which is sent to MCU */
+		status = mcu_en & AFE_IRQ_STATUS_BITS;
+
+		irq_ret = IRQ_NONE;
+		goto err_irq;
+	}
+
+	for (i = 0; i < MT6797_MEMIF_NUM; i++) {
+		struct mtk_base_afe_memif *memif = &afe->memif[i];
+
+		if (!memif->substream)
+			continue;
+
+		irq = &afe->irqs[memif->irq_usage];
+
+		if (status & (1 << irq->irq_data->irq_en_shift))
+			snd_pcm_period_elapsed(memif->substream);
+	}
+
+err_irq:
+	/* clear irq */
+	regmap_write(afe->regmap,
+		     AFE_IRQ_MCU_CLR,
+		     status & AFE_IRQ_STATUS_BITS);
+
+	return irq_ret;
+}
+
+static int mt6797_afe_runtime_suspend(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	unsigned int afe_on_retm;
+	int retry = 0;
+
+	/* disable AFE */
+	regmap_update_bits(afe->regmap, AFE_DAC_CON0, AFE_ON_MASK_SFT, 0x0);
+	do {
+		regmap_read(afe->regmap, AFE_DAC_CON0, &afe_on_retm);
+		if ((afe_on_retm & AFE_ON_RETM_MASK_SFT) == 0)
+			break;
+
+		udelay(10);
+	} while (++retry < 100000);
+
+	if (retry)
+		dev_warn(afe->dev, "%s(), retry %d\n", __func__, retry);
+
+	/* make sure all irq status are cleared */
+	regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
+
+	return mt6797_afe_disable_clock(afe);
+}
+
+static int mt6797_afe_runtime_resume(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	int ret;
+
+	ret = mt6797_afe_enable_clock(afe);
+	if (ret)
+		return ret;
+
+	/* irq signal to mcu only */
+	regmap_write(afe->regmap, AFE_IRQ_MCU_EN, AFE_IRQ_MCU_EN_MASK_SFT);
+
+	/* force all memif use normal mode */
+	regmap_update_bits(afe->regmap, AFE_MEMIF_HDALIGN,
+			   0x7ff << 16, 0x7ff << 16);
+	/* force cpu use normal mode when access sram data */
+	regmap_update_bits(afe->regmap, AFE_MEMIF_MSB,
+			   CPU_COMPACT_MODE_MASK_SFT, 0);
+	/* force cpu use 8_24 format when writing 32bit data */
+	regmap_update_bits(afe->regmap, AFE_MEMIF_MSB,
+			   CPU_HD_ALIGN_MASK_SFT, 0);
+
+	/* set all output port to 24bit */
+	regmap_update_bits(afe->regmap, AFE_CONN_24BIT,
+			   0x3fffffff, 0x3fffffff);
+
+	/* enable AFE */
+	regmap_update_bits(afe->regmap, AFE_DAC_CON0,
+			   AFE_ON_MASK_SFT,
+			   0x1 << AFE_ON_SFT);
+
+	return 0;
+}
+
+static int mt6797_afe_component_probe(struct snd_soc_component *component)
+{
+	return mtk_afe_add_sub_dai_control(component);
+}
+
+static const struct snd_soc_component_driver mt6797_afe_component = {
+	.name = AFE_PCM_NAME,
+	.ops = &mtk_afe_pcm_ops,
+	.pcm_new = mtk_afe_pcm_new,
+	.pcm_free = mtk_afe_pcm_free,
+	.probe = mt6797_afe_component_probe,
+};
+
+static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+	struct mtk_base_afe *afe;
+	struct mt6797_afe_private *afe_priv;
+	struct resource *res;
+	struct device *dev;
+	int i, irq_id, ret;
+
+	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+	if (!afe)
+		return -ENOMEM;
+
+	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+					  GFP_KERNEL);
+	if (!afe->platform_priv)
+		return -ENOMEM;
+
+	afe_priv = afe->platform_priv;
+	afe->dev = &pdev->dev;
+	dev = afe->dev;
+
+	/* initial audio related clock */
+	ret = mt6797_init_clock(afe);
+	if (ret) {
+		dev_err(dev, "init clock error\n");
+		return ret;
+	}
+
+	/* regmap init */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	afe->base_addr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(afe->base_addr))
+		return PTR_ERR(afe->base_addr);
+
+	afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
+					    &mt6797_afe_regmap_config);
+	if (IS_ERR(afe->regmap))
+		return PTR_ERR(afe->regmap);
+
+	/* init memif */
+	afe->memif_size = MT6797_MEMIF_NUM;
+	afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+				  GFP_KERNEL);
+	if (!afe->memif)
+		return -ENOMEM;
+
+	for (i = 0; i < afe->memif_size; i++) {
+		afe->memif[i].data = &memif_data[i];
+		afe->memif[i].irq_usage = -1;
+	}
+
+	mutex_init(&afe->irq_alloc_lock);
+
+	/* irq initialize */
+	afe->irqs_size = MT6797_IRQ_NUM;
+	afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+				 GFP_KERNEL);
+	if (!afe->irqs)
+		return -ENOMEM;
+
+	for (i = 0; i < afe->irqs_size; i++)
+		afe->irqs[i].irq_data = &irq_data[i];
+
+	/* request irq */
+	irq_id = platform_get_irq(pdev, 0);
+	if (!irq_id) {
+		dev_err(dev, "%s no irq found\n", dev->of_node->name);
+		return -ENXIO;
+	}
+	ret = devm_request_irq(dev, irq_id, mt6797_afe_irq_handler,
+			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+	if (ret) {
+		dev_err(dev, "could not request_irq for asys-isr\n");
+		return ret;
+	}
+
+	/* init sub_dais */
+	afe->num_sub_dais = MT6797_DAI_NUM;
+	afe->sub_dais = devm_kcalloc(dev, afe->num_sub_dais,
+				     sizeof(*afe->sub_dais),
+				     GFP_KERNEL);
+	if (!afe->sub_dais)
+		return -ENOMEM;
+
+	mt6797_dai_adda_register(afe);
+	mt6797_dai_pcm_register(afe);
+	mt6797_dai_hostless_register(afe);
+
+	afe->sub_dais[MT6797_MEMIF_DL1].dai_drivers = mt6797_memif_dai_driver;
+	afe->sub_dais[MT6797_MEMIF_DL1].num_dai_drivers =
+		ARRAY_SIZE(mt6797_memif_dai_driver);
+	afe->sub_dais[MT6797_MEMIF_DL1].dapm_widgets = mt6797_memif_widgets;
+	afe->sub_dais[MT6797_MEMIF_DL1].num_dapm_widgets =
+		ARRAY_SIZE(mt6797_memif_widgets);
+	afe->sub_dais[MT6797_MEMIF_DL1].dapm_routes = mt6797_memif_routes;
+	afe->sub_dais[MT6797_MEMIF_DL1].num_dapm_routes =
+		ARRAY_SIZE(mt6797_memif_routes);
+
+	/* init dai_driver and component_driver */
+	mtk_afe_combine_sub_dai(afe);
+
+	afe->mtk_afe_hardware = &mt6797_afe_hardware;
+	afe->memif_fs = mt6797_memif_fs;
+	afe->irq_fs = mt6797_irq_fs;
+
+	afe->runtime_resume = mt6797_afe_runtime_resume;
+	afe->runtime_suspend = mt6797_afe_runtime_suspend;
+
+	platform_set_drvdata(pdev, afe);
+
+	pm_runtime_enable(dev);
+	if (!pm_runtime_enabled(dev))
+		goto err_pm_disable;
+	pm_runtime_get_sync(&pdev->dev);
+
+	/* register component */
+	ret = devm_snd_soc_register_component(dev, &mt6797_afe_component,
+					      NULL, 0);
+	if (ret) {
+		dev_warn(dev, "err_platform\n");
+		goto err_pm_disable;
+	}
+
+	ret = devm_snd_soc_register_component(afe->dev,
+				     &mt6797_afe_pcm_dai_component,
+				     afe->dai_drivers,
+				     afe->num_dai_drivers);
+	if (ret) {
+		dev_warn(dev, "err_dai_component\n");
+		goto err_pm_disable;
+	}
+
+	return 0;
+
+err_pm_disable:
+	pm_runtime_disable(dev);
+
+	return ret;
+}
+
+static int mt6797_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		mt6797_afe_runtime_suspend(&pdev->dev);
+	pm_runtime_put_sync(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id mt6797_afe_pcm_dt_match[] = {
+	{ .compatible = "mediatek,mt6797-audio", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mt6797_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt6797_afe_pm_ops = {
+	SET_RUNTIME_PM_OPS(mt6797_afe_runtime_suspend,
+			   mt6797_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt6797_afe_pcm_driver = {
+	.driver = {
+		   .name = "mt6797-audio",
+		   .of_match_table = mt6797_afe_pcm_dt_match,
+#ifdef CONFIG_PM
+		   .pm = &mt6797_afe_pm_ops,
+#endif
+	},
+	.probe = mt6797_afe_pcm_dev_probe,
+	.remove = mt6797_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt6797_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 6797");
+MODULE_AUTHOR("KaiChieh Chuang <kaichieh.chuang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/mt6797/mt6797-dai-adda.c b/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
new file mode 100644
index 000000000000..ad083265ce94
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
@@ -0,0 +1,396 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI ADDA Control
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include "mt6797-afe-common.h"
+#include "mt6797-interconnection.h"
+#include "mt6797-reg.h"
+
+enum {
+	MTK_AFE_ADDA_DL_RATE_8K = 0,
+	MTK_AFE_ADDA_DL_RATE_11K = 1,
+	MTK_AFE_ADDA_DL_RATE_12K = 2,
+	MTK_AFE_ADDA_DL_RATE_16K = 3,
+	MTK_AFE_ADDA_DL_RATE_22K = 4,
+	MTK_AFE_ADDA_DL_RATE_24K = 5,
+	MTK_AFE_ADDA_DL_RATE_32K = 6,
+	MTK_AFE_ADDA_DL_RATE_44K = 7,
+	MTK_AFE_ADDA_DL_RATE_48K = 8,
+	MTK_AFE_ADDA_DL_RATE_96K = 9,
+	MTK_AFE_ADDA_DL_RATE_192K = 10,
+};
+
+enum {
+	MTK_AFE_ADDA_UL_RATE_8K = 0,
+	MTK_AFE_ADDA_UL_RATE_16K = 1,
+	MTK_AFE_ADDA_UL_RATE_32K = 2,
+	MTK_AFE_ADDA_UL_RATE_48K = 3,
+	MTK_AFE_ADDA_UL_RATE_96K = 4,
+	MTK_AFE_ADDA_UL_RATE_192K = 5,
+	MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
+};
+
+static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
+					   unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return MTK_AFE_ADDA_DL_RATE_8K;
+	case 11025:
+		return MTK_AFE_ADDA_DL_RATE_11K;
+	case 12000:
+		return MTK_AFE_ADDA_DL_RATE_12K;
+	case 16000:
+		return MTK_AFE_ADDA_DL_RATE_16K;
+	case 22050:
+		return MTK_AFE_ADDA_DL_RATE_22K;
+	case 24000:
+		return MTK_AFE_ADDA_DL_RATE_24K;
+	case 32000:
+		return MTK_AFE_ADDA_DL_RATE_32K;
+	case 44100:
+		return MTK_AFE_ADDA_DL_RATE_44K;
+	case 48000:
+		return MTK_AFE_ADDA_DL_RATE_48K;
+	case 96000:
+		return MTK_AFE_ADDA_DL_RATE_96K;
+	case 192000:
+		return MTK_AFE_ADDA_DL_RATE_192K;
+	default:
+		dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+			 __func__, rate);
+		return MTK_AFE_ADDA_DL_RATE_48K;
+	}
+}
+
+static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
+					   unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return MTK_AFE_ADDA_UL_RATE_8K;
+	case 16000:
+		return MTK_AFE_ADDA_UL_RATE_16K;
+	case 32000:
+		return MTK_AFE_ADDA_UL_RATE_32K;
+	case 48000:
+		return MTK_AFE_ADDA_UL_RATE_48K;
+	case 96000:
+		return MTK_AFE_ADDA_UL_RATE_96K;
+	case 192000:
+		return MTK_AFE_ADDA_UL_RATE_192K;
+	default:
+		dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+			 __func__, rate);
+		return MTK_AFE_ADDA_UL_RATE_48K;
+	}
+}
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN3, I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN3, I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN3,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN3,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN3,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN3,
+				    I_PCM_2_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN4, I_DL1_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN4, I_DL1_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN4, I_DL2_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN4, I_DL2_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN4, I_DL3_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN4, I_DL3_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN4,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN4,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN4,
+				    I_PCM_1_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN4,
+				    I_PCM_2_CAP_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN4,
+				    I_PCM_1_CAP_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN4,
+				    I_PCM_2_CAP_CH2, 1, 0),
+};
+
+static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol,
+			     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+	dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+		__func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMD:
+		/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+		usleep_range(125, 135);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+enum {
+	SUPPLY_SEQ_AUD_TOP_PDN,
+	SUPPLY_SEQ_ADDA_AFE_ON,
+	SUPPLY_SEQ_ADDA_DL_ON,
+	SUPPLY_SEQ_ADDA_UL_ON,
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+	/* adda */
+	SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_adda_dl_ch1_mix,
+			   ARRAY_SIZE(mtk_adda_dl_ch1_mix)),
+	SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_adda_dl_ch2_mix,
+			   ARRAY_SIZE(mtk_adda_dl_ch2_mix)),
+
+	SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
+			      AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0,
+			      NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON,
+			      AFE_ADDA_DL_SRC2_CON0,
+			      DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0,
+			      NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+			      AFE_ADDA_UL_SRC_CON0,
+			      UL_SRC_ON_TMP_CTL_SFT, 0,
+			      mtk_adda_ul_event,
+			      SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("aud_dac_clk", SUPPLY_SEQ_AUD_TOP_PDN,
+			      AUDIO_TOP_CON0, PDN_DAC_SFT, 1,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("aud_dac_predis_clk", SUPPLY_SEQ_AUD_TOP_PDN,
+			      AUDIO_TOP_CON0, PDN_DAC_PREDIS_SFT, 1,
+			      NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("aud_adc_clk", SUPPLY_SEQ_AUD_TOP_PDN,
+			      AUDIO_TOP_CON0, PDN_ADC_SFT, 1,
+			      NULL, 0),
+
+	SND_SOC_DAPM_CLOCK_SUPPLY("mtkaif_26m_clk"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+	/* playback */
+	{"ADDA_DL_CH1", "DL1_CH1", "DL1"},
+	{"ADDA_DL_CH2", "DL1_CH1", "DL1"},
+	{"ADDA_DL_CH2", "DL1_CH2", "DL1"},
+
+	{"ADDA_DL_CH1", "DL2_CH1", "DL2"},
+	{"ADDA_DL_CH2", "DL2_CH1", "DL2"},
+	{"ADDA_DL_CH2", "DL2_CH2", "DL2"},
+
+	{"ADDA_DL_CH1", "DL3_CH1", "DL3"},
+	{"ADDA_DL_CH2", "DL3_CH1", "DL3"},
+	{"ADDA_DL_CH2", "DL3_CH2", "DL3"},
+
+	{"ADDA Playback", NULL, "ADDA_DL_CH1"},
+	{"ADDA Playback", NULL, "ADDA_DL_CH2"},
+
+	/* adda enable */
+	{"ADDA Playback", NULL, "ADDA Enable"},
+	{"ADDA Playback", NULL, "ADDA Playback Enable"},
+	{"ADDA Capture", NULL, "ADDA Enable"},
+	{"ADDA Capture", NULL, "ADDA Capture Enable"},
+
+	/* clk */
+	{"ADDA Playback", NULL, "mtkaif_26m_clk"},
+	{"ADDA Playback", NULL, "aud_dac_clk"},
+	{"ADDA Playback", NULL, "aud_dac_predis_clk"},
+
+	{"ADDA Capture", NULL, "mtkaif_26m_clk"},
+	{"ADDA Capture", NULL, "aud_adc_clk"},
+};
+
+/* dai ops */
+static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	unsigned int rate = params_rate(params);
+
+	dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+		__func__, dai->id, substream->stream, rate);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		unsigned int dl_src2_con0 = 0;
+		unsigned int dl_src2_con1 = 0;
+
+		/* clean predistortion */
+		regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0);
+		regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0);
+
+		/* set input sampling rate */
+		dl_src2_con0 = adda_dl_rate_transform(afe, rate) << 28;
+
+		/* set output mode */
+		switch (rate) {
+		case 192000:
+			dl_src2_con0 |= (0x1 << 24); /* UP_SAMPLING_RATE_X2 */
+			dl_src2_con0 |= 1 << 14;
+			break;
+		case 96000:
+			dl_src2_con0 |= (0x2 << 24); /* UP_SAMPLING_RATE_X4 */
+			dl_src2_con0 |= 1 << 14;
+			break;
+		default:
+			dl_src2_con0 |= (0x3 << 24); /* UP_SAMPLING_RATE_X8 */
+			break;
+		}
+
+		/* turn off mute function */
+		dl_src2_con0 |= (0x03 << 11);
+
+		/* set voice input data if input sample rate is 8k or 16k */
+		if (rate == 8000 || rate == 16000)
+			dl_src2_con0 |= 0x01 << 5;
+
+		if (rate < 96000) {
+			/* SA suggest apply -0.3db to audio/speech path */
+			dl_src2_con1 = 0xf74f0000;
+		} else {
+			/* SA suggest apply -0.3db to audio/speech path
+			 * with DL gain set to half,
+			 * 0xFFFF = 0dB -> 0x8000 = 0dB when 96k, 192k
+			 */
+			dl_src2_con1 = 0x7ba70000;
+		}
+
+		/* turn on down-link gain */
+		dl_src2_con0 = dl_src2_con0 | (0x01 << 1);
+
+		regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON0, dl_src2_con0);
+		regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON1, dl_src2_con1);
+	} else {
+		unsigned int voice_mode = 0;
+		unsigned int ul_src_con0 = 0;	/* default value */
+
+		/* Using Internal ADC */
+		regmap_update_bits(afe->regmap,
+				   AFE_ADDA_TOP_CON0,
+				   0x1 << 0,
+				   0x0 << 0);
+
+		voice_mode = adda_ul_rate_transform(afe, rate);
+
+		ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
+
+		/* up8x txif sat on */
+		regmap_write(afe->regmap, AFE_ADDA_NEWIF_CFG0, 0x03F87201);
+
+		if (rate >= 96000) {	/* hires */
+			/* use hires format [1 0 23] */
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_NEWIF_CFG0,
+					   0x1 << 5,
+					   0x1 << 5);
+
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_NEWIF_CFG2,
+					   0xf << 28,
+					   voice_mode << 28);
+		} else {	/* normal 8~48k */
+			/* use fixed 260k anc path */
+			regmap_update_bits(afe->regmap,
+					   AFE_ADDA_NEWIF_CFG2,
+					   0xf << 28,
+					   8 << 28);
+
+			/* ul_use_cic_out */
+			ul_src_con0 |= 0x1 << 20;
+		}
+
+		regmap_update_bits(afe->regmap,
+				   AFE_ADDA_NEWIF_CFG2,
+				   0xf << 28,
+				   8 << 28);
+
+		regmap_update_bits(afe->regmap,
+				   AFE_ADDA_UL_SRC_CON0,
+				   0xfffffffe,
+				   ul_src_con0);
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_adda_ops = {
+	.hw_params = mtk_dai_adda_hw_params,
+};
+
+/* dai driver */
+#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\
+				 SNDRV_PCM_RATE_96000 |\
+				 SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+				SNDRV_PCM_RATE_16000 |\
+				SNDRV_PCM_RATE_32000 |\
+				SNDRV_PCM_RATE_48000 |\
+				SNDRV_PCM_RATE_96000 |\
+				SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			  SNDRV_PCM_FMTBIT_S24_LE |\
+			  SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
+	{
+		.name = "ADDA",
+		.id = MT6797_DAI_ADDA,
+		.playback = {
+			.stream_name = "ADDA Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_PLAYBACK_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.capture = {
+			.stream_name = "ADDA Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ADDA_CAPTURE_RATES,
+			.formats = MTK_ADDA_FORMATS,
+		},
+		.ops = &mtk_dai_adda_ops,
+	},
+};
+
+int mt6797_dai_adda_register(struct mtk_base_afe *afe)
+{
+	int id = MT6797_DAI_ADDA;
+
+	afe->sub_dais[id].dai_drivers = mtk_dai_adda_driver;
+	afe->sub_dais[id].num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+
+	afe->sub_dais[id].dapm_widgets = mtk_dai_adda_widgets;
+	afe->sub_dais[id].num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+	afe->sub_dais[id].dapm_routes = mtk_dai_adda_routes;
+	afe->sub_dais[id].num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+	return 0;
+}
diff --git a/sound/soc/mediatek/mt6797/mt6797-dai-hostless.c b/sound/soc/mediatek/mt6797/mt6797-dai-hostless.c
new file mode 100644
index 000000000000..4cf985b15a11
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-dai-hostless.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI Hostless Control
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include "mt6797-afe-common.h"
+
+/* dai component */
+static const struct snd_soc_dapm_route mtk_dai_hostless_routes[] = {
+	/* Hostless ADDA Loopback */
+	{"ADDA_DL_CH1", "ADDA_UL_CH1", "Hostless LPBK DL"},
+	{"ADDA_DL_CH1", "ADDA_UL_CH2", "Hostless LPBK DL"},
+	{"ADDA_DL_CH2", "ADDA_UL_CH1", "Hostless LPBK DL"},
+	{"ADDA_DL_CH2", "ADDA_UL_CH2", "Hostless LPBK DL"},
+	{"Hostless LPBK UL", NULL, "ADDA Capture"},
+
+	/* Hostless Speech */
+	{"ADDA_DL_CH1", "PCM_1_CAP_CH1", "Hostless Speech DL"},
+	{"ADDA_DL_CH2", "PCM_1_CAP_CH1", "Hostless Speech DL"},
+	{"ADDA_DL_CH2", "PCM_1_CAP_CH2", "Hostless Speech DL"},
+	{"ADDA_DL_CH1", "PCM_2_CAP_CH1", "Hostless Speech DL"},
+	{"ADDA_DL_CH2", "PCM_2_CAP_CH1", "Hostless Speech DL"},
+	{"ADDA_DL_CH2", "PCM_2_CAP_CH2", "Hostless Speech DL"},
+	{"PCM_1_PB_CH1", "ADDA_UL_CH1", "Hostless Speech DL"},
+	{"PCM_1_PB_CH2", "ADDA_UL_CH2", "Hostless Speech DL"},
+	{"PCM_2_PB_CH1", "ADDA_UL_CH1", "Hostless Speech DL"},
+	{"PCM_2_PB_CH2", "ADDA_UL_CH2", "Hostless Speech DL"},
+
+	{"Hostless Speech UL", NULL, "PCM 1 Capture"},
+	{"Hostless Speech UL", NULL, "PCM 2 Capture"},
+	{"Hostless Speech UL", NULL, "ADDA Capture"},
+};
+
+/* dai ops */
+static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+	return snd_soc_set_runtime_hwparams(substream, afe->mtk_afe_hardware);
+}
+
+static const struct snd_soc_dai_ops mtk_dai_hostless_ops = {
+	.startup = mtk_dai_hostless_startup,
+};
+
+/* dai driver */
+#define MTK_HOSTLESS_RATES (SNDRV_PCM_RATE_8000_48000 |\
+			   SNDRV_PCM_RATE_88200 |\
+			   SNDRV_PCM_RATE_96000 |\
+			   SNDRV_PCM_RATE_176400 |\
+			   SNDRV_PCM_RATE_192000)
+
+#define MTK_HOSTLESS_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			     SNDRV_PCM_FMTBIT_S24_LE |\
+			     SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_hostless_driver[] = {
+	{
+		.name = "Hostless LPBK DAI",
+		.id = MT6797_DAI_HOSTLESS_LPBK,
+		.playback = {
+			.stream_name = "Hostless LPBK DL",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_HOSTLESS_RATES,
+			.formats = MTK_HOSTLESS_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Hostless LPBK UL",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_HOSTLESS_RATES,
+			.formats = MTK_HOSTLESS_FORMATS,
+		},
+		.ops = &mtk_dai_hostless_ops,
+	},
+	{
+		.name = "Hostless Speech DAI",
+		.id = MT6797_DAI_HOSTLESS_SPEECH,
+		.playback = {
+			.stream_name = "Hostless Speech DL",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_HOSTLESS_RATES,
+			.formats = MTK_HOSTLESS_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Hostless Speech UL",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_HOSTLESS_RATES,
+			.formats = MTK_HOSTLESS_FORMATS,
+		},
+		.ops = &mtk_dai_hostless_ops,
+	},
+};
+
+int mt6797_dai_hostless_register(struct mtk_base_afe *afe)
+{
+	int id = MT6797_DAI_HOSTLESS_LPBK;
+
+	afe->sub_dais[id].dai_drivers = mtk_dai_hostless_driver;
+	afe->sub_dais[id].num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver);
+
+	afe->sub_dais[id].dapm_routes = mtk_dai_hostless_routes;
+	afe->sub_dais[id].num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes);
+
+	return 0;
+}
diff --git a/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c b/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c
new file mode 100644
index 000000000000..16d5b5067204
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI I2S Control
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt6797-afe-common.h"
+#include "mt6797-interconnection.h"
+#include "mt6797-reg.h"
+
+enum AUD_TX_LCH_RPT {
+	AUD_TX_LCH_RPT_NO_REPEAT = 0,
+	AUD_TX_LCH_RPT_REPEAT = 1
+};
+
+enum AUD_VBT_16K_MODE {
+	AUD_VBT_16K_MODE_DISABLE = 0,
+	AUD_VBT_16K_MODE_ENABLE = 1
+};
+
+enum AUD_EXT_MODEM {
+	AUD_EXT_MODEM_SELECT_INTERNAL = 0,
+	AUD_EXT_MODEM_SELECT_EXTERNAL = 1
+};
+
+enum AUD_PCM_SYNC_TYPE {
+	/* bck sync length = 1 */
+	AUD_PCM_ONE_BCK_CYCLE_SYNC = 0,
+	/* bck sync length = PCM_INTF_CON1[9:13] */
+	AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1
+};
+
+enum AUD_BT_MODE {
+	AUD_BT_MODE_DUAL_MIC_ON_TX = 0,
+	AUD_BT_MODE_SINGLE_MIC_ON_TX = 1
+};
+
+enum AUD_PCM_AFIFO_SRC {
+	/* slave mode & external modem uses different crystal */
+	AUD_PCM_AFIFO_ASRC = 0,
+	/* slave mode & external modem uses the same crystal */
+	AUD_PCM_AFIFO_AFIFO = 1
+};
+
+enum AUD_PCM_CLOCK_SOURCE {
+	AUD_PCM_CLOCK_MASTER_MODE = 0,
+	AUD_PCM_CLOCK_SLAVE_MODE = 1
+};
+
+enum AUD_PCM_WLEN {
+	AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0,
+	AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1
+};
+
+enum AUD_PCM_MODE {
+	AUD_PCM_MODE_PCM_MODE_8K = 0,
+	AUD_PCM_MODE_PCM_MODE_16K = 1,
+	AUD_PCM_MODE_PCM_MODE_32K = 2,
+	AUD_PCM_MODE_PCM_MODE_48K = 3,
+};
+
+enum AUD_PCM_FMT {
+	AUD_PCM_FMT_I2S = 0,
+	AUD_PCM_FMT_EIAJ = 1,
+	AUD_PCM_FMT_PCM_MODE_A = 2,
+	AUD_PCM_FMT_PCM_MODE_B = 3
+};
+
+enum AUD_BCLK_OUT_INV {
+	AUD_BCLK_OUT_INV_NO_INVERSE = 0,
+	AUD_BCLK_OUT_INV_INVERSE = 1
+};
+
+enum AUD_PCM_EN {
+	AUD_PCM_EN_DISABLE = 0,
+	AUD_PCM_EN_ENABLE = 1
+};
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN7,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN7,
+				    I_DL2_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN8,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN8,
+				    I_DL2_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch4_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN27,
+				    I_DL1_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN17,
+				    I_ADDA_UL_CH1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN17,
+				    I_DL2_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN18,
+				    I_ADDA_UL_CH2, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN18,
+				    I_DL2_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_2_playback_ch4_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN24,
+				    I_DL1_CH1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+	/* inter-connections */
+	SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_pcm_1_playback_ch1_mix,
+			   ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)),
+	SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_pcm_1_playback_ch2_mix,
+			   ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)),
+	SND_SOC_DAPM_MIXER("PCM_1_PB_CH4", SND_SOC_NOPM, 0, 0,
+			   mtk_pcm_1_playback_ch4_mix,
+			   ARRAY_SIZE(mtk_pcm_1_playback_ch4_mix)),
+	SND_SOC_DAPM_MIXER("PCM_2_PB_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_pcm_2_playback_ch1_mix,
+			   ARRAY_SIZE(mtk_pcm_2_playback_ch1_mix)),
+	SND_SOC_DAPM_MIXER("PCM_2_PB_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_pcm_2_playback_ch2_mix,
+			   ARRAY_SIZE(mtk_pcm_2_playback_ch2_mix)),
+	SND_SOC_DAPM_MIXER("PCM_2_PB_CH4", SND_SOC_NOPM, 0, 0,
+			   mtk_pcm_2_playback_ch4_mix,
+			   ARRAY_SIZE(mtk_pcm_2_playback_ch4_mix)),
+
+	SND_SOC_DAPM_SUPPLY("PCM_1_EN", PCM_INTF_CON1, PCM_EN_SFT, 0,
+			    NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("PCM_2_EN", PCM2_INTF_CON, PCM2_EN_SFT, 0,
+			    NULL, 0),
+
+	SND_SOC_DAPM_INPUT("MD1_TO_AFE"),
+	SND_SOC_DAPM_INPUT("MD2_TO_AFE"),
+	SND_SOC_DAPM_OUTPUT("AFE_TO_MD1"),
+	SND_SOC_DAPM_OUTPUT("AFE_TO_MD2"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+	{"PCM 1 Playback", NULL, "PCM_1_PB_CH1"},
+	{"PCM 1 Playback", NULL, "PCM_1_PB_CH2"},
+	{"PCM 1 Playback", NULL, "PCM_1_PB_CH4"},
+	{"PCM 2 Playback", NULL, "PCM_2_PB_CH1"},
+	{"PCM 2 Playback", NULL, "PCM_2_PB_CH2"},
+	{"PCM 2 Playback", NULL, "PCM_2_PB_CH4"},
+
+	{"PCM 1 Playback", NULL, "PCM_1_EN"},
+	{"PCM 2 Playback", NULL, "PCM_2_EN"},
+	{"PCM 1 Capture", NULL, "PCM_1_EN"},
+	{"PCM 2 Capture", NULL, "PCM_2_EN"},
+
+	{"AFE_TO_MD1", NULL, "PCM 2 Playback"},
+	{"AFE_TO_MD2", NULL, "PCM 1 Playback"},
+	{"PCM 2 Capture", NULL, "MD1_TO_AFE"},
+	{"PCM 1 Capture", NULL, "MD2_TO_AFE"},
+
+	{"PCM_1_PB_CH1", "DL2_CH1", "DL2"},
+	{"PCM_1_PB_CH2", "DL2_CH2", "DL2"},
+	{"PCM_1_PB_CH4", "DL1_CH1", "DL1"},
+	{"PCM_2_PB_CH1", "DL2_CH1", "DL2"},
+	{"PCM_2_PB_CH2", "DL2_CH2", "DL2"},
+	{"PCM_2_PB_CH4", "DL1_CH1", "DL1"},
+};
+
+/* dai ops */
+static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	unsigned int rate = params_rate(params);
+	unsigned int rate_reg = mt6797_rate_transform(afe->dev, rate, dai->id);
+	unsigned int pcm_con = 0;
+
+	dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d, rate_reg %d, widget active p %d, c %d\n",
+		__func__,
+		dai->id,
+		substream->stream,
+		rate,
+		rate_reg,
+		dai->playback_widget->active,
+		dai->capture_widget->active);
+
+	if (dai->playback_widget->active || dai->capture_widget->active)
+		return 0;
+
+	switch (dai->id) {
+	case MT6797_DAI_PCM_1:
+		pcm_con |= AUD_BCLK_OUT_INV_NO_INVERSE << PCM_BCLK_OUT_INV_SFT;
+		pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT;
+		pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT;
+		pcm_con |= AUD_EXT_MODEM_SELECT_INTERNAL << PCM_EXT_MODEM_SFT;
+		pcm_con |= 0 << PCM_SYNC_LENGTH_SFT;
+		pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT;
+		pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT;
+		pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT;
+		pcm_con |= AUD_PCM_CLOCK_SLAVE_MODE << PCM_SLAVE_SFT;
+		pcm_con |= rate_reg << PCM_MODE_SFT;
+		pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM_FMT_SFT;
+
+		regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+				   0xfffffffe, pcm_con);
+		break;
+	case MT6797_DAI_PCM_2:
+		pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM2_TX_LCH_RPT_SFT;
+		pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM2_VBT_16K_MODE_SFT;
+		pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM2_BT_MODE_SFT;
+		pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM2_AFIFO_SFT;
+		pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM2_WLEN_SFT;
+		pcm_con |= rate_reg << PCM2_MODE_SFT;
+		pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM2_FMT_SFT;
+
+		regmap_update_bits(afe->regmap, PCM2_INTF_CON,
+				   0xfffffffe, pcm_con);
+		break;
+	default:
+		dev_warn(afe->dev, "%s(), id %d not support\n",
+			 __func__, dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
+	.hw_params = mtk_dai_pcm_hw_params,
+};
+
+/* dai driver */
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\
+		       SNDRV_PCM_RATE_16000 |\
+		       SNDRV_PCM_RATE_32000 |\
+		       SNDRV_PCM_RATE_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
+	{
+		.name = "PCM 1",
+		.id = MT6797_DAI_PCM_1,
+		.playback = {
+			.stream_name = "PCM 1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.capture = {
+			.stream_name = "PCM 1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_dai_pcm_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "PCM 2",
+		.id = MT6797_DAI_PCM_2,
+		.playback = {
+			.stream_name = "PCM 2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.capture = {
+			.stream_name = "PCM 2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_dai_pcm_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+};
+
+int mt6797_dai_pcm_register(struct mtk_base_afe *afe)
+{
+	int id = MT6797_DAI_PCM_1;
+
+	afe->sub_dais[id].dai_drivers = mtk_dai_pcm_driver;
+	afe->sub_dais[id].num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+
+	afe->sub_dais[id].dapm_widgets = mtk_dai_pcm_widgets;
+	afe->sub_dais[id].num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+	afe->sub_dais[id].dapm_routes = mtk_dai_pcm_routes;
+	afe->sub_dais[id].num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+
+	return 0;
+}
diff --git a/sound/soc/mediatek/mt6797/mt6797-interconnection.h b/sound/soc/mediatek/mt6797/mt6797-interconnection.h
new file mode 100644
index 000000000000..07b759b20079
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-interconnection.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Mediatek MT6797 audio driver interconnection definition
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef _MT6797_INTERCONNECTION_H_
+#define _MT6797_INTERCONNECTION_H_
+
+#define I_I2S0_CH1 0
+#define I_I2S0_CH2 1
+#define I_ADDA_UL_CH1 3
+#define I_ADDA_UL_CH2 4
+#define I_DL1_CH1 5
+#define I_DL1_CH2 6
+#define I_DL2_CH1 7
+#define I_DL2_CH2 8
+#define I_PCM_1_CAP_CH1 9
+#define I_GAIN1_OUT_CH1 10
+#define I_GAIN1_OUT_CH2 11
+#define I_GAIN2_OUT_CH1 12
+#define I_GAIN2_OUT_CH2 13
+#define I_PCM_2_CAP_CH1 14
+#define I_PCM_2_CAP_CH2 21
+#define I_PCM_1_CAP_CH2 22
+#define I_DL3_CH1 23
+#define I_DL3_CH2 24
+#define I_I2S2_CH1 25
+#define I_I2S2_CH2 26
+
+#endif
diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c
new file mode 100644
index 000000000000..b1558c57b9ca
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt6797-mt6351.c  --  MT6797 MT6351 ALSA SoC machine driver
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "mt6797-afe-common.h"
+
+static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = {
+	/* FE */
+	{
+		.name = "Playback_1",
+		.stream_name = "Playback_1",
+		.cpu_dai_name = "DL1",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+	},
+	{
+		.name = "Playback_2",
+		.stream_name = "Playback_2",
+		.cpu_dai_name = "DL2",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+	},
+	{
+		.name = "Playback_3",
+		.stream_name = "Playback_3",
+		.cpu_dai_name = "DL3",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+	},
+	{
+		.name = "Capture_1",
+		.stream_name = "Capture_1",
+		.cpu_dai_name = "UL1",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	{
+		.name = "Capture_2",
+		.stream_name = "Capture_2",
+		.cpu_dai_name = "UL2",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	{
+		.name = "Capture_3",
+		.stream_name = "Capture_3",
+		.cpu_dai_name = "UL3",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	{
+		.name = "Capture_Mono_1",
+		.stream_name = "Capture_Mono_1",
+		.cpu_dai_name = "UL_MONO_1",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	{
+		.name = "Hostless_LPBK",
+		.stream_name = "Hostless_LPBK",
+		.cpu_dai_name = "Hostless LPBK DAI",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "Hostless_Speech",
+		.stream_name = "Hostless_Speech",
+		.cpu_dai_name = "Hostless Speech DAI",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+			    SND_SOC_DPCM_TRIGGER_PRE},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+	},
+	/* BE */
+	{
+		.name = "Primary Codec",
+		.cpu_dai_name = "ADDA",
+		.codec_dai_name = "mt6351-snd-codec-aif1",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "PCM 1",
+		.cpu_dai_name = "PCM 1",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "PCM 2",
+		.cpu_dai_name = "PCM 2",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+	},
+};
+
+static struct snd_soc_card mt6797_mt6351_card = {
+	.name = "mt6797-mt6351",
+	.owner = THIS_MODULE,
+	.dai_link = mt6797_mt6351_dai_links,
+	.num_links = ARRAY_SIZE(mt6797_mt6351_dai_links),
+};
+
+static int mt6797_mt6351_dev_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &mt6797_mt6351_card;
+	struct device_node *platform_node, *codec_node;
+	int ret, i;
+
+	card->dev = &pdev->dev;
+
+	platform_node = of_parse_phandle(pdev->dev.of_node,
+					 "mediatek,platform", 0);
+	if (!platform_node) {
+		dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < card->num_links; i++) {
+		if (mt6797_mt6351_dai_links[i].platform_name)
+			continue;
+		mt6797_mt6351_dai_links[i].platform_of_node = platform_node;
+	}
+
+	codec_node = of_parse_phandle(pdev->dev.of_node,
+				      "mediatek,audio-codec", 0);
+	if (!codec_node) {
+		dev_err(&pdev->dev,
+			"Property 'audio-codec' missing or invalid\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < card->num_links; i++) {
+		if (mt6797_mt6351_dai_links[i].codec_name)
+			continue;
+		mt6797_mt6351_dai_links[i].codec_of_node = codec_node;
+	}
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt6797_mt6351_dt_match[] = {
+	{.compatible = "mediatek,mt6797-mt6351-sound",},
+	{}
+};
+#endif
+
+static struct platform_driver mt6797_mt6351_driver = {
+	.driver = {
+		.name = "mt6797-mt6351",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_OF
+		.of_match_table = mt6797_mt6351_dt_match,
+#endif
+	},
+	.probe = mt6797_mt6351_dev_probe,
+};
+
+module_platform_driver(mt6797_mt6351_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT6797 MT6351 ALSA SoC machine driver");
+MODULE_AUTHOR("KaiChieh Chuang <kaichieh.chuang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt6797 mt6351 soc card");
+
diff --git a/sound/soc/mediatek/mt6797/mt6797-reg.h b/sound/soc/mediatek/mt6797/mt6797-reg.h
new file mode 100644
index 000000000000..978f146c143c
--- /dev/null
+++ b/sound/soc/mediatek/mt6797/mt6797-reg.h
@@ -0,0 +1,1015 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt6797-reg.h  --  Mediatek 6797 audio driver reg definition
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef _MT6797_REG_H_
+#define _MT6797_REG_H_
+
+#define AUDIO_TOP_CON0            0x0000
+#define AUDIO_TOP_CON1            0x0004
+#define AUDIO_TOP_CON3            0x000c
+#define AFE_DAC_CON0              0x0010
+#define AFE_DAC_CON1              0x0014
+#define AFE_I2S_CON               0x0018
+#define AFE_DAIBT_CON0            0x001c
+#define AFE_CONN0                 0x0020
+#define AFE_CONN1                 0x0024
+#define AFE_CONN2                 0x0028
+#define AFE_CONN3                 0x002c
+#define AFE_CONN4                 0x0030
+#define AFE_I2S_CON1              0x0034
+#define AFE_I2S_CON2              0x0038
+#define AFE_MRGIF_CON             0x003c
+#define AFE_DL1_BASE              0x0040
+#define AFE_DL1_CUR               0x0044
+#define AFE_DL1_END               0x0048
+#define AFE_I2S_CON3              0x004c
+#define AFE_DL2_BASE              0x0050
+#define AFE_DL2_CUR               0x0054
+#define AFE_DL2_END               0x0058
+#define AFE_CONN5                 0x005c
+#define AFE_CONN_24BIT            0x006c
+#define AFE_AWB_BASE              0x0070
+#define AFE_AWB_END               0x0078
+#define AFE_AWB_CUR               0x007c
+#define AFE_VUL_BASE              0x0080
+#define AFE_VUL_END               0x0088
+#define AFE_VUL_CUR               0x008c
+#define AFE_DAI_BASE              0x0090
+#define AFE_DAI_END               0x0098
+#define AFE_DAI_CUR               0x009c
+#define AFE_CONN6                 0x00bc
+#define AFE_MEMIF_MSB             0x00cc
+#define AFE_MEMIF_MON0            0x00d0
+#define AFE_MEMIF_MON1            0x00d4
+#define AFE_MEMIF_MON2            0x00d8
+#define AFE_MEMIF_MON4            0x00e0
+#define AFE_ADDA_DL_SRC2_CON0     0x0108
+#define AFE_ADDA_DL_SRC2_CON1     0x010c
+#define AFE_ADDA_UL_SRC_CON0      0x0114
+#define AFE_ADDA_UL_SRC_CON1      0x0118
+#define AFE_ADDA_TOP_CON0         0x0120
+#define AFE_ADDA_UL_DL_CON0       0x0124
+#define AFE_ADDA_SRC_DEBUG        0x012c
+#define AFE_ADDA_SRC_DEBUG_MON0   0x0130
+#define AFE_ADDA_SRC_DEBUG_MON1   0x0134
+#define AFE_ADDA_NEWIF_CFG0       0x0138
+#define AFE_ADDA_NEWIF_CFG1       0x013c
+#define AFE_ADDA_NEWIF_CFG2       0x0140
+#define AFE_DMA_CTL               0x0150
+#define AFE_DMA_MON0              0x0154
+#define AFE_DMA_MON1              0x0158
+#define AFE_SIDETONE_DEBUG        0x01d0
+#define AFE_SIDETONE_MON          0x01d4
+#define AFE_SIDETONE_CON0         0x01e0
+#define AFE_SIDETONE_COEFF        0x01e4
+#define AFE_SIDETONE_CON1         0x01e8
+#define AFE_SIDETONE_GAIN         0x01ec
+#define AFE_SGEN_CON0             0x01f0
+#define AFE_SINEGEN_CON_TDM       0x01fc
+#define AFE_TOP_CON0              0x0200
+#define AFE_ADDA_PREDIS_CON0      0x0260
+#define AFE_ADDA_PREDIS_CON1      0x0264
+#define AFE_MRGIF_MON0            0x0270
+#define AFE_MRGIF_MON1            0x0274
+#define AFE_MRGIF_MON2            0x0278
+#define AFE_I2S_MON               0x027c
+#define AFE_MOD_DAI_BASE          0x0330
+#define AFE_MOD_DAI_END           0x0338
+#define AFE_MOD_DAI_CUR           0x033c
+#define AFE_VUL_D2_BASE           0x0350
+#define AFE_VUL_D2_END            0x0358
+#define AFE_VUL_D2_CUR            0x035c
+#define AFE_DL3_BASE              0x0360
+#define AFE_DL3_CUR               0x0364
+#define AFE_DL3_END               0x0368
+#define AFE_HDMI_OUT_CON0         0x0370
+#define AFE_HDMI_BASE             0x0374
+#define AFE_HDMI_CUR              0x0378
+#define AFE_HDMI_END              0x037c
+#define AFE_HDMI_CONN0            0x0390
+#define AFE_IRQ3_MCU_CNT_MON      0x0398
+#define AFE_IRQ4_MCU_CNT_MON      0x039c
+#define AFE_IRQ_MCU_CON           0x03a0
+#define AFE_IRQ_MCU_STATUS        0x03a4
+#define AFE_IRQ_MCU_CLR           0x03a8
+#define AFE_IRQ_MCU_CNT1          0x03ac
+#define AFE_IRQ_MCU_CNT2          0x03b0
+#define AFE_IRQ_MCU_EN            0x03b4
+#define AFE_IRQ_MCU_MON2          0x03b8
+#define AFE_IRQ_MCU_CNT5          0x03bc
+#define AFE_IRQ1_MCU_CNT_MON      0x03c0
+#define AFE_IRQ2_MCU_CNT_MON      0x03c4
+#define AFE_IRQ1_MCU_EN_CNT_MON   0x03c8
+#define AFE_IRQ5_MCU_CNT_MON      0x03cc
+#define AFE_MEMIF_MINLEN          0x03d0
+#define AFE_MEMIF_MAXLEN          0x03d4
+#define AFE_MEMIF_PBUF_SIZE       0x03d8
+#define AFE_IRQ_MCU_CNT7          0x03dc
+#define AFE_IRQ7_MCU_CNT_MON      0x03e0
+#define AFE_IRQ_MCU_CNT3          0x03e4
+#define AFE_IRQ_MCU_CNT4          0x03e8
+#define AFE_APLL1_TUNER_CFG       0x03f0
+#define AFE_APLL2_TUNER_CFG       0x03f4
+#define AFE_MEMIF_HD_MODE         0x03f8
+#define AFE_MEMIF_HDALIGN         0x03fc
+#define AFE_GAIN1_CON0            0x0410
+#define AFE_GAIN1_CON1            0x0414
+#define AFE_GAIN1_CON2            0x0418
+#define AFE_GAIN1_CON3            0x041c
+#define AFE_CONN7                 0x0420
+#define AFE_GAIN1_CUR             0x0424
+#define AFE_GAIN2_CON0            0x0428
+#define AFE_GAIN2_CON1            0x042c
+#define AFE_GAIN2_CON2            0x0430
+#define AFE_GAIN2_CON3            0x0434
+#define AFE_CONN8                 0x0438
+#define AFE_GAIN2_CUR             0x043c
+#define AFE_CONN9                 0x0440
+#define AFE_CONN10                0x0444
+#define AFE_CONN11                0x0448
+#define AFE_CONN12                0x044c
+#define AFE_CONN13                0x0450
+#define AFE_CONN14                0x0454
+#define AFE_CONN15                0x0458
+#define AFE_CONN16                0x045c
+#define AFE_CONN17                0x0460
+#define AFE_CONN18                0x0464
+#define AFE_CONN19                0x0468
+#define AFE_CONN20                0x046c
+#define AFE_CONN21                0x0470
+#define AFE_CONN22                0x0474
+#define AFE_CONN23                0x0478
+#define AFE_CONN24                0x047c
+#define AFE_CONN_RS               0x0494
+#define AFE_CONN_DI               0x0498
+#define AFE_CONN25                0x04b0
+#define AFE_CONN26                0x04b4
+#define AFE_CONN27                0x04b8
+#define AFE_CONN28                0x04bc
+#define AFE_CONN29                0x04c0
+#define AFE_SRAM_DELSEL_CON0      0x04f0
+#define AFE_SRAM_DELSEL_CON1      0x04f4
+#define AFE_ASRC_CON0             0x0500
+#define AFE_ASRC_CON1             0x0504
+#define AFE_ASRC_CON2             0x0508
+#define AFE_ASRC_CON3             0x050c
+#define AFE_ASRC_CON4             0x0510
+#define AFE_ASRC_CON5             0x0514
+#define AFE_ASRC_CON6             0x0518
+#define AFE_ASRC_CON7             0x051c
+#define AFE_ASRC_CON8             0x0520
+#define AFE_ASRC_CON9             0x0524
+#define AFE_ASRC_CON10            0x0528
+#define AFE_ASRC_CON11            0x052c
+#define PCM_INTF_CON1             0x0530
+#define PCM_INTF_CON2             0x0538
+#define PCM2_INTF_CON             0x053c
+#define AFE_TDM_CON1              0x0548
+#define AFE_TDM_CON2              0x054c
+#define AFE_ASRC_CON13            0x0550
+#define AFE_ASRC_CON14            0x0554
+#define AFE_ASRC_CON15            0x0558
+#define AFE_ASRC_CON16            0x055c
+#define AFE_ASRC_CON17            0x0560
+#define AFE_ASRC_CON18            0x0564
+#define AFE_ASRC_CON19            0x0568
+#define AFE_ASRC_CON20            0x056c
+#define AFE_ASRC_CON21            0x0570
+#define CLK_AUDDIV_0              0x05a0
+#define CLK_AUDDIV_1              0x05a4
+#define CLK_AUDDIV_2              0x05a8
+#define CLK_AUDDIV_3              0x05ac
+#define AUDIO_TOP_DBG_CON         0x05c8
+#define AUDIO_TOP_DBG_MON0        0x05cc
+#define AUDIO_TOP_DBG_MON1        0x05d0
+#define AUDIO_TOP_DBG_MON2        0x05d4
+#define AFE_ADDA2_TOP_CON0        0x0600
+#define AFE_ASRC4_CON0            0x06c0
+#define AFE_ASRC4_CON1            0x06c4
+#define AFE_ASRC4_CON2            0x06c8
+#define AFE_ASRC4_CON3            0x06cc
+#define AFE_ASRC4_CON4            0x06d0
+#define AFE_ASRC4_CON5            0x06d4
+#define AFE_ASRC4_CON6            0x06d8
+#define AFE_ASRC4_CON7            0x06dc
+#define AFE_ASRC4_CON8            0x06e0
+#define AFE_ASRC4_CON9            0x06e4
+#define AFE_ASRC4_CON10           0x06e8
+#define AFE_ASRC4_CON11           0x06ec
+#define AFE_ASRC4_CON12           0x06f0
+#define AFE_ASRC4_CON13           0x06f4
+#define AFE_ASRC4_CON14           0x06f8
+#define AFE_ASRC2_CON0            0x0700
+#define AFE_ASRC2_CON1            0x0704
+#define AFE_ASRC2_CON2            0x0708
+#define AFE_ASRC2_CON3            0x070c
+#define AFE_ASRC2_CON4            0x0710
+#define AFE_ASRC2_CON5            0x0714
+#define AFE_ASRC2_CON6            0x0718
+#define AFE_ASRC2_CON7            0x071c
+#define AFE_ASRC2_CON8            0x0720
+#define AFE_ASRC2_CON9            0x0724
+#define AFE_ASRC2_CON10           0x0728
+#define AFE_ASRC2_CON11           0x072c
+#define AFE_ASRC2_CON12           0x0730
+#define AFE_ASRC2_CON13           0x0734
+#define AFE_ASRC2_CON14           0x0738
+#define AFE_ASRC3_CON0            0x0740
+#define AFE_ASRC3_CON1            0x0744
+#define AFE_ASRC3_CON2            0x0748
+#define AFE_ASRC3_CON3            0x074c
+#define AFE_ASRC3_CON4            0x0750
+#define AFE_ASRC3_CON5            0x0754
+#define AFE_ASRC3_CON6            0x0758
+#define AFE_ASRC3_CON7            0x075c
+#define AFE_ASRC3_CON8            0x0760
+#define AFE_ASRC3_CON9            0x0764
+#define AFE_ASRC3_CON10           0x0768
+#define AFE_ASRC3_CON11           0x076c
+#define AFE_ASRC3_CON12           0x0770
+#define AFE_ASRC3_CON13           0x0774
+#define AFE_ASRC3_CON14           0x0778
+#define AFE_GENERAL_REG0          0x0800
+#define AFE_GENERAL_REG1          0x0804
+#define AFE_GENERAL_REG2          0x0808
+#define AFE_GENERAL_REG3          0x080c
+#define AFE_GENERAL_REG4          0x0810
+#define AFE_GENERAL_REG5          0x0814
+#define AFE_GENERAL_REG6          0x0818
+#define AFE_GENERAL_REG7          0x081c
+#define AFE_GENERAL_REG8          0x0820
+#define AFE_GENERAL_REG9          0x0824
+#define AFE_GENERAL_REG10         0x0828
+#define AFE_GENERAL_REG11         0x082c
+#define AFE_GENERAL_REG12         0x0830
+#define AFE_GENERAL_REG13         0x0834
+#define AFE_GENERAL_REG14         0x0838
+#define AFE_GENERAL_REG15         0x083c
+#define AFE_CBIP_CFG0             0x0840
+#define AFE_CBIP_MON0             0x0844
+#define AFE_CBIP_SLV_MUX_MON0     0x0848
+#define AFE_CBIP_SLV_DECODER_MON0 0x084c
+
+#define AFE_MAX_REGISTER AFE_CBIP_SLV_DECODER_MON0
+#define AFE_IRQ_STATUS_BITS 0x5f
+
+/* AUDIO_TOP_CON0 */
+#define AHB_IDLE_EN_INT_SFT                                 30
+#define AHB_IDLE_EN_INT_MASK                                0x1
+#define AHB_IDLE_EN_INT_MASK_SFT                            (0x1 << 30)
+#define AHB_IDLE_EN_EXT_SFT                                 29
+#define AHB_IDLE_EN_EXT_MASK                                0x1
+#define AHB_IDLE_EN_EXT_MASK_SFT                            (0x1 << 29)
+#define PDN_TML_SFT                                         27
+#define PDN_TML_MASK                                        0x1
+#define PDN_TML_MASK_SFT                                    (0x1 << 27)
+#define PDN_DAC_PREDIS_SFT                                  26
+#define PDN_DAC_PREDIS_MASK                                 0x1
+#define PDN_DAC_PREDIS_MASK_SFT                             (0x1 << 26)
+#define PDN_DAC_SFT                                         25
+#define PDN_DAC_MASK                                        0x1
+#define PDN_DAC_MASK_SFT                                    (0x1 << 25)
+#define PDN_ADC_SFT                                         24
+#define PDN_ADC_MASK                                        0x1
+#define PDN_ADC_MASK_SFT                                    (0x1 << 24)
+#define PDN_TDM_CK_SFT                                      20
+#define PDN_TDM_CK_MASK                                     0x1
+#define PDN_TDM_CK_MASK_SFT                                 (0x1 << 20)
+#define PDN_APLL_TUNER_SFT                                  19
+#define PDN_APLL_TUNER_MASK                                 0x1
+#define PDN_APLL_TUNER_MASK_SFT                             (0x1 << 19)
+#define PDN_APLL2_TUNER_SFT                                 18
+#define PDN_APLL2_TUNER_MASK                                0x1
+#define PDN_APLL2_TUNER_MASK_SFT                            (0x1 << 18)
+#define APB3_SEL_SFT                                        14
+#define APB3_SEL_MASK                                       0x1
+#define APB3_SEL_MASK_SFT                                   (0x1 << 14)
+#define APB_R2T_SFT                                         13
+#define APB_R2T_MASK                                        0x1
+#define APB_R2T_MASK_SFT                                    (0x1 << 13)
+#define APB_W2T_SFT                                         12
+#define APB_W2T_MASK                                        0x1
+#define APB_W2T_MASK_SFT                                    (0x1 << 12)
+#define PDN_24M_SFT                                         9
+#define PDN_24M_MASK                                        0x1
+#define PDN_24M_MASK_SFT                                    (0x1 << 9)
+#define PDN_22M_SFT                                         8
+#define PDN_22M_MASK                                        0x1
+#define PDN_22M_MASK_SFT                                    (0x1 << 8)
+#define PDN_ADDA4_ADC_SFT                                   7
+#define PDN_ADDA4_ADC_MASK                                  0x1
+#define PDN_ADDA4_ADC_MASK_SFT                              (0x1 << 7)
+#define PDN_I2S_SFT                                         6
+#define PDN_I2S_MASK                                        0x1
+#define PDN_I2S_MASK_SFT                                    (0x1 << 6)
+#define PDN_AFE_SFT                                         2
+#define PDN_AFE_MASK                                        0x1
+#define PDN_AFE_MASK_SFT                                    (0x1 << 2)
+
+/* AUDIO_TOP_CON1 */
+#define PDN_ADC_HIRES_TML_SFT                               17
+#define PDN_ADC_HIRES_TML_MASK                              0x1
+#define PDN_ADC_HIRES_TML_MASK_SFT                          (0x1 << 17)
+#define PDN_ADC_HIRES_SFT                                   16
+#define PDN_ADC_HIRES_MASK                                  0x1
+#define PDN_ADC_HIRES_MASK_SFT                              (0x1 << 16)
+#define I2S4_BCLK_SW_CG_SFT                                 7
+#define I2S4_BCLK_SW_CG_MASK                                0x1
+#define I2S4_BCLK_SW_CG_MASK_SFT                            (0x1 << 7)
+#define I2S3_BCLK_SW_CG_SFT                                 6
+#define I2S3_BCLK_SW_CG_MASK                                0x1
+#define I2S3_BCLK_SW_CG_MASK_SFT                            (0x1 << 6)
+#define I2S2_BCLK_SW_CG_SFT                                 5
+#define I2S2_BCLK_SW_CG_MASK                                0x1
+#define I2S2_BCLK_SW_CG_MASK_SFT                            (0x1 << 5)
+#define I2S1_BCLK_SW_CG_SFT                                 4
+#define I2S1_BCLK_SW_CG_MASK                                0x1
+#define I2S1_BCLK_SW_CG_MASK_SFT                            (0x1 << 4)
+#define I2S_SOFT_RST2_SFT                                   2
+#define I2S_SOFT_RST2_MASK                                  0x1
+#define I2S_SOFT_RST2_MASK_SFT                              (0x1 << 2)
+#define I2S_SOFT_RST_SFT                                    1
+#define I2S_SOFT_RST_MASK                                   0x1
+#define I2S_SOFT_RST_MASK_SFT                               (0x1 << 1)
+
+/* AFE_DAC_CON0 */
+#define AFE_AWB_RETM_SFT                                    31
+#define AFE_AWB_RETM_MASK                                   0x1
+#define AFE_AWB_RETM_MASK_SFT                               (0x1 << 31)
+#define AFE_DL1_DATA2_RETM_SFT                              30
+#define AFE_DL1_DATA2_RETM_MASK                             0x1
+#define AFE_DL1_DATA2_RETM_MASK_SFT                         (0x1 << 30)
+#define AFE_DL2_RETM_SFT                                    29
+#define AFE_DL2_RETM_MASK                                   0x1
+#define AFE_DL2_RETM_MASK_SFT                               (0x1 << 29)
+#define AFE_DL1_RETM_SFT                                    28
+#define AFE_DL1_RETM_MASK                                   0x1
+#define AFE_DL1_RETM_MASK_SFT                               (0x1 << 28)
+#define AFE_ON_RETM_SFT                                     27
+#define AFE_ON_RETM_MASK                                    0x1
+#define AFE_ON_RETM_MASK_SFT                                (0x1 << 27)
+#define MOD_DAI_DUP_WR_SFT                                  26
+#define MOD_DAI_DUP_WR_MASK                                 0x1
+#define MOD_DAI_DUP_WR_MASK_SFT                             (0x1 << 26)
+#define DAI_MODE_SFT                                        24
+#define DAI_MODE_MASK                                       0x3
+#define DAI_MODE_MASK_SFT                                   (0x3 << 24)
+#define VUL_DATA2_MODE_SFT                                  20
+#define VUL_DATA2_MODE_MASK                                 0xf
+#define VUL_DATA2_MODE_MASK_SFT                             (0xf << 20)
+#define DL1_DATA2_MODE_SFT                                  16
+#define DL1_DATA2_MODE_MASK                                 0xf
+#define DL1_DATA2_MODE_MASK_SFT                             (0xf << 16)
+#define DL3_MODE_SFT                                        12
+#define DL3_MODE_MASK                                       0xf
+#define DL3_MODE_MASK_SFT                                   (0xf << 12)
+#define VUL_DATA2_R_MONO_SFT                                11
+#define VUL_DATA2_R_MONO_MASK                               0x1
+#define VUL_DATA2_R_MONO_MASK_SFT                           (0x1 << 11)
+#define VUL_DATA2_DATA_SFT                                  10
+#define VUL_DATA2_DATA_MASK                                 0x1
+#define VUL_DATA2_DATA_MASK_SFT                             (0x1 << 10)
+#define VUL_DATA2_ON_SFT                                    9
+#define VUL_DATA2_ON_MASK                                   0x1
+#define VUL_DATA2_ON_MASK_SFT                               (0x1 << 9)
+#define DL1_DATA2_ON_SFT                                    8
+#define DL1_DATA2_ON_MASK                                   0x1
+#define DL1_DATA2_ON_MASK_SFT                               (0x1 << 8)
+#define MOD_DAI_ON_SFT                                      7
+#define MOD_DAI_ON_MASK                                     0x1
+#define MOD_DAI_ON_MASK_SFT                                 (0x1 << 7)
+#define AWB_ON_SFT                                          6
+#define AWB_ON_MASK                                         0x1
+#define AWB_ON_MASK_SFT                                     (0x1 << 6)
+#define DL3_ON_SFT                                          5
+#define DL3_ON_MASK                                         0x1
+#define DL3_ON_MASK_SFT                                     (0x1 << 5)
+#define DAI_ON_SFT                                          4
+#define DAI_ON_MASK                                         0x1
+#define DAI_ON_MASK_SFT                                     (0x1 << 4)
+#define VUL_ON_SFT                                          3
+#define VUL_ON_MASK                                         0x1
+#define VUL_ON_MASK_SFT                                     (0x1 << 3)
+#define DL2_ON_SFT                                          2
+#define DL2_ON_MASK                                         0x1
+#define DL2_ON_MASK_SFT                                     (0x1 << 2)
+#define DL1_ON_SFT                                          1
+#define DL1_ON_MASK                                         0x1
+#define DL1_ON_MASK_SFT                                     (0x1 << 1)
+#define AFE_ON_SFT                                          0
+#define AFE_ON_MASK                                         0x1
+#define AFE_ON_MASK_SFT                                     (0x1 << 0)
+
+/* AFE_DAC_CON1 */
+#define MOD_DAI_MODE_SFT                                    30
+#define MOD_DAI_MODE_MASK                                   0x3
+#define MOD_DAI_MODE_MASK_SFT                               (0x3 << 30)
+#define DAI_DUP_WR_SFT                                      29
+#define DAI_DUP_WR_MASK                                     0x1
+#define DAI_DUP_WR_MASK_SFT                                 (0x1 << 29)
+#define VUL_R_MONO_SFT                                      28
+#define VUL_R_MONO_MASK                                     0x1
+#define VUL_R_MONO_MASK_SFT                                 (0x1 << 28)
+#define VUL_DATA_SFT                                        27
+#define VUL_DATA_MASK                                       0x1
+#define VUL_DATA_MASK_SFT                                   (0x1 << 27)
+#define AXI_2X1_CG_DISABLE_SFT                              26
+#define AXI_2X1_CG_DISABLE_MASK                             0x1
+#define AXI_2X1_CG_DISABLE_MASK_SFT                         (0x1 << 26)
+#define AWB_R_MONO_SFT                                      25
+#define AWB_R_MONO_MASK                                     0x1
+#define AWB_R_MONO_MASK_SFT                                 (0x1 << 25)
+#define AWB_DATA_SFT                                        24
+#define AWB_DATA_MASK                                       0x1
+#define AWB_DATA_MASK_SFT                                   (0x1 << 24)
+#define DL3_DATA_SFT                                        23
+#define DL3_DATA_MASK                                       0x1
+#define DL3_DATA_MASK_SFT                                   (0x1 << 23)
+#define DL2_DATA_SFT                                        22
+#define DL2_DATA_MASK                                       0x1
+#define DL2_DATA_MASK_SFT                                   (0x1 << 22)
+#define DL1_DATA_SFT                                        21
+#define DL1_DATA_MASK                                       0x1
+#define DL1_DATA_MASK_SFT                                   (0x1 << 21)
+#define DL1_DATA2_DATA_SFT                                  20
+#define DL1_DATA2_DATA_MASK                                 0x1
+#define DL1_DATA2_DATA_MASK_SFT                             (0x1 << 20)
+#define VUL_MODE_SFT                                        16
+#define VUL_MODE_MASK                                       0xf
+#define VUL_MODE_MASK_SFT                                   (0xf << 16)
+#define AWB_MODE_SFT                                        12
+#define AWB_MODE_MASK                                       0xf
+#define AWB_MODE_MASK_SFT                                   (0xf << 12)
+#define I2S_MODE_SFT                                        8
+#define I2S_MODE_MASK                                       0xf
+#define I2S_MODE_MASK_SFT                                   (0xf << 8)
+#define DL2_MODE_SFT                                        4
+#define DL2_MODE_MASK                                       0xf
+#define DL2_MODE_MASK_SFT                                   (0xf << 4)
+#define DL1_MODE_SFT                                        0
+#define DL1_MODE_MASK                                       0xf
+#define DL1_MODE_MASK_SFT                                   (0xf << 0)
+
+/* AFE_ADDA_DL_SRC2_CON0 */
+#define DL_2_INPUT_MODE_CTL_SFT                             28
+#define DL_2_INPUT_MODE_CTL_MASK                            0xf
+#define DL_2_INPUT_MODE_CTL_MASK_SFT                        (0xf << 28)
+#define DL_2_CH1_SATURATION_EN_CTL_SFT                      27
+#define DL_2_CH1_SATURATION_EN_CTL_MASK                     0x1
+#define DL_2_CH1_SATURATION_EN_CTL_MASK_SFT                 (0x1 << 27)
+#define DL_2_CH2_SATURATION_EN_CTL_SFT                      26
+#define DL_2_CH2_SATURATION_EN_CTL_MASK                     0x1
+#define DL_2_CH2_SATURATION_EN_CTL_MASK_SFT                 (0x1 << 26)
+#define DL_2_OUTPUT_SEL_CTL_SFT                             24
+#define DL_2_OUTPUT_SEL_CTL_MASK                            0x3
+#define DL_2_OUTPUT_SEL_CTL_MASK_SFT                        (0x3 << 24)
+#define DL_2_FADEIN_0START_EN_SFT                           16
+#define DL_2_FADEIN_0START_EN_MASK                          0x3
+#define DL_2_FADEIN_0START_EN_MASK_SFT                      (0x3 << 16)
+#define DL_DISABLE_HW_CG_CTL_SFT                            15
+#define DL_DISABLE_HW_CG_CTL_MASK                           0x1
+#define DL_DISABLE_HW_CG_CTL_MASK_SFT                       (0x1 << 15)
+#define C_DATA_EN_SEL_CTL_PRE_SFT                           14
+#define C_DATA_EN_SEL_CTL_PRE_MASK                          0x1
+#define C_DATA_EN_SEL_CTL_PRE_MASK_SFT                      (0x1 << 14)
+#define DL_2_SIDE_TONE_ON_CTL_PRE_SFT                       13
+#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK                      0x1
+#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK_SFT                  (0x1 << 13)
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_SFT                       12
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK                      0x1
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK_SFT                  (0x1 << 12)
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_SFT                       11
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK                      0x1
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK_SFT                  (0x1 << 11)
+#define DL2_ARAMPSP_CTL_PRE_SFT                             9
+#define DL2_ARAMPSP_CTL_PRE_MASK                            0x3
+#define DL2_ARAMPSP_CTL_PRE_MASK_SFT                        (0x3 << 9)
+#define DL_2_IIRMODE_CTL_PRE_SFT                            6
+#define DL_2_IIRMODE_CTL_PRE_MASK                           0x7
+#define DL_2_IIRMODE_CTL_PRE_MASK_SFT                       (0x7 << 6)
+#define DL_2_VOICE_MODE_CTL_PRE_SFT                         5
+#define DL_2_VOICE_MODE_CTL_PRE_MASK                        0x1
+#define DL_2_VOICE_MODE_CTL_PRE_MASK_SFT                    (0x1 << 5)
+#define D2_2_MUTE_CH1_ON_CTL_PRE_SFT                        4
+#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK                       0x1
+#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK_SFT                   (0x1 << 4)
+#define D2_2_MUTE_CH2_ON_CTL_PRE_SFT                        3
+#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK                       0x1
+#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK_SFT                   (0x1 << 3)
+#define DL_2_IIR_ON_CTL_PRE_SFT                             2
+#define DL_2_IIR_ON_CTL_PRE_MASK                            0x1
+#define DL_2_IIR_ON_CTL_PRE_MASK_SFT                        (0x1 << 2)
+#define DL_2_GAIN_ON_CTL_PRE_SFT                            1
+#define DL_2_GAIN_ON_CTL_PRE_MASK                           0x1
+#define DL_2_GAIN_ON_CTL_PRE_MASK_SFT                       (0x1 << 1)
+#define DL_2_SRC_ON_TMP_CTL_PRE_SFT                         0
+#define DL_2_SRC_ON_TMP_CTL_PRE_MASK                        0x1
+#define DL_2_SRC_ON_TMP_CTL_PRE_MASK_SFT                    (0x1 << 0)
+
+/* AFE_ADDA_DL_SRC2_CON1 */
+#define DL_2_GAIN_CTL_PRE_SFT                               16
+#define DL_2_GAIN_CTL_PRE_MASK                              0xffff
+#define DL_2_GAIN_CTL_PRE_MASK_SFT                          (0xffff << 16)
+#define DL_2_GAIN_MODE_CTL_SFT                              0
+#define DL_2_GAIN_MODE_CTL_MASK                             0x1
+#define DL_2_GAIN_MODE_CTL_MASK_SFT                         (0x1 << 0)
+
+/* AFE_ADDA_UL_SRC_CON0 */
+#define C_COMB_OUT_SIN_GEN_CTL_SFT                          31
+#define C_COMB_OUT_SIN_GEN_CTL_MASK                         0x1
+#define C_COMB_OUT_SIN_GEN_CTL_MASK_SFT                     (0x1 << 31)
+#define C_BASEBAND_SIN_GEN_CTL_SFT                          30
+#define C_BASEBAND_SIN_GEN_CTL_MASK                         0x1
+#define C_BASEBAND_SIN_GEN_CTL_MASK_SFT                     (0x1 << 30)
+#define C_DIGMIC_PHASE_SEL_CH1_CTL_SFT                      27
+#define C_DIGMIC_PHASE_SEL_CH1_CTL_MASK                     0x7
+#define C_DIGMIC_PHASE_SEL_CH1_CTL_MASK_SFT                 (0x7 << 27)
+#define C_DIGMIC_PHASE_SEL_CH2_CTL_SFT                      24
+#define C_DIGMIC_PHASE_SEL_CH2_CTL_MASK                     0x7
+#define C_DIGMIC_PHASE_SEL_CH2_CTL_MASK_SFT                 (0x7 << 24)
+#define C_TWO_DIGITAL_MIC_CTL_SFT                           23
+#define C_TWO_DIGITAL_MIC_CTL_MASK                          0x1
+#define C_TWO_DIGITAL_MIC_CTL_MASK_SFT                      (0x1 << 23)
+#define UL_MODE_3P25M_CH2_CTL_SFT                           22
+#define UL_MODE_3P25M_CH2_CTL_MASK                          0x1
+#define UL_MODE_3P25M_CH2_CTL_MASK_SFT                      (0x1 << 22)
+#define UL_MODE_3P25M_CH1_CTL_SFT                           21
+#define UL_MODE_3P25M_CH1_CTL_MASK                          0x1
+#define UL_MODE_3P25M_CH1_CTL_MASK_SFT                      (0x1 << 21)
+#define UL_SRC_USE_CIC_OUT_CTL_SFT                          20
+#define UL_SRC_USE_CIC_OUT_CTL_MASK                         0x1
+#define UL_SRC_USE_CIC_OUT_CTL_MASK_SFT                     (0x1 << 20)
+#define UL_VOICE_MODE_CH1_CH2_CTL_SFT                       17
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK                      0x7
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT                  (0x7 << 17)
+#define DMIC_LOW_POWER_MODE_CTL_SFT                         14
+#define DMIC_LOW_POWER_MODE_CTL_MASK                        0x3
+#define DMIC_LOW_POWER_MODE_CTL_MASK_SFT                    (0x3 << 14)
+#define DMIC_48K_SEL_CTL_SFT                                13
+#define DMIC_48K_SEL_CTL_MASK                               0x1
+#define DMIC_48K_SEL_CTL_MASK_SFT                           (0x1 << 13)
+#define UL_DISABLE_HW_CG_CTL_SFT                            12
+#define UL_DISABLE_HW_CG_CTL_MASK                           0x1
+#define UL_DISABLE_HW_CG_CTL_MASK_SFT                       (0x1 << 12)
+#define UL_IIR_ON_TMP_CTL_SFT                               10
+#define UL_IIR_ON_TMP_CTL_MASK                              0x1
+#define UL_IIR_ON_TMP_CTL_MASK_SFT                          (0x1 << 10)
+#define UL_IIRMODE_CTL_SFT                                  7
+#define UL_IIRMODE_CTL_MASK                                 0x7
+#define UL_IIRMODE_CTL_MASK_SFT                             (0x7 << 7)
+#define DIGMIC_3P25M_1P625M_SEL_CTL_SFT                     5
+#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK                    0x1
+#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT                (0x1 << 5)
+#define AGC_260K_SEL_CH2_CTL_SFT                            4
+#define AGC_260K_SEL_CH2_CTL_MASK                           0x1
+#define AGC_260K_SEL_CH2_CTL_MASK_SFT                       (0x1 << 4)
+#define AGC_260K_SEL_CH1_CTL_SFT                            3
+#define AGC_260K_SEL_CH1_CTL_MASK                           0x1
+#define AGC_260K_SEL_CH1_CTL_MASK_SFT                       (0x1 << 3)
+#define UL_LOOP_BACK_MODE_CTL_SFT                           2
+#define UL_LOOP_BACK_MODE_CTL_MASK                          0x1
+#define UL_LOOP_BACK_MODE_CTL_MASK_SFT                      (0x1 << 2)
+#define UL_SDM_3_LEVEL_CTL_SFT                              1
+#define UL_SDM_3_LEVEL_CTL_MASK                             0x1
+#define UL_SDM_3_LEVEL_CTL_MASK_SFT                         (0x1 << 1)
+#define UL_SRC_ON_TMP_CTL_SFT                               0
+#define UL_SRC_ON_TMP_CTL_MASK                              0x1
+#define UL_SRC_ON_TMP_CTL_MASK_SFT                          (0x1 << 0)
+
+/* AFE_ADDA_UL_SRC_CON1 */
+#define C_SDM_RESET_CTL_SFT                                 31
+#define C_SDM_RESET_CTL_MASK                                0x1
+#define C_SDM_RESET_CTL_MASK_SFT                            (0x1 << 31)
+#define ADITHON_CTL_SFT                                     30
+#define ADITHON_CTL_MASK                                    0x1
+#define ADITHON_CTL_MASK_SFT                                (0x1 << 30)
+#define ADITHVAL_CTL_SFT                                    28
+#define ADITHVAL_CTL_MASK                                   0x3
+#define ADITHVAL_CTL_MASK_SFT                               (0x3 << 28)
+#define C_DAC_EN_CTL_SFT                                    27
+#define C_DAC_EN_CTL_MASK                                   0x1
+#define C_DAC_EN_CTL_MASK_SFT                               (0x1 << 27)
+#define C_MUTE_SW_CTL_SFT                                   26
+#define C_MUTE_SW_CTL_MASK                                  0x1
+#define C_MUTE_SW_CTL_MASK_SFT                              (0x1 << 26)
+#define ASDM_SRC_SEL_CTL_SFT                                25
+#define ASDM_SRC_SEL_CTL_MASK                               0x1
+#define ASDM_SRC_SEL_CTL_MASK_SFT                           (0x1 << 25)
+#define C_AMP_DIV_CH2_CTL_SFT                               21
+#define C_AMP_DIV_CH2_CTL_MASK                              0x7
+#define C_AMP_DIV_CH2_CTL_MASK_SFT                          (0x7 << 21)
+#define C_FREQ_DIV_CH2_CTL_SFT                              16
+#define C_FREQ_DIV_CH2_CTL_MASK                             0x1f
+#define C_FREQ_DIV_CH2_CTL_MASK_SFT                         (0x1f << 16)
+#define C_SINE_MODE_CH2_CTL_SFT                             12
+#define C_SINE_MODE_CH2_CTL_MASK                            0xf
+#define C_SINE_MODE_CH2_CTL_MASK_SFT                        (0xf << 12)
+#define C_AMP_DIV_CH1_CTL_SFT                               9
+#define C_AMP_DIV_CH1_CTL_MASK                              0x7
+#define C_AMP_DIV_CH1_CTL_MASK_SFT                          (0x7 << 9)
+#define C_FREQ_DIV_CH1_CTL_SFT                              4
+#define C_FREQ_DIV_CH1_CTL_MASK                             0x1f
+#define C_FREQ_DIV_CH1_CTL_MASK_SFT                         (0x1f << 4)
+#define C_SINE_MODE_CH1_CTL_SFT                             0
+#define C_SINE_MODE_CH1_CTL_MASK                            0xf
+#define C_SINE_MODE_CH1_CTL_MASK_SFT                        (0xf << 0)
+
+/* AFE_ADDA_TOP_CON0 */
+#define C_LOOP_BACK_MODE_CTL_SFT                            12
+#define C_LOOP_BACK_MODE_CTL_MASK                           0xf
+#define C_LOOP_BACK_MODE_CTL_MASK_SFT                       (0xf << 12)
+#define C_EXT_ADC_CTL_SFT                                   0
+#define C_EXT_ADC_CTL_MASK                                  0x1
+#define C_EXT_ADC_CTL_MASK_SFT                              (0x1 << 0)
+
+/* AFE_ADDA_UL_DL_CON0 */
+#define AFE_UL_DL_CON0_RESERVED_SFT                         1
+#define AFE_UL_DL_CON0_RESERVED_MASK                        0x3fff
+#define AFE_UL_DL_CON0_RESERVED_MASK_SFT                    (0x3fff << 1)
+#define ADDA_AFE_ON_SFT                                     0
+#define ADDA_AFE_ON_MASK                                    0x1
+#define ADDA_AFE_ON_MASK_SFT                                (0x1 << 0)
+
+/* AFE_IRQ_MCU_CON */
+#define IRQ7_MCU_MODE_SFT                                   24
+#define IRQ7_MCU_MODE_MASK                                  0xf
+#define IRQ7_MCU_MODE_MASK_SFT                              (0xf << 24)
+#define IRQ4_MCU_MODE_SFT                                   20
+#define IRQ4_MCU_MODE_MASK                                  0xf
+#define IRQ4_MCU_MODE_MASK_SFT                              (0xf << 20)
+#define IRQ3_MCU_MODE_SFT                                   16
+#define IRQ3_MCU_MODE_MASK                                  0xf
+#define IRQ3_MCU_MODE_MASK_SFT                              (0xf << 16)
+#define IRQ7_MCU_ON_SFT                                     14
+#define IRQ7_MCU_ON_MASK                                    0x1
+#define IRQ7_MCU_ON_MASK_SFT                                (0x1 << 14)
+#define IRQ5_MCU_ON_SFT                                     12
+#define IRQ5_MCU_ON_MASK                                    0x1
+#define IRQ5_MCU_ON_MASK_SFT                                (0x1 << 12)
+#define IRQ2_MCU_MODE_SFT                                   8
+#define IRQ2_MCU_MODE_MASK                                  0xf
+#define IRQ2_MCU_MODE_MASK_SFT                              (0xf << 8)
+#define IRQ1_MCU_MODE_SFT                                   4
+#define IRQ1_MCU_MODE_MASK                                  0xf
+#define IRQ1_MCU_MODE_MASK_SFT                              (0xf << 4)
+#define IRQ4_MCU_ON_SFT                                     3
+#define IRQ4_MCU_ON_MASK                                    0x1
+#define IRQ4_MCU_ON_MASK_SFT                                (0x1 << 3)
+#define IRQ3_MCU_ON_SFT                                     2
+#define IRQ3_MCU_ON_MASK                                    0x1
+#define IRQ3_MCU_ON_MASK_SFT                                (0x1 << 2)
+#define IRQ2_MCU_ON_SFT                                     1
+#define IRQ2_MCU_ON_MASK                                    0x1
+#define IRQ2_MCU_ON_MASK_SFT                                (0x1 << 1)
+#define IRQ1_MCU_ON_SFT                                     0
+#define IRQ1_MCU_ON_MASK                                    0x1
+#define IRQ1_MCU_ON_MASK_SFT                                (0x1 << 0)
+
+/* AFE_IRQ_MCU_EN */
+#define AFE_IRQ_CM4_EN_SFT                                  16
+#define AFE_IRQ_CM4_EN_MASK                                 0x7f
+#define AFE_IRQ_CM4_EN_MASK_SFT                             (0x7f << 16)
+#define AFE_IRQ_MD32_EN_SFT                                 8
+#define AFE_IRQ_MD32_EN_MASK                                0x7f
+#define AFE_IRQ_MD32_EN_MASK_SFT                            (0x7f << 8)
+#define AFE_IRQ_MCU_EN_SFT                                  0
+#define AFE_IRQ_MCU_EN_MASK                                 0x7f
+#define AFE_IRQ_MCU_EN_MASK_SFT                             (0x7f << 0)
+
+/* AFE_IRQ_MCU_CLR */
+#define IRQ7_MCU_CLR_SFT                                    6
+#define IRQ7_MCU_CLR_MASK                                   0x1
+#define IRQ7_MCU_CLR_MASK_SFT                               (0x1 << 6)
+#define IRQ5_MCU_CLR_SFT                                    4
+#define IRQ5_MCU_CLR_MASK                                   0x1
+#define IRQ5_MCU_CLR_MASK_SFT                               (0x1 << 4)
+#define IRQ4_MCU_CLR_SFT                                    3
+#define IRQ4_MCU_CLR_MASK                                   0x1
+#define IRQ4_MCU_CLR_MASK_SFT                               (0x1 << 3)
+#define IRQ3_MCU_CLR_SFT                                    2
+#define IRQ3_MCU_CLR_MASK                                   0x1
+#define IRQ3_MCU_CLR_MASK_SFT                               (0x1 << 2)
+#define IRQ2_MCU_CLR_SFT                                    1
+#define IRQ2_MCU_CLR_MASK                                   0x1
+#define IRQ2_MCU_CLR_MASK_SFT                               (0x1 << 1)
+#define IRQ1_MCU_CLR_SFT                                    0
+#define IRQ1_MCU_CLR_MASK                                   0x1
+#define IRQ1_MCU_CLR_MASK_SFT                               (0x1 << 0)
+
+/* AFE_IRQ_MCU_CNT1 */
+#define AFE_IRQ_MCU_CNT1_SFT                                0
+#define AFE_IRQ_MCU_CNT1_MASK                               0x3ffff
+#define AFE_IRQ_MCU_CNT1_MASK_SFT                           (0x3ffff << 0)
+
+/* AFE_IRQ_MCU_CNT2 */
+#define AFE_IRQ_MCU_CNT2_SFT                                0
+#define AFE_IRQ_MCU_CNT2_MASK                               0x3ffff
+#define AFE_IRQ_MCU_CNT2_MASK_SFT                           (0x3ffff << 0)
+
+/* AFE_IRQ_MCU_CNT3 */
+#define AFE_IRQ_MCU_CNT3_SFT                                0
+#define AFE_IRQ_MCU_CNT3_MASK                               0x3ffff
+#define AFE_IRQ_MCU_CNT3_MASK_SFT                           (0x3ffff << 0)
+
+/* AFE_IRQ_MCU_CNT4 */
+#define AFE_IRQ_MCU_CNT4_SFT                                0
+#define AFE_IRQ_MCU_CNT4_MASK                               0x3ffff
+#define AFE_IRQ_MCU_CNT4_MASK_SFT                           (0x3ffff << 0)
+
+/* AFE_IRQ_MCU_CNT5 */
+#define AFE_IRQ_MCU_CNT5_SFT                                0
+#define AFE_IRQ_MCU_CNT5_MASK                               0x3ffff
+#define AFE_IRQ_MCU_CNT5_MASK_SFT                           (0x3ffff << 0)
+
+/* AFE_IRQ_MCU_CNT7 */
+#define AFE_IRQ_MCU_CNT7_SFT                                0
+#define AFE_IRQ_MCU_CNT7_MASK                               0x3ffff
+#define AFE_IRQ_MCU_CNT7_MASK_SFT                           (0x3ffff << 0)
+
+/* AFE_MEMIF_MSB */
+#define CPU_COMPACT_MODE_SFT                                23
+#define CPU_COMPACT_MODE_MASK                               0x1
+#define CPU_COMPACT_MODE_MASK_SFT                           (0x1 << 23)
+#define CPU_HD_ALIGN_SFT                                    22
+#define CPU_HD_ALIGN_MASK                                   0x1
+#define CPU_HD_ALIGN_MASK_SFT                               (0x1 << 22)
+
+/* AFE_MEMIF_HD_MODE */
+#define HDMI_HD_SFT                                         20
+#define HDMI_HD_MASK                                        0x3
+#define HDMI_HD_MASK_SFT                                    (0x3 << 20)
+#define MOD_DAI_HD_SFT                                      18
+#define MOD_DAI_HD_MASK                                     0x3
+#define MOD_DAI_HD_MASK_SFT                                 (0x3 << 18)
+#define DAI_HD_SFT                                          16
+#define DAI_HD_MASK                                         0x3
+#define DAI_HD_MASK_SFT                                     (0x3 << 16)
+#define VUL_DATA2_HD_SFT                                    12
+#define VUL_DATA2_HD_MASK                                   0x3
+#define VUL_DATA2_HD_MASK_SFT                               (0x3 << 12)
+#define VUL_HD_SFT                                          10
+#define VUL_HD_MASK                                         0x3
+#define VUL_HD_MASK_SFT                                     (0x3 << 10)
+#define AWB_HD_SFT                                          8
+#define AWB_HD_MASK                                         0x3
+#define AWB_HD_MASK_SFT                                     (0x3 << 8)
+#define DL3_HD_SFT                                          6
+#define DL3_HD_MASK                                         0x3
+#define DL3_HD_MASK_SFT                                     (0x3 << 6)
+#define DL2_HD_SFT                                          4
+#define DL2_HD_MASK                                         0x3
+#define DL2_HD_MASK_SFT                                     (0x3 << 4)
+#define DL1_DATA2_HD_SFT                                    2
+#define DL1_DATA2_HD_MASK                                   0x3
+#define DL1_DATA2_HD_MASK_SFT                               (0x3 << 2)
+#define DL1_HD_SFT                                          0
+#define DL1_HD_MASK                                         0x3
+#define DL1_HD_MASK_SFT                                     (0x3 << 0)
+
+/* AFE_MEMIF_HDALIGN */
+#define HDMI_NORMAL_MODE_SFT                                26
+#define HDMI_NORMAL_MODE_MASK                               0x1
+#define HDMI_NORMAL_MODE_MASK_SFT                           (0x1 << 26)
+#define MOD_DAI_NORMAL_MODE_SFT                             25
+#define MOD_DAI_NORMAL_MODE_MASK                            0x1
+#define MOD_DAI_NORMAL_MODE_MASK_SFT                        (0x1 << 25)
+#define DAI_NORMAL_MODE_SFT                                 24
+#define DAI_NORMAL_MODE_MASK                                0x1
+#define DAI_NORMAL_MODE_MASK_SFT                            (0x1 << 24)
+#define VUL_DATA2_NORMAL_MODE_SFT                           22
+#define VUL_DATA2_NORMAL_MODE_MASK                          0x1
+#define VUL_DATA2_NORMAL_MODE_MASK_SFT                      (0x1 << 22)
+#define VUL_NORMAL_MODE_SFT                                 21
+#define VUL_NORMAL_MODE_MASK                                0x1
+#define VUL_NORMAL_MODE_MASK_SFT                            (0x1 << 21)
+#define AWB_NORMAL_MODE_SFT                                 20
+#define AWB_NORMAL_MODE_MASK                                0x1
+#define AWB_NORMAL_MODE_MASK_SFT                            (0x1 << 20)
+#define DL3_NORMAL_MODE_SFT                                 19
+#define DL3_NORMAL_MODE_MASK                                0x1
+#define DL3_NORMAL_MODE_MASK_SFT                            (0x1 << 19)
+#define DL2_NORMAL_MODE_SFT                                 18
+#define DL2_NORMAL_MODE_MASK                                0x1
+#define DL2_NORMAL_MODE_MASK_SFT                            (0x1 << 18)
+#define DL1_DATA2_NORMAL_MODE_SFT                           17
+#define DL1_DATA2_NORMAL_MODE_MASK                          0x1
+#define DL1_DATA2_NORMAL_MODE_MASK_SFT                      (0x1 << 17)
+#define DL1_NORMAL_MODE_SFT                                 16
+#define DL1_NORMAL_MODE_MASK                                0x1
+#define DL1_NORMAL_MODE_MASK_SFT                            (0x1 << 16)
+#define HDMI_HD_ALIGN_SFT                                   10
+#define HDMI_HD_ALIGN_MASK                                  0x1
+#define HDMI_HD_ALIGN_MASK_SFT                              (0x1 << 10)
+#define MOD_DAI_HD_ALIGN_SFT                                9
+#define MOD_DAI_HD_ALIGN_MASK                               0x1
+#define MOD_DAI_HD_ALIGN_MASK_SFT                           (0x1 << 9)
+#define DAI_ALIGN_SFT                                       8
+#define DAI_ALIGN_MASK                                      0x1
+#define DAI_ALIGN_MASK_SFT                                  (0x1 << 8)
+#define VUL2_HD_ALIGN_SFT                                   7
+#define VUL2_HD_ALIGN_MASK                                  0x1
+#define VUL2_HD_ALIGN_MASK_SFT                              (0x1 << 7)
+#define VUL_DATA2_HD_ALIGN_SFT                              6
+#define VUL_DATA2_HD_ALIGN_MASK                             0x1
+#define VUL_DATA2_HD_ALIGN_MASK_SFT                         (0x1 << 6)
+#define VUL_HD_ALIGN_SFT                                    5
+#define VUL_HD_ALIGN_MASK                                   0x1
+#define VUL_HD_ALIGN_MASK_SFT                               (0x1 << 5)
+#define AWB_HD_ALIGN_SFT                                    4
+#define AWB_HD_ALIGN_MASK                                   0x1
+#define AWB_HD_ALIGN_MASK_SFT                               (0x1 << 4)
+#define DL3_HD_ALIGN_SFT                                    3
+#define DL3_HD_ALIGN_MASK                                   0x1
+#define DL3_HD_ALIGN_MASK_SFT                               (0x1 << 3)
+#define DL2_HD_ALIGN_SFT                                    2
+#define DL2_HD_ALIGN_MASK                                   0x1
+#define DL2_HD_ALIGN_MASK_SFT                               (0x1 << 2)
+#define DL1_DATA2_HD_ALIGN_SFT                              1
+#define DL1_DATA2_HD_ALIGN_MASK                             0x1
+#define DL1_DATA2_HD_ALIGN_MASK_SFT                         (0x1 << 1)
+#define DL1_HD_ALIGN_SFT                                    0
+#define DL1_HD_ALIGN_MASK                                   0x1
+#define DL1_HD_ALIGN_MASK_SFT                               (0x1 << 0)
+
+/* PCM_INTF_CON1 */
+#define PCM_FIX_VALUE_SEL_SFT                               31
+#define PCM_FIX_VALUE_SEL_MASK                              0x1
+#define PCM_FIX_VALUE_SEL_MASK_SFT                          (0x1 << 31)
+#define PCM_BUFFER_LOOPBACK_SFT                             30
+#define PCM_BUFFER_LOOPBACK_MASK                            0x1
+#define PCM_BUFFER_LOOPBACK_MASK_SFT                        (0x1 << 30)
+#define PCM_PARALLEL_LOOPBACK_SFT                           29
+#define PCM_PARALLEL_LOOPBACK_MASK                          0x1
+#define PCM_PARALLEL_LOOPBACK_MASK_SFT                      (0x1 << 29)
+#define PCM_SERIAL_LOOPBACK_SFT                             28
+#define PCM_SERIAL_LOOPBACK_MASK                            0x1
+#define PCM_SERIAL_LOOPBACK_MASK_SFT                        (0x1 << 28)
+#define PCM_DAI_PCM_LOOPBACK_SFT                            27
+#define PCM_DAI_PCM_LOOPBACK_MASK                           0x1
+#define PCM_DAI_PCM_LOOPBACK_MASK_SFT                       (0x1 << 27)
+#define PCM_I2S_PCM_LOOPBACK_SFT                            26
+#define PCM_I2S_PCM_LOOPBACK_MASK                           0x1
+#define PCM_I2S_PCM_LOOPBACK_MASK_SFT                       (0x1 << 26)
+#define PCM_SYNC_DELSEL_SFT                                 25
+#define PCM_SYNC_DELSEL_MASK                                0x1
+#define PCM_SYNC_DELSEL_MASK_SFT                            (0x1 << 25)
+#define PCM_TX_LR_SWAP_SFT                                  24
+#define PCM_TX_LR_SWAP_MASK                                 0x1
+#define PCM_TX_LR_SWAP_MASK_SFT                             (0x1 << 24)
+#define PCM_SYNC_OUT_INV_SFT                                23
+#define PCM_SYNC_OUT_INV_MASK                               0x1
+#define PCM_SYNC_OUT_INV_MASK_SFT                           (0x1 << 23)
+#define PCM_BCLK_OUT_INV_SFT                                22
+#define PCM_BCLK_OUT_INV_MASK                               0x1
+#define PCM_BCLK_OUT_INV_MASK_SFT                           (0x1 << 22)
+#define PCM_SYNC_IN_INV_SFT                                 21
+#define PCM_SYNC_IN_INV_MASK                                0x1
+#define PCM_SYNC_IN_INV_MASK_SFT                            (0x1 << 21)
+#define PCM_BCLK_IN_INV_SFT                                 20
+#define PCM_BCLK_IN_INV_MASK                                0x1
+#define PCM_BCLK_IN_INV_MASK_SFT                            (0x1 << 20)
+#define PCM_TX_LCH_RPT_SFT                                  19
+#define PCM_TX_LCH_RPT_MASK                                 0x1
+#define PCM_TX_LCH_RPT_MASK_SFT                             (0x1 << 19)
+#define PCM_VBT_16K_MODE_SFT                                18
+#define PCM_VBT_16K_MODE_MASK                               0x1
+#define PCM_VBT_16K_MODE_MASK_SFT                           (0x1 << 18)
+#define PCM_EXT_MODEM_SFT                                   17
+#define PCM_EXT_MODEM_MASK                                  0x1
+#define PCM_EXT_MODEM_MASK_SFT                              (0x1 << 17)
+#define PCM_24BIT_SFT                                       16
+#define PCM_24BIT_MASK                                      0x1
+#define PCM_24BIT_MASK_SFT                                  (0x1 << 16)
+#define PCM_WLEN_SFT                                        14
+#define PCM_WLEN_MASK                                       0x3
+#define PCM_WLEN_MASK_SFT                                   (0x3 << 14)
+#define PCM_SYNC_LENGTH_SFT                                 9
+#define PCM_SYNC_LENGTH_MASK                                0x1f
+#define PCM_SYNC_LENGTH_MASK_SFT                            (0x1f << 9)
+#define PCM_SYNC_TYPE_SFT                                   8
+#define PCM_SYNC_TYPE_MASK                                  0x1
+#define PCM_SYNC_TYPE_MASK_SFT                              (0x1 << 8)
+#define PCM_BT_MODE_SFT                                     7
+#define PCM_BT_MODE_MASK                                    0x1
+#define PCM_BT_MODE_MASK_SFT                                (0x1 << 7)
+#define PCM_BYP_ASRC_SFT                                    6
+#define PCM_BYP_ASRC_MASK                                   0x1
+#define PCM_BYP_ASRC_MASK_SFT                               (0x1 << 6)
+#define PCM_SLAVE_SFT                                       5
+#define PCM_SLAVE_MASK                                      0x1
+#define PCM_SLAVE_MASK_SFT                                  (0x1 << 5)
+#define PCM_MODE_SFT                                        3
+#define PCM_MODE_MASK                                       0x3
+#define PCM_MODE_MASK_SFT                                   (0x3 << 3)
+#define PCM_FMT_SFT                                         1
+#define PCM_FMT_MASK                                        0x3
+#define PCM_FMT_MASK_SFT                                    (0x3 << 1)
+#define PCM_EN_SFT                                          0
+#define PCM_EN_MASK                                         0x1
+#define PCM_EN_MASK_SFT                                     (0x1 << 0)
+
+/* PCM_INTF_CON2 */
+#define PCM1_TX_FIFO_OV_SFT                                 31
+#define PCM1_TX_FIFO_OV_MASK                                0x1
+#define PCM1_TX_FIFO_OV_MASK_SFT                            (0x1 << 31)
+#define PCM1_RX_FIFO_OV_SFT                                 30
+#define PCM1_RX_FIFO_OV_MASK                                0x1
+#define PCM1_RX_FIFO_OV_MASK_SFT                            (0x1 << 30)
+#define PCM2_TX_FIFO_OV_SFT                                 29
+#define PCM2_TX_FIFO_OV_MASK                                0x1
+#define PCM2_TX_FIFO_OV_MASK_SFT                            (0x1 << 29)
+#define PCM2_RX_FIFO_OV_SFT                                 28
+#define PCM2_RX_FIFO_OV_MASK                                0x1
+#define PCM2_RX_FIFO_OV_MASK_SFT                            (0x1 << 28)
+#define PCM1_SYNC_GLITCH_SFT                                27
+#define PCM1_SYNC_GLITCH_MASK                               0x1
+#define PCM1_SYNC_GLITCH_MASK_SFT                           (0x1 << 27)
+#define PCM2_SYNC_GLITCH_SFT                                26
+#define PCM2_SYNC_GLITCH_MASK                               0x1
+#define PCM2_SYNC_GLITCH_MASK_SFT                           (0x1 << 26)
+#define PCM1_PCM2_LOOPBACK_SFT                              15
+#define PCM1_PCM2_LOOPBACK_MASK                             0x1
+#define PCM1_PCM2_LOOPBACK_MASK_SFT                         (0x1 << 15)
+#define DAI_PCM_LOOPBACK_CH_SFT                             13
+#define DAI_PCM_LOOPBACK_CH_MASK                            0x1
+#define DAI_PCM_LOOPBACK_CH_MASK_SFT                        (0x1 << 13)
+#define I2S_PCM_LOOPBACK_CH_SFT                             12
+#define I2S_PCM_LOOPBACK_CH_MASK                            0x1
+#define I2S_PCM_LOOPBACK_CH_MASK_SFT                        (0x1 << 12)
+#define PCM_USE_MD3_SFT                                     8
+#define PCM_USE_MD3_MASK                                    0x1
+#define PCM_USE_MD3_MASK_SFT                                (0x1 << 8)
+#define TX_FIX_VALUE_SFT                                    0
+#define TX_FIX_VALUE_MASK                                   0xff
+#define TX_FIX_VALUE_MASK_SFT                               (0xff << 0)
+
+/* PCM2_INTF_CON */
+#define PCM2_TX_FIX_VALUE_SFT                                24
+#define PCM2_TX_FIX_VALUE_MASK                               0xff
+#define PCM2_TX_FIX_VALUE_MASK_SFT                           (0xff << 24)
+#define PCM2_FIX_VALUE_SEL_SFT                               23
+#define PCM2_FIX_VALUE_SEL_MASK                              0x1
+#define PCM2_FIX_VALUE_SEL_MASK_SFT                          (0x1 << 23)
+#define PCM2_BUFFER_LOOPBACK_SFT                             22
+#define PCM2_BUFFER_LOOPBACK_MASK                            0x1
+#define PCM2_BUFFER_LOOPBACK_MASK_SFT                        (0x1 << 22)
+#define PCM2_PARALLEL_LOOPBACK_SFT                           21
+#define PCM2_PARALLEL_LOOPBACK_MASK                          0x1
+#define PCM2_PARALLEL_LOOPBACK_MASK_SFT                      (0x1 << 21)
+#define PCM2_SERIAL_LOOPBACK_SFT                             20
+#define PCM2_SERIAL_LOOPBACK_MASK                            0x1
+#define PCM2_SERIAL_LOOPBACK_MASK_SFT                        (0x1 << 20)
+#define PCM2_DAI_PCM_LOOPBACK_SFT                            19
+#define PCM2_DAI_PCM_LOOPBACK_MASK                           0x1
+#define PCM2_DAI_PCM_LOOPBACK_MASK_SFT                       (0x1 << 19)
+#define PCM2_I2S_PCM_LOOPBACK_SFT                            18
+#define PCM2_I2S_PCM_LOOPBACK_MASK                           0x1
+#define PCM2_I2S_PCM_LOOPBACK_MASK_SFT                       (0x1 << 18)
+#define PCM2_SYNC_DELSEL_SFT                                 17
+#define PCM2_SYNC_DELSEL_MASK                                0x1
+#define PCM2_SYNC_DELSEL_MASK_SFT                            (0x1 << 17)
+#define PCM2_TX_LR_SWAP_SFT                                  16
+#define PCM2_TX_LR_SWAP_MASK                                 0x1
+#define PCM2_TX_LR_SWAP_MASK_SFT                             (0x1 << 16)
+#define PCM2_SYNC_IN_INV_SFT                                 15
+#define PCM2_SYNC_IN_INV_MASK                                0x1
+#define PCM2_SYNC_IN_INV_MASK_SFT                            (0x1 << 15)
+#define PCM2_BCLK_IN_INV_SFT                                 14
+#define PCM2_BCLK_IN_INV_MASK                                0x1
+#define PCM2_BCLK_IN_INV_MASK_SFT                            (0x1 << 14)
+#define PCM2_TX_LCH_RPT_SFT                                  13
+#define PCM2_TX_LCH_RPT_MASK                                 0x1
+#define PCM2_TX_LCH_RPT_MASK_SFT                             (0x1 << 13)
+#define PCM2_VBT_16K_MODE_SFT                                12
+#define PCM2_VBT_16K_MODE_MASK                               0x1
+#define PCM2_VBT_16K_MODE_MASK_SFT                           (0x1 << 12)
+#define PCM2_LOOPBACK_CH_SEL_SFT                             10
+#define PCM2_LOOPBACK_CH_SEL_MASK                            0x3
+#define PCM2_LOOPBACK_CH_SEL_MASK_SFT                        (0x3 << 10)
+#define PCM2_TX2_BT_MODE_SFT                                 8
+#define PCM2_TX2_BT_MODE_MASK                                0x1
+#define PCM2_TX2_BT_MODE_MASK_SFT                            (0x1 << 8)
+#define PCM2_BT_MODE_SFT                                     7
+#define PCM2_BT_MODE_MASK                                    0x1
+#define PCM2_BT_MODE_MASK_SFT                                (0x1 << 7)
+#define PCM2_AFIFO_SFT                                       6
+#define PCM2_AFIFO_MASK                                      0x1
+#define PCM2_AFIFO_MASK_SFT                                  (0x1 << 6)
+#define PCM2_WLEN_SFT                                        5
+#define PCM2_WLEN_MASK                                       0x1
+#define PCM2_WLEN_MASK_SFT                                   (0x1 << 5)
+#define PCM2_MODE_SFT                                        3
+#define PCM2_MODE_MASK                                       0x3
+#define PCM2_MODE_MASK_SFT                                   (0x3 << 3)
+#define PCM2_FMT_SFT                                         1
+#define PCM2_FMT_MASK                                        0x3
+#define PCM2_FMT_MASK_SFT                                    (0x3 << 1)
+#define PCM2_EN_SFT                                          0
+#define PCM2_EN_MASK                                         0x1
+#define PCM2_EN_MASK_SFT                                     (0x1 << 0)
+#endif
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-common.h b/sound/soc/mediatek/mt8173/mt8173-afe-common.h
index 9a4837cc181a..396fe2355eea 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-common.h
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-common.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * mt8173_afe_common.h  --  Mediatek 8173 audio driver common definitions
  *
@@ -6,15 +7,6 @@
  *             Sascha Hauer <s.hauer@pengutronix.de>
  *             Hidalgo Huang <hidalgo.huang@mediatek.com>
  *             Ir Lian <ir.lian@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #ifndef _MT8173_AFE_COMMON_H_
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index 65d1433a0944..c0b6697503fd 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Mediatek 8173 ALSA SoC AFE platform driver
  *
@@ -6,15 +7,6 @@
  *             Sascha Hauer <s.hauer@pengutronix.de>
  *             Hidalgo Huang <hidalgo.huang@mediatek.com>
  *             Ir Lian <ir.lian@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/delay.h>
@@ -303,9 +295,7 @@ static void mt8173_afe_dais_disable_clks(struct mtk_base_afe *afe,
 static int mt8173_afe_i2s_startup(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai)
 {
-	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 
 	if (dai->active)
 		return 0;
@@ -318,9 +308,7 @@ static int mt8173_afe_i2s_startup(struct snd_pcm_substream *substream,
 static void mt8173_afe_i2s_shutdown(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *dai)
 {
-	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 
 	if (dai->active)
 		return;
@@ -334,10 +322,8 @@ static void mt8173_afe_i2s_shutdown(struct snd_pcm_substream *substream,
 static int mt8173_afe_i2s_prepare(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime * const runtime = substream->runtime;
-	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
-	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 	int ret;
 
@@ -358,9 +344,7 @@ static int mt8173_afe_i2s_prepare(struct snd_pcm_substream *substream,
 static int mt8173_afe_hdmi_startup(struct snd_pcm_substream *substream,
 				   struct snd_soc_dai *dai)
 {
-	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 
 	if (dai->active)
@@ -374,9 +358,7 @@ static int mt8173_afe_hdmi_startup(struct snd_pcm_substream *substream,
 static void mt8173_afe_hdmi_shutdown(struct snd_pcm_substream *substream,
 				     struct snd_soc_dai *dai)
 {
-	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 
 	if (dai->active)
@@ -389,10 +371,8 @@ static void mt8173_afe_hdmi_shutdown(struct snd_pcm_substream *substream,
 static int mt8173_afe_hdmi_prepare(struct snd_pcm_substream *substream,
 				   struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime * const runtime = substream->runtime;
-	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
-	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 
 	unsigned int val;
@@ -454,9 +434,7 @@ static int mt8173_afe_hdmi_prepare(struct snd_pcm_substream *substream,
 static int mt8173_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
 				   struct snd_soc_dai *dai)
 {
-	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);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
 
 	dev_info(afe->dev, "%s cmd=%d %s\n", __func__, cmd, dai->name);
 
diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c
index b49b527a7cf9..902d111016d6 100644
--- a/sound/soc/mediatek/mt8173/mt8173-max98090.c
+++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * mt8173-max98090.c  --  MT8173 MAX98090 ALSA SoC machine driver
  *
  * Copyright (c) 2015 MediaTek Inc.
  * Author: Koro Chen <koro.chen@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/module.h>
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
index 904f3ee6b0eb..582174d98c6c 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * mt8173-rt5650-rt5514.c  --  MT8173 machine driver with RT5650/5514 codecs
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Koro Chen <koro.chen@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/module.h>
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
index 9c61b8c099c5..b3670c8a5b8d 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * mt8173-rt5650-rt5676.c  --  MT8173 machine driver with RT5650/5676 codecs
  *
  * Copyright (c) 2015 MediaTek Inc.
  * Author: Koro Chen <koro.chen@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/module.h>
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index 84aa09d3dd98..7a89b4aad182 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * mt8173-rt5650.c  --  MT8173 machine driver with RT5650 codecs
  *
  * Copyright (c) 2016 MediaTek Inc.
  * Author: Koro Chen <koro.chen@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/module.h>
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index f5451c78ede5..6dccea6fdaeb 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -1,7 +1,12 @@
 config SND_OMAP_SOC
-	tristate "SoC Audio for the Texas Instruments OMAP chips"
+	tristate "SoC Audio for Texas Instruments OMAP chips (deprecated)"
 	depends on (ARCH_OMAP && DMA_OMAP) || (ARM && COMPILE_TEST)
-	select SND_DMAENGINE_PCM
+	select SND_SDMA_SOC
+
+config SND_SDMA_SOC
+	tristate "SoC Audio for Texas Instruments chips using sDMA"
+	depends on DMA_OMAP || COMPILE_TEST
+	select SND_SOC_GENERIC_DMAENGINE_PCM
 
 config SND_OMAP_SOC_DMIC
 	tristate
@@ -14,7 +19,7 @@ config SND_OMAP_SOC_MCPDM
 
 config SND_OMAP_SOC_HDMI_AUDIO
 	tristate "HDMI audio support for OMAP4+ based SoCs"
-	depends on SND_OMAP_SOC
+	depends on SND_SDMA_SOC
 	help
 	  For HDMI audio to work OMAPDSS HDMI support should be
 	  enabled.
@@ -29,8 +34,7 @@ config SND_OMAP_SOC_HDMI_AUDIO
 
 config SND_OMAP_SOC_N810
 	tristate "SoC Audio support for Nokia N810"
-	depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C
-	depends on OMAP_MUX
+	depends on SND_SDMA_SOC && MACH_NOKIA_N810 && I2C
 	select SND_OMAP_SOC_MCBSP
 	select SND_SOC_TLV320AIC3X
 	help
@@ -38,7 +42,7 @@ config SND_OMAP_SOC_N810
 
 config SND_OMAP_SOC_RX51
 	tristate "SoC Audio support for Nokia N900 (RX-51)"
-	depends on SND_OMAP_SOC && ARM && I2C
+	depends on SND_SDMA_SOC && ARM && I2C
 	select SND_OMAP_SOC_MCBSP
 	select SND_SOC_TLV320AIC3X
 	select SND_SOC_TPA6130A2
@@ -49,7 +53,7 @@ config SND_OMAP_SOC_RX51
 
 config SND_OMAP_SOC_AMS_DELTA
 	tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
-	depends on SND_OMAP_SOC && MACH_AMS_DELTA && TTY
+	depends on SND_SDMA_SOC && MACH_AMS_DELTA && TTY
 	select SND_OMAP_SOC_MCBSP
 	select SND_SOC_CX20442
 	help
@@ -68,7 +72,7 @@ config SND_OMAP_SOC_AMS_DELTA
 
 config SND_OMAP_SOC_OSK5912
 	tristate "SoC Audio support for omap osk5912"
-	depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C
+	depends on SND_SDMA_SOC && MACH_OMAP_OSK && I2C
 	select SND_OMAP_SOC_MCBSP
 	select SND_SOC_TLV320AIC23_I2C
 	help
@@ -76,7 +80,7 @@ config SND_OMAP_SOC_OSK5912
 
 config SND_OMAP_SOC_AM3517EVM
 	tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
-	depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C
+	depends on SND_SDMA_SOC && MACH_OMAP3517EVM && I2C
 	select SND_OMAP_SOC_MCBSP
 	select SND_SOC_TLV320AIC23_I2C
 	help
@@ -85,7 +89,7 @@ config SND_OMAP_SOC_AM3517EVM
 
 config SND_OMAP_SOC_OMAP_TWL4030
 	tristate "SoC Audio support for TI SoC based boards with twl4030 codec"
-	depends on TWL4030_CORE && SND_OMAP_SOC
+	depends on TWL4030_CORE && SND_SDMA_SOC
 	select SND_OMAP_SOC_MCBSP
 	select SND_SOC_TWL4030
 	help
@@ -100,7 +104,7 @@ config SND_OMAP_SOC_OMAP_TWL4030
 
 config SND_OMAP_SOC_OMAP_ABE_TWL6040
 	tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
-	depends on TWL6040_CORE && SND_OMAP_SOC && COMMON_CLK
+	depends on TWL6040_CORE && SND_SDMA_SOC && COMMON_CLK
 	depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST
 	select SND_OMAP_SOC_DMIC
 	select SND_OMAP_SOC_MCPDM
@@ -118,7 +122,7 @@ config SND_OMAP_SOC_OMAP_ABE_TWL6040
 
 config SND_OMAP_SOC_OMAP3_PANDORA
 	tristate "SoC Audio support for OMAP3 Pandora"
-	depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA
+	depends on TWL4030_CORE && SND_SDMA_SOC && MACH_OMAP3_PANDORA
 	select SND_OMAP_SOC_MCBSP
 	select SND_SOC_TWL4030
 	help
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index a6785dc4fc90..53eba3413485 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -1,12 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0
 # OMAP Platform Support
-snd-soc-omap-objs := omap-pcm.o
+snd-soc-sdma-objs := sdma-pcm.o
 snd-soc-omap-dmic-objs := omap-dmic.o
 snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o
 snd-soc-omap-mcpdm-objs := omap-mcpdm.o
 snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o
 
-obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
+obj-$(CONFIG_SND_SDMA_SOC) += snd-soc-sdma.o
 obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o
 obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
 obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 71e5f31fa306..9cfefe44a75f 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -80,9 +80,9 @@ static void n810_ext_control(struct snd_soc_dapm_context *dapm)
 	else
 		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
 	if (line1l)
-		snd_soc_dapm_enable_pin_unlocked(dapm, "LINE1L");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
 	else
-		snd_soc_dapm_disable_pin_unlocked(dapm, "LINE1L");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
 
 	if (n810_dmic_func)
 		snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
@@ -222,6 +222,7 @@ static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = {
 	SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event),
 	SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event),
 	SND_SOC_DAPM_MIC("DMic", NULL),
+	SND_SOC_DAPM_MIC("HS Mic", NULL),
 };
 
 static const struct snd_soc_dapm_route audio_map[] = {
@@ -231,8 +232,14 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"Ext Spk", NULL, "LLOUT"},
 	{"Ext Spk", NULL, "RLOUT"},
 
-	{"DMic Rate 64", NULL, "Mic Bias"},
-	{"Mic Bias", NULL, "DMic"},
+	{"DMic Rate 64", NULL, "DMic"},
+	{"DMic", NULL, "Mic Bias"},
+
+	/*
+	 * Note that the mic bias is coming from Retu/Vilma and we don't have
+	 * control over it atm. The analog HS mic is not working. <- TODO
+	 */
+	{"LINE1L", NULL, "HS Mic"},
 };
 
 static const char *spk_function[] = {"Off", "On"};
@@ -257,9 +264,9 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = {
 static struct snd_soc_dai_link n810_dai = {
 	.name = "TLV320AIC33",
 	.stream_name = "AIC33",
-	.cpu_dai_name = "omap-mcbsp.2",
-	.platform_name = "omap-mcbsp.2",
-	.codec_name = "tlv320aic3x-codec.2-0018",
+	.cpu_dai_name = "48076000.mcbsp",
+	.platform_name = "48076000.mcbsp",
+	.codec_name = "tlv320aic3x-codec.1-0018",
 	.codec_dai_name = "tlv320aic3x-hifi",
 	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 		   SND_SOC_DAIFMT_CBM_CFM,
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index b2f5d2fa354d..51dd7c65096b 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -40,9 +40,9 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
-#include <sound/omap-pcm.h>
 
 #include "omap-dmic.h"
+#include "sdma-pcm.h"
 
 struct omap_dmic {
 	struct device *dev;
@@ -501,7 +501,7 @@ static int asoc_dmic_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	ret = omap_pcm_platform_register(&pdev->dev);
+	ret = sdma_pcm_platform_register(&pdev->dev, NULL, "up_link");
 	if (ret)
 		return ret;
 
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c
index 8eeac7cab1c1..8a99a8837dc9 100644
--- a/sound/soc/omap/omap-hdmi-audio.c
+++ b/sound/soc/omap/omap-hdmi-audio.c
@@ -26,9 +26,10 @@
 #include <sound/dmaengine_pcm.h>
 #include <uapi/sound/asound.h>
 #include <sound/asoundef.h>
-#include <sound/omap-pcm.h>
 #include <sound/omap-hdmi-audio.h>
 
+#include "sdma-pcm.h"
+
 #define DRV_NAME "omap-hdmi-audio"
 
 struct hdmi_audio_data {
@@ -352,7 +353,7 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	ret = omap_pcm_platform_register(ad->dssdev);
+	ret = sdma_pcm_platform_register(ad->dssdev, "audio_tx", NULL);
 	if (ret)
 		return ret;
 
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 6b40bdbef336..d0ebb6b9bfac 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -34,11 +34,11 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
-#include <sound/omap-pcm.h>
 
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 #include "mcbsp.h"
 #include "omap-mcbsp.h"
+#include "sdma-pcm.h"
 
 #define OMAP_MCBSP_RATES	(SNDRV_PCM_RATE_8000_96000)
 
@@ -868,7 +868,7 @@ static int asoc_mcbsp_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	return omap_pcm_platform_register(&pdev->dev);
+	return sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
 }
 
 static int asoc_mcbsp_remove(struct platform_device *pdev)
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 64609c77a79d..0e97360f9890 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -40,9 +40,9 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
-#include <sound/omap-pcm.h>
 
 #include "omap-mcpdm.h"
+#include "sdma-pcm.h"
 
 struct mcpdm_link_config {
 	u32 link_mask; /* channel mask for the direction */
@@ -548,7 +548,7 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	return omap_pcm_platform_register(&pdev->dev);
+	return sdma_pcm_platform_register(&pdev->dev, "dn_link", "up_link");
 }
 
 static const struct of_device_id omap_mcpdm_of_match[] = {
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
deleted file mode 100644
index 778cc8f75b6a..000000000000
--- a/sound/soc/omap/omap-pcm.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * omap-pcm.c  --  ALSA PCM interface for the OMAP SoC
- *
- * Copyright (C) 2008 Nokia Corporation
- *
- * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
- *          Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/omap-dma.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/dmaengine_pcm.h>
-#include <sound/soc.h>
-#include <sound/omap-pcm.h>
-
-#ifdef CONFIG_ARCH_OMAP1
-#define pcm_omap1510()	cpu_is_omap1510()
-#else
-#define pcm_omap1510()	0
-#endif
-
-static struct snd_pcm_hardware omap_pcm_hardware = {
-	.info			= SNDRV_PCM_INFO_MMAP |
-				  SNDRV_PCM_INFO_MMAP_VALID |
-				  SNDRV_PCM_INFO_INTERLEAVED |
-				  SNDRV_PCM_INFO_PAUSE |
-				  SNDRV_PCM_INFO_RESUME |
-				  SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
-	.period_bytes_min	= 32,
-	.period_bytes_max	= 64 * 1024,
-	.periods_min		= 2,
-	.periods_max		= 255,
-	.buffer_bytes_max	= 128 * 1024,
-};
-
-/* sDMA supports only 1, 2, and 4 byte transfer elements. */
-static void omap_pcm_limit_supported_formats(void)
-{
-	int i;
-
-	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
-		switch (snd_pcm_format_physical_width(i)) {
-		case 8:
-		case 16:
-		case 32:
-			omap_pcm_hardware.formats |= (1LL << i);
-			break;
-		default:
-			break;
-		}
-	}
-}
-
-/* this may get called several times by oss emulation */
-static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
-			      struct snd_pcm_hw_params *params)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct omap_pcm_dma_data *dma_data;
-	struct dma_slave_config config;
-	struct dma_chan *chan;
-	int err = 0;
-
-	memset(&config, 0x00, sizeof(config));
-
-	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	/* return if this is a bufferless transfer e.g.
-	 * codec <--> BT codec or GSM modem -- lg FIXME */
-	if (!dma_data)
-		return 0;
-
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-	runtime->dma_bytes = params_buffer_bytes(params);
-
-	chan = snd_dmaengine_pcm_get_chan(substream);
-	if (!chan)
-		return -EINVAL;
-
-	/* fills in addr_width and direction */
-	err = snd_hwparams_to_dma_slave_config(substream, params, &config);
-	if (err)
-		return err;
-
-	snd_dmaengine_pcm_set_config_from_dai_data(substream,
-			snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
-			&config);
-
-	return dmaengine_slave_config(chan, &config);
-}
-
-static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	snd_pcm_set_runtime_buffer(substream, NULL);
-	return 0;
-}
-
-static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
-{
-	snd_pcm_uframes_t offset;
-
-	if (pcm_omap1510())
-		offset = snd_dmaengine_pcm_pointer_no_residue(substream);
-	else
-		offset = snd_dmaengine_pcm_pointer(substream);
-
-	return offset;
-}
-
-static int omap_pcm_open(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_dmaengine_dai_dma_data *dma_data;
-	int ret;
-
-	snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
-
-	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	/* DT boot: filter_data is the DMA name */
-	if (rtd->cpu_dai->dev->of_node) {
-		struct dma_chan *chan;
-
-		chan = dma_request_slave_channel(rtd->cpu_dai->dev,
-						 dma_data->filter_data);
-		ret = snd_dmaengine_pcm_open(substream, chan);
-	} else {
-		ret = snd_dmaengine_pcm_open_request_chan(substream,
-							  omap_dma_filter_fn,
-							  dma_data->filter_data);
-	}
-	return ret;
-}
-
-static int omap_pcm_mmap(struct snd_pcm_substream *substream,
-	struct vm_area_struct *vma)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	return dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area,
-			   runtime->dma_addr, runtime->dma_bytes);
-}
-
-static const struct snd_pcm_ops omap_pcm_ops = {
-	.open		= omap_pcm_open,
-	.close		= snd_dmaengine_pcm_close_release_chan,
-	.ioctl		= snd_pcm_lib_ioctl,
-	.hw_params	= omap_pcm_hw_params,
-	.hw_free	= omap_pcm_hw_free,
-	.trigger	= snd_dmaengine_pcm_trigger,
-	.pointer	= omap_pcm_pointer,
-	.mmap		= omap_pcm_mmap,
-};
-
-static int omap_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
-	int stream)
-{
-	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	size_t size = omap_pcm_hardware.buffer_bytes_max;
-
-	buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	buf->dev.dev = pcm->card->dev;
-	buf->private_data = NULL;
-	buf->area = dma_alloc_wc(pcm->card->dev, size, &buf->addr, GFP_KERNEL);
-	if (!buf->area)
-		return -ENOMEM;
-
-	buf->bytes = size;
-	return 0;
-}
-
-static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-	struct snd_pcm_substream *substream;
-	struct snd_dma_buffer *buf;
-	int stream;
-
-	for (stream = 0; stream < 2; stream++) {
-		substream = pcm->streams[stream].substream;
-		if (!substream)
-			continue;
-
-		buf = &substream->dma_buffer;
-		if (!buf->area)
-			continue;
-
-		dma_free_wc(pcm->card->dev, buf->bytes, buf->area, buf->addr);
-		buf->area = NULL;
-	}
-}
-
-static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_card *card = rtd->card->snd_card;
-	struct snd_pcm *pcm = rtd->pcm;
-	int ret;
-
-	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
-	if (ret)
-		return ret;
-
-	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-		ret = omap_pcm_preallocate_dma_buffer(pcm,
-			SNDRV_PCM_STREAM_PLAYBACK);
-		if (ret)
-			goto out;
-	}
-
-	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-		ret = omap_pcm_preallocate_dma_buffer(pcm,
-			SNDRV_PCM_STREAM_CAPTURE);
-		if (ret)
-			goto out;
-	}
-
-out:
-	/* free preallocated buffers in case of error */
-	if (ret)
-		omap_pcm_free_dma_buffers(pcm);
-
-	return ret;
-}
-
-static const struct snd_soc_component_driver omap_soc_component = {
-	.ops		= &omap_pcm_ops,
-	.pcm_new	= omap_pcm_new,
-	.pcm_free	= omap_pcm_free_dma_buffers,
-};
-
-int omap_pcm_platform_register(struct device *dev)
-{
-	omap_pcm_limit_supported_formats();
-	return devm_snd_soc_register_component(dev, &omap_soc_component,
-					       NULL, 0);
-}
-EXPORT_SYMBOL_GPL(omap_pcm_platform_register);
-
-MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
-MODULE_DESCRIPTION("OMAP PCM DMA module");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/sdma-pcm.c b/sound/soc/omap/sdma-pcm.c
new file mode 100644
index 000000000000..21a9c2499d48
--- /dev/null
+++ b/sound/soc/omap/sdma-pcm.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+#include <linux/omap-dmaengine.h>
+
+#include "sdma-pcm.h"
+
+static const struct snd_pcm_hardware sdma_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
+				  SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+				  SNDRV_PCM_INFO_INTERLEAVED,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 64 * 1024,
+	.buffer_bytes_max	= 128 * 1024,
+	.periods_min		= 2,
+	.periods_max		= 255,
+};
+
+static const struct snd_dmaengine_pcm_config sdma_dmaengine_pcm_config = {
+	.pcm_hardware = &sdma_pcm_hardware,
+	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+	.compat_filter_fn = omap_dma_filter_fn,
+	.prealloc_buffer_size = 128 * 1024,
+};
+
+int sdma_pcm_platform_register(struct device *dev,
+			       char *txdmachan, char *rxdmachan)
+{
+	struct snd_dmaengine_pcm_config *config;
+	unsigned int flags = SND_DMAENGINE_PCM_FLAG_COMPAT;
+
+	/* Standard names for the directions: 'tx' and 'rx' */
+	if (!txdmachan && !rxdmachan)
+		return devm_snd_dmaengine_pcm_register(dev,
+						&sdma_dmaengine_pcm_config,
+						flags);
+
+	config = devm_kzalloc(dev, sizeof(*config), GFP_KERNEL);
+	if (!config)
+		return -ENOMEM;
+
+	*config = sdma_dmaengine_pcm_config;
+
+	if (!txdmachan || !rxdmachan) {
+		/* One direction only PCM */
+		flags |= SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX;
+		if (!txdmachan) {
+			txdmachan = rxdmachan;
+			rxdmachan = NULL;
+		}
+	}
+
+	config->chan_names[0] = txdmachan;
+	config->chan_names[1] = rxdmachan;
+
+	return devm_snd_dmaengine_pcm_register(dev, config, flags);
+}
+EXPORT_SYMBOL_GPL(sdma_pcm_platform_register);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("sDMA PCM ASoC platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/omap/sdma-pcm.h b/sound/soc/omap/sdma-pcm.h
new file mode 100644
index 000000000000..34a7f90b2587
--- /dev/null
+++ b/sound/soc/omap/sdma-pcm.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ */
+
+#ifndef __SDMA_PCM_H__
+#define __SDMA_PCM_H__
+
+#if IS_ENABLED(CONFIG_SND_SDMA_SOC)
+int sdma_pcm_platform_register(struct device *dev,
+			       char *txdmachan, char *rxdmachan);
+#else
+static inline int sdma_pcm_platform_register(struct device *dev,
+					     char *txdmachan, char *rxdmachan)
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_SND_SDMA_SOC */
+
+#endif /* __SDMA_PCM_H__ */
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 484ab3c2ad67..960744e46edc 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -1,7 +1,6 @@
 config SND_PXA2XX_SOC
 	tristate "SoC Audio for the Intel PXA2xx chip"
 	depends on ARCH_PXA || COMPILE_TEST
-	depends on HAS_DMA
 	select SND_PXA2XX_LIB
 	help
 	  Say Y or M if you want to add support for codecs attached to
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 0291c7cb64eb..6fc986080130 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -43,7 +43,8 @@
 struct ssp_priv {
 	struct ssp_device *ssp;
 	unsigned int sysclk;
-	int dai_fmt;
+	unsigned int dai_fmt;
+	unsigned int configured_dai_fmt;
 #ifdef CONFIG_PM
 	uint32_t	cr0;
 	uint32_t	cr1;
@@ -216,10 +217,9 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 {
 	struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
 	struct ssp_device *ssp = priv->ssp;
-	int val;
 
 	u32 sscr0 = pxa_ssp_read_reg(ssp, SSCR0) &
-		~(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
+		~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
 
 	dev_dbg(&ssp->pdev->dev,
 		"pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %u\n",
@@ -257,8 +257,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 	 * on PXA2xx.  On PXA3xx it must be enabled when doing so. */
 	if (ssp->type != PXA3xx_SSP)
 		clk_disable_unprepare(ssp->clk);
-	val = pxa_ssp_read_reg(ssp, SSCR0) | sscr0;
-	pxa_ssp_write_reg(ssp, SSCR0, val);
+	pxa_ssp_write_reg(ssp, SSCR0, sscr0);
 	if (ssp->type != PXA3xx_SSP)
 		clk_prepare_enable(ssp->clk);
 
@@ -433,36 +432,72 @@ static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
 	return 0;
 }
 
+static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+			       unsigned int fmt)
+{
+	struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+	case SND_SOC_DAIFMT_NB_IF:
+	case SND_SOC_DAIFMT_IB_IF:
+	case SND_SOC_DAIFMT_IB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Settings will be applied in hw_params() */
+	priv->dai_fmt = fmt;
+
+	return 0;
+}
+
 /*
  * Set up the SSP DAI format.
  * The SSP Port must be inactive before calling this function as the
  * physical interface format is changed.
  */
-static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
-		unsigned int fmt)
+static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv)
 {
-	struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
 	struct ssp_device *ssp = priv->ssp;
 	u32 sscr0, sscr1, sspsp, scfr;
 
 	/* check if we need to change anything at all */
-	if (priv->dai_fmt == fmt)
+	if (priv->configured_dai_fmt == priv->dai_fmt)
 		return 0;
 
-	/* we can only change the settings if the port is not in use */
-	if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
-		dev_err(&ssp->pdev->dev,
-			"can't change hardware dai format: stream is in use");
-		return -EINVAL;
-	}
-
 	/* reset port settings */
 	sscr0 = pxa_ssp_read_reg(ssp, SSCR0) &
-		~(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
-	sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
-	sspsp = 0;
+		~(SSCR0_PSP | SSCR0_MOD);
+	sscr1 = pxa_ssp_read_reg(ssp, SSCR1) &
+		~(SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_SCFR |
+		  SSCR1_RWOT | SSCR1_TRAIL | SSCR1_TFT | SSCR1_RFT);
+	sspsp = pxa_ssp_read_reg(ssp, SSPSP) &
+		~(SSPSP_SFRMP | SSPSP_SCMODE(3));
 
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	sscr1 |= SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
+
+	switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
 		sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_SCFR;
 		break;
@@ -475,7 +510,7 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 		return -EINVAL;
 	}
 
-	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	switch (priv->dai_fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF:
 		sspsp |= SSPSP_SFRMP;
 		break;
@@ -491,7 +526,7 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 		return -EINVAL;
 	}
 
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 		sscr0 |= SSCR0_PSP;
 		sscr1 |= SSCR1_RWOT | SSCR1_TRAIL;
@@ -513,7 +548,7 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 	pxa_ssp_write_reg(ssp, SSCR1, sscr1);
 	pxa_ssp_write_reg(ssp, SSPSP, sspsp);
 
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
 	case SND_SOC_DAIFMT_CBM_CFS:
 		scfr = pxa_ssp_read_reg(ssp, SSCR1) | SSCR1_SCFR;
@@ -530,7 +565,7 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 	 * we have to defer some things until hw_params() where we
 	 * know parameters like the sample size.
 	 */
-	priv->dai_fmt = fmt;
+	priv->configured_dai_fmt = priv->dai_fmt;
 
 	return 0;
 }
@@ -551,6 +586,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
 	int width = snd_pcm_format_physical_width(params_format(params));
 	int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf;
 	struct snd_dmaengine_dai_dma_data *dma_data;
+	int ret;
 
 	dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
 
@@ -566,6 +602,10 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
 	if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
 		return 0;
 
+	ret = pxa_ssp_configure_dai_fmt(priv);
+	if (ret < 0)
+		return ret;
+
 	/* clear selected SSP bits */
 	sscr0 = pxa_ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
 
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 8ec9a074b38b..87838fa27997 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -11,24 +11,21 @@ config SND_SOC_LPASS_CPU
 
 config SND_SOC_LPASS_PLATFORM
 	tristate
-	depends on HAS_DMA
 	select REGMAP_MMIO
 
 config SND_SOC_LPASS_IPQ806X
 	tristate
-	depends on HAS_DMA
 	select SND_SOC_LPASS_CPU
 	select SND_SOC_LPASS_PLATFORM
 
 config SND_SOC_LPASS_APQ8016
 	tristate
-	depends on HAS_DMA
 	select SND_SOC_LPASS_CPU
 	select SND_SOC_LPASS_PLATFORM
 
 config SND_SOC_STORM
 	tristate "ASoC I2S support for Storm boards"
-	depends on SND_SOC_QCOM && HAS_DMA
+	depends on SND_SOC_QCOM
 	select SND_SOC_LPASS_IPQ806X
 	select SND_SOC_MAX98357A
 	help
@@ -37,9 +34,59 @@ config SND_SOC_STORM
 
 config SND_SOC_APQ8016_SBC
 	tristate "SoC Audio support for APQ8016 SBC platforms"
-	depends on SND_SOC_QCOM && HAS_DMA
+	depends on SND_SOC_QCOM
 	select SND_SOC_LPASS_APQ8016
 	help
           Support for Qualcomm Technologies LPASS audio block in
           APQ8016 SOC-based systems.
           Say Y if you want to use audio devices on MI2S.
+
+config SND_SOC_QDSP6_COMMON
+	tristate
+
+config SND_SOC_QDSP6_CORE
+	tristate
+
+config SND_SOC_QDSP6_AFE
+	tristate
+
+config SND_SOC_QDSP6_AFE_DAI
+	tristate
+
+config SND_SOC_QDSP6_ADM
+	tristate
+
+config SND_SOC_QDSP6_ROUTING
+	tristate
+
+config SND_SOC_QDSP6_ASM
+	tristate
+
+config SND_SOC_QDSP6_ASM_DAI
+	tristate
+
+config SND_SOC_QDSP6
+	tristate "SoC ALSA audio driver for QDSP6"
+	depends on QCOM_APR && HAS_DMA
+	select SND_SOC_QDSP6_COMMON
+	select SND_SOC_QDSP6_CORE
+	select SND_SOC_QDSP6_AFE
+	select SND_SOC_QDSP6_AFE_DAI
+	select SND_SOC_QDSP6_ADM
+	select SND_SOC_QDSP6_ROUTING
+	select SND_SOC_QDSP6_ASM
+	select SND_SOC_QDSP6_ASM_DAI
+	help
+	 To add support for MSM QDSP6 Soc Audio.
+	 This will enable sound soc platform specific
+	 audio drivers. This includes q6asm, q6adm,
+	 q6afe interfaces to DSP using apr.
+
+config SND_SOC_MSM8996
+	tristate "SoC Machine driver for MSM8996 and APQ8096 boards"
+	depends on QCOM_APR
+	select SND_SOC_QDSP6
+	help
+          Support for Qualcomm Technologies LPASS audio block in
+          APQ8096 SoC-based systems.
+          Say Y if you want to use audio device on this SoCs
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index d5280355c24f..206945bb9ba1 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -13,6 +13,11 @@ obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
 # Machine
 snd-soc-storm-objs := storm.o
 snd-soc-apq8016-sbc-objs := apq8016_sbc.o
+snd-soc-apq8096-objs := apq8096.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
+
+#DSP lib
+obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
index 704428735e3c..1dd23bba1bed 100644
--- a/sound/soc/qcom/apq8016_sbc.c
+++ b/sound/soc/qcom/apq8016_sbc.c
@@ -147,7 +147,8 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
 	num_links = of_get_child_count(node);
 
 	/* Allocate the private data and the DAI link array */
-	data = devm_kzalloc(dev, sizeof(*data) + sizeof(*link) * num_links,
+	data = devm_kzalloc(dev,
+			    struct_size(data, dai_link, num_links),
 			    GFP_KERNEL);
 	if (!data)
 		return ERR_PTR(-ENOMEM);
diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c
new file mode 100644
index 000000000000..561cd429e6f2
--- /dev/null
+++ b/sound/soc/qcom/apq8096.c
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, Linaro Limited
+
+#include <linux/soc/qcom/apr.h>
+#include <linux/module.h>
+#include <linux/component.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+
+static int apq8096_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 apq8096_sbc_parse_of(struct snd_soc_card *card)
+{
+	struct device_node *np;
+	struct device_node *codec = NULL;
+	struct device_node *platform = NULL;
+	struct device_node *cpu = NULL;
+	struct device *dev = card->dev;
+	struct snd_soc_dai_link *link;
+	int ret, num_links;
+
+	ret = snd_soc_of_parse_card_name(card, "qcom,model");
+	if (ret) {
+		dev_err(dev, "Error parsing card name: %d\n", ret);
+		return ret;
+	}
+
+	/* DAPM routes */
+	if (of_property_read_bool(dev->of_node, "qcom,audio-routing")) {
+		ret = snd_soc_of_parse_audio_routing(card,
+					"qcom,audio-routing");
+		if (ret)
+			return ret;
+	}
+
+	/* Populate links */
+	num_links = of_get_child_count(dev->of_node);
+
+	/* Allocate the DAI link array */
+	card->dai_link = kcalloc(num_links, sizeof(*link), GFP_KERNEL);
+	if (!card->dai_link)
+		return -ENOMEM;
+
+	card->num_links	= num_links;
+	link = card->dai_link;
+
+	for_each_child_of_node(dev->of_node, np) {
+		cpu = of_get_child_by_name(np, "cpu");
+		if (!cpu) {
+			dev_err(dev, "Can't find cpu DT node\n");
+			ret = -EINVAL;
+			goto err;
+		}
+
+		link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0);
+		if (!link->cpu_of_node) {
+			dev_err(card->dev, "error getting cpu phandle\n");
+			ret = -EINVAL;
+			goto err;
+		}
+
+		ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name);
+		if (ret) {
+			dev_err(card->dev, "error getting cpu dai name\n");
+			goto err;
+		}
+
+		platform = of_get_child_by_name(np, "platform");
+		codec = of_get_child_by_name(np, "codec");
+		if (codec && platform) {
+			link->platform_of_node = of_parse_phandle(platform,
+								  "sound-dai",
+								   0);
+			if (!link->platform_of_node) {
+				dev_err(card->dev, "platform dai not found\n");
+				ret = -EINVAL;
+				goto err;
+			}
+
+			ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
+			if (ret < 0) {
+				dev_err(card->dev, "codec dai not found\n");
+				goto err;
+			}
+			link->no_pcm = 1;
+			link->ignore_pmdown_time = 1;
+			link->be_hw_params_fixup = apq8096_be_hw_params_fixup;
+		} else {
+			link->platform_of_node = link->cpu_of_node;
+			link->codec_dai_name = "snd-soc-dummy-dai";
+			link->codec_name = "snd-soc-dummy";
+			link->dynamic = 1;
+		}
+
+		link->ignore_suspend = 1;
+		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;
+		}
+
+		link->dpcm_playback = 1;
+		link->dpcm_capture = 1;
+		link->stream_name = link->name;
+		link++;
+	}
+
+	return 0;
+err:
+	of_node_put(cpu);
+	of_node_put(codec);
+	of_node_put(platform);
+	kfree(card->dai_link);
+	return ret;
+}
+
+static int apq8096_bind(struct device *dev)
+{
+	struct snd_soc_card *card;
+	int ret;
+
+	card = kzalloc(sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
+
+	component_bind_all(dev, card);
+	card->dev = dev;
+	ret = apq8096_sbc_parse_of(card);
+	if (ret) {
+		dev_err(dev, "Error parsing OF data\n");
+		goto err;
+	}
+
+	ret = snd_soc_register_card(card);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	component_unbind_all(dev, card);
+	kfree(card);
+	return ret;
+}
+
+static void apq8096_unbind(struct device *dev)
+{
+	struct snd_soc_card *card = dev_get_drvdata(dev);
+
+	snd_soc_unregister_card(card);
+	component_unbind_all(dev, card);
+	kfree(card->dai_link);
+	kfree(card);
+}
+
+static const struct component_master_ops apq8096_ops = {
+	.bind = apq8096_bind,
+	.unbind = apq8096_unbind,
+};
+
+static int apq8016_compare_of(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+static void apq8016_release_of(struct device *dev, void *data)
+{
+	of_node_put(data);
+}
+
+static int add_audio_components(struct device *dev,
+				struct component_match **matchptr)
+{
+	struct device_node *np, *platform, *cpu, *node, *dai_node;
+
+	node = dev->of_node;
+
+	for_each_child_of_node(node, np) {
+		cpu = of_get_child_by_name(np, "cpu");
+		if (cpu) {
+			dai_node = of_parse_phandle(cpu, "sound-dai", 0);
+			of_node_get(dai_node);
+			component_match_add_release(dev, matchptr,
+						    apq8016_release_of,
+						    apq8016_compare_of,
+						    dai_node);
+		}
+
+		platform = of_get_child_by_name(np, "platform");
+		if (platform) {
+			dai_node = of_parse_phandle(platform, "sound-dai", 0);
+			component_match_add_release(dev, matchptr,
+						    apq8016_release_of,
+						    apq8016_compare_of,
+						    dai_node);
+		}
+	}
+
+	return 0;
+}
+
+static int apq8096_platform_probe(struct platform_device *pdev)
+{
+	struct component_match *match = NULL;
+	int ret;
+
+	ret = add_audio_components(&pdev->dev, &match);
+	if (ret)
+		return ret;
+
+	return component_master_add_with_match(&pdev->dev, &apq8096_ops, match);
+}
+
+static int apq8096_platform_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &apq8096_ops);
+
+	return 0;
+}
+
+static const struct of_device_id msm_snd_apq8096_dt_match[] = {
+	{.compatible = "qcom,apq8096-sndcard"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_snd_apq8096_dt_match);
+
+static struct platform_driver msm_snd_apq8096_driver = {
+	.probe  = apq8096_platform_probe,
+	.remove = apq8096_platform_remove,
+	.driver = {
+		.name = "msm-snd-apq8096",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_snd_apq8096_dt_match,
+	},
+};
+module_platform_driver(msm_snd_apq8096_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_DESCRIPTION("APQ8096 ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile
new file mode 100644
index 000000000000..c33b3cacbea1
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o
+obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o
+obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o
+obj-$(CONFIG_SND_SOC_QDSP6_AFE_DAI) += q6afe-dai.o
+obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o
+obj-$(CONFIG_SND_SOC_QDSP6_ROUTING) += q6routing.o
+obj-$(CONFIG_SND_SOC_QDSP6_ASM) += q6asm.o
+obj-$(CONFIG_SND_SOC_QDSP6_ASM_DAI) += q6asm-dai.o
diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c
new file mode 100644
index 000000000000..9983c665a941
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6adm.c
@@ -0,0 +1,646 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+// Copyright (c) 2018, Linaro Limited
+
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/kref.h>
+#include <linux/wait.h>
+#include <linux/soc/qcom/apr.h>
+#include <linux/platform_device.h>
+#include <sound/asound.h>
+#include "q6adm.h"
+#include "q6afe.h"
+#include "q6core.h"
+#include "q6dsp-errno.h"
+#include "q6dsp-common.h"
+
+#define ADM_CMD_DEVICE_OPEN_V5		0x00010326
+#define ADM_CMDRSP_DEVICE_OPEN_V5	0x00010329
+#define ADM_CMD_DEVICE_CLOSE_V5		0x00010327
+#define ADM_CMD_MATRIX_MAP_ROUTINGS_V5	0x00010325
+
+#define TIMEOUT_MS 1000
+#define RESET_COPP_ID 99
+#define INVALID_COPP_ID 0xFF
+/* Definition for a legacy device session. */
+#define ADM_LEGACY_DEVICE_SESSION	0
+#define ADM_MATRIX_ID_AUDIO_RX		0
+#define ADM_MATRIX_ID_AUDIO_TX		1
+
+struct q6copp {
+	int afe_port;
+	int copp_idx;
+	int id;
+	int topology;
+	int mode;
+	int rate;
+	int bit_width;
+	int channels;
+	int app_type;
+	int acdb_id;
+
+	struct aprv2_ibasic_rsp_result_t result;
+	struct kref refcount;
+	wait_queue_head_t wait;
+	struct list_head node;
+	struct q6adm *adm;
+};
+
+struct q6adm {
+	struct apr_device *apr;
+	struct device *dev;
+	struct q6core_svc_api_info ainfo;
+	unsigned long copp_bitmap[AFE_MAX_PORTS];
+	struct list_head copps_list;
+	spinlock_t copps_list_lock;
+	struct aprv2_ibasic_rsp_result_t result;
+	struct mutex lock;
+	wait_queue_head_t matrix_map_wait;
+	struct platform_device *pdev_routing;
+};
+
+struct q6adm_cmd_device_open_v5 {
+	u16 flags;
+	u16 mode_of_operation;
+	u16 endpoint_id_1;
+	u16 endpoint_id_2;
+	u32 topology_id;
+	u16 dev_num_channel;
+	u16 bit_width;
+	u32 sample_rate;
+	u8 dev_channel_mapping[8];
+} __packed;
+
+struct q6adm_cmd_matrix_map_routings_v5 {
+	u32 matrix_id;
+	u32 num_sessions;
+} __packed;
+
+struct q6adm_session_map_node_v5 {
+	u16 session_id;
+	u16 num_copps;
+} __packed;
+
+static struct q6copp *q6adm_find_copp(struct q6adm *adm, int port_idx,
+				  int copp_idx)
+{
+	struct q6copp *c = NULL;
+	struct q6copp *ret = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adm->copps_list_lock, flags);
+	list_for_each_entry(c, &adm->copps_list, node) {
+		if ((port_idx == c->afe_port) && (copp_idx == c->copp_idx)) {
+			ret = c;
+			kref_get(&c->refcount);
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&adm->copps_list_lock, flags);
+
+	return ret;
+
+}
+
+static void q6adm_free_copp(struct kref *ref)
+{
+	struct q6copp *c = container_of(ref, struct q6copp, refcount);
+	struct q6adm *adm = c->adm;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adm->copps_list_lock, flags);
+	clear_bit(c->copp_idx, &adm->copp_bitmap[c->afe_port]);
+	list_del(&c->node);
+	spin_unlock_irqrestore(&adm->copps_list_lock, flags);
+	kfree(c);
+}
+
+static int q6adm_callback(struct apr_device *adev, struct apr_resp_pkt *data)
+{
+	struct aprv2_ibasic_rsp_result_t *result = data->payload;
+	int port_idx, copp_idx;
+	struct apr_hdr *hdr = &data->hdr;
+	struct q6copp *copp;
+	struct q6adm *adm = dev_get_drvdata(&adev->dev);
+
+	if (!data->payload_size)
+		return 0;
+
+	copp_idx = (hdr->token) & 0XFF;
+	port_idx = ((hdr->token) >> 16) & 0xFF;
+	if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
+		dev_err(&adev->dev, "Invalid port idx %d token %d\n",
+		       port_idx, hdr->token);
+		return 0;
+	}
+	if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+		dev_err(&adev->dev, "Invalid copp idx %d token %d\n",
+			copp_idx, hdr->token);
+		return 0;
+	}
+
+	switch (hdr->opcode) {
+	case APR_BASIC_RSP_RESULT: {
+		if (result->status != 0) {
+			dev_err(&adev->dev, "cmd = 0x%x return error = 0x%x\n",
+				result->opcode, result->status);
+		}
+		switch (result->opcode) {
+		case ADM_CMD_DEVICE_OPEN_V5:
+		case ADM_CMD_DEVICE_CLOSE_V5:
+			copp = q6adm_find_copp(adm, port_idx, copp_idx);
+			if (!copp)
+				return 0;
+
+			copp->result = *result;
+			wake_up(&copp->wait);
+			kref_put(&copp->refcount, q6adm_free_copp);
+			break;
+		case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
+			adm->result = *result;
+			wake_up(&adm->matrix_map_wait);
+			break;
+
+		default:
+			dev_err(&adev->dev, "Unknown Cmd: 0x%x\n",
+				result->opcode);
+			break;
+		}
+		return 0;
+	}
+	case ADM_CMDRSP_DEVICE_OPEN_V5: {
+		struct adm_cmd_rsp_device_open_v5 {
+			u32 status;
+			u16 copp_id;
+			u16 reserved;
+		} __packed * open = data->payload;
+
+		copp = q6adm_find_copp(adm, port_idx, copp_idx);
+		if (!copp)
+			return 0;
+
+		if (open->copp_id == INVALID_COPP_ID) {
+			dev_err(&adev->dev, "Invalid coppid rxed %d\n",
+				open->copp_id);
+			copp->result.status = ADSP_EBADPARAM;
+			wake_up(&copp->wait);
+			kref_put(&copp->refcount, q6adm_free_copp);
+			break;
+		}
+		copp->result.opcode = hdr->opcode;
+		copp->id = open->copp_id;
+		wake_up(&copp->wait);
+		kref_put(&copp->refcount, q6adm_free_copp);
+	}
+	break;
+	default:
+		dev_err(&adev->dev, "Unknown cmd:0x%x\n",
+		       hdr->opcode);
+		break;
+	}
+
+	return 0;
+}
+
+static struct q6copp *q6adm_alloc_copp(struct q6adm *adm, int port_idx)
+{
+	struct q6copp *c;
+	int idx;
+
+	idx = find_first_zero_bit(&adm->copp_bitmap[port_idx],
+				  MAX_COPPS_PER_PORT);
+
+	if (idx > MAX_COPPS_PER_PORT)
+		return ERR_PTR(-EBUSY);
+
+	c = kzalloc(sizeof(*c), GFP_ATOMIC);
+	if (!c)
+		return ERR_PTR(-ENOMEM);
+
+	set_bit(idx, &adm->copp_bitmap[port_idx]);
+	c->copp_idx = idx;
+	c->afe_port = port_idx;
+	c->adm = adm;
+
+	init_waitqueue_head(&c->wait);
+
+	return c;
+}
+
+static int q6adm_apr_send_copp_pkt(struct q6adm *adm, struct q6copp *copp,
+				   struct apr_pkt *pkt, uint32_t rsp_opcode)
+{
+	struct device *dev = adm->dev;
+	uint32_t opcode = pkt->hdr.opcode;
+	int ret;
+
+	mutex_lock(&adm->lock);
+	copp->result.opcode = 0;
+	copp->result.status = 0;
+	ret = apr_send_pkt(adm->apr, pkt);
+	if (ret < 0) {
+		dev_err(dev, "Failed to send APR packet\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* Wait for the callback with copp id */
+	if (rsp_opcode)
+		ret = wait_event_timeout(copp->wait,
+					 (copp->result.opcode == opcode) ||
+					 (copp->result.opcode == rsp_opcode),
+					 msecs_to_jiffies(TIMEOUT_MS));
+	else
+		ret = wait_event_timeout(copp->wait,
+					 (copp->result.opcode == opcode),
+					 msecs_to_jiffies(TIMEOUT_MS));
+
+	if (!ret) {
+		dev_err(dev, "ADM copp cmd timedout\n");
+		ret = -ETIMEDOUT;
+	} else if (copp->result.status > 0) {
+		dev_err(dev, "DSP returned error[%d]\n",
+			copp->result.status);
+		ret = -EINVAL;
+	}
+
+err:
+	mutex_unlock(&adm->lock);
+	return ret;
+}
+
+static int q6adm_device_close(struct q6adm *adm, struct q6copp *copp,
+			      int port_id, int copp_idx)
+{
+	struct apr_pkt close;
+
+	close.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE),
+					APR_PKT_VER);
+	close.hdr.pkt_size = sizeof(close);
+	close.hdr.src_port = port_id;
+	close.hdr.dest_port = copp->id;
+	close.hdr.token = port_id << 16 | copp_idx;
+	close.hdr.opcode = ADM_CMD_DEVICE_CLOSE_V5;
+
+	return q6adm_apr_send_copp_pkt(adm, copp, &close, 0);
+}
+
+static struct q6copp *q6adm_find_matching_copp(struct q6adm *adm,
+					       int port_id, int topology,
+					       int mode, int rate,
+					       int channel_mode, int bit_width,
+					       int app_type)
+{
+	struct q6copp *c = NULL;
+	struct q6copp *ret = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adm->copps_list_lock, flags);
+
+	list_for_each_entry(c, &adm->copps_list, node) {
+		if ((port_id == c->afe_port) && (topology == c->topology) &&
+		    (mode == c->mode) && (rate == c->rate) &&
+		    (bit_width == c->bit_width) && (app_type == c->app_type)) {
+			ret = c;
+			kref_get(&c->refcount);
+		}
+	}
+	spin_unlock_irqrestore(&adm->copps_list_lock, flags);
+
+	return ret;
+}
+
+static int q6adm_device_open(struct q6adm *adm, struct q6copp *copp,
+			     int port_id, int path, int topology,
+			     int channel_mode, int bit_width, int rate)
+{
+	struct q6adm_cmd_device_open_v5 *open;
+	int afe_port = q6afe_get_port_id(port_id);
+	struct apr_pkt *pkt;
+	void *p;
+	int ret, pkt_size;
+
+	pkt_size = APR_HDR_SIZE + sizeof(*open);
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	open = p + APR_HDR_SIZE;
+	pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					   APR_HDR_LEN(APR_HDR_SIZE),
+					   APR_PKT_VER);
+	pkt->hdr.pkt_size = pkt_size;
+	pkt->hdr.src_port = afe_port;
+	pkt->hdr.dest_port = afe_port;
+	pkt->hdr.token = port_id << 16 | copp->copp_idx;
+	pkt->hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
+	open->flags = ADM_LEGACY_DEVICE_SESSION;
+	open->mode_of_operation = path;
+	open->endpoint_id_1 = afe_port;
+	open->topology_id = topology;
+	open->dev_num_channel = channel_mode & 0x00FF;
+	open->bit_width = bit_width;
+	open->sample_rate = rate;
+
+	ret = q6dsp_map_channels(&open->dev_channel_mapping[0],
+				 channel_mode);
+	if (ret)
+		goto err;
+
+	ret = q6adm_apr_send_copp_pkt(adm, copp, pkt,
+				      ADM_CMDRSP_DEVICE_OPEN_V5);
+
+err:
+	kfree(pkt);
+	return ret;
+}
+
+/**
+ * q6adm_open() - open adm and grab a free copp
+ *
+ * @dev: Pointer to adm child device.
+ * @port_id: port id
+ * @path: playback or capture path.
+ * @rate: rate at which copp is required.
+ * @channel_mode: channel mode
+ * @topology: adm topology id
+ * @perf_mode: performace mode.
+ * @bit_width: audio sample bit width
+ * @app_type: Application type.
+ * @acdb_id: ACDB id
+ *
+ * Return: Will be an negative on error or a valid copp pointer on success.
+ */
+struct q6copp *q6adm_open(struct device *dev, int port_id, int path, int rate,
+	       int channel_mode, int topology, int perf_mode,
+	       uint16_t bit_width, int app_type, int acdb_id)
+{
+	struct q6adm *adm = dev_get_drvdata(dev->parent);
+	struct q6copp *copp;
+	unsigned long flags;
+	int ret = 0;
+
+	if (port_id < 0) {
+		dev_err(dev, "Invalid port_id 0x%x\n", port_id);
+		return ERR_PTR(-EINVAL);
+	}
+
+	copp = q6adm_find_matching_copp(adm, port_id, topology, perf_mode,
+				      rate, channel_mode, bit_width, app_type);
+	if (copp) {
+		dev_err(dev, "Found Matching Copp 0x%x\n", copp->copp_idx);
+		return copp;
+	}
+
+	spin_lock_irqsave(&adm->copps_list_lock, flags);
+	copp = q6adm_alloc_copp(adm, port_id);
+	if (IS_ERR_OR_NULL(copp)) {
+		spin_unlock_irqrestore(&adm->copps_list_lock, flags);
+		return ERR_CAST(copp);
+	}
+
+	list_add_tail(&copp->node, &adm->copps_list);
+	spin_unlock_irqrestore(&adm->copps_list_lock, flags);
+
+	kref_init(&copp->refcount);
+	copp->topology = topology;
+	copp->mode = perf_mode;
+	copp->rate = rate;
+	copp->channels = channel_mode;
+	copp->bit_width = bit_width;
+	copp->app_type = app_type;
+
+
+	ret = q6adm_device_open(adm, copp, port_id, path, topology,
+				channel_mode, bit_width, rate);
+	if (ret < 0) {
+		kref_put(&copp->refcount, q6adm_free_copp);
+		return ERR_PTR(ret);
+	}
+
+	return copp;
+}
+EXPORT_SYMBOL_GPL(q6adm_open);
+
+/**
+ * q6adm_get_copp_id() - get copp index
+ *
+ * @copp: Pointer to valid copp
+ *
+ * Return: Will be an negative on error or a valid copp index on success.
+ **/
+int q6adm_get_copp_id(struct q6copp *copp)
+{
+	if (!copp)
+		return -EINVAL;
+
+	return copp->copp_idx;
+}
+EXPORT_SYMBOL_GPL(q6adm_get_copp_id);
+
+/**
+ * q6adm_matrix_map() - Map asm streams and afe ports using payload
+ *
+ * @dev: Pointer to adm child device.
+ * @path: playback or capture path.
+ * @payload_map: map between session id and afe ports.
+ * @perf_mode: Performace mode.
+ *
+ * Return: Will be an negative on error or a zero on success.
+ */
+int q6adm_matrix_map(struct device *dev, int path,
+		     struct route_payload payload_map, int perf_mode)
+{
+	struct q6adm *adm = dev_get_drvdata(dev->parent);
+	struct q6adm_cmd_matrix_map_routings_v5 *route;
+	struct q6adm_session_map_node_v5 *node;
+	struct apr_pkt *pkt;
+	uint16_t *copps_list;
+	int pkt_size, ret, i, copp_idx;
+	void *matrix_map = NULL;
+	struct q6copp *copp;
+
+	/* Assumes port_ids have already been validated during adm_open */
+	pkt_size = (APR_HDR_SIZE + sizeof(*route) +  sizeof(*node) +
+		    (sizeof(uint32_t) * payload_map.num_copps));
+
+	matrix_map = kzalloc(pkt_size, GFP_KERNEL);
+	if (!matrix_map)
+		return -ENOMEM;
+
+	pkt = matrix_map;
+	route = matrix_map + APR_HDR_SIZE;
+	node = matrix_map + APR_HDR_SIZE + sizeof(*route);
+	copps_list = matrix_map + APR_HDR_SIZE + sizeof(*route) + sizeof(*node);
+
+	pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					   APR_HDR_LEN(APR_HDR_SIZE),
+					   APR_PKT_VER);
+	pkt->hdr.pkt_size = pkt_size;
+	pkt->hdr.token = 0;
+	pkt->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
+	route->num_sessions = 1;
+
+	switch (path) {
+	case ADM_PATH_PLAYBACK:
+		route->matrix_id = ADM_MATRIX_ID_AUDIO_RX;
+		break;
+	case ADM_PATH_LIVE_REC:
+		route->matrix_id = ADM_MATRIX_ID_AUDIO_TX;
+		break;
+	default:
+		dev_err(dev, "Wrong path set[%d]\n", path);
+		break;
+	}
+
+	node->session_id = payload_map.session_id;
+	node->num_copps = payload_map.num_copps;
+
+	for (i = 0; i < payload_map.num_copps; i++) {
+		int port_idx = payload_map.port_id[i];
+
+		if (port_idx < 0) {
+			dev_err(dev, "Invalid port_id 0x%x\n",
+				payload_map.port_id[i]);
+			kfree(pkt);
+			return -EINVAL;
+		}
+		copp_idx = payload_map.copp_idx[i];
+
+		copp = q6adm_find_copp(adm, port_idx, copp_idx);
+		if (!copp) {
+			kfree(pkt);
+			return -EINVAL;
+		}
+
+		copps_list[i] = copp->id;
+		kref_put(&copp->refcount, q6adm_free_copp);
+	}
+
+	mutex_lock(&adm->lock);
+	adm->result.status = 0;
+	adm->result.opcode = 0;
+
+	ret = apr_send_pkt(adm->apr, pkt);
+	if (ret < 0) {
+		dev_err(dev, "routing for stream %d failed ret %d\n",
+		       payload_map.session_id, ret);
+		goto fail_cmd;
+	}
+	ret = wait_event_timeout(adm->matrix_map_wait,
+				 adm->result.opcode == pkt->hdr.opcode,
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		dev_err(dev, "routing for stream %d failed\n",
+		       payload_map.session_id);
+		ret = -ETIMEDOUT;
+		goto fail_cmd;
+	} else if (adm->result.status > 0) {
+		dev_err(dev, "DSP returned error[%d]\n",
+			adm->result.status);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+fail_cmd:
+	mutex_unlock(&adm->lock);
+	kfree(pkt);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(q6adm_matrix_map);
+
+/**
+ * q6adm_close() - Close adm copp
+ *
+ * @dev: Pointer to adm child device.
+ * @copp: pointer to previously opened copp
+ *
+ * Return: Will be an negative on error or a zero on success.
+ */
+int q6adm_close(struct device *dev, struct q6copp *copp)
+{
+	struct q6adm *adm = dev_get_drvdata(dev->parent);
+	int ret = 0;
+
+	ret = q6adm_device_close(adm, copp, copp->afe_port, copp->copp_idx);
+	if (ret < 0) {
+		dev_err(adm->dev, "Failed to close copp %d\n", ret);
+		return ret;
+	}
+
+	kref_put(&copp->refcount, q6adm_free_copp);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(q6adm_close);
+
+static int q6adm_probe(struct apr_device *adev)
+{
+	struct device *dev = &adev->dev;
+	struct device_node *dais_np;
+	struct q6adm *adm;
+
+	adm = devm_kzalloc(&adev->dev, sizeof(*adm), GFP_KERNEL);
+	if (!adm)
+		return -ENOMEM;
+
+	adm->apr = adev;
+	dev_set_drvdata(&adev->dev, adm);
+	adm->dev = dev;
+	q6core_get_svc_api_info(adev->svc_id, &adm->ainfo);
+	mutex_init(&adm->lock);
+	init_waitqueue_head(&adm->matrix_map_wait);
+
+	INIT_LIST_HEAD(&adm->copps_list);
+	spin_lock_init(&adm->copps_list_lock);
+
+	dais_np = of_get_child_by_name(dev->of_node, "routing");
+	if (dais_np) {
+		adm->pdev_routing = of_platform_device_create(dais_np,
+							   "q6routing", dev);
+		of_node_put(dais_np);
+	}
+
+	return 0;
+}
+
+static int q6adm_remove(struct apr_device *adev)
+{
+	struct q6adm *adm = dev_get_drvdata(&adev->dev);
+
+	if (adm->pdev_routing)
+		of_platform_device_destroy(&adm->pdev_routing->dev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id q6adm_device_id[]  = {
+	{ .compatible = "qcom,q6adm" },
+	{},
+};
+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",
+		.of_match_table = of_match_ptr(q6adm_device_id),
+	},
+};
+
+module_apr_driver(qcom_q6adm_driver);
+MODULE_DESCRIPTION("Q6 Audio Device Manager");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/q6adm.h b/sound/soc/qcom/qdsp6/q6adm.h
new file mode 100644
index 000000000000..4f56999b7fab
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6adm.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __Q6_ADM_V2_H__
+#define __Q6_ADM_V2_H__
+
+#define ADM_PATH_PLAYBACK	0x1
+#define ADM_PATH_LIVE_REC	0x2
+#define MAX_COPPS_PER_PORT	8
+#define NULL_COPP_TOPOLOGY	0x00010312
+
+/* multiple copp per stream. */
+struct route_payload {
+	int num_copps;
+	int session_id;
+	int copp_idx[MAX_COPPS_PER_PORT];
+	int port_id[MAX_COPPS_PER_PORT];
+};
+
+struct q6copp;
+struct q6copp *q6adm_open(struct device *dev, int port_id, int path, int rate,
+			   int channel_mode, int topology, int perf_mode,
+			   uint16_t bit_width, int app_type, int acdb_id);
+int q6adm_close(struct device *dev, struct q6copp *copp);
+int q6adm_get_copp_id(struct q6copp *copp);
+int q6adm_matrix_map(struct device *dev, int path,
+		     struct route_payload payload_map, int perf_mode);
+
+#endif /* __Q6_ADM_V2_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
new file mode 100644
index 000000000000..5002dd05bf27
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -0,0 +1,1303 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+// Copyright (c) 2018, Linaro Limited
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include "q6afe.h"
+
+#define Q6AFE_TDM_PB_DAI(pre, num, did) {				\
+		.playback = {						\
+			.stream_name = pre" TDM"#num" Playback",	\
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+				SNDRV_PCM_RATE_176400,			\
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |		\
+				   SNDRV_PCM_FMTBIT_S24_LE |		\
+				   SNDRV_PCM_FMTBIT_S32_LE,		\
+			.channels_min = 1,				\
+			.channels_max = 8,				\
+			.rate_min = 8000,				\
+			.rate_max = 176400,				\
+		},							\
+		.name = #did,						\
+		.ops = &q6tdm_ops,					\
+		.id = did,						\
+		.probe = msm_dai_q6_dai_probe,				\
+		.remove = msm_dai_q6_dai_remove,			\
+	}
+
+#define Q6AFE_TDM_CAP_DAI(pre, num, did) {				\
+		.capture = {						\
+			.stream_name = pre" TDM"#num" Capture",		\
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+				SNDRV_PCM_RATE_176400,			\
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |		\
+				   SNDRV_PCM_FMTBIT_S24_LE |		\
+				   SNDRV_PCM_FMTBIT_S32_LE,		\
+			.channels_min = 1,				\
+			.channels_max = 8,				\
+			.rate_min = 8000,				\
+			.rate_max = 176400,				\
+		},							\
+		.name = #did,						\
+		.ops = &q6tdm_ops,					\
+		.id = did,						\
+		.probe = msm_dai_q6_dai_probe,				\
+		.remove = msm_dai_q6_dai_remove,			\
+	}
+
+struct q6afe_dai_priv_data {
+	uint32_t sd_line_mask;
+	uint32_t sync_mode;
+	uint32_t sync_src;
+	uint32_t data_out_enable;
+	uint32_t invert_sync;
+	uint32_t data_delay;
+	uint32_t data_align;
+};
+
+struct q6afe_dai_data {
+	struct q6afe_port *port[AFE_PORT_MAX];
+	struct q6afe_port_config port_config[AFE_PORT_MAX];
+	bool is_port_started[AFE_PORT_MAX];
+	struct q6afe_dai_priv_data priv[AFE_PORT_MAX];
+};
+
+static int q6slim_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct q6afe_slim_cfg *slim = &dai_data->port_config[dai->id].slim;
+
+	slim->num_channels = params_channels(params);
+	slim->sample_rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FORMAT_SPECIAL:
+		slim->bit_width = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		slim->bit_width = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		slim->bit_width = 32;
+		break;
+	default:
+		pr_err("%s: format %d\n",
+			__func__, params_format(params));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int q6hdmi_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	int channels = params_channels(params);
+	struct q6afe_hdmi_cfg *hdmi = &dai_data->port_config[dai->id].hdmi;
+
+	hdmi->sample_rate = params_rate(params);
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		hdmi->bit_width = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		hdmi->bit_width = 24;
+		break;
+	}
+
+	/* HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4 */
+	switch (channels) {
+	case 2:
+		hdmi->channel_allocation = 0;
+		break;
+	case 3:
+		hdmi->channel_allocation = 0x02;
+		break;
+	case 4:
+		hdmi->channel_allocation = 0x06;
+		break;
+	case 5:
+		hdmi->channel_allocation = 0x0A;
+		break;
+	case 6:
+		hdmi->channel_allocation = 0x0B;
+		break;
+	case 7:
+		hdmi->channel_allocation = 0x12;
+		break;
+	case 8:
+		hdmi->channel_allocation = 0x13;
+		break;
+	default:
+		dev_err(dai->dev, "invalid Channels = %u\n", channels);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int q6i2s_hw_params(struct snd_pcm_substream *substream,
+			   struct snd_pcm_hw_params *params,
+			   struct snd_soc_dai *dai)
+{
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct q6afe_i2s_cfg *i2s = &dai_data->port_config[dai->id].i2s_cfg;
+
+	i2s->sample_rate = params_rate(params);
+	i2s->bit_width = params_width(params);
+	i2s->num_channels = params_channels(params);
+	i2s->sd_line_mask = dai_data->priv[dai->id].sd_line_mask;
+
+	return 0;
+}
+
+static int q6i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct q6afe_i2s_cfg *i2s = &dai_data->port_config[dai->id].i2s_cfg;
+
+	i2s->fmt = fmt;
+
+	return 0;
+}
+
+static int q6tdm_set_tdm_slot(struct snd_soc_dai *dai,
+				unsigned int tx_mask,
+				unsigned int rx_mask,
+				int slots, int slot_width)
+{
+
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct q6afe_tdm_cfg *tdm = &dai_data->port_config[dai->id].tdm;
+	unsigned int cap_mask;
+	int rc = 0;
+
+	/* HW only supports 16 and 32 bit slot width configuration */
+	if ((slot_width != 16) && (slot_width != 32)) {
+		dev_err(dai->dev, "%s: invalid slot_width %d\n",
+			__func__, slot_width);
+		return -EINVAL;
+	}
+
+	/* HW supports 1-32 slots configuration. Typical: 1, 2, 4, 8, 16, 32 */
+	switch (slots) {
+	case 2:
+		cap_mask = 0x03;
+		break;
+	case 4:
+		cap_mask = 0x0F;
+		break;
+	case 8:
+		cap_mask = 0xFF;
+		break;
+	case 16:
+		cap_mask = 0xFFFF;
+		break;
+	default:
+		dev_err(dai->dev, "%s: invalid slots %d\n",
+			__func__, slots);
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
+		tdm->nslots_per_frame = slots;
+		tdm->slot_width = slot_width;
+		/* TDM RX dais ids are even and tx are odd */
+		tdm->slot_mask = (dai->id & 0x1 ? tx_mask : rx_mask) & cap_mask;
+		break;
+	default:
+		dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
+			__func__, dai->id);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int q6tdm_set_channel_map(struct snd_soc_dai *dai,
+				unsigned int tx_num, unsigned int *tx_slot,
+				unsigned int rx_num, unsigned int *rx_slot)
+{
+
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct q6afe_tdm_cfg *tdm = &dai_data->port_config[dai->id].tdm;
+	int rc = 0;
+	int i = 0;
+
+	switch (dai->id) {
+	case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
+		if (dai->id & 0x1) {
+			if (!tx_slot) {
+				dev_err(dai->dev, "tx slot not found\n");
+				return -EINVAL;
+			}
+			if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+				dev_err(dai->dev, "invalid tx num %d\n",
+					tx_num);
+				return -EINVAL;
+			}
+
+			for (i = 0; i < tx_num; i++)
+				tdm->ch_mapping[i] = tx_slot[i];
+
+			for (i = tx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
+				tdm->ch_mapping[i] = Q6AFE_CMAP_INVALID;
+
+			tdm->num_channels = tx_num;
+		} else {
+			/* rx */
+			if (!rx_slot) {
+				dev_err(dai->dev, "rx slot not found\n");
+				return -EINVAL;
+			}
+			if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+				dev_err(dai->dev, "invalid rx num %d\n",
+					rx_num);
+				return -EINVAL;
+			}
+
+			for (i = 0; i < rx_num; i++)
+				tdm->ch_mapping[i] = rx_slot[i];
+
+			for (i = rx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
+				tdm->ch_mapping[i] = Q6AFE_CMAP_INVALID;
+
+			tdm->num_channels = rx_num;
+		}
+
+		break;
+	default:
+		dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
+			__func__, dai->id);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int q6tdm_hw_params(struct snd_pcm_substream *substream,
+			   struct snd_pcm_hw_params *params,
+			   struct snd_soc_dai *dai)
+{
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct q6afe_tdm_cfg *tdm = &dai_data->port_config[dai->id].tdm;
+
+	tdm->bit_width = params_width(params);
+	tdm->sample_rate = params_rate(params);
+	tdm->num_channels = params_channels(params);
+	tdm->data_align_type = dai_data->priv[dai->id].data_align;
+	tdm->sync_src = dai_data->priv[dai->id].sync_src;
+	tdm->sync_mode = dai_data->priv[dai->id].sync_mode;
+
+	return 0;
+}
+static void q6afe_dai_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	int rc;
+
+	rc = q6afe_port_stop(dai_data->port[dai->id]);
+	if (rc < 0)
+		dev_err(dai->dev, "fail to close AFE port (%d)\n", rc);
+
+	dai_data->is_port_started[dai->id] = false;
+
+}
+
+static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	int rc;
+
+	if (dai_data->is_port_started[dai->id]) {
+		/* stop the port and restart with new port config */
+		rc = q6afe_port_stop(dai_data->port[dai->id]);
+		if (rc < 0) {
+			dev_err(dai->dev, "fail to close AFE port (%d)\n", rc);
+			return rc;
+		}
+	}
+
+	switch (dai->id) {
+	case HDMI_RX:
+		q6afe_hdmi_port_prepare(dai_data->port[dai->id],
+					&dai_data->port_config[dai->id].hdmi);
+		break;
+	case SLIMBUS_0_RX ... SLIMBUS_6_TX:
+		q6afe_slim_port_prepare(dai_data->port[dai->id],
+					&dai_data->port_config[dai->id].slim);
+		break;
+	case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
+		rc = q6afe_i2s_port_prepare(dai_data->port[dai->id],
+			       &dai_data->port_config[dai->id].i2s_cfg);
+		if (rc < 0) {
+			dev_err(dai->dev, "fail to prepare AFE port %x\n",
+				dai->id);
+			return rc;
+		}
+		break;
+	case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
+		q6afe_tdm_port_prepare(dai_data->port[dai->id],
+					&dai_data->port_config[dai->id].tdm);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rc = q6afe_port_start(dai_data->port[dai->id]);
+	if (rc < 0) {
+		dev_err(dai->dev, "fail to start AFE port %x\n", dai->id);
+		return rc;
+	}
+	dai_data->is_port_started[dai->id] = true;
+
+	return 0;
+}
+
+static int q6slim_set_channel_map(struct snd_soc_dai *dai,
+				unsigned int tx_num, unsigned int *tx_slot,
+				unsigned int rx_num, unsigned int *rx_slot)
+{
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct q6afe_port_config *pcfg = &dai_data->port_config[dai->id];
+	int i;
+
+	if (!rx_slot) {
+		pr_err("%s: rx slot not found\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < rx_num; i++) {
+		pcfg->slim.ch_mapping[i] =   rx_slot[i];
+		pr_debug("%s: find number of channels[%d] ch[%d]\n",
+		       __func__, i, rx_slot[i]);
+	}
+
+	pcfg->slim.num_channels = rx_num;
+
+	pr_debug("%s: SLIMBUS_%d_RX cnt[%d] ch[%d %d]\n", __func__,
+		(dai->id - SLIMBUS_0_RX) / 2, rx_num,
+		pcfg->slim.ch_mapping[0],
+		pcfg->slim.ch_mapping[1]);
+
+	return 0;
+}
+
+static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct q6afe_port *port = dai_data->port[dai->id];
+
+	switch (clk_id) {
+	case LPAIF_DIG_CLK:
+		return q6afe_port_set_sysclk(port, clk_id, 0, 5, freq, dir);
+	case LPAIF_BIT_CLK:
+	case LPAIF_OSR_CLK:
+		return q6afe_port_set_sysclk(port, clk_id,
+					     Q6AFE_LPASS_CLK_SRC_INTERNAL,
+					     Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+					     freq, dir);
+	case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR:
+	case Q6AFE_LPASS_CLK_ID_MCLK_1 ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1:
+		return q6afe_port_set_sysclk(port, clk_id,
+					     Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+					     Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+					     freq, dir);
+	case Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT ... Q6AFE_LPASS_CLK_ID_QUIN_TDM_EBIT:
+		return q6afe_port_set_sysclk(port, clk_id,
+					     Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO,
+					     Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+					     freq, dir);
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
+	{"HDMI Playback", NULL, "HDMI_RX"},
+	{"Slimbus1 Playback", NULL, "SLIMBUS_1_RX"},
+	{"Slimbus2 Playback", NULL, "SLIMBUS_2_RX"},
+	{"Slimbus3 Playback", NULL, "SLIMBUS_3_RX"},
+	{"Slimbus4 Playback", NULL, "SLIMBUS_4_RX"},
+	{"Slimbus5 Playback", NULL, "SLIMBUS_5_RX"},
+	{"Slimbus6 Playback", NULL, "SLIMBUS_6_RX"},
+
+	{"Primary MI2S Playback", NULL, "PRI_MI2S_RX"},
+	{"Secondary MI2S Playback", NULL, "SEC_MI2S_RX"},
+	{"Tertiary MI2S Playback", NULL, "TERT_MI2S_RX"},
+	{"Quaternary MI2S Playback", NULL, "QUAT_MI2S_RX"},
+
+	{"Primary TDM0 Playback", NULL, "PRIMARY_TDM_RX_0"},
+	{"Primary TDM1 Playback", NULL, "PRIMARY_TDM_RX_1"},
+	{"Primary TDM2 Playback", NULL, "PRIMARY_TDM_RX_2"},
+	{"Primary TDM3 Playback", NULL, "PRIMARY_TDM_RX_3"},
+	{"Primary TDM4 Playback", NULL, "PRIMARY_TDM_RX_4"},
+	{"Primary TDM5 Playback", NULL, "PRIMARY_TDM_RX_5"},
+	{"Primary TDM6 Playback", NULL, "PRIMARY_TDM_RX_6"},
+	{"Primary TDM7 Playback", NULL, "PRIMARY_TDM_RX_7"},
+
+	{"Secondary TDM0 Playback", NULL, "SEC_TDM_RX_0"},
+	{"Secondary TDM1 Playback", NULL, "SEC_TDM_RX_1"},
+	{"Secondary TDM2 Playback", NULL, "SEC_TDM_RX_2"},
+	{"Secondary TDM3 Playback", NULL, "SEC_TDM_RX_3"},
+	{"Secondary TDM4 Playback", NULL, "SEC_TDM_RX_4"},
+	{"Secondary TDM5 Playback", NULL, "SEC_TDM_RX_5"},
+	{"Secondary TDM6 Playback", NULL, "SEC_TDM_RX_6"},
+	{"Secondary TDM7 Playback", NULL, "SEC_TDM_RX_7"},
+
+	{"Tertiary TDM0 Playback", NULL, "TERT_TDM_RX_0"},
+	{"Tertiary TDM1 Playback", NULL, "TERT_TDM_RX_1"},
+	{"Tertiary TDM2 Playback", NULL, "TERT_TDM_RX_2"},
+	{"Tertiary TDM3 Playback", NULL, "TERT_TDM_RX_3"},
+	{"Tertiary TDM4 Playback", NULL, "TERT_TDM_RX_4"},
+	{"Tertiary TDM5 Playback", NULL, "TERT_TDM_RX_5"},
+	{"Tertiary TDM6 Playback", NULL, "TERT_TDM_RX_6"},
+	{"Tertiary TDM7 Playback", NULL, "TERT_TDM_RX_7"},
+
+	{"Quaternary TDM0 Playback", NULL, "QUAT_TDM_RX_0"},
+	{"Quaternary TDM1 Playback", NULL, "QUAT_TDM_RX_1"},
+	{"Quaternary TDM2 Playback", NULL, "QUAT_TDM_RX_2"},
+	{"Quaternary TDM3 Playback", NULL, "QUAT_TDM_RX_3"},
+	{"Quaternary TDM4 Playback", NULL, "QUAT_TDM_RX_4"},
+	{"Quaternary TDM5 Playback", NULL, "QUAT_TDM_RX_5"},
+	{"Quaternary TDM6 Playback", NULL, "QUAT_TDM_RX_6"},
+	{"Quaternary TDM7 Playback", NULL, "QUAT_TDM_RX_7"},
+
+	{"Quinary TDM0 Playback", NULL, "QUIN_TDM_RX_0"},
+	{"Quinary TDM1 Playback", NULL, "QUIN_TDM_RX_1"},
+	{"Quinary TDM2 Playback", NULL, "QUIN_TDM_RX_2"},
+	{"Quinary TDM3 Playback", NULL, "QUIN_TDM_RX_3"},
+	{"Quinary TDM4 Playback", NULL, "QUIN_TDM_RX_4"},
+	{"Quinary TDM5 Playback", NULL, "QUIN_TDM_RX_5"},
+	{"Quinary TDM6 Playback", NULL, "QUIN_TDM_RX_6"},
+	{"Quinary TDM7 Playback", NULL, "QUIN_TDM_RX_7"},
+
+	{"PRIMARY_TDM_TX_0", NULL, "Primary TDM0 Capture"},
+	{"PRIMARY_TDM_TX_1", NULL, "Primary TDM1 Capture"},
+	{"PRIMARY_TDM_TX_2", NULL, "Primary TDM2 Capture"},
+	{"PRIMARY_TDM_TX_3", NULL, "Primary TDM3 Capture"},
+	{"PRIMARY_TDM_TX_4", NULL, "Primary TDM4 Capture"},
+	{"PRIMARY_TDM_TX_5", NULL, "Primary TDM5 Capture"},
+	{"PRIMARY_TDM_TX_6", NULL, "Primary TDM6 Capture"},
+	{"PRIMARY_TDM_TX_7", NULL, "Primary TDM7 Capture"},
+
+	{"SEC_TDM_TX_0", NULL, "Secondary TDM0 Capture"},
+	{"SEC_TDM_TX_1", NULL, "Secondary TDM1 Capture"},
+	{"SEC_TDM_TX_2", NULL, "Secondary TDM2 Capture"},
+	{"SEC_TDM_TX_3", NULL, "Secondary TDM3 Capture"},
+	{"SEC_TDM_TX_4", NULL, "Secondary TDM4 Capture"},
+	{"SEC_TDM_TX_5", NULL, "Secondary TDM5 Capture"},
+	{"SEC_TDM_TX_6", NULL, "Secondary TDM6 Capture"},
+	{"SEC_TDM_TX_7", NULL, "Secondary TDM7 Capture"},
+
+	{"TERT_TDM_TX_0", NULL, "Tertiary TDM0 Capture"},
+	{"TERT_TDM_TX_1", NULL, "Tertiary TDM1 Capture"},
+	{"TERT_TDM_TX_2", NULL, "Tertiary TDM2 Capture"},
+	{"TERT_TDM_TX_3", NULL, "Tertiary TDM3 Capture"},
+	{"TERT_TDM_TX_4", NULL, "Tertiary TDM4 Capture"},
+	{"TERT_TDM_TX_5", NULL, "Tertiary TDM5 Capture"},
+	{"TERT_TDM_TX_6", NULL, "Tertiary TDM6 Capture"},
+	{"TERT_TDM_TX_7", NULL, "Tertiary TDM7 Capture"},
+
+	{"QUAT_TDM_TX_0", NULL, "Quaternary TDM0 Capture"},
+	{"QUAT_TDM_TX_1", NULL, "Quaternary TDM1 Capture"},
+	{"QUAT_TDM_TX_2", NULL, "Quaternary TDM2 Capture"},
+	{"QUAT_TDM_TX_3", NULL, "Quaternary TDM3 Capture"},
+	{"QUAT_TDM_TX_4", NULL, "Quaternary TDM4 Capture"},
+	{"QUAT_TDM_TX_5", NULL, "Quaternary TDM5 Capture"},
+	{"QUAT_TDM_TX_6", NULL, "Quaternary TDM6 Capture"},
+	{"QUAT_TDM_TX_7", NULL, "Quaternary TDM7 Capture"},
+
+	{"QUIN_TDM_TX_0", NULL, "Quinary TDM0 Capture"},
+	{"QUIN_TDM_TX_1", NULL, "Quinary TDM1 Capture"},
+	{"QUIN_TDM_TX_2", NULL, "Quinary TDM2 Capture"},
+	{"QUIN_TDM_TX_3", NULL, "Quinary TDM3 Capture"},
+	{"QUIN_TDM_TX_4", NULL, "Quinary TDM4 Capture"},
+	{"QUIN_TDM_TX_5", NULL, "Quinary TDM5 Capture"},
+	{"QUIN_TDM_TX_6", NULL, "Quinary TDM6 Capture"},
+	{"QUIN_TDM_TX_7", NULL, "Quinary TDM7 Capture"},
+
+	{"TERT_MI2S_TX", NULL, "Tertiary MI2S Capture"},
+	{"PRI_MI2S_TX", NULL, "Primary MI2S Capture"},
+	{"SEC_MI2S_TX", NULL, "Secondary MI2S Capture"},
+	{"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"},
+};
+
+static struct snd_soc_dai_ops q6hdmi_ops = {
+	.prepare	= q6afe_dai_prepare,
+	.hw_params	= q6hdmi_hw_params,
+	.shutdown	= q6afe_dai_shutdown,
+};
+
+static struct snd_soc_dai_ops q6i2s_ops = {
+	.prepare	= q6afe_dai_prepare,
+	.hw_params	= q6i2s_hw_params,
+	.set_fmt	= q6i2s_set_fmt,
+	.shutdown	= q6afe_dai_shutdown,
+	.set_sysclk	= q6afe_mi2s_set_sysclk,
+};
+
+static struct snd_soc_dai_ops q6slim_ops = {
+	.prepare	= q6afe_dai_prepare,
+	.hw_params	= q6slim_hw_params,
+	.shutdown	= q6afe_dai_shutdown,
+	.set_channel_map = q6slim_set_channel_map,
+};
+
+static struct snd_soc_dai_ops q6tdm_ops = {
+	.prepare	= q6afe_dai_prepare,
+	.shutdown	= q6afe_dai_shutdown,
+	.set_sysclk	= q6afe_mi2s_set_sysclk,
+	.set_tdm_slot     = q6tdm_set_tdm_slot,
+	.set_channel_map  = q6tdm_set_channel_map,
+	.hw_params        = q6tdm_hw_params,
+};
+
+static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
+{
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct q6afe_port *port;
+
+	port = q6afe_port_get_from_id(dai->dev, dai->id);
+	if (IS_ERR(port)) {
+		dev_err(dai->dev, "Unable to get afe port\n");
+		return -EINVAL;
+	}
+	dai_data->port[dai->id] = port;
+
+	return 0;
+}
+
+static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
+{
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	q6afe_port_put(dai_data->port[dai->id]);
+	dai_data->port[dai->id] = NULL;
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver q6afe_dais[] = {
+	{
+		.playback = {
+			.stream_name = "HDMI Playback",
+			.rates = SNDRV_PCM_RATE_48000 |
+				 SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.channels_min = 2,
+			.channels_max = 8,
+			.rate_max =     192000,
+			.rate_min =	48000,
+		},
+		.ops = &q6hdmi_ops,
+		.id = HDMI_RX,
+		.name = "HDMI",
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.name = "SLIMBUS_0_RX",
+		.ops = &q6slim_ops,
+		.id = SLIMBUS_0_RX,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+		.playback = {
+			.stream_name = "Slimbus Playback",
+			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min = 8000,
+			.rate_max = 192000,
+		},
+	}, {
+		.playback = {
+			.stream_name = "Slimbus1 Playback",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min = 8000,
+			.rate_max = 192000,
+		},
+		.name = "SLIMBUS_1_RX",
+		.ops = &q6slim_ops,
+		.id = SLIMBUS_1_RX,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.playback = {
+			.stream_name = "Slimbus2 Playback",
+			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min = 8000,
+			.rate_max = 192000,
+		},
+		.name = "SLIMBUS_2_RX",
+		.ops = &q6slim_ops,
+		.id = SLIMBUS_2_RX,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.playback = {
+			.stream_name = "Slimbus3 Playback",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min = 8000,
+			.rate_max = 192000,
+		},
+		.name = "SLIMBUS_3_RX",
+		.ops = &q6slim_ops,
+		.id = SLIMBUS_3_RX,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.playback = {
+			.stream_name = "Slimbus4 Playback",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min = 8000,
+			.rate_max = 192000,
+		},
+		.name = "SLIMBUS_4_RX",
+		.ops = &q6slim_ops,
+		.id = SLIMBUS_4_RX,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.playback = {
+			.stream_name = "Slimbus5 Playback",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min = 8000,
+			.rate_max = 192000,
+		},
+		.name = "SLIMBUS_5_RX",
+		.ops = &q6slim_ops,
+		.id = SLIMBUS_5_RX,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.playback = {
+			.stream_name = "Slimbus6 Playback",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min = 8000,
+			.rate_max = 192000,
+		},
+		.ops = &q6slim_ops,
+		.name = "SLIMBUS_6_RX",
+		.id = SLIMBUS_6_RX,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.playback = {
+			.stream_name = "Primary MI2S Playback",
+			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.id = PRIMARY_MI2S_RX,
+		.name = "PRI_MI2S_RX",
+		.ops = &q6i2s_ops,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.capture = {
+			.stream_name = "Primary MI2S Capture",
+			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.id = PRIMARY_MI2S_TX,
+		.name = "PRI_MI2S_TX",
+		.ops = &q6i2s_ops,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.playback = {
+			.stream_name = "Secondary MI2S Playback",
+			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.name = "SEC_MI2S_RX",
+		.id = SECONDARY_MI2S_RX,
+		.ops = &q6i2s_ops,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.capture = {
+			.stream_name = "Secondary MI2S Capture",
+			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.id = SECONDARY_MI2S_TX,
+		.name = "SEC_MI2S_TX",
+		.ops = &q6i2s_ops,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.playback = {
+			.stream_name = "Tertiary MI2S Playback",
+			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.name = "TERT_MI2S_RX",
+		.id = TERTIARY_MI2S_RX,
+		.ops = &q6i2s_ops,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.capture = {
+			.stream_name = "Tertiary MI2S Capture",
+			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.id = TERTIARY_MI2S_TX,
+		.name = "TERT_MI2S_TX",
+		.ops = &q6i2s_ops,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.playback = {
+			.stream_name = "Quaternary MI2S Playback",
+			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.name = "QUAT_MI2S_RX",
+		.id = QUATERNARY_MI2S_RX,
+		.ops = &q6i2s_ops,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	}, {
+		.capture = {
+			.stream_name = "Quaternary MI2S Capture",
+			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.id = QUATERNARY_MI2S_TX,
+		.name = "QUAT_MI2S_TX",
+		.ops = &q6i2s_ops,
+		.probe = msm_dai_q6_dai_probe,
+		.remove = msm_dai_q6_dai_remove,
+	},
+	Q6AFE_TDM_PB_DAI("Primary", 0, PRIMARY_TDM_RX_0),
+	Q6AFE_TDM_PB_DAI("Primary", 1, PRIMARY_TDM_RX_1),
+	Q6AFE_TDM_PB_DAI("Primary", 2, PRIMARY_TDM_RX_2),
+	Q6AFE_TDM_PB_DAI("Primary", 3, PRIMARY_TDM_RX_3),
+	Q6AFE_TDM_PB_DAI("Primary", 4, PRIMARY_TDM_RX_4),
+	Q6AFE_TDM_PB_DAI("Primary", 5, PRIMARY_TDM_RX_5),
+	Q6AFE_TDM_PB_DAI("Primary", 6, PRIMARY_TDM_RX_6),
+	Q6AFE_TDM_PB_DAI("Primary", 7, PRIMARY_TDM_RX_7),
+	Q6AFE_TDM_CAP_DAI("Primary", 0, PRIMARY_TDM_TX_0),
+	Q6AFE_TDM_CAP_DAI("Primary", 1, PRIMARY_TDM_TX_1),
+	Q6AFE_TDM_CAP_DAI("Primary", 2, PRIMARY_TDM_TX_2),
+	Q6AFE_TDM_CAP_DAI("Primary", 3, PRIMARY_TDM_TX_3),
+	Q6AFE_TDM_CAP_DAI("Primary", 4, PRIMARY_TDM_TX_4),
+	Q6AFE_TDM_CAP_DAI("Primary", 5, PRIMARY_TDM_TX_5),
+	Q6AFE_TDM_CAP_DAI("Primary", 6, PRIMARY_TDM_TX_6),
+	Q6AFE_TDM_CAP_DAI("Primary", 7, PRIMARY_TDM_TX_7),
+	Q6AFE_TDM_PB_DAI("Secondary", 0, SECONDARY_TDM_RX_0),
+	Q6AFE_TDM_PB_DAI("Secondary", 1, SECONDARY_TDM_RX_1),
+	Q6AFE_TDM_PB_DAI("Secondary", 2, SECONDARY_TDM_RX_2),
+	Q6AFE_TDM_PB_DAI("Secondary", 3, SECONDARY_TDM_RX_3),
+	Q6AFE_TDM_PB_DAI("Secondary", 4, SECONDARY_TDM_RX_4),
+	Q6AFE_TDM_PB_DAI("Secondary", 5, SECONDARY_TDM_RX_5),
+	Q6AFE_TDM_PB_DAI("Secondary", 6, SECONDARY_TDM_RX_6),
+	Q6AFE_TDM_PB_DAI("Secondary", 7, SECONDARY_TDM_RX_7),
+	Q6AFE_TDM_CAP_DAI("Secondary", 0, SECONDARY_TDM_TX_0),
+	Q6AFE_TDM_CAP_DAI("Secondary", 1, SECONDARY_TDM_TX_1),
+	Q6AFE_TDM_CAP_DAI("Secondary", 2, SECONDARY_TDM_TX_2),
+	Q6AFE_TDM_CAP_DAI("Secondary", 3, SECONDARY_TDM_TX_3),
+	Q6AFE_TDM_CAP_DAI("Secondary", 4, SECONDARY_TDM_TX_4),
+	Q6AFE_TDM_CAP_DAI("Secondary", 5, SECONDARY_TDM_TX_5),
+	Q6AFE_TDM_CAP_DAI("Secondary", 6, SECONDARY_TDM_TX_6),
+	Q6AFE_TDM_CAP_DAI("Secondary", 7, SECONDARY_TDM_TX_7),
+	Q6AFE_TDM_PB_DAI("Tertiary", 0, TERTIARY_TDM_RX_0),
+	Q6AFE_TDM_PB_DAI("Tertiary", 1, TERTIARY_TDM_RX_1),
+	Q6AFE_TDM_PB_DAI("Tertiary", 2, TERTIARY_TDM_RX_2),
+	Q6AFE_TDM_PB_DAI("Tertiary", 3, TERTIARY_TDM_RX_3),
+	Q6AFE_TDM_PB_DAI("Tertiary", 4, TERTIARY_TDM_RX_4),
+	Q6AFE_TDM_PB_DAI("Tertiary", 5, TERTIARY_TDM_RX_5),
+	Q6AFE_TDM_PB_DAI("Tertiary", 6, TERTIARY_TDM_RX_6),
+	Q6AFE_TDM_PB_DAI("Tertiary", 7, TERTIARY_TDM_RX_7),
+	Q6AFE_TDM_CAP_DAI("Tertiary", 0, TERTIARY_TDM_TX_0),
+	Q6AFE_TDM_CAP_DAI("Tertiary", 1, TERTIARY_TDM_TX_1),
+	Q6AFE_TDM_CAP_DAI("Tertiary", 2, TERTIARY_TDM_TX_2),
+	Q6AFE_TDM_CAP_DAI("Tertiary", 3, TERTIARY_TDM_TX_3),
+	Q6AFE_TDM_CAP_DAI("Tertiary", 4, TERTIARY_TDM_TX_4),
+	Q6AFE_TDM_CAP_DAI("Tertiary", 5, TERTIARY_TDM_TX_5),
+	Q6AFE_TDM_CAP_DAI("Tertiary", 6, TERTIARY_TDM_TX_6),
+	Q6AFE_TDM_CAP_DAI("Tertiary", 7, TERTIARY_TDM_TX_7),
+	Q6AFE_TDM_PB_DAI("Quaternary", 0, QUATERNARY_TDM_RX_0),
+	Q6AFE_TDM_PB_DAI("Quaternary", 1, QUATERNARY_TDM_RX_1),
+	Q6AFE_TDM_PB_DAI("Quaternary", 2, QUATERNARY_TDM_RX_2),
+	Q6AFE_TDM_PB_DAI("Quaternary", 3, QUATERNARY_TDM_RX_3),
+	Q6AFE_TDM_PB_DAI("Quaternary", 4, QUATERNARY_TDM_RX_4),
+	Q6AFE_TDM_PB_DAI("Quaternary", 5, QUATERNARY_TDM_RX_5),
+	Q6AFE_TDM_PB_DAI("Quaternary", 6, QUATERNARY_TDM_RX_6),
+	Q6AFE_TDM_PB_DAI("Quaternary", 7, QUATERNARY_TDM_RX_7),
+	Q6AFE_TDM_CAP_DAI("Quaternary", 0, QUATERNARY_TDM_TX_0),
+	Q6AFE_TDM_CAP_DAI("Quaternary", 1, QUATERNARY_TDM_TX_1),
+	Q6AFE_TDM_CAP_DAI("Quaternary", 2, QUATERNARY_TDM_TX_2),
+	Q6AFE_TDM_CAP_DAI("Quaternary", 3, QUATERNARY_TDM_TX_3),
+	Q6AFE_TDM_CAP_DAI("Quaternary", 4, QUATERNARY_TDM_TX_4),
+	Q6AFE_TDM_CAP_DAI("Quaternary", 5, QUATERNARY_TDM_TX_5),
+	Q6AFE_TDM_CAP_DAI("Quaternary", 6, QUATERNARY_TDM_TX_6),
+	Q6AFE_TDM_CAP_DAI("Quaternary", 7, QUATERNARY_TDM_TX_7),
+	Q6AFE_TDM_PB_DAI("Quinary", 0, QUINARY_TDM_RX_0),
+	Q6AFE_TDM_PB_DAI("Quinary", 1, QUINARY_TDM_RX_1),
+	Q6AFE_TDM_PB_DAI("Quinary", 2, QUINARY_TDM_RX_2),
+	Q6AFE_TDM_PB_DAI("Quinary", 3, QUINARY_TDM_RX_3),
+	Q6AFE_TDM_PB_DAI("Quinary", 4, QUINARY_TDM_RX_4),
+	Q6AFE_TDM_PB_DAI("Quinary", 5, QUINARY_TDM_RX_5),
+	Q6AFE_TDM_PB_DAI("Quinary", 6, QUINARY_TDM_RX_6),
+	Q6AFE_TDM_PB_DAI("Quinary", 7, QUINARY_TDM_RX_7),
+	Q6AFE_TDM_CAP_DAI("Quinary", 0, QUINARY_TDM_TX_0),
+	Q6AFE_TDM_CAP_DAI("Quinary", 1, QUINARY_TDM_TX_1),
+	Q6AFE_TDM_CAP_DAI("Quinary", 2, QUINARY_TDM_TX_2),
+	Q6AFE_TDM_CAP_DAI("Quinary", 3, QUINARY_TDM_TX_3),
+	Q6AFE_TDM_CAP_DAI("Quinary", 4, QUINARY_TDM_TX_4),
+	Q6AFE_TDM_CAP_DAI("Quinary", 5, QUINARY_TDM_TX_5),
+	Q6AFE_TDM_CAP_DAI("Quinary", 6, QUINARY_TDM_TX_6),
+	Q6AFE_TDM_CAP_DAI("Quinary", 7, QUINARY_TDM_TX_7),
+};
+
+static int q6afe_of_xlate_dai_name(struct snd_soc_component *component,
+				   struct of_phandle_args *args,
+				   const char **dai_name)
+{
+	int id = args->args[0];
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i  < ARRAY_SIZE(q6afe_dais); i++) {
+		if (q6afe_dais[i].id == id) {
+			*dai_name = q6afe_dais[i].name;
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
+	SND_SOC_DAPM_AIF_OUT("HDMI_RX", "HDMI Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_RX", "Slimbus Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_RX", "Slimbus1 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIMBUS_2_RX", "Slimbus2 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIMBUS_3_RX", "Slimbus3 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_RX", "Slimbus4 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_RX", "Slimbus5 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_RX", "Slimbus6 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUAT_MI2S_TX", "Quaternary MI2S Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TERT_MI2S_RX", "Tertiary MI2S Playback",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("TERT_MI2S_TX", "Tertiary MI2S Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SEC_MI2S_RX", "Secondary MI2S Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SEC_MI2S_TX", "Secondary MI2S Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SEC_MI2S_RX_SD1",
+			"Secondary MI2S Playback SD1",
+			0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PRI_MI2S_RX", "Primary MI2S Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PRI_MI2S_TX", "Primary MI2S Capture",
+						0, 0, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_0", "Primary TDM0 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_1", "Primary TDM1 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_2", "Primary TDM2 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_3", "Primary TDM3 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_4", "Primary TDM4 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_5", "Primary TDM5 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_6", "Primary TDM6 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_7", "Primary TDM7 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_0", "Primary TDM0 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_1", "Primary TDM1 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_2", "Primary TDM2 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_3", "Primary TDM3 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_4", "Primary TDM4 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_5", "Primary TDM5 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_6", "Primary TDM6 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_7", "Primary TDM7 Capture",
+						0, 0, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_0", "Secondary TDM0 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_1", "Secondary TDM1 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_2", "Secondary TDM2 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_3", "Secondary TDM3 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_4", "Secondary TDM4 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_5", "Secondary TDM5 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_6", "Secondary TDM6 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_7", "Secondary TDM7 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_0", "Secondary TDM0 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_1", "Secondary TDM1 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_2", "Secondary TDM2 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_3", "Secondary TDM3 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_4", "Secondary TDM4 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_5", "Secondary TDM5 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_6", "Secondary TDM6 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_7", "Secondary TDM7 Capture",
+						0, 0, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_0", "Tertiary TDM0 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_1", "Tertiary TDM1 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_2", "Tertiary TDM2 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_3", "Tertiary TDM3 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_4", "Tertiary TDM4 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_5", "Tertiary TDM5 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_6", "Tertiary TDM6 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_7", "Tertiary TDM7 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_0", "Tertiary TDM0 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_1", "Tertiary TDM1 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_2", "Tertiary TDM2 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_3", "Tertiary TDM3 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_4", "Tertiary TDM4 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_5", "Tertiary TDM5 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_6", "Tertiary TDM6 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_7", "Tertiary TDM7 Capture",
+						0, 0, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_0", "Quaternary TDM0 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_1", "Quaternary TDM1 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_2", "Quaternary TDM2 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_3", "Quaternary TDM3 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_4", "Quaternary TDM4 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_5", "Quaternary TDM5 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_6", "Quaternary TDM6 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_7", "Quaternary TDM7 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_0", "Quaternary TDM0 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_1", "Quaternary TDM1 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_2", "Quaternary TDM2 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_3", "Quaternary TDM3 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_4", "Quaternary TDM4 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_5", "Quaternary TDM5 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_6", "Quaternary TDM6 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_7", "Quaternary TDM7 Capture",
+						0, 0, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_0", "Quinary TDM0 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_1", "Quinary TDM1 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_2", "Quinary TDM2 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_3", "Quinary TDM3 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_4", "Quinary TDM4 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_5", "Quinary TDM5 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_6", "Quinary TDM6 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_7", "Quinary TDM7 Playback",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_0", "Quinary TDM0 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_1", "Quinary TDM1 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_2", "Quinary TDM2 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_3", "Quinary TDM3 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_4", "Quinary TDM4 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_5", "Quinary TDM5 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_6", "Quinary TDM6 Capture",
+						0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_7", "Quinary TDM7 Capture",
+						0, 0, 0, 0),
+};
+
+static const struct snd_soc_component_driver q6afe_dai_component = {
+	.name		= "q6afe-dai-component",
+	.dapm_widgets = q6afe_dai_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(q6afe_dai_widgets),
+	.dapm_routes = q6afe_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(q6afe_dapm_routes),
+	.of_xlate_dai_name = q6afe_of_xlate_dai_name,
+
+};
+
+static void of_q6afe_parse_dai_data(struct device *dev,
+				    struct q6afe_dai_data *data)
+{
+	struct device_node *node;
+	int ret;
+
+	for_each_child_of_node(dev->of_node, node) {
+		unsigned int lines[Q6AFE_MAX_MI2S_LINES];
+		struct q6afe_dai_priv_data *priv;
+		int id, i, num_lines;
+
+		ret = of_property_read_u32(node, "reg", &id);
+		if (ret || id > AFE_PORT_MAX) {
+			dev_err(dev, "valid dai id not found:%d\n", ret);
+			continue;
+		}
+
+		switch (id) {
+		/* MI2S specific properties */
+		case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
+			priv = &data->priv[id];
+			ret = of_property_read_variable_u32_array(node,
+							"qcom,sd-lines",
+							lines, 0,
+							Q6AFE_MAX_MI2S_LINES);
+			if (ret < 0)
+				num_lines = 0;
+			else
+				num_lines = ret;
+
+			priv->sd_line_mask = 0;
+
+			for (i = 0; i < num_lines; i++)
+				priv->sd_line_mask |= BIT(lines[i]);
+
+			break;
+		case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
+			priv = &data->priv[id];
+			ret = of_property_read_u32(node, "qcom,tdm-sync-mode",
+						   &priv->sync_mode);
+			if (ret) {
+				dev_err(dev, "No Sync mode from DT\n");
+				break;
+			}
+			ret = of_property_read_u32(node, "qcom,tdm-sync-src",
+						   &priv->sync_src);
+			if (ret) {
+				dev_err(dev, "No Sync Src from DT\n");
+				break;
+			}
+			ret = of_property_read_u32(node, "qcom,tdm-data-out",
+						   &priv->data_out_enable);
+			if (ret) {
+				dev_err(dev, "No Data out enable from DT\n");
+				break;
+			}
+			ret = of_property_read_u32(node, "qcom,tdm-invert-sync",
+						   &priv->invert_sync);
+			if (ret) {
+				dev_err(dev, "No Invert sync from DT\n");
+				break;
+			}
+			ret = of_property_read_u32(node, "qcom,tdm-data-delay",
+						   &priv->data_delay);
+			if (ret) {
+				dev_err(dev, "No Data Delay from DT\n");
+				break;
+			}
+			ret = of_property_read_u32(node, "qcom,tdm-data-align",
+						   &priv->data_align);
+			if (ret) {
+				dev_err(dev, "No Data align from DT\n");
+				break;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static int q6afe_dai_bind(struct device *dev, struct device *master, void *data)
+{
+	struct q6afe_dai_data *dai_data;
+
+	dai_data = kzalloc(sizeof(*dai_data), GFP_KERNEL);
+	if (!dai_data)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, dai_data);
+
+	of_q6afe_parse_dai_data(dev, dai_data);
+
+	return snd_soc_register_component(dev, &q6afe_dai_component,
+					  q6afe_dais, ARRAY_SIZE(q6afe_dais));
+}
+
+static void q6afe_dai_unbind(struct device *dev, struct device *master,
+			     void *data)
+{
+	struct q6afe_dai_data *dai_data = dev_get_drvdata(dev);
+
+	snd_soc_unregister_component(dev);
+	kfree(dai_data);
+}
+
+static const struct component_ops q6afe_dai_comp_ops = {
+	.bind   = q6afe_dai_bind,
+	.unbind = q6afe_dai_unbind,
+};
+
+static int q6afe_dai_dev_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &q6afe_dai_comp_ops);
+}
+
+static int q6afe_dai_dev_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &q6afe_dai_comp_ops);
+	return 0;
+}
+
+static struct platform_driver q6afe_dai_platform_driver = {
+	.driver = {
+		.name = "q6afe-dai",
+	},
+	.probe = q6afe_dai_dev_probe,
+	.remove = q6afe_dai_dev_remove,
+};
+module_platform_driver(q6afe_dai_platform_driver);
+
+MODULE_DESCRIPTION("Q6 Audio Fronend dai driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
new file mode 100644
index 000000000000..01f43218984b
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -0,0 +1,1495 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+// Copyright (c) 2018, Linaro Limited
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/soc/qcom/apr.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "q6dsp-errno.h"
+#include "q6core.h"
+#include "q6afe.h"
+
+/* AFE CMDs */
+#define AFE_PORT_CMD_DEVICE_START	0x000100E5
+#define AFE_PORT_CMD_DEVICE_STOP	0x000100E6
+#define AFE_PORT_CMD_SET_PARAM_V2	0x000100EF
+#define AFE_SVC_CMD_SET_PARAM		0x000100f3
+#define AFE_PORT_CMDRSP_GET_PARAM_V2	0x00010106
+#define AFE_PARAM_ID_HDMI_CONFIG	0x00010210
+#define AFE_MODULE_AUDIO_DEV_INTERFACE	0x0001020C
+#define AFE_MODULE_TDM			0x0001028A
+
+#define AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG 0x00010235
+
+#define AFE_PARAM_ID_LPAIF_CLK_CONFIG	0x00010238
+#define AFE_PARAM_ID_INT_DIGITAL_CDC_CLK_CONFIG	0x00010239
+
+#define AFE_PARAM_ID_SLIMBUS_CONFIG    0x00010212
+#define AFE_PARAM_ID_I2S_CONFIG	0x0001020D
+#define AFE_PARAM_ID_TDM_CONFIG	0x0001029D
+#define AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG	0x00010297
+
+/* I2S config specific */
+#define AFE_API_VERSION_I2S_CONFIG	0x1
+#define AFE_PORT_I2S_SD0		0x1
+#define AFE_PORT_I2S_SD1		0x2
+#define AFE_PORT_I2S_SD2		0x3
+#define AFE_PORT_I2S_SD3		0x4
+#define AFE_PORT_I2S_SD0_MASK		BIT(0x1)
+#define AFE_PORT_I2S_SD1_MASK		BIT(0x2)
+#define AFE_PORT_I2S_SD2_MASK		BIT(0x3)
+#define AFE_PORT_I2S_SD3_MASK		BIT(0x4)
+#define AFE_PORT_I2S_SD0_1_MASK		GENMASK(2, 1)
+#define AFE_PORT_I2S_SD2_3_MASK		GENMASK(4, 3)
+#define AFE_PORT_I2S_SD0_1_2_MASK	GENMASK(3, 1)
+#define AFE_PORT_I2S_SD0_1_2_3_MASK	GENMASK(4, 1)
+#define AFE_PORT_I2S_QUAD01		0x5
+#define AFE_PORT_I2S_QUAD23		0x6
+#define AFE_PORT_I2S_6CHS		0x7
+#define AFE_PORT_I2S_8CHS		0x8
+#define AFE_PORT_I2S_MONO		0x0
+#define AFE_PORT_I2S_STEREO		0x1
+#define AFE_PORT_CONFIG_I2S_WS_SRC_EXTERNAL	0x0
+#define AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL	0x1
+#define AFE_LINEAR_PCM_DATA				0x0
+
+
+/* Port IDs */
+#define AFE_API_VERSION_HDMI_CONFIG	0x1
+#define AFE_PORT_ID_MULTICHAN_HDMI_RX	0x100E
+
+#define AFE_API_VERSION_SLIMBUS_CONFIG 0x1
+/* Clock set API version */
+#define AFE_API_VERSION_CLOCK_SET 1
+#define Q6AFE_LPASS_CLK_CONFIG_API_VERSION	0x1
+#define AFE_MODULE_CLOCK_SET		0x0001028F
+#define AFE_PARAM_ID_CLOCK_SET		0x00010290
+
+/* SLIMbus Rx port on channel 0. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX      0x4000
+/* SLIMbus Tx port on channel 0. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX      0x4001
+/* SLIMbus Rx port on channel 1. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX      0x4002
+/* SLIMbus Tx port on channel 1. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX      0x4003
+/* SLIMbus Rx port on channel 2. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX      0x4004
+/* SLIMbus Tx port on channel 2. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX      0x4005
+/* SLIMbus Rx port on channel 3. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_RX      0x4006
+/* SLIMbus Tx port on channel 3. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX      0x4007
+/* SLIMbus Rx port on channel 4. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX      0x4008
+/* SLIMbus Tx port on channel 4. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX      0x4009
+/* SLIMbus Rx port on channel 5. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX      0x400a
+/* SLIMbus Tx port on channel 5. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX      0x400b
+/* SLIMbus Rx port on channel 6. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX      0x400c
+/* SLIMbus Tx port on channel 6. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_TX      0x400d
+#define AFE_PORT_ID_PRIMARY_MI2S_RX         0x1000
+#define AFE_PORT_ID_PRIMARY_MI2S_TX         0x1001
+#define AFE_PORT_ID_SECONDARY_MI2S_RX       0x1002
+#define AFE_PORT_ID_SECONDARY_MI2S_TX       0x1003
+#define AFE_PORT_ID_TERTIARY_MI2S_RX        0x1004
+#define AFE_PORT_ID_TERTIARY_MI2S_TX        0x1005
+#define AFE_PORT_ID_QUATERNARY_MI2S_RX      0x1006
+#define AFE_PORT_ID_QUATERNARY_MI2S_TX      0x1007
+
+/* Start of the range of port IDs for TDM devices. */
+#define AFE_PORT_ID_TDM_PORT_RANGE_START	0x9000
+
+/* End of the range of port IDs for TDM devices. */
+#define AFE_PORT_ID_TDM_PORT_RANGE_END \
+	(AFE_PORT_ID_TDM_PORT_RANGE_START+0x50-1)
+
+/* Size of the range of port IDs for TDM ports. */
+#define AFE_PORT_ID_TDM_PORT_RANGE_SIZE \
+	(AFE_PORT_ID_TDM_PORT_RANGE_END - \
+	AFE_PORT_ID_TDM_PORT_RANGE_START+1)
+
+#define AFE_PORT_ID_PRIMARY_TDM_RX \
+	(AFE_PORT_ID_TDM_PORT_RANGE_START + 0x00)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_1 \
+	(AFE_PORT_ID_PRIMARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_2 \
+	(AFE_PORT_ID_PRIMARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_3 \
+	(AFE_PORT_ID_PRIMARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_4 \
+	(AFE_PORT_ID_PRIMARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_5 \
+	(AFE_PORT_ID_PRIMARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_6 \
+	(AFE_PORT_ID_PRIMARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_7 \
+	(AFE_PORT_ID_PRIMARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_PRIMARY_TDM_TX \
+	(AFE_PORT_ID_TDM_PORT_RANGE_START + 0x01)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_1 \
+	(AFE_PORT_ID_PRIMARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_2 \
+	(AFE_PORT_ID_PRIMARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_3 \
+	(AFE_PORT_ID_PRIMARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_4 \
+	(AFE_PORT_ID_PRIMARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_5 \
+	(AFE_PORT_ID_PRIMARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_6 \
+	(AFE_PORT_ID_PRIMARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_7 \
+	(AFE_PORT_ID_PRIMARY_TDM_TX + 0x0E)
+
+#define AFE_PORT_ID_SECONDARY_TDM_RX \
+	(AFE_PORT_ID_TDM_PORT_RANGE_START + 0x10)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_1 \
+	(AFE_PORT_ID_SECONDARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_2 \
+	(AFE_PORT_ID_SECONDARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_3 \
+	(AFE_PORT_ID_SECONDARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_4 \
+	(AFE_PORT_ID_SECONDARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_5 \
+	(AFE_PORT_ID_SECONDARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_6 \
+	(AFE_PORT_ID_SECONDARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_7 \
+	(AFE_PORT_ID_SECONDARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_SECONDARY_TDM_TX \
+	(AFE_PORT_ID_TDM_PORT_RANGE_START + 0x11)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_1 \
+	(AFE_PORT_ID_SECONDARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_2 \
+	(AFE_PORT_ID_SECONDARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_3 \
+	(AFE_PORT_ID_SECONDARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_4 \
+	(AFE_PORT_ID_SECONDARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_5 \
+	(AFE_PORT_ID_SECONDARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_6 \
+	(AFE_PORT_ID_SECONDARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_7 \
+	(AFE_PORT_ID_SECONDARY_TDM_TX + 0x0E)
+
+#define AFE_PORT_ID_TERTIARY_TDM_RX \
+	(AFE_PORT_ID_TDM_PORT_RANGE_START + 0x20)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_1 \
+	(AFE_PORT_ID_TERTIARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_2 \
+	(AFE_PORT_ID_TERTIARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_3 \
+	(AFE_PORT_ID_TERTIARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_4 \
+	(AFE_PORT_ID_TERTIARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_5 \
+	(AFE_PORT_ID_TERTIARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_6 \
+	(AFE_PORT_ID_TERTIARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_7 \
+	(AFE_PORT_ID_TERTIARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_TERTIARY_TDM_TX \
+	(AFE_PORT_ID_TDM_PORT_RANGE_START + 0x21)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_1 \
+	(AFE_PORT_ID_TERTIARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_2 \
+	(AFE_PORT_ID_TERTIARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_3 \
+	(AFE_PORT_ID_TERTIARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_4 \
+	(AFE_PORT_ID_TERTIARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_5 \
+	(AFE_PORT_ID_TERTIARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_6 \
+	(AFE_PORT_ID_TERTIARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_7 \
+	(AFE_PORT_ID_TERTIARY_TDM_TX + 0x0E)
+
+#define AFE_PORT_ID_QUATERNARY_TDM_RX \
+	(AFE_PORT_ID_TDM_PORT_RANGE_START + 0x30)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_1 \
+	(AFE_PORT_ID_QUATERNARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_2 \
+	(AFE_PORT_ID_QUATERNARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_3 \
+	(AFE_PORT_ID_QUATERNARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_4 \
+	(AFE_PORT_ID_QUATERNARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_5 \
+	(AFE_PORT_ID_QUATERNARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_6 \
+	(AFE_PORT_ID_QUATERNARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_7 \
+	(AFE_PORT_ID_QUATERNARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_QUATERNARY_TDM_TX \
+	(AFE_PORT_ID_TDM_PORT_RANGE_START + 0x31)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_1 \
+	(AFE_PORT_ID_QUATERNARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_2 \
+	(AFE_PORT_ID_QUATERNARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_3 \
+	(AFE_PORT_ID_QUATERNARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_4 \
+	(AFE_PORT_ID_QUATERNARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_5 \
+	(AFE_PORT_ID_QUATERNARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_6 \
+	(AFE_PORT_ID_QUATERNARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_7 \
+	(AFE_PORT_ID_QUATERNARY_TDM_TX + 0x0E)
+
+#define AFE_PORT_ID_QUINARY_TDM_RX \
+	(AFE_PORT_ID_TDM_PORT_RANGE_START + 0x40)
+#define AFE_PORT_ID_QUINARY_TDM_RX_1 \
+	(AFE_PORT_ID_QUINARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_QUINARY_TDM_RX_2 \
+	(AFE_PORT_ID_QUINARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_QUINARY_TDM_RX_3 \
+	(AFE_PORT_ID_QUINARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_QUINARY_TDM_RX_4 \
+	(AFE_PORT_ID_QUINARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_QUINARY_TDM_RX_5 \
+	(AFE_PORT_ID_QUINARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_QUINARY_TDM_RX_6 \
+	(AFE_PORT_ID_QUINARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_QUINARY_TDM_RX_7 \
+	(AFE_PORT_ID_QUINARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_QUINARY_TDM_TX \
+	(AFE_PORT_ID_TDM_PORT_RANGE_START + 0x41)
+#define AFE_PORT_ID_QUINARY_TDM_TX_1 \
+	(AFE_PORT_ID_QUINARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_QUINARY_TDM_TX_2 \
+	(AFE_PORT_ID_QUINARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_QUINARY_TDM_TX_3 \
+	(AFE_PORT_ID_QUINARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_QUINARY_TDM_TX_4 \
+	(AFE_PORT_ID_QUINARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_QUINARY_TDM_TX_5 \
+	(AFE_PORT_ID_QUINARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_QUINARY_TDM_TX_6 \
+	(AFE_PORT_ID_QUINARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_QUINARY_TDM_TX_7 \
+	(AFE_PORT_ID_QUINARY_TDM_TX + 0x0E)
+
+#define Q6AFE_LPASS_MODE_CLK1_VALID 1
+#define Q6AFE_LPASS_MODE_CLK2_VALID 2
+#define Q6AFE_LPASS_CLK_SRC_INTERNAL 1
+#define Q6AFE_LPASS_CLK_ROOT_DEFAULT 0
+#define AFE_API_VERSION_TDM_CONFIG              1
+#define AFE_API_VERSION_SLOT_MAPPING_CONFIG	1
+
+#define TIMEOUT_MS 1000
+#define AFE_CMD_RESP_AVAIL	0
+#define AFE_CMD_RESP_NONE	1
+
+struct q6afe {
+	struct apr_device *apr;
+	struct device *dev;
+	struct q6core_svc_api_info ainfo;
+	struct mutex lock;
+	struct list_head port_list;
+	spinlock_t port_list_lock;
+	struct platform_device *pdev_dais;
+};
+
+struct afe_port_cmd_device_start {
+	u16 port_id;
+	u16 reserved;
+} __packed;
+
+struct afe_port_cmd_device_stop {
+	u16 port_id;
+	u16 reserved;
+/* Reserved for 32-bit alignment. This field must be set to 0.*/
+} __packed;
+
+struct afe_port_param_data_v2 {
+	u32 module_id;
+	u32 param_id;
+	u16 param_size;
+	u16 reserved;
+} __packed;
+
+struct afe_svc_cmd_set_param {
+	uint32_t payload_size;
+	uint32_t payload_address_lsw;
+	uint32_t payload_address_msw;
+	uint32_t mem_map_handle;
+} __packed;
+
+struct afe_port_cmd_set_param_v2 {
+	u16 port_id;
+	u16 payload_size;
+	u32 payload_address_lsw;
+	u32 payload_address_msw;
+	u32 mem_map_handle;
+} __packed;
+
+struct afe_param_id_hdmi_multi_chan_audio_cfg {
+	u32 hdmi_cfg_minor_version;
+	u16 datatype;
+	u16 channel_allocation;
+	u32 sample_rate;
+	u16 bit_width;
+	u16 reserved;
+} __packed;
+
+struct afe_param_id_slimbus_cfg {
+	u32                  sb_cfg_minor_version;
+/* Minor version used for tracking the version of the SLIMBUS
+ * configuration interface.
+ * Supported values: #AFE_API_VERSION_SLIMBUS_CONFIG
+ */
+
+	u16                  slimbus_dev_id;
+/* SLIMbus hardware device ID, which is required to handle
+ * multiple SLIMbus hardware blocks.
+ * Supported values: - #AFE_SLIMBUS_DEVICE_1 - #AFE_SLIMBUS_DEVICE_2
+ */
+	u16                  bit_width;
+/* Bit width of the sample.
+ * Supported values: 16, 24
+ */
+	u16                  data_format;
+/* Data format supported by the SLIMbus hardware. The default is
+ * 0 (#AFE_SB_DATA_FORMAT_NOT_INDICATED), which indicates the
+ * hardware does not perform any format conversions before the data
+ * transfer.
+ */
+	u16                  num_channels;
+/* Number of channels.
+ * Supported values: 1 to #AFE_PORT_MAX_AUDIO_CHAN_CNT
+ */
+	u8  shared_ch_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+/* Mapping of shared channel IDs (128 to 255) to which the
+ * master port is to be connected.
+ * Shared_channel_mapping[i] represents the shared channel assigned
+ * for audio channel i in multichannel audio data.
+ */
+	u32              sample_rate;
+/* Sampling rate of the port.
+ * Supported values:
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_16K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_96K
+ * - #AFE_PORT_SAMPLE_RATE_192K
+ */
+} __packed;
+
+struct afe_clk_cfg {
+	u32                  i2s_cfg_minor_version;
+	u32                  clk_val1;
+	u32                  clk_val2;
+	u16                  clk_src;
+	u16                  clk_root;
+	u16                  clk_set_mode;
+	u16                  reserved;
+} __packed;
+
+struct afe_digital_clk_cfg {
+	u32                  i2s_cfg_minor_version;
+	u32                  clk_val;
+	u16                  clk_root;
+	u16                  reserved;
+} __packed;
+
+struct afe_param_id_i2s_cfg {
+	u32	i2s_cfg_minor_version;
+	u16	bit_width;
+	u16	channel_mode;
+	u16	mono_stereo;
+	u16	ws_src;
+	u32	sample_rate;
+	u16	data_format;
+	u16	reserved;
+} __packed;
+
+struct afe_param_id_tdm_cfg {
+	u32	tdm_cfg_minor_version;
+	u32	num_channels;
+	u32	sample_rate;
+	u32	bit_width;
+	u16	data_format;
+	u16	sync_mode;
+	u16	sync_src;
+	u16	nslots_per_frame;
+	u16	ctrl_data_out_enable;
+	u16	ctrl_invert_sync_pulse;
+	u16	ctrl_sync_data_delay;
+	u16	slot_width;
+	u32	slot_mask;
+} __packed;
+
+union afe_port_config {
+	struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch;
+	struct afe_param_id_slimbus_cfg           slim_cfg;
+	struct afe_param_id_i2s_cfg	i2s_cfg;
+	struct afe_param_id_tdm_cfg	tdm_cfg;
+} __packed;
+
+
+struct afe_clk_set {
+	uint32_t clk_set_minor_version;
+	uint32_t clk_id;
+	uint32_t clk_freq_in_hz;
+	uint16_t clk_attri;
+	uint16_t clk_root;
+	uint32_t enable;
+};
+
+struct afe_param_id_slot_mapping_cfg {
+	u32	minor_version;
+	u16	num_channels;
+	u16	bitwidth;
+	u32	data_align_type;
+	u16	ch_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+} __packed;
+
+struct q6afe_port {
+	wait_queue_head_t wait;
+	union afe_port_config port_cfg;
+	struct afe_param_id_slot_mapping_cfg *scfg;
+	struct aprv2_ibasic_rsp_result_t result;
+	int token;
+	int id;
+	int cfg_type;
+	struct q6afe *afe;
+	struct kref refcount;
+	struct list_head node;
+};
+
+struct afe_port_map {
+	int port_id;
+	int token;
+	int is_rx;
+	int is_dig_pcm;
+};
+
+/*
+ * Mapping between Virtual Port IDs to DSP AFE Port ID
+ * On B Family SoCs DSP Port IDs are consistent across multiple SoCs
+ * on A Family SoCs DSP port IDs are same as virtual Port IDs.
+ */
+
+static struct afe_port_map port_maps[AFE_PORT_MAX] = {
+	[HDMI_RX] = { AFE_PORT_ID_MULTICHAN_HDMI_RX, HDMI_RX, 1, 1},
+	[SLIMBUS_0_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX,
+				SLIMBUS_0_RX, 1, 1},
+	[SLIMBUS_1_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX,
+				SLIMBUS_1_RX, 1, 1},
+	[SLIMBUS_2_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX,
+				SLIMBUS_2_RX, 1, 1},
+	[SLIMBUS_3_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_RX,
+				SLIMBUS_3_RX, 1, 1},
+	[SLIMBUS_4_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX,
+				SLIMBUS_4_RX, 1, 1},
+	[SLIMBUS_5_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX,
+				SLIMBUS_5_RX, 1, 1},
+	[SLIMBUS_6_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX,
+				SLIMBUS_6_RX, 1, 1},
+	[PRIMARY_MI2S_RX] = { AFE_PORT_ID_PRIMARY_MI2S_RX,
+				PRIMARY_MI2S_RX, 1, 1},
+	[PRIMARY_MI2S_TX] = { AFE_PORT_ID_PRIMARY_MI2S_TX,
+				PRIMARY_MI2S_RX, 0, 1},
+	[SECONDARY_MI2S_RX] = { AFE_PORT_ID_SECONDARY_MI2S_RX,
+				SECONDARY_MI2S_RX, 1, 1},
+	[SECONDARY_MI2S_TX] = { AFE_PORT_ID_SECONDARY_MI2S_TX,
+				SECONDARY_MI2S_TX, 0, 1},
+	[TERTIARY_MI2S_RX] = { AFE_PORT_ID_TERTIARY_MI2S_RX,
+				TERTIARY_MI2S_RX, 1, 1},
+	[TERTIARY_MI2S_TX] = { AFE_PORT_ID_TERTIARY_MI2S_TX,
+				TERTIARY_MI2S_TX, 0, 1},
+	[QUATERNARY_MI2S_RX] = { AFE_PORT_ID_QUATERNARY_MI2S_RX,
+				QUATERNARY_MI2S_RX, 1, 1},
+	[QUATERNARY_MI2S_TX] = { AFE_PORT_ID_QUATERNARY_MI2S_TX,
+				QUATERNARY_MI2S_TX, 0, 1},
+	[PRIMARY_TDM_RX_0] =  { AFE_PORT_ID_PRIMARY_TDM_RX,
+				PRIMARY_TDM_RX_0, 1, 1},
+	[PRIMARY_TDM_TX_0] =  { AFE_PORT_ID_PRIMARY_TDM_TX,
+				PRIMARY_TDM_TX_0, 0, 1},
+	[PRIMARY_TDM_RX_1] =  { AFE_PORT_ID_PRIMARY_TDM_RX_1,
+				PRIMARY_TDM_RX_1, 1, 1},
+	[PRIMARY_TDM_TX_1] =  { AFE_PORT_ID_PRIMARY_TDM_TX_1,
+				PRIMARY_TDM_TX_1, 0, 1},
+	[PRIMARY_TDM_RX_2] =  { AFE_PORT_ID_PRIMARY_TDM_RX_2,
+				PRIMARY_TDM_RX_2, 1, 1},
+	[PRIMARY_TDM_TX_2] =  { AFE_PORT_ID_PRIMARY_TDM_TX_2,
+				PRIMARY_TDM_TX_2, 0, 1},
+	[PRIMARY_TDM_RX_3] =  { AFE_PORT_ID_PRIMARY_TDM_RX_3,
+				PRIMARY_TDM_RX_3, 1, 1},
+	[PRIMARY_TDM_TX_3] =  { AFE_PORT_ID_PRIMARY_TDM_TX_3,
+				PRIMARY_TDM_TX_3, 0, 1},
+	[PRIMARY_TDM_RX_4] =  { AFE_PORT_ID_PRIMARY_TDM_RX_4,
+				PRIMARY_TDM_RX_4, 1, 1},
+	[PRIMARY_TDM_TX_4] =  { AFE_PORT_ID_PRIMARY_TDM_TX_4,
+				PRIMARY_TDM_TX_4, 0, 1},
+	[PRIMARY_TDM_RX_5] =  { AFE_PORT_ID_PRIMARY_TDM_RX_5,
+				PRIMARY_TDM_RX_5, 1, 1},
+	[PRIMARY_TDM_TX_5] =  { AFE_PORT_ID_PRIMARY_TDM_TX_5,
+				PRIMARY_TDM_TX_5, 0, 1},
+	[PRIMARY_TDM_RX_6] =  { AFE_PORT_ID_PRIMARY_TDM_RX_6,
+				PRIMARY_TDM_RX_6, 1, 1},
+	[PRIMARY_TDM_TX_6] =  { AFE_PORT_ID_PRIMARY_TDM_TX_6,
+				PRIMARY_TDM_TX_6, 0, 1},
+	[PRIMARY_TDM_RX_7] =  { AFE_PORT_ID_PRIMARY_TDM_RX_7,
+				PRIMARY_TDM_RX_7, 1, 1},
+	[PRIMARY_TDM_TX_7] =  { AFE_PORT_ID_PRIMARY_TDM_TX_7,
+				PRIMARY_TDM_TX_7, 0, 1},
+	[SECONDARY_TDM_RX_0] =  { AFE_PORT_ID_SECONDARY_TDM_RX,
+				SECONDARY_TDM_RX_0, 1, 1},
+	[SECONDARY_TDM_TX_0] =  { AFE_PORT_ID_SECONDARY_TDM_TX,
+				SECONDARY_TDM_TX_0, 0, 1},
+	[SECONDARY_TDM_RX_1] =  { AFE_PORT_ID_SECONDARY_TDM_RX_1,
+				SECONDARY_TDM_RX_1, 1, 1},
+	[SECONDARY_TDM_TX_1] =  { AFE_PORT_ID_SECONDARY_TDM_TX_1,
+				SECONDARY_TDM_TX_1, 0, 1},
+	[SECONDARY_TDM_RX_2] =  { AFE_PORT_ID_SECONDARY_TDM_RX_2,
+				SECONDARY_TDM_RX_2, 1, 1},
+	[SECONDARY_TDM_TX_2] =  { AFE_PORT_ID_SECONDARY_TDM_TX_2,
+				SECONDARY_TDM_TX_2, 0, 1},
+	[SECONDARY_TDM_RX_3] =  { AFE_PORT_ID_SECONDARY_TDM_RX_3,
+				SECONDARY_TDM_RX_3, 1, 1},
+	[SECONDARY_TDM_TX_3] =  { AFE_PORT_ID_SECONDARY_TDM_TX_3,
+				SECONDARY_TDM_TX_3, 0, 1},
+	[SECONDARY_TDM_RX_4] =  { AFE_PORT_ID_SECONDARY_TDM_RX_4,
+				SECONDARY_TDM_RX_4, 1, 1},
+	[SECONDARY_TDM_TX_4] =  { AFE_PORT_ID_SECONDARY_TDM_TX_4,
+				SECONDARY_TDM_TX_4, 0, 1},
+	[SECONDARY_TDM_RX_5] =  { AFE_PORT_ID_SECONDARY_TDM_RX_5,
+				SECONDARY_TDM_RX_5, 1, 1},
+	[SECONDARY_TDM_TX_5] =  { AFE_PORT_ID_SECONDARY_TDM_TX_5,
+				SECONDARY_TDM_TX_5, 0, 1},
+	[SECONDARY_TDM_RX_6] =  { AFE_PORT_ID_SECONDARY_TDM_RX_6,
+				SECONDARY_TDM_RX_6, 1, 1},
+	[SECONDARY_TDM_TX_6] =  { AFE_PORT_ID_SECONDARY_TDM_TX_6,
+				SECONDARY_TDM_TX_6, 0, 1},
+	[SECONDARY_TDM_RX_7] =  { AFE_PORT_ID_SECONDARY_TDM_RX_7,
+				SECONDARY_TDM_RX_7, 1, 1},
+	[SECONDARY_TDM_TX_7] =  { AFE_PORT_ID_SECONDARY_TDM_TX_7,
+				SECONDARY_TDM_TX_7, 0, 1},
+	[TERTIARY_TDM_RX_0] =  { AFE_PORT_ID_TERTIARY_TDM_RX,
+				TERTIARY_TDM_RX_0, 1, 1},
+	[TERTIARY_TDM_TX_0] =  { AFE_PORT_ID_TERTIARY_TDM_TX,
+				TERTIARY_TDM_TX_0, 0, 1},
+	[TERTIARY_TDM_RX_1] =  { AFE_PORT_ID_TERTIARY_TDM_RX_1,
+				TERTIARY_TDM_RX_1, 1, 1},
+	[TERTIARY_TDM_TX_1] =  { AFE_PORT_ID_TERTIARY_TDM_TX_1,
+				TERTIARY_TDM_TX_1, 0, 1},
+	[TERTIARY_TDM_RX_2] =  { AFE_PORT_ID_TERTIARY_TDM_RX_2,
+				TERTIARY_TDM_RX_2, 1, 1},
+	[TERTIARY_TDM_TX_2] =  { AFE_PORT_ID_TERTIARY_TDM_TX_2,
+				TERTIARY_TDM_TX_2, 0, 1},
+	[TERTIARY_TDM_RX_3] =  { AFE_PORT_ID_TERTIARY_TDM_RX_3,
+				TERTIARY_TDM_RX_3, 1, 1},
+	[TERTIARY_TDM_TX_3] =  { AFE_PORT_ID_TERTIARY_TDM_TX_3,
+				TERTIARY_TDM_TX_3, 0, 1},
+	[TERTIARY_TDM_RX_4] =  { AFE_PORT_ID_TERTIARY_TDM_RX_4,
+				TERTIARY_TDM_RX_4, 1, 1},
+	[TERTIARY_TDM_TX_4] =  { AFE_PORT_ID_TERTIARY_TDM_TX_4,
+				TERTIARY_TDM_TX_4, 0, 1},
+	[TERTIARY_TDM_RX_5] =  { AFE_PORT_ID_TERTIARY_TDM_RX_5,
+				TERTIARY_TDM_RX_5, 1, 1},
+	[TERTIARY_TDM_TX_5] =  { AFE_PORT_ID_TERTIARY_TDM_TX_5,
+				TERTIARY_TDM_TX_5, 0, 1},
+	[TERTIARY_TDM_RX_6] =  { AFE_PORT_ID_TERTIARY_TDM_RX_6,
+				TERTIARY_TDM_RX_6, 1, 1},
+	[TERTIARY_TDM_TX_6] =  { AFE_PORT_ID_TERTIARY_TDM_TX_6,
+				TERTIARY_TDM_TX_6, 0, 1},
+	[TERTIARY_TDM_RX_7] =  { AFE_PORT_ID_TERTIARY_TDM_RX_7,
+				TERTIARY_TDM_RX_7, 1, 1},
+	[TERTIARY_TDM_TX_7] =  { AFE_PORT_ID_TERTIARY_TDM_TX_7,
+				TERTIARY_TDM_TX_7, 0, 1},
+	[QUATERNARY_TDM_RX_0] =  { AFE_PORT_ID_QUATERNARY_TDM_RX,
+				QUATERNARY_TDM_RX_0, 1, 1},
+	[QUATERNARY_TDM_TX_0] =  { AFE_PORT_ID_QUATERNARY_TDM_TX,
+				QUATERNARY_TDM_TX_0, 0, 1},
+	[QUATERNARY_TDM_RX_1] =  { AFE_PORT_ID_QUATERNARY_TDM_RX_1,
+				QUATERNARY_TDM_RX_1, 1, 1},
+	[QUATERNARY_TDM_TX_1] =  { AFE_PORT_ID_QUATERNARY_TDM_TX_1,
+				QUATERNARY_TDM_TX_1, 0, 1},
+	[QUATERNARY_TDM_RX_2] =  { AFE_PORT_ID_QUATERNARY_TDM_RX_2,
+				QUATERNARY_TDM_RX_2, 1, 1},
+	[QUATERNARY_TDM_TX_2] =  { AFE_PORT_ID_QUATERNARY_TDM_TX_2,
+				QUATERNARY_TDM_TX_2, 0, 1},
+	[QUATERNARY_TDM_RX_3] =  { AFE_PORT_ID_QUATERNARY_TDM_RX_3,
+				QUATERNARY_TDM_RX_3, 1, 1},
+	[QUATERNARY_TDM_TX_3] =  { AFE_PORT_ID_QUATERNARY_TDM_TX_3,
+				QUATERNARY_TDM_TX_3, 0, 1},
+	[QUATERNARY_TDM_RX_4] =  { AFE_PORT_ID_QUATERNARY_TDM_RX_4,
+				QUATERNARY_TDM_RX_4, 1, 1},
+	[QUATERNARY_TDM_TX_4] =  { AFE_PORT_ID_QUATERNARY_TDM_TX_4,
+				QUATERNARY_TDM_TX_4, 0, 1},
+	[QUATERNARY_TDM_RX_5] =  { AFE_PORT_ID_QUATERNARY_TDM_RX_5,
+				QUATERNARY_TDM_RX_5, 1, 1},
+	[QUATERNARY_TDM_TX_5] =  { AFE_PORT_ID_QUATERNARY_TDM_TX_5,
+				QUATERNARY_TDM_TX_5, 0, 1},
+	[QUATERNARY_TDM_RX_6] =  { AFE_PORT_ID_QUATERNARY_TDM_RX_6,
+				QUATERNARY_TDM_RX_6, 1, 1},
+	[QUATERNARY_TDM_TX_6] =  { AFE_PORT_ID_QUATERNARY_TDM_TX_6,
+				QUATERNARY_TDM_TX_6, 0, 1},
+	[QUATERNARY_TDM_RX_7] =  { AFE_PORT_ID_QUATERNARY_TDM_RX_7,
+				QUATERNARY_TDM_RX_7, 1, 1},
+	[QUATERNARY_TDM_TX_7] =  { AFE_PORT_ID_QUATERNARY_TDM_TX_7,
+				QUATERNARY_TDM_TX_7, 0, 1},
+	[QUINARY_TDM_RX_0] =  { AFE_PORT_ID_QUINARY_TDM_RX,
+				QUINARY_TDM_RX_0, 1, 1},
+	[QUINARY_TDM_TX_0] =  { AFE_PORT_ID_QUINARY_TDM_TX,
+				QUINARY_TDM_TX_0, 0, 1},
+	[QUINARY_TDM_RX_1] =  { AFE_PORT_ID_QUINARY_TDM_RX_1,
+				QUINARY_TDM_RX_1, 1, 1},
+	[QUINARY_TDM_TX_1] =  { AFE_PORT_ID_QUINARY_TDM_TX_1,
+				QUINARY_TDM_TX_1, 0, 1},
+	[QUINARY_TDM_RX_2] =  { AFE_PORT_ID_QUINARY_TDM_RX_2,
+				QUINARY_TDM_RX_2, 1, 1},
+	[QUINARY_TDM_TX_2] =  { AFE_PORT_ID_QUINARY_TDM_TX_2,
+				QUINARY_TDM_TX_2, 0, 1},
+	[QUINARY_TDM_RX_3] =  { AFE_PORT_ID_QUINARY_TDM_RX_3,
+				QUINARY_TDM_RX_3, 1, 1},
+	[QUINARY_TDM_TX_3] =  { AFE_PORT_ID_QUINARY_TDM_TX_3,
+				QUINARY_TDM_TX_3, 0, 1},
+	[QUINARY_TDM_RX_4] =  { AFE_PORT_ID_QUINARY_TDM_RX_4,
+				QUINARY_TDM_RX_4, 1, 1},
+	[QUINARY_TDM_TX_4] =  { AFE_PORT_ID_QUINARY_TDM_TX_4,
+				QUINARY_TDM_TX_4, 0, 1},
+	[QUINARY_TDM_RX_5] =  { AFE_PORT_ID_QUINARY_TDM_RX_5,
+				QUINARY_TDM_RX_5, 1, 1},
+	[QUINARY_TDM_TX_5] =  { AFE_PORT_ID_QUINARY_TDM_TX_5,
+				QUINARY_TDM_TX_5, 0, 1},
+	[QUINARY_TDM_RX_6] =  { AFE_PORT_ID_QUINARY_TDM_RX_6,
+				QUINARY_TDM_RX_6, 1, 1},
+	[QUINARY_TDM_TX_6] =  { AFE_PORT_ID_QUINARY_TDM_TX_6,
+				QUINARY_TDM_TX_6, 0, 1},
+	[QUINARY_TDM_RX_7] =  { AFE_PORT_ID_QUINARY_TDM_RX_7,
+				QUINARY_TDM_RX_7, 1, 1},
+	[QUINARY_TDM_TX_7] =  { AFE_PORT_ID_QUINARY_TDM_TX_7,
+				QUINARY_TDM_TX_7, 0, 1},
+};
+
+static void q6afe_port_free(struct kref *ref)
+{
+	struct q6afe_port *port;
+	struct q6afe *afe;
+	unsigned long flags;
+
+	port = container_of(ref, struct q6afe_port, refcount);
+	afe = port->afe;
+	spin_lock_irqsave(&afe->port_list_lock, flags);
+	list_del(&port->node);
+	spin_unlock_irqrestore(&afe->port_list_lock, flags);
+	kfree(port->scfg);
+	kfree(port);
+}
+
+static struct q6afe_port *q6afe_find_port(struct q6afe *afe, int token)
+{
+	struct q6afe_port *p = NULL;
+	struct q6afe_port *ret = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&afe->port_list_lock, flags);
+	list_for_each_entry(p, &afe->port_list, node)
+		if (p->token == token) {
+			ret = p;
+			kref_get(&p->refcount);
+			break;
+		}
+
+	spin_unlock_irqrestore(&afe->port_list_lock, flags);
+	return ret;
+}
+
+static int q6afe_callback(struct apr_device *adev, struct apr_resp_pkt *data)
+{
+	struct q6afe *afe = dev_get_drvdata(&adev->dev);
+	struct aprv2_ibasic_rsp_result_t *res;
+	struct apr_hdr *hdr = &data->hdr;
+	struct q6afe_port *port;
+
+	if (!data->payload_size)
+		return 0;
+
+	res = data->payload;
+	switch (hdr->opcode) {
+	case APR_BASIC_RSP_RESULT: {
+		if (res->status) {
+			dev_err(afe->dev, "cmd = 0x%x returned error = 0x%x\n",
+				res->opcode, res->status);
+		}
+		switch (res->opcode) {
+		case AFE_PORT_CMD_SET_PARAM_V2:
+		case AFE_PORT_CMD_DEVICE_STOP:
+		case AFE_PORT_CMD_DEVICE_START:
+		case AFE_SVC_CMD_SET_PARAM:
+			port = q6afe_find_port(afe, hdr->token);
+			if (port) {
+				port->result = *res;
+				wake_up(&port->wait);
+				kref_put(&port->refcount, q6afe_port_free);
+			}
+			break;
+		default:
+			dev_err(afe->dev, "Unknown cmd 0x%x\n",	res->opcode);
+			break;
+		}
+	}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * q6afe_get_port_id() - Get port id from a given port index
+ *
+ * @index: port index
+ *
+ * Return: Will be an negative on error or valid port_id on success
+ */
+int q6afe_get_port_id(int index)
+{
+	if (index < 0 || index > AFE_PORT_MAX)
+		return -EINVAL;
+
+	return port_maps[index].port_id;
+}
+EXPORT_SYMBOL_GPL(q6afe_get_port_id);
+
+static int afe_apr_send_pkt(struct q6afe *afe, struct apr_pkt *pkt,
+			    struct q6afe_port *port)
+{
+	wait_queue_head_t *wait = &port->wait;
+	struct apr_hdr *hdr = &pkt->hdr;
+	int ret;
+
+	mutex_lock(&afe->lock);
+	port->result.opcode = 0;
+	port->result.status = 0;
+
+	ret = apr_send_pkt(afe->apr, pkt);
+	if (ret < 0) {
+		dev_err(afe->dev, "packet not transmitted (%d)\n", ret);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = wait_event_timeout(*wait, (port->result.opcode == hdr->opcode),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		ret = -ETIMEDOUT;
+	} else if (port->result.status > 0) {
+		dev_err(afe->dev, "DSP returned error[%x]\n",
+			port->result.status);
+		ret = -EINVAL;
+	} else {
+		ret = 0;
+	}
+
+err:
+	mutex_unlock(&afe->lock);
+
+	return ret;
+}
+
+static int q6afe_port_set_param(struct q6afe_port *port, void *data,
+				int param_id, int module_id, int psize)
+{
+	struct afe_svc_cmd_set_param *param;
+	struct afe_port_param_data_v2 *pdata;
+	struct q6afe *afe = port->afe;
+	struct apr_pkt *pkt;
+	u16 port_id = port->id;
+	int ret, pkt_size;
+	void *p, *pl;
+
+	pkt_size = APR_HDR_SIZE + sizeof(*param) + sizeof(*pdata) + psize;
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	param = p + APR_HDR_SIZE;
+	pdata = p + APR_HDR_SIZE + sizeof(*param);
+	pl = p + APR_HDR_SIZE + sizeof(*param) + sizeof(*pdata);
+	memcpy(pl, data, psize);
+
+	pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					   APR_HDR_LEN(APR_HDR_SIZE),
+					   APR_PKT_VER);
+	pkt->hdr.pkt_size = pkt_size;
+	pkt->hdr.src_port = 0;
+	pkt->hdr.dest_port = 0;
+	pkt->hdr.token = port->token;
+	pkt->hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+	param->payload_size = sizeof(*pdata) + psize;
+	param->payload_address_lsw = 0x00;
+	param->payload_address_msw = 0x00;
+	param->mem_map_handle = 0x00;
+	pdata->module_id = module_id;
+	pdata->param_id = param_id;
+	pdata->param_size = psize;
+
+	ret = afe_apr_send_pkt(afe, pkt, port);
+	if (ret)
+		dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
+		       port_id, ret);
+
+	kfree(pkt);
+	return ret;
+}
+
+static int q6afe_port_set_param_v2(struct q6afe_port *port, void *data,
+				   int param_id, int module_id, int psize)
+{
+	struct afe_port_cmd_set_param_v2 *param;
+	struct afe_port_param_data_v2 *pdata;
+	struct q6afe *afe = port->afe;
+	struct apr_pkt *pkt;
+	u16 port_id = port->id;
+	int ret, pkt_size;
+	void *p, *pl;
+
+	pkt_size = APR_HDR_SIZE + sizeof(*param) + sizeof(*pdata) + psize;
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	param = p + APR_HDR_SIZE;
+	pdata = p + APR_HDR_SIZE + sizeof(*param);
+	pl = p + APR_HDR_SIZE + sizeof(*param) + sizeof(*pdata);
+	memcpy(pl, data, psize);
+
+	pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					   APR_HDR_LEN(APR_HDR_SIZE),
+					   APR_PKT_VER);
+	pkt->hdr.pkt_size = pkt_size;
+	pkt->hdr.src_port = 0;
+	pkt->hdr.dest_port = 0;
+	pkt->hdr.token = port->token;
+	pkt->hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+
+	param->port_id = port_id;
+	param->payload_size = sizeof(*pdata) + psize;
+	param->payload_address_lsw = 0x00;
+	param->payload_address_msw = 0x00;
+	param->mem_map_handle = 0x00;
+	pdata->module_id = module_id;
+	pdata->param_id = param_id;
+	pdata->param_size = psize;
+
+	ret = afe_apr_send_pkt(afe, pkt, port);
+	if (ret)
+		dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
+		       port_id, ret);
+
+	kfree(pkt);
+	return ret;
+}
+
+static int q6afe_set_lpass_clock(struct q6afe_port *port,
+				 struct afe_clk_cfg *cfg)
+{
+	return q6afe_port_set_param_v2(port, cfg,
+				       AFE_PARAM_ID_LPAIF_CLK_CONFIG,
+				       AFE_MODULE_AUDIO_DEV_INTERFACE,
+				       sizeof(*cfg));
+}
+
+static int q6afe_set_lpass_clock_v2(struct q6afe_port *port,
+				 struct afe_clk_set *cfg)
+{
+	return q6afe_port_set_param(port, cfg, AFE_PARAM_ID_CLOCK_SET,
+				    AFE_MODULE_CLOCK_SET, sizeof(*cfg));
+}
+
+static int q6afe_set_digital_codec_core_clock(struct q6afe_port *port,
+					      struct afe_digital_clk_cfg *cfg)
+{
+	return q6afe_port_set_param_v2(port, cfg,
+				       AFE_PARAM_ID_INT_DIGITAL_CDC_CLK_CONFIG,
+				       AFE_MODULE_AUDIO_DEV_INTERFACE,
+				       sizeof(*cfg));
+}
+
+int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id,
+			  int clk_src, int clk_root,
+			  unsigned int freq, int dir)
+{
+	struct afe_clk_cfg ccfg = {0,};
+	struct afe_clk_set cset = {0,};
+	struct afe_digital_clk_cfg dcfg = {0,};
+	int ret;
+
+	switch (clk_id) {
+	case LPAIF_DIG_CLK:
+		dcfg.i2s_cfg_minor_version = AFE_API_VERSION_I2S_CONFIG;
+		dcfg.clk_val = freq;
+		dcfg.clk_root = clk_root;
+		ret = q6afe_set_digital_codec_core_clock(port, &dcfg);
+		break;
+	case LPAIF_BIT_CLK:
+		ccfg.i2s_cfg_minor_version = AFE_API_VERSION_I2S_CONFIG;
+		ccfg.clk_val1 = freq;
+		ccfg.clk_src = clk_src;
+		ccfg.clk_root = clk_root;
+		ccfg.clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID;
+		ret = q6afe_set_lpass_clock(port, &ccfg);
+		break;
+
+	case LPAIF_OSR_CLK:
+		ccfg.i2s_cfg_minor_version = AFE_API_VERSION_I2S_CONFIG;
+		ccfg.clk_val2 = freq;
+		ccfg.clk_src = clk_src;
+		ccfg.clk_root = clk_root;
+		ccfg.clk_set_mode = Q6AFE_LPASS_MODE_CLK2_VALID;
+		ret = q6afe_set_lpass_clock(port, &ccfg);
+		break;
+	case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR:
+	case Q6AFE_LPASS_CLK_ID_MCLK_1 ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1:
+	case Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT ... Q6AFE_LPASS_CLK_ID_QUIN_TDM_EBIT:
+		cset.clk_set_minor_version = AFE_API_VERSION_CLOCK_SET;
+		cset.clk_id = clk_id;
+		cset.clk_freq_in_hz = freq;
+		cset.clk_attri = clk_src;
+		cset.clk_root = clk_root;
+		cset.enable = !!freq;
+		ret = q6afe_set_lpass_clock_v2(port, &cset);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(q6afe_port_set_sysclk);
+
+/**
+ * q6afe_port_stop() - Stop a afe port
+ *
+ * @port: Instance of port to stop
+ *
+ * Return: Will be an negative on packet size on success.
+ */
+int q6afe_port_stop(struct q6afe_port *port)
+{
+	struct afe_port_cmd_device_stop *stop;
+	struct q6afe *afe = port->afe;
+	struct apr_pkt *pkt;
+	int port_id = port->id;
+	int ret = 0;
+	int index, pkt_size;
+	void *p;
+
+	port_id = port->id;
+	index = port->token;
+	if (index < 0 || index > AFE_PORT_MAX) {
+		dev_err(afe->dev, "AFE port index[%d] invalid!\n", index);
+		return -EINVAL;
+	}
+
+	pkt_size = APR_HDR_SIZE + sizeof(*stop);
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	stop = p + APR_HDR_SIZE;
+
+	pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					   APR_HDR_LEN(APR_HDR_SIZE),
+					   APR_PKT_VER);
+	pkt->hdr.pkt_size = pkt_size;
+	pkt->hdr.src_port = 0;
+	pkt->hdr.dest_port = 0;
+	pkt->hdr.token = index;
+	pkt->hdr.opcode = AFE_PORT_CMD_DEVICE_STOP;
+	stop->port_id = port_id;
+	stop->reserved = 0;
+
+	ret = afe_apr_send_pkt(afe, pkt, port);
+	if (ret)
+		dev_err(afe->dev, "AFE close failed %d\n", ret);
+
+	kfree(pkt);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(q6afe_port_stop);
+
+/**
+ * q6afe_slim_port_prepare() - Prepare slim afe port.
+ *
+ * @port: Instance of afe port
+ * @cfg: SLIM configuration for the afe port
+ *
+ */
+void q6afe_slim_port_prepare(struct q6afe_port *port,
+			     struct q6afe_slim_cfg *cfg)
+{
+	union afe_port_config *pcfg = &port->port_cfg;
+
+	pcfg->slim_cfg.sb_cfg_minor_version = AFE_API_VERSION_SLIMBUS_CONFIG;
+	pcfg->slim_cfg.sample_rate = cfg->sample_rate;
+	pcfg->slim_cfg.bit_width = cfg->bit_width;
+	pcfg->slim_cfg.num_channels = cfg->num_channels;
+	pcfg->slim_cfg.data_format = cfg->data_format;
+	pcfg->slim_cfg.shared_ch_mapping[0] = cfg->ch_mapping[0];
+	pcfg->slim_cfg.shared_ch_mapping[1] = cfg->ch_mapping[1];
+	pcfg->slim_cfg.shared_ch_mapping[2] = cfg->ch_mapping[2];
+	pcfg->slim_cfg.shared_ch_mapping[3] = cfg->ch_mapping[3];
+
+}
+EXPORT_SYMBOL_GPL(q6afe_slim_port_prepare);
+
+/**
+ * q6afe_tdm_port_prepare() - Prepare tdm afe port.
+ *
+ * @port: Instance of afe port
+ * @cfg: TDM configuration for the afe port
+ *
+ */
+void q6afe_tdm_port_prepare(struct q6afe_port *port,
+			     struct q6afe_tdm_cfg *cfg)
+{
+	union afe_port_config *pcfg = &port->port_cfg;
+
+	pcfg->tdm_cfg.tdm_cfg_minor_version = AFE_API_VERSION_TDM_CONFIG;
+	pcfg->tdm_cfg.num_channels = cfg->num_channels;
+	pcfg->tdm_cfg.sample_rate = cfg->sample_rate;
+	pcfg->tdm_cfg.bit_width = cfg->bit_width;
+	pcfg->tdm_cfg.data_format = cfg->data_format;
+	pcfg->tdm_cfg.sync_mode = cfg->sync_mode;
+	pcfg->tdm_cfg.sync_src = cfg->sync_src;
+	pcfg->tdm_cfg.nslots_per_frame = cfg->nslots_per_frame;
+
+	pcfg->tdm_cfg.slot_width = cfg->slot_width;
+	pcfg->tdm_cfg.slot_mask = cfg->slot_mask;
+	port->scfg = kzalloc(sizeof(*port->scfg), GFP_KERNEL);
+	if (!port->scfg)
+		return;
+
+	port->scfg->minor_version = AFE_API_VERSION_SLOT_MAPPING_CONFIG;
+	port->scfg->num_channels = cfg->num_channels;
+	port->scfg->bitwidth = cfg->bit_width;
+	port->scfg->data_align_type = cfg->data_align_type;
+	memcpy(port->scfg->ch_mapping, cfg->ch_mapping,
+			sizeof(u16) * AFE_PORT_MAX_AUDIO_CHAN_CNT);
+}
+EXPORT_SYMBOL_GPL(q6afe_tdm_port_prepare);
+
+/**
+ * q6afe_hdmi_port_prepare() - Prepare hdmi afe port.
+ *
+ * @port: Instance of afe port
+ * @cfg: HDMI configuration for the afe port
+ *
+ */
+void q6afe_hdmi_port_prepare(struct q6afe_port *port,
+			     struct q6afe_hdmi_cfg *cfg)
+{
+	union afe_port_config *pcfg = &port->port_cfg;
+
+	pcfg->hdmi_multi_ch.hdmi_cfg_minor_version =
+					AFE_API_VERSION_HDMI_CONFIG;
+	pcfg->hdmi_multi_ch.datatype = cfg->datatype;
+	pcfg->hdmi_multi_ch.channel_allocation = cfg->channel_allocation;
+	pcfg->hdmi_multi_ch.sample_rate = cfg->sample_rate;
+	pcfg->hdmi_multi_ch.bit_width = cfg->bit_width;
+}
+EXPORT_SYMBOL_GPL(q6afe_hdmi_port_prepare);
+
+/**
+ * q6afe_i2s_port_prepare() - Prepare i2s afe port.
+ *
+ * @port: Instance of afe port
+ * @cfg: I2S configuration for the afe port
+ * Return: Will be an negative on error and zero on success.
+ */
+int q6afe_i2s_port_prepare(struct q6afe_port *port, struct q6afe_i2s_cfg *cfg)
+{
+	union afe_port_config *pcfg = &port->port_cfg;
+	struct device *dev = port->afe->dev;
+	int num_sd_lines;
+
+	pcfg->i2s_cfg.i2s_cfg_minor_version = AFE_API_VERSION_I2S_CONFIG;
+	pcfg->i2s_cfg.sample_rate = cfg->sample_rate;
+	pcfg->i2s_cfg.bit_width = cfg->bit_width;
+	pcfg->i2s_cfg.data_format = AFE_LINEAR_PCM_DATA;
+
+	switch (cfg->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		pcfg->i2s_cfg.ws_src = AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* CPU is slave */
+		pcfg->i2s_cfg.ws_src = AFE_PORT_CONFIG_I2S_WS_SRC_EXTERNAL;
+		break;
+	default:
+		break;
+	}
+
+	num_sd_lines = hweight_long(cfg->sd_line_mask);
+
+	switch (num_sd_lines) {
+	case 0:
+		dev_err(dev, "no line is assigned\n");
+		return -EINVAL;
+	case 1:
+		switch (cfg->sd_line_mask) {
+		case AFE_PORT_I2S_SD0_MASK:
+			pcfg->i2s_cfg.channel_mode = AFE_PORT_I2S_SD0;
+			break;
+		case AFE_PORT_I2S_SD1_MASK:
+			pcfg->i2s_cfg.channel_mode = AFE_PORT_I2S_SD1;
+			break;
+		case AFE_PORT_I2S_SD2_MASK:
+			pcfg->i2s_cfg.channel_mode = AFE_PORT_I2S_SD2;
+			break;
+		case AFE_PORT_I2S_SD3_MASK:
+			pcfg->i2s_cfg.channel_mode = AFE_PORT_I2S_SD3;
+			break;
+		default:
+			dev_err(dev, "Invalid SD lines\n");
+			return -EINVAL;
+		}
+		break;
+	case 2:
+		switch (cfg->sd_line_mask) {
+		case AFE_PORT_I2S_SD0_1_MASK:
+			pcfg->i2s_cfg.channel_mode = AFE_PORT_I2S_QUAD01;
+			break;
+		case AFE_PORT_I2S_SD2_3_MASK:
+			pcfg->i2s_cfg.channel_mode = AFE_PORT_I2S_QUAD23;
+			break;
+		default:
+			dev_err(dev, "Invalid SD lines\n");
+			return -EINVAL;
+		}
+		break;
+	case 3:
+		switch (cfg->sd_line_mask) {
+		case AFE_PORT_I2S_SD0_1_2_MASK:
+			pcfg->i2s_cfg.channel_mode = AFE_PORT_I2S_6CHS;
+			break;
+		default:
+			dev_err(dev, "Invalid SD lines\n");
+			return -EINVAL;
+		}
+		break;
+	case 4:
+		switch (cfg->sd_line_mask) {
+		case AFE_PORT_I2S_SD0_1_2_3_MASK:
+			pcfg->i2s_cfg.channel_mode = AFE_PORT_I2S_8CHS;
+
+			break;
+		default:
+			dev_err(dev, "Invalid SD lines\n");
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(dev, "Invalid SD lines\n");
+		return -EINVAL;
+	}
+
+	switch (cfg->num_channels) {
+	case 1:
+	case 2:
+		switch (pcfg->i2s_cfg.channel_mode) {
+		case AFE_PORT_I2S_QUAD01:
+		case AFE_PORT_I2S_6CHS:
+		case AFE_PORT_I2S_8CHS:
+			pcfg->i2s_cfg.channel_mode = AFE_PORT_I2S_SD0;
+			break;
+		case AFE_PORT_I2S_QUAD23:
+				pcfg->i2s_cfg.channel_mode = AFE_PORT_I2S_SD2;
+			break;
+		}
+
+		if (cfg->num_channels == 2)
+			pcfg->i2s_cfg.mono_stereo = AFE_PORT_I2S_STEREO;
+		else
+			pcfg->i2s_cfg.mono_stereo = AFE_PORT_I2S_MONO;
+
+		break;
+	case 3:
+	case 4:
+		if (pcfg->i2s_cfg.channel_mode < AFE_PORT_I2S_QUAD01) {
+			dev_err(dev, "Invalid Channel mode\n");
+			return -EINVAL;
+		}
+		break;
+	case 5:
+	case 6:
+		if (pcfg->i2s_cfg.channel_mode < AFE_PORT_I2S_6CHS) {
+			dev_err(dev, "Invalid Channel mode\n");
+			return -EINVAL;
+		}
+		break;
+	case 7:
+	case 8:
+		if (pcfg->i2s_cfg.channel_mode < AFE_PORT_I2S_8CHS) {
+			dev_err(dev, "Invalid Channel mode\n");
+			return -EINVAL;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(q6afe_i2s_port_prepare);
+
+/**
+ * q6afe_port_start() - Start a afe port
+ *
+ * @port: Instance of port to start
+ *
+ * Return: Will be an negative on packet size on success.
+ */
+int q6afe_port_start(struct q6afe_port *port)
+{
+	struct afe_port_cmd_device_start *start;
+	struct q6afe *afe = port->afe;
+	int port_id = port->id;
+	int ret, param_id = port->cfg_type;
+	struct apr_pkt *pkt;
+	int pkt_size;
+	void *p;
+
+	ret  = q6afe_port_set_param_v2(port, &port->port_cfg, param_id,
+				       AFE_MODULE_AUDIO_DEV_INTERFACE,
+				       sizeof(port->port_cfg));
+	if (ret) {
+		dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
+			port_id, ret);
+		return ret;
+	}
+
+	if (port->scfg) {
+		ret  = q6afe_port_set_param_v2(port, port->scfg,
+					AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG,
+					AFE_MODULE_TDM, sizeof(*port->scfg));
+		if (ret) {
+			dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
+			port_id, ret);
+			return ret;
+		}
+	}
+
+	pkt_size = APR_HDR_SIZE + sizeof(*start);
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	start = p + APR_HDR_SIZE;
+
+	pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					    APR_HDR_LEN(APR_HDR_SIZE),
+					    APR_PKT_VER);
+	pkt->hdr.pkt_size = pkt_size;
+	pkt->hdr.src_port = 0;
+	pkt->hdr.dest_port = 0;
+	pkt->hdr.token = port->token;
+	pkt->hdr.opcode = AFE_PORT_CMD_DEVICE_START;
+
+	start->port_id = port_id;
+
+	ret = afe_apr_send_pkt(afe, pkt, port);
+	if (ret)
+		dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
+			port_id, ret);
+
+	kfree(pkt);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(q6afe_port_start);
+
+/**
+ * q6afe_port_get_from_id() - Get port instance from a port id
+ *
+ * @dev: Pointer to afe child device.
+ * @id: port id
+ *
+ * Return: Will be an error pointer on error or a valid afe port
+ * on success.
+ */
+struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
+{
+	int port_id;
+	struct q6afe *afe = dev_get_drvdata(dev->parent);
+	struct q6afe_port *port;
+	unsigned long flags;
+	int cfg_type;
+
+	if (id < 0 || id > AFE_PORT_MAX) {
+		dev_err(dev, "AFE port token[%d] invalid!\n", id);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* if port is multiple times bind/unbind before callback finishes */
+	port = q6afe_find_port(afe, id);
+	if (port) {
+		dev_err(dev, "AFE Port already open\n");
+		return port;
+	}
+
+	port_id = port_maps[id].port_id;
+
+	switch (port_id) {
+	case AFE_PORT_ID_MULTICHAN_HDMI_RX:
+		cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
+		break;
+	case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX:
+	case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX:
+	case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX:
+	case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_RX:
+	case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX:
+	case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX:
+	case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX:
+		cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
+		break;
+
+	case AFE_PORT_ID_PRIMARY_MI2S_RX:
+	case AFE_PORT_ID_PRIMARY_MI2S_TX:
+	case AFE_PORT_ID_SECONDARY_MI2S_RX:
+	case AFE_PORT_ID_SECONDARY_MI2S_TX:
+	case AFE_PORT_ID_TERTIARY_MI2S_RX:
+	case AFE_PORT_ID_TERTIARY_MI2S_TX:
+	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+		cfg_type = AFE_PARAM_ID_I2S_CONFIG;
+		break;
+	case AFE_PORT_ID_PRIMARY_TDM_RX ... AFE_PORT_ID_QUINARY_TDM_TX_7:
+		cfg_type = AFE_PARAM_ID_TDM_CONFIG;
+		break;
+
+	default:
+		dev_err(dev, "Invalid port id 0x%x\n", port_id);
+		return ERR_PTR(-EINVAL);
+	}
+
+	port = kzalloc(sizeof(*port), GFP_KERNEL);
+	if (!port)
+		return ERR_PTR(-ENOMEM);
+
+	init_waitqueue_head(&port->wait);
+
+	port->token = id;
+	port->id = port_id;
+	port->afe = afe;
+	port->cfg_type = cfg_type;
+	kref_init(&port->refcount);
+
+	spin_lock_irqsave(&afe->port_list_lock, flags);
+	list_add_tail(&port->node, &afe->port_list);
+	spin_unlock_irqrestore(&afe->port_list_lock, flags);
+
+	return port;
+
+}
+EXPORT_SYMBOL_GPL(q6afe_port_get_from_id);
+
+/**
+ * q6afe_port_put() - Release port reference
+ *
+ * @port: Instance of port to put
+ */
+void q6afe_port_put(struct q6afe_port *port)
+{
+	kref_put(&port->refcount, q6afe_port_free);
+}
+EXPORT_SYMBOL_GPL(q6afe_port_put);
+
+static int q6afe_probe(struct apr_device *adev)
+{
+	struct q6afe *afe;
+	struct device *dev = &adev->dev;
+	struct device_node *dais_np;
+
+	afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL);
+	if (!afe)
+		return -ENOMEM;
+
+	q6core_get_svc_api_info(adev->svc_id, &afe->ainfo);
+	afe->apr = adev;
+	mutex_init(&afe->lock);
+	afe->dev = dev;
+	INIT_LIST_HEAD(&afe->port_list);
+	spin_lock_init(&afe->port_list_lock);
+
+	dev_set_drvdata(dev, afe);
+
+	dais_np = of_get_child_by_name(dev->of_node, "dais");
+	if (dais_np) {
+		afe->pdev_dais = of_platform_device_create(dais_np,
+							   "q6afe-dai", dev);
+		of_node_put(dais_np);
+	}
+
+	return 0;
+}
+
+static int q6afe_remove(struct apr_device *adev)
+{
+	struct q6afe *afe = dev_get_drvdata(&adev->dev);
+
+	if (afe->pdev_dais)
+		of_platform_device_destroy(&afe->pdev_dais->dev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id q6afe_device_id[]  = {
+	{ .compatible = "qcom,q6afe" },
+	{},
+};
+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",
+		.of_match_table = of_match_ptr(q6afe_device_id),
+
+	},
+};
+
+module_apr_driver(qcom_q6afe_driver);
+MODULE_DESCRIPTION("Q6 Audio Front End");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h
new file mode 100644
index 000000000000..c7ed5422baff
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6afe.h
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __Q6AFE_H__
+#define __Q6AFE_H__
+
+#include <dt-bindings/sound/qcom,q6afe.h>
+
+#define AFE_PORT_MAX		105
+
+#define MSM_AFE_PORT_TYPE_RX 0
+#define MSM_AFE_PORT_TYPE_TX 1
+#define AFE_MAX_PORTS AFE_PORT_MAX
+
+#define Q6AFE_MAX_MI2S_LINES	4
+
+#define AFE_MAX_CHAN_COUNT	8
+#define AFE_PORT_MAX_AUDIO_CHAN_CNT	0x8
+
+#define Q6AFE_LPASS_CLK_SRC_INTERNAL 1
+#define Q6AFE_LPASS_CLK_ROOT_DEFAULT 0
+
+#define LPAIF_DIG_CLK	1
+#define LPAIF_BIT_CLK	2
+#define LPAIF_OSR_CLK	3
+
+/* Clock ID for Primary I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT                          0x100
+/* Clock ID for Primary I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT                          0x101
+/* Clock ID for Secondary I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT                          0x102
+/* Clock ID for Secondary I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT                          0x103
+/* Clock ID for Tertiary I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT                          0x104
+/* Clock ID for Tertiary I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT                          0x105
+/* Clock ID for Quartnery I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT                         0x106
+/* Clock ID for Quartnery I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT                         0x107
+/* Clock ID for Speaker I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_IBIT                       0x108
+/* Clock ID for Speaker I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_EBIT                       0x109
+/* Clock ID for Speaker I2S OSR */
+#define Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR                        0x10A
+
+/* Clock ID for QUINARY  I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT			0x10B
+/* Clock ID for QUINARY  I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_QUI_MI2S_EBIT			0x10C
+/* Clock ID for SENARY  I2S IBIT */
+#define Q6AFE_LPASS_CLK_ID_SEN_MI2S_IBIT			0x10D
+/* Clock ID for SENARY  I2S EBIT */
+#define Q6AFE_LPASS_CLK_ID_SEN_MI2S_EBIT			0x10E
+/* Clock ID for INT0 I2S IBIT  */
+#define Q6AFE_LPASS_CLK_ID_INT0_MI2S_IBIT                       0x10F
+/* Clock ID for INT1 I2S IBIT  */
+#define Q6AFE_LPASS_CLK_ID_INT1_MI2S_IBIT                       0x110
+/* Clock ID for INT2 I2S IBIT  */
+#define Q6AFE_LPASS_CLK_ID_INT2_MI2S_IBIT                       0x111
+/* Clock ID for INT3 I2S IBIT  */
+#define Q6AFE_LPASS_CLK_ID_INT3_MI2S_IBIT                       0x112
+/* Clock ID for INT4 I2S IBIT  */
+#define Q6AFE_LPASS_CLK_ID_INT4_MI2S_IBIT                       0x113
+/* Clock ID for INT5 I2S IBIT  */
+#define Q6AFE_LPASS_CLK_ID_INT5_MI2S_IBIT                       0x114
+/* Clock ID for INT6 I2S IBIT  */
+#define Q6AFE_LPASS_CLK_ID_INT6_MI2S_IBIT                       0x115
+
+/* Clock ID for QUINARY MI2S OSR CLK  */
+#define Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR                         0x116
+
+/* Clock ID for Primary PCM IBIT */
+#define Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT                           0x200
+/* Clock ID for Primary PCM EBIT */
+#define Q6AFE_LPASS_CLK_ID_PRI_PCM_EBIT                           0x201
+/* Clock ID for Secondary PCM IBIT */
+#define Q6AFE_LPASS_CLK_ID_SEC_PCM_IBIT                           0x202
+/* Clock ID for Secondary PCM EBIT */
+#define Q6AFE_LPASS_CLK_ID_SEC_PCM_EBIT                           0x203
+/* Clock ID for Tertiary PCM IBIT */
+#define Q6AFE_LPASS_CLK_ID_TER_PCM_IBIT                           0x204
+/* Clock ID for Tertiary PCM EBIT */
+#define Q6AFE_LPASS_CLK_ID_TER_PCM_EBIT                           0x205
+/* Clock ID for Quartery PCM IBIT */
+#define Q6AFE_LPASS_CLK_ID_QUAD_PCM_IBIT                          0x206
+/* Clock ID for Quartery PCM EBIT */
+#define Q6AFE_LPASS_CLK_ID_QUAD_PCM_EBIT                          0x207
+/* Clock ID for Quinary PCM IBIT */
+#define Q6AFE_LPASS_CLK_ID_QUIN_PCM_IBIT                          0x208
+/* Clock ID for Quinary PCM EBIT */
+#define Q6AFE_LPASS_CLK_ID_QUIN_PCM_EBIT                          0x209
+/* Clock ID for QUINARY PCM OSR  */
+#define Q6AFE_LPASS_CLK_ID_QUI_PCM_OSR                            0x20A
+
+/** Clock ID for Primary TDM IBIT */
+#define Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT                           0x200
+/** Clock ID for Primary TDM EBIT */
+#define Q6AFE_LPASS_CLK_ID_PRI_TDM_EBIT                           0x201
+/** Clock ID for Secondary TDM IBIT */
+#define Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT                           0x202
+/** Clock ID for Secondary TDM EBIT */
+#define Q6AFE_LPASS_CLK_ID_SEC_TDM_EBIT                           0x203
+/** Clock ID for Tertiary TDM IBIT */
+#define Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT                           0x204
+/** Clock ID for Tertiary TDM EBIT */
+#define Q6AFE_LPASS_CLK_ID_TER_TDM_EBIT                           0x205
+/** Clock ID for Quartery TDM IBIT */
+#define Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT                          0x206
+/** Clock ID for Quartery TDM EBIT */
+#define Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT                          0x207
+/** Clock ID for Quinary TDM IBIT */
+#define Q6AFE_LPASS_CLK_ID_QUIN_TDM_IBIT                          0x208
+/** Clock ID for Quinary TDM EBIT */
+#define Q6AFE_LPASS_CLK_ID_QUIN_TDM_EBIT                          0x209
+/** Clock ID for Quinary TDM OSR */
+#define Q6AFE_LPASS_CLK_ID_QUIN_TDM_OSR                           0x20A
+
+/* Clock ID for MCLK1 */
+#define Q6AFE_LPASS_CLK_ID_MCLK_1                                 0x300
+/* Clock ID for MCLK2 */
+#define Q6AFE_LPASS_CLK_ID_MCLK_2                                 0x301
+/* Clock ID for MCLK3 */
+#define Q6AFE_LPASS_CLK_ID_MCLK_3                                 0x302
+/* Clock ID for MCLK4 */
+#define Q6AFE_LPASS_CLK_ID_MCLK_4                                 0x304
+/* Clock ID for Internal Digital Codec Core */
+#define Q6AFE_LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE            0x303
+/* Clock ID for INT MCLK0 */
+#define Q6AFE_LPASS_CLK_ID_INT_MCLK_0                             0x305
+/* Clock ID for INT MCLK1 */
+#define Q6AFE_LPASS_CLK_ID_INT_MCLK_1                             0x306
+
+/* Clock attribute for invalid use (reserved for internal usage) */
+#define Q6AFE_LPASS_CLK_ATTRIBUTE_INVALID		0x0
+/* Clock attribute for no couple case */
+#define Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO		0x1
+/* Clock attribute for dividend couple case */
+#define Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND	0x2
+/* Clock attribute for divisor couple case */
+#define Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR	0x3
+/* Clock attribute for invert and no couple case */
+#define Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO	0x4
+
+#define Q6AFE_CMAP_INVALID		0xFFFF
+
+struct q6afe_hdmi_cfg {
+	u16                  datatype;
+	u16                  channel_allocation;
+	u32                  sample_rate;
+	u16                  bit_width;
+};
+
+struct q6afe_slim_cfg {
+	u32	sample_rate;
+	u16	bit_width;
+	u16	data_format;
+	u16	num_channels;
+	u8	ch_mapping[AFE_MAX_CHAN_COUNT];
+};
+
+struct q6afe_i2s_cfg {
+	u32	sample_rate;
+	u16	bit_width;
+	u16	data_format;
+	u16	num_channels;
+	u32	sd_line_mask;
+	int fmt;
+};
+
+struct q6afe_tdm_cfg {
+	u16	num_channels;
+	u32	sample_rate;
+	u16	bit_width;
+	u16	data_format;
+	u16	sync_mode;
+	u16	sync_src;
+	u16	nslots_per_frame;
+	u16	slot_width;
+	u16	slot_mask;
+	u32	data_align_type;
+	u16	ch_mapping[AFE_MAX_CHAN_COUNT];
+};
+
+struct q6afe_port_config {
+	struct q6afe_hdmi_cfg hdmi;
+	struct q6afe_slim_cfg slim;
+	struct q6afe_i2s_cfg i2s_cfg;
+	struct q6afe_tdm_cfg tdm;
+};
+
+struct q6afe_port;
+
+struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id);
+int q6afe_port_start(struct q6afe_port *port);
+int q6afe_port_stop(struct q6afe_port *port);
+void q6afe_port_put(struct q6afe_port *port);
+int q6afe_get_port_id(int index);
+void q6afe_hdmi_port_prepare(struct q6afe_port *port,
+			    struct q6afe_hdmi_cfg *cfg);
+void q6afe_slim_port_prepare(struct q6afe_port *port,
+			  struct q6afe_slim_cfg *cfg);
+int q6afe_i2s_port_prepare(struct q6afe_port *port, struct q6afe_i2s_cfg *cfg);
+void q6afe_tdm_port_prepare(struct q6afe_port *port, struct q6afe_tdm_cfg *cfg);
+
+int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id,
+			  int clk_src, int clk_root,
+			  unsigned int freq, int dir);
+#endif /* __Q6AFE_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
new file mode 100644
index 000000000000..349c6a883c63
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -0,0 +1,624 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+// Copyright (c) 2018, Linaro Limited
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/component.h>
+#include <sound/soc.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_device.h>
+#include <sound/pcm_params.h>
+#include "q6asm.h"
+#include "q6routing.h"
+#include "q6dsp-errno.h"
+
+#define DRV_NAME	"q6asm-fe-dai"
+
+#define PLAYBACK_MIN_NUM_PERIODS    2
+#define PLAYBACK_MAX_NUM_PERIODS   8
+#define PLAYBACK_MAX_PERIOD_SIZE    65536
+#define PLAYBACK_MIN_PERIOD_SIZE    128
+#define CAPTURE_MIN_NUM_PERIODS     2
+#define CAPTURE_MAX_NUM_PERIODS     8
+#define CAPTURE_MAX_PERIOD_SIZE     4096
+#define CAPTURE_MIN_PERIOD_SIZE     320
+#define SID_MASK_DEFAULT	0xF
+
+enum stream_state {
+	Q6ASM_STREAM_IDLE = 0,
+	Q6ASM_STREAM_STOPPED,
+	Q6ASM_STREAM_RUNNING,
+};
+
+struct q6asm_dai_rtd {
+	struct snd_pcm_substream *substream;
+	phys_addr_t phys;
+	unsigned int pcm_size;
+	unsigned int pcm_count;
+	unsigned int pcm_irq_pos;       /* IRQ position */
+	unsigned int periods;
+	uint16_t bits_per_sample;
+	uint16_t source; /* Encoding source bit mask */
+	struct audio_client *audio_client;
+	uint16_t session_id;
+	enum stream_state state;
+};
+
+struct q6asm_dai_data {
+	long long int sid;
+};
+
+static struct snd_pcm_hardware q6asm_dai_hardware_capture = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              (SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S24_LE),
+	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         4,
+	.buffer_bytes_max =     CAPTURE_MAX_NUM_PERIODS *
+				CAPTURE_MAX_PERIOD_SIZE,
+	.period_bytes_min =	CAPTURE_MIN_PERIOD_SIZE,
+	.period_bytes_max =     CAPTURE_MAX_PERIOD_SIZE,
+	.periods_min =          CAPTURE_MIN_NUM_PERIODS,
+	.periods_max =          CAPTURE_MAX_NUM_PERIODS,
+	.fifo_size =            0,
+};
+
+static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              (SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S24_LE),
+	.rates =                SNDRV_PCM_RATE_8000_192000,
+	.rate_min =             8000,
+	.rate_max =             192000,
+	.channels_min =         1,
+	.channels_max =         8,
+	.buffer_bytes_max =     (PLAYBACK_MAX_NUM_PERIODS *
+				PLAYBACK_MAX_PERIOD_SIZE),
+	.period_bytes_min =	PLAYBACK_MIN_PERIOD_SIZE,
+	.period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
+	.periods_min =          PLAYBACK_MIN_NUM_PERIODS,
+	.periods_max =          PLAYBACK_MAX_NUM_PERIODS,
+	.fifo_size =            0,
+};
+
+#define Q6ASM_FEDAI_DRIVER(num) { \
+		.playback = {						\
+			.stream_name = "MultiMedia"#num" Playback",	\
+			.rates = (SNDRV_PCM_RATE_8000_192000|		\
+					SNDRV_PCM_RATE_KNOT),		\
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |		\
+					SNDRV_PCM_FMTBIT_S24_LE),	\
+			.channels_min = 1,				\
+			.channels_max = 8,				\
+			.rate_min =     8000,				\
+			.rate_max =	192000,				\
+		},							\
+		.capture = {						\
+			.stream_name = "MultiMedia"#num" Capture",	\
+			.rates = (SNDRV_PCM_RATE_8000_48000|		\
+					SNDRV_PCM_RATE_KNOT),		\
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |		\
+				    SNDRV_PCM_FMTBIT_S24_LE),		\
+			.channels_min = 1,				\
+			.channels_max = 4,				\
+			.rate_min =     8000,				\
+			.rate_max =	48000,				\
+		},							\
+		.name = "MultiMedia"#num,				\
+		.probe = fe_dai_probe,					\
+		.id = MSM_FRONTEND_DAI_MULTIMEDIA##num,			\
+	}
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+	88200, 96000, 176400, 192000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void event_handler(uint32_t opcode, uint32_t token,
+			  uint32_t *payload, void *priv)
+{
+	struct q6asm_dai_rtd *prtd = priv;
+	struct snd_pcm_substream *substream = prtd->substream;
+
+	switch (opcode) {
+	case ASM_CLIENT_EVENT_CMD_RUN_DONE:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			q6asm_write_async(prtd->audio_client,
+				   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+		break;
+	case ASM_CLIENT_EVENT_CMD_EOS_DONE:
+		prtd->state = Q6ASM_STREAM_STOPPED;
+		break;
+	case ASM_CLIENT_EVENT_DATA_WRITE_DONE: {
+		prtd->pcm_irq_pos += prtd->pcm_count;
+		snd_pcm_period_elapsed(substream);
+		if (prtd->state == Q6ASM_STREAM_RUNNING)
+			q6asm_write_async(prtd->audio_client,
+					   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+
+		break;
+		}
+	case ASM_CLIENT_EVENT_DATA_READ_DONE:
+		prtd->pcm_irq_pos += prtd->pcm_count;
+		snd_pcm_period_elapsed(substream);
+		if (prtd->state == Q6ASM_STREAM_RUNNING)
+			q6asm_read(prtd->audio_client);
+
+		break;
+	default:
+		break;
+	}
+}
+
+static int q6asm_dai_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct q6asm_dai_rtd *prtd = runtime->private_data;
+	struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+	struct q6asm_dai_data *pdata;
+	int ret, i;
+
+	pdata = snd_soc_component_get_drvdata(c);
+	if (!pdata)
+		return -EINVAL;
+
+	if (!prtd || !prtd->audio_client) {
+		pr_err("%s: private data null or audio client freed\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	/* rate and channels are sent to audio driver */
+	if (prtd->state) {
+		/* clear the previous setup if any  */
+		q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+		q6asm_unmap_memory_regions(substream->stream,
+					   prtd->audio_client);
+		q6routing_stream_close(soc_prtd->dai_link->id,
+					 substream->stream);
+	}
+
+	ret = q6asm_map_memory_regions(substream->stream, prtd->audio_client,
+				       prtd->phys,
+				       (prtd->pcm_size / prtd->periods),
+				       prtd->periods);
+
+	if (ret < 0) {
+		pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
+							ret);
+		return -ENOMEM;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM,
+				       prtd->bits_per_sample);
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM,
+				       prtd->bits_per_sample);
+	}
+
+	if (ret < 0) {
+		pr_err("%s: q6asm_open_write failed\n", __func__);
+		q6asm_audio_client_free(prtd->audio_client);
+		prtd->audio_client = NULL;
+		return -ENOMEM;
+	}
+
+	prtd->session_id = q6asm_get_session_id(prtd->audio_client);
+	ret = q6routing_stream_open(soc_prtd->dai_link->id, LEGACY_PCM_MODE,
+			      prtd->session_id, substream->stream);
+	if (ret) {
+		pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
+		return ret;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = q6asm_media_format_block_multi_ch_pcm(
+				prtd->audio_client, runtime->rate,
+				runtime->channels, NULL,
+				prtd->bits_per_sample);
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client,
+					runtime->rate, runtime->channels,
+					prtd->bits_per_sample);
+
+		/* Queue the buffers */
+		for (i = 0; i < runtime->periods; i++)
+			q6asm_read(prtd->audio_client);
+
+	}
+	if (ret < 0)
+		pr_info("%s: CMD Format block failed\n", __func__);
+
+	prtd->state = Q6ASM_STREAM_RUNNING;
+
+	return 0;
+}
+
+static int q6asm_dai_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct q6asm_dai_rtd *prtd = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		prtd->state = Q6ASM_STREAM_STOPPED;
+		ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int q6asm_dai_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_prtd->cpu_dai;
+	struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+	struct q6asm_dai_rtd *prtd;
+	struct q6asm_dai_data *pdata;
+	struct device *dev = c->dev;
+	int ret = 0;
+	int stream_id;
+
+	stream_id = cpu_dai->driver->id;
+
+	pdata = snd_soc_component_get_drvdata(c);
+	if (!pdata) {
+		pr_err("Drv data not found ..\n");
+		return -EINVAL;
+	}
+
+	prtd = kzalloc(sizeof(struct q6asm_dai_rtd), GFP_KERNEL);
+	if (prtd == NULL)
+		return -ENOMEM;
+
+	prtd->substream = substream;
+	prtd->audio_client = q6asm_audio_client_alloc(dev,
+				(q6asm_cb)event_handler, prtd, stream_id,
+				LEGACY_PCM_MODE);
+	if (!prtd->audio_client) {
+		pr_info("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		runtime->hw = q6asm_dai_hardware_playback;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		runtime->hw = q6asm_dai_hardware_capture;
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&constraints_sample_rates);
+	if (ret < 0)
+		pr_info("snd_pcm_hw_constraint_list failed\n");
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		pr_info("snd_pcm_hw_constraint_integer failed\n");
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = snd_pcm_hw_constraint_minmax(runtime,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
+			PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
+		if (ret < 0) {
+			pr_err("constraint for buffer bytes min max ret = %d\n",
+									ret);
+		}
+	}
+
+	ret = snd_pcm_hw_constraint_step(runtime, 0,
+		SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+	if (ret < 0) {
+		pr_err("constraint for period bytes step ret = %d\n",
+								ret);
+	}
+	ret = snd_pcm_hw_constraint_step(runtime, 0,
+		SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
+	if (ret < 0) {
+		pr_err("constraint for buffer bytes step ret = %d\n",
+								ret);
+	}
+
+	runtime->private_data = prtd;
+
+	snd_soc_set_runtime_hwparams(substream, &q6asm_dai_hardware_playback);
+
+	runtime->dma_bytes = q6asm_dai_hardware_playback.buffer_bytes_max;
+
+
+	if (pdata->sid < 0)
+		prtd->phys = substream->dma_buffer.addr;
+	else
+		prtd->phys = substream->dma_buffer.addr | (pdata->sid << 32);
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+
+static int q6asm_dai_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct q6asm_dai_rtd *prtd = runtime->private_data;
+
+	if (prtd->audio_client) {
+		q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+		q6asm_unmap_memory_regions(substream->stream,
+					   prtd->audio_client);
+		q6asm_audio_client_free(prtd->audio_client);
+		prtd->audio_client = NULL;
+	}
+	q6routing_stream_close(soc_prtd->dai_link->id,
+						substream->stream);
+	kfree(prtd);
+	return 0;
+}
+
+static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct q6asm_dai_rtd *prtd = runtime->private_data;
+
+	if (prtd->pcm_irq_pos >= prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int q6asm_dai_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+	struct device *dev = c->dev;
+
+	return dma_mmap_coherent(dev, vma,
+			runtime->dma_area, runtime->dma_addr,
+			runtime->dma_bytes);
+}
+
+static int q6asm_dai_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct q6asm_dai_rtd *prtd = runtime->private_data;
+
+	prtd->pcm_size = params_buffer_bytes(params);
+	prtd->periods = params_periods(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		prtd->bits_per_sample = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		prtd->bits_per_sample = 24;
+		break;
+	}
+
+	return 0;
+}
+
+static struct snd_pcm_ops q6asm_dai_ops = {
+	.open           = q6asm_dai_open,
+	.hw_params	= q6asm_dai_hw_params,
+	.close          = q6asm_dai_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.prepare        = q6asm_dai_prepare,
+	.trigger        = q6asm_dai_trigger,
+	.pointer        = q6asm_dai_pointer,
+	.mmap		= q6asm_dai_mmap,
+};
+
+static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm_substream *psubstream, *csubstream;
+	struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct snd_pcm *pcm = rtd->pcm;
+	struct device *dev;
+	int size, ret;
+
+	dev = c->dev;
+	size = q6asm_dai_hardware_playback.buffer_bytes_max;
+	psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	if (psubstream) {
+		ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
+					  &psubstream->dma_buffer);
+		if (ret) {
+			dev_err(dev, "Cannot allocate buffer(s)\n");
+			return ret;
+		}
+	}
+
+	csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+	if (csubstream) {
+		ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
+					  &csubstream->dma_buffer);
+		if (ret) {
+			dev_err(dev, "Cannot allocate buffer(s)\n");
+			if (psubstream)
+				snd_dma_free_pages(&psubstream->dma_buffer);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static void q6asm_dai_pcm_free(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
+		substream = pcm->streams[i].substream;
+		if (substream) {
+			snd_dma_free_pages(&substream->dma_buffer);
+			substream->dma_buffer.area = NULL;
+			substream->dma_buffer.addr = 0;
+		}
+	}
+}
+
+static const struct snd_soc_dapm_route afe_pcm_routes[] = {
+	{"MM_DL1",  NULL, "MultiMedia1 Playback" },
+	{"MM_DL2",  NULL, "MultiMedia2 Playback" },
+	{"MM_DL3",  NULL, "MultiMedia3 Playback" },
+	{"MM_DL4",  NULL, "MultiMedia4 Playback" },
+	{"MM_DL5",  NULL, "MultiMedia5 Playback" },
+	{"MM_DL6",  NULL, "MultiMedia6 Playback" },
+	{"MM_DL7",  NULL, "MultiMedia7 Playback" },
+	{"MM_DL7",  NULL, "MultiMedia8 Playback" },
+	{"MultiMedia1 Capture", NULL, "MM_UL1"},
+	{"MultiMedia2 Capture", NULL, "MM_UL2"},
+	{"MultiMedia3 Capture", NULL, "MM_UL3"},
+	{"MultiMedia4 Capture", NULL, "MM_UL4"},
+	{"MultiMedia5 Capture", NULL, "MM_UL5"},
+	{"MultiMedia6 Capture", NULL, "MM_UL6"},
+	{"MultiMedia7 Capture", NULL, "MM_UL7"},
+	{"MultiMedia8 Capture", NULL, "MM_UL8"},
+
+};
+
+static int fe_dai_probe(struct snd_soc_dai *dai)
+{
+	struct snd_soc_dapm_context *dapm;
+
+	dapm = snd_soc_component_get_dapm(dai->component);
+	snd_soc_dapm_add_routes(dapm, afe_pcm_routes,
+				ARRAY_SIZE(afe_pcm_routes));
+
+	return 0;
+}
+
+
+static const struct snd_soc_component_driver q6asm_fe_dai_component = {
+	.name		= DRV_NAME,
+	.ops		= &q6asm_dai_ops,
+	.pcm_new	= q6asm_dai_pcm_new,
+	.pcm_free	= q6asm_dai_pcm_free,
+
+};
+
+static struct snd_soc_dai_driver q6asm_fe_dais[] = {
+	Q6ASM_FEDAI_DRIVER(1),
+	Q6ASM_FEDAI_DRIVER(2),
+	Q6ASM_FEDAI_DRIVER(3),
+	Q6ASM_FEDAI_DRIVER(4),
+	Q6ASM_FEDAI_DRIVER(5),
+	Q6ASM_FEDAI_DRIVER(6),
+	Q6ASM_FEDAI_DRIVER(7),
+	Q6ASM_FEDAI_DRIVER(8),
+};
+
+static int q6asm_dai_bind(struct device *dev, struct device *master, void *data)
+{
+	struct device_node *node = dev->of_node;
+	struct of_phandle_args args;
+	struct q6asm_dai_data *pdata;
+	int rc;
+
+	pdata = kzalloc(sizeof(struct q6asm_dai_data), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	rc = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args);
+	if (rc < 0)
+		pdata->sid = -1;
+	else
+		pdata->sid = args.args[0] & SID_MASK_DEFAULT;
+
+	dev_set_drvdata(dev, pdata);
+
+	return snd_soc_register_component(dev, &q6asm_fe_dai_component,
+					q6asm_fe_dais,
+					ARRAY_SIZE(q6asm_fe_dais));
+}
+static void q6asm_dai_unbind(struct device *dev, struct device *master,
+			     void *data)
+{
+	struct q6asm_dai_data *pdata = dev_get_drvdata(dev);
+
+	snd_soc_unregister_component(dev);
+
+	kfree(pdata);
+
+}
+
+static const struct component_ops q6asm_dai_comp_ops = {
+	.bind   = q6asm_dai_bind,
+	.unbind = q6asm_dai_unbind,
+};
+
+static int q6asm_dai_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &q6asm_dai_comp_ops);
+}
+
+static int q6asm_dai_dev_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &q6asm_dai_comp_ops);
+	return 0;
+}
+
+static struct platform_driver q6asm_dai_platform_driver = {
+	.driver = {
+		.name = "q6asm-dai",
+	},
+	.probe = q6asm_dai_probe,
+	.remove = q6asm_dai_dev_remove,
+};
+module_platform_driver(q6asm_dai_platform_driver);
+
+MODULE_DESCRIPTION("Q6ASM dai driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
new file mode 100644
index 000000000000..530852385cad
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -0,0 +1,1399 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+// Copyright (c) 2018, Linaro Limited
+
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/soc/qcom/apr.h>
+#include <linux/device.h>
+#include <linux/of_platform.h>
+#include <linux/spinlock.h>
+#include <linux/kref.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <uapi/sound/asound.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include "q6asm.h"
+#include "q6core.h"
+#include "q6dsp-errno.h"
+#include "q6dsp-common.h"
+
+#define ASM_STREAM_CMD_CLOSE			0x00010BCD
+#define ASM_STREAM_CMD_FLUSH			0x00010BCE
+#define ASM_SESSION_CMD_PAUSE			0x00010BD3
+#define ASM_DATA_CMD_EOS			0x00010BDB
+#define ASM_NULL_POPP_TOPOLOGY			0x00010C68
+#define ASM_STREAM_CMD_FLUSH_READBUFS		0x00010C09
+#define ASM_STREAM_CMD_SET_ENCDEC_PARAM		0x00010C10
+#define ASM_STREAM_POSTPROC_TOPO_ID_NONE	0x00010C68
+#define ASM_CMD_SHARED_MEM_MAP_REGIONS		0x00010D92
+#define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS	0x00010D93
+#define ASM_CMD_SHARED_MEM_UNMAP_REGIONS	0x00010D94
+#define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2	0x00010D98
+#define ASM_DATA_EVENT_WRITE_DONE_V2		0x00010D99
+#define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2	0x00010DA3
+#define ASM_SESSION_CMD_RUN_V2			0x00010DAA
+#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2	0x00010DA5
+#define ASM_DATA_CMD_WRITE_V2			0x00010DAB
+#define ASM_DATA_CMD_READ_V2			0x00010DAC
+#define ASM_SESSION_CMD_SUSPEND			0x00010DEC
+#define ASM_STREAM_CMD_OPEN_WRITE_V3		0x00010DB3
+#define ASM_STREAM_CMD_OPEN_READ_V3                 0x00010DB4
+#define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A
+#define ASM_STREAM_CMD_OPEN_READWRITE_V2        0x00010D8D
+
+
+#define ASM_LEGACY_STREAM_SESSION	0
+/* Bit shift for the stream_perf_mode subfield. */
+#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ              29
+#define ASM_END_POINT_DEVICE_MATRIX	0
+#define ASM_DEFAULT_APP_TYPE		0
+#define ASM_SYNC_IO_MODE		0x0001
+#define ASM_ASYNC_IO_MODE		0x0002
+#define ASM_TUN_READ_IO_MODE		0x0004	/* tunnel read write mode */
+#define ASM_TUN_WRITE_IO_MODE		0x0008	/* tunnel read write mode */
+#define ASM_SHIFT_GAPLESS_MODE_FLAG	31
+#define ADSP_MEMORY_MAP_SHMEM8_4K_POOL	3
+
+struct avs_cmd_shared_mem_map_regions {
+	u16 mem_pool_id;
+	u16 num_regions;
+	u32 property_flag;
+} __packed;
+
+struct avs_shared_map_region_payload {
+	u32 shm_addr_lsw;
+	u32 shm_addr_msw;
+	u32 mem_size_bytes;
+} __packed;
+
+struct avs_cmd_shared_mem_unmap_regions {
+	u32 mem_map_handle;
+} __packed;
+
+struct asm_data_cmd_media_fmt_update_v2 {
+	u32 fmt_blk_size;
+} __packed;
+
+struct asm_multi_channel_pcm_fmt_blk_v2 {
+	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
+	u16 num_channels;
+	u16 bits_per_sample;
+	u32 sample_rate;
+	u16 is_signed;
+	u16 reserved;
+	u8 channel_mapping[PCM_MAX_NUM_CHANNEL];
+} __packed;
+
+struct asm_stream_cmd_set_encdec_param {
+	u32                  param_id;
+	u32                  param_size;
+} __packed;
+
+struct asm_enc_cfg_blk_param_v2 {
+	u32                  frames_per_buf;
+	u32                  enc_cfg_blk_size;
+} __packed;
+
+struct asm_multi_channel_pcm_enc_cfg_v2 {
+	struct asm_stream_cmd_set_encdec_param  encdec;
+	struct asm_enc_cfg_blk_param_v2	encblk;
+	uint16_t  num_channels;
+	uint16_t  bits_per_sample;
+	uint32_t  sample_rate;
+	uint16_t  is_signed;
+	uint16_t  reserved;
+	uint8_t   channel_mapping[8];
+} __packed;
+
+struct asm_data_cmd_read_v2 {
+	u32                  buf_addr_lsw;
+	u32                  buf_addr_msw;
+	u32                  mem_map_handle;
+	u32                  buf_size;
+	u32                  seq_id;
+} __packed;
+
+struct asm_data_cmd_read_v2_done {
+	u32	status;
+	u32	buf_addr_lsw;
+	u32	buf_addr_msw;
+};
+
+struct asm_stream_cmd_open_read_v3 {
+	u32                    mode_flags;
+	u32                    src_endpointype;
+	u32                    preprocopo_id;
+	u32                    enc_cfg_id;
+	u16                    bits_per_sample;
+	u16                    reserved;
+} __packed;
+
+struct asm_data_cmd_write_v2 {
+	u32 buf_addr_lsw;
+	u32 buf_addr_msw;
+	u32 mem_map_handle;
+	u32 buf_size;
+	u32 seq_id;
+	u32 timestamp_lsw;
+	u32 timestamp_msw;
+	u32 flags;
+} __packed;
+
+struct asm_stream_cmd_open_write_v3 {
+	uint32_t mode_flags;
+	uint16_t sink_endpointype;
+	uint16_t bits_per_sample;
+	uint32_t postprocopo_id;
+	uint32_t dec_fmt_id;
+} __packed;
+
+struct asm_session_cmd_run_v2 {
+	u32 flags;
+	u32 time_lsw;
+	u32 time_msw;
+} __packed;
+
+struct audio_buffer {
+	phys_addr_t phys;
+	uint32_t size;		/* size of buffer */
+};
+
+struct audio_port_data {
+	struct audio_buffer *buf;
+	uint32_t num_periods;
+	uint32_t dsp_buf;
+	uint32_t mem_map_handle;
+};
+
+struct q6asm {
+	struct apr_device *adev;
+	struct device *dev;
+	struct q6core_svc_api_info ainfo;
+	wait_queue_head_t mem_wait;
+	struct platform_device *pcmdev;
+	spinlock_t slock;
+	struct audio_client *session[MAX_SESSIONS + 1];
+	struct platform_device *pdev_dais;
+};
+
+struct audio_client {
+	int session;
+	q6asm_cb cb;
+	void *priv;
+	uint32_t io_mode;
+	struct apr_device *adev;
+	struct mutex cmd_lock;
+	spinlock_t lock;
+	struct kref refcount;
+	/* idx:1 out port, 0: in port */
+	struct audio_port_data port[2];
+	wait_queue_head_t cmd_wait;
+	struct aprv2_ibasic_rsp_result_t result;
+	int perf_mode;
+	int stream_id;
+	struct q6asm *q6asm;
+	struct device *dev;
+};
+
+static inline void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+				 uint32_t pkt_size, bool cmd_flg,
+				 uint32_t stream_id)
+{
+	hdr->hdr_field = APR_SEQ_CMD_HDR_FIELD;
+	hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
+	hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
+	hdr->pkt_size = pkt_size;
+	if (cmd_flg)
+		hdr->token = ac->session;
+}
+
+static int q6asm_apr_send_session_pkt(struct q6asm *a, struct audio_client *ac,
+				      struct apr_pkt *pkt, uint32_t rsp_opcode)
+{
+	struct apr_hdr *hdr = &pkt->hdr;
+	int rc;
+
+	mutex_lock(&ac->cmd_lock);
+	ac->result.opcode = 0;
+	ac->result.status = 0;
+	rc = apr_send_pkt(a->adev, pkt);
+	if (rc < 0)
+		goto err;
+
+	if (rsp_opcode)
+		rc = wait_event_timeout(a->mem_wait,
+					(ac->result.opcode == hdr->opcode) ||
+					(ac->result.opcode == rsp_opcode),
+					5 * HZ);
+	else
+		rc = wait_event_timeout(a->mem_wait,
+					(ac->result.opcode == hdr->opcode),
+					5 * HZ);
+
+	if (!rc) {
+		dev_err(a->dev, "CMD timeout\n");
+		rc = -ETIMEDOUT;
+	} else if (ac->result.status > 0) {
+		dev_err(a->dev, "DSP returned error[%x]\n",
+			ac->result.status);
+		rc = -EINVAL;
+	}
+
+err:
+	mutex_unlock(&ac->cmd_lock);
+	return rc;
+}
+
+static int __q6asm_memory_unmap(struct audio_client *ac,
+				phys_addr_t buf_add, int dir)
+{
+	struct avs_cmd_shared_mem_unmap_regions *mem_unmap;
+	struct q6asm *a = dev_get_drvdata(ac->dev->parent);
+	struct apr_pkt *pkt;
+	int rc, pkt_size;
+	void *p;
+
+	if (ac->port[dir].mem_map_handle == 0) {
+		dev_err(ac->dev, "invalid mem handle\n");
+		return -EINVAL;
+	}
+
+	pkt_size = APR_HDR_SIZE + sizeof(*mem_unmap);
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	mem_unmap = p + APR_HDR_SIZE;
+
+	pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
+	pkt->hdr.src_port = 0;
+	pkt->hdr.dest_port = 0;
+	pkt->hdr.pkt_size = pkt_size;
+	pkt->hdr.token = ((ac->session << 8) | dir);
+
+	pkt->hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
+	mem_unmap->mem_map_handle = ac->port[dir].mem_map_handle;
+
+	rc = q6asm_apr_send_session_pkt(a, ac, pkt, 0);
+	if (rc < 0) {
+		kfree(pkt);
+		return rc;
+	}
+
+	ac->port[dir].mem_map_handle = 0;
+
+	kfree(pkt);
+	return 0;
+}
+
+
+static void q6asm_audio_client_free_buf(struct audio_client *ac,
+					struct audio_port_data *port)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ac->lock, flags);
+	port->num_periods = 0;
+	kfree(port->buf);
+	port->buf = NULL;
+	spin_unlock_irqrestore(&ac->lock, flags);
+}
+
+/**
+ * q6asm_unmap_memory_regions() - unmap memory regions in the dsp.
+ *
+ * @dir: direction of audio stream
+ * @ac: audio client instanace
+ *
+ * Return: Will be an negative value on failure or zero on success
+ */
+int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac)
+{
+	struct audio_port_data *port;
+	int cnt = 0;
+	int rc = 0;
+
+	port = &ac->port[dir];
+	if (!port->buf) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	cnt = port->num_periods - 1;
+	if (cnt >= 0) {
+		rc = __q6asm_memory_unmap(ac, port->buf[dir].phys, dir);
+		if (rc < 0) {
+			dev_err(ac->dev, "%s: Memory_unmap_regions failed %d\n",
+				__func__, rc);
+			goto err;
+		}
+	}
+
+	q6asm_audio_client_free_buf(ac, port);
+
+err:
+	return rc;
+}
+EXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions);
+
+static int __q6asm_memory_map_regions(struct audio_client *ac, int dir,
+				      size_t period_sz, unsigned int periods,
+				      bool is_contiguous)
+{
+	struct avs_cmd_shared_mem_map_regions *cmd = NULL;
+	struct avs_shared_map_region_payload *mregions = NULL;
+	struct q6asm *a = dev_get_drvdata(ac->dev->parent);
+	struct audio_port_data *port = NULL;
+	struct audio_buffer *ab = NULL;
+	struct apr_pkt *pkt;
+	void *p;
+	unsigned long flags;
+	uint32_t num_regions, buf_sz;
+	int rc, i, pkt_size;
+
+	if (is_contiguous) {
+		num_regions = 1;
+		buf_sz = period_sz * periods;
+	} else {
+		buf_sz = period_sz;
+		num_regions = periods;
+	}
+
+	/* DSP expects size should be aligned to 4K */
+	buf_sz = ALIGN(buf_sz, 4096);
+
+	pkt_size = APR_HDR_SIZE + sizeof(*cmd) +
+		   (sizeof(*mregions) * num_regions);
+
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	cmd = p + APR_HDR_SIZE;
+	mregions = p + APR_HDR_SIZE +  sizeof(*cmd);
+
+	pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
+	pkt->hdr.src_port = 0;
+	pkt->hdr.dest_port = 0;
+	pkt->hdr.pkt_size = pkt_size;
+	pkt->hdr.token = ((ac->session << 8) | dir);
+	pkt->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
+
+	cmd->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+	cmd->num_regions = num_regions;
+	cmd->property_flag = 0x00;
+
+	spin_lock_irqsave(&ac->lock, flags);
+	port = &ac->port[dir];
+
+	for (i = 0; i < num_regions; i++) {
+		ab = &port->buf[i];
+		mregions->shm_addr_lsw = lower_32_bits(ab->phys);
+		mregions->shm_addr_msw = upper_32_bits(ab->phys);
+		mregions->mem_size_bytes = buf_sz;
+		++mregions;
+	}
+	spin_unlock_irqrestore(&ac->lock, flags);
+
+	rc = q6asm_apr_send_session_pkt(a, ac, pkt,
+					ASM_CMDRSP_SHARED_MEM_MAP_REGIONS);
+
+	kfree(pkt);
+
+	return rc;
+}
+
+/**
+ * q6asm_map_memory_regions() - map memory regions in the dsp.
+ *
+ * @dir: direction of audio stream
+ * @ac: audio client instanace
+ * @phys: physcial address that needs mapping.
+ * @period_sz: audio period size
+ * @periods: number of periods
+ *
+ * Return: Will be an negative value on failure or zero on success
+ */
+int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac,
+			     phys_addr_t phys,
+			     size_t period_sz, unsigned int periods)
+{
+	struct audio_buffer *buf;
+	unsigned long flags;
+	int cnt;
+	int rc;
+
+	spin_lock_irqsave(&ac->lock, flags);
+	if (ac->port[dir].buf) {
+		dev_err(ac->dev, "Buffer already allocated\n");
+		spin_unlock_irqrestore(&ac->lock, flags);
+		return 0;
+	}
+
+	buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_ATOMIC);
+	if (!buf) {
+		spin_unlock_irqrestore(&ac->lock, flags);
+		return -ENOMEM;
+	}
+
+
+	ac->port[dir].buf = buf;
+
+	buf[0].phys = phys;
+	buf[0].size = period_sz;
+
+	for (cnt = 1; cnt < periods; cnt++) {
+		if (period_sz > 0) {
+			buf[cnt].phys = buf[0].phys + (cnt * period_sz);
+			buf[cnt].size = period_sz;
+		}
+	}
+	ac->port[dir].num_periods = periods;
+
+	spin_unlock_irqrestore(&ac->lock, flags);
+
+	rc = __q6asm_memory_map_regions(ac, dir, period_sz, periods, 1);
+	if (rc < 0) {
+		dev_err(ac->dev, "Memory_map_regions failed\n");
+		q6asm_audio_client_free_buf(ac, &ac->port[dir]);
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(q6asm_map_memory_regions);
+
+static void q6asm_audio_client_release(struct kref *ref)
+{
+	struct audio_client *ac;
+	struct q6asm *a;
+	unsigned long flags;
+
+	ac = container_of(ref, struct audio_client, refcount);
+	a = ac->q6asm;
+
+	spin_lock_irqsave(&a->slock, flags);
+	a->session[ac->session] = NULL;
+	spin_unlock_irqrestore(&a->slock, flags);
+
+	kfree(ac);
+}
+
+/**
+ * q6asm_audio_client_free() - Freee allocated audio client
+ *
+ * @ac: audio client to free
+ */
+void q6asm_audio_client_free(struct audio_client *ac)
+{
+	kref_put(&ac->refcount, q6asm_audio_client_release);
+}
+EXPORT_SYMBOL_GPL(q6asm_audio_client_free);
+
+static struct audio_client *q6asm_get_audio_client(struct q6asm *a,
+						   int session_id)
+{
+	struct audio_client *ac = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&a->slock, flags);
+	if ((session_id <= 0) || (session_id > MAX_SESSIONS)) {
+		dev_err(a->dev, "invalid session: %d\n", session_id);
+		goto err;
+	}
+
+	/* check for valid session */
+	if (!a->session[session_id])
+		goto err;
+	else if (a->session[session_id]->session != session_id)
+		goto err;
+
+	ac = a->session[session_id];
+	kref_get(&ac->refcount);
+err:
+	spin_unlock_irqrestore(&a->slock, flags);
+	return ac;
+}
+
+static int32_t q6asm_stream_callback(struct apr_device *adev,
+				     struct apr_resp_pkt *data,
+				     int session_id)
+{
+	struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
+	struct aprv2_ibasic_rsp_result_t *result;
+	struct apr_hdr *hdr = &data->hdr;
+	struct audio_port_data *port;
+	struct audio_client *ac;
+	uint32_t client_event = 0;
+	int ret = 0;
+
+	ac = q6asm_get_audio_client(q6asm, session_id);
+	if (!ac)/* Audio client might already be freed by now */
+		return 0;
+
+	result = data->payload;
+
+	switch (hdr->opcode) {
+	case APR_BASIC_RSP_RESULT:
+		switch (result->opcode) {
+		case ASM_SESSION_CMD_PAUSE:
+			client_event = ASM_CLIENT_EVENT_CMD_PAUSE_DONE;
+			break;
+		case ASM_SESSION_CMD_SUSPEND:
+			client_event = ASM_CLIENT_EVENT_CMD_SUSPEND_DONE;
+			break;
+		case ASM_DATA_CMD_EOS:
+			client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE;
+			break;
+		case ASM_STREAM_CMD_FLUSH:
+			client_event = ASM_CLIENT_EVENT_CMD_FLUSH_DONE;
+			break;
+		case ASM_SESSION_CMD_RUN_V2:
+			client_event = ASM_CLIENT_EVENT_CMD_RUN_DONE;
+			break;
+		case ASM_STREAM_CMD_CLOSE:
+			client_event = ASM_CLIENT_EVENT_CMD_CLOSE_DONE;
+			break;
+		case ASM_STREAM_CMD_FLUSH_READBUFS:
+			client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE;
+			break;
+		case ASM_STREAM_CMD_OPEN_WRITE_V3:
+		case ASM_STREAM_CMD_OPEN_READ_V3:
+		case ASM_STREAM_CMD_OPEN_READWRITE_V2:
+		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
+			if (result->status != 0) {
+				dev_err(ac->dev,
+					"cmd = 0x%x returned error = 0x%x\n",
+					result->opcode, result->status);
+				ac->result = *result;
+				wake_up(&ac->cmd_wait);
+				ret = 0;
+				goto done;
+			}
+			break;
+		default:
+			dev_err(ac->dev, "command[0x%x] not expecting rsp\n",
+				result->opcode);
+			break;
+		}
+
+		ac->result = *result;
+		wake_up(&ac->cmd_wait);
+
+		if (ac->cb)
+			ac->cb(client_event, hdr->token,
+			       data->payload, ac->priv);
+
+		ret = 0;
+		goto done;
+
+	case ASM_DATA_EVENT_WRITE_DONE_V2:
+		client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE;
+		if (ac->io_mode & ASM_SYNC_IO_MODE) {
+			phys_addr_t phys;
+			unsigned long flags;
+
+			spin_lock_irqsave(&ac->lock, flags);
+
+			port =  &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
+
+			if (!port->buf) {
+				spin_unlock_irqrestore(&ac->lock, flags);
+				ret = 0;
+				goto done;
+			}
+
+			phys = port->buf[hdr->token].phys;
+
+			if (lower_32_bits(phys) != result->opcode ||
+			    upper_32_bits(phys) != result->status) {
+				dev_err(ac->dev, "Expected addr %pa\n",
+					&port->buf[hdr->token].phys);
+				spin_unlock_irqrestore(&ac->lock, flags);
+				ret = -EINVAL;
+				goto done;
+			}
+			spin_unlock_irqrestore(&ac->lock, flags);
+		}
+		break;
+	case ASM_DATA_EVENT_READ_DONE_V2:
+		client_event = ASM_CLIENT_EVENT_DATA_READ_DONE;
+		if (ac->io_mode & ASM_SYNC_IO_MODE) {
+			struct asm_data_cmd_read_v2_done *done = data->payload;
+			unsigned long flags;
+			phys_addr_t phys;
+
+			spin_lock_irqsave(&ac->lock, flags);
+			port =  &ac->port[SNDRV_PCM_STREAM_CAPTURE];
+			if (!port->buf) {
+				spin_unlock_irqrestore(&ac->lock, flags);
+				ret = 0;
+				goto done;
+			}
+
+			phys = port->buf[hdr->token].phys;
+
+			if (upper_32_bits(phys) != done->buf_addr_msw ||
+			    lower_32_bits(phys) != done->buf_addr_lsw) {
+				dev_err(ac->dev, "Expected addr %pa %08x-%08x\n",
+					&port->buf[hdr->token].phys,
+					done->buf_addr_lsw,
+					done->buf_addr_msw);
+				spin_unlock_irqrestore(&ac->lock, flags);
+				ret = -EINVAL;
+				goto done;
+			}
+			spin_unlock_irqrestore(&ac->lock, flags);
+		}
+
+		break;
+	}
+
+	if (ac->cb)
+		ac->cb(client_event, hdr->token, data->payload, ac->priv);
+
+done:
+	kref_put(&ac->refcount, q6asm_audio_client_release);
+	return ret;
+}
+
+static int q6asm_srvc_callback(struct apr_device *adev,
+			       struct apr_resp_pkt *data)
+{
+	struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
+	struct aprv2_ibasic_rsp_result_t *result;
+	struct audio_port_data *port;
+	struct audio_client *ac = NULL;
+	struct apr_hdr *hdr = &data->hdr;
+	struct q6asm *a;
+	uint32_t sid = 0;
+	uint32_t dir = 0;
+	int session_id;
+
+	session_id = (hdr->dest_port >> 8) & 0xFF;
+	if (session_id)
+		return q6asm_stream_callback(adev, data, session_id);
+
+	sid = (hdr->token >> 8) & 0x0F;
+	ac = q6asm_get_audio_client(q6asm, sid);
+	if (!ac) {
+		dev_err(&adev->dev, "Audio Client not active\n");
+		return 0;
+	}
+
+	a = dev_get_drvdata(ac->dev->parent);
+	dir = (hdr->token & 0x0F);
+	port = &ac->port[dir];
+	result = data->payload;
+
+	switch (hdr->opcode) {
+	case APR_BASIC_RSP_RESULT:
+		switch (result->opcode) {
+		case ASM_CMD_SHARED_MEM_MAP_REGIONS:
+		case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
+			ac->result = *result;
+			wake_up(&a->mem_wait);
+			break;
+		default:
+			dev_err(&adev->dev, "command[0x%x] not expecting rsp\n",
+				 result->opcode);
+			break;
+		}
+		goto done;
+	case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:
+		ac->result.status = 0;
+		ac->result.opcode = hdr->opcode;
+		port->mem_map_handle = result->opcode;
+		wake_up(&a->mem_wait);
+		break;
+	case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
+		ac->result.opcode = hdr->opcode;
+		ac->result.status = 0;
+		port->mem_map_handle = 0;
+		wake_up(&a->mem_wait);
+		break;
+	default:
+		dev_dbg(&adev->dev, "command[0x%x]success [0x%x]\n",
+			result->opcode, result->status);
+		break;
+	}
+
+	if (ac->cb)
+		ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv);
+
+done:
+	kref_put(&ac->refcount, q6asm_audio_client_release);
+
+	return 0;
+}
+
+/**
+ * q6asm_get_session_id() - get session id for audio client
+ *
+ * @c: audio client pointer
+ *
+ * Return: Will be an session id of the audio client.
+ */
+int q6asm_get_session_id(struct audio_client *c)
+{
+	return c->session;
+}
+EXPORT_SYMBOL_GPL(q6asm_get_session_id);
+
+/**
+ * q6asm_audio_client_alloc() - Allocate a new audio client
+ *
+ * @dev: Pointer to asm child device.
+ * @cb: event callback.
+ * @priv: private data associated with this client.
+ * @stream_id: stream id
+ * @perf_mode: performace mode for this client
+ *
+ * Return: Will be an error pointer on error or a valid audio client
+ * on success.
+ */
+struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb,
+					      void *priv, int stream_id,
+					      int perf_mode)
+{
+	struct q6asm *a = dev_get_drvdata(dev->parent);
+	struct audio_client *ac;
+	unsigned long flags;
+
+	ac = q6asm_get_audio_client(a, stream_id + 1);
+	if (ac) {
+		dev_err(dev, "Audio Client already active\n");
+		return ac;
+	}
+
+	ac = kzalloc(sizeof(*ac), GFP_KERNEL);
+	if (!ac)
+		return ERR_PTR(-ENOMEM);
+
+	spin_lock_irqsave(&a->slock, flags);
+	a->session[stream_id + 1] = ac;
+	spin_unlock_irqrestore(&a->slock, flags);
+	ac->session = stream_id + 1;
+	ac->cb = cb;
+	ac->dev = dev;
+	ac->q6asm = a;
+	ac->priv = priv;
+	ac->io_mode = ASM_SYNC_IO_MODE;
+	ac->perf_mode = perf_mode;
+	/* DSP expects stream id from 1 */
+	ac->stream_id = 1;
+	ac->adev = a->adev;
+	kref_init(&ac->refcount);
+
+	init_waitqueue_head(&ac->cmd_wait);
+	mutex_init(&ac->cmd_lock);
+	spin_lock_init(&ac->lock);
+
+	return ac;
+}
+EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc);
+
+static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt)
+{
+	struct apr_hdr *hdr = &pkt->hdr;
+	int rc;
+
+	mutex_lock(&ac->cmd_lock);
+	ac->result.opcode = 0;
+	ac->result.status = 0;
+
+	rc = apr_send_pkt(ac->adev, pkt);
+	if (rc < 0)
+		goto err;
+
+	rc = wait_event_timeout(ac->cmd_wait,
+				(ac->result.opcode == hdr->opcode), 5 * HZ);
+	if (!rc) {
+		dev_err(ac->dev, "CMD timeout\n");
+		rc =  -ETIMEDOUT;
+		goto err;
+	}
+
+	if (ac->result.status > 0) {
+		dev_err(ac->dev, "DSP returned error[%x]\n",
+			ac->result.status);
+		rc = -EINVAL;
+	} else {
+		rc = 0;
+	}
+
+
+err:
+	mutex_unlock(&ac->cmd_lock);
+	return rc;
+}
+
+/**
+ * q6asm_open_write() - Open audio client for writing
+ *
+ * @ac: audio client pointer
+ * @format: audio sample format
+ * @bits_per_sample: bits per sample
+ *
+ * Return: Will be an negative value on error or zero on success
+ */
+int q6asm_open_write(struct audio_client *ac, uint32_t format,
+		     uint16_t bits_per_sample)
+{
+	struct asm_stream_cmd_open_write_v3 *open;
+	struct apr_pkt *pkt;
+	void *p;
+	int rc, pkt_size;
+
+	pkt_size = APR_HDR_SIZE + sizeof(*open);
+
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	open = p + APR_HDR_SIZE;
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+
+	pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
+	open->mode_flags = 0x00;
+	open->mode_flags |= ASM_LEGACY_STREAM_SESSION;
+
+	/* source endpoint : matrix */
+	open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
+	open->bits_per_sample = bits_per_sample;
+	open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY;
+
+	switch (format) {
+	case FORMAT_LINEAR_PCM:
+		open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+		break;
+	default:
+		dev_err(ac->dev, "Invalid format 0x%x\n", format);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = q6asm_ac_send_cmd_sync(ac, pkt);
+	if (rc < 0)
+		goto err;
+
+	ac->io_mode |= ASM_TUN_WRITE_IO_MODE;
+
+err:
+	kfree(pkt);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(q6asm_open_write);
+
+static int __q6asm_run(struct audio_client *ac, uint32_t flags,
+	      uint32_t msw_ts, uint32_t lsw_ts, bool wait)
+{
+	struct asm_session_cmd_run_v2 *run;
+	struct apr_pkt *pkt;
+	int pkt_size, rc;
+	void *p;
+
+	pkt_size = APR_HDR_SIZE + sizeof(*run);
+	p = kzalloc(pkt_size, GFP_ATOMIC);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	run = p + APR_HDR_SIZE;
+
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+
+	pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2;
+	run->flags = flags;
+	run->time_lsw = lsw_ts;
+	run->time_msw = msw_ts;
+	if (wait) {
+		rc = q6asm_ac_send_cmd_sync(ac, pkt);
+	} else {
+		rc = apr_send_pkt(ac->adev, pkt);
+		if (rc == pkt_size)
+			rc = 0;
+	}
+
+	kfree(pkt);
+	return rc;
+}
+
+/**
+ * q6asm_run() - start the audio client
+ *
+ * @ac: audio client pointer
+ * @flags: flags associated with write
+ * @msw_ts: timestamp msw
+ * @lsw_ts: timestamp lsw
+ *
+ * Return: Will be an negative value on error or zero on success
+ */
+int q6asm_run(struct audio_client *ac, uint32_t flags,
+	      uint32_t msw_ts, uint32_t lsw_ts)
+{
+	return __q6asm_run(ac, flags, msw_ts, lsw_ts, true);
+}
+EXPORT_SYMBOL_GPL(q6asm_run);
+
+/**
+ * q6asm_run_nowait() - start the audio client withou blocking
+ *
+ * @ac: audio client pointer
+ * @flags: flags associated with write
+ * @msw_ts: timestamp msw
+ * @lsw_ts: timestamp lsw
+ *
+ * Return: Will be an negative value on error or zero on success
+ */
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+	      uint32_t msw_ts, uint32_t lsw_ts)
+{
+	return __q6asm_run(ac, flags, msw_ts, lsw_ts, false);
+}
+EXPORT_SYMBOL_GPL(q6asm_run_nowait);
+
+/**
+ * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration
+ *
+ * @ac: audio client pointer
+ * @rate: audio sample rate
+ * @channels: number of audio channels.
+ * @channel_map: channel map pointer
+ * @bits_per_sample: bits per sample
+ *
+ * Return: Will be an negative value on error or zero on success
+ */
+int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+					  uint32_t rate, uint32_t channels,
+					  u8 channel_map[PCM_MAX_NUM_CHANNEL],
+					  uint16_t bits_per_sample)
+{
+	struct asm_multi_channel_pcm_fmt_blk_v2 *fmt;
+	struct apr_pkt *pkt;
+	u8 *channel_mapping;
+	void *p;
+	int rc, pkt_size;
+
+	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	fmt = p + APR_HDR_SIZE;
+
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+
+	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
+	fmt->num_channels = channels;
+	fmt->bits_per_sample = bits_per_sample;
+	fmt->sample_rate = rate;
+	fmt->is_signed = 1;
+
+	channel_mapping = fmt->channel_mapping;
+
+	if (channel_map) {
+		memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL);
+	} else {
+		if (q6dsp_map_channels(channel_mapping, channels)) {
+			dev_err(ac->dev, " map channels failed %d\n", channels);
+			rc = -EINVAL;
+			goto err;
+		}
+	}
+
+	rc = q6asm_ac_send_cmd_sync(ac, pkt);
+
+err:
+	kfree(pkt);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
+
+/**
+ * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
+ *
+ * @ac: audio client pointer
+ * @rate: audio sample rate
+ * @channels: number of audio channels.
+ * @bits_per_sample: bits per sample
+ *
+ * Return: Will be an negative value on error or zero on success
+ */
+int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
+		uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
+{
+	struct asm_multi_channel_pcm_enc_cfg_v2  *enc_cfg;
+	struct apr_pkt *pkt;
+	u8 *channel_mapping;
+	u32 frames_per_buf = 0;
+	int pkt_size, rc;
+	void *p;
+
+	pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg);
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	enc_cfg = p + APR_HDR_SIZE;
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+
+	pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+	enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec);
+	enc_cfg->encblk.frames_per_buf = frames_per_buf;
+	enc_cfg->encblk.enc_cfg_blk_size  = enc_cfg->encdec.param_size -
+					sizeof(struct asm_enc_cfg_blk_param_v2);
+
+	enc_cfg->num_channels = channels;
+	enc_cfg->bits_per_sample = bits_per_sample;
+	enc_cfg->sample_rate = rate;
+	enc_cfg->is_signed = 1;
+	channel_mapping = enc_cfg->channel_mapping;
+
+	if (q6dsp_map_channels(channel_mapping, channels)) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = q6asm_ac_send_cmd_sync(ac, pkt);
+err:
+	kfree(pkt);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
+
+/**
+ * q6asm_read() - read data of period size from audio client
+ *
+ * @ac: audio client pointer
+ *
+ * Return: Will be an negative value on error or zero on success
+ */
+int q6asm_read(struct audio_client *ac)
+{
+	struct asm_data_cmd_read_v2 *read;
+	struct audio_port_data *port;
+	struct audio_buffer *ab;
+	struct apr_pkt *pkt;
+	unsigned long flags;
+	int pkt_size;
+	int rc = 0;
+	void *p;
+
+	pkt_size = APR_HDR_SIZE + sizeof(*read);
+	p = kzalloc(pkt_size, GFP_ATOMIC);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	read = p + APR_HDR_SIZE;
+
+	spin_lock_irqsave(&ac->lock, flags);
+	port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
+	ab = &port->buf[port->dsp_buf];
+	pkt->hdr.opcode = ASM_DATA_CMD_READ_V2;
+	read->buf_addr_lsw = lower_32_bits(ab->phys);
+	read->buf_addr_msw = upper_32_bits(ab->phys);
+	read->mem_map_handle = port->mem_map_handle;
+
+	read->buf_size = ab->size;
+	read->seq_id = port->dsp_buf;
+	pkt->hdr.token = port->dsp_buf;
+
+	port->dsp_buf++;
+
+	if (port->dsp_buf >= port->num_periods)
+		port->dsp_buf = 0;
+
+	spin_unlock_irqrestore(&ac->lock, flags);
+	rc = apr_send_pkt(ac->adev, pkt);
+	if (rc == pkt_size)
+		rc = 0;
+	else
+		pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc);
+
+	kfree(pkt);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(q6asm_read);
+
+static int __q6asm_open_read(struct audio_client *ac,
+		uint32_t format, uint16_t bits_per_sample)
+{
+	struct asm_stream_cmd_open_read_v3 *open;
+	struct apr_pkt *pkt;
+	int pkt_size, rc;
+	void *p;
+
+	pkt_size = APR_HDR_SIZE + sizeof(*open);
+	p = kzalloc(pkt_size, GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	open = p + APR_HDR_SIZE;
+
+	q6asm_add_hdr(ac, &pkt->hdr,  pkt_size, true, ac->stream_id);
+	pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
+	/* Stream prio : High, provide meta info with encoded frames */
+	open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
+
+	open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
+	open->bits_per_sample = bits_per_sample;
+	open->mode_flags = 0x0;
+
+	open->mode_flags |= ASM_LEGACY_STREAM_SESSION <<
+				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
+
+	switch (format) {
+	case FORMAT_LINEAR_PCM:
+		open->mode_flags |= 0x00;
+		open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
+		break;
+	default:
+		pr_err("Invalid format[%d]\n", format);
+	}
+
+	rc = q6asm_ac_send_cmd_sync(ac, pkt);
+
+	kfree(pkt);
+	return rc;
+}
+
+/**
+ * q6asm_open_read() - Open audio client for reading
+ *
+ * @ac: audio client pointer
+ * @format: audio sample format
+ * @bits_per_sample: bits per sample
+ *
+ * Return: Will be an negative value on error or zero on success
+ */
+int q6asm_open_read(struct audio_client *ac, uint32_t format,
+			uint16_t bits_per_sample)
+{
+	return __q6asm_open_read(ac, format, bits_per_sample);
+}
+EXPORT_SYMBOL_GPL(q6asm_open_read);
+
+/**
+ * q6asm_write_async() - non blocking write
+ *
+ * @ac: audio client pointer
+ * @len: lenght in bytes
+ * @msw_ts: timestamp msw
+ * @lsw_ts: timestamp lsw
+ * @wflags: flags associated with write
+ *
+ * Return: Will be an negative value on error or zero on success
+ */
+int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+		       uint32_t lsw_ts, uint32_t wflags)
+{
+	struct asm_data_cmd_write_v2 *write;
+	struct audio_port_data *port;
+	struct audio_buffer *ab;
+	unsigned long flags;
+	struct apr_pkt *pkt;
+	int pkt_size;
+	int rc = 0;
+	void *p;
+
+	pkt_size = APR_HDR_SIZE + sizeof(*write);
+	p = kzalloc(pkt_size, GFP_ATOMIC);
+	if (!p)
+		return -ENOMEM;
+
+	pkt = p;
+	write = p + APR_HDR_SIZE;
+
+	spin_lock_irqsave(&ac->lock, flags);
+	port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
+	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
+
+	ab = &port->buf[port->dsp_buf];
+	pkt->hdr.token = port->dsp_buf;
+	pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2;
+	write->buf_addr_lsw = lower_32_bits(ab->phys);
+	write->buf_addr_msw = upper_32_bits(ab->phys);
+	write->buf_size = len;
+	write->seq_id = port->dsp_buf;
+	write->timestamp_lsw = lsw_ts;
+	write->timestamp_msw = msw_ts;
+	write->mem_map_handle =
+	    ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle;
+
+	if (wflags == NO_TIMESTAMP)
+		write->flags = (wflags & 0x800000FF);
+	else
+		write->flags = (0x80000000 | wflags);
+
+	port->dsp_buf++;
+
+	if (port->dsp_buf >= port->num_periods)
+		port->dsp_buf = 0;
+
+	spin_unlock_irqrestore(&ac->lock, flags);
+	rc = apr_send_pkt(ac->adev, pkt);
+	if (rc == pkt_size)
+		rc = 0;
+
+	kfree(pkt);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(q6asm_write_async);
+
+static void q6asm_reset_buf_state(struct audio_client *ac)
+{
+	struct audio_port_data *port = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ac->lock, flags);
+	port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
+	port->dsp_buf = 0;
+	port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
+	port->dsp_buf = 0;
+	spin_unlock_irqrestore(&ac->lock, flags);
+}
+
+static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait)
+{
+	int stream_id = ac->stream_id;
+	struct apr_pkt pkt;
+	int rc;
+
+	q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id);
+
+	switch (cmd) {
+	case CMD_PAUSE:
+		pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE;
+		break;
+	case CMD_SUSPEND:
+		pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND;
+		break;
+	case CMD_FLUSH:
+		pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH;
+		break;
+	case CMD_OUT_FLUSH:
+		pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
+		break;
+	case CMD_EOS:
+		pkt.hdr.opcode = ASM_DATA_CMD_EOS;
+		break;
+	case CMD_CLOSE:
+		pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (wait)
+		rc = q6asm_ac_send_cmd_sync(ac, &pkt);
+	else
+		return apr_send_pkt(ac->adev, &pkt);
+
+	if (rc < 0)
+		return rc;
+
+	if (cmd == CMD_FLUSH)
+		q6asm_reset_buf_state(ac);
+
+	return 0;
+}
+
+/**
+ * q6asm_cmd() - run cmd on audio client
+ *
+ * @ac: audio client pointer
+ * @cmd: command to run on audio client.
+ *
+ * Return: Will be an negative value on error or zero on success
+ */
+int q6asm_cmd(struct audio_client *ac, int cmd)
+{
+	return __q6asm_cmd(ac, cmd, true);
+}
+EXPORT_SYMBOL_GPL(q6asm_cmd);
+
+/**
+ * q6asm_cmd_nowait() - non blocking, run cmd on audio client
+ *
+ * @ac: audio client pointer
+ * @cmd: command to run on audio client.
+ *
+ * Return: Will be an negative value on error or zero on success
+ */
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+{
+	return __q6asm_cmd(ac, cmd, false);
+}
+EXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
+
+static int q6asm_probe(struct apr_device *adev)
+{
+	struct device *dev = &adev->dev;
+	struct device_node *dais_np;
+	struct q6asm *q6asm;
+
+	q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL);
+	if (!q6asm)
+		return -ENOMEM;
+
+	q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo);
+
+	q6asm->dev = dev;
+	q6asm->adev = adev;
+	init_waitqueue_head(&q6asm->mem_wait);
+	spin_lock_init(&q6asm->slock);
+	dev_set_drvdata(dev, q6asm);
+
+	dais_np = of_get_child_by_name(dev->of_node, "dais");
+	if (dais_np) {
+		q6asm->pdev_dais = of_platform_device_create(dais_np,
+							   "q6asm-dai", dev);
+		of_node_put(dais_np);
+	}
+
+	return 0;
+}
+
+static int q6asm_remove(struct apr_device *adev)
+{
+	struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
+
+	if (q6asm->pdev_dais)
+		of_platform_device_destroy(&q6asm->pdev_dais->dev, NULL);
+
+	return 0;
+}
+static const struct of_device_id q6asm_device_id[]  = {
+	{ .compatible = "qcom,q6asm" },
+	{},
+};
+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",
+		.of_match_table = of_match_ptr(q6asm_device_id),
+	},
+};
+
+module_apr_driver(qcom_q6asm_driver);
+MODULE_DESCRIPTION("Q6 Audio Stream Manager driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h
new file mode 100644
index 000000000000..9f5fb573e4a0
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6asm.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __Q6_ASM_H__
+#define __Q6_ASM_H__
+#include "q6dsp-common.h"
+#include <dt-bindings/sound/qcom,q6asm.h>
+
+/* ASM client callback events */
+#define CMD_PAUSE			0x0001
+#define ASM_CLIENT_EVENT_CMD_PAUSE_DONE		0x1001
+#define CMD_FLUSH				0x0002
+#define ASM_CLIENT_EVENT_CMD_FLUSH_DONE		0x1002
+#define CMD_EOS				0x0003
+#define ASM_CLIENT_EVENT_CMD_EOS_DONE		0x1003
+#define CMD_CLOSE				0x0004
+#define ASM_CLIENT_EVENT_CMD_CLOSE_DONE		0x1004
+#define CMD_OUT_FLUSH				0x0005
+#define ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE	0x1005
+#define CMD_SUSPEND				0x0006
+#define ASM_CLIENT_EVENT_CMD_SUSPEND_DONE	0x1006
+#define ASM_CLIENT_EVENT_CMD_RUN_DONE		0x1008
+#define ASM_CLIENT_EVENT_DATA_WRITE_DONE	0x1009
+#define ASM_CLIENT_EVENT_DATA_READ_DONE		0x100a
+
+enum {
+	LEGACY_PCM_MODE = 0,
+	LOW_LATENCY_PCM_MODE,
+	ULTRA_LOW_LATENCY_PCM_MODE,
+	ULL_POST_PROCESSING_PCM_MODE,
+};
+
+#define MAX_SESSIONS	8
+#define NO_TIMESTAMP    0xFF00
+#define FORMAT_LINEAR_PCM   0x0000
+
+typedef void (*q6asm_cb) (uint32_t opcode, uint32_t token,
+			  void *payload, void *priv);
+struct audio_client;
+struct audio_client *q6asm_audio_client_alloc(struct device *dev,
+					      q6asm_cb cb, void *priv,
+					      int session_id, int perf_mode);
+void q6asm_audio_client_free(struct audio_client *ac);
+int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+		       uint32_t lsw_ts, uint32_t flags);
+int q6asm_open_write(struct audio_client *ac, uint32_t format,
+		     uint16_t bits_per_sample);
+
+int q6asm_open_read(struct audio_client *ac, uint32_t format,
+		     uint16_t bits_per_sample);
+int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
+		uint32_t rate, uint32_t channels, uint16_t bits_per_sample);
+int q6asm_read(struct audio_client *ac);
+
+int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+					  uint32_t rate, uint32_t channels,
+					  u8 channel_map[PCM_MAX_NUM_CHANNEL],
+					  uint16_t bits_per_sample);
+int q6asm_run(struct audio_client *ac, uint32_t flags, uint32_t msw_ts,
+	      uint32_t lsw_ts);
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, uint32_t msw_ts,
+		     uint32_t lsw_ts);
+int q6asm_cmd(struct audio_client *ac, int cmd);
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd);
+int q6asm_get_session_id(struct audio_client *ac);
+int q6asm_map_memory_regions(unsigned int dir,
+			     struct audio_client *ac,
+			     phys_addr_t phys,
+			     size_t bufsz, unsigned int bufcnt);
+int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac);
+#endif /* __Q6_ASM_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6core.c b/sound/soc/qcom/qdsp6/q6core.c
new file mode 100644
index 000000000000..06f03a5fe9bd
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6core.c
@@ -0,0 +1,380 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+// Copyright (c) 2018, Linaro Limited
+
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/jiffies.h>
+#include <linux/wait.h>
+#include <linux/soc/qcom/apr.h>
+#include "q6core.h"
+#include "q6dsp-errno.h"
+
+#define ADSP_STATE_READY_TIMEOUT_MS    3000
+#define Q6_READY_TIMEOUT_MS 100
+#define AVCS_CMD_ADSP_EVENT_GET_STATE		0x0001290C
+#define AVCS_CMDRSP_ADSP_EVENT_GET_STATE	0x0001290D
+#define AVCS_GET_VERSIONS       0x00012905
+#define AVCS_GET_VERSIONS_RSP   0x00012906
+#define AVCS_CMD_GET_FWK_VERSION	0x001292c
+#define AVCS_CMDRSP_GET_FWK_VERSION	0x001292d
+
+struct avcs_svc_info {
+	uint32_t service_id;
+	uint32_t version;
+} __packed;
+
+struct avcs_cmdrsp_get_version {
+	uint32_t build_id;
+	uint32_t num_services;
+	struct avcs_svc_info svc_api_info[];
+} __packed;
+
+/* for ADSP2.8 and above */
+struct avcs_svc_api_info {
+	uint32_t service_id;
+	uint32_t api_version;
+	uint32_t api_branch_version;
+} __packed;
+
+struct avcs_cmdrsp_get_fwk_version {
+	uint32_t build_major_version;
+	uint32_t build_minor_version;
+	uint32_t build_branch_version;
+	uint32_t build_subbranch_version;
+	uint32_t num_services;
+	struct avcs_svc_api_info svc_api_info[];
+} __packed;
+
+struct q6core {
+	struct apr_device *adev;
+	wait_queue_head_t wait;
+	uint32_t avcs_state;
+	struct mutex lock;
+	bool resp_received;
+	uint32_t num_services;
+	struct avcs_cmdrsp_get_fwk_version *fwk_version;
+	struct avcs_cmdrsp_get_version *svc_version;
+	bool fwk_version_supported;
+	bool get_state_supported;
+	bool get_version_supported;
+	bool is_version_requested;
+};
+
+static struct q6core *g_core;
+
+static int q6core_callback(struct apr_device *adev, struct apr_resp_pkt *data)
+{
+	struct q6core *core = dev_get_drvdata(&adev->dev);
+	struct aprv2_ibasic_rsp_result_t *result;
+	struct apr_hdr *hdr = &data->hdr;
+
+	result = data->payload;
+	switch (hdr->opcode) {
+	case APR_BASIC_RSP_RESULT:{
+		result = data->payload;
+		switch (result->opcode) {
+		case AVCS_GET_VERSIONS:
+			if (result->status == ADSP_EUNSUPPORTED)
+				core->get_version_supported = false;
+			core->resp_received = true;
+			break;
+		case AVCS_CMD_GET_FWK_VERSION:
+			if (result->status == ADSP_EUNSUPPORTED)
+				core->fwk_version_supported = false;
+			core->resp_received = true;
+			break;
+		case AVCS_CMD_ADSP_EVENT_GET_STATE:
+			if (result->status == ADSP_EUNSUPPORTED)
+				core->get_state_supported = false;
+			core->resp_received = true;
+			break;
+		}
+		break;
+	}
+	case AVCS_CMDRSP_GET_FWK_VERSION: {
+		struct avcs_cmdrsp_get_fwk_version *fwk;
+		int bytes;
+
+		fwk = data->payload;
+		bytes = sizeof(*fwk) + fwk->num_services *
+				sizeof(fwk->svc_api_info[0]);
+
+		core->fwk_version = kzalloc(bytes, GFP_ATOMIC);
+		if (!core->fwk_version)
+			return -ENOMEM;
+
+		memcpy(core->fwk_version, data->payload, bytes);
+
+		core->fwk_version_supported = true;
+		core->resp_received = true;
+
+		break;
+	}
+	case AVCS_GET_VERSIONS_RSP: {
+		struct avcs_cmdrsp_get_version *v;
+		int len;
+
+		v = data->payload;
+
+		len = sizeof(*v) + v->num_services * sizeof(v->svc_api_info[0]);
+
+		core->svc_version = kzalloc(len, GFP_ATOMIC);
+		if (!core->svc_version)
+			return -ENOMEM;
+
+		memcpy(core->svc_version, data->payload, len);
+
+		core->get_version_supported = true;
+		core->resp_received = true;
+
+		break;
+	}
+	case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:
+		core->get_state_supported = true;
+		core->avcs_state = result->opcode;
+
+		core->resp_received = true;
+		break;
+	default:
+		dev_err(&adev->dev, "Message id from adsp core svc: 0x%x\n",
+			hdr->opcode);
+		break;
+	}
+
+	if (core->resp_received)
+		wake_up(&core->wait);
+
+	return 0;
+}
+
+static int q6core_get_fwk_versions(struct q6core *core)
+{
+	struct apr_device *adev = core->adev;
+	struct apr_pkt pkt;
+	int rc;
+
+	pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				      APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	pkt.hdr.pkt_size = APR_HDR_SIZE;
+	pkt.hdr.opcode = AVCS_CMD_GET_FWK_VERSION;
+
+	rc = apr_send_pkt(adev, &pkt);
+	if (rc < 0)
+		return rc;
+
+	rc = wait_event_timeout(core->wait, (core->resp_received),
+				msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
+	if (rc > 0 && core->resp_received) {
+		core->resp_received = false;
+
+		if (!core->fwk_version_supported)
+			return -ENOTSUPP;
+		else
+			return 0;
+	}
+
+
+	return rc;
+}
+
+static int q6core_get_svc_versions(struct q6core *core)
+{
+	struct apr_device *adev = core->adev;
+	struct apr_pkt pkt;
+	int rc;
+
+	pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				      APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	pkt.hdr.pkt_size = APR_HDR_SIZE;
+	pkt.hdr.opcode = AVCS_GET_VERSIONS;
+
+	rc = apr_send_pkt(adev, &pkt);
+	if (rc < 0)
+		return rc;
+
+	rc = wait_event_timeout(core->wait, (core->resp_received),
+				msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
+	if (rc > 0 && core->resp_received) {
+		core->resp_received = false;
+		return 0;
+	}
+
+	return rc;
+}
+
+static bool __q6core_is_adsp_ready(struct q6core *core)
+{
+	struct apr_device *adev = core->adev;
+	struct apr_pkt pkt;
+	int rc;
+
+	core->get_state_supported = false;
+
+	pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				      APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	pkt.hdr.pkt_size = APR_HDR_SIZE;
+	pkt.hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;
+
+	rc = apr_send_pkt(adev, &pkt);
+	if (rc < 0)
+		return false;
+
+	rc = wait_event_timeout(core->wait, (core->resp_received),
+				msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
+	if (rc > 0 && core->resp_received) {
+		core->resp_received = false;
+
+		if (core->avcs_state)
+			return true;
+	}
+
+	/* assume that the adsp is up if we not support this command */
+	if (!core->get_state_supported)
+		return true;
+
+	return false;
+}
+
+/**
+ * q6core_get_svc_api_info() - Get version number of a service.
+ *
+ * @svc_id: service id of the service.
+ * @ainfo: Valid struct pointer to fill svc api information.
+ *
+ * Return: zero on success and error code on failure or unsupported
+ */
+int q6core_get_svc_api_info(int svc_id, struct q6core_svc_api_info *ainfo)
+{
+	int i;
+	int ret = -ENOTSUPP;
+
+	if (!g_core || !ainfo)
+		return 0;
+
+	mutex_lock(&g_core->lock);
+	if (!g_core->is_version_requested) {
+		if (q6core_get_fwk_versions(g_core) == -ENOTSUPP)
+			q6core_get_svc_versions(g_core);
+		g_core->is_version_requested = true;
+	}
+
+	if (g_core->fwk_version_supported) {
+		for (i = 0; i < g_core->fwk_version->num_services; i++) {
+			struct avcs_svc_api_info *info;
+
+			info = &g_core->fwk_version->svc_api_info[i];
+			if (svc_id != info->service_id)
+				continue;
+
+			ainfo->api_version = info->api_version;
+			ainfo->api_branch_version = info->api_branch_version;
+			ret = 0;
+			break;
+		}
+	} else if (g_core->get_version_supported) {
+		for (i = 0; i < g_core->svc_version->num_services; i++) {
+			struct avcs_svc_info *info;
+
+			info = &g_core->svc_version->svc_api_info[i];
+			if (svc_id != info->service_id)
+				continue;
+
+			ainfo->api_version = info->version;
+			ainfo->api_branch_version = 0;
+			ret = 0;
+			break;
+		}
+	}
+
+	mutex_unlock(&g_core->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(q6core_get_svc_api_info);
+
+/**
+ * q6core_is_adsp_ready() - Get status of adsp
+ *
+ * Return: Will be an true if adsp is ready and false if not.
+ */
+bool q6core_is_adsp_ready(void)
+{
+	unsigned long  timeout;
+	bool ret = false;
+
+	if (!g_core)
+		return false;
+
+	mutex_lock(&g_core->lock);
+	timeout = jiffies + msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+	for (;;) {
+		if (__q6core_is_adsp_ready(g_core)) {
+			ret = true;
+			break;
+		}
+
+		if (!time_after(timeout, jiffies)) {
+			ret = false;
+			break;
+		}
+	}
+
+	mutex_unlock(&g_core->lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(q6core_is_adsp_ready);
+
+static int q6core_probe(struct apr_device *adev)
+{
+	g_core = kzalloc(sizeof(*g_core), GFP_KERNEL);
+	if (!g_core)
+		return -ENOMEM;
+
+	dev_set_drvdata(&adev->dev, g_core);
+
+	mutex_init(&g_core->lock);
+	g_core->adev = adev;
+	init_waitqueue_head(&g_core->wait);
+	return 0;
+}
+
+static int q6core_exit(struct apr_device *adev)
+{
+	struct q6core *core = dev_get_drvdata(&adev->dev);
+
+	if (core->fwk_version_supported)
+		kfree(core->fwk_version);
+	if (core->get_version_supported)
+		kfree(core->svc_version);
+
+	g_core = NULL;
+	kfree(core);
+
+	return 0;
+}
+
+static const struct of_device_id q6core_device_id[]  = {
+	{ .compatible = "qcom,q6core" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, q6core_device_id);
+
+static struct apr_driver qcom_q6core_driver = {
+	.probe = q6core_probe,
+	.remove = q6core_exit,
+	.callback = q6core_callback,
+	.driver = {
+		.name = "qcom-q6core",
+		.of_match_table = of_match_ptr(q6core_device_id),
+	},
+};
+
+module_apr_driver(qcom_q6core_driver);
+MODULE_DESCRIPTION("q6 core");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/q6core.h b/sound/soc/qcom/qdsp6/q6core.h
new file mode 100644
index 000000000000..4105b1d730be
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6core.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __Q6CORE_H__
+#define __Q6CORE_H__
+
+struct q6core_svc_api_info {
+	uint32_t service_id;
+	uint32_t api_version;
+	uint32_t api_branch_version;
+};
+
+bool q6core_is_adsp_ready(void);
+int q6core_get_svc_api_info(int svc_id, struct q6core_svc_api_info *ainfo);
+
+#endif /* __Q6CORE_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6dsp-common.c b/sound/soc/qcom/qdsp6/q6dsp-common.c
new file mode 100644
index 000000000000..d393003492c7
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6dsp-common.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+// Copyright (c) 2018, Linaro Limited
+
+#include "q6dsp-common.h"
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+int q6dsp_map_channels(u8 ch_map[PCM_MAX_NUM_CHANNEL], int ch)
+{
+	memset(ch_map, 0, PCM_MAX_NUM_CHANNEL);
+
+	switch (ch) {
+	case 1:
+		ch_map[0] = PCM_CHANNEL_FC;
+		break;
+	case 2:
+		ch_map[0] = PCM_CHANNEL_FL;
+		ch_map[1] = PCM_CHANNEL_FR;
+		break;
+	case 3:
+		ch_map[0] = PCM_CHANNEL_FL;
+		ch_map[1] = PCM_CHANNEL_FR;
+		ch_map[2] = PCM_CHANNEL_FC;
+		break;
+	case 4:
+		ch_map[0] = PCM_CHANNEL_FL;
+		ch_map[1] = PCM_CHANNEL_FR;
+		ch_map[2] = PCM_CHANNEL_LS;
+		ch_map[3] = PCM_CHANNEL_RS;
+		break;
+	case 5:
+		ch_map[0] = PCM_CHANNEL_FL;
+		ch_map[1] = PCM_CHANNEL_FR;
+		ch_map[2] = PCM_CHANNEL_FC;
+		ch_map[3] = PCM_CHANNEL_LS;
+		ch_map[4] = PCM_CHANNEL_RS;
+		break;
+	case 6:
+		ch_map[0] = PCM_CHANNEL_FL;
+		ch_map[1] = PCM_CHANNEL_FR;
+		ch_map[2] = PCM_CHANNEL_LFE;
+		ch_map[3] = PCM_CHANNEL_FC;
+		ch_map[4] = PCM_CHANNEL_LS;
+		ch_map[5] = PCM_CHANNEL_RS;
+		break;
+	case 8:
+		ch_map[0] = PCM_CHANNEL_FL;
+		ch_map[1] = PCM_CHANNEL_FR;
+		ch_map[2] = PCM_CHANNEL_LFE;
+		ch_map[3] = PCM_CHANNEL_FC;
+		ch_map[4] = PCM_CHANNEL_LS;
+		ch_map[5] = PCM_CHANNEL_RS;
+		ch_map[6] = PCM_CHANNEL_LB;
+		ch_map[7] = PCM_CHANNEL_RB;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(q6dsp_map_channels);
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/q6dsp-common.h b/sound/soc/qcom/qdsp6/q6dsp-common.h
new file mode 100644
index 000000000000..01094d108b8a
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6dsp-common.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __Q6DSP_COMMON_H__
+#define __Q6DSP_COMMON_H__
+
+#include <linux/kernel.h>
+
+#define PCM_MAX_NUM_CHANNEL  8
+#define PCM_CHANNEL_NULL 0
+
+#define PCM_CHANNEL_FL    1	/* Front left channel. */
+#define PCM_CHANNEL_FR    2	/* Front right channel. */
+#define PCM_CHANNEL_FC    3	/* Front center channel. */
+#define PCM_CHANNEL_LS   4	/* Left surround channel. */
+#define PCM_CHANNEL_RS   5	/* Right surround channel. */
+#define PCM_CHANNEL_LFE  6	/* Low frequency effect channel. */
+#define PCM_CHANNEL_CS   7	/* Center surround channel; Rear center ch */
+#define PCM_CHANNEL_LB   8	/* Left back channel; Rear left channel. */
+#define PCM_CHANNEL_RB   9	/* Right back channel; Rear right channel. */
+#define PCM_CHANNELS   10	/* Top surround channel. */
+
+int q6dsp_map_channels(u8 ch_map[PCM_MAX_NUM_CHANNEL], int ch);
+
+#endif /* __Q6DSP_COMMON_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6dsp-errno.h b/sound/soc/qcom/qdsp6/q6dsp-errno.h
new file mode 100644
index 000000000000..1ec00ff8c1d2
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6dsp-errno.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __Q6DSP_ERR_NO_H__
+#define __Q6DSP_ERR_NO_H__
+#include <linux/kernel.h>
+
+/* Success. The operation completed with no errors. */
+#define ADSP_EOK          0x00000000
+/* General failure. */
+#define ADSP_EFAILED      0x00000001
+/* Bad operation parameter. */
+#define ADSP_EBADPARAM    0x00000002
+/* Unsupported routine or operation. */
+#define ADSP_EUNSUPPORTED 0x00000003
+/* Unsupported version. */
+#define ADSP_EVERSION     0x00000004
+/* Unexpected problem encountered. */
+#define ADSP_EUNEXPECTED  0x00000005
+/* Unhandled problem occurred. */
+#define ADSP_EPANIC       0x00000006
+/* Unable to allocate resource. */
+#define ADSP_ENORESOURCE  0x00000007
+/* Invalid handle. */
+#define ADSP_EHANDLE      0x00000008
+/* Operation is already processed. */
+#define ADSP_EALREADY     0x00000009
+/* Operation is not ready to be processed. */
+#define ADSP_ENOTREADY    0x0000000A
+/* Operation is pending completion. */
+#define ADSP_EPENDING     0x0000000B
+/* Operation could not be accepted or processed. */
+#define ADSP_EBUSY        0x0000000C
+/* Operation aborted due to an error. */
+#define ADSP_EABORTED     0x0000000D
+/* Operation preempted by a higher priority. */
+#define ADSP_EPREEMPTED   0x0000000E
+/* Operation requests intervention to complete. */
+#define ADSP_ECONTINUE    0x0000000F
+/* Operation requests immediate intervention to complete. */
+#define ADSP_EIMMEDIATE   0x00000010
+/* Operation is not implemented. */
+#define ADSP_ENOTIMPL     0x00000011
+/* Operation needs more data or resources. */
+#define ADSP_ENEEDMORE    0x00000012
+/* Operation does not have memory. */
+#define ADSP_ENOMEMORY    0x00000014
+/* Item does not exist. */
+#define ADSP_ENOTEXIST    0x00000015
+/* Max count for adsp error code sent to HLOS*/
+
+#endif /*__Q6DSP_ERR_NO_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
new file mode 100644
index 000000000000..593f66b8622f
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -0,0 +1,1006 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+// Copyright (c) 2018, Linaro Limited
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/bitops.h>
+#include <linux/component.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/control.h>
+#include <sound/asound.h>
+#include <sound/pcm_params.h>
+#include "q6afe.h"
+#include "q6asm.h"
+#include "q6adm.h"
+#include "q6routing.h"
+
+#define DRV_NAME "q6routing-component"
+
+#define Q6ROUTING_RX_MIXERS(id)						\
+	SOC_SINGLE_EXT("MultiMedia1", id,				\
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,\
+	msm_routing_put_audio_mixer),					\
+	SOC_SINGLE_EXT("MultiMedia2", id,				\
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,\
+	msm_routing_put_audio_mixer),					\
+	SOC_SINGLE_EXT("MultiMedia3", id,				\
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,\
+	msm_routing_put_audio_mixer),					\
+	SOC_SINGLE_EXT("MultiMedia4", id,				\
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,\
+	msm_routing_put_audio_mixer),					\
+	SOC_SINGLE_EXT("MultiMedia5", id,				\
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,\
+	msm_routing_put_audio_mixer),					\
+	SOC_SINGLE_EXT("MultiMedia6", id,				\
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,\
+	msm_routing_put_audio_mixer),					\
+	SOC_SINGLE_EXT("MultiMedia7", id,				\
+	MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,\
+	msm_routing_put_audio_mixer),					\
+	SOC_SINGLE_EXT("MultiMedia8", id,				\
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,\
+	msm_routing_put_audio_mixer),
+
+#define Q6ROUTING_RX_DAPM_ROUTE(mix_name, s)	\
+	{ mix_name, "MultiMedia1", "MM_DL1" },	\
+	{ mix_name, "MultiMedia2", "MM_DL2" },	\
+	{ mix_name, "MultiMedia3", "MM_DL3" },	\
+	{ mix_name, "MultiMedia4", "MM_DL4" },	\
+	{ mix_name, "MultiMedia5", "MM_DL5" },	\
+	{ mix_name, "MultiMedia6", "MM_DL6" },	\
+	{ mix_name, "MultiMedia7", "MM_DL7" },	\
+	{ mix_name, "MultiMedia8", "MM_DL8" },	\
+	{ s, NULL, mix_name }
+
+#define Q6ROUTING_TX_DAPM_ROUTE(mix_name)		\
+	{ mix_name, "PRI_MI2S_TX", "PRI_MI2S_TX" },	\
+	{ mix_name, "SEC_MI2S_TX", "SEC_MI2S_TX" },	\
+	{ mix_name, "QUAT_MI2S_TX", "QUAT_MI2S_TX" },	\
+	{ mix_name, "TERT_MI2S_TX", "TERT_MI2S_TX" },		\
+	{ mix_name, "PRIMARY_TDM_TX_0", "PRIMARY_TDM_TX_0"},	\
+	{ mix_name, "PRIMARY_TDM_TX_1", "PRIMARY_TDM_TX_1"},	\
+	{ mix_name, "PRIMARY_TDM_TX_2", "PRIMARY_TDM_TX_2"},	\
+	{ mix_name, "PRIMARY_TDM_TX_3", "PRIMARY_TDM_TX_3"},	\
+	{ mix_name, "PRIMARY_TDM_TX_4", "PRIMARY_TDM_TX_4"},	\
+	{ mix_name, "PRIMARY_TDM_TX_5", "PRIMARY_TDM_TX_5"},	\
+	{ mix_name, "PRIMARY_TDM_TX_6", "PRIMARY_TDM_TX_6"},	\
+	{ mix_name, "PRIMARY_TDM_TX_7", "PRIMARY_TDM_TX_7"},	\
+	{ mix_name, "SEC_TDM_TX_0", "SEC_TDM_TX_0"},		\
+	{ mix_name, "SEC_TDM_TX_1", "SEC_TDM_TX_1"},		\
+	{ mix_name, "SEC_TDM_TX_2", "SEC_TDM_TX_2"},		\
+	{ mix_name, "SEC_TDM_TX_3", "SEC_TDM_TX_3"},		\
+	{ mix_name, "SEC_TDM_TX_4", "SEC_TDM_TX_4"},		\
+	{ mix_name, "SEC_TDM_TX_5", "SEC_TDM_TX_5"},		\
+	{ mix_name, "SEC_TDM_TX_6", "SEC_TDM_TX_6"},		\
+	{ mix_name, "SEC_TDM_TX_7", "SEC_TDM_TX_7"},		\
+	{ mix_name, "TERT_TDM_TX_0", "TERT_TDM_TX_0"},		\
+	{ mix_name, "TERT_TDM_TX_1", "TERT_TDM_TX_1"},		\
+	{ mix_name, "TERT_TDM_TX_2", "TERT_TDM_TX_2"},		\
+	{ mix_name, "TERT_TDM_TX_3", "TERT_TDM_TX_3"},		\
+	{ mix_name, "TERT_TDM_TX_4", "TERT_TDM_TX_4"},		\
+	{ mix_name, "TERT_TDM_TX_5", "TERT_TDM_TX_5"},		\
+	{ mix_name, "TERT_TDM_TX_6", "TERT_TDM_TX_6"},		\
+	{ mix_name, "TERT_TDM_TX_7", "TERT_TDM_TX_7"},		\
+	{ mix_name, "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},		\
+	{ mix_name, "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},		\
+	{ mix_name, "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},		\
+	{ mix_name, "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},		\
+	{ mix_name, "QUAT_TDM_TX_4", "QUAT_TDM_TX_4"},		\
+	{ mix_name, "QUAT_TDM_TX_5", "QUAT_TDM_TX_5"},		\
+	{ mix_name, "QUAT_TDM_TX_6", "QUAT_TDM_TX_6"},		\
+	{ mix_name, "QUAT_TDM_TX_7", "QUAT_TDM_TX_7"},		\
+	{ mix_name, "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},		\
+	{ mix_name, "QUIN_TDM_TX_1", "QUIN_TDM_TX_1"},		\
+	{ mix_name, "QUIN_TDM_TX_2", "QUIN_TDM_TX_2"},		\
+	{ mix_name, "QUIN_TDM_TX_3", "QUIN_TDM_TX_3"},		\
+	{ mix_name, "QUIN_TDM_TX_4", "QUIN_TDM_TX_4"},		\
+	{ mix_name, "QUIN_TDM_TX_5", "QUIN_TDM_TX_5"},		\
+	{ mix_name, "QUIN_TDM_TX_6", "QUIN_TDM_TX_6"},		\
+	{ mix_name, "QUIN_TDM_TX_7", "QUIN_TDM_TX_7"}
+
+#define Q6ROUTING_TX_MIXERS(id)						\
+	SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX,			\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("PRIMARY_TDM_TX_0", PRIMARY_TDM_TX_0,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("PRIMARY_TDM_TX_1", PRIMARY_TDM_TX_1,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("PRIMARY_TDM_TX_2", PRIMARY_TDM_TX_2,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("PRIMARY_TDM_TX_3", PRIMARY_TDM_TX_3,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("PRIMARY_TDM_TX_4", PRIMARY_TDM_TX_4,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("PRIMARY_TDM_TX_5", PRIMARY_TDM_TX_5,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("PRIMARY_TDM_TX_6", PRIMARY_TDM_TX_6,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("PRIMARY_TDM_TX_7", PRIMARY_TDM_TX_7,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", SECONDARY_TDM_TX_0,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", SECONDARY_TDM_TX_1,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", SECONDARY_TDM_TX_2,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", SECONDARY_TDM_TX_3,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("SEC_TDM_TX_4", SECONDARY_TDM_TX_4,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("SEC_TDM_TX_5", SECONDARY_TDM_TX_5,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("SEC_TDM_TX_6", SECONDARY_TDM_TX_6,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("SEC_TDM_TX_7", SECONDARY_TDM_TX_7,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("TERT_TDM_TX_0", TERTIARY_TDM_TX_0,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("TERT_TDM_TX_1", TERTIARY_TDM_TX_1,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("TERT_TDM_TX_2", TERTIARY_TDM_TX_2,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("TERT_TDM_TX_3", TERTIARY_TDM_TX_3,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("TERT_TDM_TX_4", TERTIARY_TDM_TX_4,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("TERT_TDM_TX_5", TERTIARY_TDM_TX_5,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("TERT_TDM_TX_6", TERTIARY_TDM_TX_6,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("TERT_TDM_TX_7", TERTIARY_TDM_TX_7,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0", QUATERNARY_TDM_TX_0,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUAT_TDM_TX_1", QUATERNARY_TDM_TX_1,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUAT_TDM_TX_2", QUATERNARY_TDM_TX_2,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUAT_TDM_TX_3", QUATERNARY_TDM_TX_3,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUAT_TDM_TX_4", QUATERNARY_TDM_TX_4,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUAT_TDM_TX_5", QUATERNARY_TDM_TX_5,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUAT_TDM_TX_6", QUATERNARY_TDM_TX_6,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUAT_TDM_TX_7", QUATERNARY_TDM_TX_7,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUIN_TDM_TX_0", QUINARY_TDM_TX_0,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUIN_TDM_TX_1", QUINARY_TDM_TX_1,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUIN_TDM_TX_2", QUINARY_TDM_TX_2,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUIN_TDM_TX_3", QUINARY_TDM_TX_3,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUIN_TDM_TX_4", QUINARY_TDM_TX_4,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUIN_TDM_TX_5", QUINARY_TDM_TX_5,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUIN_TDM_TX_6", QUINARY_TDM_TX_6,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),				\
+	SOC_SINGLE_EXT("QUIN_TDM_TX_7", QUINARY_TDM_TX_7,		\
+		id, 1, 0, msm_routing_get_audio_mixer,			\
+		msm_routing_put_audio_mixer),
+
+struct session_data {
+	int state;
+	int port_id;
+	int path_type;
+	int app_type;
+	int acdb_id;
+	int sample_rate;
+	int bits_per_sample;
+	int channels;
+	int perf_mode;
+	int numcopps;
+	int fedai_id;
+	unsigned long copp_map;
+	struct q6copp *copps[MAX_COPPS_PER_PORT];
+};
+
+struct msm_routing_data {
+	struct session_data sessions[MAX_SESSIONS];
+	struct session_data port_data[AFE_MAX_PORTS];
+	struct device *dev;
+	struct mutex lock;
+};
+
+static struct msm_routing_data *routing_data;
+
+/**
+ * q6routing_stream_open() - Register a new stream for route setup
+ *
+ * @fedai_id: Frontend dai id.
+ * @perf_mode: Performance mode.
+ * @stream_id: ASM stream id to map.
+ * @stream_type: Direction of stream
+ *
+ * Return: Will be an negative on error or a zero on success.
+ */
+int q6routing_stream_open(int fedai_id, int perf_mode,
+			   int stream_id, int stream_type)
+{
+	int j, topology, num_copps = 0;
+	struct route_payload payload;
+	struct q6copp *copp;
+	int copp_idx;
+	struct session_data *session, *pdata;
+
+	if (!routing_data) {
+		pr_err("Routing driver not yet ready\n");
+		return -EINVAL;
+	}
+
+	session = &routing_data->sessions[stream_id - 1];
+	pdata = &routing_data->port_data[session->port_id];
+
+	mutex_lock(&routing_data->lock);
+	session->fedai_id = fedai_id;
+
+	session->path_type = pdata->path_type;
+	session->sample_rate = pdata->sample_rate;
+	session->channels = pdata->channels;
+	session->bits_per_sample = pdata->bits_per_sample;
+
+	payload.num_copps = 0; /* only RX needs to use payload */
+	topology = NULL_COPP_TOPOLOGY;
+	copp = q6adm_open(routing_data->dev, session->port_id,
+			      session->path_type, session->sample_rate,
+			      session->channels, topology, perf_mode,
+			      session->bits_per_sample, 0, 0);
+
+	if (!copp) {
+		mutex_unlock(&routing_data->lock);
+		return -EINVAL;
+	}
+
+	copp_idx = q6adm_get_copp_id(copp);
+	set_bit(copp_idx, &session->copp_map);
+	session->copps[copp_idx] = copp;
+
+	for_each_set_bit(j, &session->copp_map, MAX_COPPS_PER_PORT) {
+		payload.port_id[num_copps] = session->port_id;
+		payload.copp_idx[num_copps] = j;
+		num_copps++;
+	}
+
+	if (num_copps) {
+		payload.num_copps = num_copps;
+		payload.session_id = stream_id;
+		q6adm_matrix_map(routing_data->dev, session->path_type,
+				 payload, perf_mode);
+	}
+	mutex_unlock(&routing_data->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(q6routing_stream_open);
+
+static struct session_data *get_session_from_id(struct msm_routing_data *data,
+						int fedai_id)
+{
+	int i;
+
+	for (i = 0; i < MAX_SESSIONS; i++) {
+		if (fedai_id == data->sessions[i].fedai_id)
+			return &data->sessions[i];
+	}
+
+	return NULL;
+}
+/**
+ * q6routing_stream_close() - Deregister a stream
+ *
+ * @fedai_id: Frontend dai id.
+ * @stream_type: Direction of stream
+ *
+ * Return: Will be an negative on error or a zero on success.
+ */
+void q6routing_stream_close(int fedai_id, int stream_type)
+{
+	struct session_data *session;
+	int idx;
+
+	session = get_session_from_id(routing_data, fedai_id);
+	if (!session)
+		return;
+
+	for_each_set_bit(idx, &session->copp_map, MAX_COPPS_PER_PORT) {
+		if (session->copps[idx]) {
+			q6adm_close(routing_data->dev, session->copps[idx]);
+			session->copps[idx] = NULL;
+		}
+	}
+
+	session->fedai_id = -1;
+	session->copp_map = 0;
+}
+EXPORT_SYMBOL_GPL(q6routing_stream_close);
+
+static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm =
+	    snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct soc_mixer_control *mc =
+	    (struct soc_mixer_control *)kcontrol->private_value;
+	int session_id = mc->shift;
+	struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
+	struct msm_routing_data *priv = dev_get_drvdata(c->dev);
+	struct session_data *session = &priv->sessions[session_id];
+
+	if (session->port_id == mc->reg)
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	return 0;
+}
+
+static int msm_routing_put_audio_mixer(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 msm_routing_data *data = dev_get_drvdata(c->dev);
+	struct soc_mixer_control *mc =
+		    (struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_dapm_update *update = NULL;
+	int be_id = mc->reg;
+	int session_id = mc->shift;
+	struct session_data *session = &data->sessions[session_id];
+
+	if (ucontrol->value.integer.value[0]) {
+		session->port_id = be_id;
+		snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, update);
+	} else {
+		session->port_id = -1;
+		snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, update);
+	}
+
+	return 1;
+}
+
+static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(HDMI_RX) };
+
+static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(PRIMARY_MI2S_RX) };
+
+static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SECONDARY_MI2S_RX) };
+
+static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUATERNARY_MI2S_RX) };
+
+static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(TERTIARY_MI2S_RX) };
+
+static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SLIMBUS_0_RX) };
+
+static const struct snd_kcontrol_new slimbus_1_rx_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SLIMBUS_1_RX) };
+
+static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SLIMBUS_2_RX) };
+
+static const struct snd_kcontrol_new slimbus_3_rx_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SLIMBUS_3_RX) };
+
+static const struct snd_kcontrol_new slimbus_4_rx_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SLIMBUS_4_RX) };
+
+static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SLIMBUS_5_RX) };
+
+static const struct snd_kcontrol_new slimbus_6_rx_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SLIMBUS_6_RX) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_0_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_0) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_1) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_2_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_2) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_3_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_3) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_4_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_4) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_5_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_5) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_6_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_6) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_7_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_7) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_0_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_0) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_1) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_2_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_2) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_3_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_3) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_4_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_4) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_5_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_5) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_6_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_6) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_7_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_7) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_0_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_0) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_1_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_1) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_2_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_2) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_3) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_4) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_5_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_5) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_6_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_6) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_7_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_7) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_0) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_1_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_1) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_2) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_3) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_4_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_4) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_5_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_5) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_6_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_6) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_7_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_7) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_0_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_0) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_1_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_1) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_2_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_2) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_3_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_3) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_4_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_4) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_5_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_5) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_6_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_6) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_7_mixer_controls[] = {
+	Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_7) };
+
+
+static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
+	Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA1) };
+
+static const struct snd_kcontrol_new mmul2_mixer_controls[] = {
+	Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA2) };
+
+static const struct snd_kcontrol_new mmul3_mixer_controls[] = {
+	Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA3) };
+
+static const struct snd_kcontrol_new mmul4_mixer_controls[] = {
+	Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA4) };
+
+static const struct snd_kcontrol_new mmul5_mixer_controls[] = {
+	Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA5) };
+
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+	Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA6) };
+
+static const struct snd_kcontrol_new mmul7_mixer_controls[] = {
+	Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA7) };
+
+static const struct snd_kcontrol_new mmul8_mixer_controls[] = {
+	Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA8) };
+
+static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
+	/* Frontend AIF */
+	SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
+
+	/* Mixer definitions */
+	SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0,
+			   hdmi_mixer_controls,
+			   ARRAY_SIZE(hdmi_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+			   slimbus_rx_mixer_controls,
+			   ARRAY_SIZE(slimbus_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+			   slimbus_1_rx_mixer_controls,
+			   ARRAY_SIZE(slimbus_1_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_2_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+			   slimbus_2_rx_mixer_controls,
+			   ARRAY_SIZE(slimbus_2_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_3_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+			   slimbus_3_rx_mixer_controls,
+			   ARRAY_SIZE(slimbus_3_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_4_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+			   slimbus_4_rx_mixer_controls,
+			   ARRAY_SIZE(slimbus_4_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_5_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+			   slimbus_5_rx_mixer_controls,
+			    ARRAY_SIZE(slimbus_5_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_6_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+			   slimbus_6_rx_mixer_controls,
+			   ARRAY_SIZE(slimbus_6_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRI_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+			   primary_mi2s_rx_mixer_controls,
+			   ARRAY_SIZE(primary_mi2s_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+			   secondary_mi2s_rx_mixer_controls,
+			   ARRAY_SIZE(secondary_mi2s_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+			   quaternary_mi2s_rx_mixer_controls,
+			   ARRAY_SIZE(quaternary_mi2s_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("TERT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+			   tertiary_mi2s_rx_mixer_controls,
+			   ARRAY_SIZE(tertiary_mi2s_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_0_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_0_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_1_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_2_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_3_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_4_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_4_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_5_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_6_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_6_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				pri_tdm_rx_7_mixer_controls,
+				ARRAY_SIZE(pri_tdm_rx_7_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				sec_tdm_rx_0_mixer_controls,
+				ARRAY_SIZE(sec_tdm_rx_0_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				sec_tdm_rx_1_mixer_controls,
+				ARRAY_SIZE(sec_tdm_rx_1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				sec_tdm_rx_2_mixer_controls,
+				ARRAY_SIZE(sec_tdm_rx_2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				sec_tdm_rx_3_mixer_controls,
+				ARRAY_SIZE(sec_tdm_rx_3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				sec_tdm_rx_4_mixer_controls,
+				ARRAY_SIZE(sec_tdm_rx_4_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				sec_tdm_rx_5_mixer_controls,
+				ARRAY_SIZE(sec_tdm_rx_5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				sec_tdm_rx_6_mixer_controls,
+				ARRAY_SIZE(sec_tdm_rx_6_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SEC_TDM_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				sec_tdm_rx_7_mixer_controls,
+				ARRAY_SIZE(sec_tdm_rx_7_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("TERT_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				tert_tdm_rx_0_mixer_controls,
+				ARRAY_SIZE(tert_tdm_rx_0_mixer_controls)),
+	SND_SOC_DAPM_MIXER("TERT_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				tert_tdm_rx_1_mixer_controls,
+				ARRAY_SIZE(tert_tdm_rx_1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("TERT_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				tert_tdm_rx_2_mixer_controls,
+				ARRAY_SIZE(tert_tdm_rx_2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("TERT_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				tert_tdm_rx_3_mixer_controls,
+				ARRAY_SIZE(tert_tdm_rx_3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("TERT_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				tert_tdm_rx_4_mixer_controls,
+				ARRAY_SIZE(tert_tdm_rx_4_mixer_controls)),
+	SND_SOC_DAPM_MIXER("TERT_TDM_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				tert_tdm_rx_5_mixer_controls,
+				ARRAY_SIZE(tert_tdm_rx_5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("TERT_TDM_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				tert_tdm_rx_6_mixer_controls,
+				ARRAY_SIZE(tert_tdm_rx_6_mixer_controls)),
+	SND_SOC_DAPM_MIXER("TERT_TDM_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				tert_tdm_rx_7_mixer_controls,
+				ARRAY_SIZE(tert_tdm_rx_7_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quat_tdm_rx_0_mixer_controls,
+				ARRAY_SIZE(quat_tdm_rx_0_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quat_tdm_rx_1_mixer_controls,
+				ARRAY_SIZE(quat_tdm_rx_1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quat_tdm_rx_2_mixer_controls,
+				ARRAY_SIZE(quat_tdm_rx_2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quat_tdm_rx_3_mixer_controls,
+				ARRAY_SIZE(quat_tdm_rx_3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quat_tdm_rx_4_mixer_controls,
+				ARRAY_SIZE(quat_tdm_rx_4_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quat_tdm_rx_5_mixer_controls,
+				ARRAY_SIZE(quat_tdm_rx_5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quat_tdm_rx_6_mixer_controls,
+				ARRAY_SIZE(quat_tdm_rx_6_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quat_tdm_rx_7_mixer_controls,
+				ARRAY_SIZE(quat_tdm_rx_7_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("QUIN_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quin_tdm_rx_0_mixer_controls,
+				ARRAY_SIZE(quin_tdm_rx_0_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUIN_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quin_tdm_rx_1_mixer_controls,
+				ARRAY_SIZE(quin_tdm_rx_1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUIN_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quin_tdm_rx_2_mixer_controls,
+				ARRAY_SIZE(quin_tdm_rx_2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUIN_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quin_tdm_rx_3_mixer_controls,
+				ARRAY_SIZE(quin_tdm_rx_3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUIN_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quin_tdm_rx_4_mixer_controls,
+				ARRAY_SIZE(quin_tdm_rx_4_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUIN_TDM_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quin_tdm_rx_5_mixer_controls,
+				ARRAY_SIZE(quin_tdm_rx_5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUIN_TDM_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quin_tdm_rx_6_mixer_controls,
+				ARRAY_SIZE(quin_tdm_rx_6_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUIN_TDM_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quin_tdm_rx_7_mixer_controls,
+				ARRAY_SIZE(quin_tdm_rx_7_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
+		mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
+		mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia3 Mixer", SND_SOC_NOPM, 0, 0,
+		mmul3_mixer_controls, ARRAY_SIZE(mmul3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia4 Mixer", SND_SOC_NOPM, 0, 0,
+		mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
+		mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+		mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia7 Mixer", SND_SOC_NOPM, 0, 0,
+		mmul7_mixer_controls, ARRAY_SIZE(mmul7_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
+		mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
+
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	Q6ROUTING_RX_DAPM_ROUTE("HDMI Mixer", "HDMI_RX"),
+	Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_0_RX Audio Mixer", "SLIMBUS_0_RX"),
+	Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_1_RX Audio Mixer", "SLIMBUS_1_RX"),
+	Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_2_RX Audio Mixer", "SLIMBUS_2_RX"),
+	Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_3_RX Audio Mixer", "SLIMBUS_3_RX"),
+	Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_4_RX Audio Mixer", "SLIMBUS_4_RX"),
+	Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_5_RX Audio Mixer", "SLIMBUS_5_RX"),
+	Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_6_RX Audio Mixer", "SLIMBUS_6_RX"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUAT_MI2S_RX Audio Mixer", "QUAT_MI2S_RX"),
+	Q6ROUTING_RX_DAPM_ROUTE("TERT_MI2S_RX Audio Mixer", "TERT_MI2S_RX"),
+	Q6ROUTING_RX_DAPM_ROUTE("SEC_MI2S_RX Audio Mixer", "SEC_MI2S_RX"),
+	Q6ROUTING_RX_DAPM_ROUTE("PRI_MI2S_RX Audio Mixer", "PRI_MI2S_RX"),
+	Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_0 Audio Mixer",
+				"PRIMARY_TDM_RX_0"),
+	Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_1 Audio Mixer",
+				"PRIMARY_TDM_RX_1"),
+	Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_2 Audio Mixer",
+				"PRIMARY_TDM_RX_2"),
+	Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_3 Audio Mixer",
+				"PRIMARY_TDM_RX_3"),
+	Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_4 Audio Mixer",
+				"PRIMARY_TDM_RX_4"),
+	Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_5 Audio Mixer",
+				"PRIMARY_TDM_RX_5"),
+	Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_6 Audio Mixer",
+				"PRIMARY_TDM_RX_6"),
+	Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_7 Audio Mixer",
+				"PRIMARY_TDM_RX_7"),
+	Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_0 Audio Mixer", "SEC_TDM_RX_0"),
+	Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_1 Audio Mixer", "SEC_TDM_RX_1"),
+	Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_2 Audio Mixer", "SEC_TDM_RX_2"),
+	Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_3 Audio Mixer", "SEC_TDM_RX_3"),
+	Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_4 Audio Mixer", "SEC_TDM_RX_4"),
+	Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_5 Audio Mixer", "SEC_TDM_RX_5"),
+	Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_6 Audio Mixer", "SEC_TDM_RX_6"),
+	Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_7 Audio Mixer", "SEC_TDM_RX_7"),
+	Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_0 Audio Mixer", "TERT_TDM_RX_0"),
+	Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_1 Audio Mixer", "TERT_TDM_RX_1"),
+	Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_2 Audio Mixer", "TERT_TDM_RX_2"),
+	Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_3 Audio Mixer", "TERT_TDM_RX_3"),
+	Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_4 Audio Mixer", "TERT_TDM_RX_4"),
+	Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_5 Audio Mixer", "TERT_TDM_RX_5"),
+	Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_6 Audio Mixer", "TERT_TDM_RX_6"),
+	Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_7 Audio Mixer", "TERT_TDM_RX_7"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_0 Audio Mixer", "QUAT_TDM_RX_0"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_1 Audio Mixer", "QUAT_TDM_RX_1"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_2 Audio Mixer", "QUAT_TDM_RX_2"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_3 Audio Mixer", "QUAT_TDM_RX_3"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_4 Audio Mixer", "QUAT_TDM_RX_4"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_5 Audio Mixer", "QUAT_TDM_RX_5"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_6 Audio Mixer", "QUAT_TDM_RX_6"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_7 Audio Mixer", "QUAT_TDM_RX_7"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_0 Audio Mixer", "QUIN_TDM_RX_0"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_1 Audio Mixer", "QUIN_TDM_RX_1"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_2 Audio Mixer", "QUIN_TDM_RX_2"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_3 Audio Mixer", "QUIN_TDM_RX_3"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_4 Audio Mixer", "QUIN_TDM_RX_4"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_5 Audio Mixer", "QUIN_TDM_RX_5"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_6 Audio Mixer", "QUIN_TDM_RX_6"),
+	Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_7 Audio Mixer", "QUIN_TDM_RX_7"),
+	Q6ROUTING_TX_DAPM_ROUTE("MultiMedia1 Mixer"),
+	Q6ROUTING_TX_DAPM_ROUTE("MultiMedia2 Mixer"),
+	Q6ROUTING_TX_DAPM_ROUTE("MultiMedia3 Mixer"),
+	Q6ROUTING_TX_DAPM_ROUTE("MultiMedia4 Mixer"),
+	Q6ROUTING_TX_DAPM_ROUTE("MultiMedia5 Mixer"),
+	Q6ROUTING_TX_DAPM_ROUTE("MultiMedia6 Mixer"),
+	Q6ROUTING_TX_DAPM_ROUTE("MultiMedia7 Mixer"),
+	Q6ROUTING_TX_DAPM_ROUTE("MultiMedia8 Mixer"),
+
+	{"MM_UL1", NULL, "MultiMedia1 Mixer"},
+	{"MM_UL2", NULL, "MultiMedia2 Mixer"},
+	{"MM_UL3", NULL, "MultiMedia3 Mixer"},
+	{"MM_UL4", NULL, "MultiMedia4 Mixer"},
+	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
+	{"MM_UL6", NULL, "MultiMedia6 Mixer"},
+	{"MM_UL7", NULL, "MultiMedia7 Mixer"},
+	{"MM_UL8", NULL, "MultiMedia8 Mixer"},
+};
+
+static int routing_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_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct msm_routing_data *data = dev_get_drvdata(c->dev);
+	unsigned int be_id = rtd->cpu_dai->id;
+	struct session_data *session;
+	int path_type;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		path_type = ADM_PATH_PLAYBACK;
+	else
+		path_type = ADM_PATH_LIVE_REC;
+
+	if (be_id > AFE_MAX_PORTS)
+		return -EINVAL;
+
+	session = &data->port_data[be_id];
+
+	mutex_lock(&data->lock);
+
+	session->path_type = path_type;
+	session->sample_rate = params_rate(params);
+	session->channels = params_channels(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+			session->bits_per_sample = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+			session->bits_per_sample = 24;
+		break;
+	default:
+		break;
+	}
+
+	mutex_unlock(&data->lock);
+	return 0;
+}
+
+static struct snd_pcm_ops q6pcm_routing_ops = {
+	.hw_params = routing_hw_params,
+};
+
+static int msm_routing_probe(struct snd_soc_component *c)
+{
+	int i;
+
+	for (i = 0; i < MAX_SESSIONS; i++)
+		routing_data->sessions[i].port_id = -1;
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver msm_soc_routing_component = {
+	.ops = &q6pcm_routing_ops,
+	.probe = msm_routing_probe,
+	.name = DRV_NAME,
+	.dapm_widgets = msm_qdsp6_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(msm_qdsp6_widgets),
+	.dapm_routes = intercon,
+	.num_dapm_routes = ARRAY_SIZE(intercon),
+};
+
+static int q6routing_dai_bind(struct device *dev, struct device *master,
+			      void *data)
+{
+	routing_data = kzalloc(sizeof(*routing_data), GFP_KERNEL);
+	if (!routing_data)
+		return -ENOMEM;
+
+	routing_data->dev = dev;
+
+	mutex_init(&routing_data->lock);
+	dev_set_drvdata(dev, routing_data);
+
+	return snd_soc_register_component(dev, &msm_soc_routing_component,
+					  NULL, 0);
+}
+
+static void q6routing_dai_unbind(struct device *dev, struct device *master,
+				 void *d)
+{
+	struct msm_routing_data *data = dev_get_drvdata(dev);
+
+	snd_soc_unregister_component(dev);
+
+	kfree(data);
+
+	routing_data = NULL;
+}
+
+static const struct component_ops q6routing_dai_comp_ops = {
+	.bind   = q6routing_dai_bind,
+	.unbind = q6routing_dai_unbind,
+};
+
+static int q6pcm_routing_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &q6routing_dai_comp_ops);
+}
+
+static int q6pcm_routing_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &q6routing_dai_comp_ops);
+	return 0;
+}
+
+static struct platform_driver q6pcm_routing_platform_driver = {
+	.driver = {
+		.name = "q6routing",
+	},
+	.probe = q6pcm_routing_probe,
+	.remove = q6pcm_routing_remove,
+};
+module_platform_driver(q6pcm_routing_platform_driver);
+
+MODULE_DESCRIPTION("Q6 Routing platform");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/q6routing.h b/sound/soc/qcom/qdsp6/q6routing.h
new file mode 100644
index 000000000000..35514e651130
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6routing.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _Q6_PCM_ROUTING_H
+#define _Q6_PCM_ROUTING_H
+
+int q6routing_stream_open(int fedai_id, int perf_mode,
+			   int stream_id, int stream_type);
+void q6routing_stream_close(int fedai_id, int stream_type);
+
+#endif /*_Q6_PCM_ROUTING_H */
diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c
index 9a10181a0811..f184168f9a41 100644
--- a/sound/soc/rockchip/rk3399_gru_sound.c
+++ b/sound/soc/rockchip/rk3399_gru_sound.c
@@ -220,45 +220,6 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static int rockchip_sound_cdndp_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 *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	int mclk, ret;
-
-	/* in bypass mode, the mclk has to be one of the frequencies below */
-	switch (params_rate(params)) {
-	case 8000:
-	case 16000:
-	case 24000:
-	case 32000:
-	case 48000:
-	case 64000:
-	case 96000:
-		mclk = 12288000;
-		break;
-	case 11025:
-	case 22050:
-	case 44100:
-	case 88200:
-		mclk = 11289600;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
-				     SND_SOC_CLOCK_OUT);
-	if (ret < 0) {
-		dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
 static int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params)
 {
@@ -293,10 +254,6 @@ static const struct snd_soc_ops rockchip_sound_da7219_ops = {
 	.hw_params = rockchip_sound_da7219_hw_params,
 };
 
-static const struct snd_soc_ops rockchip_sound_cdndp_ops = {
-	.hw_params = rockchip_sound_cdndp_hw_params,
-};
-
 static const struct snd_soc_ops rockchip_sound_dmic_ops = {
 	.hw_params = rockchip_sound_dmic_hw_params,
 };
@@ -323,8 +280,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = {
 	[DAILINK_CDNDP] = {
 		.name = "DP",
 		.stream_name = "DP PCM",
-		.codec_dai_name = "i2s-hifi",
-		.ops = &rockchip_sound_cdndp_ops,
+		.codec_dai_name = "spdif-hifi",
 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 			SND_SOC_DAIFMT_CBS_CFS,
 	},
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 1aa5cd77ca24..0ae0800bf3a8 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -1,5 +1,5 @@
-menu "SoC Audio support for SuperH"
-	depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
+menu "SoC Audio support for Renesas SoCs"
+	depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
 
 config SND_SOC_PCM_SH7760
 	tristate "SoC Audio support for Renesas SH7760"
@@ -28,7 +28,7 @@ config SND_SOC_SH4_FSI
 
 config SND_SOC_SH4_SIU
 	tristate
-	depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
+	depends on ARCH_SHMOBILE && HAVE_CLK
 	select DMA_ENGINE
 	select DMADEVICES
 	select SH_DMAE
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
index f1d4fb566892..4221937ae79b 100644
--- a/sound/soc/sh/rcar/cmd.c
+++ b/sound/soc/sh/rcar/cmd.c
@@ -125,6 +125,13 @@ static struct rsnd_mod_ops rsnd_cmd_ops = {
 	.stop	= rsnd_cmd_stop,
 };
 
+static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
+{
+	if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
+		id = 0;
+
+	return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
+}
 int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
 {
 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
@@ -133,14 +140,6 @@ int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
 	return rsnd_dai_connect(mod, io, mod->type);
 }
 
-struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
-{
-	if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
-		id = 0;
-
-	return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
-}
-
 int rsnd_cmd_probe(struct rsnd_priv *priv)
 {
 	struct device *dev = rsnd_priv_to_dev(priv);
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 94f081b93258..af04d41a4274 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -111,7 +111,7 @@
 static const struct of_device_id rsnd_of_match[] = {
 	{ .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
 	{ .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 },
-	{ .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN2 }, /* gen2 compatible */
+	{ .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN3 },
 	{},
 };
 MODULE_DEVICE_TABLE(of, rsnd_of_match);
@@ -1352,6 +1352,37 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
 #define PREALLOC_BUFFER		(32 * 1024)
 #define PREALLOC_BUFFER_MAX	(32 * 1024)
 
+static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd,
+				  struct rsnd_dai_stream *io,
+				  int stream)
+{
+	struct rsnd_priv *priv = rsnd_io_to_priv(io);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct snd_pcm_substream *substream;
+	int err;
+
+	/*
+	 * use Audio-DMAC dev if we can use IPMMU
+	 * see
+	 *	rsnd_dmaen_attach()
+	 */
+	if (io->dmac_dev)
+		dev = io->dmac_dev;
+
+	for (substream = rtd->pcm->streams[stream].substream;
+	     substream;
+	     substream = substream->next) {
+		err = snd_pcm_lib_preallocate_pages(substream,
+					SNDRV_DMA_TYPE_DEV,
+					dev,
+					PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
 static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_dai *dai = rtd->cpu_dai;
@@ -1366,11 +1397,17 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	if (ret)
 		return ret;
 
-	return snd_pcm_lib_preallocate_pages_for_all(
-		rtd->pcm,
-		SNDRV_DMA_TYPE_DEV,
-		rtd->card->snd_card->dev,
-		PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+	ret = rsnd_preallocate_pages(rtd, &rdai->playback,
+				     SNDRV_PCM_STREAM_PLAYBACK);
+	if (ret)
+		return ret;
+
+	ret = rsnd_preallocate_pages(rtd, &rdai->capture,
+				     SNDRV_PCM_STREAM_CAPTURE);
+	if (ret)
+		return ret;
+
+	return 0;
 }
 
 static const struct snd_soc_component_driver rsnd_soc_component = {
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 41de23417c4a..ef82b94d038b 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -253,6 +253,13 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
 		return -EAGAIN;
 	}
 
+	/*
+	 * use it for IPMMU if needed
+	 * see
+	 *	rsnd_preallocate_pages()
+	 */
+	io->dmac_dev = chan->device->dev;
+
 	dma_release_channel(chan);
 
 	dmac->dmaen_num++;
@@ -695,7 +702,7 @@ static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
 
 	rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to);
 
-	/* for Gen2 */
+	/* for Gen2 or later */
 	if (mod_from && mod_to) {
 		ops	= &rsnd_dmapp_ops;
 		attach	= rsnd_dmapp_attach;
@@ -773,7 +780,7 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
 		return 0;
 
 	/*
-	 * for Gen2
+	 * for Gen2 or later
 	 */
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp");
 	dmac = devm_kzalloc(dev, sizeof(*dmac), GFP_KERNEL);
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index f04c4100043a..25642e92dae0 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -414,7 +414,8 @@ int rsnd_gen_probe(struct rsnd_priv *priv)
 	ret = -ENODEV;
 	if (rsnd_is_gen1(priv))
 		ret = rsnd_gen1_probe(priv);
-	else if (rsnd_is_gen2(priv))
+	else if (rsnd_is_gen2(priv) ||
+		 rsnd_is_gen3(priv))
 		ret = rsnd_gen2_probe(priv);
 
 	if (ret < 0)
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 172c8d612890..6d7280d2d9be 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -435,6 +435,7 @@ struct rsnd_dai_stream {
 	struct snd_pcm_substream *substream;
 	struct rsnd_mod *mod[RSND_MOD_MAX];
 	struct rsnd_dai *rdai;
+	struct device *dmac_dev; /* for IPMMU */
 	u32 parent_ssi_status;
 };
 #define rsnd_io_to_mod(io, i)	((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
@@ -538,6 +539,7 @@ struct rsnd_priv {
 #define RSND_GEN_MASK	(0xF << 0)
 #define RSND_GEN1	(1 << 0)
 #define RSND_GEN2	(2 << 0)
+#define RSND_GEN3	(3 << 0)
 
 	/*
 	 * below value will be filled on rsnd_gen_probe()
@@ -609,6 +611,7 @@ struct rsnd_priv {
 
 #define rsnd_is_gen1(priv)	(((priv)->flags & RSND_GEN_MASK) == RSND_GEN1)
 #define rsnd_is_gen2(priv)	(((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
+#define rsnd_is_gen3(priv)	(((priv)->flags & RSND_GEN_MASK) == RSND_GEN3)
 
 #define rsnd_flags_has(p, f) ((p)->flags & (f))
 #define rsnd_flags_set(p, f) ((p)->flags |= (f))
@@ -775,7 +778,6 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
 int rsnd_cmd_probe(struct rsnd_priv *priv);
 void rsnd_cmd_remove(struct rsnd_priv *priv);
 int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id);
-struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id);
 
 void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
 #ifdef DEBUG
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 333b802681ad..9538f76f8e20 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -171,7 +171,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
 		if (status & bit)
 			return;
 
-		udelay(50);
+		udelay(5);
 	}
 
 	dev_warn(dev, "%s[%d] status check failed\n",
@@ -1004,19 +1004,26 @@ static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
 	struct rsnd_ssi *ssi;
+	struct device_node *remote_node = of_graph_get_port_parent(remote_ep);
+
+	/* support Gen3 only */
+	if (!rsnd_is_gen3(priv))
+		return;
 
 	if (!mod)
 		return;
 
 	ssi  = rsnd_mod_to_ssi(mod);
 
-	if (strstr(remote_ep->full_name, "hdmi0")) {
+	/* HDMI0 */
+	if (strstr(remote_node->full_name, "hdmi@fead0000")) {
 		rsnd_flags_set(ssi, RSND_SSI_HDMI0);
 		dev_dbg(dev, "%s[%d] connected to HDMI0\n",
 			 rsnd_mod_name(mod), rsnd_mod_id(mod));
 	}
 
-	if (strstr(remote_ep->full_name, "hdmi1")) {
+	/* HDMI1 */
+	if (strstr(remote_node->full_name, "hdmi@feae0000")) {
 		rsnd_flags_set(ssi, RSND_SSI_HDMI1);
 		dev_dbg(dev, "%s[%d] connected to HDMI1\n",
 			rsnd_mod_name(mod), rsnd_mod_id(mod));
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
deleted file mode 100644
index 07f43356f963..000000000000
--- a/sound/soc/soc-cache.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * soc-cache.c  --  ASoC register cache helpers
- *
- * Copyright 2009 Wolfson Microelectronics PLC.
- *
- * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#include <sound/soc.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-
-int snd_soc_cache_init(struct snd_soc_codec *codec)
-{
-	const struct snd_soc_codec_driver *codec_drv = codec->driver;
-	size_t reg_size;
-
-	reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
-
-	if (!reg_size)
-		return 0;
-
-	dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n",
-				codec->component.name);
-
-	if (codec_drv->reg_cache_default)
-		codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
-					   reg_size, GFP_KERNEL);
-	else
-		codec->reg_cache = kzalloc(reg_size, GFP_KERNEL);
-	if (!codec->reg_cache)
-		return -ENOMEM;
-
-	return 0;
-}
-
-/*
- * NOTE: keep in mind that this function might be called
- * multiple times.
- */
-int snd_soc_cache_exit(struct snd_soc_codec *codec)
-{
-	dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n",
-			codec->component.name);
-	kfree(codec->reg_cache);
-	codec->reg_cache = NULL;
-	return 0;
-}
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 82402688bd8e..e095115fa9f9 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -26,56 +26,79 @@
 #include <sound/initval.h>
 #include <sound/soc-dpcm.h>
 
-static int soc_compr_open(struct snd_compr_stream *cstream)
+static int soc_compr_components_open(struct snd_compr_stream *cstream,
+				     struct snd_soc_component **last)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	int ret = 0, __ret;
+	int ret;
 
-	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
+	for_each_rtdcom(rtd, rtdcom) {
+		component = rtdcom->component;
 
-	if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
-		ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
-		if (ret < 0) {
-			dev_err(cpu_dai->dev,
-				"Compress ASoC: can't open interface %s: %d\n",
-				cpu_dai->name, ret);
-			goto out;
-		}
-	}
+		if (!component->driver->compr_ops ||
+		    !component->driver->compr_ops->open)
+			continue;
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->open) {
-		ret = platform->driver->compr_ops->open(cstream);
+		ret = component->driver->compr_ops->open(cstream);
 		if (ret < 0) {
-			dev_err(platform->dev,
+			dev_err(component->dev,
 				"Compress ASoC: can't open platform %s: %d\n",
-				platform->component.name, ret);
-			goto plat_err;
+				component->name, ret);
+
+			*last = component;
+			return ret;
 		}
 	}
 
+	*last = NULL;
+	return 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;
+	struct snd_soc_rtdcom_list *rtdcom;
+
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
+		if (component == last)
+			break;
 
 		if (!component->driver->compr_ops ||
-		    !component->driver->compr_ops->open)
+		    !component->driver->compr_ops->free)
 			continue;
 
-		__ret = component->driver->compr_ops->open(cstream);
-		if (__ret < 0) {
-			dev_err(component->dev,
-				"Compress ASoC: can't open platform %s: %d\n",
-				component->name, __ret);
-			ret = __ret;
+		component->driver->compr_ops->free(cstream);
+	}
+
+	return 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;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret;
+
+	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
+
+	if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
+		ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
+		if (ret < 0) {
+			dev_err(cpu_dai->dev,
+				"Compress ASoC: can't open interface %s: %d\n",
+				cpu_dai->name, ret);
+			goto out;
 		}
 	}
+
+	ret = soc_compr_components_open(cstream, &component);
 	if (ret < 0)
 		goto machine_err;
 
@@ -96,23 +119,8 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
 	return 0;
 
 machine_err:
-	for_each_rtdcom(rtd, rtdcom) {
-		component = rtdcom->component;
-
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
-		if (!component->driver->compr_ops ||
-		    !component->driver->compr_ops->free)
-			continue;
+	soc_compr_components_free(cstream, component);
 
-		component->driver->compr_ops->free(cstream);
-	}
-
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->free)
-		platform->driver->compr_ops->free(cstream);
-plat_err:
 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
 		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
 out:
@@ -125,14 +133,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_platform *platform = fe->platform;
 	struct snd_soc_component *component;
-	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
 	struct snd_soc_dpcm *dpcm;
 	struct snd_soc_dapm_widget_list *list;
 	int stream;
-	int ret = 0, __ret;
+	int ret;
 
 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
 		stream = SNDRV_PCM_STREAM_PLAYBACK;
@@ -151,35 +157,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 		}
 	}
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->open) {
-		ret = platform->driver->compr_ops->open(cstream);
-		if (ret < 0) {
-			dev_err(platform->dev,
-				"Compress ASoC: can't open platform %s: %d\n",
-				platform->component.name, ret);
-			goto plat_err;
-		}
-	}
-
-	for_each_rtdcom(fe, rtdcom) {
-		component = rtdcom->component;
-
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
-		if (!component->driver->compr_ops ||
-		    !component->driver->compr_ops->open)
-			continue;
-
-		__ret = component->driver->compr_ops->open(cstream);
-		if (__ret < 0) {
-			dev_err(component->dev,
-				"Compress ASoC: can't open platform %s: %d\n",
-				component->name, __ret);
-			ret = __ret;
-		}
-	}
+	ret = soc_compr_components_open(cstream, &component);
 	if (ret < 0)
 		goto machine_err;
 
@@ -235,23 +213,8 @@ fe_err:
 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
 		fe->dai_link->compr_ops->shutdown(cstream);
 machine_err:
-	for_each_rtdcom(fe, rtdcom) {
-		component = rtdcom->component;
-
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
+	soc_compr_components_free(cstream, component);
 
-		if (!component->driver->compr_ops ||
-		    !component->driver->compr_ops->free)
-			continue;
-
-		component->driver->compr_ops->free(cstream);
-	}
-
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->free)
-		platform->driver->compr_ops->free(cstream);
-plat_err:
 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
 		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
 out:
@@ -292,9 +255,6 @@ static void close_delayed_work(struct work_struct *work)
 static int soc_compr_free(struct snd_compr_stream *cstream)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
-	struct snd_soc_component *component;
-	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	int stream;
@@ -319,22 +279,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
 	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
 		rtd->dai_link->compr_ops->shutdown(cstream);
 
-	for_each_rtdcom(rtd, rtdcom) {
-		component = rtdcom->component;
-
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
-		if (!component->driver->compr_ops ||
-		    !component->driver->compr_ops->free)
-			continue;
-
-		component->driver->compr_ops->free(cstream);
-	}
-
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->free)
-		platform->driver->compr_ops->free(cstream);
+	soc_compr_components_free(cstream, NULL);
 
 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
 		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
@@ -342,8 +287,8 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
 	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
 		if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
 			snd_soc_dapm_stream_event(rtd,
-					SNDRV_PCM_STREAM_PLAYBACK,
-					SND_SOC_DAPM_STREAM_STOP);
+						  SNDRV_PCM_STREAM_PLAYBACK,
+						  SND_SOC_DAPM_STREAM_STOP);
 		} else {
 			rtd->pop_wait = 1;
 			queue_delayed_work(system_power_efficient_wq,
@@ -353,8 +298,8 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
 	} else {
 		/* capture streams can be powered down now */
 		snd_soc_dapm_stream_event(rtd,
-			SNDRV_PCM_STREAM_CAPTURE,
-			SND_SOC_DAPM_STREAM_STOP);
+					  SNDRV_PCM_STREAM_CAPTURE,
+					  SND_SOC_DAPM_STREAM_STOP);
 	}
 
 	mutex_unlock(&rtd->pcm_mutex);
@@ -364,9 +309,6 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
 static int soc_compr_free_fe(struct snd_compr_stream *cstream)
 {
 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
-	struct snd_soc_platform *platform = fe->platform;
-	struct snd_soc_component *component;
-	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
 	struct snd_soc_dpcm *dpcm;
 	int stream, ret;
@@ -404,22 +346,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
 		fe->dai_link->compr_ops->shutdown(cstream);
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->free)
-		platform->driver->compr_ops->free(cstream);
-
-	for_each_rtdcom(fe, rtdcom) {
-		component = rtdcom->component;
-
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
-		if (!component->driver->compr_ops ||
-		    !component->driver->compr_ops->free)
-			continue;
-
-		component->driver->compr_ops->free(cstream);
-	}
+	soc_compr_components_free(cstream, NULL);
 
 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
 		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
@@ -432,7 +359,6 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 {
 
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
@@ -441,19 +367,9 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
-		ret = platform->driver->compr_ops->trigger(cstream, cmd);
-		if (ret < 0)
-			goto out;
-	}
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->trigger)
 			continue;
@@ -485,7 +401,6 @@ out:
 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_platform *platform = fe->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
@@ -494,19 +409,9 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
 	if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
 		cmd == SND_COMPR_TRIGGER_DRAIN) {
 
-		if (platform &&
-		    platform->driver->compr_ops &&
-		    platform->driver->compr_ops->trigger)
-			return platform->driver->compr_ops->trigger(cstream,
-								    cmd);
-
 		for_each_rtdcom(fe, rtdcom) {
 			component = rtdcom->component;
 
-			/* ignore duplication for now */
-			if (platform && (component == &platform->component))
-				continue;
-
 			if (!component->driver->compr_ops ||
 			    !component->driver->compr_ops->trigger)
 				continue;
@@ -523,7 +428,6 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
 	else
 		stream = SNDRV_PCM_STREAM_CAPTURE;
 
-
 	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) {
@@ -532,19 +436,9 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
 			goto out;
 	}
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
-		ret = platform->driver->compr_ops->trigger(cstream, cmd);
-		if (ret < 0)
-			goto out;
-	}
-
 	for_each_rtdcom(fe, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->trigger)
 			continue;
@@ -585,7 +479,6 @@ 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_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -593,11 +486,12 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
-	/* first we call set_params for the platform driver
-	 * this should configure the soc side
-	 * if the machine has compressed ops then we call that as well
-	 * expectation is that platform and machine will configure everything
-	 * for this compress path, like configuring pcm port for codec
+	/*
+	 * First we call set_params for the CPU DAI, then the component
+	 * driver this should configure the SoC side. If the machine has
+	 * compressed ops then we call that as well. The expectation is
+	 * that these callbacks will configure everything for this compress
+	 * path, like configuring a PCM port for a CODEC.
 	 */
 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
 		ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
@@ -605,19 +499,9 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
 			goto err;
 	}
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
-		ret = platform->driver->compr_ops->set_params(cstream, params);
-		if (ret < 0)
-			goto err;
-	}
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->set_params)
 			continue;
@@ -637,10 +521,10 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
 
 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
-					SND_SOC_DAPM_STREAM_START);
+					  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_START);
 
 	/* cancel any delayed stream shutdown that is pending */
 	rtd->pop_wait = 0;
@@ -656,12 +540,11 @@ err:
 }
 
 static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
-					struct snd_compr_params *params)
+				   struct snd_compr_params *params)
 {
 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
 	struct snd_pcm_substream *fe_substream =
 		 fe->pcm->streams[cstream->direction].substream;
-	struct snd_soc_platform *platform = fe->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = fe->cpu_dai;
@@ -680,19 +563,9 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
 			goto out;
 	}
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
-		ret = platform->driver->compr_ops->set_params(cstream, params);
-		if (ret < 0)
-			goto out;
-	}
-
 	for_each_rtdcom(fe, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->set_params)
 			continue;
@@ -738,10 +611,9 @@ out:
 }
 
 static int soc_compr_get_params(struct snd_compr_stream *cstream,
-					struct snd_codec *params)
+				struct snd_codec *params)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -755,19 +627,9 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream,
 			goto err;
 	}
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->get_params) {
-		ret = platform->driver->compr_ops->get_params(cstream, params);
-		if (ret < 0)
-			goto err;
-	}
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->get_params)
 			continue;
@@ -783,29 +645,18 @@ err:
 }
 
 static int soc_compr_get_caps(struct snd_compr_stream *cstream,
-				struct snd_compr_caps *caps)
+			      struct snd_compr_caps *caps)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	int ret = 0, __ret;
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->get_caps) {
-		ret = platform->driver->compr_ops->get_caps(cstream, caps);
-		if (ret < 0)
-			goto err;
-	}
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->get_caps)
 			continue;
@@ -815,35 +666,23 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream,
 			ret = __ret;
 	}
 
-err:
 	mutex_unlock(&rtd->pcm_mutex);
 	return ret;
 }
 
 static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
-				struct snd_compr_codec_caps *codec)
+				    struct snd_compr_codec_caps *codec)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	int ret = 0, __ret;
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps) {
-		ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
-		if (ret < 0)
-			goto err;
-	}
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->get_codec_caps)
 			continue;
@@ -853,7 +692,6 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
 			ret = __ret;
 	}
 
-err:
 	mutex_unlock(&rtd->pcm_mutex);
 	return ret;
 }
@@ -861,7 +699,6 @@ err:
 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_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -875,19 +712,9 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
 			goto err;
 	}
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->ack) {
-		ret = platform->driver->compr_ops->ack(cstream, bytes);
-		if (ret < 0)
-			goto err;
-	}
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->ack)
 			continue;
@@ -903,10 +730,9 @@ err:
 }
 
 static int soc_compr_pointer(struct snd_compr_stream *cstream,
-			struct snd_compr_tstamp *tstamp)
+			     struct snd_compr_tstamp *tstamp)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	int ret = 0, __ret;
@@ -917,19 +743,9 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,
 	if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer)
 		cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai);
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->pointer) {
-		ret = platform->driver->compr_ops->pointer(cstream, tstamp);
-		if (ret < 0)
-			goto err;
-	}
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->pointer)
 			continue;
@@ -939,7 +755,6 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,
 			ret = __ret;
 	}
 
-err:
 	mutex_unlock(&rtd->pcm_mutex);
 	return ret;
 }
@@ -948,26 +763,15 @@ 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_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	int ret = 0;
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->copy) {
-		ret = platform->driver->compr_ops->copy(cstream, buf, count);
-		if (ret < 0)
-			goto err;
-	}
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->copy)
 			continue;
@@ -976,16 +780,14 @@ static int soc_compr_copy(struct snd_compr_stream *cstream,
 		break;
 	}
 
-err:
 	mutex_unlock(&rtd->pcm_mutex);
 	return ret;
 }
 
 static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
-				struct snd_compr_metadata *metadata)
+				  struct snd_compr_metadata *metadata)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -997,19 +799,9 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
 			return ret;
 	}
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->set_metadata) {
-		ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
-		if (ret < 0)
-			return ret;
-	}
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->set_metadata)
 			continue;
@@ -1023,10 +815,9 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
 }
 
 static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
-				struct snd_compr_metadata *metadata)
+				  struct snd_compr_metadata *metadata)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -1038,19 +829,9 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
 			return ret;
 	}
 
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->get_metadata) {
-		ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
-		if (ret < 0)
-			return ret;
-	}
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->get_metadata)
 			continue;
@@ -1103,7 +884,6 @@ static struct snd_compr_ops soc_compr_dyn_ops = {
  */
 int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 {
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
@@ -1184,26 +964,17 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 		memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
 	}
 
-
-	/* Add copy callback for not memory mapped DSPs */
-	if (platform && platform->driver->compr_ops && platform->driver->compr_ops->copy)
-		compr->ops->copy = soc_compr_copy;
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->compr_ops ||
 		    !component->driver->compr_ops->copy)
 			continue;
 
 		compr->ops->copy = soc_compr_copy;
+		break;
 	}
 
-
 	mutex_init(&compr->lock);
 	ret = snd_compress_new(rtd->card->snd_card, num, direction,
 				new_name, compr);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index bf7ca32ab31f..3d56f1fe5914 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -56,8 +56,6 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
 #endif
 
 static DEFINE_MUTEX(client_mutex);
-static LIST_HEAD(platform_list);
-static LIST_HEAD(codec_list);
 static LIST_HEAD(component_list);
 
 /*
@@ -83,98 +81,6 @@ static const char * const dmi_blacklist[] = {
 	NULL,	/* terminator */
 };
 
-/* returns the minimum number of bytes needed to represent
- * a particular given value */
-static int min_bytes_needed(unsigned long val)
-{
-	int c = 0;
-	int i;
-
-	for (i = (sizeof val * 8) - 1; i >= 0; --i, ++c)
-		if (val & (1UL << i))
-			break;
-	c = (sizeof val * 8) - c;
-	if (!c || (c % 8))
-		c = (c + 8) / 8;
-	else
-		c /= 8;
-	return c;
-}
-
-/* fill buf which is 'len' bytes with a formatted
- * string of the form 'reg: value\n' */
-static int format_register_str(struct snd_soc_codec *codec,
-			       unsigned int reg, char *buf, size_t len)
-{
-	int wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
-	int regsize = codec->driver->reg_word_size * 2;
-	int ret;
-
-	/* +2 for ': ' and + 1 for '\n' */
-	if (wordsize + regsize + 2 + 1 != len)
-		return -EINVAL;
-
-	sprintf(buf, "%.*x: ", wordsize, reg);
-	buf += wordsize + 2;
-
-	ret = snd_soc_read(codec, reg);
-	if (ret < 0)
-		memset(buf, 'X', regsize);
-	else
-		sprintf(buf, "%.*x", regsize, ret);
-	buf[regsize] = '\n';
-	/* no NUL-termination needed */
-	return 0;
-}
-
-/* codec register dump */
-static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf,
-				  size_t count, loff_t pos)
-{
-	int i, step = 1;
-	int wordsize, regsize;
-	int len;
-	size_t total = 0;
-	loff_t p = 0;
-
-	wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
-	regsize = codec->driver->reg_word_size * 2;
-
-	len = wordsize + regsize + 2 + 1;
-
-	if (!codec->driver->reg_cache_size)
-		return 0;
-
-	if (codec->driver->reg_cache_step)
-		step = codec->driver->reg_cache_step;
-
-	for (i = 0; i < codec->driver->reg_cache_size; i += step) {
-		/* only support larger than PAGE_SIZE bytes debugfs
-		 * entries for the default case */
-		if (p >= pos) {
-			if (total + len >= count - 1)
-				break;
-			format_register_str(codec, i, buf + total, len);
-			total += len;
-		}
-		p += len;
-	}
-
-	total = min(total, count - 1);
-
-	return total;
-}
-
-static ssize_t codec_reg_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
-{
-	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
-
-	return soc_codec_reg_show(rtd->codec, buf, PAGE_SIZE, 0);
-}
-
-static DEVICE_ATTR_RO(codec_reg);
-
 static ssize_t pmdown_time_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
@@ -200,7 +106,6 @@ static ssize_t pmdown_time_set(struct device *dev,
 static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set);
 
 static struct attribute *soc_dev_attrs[] = {
-	&dev_attr_codec_reg.attr,
 	&dev_attr_pmdown_time.attr,
 	NULL
 };
@@ -233,71 +138,6 @@ static const struct attribute_group *soc_dev_attr_groups[] = {
 };
 
 #ifdef CONFIG_DEBUG_FS
-static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
-				   size_t count, loff_t *ppos)
-{
-	ssize_t ret;
-	struct snd_soc_codec *codec = file->private_data;
-	char *buf;
-
-	if (*ppos < 0 || !count)
-		return -EINVAL;
-
-	buf = kmalloc(count, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	ret = soc_codec_reg_show(codec, buf, count, *ppos);
-	if (ret >= 0) {
-		if (copy_to_user(user_buf, buf, ret)) {
-			kfree(buf);
-			return -EFAULT;
-		}
-		*ppos += ret;
-	}
-
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t codec_reg_write_file(struct file *file,
-		const char __user *user_buf, size_t count, loff_t *ppos)
-{
-	char buf[32];
-	size_t buf_size;
-	char *start = buf;
-	unsigned long reg, value;
-	struct snd_soc_codec *codec = file->private_data;
-	int ret;
-
-	buf_size = min(count, (sizeof(buf)-1));
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-	buf[buf_size] = 0;
-
-	while (*start == ' ')
-		start++;
-	reg = simple_strtoul(start, &start, 16);
-	while (*start == ' ')
-		start++;
-	ret = kstrtoul(start, 16, &value);
-	if (ret)
-		return ret;
-
-	/* Userspace has been fiddling around behind the kernel's back */
-	add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE);
-
-	snd_soc_write(codec, reg, value);
-	return buf_size;
-}
-
-static const struct file_operations codec_reg_fops = {
-	.open = simple_open,
-	.read = codec_reg_read_file,
-	.write = codec_reg_write_file,
-	.llseek = default_llseek,
-};
-
 static void soc_init_component_debugfs(struct snd_soc_component *component)
 {
 	if (!component->card->debugfs_card_root)
@@ -326,9 +166,6 @@ static void soc_init_component_debugfs(struct snd_soc_component *component)
 
 	snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component),
 		component->debugfs_root);
-
-	if (component->init_debugfs)
-		component->init_debugfs(component);
 }
 
 static void soc_cleanup_component_debugfs(struct snd_soc_component *component)
@@ -336,34 +173,6 @@ static void soc_cleanup_component_debugfs(struct snd_soc_component *component)
 	debugfs_remove_recursive(component->debugfs_root);
 }
 
-static void soc_init_codec_debugfs(struct snd_soc_component *component)
-{
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
-	struct dentry *debugfs_reg;
-
-	debugfs_reg = debugfs_create_file("codec_reg", 0644,
-					  codec->component.debugfs_root,
-					  codec, &codec_reg_fops);
-	if (!debugfs_reg)
-		dev_warn(codec->dev,
-			"ASoC: Failed to create codec register debugfs file\n");
-}
-
-static int codec_list_show(struct seq_file *m, void *v)
-{
-	struct snd_soc_codec *codec;
-
-	mutex_lock(&client_mutex);
-
-	list_for_each_entry(codec, &codec_list, list)
-		seq_printf(m, "%s\n", codec->component.name);
-
-	mutex_unlock(&client_mutex);
-
-	return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(codec_list);
-
 static int dai_list_show(struct seq_file *m, void *v)
 {
 	struct snd_soc_component *component;
@@ -381,20 +190,20 @@ static int dai_list_show(struct seq_file *m, void *v)
 }
 DEFINE_SHOW_ATTRIBUTE(dai_list);
 
-static int platform_list_show(struct seq_file *m, void *v)
+static int component_list_show(struct seq_file *m, void *v)
 {
-	struct snd_soc_platform *platform;
+	struct snd_soc_component *component;
 
 	mutex_lock(&client_mutex);
 
-	list_for_each_entry(platform, &platform_list, list)
-		seq_printf(m, "%s\n", platform->component.name);
+	list_for_each_entry(component, &component_list, list)
+		seq_printf(m, "%s\n", component->name);
 
 	mutex_unlock(&client_mutex);
 
 	return 0;
 }
-DEFINE_SHOW_ATTRIBUTE(platform_list);
+DEFINE_SHOW_ATTRIBUTE(component_list);
 
 static void soc_init_card_debugfs(struct snd_soc_card *card)
 {
@@ -431,17 +240,13 @@ static void snd_soc_debugfs_init(void)
 		return;
 	}
 
-	if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL,
-				 &codec_list_fops))
-		pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
-
 	if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
 				 &dai_list_fops))
 		pr_warn("ASoC: Failed to create DAI list debugfs file\n");
 
-	if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL,
-				 &platform_list_fops))
-		pr_warn("ASoC: Failed to create platform list debugfs file\n");
+	if (!debugfs_create_file("components", 0444, snd_soc_debugfs_root, NULL,
+				 &component_list_fops))
+		pr_warn("ASoC: Failed to create component list debugfs file\n");
 }
 
 static void snd_soc_debugfs_exit(void)
@@ -451,8 +256,6 @@ static void snd_soc_debugfs_exit(void)
 
 #else
 
-#define soc_init_codec_debugfs NULL
-
 static inline void soc_init_component_debugfs(
 	struct snd_soc_component *component)
 {
@@ -732,8 +535,8 @@ int snd_soc_suspend(struct device *dev)
 				}
 
 			case SND_SOC_BIAS_OFF:
-				if (component->suspend)
-					component->suspend(component);
+				if (component->driver->suspend)
+					component->driver->suspend(component);
 				component->suspended = 1;
 				if (component->regmap)
 					regcache_mark_dirty(component->regmap);
@@ -804,8 +607,8 @@ static void soc_resume_deferred(struct work_struct *work)
 
 	list_for_each_entry(component, &card->component_dev_list, card_list) {
 		if (component->suspended) {
-			if (component->resume)
-				component->resume(component);
+			if (component->driver->resume)
+				component->driver->resume(component);
 			component->suspended = 0;
 		}
 	}
@@ -1045,7 +848,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
 	struct snd_soc_dai_link_component cpu_dai_component;
 	struct snd_soc_component *component;
 	struct snd_soc_dai **codec_dais;
-	struct snd_soc_platform *platform;
 	struct device_node *platform_of_node;
 	const char *platform_name;
 	int i;
@@ -1089,7 +891,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
 
 	/* Single codec links expect codec and codec_dai in runtime data */
 	rtd->codec_dai = codec_dais[0];
-	rtd->codec = rtd->codec_dai->codec;
 
 	/* if there's no platform we match on the empty platform */
 	platform_name = dai_link->platform_name;
@@ -1113,23 +914,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
 		snd_soc_rtdcom_add(rtd, component);
 	}
 
-	/* find one from the set of registered platforms */
-	list_for_each_entry(platform, &platform_list, list) {
-		platform_of_node = platform->dev->of_node;
-		if (!platform_of_node && platform->dev->parent->of_node)
-			platform_of_node = platform->dev->parent->of_node;
-
-		if (dai_link->platform_of_node) {
-			if (platform_of_node != dai_link->platform_of_node)
-				continue;
-		} else {
-			if (strcmp(platform->component.name, platform_name))
-				continue;
-		}
-
-		rtd->platform = platform;
-	}
-
 	soc_add_pcm_runtime(card, rtd);
 	return 0;
 
@@ -1145,8 +929,8 @@ static void soc_remove_component(struct snd_soc_component *component)
 
 	list_del(&component->card_list);
 
-	if (component->remove)
-		component->remove(component);
+	if (component->driver->remove)
+		component->driver->remove(component);
 
 	snd_soc_dapm_free(snd_soc_component_get_dapm(component));
 
@@ -1421,7 +1205,12 @@ 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 (map->of_node && component->dev->of_node != map->of_node)
+		struct device_node *component_of_node = component->dev->of_node;
+
+		if (!component_of_node && component->dev->parent)
+			component_of_node = component->dev->parent->of_node;
+
+		if (map->of_node && component_of_node != map->of_node)
 			continue;
 		if (map->dev_name && strcmp(component->name, map->dev_name))
 			continue;
@@ -1480,8 +1269,8 @@ static int soc_probe_component(struct snd_soc_card *card,
 		}
 	}
 
-	if (component->probe) {
-		ret = component->probe(component);
+	if (component->driver->probe) {
+		ret = component->driver->probe(component);
 		if (ret < 0) {
 			dev_err(component->dev,
 				"ASoC: failed to probe component %d\n", ret);
@@ -1838,24 +1627,6 @@ static void soc_remove_aux_devices(struct snd_soc_card *card)
 	}
 }
 
-static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
-{
-	int ret;
-
-	if (codec->cache_init)
-		return 0;
-
-	ret = snd_soc_cache_init(codec);
-	if (ret < 0) {
-		dev_err(codec->dev,
-			"ASoC: Failed to set cache compression type: %d\n",
-			ret);
-		return ret;
-	}
-	codec->cache_init = 1;
-	return 0;
-}
-
 /**
  * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime
  * @rtd: The runtime for which the DAI link format should be changed
@@ -1890,8 +1661,7 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
 
 	/* Flip the polarity for the "CPU" end of a CODEC<->CODEC link */
 	/* the component which has non_legacy_dai_naming is Codec */
-	if (cpu_dai->codec ||
-	    cpu_dai->component->driver->non_legacy_dai_naming) {
+	if (cpu_dai->component->driver->non_legacy_dai_naming) {
 		unsigned int inv_dai_fmt;
 
 		inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK;
@@ -2078,7 +1848,6 @@ EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
 
 static int snd_soc_instantiate_card(struct snd_soc_card *card)
 {
-	struct snd_soc_codec *codec;
 	struct snd_soc_pcm_runtime *rtd;
 	struct snd_soc_dai_link *dai_link;
 	int ret, i, order;
@@ -2104,15 +1873,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
 	for (i = 0; i < card->num_links; i++)
 		snd_soc_add_dai_link(card, card->dai_link+i);
 
-	/* initialize the register cache for each available codec */
-	list_for_each_entry(codec, &codec_list, list) {
-		if (codec->cache_init)
-			continue;
-		ret = snd_soc_init_codec_cache(codec);
-		if (ret < 0)
-			goto base_error;
-	}
-
 	/* card bind complete so register a sound card */
 	ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
 			card->owner, 0, &card->snd_card);
@@ -2494,43 +2254,6 @@ int snd_soc_add_component_controls(struct snd_soc_component *component,
 EXPORT_SYMBOL_GPL(snd_soc_add_component_controls);
 
 /**
- * snd_soc_add_codec_controls - add an array of controls to a codec.
- * Convenience function to add a list of controls. Many codecs were
- * duplicating this code.
- *
- * @codec: codec to add controls to
- * @controls: array of controls to add
- * @num_controls: number of elements in the array
- *
- * Return 0 for success, else error.
- */
-int snd_soc_add_codec_controls(struct snd_soc_codec *codec,
-	const struct snd_kcontrol_new *controls, unsigned int num_controls)
-{
-	return snd_soc_add_component_controls(&codec->component, controls,
-		num_controls);
-}
-EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls);
-
-/**
- * snd_soc_add_platform_controls - add an array of controls to a platform.
- * Convenience function to add a list of controls.
- *
- * @platform: platform to add controls to
- * @controls: array of controls to add
- * @num_controls: number of elements in the array
- *
- * Return 0 for success, else error.
- */
-int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
-	const struct snd_kcontrol_new *controls, unsigned int num_controls)
-{
-	return snd_soc_add_component_controls(&platform->component, controls,
-		num_controls);
-}
-EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls);
-
-/**
  * snd_soc_add_card_controls - add an array of controls to a SoC card.
  * Convenience function to add a list of controls.
  *
@@ -2591,27 +2314,6 @@ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
 
 /**
- * snd_soc_codec_set_sysclk - configure CODEC system or master clock.
- * @codec: CODEC
- * @clk_id: DAI specific clock ID
- * @source: Source for the clock
- * @freq: new clock frequency in Hz
- * @dir: new clock direction - input/output.
- *
- * Configures the CODEC master (MCLK) or system (SYSCLK) clocking.
- */
-int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
-			     int source, unsigned int freq, int dir)
-{
-	if (codec->driver->set_sysclk)
-		return codec->driver->set_sysclk(codec, clk_id, source,
-						 freq, dir);
-	else
-		return -ENOTSUPP;
-}
-EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk);
-
-/**
  * snd_soc_component_set_sysclk - configure COMPONENT system or master clock.
  * @component: COMPONENT
  * @clk_id: DAI specific clock ID
@@ -2624,11 +2326,6 @@ EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk);
 int snd_soc_component_set_sysclk(struct snd_soc_component *component, int clk_id,
 			     int source, unsigned int freq, int dir)
 {
-	/* will be removed */
-	if (component->set_sysclk)
-		return component->set_sysclk(component, clk_id, source,
-					     freq, dir);
-
 	if (component->driver->set_sysclk)
 		return component->driver->set_sysclk(component, clk_id, source,
 						 freq, dir);
@@ -2680,27 +2377,6 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
 
 /*
- * snd_soc_codec_set_pll - configure codec PLL.
- * @codec: CODEC
- * @pll_id: DAI specific PLL ID
- * @source: DAI specific source for the PLL
- * @freq_in: PLL input clock frequency in Hz
- * @freq_out: requested PLL output clock frequency in Hz
- *
- * Configures and enables PLL to generate output clock based on input clock.
- */
-int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
-			  unsigned int freq_in, unsigned int freq_out)
-{
-	if (codec->driver->set_pll)
-		return codec->driver->set_pll(codec, pll_id, source,
-					      freq_in, freq_out);
-	else
-		return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll);
-
-/*
  * snd_soc_component_set_pll - configure component PLL.
  * @component: COMPONENT
  * @pll_id: DAI specific PLL ID
@@ -2714,11 +2390,6 @@ int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id,
 			      int source, unsigned int freq_in,
 			      unsigned int freq_out)
 {
-	/* will be removed */
-	if (component->set_pll)
-		return component->set_pll(component, pll_id, source,
-					      freq_in, freq_out);
-
 	if (component->driver->set_pll)
 		return component->driver->set_pll(component, pll_id, source,
 					      freq_in, freq_out);
@@ -3112,8 +2783,7 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component,
  *                     parent's name.
  */
 static int snd_soc_register_dais(struct snd_soc_component *component,
-	struct snd_soc_dai_driver *dai_drv, size_t count,
-	bool legacy_dai_naming)
+				 struct snd_soc_dai_driver *dai_drv, size_t count)
 {
 	struct device *dev = component->dev;
 	struct snd_soc_dai *dai;
@@ -3125,7 +2795,7 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
 	for (i = 0; i < count; i++) {
 
 		dai = soc_add_dai(component, dai_drv + i,
-				count == 1 && legacy_dai_naming);
+				  count == 1 && !component->driver->non_legacy_dai_naming);
 		if (dai == NULL) {
 			ret = -ENOMEM;
 			goto err;
@@ -3198,22 +2868,6 @@ static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm,
 	return component->driver->stream_event(component, event);
 }
 
-static int snd_soc_component_drv_pcm_new(struct snd_soc_component *component,
-					struct snd_soc_pcm_runtime *rtd)
-{
-	if (component->driver->pcm_new)
-		return component->driver->pcm_new(rtd);
-
-	return 0;
-}
-
-static void snd_soc_component_drv_pcm_free(struct snd_soc_component *component,
-					  struct snd_pcm *pcm)
-{
-	if (component->driver->pcm_free)
-		component->driver->pcm_free(pcm);
-}
-
 static int snd_soc_component_set_bias_level(struct snd_soc_dapm_context *dapm,
 					enum snd_soc_bias_level level)
 {
@@ -3235,15 +2889,6 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
 
 	component->dev = dev;
 	component->driver = driver;
-	component->probe = component->driver->probe;
-	component->remove = component->driver->remove;
-	component->suspend = component->driver->suspend;
-	component->resume = component->driver->resume;
-	component->set_sysclk = component->driver->set_sysclk;
-	component->set_pll = component->driver->set_pll;
-	component->set_jack = component->driver->set_jack;
-	component->pcm_new = snd_soc_component_drv_pcm_new;
-	component->pcm_free = snd_soc_component_drv_pcm_free;
 
 	dapm = snd_soc_component_get_dapm(component);
 	dapm->dev = dev;
@@ -3312,9 +2957,11 @@ EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap);
 
 #endif
 
-static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
+static void snd_soc_component_add(struct snd_soc_component *component)
 {
-	if (!component->write && !component->read) {
+	mutex_lock(&client_mutex);
+
+	if (!component->driver->write && !component->driver->read) {
 		if (!component->regmap)
 			component->regmap = dev_get_regmap(component->dev, NULL);
 		if (component->regmap)
@@ -3323,12 +2970,7 @@ static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
 
 	list_add(&component->list, &component_list);
 	INIT_LIST_HEAD(&component->dobj_list);
-}
 
-static void snd_soc_component_add(struct snd_soc_component *component)
-{
-	mutex_lock(&client_mutex);
-	snd_soc_component_add_unlocked(component);
 	mutex_unlock(&client_mutex);
 }
 
@@ -3396,9 +3038,6 @@ int snd_soc_add_component(struct device *dev,
 	if (ret)
 		goto err_free;
 
-	component->ignore_pmdown_time = true;
-	component->registered_as_component = true;
-
 	if (component_driver->endianness) {
 		for (i = 0; i < num_dai; i++) {
 			convert_endianness_formats(&dai_drv[i].playback);
@@ -3406,8 +3045,7 @@ int snd_soc_add_component(struct device *dev,
 		}
 	}
 
-	ret = snd_soc_register_dais(component, dai_drv, num_dai,
-				    !component_driver->non_legacy_dai_naming);
+	ret = snd_soc_register_dais(component, dai_drv, num_dai);
 	if (ret < 0) {
 		dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);
 		goto err_cleanup;
@@ -3453,8 +3091,7 @@ static int __snd_soc_unregister_component(struct device *dev)
 
 	mutex_lock(&client_mutex);
 	list_for_each_entry(component, &component_list, list) {
-		if (dev != component->dev ||
-		    !component->registered_as_component)
+		if (dev != component->dev)
 			continue;
 
 		snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
@@ -3503,375 +3140,6 @@ struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(snd_soc_lookup_component);
 
-static int snd_soc_platform_drv_probe(struct snd_soc_component *component)
-{
-	struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
-
-	return platform->driver->probe(platform);
-}
-
-static void snd_soc_platform_drv_remove(struct snd_soc_component *component)
-{
-	struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
-
-	platform->driver->remove(platform);
-}
-
-static int snd_soc_platform_drv_pcm_new(struct snd_soc_component *component,
-					struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
-
-	if (platform->driver->pcm_new)
-		return platform->driver->pcm_new(rtd);
-
-	return 0;
-}
-
-static void snd_soc_platform_drv_pcm_free(struct snd_soc_component *component,
-					  struct snd_pcm *pcm)
-{
-	struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
-
-	if (platform->driver->pcm_free)
-		platform->driver->pcm_free(pcm);
-}
-
-/**
- * snd_soc_add_platform - Add a platform to the ASoC core
- * @dev: The parent device for the platform
- * @platform: The platform to add
- * @platform_drv: The driver for the platform
- */
-int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
-		const struct snd_soc_platform_driver *platform_drv)
-{
-	int ret;
-
-	ret = snd_soc_component_initialize(&platform->component,
-			&platform_drv->component_driver, dev);
-	if (ret)
-		return ret;
-
-	platform->dev = dev;
-	platform->driver = platform_drv;
-
-	if (platform_drv->probe)
-		platform->component.probe = snd_soc_platform_drv_probe;
-	if (platform_drv->remove)
-		platform->component.remove = snd_soc_platform_drv_remove;
-	if (platform_drv->pcm_new)
-		platform->component.pcm_new = snd_soc_platform_drv_pcm_new;
-	if (platform_drv->pcm_free)
-		platform->component.pcm_free = snd_soc_platform_drv_pcm_free;
-
-#ifdef CONFIG_DEBUG_FS
-	platform->component.debugfs_prefix = "platform";
-#endif
-
-	mutex_lock(&client_mutex);
-	snd_soc_component_add_unlocked(&platform->component);
-	list_add(&platform->list, &platform_list);
-	mutex_unlock(&client_mutex);
-
-	dev_dbg(dev, "ASoC: Registered platform '%s'\n",
-		platform->component.name);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_add_platform);
-
-/**
- * snd_soc_register_platform - Register a platform with the ASoC core
- *
- * @dev: The device for the platform
- * @platform_drv: The driver for the platform
- */
-int snd_soc_register_platform(struct device *dev,
-		const struct snd_soc_platform_driver *platform_drv)
-{
-	struct snd_soc_platform *platform;
-	int ret;
-
-	dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev));
-
-	platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
-	if (platform == NULL)
-		return -ENOMEM;
-
-	ret = snd_soc_add_platform(dev, platform, platform_drv);
-	if (ret)
-		kfree(platform);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_register_platform);
-
-/**
- * snd_soc_remove_platform - Remove a platform from the ASoC core
- * @platform: the platform to remove
- */
-void snd_soc_remove_platform(struct snd_soc_platform *platform)
-{
-
-	mutex_lock(&client_mutex);
-	list_del(&platform->list);
-	snd_soc_component_del_unlocked(&platform->component);
-	mutex_unlock(&client_mutex);
-
-	dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n",
-		platform->component.name);
-
-	snd_soc_component_cleanup(&platform->component);
-}
-EXPORT_SYMBOL_GPL(snd_soc_remove_platform);
-
-struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev)
-{
-	struct snd_soc_platform *platform;
-
-	mutex_lock(&client_mutex);
-	list_for_each_entry(platform, &platform_list, list) {
-		if (dev == platform->dev) {
-			mutex_unlock(&client_mutex);
-			return platform;
-		}
-	}
-	mutex_unlock(&client_mutex);
-
-	return NULL;
-}
-EXPORT_SYMBOL_GPL(snd_soc_lookup_platform);
-
-/**
- * snd_soc_unregister_platform - Unregister a platform from the ASoC core
- *
- * @dev: platform to unregister
- */
-void snd_soc_unregister_platform(struct device *dev)
-{
-	struct snd_soc_platform *platform;
-
-	platform = snd_soc_lookup_platform(dev);
-	if (!platform)
-		return;
-
-	snd_soc_remove_platform(platform);
-	kfree(platform);
-}
-EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
-
-static int snd_soc_codec_drv_probe(struct snd_soc_component *component)
-{
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
-
-	return codec->driver->probe(codec);
-}
-
-static void snd_soc_codec_drv_remove(struct snd_soc_component *component)
-{
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
-
-	codec->driver->remove(codec);
-}
-
-static int snd_soc_codec_drv_suspend(struct snd_soc_component *component)
-{
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
-
-	return codec->driver->suspend(codec);
-}
-
-static int snd_soc_codec_drv_resume(struct snd_soc_component *component)
-{
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
-
-	return codec->driver->resume(codec);
-}
-
-static int snd_soc_codec_drv_write(struct snd_soc_component *component,
-	unsigned int reg, unsigned int val)
-{
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
-
-	return codec->driver->write(codec, reg, val);
-}
-
-static int snd_soc_codec_drv_read(struct snd_soc_component *component,
-	unsigned int reg, unsigned int *val)
-{
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
-
-	*val = codec->driver->read(codec, reg);
-
-	return 0;
-}
-
-static int snd_soc_codec_set_sysclk_(struct snd_soc_component *component,
-			  int clk_id, int source, unsigned int freq, int dir)
-{
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
-
-	return snd_soc_codec_set_sysclk(codec, clk_id, source, freq, dir);
-}
-
-static int snd_soc_codec_set_pll_(struct snd_soc_component *component,
-				  int pll_id, int source, unsigned int freq_in,
-				  unsigned int freq_out)
-{
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
-
-	return snd_soc_codec_set_pll(codec, pll_id, source, freq_in, freq_out);
-}
-
-static int snd_soc_codec_set_jack_(struct snd_soc_component *component,
-			       struct snd_soc_jack *jack, void *data)
-{
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
-
-	return snd_soc_codec_set_jack(codec, jack, data);
-}
-
-static int snd_soc_codec_set_bias_level(struct snd_soc_dapm_context *dapm,
-	enum snd_soc_bias_level level)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
-
-	return codec->driver->set_bias_level(codec, level);
-}
-
-/**
- * snd_soc_register_codec - Register a codec with the ASoC core
- *
- * @dev: The parent device for this codec
- * @codec_drv: Codec driver
- * @dai_drv: The associated DAI driver
- * @num_dai: Number of DAIs
- */
-int snd_soc_register_codec(struct device *dev,
-			   const struct snd_soc_codec_driver *codec_drv,
-			   struct snd_soc_dai_driver *dai_drv,
-			   int num_dai)
-{
-	struct snd_soc_dapm_context *dapm;
-	struct snd_soc_codec *codec;
-	struct snd_soc_dai *dai;
-	int ret, i;
-
-	dev_dbg(dev, "codec register %s\n", dev_name(dev));
-
-	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-	if (codec == NULL)
-		return -ENOMEM;
-
-	codec->component.codec = codec;
-
-	ret = snd_soc_component_initialize(&codec->component,
-			&codec_drv->component_driver, dev);
-	if (ret)
-		goto err_free;
-
-	if (codec_drv->probe)
-		codec->component.probe = snd_soc_codec_drv_probe;
-	if (codec_drv->remove)
-		codec->component.remove = snd_soc_codec_drv_remove;
-	if (codec_drv->suspend)
-		codec->component.suspend = snd_soc_codec_drv_suspend;
-	if (codec_drv->resume)
-		codec->component.resume = snd_soc_codec_drv_resume;
-	if (codec_drv->write)
-		codec->component.write = snd_soc_codec_drv_write;
-	if (codec_drv->read)
-		codec->component.read = snd_soc_codec_drv_read;
-	if (codec_drv->set_sysclk)
-		codec->component.set_sysclk = snd_soc_codec_set_sysclk_;
-	if (codec_drv->set_pll)
-		codec->component.set_pll = snd_soc_codec_set_pll_;
-	if (codec_drv->set_jack)
-		codec->component.set_jack = snd_soc_codec_set_jack_;
-	codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
-
-	dapm = snd_soc_codec_get_dapm(codec);
-	dapm->idle_bias_off = codec_drv->idle_bias_off;
-	dapm->suspend_bias_off = codec_drv->suspend_bias_off;
-	if (codec_drv->seq_notifier)
-		dapm->seq_notifier = codec_drv->seq_notifier;
-	if (codec_drv->set_bias_level)
-		dapm->set_bias_level = snd_soc_codec_set_bias_level;
-	codec->dev = dev;
-	codec->driver = codec_drv;
-	codec->component.val_bytes = codec_drv->reg_word_size;
-
-#ifdef CONFIG_DEBUG_FS
-	codec->component.init_debugfs = soc_init_codec_debugfs;
-	codec->component.debugfs_prefix = "codec";
-#endif
-
-	if (codec_drv->get_regmap)
-		codec->component.regmap = codec_drv->get_regmap(dev);
-
-	for (i = 0; i < num_dai; i++) {
-		convert_endianness_formats(&dai_drv[i].playback);
-		convert_endianness_formats(&dai_drv[i].capture);
-	}
-
-	ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false);
-	if (ret < 0) {
-		dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);
-		goto err_cleanup;
-	}
-
-	list_for_each_entry(dai, &codec->component.dai_list, list)
-		dai->codec = codec;
-
-	mutex_lock(&client_mutex);
-	snd_soc_component_add_unlocked(&codec->component);
-	list_add(&codec->list, &codec_list);
-	mutex_unlock(&client_mutex);
-
-	dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n",
-		codec->component.name);
-	return 0;
-
-err_cleanup:
-	snd_soc_component_cleanup(&codec->component);
-err_free:
-	kfree(codec);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_register_codec);
-
-/**
- * snd_soc_unregister_codec - Unregister a codec from the ASoC core
- *
- * @dev: codec to unregister
- */
-void snd_soc_unregister_codec(struct device *dev)
-{
-	struct snd_soc_codec *codec;
-
-	mutex_lock(&client_mutex);
-	list_for_each_entry(codec, &codec_list, list) {
-		if (dev == codec->dev)
-			goto found;
-	}
-	mutex_unlock(&client_mutex);
-	return;
-
-found:
-	list_del(&codec->list);
-	snd_soc_component_del_unlocked(&codec->component);
-	mutex_unlock(&client_mutex);
-
-	dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n",
-			codec->component.name);
-
-	snd_soc_component_cleanup(&codec->component);
-	snd_soc_cache_exit(codec);
-	kfree(codec);
-}
-EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
-
 /* Retrieve a card's name from device tree */
 int snd_soc_of_parse_card_name(struct snd_soc_card *card,
 			       const char *propname)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 2d9709104ec5..255cad43a972 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -433,6 +433,8 @@ err_data:
 static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
 {
 	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
+
+	list_del(&data->paths);
 	kfree(data->wlist);
 	kfree(data);
 }
@@ -724,18 +726,14 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
 		item = 0;
 	}
 
-	for (i = 0; i < e->items; i++) {
-		if (!(strcmp(control_name, e->texts[i]))) {
-			path->name = e->texts[i];
-			if (i == item)
-				path->connect = 1;
-			else
-				path->connect = 0;
-			return 0;
-		}
-	}
+	i = match_string(e->texts, e->items, control_name);
+	if (i < 0)
+		return -ENODEV;
+
+	path->name = e->texts[i];
+	path->connect = (i == item);
+	return 0;
 
-	return -ENODEV;
 }
 
 /* set up initial codec paths */
@@ -1088,7 +1086,7 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
 	list_for_each(it, widgets)
 		size++;
 
-	*list = kzalloc(sizeof(**list) + size * sizeof(*w), GFP_KERNEL);
+	*list = kzalloc(struct_size(*list, widgets, size), GFP_KERNEL);
 	if (*list == NULL)
 		return -ENOMEM;
 
diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c
index a57921eeee81..7ac745df1412 100644
--- a/sound/soc/soc-devres.c
+++ b/sound/soc/soc-devres.c
@@ -52,41 +52,6 @@ int devm_snd_soc_register_component(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_snd_soc_register_component);
 
-static void devm_platform_release(struct device *dev, void *res)
-{
-	snd_soc_unregister_platform(*(struct device **)res);
-}
-
-/**
- * devm_snd_soc_register_platform - resource managed platform registration
- * @dev: Device used to manage platform
- * @platform_drv: platform to register
- *
- * Register a platform driver with automatic unregistration when the device is
- * unregistered.
- */
-int devm_snd_soc_register_platform(struct device *dev,
-			const struct snd_soc_platform_driver *platform_drv)
-{
-	struct device **ptr;
-	int ret;
-
-	ptr = devres_alloc(devm_platform_release, sizeof(*ptr), GFP_KERNEL);
-	if (!ptr)
-		return -ENOMEM;
-
-	ret = snd_soc_register_platform(dev, platform_drv);
-	if (ret == 0) {
-		*ptr = dev;
-		devres_add(dev, ptr);
-	} else {
-		devres_free(ptr);
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(devm_snd_soc_register_platform);
-
 static void devm_card_release(struct device *dev, void *res)
 {
 	snd_soc_unregister_card(*(struct snd_soc_card **)res);
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index d36a192fbece..026cd5347e53 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -32,8 +32,6 @@ int snd_soc_component_read(struct snd_soc_component *component,
 
 	if (component->regmap)
 		ret = regmap_read(component->regmap, reg, val);
-	else if (component->read)
-		ret = component->read(component, reg, val);
 	else if (component->driver->read) {
 		*val = component->driver->read(component, reg);
 		ret = 0;
@@ -72,8 +70,6 @@ int snd_soc_component_write(struct snd_soc_component *component,
 {
 	if (component->regmap)
 		return regmap_write(component->regmap, reg, val);
-	else if (component->write)
-		return component->write(component, reg, val);
 	else if (component->driver->write)
 		return component->driver->write(component, reg, val);
 	else
@@ -209,82 +205,3 @@ int snd_soc_component_test_bits(struct snd_soc_component *component,
 	return old != new;
 }
 EXPORT_SYMBOL_GPL(snd_soc_component_test_bits);
-
-unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg)
-{
-	unsigned int val;
-	int ret;
-
-	ret = snd_soc_component_read(&codec->component, reg, &val);
-	if (ret < 0)
-		return -1;
-
-	return val;
-}
-EXPORT_SYMBOL_GPL(snd_soc_read);
-
-int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int val)
-{
-	return snd_soc_component_write(&codec->component, reg, val);
-}
-EXPORT_SYMBOL_GPL(snd_soc_write);
-
-/**
- * snd_soc_update_bits - update codec register bits
- * @codec: audio codec
- * @reg: codec register
- * @mask: register mask
- * @value: new value
- *
- * Writes new register value.
- *
- * Returns 1 for change, 0 for no change, or negative error code.
- */
-int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned int reg,
-				unsigned int mask, unsigned int value)
-{
-	return snd_soc_component_update_bits(&codec->component, reg, mask,
-		value);
-}
-EXPORT_SYMBOL_GPL(snd_soc_update_bits);
-
-/**
- * snd_soc_test_bits - test register for change
- * @codec: audio codec
- * @reg: codec register
- * @mask: register mask
- * @value: new value
- *
- * Tests a register with a new value and checks if the new value is
- * different from the old value.
- *
- * Returns 1 for change else 0.
- */
-int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
-				unsigned int mask, unsigned int value)
-{
-	return snd_soc_component_test_bits(&codec->component, reg, mask, value);
-}
-EXPORT_SYMBOL_GPL(snd_soc_test_bits);
-
-int snd_soc_platform_read(struct snd_soc_platform *platform,
-					unsigned int reg)
-{
-	unsigned int val;
-	int ret;
-
-	ret = snd_soc_component_read(&platform->component, reg, &val);
-	if (ret < 0)
-		return -1;
-
-	return val;
-}
-EXPORT_SYMBOL_GPL(snd_soc_platform_read);
-
-int snd_soc_platform_write(struct snd_soc_platform *platform,
-					 unsigned int reg, unsigned int val)
-{
-	return snd_soc_component_write(&platform->component, reg, val);
-}
-EXPORT_SYMBOL_GPL(snd_soc_platform_write);
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 99902ae1a2d9..b2b16044ae80 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -29,24 +29,6 @@ struct jack_gpio_tbl {
 };
 
 /**
- * snd_soc_codec_set_jack - configure codec jack.
- * @codec: CODEC
- * @jack: structure to use for the jack
- * @data: can be used if codec driver need extra data for configuring jack
- *
- * Configures and enables jack detection function.
- */
-int snd_soc_codec_set_jack(struct snd_soc_codec *codec,
-	struct snd_soc_jack *jack, void *data)
-{
-	if (codec->driver->set_jack)
-		return codec->driver->set_jack(codec, jack, data);
-	else
-		return -ENOTSUPP;
-}
-EXPORT_SYMBOL_GPL(snd_soc_codec_set_jack);
-
-/**
  * snd_soc_component_set_jack - configure component jack.
  * @component: COMPONENTs
  * @jack: structure to use for the jack
@@ -57,10 +39,6 @@ EXPORT_SYMBOL_GPL(snd_soc_codec_set_jack);
 int snd_soc_component_set_jack(struct snd_soc_component *component,
 			       struct snd_soc_jack *jack, void *data)
 {
-	/* will be removed */
-	if (component->set_jack)
-		return component->set_jack(component, jack, data);
-
 	if (component->driver->set_jack)
 		return component->driver->set_jack(component, jack, data);
 
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 68d9dc930096..5e7ae47a9658 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -135,7 +135,6 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_component *component;
-	int i;
 	bool ignore = true;
 
 	if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
@@ -147,10 +146,6 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
 		ignore &= !component->driver->use_pmdown_time;
 	}
 
-	/* this will be removed */
-	for (i = 0; i < rtd->num_codecs; i++)
-		ignore &= rtd->codec_dais[i]->component->ignore_pmdown_time;
-
 	return ignore;
 }
 
@@ -456,13 +451,12 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
 /*
  * Called by ALSA when a PCM substream is opened, the runtime->hw record is
  * then initialized and any private data can be allocated. This also calls
- * startup for the cpu DAI, platform, machine and codec DAI.
+ * startup for the cpu DAI, component, machine and codec DAI.
  */
 static int soc_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -492,23 +486,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 		}
 	}
 
-	if (platform && platform->driver->ops && platform->driver->ops->open) {
-		ret = platform->driver->ops->open(substream);
-		if (ret < 0) {
-			dev_err(platform->dev, "ASoC: can't open platform"
-				" %s: %d\n", platform->component.name, ret);
-			goto platform_err;
-		}
-	}
-
 	ret = 0;
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->ops ||
 		    !component->driver->ops->open)
 			continue;
@@ -517,7 +498,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 		if (__ret < 0) {
 			dev_err(component->dev,
 				"ASoC: can't open component %s: %d\n",
-				component->name, ret);
+				component->name, __ret);
 			ret = __ret;
 		}
 	}
@@ -634,10 +615,6 @@ component_err:
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->ops ||
 		    !component->driver->ops->close)
 			continue;
@@ -645,10 +622,6 @@ component_err:
 		component->driver->ops->close(substream);
 	}
 
-	if (platform && platform->driver->ops && platform->driver->ops->close)
-		platform->driver->ops->close(substream);
-
-platform_err:
 	if (cpu_dai->driver->ops->shutdown)
 		cpu_dai->driver->ops->shutdown(substream, cpu_dai);
 out:
@@ -701,13 +674,12 @@ static void close_delayed_work(struct work_struct *work)
 
 /*
  * Called by ALSA when a PCM substream is closed. Private data can be
- * freed here. The cpu DAI, codec DAI, machine and platform are also
+ * freed here. The cpu DAI, codec DAI, machine and components are also
  * shutdown.
  */
 static int soc_pcm_close(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -742,16 +714,9 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
 	if (rtd->dai_link->ops->shutdown)
 		rtd->dai_link->ops->shutdown(substream);
 
-	if (platform && platform->driver->ops && platform->driver->ops->close)
-		platform->driver->ops->close(substream);
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->ops ||
 		    !component->driver->ops->close)
 			continue;
@@ -805,7 +770,6 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
 static int soc_pcm_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -823,22 +787,9 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
 		}
 	}
 
-	if (platform && platform->driver->ops && platform->driver->ops->prepare) {
-		ret = platform->driver->ops->prepare(substream);
-		if (ret < 0) {
-			dev_err(platform->dev, "ASoC: platform prepare error:"
-				" %d\n", ret);
-			goto out;
-		}
-	}
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->ops ||
 		    !component->driver->ops->prepare)
 			continue;
@@ -932,7 +883,6 @@ static int soc_pcm_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_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -994,23 +944,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 	if (ret < 0)
 		goto interface_err;
 
-	if (platform && platform->driver->ops && platform->driver->ops->hw_params) {
-		ret = platform->driver->ops->hw_params(substream, params);
-		if (ret < 0) {
-			dev_err(platform->dev, "ASoC: %s hw params failed: %d\n",
-			       platform->component.name, ret);
-			goto platform_err;
-		}
-	}
-
 	ret = 0;
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->ops ||
 		    !component->driver->ops->hw_params)
 			continue;
@@ -1019,7 +956,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 		if (__ret < 0) {
 			dev_err(component->dev,
 				"ASoC: %s hw params failed: %d\n",
-				component->name, ret);
+				component->name, __ret);
 			ret = __ret;
 		}
 	}
@@ -1043,10 +980,6 @@ component_err:
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->ops ||
 		    !component->driver->ops->hw_free)
 			continue;
@@ -1054,10 +987,6 @@ component_err:
 		component->driver->ops->hw_free(substream);
 	}
 
-	if (platform && platform->driver->ops && platform->driver->ops->hw_free)
-		platform->driver->ops->hw_free(substream);
-
-platform_err:
 	if (cpu_dai->driver->ops->hw_free)
 		cpu_dai->driver->ops->hw_free(substream, cpu_dai);
 
@@ -1085,7 +1014,6 @@ codec_err:
 static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -1123,18 +1051,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 	if (rtd->dai_link->ops->hw_free)
 		rtd->dai_link->ops->hw_free(substream);
 
-	/* free any DMA resources */
-	if (platform && platform->driver->ops && platform->driver->ops->hw_free)
-		platform->driver->ops->hw_free(substream);
-
 	/* free any component resources */
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->ops ||
 		    !component->driver->ops->hw_free)
 			continue;
@@ -1159,7 +1079,6 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -1176,19 +1095,9 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 		}
 	}
 
-	if (platform && platform->driver->ops && platform->driver->ops->trigger) {
-		ret = platform->driver->ops->trigger(substream, cmd);
-		if (ret < 0)
-			return ret;
-	}
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->ops ||
 		    !component->driver->ops->trigger)
 			continue;
@@ -1240,13 +1149,12 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
 }
 /*
  * soc level wrapper for pointer callback
- * If cpu_dai, codec_dai, platform driver has the delay callback, than
+ * If cpu_dai, codec_dai, component driver has the delay callback, then
  * the runtime->delay will be updated accordingly.
  */
 static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -1257,16 +1165,9 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
 	snd_pcm_sframes_t codec_delay = 0;
 	int i;
 
-	if (platform && platform->driver->ops && platform->driver->ops->pointer)
-		offset = platform->driver->ops->pointer(substream);
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->ops ||
 		    !component->driver->ops->pointer)
 			continue;
@@ -1878,14 +1779,15 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
 
 		/* Symmetry only applies if we've got an active stream. */
 		if (rtd->cpu_dai->active) {
-			err = soc_pcm_apply_symmetry(be_substream, rtd->cpu_dai);
+			err = soc_pcm_apply_symmetry(fe_substream,
+						     rtd->cpu_dai);
 			if (err < 0)
 				return err;
 		}
 
 		for (i = 0; i < rtd->num_codecs; i++) {
 			if (rtd->codec_dais[i]->active) {
-				err = soc_pcm_apply_symmetry(be_substream,
+				err = soc_pcm_apply_symmetry(fe_substream,
 							     rtd->codec_dais[i]);
 				if (err < 0)
 					return err;
@@ -1965,8 +1867,10 @@ int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
 			continue;
 
 		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
-		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN))
-			continue;
+		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
+			soc_pcm_hw_free(be_substream);
+			be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
+		}
 
 		dev_dbg(be->dev, "ASoC: close BE %s\n",
 			be->dai_link->name);
@@ -2470,20 +2374,12 @@ static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
 		     unsigned int cmd, void *arg)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	struct snd_soc_rtdcom_list *rtdcom;
 
-	if (platform && platform->driver->ops && platform->driver->ops->ioctl)
-		return platform->driver->ops->ioctl(substream, cmd, arg);
-
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		/* ignore duplication for now */
-		if (platform && (component == &platform->component))
-			continue;
-
 		if (!component->driver->ops ||
 		    !component->driver->ops->ioctl)
 			continue;
@@ -2847,8 +2743,8 @@ static void soc_pcm_private_free(struct snd_pcm *pcm)
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		if (component->pcm_free)
-			component->pcm_free(component, pcm);
+		if (component->driver->pcm_free)
+			component->driver->pcm_free(pcm);
 	}
 }
 
@@ -2987,7 +2883,6 @@ static int soc_rtdcom_mmap(struct snd_pcm_substream *substream,
 /* create a new pcm */
 int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 {
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_dai *codec_dai;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_component *component;
@@ -3106,16 +3001,6 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 			rtd->ops.mmap		= soc_rtdcom_mmap;
 	}
 
-	/* overwrite */
-	if (platform && platform->driver->ops) {
-		rtd->ops.ack		= platform->driver->ops->ack;
-		rtd->ops.copy_user	= platform->driver->ops->copy_user;
-		rtd->ops.copy_kernel	= platform->driver->ops->copy_kernel;
-		rtd->ops.fill_silence	= platform->driver->ops->fill_silence;
-		rtd->ops.page		= platform->driver->ops->page;
-		rtd->ops.mmap		= platform->driver->ops->mmap;
-	}
-
 	if (playback)
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
 
@@ -3125,10 +3010,10 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 	for_each_rtdcom(rtd, rtdcom) {
 		component = rtdcom->component;
 
-		if (!component->pcm_new)
+		if (!component->driver->pcm_new)
 			continue;
 
-		ret = component->pcm_new(component, rtd);
+		ret = component->driver->pcm_new(rtd);
 		if (ret < 0) {
 			dev_err(component->dev,
 				"ASoC: pcm constructor failed: %d\n",
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 986b8b2f90fb..3fd5d9c867b9 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -54,62 +54,6 @@
 #define SOC_TPLG_PASS_START	SOC_TPLG_PASS_MANIFEST
 #define SOC_TPLG_PASS_END	SOC_TPLG_PASS_LINK
 
-/*
- * Old version of ABI structs, supported for backward compatibility.
- */
-
-/* Manifest v4 */
-struct snd_soc_tplg_manifest_v4 {
-	__le32 size;		/* in bytes of this structure */
-	__le32 control_elems;	/* number of control elements */
-	__le32 widget_elems;	/* number of widget elements */
-	__le32 graph_elems;	/* number of graph elements */
-	__le32 pcm_elems;	/* number of PCM elements */
-	__le32 dai_link_elems;	/* number of DAI link elements */
-	struct snd_soc_tplg_private priv;
-} __packed;
-
-/* Stream Capabilities v4 */
-struct snd_soc_tplg_stream_caps_v4 {
-	__le32 size;		/* in bytes of this structure */
-	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-	__le64 formats;	/* supported formats SNDRV_PCM_FMTBIT_* */
-	__le32 rates;		/* supported rates SNDRV_PCM_RATE_* */
-	__le32 rate_min;	/* min rate */
-	__le32 rate_max;	/* max rate */
-	__le32 channels_min;	/* min channels */
-	__le32 channels_max;	/* max channels */
-	__le32 periods_min;	/* min number of periods */
-	__le32 periods_max;	/* max number of periods */
-	__le32 period_size_min;	/* min period size bytes */
-	__le32 period_size_max;	/* max period size bytes */
-	__le32 buffer_size_min;	/* min buffer size bytes */
-	__le32 buffer_size_max;	/* max buffer size bytes */
-} __packed;
-
-/* PCM v4 */
-struct snd_soc_tplg_pcm_v4 {
-	__le32 size;		/* in bytes of this structure */
-	char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-	char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-	__le32 pcm_id;		/* unique ID - used to match with DAI link */
-	__le32 dai_id;		/* unique ID - used to match */
-	__le32 playback;	/* supports playback mode */
-	__le32 capture;		/* supports capture mode */
-	__le32 compress;	/* 1 = compressed; 0 = PCM */
-	struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */
-	__le32 num_streams;	/* number of streams */
-	struct snd_soc_tplg_stream_caps_v4 caps[2]; /* playback and capture for DAI */
-} __packed;
-
-/* Physical link config v4 */
-struct snd_soc_tplg_link_config_v4 {
-	__le32 size;            /* in bytes of this structure */
-	__le32 id;              /* unique ID - used to match */
-	struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */
-	__le32 num_streams;     /* number of streams */
-} __packed;
-
 /* topology context */
 struct soc_tplg {
 	const struct firmware *fw;
@@ -1754,6 +1698,9 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
 		set_stream_info(stream, caps);
 	}
 
+	if (pcm->compress)
+		dai_drv->compress_new = snd_soc_new_compress;
+
 	/* pass control to component driver for optional further init */
 	ret = soc_tplg_dai_load(tplg, dai_drv);
 	if (ret < 0) {
@@ -2006,6 +1953,21 @@ static void set_link_hw_format(struct snd_soc_dai_link *link,
 
 		link->dai_fmt = hw_config->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
 
+		/* clock gating */
+		switch (hw_config->clock_gated) {
+		case SND_SOC_TPLG_DAI_CLK_GATE_GATED:
+			link->dai_fmt |= SND_SOC_DAIFMT_GATED;
+			break;
+
+		case SND_SOC_TPLG_DAI_CLK_GATE_CONT:
+			link->dai_fmt |= SND_SOC_DAIFMT_CONT;
+			break;
+
+		default:
+			/* ignore the value */
+			break;
+		}
+
 		/* clock signal polarity */
 		invert_bclk = hw_config->invert_bclk;
 		invert_fsync = hw_config->invert_fsync;
@@ -2019,13 +1981,15 @@ 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;
-		fsync_master = hw_config->fsync_master;
-		if (!bclk_master && !fsync_master)
+		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_CBS_CFM;
+		else if (bclk_master && !fsync_master)
 			link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
 		else
 			link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
@@ -2293,8 +2257,11 @@ static int manifest_new_ver(struct soc_tplg *tplg,
 	*manifest = NULL;
 
 	if (src->size != sizeof(*src_v4)) {
-		dev_err(tplg->dev, "ASoC: invalid manifest size\n");
-		return -EINVAL;
+		dev_warn(tplg->dev, "ASoC: invalid manifest size %d\n",
+			 src->size);
+		if (src->size)
+			return -EINVAL;
+		src->size = sizeof(*src_v4);
 	}
 
 	dev_warn(tplg->dev, "ASoC: old version of manifest\n");
diff --git a/sound/soc/uniphier/aio-compress.c b/sound/soc/uniphier/aio-compress.c
index 4c1027aa615e..17f773ac5ca1 100644
--- a/sound/soc/uniphier/aio-compress.c
+++ b/sound/soc/uniphier/aio-compress.c
@@ -3,19 +3,6 @@
 // Socionext UniPhier AIO Compress Audio driver.
 //
 // Copyright (c) 2017-2018 Socionext Inc.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; version 2
-// of the License.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include <linux/bitfield.h>
 #include <linux/circ_buf.h>
diff --git a/sound/soc/uniphier/aio-core.c b/sound/soc/uniphier/aio-core.c
index 6d50042a4571..638cb3fc5f7b 100644
--- a/sound/soc/uniphier/aio-core.c
+++ b/sound/soc/uniphier/aio-core.c
@@ -3,19 +3,6 @@
 // Socionext UniPhier AIO ALSA common driver.
 //
 // Copyright (c) 2016-2018 Socionext Inc.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; version 2
-// of the License.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include <linux/bitfield.h>
 #include <linux/errno.h>
@@ -673,6 +660,64 @@ void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable)
 }
 
 /**
+ * aio_port_get_volume - get volume of AIO port block
+ * @sub: the AIO substream pointer
+ *
+ * Return: current volume, range is 0x0000 - 0xffff
+ */
+int aio_port_get_volume(struct uniphier_aio_sub *sub)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 v;
+
+	regmap_read(r, OPORTMXTYVOLGAINSTATUS(sub->swm->oport.map, 0), &v);
+
+	return FIELD_GET(OPORTMXTYVOLGAINSTATUS_CUR_MASK, v);
+}
+
+/**
+ * aio_port_set_volume - set volume of AIO port block
+ * @sub: the AIO substream pointer
+ * @vol: target volume, range is 0x0000 - 0xffff.
+ *
+ * Change digital volume and perfome fade-out/fade-in effect for specified
+ * output slot of port. Gained PCM value can calculate as the following:
+ *   Gained = Original * vol / 0x4000
+ */
+void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	int oport_map = sub->swm->oport.map;
+	int cur, diff, slope = 0, fs;
+
+	if (sub->swm->dir == PORT_DIR_INPUT)
+		return;
+
+	cur = aio_port_get_volume(sub);
+	diff = abs(vol - cur);
+	fs = params_rate(&sub->params);
+	if (fs)
+		slope = diff / AUD_VOL_FADE_TIME * 1000 / fs;
+	slope = max(1, slope);
+
+	regmap_update_bits(r, OPORTMXTYVOLPARA1(oport_map, 0),
+			   OPORTMXTYVOLPARA1_SLOPEU_MASK, slope << 16);
+	regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
+			   OPORTMXTYVOLPARA2_TARGET_MASK, vol);
+
+	if (cur < vol)
+		regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
+				   OPORTMXTYVOLPARA2_FADE_MASK,
+				   OPORTMXTYVOLPARA2_FADE_FADEIN);
+	else
+		regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
+				   OPORTMXTYVOLPARA2_FADE_MASK,
+				   OPORTMXTYVOLPARA2_FADE_FADEOUT);
+
+	regmap_write(r, AOUTFADECTR0, BIT(oport_map));
+}
+
+/**
  * aio_if_set_param - set parameters of AIO DMA I/F block
  * @sub: the AIO substream pointer
  * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c
index 1e5eb8e6f8c7..80daec17be25 100644
--- a/sound/soc/uniphier/aio-cpu.c
+++ b/sound/soc/uniphier/aio-cpu.c
@@ -3,19 +3,6 @@
 // Socionext UniPhier AIO ALSA CPU DAI driver.
 //
 // Copyright (c) 2016-2018 Socionext Inc.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; version 2
-// of the License.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include <linux/clk.h>
 #include <linux/errno.h>
@@ -45,6 +32,35 @@ static bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id)
 	return chip->plls[pll_id].enable;
 }
 
+/**
+ * find_volume - find volume supported HW port by HW port number
+ * @chip: the AIO chip pointer
+ * @oport_hw: HW port number, one of AUD_HW_XXXX
+ *
+ * Find AIO device from device list by HW port number. Volume feature is
+ * available only in Output and PCM ports, this limitation comes from HW
+ * specifications.
+ *
+ * Return: The pointer of AIO substream if successful, otherwise NULL on error.
+ */
+static struct uniphier_aio_sub *find_volume(struct uniphier_aio_chip *chip,
+					    int oport_hw)
+{
+	int i;
+
+	for (i = 0; i < chip->num_aios; i++) {
+		struct uniphier_aio_sub *sub = &chip->aios[i].sub[0];
+
+		if (!sub->swm)
+			continue;
+
+		if (sub->swm->oport.hw == oport_hw)
+			return sub;
+	}
+
+	return NULL;
+}
+
 static bool match_spec(const struct uniphier_aio_spec *spec,
 		       const char *name, int dir)
 {
@@ -300,6 +316,7 @@ static int uniphier_aio_hw_params(struct snd_pcm_substream *substream,
 	sub->setting = 1;
 
 	aio_port_reset(sub);
+	aio_port_set_volume(sub, sub->vol);
 	aio_src_reset(sub);
 
 	return 0;
@@ -386,6 +403,8 @@ int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
 
 		sub->swm = &spec->swm;
 		sub->spec = spec;
+
+		sub->vol = AUD_VOL_INIT;
 	}
 
 	aio_iecout_set_enable(aio->chip, true);
@@ -462,8 +481,116 @@ err_out_clock:
 }
 EXPORT_SYMBOL_GPL(uniphier_aio_dai_resume);
 
+static int uniphier_aio_vol_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = AUD_VOL_MAX;
+
+	return 0;
+}
+
+static int uniphier_aio_vol_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+	struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
+	struct uniphier_aio_sub *sub;
+	int oport_hw = kcontrol->private_value;
+
+	sub = find_volume(chip, oport_hw);
+	if (!sub)
+		return 0;
+
+	ucontrol->value.integer.value[0] = sub->vol;
+
+	return 0;
+}
+
+static int uniphier_aio_vol_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+	struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
+	struct uniphier_aio_sub *sub;
+	int oport_hw = kcontrol->private_value;
+
+	sub = find_volume(chip, oport_hw);
+	if (!sub)
+		return 0;
+
+	if (sub->vol == ucontrol->value.integer.value[0])
+		return 0;
+	sub->vol = ucontrol->value.integer.value[0];
+
+	aio_port_set_volume(sub, sub->vol);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new uniphier_aio_controls[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.name = "HPCMOUT1 Volume",
+		.info = uniphier_aio_vol_info,
+		.get = uniphier_aio_vol_get,
+		.put = uniphier_aio_vol_put,
+		.private_value = AUD_HW_HPCMOUT1,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.name = "PCMOUT1 Volume",
+		.info = uniphier_aio_vol_info,
+		.get = uniphier_aio_vol_get,
+		.put = uniphier_aio_vol_put,
+		.private_value = AUD_HW_PCMOUT1,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.name = "PCMOUT2 Volume",
+		.info = uniphier_aio_vol_info,
+		.get = uniphier_aio_vol_get,
+		.put = uniphier_aio_vol_put,
+		.private_value = AUD_HW_PCMOUT2,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.name = "PCMOUT3 Volume",
+		.info = uniphier_aio_vol_info,
+		.get = uniphier_aio_vol_get,
+		.put = uniphier_aio_vol_put,
+		.private_value = AUD_HW_PCMOUT3,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.name = "HIECOUT1 Volume",
+		.info = uniphier_aio_vol_info,
+		.get = uniphier_aio_vol_get,
+		.put = uniphier_aio_vol_put,
+		.private_value = AUD_HW_HIECOUT1,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.name = "IECOUT1 Volume",
+		.info = uniphier_aio_vol_info,
+		.get = uniphier_aio_vol_get,
+		.put = uniphier_aio_vol_put,
+		.private_value = AUD_HW_IECOUT1,
+	},
+};
+
 static const struct snd_soc_component_driver uniphier_aio_component = {
 	.name = "uniphier-aio",
+	.controls = uniphier_aio_controls,
+	.num_controls = ARRAY_SIZE(uniphier_aio_controls),
 };
 
 int uniphier_aio_probe(struct platform_device *pdev)
diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c
index ef7bafa8e171..4ec6b65bfb44 100644
--- a/sound/soc/uniphier/aio-dma.c
+++ b/sound/soc/uniphier/aio-dma.c
@@ -3,19 +3,6 @@
 // Socionext UniPhier AIO DMA driver.
 //
 // Copyright (c) 2016-2018 Socionext Inc.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; version 2
-// of the License.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include <linux/dma-mapping.h>
 #include <linux/errno.h>
diff --git a/sound/soc/uniphier/aio-ld11.c b/sound/soc/uniphier/aio-ld11.c
index 4c4dd3dd4dee..ab04d3331be9 100644
--- a/sound/soc/uniphier/aio-ld11.c
+++ b/sound/soc/uniphier/aio-ld11.c
@@ -3,19 +3,6 @@
 // Socionext UniPhier AIO ALSA driver for LD11/LD20.
 //
 // Copyright (c) 2016-2018 Socionext Inc.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; version 2
-// of the License.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include <linux/module.h>
 
diff --git a/sound/soc/uniphier/aio-reg.h b/sound/soc/uniphier/aio-reg.h
index 136d3563cf44..45fdc6ae358a 100644
--- a/sound/soc/uniphier/aio-reg.h
+++ b/sound/soc/uniphier/aio-reg.h
@@ -3,19 +3,6 @@
  * Socionext UniPhier AIO ALSA driver.
  *
  * Copyright (c) 2016-2018 Socionext Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef SND_UNIPHIER_AIO_REG_H__
@@ -182,6 +169,7 @@
 #define PBINMXPAUSECTR1(n)               (0x20208 + 0x40 * (n))
 
 /* AOUT */
+#define AOUTFADECTR0                     0x40020
 #define AOUTENCTR0                       0x40040
 #define AOUTENCTR1                       0x40044
 #define AOUTENCTR2                       0x40048
@@ -192,6 +180,9 @@
 #define AOUTSRCRSTCTR1                   0x400c4
 #define AOUTSRCRSTCTR2                   0x400c8
 
+/* AOUT PCMOUT has 5 slots, slot0-3: D0-3, slot4: DMIX */
+#define OPORT_SLOT_MAX                     5
+
 /* AOUT(PCMOUTN) */
 #define OPORTMXCTR1(n)                   (0x42000 + 0x400 * (n))
 #define   OPORTMXCTR1_I2SLRSEL_MASK        (0x11 << 10)
@@ -372,11 +363,30 @@
 #define   OPORTMXMASK_XCKMSK_ON            (0x0 << 0)
 #define   OPORTMXMASK_XCKMSK_OFF           (0x7 << 0)
 #define OPORTMXDEBUG(n)                  (0x420fc + 0x400 * (n))
-#define OPORTMXT0RSTCTR(n)               (0x4211c + 0x400 * (n))
-#define OPORTMXT1RSTCTR(n)               (0x4213c + 0x400 * (n))
-#define OPORTMXT2RSTCTR(n)               (0x4215c + 0x400 * (n))
-#define OPORTMXT3RSTCTR(n)               (0x4217c + 0x400 * (n))
-#define OPORTMXT4RSTCTR(n)               (0x4219c + 0x400 * (n))
+#define OPORTMXTYVOLPARA1(n, m)          (0x42100 + 0x400 * (n) + 0x20 * (m))
+#define   OPORTMXTYVOLPARA1_SLOPEU_MASK    GENMASK(31, 16)
+#define OPORTMXTYVOLPARA2(n, m)          (0x42104 + 0x400 * (n) + 0x20 * (m))
+#define   OPORTMXTYVOLPARA2_FADE_MASK      GENMASK(17, 16)
+#define   OPORTMXTYVOLPARA2_FADE_NOOP      (0x0 << 16)
+#define   OPORTMXTYVOLPARA2_FADE_FADEOUT   (0x1 << 16)
+#define   OPORTMXTYVOLPARA2_FADE_FADEIN    (0x2 << 16)
+#define   OPORTMXTYVOLPARA2_TARGET_MASK    GENMASK(15, 0)
+#define OPORTMXTYVOLGAINSTATUS(n, m)     (0x42108 + 0x400 * (n) + 0x20 * (m))
+#define   OPORTMXTYVOLGAINSTATUS_CUR_MASK  GENMASK(15, 0)
+#define OPORTMXTYSLOTCTR(n, m)           (0x42114 + 0x400 * (n) + 0x20 * (m))
+#define   OPORTMXTYSLOTCTR_SLOTSEL_MASK    GENMASK(11, 8)
+#define   OPORTMXTYSLOTCTR_SLOTSEL_SLOT0   (0x8 << 8)
+#define   OPORTMXTYSLOTCTR_SLOTSEL_SLOT1   (0x9 << 8)
+#define   OPORTMXTYSLOTCTR_SLOTSEL_SLOT2   (0xa << 8)
+#define   OPORTMXTYSLOTCTR_SLOTSEL_SLOT3   (0xb << 8)
+#define   OPORTMXTYSLOTCTR_SLOTSEL_SLOT4   (0xc << 8)
+#define   OPORTMXT0SLOTCTR_MUTEOFF_MASK    BIT(1)
+#define   OPORTMXT0SLOTCTR_MUTEOFF_MUTE    (0x0 << 1)
+#define   OPORTMXT0SLOTCTR_MUTEOFF_UNMUTE  (0x1 << 1)
+#define OPORTMXTYRSTCTR(n, m)            (0x4211c + 0x400 * (n) + 0x20 * (m))
+#define   OPORTMXT0RSTCTR_RST_MASK         BIT(1)
+#define   OPORTMXT0RSTCTR_RST_OFF          (0x0 << 1)
+#define   OPORTMXT0RSTCTR_RST_ON           (0x1 << 1)
 
 #define SBF_(frame, shift)    (((frame) * 2 - 1) << shift)
 
diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h
index 8cab4a553a97..aa89c2f6fa24 100644
--- a/sound/soc/uniphier/aio.h
+++ b/sound/soc/uniphier/aio.h
@@ -3,19 +3,6 @@
  * Socionext UniPhier AIO ALSA driver.
  *
  * Copyright (c) 2016-2018 Socionext Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef SND_UNIPHIER_AIO_H__
@@ -143,6 +130,10 @@ enum IEC61937_PC {
 #define AUD_PLLDIV_1_1    2
 #define AUD_PLLDIV_2_3    3
 
+#define AUD_VOL_INIT         0x4000 /* +0dB */
+#define AUD_VOL_MAX          0xffff /* +6dB */
+#define AUD_VOL_FADE_TIME    20 /* 20ms */
+
 #define AUD_RING_SIZE            (128 * 1024)
 
 #define AUD_MIN_FRAGMENT         4
@@ -244,6 +235,7 @@ struct uniphier_aio_sub {
 	/* For PCM audio */
 	struct snd_pcm_substream *substream;
 	struct snd_pcm_hw_params params;
+	int vol;
 
 	/* For compress audio */
 	struct snd_compr_stream *cstream;
@@ -336,6 +328,8 @@ int aio_port_set_clk(struct uniphier_aio_sub *sub);
 int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
 		       const struct snd_pcm_hw_params *params);
 void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable);
+int aio_port_get_volume(struct uniphier_aio_sub *sub);
+void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol);
 int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through);
 int aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
 			      enum IEC61937_PC pc);
diff --git a/sound/soc/uniphier/evea.c b/sound/soc/uniphier/evea.c
index 73fd6730095c..f9c10165fbc1 100644
--- a/sound/soc/uniphier/evea.c
+++ b/sound/soc/uniphier/evea.c
@@ -54,8 +54,21 @@ struct evea_priv {
 	int switch_hp;
 };
 
+static const char * const linsw1_sel1_text[] = {
+	"LIN1", "LIN2", "LIN3"
+};
+
+static SOC_ENUM_SINGLE_DECL(linsw1_sel1_enum,
+	ALINSW1, ALINSW1_SEL1_SHIFT,
+	linsw1_sel1_text);
+
+static const struct snd_kcontrol_new linesw1_mux[] = {
+	SOC_DAPM_ENUM("Line In 1 Source", linsw1_sel1_enum),
+};
+
 static const struct snd_soc_dapm_widget evea_widgets[] = {
-	SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_MUX("Line In 1 Mux", SND_SOC_NOPM, 0, 0, linesw1_mux),
 	SND_SOC_DAPM_INPUT("LIN1_LP"),
 	SND_SOC_DAPM_INPUT("LIN1_RP"),
 	SND_SOC_DAPM_INPUT("LIN2_LP"),
@@ -63,7 +76,9 @@ static const struct snd_soc_dapm_widget evea_widgets[] = {
 	SND_SOC_DAPM_INPUT("LIN3_LP"),
 	SND_SOC_DAPM_INPUT("LIN3_RP"),
 
-	SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC HP", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC LO1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC LO2", NULL, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_OUTPUT("HP1_L"),
 	SND_SOC_DAPM_OUTPUT("HP1_R"),
 	SND_SOC_DAPM_OUTPUT("LO2_L"),
@@ -71,17 +86,22 @@ static const struct snd_soc_dapm_widget evea_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route evea_routes[] = {
-	{ "ADC", NULL, "LIN1_LP" },
-	{ "ADC", NULL, "LIN1_RP" },
-	{ "ADC", NULL, "LIN2_LP" },
-	{ "ADC", NULL, "LIN2_RP" },
-	{ "ADC", NULL, "LIN3_LP" },
-	{ "ADC", NULL, "LIN3_RP" },
-
-	{ "HP1_L", NULL, "DAC" },
-	{ "HP1_R", NULL, "DAC" },
-	{ "LO2_L", NULL, "DAC" },
-	{ "LO2_R", NULL, "DAC" },
+	{ "Line In 1", NULL, "ADC" },
+	{ "ADC", NULL, "Line In 1 Mux" },
+	{ "Line In 1 Mux", "LIN1", "LIN1_LP" },
+	{ "Line In 1 Mux", "LIN1", "LIN1_RP" },
+	{ "Line In 1 Mux", "LIN2", "LIN2_LP" },
+	{ "Line In 1 Mux", "LIN2", "LIN2_RP" },
+	{ "Line In 1 Mux", "LIN3", "LIN3_LP" },
+	{ "Line In 1 Mux", "LIN3", "LIN3_RP" },
+
+	{ "DAC HP", NULL, "Headphone 1" },
+	{ "DAC LO1", NULL, "Line Out 1" },
+	{ "DAC LO2", NULL, "Line Out 2" },
+	{ "HP1_L", NULL, "DAC HP" },
+	{ "HP1_R", NULL, "DAC HP" },
+	{ "LO2_L", NULL, "DAC LO2" },
+	{ "LO2_R", NULL, "DAC LO2" },
 };
 
 static void evea_set_power_state_on(struct evea_priv *evea)
@@ -280,16 +300,7 @@ static int evea_set_switch_hp(struct snd_kcontrol *kcontrol,
 	return evea_update_switch_hp(evea);
 }
 
-static const char * const linsw1_sel1_text[] = {
-	"LIN1", "LIN2", "LIN3"
-};
-
-static SOC_ENUM_SINGLE_DECL(linsw1_sel1_enum,
-	ALINSW1, ALINSW1_SEL1_SHIFT,
-	linsw1_sel1_text);
-
 static const struct snd_kcontrol_new evea_controls[] = {
-	SOC_ENUM("Line Capture Source", linsw1_sel1_enum),
 	SOC_SINGLE_BOOL_EXT("Line Capture Switch", 0,
 			    evea_get_switch_lin, evea_set_switch_lin),
 	SOC_SINGLE_BOOL_EXT("Line Playback Switch", 0,
diff --git a/sound/soc/zte/zx-i2s.c b/sound/soc/zte/zx-i2s.c
index 9a0565937d1f..0d36630aa1a7 100644
--- a/sound/soc/zte/zx-i2s.c
+++ b/sound/soc/zte/zx-i2s.c
@@ -20,9 +20,6 @@
 #include <sound/core.h>
 #include <sound/dmaengine_pcm.h>
 #include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
 
 #define ZX_I2S_PROCESS_CTRL	0x04
 #define ZX_I2S_TIMING_CTRL	0x08
@@ -197,7 +194,7 @@ static int zx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_LSB_JUSTIF);
 		break;
 	default:
-		dev_err(cpu_dai->dev, "Unknown i2s timeing\n");
+		dev_err(cpu_dai->dev, "Unknown i2s timing\n");
 		return -EINVAL;
 	}