summary refs log tree commit diff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/atmel/ac97c.c9
-rw-r--r--sound/core/control.c2
-rw-r--r--sound/core/seq/Kconfig4
-rw-r--r--sound/core/seq/seq_clientmgr.c13
-rw-r--r--sound/core/seq/seq_queue.c14
-rw-r--r--sound/core/seq/seq_queue.h2
-rw-r--r--sound/firewire/iso-resources.c7
-rw-r--r--sound/firewire/motu/motu.c1
-rw-r--r--sound/pci/emu10k1/emufx.c14
-rw-r--r--sound/pci/fm801.c4
-rw-r--r--sound/pci/hda/patch_conexant.c2
-rw-r--r--sound/pci/hda/patch_hdmi.c27
-rw-r--r--sound/pci/hda/patch_realtek.c146
-rw-r--r--sound/soc/atmel/atmel-classd.c1
-rw-r--r--sound/soc/atmel/atmel-pdmic.c1
-rw-r--r--sound/soc/au1x/db1200.c2
-rw-r--r--sound/soc/au1x/dbdma2.c2
-rw-r--r--sound/soc/au1x/dma.c2
-rw-r--r--sound/soc/au1x/psc-ac97.c2
-rw-r--r--sound/soc/au1x/psc-i2s.c2
-rw-r--r--sound/soc/bcm/cygnus-ssp.c237
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c2
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c2
-rw-r--r--sound/soc/blackfin/bf6xx-i2s.c2
-rw-r--r--sound/soc/blackfin/bf6xx-sport.c38
-rw-r--r--sound/soc/cirrus/edb93xx.c2
-rw-r--r--sound/soc/cirrus/snappercl15.c2
-rw-r--r--sound/soc/codecs/88pm860x-codec.c2
-rw-r--r--sound/soc/codecs/Kconfig15
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/ab8500-codec.c2
-rw-r--r--sound/soc/codecs/ac97.c2
-rw-r--r--sound/soc/codecs/ad1836.c2
-rw-r--r--sound/soc/codecs/ad193x.c2
-rw-r--r--sound/soc/codecs/ad1980.c2
-rw-r--r--sound/soc/codecs/ad73311.c2
-rw-r--r--sound/soc/codecs/adau1373.c2
-rw-r--r--sound/soc/codecs/adau1701.c2
-rw-r--r--sound/soc/codecs/adau1977.c8
-rw-r--r--sound/soc/codecs/adav80x.c2
-rw-r--r--sound/soc/codecs/ads117x.c2
-rw-r--r--sound/soc/codecs/ak4104.c2
-rw-r--r--sound/soc/codecs/ak4535.c2
-rw-r--r--sound/soc/codecs/ak4554.c2
-rw-r--r--sound/soc/codecs/ak4613.c2
-rw-r--r--sound/soc/codecs/ak4641.c2
-rw-r--r--sound/soc/codecs/ak4642.c2
-rw-r--r--sound/soc/codecs/ak4671.c2
-rw-r--r--sound/soc/codecs/ak5386.c2
-rw-r--r--sound/soc/codecs/alc5623.c2
-rw-r--r--sound/soc/codecs/arizona.c4
-rw-r--r--sound/soc/codecs/bt-sco.c2
-rw-r--r--sound/soc/codecs/cq93vc.c2
-rw-r--r--sound/soc/codecs/cs35l33.c14
-rw-r--r--sound/soc/codecs/cs35l34.c5
-rw-r--r--sound/soc/codecs/cs35l35.c2
-rw-r--r--sound/soc/codecs/cs4271.c2
-rw-r--r--sound/soc/codecs/cs42l42.c11
-rw-r--r--sound/soc/codecs/cs42l51.c2
-rw-r--r--sound/soc/codecs/cs43130.c2690
-rw-r--r--sound/soc/codecs/cs43130.h546
-rw-r--r--sound/soc/codecs/cs4349.c2
-rw-r--r--sound/soc/codecs/cs47l24.c6
-rw-r--r--sound/soc/codecs/cs53l30.c17
-rw-r--r--sound/soc/codecs/cx20442.c2
-rw-r--r--sound/soc/codecs/da7210.c2
-rw-r--r--sound/soc/codecs/da7213.c2
-rw-r--r--sound/soc/codecs/da7218.c2
-rw-r--r--sound/soc/codecs/da7219.c2
-rw-r--r--sound/soc/codecs/da732x.c2
-rw-r--r--sound/soc/codecs/da9055.c2
-rw-r--r--sound/soc/codecs/dmic.c54
-rw-r--r--sound/soc/codecs/es7134.c2
-rw-r--r--sound/soc/codecs/es8316.c4
-rw-r--r--sound/soc/codecs/es8328.c2
-rw-r--r--sound/soc/codecs/hdac_hdmi.c43
-rw-r--r--sound/soc/codecs/hdmi-codec.c47
-rw-r--r--sound/soc/codecs/ics43432.c2
-rw-r--r--sound/soc/codecs/inno_rk3036.c4
-rw-r--r--sound/soc/codecs/isabelle.c2
-rw-r--r--sound/soc/codecs/jz4740.c2
-rw-r--r--sound/soc/codecs/lm4857.c2
-rw-r--r--sound/soc/codecs/lm49453.c2
-rw-r--r--sound/soc/codecs/max9768.c2
-rw-r--r--sound/soc/codecs/max98088.c2
-rw-r--r--sound/soc/codecs/max98090.c2
-rw-r--r--sound/soc/codecs/max98095.c2
-rw-r--r--sound/soc/codecs/max98357a.c2
-rw-r--r--sound/soc/codecs/max98371.c14
-rw-r--r--sound/soc/codecs/max9850.c2
-rw-r--r--sound/soc/codecs/max9860.c2
-rw-r--r--sound/soc/codecs/max9867.c4
-rw-r--r--sound/soc/codecs/max98926.c8
-rw-r--r--sound/soc/codecs/max98927.c87
-rw-r--r--sound/soc/codecs/mc13783.c2
-rw-r--r--sound/soc/codecs/ml26124.c2
-rw-r--r--sound/soc/codecs/msm8916-wcd-analog.c417
-rw-r--r--sound/soc/codecs/msm8916-wcd-digital.c39
-rw-r--r--sound/soc/codecs/nau8540.c2
-rw-r--r--sound/soc/codecs/nau8810.c2
-rw-r--r--sound/soc/codecs/nau8824.c2
-rw-r--r--sound/soc/codecs/nau8825.c28
-rw-r--r--sound/soc/codecs/pcm1681.c2
-rw-r--r--sound/soc/codecs/pcm179x.c2
-rw-r--r--sound/soc/codecs/pcm3008.c2
-rw-r--r--sound/soc/codecs/pcm512x.c2
-rw-r--r--sound/soc/codecs/rt274.c1229
-rw-r--r--sound/soc/codecs/rt274.h217
-rw-r--r--sound/soc/codecs/rt286.c2
-rw-r--r--sound/soc/codecs/rt298.c2
-rw-r--r--sound/soc/codecs/rt5514-spi.c146
-rw-r--r--sound/soc/codecs/rt5514-spi.h7
-rw-r--r--sound/soc/codecs/rt5514.c174
-rw-r--r--sound/soc/codecs/rt5514.h22
-rw-r--r--sound/soc/codecs/rt5616.c4
-rw-r--r--sound/soc/codecs/rt5631.c2
-rw-r--r--sound/soc/codecs/rt5640.c2
-rw-r--r--sound/soc/codecs/rt5645.c45
-rw-r--r--sound/soc/codecs/rt5651.c2
-rw-r--r--sound/soc/codecs/rt5659.c4
-rw-r--r--sound/soc/codecs/rt5660.c2
-rw-r--r--sound/soc/codecs/rt5663.c282
-rw-r--r--sound/soc/codecs/rt5663.h2
-rw-r--r--sound/soc/codecs/rt5665.c6
-rw-r--r--sound/soc/codecs/rt5665.h4
-rw-r--r--sound/soc/codecs/rt5670.c64
-rw-r--r--sound/soc/codecs/rt5677.c81
-rw-r--r--sound/soc/codecs/rt5677.h30
-rw-r--r--sound/soc/codecs/sgtl5000.c6
-rw-r--r--sound/soc/codecs/si476x.c2
-rw-r--r--sound/soc/codecs/sirf-audio-codec.c12
-rw-r--r--sound/soc/codecs/sn95031.c2
-rw-r--r--sound/soc/codecs/spdif_receiver.c2
-rw-r--r--sound/soc/codecs/spdif_transmitter.c2
-rw-r--r--sound/soc/codecs/ssm2518.c2
-rw-r--r--sound/soc/codecs/ssm2602.c2
-rw-r--r--sound/soc/codecs/ssm4567.c2
-rw-r--r--sound/soc/codecs/stac9766.c2
-rw-r--r--sound/soc/codecs/tas2552.c2
-rw-r--r--sound/soc/codecs/tas5086.c2
-rw-r--r--sound/soc/codecs/tas5720.c4
-rw-r--r--sound/soc/codecs/tlv320aic23.c2
-rw-r--r--sound/soc/codecs/tlv320aic26.c2
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c2
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c2
-rw-r--r--sound/soc/codecs/tlv320aic3x.c2
-rw-r--r--sound/soc/codecs/tlv320dac33.c2
-rw-r--r--sound/soc/codecs/twl4030.c2
-rw-r--r--sound/soc/codecs/twl6040.c2
-rw-r--r--sound/soc/codecs/uda134x.c2
-rw-r--r--sound/soc/codecs/uda1380.c2
-rw-r--r--sound/soc/codecs/wl1273.c2
-rw-r--r--sound/soc/codecs/wm5102.c4
-rw-r--r--sound/soc/codecs/wm5110.c4
-rw-r--r--sound/soc/codecs/zx_aud96p22.c4
-rw-r--r--sound/soc/davinci/davinci-mcasp.c6
-rw-r--r--sound/soc/davinci/davinci-vcif.c5
-rw-r--r--sound/soc/dwc/dwc-i2s.c6
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c2
-rw-r--r--sound/soc/fsl/fsl_asrc.c2
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c6
-rw-r--r--sound/soc/fsl/fsl_dma.c11
-rw-r--r--sound/soc/fsl/fsl_esai.c2
-rw-r--r--sound/soc/fsl/fsl_spdif.c2
-rw-r--r--sound/soc/fsl/fsl_ssi.c4
-rw-r--r--sound/soc/fsl/imx-audmux.c16
-rw-r--r--sound/soc/fsl/imx-es8328.c3
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c6
-rw-r--r--sound/soc/fsl/imx-ssi.c4
-rw-r--r--sound/soc/fsl/mpc5200_dma.c4
-rw-r--r--sound/soc/generic/audio-graph-card.c12
-rw-r--r--sound/soc/generic/audio-graph-scu-card.c17
-rw-r--r--sound/soc/generic/simple-card-utils.c10
-rw-r--r--sound/soc/generic/simple-card.c10
-rw-r--r--sound/soc/hisilicon/hi6210-i2s.c2
-rw-r--r--sound/soc/img/img-i2s-in.c2
-rw-r--r--sound/soc/img/img-i2s-out.c2
-rw-r--r--sound/soc/img/img-parallel-out.c2
-rw-r--r--sound/soc/img/img-spdif-in.c2
-rw-r--r--sound/soc/img/img-spdif-out.c2
-rw-r--r--sound/soc/intel/Kconfig3
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c10
-rw-r--r--sound/soc/intel/atom/sst/sst_drv_interface.c4
-rw-r--r--sound/soc/intel/atom/sst/sst_pci.c2
-rw-r--r--sound/soc/intel/baytrail/sst-baytrail-pcm.c4
-rw-r--r--sound/soc/intel/boards/bxt_rt298.c86
-rw-r--r--sound/soc/intel/boards/byt-max98090.c12
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c10
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c310
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c94
-rw-r--r--sound/soc/intel/boards/mfld_machine.c4
-rw-r--r--sound/soc/intel/haswell/sst-haswell-pcm.c2
-rw-r--r--sound/soc/intel/skylake/Makefile5
-rw-r--r--sound/soc/intel/skylake/bxt-sst.c14
-rw-r--r--sound/soc/intel/skylake/cnl-sst-dsp.c274
-rw-r--r--sound/soc/intel/skylake/cnl-sst-dsp.h112
-rw-r--r--sound/soc/intel/skylake/cnl-sst.c497
-rw-r--r--sound/soc/intel/skylake/skl-messages.c167
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c82
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.c6
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c6
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.h12
-rw-r--r--sound/soc/intel/skylake/skl-sst-utils.c6
-rw-r--r--sound/soc/intel/skylake/skl-sst.c12
-rw-r--r--sound/soc/intel/skylake/skl-topology.c741
-rw-r--r--sound/soc/intel/skylake/skl-topology.h83
-rw-r--r--sound/soc/intel/skylake/skl.c34
-rw-r--r--sound/soc/intel/skylake/skl.h3
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c21
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c2
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c11
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c2
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-pcm.c15
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c1
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c1
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c1
-rw-r--r--sound/soc/mxs/mxs-saif.c13
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c1
-rw-r--r--sound/soc/nuc900/nuc900-pcm.c4
-rw-r--r--sound/soc/omap/ams-delta.c10
-rw-r--r--sound/soc/omap/omap-pcm.c4
-rw-r--r--sound/soc/omap/omap-twl4030.c13
-rw-r--r--sound/soc/omap/rx51.c9
-rw-r--r--sound/soc/pxa/Kconfig1
-rw-r--r--sound/soc/pxa/hx4700.c8
-rw-r--r--sound/soc/pxa/mmp-pcm.c4
-rw-r--r--sound/soc/pxa/mmp-sspa.c2
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c4
-rw-r--r--sound/soc/qcom/apq8016_sbc.c58
-rw-r--r--sound/soc/qcom/lpass-platform.c4
-rw-r--r--sound/soc/qcom/storm.c1
-rw-r--r--sound/soc/rockchip/Kconfig2
-rw-r--r--sound/soc/rockchip/rk3288_hdmi_analog.c4
-rw-r--r--sound/soc/rockchip/rk3399_gru_sound.c270
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c4
-rw-r--r--sound/soc/rockchip/rockchip_pdm.c2
-rw-r--r--sound/soc/samsung/h1940_uda1380.c9
-rw-r--r--sound/soc/samsung/i2s.c45
-rw-r--r--sound/soc/samsung/idma.c4
-rw-r--r--sound/soc/samsung/jive_wm8750.c2
-rw-r--r--sound/soc/samsung/odroid.c50
-rw-r--r--sound/soc/samsung/pcm.c8
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c10
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c14
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.h7
-rw-r--r--sound/soc/samsung/s3c2412-i2s.c15
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c11
-rw-r--r--sound/soc/samsung/s3c24xx_simtec.c2
-rw-r--r--sound/soc/samsung/s3c24xx_uda134x.c3
-rw-r--r--sound/soc/samsung/smartq_wm8987.c9
-rw-r--r--sound/soc/samsung/smdk_spdif.c2
-rw-r--r--sound/soc/samsung/spdif.c8
-rw-r--r--sound/soc/samsung/tm2_wm5110.c4
-rw-r--r--sound/soc/sh/dma-sh7760.c6
-rw-r--r--sound/soc/sh/fsi.c12
-rw-r--r--sound/soc/sh/hac.c2
-rw-r--r--sound/soc/sh/migor.c2
-rw-r--r--sound/soc/sh/rcar/adg.c11
-rw-r--r--sound/soc/sh/rcar/core.c109
-rw-r--r--sound/soc/sh/rcar/ctu.c5
-rw-r--r--sound/soc/sh/rcar/dma.c2
-rw-r--r--sound/soc/sh/rcar/dvc.c5
-rw-r--r--sound/soc/sh/rcar/gen.c4
-rw-r--r--sound/soc/sh/rcar/mix.c5
-rw-r--r--sound/soc/sh/rcar/rsnd.h1
-rw-r--r--sound/soc/sh/rcar/src.c14
-rw-r--r--sound/soc/sh/rcar/ssi.c141
-rw-r--r--sound/soc/sh/rcar/ssiu.c2
-rw-r--r--sound/soc/sh/siu_dai.c2
-rw-r--r--sound/soc/sh/siu_pcm.c2
-rw-r--r--sound/soc/soc-compress.c23
-rw-r--r--sound/soc/soc-core.c348
-rw-r--r--sound/soc/soc-jack.c76
-rw-r--r--sound/soc/soc-pcm.c79
-rw-r--r--sound/soc/tegra/tegra_alc5632.c13
-rw-r--r--sound/soc/tegra/tegra_max98090.c18
-rw-r--r--sound/soc/tegra/tegra_rt5640.c13
-rw-r--r--sound/soc/tegra/tegra_rt5677.c18
-rw-r--r--sound/soc/tegra/tegra_wm8903.c6
-rw-r--r--sound/soc/ux500/mop500.c4
-rw-r--r--sound/usb/mixer.c2
-rw-r--r--sound/usb/mixer.h1
-rw-r--r--sound/usb/mixer_quirks.c6
-rw-r--r--sound/usb/quirks.c14
284 files changed, 9682 insertions, 1804 deletions
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index 9d2c9d9af688..d78405329ceb 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -783,7 +783,9 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
 		dev_dbg(&pdev->dev, "no peripheral clock\n");
 		return PTR_ERR(pclk);
 	}
-	clk_prepare_enable(pclk);
+	retval = clk_prepare_enable(pclk);
+	if (retval)
+		goto err_prepare_enable;
 
 	retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
 			      SNDRV_DEFAULT_STR1, THIS_MODULE,
@@ -879,6 +881,7 @@ err_request_irq:
 	snd_card_free(card);
 err_snd_card_new:
 	clk_disable_unprepare(pclk);
+err_prepare_enable:
 	clk_put(pclk);
 	return retval;
 }
@@ -897,9 +900,9 @@ static int atmel_ac97c_resume(struct device *pdev)
 {
 	struct snd_card *card = dev_get_drvdata(pdev);
 	struct atmel_ac97c *chip = card->private_data;
+	int ret = clk_prepare_enable(chip->pclk);
 
-	clk_prepare_enable(chip->pclk);
-	return 0;
+	return ret;
 }
 
 static SIMPLE_DEV_PM_OPS(atmel_ac97c_pm, atmel_ac97c_suspend, atmel_ac97c_resume);
diff --git a/sound/core/control.c b/sound/core/control.c
index 3c6be1452e35..4525e127afd9 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1137,7 +1137,7 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
 		mutex_lock(&ue->card->user_ctl_lock);
 		change = ue->tlv_data_size != size;
 		if (!change)
-			change = memcmp(ue->tlv_data, new_data, size);
+			change = memcmp(ue->tlv_data, new_data, size) != 0;
 		kfree(ue->tlv_data);
 		ue->tlv_data = new_data;
 		ue->tlv_data_size = size;
diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig
index a536760a94c2..45c1336c6597 100644
--- a/sound/core/seq/Kconfig
+++ b/sound/core/seq/Kconfig
@@ -47,10 +47,10 @@ config SND_SEQ_HRTIMER_DEFAULT
 	  timer.
 
 config SND_SEQ_MIDI_EVENT
-	def_tristate SND_RAWMIDI
+	tristate
 
 config SND_SEQ_MIDI
-	tristate
+	def_tristate SND_RAWMIDI
 	select SND_SEQ_MIDI_EVENT
 
 config SND_SEQ_MIDI_EMUL
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 272c55fe17c8..ea2d0ae85bd3 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1502,16 +1502,11 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client,
 static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
 {
 	struct snd_seq_queue_info *info = arg;
-	int result;
 	struct snd_seq_queue *q;
 
-	result = snd_seq_queue_alloc(client->number, info->locked, info->flags);
-	if (result < 0)
-		return result;
-
-	q = queueptr(result);
-	if (q == NULL)
-		return -EINVAL;
+	q = snd_seq_queue_alloc(client->number, info->locked, info->flags);
+	if (IS_ERR(q))
+		return PTR_ERR(q);
 
 	info->queue = q->queue;
 	info->locked = q->locked;
@@ -1521,7 +1516,7 @@ static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
 	if (!info->name[0])
 		snprintf(info->name, sizeof(info->name), "Queue-%d", q->queue);
 	strlcpy(q->name, info->name, sizeof(q->name));
-	queuefree(q);
+	snd_use_lock_free(&q->use_lock);
 
 	return 0;
 }
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 450c5187eecb..79e0c5604ef8 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -184,22 +184,26 @@ void __exit snd_seq_queues_delete(void)
 static void queue_use(struct snd_seq_queue *queue, int client, int use);
 
 /* allocate a new queue -
- * return queue index value or negative value for error
+ * return pointer to new queue or ERR_PTR(-errno) for error
+ * The new queue's use_lock is set to 1. It is the caller's responsibility to
+ * call snd_use_lock_free(&q->use_lock).
  */
-int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
+struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
 {
 	struct snd_seq_queue *q;
 
 	q = queue_new(client, locked);
 	if (q == NULL)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	q->info_flags = info_flags;
 	queue_use(q, client, 1);
+	snd_use_lock_use(&q->use_lock);
 	if (queue_list_add(q) < 0) {
+		snd_use_lock_free(&q->use_lock);
 		queue_delete(q);
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	}
-	return q->queue;
+	return q;
 }
 
 /* delete a queue - queue must be owned by the client */
diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
index 30c8111477f6..719093489a2c 100644
--- a/sound/core/seq/seq_queue.h
+++ b/sound/core/seq/seq_queue.h
@@ -71,7 +71,7 @@ void snd_seq_queues_delete(void);
 
 
 /* create new queue (constructor) */
-int snd_seq_queue_alloc(int client, int locked, unsigned int flags);
+struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int flags);
 
 /* delete queue (destructor) */
 int snd_seq_queue_delete(int client, int queueid);
diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c
index f0e4d502d604..066b5df666f4 100644
--- a/sound/firewire/iso-resources.c
+++ b/sound/firewire/iso-resources.c
@@ -210,9 +210,14 @@ EXPORT_SYMBOL(fw_iso_resources_update);
  */
 void fw_iso_resources_free(struct fw_iso_resources *r)
 {
-	struct fw_card *card = fw_parent_device(r->unit)->card;
+	struct fw_card *card;
 	int bandwidth, channel;
 
+	/* Not initialized. */
+	if (r->unit == NULL)
+		return;
+	card = fw_parent_device(r->unit)->card;
+
 	mutex_lock(&r->mutex);
 
 	if (r->allocated) {
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c
index bf779cfeef0d..59a270406353 100644
--- a/sound/firewire/motu/motu.c
+++ b/sound/firewire/motu/motu.c
@@ -128,6 +128,7 @@ static void do_registration(struct work_struct *work)
 	return;
 error:
 	snd_motu_transaction_unregister(motu);
+	snd_motu_stream_destroy_duplex(motu);
 	snd_card_free(motu->card);
 	dev_info(&motu->unit->device,
 		 "Sound card registration failed: %d\n", err);
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index dc585959ca32..a2b56b188be4 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -698,10 +698,18 @@ static int copy_gctl(struct snd_emu10k1 *emu,
 {
 	struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
 
-	if (emu->support_tlv)
-		return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl));
+	if (emu->support_tlv) {
+		if (in_kernel)
+			memcpy(gctl, (void *)&_gctl[idx], sizeof(*gctl));
+		else if (copy_from_user(gctl, &_gctl[idx], sizeof(*gctl)))
+			return -EFAULT;
+		return 0;
+	}
+
 	octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
-	if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
+	if (in_kernel)
+		memcpy(gctl, (void *)&octl[idx], sizeof(*octl));
+	else if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
 		return -EFAULT;
 	gctl->tlv = NULL;
 	return 0;
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 2e402ece4c86..8e6b04b39dcc 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1235,8 +1235,6 @@ static int snd_fm801_create(struct snd_card *card,
 		}
 	}
 
-	snd_fm801_chip_init(chip);
-
 	if ((chip->tea575x_tuner & TUNER_ONLY) == 0) {
 		if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
 				IRQF_SHARED, KBUILD_MODNAME, chip)) {
@@ -1248,6 +1246,8 @@ static int snd_fm801_create(struct snd_card *card,
 		pci_set_master(pci);
 	}
 
+	snd_fm801_chip_init(chip);
+
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 		snd_fm801_free(chip);
 		return err;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 63bc894ddf5e..a81aacf684b2 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -933,6 +933,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
 	SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
 	SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
 	SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
+	SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO),
 	SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
 	SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
 	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
@@ -946,6 +947,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
 	SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
+	SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI),
 	SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index d549f35f39d3..53f9311370de 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -3733,11 +3733,15 @@ HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI",	patch_atihdmi),
 HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI",	patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI",	patch_nvhdmi_2ch),
 HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
 HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI",	patch_nvhdmi_8ch_7x),
 HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
 HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
 HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI",	patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI",	patch_nvhdmi),
@@ -3764,17 +3768,40 @@ HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI",	patch_nvhdmi_2ch),
 HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI",	patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI",	patch_nvhdmi_2ch),
 HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP",	patch_via_hdmi),
 HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP",	patch_via_hdmi),
 HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP",	patch_generic_hdmi),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 45d58fc1df39..217bb582aff1 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -2296,6 +2296,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
 	SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
 	SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
+	SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP),
 	SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
 	SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
 
@@ -3838,6 +3839,17 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
 	}
 }
 
+static struct coef_fw alc225_pre_hsmode[] = {
+	UPDATE_COEF(0x4a, 1<<8, 0),
+	UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
+	UPDATE_COEF(0x63, 3<<14, 3<<14),
+	UPDATE_COEF(0x4a, 3<<4, 2<<4),
+	UPDATE_COEF(0x4a, 3<<10, 3<<10),
+	UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+	UPDATE_COEF(0x4a, 3<<10, 0),
+	{}
+};
+
 static void alc_headset_mode_unplugged(struct hda_codec *codec)
 {
 	static struct coef_fw coef0255[] = {
@@ -3873,6 +3885,10 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
 		UPDATE_COEF(0x67, 0x2000, 0),
 		{}
 	};
+	static struct coef_fw coef0298[] = {
+		UPDATE_COEF(0x19, 0x1300, 0x0300),
+		{}
+	};
 	static struct coef_fw coef0292[] = {
 		WRITE_COEF(0x76, 0x000e),
 		WRITE_COEF(0x6c, 0x2400),
@@ -3895,13 +3911,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
 		{}
 	};
 	static struct coef_fw coef0225[] = {
-		UPDATE_COEF(0x4a, 1<<8, 0),
-		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
-		UPDATE_COEF(0x63, 3<<14, 3<<14),
-		UPDATE_COEF(0x4a, 3<<4, 2<<4),
-		UPDATE_COEF(0x4a, 3<<10, 3<<10),
-		UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
-		UPDATE_COEF(0x4a, 3<<10, 0),
+		UPDATE_COEF(0x63, 3<<14, 0),
 		{}
 	};
 	static struct coef_fw coef0274[] = {
@@ -3935,7 +3945,10 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
 		break;
 	case 0x10ec0286:
 	case 0x10ec0288:
+		alc_process_coef_fw(codec, coef0288);
+		break;
 	case 0x10ec0298:
+		alc_process_coef_fw(codec, coef0298);
 		alc_process_coef_fw(codec, coef0288);
 		break;
 	case 0x10ec0292:
@@ -3976,6 +3989,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
 		{}
 	};
 	static struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x4f, 0x00c0, 0),
 		UPDATE_COEF(0x50, 0x2000, 0),
 		UPDATE_COEF(0x56, 0x0006, 0),
 		UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
@@ -4039,7 +4053,6 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
 	case 0x10ec0286:
 	case 0x10ec0288:
 	case 0x10ec0298:
-		alc_update_coef_idx(codec, 0x4f, 0x000c, 0);
 		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
 		alc_process_coef_fw(codec, coef0288);
 		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
@@ -4072,6 +4085,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
 	case 0x10ec0225:
 	case 0x10ec0295:
 	case 0x10ec0299:
+		alc_process_coef_fw(codec, alc225_pre_hsmode);
 		alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
 		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
 		alc_process_coef_fw(codec, coef0225);
@@ -4084,7 +4098,12 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
 static void alc_headset_mode_default(struct hda_codec *codec)
 {
 	static struct coef_fw coef0225[] = {
-		UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+		UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10),
+		UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10),
+		UPDATE_COEF(0x49, 3<<8, 0<<8),
+		UPDATE_COEF(0x4a, 3<<4, 3<<4),
+		UPDATE_COEF(0x63, 3<<14, 0),
+		UPDATE_COEF(0x67, 0xf000, 0x3000),
 		{}
 	};
 	static struct coef_fw coef0255[] = {
@@ -4138,6 +4157,7 @@ static void alc_headset_mode_default(struct hda_codec *codec)
 	case 0x10ec0225:
 	case 0x10ec0295:
 	case 0x10ec0299:
+		alc_process_coef_fw(codec, alc225_pre_hsmode);
 		alc_process_coef_fw(codec, coef0225);
 		break;
 	case 0x10ec0255:
@@ -4177,6 +4197,8 @@ static void alc_headset_mode_default(struct hda_codec *codec)
 /* Iphone type */
 static void alc_headset_mode_ctia(struct hda_codec *codec)
 {
+	int val;
+
 	static struct coef_fw coef0255[] = {
 		WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
 		WRITE_COEF(0x1b, 0x0c2b),
@@ -4219,11 +4241,14 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
 		WRITE_COEF(0xc3, 0x0000),
 		{}
 	};
-	static struct coef_fw coef0225[] = {
+	static struct coef_fw coef0225_1[] = {
 		UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
-		UPDATE_COEF(0x49, 1<<8, 1<<8),
-		UPDATE_COEF(0x4a, 7<<6, 7<<6),
-		UPDATE_COEF(0x4a, 3<<4, 3<<4),
+		UPDATE_COEF(0x63, 3<<14, 2<<14),
+		{}
+	};
+	static struct coef_fw coef0225_2[] = {
+		UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
+		UPDATE_COEF(0x63, 3<<14, 1<<14),
 		{}
 	};
 
@@ -4244,8 +4269,17 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
 		alc_process_coef_fw(codec, coef0233);
 		break;
 	case 0x10ec0298:
-		alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);/* Headset output enable */
-		/* ALC298 jack type setting is the same with ALC286/ALC288 */
+		val = alc_read_coef_idx(codec, 0x50);
+		if (val & (1 << 12)) {
+			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
+			alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+			msleep(300);
+		} else {
+			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
+			alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+			msleep(300);
+		}
+		break;
 	case 0x10ec0286:
 	case 0x10ec0288:
 		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
@@ -4264,7 +4298,11 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
 	case 0x10ec0225:
 	case 0x10ec0295:
 	case 0x10ec0299:
-		alc_process_coef_fw(codec, coef0225);
+		val = alc_read_coef_idx(codec, 0x45);
+		if (val & (1 << 9))
+			alc_process_coef_fw(codec, coef0225_2);
+		else
+			alc_process_coef_fw(codec, coef0225_1);
 		break;
 	case 0x10ec0867:
 		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
@@ -4320,9 +4358,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
 	};
 	static struct coef_fw coef0225[] = {
 		UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
-		UPDATE_COEF(0x49, 1<<8, 1<<8),
-		UPDATE_COEF(0x4a, 7<<6, 7<<6),
-		UPDATE_COEF(0x4a, 3<<4, 3<<4),
+		UPDATE_COEF(0x63, 3<<14, 2<<14),
 		{}
 	};
 
@@ -4344,7 +4380,9 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
 		break;
 	case 0x10ec0298:
 		alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */
-		/* ALC298 jack type setting is the same with ALC286/ALC288 */
+		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
+		msleep(300);
+		break;
 	case 0x10ec0286:
 	case 0x10ec0288:
 		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
@@ -4384,6 +4422,14 @@ static void alc_determine_headset_type(struct hda_codec *codec)
 		UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
 		{}
 	};
+	static struct coef_fw coef0298[] = {
+		UPDATE_COEF(0x50, 0x2000, 0x2000),
+		UPDATE_COEF(0x56, 0x0006, 0x0006),
+		UPDATE_COEF(0x66, 0x0008, 0),
+		UPDATE_COEF(0x67, 0x2000, 0),
+		UPDATE_COEF(0x19, 0x1300, 0x1300),
+		{}
+	};
 	static struct coef_fw coef0293[] = {
 		UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
 		WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
@@ -4396,11 +4442,6 @@ static void alc_determine_headset_type(struct hda_codec *codec)
 		WRITE_COEF(0xc3, 0x0c00),
 		{}
 	};
-	static struct coef_fw coef0225[] = {
-		UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
-		UPDATE_COEF(0x49, 1<<8, 1<<8),
-		{}
-	};
 	static struct coef_fw coef0274[] = {
 		UPDATE_COEF(0x4a, 0x0010, 0),
 		UPDATE_COEF(0x4a, 0x8000, 0),
@@ -4433,8 +4474,34 @@ static void alc_determine_headset_type(struct hda_codec *codec)
 		is_ctia = (val & 0x0070) == 0x0070;
 		break;
 	case 0x10ec0298:
-		alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020); /* Headset output enable */
-		/* ALC298 check jack type is the same with ALC286/ALC288 */
+		snd_hda_codec_write(codec, 0x21, 0,
+			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+		msleep(100);
+		snd_hda_codec_write(codec, 0x21, 0,
+			    AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+		msleep(200);
+
+		val = alc_read_coef_idx(codec, 0x50);
+		if (val & (1 << 12)) {
+			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
+			alc_process_coef_fw(codec, coef0288);
+			msleep(350);
+			val = alc_read_coef_idx(codec, 0x50);
+			is_ctia = (val & 0x0070) == 0x0070;
+		} else {
+			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
+			alc_process_coef_fw(codec, coef0288);
+			msleep(350);
+			val = alc_read_coef_idx(codec, 0x50);
+			is_ctia = (val & 0x0070) == 0x0070;
+		}
+		alc_process_coef_fw(codec, coef0298);
+		snd_hda_codec_write(codec, 0x21, 0,
+			    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+		msleep(75);
+		snd_hda_codec_write(codec, 0x21, 0,
+			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+		break;
 	case 0x10ec0286:
 	case 0x10ec0288:
 		alc_process_coef_fw(codec, coef0288);
@@ -4463,10 +4530,25 @@ static void alc_determine_headset_type(struct hda_codec *codec)
 	case 0x10ec0225:
 	case 0x10ec0295:
 	case 0x10ec0299:
-		alc_process_coef_fw(codec, coef0225);
-		msleep(800);
-		val = alc_read_coef_idx(codec, 0x46);
-		is_ctia = (val & 0x00f0) == 0x00f0;
+		alc_process_coef_fw(codec, alc225_pre_hsmode);
+		alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000);
+		val = alc_read_coef_idx(codec, 0x45);
+		if (val & (1 << 9)) {
+			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
+			alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8);
+			msleep(800);
+			val = alc_read_coef_idx(codec, 0x46);
+			is_ctia = (val & 0x00f0) == 0x00f0;
+		} else {
+			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
+			alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
+			msleep(800);
+			val = alc_read_coef_idx(codec, 0x46);
+			is_ctia = (val & 0x00f0) == 0x00f0;
+		}
+		alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6);
+		alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4);
+		alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
 		break;
 	case 0x10ec0867:
 		is_ctia = true;
@@ -6565,7 +6647,6 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
 	SND_HDA_PIN_QUIRK(0x10ec0299, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
 		ALC225_STANDARD_PINS,
 		{0x12, 0xb7a60130},
-		{0x13, 0xb8a61140},
 		{0x17, 0x90170110}),
 	{}
 };
@@ -6724,6 +6805,7 @@ static int patch_alc269(struct hda_codec *codec)
 	case 0x10ec0225:
 	case 0x10ec0295:
 		spec->codec_variant = ALC269_TYPE_ALC225;
+		spec->gen.mixer_nid = 0; /* no loopback on ALC225 ALC295 */
 		break;
 	case 0x10ec0299:
 		spec->codec_variant = ALC269_TYPE_ALC225;
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index b7ef8c59b49a..0cd7caaed9c4 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -652,7 +652,6 @@ static int atmel_classd_probe(struct platform_device *pdev)
 	}
 
 	snd_soc_card_set_drvdata(card, dd);
-	platform_set_drvdata(pdev, card);
 
 	ret = atmel_classd_asoc_card_init(dev, card);
 	if (ret) {
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c
index c917df7715d1..8e3d34be9e69 100644
--- a/sound/soc/atmel/atmel-pdmic.c
+++ b/sound/soc/atmel/atmel-pdmic.c
@@ -694,7 +694,6 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
 	}
 
 	snd_soc_card_set_drvdata(card, dd);
-	platform_set_drvdata(pdev, card);
 
 	ret = atmel_pdmic_asoc_card_init(dev, card);
 	if (ret) {
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index 5c73061d912a..301e1fc9a377 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -99,7 +99,7 @@ static int db1200_i2s_startup(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static struct snd_soc_ops db1200_i2s_wm8731_ops = {
+static const struct snd_soc_ops db1200_i2s_wm8731_ops = {
 	.startup	= db1200_i2s_startup,
 };
 
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index b5d1caa04d8e..6a035ca0f521 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -304,7 +304,7 @@ static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static struct snd_pcm_ops au1xpsc_pcm_ops = {
+static const struct snd_pcm_ops au1xpsc_pcm_ops = {
 	.open		= au1xpsc_pcm_open,
 	.close		= au1xpsc_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
index fcf5a9adde81..19457e2b351e 100644
--- a/sound/soc/au1x/dma.c
+++ b/sound/soc/au1x/dma.c
@@ -277,7 +277,7 @@ static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_pcm_substream *ss)
 	return bytes_to_frames(ss->runtime, location);
 }
 
-static struct snd_pcm_ops alchemy_pcm_ops = {
+static const struct snd_pcm_ops alchemy_pcm_ops = {
 	.open			= alchemy_pcm_open,
 	.close			= alchemy_pcm_close,
 	.ioctl			= snd_pcm_lib_ioctl,
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index bb53c7059005..a2050ae5a3fe 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -474,7 +474,7 @@ static int au1xpsc_ac97_drvresume(struct device *dev)
 	return 0;
 }
 
-static struct dev_pm_ops au1xpscac97_pmops = {
+static const struct dev_pm_ops au1xpscac97_pmops = {
 	.suspend	= au1xpsc_ac97_drvsuspend,
 	.resume		= au1xpsc_ac97_drvresume,
 };
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index 0bf9d62b91a0..e6eec081eaae 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -392,7 +392,7 @@ static int au1xpsc_i2s_drvresume(struct device *dev)
 	return 0;
 }
 
-static struct dev_pm_ops au1xpsci2s_pmops = {
+static const struct dev_pm_ops au1xpsci2s_pmops = {
 	.suspend	= au1xpsc_i2s_drvsuspend,
 	.resume		= au1xpsc_i2s_drvresume,
 };
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index e710bb0c5637..15c438f0f22d 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -27,12 +27,6 @@
 
 #define DEFAULT_VCO    1354750204
 
-#define CYGNUS_TDM_RATE \
-		(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
-		SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050 | \
-		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-		SNDRV_PCM_RATE_48000)
-
 #define CAPTURE_FCI_ID_BASE 0x180
 #define CYGNUS_SSP_TRISTATE_MASK 0x001fff
 #define CYGNUS_PLLCLKSEL_MASK 0xf
@@ -234,152 +228,20 @@ static const struct pll_macro_entry pll_predef_mclk[] = {
 	{98304000, 2},
 };
 
+#define CYGNUS_RATE_MIN     8000
+#define CYGNUS_RATE_MAX   384000
+
 /* List of valid frame sizes for tdm mode */
 static const int ssp_valid_tdm_framesize[] = {32, 64, 128, 256, 512};
 
-/*
- * Use this relationship to derive the sampling rate (lrclk)
- * lrclk = (mclk) / ((2*mclk_to_sclk_ratio) * (32 * SCLK))).
- *
- * Use mclk and pll_ch from the table above
- *
- * Valid SCLK = 0/1/2/4/8/12
- *
- * mclk_to_sclk_ratio = number of MCLK per SCLK. Division is twice the
- * value programmed in this field.
- * Valid mclk_to_sclk_ratio = 1 through to 15
- *
- * eg: To set lrclk = 48khz, set mclk = 12288000, mclk_to_sclk_ratio = 2,
- * SCLK = 64
- */
-struct _ssp_clk_coeff {
-	u32 mclk;
-	u32 sclk_rate;
-	u32 rate;
-	u32 mclk_rate;
+static const unsigned int cygnus_rates[] = {
+	 8000, 11025,  16000,  22050,  32000,  44100, 48000,
+	88200, 96000, 176400, 192000, 352800, 384000
 };
 
-static const struct _ssp_clk_coeff ssp_clk_coeff[] = {
-	{ 4096000,  32,  16000, 4},
-	{ 4096000,  32,  32000, 2},
-	{ 4096000,  64,   8000, 4},
-	{ 4096000,  64,  16000, 2},
-	{ 4096000,  64,  32000, 1},
-	{ 4096000, 128,   8000, 2},
-	{ 4096000, 128,  16000, 1},
-	{ 4096000, 256,   8000, 1},
-
-	{ 6144000,  32,  16000, 6},
-	{ 6144000,  32,  32000, 3},
-	{ 6144000,  32,  48000, 2},
-	{ 6144000,  32,  96000, 1},
-	{ 6144000,  64,   8000, 6},
-	{ 6144000,  64,  16000, 3},
-	{ 6144000,  64,  48000, 1},
-	{ 6144000, 128,   8000, 3},
-
-	{ 8192000,  32,  32000, 4},
-	{ 8192000,  64,  16000, 4},
-	{ 8192000,  64,  32000, 2},
-	{ 8192000, 128,   8000, 4},
-	{ 8192000, 128,  16000, 2},
-	{ 8192000, 128,  32000, 1},
-	{ 8192000, 256,   8000, 2},
-	{ 8192000, 256,  16000, 1},
-	{ 8192000, 512,   8000, 1},
-
-	{12288000,  32,  32000, 6},
-	{12288000,  32,  48000, 4},
-	{12288000,  32,  96000, 2},
-	{12288000,  32, 192000, 1},
-	{12288000,  64,  16000, 6},
-	{12288000,  64,  32000, 3},
-	{12288000,  64,  48000, 2},
-	{12288000,  64,  96000, 1},
-	{12288000, 128,   8000, 6},
-	{12288000, 128,  16000, 3},
-	{12288000, 128,  48000, 1},
-	{12288000, 256,   8000, 3},
-
-	{16384000,  64,  32000, 4},
-	{16384000, 128,  16000, 4},
-	{16384000, 128,  32000, 2},
-	{16384000, 256,   8000, 4},
-	{16384000, 256,  16000, 2},
-	{16384000, 256,  32000, 1},
-	{16384000, 512,   8000, 2},
-	{16384000, 512,  16000, 1},
-
-	{24576000,  32,  96000, 4},
-	{24576000,  32, 192000, 2},
-	{24576000,  64,  32000, 6},
-	{24576000,  64,  48000, 4},
-	{24576000,  64,  96000, 2},
-	{24576000,  64, 192000, 1},
-	{24576000, 128,  16000, 6},
-	{24576000, 128,  32000, 3},
-	{24576000, 128,  48000, 2},
-	{24576000, 256,   8000, 6},
-	{24576000, 256,  16000, 3},
-	{24576000, 256,  48000, 1},
-	{24576000, 512,   8000, 3},
-
-	{49152000,  32, 192000, 4},
-	{49152000,  64,  96000, 4},
-	{49152000,  64, 192000, 2},
-	{49152000, 128,  32000, 6},
-	{49152000, 128,  48000, 4},
-	{49152000, 128,  96000, 2},
-	{49152000, 128, 192000, 1},
-	{49152000, 256,  16000, 6},
-	{49152000, 256,  32000, 3},
-	{49152000, 256,  48000, 2},
-	{49152000, 256,  96000, 1},
-	{49152000, 512,   8000, 6},
-	{49152000, 512,  16000, 3},
-	{49152000, 512,  48000, 1},
-
-	{ 5644800,  32,  22050, 4},
-	{ 5644800,  32,  44100, 2},
-	{ 5644800,  32,  88200, 1},
-	{ 5644800,  64,  11025, 4},
-	{ 5644800,  64,  22050, 2},
-	{ 5644800,  64,  44100, 1},
-
-	{11289600,  32,  44100, 4},
-	{11289600,  32,  88200, 2},
-	{11289600,  32, 176400, 1},
-	{11289600,  64,  22050, 4},
-	{11289600,  64,  44100, 2},
-	{11289600,  64,  88200, 1},
-	{11289600, 128,  11025, 4},
-	{11289600, 128,  22050, 2},
-	{11289600, 128,  44100, 1},
-
-	{22579200,  32,  88200, 4},
-	{22579200,  32, 176400, 2},
-	{22579200,  64,  44100, 4},
-	{22579200,  64,  88200, 2},
-	{22579200,  64, 176400, 1},
-	{22579200, 128,  22050, 4},
-	{22579200, 128,  44100, 2},
-	{22579200, 128,  88200, 1},
-	{22579200, 256,  11025, 4},
-	{22579200, 256,  22050, 2},
-	{22579200, 256,  44100, 1},
-
-	{45158400,  32, 176400, 4},
-	{45158400,  64,  88200, 4},
-	{45158400,  64, 176400, 2},
-	{45158400, 128,  44100, 4},
-	{45158400, 128,  88200, 2},
-	{45158400, 128, 176400, 1},
-	{45158400, 256,  22050, 4},
-	{45158400, 256,  44100, 2},
-	{45158400, 256,  88200, 1},
-	{45158400, 512,  11025, 4},
-	{45158400, 512,  22050, 2},
-	{45158400, 512,  44100, 1},
+static const struct snd_pcm_hw_constraint_list cygnus_rate_constraint = {
+	.count = ARRAY_SIZE(cygnus_rates),
+	.list = cygnus_rates,
 };
 
 static struct cygnus_aio_port *cygnus_dai_get_portinfo(struct snd_soc_dai *dai)
@@ -679,40 +541,55 @@ static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk,
 	return p_entry->pll_ch_num;
 }
 
-static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
-			struct cygnus_audio *cygaud)
+static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 {
-	u32 value, i = 0;
+	u32 value;
 	u32 mask = 0xf;
 	u32 sclk;
-	bool found = false;
-	const struct _ssp_clk_coeff *p_entry = NULL;
+	u32 mclk_rate;
+	unsigned int bit_rate;
+	unsigned int ratio;
 
-	for (i = 0; i < ARRAY_SIZE(ssp_clk_coeff); i++) {
-		p_entry = &ssp_clk_coeff[i];
-		if ((p_entry->rate == aio->lrclk) &&
-		    (p_entry->sclk_rate == aio->bit_per_frame) &&
-		    (p_entry->mclk == aio->mclk)) {
-			found = true;
-			break;
-		}
-	}
-	if (!found) {
+	bit_rate = aio->bit_per_frame * aio->lrclk;
+
+	/*
+	 * Check if the bit clock can be generated from the given MCLK.
+	 * MCLK must be a perfect multiple of bit clock and must be one of the
+	 * following values... (2,4,6,8,10,12,14)
+	 */
+	if ((aio->mclk % bit_rate) != 0)
+		return -EINVAL;
+
+	ratio = aio->mclk / bit_rate;
+	switch (ratio) {
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+	case 10:
+	case 12:
+	case 14:
+		mclk_rate = ratio / 2;
+		break;
+
+	default:
 		dev_err(aio->cygaud->dev,
-			"No valid match found in ssp_clk_coeff array\n");
+			"Invalid combination of MCLK and BCLK\n");
 		dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
 			aio->lrclk, aio->bit_per_frame, aio->mclk);
 		return -EINVAL;
 	}
 
-	sclk = aio->bit_per_frame;
-	if (sclk == 512)
-		sclk = 0;
-	/* sclks_per_1fs_div = sclk cycles/32 */
-	sclk /= 32;
 	/* Set sclk rate */
 	switch (aio->port_type) {
 	case PORT_TDM:
+		sclk = aio->bit_per_frame;
+		if (sclk == 512)
+			sclk = 0;
+
+		/* sclks_per_1fs_div = sclk cycles/32 */
+		sclk /= 32;
+
 		/* Set number of bitclks per frame */
 		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
 		value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32);
@@ -731,7 +608,7 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
 	/* Set MCLK_RATE ssp port (spdif and ssp are the same) */
 	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 	value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT);
-	value |= (p_entry->mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
+	value |= (mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
 	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 
 	dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
@@ -745,7 +622,6 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
 	int rate, bitres;
 	u32 value;
 	u32 mask = 0x1f;
@@ -841,7 +717,7 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	aio->lrclk = rate;
 
 	if (!aio->is_slave)
-		ret = cygnus_ssp_set_clocks(aio, cygaud);
+		ret = cygnus_ssp_set_clocks(aio);
 
 	return ret;
 }
@@ -888,6 +764,11 @@ static int cygnus_ssp_startup(struct snd_pcm_substream *substream,
 	else
 		aio->clk_trace.cap_en = true;
 
+	substream->runtime->hw.rate_min = CYGNUS_RATE_MIN;
+	substream->runtime->hw.rate_max = CYGNUS_RATE_MAX;
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint);
 	return 0;
 }
 
@@ -1261,9 +1142,7 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
 	.playback = { \
 		.channels_min = 1, \
 		.channels_max = 16, \
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
-			SNDRV_PCM_RATE_192000, \
+		.rates = SNDRV_PCM_RATE_KNOT, \
 		.formats = SNDRV_PCM_FMTBIT_S8 | \
 				SNDRV_PCM_FMTBIT_S16_LE | \
 				SNDRV_PCM_FMTBIT_S32_LE, \
@@ -1271,9 +1150,7 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
 	.capture = { \
 		.channels_min = 2, \
 		.channels_max = 16, \
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
-			SNDRV_PCM_RATE_192000, \
+		.rates = SNDRV_PCM_RATE_KNOT, \
 		.formats =  SNDRV_PCM_FMTBIT_S16_LE | \
 					SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
@@ -1288,14 +1165,12 @@ static const struct snd_soc_dai_driver cygnus_ssp_dai_info[] = {
 	INIT_CPU_DAI(2),
 };
 
-static struct snd_soc_dai_driver cygnus_spdif_dai_info = {
+static const struct snd_soc_dai_driver cygnus_spdif_dai_info = {
 	.name = "cygnus-spdif",
 	.playback = {
 		.channels_min = 2,
 		.channels_max = 2,
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 |
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
-			SNDRV_PCM_RATE_192000,
+		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
 			SNDRV_PCM_FMTBIT_S32_LE,
 	},
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 913e29275f4e..8c1d1983b8f9 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -308,7 +308,7 @@ static	int bf5xx_pcm_copy_user(struct snd_pcm_substream *substream,
 }
 #endif
 
-static struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
+static const struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
 	.open		= bf5xx_pcm_open,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= bf5xx_pcm_hw_params,
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index 470d99abf6f6..51cae76f14e6 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -318,7 +318,7 @@ static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
+static const struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
 	.open		= bf5xx_pcm_open,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= bf5xx_pcm_hw_params,
diff --git a/sound/soc/blackfin/bf6xx-i2s.c b/sound/soc/blackfin/bf6xx-i2s.c
index bd3b4d464145..819cff149a25 100644
--- a/sound/soc/blackfin/bf6xx-i2s.c
+++ b/sound/soc/blackfin/bf6xx-i2s.c
@@ -164,7 +164,7 @@ static int bfin_i2s_resume(struct snd_soc_dai *dai)
 #define BFIN_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
 		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops bfin_i2s_dai_ops = {
+static const struct snd_soc_dai_ops bfin_i2s_dai_ops = {
 	.hw_params	= bfin_i2s_hw_params,
 	.set_fmt	= bfin_i2s_set_dai_fmt,
 };
diff --git a/sound/soc/blackfin/bf6xx-sport.c b/sound/soc/blackfin/bf6xx-sport.c
index dfb744381c42..d2caadfe7b6d 100644
--- a/sound/soc/blackfin/bf6xx-sport.c
+++ b/sound/soc/blackfin/bf6xx-sport.c
@@ -129,7 +129,7 @@ static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
 
 	for (i = 0; i < fragcount; ++i) {
 		desc[i].next_desc_addr  = &(desc[i + 1]);
-		desc[i].start_addr = (unsigned long)buf + i*fragsize;
+		desc[i].start_addr = (unsigned long)buf + i * fragsize;
 		desc[i].cfg = cfg;
 		desc[i].x_count = count;
 		desc[i].x_modify = wdsize;
@@ -138,7 +138,7 @@ static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
 	}
 
 	/* make circular */
-	desc[fragcount-1].next_desc_addr = desc;
+	desc[fragcount - 1].next_desc_addr = desc;
 }
 
 int sport_config_tx_dma(struct sport_device *sport, void *buf,
@@ -148,7 +148,7 @@ int sport_config_tx_dma(struct sport_device *sport, void *buf,
 	unsigned int cfg;
 	dma_addr_t addr;
 
-	count = fragsize/sport->wdsize;
+	count = fragsize / sport->wdsize;
 
 	if (sport->tx_desc)
 		dma_free_coherent(NULL, sport->tx_desc_size,
@@ -166,8 +166,7 @@ int sport_config_tx_dma(struct sport_device *sport, void *buf,
 	cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize) | NDSIZE_6;
 
 	setup_desc(sport->tx_desc, buf, fragcount, fragsize,
-			cfg|DMAEN, count, sport->wdsize);
-
+		   cfg | DMAEN, count, sport->wdsize);
 	return 0;
 }
 EXPORT_SYMBOL(sport_config_tx_dma);
@@ -179,7 +178,7 @@ int sport_config_rx_dma(struct sport_device *sport, void *buf,
 	unsigned int cfg;
 	dma_addr_t addr;
 
-	count = fragsize/sport->wdsize;
+	count = fragsize / sport->wdsize;
 
 	if (sport->rx_desc)
 		dma_free_coherent(NULL, sport->rx_desc_size,
@@ -198,8 +197,7 @@ int sport_config_rx_dma(struct sport_device *sport, void *buf,
 		| WNR | NDSIZE_6;
 
 	setup_desc(sport->rx_desc, buf, fragcount, fragsize,
-			cfg|DMAEN, count, sport->wdsize);
-
+		   cfg | DMAEN, count, sport->wdsize);
 	return 0;
 }
 EXPORT_SYMBOL(sport_config_rx_dma);
@@ -226,7 +224,7 @@ static irqreturn_t sport_tx_irq(int irq, void *dev_id)
 	static unsigned long status;
 
 	status = get_dma_curr_irqstat(sport->tx_dma_chan);
-	if (status & (DMA_DONE|DMA_ERR)) {
+	if (status & (DMA_DONE | DMA_ERR)) {
 		clear_dma_irqstat(sport->tx_dma_chan);
 		SSYNC();
 	}
@@ -241,7 +239,7 @@ static irqreturn_t sport_rx_irq(int irq, void *dev_id)
 	unsigned long status;
 
 	status = get_dma_curr_irqstat(sport->rx_dma_chan);
-	if (status & (DMA_DONE|DMA_ERR)) {
+	if (status & (DMA_DONE | DMA_ERR)) {
 		clear_dma_irqstat(sport->rx_dma_chan);
 		SSYNC();
 	}
@@ -388,26 +386,24 @@ struct sport_device *sport_create(struct platform_device *pdev)
 	int ret;
 
 	sport = kzalloc(sizeof(*sport), GFP_KERNEL);
-	if (!sport) {
-		dev_err(dev, "Unable to allocate memory for sport device\n");
+	if (!sport)
 		return NULL;
-	}
+
 	sport->pdev = pdev;
 
 	ret = sport_get_resource(sport);
-	if (ret) {
-		kfree(sport);
-		return NULL;
-	}
+	if (ret)
+		goto free_data;
 
 	ret = sport_request_resource(sport);
-	if (ret) {
-		kfree(sport);
-		return NULL;
-	}
+	if (ret)
+		goto free_data;
 
 	dev_dbg(dev, "SPORT create success\n");
 	return sport;
+free_data:
+	kfree(sport);
+	return NULL;
 }
 EXPORT_SYMBOL(sport_create);
 
diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c
index 85962657aabe..c53bd6f2c2d7 100644
--- a/sound/soc/cirrus/edb93xx.c
+++ b/sound/soc/cirrus/edb93xx.c
@@ -56,7 +56,7 @@ static int edb93xx_hw_params(struct snd_pcm_substream *substream,
 				      SND_SOC_CLOCK_OUT);
 }
 
-static struct snd_soc_ops edb93xx_ops = {
+static const struct snd_soc_ops edb93xx_ops = {
 	.hw_params	= edb93xx_hw_params,
 };
 
diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c
index 98089df08df6..2334ec19e7eb 100644
--- a/sound/soc/cirrus/snappercl15.c
+++ b/sound/soc/cirrus/snappercl15.c
@@ -45,7 +45,7 @@ static int snappercl15_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static struct snd_soc_ops snappercl15_ops = {
+static const struct snd_soc_ops snappercl15_ops = {
 	.hw_params	= snappercl15_hw_params,
 };
 
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index b013a4c62b63..848c5fe49bc7 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -1355,7 +1355,7 @@ static struct regmap *pm860x_get_regmap(struct device *dev)
 	return pm860x->regmap;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
+static const struct snd_soc_codec_driver soc_codec_dev_pm860x = {
 	.probe		= pm860x_probe,
 	.remove		= pm860x_remove,
 	.set_bias_level	= pm860x_set_bias_level,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 6c78b0b49b81..d81bc4195603 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -60,6 +60,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_CS4271_I2C if I2C
 	select SND_SOC_CS4271_SPI if SPI_MASTER
 	select SND_SOC_CS42XX8_I2C if I2C
+	select SND_SOC_CS43130 if I2C
 	select SND_SOC_CS4349 if I2C
 	select SND_SOC_CS47L24 if MFD_CS47L24
 	select SND_SOC_CS53L30 if I2C
@@ -71,7 +72,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_DA732X if I2C
 	select SND_SOC_DA9055 if I2C
 	select SND_SOC_DIO2125
-	select SND_SOC_DMIC
+	select SND_SOC_DMIC if GPIOLIB
 	select SND_SOC_ES8316 if I2C
 	select SND_SOC_ES8328_SPI if SPI_MASTER
 	select SND_SOC_ES8328_I2C if I2C
@@ -114,6 +115,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_PCM5102A
 	select SND_SOC_PCM512x_I2C if I2C
 	select SND_SOC_PCM512x_SPI if SPI_MASTER
+	select SND_SOC_RT274 if I2C
 	select SND_SOC_RT286 if I2C
 	select SND_SOC_RT298 if I2C
 	select SND_SOC_RT5514 if I2C
@@ -486,6 +488,11 @@ config SND_SOC_CS42XX8_I2C
 	select SND_SOC_CS42XX8
 	select REGMAP_I2C
 
+# Cirrus Logic CS43130 HiFi DAC
+config SND_SOC_CS43130
+        tristate "Cirrus Logic CS43130 CODEC"
+        depends on I2C
+
 # Cirrus Logic CS4349 HiFi DAC
 config SND_SOC_CS4349
 	tristate "Cirrus Logic CS4349 CODEC"
@@ -716,11 +723,17 @@ config SND_SOC_RL6231
 
 config SND_SOC_RL6347A
 	tristate
+	default y if SND_SOC_RT274=y
 	default y if SND_SOC_RT286=y
 	default y if SND_SOC_RT298=y
+	default m if SND_SOC_RT274=m
 	default m if SND_SOC_RT286=m
 	default m if SND_SOC_RT298=m
 
+config SND_SOC_RT274
+	tristate
+	depends on I2C
+
 config SND_SOC_RT286
 	tristate
 	depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 1755a54e3dc9..696e371f0e0c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -53,6 +53,7 @@ snd-soc-cs4271-i2c-objs := cs4271-i2c.o
 snd-soc-cs4271-spi-objs := cs4271-spi.o
 snd-soc-cs42xx8-objs := cs42xx8.o
 snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
+snd-soc-cs43130-objs := cs43130.o
 snd-soc-cs4349-objs := cs4349.o
 snd-soc-cs47l24-objs := cs47l24.o
 snd-soc-cs53l30-objs := cs53l30.o
@@ -113,6 +114,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-rt274-objs := rt274.o
 snd-soc-rt286-objs := rt286.o
 snd-soc-rt298-objs := rt298.o
 snd-soc-rt5514-objs := rt5514.o
@@ -290,6 +292,7 @@ obj-$(CONFIG_SND_SOC_CS4271_I2C)	+= snd-soc-cs4271-i2c.o
 obj-$(CONFIG_SND_SOC_CS4271_SPI)	+= snd-soc-cs4271-spi.o
 obj-$(CONFIG_SND_SOC_CS42XX8)	+= snd-soc-cs42xx8.o
 obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
+obj-$(CONFIG_SND_SOC_CS43130)   += snd-soc-cs43130.o
 obj-$(CONFIG_SND_SOC_CS4349)	+= snd-soc-cs4349.o
 obj-$(CONFIG_SND_SOC_CS47L24)	+= snd-soc-cs47l24.o
 obj-$(CONFIG_SND_SOC_CS53L30)	+= snd-soc-cs53l30.o
@@ -320,6 +323,7 @@ obj-$(CONFIG_SND_SOC_MAX98088)	+= snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_MAX98090)	+= snd-soc-max98090.o
 obj-$(CONFIG_SND_SOC_MAX98095)	+= snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX98357A)	+= snd-soc-max98357a.o
+obj-$(CONFIG_SND_SOC_MAX98371)	+= snd-soc-max98371.o
 obj-$(CONFIG_SND_SOC_MAX9867)	+= snd-soc-max9867.o
 obj-$(CONFIG_SND_SOC_MAX98925)	+= snd-soc-max98925.o
 obj-$(CONFIG_SND_SOC_MAX98926)	+= snd-soc-max98926.o
@@ -349,6 +353,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_RT274)	+= snd-soc-rt274.o
 obj-$(CONFIG_SND_SOC_RT286)	+= snd-soc-rt286.o
 obj-$(CONFIG_SND_SOC_RT298)	+= snd-soc-rt298.o
 obj-$(CONFIG_SND_SOC_RT5514)	+= snd-soc-rt5514.o
@@ -372,6 +377,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_SN95031)	+=snd-soc-sn95031.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_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
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 312b2a11abb6..006627b8c3a8 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -2523,7 +2523,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
 	return status;
 }
 
-static struct snd_soc_codec_driver ab8500_codec_driver = {
+static const struct snd_soc_codec_driver ab8500_codec_driver = {
 	.probe =		ab8500_codec_probe,
 	.component_driver = {
 		.controls =		ab8500_ctrls,
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index f7f04c6be01e..440b4ce54376 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -112,7 +112,7 @@ static int ac97_soc_resume(struct snd_soc_codec *codec)
 #define ac97_soc_resume NULL
 #endif
 
-static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ac97 = {
 	.probe = 	ac97_soc_probe,
 	.suspend =	ac97_soc_suspend,
 	.resume =	ac97_soc_resume,
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index a478239aadac..d0361caad09e 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -321,7 +321,7 @@ static int ad1836_remove(struct snd_soc_codec *codec)
 		AD1836_ADC_SERFMT_MASK, 0);
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
 	.probe = ad1836_probe,
 	.remove = ad1836_remove,
 	.suspend = ad1836_suspend,
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index d643557d89a7..d10988eec0c1 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -408,7 +408,7 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
+static const struct snd_soc_codec_driver soc_codec_dev_ad193x = {
 	.probe = ad193x_codec_probe,
 	.component_driver = {
 		.controls		= ad193x_snd_controls,
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index b7c1b9f4bf5f..ce89bfb42094 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -295,7 +295,7 @@ static int ad1980_soc_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
 	.probe = 	ad1980_soc_probe,
 	.remove = 	ad1980_soc_remove,
 
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index 3e358a49442d..d8d86a0fea60 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -54,7 +54,7 @@ static struct snd_soc_dai_driver ad73311_dai = {
 		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_ad73311 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ad73311 = {
 	.component_driver = {
 		.dapm_widgets		= ad73311_dapm_widgets,
 		.num_dapm_widgets	= ARRAY_SIZE(ad73311_dapm_widgets),
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 8fa9045571ff..a865945d776a 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -1458,7 +1458,7 @@ static const struct regmap_config adau1373_regmap_config = {
 	.num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults),
 };
 
-static struct snd_soc_codec_driver adau1373_codec_driver = {
+static const struct snd_soc_codec_driver adau1373_codec_driver = {
 	.probe =	adau1373_probe,
 	.resume =	adau1373_resume,
 	.set_bias_level = adau1373_set_bias_level,
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 3bad1bc8c00a..805afac8146b 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -757,7 +757,7 @@ static int adau1701_resume(struct snd_soc_codec *codec)
 #define adau1701_suspend 	NULL
 #endif /* CONFIG_PM */
 
-static struct snd_soc_codec_driver adau1701_codec_drv = {
+static const struct snd_soc_codec_driver adau1701_codec_drv = {
 	.probe			= adau1701_probe,
 	.remove			= adau1701_remove,
 	.resume			= adau1701_resume,
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
index b319db6a69f8..e384f212beb2 100644
--- a/sound/soc/codecs/adau1977.c
+++ b/sound/soc/codecs/adau1977.c
@@ -388,8 +388,7 @@ static int adau1977_power_disable(struct adau1977 *adau1977)
 
 	regcache_mark_dirty(adau1977->regmap);
 
-	if (adau1977->reset_gpio)
-		gpiod_set_value_cansleep(adau1977->reset_gpio, 0);
+	gpiod_set_value_cansleep(adau1977->reset_gpio, 0);
 
 	regcache_cache_only(adau1977->regmap, true);
 
@@ -420,8 +419,7 @@ static int adau1977_power_enable(struct adau1977 *adau1977)
 			goto err_disable_avdd;
 	}
 
-	if (adau1977->reset_gpio)
-		gpiod_set_value_cansleep(adau1977->reset_gpio, 1);
+	gpiod_set_value_cansleep(adau1977->reset_gpio, 1);
 
 	regcache_cache_only(adau1977->regmap, false);
 
@@ -867,7 +865,7 @@ static int adau1977_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver adau1977_codec_driver = {
+static const struct snd_soc_codec_driver adau1977_codec_driver = {
 	.probe = adau1977_codec_probe,
 	.set_bias_level = adau1977_set_bias_level,
 	.set_sysclk = adau1977_set_sysclk,
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index 6e793ebb5883..da7ca81f47cf 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -825,7 +825,7 @@ static int adav80x_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver adav80x_codec_driver = {
+static const struct snd_soc_codec_driver adav80x_codec_driver = {
 	.probe = adav80x_probe,
 	.resume = adav80x_resume,
 	.set_bias_level = adav80x_set_bias_level,
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
index 90c756d183b4..b7f0057c0239 100644
--- a/sound/soc/codecs/ads117x.c
+++ b/sound/soc/codecs/ads117x.c
@@ -58,7 +58,7 @@ static struct snd_soc_dai_driver ads117x_dai = {
 		.formats = ADS117X_FORMATS,},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_ads117x = {
+static const struct snd_soc_codec_driver soc_codec_dev_ads117x = {
 	.component_driver = {
 		.dapm_widgets		= ads117x_dapm_widgets,
 		.num_dapm_widgets	= ARRAY_SIZE(ads117x_dapm_widgets),
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 1a9d233c94d0..dbb184118f2e 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -242,7 +242,7 @@ static int ak4104_soc_resume(struct snd_soc_codec *codec)
 #define ak4104_soc_resume	NULL
 #endif /* CONFIG_PM */
 
-static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
+static const struct snd_soc_codec_driver soc_codec_device_ak4104 = {
 	.probe = ak4104_probe,
 	.remove = ak4104_remove,
 	.suspend = ak4104_soc_suspend,
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 66cfffde9a12..e3c157dc88db 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -390,7 +390,7 @@ static const struct regmap_config ak4535_regmap = {
 	.num_reg_defaults = ARRAY_SIZE(ak4535_reg_defaults),
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
 	.resume =	ak4535_resume,
 	.set_bias_level = ak4535_set_bias_level,
 	.suspend_bias_off = true,
diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c
index b92c548b9d29..0bb4fe5c122a 100644
--- a/sound/soc/codecs/ak4554.c
+++ b/sound/soc/codecs/ak4554.c
@@ -64,7 +64,7 @@ static struct snd_soc_dai_driver ak4554_dai = {
 	.symmetric_rates = 1,
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_ak4554 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ak4554 = {
 	.component_driver = {
 		.dapm_widgets		= ak4554_dapm_widgets,
 		.num_dapm_widgets	= ARRAY_SIZE(ak4554_dapm_widgets),
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 690edebf029e..b95bb8b52e51 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -522,7 +522,7 @@ static int ak4613_resume(struct snd_soc_codec *codec)
 	return regcache_sync(regmap);
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
 	.suspend		= ak4613_suspend,
 	.resume			= ak4613_resume,
 	.set_bias_level		= ak4613_set_bias_level,
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index ebdaf56c1d61..60142ff32d4f 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -524,7 +524,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = {
 },
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
 	.component_driver = {
 		.controls		= ak4641_snd_controls,
 		.num_controls		= ARRAY_SIZE(ak4641_snd_controls),
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 66de8a2013a6..29530c567bd9 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -550,7 +550,7 @@ static int ak4642_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
 	.probe			= ak4642_probe,
 	.suspend		= ak4642_suspend,
 	.resume			= ak4642_resume,
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index 6088afaabf62..dcfdff56fc5a 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -610,7 +610,7 @@ static struct snd_soc_dai_driver ak4671_dai = {
 	.ops = &ak4671_dai_ops,
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
 	.set_bias_level = ak4671_set_bias_level,
 	.component_driver = {
 		.controls		= ak4671_snd_controls,
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
index 0ef2df223336..d0e16c03815c 100644
--- a/sound/soc/codecs/ak5386.c
+++ b/sound/soc/codecs/ak5386.c
@@ -69,7 +69,7 @@ static int ak5386_soc_resume(struct snd_soc_codec *codec)
 #define ak5386_soc_resume	NULL
 #endif /* CONFIG_PM */
 
-static struct snd_soc_codec_driver soc_codec_ak5386 = {
+static const struct snd_soc_codec_driver soc_codec_ak5386 = {
 	.probe = ak5386_soc_probe,
 	.remove = ak5386_soc_remove,
 	.suspend = ak5386_soc_suspend,
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index d2e3a3ef7499..1db965a93632 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -951,7 +951,7 @@ static int alc5623_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_device_alc5623 = {
+static const struct snd_soc_codec_driver soc_codec_device_alc5623 = {
 	.probe = alc5623_probe,
 	.suspend = alc5623_suspend,
 	.resume = alc5623_resume,
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 0a734d910850..a1149f6a8450 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -710,7 +710,7 @@ const struct soc_enum arizona_anc_input_src[] = {
 			ARRAY_SIZE(arizona_anc_input_src_text),
 			arizona_anc_input_src_text),
 	SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
-			ARIZONA_FCL_MIC_MODE_SEL,
+			ARIZONA_FCL_MIC_MODE_SEL_SHIFT,
 			ARRAY_SIZE(arizona_anc_channel_src_text),
 			arizona_anc_channel_src_text),
 	SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
@@ -718,7 +718,7 @@ const struct soc_enum arizona_anc_input_src[] = {
 			ARRAY_SIZE(arizona_anc_input_src_text),
 			arizona_anc_input_src_text),
 	SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
-			ARIZONA_FCR_MIC_MODE_SEL,
+			ARIZONA_FCR_MIC_MODE_SEL_SHIFT,
 			ARRAY_SIZE(arizona_anc_channel_src_text),
 			arizona_anc_channel_src_text),
 };
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
index 8014e697d540..806191addb44 100644
--- a/sound/soc/codecs/bt-sco.c
+++ b/sound/soc/codecs/bt-sco.c
@@ -62,7 +62,7 @@ static struct snd_soc_dai_driver bt_sco_dai[] = {
 	}
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
+static const struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
 	.component_driver = {
 		.dapm_widgets		= bt_sco_widgets,
 		.num_dapm_widgets	= ARRAY_SIZE(bt_sco_widgets),
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index 7a2d9a2ee427..6ed2cc374768 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -128,7 +128,7 @@ static struct regmap *cq93vc_get_regmap(struct device *dev)
 	return davinci_vc->regmap;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
+static const struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
 	.set_bias_level = cq93vc_set_bias_level,
 	.get_regmap = cq93vc_get_regmap,
 	.component_driver = {
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c
index 6df29fa30fb9..854cf8f27605 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -831,7 +831,7 @@ static int cs35l33_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs35l33 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs35l33 = {
 	.probe = cs35l33_probe,
 
 	.set_bias_level = cs35l33_set_bias_level,
@@ -869,8 +869,7 @@ static int __maybe_unused cs35l33_runtime_resume(struct device *dev)
 
 	dev_dbg(dev, "%s\n", __func__);
 
-	if (cs35l33->reset_gpio)
-		gpiod_set_value_cansleep(cs35l33->reset_gpio, 0);
+	gpiod_set_value_cansleep(cs35l33->reset_gpio, 0);
 
 	ret = regulator_bulk_enable(cs35l33->num_core_supplies,
 		cs35l33->core_supplies);
@@ -881,8 +880,7 @@ static int __maybe_unused cs35l33_runtime_resume(struct device *dev)
 
 	regcache_cache_only(cs35l33->regmap, false);
 
-	if (cs35l33->reset_gpio)
-		gpiod_set_value_cansleep(cs35l33->reset_gpio, 1);
+	gpiod_set_value_cansleep(cs35l33->reset_gpio, 1);
 
 	msleep(CS35L33_BOOT_DELAY);
 
@@ -1191,8 +1189,7 @@ static int cs35l33_i2c_probe(struct i2c_client *i2c_client,
 		return ret;
 	}
 
-	if (cs35l33->reset_gpio)
-		gpiod_set_value_cansleep(cs35l33->reset_gpio, 1);
+	gpiod_set_value_cansleep(cs35l33->reset_gpio, 1);
 
 	msleep(CS35L33_BOOT_DELAY);
 	regcache_cache_only(cs35l33->regmap, false);
@@ -1262,8 +1259,7 @@ static int cs35l33_i2c_remove(struct i2c_client *client)
 
 	snd_soc_unregister_codec(&client->dev);
 
-	if (cs35l33->reset_gpio)
-		gpiod_set_value_cansleep(cs35l33->reset_gpio, 0);
+	gpiod_set_value_cansleep(cs35l33->reset_gpio, 0);
 
 	pm_runtime_disable(&client->dev);
 	regulator_bulk_disable(cs35l33->num_core_supplies,
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index 0a747c66cc6c..1e05026bedca 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -779,7 +779,7 @@ static int cs35l34_probe(struct snd_soc_codec *codec)
 }
 
 
-static struct snd_soc_codec_driver soc_codec_dev_cs35l34 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs35l34 = {
 	.probe = cs35l34_probe,
 
 	.component_driver = {
@@ -1138,8 +1138,7 @@ static int cs35l34_i2c_remove(struct i2c_client *client)
 
 	snd_soc_unregister_codec(&client->dev);
 
-	if (cs35l34->reset_gpio)
-		gpiod_set_value_cansleep(cs35l34->reset_gpio, 0);
+	gpiod_set_value_cansleep(cs35l34->reset_gpio, 0);
 
 	pm_runtime_disable(&client->dev);
 	regulator_bulk_disable(cs35l34->num_core_supplies,
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index f1ee184ecab2..129978d1243e 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -1079,7 +1079,7 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs35l35 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs35l35 = {
 	.probe = cs35l35_codec_probe,
 	.set_sysclk = cs35l35_codec_set_sysclk,
 	.component_driver = {
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index d8824773dc29..49a80627af12 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -639,7 +639,7 @@ static int cs4271_codec_remove(struct snd_soc_codec *codec)
 	return 0;
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
 	.probe			= cs4271_codec_probe,
 	.remove			= cs4271_codec_remove,
 	.suspend		= cs4271_soc_suspend,
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 55e4520cdcaf..a2324a0e72ee 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -911,7 +911,7 @@ static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute)
 			SNDRV_PCM_FMTBIT_S32_LE)
 
 
-static struct snd_soc_dai_ops cs42l42_ops = {
+static const struct snd_soc_dai_ops cs42l42_ops = {
 	.hw_params	= cs42l42_pcm_hw_params,
 	.set_fmt	= cs42l42_set_dai_fmt,
 	.set_sysclk	= cs42l42_set_sysclk,
@@ -1898,8 +1898,7 @@ static int cs42l42_i2c_remove(struct i2c_client *i2c_client)
 	snd_soc_unregister_codec(&i2c_client->dev);
 
 	/* Hold down reset */
-	if (cs42l42->reset_gpio)
-		gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+	gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
 
 	return 0;
 }
@@ -1913,8 +1912,7 @@ static int cs42l42_runtime_suspend(struct device *dev)
 	regcache_mark_dirty(cs42l42->regmap);
 
 	/* Hold down reset */
-	if (cs42l42->reset_gpio)
-		gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+	gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
 
 	/* remove power */
 	regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
@@ -1937,8 +1935,7 @@ static int cs42l42_runtime_resume(struct device *dev)
 		return ret;
 	}
 
-	if (cs42l42->reset_gpio)
-		gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+	gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
 
 	regcache_cache_only(cs42l42->regmap, false);
 	regcache_sync(cs42l42->regmap);
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 96cfe38943cd..f8072f1897d4 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -504,7 +504,7 @@ static int cs42l51_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
+static const struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
 	.probe = cs42l51_codec_probe,
 
 	.component_driver = {
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
new file mode 100644
index 000000000000..220e30199c5b
--- /dev/null
+++ b/sound/soc/codecs/cs43130.c
@@ -0,0 +1,2690 @@
+/*
+ * cs43130.c  --  CS43130 ALSA Soc Audio driver
+ *
+ * Copyright 2017 Cirrus Logic, Inc.
+ *
+ * Authors: Li Xu <li.xu@cirrus.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/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_irq.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <sound/jack.h>
+
+#include "cs43130.h"
+
+static const struct reg_default cs43130_reg_defaults[] = {
+	{CS43130_SYS_CLK_CTL_1, 0x06},
+	{CS43130_SP_SRATE, 0x01},
+	{CS43130_SP_BITSIZE, 0x05},
+	{CS43130_PAD_INT_CFG, 0x03},
+	{CS43130_PWDN_CTL, 0xFE},
+	{CS43130_CRYSTAL_SET, 0x04},
+	{CS43130_PLL_SET_1, 0x00},
+	{CS43130_PLL_SET_2, 0x00},
+	{CS43130_PLL_SET_3, 0x00},
+	{CS43130_PLL_SET_4, 0x00},
+	{CS43130_PLL_SET_5, 0x40},
+	{CS43130_PLL_SET_6, 0x10},
+	{CS43130_PLL_SET_7, 0x80},
+	{CS43130_PLL_SET_8, 0x03},
+	{CS43130_PLL_SET_9, 0x02},
+	{CS43130_PLL_SET_10, 0x02},
+	{CS43130_CLKOUT_CTL, 0x00},
+	{CS43130_ASP_NUM_1, 0x01},
+	{CS43130_ASP_NUM_2, 0x00},
+	{CS43130_ASP_DEN_1, 0x08},
+	{CS43130_ASP_DEN_2, 0x00},
+	{CS43130_ASP_LRCK_HI_TIME_1, 0x1F},
+	{CS43130_ASP_LRCK_HI_TIME_2, 0x00},
+	{CS43130_ASP_LRCK_PERIOD_1, 0x3F},
+	{CS43130_ASP_LRCK_PERIOD_2, 0x00},
+	{CS43130_ASP_CLOCK_CONF, 0x0C},
+	{CS43130_ASP_FRAME_CONF, 0x0A},
+	{CS43130_XSP_NUM_1, 0x01},
+	{CS43130_XSP_NUM_2, 0x00},
+	{CS43130_XSP_DEN_1, 0x02},
+	{CS43130_XSP_DEN_2, 0x00},
+	{CS43130_XSP_LRCK_HI_TIME_1, 0x1F},
+	{CS43130_XSP_LRCK_HI_TIME_2, 0x00},
+	{CS43130_XSP_LRCK_PERIOD_1, 0x3F},
+	{CS43130_XSP_LRCK_PERIOD_2, 0x00},
+	{CS43130_XSP_CLOCK_CONF, 0x0C},
+	{CS43130_XSP_FRAME_CONF, 0x0A},
+	{CS43130_ASP_CH_1_LOC, 0x00},
+	{CS43130_ASP_CH_2_LOC, 0x00},
+	{CS43130_ASP_CH_1_SZ_EN, 0x06},
+	{CS43130_ASP_CH_2_SZ_EN, 0x0E},
+	{CS43130_XSP_CH_1_LOC, 0x00},
+	{CS43130_XSP_CH_2_LOC, 0x00},
+	{CS43130_XSP_CH_1_SZ_EN, 0x06},
+	{CS43130_XSP_CH_2_SZ_EN, 0x0E},
+	{CS43130_DSD_VOL_B, 0x78},
+	{CS43130_DSD_VOL_A, 0x78},
+	{CS43130_DSD_PATH_CTL_1, 0xA8},
+	{CS43130_DSD_INT_CFG, 0x00},
+	{CS43130_DSD_PATH_CTL_2, 0x02},
+	{CS43130_DSD_PCM_MIX_CTL, 0x00},
+	{CS43130_DSD_PATH_CTL_3, 0x40},
+	{CS43130_HP_OUT_CTL_1, 0x30},
+	{CS43130_PCM_FILT_OPT, 0x02},
+	{CS43130_PCM_VOL_B, 0x78},
+	{CS43130_PCM_VOL_A, 0x78},
+	{CS43130_PCM_PATH_CTL_1, 0xA8},
+	{CS43130_PCM_PATH_CTL_2, 0x00},
+	{CS43130_CLASS_H_CTL, 0x1E},
+	{CS43130_HP_DETECT, 0x04},
+	{CS43130_HP_LOAD_1, 0x00},
+	{CS43130_HP_MEAS_LOAD_1, 0x00},
+	{CS43130_HP_MEAS_LOAD_2, 0x00},
+	{CS43130_INT_MASK_1, 0xFF},
+	{CS43130_INT_MASK_2, 0xFF},
+	{CS43130_INT_MASK_3, 0xFF},
+	{CS43130_INT_MASK_4, 0xFF},
+	{CS43130_INT_MASK_5, 0xFF},
+};
+
+static bool cs43130_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
+	case CS43130_HP_DC_STAT_1 ... CS43130_HP_DC_STAT_2:
+	case CS43130_HP_AC_STAT_1 ... CS43130_HP_AC_STAT_2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs43130_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS43130_DEVID_AB ... CS43130_SYS_CLK_CTL_1:
+	case CS43130_SP_SRATE ... CS43130_PAD_INT_CFG:
+	case CS43130_PWDN_CTL:
+	case CS43130_CRYSTAL_SET:
+	case CS43130_PLL_SET_1 ... CS43130_PLL_SET_5:
+	case CS43130_PLL_SET_6:
+	case CS43130_PLL_SET_7:
+	case CS43130_PLL_SET_8:
+	case CS43130_PLL_SET_9:
+	case CS43130_PLL_SET_10:
+	case CS43130_CLKOUT_CTL:
+	case CS43130_ASP_NUM_1 ... CS43130_ASP_FRAME_CONF:
+	case CS43130_XSP_NUM_1 ... CS43130_XSP_FRAME_CONF:
+	case CS43130_ASP_CH_1_LOC:
+	case CS43130_ASP_CH_2_LOC:
+	case CS43130_ASP_CH_1_SZ_EN:
+	case CS43130_ASP_CH_2_SZ_EN:
+	case CS43130_XSP_CH_1_LOC:
+	case CS43130_XSP_CH_2_LOC:
+	case CS43130_XSP_CH_1_SZ_EN:
+	case CS43130_XSP_CH_2_SZ_EN:
+	case CS43130_DSD_VOL_B ... CS43130_DSD_PATH_CTL_3:
+	case CS43130_HP_OUT_CTL_1:
+	case CS43130_PCM_FILT_OPT ... CS43130_PCM_PATH_CTL_2:
+	case CS43130_CLASS_H_CTL:
+	case CS43130_HP_DETECT:
+	case CS43130_HP_STATUS:
+	case CS43130_HP_LOAD_1:
+	case CS43130_HP_MEAS_LOAD_1:
+	case CS43130_HP_MEAS_LOAD_2:
+	case CS43130_HP_DC_STAT_1:
+	case CS43130_HP_DC_STAT_2:
+	case CS43130_HP_AC_STAT_1:
+	case CS43130_HP_AC_STAT_2:
+	case CS43130_HP_LOAD_STAT:
+	case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
+	case CS43130_INT_MASK_1 ... CS43130_INT_MASK_5:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs43130_precious_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
+		return true;
+	default:
+		return false;
+	}
+}
+
+struct cs43130_pll_params {
+	unsigned int pll_in;
+	u8 sclk_prediv;
+	u8 pll_div_int;
+	u32 pll_div_frac;
+	u8 pll_mode;
+	u8 pll_divout;
+	unsigned int pll_out;
+	u8 pll_cal_ratio;
+};
+
+static const struct cs43130_pll_params pll_ratio_table[] = {
+	{9600000, 0x02, 0x49, 0x800000, 0x00, 0x08, 22579200, 151},
+	{9600000, 0x02, 0x50, 0x000000, 0x00, 0x08, 24576000, 164},
+
+	{11289600, 0x02, 0X40, 0, 0x01, 0x08, 22579200, 128},
+	{11289600, 0x02, 0x44, 0x06F700, 0x0, 0x08, 24576000, 139},
+
+	{12000000, 0x02, 0x49, 0x800000, 0x00, 0x0A, 22579200, 120},
+	{12000000, 0x02, 0x40, 0x000000, 0x00, 0x08, 24576000, 131},
+
+	{12288000, 0x02, 0x49, 0x800000, 0x01, 0x0A, 22579200, 118},
+	{12288000, 0x02, 0x40, 0x000000, 0x01, 0x08, 24576000, 128},
+
+	{13000000, 0x02, 0x45, 0x797680, 0x01, 0x0A, 22579200, 111},
+	{13000000, 0x02, 0x3C, 0x7EA940, 0x01, 0x08, 24576000, 121},
+
+	{19200000, 0x03, 0x49, 0x800000, 0x00, 0x08, 22579200, 151},
+	{19200000, 0x03, 0x50, 0x000000, 0x00, 0x08, 24576000, 164},
+
+	{22579200, 0, 0, 0, 0, 0, 22579200, 0},
+	{22579200, 0x03, 0x44, 0x06F700, 0x00, 0x08, 24576000, 139},
+
+	{24000000, 0x03, 0x49, 0x800000, 0x00, 0x0A, 22579200, 120},
+	{24000000, 0x03, 0x40, 0x000000, 0x00, 0x08, 24576000, 131},
+
+	{24576000, 0x03, 0x49, 0x800000, 0x01, 0x0A, 22579200, 118},
+	{24576000, 0, 0, 0, 0, 0, 24576000, 0},
+
+	{26000000, 0x03, 0x45, 0x797680, 0x01, 0x0A, 22579200, 111},
+	{26000000, 0x03, 0x3C, 0x7EA940, 0x01, 0x08, 24576000, 121},
+};
+
+static const struct cs43130_pll_params *cs43130_get_pll_table(
+		unsigned int freq_in, unsigned int freq_out)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
+		if (pll_ratio_table[i].pll_in == freq_in &&
+		    pll_ratio_table[i].pll_out == freq_out)
+			return &pll_ratio_table[i];
+	}
+
+	return NULL;
+}
+
+static int cs43130_pll_config(struct snd_soc_codec *codec)
+{
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	const struct cs43130_pll_params *pll_entry;
+
+	dev_dbg(codec->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n",
+		cs43130->mclk, cs43130->mclk_int);
+
+	pll_entry = cs43130_get_pll_table(cs43130->mclk, cs43130->mclk_int);
+	if (!pll_entry)
+		return -EINVAL;
+
+	if (pll_entry->pll_cal_ratio == 0) {
+		regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_1,
+				   CS43130_PLL_START_MASK, 0);
+
+		cs43130->pll_bypass = true;
+		return 0;
+	}
+
+	cs43130->pll_bypass = false;
+
+	regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_2,
+			   CS43130_PLL_DIV_DATA_MASK,
+			   pll_entry->pll_div_frac >>
+			   CS43130_PLL_DIV_FRAC_0_DATA_SHIFT);
+	regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_3,
+			   CS43130_PLL_DIV_DATA_MASK,
+			   pll_entry->pll_div_frac >>
+			   CS43130_PLL_DIV_FRAC_1_DATA_SHIFT);
+	regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_4,
+			   CS43130_PLL_DIV_DATA_MASK,
+			   pll_entry->pll_div_frac >>
+			   CS43130_PLL_DIV_FRAC_2_DATA_SHIFT);
+	regmap_write(cs43130->regmap, CS43130_PLL_SET_5,
+		     pll_entry->pll_div_int);
+	regmap_write(cs43130->regmap, CS43130_PLL_SET_6, pll_entry->pll_divout);
+	regmap_write(cs43130->regmap, CS43130_PLL_SET_7,
+		     pll_entry->pll_cal_ratio);
+	regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_8,
+			   CS43130_PLL_MODE_MASK,
+			   pll_entry->pll_mode << CS43130_PLL_MODE_SHIFT);
+	regmap_write(cs43130->regmap, CS43130_PLL_SET_9,
+		     pll_entry->sclk_prediv);
+	regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_1,
+			   CS43130_PLL_START_MASK, 1);
+
+	return 0;
+}
+
+static int cs43130_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
+			   unsigned int freq_in, unsigned int freq_out)
+{
+	int ret = 0;
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+	switch (freq_in) {
+	case 9600000:
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 13000000:
+	case 19200000:
+	case 22579200:
+	case 24000000:
+	case 24576000:
+	case 26000000:
+		cs43130->mclk = freq_in;
+		break;
+	default:
+		dev_err(codec->dev,
+			"unsupported pll input reference clock:%d\n", freq_in);
+		return -EINVAL;
+	}
+
+	switch (freq_out) {
+	case 22579200:
+		cs43130->mclk_int = freq_out;
+		break;
+	case 24576000:
+		cs43130->mclk_int = freq_out;
+		break;
+	default:
+		dev_err(codec->dev,
+			"unsupported pll output ref clock: %u\n", freq_out);
+		return -EINVAL;
+	}
+
+	ret = cs43130_pll_config(codec);
+	dev_dbg(codec->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass);
+	return ret;
+}
+
+static int cs43130_change_clksrc(struct snd_soc_codec *codec,
+				 enum cs43130_mclk_src_sel src)
+{
+	int ret;
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	int mclk_int_decoded;
+
+	if (src == cs43130->mclk_int_src) {
+		/* clk source has not changed */
+		return 0;
+	}
+
+	switch (cs43130->mclk_int) {
+	case CS43130_MCLK_22M:
+		mclk_int_decoded = CS43130_MCLK_22P5;
+		break;
+	case CS43130_MCLK_24M:
+		mclk_int_decoded = CS43130_MCLK_24P5;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int);
+		return -EINVAL;
+	}
+
+	switch (src) {
+	case CS43130_MCLK_SRC_EXT:
+		cs43130->pll_bypass = true;
+		cs43130->mclk_int_src = CS43130_MCLK_SRC_EXT;
+		if (cs43130->xtal_ibias == CS43130_XTAL_UNUSED) {
+			regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+					   CS43130_PDN_XTAL_MASK,
+					   1 << CS43130_PDN_XTAL_SHIFT);
+		} else {
+			reinit_completion(&cs43130->xtal_rdy);
+			regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+					   CS43130_XTAL_RDY_INT_MASK, 0);
+			regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+					   CS43130_PDN_XTAL_MASK, 0);
+			ret = wait_for_completion_timeout(&cs43130->xtal_rdy,
+							  msecs_to_jiffies(100));
+			regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+					   CS43130_XTAL_RDY_INT_MASK,
+					   1 << CS43130_XTAL_RDY_INT_SHIFT);
+			if (ret == 0) {
+				dev_err(codec->dev, "Timeout waiting for XTAL_READY interrupt\n");
+				return -ETIMEDOUT;
+			}
+		}
+
+		regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+				   CS43130_MCLK_SRC_SEL_MASK,
+				   src << CS43130_MCLK_SRC_SEL_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+				   CS43130_MCLK_INT_MASK,
+				   mclk_int_decoded << CS43130_MCLK_INT_SHIFT);
+		usleep_range(150, 200);
+
+		regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+				   CS43130_PDN_PLL_MASK,
+				   1 << CS43130_PDN_PLL_SHIFT);
+		break;
+	case CS43130_MCLK_SRC_PLL:
+		cs43130->pll_bypass = false;
+		cs43130->mclk_int_src = CS43130_MCLK_SRC_PLL;
+		if (cs43130->xtal_ibias == CS43130_XTAL_UNUSED) {
+			regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+					   CS43130_PDN_XTAL_MASK,
+					   1 << CS43130_PDN_XTAL_SHIFT);
+		} else {
+			reinit_completion(&cs43130->xtal_rdy);
+			regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+					   CS43130_XTAL_RDY_INT_MASK, 0);
+			regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+					   CS43130_PDN_XTAL_MASK, 0);
+			ret = wait_for_completion_timeout(&cs43130->xtal_rdy,
+							  msecs_to_jiffies(100));
+			regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+					   CS43130_XTAL_RDY_INT_MASK,
+					   1 << CS43130_XTAL_RDY_INT_SHIFT);
+			if (ret == 0) {
+				dev_err(codec->dev, "Timeout waiting for XTAL_READY interrupt\n");
+				return -ETIMEDOUT;
+			}
+		}
+
+		reinit_completion(&cs43130->pll_rdy);
+		regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+				   CS43130_PLL_RDY_INT_MASK, 0);
+		regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+				   CS43130_PDN_PLL_MASK, 0);
+		ret = wait_for_completion_timeout(&cs43130->pll_rdy,
+						  msecs_to_jiffies(100));
+		regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+				   CS43130_PLL_RDY_INT_MASK,
+				   1 << CS43130_PLL_RDY_INT_SHIFT);
+		if (ret == 0) {
+			dev_err(codec->dev, "Timeout waiting for PLL_READY interrupt\n");
+			return -ETIMEDOUT;
+		}
+
+		regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+				   CS43130_MCLK_SRC_SEL_MASK,
+				   src << CS43130_MCLK_SRC_SEL_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+				   CS43130_MCLK_INT_MASK,
+				   mclk_int_decoded << CS43130_MCLK_INT_SHIFT);
+		usleep_range(150, 200);
+		break;
+	case CS43130_MCLK_SRC_RCO:
+		cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO;
+
+		regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+				   CS43130_MCLK_SRC_SEL_MASK,
+				   src << CS43130_MCLK_SRC_SEL_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+				   CS43130_MCLK_INT_MASK,
+				   CS43130_MCLK_22P5 << CS43130_MCLK_INT_SHIFT);
+		usleep_range(150, 200);
+
+		regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+				   CS43130_PDN_XTAL_MASK,
+				   1 << CS43130_PDN_XTAL_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+				   CS43130_PDN_PLL_MASK,
+				   1 << CS43130_PDN_PLL_SHIFT);
+		break;
+	default:
+		dev_err(codec->dev, "Invalid MCLK source value\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct cs43130_bitwidth_map cs43130_bitwidth_table[] = {
+	{8,	CS43130_SP_BIT_SIZE_8,	CS43130_CH_BIT_SIZE_8},
+	{16,	CS43130_SP_BIT_SIZE_16, CS43130_CH_BIT_SIZE_16},
+	{24,	CS43130_SP_BIT_SIZE_24, CS43130_CH_BIT_SIZE_24},
+	{32,	CS43130_SP_BIT_SIZE_32, CS43130_CH_BIT_SIZE_32},
+};
+
+static const struct cs43130_bitwidth_map *cs43130_get_bitwidth_table(
+				unsigned int bitwidth)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cs43130_bitwidth_table); i++) {
+		if (cs43130_bitwidth_table[i].bitwidth == bitwidth)
+			return &cs43130_bitwidth_table[i];
+	}
+
+	return NULL;
+}
+
+static int cs43130_set_bitwidth(int dai_id, unsigned int bitwidth_dai,
+			  struct regmap *regmap)
+{
+	const struct cs43130_bitwidth_map *bw_map;
+
+	bw_map = cs43130_get_bitwidth_table(bitwidth_dai);
+	if (!bw_map)
+		return -EINVAL;
+
+	switch (dai_id) {
+	case CS43130_ASP_PCM_DAI:
+	case CS43130_ASP_DOP_DAI:
+		regmap_update_bits(regmap, CS43130_ASP_CH_1_SZ_EN,
+				   CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
+		regmap_update_bits(regmap, CS43130_ASP_CH_2_SZ_EN,
+				   CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
+		regmap_update_bits(regmap, CS43130_SP_BITSIZE,
+				   CS43130_ASP_BITSIZE_MASK, bw_map->sp_bit);
+		break;
+	case CS43130_XSP_DOP_DAI:
+		regmap_update_bits(regmap, CS43130_XSP_CH_1_SZ_EN,
+				   CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
+		regmap_update_bits(regmap, CS43130_XSP_CH_2_SZ_EN,
+				   CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
+		regmap_update_bits(regmap, CS43130_SP_BITSIZE,
+				   CS43130_XSP_BITSIZE_MASK, bw_map->sp_bit <<
+				   CS43130_XSP_BITSIZE_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct cs43130_rate_map cs43130_rate_table[] = {
+	{32000,		CS43130_ASP_SPRATE_32K},
+	{44100,		CS43130_ASP_SPRATE_44_1K},
+	{48000,		CS43130_ASP_SPRATE_48K},
+	{88200,		CS43130_ASP_SPRATE_88_2K},
+	{96000,		CS43130_ASP_SPRATE_96K},
+	{176400,	CS43130_ASP_SPRATE_176_4K},
+	{192000,	CS43130_ASP_SPRATE_192K},
+	{352800,	CS43130_ASP_SPRATE_352_8K},
+	{384000,	CS43130_ASP_SPRATE_384K},
+};
+
+static const struct cs43130_rate_map *cs43130_get_rate_table(int fs)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cs43130_rate_table); i++) {
+		if (cs43130_rate_table[i].fs == fs)
+			return &cs43130_rate_table[i];
+	}
+
+	return NULL;
+}
+
+static const struct cs43130_clk_gen *cs43130_get_clk_gen(int mclk_int, int fs,
+		const struct cs43130_clk_gen *clk_gen_table, int len_clk_gen_table)
+{
+	int i;
+
+	for (i = 0; i < len_clk_gen_table; i++) {
+		if (clk_gen_table[i].mclk_int == mclk_int &&
+		    clk_gen_table[i].fs == fs)
+			return &clk_gen_table[i];
+	}
+
+	return NULL;
+}
+
+static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk,
+			      struct snd_pcm_hw_params *params,
+			      struct cs43130_private *cs43130)
+{
+	u16 frm_size;
+	u16 hi_size;
+	u8 frm_delay;
+	u8 frm_phase;
+	u8 frm_data;
+	u8 sclk_edge;
+	u8 lrck_edge;
+	u8 clk_data;
+	u8 loc_ch1;
+	u8 loc_ch2;
+	u8 dai_mode_val;
+	const struct cs43130_clk_gen *clk_gen;
+
+	switch (cs43130->dais[dai_id].dai_format) {
+	case SND_SOC_DAIFMT_I2S:
+		hi_size = bitwidth_sclk;
+		frm_delay = 2;
+		frm_phase = 0;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		hi_size = bitwidth_sclk;
+		frm_delay = 2;
+		frm_phase = 1;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		hi_size = 1;
+		frm_delay = 2;
+		frm_phase = 1;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		hi_size = 1;
+		frm_delay = 0;
+		frm_phase = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (cs43130->dais[dai_id].dai_mode) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		dai_mode_val = 0;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		dai_mode_val = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	frm_size = bitwidth_sclk * params_channels(params);
+	sclk_edge = 1;
+	lrck_edge = 0;
+	loc_ch1 = 0;
+	loc_ch2 = bitwidth_sclk * (params_channels(params) - 1);
+
+	frm_data = frm_delay & CS43130_SP_FSD_MASK;
+	frm_data |= (frm_phase << CS43130_SP_STP_SHIFT) & CS43130_SP_STP_MASK;
+
+	clk_data = lrck_edge & CS43130_SP_LCPOL_IN_MASK;
+	clk_data |= (lrck_edge << CS43130_SP_LCPOL_OUT_SHIFT) &
+		    CS43130_SP_LCPOL_OUT_MASK;
+	clk_data |= (sclk_edge << CS43130_SP_SCPOL_IN_SHIFT) &
+		    CS43130_SP_SCPOL_IN_MASK;
+	clk_data |= (sclk_edge << CS43130_SP_SCPOL_OUT_SHIFT) &
+		    CS43130_SP_SCPOL_OUT_MASK;
+	clk_data |= (dai_mode_val << CS43130_SP_MODE_SHIFT) &
+		    CS43130_SP_MODE_MASK;
+
+	switch (dai_id) {
+	case CS43130_ASP_PCM_DAI:
+	case CS43130_ASP_DOP_DAI:
+		regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_PERIOD_1,
+			CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
+			CS43130_SP_LCPR_LSB_DATA_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_PERIOD_2,
+			CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
+			CS43130_SP_LCPR_MSB_DATA_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_HI_TIME_1,
+			CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
+			CS43130_SP_LCHI_LSB_DATA_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_HI_TIME_2,
+			CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
+			CS43130_SP_LCHI_MSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_ASP_FRAME_CONF, frm_data);
+		regmap_write(cs43130->regmap, CS43130_ASP_CH_1_LOC, loc_ch1);
+		regmap_write(cs43130->regmap, CS43130_ASP_CH_2_LOC, loc_ch2);
+		regmap_update_bits(cs43130->regmap, CS43130_ASP_CH_1_SZ_EN,
+			CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_ASP_CH_2_SZ_EN,
+			CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_ASP_CLOCK_CONF, clk_data);
+		break;
+	case CS43130_XSP_DOP_DAI:
+		regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_PERIOD_1,
+			CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
+			CS43130_SP_LCPR_LSB_DATA_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_PERIOD_2,
+			CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
+			CS43130_SP_LCPR_MSB_DATA_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_HI_TIME_1,
+			CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
+			CS43130_SP_LCHI_LSB_DATA_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_HI_TIME_2,
+			CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
+			CS43130_SP_LCHI_MSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_XSP_FRAME_CONF, frm_data);
+		regmap_write(cs43130->regmap, CS43130_XSP_CH_1_LOC, loc_ch1);
+		regmap_write(cs43130->regmap, CS43130_XSP_CH_2_LOC, loc_ch2);
+		regmap_update_bits(cs43130->regmap, CS43130_XSP_CH_1_SZ_EN,
+			CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_XSP_CH_2_SZ_EN,
+			CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_XSP_CLOCK_CONF, clk_data);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (frm_size) {
+	case 16:
+		clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
+					      params_rate(params),
+					      cs43130_16_clk_gen,
+					      ARRAY_SIZE(cs43130_16_clk_gen));
+		break;
+	case 32:
+		clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
+					      params_rate(params),
+					      cs43130_32_clk_gen,
+					      ARRAY_SIZE(cs43130_32_clk_gen));
+		break;
+	case 48:
+		clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
+					      params_rate(params),
+					      cs43130_48_clk_gen,
+					      ARRAY_SIZE(cs43130_48_clk_gen));
+		break;
+	case 64:
+		clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
+					      params_rate(params),
+					      cs43130_64_clk_gen,
+					      ARRAY_SIZE(cs43130_64_clk_gen));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (!clk_gen)
+		return -EINVAL;
+
+	switch (dai_id) {
+	case CS43130_ASP_PCM_DAI:
+	case CS43130_ASP_DOP_DAI:
+		regmap_write(cs43130->regmap, CS43130_ASP_DEN_1,
+			     (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >>
+			     CS43130_SP_M_LSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_ASP_DEN_2,
+			     (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >>
+			     CS43130_SP_M_MSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_ASP_NUM_1,
+			     (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >>
+			     CS43130_SP_N_LSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_ASP_NUM_2,
+			     (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >>
+			     CS43130_SP_N_MSB_DATA_SHIFT);
+		break;
+	case CS43130_XSP_DOP_DAI:
+		regmap_write(cs43130->regmap, CS43130_XSP_DEN_1,
+			     (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >>
+			     CS43130_SP_M_LSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_XSP_DEN_2,
+			     (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >>
+			     CS43130_SP_M_MSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_XSP_NUM_1,
+			     (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >>
+			     CS43130_SP_N_LSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_XSP_NUM_2,
+			     (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >>
+			     CS43130_SP_N_MSB_DATA_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cs43130_pcm_dsd_mix(bool en, struct regmap *regmap)
+{
+	if (en) {
+		regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL,
+				   CS43130_MIX_PCM_PREP_MASK,
+				   1 << CS43130_MIX_PCM_PREP_SHIFT);
+		usleep_range(6000, 6050);
+		regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL,
+				   CS43130_MIX_PCM_DSD_MASK,
+				   1 << CS43130_MIX_PCM_DSD_SHIFT);
+	} else {
+		regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL,
+				   CS43130_MIX_PCM_DSD_MASK,
+				   0 << CS43130_MIX_PCM_DSD_SHIFT);
+		usleep_range(1600, 1650);
+		regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL,
+				   CS43130_MIX_PCM_PREP_MASK,
+				   0 << CS43130_MIX_PCM_PREP_SHIFT);
+	}
+
+	return 0;
+}
+
+static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	unsigned int required_clk;
+	u8 dsd_speed;
+
+	mutex_lock(&cs43130->clk_mutex);
+	if (!cs43130->clk_req) {
+		/* no DAI is currently using clk */
+		if (!(CS43130_MCLK_22M % params_rate(params)))
+			required_clk = CS43130_MCLK_22M;
+		else
+			required_clk = CS43130_MCLK_24M;
+
+		cs43130_set_pll(codec, 0, 0, cs43130->mclk, required_clk);
+		if (cs43130->pll_bypass)
+			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT);
+		else
+			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL);
+	}
+
+	cs43130->clk_req++;
+	if (cs43130->clk_req == 2)
+		cs43130_pcm_dsd_mix(true, cs43130->regmap);
+	mutex_unlock(&cs43130->clk_mutex);
+
+	switch (params_rate(params)) {
+	case 176400:
+		dsd_speed = 0;
+		break;
+	case 352800:
+		dsd_speed = 1;
+		break;
+	default:
+		dev_err(codec->dev, "Rate(%u) not supported\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	if (cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM)
+		regmap_update_bits(cs43130->regmap, CS43130_DSD_INT_CFG,
+				   CS43130_DSD_MASTER, CS43130_DSD_MASTER);
+	else
+		regmap_update_bits(cs43130->regmap, CS43130_DSD_INT_CFG,
+				   CS43130_DSD_MASTER, 0);
+
+	regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+			   CS43130_DSD_SPEED_MASK,
+			   dsd_speed << CS43130_DSD_SPEED_SHIFT);
+	regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+			   CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_DSD <<
+			   CS43130_DSD_SRC_SHIFT);
+
+	return 0;
+}
+
+static int cs43130_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	const struct cs43130_rate_map *rate_map;
+	unsigned int sclk = cs43130->dais[dai->id].sclk;
+	unsigned int bitwidth_sclk;
+	unsigned int bitwidth_dai = (unsigned int)(params_width(params));
+	unsigned int required_clk;
+	u8 dsd_speed;
+
+	mutex_lock(&cs43130->clk_mutex);
+	if (!cs43130->clk_req) {
+		/* no DAI is currently using clk */
+		if (!(CS43130_MCLK_22M % params_rate(params)))
+			required_clk = CS43130_MCLK_22M;
+		else
+			required_clk = CS43130_MCLK_24M;
+
+		cs43130_set_pll(codec, 0, 0, cs43130->mclk, required_clk);
+		if (cs43130->pll_bypass)
+			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT);
+		else
+			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL);
+	}
+
+	cs43130->clk_req++;
+	if (cs43130->clk_req == 2)
+		cs43130_pcm_dsd_mix(true, cs43130->regmap);
+	mutex_unlock(&cs43130->clk_mutex);
+
+	switch (dai->id) {
+	case CS43130_ASP_DOP_DAI:
+	case CS43130_XSP_DOP_DAI:
+		/* DoP bitwidth is always 24-bit */
+		bitwidth_dai = 24;
+		sclk = params_rate(params) * bitwidth_dai *
+		       params_channels(params);
+
+		switch (params_rate(params)) {
+		case 176400:
+			dsd_speed = 0;
+			break;
+		case 352800:
+			dsd_speed = 1;
+			break;
+		default:
+			dev_err(codec->dev, "Rate(%u) not supported\n",
+				params_rate(params));
+			return -EINVAL;
+		}
+
+		regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+				   CS43130_DSD_SPEED_MASK,
+				   dsd_speed << CS43130_DSD_SPEED_SHIFT);
+		break;
+	case CS43130_ASP_PCM_DAI:
+		rate_map = cs43130_get_rate_table(params_rate(params));
+		if (!rate_map)
+			return -EINVAL;
+
+		regmap_write(cs43130->regmap, CS43130_SP_SRATE, rate_map->val);
+		break;
+	default:
+		dev_err(codec->dev, "Invalid DAI (%d)\n", dai->id);
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case CS43130_ASP_DOP_DAI:
+		regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+				   CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_ASP <<
+				   CS43130_DSD_SRC_SHIFT);
+		break;
+	case CS43130_XSP_DOP_DAI:
+		regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+				   CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_XSP <<
+				   CS43130_DSD_SRC_SHIFT);
+	}
+
+	if (!sclk && cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM)
+		/* Calculate SCLK in master mode if unassigned */
+		sclk = params_rate(params) * bitwidth_dai *
+		       params_channels(params);
+
+	if (!sclk) {
+		/* at this point, SCLK must be set */
+		dev_err(codec->dev, "SCLK freq is not set\n");
+		return -EINVAL;
+	}
+
+	bitwidth_sclk = (sclk / params_rate(params)) / params_channels(params);
+	if (bitwidth_sclk < bitwidth_dai) {
+		dev_err(codec->dev, "Format not supported: SCLK freq is too low\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(codec->dev,
+		"sclk = %u, fs = %d, bitwidth_dai = %u\n",
+		sclk, params_rate(params), bitwidth_dai);
+
+	dev_dbg(codec->dev,
+		"bitwidth_sclk = %u, num_ch = %u\n",
+		bitwidth_sclk, params_channels(params));
+
+	cs43130_set_bitwidth(dai->id, bitwidth_dai, cs43130->regmap);
+	cs43130_set_sp_fmt(dai->id, bitwidth_sclk, params, cs43130);
+
+	return 0;
+}
+
+static int cs43130_hw_free(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+	mutex_lock(&cs43130->clk_mutex);
+	cs43130->clk_req--;
+	if (!cs43130->clk_req) {
+		/* no DAI is currently using clk */
+		cs43130_change_clksrc(codec, CS43130_MCLK_SRC_RCO);
+		cs43130_pcm_dsd_mix(false, cs43130->regmap);
+	}
+	mutex_unlock(&cs43130->clk_mutex);
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(pcm_vol_tlv, -12750, 50, 1);
+
+static const char * const pcm_ch_text[] = {
+	"Left-Right Ch",
+	"Left-Left Ch",
+	"Right-Left Ch",
+	"Right-Right Ch",
+};
+
+static const struct reg_sequence pcm_ch_en_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{0x180005, 0x8C},
+	{0x180007, 0xAB},
+	{0x180015, 0x31},
+	{0x180017, 0xB2},
+	{0x180025, 0x30},
+	{0x180027, 0x84},
+	{0x180035, 0x9C},
+	{0x180037, 0xAE},
+	{0x18000D, 0x24},
+	{0x18000F, 0xA3},
+	{0x18001D, 0x05},
+	{0x18001F, 0xD4},
+	{0x18002D, 0x0B},
+	{0x18002F, 0xC7},
+	{0x18003D, 0x71},
+	{0x18003F, 0xE7},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence pcm_ch_dis_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{0x180005, 0x24},
+	{0x180007, 0xA3},
+	{0x180015, 0x05},
+	{0x180017, 0xD4},
+	{0x180025, 0x0B},
+	{0x180027, 0xC7},
+	{0x180035, 0x71},
+	{0x180037, 0xE7},
+	{0x18000D, 0x8C},
+	{0x18000F, 0xAB},
+	{0x18001D, 0x31},
+	{0x18001F, 0xB2},
+	{0x18002D, 0x30},
+	{0x18002F, 0x84},
+	{0x18003D, 0x9C},
+	{0x18003F, 0xAE},
+	{CS43130_DXD1, 0},
+};
+
+static int cs43130_pcm_ch_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	return snd_soc_get_enum_double(kcontrol, ucontrol);
+}
+
+static int cs43130_pcm_ch_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int *item = ucontrol->value.enumerated.item;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val;
+
+	if (item[0] >= e->items)
+		return -EINVAL;
+	val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+	switch (cs43130->dev_id) {
+	case CS43131_CHIP_ID:
+	case CS43198_CHIP_ID:
+		if (val >= 2)
+			regmap_multi_reg_write(cs43130->regmap, pcm_ch_en_seq,
+					       ARRAY_SIZE(pcm_ch_en_seq));
+		else
+			regmap_multi_reg_write(cs43130->regmap, pcm_ch_dis_seq,
+					       ARRAY_SIZE(pcm_ch_dis_seq));
+	}
+
+	return snd_soc_put_enum_double(kcontrol, ucontrol);
+}
+
+static SOC_ENUM_SINGLE_DECL(pcm_ch_enum, CS43130_PCM_PATH_CTL_2, 0,
+			    pcm_ch_text);
+
+static const char * const pcm_spd_texts[] = {
+	"Fast",
+	"Slow",
+};
+
+static SOC_ENUM_SINGLE_DECL(pcm_spd_enum, CS43130_PCM_FILT_OPT, 7,
+			    pcm_spd_texts);
+
+static const char * const dsd_texts[] = {
+	"Off",
+	"BCKA Mode",
+	"BCKD Mode",
+};
+
+static const unsigned int dsd_values[] = {
+	CS43130_DSD_SRC_DSD,
+	CS43130_DSD_SRC_ASP,
+	CS43130_DSD_SRC_XSP,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(dsd_enum, CS43130_DSD_INT_CFG, 0, 0x03,
+				  dsd_texts, dsd_values);
+
+static const struct snd_kcontrol_new cs43130_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Master Playback Volume",
+			 CS43130_PCM_VOL_A, CS43130_PCM_VOL_B, 0, 0xFF, 1,
+			 pcm_vol_tlv),
+	SOC_DOUBLE_R_TLV("Master DSD Playback Volume",
+			 CS43130_DSD_VOL_A, CS43130_DSD_VOL_B, 0, 0xFF, 1,
+			 pcm_vol_tlv),
+	SOC_ENUM_EXT("PCM Ch Select", pcm_ch_enum, cs43130_pcm_ch_get,
+		     cs43130_pcm_ch_put),
+	SOC_ENUM("PCM Filter Speed", pcm_spd_enum),
+	SOC_SINGLE("PCM Phase Compensation", CS43130_PCM_FILT_OPT, 6, 1, 0),
+	SOC_SINGLE("PCM Nonoversample Emulate", CS43130_PCM_FILT_OPT, 5, 1, 0),
+	SOC_SINGLE("PCM High-pass Filter", CS43130_PCM_FILT_OPT, 1, 1, 0),
+	SOC_SINGLE("PCM De-emphasis Filter", CS43130_PCM_FILT_OPT, 0, 1, 0),
+	SOC_ENUM("DSD Phase Modulation", dsd_enum),
+};
+
+static const struct reg_sequence pcm_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD7, 0x01},
+	{CS43130_DXD8, 0},
+	{CS43130_DXD9, 0x01},
+	{CS43130_DXD3, 0x12},
+	{CS43130_DXD4, 0},
+	{CS43130_DXD10, 0x28},
+	{CS43130_DXD11, 0x28},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence dsd_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD7, 0x01},
+	{CS43130_DXD8, 0},
+	{CS43130_DXD9, 0x01},
+	{CS43130_DXD3, 0x12},
+	{CS43130_DXD4, 0},
+	{CS43130_DXD10, 0x1E},
+	{CS43130_DXD11, 0x20},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence pop_free_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD12, 0x0A},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence pop_free_seq2[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD13, 0x20},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence mute_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD3, 0x12},
+	{CS43130_DXD5, 0x02},
+	{CS43130_DXD4, 0x12},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence unmute_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD3, 0x10},
+	{CS43130_DXD5, 0},
+	{CS43130_DXD4, 0x16},
+	{CS43130_DXD1, 0},
+};
+
+static int cs43130_dsd_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, dsd_seq,
+					       ARRAY_SIZE(dsd_seq));
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_1,
+				   CS43130_MUTE_MASK, 0);
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, unmute_seq,
+					       ARRAY_SIZE(unmute_seq));
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, mute_seq,
+					       ARRAY_SIZE(mute_seq));
+			regmap_update_bits(cs43130->regmap,
+					   CS43130_DSD_PATH_CTL_1,
+					   CS43130_MUTE_MASK, CS43130_MUTE_EN);
+			/*
+			 * DSD Power Down Sequence
+			 * According to Design, 130ms is preferred.
+			 */
+			msleep(130);
+			break;
+		case CS43131_CHIP_ID:
+		case CS43198_CHIP_ID:
+			regmap_update_bits(cs43130->regmap,
+					   CS43130_DSD_PATH_CTL_1,
+					   CS43130_MUTE_MASK, CS43130_MUTE_EN);
+		}
+		break;
+	default:
+		dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cs43130_pcm_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, pcm_seq,
+					       ARRAY_SIZE(pcm_seq));
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(cs43130->regmap, CS43130_PCM_PATH_CTL_1,
+				   CS43130_MUTE_MASK, 0);
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, unmute_seq,
+					       ARRAY_SIZE(unmute_seq));
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, mute_seq,
+					       ARRAY_SIZE(mute_seq));
+			regmap_update_bits(cs43130->regmap,
+					   CS43130_PCM_PATH_CTL_1,
+					   CS43130_MUTE_MASK, CS43130_MUTE_EN);
+			/*
+			 * PCM Power Down Sequence
+			 * According to Design, 130ms is preferred.
+			 */
+			msleep(130);
+			break;
+		case CS43131_CHIP_ID:
+		case CS43198_CHIP_ID:
+			regmap_update_bits(cs43130->regmap,
+					   CS43130_PCM_PATH_CTL_1,
+					   CS43130_MUTE_MASK, CS43130_MUTE_EN);
+		}
+		break;
+	default:
+		dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct reg_sequence dac_postpmu_seq[] = {
+	{CS43130_DXD9, 0x0C},
+	{CS43130_DXD3, 0x10},
+	{CS43130_DXD4, 0x20},
+};
+
+static const struct reg_sequence dac_postpmd_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD6, 0x01},
+	{CS43130_DXD1, 0},
+};
+
+static int cs43130_dac_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, pop_free_seq,
+					       ARRAY_SIZE(pop_free_seq));
+			break;
+		case CS43131_CHIP_ID:
+		case CS43198_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, pop_free_seq2,
+					       ARRAY_SIZE(pop_free_seq2));
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(10000, 10050);
+
+		regmap_write(cs43130->regmap, CS43130_DXD1, 0x99);
+
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, dac_postpmu_seq,
+					       ARRAY_SIZE(dac_postpmu_seq));
+			/*
+			 * Per datasheet, Sec. PCM Power-Up Sequence.
+			 * According to Design, CS43130_DXD12 must be 0 to meet
+			 * THDN and Dynamic Range spec.
+			 */
+			msleep(1000);
+			regmap_write(cs43130->regmap, CS43130_DXD12, 0);
+			break;
+		case CS43131_CHIP_ID:
+		case CS43198_CHIP_ID:
+			usleep_range(12000, 12010);
+			regmap_write(cs43130->regmap, CS43130_DXD13, 0);
+		}
+
+		regmap_write(cs43130->regmap, CS43130_DXD1, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, dac_postpmd_seq,
+					       ARRAY_SIZE(dac_postpmd_seq));
+		}
+		break;
+	default:
+		dev_err(codec->dev, "Invalid DAC event = 0x%x\n", event);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct reg_sequence hpin_prepmd_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD15, 0x64},
+	{CS43130_DXD14, 0},
+	{CS43130_DXD2, 0},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence hpin_postpmu_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD2, 1},
+	{CS43130_DXD14, 0xDC},
+	{CS43130_DXD15, 0xE4},
+	{CS43130_DXD1, 0},
+};
+
+static int cs43130_hpin_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_multi_reg_write(cs43130->regmap, hpin_prepmd_seq,
+				       ARRAY_SIZE(hpin_prepmd_seq));
+		break;
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_multi_reg_write(cs43130->regmap, hpin_postpmu_seq,
+				       ARRAY_SIZE(hpin_postpmu_seq));
+		break;
+	default:
+		dev_err(codec->dev, "Invalid HPIN event = 0x%x\n", event);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget digital_hp_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("HPOUTA"),
+	SND_SOC_DAPM_OUTPUT("HPOUTB"),
+
+	SND_SOC_DAPM_AIF_IN_E("ASPIN PCM", NULL, 0, CS43130_PWDN_CTL,
+			      CS43130_PDN_ASP_SHIFT, 1, cs43130_pcm_event,
+			      (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_PRE_PMD)),
+
+	SND_SOC_DAPM_AIF_IN_E("ASPIN DoP", NULL, 0, CS43130_PWDN_CTL,
+			      CS43130_PDN_ASP_SHIFT, 1, cs43130_dsd_event,
+			      (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_PRE_PMD)),
+
+	SND_SOC_DAPM_AIF_IN_E("XSPIN DoP", NULL, 0, CS43130_PWDN_CTL,
+			      CS43130_PDN_XSP_SHIFT, 1, cs43130_dsd_event,
+			      (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_PRE_PMD)),
+
+	SND_SOC_DAPM_AIF_IN_E("XSPIN DSD", NULL, 0, CS43130_PWDN_CTL,
+			      CS43130_PDN_DSDIF_SHIFT, 1, cs43130_dsd_event,
+			      (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_PRE_PMD)),
+
+	SND_SOC_DAPM_DAC("DSD", NULL, CS43130_DSD_PATH_CTL_2,
+			 CS43130_DSD_EN_SHIFT, 0),
+
+	SND_SOC_DAPM_DAC_E("HiFi DAC", NULL, CS43130_PWDN_CTL,
+			   CS43130_PDN_HP_SHIFT, 1, cs43130_dac_event,
+			   (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD)),
+};
+
+static const struct snd_soc_dapm_widget analog_hp_widgets[] = {
+	SND_SOC_DAPM_DAC_E("Analog Playback", NULL, CS43130_HP_OUT_CTL_1,
+			   CS43130_HP_IN_EN_SHIFT, 0, cs43130_hpin_event,
+			   (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)),
+};
+
+static struct snd_soc_dapm_widget all_hp_widgets[
+			ARRAY_SIZE(digital_hp_widgets) +
+			ARRAY_SIZE(analog_hp_widgets)];
+
+static const struct snd_soc_dapm_route digital_hp_routes[] = {
+	{"ASPIN PCM", NULL, "ASP PCM Playback"},
+	{"ASPIN DoP", NULL, "ASP DoP Playback"},
+	{"XSPIN DoP", NULL, "XSP DoP Playback"},
+	{"XSPIN DSD", NULL, "XSP DSD Playback"},
+	{"DSD", NULL, "ASPIN DoP"},
+	{"DSD", NULL, "XSPIN DoP"},
+	{"DSD", NULL, "XSPIN DSD"},
+	{"HiFi DAC", NULL, "ASPIN PCM"},
+	{"HiFi DAC", NULL, "DSD"},
+	{"HPOUTA", NULL, "HiFi DAC"},
+	{"HPOUTB", NULL, "HiFi DAC"},
+};
+
+static const struct snd_soc_dapm_route analog_hp_routes[] = {
+	{"HPOUTA", NULL, "Analog Playback"},
+	{"HPOUTB", NULL, "Analog Playback"},
+};
+
+static struct snd_soc_dapm_route all_hp_routes[
+			ARRAY_SIZE(digital_hp_routes) +
+			ARRAY_SIZE(analog_hp_routes)];
+
+static const unsigned int cs43130_asp_src_rates[] = {
+	32000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000
+};
+
+static const struct snd_pcm_hw_constraint_list cs43130_asp_constraints = {
+	.count	= ARRAY_SIZE(cs43130_asp_src_rates),
+	.list	= cs43130_asp_src_rates,
+};
+
+static int cs43130_pcm_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  &cs43130_asp_constraints);
+}
+
+static const unsigned int cs43130_dop_src_rates[] = {
+	176400, 352800,
+};
+
+static const struct snd_pcm_hw_constraint_list cs43130_dop_constraints = {
+	.count	= ARRAY_SIZE(cs43130_dop_src_rates),
+	.list	= cs43130_dop_src_rates,
+};
+
+static int cs43130_dop_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  &cs43130_dop_constraints);
+}
+
+static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM;
+		break;
+	default:
+		dev_err(codec->dev, "unsupported mode\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_B;
+		break;
+	default:
+		dev_err(codec->dev,
+			"unsupported audio format\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(codec->dev, "dai_id = %d,  dai_mode = %u, dai_format = %u\n",
+		codec_dai->id,
+		cs43130->dais[codec_dai->id].dai_mode,
+		cs43130->dais[codec_dai->id].dai_format);
+
+	return 0;
+}
+
+static int cs43130_dsd_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM;
+		break;
+	default:
+		dev_err(codec->dev, "Unsupported DAI format.\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(codec->dev, "dai_mode = 0x%x\n",
+		cs43130->dais[codec_dai->id].dai_mode);
+
+	return 0;
+}
+
+static int cs43130_set_sysclk(struct snd_soc_dai *codec_dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+	cs43130->dais[codec_dai->id].sclk = freq;
+	dev_dbg(codec->dev, "dai_id = %d,  sclk = %u\n", codec_dai->id,
+		cs43130->dais[codec_dai->id].sclk);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops cs43130_pcm_ops = {
+	.startup	= cs43130_pcm_startup,
+	.hw_params	= cs43130_hw_params,
+	.hw_free	= cs43130_hw_free,
+	.set_sysclk	= cs43130_set_sysclk,
+	.set_fmt	= cs43130_pcm_set_fmt,
+};
+
+static const struct snd_soc_dai_ops cs43130_dop_ops = {
+	.startup	= cs43130_dop_startup,
+	.hw_params	= cs43130_hw_params,
+	.hw_free	= cs43130_hw_free,
+	.set_sysclk	= cs43130_set_sysclk,
+	.set_fmt	= cs43130_pcm_set_fmt,
+};
+
+static const struct snd_soc_dai_ops cs43130_dsd_ops = {
+	.startup        = cs43130_dop_startup,
+	.hw_params	= cs43130_dsd_hw_params,
+	.hw_free	= cs43130_hw_free,
+	.set_fmt	= cs43130_dsd_set_fmt,
+};
+
+static struct snd_soc_dai_driver cs43130_dai[] = {
+	{
+		.name = "cs43130-asp-pcm",
+		.id = CS43130_ASP_PCM_DAI,
+		.playback = {
+			.stream_name = "ASP PCM Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS43130_PCM_FORMATS,
+		},
+		.ops = &cs43130_pcm_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "cs43130-asp-dop",
+		.id = CS43130_ASP_DOP_DAI,
+		.playback = {
+			.stream_name = "ASP DoP Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS43130_DOP_FORMATS,
+		},
+		.ops = &cs43130_dop_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "cs43130-xsp-dop",
+		.id = CS43130_XSP_DOP_DAI,
+		.playback = {
+			.stream_name = "XSP DoP Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS43130_DOP_FORMATS,
+		},
+		.ops = &cs43130_dop_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "cs43130-xsp-dsd",
+		.id = CS43130_XSP_DSD_DAI,
+		.playback = {
+			.stream_name = "XSP DSD Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS43130_DOP_FORMATS,
+		},
+		.ops = &cs43130_dsd_ops,
+	},
+
+};
+
+static int cs43130_codec_set_sysclk(struct snd_soc_codec *codec,
+				    int clk_id, int source, unsigned int freq,
+				    int dir)
+{
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n",
+		clk_id, source, freq, dir);
+
+	switch (freq) {
+	case CS43130_MCLK_22M:
+	case CS43130_MCLK_24M:
+		cs43130->mclk = freq;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid MCLK INT freq: %u\n", freq);
+		return -EINVAL;
+	}
+
+	if (source == CS43130_MCLK_SRC_EXT) {
+		cs43130->pll_bypass = true;
+	} else {
+		dev_err(codec->dev, "Invalid MCLK source\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline u16 cs43130_get_ac_reg_val(u16 ac_freq)
+{
+	/* AC freq is counted in 5.94Hz step. */
+	return ac_freq / 6;
+}
+
+static int cs43130_show_dc(struct device *dev, char *buf, u8 ch)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct cs43130_private *cs43130 = i2c_get_clientdata(client);
+
+	if (!cs43130->hpload_done)
+		return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n");
+	else
+		return scnprintf(buf, PAGE_SIZE, "%u\n",
+				 cs43130->hpload_dc[ch]);
+}
+
+static ssize_t cs43130_show_dc_l(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	return cs43130_show_dc(dev, buf, HP_LEFT);
+}
+
+static ssize_t cs43130_show_dc_r(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	return cs43130_show_dc(dev, buf, HP_RIGHT);
+}
+
+static u16 const cs43130_ac_freq[CS43130_AC_FREQ] = {
+	24,
+	43,
+	93,
+	200,
+	431,
+	928,
+	2000,
+	4309,
+	9283,
+	20000,
+};
+
+static int cs43130_show_ac(struct device *dev, char *buf, u8 ch)
+{
+	int i, j = 0, tmp;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct cs43130_private *cs43130 = i2c_get_clientdata(client);
+
+	if (cs43130->hpload_done && cs43130->ac_meas) {
+		for (i = 0; i < ARRAY_SIZE(cs43130_ac_freq); i++) {
+			tmp = scnprintf(buf + j, PAGE_SIZE - j, "%u\n",
+					cs43130->hpload_ac[i][ch]);
+			if (!tmp)
+				break;
+
+			j += tmp;
+		}
+
+		return j;
+	} else {
+		return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n");
+	}
+}
+
+static ssize_t cs43130_show_ac_l(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	return cs43130_show_ac(dev, buf, HP_LEFT);
+}
+
+static ssize_t cs43130_show_ac_r(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	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 struct reg_sequence hp_en_cal_seq[] = {
+	{CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
+	{CS43130_HP_MEAS_LOAD_1, 0},
+	{CS43130_HP_MEAS_LOAD_2, 0},
+	{CS43130_INT_MASK_4, 0},
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD16, 0xBB},
+	{CS43130_DXD12, 0x01},
+	{CS43130_DXD19, 0xCB},
+	{CS43130_DXD17, 0x95},
+	{CS43130_DXD18, 0x0B},
+	{CS43130_DXD1, 0},
+	{CS43130_HP_LOAD_1, 0x80},
+};
+
+static struct reg_sequence hp_en_cal_seq2[] = {
+	{CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
+	{CS43130_HP_MEAS_LOAD_1, 0},
+	{CS43130_HP_MEAS_LOAD_2, 0},
+	{CS43130_INT_MASK_4, 0},
+	{CS43130_HP_LOAD_1, 0x80},
+};
+
+static struct reg_sequence hp_dis_cal_seq[] = {
+	{CS43130_HP_LOAD_1, 0x80},
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD12, 0},
+	{CS43130_DXD1, 0},
+	{CS43130_HP_LOAD_1, 0},
+};
+
+static struct reg_sequence hp_dis_cal_seq2[] = {
+	{CS43130_HP_LOAD_1, 0x80},
+	{CS43130_HP_LOAD_1, 0},
+};
+
+static struct reg_sequence hp_dc_ch_l_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD19, 0x0A},
+	{CS43130_DXD17, 0x93},
+	{CS43130_DXD18, 0x0A},
+	{CS43130_DXD1, 0},
+	{CS43130_HP_LOAD_1, 0x80},
+	{CS43130_HP_LOAD_1, 0x81},
+};
+
+static struct reg_sequence hp_dc_ch_l_seq2[] = {
+	{CS43130_HP_LOAD_1, 0x80},
+	{CS43130_HP_LOAD_1, 0x81},
+};
+
+static struct reg_sequence hp_dc_ch_r_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD19, 0x8A},
+	{CS43130_DXD17, 0x15},
+	{CS43130_DXD18, 0x06},
+	{CS43130_DXD1, 0},
+	{CS43130_HP_LOAD_1, 0x90},
+	{CS43130_HP_LOAD_1, 0x91},
+};
+
+static struct reg_sequence hp_dc_ch_r_seq2[] = {
+	{CS43130_HP_LOAD_1, 0x90},
+	{CS43130_HP_LOAD_1, 0x91},
+};
+
+static struct reg_sequence hp_ac_ch_l_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD19, 0x0A},
+	{CS43130_DXD17, 0x93},
+	{CS43130_DXD18, 0x0A},
+	{CS43130_DXD1, 0},
+	{CS43130_HP_LOAD_1, 0x80},
+	{CS43130_HP_LOAD_1, 0x82},
+};
+
+static struct reg_sequence hp_ac_ch_l_seq2[] = {
+	{CS43130_HP_LOAD_1, 0x80},
+	{CS43130_HP_LOAD_1, 0x82},
+};
+
+static struct reg_sequence hp_ac_ch_r_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD19, 0x8A},
+	{CS43130_DXD17, 0x15},
+	{CS43130_DXD18, 0x06},
+	{CS43130_DXD1, 0},
+	{CS43130_HP_LOAD_1, 0x90},
+	{CS43130_HP_LOAD_1, 0x92},
+};
+
+static struct reg_sequence hp_ac_ch_r_seq2[] = {
+	{CS43130_HP_LOAD_1, 0x90},
+	{CS43130_HP_LOAD_1, 0x92},
+};
+
+static struct reg_sequence hp_cln_seq[] = {
+	{CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
+	{CS43130_HP_MEAS_LOAD_1, 0},
+	{CS43130_HP_MEAS_LOAD_2, 0},
+};
+
+struct reg_sequences {
+	struct reg_sequence	*seq;
+	int			size;
+	unsigned int		msk;
+};
+
+static struct reg_sequences hpload_seq1[] = {
+	{
+		.seq	= hp_en_cal_seq,
+		.size	= ARRAY_SIZE(hp_en_cal_seq),
+		.msk	= CS43130_HPLOAD_ON_INT,
+	},
+	{
+		.seq	= hp_dc_ch_l_seq,
+		.size	= ARRAY_SIZE(hp_dc_ch_l_seq),
+		.msk	= CS43130_HPLOAD_DC_INT,
+	},
+	{
+		.seq	= hp_ac_ch_l_seq,
+		.size	= ARRAY_SIZE(hp_ac_ch_l_seq),
+		.msk	= CS43130_HPLOAD_AC_INT,
+	},
+	{
+		.seq	= hp_dis_cal_seq,
+		.size	= ARRAY_SIZE(hp_dis_cal_seq),
+		.msk	= CS43130_HPLOAD_OFF_INT,
+	},
+	{
+		.seq	= hp_en_cal_seq,
+		.size	= ARRAY_SIZE(hp_en_cal_seq),
+		.msk	= CS43130_HPLOAD_ON_INT,
+	},
+	{
+		.seq	= hp_dc_ch_r_seq,
+		.size	= ARRAY_SIZE(hp_dc_ch_r_seq),
+		.msk	= CS43130_HPLOAD_DC_INT,
+	},
+	{
+		.seq	= hp_ac_ch_r_seq,
+		.size	= ARRAY_SIZE(hp_ac_ch_r_seq),
+		.msk	= CS43130_HPLOAD_AC_INT,
+	},
+};
+
+static struct reg_sequences hpload_seq2[] = {
+	{
+		.seq	= hp_en_cal_seq2,
+		.size	= ARRAY_SIZE(hp_en_cal_seq2),
+		.msk	= CS43130_HPLOAD_ON_INT,
+	},
+	{
+		.seq	= hp_dc_ch_l_seq2,
+		.size	= ARRAY_SIZE(hp_dc_ch_l_seq2),
+		.msk	= CS43130_HPLOAD_DC_INT,
+	},
+	{
+		.seq	= hp_ac_ch_l_seq2,
+		.size	= ARRAY_SIZE(hp_ac_ch_l_seq2),
+		.msk	= CS43130_HPLOAD_AC_INT,
+	},
+	{
+		.seq	= hp_dis_cal_seq2,
+		.size	= ARRAY_SIZE(hp_dis_cal_seq2),
+		.msk	= CS43130_HPLOAD_OFF_INT,
+	},
+	{
+		.seq	= hp_en_cal_seq2,
+		.size	= ARRAY_SIZE(hp_en_cal_seq2),
+		.msk	= CS43130_HPLOAD_ON_INT,
+	},
+	{
+		.seq	= hp_dc_ch_r_seq2,
+		.size	= ARRAY_SIZE(hp_dc_ch_r_seq2),
+		.msk	= CS43130_HPLOAD_DC_INT,
+	},
+	{
+		.seq	= hp_ac_ch_r_seq2,
+		.size	= ARRAY_SIZE(hp_ac_ch_r_seq2),
+		.msk	= CS43130_HPLOAD_AC_INT,
+	},
+};
+
+static int cs43130_update_hpload(unsigned int msk, int ac_idx,
+				 struct cs43130_private *cs43130)
+{
+	bool left_ch = true;
+	unsigned int reg;
+	u32 addr;
+	u16 impedance;
+	struct snd_soc_codec *codec = cs43130->codec;
+
+	switch (msk) {
+	case CS43130_HPLOAD_DC_INT:
+	case CS43130_HPLOAD_AC_INT:
+		break;
+	default:
+		return 0;
+	}
+
+	regmap_read(cs43130->regmap, CS43130_HP_LOAD_1, &reg);
+	if (reg & CS43130_HPLOAD_CHN_SEL)
+		left_ch = false;
+
+	if (msk == CS43130_HPLOAD_DC_INT)
+		addr = CS43130_HP_DC_STAT_1;
+	else
+		addr = CS43130_HP_AC_STAT_1;
+
+	regmap_read(cs43130->regmap, addr, &reg);
+	impedance = reg >> 3;
+	regmap_read(cs43130->regmap, addr + 1, &reg);
+	impedance |= reg << 5;
+
+	if (msk == CS43130_HPLOAD_DC_INT) {
+		if (left_ch)
+			cs43130->hpload_dc[HP_LEFT] = impedance;
+		else
+			cs43130->hpload_dc[HP_RIGHT] = impedance;
+
+		dev_dbg(codec->dev, "HP DC impedance (Ch %u): %u\n", !left_ch,
+			impedance);
+	} else {
+		if (left_ch)
+			cs43130->hpload_ac[ac_idx][HP_LEFT] = impedance;
+		else
+			cs43130->hpload_ac[ac_idx][HP_RIGHT] = impedance;
+
+		dev_dbg(codec->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n",
+			cs43130->ac_freq[ac_idx], !left_ch, impedance);
+	}
+
+	return 0;
+}
+
+static int cs43130_hpload_proc(struct cs43130_private *cs43130,
+			       struct reg_sequence *seq, int seq_size,
+			       unsigned int rslt_msk, int ac_idx)
+{
+	int ret;
+	unsigned int msk;
+	u16 ac_reg_val;
+	struct snd_soc_codec *codec = cs43130->codec;
+
+	reinit_completion(&cs43130->hpload_evt);
+
+	if (rslt_msk == CS43130_HPLOAD_AC_INT) {
+		ac_reg_val = cs43130_get_ac_reg_val(cs43130->ac_freq[ac_idx]);
+		regmap_update_bits(cs43130->regmap, CS43130_HP_LOAD_1,
+				   CS43130_HPLOAD_AC_START, 0);
+		regmap_update_bits(cs43130->regmap, CS43130_HP_MEAS_LOAD_1,
+				   CS43130_HP_MEAS_LOAD_MASK,
+				   ac_reg_val >> CS43130_HP_MEAS_LOAD_1_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_HP_MEAS_LOAD_2,
+				   CS43130_HP_MEAS_LOAD_MASK,
+				   ac_reg_val >> CS43130_HP_MEAS_LOAD_2_SHIFT);
+	}
+
+	regmap_multi_reg_write(cs43130->regmap, seq,
+			       seq_size);
+
+	ret = wait_for_completion_timeout(&cs43130->hpload_evt,
+					  msecs_to_jiffies(1000));
+	regmap_read(cs43130->regmap, CS43130_INT_MASK_4, &msk);
+	if (!ret) {
+		dev_err(codec->dev, "Timeout waiting for HPLOAD interrupt\n");
+		return -1;
+	}
+
+	dev_dbg(codec->dev, "HP load stat: %x, INT_MASK_4: %x\n",
+		cs43130->hpload_stat, msk);
+	if ((cs43130->hpload_stat & (CS43130_HPLOAD_NO_DC_INT |
+				     CS43130_HPLOAD_UNPLUG_INT |
+				     CS43130_HPLOAD_OOR_INT)) ||
+	    !(cs43130->hpload_stat & rslt_msk)) {
+		dev_dbg(codec->dev, "HP load measure failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static const struct reg_sequence hv_seq[][2] = {
+	{
+		{CS43130_CLASS_H_CTL, 0x1C},
+		{CS43130_HP_OUT_CTL_1, 0x10},
+	},
+	{
+		{CS43130_CLASS_H_CTL, 0x1E},
+		{CS43130_HP_OUT_CTL_1, 0x20},
+	},
+	{
+		{CS43130_CLASS_H_CTL, 0x1E},
+		{CS43130_HP_OUT_CTL_1, 0x30},
+	},
+};
+
+static int cs43130_set_hv(struct regmap *regmap, u16 hpload_dc,
+			  const u16 *dc_threshold)
+{
+	int i;
+
+	for (i = 0; i < CS43130_DC_THRESHOLD; i++) {
+		if (hpload_dc <= dc_threshold[i])
+			break;
+	}
+
+	regmap_multi_reg_write(regmap, hv_seq[i], ARRAY_SIZE(hv_seq[i]));
+
+	return 0;
+}
+
+static void cs43130_imp_meas(struct work_struct *wk)
+{
+	unsigned int reg, seq_size;
+	int i, ret, ac_idx;
+	struct cs43130_private *cs43130;
+	struct snd_soc_codec *codec;
+	struct reg_sequences *hpload_seq;
+
+	cs43130 = container_of(wk, struct cs43130_private, work);
+	codec = cs43130->codec;
+
+	if (!cs43130->mclk)
+		return;
+
+	cs43130->hpload_done = false;
+
+	mutex_lock(&cs43130->clk_mutex);
+	if (!cs43130->clk_req) {
+		/* clk not in use */
+		cs43130_set_pll(codec, 0, 0, cs43130->mclk, CS43130_MCLK_22M);
+		if (cs43130->pll_bypass)
+			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT);
+		else
+			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL);
+	}
+
+	cs43130->clk_req++;
+	mutex_unlock(&cs43130->clk_mutex);
+
+	regmap_read(cs43130->regmap, CS43130_INT_STATUS_4, &reg);
+
+	switch (cs43130->dev_id) {
+	case CS43130_CHIP_ID:
+		hpload_seq = hpload_seq1;
+		seq_size = ARRAY_SIZE(hpload_seq1);
+		break;
+	case CS43131_CHIP_ID:
+		hpload_seq = hpload_seq2;
+		seq_size = ARRAY_SIZE(hpload_seq2);
+	}
+
+	i = 0;
+	ac_idx = 0;
+	while (i < seq_size) {
+		ret = cs43130_hpload_proc(cs43130, hpload_seq[i].seq,
+					  hpload_seq[i].size,
+					  hpload_seq[i].msk, ac_idx);
+		if (ret < 0)
+			goto exit;
+
+		cs43130_update_hpload(hpload_seq[i].msk, ac_idx, cs43130);
+
+		if (cs43130->ac_meas &&
+		    hpload_seq[i].msk == CS43130_HPLOAD_AC_INT &&
+		    ac_idx < CS43130_AC_FREQ - 1) {
+			ac_idx++;
+		} else {
+			ac_idx = 0;
+			i++;
+		}
+	}
+	cs43130->hpload_done = true;
+
+	if (cs43130->hpload_dc[HP_LEFT] >= CS43130_LINEOUT_LOAD)
+		snd_soc_jack_report(&cs43130->jack, CS43130_JACK_LINEOUT,
+				    CS43130_JACK_MASK);
+	else
+		snd_soc_jack_report(&cs43130->jack, CS43130_JACK_HEADPHONE,
+				    CS43130_JACK_MASK);
+
+	dev_dbg(codec->dev, "Set HP output control. DC threshold\n");
+	for (i = 0; i < CS43130_DC_THRESHOLD; i++)
+		dev_dbg(codec->dev, "DC threshold[%d]: %u.\n", i,
+			cs43130->dc_threshold[i]);
+
+	cs43130_set_hv(cs43130->regmap, cs43130->hpload_dc[HP_LEFT],
+		       cs43130->dc_threshold);
+
+exit:
+	switch (cs43130->dev_id) {
+	case CS43130_CHIP_ID:
+		cs43130_hpload_proc(cs43130, hp_dis_cal_seq,
+				    ARRAY_SIZE(hp_dis_cal_seq),
+				    CS43130_HPLOAD_OFF_INT, ac_idx);
+		break;
+	case CS43131_CHIP_ID:
+		cs43130_hpload_proc(cs43130, hp_dis_cal_seq2,
+				    ARRAY_SIZE(hp_dis_cal_seq2),
+				    CS43130_HPLOAD_OFF_INT, ac_idx);
+	}
+
+	regmap_multi_reg_write(cs43130->regmap, hp_cln_seq,
+			       ARRAY_SIZE(hp_cln_seq));
+
+	mutex_lock(&cs43130->clk_mutex);
+	cs43130->clk_req--;
+	/* clk not in use */
+	if (!cs43130->clk_req)
+		cs43130_change_clksrc(codec, CS43130_MCLK_SRC_RCO);
+	mutex_unlock(&cs43130->clk_mutex);
+}
+
+static irqreturn_t cs43130_irq_thread(int irq, void *data)
+{
+	struct cs43130_private *cs43130 = (struct cs43130_private *)data;
+	struct snd_soc_codec *codec = cs43130->codec;
+	unsigned int stickies[CS43130_NUM_INT];
+	unsigned int irq_occurrance = 0;
+	unsigned int masks[CS43130_NUM_INT];
+	int i, j;
+
+	for (i = 0; i < ARRAY_SIZE(stickies); i++) {
+		regmap_read(cs43130->regmap, CS43130_INT_STATUS_1 + i,
+			    &stickies[i]);
+		regmap_read(cs43130->regmap, CS43130_INT_MASK_1 + i,
+			    &masks[i]);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(stickies); i++) {
+		stickies[i] = stickies[i] & (~masks[i]);
+		for (j = 0; j < 8; j++)
+			irq_occurrance += (stickies[i] >> j) & 1;
+	}
+	dev_dbg(codec->dev, "number of interrupts occurred (%u)\n",
+		irq_occurrance);
+
+	if (!irq_occurrance)
+		return IRQ_NONE;
+
+	if (stickies[0] & CS43130_XTAL_RDY_INT) {
+		complete(&cs43130->xtal_rdy);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[0] & CS43130_PLL_RDY_INT) {
+		complete(&cs43130->pll_rdy);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_NO_DC_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_err(codec->dev,
+			"DC load has not completed before AC load (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_UNPLUG_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_err(codec->dev, "HP unplugged during measurement (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_OOR_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_err(codec->dev, "HP load out of range (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_AC_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_dbg(codec->dev, "HP AC load measurement done (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_DC_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_dbg(codec->dev, "HP DC load measurement done (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_ON_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_dbg(codec->dev, "HP load state machine on done (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_OFF_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_dbg(codec->dev, "HP load state machine off done (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[0] & CS43130_XTAL_ERR_INT) {
+		dev_err(codec->dev, "Crystal err: clock is not running\n");
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[0] & CS43130_HP_UNPLUG_INT) {
+		dev_dbg(codec->dev, "HP unplugged\n");
+		cs43130->hpload_done = false;
+		snd_soc_jack_report(&cs43130->jack, 0, CS43130_JACK_MASK);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[0] & CS43130_HP_PLUG_INT) {
+		if (cs43130->dc_meas && !cs43130->hpload_done &&
+		    !work_busy(&cs43130->work)) {
+			dev_dbg(codec->dev, "HP load queue work\n");
+			queue_work(cs43130->wq, &cs43130->work);
+		}
+
+		snd_soc_jack_report(&cs43130->jack, SND_JACK_MECHANICAL,
+				    CS43130_JACK_MASK);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static int cs43130_probe(struct snd_soc_codec *codec)
+{
+	int ret;
+	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_card *card = codec->component.card;
+	unsigned int reg;
+
+	cs43130->codec = codec;
+
+	if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) {
+		regmap_update_bits(cs43130->regmap, CS43130_CRYSTAL_SET,
+				   CS43130_XTAL_IBIAS_MASK,
+				   cs43130->xtal_ibias);
+		regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+				   CS43130_XTAL_ERR_INT, 0);
+	}
+
+	ret = snd_soc_card_jack_new(card, "Headphone", CS43130_JACK_MASK,
+				    &cs43130->jack, NULL, 0);
+	if (ret < 0) {
+		dev_err(codec->dev, "Cannot create jack\n");
+		return ret;
+	}
+
+	cs43130->hpload_done = false;
+	if (cs43130->dc_meas) {
+		ret = device_create_file(codec->dev, &dev_attr_hpload_dc_l);
+		if (ret < 0)
+			return ret;
+
+		ret = device_create_file(codec->dev, &dev_attr_hpload_dc_r);
+		if (ret < 0)
+			return ret;
+
+		ret = device_create_file(codec->dev, &dev_attr_hpload_ac_l);
+		if (ret < 0)
+			return ret;
+
+		ret = device_create_file(codec->dev, &dev_attr_hpload_ac_r);
+		if (ret < 0)
+			return ret;
+
+		cs43130->wq = create_singlethread_workqueue("cs43130_hp");
+		INIT_WORK(&cs43130->work, cs43130_imp_meas);
+	}
+
+	regmap_read(cs43130->regmap, CS43130_INT_STATUS_1, &reg);
+	regmap_read(cs43130->regmap, CS43130_HP_STATUS, &reg);
+	regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+			   CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT, 0);
+	regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT,
+			   CS43130_HP_DETECT_CTRL_MASK, 0);
+	regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT,
+			   CS43130_HP_DETECT_CTRL_MASK,
+			   CS43130_HP_DETECT_CTRL_MASK);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs43130 = {
+	.probe			= cs43130_probe,
+	.component_driver = {
+		.controls		= cs43130_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs43130_snd_controls),
+	},
+	.set_sysclk		= cs43130_codec_set_sysclk,
+	.set_pll		= cs43130_set_pll,
+};
+
+static const struct regmap_config cs43130_regmap = {
+	.reg_bits		= 24,
+	.pad_bits		= 8,
+	.val_bits		= 8,
+
+	.max_register		= CS43130_LASTREG,
+	.reg_defaults		= cs43130_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(cs43130_reg_defaults),
+	.readable_reg		= cs43130_readable_register,
+	.precious_reg		= cs43130_precious_register,
+	.volatile_reg		= cs43130_volatile_register,
+	.cache_type		= REGCACHE_RBTREE,
+	.use_single_rw		= true, /* needed for regcache_sync */
+};
+
+static u16 const cs43130_dc_threshold[CS43130_DC_THRESHOLD] = {
+	50,
+	120,
+};
+
+static int cs43130_handle_device_data(struct i2c_client *i2c_client,
+				      struct cs43130_private *cs43130)
+{
+	struct device_node *np = i2c_client->dev.of_node;
+	unsigned int val;
+	int i;
+
+	if (of_property_read_u32(np, "cirrus,xtal-ibias", &val) < 0) {
+		/* Crystal is unused. System clock is used for external MCLK */
+		cs43130->xtal_ibias = CS43130_XTAL_UNUSED;
+		return 0;
+	}
+
+	switch (val) {
+	case 1:
+		cs43130->xtal_ibias = CS43130_XTAL_IBIAS_7_5UA;
+		break;
+	case 2:
+		cs43130->xtal_ibias = CS43130_XTAL_IBIAS_12_5UA;
+		break;
+	case 3:
+		cs43130->xtal_ibias = CS43130_XTAL_IBIAS_15UA;
+		break;
+	default:
+		dev_err(&i2c_client->dev,
+			"Invalid cirrus,xtal-ibias value: %d\n", val);
+		return -EINVAL;
+	}
+
+	cs43130->dc_meas = of_property_read_bool(np, "cirrus,dc-measure");
+	cs43130->ac_meas = of_property_read_bool(np, "cirrus,ac-measure");
+
+	if (of_property_read_u16_array(np, "cirrus,ac-freq", cs43130->ac_freq,
+					CS43130_AC_FREQ) < 0) {
+		for (i = 0; i < CS43130_AC_FREQ; i++)
+			cs43130->ac_freq[i] = cs43130_ac_freq[i];
+	}
+
+	if (of_property_read_u16_array(np, "cirrus,dc-threshold",
+				       cs43130->dc_threshold,
+				       CS43130_DC_THRESHOLD) < 0) {
+		for (i = 0; i < CS43130_DC_THRESHOLD; i++)
+			cs43130->dc_threshold[i] = cs43130_dc_threshold[i];
+	}
+
+	return 0;
+}
+
+static int cs43130_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct cs43130_private *cs43130;
+	int ret;
+	unsigned int devid = 0;
+	unsigned int reg;
+	int i;
+
+	cs43130 = devm_kzalloc(&client->dev, sizeof(*cs43130), GFP_KERNEL);
+	if (!cs43130)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, cs43130);
+
+	cs43130->regmap = devm_regmap_init_i2c(client, &cs43130_regmap);
+	if (IS_ERR(cs43130->regmap)) {
+		ret = PTR_ERR(cs43130->regmap);
+		return ret;
+	}
+
+	if (client->dev.of_node) {
+		ret = cs43130_handle_device_data(client, cs43130);
+		if (ret != 0)
+			return ret;
+	}
+	for (i = 0; i < ARRAY_SIZE(cs43130->supplies); i++)
+		cs43130->supplies[i].supply = cs43130_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&client->dev,
+				      ARRAY_SIZE(cs43130->supplies),
+				      cs43130->supplies);
+	if (ret != 0) {
+		dev_err(&client->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs43130->supplies),
+				    cs43130->supplies);
+	if (ret != 0) {
+		dev_err(&client->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	cs43130->reset_gpio = devm_gpiod_get_optional(&client->dev,
+						      "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(cs43130->reset_gpio))
+		return PTR_ERR(cs43130->reset_gpio);
+
+	gpiod_set_value_cansleep(cs43130->reset_gpio, 1);
+
+	usleep_range(2000, 2050);
+
+	ret = regmap_read(cs43130->regmap, CS43130_DEVID_AB, &reg);
+
+	devid = (reg & 0xFF) << 12;
+	ret = regmap_read(cs43130->regmap, CS43130_DEVID_CD, &reg);
+	devid |= (reg & 0xFF) << 4;
+	ret = regmap_read(cs43130->regmap, CS43130_DEVID_E, &reg);
+	devid |= (reg & 0xF0) >> 4;
+
+	switch (devid) {
+	case CS43130_CHIP_ID:
+	case CS4399_CHIP_ID:
+	case CS43131_CHIP_ID:
+	case CS43198_CHIP_ID:
+		break;
+	default:
+		dev_err(&client->dev,
+			"CS43130 Device ID %X. Expected ID %X, %X, %X or %X\n",
+			devid, CS43130_CHIP_ID, CS4399_CHIP_ID,
+			CS43131_CHIP_ID, CS43198_CHIP_ID);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	cs43130->dev_id = devid;
+	ret = regmap_read(cs43130->regmap, CS43130_REV_ID, &reg);
+	if (ret < 0) {
+		dev_err(&client->dev, "Get Revision ID failed\n");
+		goto err;
+	}
+
+	dev_info(&client->dev,
+		 "Cirrus Logic CS43130 (%x), Revision: %02X\n", devid,
+		 reg & 0xFF);
+
+	mutex_init(&cs43130->clk_mutex);
+
+	init_completion(&cs43130->xtal_rdy);
+	init_completion(&cs43130->pll_rdy);
+	init_completion(&cs43130->hpload_evt);
+
+	ret = devm_request_threaded_irq(&client->dev, client->irq,
+					NULL, cs43130_irq_thread,
+					IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+					"cs43130", cs43130);
+	if (ret != 0) {
+		dev_err(&client->dev, "Failed to request IRQ: %d\n", ret);
+		return ret;
+	}
+
+	cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO;
+
+	pm_runtime_set_autosuspend_delay(&client->dev, 100);
+	pm_runtime_use_autosuspend(&client->dev);
+	pm_runtime_set_active(&client->dev);
+	pm_runtime_enable(&client->dev);
+
+	switch (cs43130->dev_id) {
+	case CS43130_CHIP_ID:
+	case CS43131_CHIP_ID:
+		memcpy(all_hp_widgets, digital_hp_widgets,
+		       sizeof(digital_hp_widgets));
+		memcpy(all_hp_widgets + ARRAY_SIZE(digital_hp_widgets),
+		       analog_hp_widgets, sizeof(analog_hp_widgets));
+		memcpy(all_hp_routes, digital_hp_routes,
+		       sizeof(digital_hp_routes));
+		memcpy(all_hp_routes + ARRAY_SIZE(digital_hp_routes),
+		       analog_hp_routes, sizeof(analog_hp_routes));
+
+		soc_codec_dev_cs43130.component_driver.dapm_widgets =
+			all_hp_widgets;
+		soc_codec_dev_cs43130.component_driver.num_dapm_widgets =
+			ARRAY_SIZE(all_hp_widgets);
+		soc_codec_dev_cs43130.component_driver.dapm_routes =
+			all_hp_routes;
+		soc_codec_dev_cs43130.component_driver.num_dapm_routes =
+			ARRAY_SIZE(all_hp_routes);
+		break;
+	case CS43198_CHIP_ID:
+	case CS4399_CHIP_ID:
+		soc_codec_dev_cs43130.component_driver.dapm_widgets =
+			digital_hp_widgets;
+		soc_codec_dev_cs43130.component_driver.num_dapm_widgets =
+			ARRAY_SIZE(digital_hp_widgets);
+		soc_codec_dev_cs43130.component_driver.dapm_routes =
+			digital_hp_routes;
+		soc_codec_dev_cs43130.component_driver.num_dapm_routes =
+			ARRAY_SIZE(digital_hp_routes);
+	}
+
+	ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_cs43130,
+				     cs43130_dai, ARRAY_SIZE(cs43130_dai));
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"snd_soc_register_codec failed with ret = %d\n", ret);
+		goto err;
+	}
+
+	regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG,
+			   CS43130_ASP_3ST_MASK, 0);
+	regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG,
+			   CS43130_XSP_3ST_MASK, 0);
+
+	return 0;
+err:
+	return ret;
+}
+
+static int cs43130_i2c_remove(struct i2c_client *client)
+{
+	struct cs43130_private *cs43130 = i2c_get_clientdata(client);
+
+	if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED)
+		regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+				   CS43130_XTAL_ERR_INT,
+				   1 << CS43130_XTAL_ERR_INT_SHIFT);
+
+	regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+			   CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT,
+			   CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT);
+
+	if (cs43130->dc_meas) {
+		cancel_work_sync(&cs43130->work);
+		flush_workqueue(cs43130->wq);
+
+		device_remove_file(&client->dev, &dev_attr_hpload_dc_l);
+		device_remove_file(&client->dev, &dev_attr_hpload_dc_r);
+		device_remove_file(&client->dev, &dev_attr_hpload_ac_l);
+		device_remove_file(&client->dev, &dev_attr_hpload_ac_r);
+	}
+
+	if (cs43130->reset_gpio)
+		gpiod_set_value_cansleep(cs43130->reset_gpio, 0);
+
+	pm_runtime_disable(&client->dev);
+	regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies);
+
+	snd_soc_unregister_codec(&client->dev);
+
+	return 0;
+}
+
+static int cs43130_runtime_suspend(struct device *dev)
+{
+	struct cs43130_private *cs43130 = dev_get_drvdata(dev);
+
+	if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED)
+		regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+				   CS43130_XTAL_ERR_INT,
+				   1 << CS43130_XTAL_ERR_INT_SHIFT);
+
+	regcache_cache_only(cs43130->regmap, true);
+	regcache_mark_dirty(cs43130->regmap);
+
+	gpiod_set_value_cansleep(cs43130->reset_gpio, 0);
+
+	regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies);
+
+	return 0;
+}
+
+static int cs43130_runtime_resume(struct device *dev)
+{
+	struct cs43130_private *cs43130 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_bulk_enable(CS43130_NUM_SUPPLIES, cs43130->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	regcache_cache_only(cs43130->regmap, false);
+
+	gpiod_set_value_cansleep(cs43130->reset_gpio, 1);
+
+	usleep_range(2000, 2050);
+
+	ret = regcache_sync(cs43130->regmap);
+	if (ret != 0) {
+		dev_err(dev, "Failed to restore register cache\n");
+		goto err;
+	}
+
+	if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED)
+		regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+				   CS43130_XTAL_ERR_INT, 0);
+
+	return 0;
+err:
+	regcache_cache_only(cs43130->regmap, true);
+	regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies);
+
+	return ret;
+}
+
+static const struct dev_pm_ops cs43130_runtime_pm = {
+	SET_RUNTIME_PM_OPS(cs43130_runtime_suspend, cs43130_runtime_resume,
+			   NULL)
+};
+
+static const struct of_device_id cs43130_of_match[] = {
+	{.compatible = "cirrus,cs43130",},
+	{.compatible = "cirrus,cs4399",},
+	{.compatible = "cirrus,cs43131",},
+	{.compatible = "cirrus,cs43198",},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cs43130_of_match);
+
+static const struct i2c_device_id cs43130_i2c_id[] = {
+	{"cs43130", 0},
+	{"cs4399", 0},
+	{"cs43131", 0},
+	{"cs43198", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs43130_i2c_id);
+
+static struct i2c_driver cs43130_i2c_driver = {
+	.driver = {
+		.name		= "cs43130",
+		.of_match_table	= cs43130_of_match,
+		.pm             = &cs43130_runtime_pm,
+	},
+	.id_table	= cs43130_i2c_id,
+	.probe		= cs43130_i2c_probe,
+	.remove		= cs43130_i2c_remove,
+};
+
+module_i2c_driver(cs43130_i2c_driver);
+
+MODULE_AUTHOR("Li Xu <li.xu@cirrus.com>");
+MODULE_DESCRIPTION("Cirrus Logic CS43130 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h
new file mode 100644
index 000000000000..781258418d89
--- /dev/null
+++ b/sound/soc/codecs/cs43130.h
@@ -0,0 +1,546 @@
+/*
+ * ALSA SoC CS43130 codec driver
+ *
+ * Copyright 2017 Cirrus Logic, Inc.
+ *
+ * Author: Li Xu <li.xu@cirrus.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.
+ *
+ */
+
+#ifndef __CS43130_H__
+#define __CS43130_H__
+
+/* CS43130 registers addresses */
+/* all reg address is shifted by a byte for control byte to be LSB */
+#define CS43130_FIRSTREG	0x010000
+#define CS43130_LASTREG		0x190000
+#define CS43130_CHIP_ID		0x00043130
+#define CS4399_CHIP_ID		0x00043990
+#define CS43131_CHIP_ID		0x00043131
+#define CS43198_CHIP_ID		0x00043198
+#define CS43130_DEVID_AB	0x010000	/* Device ID A & B [RO] */
+#define CS43130_DEVID_CD	0x010001	/* Device ID C & D [RO] */
+#define CS43130_DEVID_E		0x010002	/* Device ID E [RO] */
+#define CS43130_FAB_ID		0x010003        /* Fab ID [RO] */
+#define CS43130_REV_ID		0x010004        /* Revision ID [RO] */
+#define CS43130_SUBREV_ID	0x010005        /* Subrevision ID */
+#define CS43130_SYS_CLK_CTL_1	0x010006	/* System Clocking Ctl 1 */
+#define CS43130_SP_SRATE	0x01000B        /* Serial Port Sample Rate */
+#define CS43130_SP_BITSIZE	0x01000C        /* Serial Port Bit Size */
+#define CS43130_PAD_INT_CFG	0x01000D	/* Pad Interface Config */
+#define CS43130_DXD1            0x010010        /* DXD1 */
+#define CS43130_DXD7            0x010025        /* DXD7 */
+#define CS43130_DXD19           0x010026        /* DXD19 */
+#define CS43130_DXD17           0x010027        /* DXD17 */
+#define CS43130_DXD18           0x010028        /* DXD18 */
+#define CS43130_DXD12           0x01002C        /* DXD12 */
+#define CS43130_DXD8            0x01002E        /* DXD8 */
+#define CS43130_PWDN_CTL	0x020000        /* Power Down Ctl */
+#define CS43130_DXD2            0x020019        /* DXD2 */
+#define CS43130_CRYSTAL_SET	0x020052	/* Crystal Setting */
+#define CS43130_PLL_SET_1	0x030001        /* PLL Setting 1 */
+#define CS43130_PLL_SET_2	0x030002        /* PLL Setting 2 */
+#define CS43130_PLL_SET_3	0x030003        /* PLL Setting 3 */
+#define CS43130_PLL_SET_4	0x030004        /* PLL Setting 4 */
+#define CS43130_PLL_SET_5	0x030005        /* PLL Setting 5 */
+#define CS43130_PLL_SET_6	0x030008        /* PLL Setting 6 */
+#define CS43130_PLL_SET_7	0x03000A        /* PLL Setting 7 */
+#define CS43130_PLL_SET_8	0x03001B        /* PLL Setting 8 */
+#define CS43130_PLL_SET_9	0x040002        /* PLL Setting 9 */
+#define CS43130_PLL_SET_10	0x040003        /* PLL Setting 10 */
+#define CS43130_CLKOUT_CTL	0x040004        /* CLKOUT Ctl */
+#define CS43130_ASP_NUM_1	0x040010        /* ASP Numerator 1 */
+#define CS43130_ASP_NUM_2	0x040011        /* ASP Numerator 2 */
+#define CS43130_ASP_DEN_1	0x040012	/* ASP Denominator 1 */
+#define CS43130_ASP_DEN_2	0x040013	/* ASP Denominator 2 */
+#define CS43130_ASP_LRCK_HI_TIME_1 0x040014	/* ASP LRCK High Time 1 */
+#define CS43130_ASP_LRCK_HI_TIME_2 0x040015	/* ASP LRCK High Time 2 */
+#define CS43130_ASP_LRCK_PERIOD_1  0x040016	/* ASP LRCK Period 1 */
+#define CS43130_ASP_LRCK_PERIOD_2  0x040017	/* ASP LRCK Period 2 */
+#define CS43130_ASP_CLOCK_CONF	0x040018	/* ASP Clock Config */
+#define CS43130_ASP_FRAME_CONF	0x040019	/* ASP Frame Config */
+#define CS43130_XSP_NUM_1	0x040020        /* XSP Numerator 1 */
+#define CS43130_XSP_NUM_2	0x040021        /* XSP Numerator 2 */
+#define CS43130_XSP_DEN_1	0x040022	/* XSP Denominator 1 */
+#define CS43130_XSP_DEN_2	0x040023	/* XSP Denominator 2 */
+#define CS43130_XSP_LRCK_HI_TIME_1 0x040024	/* XSP LRCK High Time 1 */
+#define CS43130_XSP_LRCK_HI_TIME_2 0x040025	/* XSP LRCK High Time 2 */
+#define CS43130_XSP_LRCK_PERIOD_1  0x040026	/* XSP LRCK Period 1 */
+#define CS43130_XSP_LRCK_PERIOD_2  0x040027	/* XSP LRCK Period 2 */
+#define CS43130_XSP_CLOCK_CONF	0x040028	/* XSP Clock Config */
+#define CS43130_XSP_FRAME_CONF	0x040029	/* XSP Frame Config */
+#define CS43130_ASP_CH_1_LOC	0x050000	/* ASP Chan 1 Location */
+#define CS43130_ASP_CH_2_LOC	0x050001	/* ASP Chan 2 Location */
+#define CS43130_ASP_CH_1_SZ_EN	0x05000A	/* ASP Chan 1 Size, Enable */
+#define CS43130_ASP_CH_2_SZ_EN	0x05000B	/* ASP Chan 2 Size, Enable */
+#define CS43130_XSP_CH_1_LOC	0x060000	/* XSP Chan 1 Location */
+#define CS43130_XSP_CH_2_LOC	0x060001	/* XSP Chan 2 Location */
+#define CS43130_XSP_CH_1_SZ_EN	0x06000A	/* XSP Chan 1 Size, Enable */
+#define CS43130_XSP_CH_2_SZ_EN	0x06000B	/* XSP Chan 2 Size, Enable */
+#define CS43130_DSD_VOL_B	0x070000        /* DSD Volume B */
+#define CS43130_DSD_VOL_A	0x070001        /* DSD Volume A */
+#define CS43130_DSD_PATH_CTL_1	0x070002	/* DSD Proc Path Sig Ctl 1 */
+#define CS43130_DSD_INT_CFG	0x070003	/* DSD Interface Config */
+#define CS43130_DSD_PATH_CTL_2	0x070004	/* DSD Proc Path Sig Ctl 2 */
+#define CS43130_DSD_PCM_MIX_CTL	0x070005	/* DSD and PCM Mixing Ctl */
+#define CS43130_DSD_PATH_CTL_3	0x070006	/* DSD Proc Path Sig Ctl 3 */
+#define CS43130_HP_OUT_CTL_1	0x080000	/* HP Output Ctl 1 */
+#define CS43130_DXD16		0x080024	/* DXD16 */
+#define CS43130_DXD13		0x080032	/* DXD13 */
+#define CS43130_PCM_FILT_OPT	0x090000	/* PCM Filter Option */
+#define CS43130_PCM_VOL_B	0x090001        /* PCM Volume B */
+#define CS43130_PCM_VOL_A	0x090002        /* PCM Volume A */
+#define CS43130_PCM_PATH_CTL_1	0x090003	/* PCM Path Signal Ctl 1 */
+#define CS43130_PCM_PATH_CTL_2	0x090004	/* PCM Path Signal Ctl 2 */
+#define CS43130_DXD6		0x090097	/* DXD6 */
+#define CS43130_CLASS_H_CTL	0x0B0000	/* Class H Ctl */
+#define CS43130_DXD15		0x0B0005	/* DXD15 */
+#define CS43130_DXD14		0x0B0006	/* DXD14 */
+#define CS43130_DXD3		0x0C0002	/* DXD3 */
+#define CS43130_DXD10		0x0C0003	/* DXD10 */
+#define CS43130_DXD11		0x0C0005	/* DXD11 */
+#define CS43130_DXD9		0x0C0006	/* DXD9 */
+#define CS43130_DXD4		0x0C0009	/* DXD4 */
+#define CS43130_DXD5		0x0C000E	/* DXD5 */
+#define CS43130_HP_DETECT	0x0D0000        /* HP Detect */
+#define CS43130_HP_STATUS	0x0D0001        /* HP Status [RO] */
+#define CS43130_HP_LOAD_1	0x0E0000        /* HP Load 1 */
+#define CS43130_HP_MEAS_LOAD_1	0x0E0003	/* HP Load Measurement 1 */
+#define CS43130_HP_MEAS_LOAD_2	0x0E0004	/* HP Load Measurement 2 */
+#define CS43130_HP_DC_STAT_1	0x0E000D	/* HP DC Load Status 0 [RO] */
+#define CS43130_HP_DC_STAT_2	0x0E000E	/* HP DC Load Status 1 [RO] */
+#define CS43130_HP_AC_STAT_1	0x0E0010	/* HP AC Load Status 0 [RO] */
+#define CS43130_HP_AC_STAT_2	0x0E0011	/* HP AC Load Status 1 [RO] */
+#define CS43130_HP_LOAD_STAT	0x0E001A	/* HP Load Status [RO] */
+#define CS43130_INT_STATUS_1	0x0F0000	/* Interrupt Status 1 */
+#define CS43130_INT_STATUS_2	0x0F0001	/* Interrupt Status 2 */
+#define CS43130_INT_STATUS_3	0x0F0002	/* Interrupt Status 3 */
+#define CS43130_INT_STATUS_4	0x0F0003	/* Interrupt Status 4 */
+#define CS43130_INT_STATUS_5	0x0F0004	/* Interrupt Status 5 */
+#define CS43130_INT_MASK_1	0x0F0010        /* Interrupt Mask 1 */
+#define CS43130_INT_MASK_2	0x0F0011	/* Interrupt Mask 2 */
+#define CS43130_INT_MASK_3	0x0F0012        /* Interrupt Mask 3 */
+#define CS43130_INT_MASK_4	0x0F0013        /* Interrupt Mask 4 */
+#define CS43130_INT_MASK_5	0x0F0014        /* Interrupt Mask 5 */
+
+#define CS43130_MCLK_SRC_SEL_MASK	0x03
+#define CS43130_MCLK_SRC_SEL_SHIFT	0
+#define CS43130_MCLK_INT_MASK		0x04
+#define CS43130_MCLK_INT_SHIFT		2
+#define CS43130_CH_BITSIZE_MASK		0x03
+#define CS43130_CH_EN_MASK		0x04
+#define CS43130_CH_EN_SHIFT		2
+#define CS43130_ASP_BITSIZE_MASK	0x03
+#define CS43130_XSP_BITSIZE_MASK	0x0C
+#define CS43130_XSP_BITSIZE_SHIFT	2
+#define CS43130_SP_BITSIZE_ASP_SHIFT	0
+#define CS43130_HP_DETECT_CTRL_SHIFT	6
+#define CS43130_HP_DETECT_CTRL_MASK     (0x03 << CS43130_HP_DETECT_CTRL_SHIFT)
+#define CS43130_HP_DETECT_INV_SHIFT	5
+#define CS43130_HP_DETECT_INV_MASK      (1 << CS43130_HP_DETECT_INV_SHIFT)
+
+/* CS43130_INT_MASK_1 */
+#define CS43130_HP_PLUG_INT_SHIFT       6
+#define CS43130_HP_PLUG_INT             (1 << CS43130_HP_PLUG_INT_SHIFT)
+#define CS43130_HP_UNPLUG_INT_SHIFT     5
+#define CS43130_HP_UNPLUG_INT           (1 << CS43130_HP_UNPLUG_INT_SHIFT)
+#define CS43130_XTAL_RDY_INT_SHIFT      4
+#define CS43130_XTAL_RDY_INT_MASK	0x10
+#define CS43130_XTAL_RDY_INT            (1 << CS43130_XTAL_RDY_INT_SHIFT)
+#define CS43130_XTAL_ERR_INT_SHIFT      3
+#define CS43130_XTAL_ERR_INT            (1 << CS43130_XTAL_ERR_INT_SHIFT)
+#define CS43130_PLL_RDY_INT_MASK	0x04
+#define CS43130_PLL_RDY_INT_SHIFT	2
+#define CS43130_PLL_RDY_INT		(1 << CS43130_PLL_RDY_INT_SHIFT)
+
+/* CS43130_INT_MASK_4 */
+#define CS43130_INT_MASK_ALL		0xFF
+#define CS43130_HPLOAD_NO_DC_INT_SHIFT	7
+#define CS43130_HPLOAD_NO_DC_INT	(1 << CS43130_HPLOAD_NO_DC_INT_SHIFT)
+#define CS43130_HPLOAD_UNPLUG_INT_SHIFT	6
+#define CS43130_HPLOAD_UNPLUG_INT	(1 << CS43130_HPLOAD_UNPLUG_INT_SHIFT)
+#define CS43130_HPLOAD_OOR_INT_SHIFT	4
+#define CS43130_HPLOAD_OOR_INT		(1 << CS43130_HPLOAD_OOR_INT_SHIFT)
+#define CS43130_HPLOAD_AC_INT_SHIFT	3
+#define CS43130_HPLOAD_AC_INT		(1 << CS43130_HPLOAD_AC_INT_SHIFT)
+#define CS43130_HPLOAD_DC_INT_SHIFT	2
+#define CS43130_HPLOAD_DC_INT		(1 << CS43130_HPLOAD_DC_INT_SHIFT)
+#define CS43130_HPLOAD_OFF_INT_SHIFT	1
+#define CS43130_HPLOAD_OFF_INT		(1 << CS43130_HPLOAD_OFF_INT_SHIFT)
+#define CS43130_HPLOAD_ON_INT		1
+
+/* CS43130_HP_LOAD_1 */
+#define CS43130_HPLOAD_EN_SHIFT		7
+#define CS43130_HPLOAD_EN		(1 << CS43130_HPLOAD_EN_SHIFT)
+#define CS43130_HPLOAD_CHN_SEL_SHIFT	4
+#define CS43130_HPLOAD_CHN_SEL		(1 << CS43130_HPLOAD_CHN_SEL_SHIFT)
+#define CS43130_HPLOAD_AC_START_SHIFT	1
+#define CS43130_HPLOAD_AC_START		(1 << CS43130_HPLOAD_AC_START_SHIFT)
+#define CS43130_HPLOAD_DC_START		1
+
+/* Reg CS43130_SP_BITSIZE */
+#define CS43130_SP_BIT_SIZE_8	0x03
+#define CS43130_SP_BIT_SIZE_16	0x02
+#define CS43130_SP_BIT_SIZE_24	0x01
+#define CS43130_SP_BIT_SIZE_32	0x00
+
+/* Reg CS43130_SP_CH_SZ_EN */
+#define CS43130_CH_BIT_SIZE_8	0x00
+#define CS43130_CH_BIT_SIZE_16	0x01
+#define CS43130_CH_BIT_SIZE_24	0x02
+#define CS43130_CH_BIT_SIZE_32	0x03
+
+/* PLL */
+#define CS43130_PLL_START_MASK	0x01
+#define CS43130_PLL_MODE_MASK	0x02
+#define CS43130_PLL_MODE_SHIFT	1
+
+#define CS43130_PLL_REF_PREDIV_MASK	0x3
+
+#define CS43130_SP_STP_MASK	0x10
+#define CS43130_SP_STP_SHIFT	4
+#define CS43130_SP_5050_MASK	0x08
+#define CS43130_SP_5050_SHIFT	3
+#define CS43130_SP_FSD_MASK	0x07
+
+#define CS43130_SP_MODE_MASK	0x10
+#define CS43130_SP_MODE_SHIFT	4
+#define CS43130_SP_SCPOL_OUT_MASK	0x08
+#define CS43130_SP_SCPOL_OUT_SHIFT	3
+#define CS43130_SP_SCPOL_IN_MASK	0x04
+#define CS43130_SP_SCPOL_IN_SHIFT	2
+#define CS43130_SP_LCPOL_OUT_MASK	0x02
+#define CS43130_SP_LCPOL_OUT_SHIFT	1
+#define CS43130_SP_LCPOL_IN_MASK	0x01
+#define CS43130_SP_LCPOL_IN_SHIFT	0
+
+/* Reg CS43130_PWDN_CTL */
+#define CS43130_PDN_XSP_MASK	0x80
+#define CS43130_PDN_XSP_SHIFT	7
+#define CS43130_PDN_ASP_MASK	0x40
+#define CS43130_PDN_ASP_SHIFT	6
+#define CS43130_PDN_DSPIF_MASK	0x20
+#define CS43130_PDN_DSDIF_SHIFT	5
+#define CS43130_PDN_HP_MASK	0x10
+#define CS43130_PDN_HP_SHIFT	4
+#define CS43130_PDN_XTAL_MASK	0x08
+#define CS43130_PDN_XTAL_SHIFT	3
+#define CS43130_PDN_PLL_MASK	0x04
+#define CS43130_PDN_PLL_SHIFT	2
+#define CS43130_PDN_CLKOUT_MASK	0x02
+#define CS43130_PDN_CLKOUT_SHIFT	1
+
+/* Reg CS43130_HP_OUT_CTL_1 */
+#define CS43130_HP_IN_EN_SHIFT		3
+#define CS43130_HP_IN_EN_MASK		0x08
+
+/* Reg CS43130_PAD_INT_CFG */
+#define CS43130_ASP_3ST_MASK		0x01
+#define CS43130_XSP_3ST_MASK		0x02
+
+/* Reg CS43130_PLL_SET_2 */
+#define CS43130_PLL_DIV_DATA_MASK	0x000000FF
+#define CS43130_PLL_DIV_FRAC_0_DATA_SHIFT	0
+
+/* Reg CS43130_PLL_SET_3 */
+#define CS43130_PLL_DIV_FRAC_1_DATA_SHIFT	8
+
+/* Reg CS43130_PLL_SET_4 */
+#define CS43130_PLL_DIV_FRAC_2_DATA_SHIFT	16
+
+/* Reg CS43130_SP_DEN_1 */
+#define CS43130_SP_M_LSB_DATA_MASK	0x00FF
+#define CS43130_SP_M_LSB_DATA_SHIFT	0
+
+/* Reg CS43130_SP_DEN_2 */
+#define CS43130_SP_M_MSB_DATA_MASK	0xFF00
+#define CS43130_SP_M_MSB_DATA_SHIFT	8
+
+/* Reg CS43130_SP_NUM_1 */
+#define CS43130_SP_N_LSB_DATA_MASK	0x00FF
+#define CS43130_SP_N_LSB_DATA_SHIFT	0
+
+/* Reg CS43130_SP_NUM_2 */
+#define CS43130_SP_N_MSB_DATA_MASK	0xFF00
+#define CS43130_SP_N_MSB_DATA_SHIFT	8
+
+/* Reg CS43130_SP_LRCK_HI_TIME_1 */
+#define	CS43130_SP_LCHI_DATA_MASK	0x00FF
+#define CS43130_SP_LCHI_LSB_DATA_SHIFT	0
+
+/* Reg CS43130_SP_LRCK_HI_TIME_2 */
+#define CS43130_SP_LCHI_MSB_DATA_SHIFT	8
+
+/* Reg CS43130_SP_LRCK_PERIOD_1 */
+#define CS43130_SP_LCPR_DATA_MASK	0x00FF
+#define CS43130_SP_LCPR_LSB_DATA_SHIFT	0
+
+/* Reg CS43130_SP_LRCK_PERIOD_2 */
+#define CS43130_SP_LCPR_MSB_DATA_SHIFT	8
+
+#define CS43130_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8  | \
+			SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | \
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+#define CS43130_DOP_FORMATS (SNDRV_PCM_FMTBIT_DSD_U16_LE | \
+			     SNDRV_PCM_FMTBIT_DSD_U16_BE | \
+			     SNDRV_PCM_FMTBIT_S24_LE)
+
+/* Reg CS43130_CRYSTAL_SET */
+#define CS43130_XTAL_IBIAS_MASK		0x07
+
+/* Reg CS43130_PATH_CTL_1 */
+#define CS43130_MUTE_MASK		0x03
+#define CS43130_MUTE_EN			0x03
+
+/* Reg CS43130_DSD_INT_CFG */
+#define CS43130_DSD_MASTER		0x04
+
+/* Reg CS43130_DSD_PATH_CTL_2 */
+#define CS43130_DSD_SRC_MASK		0x60
+#define CS43130_DSD_SRC_SHIFT		5
+#define CS43130_DSD_EN_SHIFT		4
+#define CS43130_DSD_SPEED_MASK		0x04
+#define CS43130_DSD_SPEED_SHIFT		2
+
+/* Reg CS43130_DSD_PCM_MIX_CTL	*/
+#define CS43130_MIX_PCM_PREP_SHIFT	1
+#define CS43130_MIX_PCM_PREP_MASK	0x02
+
+#define CS43130_MIX_PCM_DSD_SHIFT	0
+#define CS43130_MIX_PCM_DSD_MASK	0x01
+
+/* Reg CS43130_HP_MEAS_LOAD */
+#define CS43130_HP_MEAS_LOAD_MASK	0x000000FF
+#define CS43130_HP_MEAS_LOAD_1_SHIFT	0
+#define CS43130_HP_MEAS_LOAD_2_SHIFT	8
+
+#define CS43130_MCLK_22M		22579200
+#define CS43130_MCLK_24M		24576000
+
+#define CS43130_LINEOUT_LOAD		5000
+#define CS43130_JACK_LINEOUT		(SND_JACK_MECHANICAL | SND_JACK_LINEOUT)
+#define CS43130_JACK_HEADPHONE		(SND_JACK_MECHANICAL | \
+					 SND_JACK_HEADPHONE)
+#define CS43130_JACK_MASK		(SND_JACK_MECHANICAL | \
+					 SND_JACK_LINEOUT | \
+					 SND_JACK_HEADPHONE)
+
+enum cs43130_dsd_src {
+	CS43130_DSD_SRC_DSD = 0,
+	CS43130_DSD_SRC_ASP = 2,
+	CS43130_DSD_SRC_XSP = 3,
+};
+
+enum cs43130_asp_rate {
+	CS43130_ASP_SPRATE_32K = 0,
+	CS43130_ASP_SPRATE_44_1K,
+	CS43130_ASP_SPRATE_48K,
+	CS43130_ASP_SPRATE_88_2K,
+	CS43130_ASP_SPRATE_96K,
+	CS43130_ASP_SPRATE_176_4K,
+	CS43130_ASP_SPRATE_192K,
+	CS43130_ASP_SPRATE_352_8K,
+	CS43130_ASP_SPRATE_384K,
+};
+
+enum cs43130_mclk_src_sel {
+	CS43130_MCLK_SRC_EXT = 0,
+	CS43130_MCLK_SRC_PLL,
+	CS43130_MCLK_SRC_RCO
+};
+
+enum cs43130_mclk_int_freq {
+	CS43130_MCLK_24P5 = 0,
+	CS43130_MCLK_22P5,
+};
+
+enum cs43130_xtal_ibias {
+	CS43130_XTAL_UNUSED = -1,
+	CS43130_XTAL_IBIAS_15UA = 2,
+	CS43130_XTAL_IBIAS_12_5UA = 4,
+	CS43130_XTAL_IBIAS_7_5UA = 6,
+};
+
+enum cs43130_dai_id {
+	CS43130_ASP_PCM_DAI = 0,
+	CS43130_ASP_DOP_DAI,
+	CS43130_XSP_DOP_DAI,
+	CS43130_XSP_DSD_DAI,
+	CS43130_DAI_ID_MAX,
+};
+
+struct cs43130_clk_gen {
+	unsigned int	mclk_int;
+	int		fs;
+	u16		den;
+	u16		num;
+};
+
+/* frm_size = 16 */
+static const struct cs43130_clk_gen cs43130_16_clk_gen[] = {
+	{22579200,	32000,		441,		10,},
+	{22579200,	44100,		32,		1,},
+	{22579200,	48000,		147,		5,},
+	{22579200,	88200,		16,		1,},
+	{22579200,	96000,		147,		10,},
+	{22579200,	176400,		8,		1,},
+	{22579200,	192000,		147,		20,},
+	{22579200,	352800,		4,		1,},
+	{22579200,	384000,		147,		40,},
+	{24576000,	32000,		48,		1,},
+	{24576000,	44100,		5120,		147,},
+	{24576000,	48000,		32,		1,},
+	{24576000,	88200,		2560,		147,},
+	{24576000,	96000,		16,		1,},
+	{24576000,	176400,		1280,		147,},
+	{24576000,	192000,		8,		1,},
+	{24576000,	352800,		640,		147,},
+	{24576000,	384000,		4,		1,},
+};
+
+/* frm_size = 32 */
+static const struct cs43130_clk_gen cs43130_32_clk_gen[] = {
+	{22579200,	32000,		441,		20,},
+	{22579200,	44100,		16,		1,},
+	{22579200,	48000,		147,		10,},
+	{22579200,	88200,		8,		1,},
+	{22579200,	96000,		147,		20,},
+	{22579200,	176400,		4,		1,},
+	{22579200,	192000,		147,		40,},
+	{22579200,	352800,		2,		1,},
+	{22579200,	384000,		147,		80,},
+	{24576000,	32000,		24,		1,},
+	{24576000,	44100,		2560,		147,},
+	{24576000,	48000,		16,		1,},
+	{24576000,	88200,		1280,		147,},
+	{24576000,	96000,		8,		1,},
+	{24576000,	176400,		640,		147,},
+	{24576000,	192000,		4,		1,},
+	{24576000,	352800,		320,		147,},
+	{24576000,	384000,		2,		1,},
+};
+
+/* frm_size = 48 */
+static const struct cs43130_clk_gen cs43130_48_clk_gen[] = {
+	{22579200,	32000,		147,		100,},
+	{22579200,	44100,		32,		3,},
+	{22579200,	48000,		49,		5,},
+	{22579200,	88200,		16,		3,},
+	{22579200,	96000,		49,		10,},
+	{22579200,	176400,		8,		3,},
+	{22579200,	192000,		49,		20,},
+	{22579200,	352800,		4,		3,},
+	{22579200,	384000,		49,		40,},
+	{24576000,	32000,		16,		1,},
+	{24576000,	44100,		5120,		441,},
+	{24576000,	48000,		32,		3,},
+	{24576000,	88200,		2560,		441,},
+	{24576000,	96000,		16,		3,},
+	{24576000,	176400,		1280,		441,},
+	{24576000,	192000,		8,		3,},
+	{24576000,	352800,		640,		441,},
+	{24576000,	384000,		4,		3,},
+};
+
+/* frm_size = 64 */
+static const struct cs43130_clk_gen cs43130_64_clk_gen[] = {
+	{22579200,	32000,		441,		40,},
+	{22579200,	44100,		8,		1,},
+	{22579200,	48000,		147,		20,},
+	{22579200,	88200,		4,		1,},
+	{22579200,	96000,		147,		40,},
+	{22579200,	176400,		2,		1,},
+	{22579200,	192000,		147,		80,},
+	{22579200,	352800,		1,		1,},
+	{24576000,	32000,		12,		1,},
+	{24576000,	44100,		1280,		147,},
+	{24576000,	48000,		8,		1,},
+	{24576000,	88200,		640,		147,},
+	{24576000,	96000,		4,		1,},
+	{24576000,	176400,		320,		147,},
+	{24576000,	192000,		2,		1,},
+	{24576000,	352800,		160,		147,},
+	{24576000,	384000,		1,		1,},
+};
+
+struct cs43130_bitwidth_map {
+	unsigned int bitwidth;
+	u8 sp_bit;
+	u8 ch_bit;
+};
+
+struct cs43130_rate_map {
+	int fs;
+	int val;
+};
+
+#define HP_LEFT			0
+#define HP_RIGHT		1
+#define CS43130_AC_FREQ		10
+#define CS43130_DC_THRESHOLD	2
+
+#define CS43130_NUM_SUPPLIES	5
+static const char *const cs43130_supply_names[CS43130_NUM_SUPPLIES] = {
+	"VA",
+	"VP",
+	"VCP",
+	"VD",
+	"VL",
+};
+
+#define CS43130_NUM_INT		5       /* number of interrupt status reg */
+
+struct cs43130_dai {
+	unsigned int			sclk;
+	unsigned int			dai_format;
+	unsigned int			dai_mode;
+};
+
+struct	cs43130_private {
+	struct snd_soc_codec		*codec;
+	struct regmap			*regmap;
+	struct regulator_bulk_data	supplies[CS43130_NUM_SUPPLIES];
+	struct gpio_desc		*reset_gpio;
+	unsigned int			dev_id; /* codec device ID */
+	int				xtal_ibias;
+
+	/* shared by both DAIs */
+	struct mutex			clk_mutex;
+	int				clk_req;
+	bool				pll_bypass;
+	struct completion		xtal_rdy;
+	struct completion		pll_rdy;
+	unsigned int			mclk;
+	unsigned int			mclk_int;
+	int				mclk_int_src;
+
+	/* DAI specific */
+	struct cs43130_dai		dais[CS43130_DAI_ID_MAX];
+
+	/* HP load specific */
+	bool				dc_meas;
+	bool				ac_meas;
+	bool				hpload_done;
+	struct completion		hpload_evt;
+	unsigned int			hpload_stat;
+	u16				hpload_dc[2];
+	u16				dc_threshold[CS43130_DC_THRESHOLD];
+	u16				ac_freq[CS43130_AC_FREQ];
+	u16				hpload_ac[CS43130_AC_FREQ][2];
+	struct workqueue_struct		*wq;
+	struct work_struct		work;
+	struct snd_soc_jack		jack;
+};
+
+#endif	/* __CS43130_H__ */
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index 231ca935cdf3..0a749c79ef57 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -255,7 +255,7 @@ static struct snd_soc_dai_driver cs4349_dai = {
 	.symmetric_rates = 1,
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_cs4349 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs4349 = {
 	.component_driver = {
 		.controls		= cs4349_snd_controls,
 		.num_controls		= ARRAY_SIZE(cs4349_snd_controls),
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index 47e6fddef92b..e09fc8f037f1 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -1183,7 +1183,7 @@ static struct regmap *cs47l24_get_regmap(struct device *dev)
 	return priv->core.arizona->regmap;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
 	.probe = cs47l24_codec_probe,
 	.remove = cs47l24_codec_remove,
 	.get_regmap = cs47l24_get_regmap,
@@ -1203,7 +1203,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
 	},
 };
 
-static struct snd_compr_ops cs47l24_compr_ops = {
+static const struct snd_compr_ops cs47l24_compr_ops = {
 	.open = cs47l24_open,
 	.free = wm_adsp_compr_free,
 	.set_params = wm_adsp_compr_set_params,
@@ -1213,7 +1213,7 @@ static struct snd_compr_ops cs47l24_compr_ops = {
 	.copy = wm_adsp_compr_copy,
 };
 
-static struct snd_soc_platform_driver cs47l24_compr_platform = {
+static const struct snd_soc_platform_driver cs47l24_compr_platform = {
 	.compr_ops = &cs47l24_compr_ops,
 };
 
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index 06933a5d0a75..c7edf2df5e36 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -842,8 +842,7 @@ static int cs53l30_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 {
 	struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec);
 
-	if (priv->mute_gpio)
-		gpiod_set_value_cansleep(priv->mute_gpio, mute);
+	gpiod_set_value_cansleep(priv->mute_gpio, mute);
 
 	return 0;
 }
@@ -892,7 +891,7 @@ static int cs53l30_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver cs53l30_driver = {
+static const struct snd_soc_codec_driver cs53l30_driver = {
 	.probe = cs53l30_codec_probe,
 	.set_bias_level = cs53l30_set_bias_level,
 	.idle_bias_off = true,
@@ -960,8 +959,7 @@ static int cs53l30_i2c_probe(struct i2c_client *client,
 		goto error;
 	}
 
-	if (cs53l30->reset_gpio)
-		gpiod_set_value_cansleep(cs53l30->reset_gpio, 1);
+	gpiod_set_value_cansleep(cs53l30->reset_gpio, 1);
 
 	i2c_set_clientdata(client, cs53l30);
 
@@ -1056,8 +1054,7 @@ static int cs53l30_i2c_remove(struct i2c_client *client)
 	snd_soc_unregister_codec(&client->dev);
 
 	/* Hold down reset */
-	if (cs53l30->reset_gpio)
-		gpiod_set_value_cansleep(cs53l30->reset_gpio, 0);
+	gpiod_set_value_cansleep(cs53l30->reset_gpio, 0);
 
 	regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies),
 			       cs53l30->supplies);
@@ -1073,8 +1070,7 @@ static int cs53l30_runtime_suspend(struct device *dev)
 	regcache_cache_only(cs53l30->regmap, true);
 
 	/* Hold down reset */
-	if (cs53l30->reset_gpio)
-		gpiod_set_value_cansleep(cs53l30->reset_gpio, 0);
+	gpiod_set_value_cansleep(cs53l30->reset_gpio, 0);
 
 	regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies),
 			       cs53l30->supplies);
@@ -1094,8 +1090,7 @@ static int cs53l30_runtime_resume(struct device *dev)
 		return ret;
 	}
 
-	if (cs53l30->reset_gpio)
-		gpiod_set_value_cansleep(cs53l30->reset_gpio, 1);
+	gpiod_set_value_cansleep(cs53l30->reset_gpio, 1);
 
 	regcache_cache_only(cs53l30->regmap, false);
 	ret = regcache_sync(cs53l30->regmap);
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index 2c12471e42a6..46b1fbb66eba 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -398,7 +398,7 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec)
 
 static const u8 cx20442_reg;
 
-static struct snd_soc_codec_driver cx20442_codec_dev = {
+static const struct snd_soc_codec_driver cx20442_codec_dev = {
 	.probe = 	cx20442_codec_probe,
 	.remove = 	cx20442_codec_remove,
 	.set_bias_level = cx20442_set_bias_level,
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 17053dfc94cf..1af443ccbc51 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -1164,7 +1164,7 @@ static int da7210_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
+static const struct snd_soc_codec_driver soc_codec_dev_da7210 = {
 	.probe			= da7210_probe,
 
 	.component_driver = {
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index c3e11897f8ae..cc0b2d2eaf15 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -1787,7 +1787,7 @@ static int da7213_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_da7213 = {
+static const struct snd_soc_codec_driver soc_codec_dev_da7213 = {
 	.probe			= da7213_probe,
 	.set_bias_level		= da7213_set_bias_level,
 
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index 6e1940eb0653..b2d42ec1dcd9 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -3035,7 +3035,7 @@ static int da7218_resume(struct snd_soc_codec *codec)
 #define da7218_resume NULL
 #endif
 
-static struct snd_soc_codec_driver soc_codec_dev_da7218 = {
+static const struct snd_soc_codec_driver soc_codec_dev_da7218 = {
 	.probe			= da7218_probe,
 	.remove			= da7218_remove,
 	.suspend		= da7218_suspend,
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index f71d72c22bfc..6f088536df32 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -1891,7 +1891,7 @@ static int da7219_resume(struct snd_soc_codec *codec)
 #define da7219_resume NULL
 #endif
 
-static struct snd_soc_codec_driver soc_codec_dev_da7219 = {
+static const struct snd_soc_codec_driver soc_codec_dev_da7219 = {
 	.probe			= da7219_probe,
 	.remove			= da7219_remove,
 	.suspend		= da7219_suspend,
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index c1cc1c1c28f2..83db4d23c90b 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -1499,7 +1499,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_da732x = {
+static const struct snd_soc_codec_driver soc_codec_dev_da732x = {
 	.set_bias_level		= da732x_set_bias_level,
 	.component_driver = {
 		.controls		= da732x_snd_controls,
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index 4efb5f897a0c..bd7faaee5802 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -1451,7 +1451,7 @@ static int da9055_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_da9055 = {
+static const struct snd_soc_codec_driver soc_codec_dev_da9055 = {
 	.probe			= da9055_probe,
 	.set_bias_level		= da9055_set_bias_level,
 
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index c82b9dc41e9a..b88a1ee66f80 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -19,6 +19,8 @@
  *
  */
 
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -27,6 +29,34 @@
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
+static int dmic_daiops_trigger(struct snd_pcm_substream *substream,
+		int cmd, struct snd_soc_dai *dai)
+{
+	struct gpio_desc *dmic_en = snd_soc_dai_get_drvdata(dai);
+
+	if (!dmic_en)
+		return 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		gpiod_set_value(dmic_en, 1);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		gpiod_set_value(dmic_en, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops dmic_dai_ops = {
+	.trigger	= dmic_daiops_trigger,
+};
+
 static struct snd_soc_dai_driver dmic_dai = {
 	.name = "dmic-hifi",
 	.capture = {
@@ -38,8 +68,23 @@ static struct snd_soc_dai_driver dmic_dai = {
 			| SNDRV_PCM_FMTBIT_S24_LE
 			| SNDRV_PCM_FMTBIT_S16_LE,
 	},
+	.ops    = &dmic_dai_ops,
 };
 
+static int dmic_codec_probe(struct snd_soc_codec *codec)
+{
+	struct gpio_desc *dmic_en;
+
+	dmic_en = devm_gpiod_get_optional(codec->dev,
+					"dmicen", GPIOD_OUT_LOW);
+	if (IS_ERR(dmic_en))
+		return PTR_ERR(dmic_en);
+
+	snd_soc_codec_set_drvdata(codec, dmic_en);
+
+	return 0;
+}
+
 static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_OUT("DMIC AIF", "Capture", 0,
 			     SND_SOC_NOPM, 0, 0),
@@ -50,7 +95,8 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"DMIC AIF", NULL, "DMic"},
 };
 
-static struct snd_soc_codec_driver soc_dmic = {
+static const struct snd_soc_codec_driver soc_dmic = {
+	.probe = dmic_codec_probe,
 	.component_driver = {
 		.dapm_widgets		= dmic_dapm_widgets,
 		.num_dapm_widgets	= ARRAY_SIZE(dmic_dapm_widgets),
@@ -73,9 +119,15 @@ static int dmic_dev_remove(struct platform_device *pdev)
 
 MODULE_ALIAS("platform:dmic-codec");
 
+static const struct of_device_id dmic_dev_match[] = {
+	{.compatible = "dmic-codec"},
+	{}
+};
+
 static struct platform_driver dmic_driver = {
 	.driver = {
 		.name = "dmic-codec",
+		.of_match_table = dmic_dev_match,
 	},
 	.probe = dmic_dev_probe,
 	.remove = dmic_dev_remove,
diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c
index 25ede825d349..3869025754d8 100644
--- a/sound/soc/codecs/es7134.c
+++ b/sound/soc/codecs/es7134.c
@@ -69,7 +69,7 @@ static const struct snd_soc_dapm_route es7134_dapm_routes[] = {
 	{ "AOUTR", NULL, "DAC" },
 };
 
-static struct snd_soc_codec_driver es7134_codec_driver = {
+static const struct snd_soc_codec_driver es7134_codec_driver = {
 	.component_driver = {
 		.dapm_widgets		= es7134_dapm_widgets,
 		.num_dapm_widgets	= ARRAY_SIZE(es7134_dapm_widgets),
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index ecc02449c569..da2d353af5ba 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -502,7 +502,7 @@ static int es8316_mute(struct snd_soc_dai *dai, int mute)
 #define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops es8316_ops = {
+static const struct snd_soc_dai_ops es8316_ops = {
 	.startup = es8316_pcm_startup,
 	.hw_params = es8316_pcm_hw_params,
 	.set_fmt = es8316_set_dai_fmt,
@@ -554,7 +554,7 @@ static int es8316_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_es8316 = {
+static const struct snd_soc_codec_driver soc_codec_dev_es8316 = {
 	.probe		= es8316_probe,
 	.idle_bias_off	= true,
 
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index ed7cc42d1ee2..bcdb8914ec16 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -830,7 +830,7 @@ const struct regmap_config es8328_regmap_config = {
 };
 EXPORT_SYMBOL_GPL(es8328_regmap_config);
 
-static struct snd_soc_codec_driver es8328_codec_driver = {
+static const struct snd_soc_codec_driver es8328_codec_driver = {
 	.probe		  = es8328_codec_probe,
 	.suspend	  = es8328_suspend,
 	.resume		  = es8328_resume,
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index bc2e74ff3b2d..e824d47cc22b 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -121,6 +121,10 @@ struct hdac_hdmi_dai_port_map {
 	struct hdac_hdmi_cvt *cvt;
 };
 
+struct hdac_hdmi_drv_data {
+	unsigned int vendor_nid;
+};
+
 struct hdac_hdmi_priv {
 	struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS];
 	struct list_head pin_list;
@@ -131,6 +135,7 @@ struct hdac_hdmi_priv {
 	int num_ports;
 	struct mutex pin_mutex;
 	struct hdac_chmap chmap;
+	struct hdac_hdmi_drv_data *drv_data;
 };
 
 static struct hdac_hdmi_pcm *
@@ -1321,6 +1326,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
 }
 
 #define INTEL_VENDOR_NID 0x08
+#define INTEL_GLK_VENDOR_NID 0x0b
 #define INTEL_GET_VENDOR_VERB 0xf81
 #define INTEL_SET_VENDOR_VERB 0x781
 #define INTEL_EN_DP12			0x02 /* enable DP 1.2 features */
@@ -1329,14 +1335,17 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
 static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
 {
 	unsigned int vendor_param;
+	struct hdac_ext_device *edev = to_ehdac_device(hdac);
+	struct hdac_hdmi_priv *hdmi = edev->private_data;
+	unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
 
-	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+	vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
 				INTEL_GET_VENDOR_VERB, 0);
 	if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
 		return;
 
 	vendor_param |= INTEL_EN_ALL_PIN_CVTS;
-	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+	vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
 				INTEL_SET_VENDOR_VERB, vendor_param);
 	if (vendor_param == -1)
 		return;
@@ -1345,22 +1354,25 @@ static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
 static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac)
 {
 	unsigned int vendor_param;
+	struct hdac_ext_device *edev = to_ehdac_device(hdac);
+	struct hdac_hdmi_priv *hdmi = edev->private_data;
+	unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
 
-	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+	vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
 				INTEL_GET_VENDOR_VERB, 0);
 	if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
 		return;
 
 	/* enable DP1.2 mode */
 	vendor_param |= INTEL_EN_DP12;
-	vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+	vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
 				INTEL_SET_VENDOR_VERB, vendor_param);
 	if (vendor_param == -1)
 		return;
 
 }
 
-static struct snd_soc_dai_ops hdmi_dai_ops = {
+static const struct snd_soc_dai_ops hdmi_dai_ops = {
 	.startup = hdac_hdmi_pcm_open,
 	.shutdown = hdac_hdmi_pcm_close,
 	.hw_params = hdac_hdmi_set_hw_params,
@@ -1858,7 +1870,7 @@ static void hdmi_codec_complete(struct device *dev)
 #define hdmi_codec_complete NULL
 #endif
 
-static struct snd_soc_codec_driver hdmi_hda_codec = {
+static const struct snd_soc_codec_driver hdmi_hda_codec = {
 	.probe		= hdmi_codec_probe,
 	.remove		= hdmi_codec_remove,
 	.idle_bias_off	= true,
@@ -1927,6 +1939,14 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
 	return port->eld.info.spk_alloc;
 }
 
+static struct hdac_hdmi_drv_data intel_glk_drv_data  = {
+	.vendor_nid = INTEL_GLK_VENDOR_NID,
+};
+
+static struct hdac_hdmi_drv_data intel_drv_data  = {
+	.vendor_nid = INTEL_VENDOR_NID,
+};
+
 static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
 {
 	struct hdac_device *codec = &edev->hdac;
@@ -1935,6 +1955,8 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
 	struct hdac_ext_link *hlink = NULL;
 	int num_dais = 0;
 	int ret = 0;
+	struct hdac_driver *hdrv = drv_to_hdac_driver(codec->dev.driver);
+	const struct hda_device_id *hdac_id = hdac_get_device_id(codec, hdrv);
 
 	/* hold the ref while we probe */
 	hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
@@ -1956,6 +1978,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
 	hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
 	hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
 
+	if (hdac_id->driver_data)
+		hdmi_priv->drv_data =
+			(struct hdac_hdmi_drv_data *)hdac_id->driver_data;
+	else
+		hdmi_priv->drv_data = &intel_drv_data;
+
 	dev_set_drvdata(&codec->dev, edev);
 
 	INIT_LIST_HEAD(&hdmi_priv->pin_list);
@@ -2127,7 +2155,8 @@ static const struct hda_device_id hdmi_list[] = {
 	HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
 	HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
 	HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0),
-	HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", 0),
+	HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI",
+						   &intel_glk_drv_data),
 	{}
 };
 
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 22ed0dc88f0a..3abf82563408 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -67,14 +67,14 @@ struct hdmi_codec_cea_spk_alloc {
 };
 
 /* Channel maps  stereo HDMI */
-const struct snd_pcm_chmap_elem hdmi_codec_stereo_chmaps[] = {
+static const struct snd_pcm_chmap_elem hdmi_codec_stereo_chmaps[] = {
 	{ .channels = 2,
 	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
 	{ }
 };
 
 /* Channel maps for multi-channel playbacks, up to 8 n_ch */
-const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = {
+static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = {
 	{ .channels = 2, /* CA_ID 0x00 */
 	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
 	{ .channels = 4, /* CA_ID 0x01 */
@@ -326,7 +326,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
 static unsigned long hdmi_codec_spk_mask_from_alloc(int spk_alloc)
 {
 	int i;
-	const unsigned long hdmi_codec_eld_spk_alloc_bits[] = {
+	static const unsigned long hdmi_codec_eld_spk_alloc_bits[] = {
 		[0] = FL | FR, [1] = LFE, [2] = FC, [3] = RL | RR,
 		[4] = RC, [5] = FLC | FRC, [6] = RLC | RRC,
 	};
@@ -340,7 +340,7 @@ static unsigned long hdmi_codec_spk_mask_from_alloc(int spk_alloc)
 	return spk_mask;
 }
 
-void hdmi_codec_eld_chmap(struct hdmi_codec_priv *hcp)
+static void hdmi_codec_eld_chmap(struct hdmi_codec_priv *hcp)
 {
 	u8 spk_alloc;
 	unsigned long spk_mask;
@@ -399,18 +399,6 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
-
-static const struct snd_kcontrol_new hdmi_controls[] = {
-	{
-		.access = SNDRV_CTL_ELEM_ACCESS_READ |
-			  SNDRV_CTL_ELEM_ACCESS_VOLATILE,
-		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
-		.name = "ELD",
-		.info = hdmi_eld_ctl_info,
-		.get = hdmi_eld_ctl_get,
-	},
-};
-
 static int hdmi_codec_new_stream(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
@@ -668,6 +656,16 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
 {
 	struct snd_soc_dai_driver *drv = dai->driver;
 	struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+	struct snd_kcontrol *kctl;
+	struct snd_kcontrol_new hdmi_eld_ctl = {
+		.access	= SNDRV_CTL_ELEM_ACCESS_READ |
+			  SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.iface	= SNDRV_CTL_ELEM_IFACE_PCM,
+		.name	= "ELD",
+		.info	= hdmi_eld_ctl_info,
+		.get	= hdmi_eld_ctl_get,
+		.device	= rtd->pcm->device,
+	};
 	int ret;
 
 	dev_dbg(dai->dev, "%s()\n", __func__);
@@ -686,14 +684,19 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
 	hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps;
 	hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
 
-	return 0;
+	/* add ELD ctl with the device number corresponding to the PCM stream */
+	kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component);
+	if (!kctl)
+		return -ENOMEM;
+
+	return snd_ctl_add(rtd->card->snd_card, kctl);
 }
 
-static struct snd_soc_dai_driver hdmi_i2s_dai = {
+static const struct snd_soc_dai_driver hdmi_i2s_dai = {
 	.name = "i2s-hifi",
 	.id = DAI_ID_I2S,
 	.playback = {
-		.stream_name = "Playback",
+		.stream_name = "I2S Playback",
 		.channels_min = 2,
 		.channels_max = 8,
 		.rates = HDMI_RATES,
@@ -708,7 +711,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
 	.name = "spdif-hifi",
 	.id = DAI_ID_SPDIF,
 	.playback = {
-		.stream_name = "Playback",
+		.stream_name = "SPDIF Playback",
 		.channels_min = 2,
 		.channels_max = 2,
 		.rates = HDMI_RATES,
@@ -730,10 +733,8 @@ static int hdmi_of_xlate_dai_id(struct snd_soc_component *component,
 	return ret;
 }
 
-static struct snd_soc_codec_driver hdmi_codec = {
+static const struct snd_soc_codec_driver hdmi_codec = {
 	.component_driver = {
-		.controls		= hdmi_controls,
-		.num_controls		= ARRAY_SIZE(hdmi_controls),
 		.dapm_widgets		= hdmi_widgets,
 		.num_dapm_widgets	= ARRAY_SIZE(hdmi_widgets),
 		.dapm_routes		= hdmi_routes,
diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c
index dd850b93938d..651206273f36 100644
--- a/sound/soc/codecs/ics43432.c
+++ b/sound/soc/codecs/ics43432.c
@@ -37,7 +37,7 @@ static struct snd_soc_dai_driver ics43432_dai = {
 	},
 };
 
-static struct snd_soc_codec_driver ics43432_codec_driver = {
+static const struct snd_soc_codec_driver ics43432_codec_driver = {
 };
 
 static int ics43432_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
index b918ba5c8ce5..6b59b6f08298 100644
--- a/sound/soc/codecs/inno_rk3036.c
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -310,7 +310,7 @@ static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream,
 			   SNDRV_PCM_FMTBIT_S24_LE  | \
 			   SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops rk3036_codec_dai_ops = {
+static const struct snd_soc_dai_ops rk3036_codec_dai_ops = {
 	.set_fmt	= rk3036_codec_dai_set_fmt,
 	.hw_params	= rk3036_codec_dai_hw_params,
 };
@@ -376,7 +376,7 @@ static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static struct snd_soc_codec_driver rk3036_codec_driver = {
+static const struct snd_soc_codec_driver rk3036_codec_driver = {
 	.probe			= rk3036_codec_probe,
 	.remove			= rk3036_codec_remove,
 	.set_bias_level		= rk3036_codec_set_bias_level,
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index a4b0eded984a..5ca99280ae00 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -1087,7 +1087,7 @@ static struct snd_soc_dai_driver isabelle_dai[] = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_isabelle = {
+static const struct snd_soc_codec_driver soc_codec_dev_isabelle = {
 	.set_bias_level = isabelle_set_bias_level,
 	.component_driver = {
 		.controls		= isabelle_snd_controls,
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 0290fab383da..6324ccdc8a5c 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -293,7 +293,7 @@ static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
+static const struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
 	.probe = jz4740_codec_dev_probe,
 	.set_bias_level = jz4740_codec_set_bias_level,
 	.suspend_bias_off = true,
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
index 558de1053f73..1e964079642a 100644
--- a/sound/soc/codecs/lm4857.c
+++ b/sound/soc/codecs/lm4857.c
@@ -100,7 +100,7 @@ static const struct snd_soc_dapm_route lm4857_routes[] = {
 	{ "EP", "Earpiece", "Mode" },
 };
 
-static struct snd_soc_component_driver lm4857_component_driver = {
+static const struct snd_soc_component_driver lm4857_component_driver = {
 	.controls = lm4857_controls,
 	.num_controls = ARRAY_SIZE(lm4857_controls),
 	.dapm_widgets = lm4857_dapm_widgets,
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index 8d413c2677cc..41e09d1287b8 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1389,7 +1389,7 @@ static struct snd_soc_dai_driver lm49453_dai[] = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
+static const struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
 	.set_bias_level = lm49453_set_bias_level,
 	.component_driver = {
 		.controls		= lm49453_snd_controls,
diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c
index 5b82e26cd5d1..7017c0389e73 100644
--- a/sound/soc/codecs/max9768.c
+++ b/sound/soc/codecs/max9768.c
@@ -151,7 +151,7 @@ static int max9768_probe(struct snd_soc_component *component)
 	return 0;
 }
 
-static struct snd_soc_component_driver max9768_component_driver = {
+static const struct snd_soc_component_driver max9768_component_driver = {
 	.probe = max9768_probe,
 	.controls = max9768_volume,
 	.num_controls = ARRAY_SIZE(max9768_volume),
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 72f77455582e..f0bb830874e5 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -1698,7 +1698,7 @@ static int max98088_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
+static const struct snd_soc_codec_driver soc_codec_dev_max98088 = {
 	.probe   = max98088_probe,
 	.remove  = max98088_remove,
 	.set_bias_level = max98088_set_bias_level,
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 66828480d484..13bcfb1ef9b4 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2499,7 +2499,7 @@ static void max98090_seq_notifier(struct snd_soc_dapm_context *dapm,
 	}
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_max98090 = {
+static const struct snd_soc_codec_driver soc_codec_dev_max98090 = {
 	.probe   = max98090_probe,
 	.remove  = max98090_remove,
 	.seq_notifier = max98090_seq_notifier,
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 6f8a757876ed..5ead87d2ab1d 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -2102,7 +2102,7 @@ static int max98095_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_max98095 = {
+static const struct snd_soc_codec_driver soc_codec_dev_max98095 = {
 	.probe   = max98095_probe,
 	.remove  = max98095_remove,
 	.suspend = max98095_suspend,
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index 6a6b68a4cb52..426ed2dae6ca 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -72,7 +72,7 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver max98357a_codec_driver = {
+static const struct snd_soc_codec_driver max98357a_codec_driver = {
 	.probe			= max98357a_codec_probe,
 	.component_driver = {
 		.dapm_widgets		= max98357a_dapm_widgets,
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
index 781be9ba8dba..7bc2a17c1e94 100644
--- a/sound/soc/codecs/max98371.c
+++ b/sound/soc/codecs/max98371.c
@@ -349,12 +349,14 @@ static struct snd_soc_dai_driver max98371_dai[] = {
 };
 
 static const struct snd_soc_codec_driver max98371_codec = {
-	.controls = max98371_snd_controls,
-	.num_controls = ARRAY_SIZE(max98371_snd_controls),
-	.dapm_routes = max98371_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
-	.dapm_widgets = max98371_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
+	.component_driver = {
+		.controls = max98371_snd_controls,
+		.num_controls = ARRAY_SIZE(max98371_snd_controls),
+		.dapm_routes = max98371_audio_map,
+		.num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
+		.dapm_widgets = max98371_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
+	},
 };
 
 static const struct regmap_config max98371_regmap = {
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index 0610840733d1..a3dfc918c278 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -301,7 +301,7 @@ static int max9850_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_max9850 = {
+static const struct snd_soc_codec_driver soc_codec_dev_max9850 = {
 	.probe =	max9850_probe,
 	.set_bias_level = max9850_set_bias_level,
 	.suspend_bias_off = true,
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index 499bdbfd0a2d..a2dc6a47f466 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -534,7 +534,7 @@ static int max9860_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static struct snd_soc_codec_driver max9860_codec_driver = {
+static const struct snd_soc_codec_driver max9860_codec_driver = {
 	.set_bias_level = max9860_set_bias_level,
 	.idle_bias_off = true,
 
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index 2a40a69a7513..2f60924fe919 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -350,7 +350,7 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static struct snd_soc_dai_ops max9867_dai_ops = {
+static const struct snd_soc_dai_ops max9867_dai_ops = {
 	.set_fmt = max9867_dai_set_fmt,
 	.set_sysclk	= max9867_set_dai_sysclk,
 	.prepare	= max9867_prepare,
@@ -413,7 +413,7 @@ static int max9867_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver max9867_codec = {
+static const struct snd_soc_codec_driver max9867_codec = {
 	.probe = max9867_probe,
 	.component_driver = {
 		.controls		= max9867_snd_controls,
diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c
index 1eff7e0b092e..03d07bf4d942 100644
--- a/sound/soc/codecs/max98926.c
+++ b/sound/soc/codecs/max98926.c
@@ -213,8 +213,8 @@ static bool max98926_readable_register(struct device *dev, unsigned int reg)
 	}
 };
 
-DECLARE_TLV_DB_SCALE(max98926_spk_tlv, -600, 100, 0);
-DECLARE_TLV_DB_RANGE(max98926_current_tlv,
+static DECLARE_TLV_DB_SCALE(max98926_spk_tlv, -600, 100, 0);
+static DECLARE_TLV_DB_RANGE(max98926_current_tlv,
 	0, 11, TLV_DB_SCALE_ITEM(20, 20, 0),
 	12, 15, TLV_DB_SCALE_ITEM(320, 40, 0),
 );
@@ -459,7 +459,7 @@ static int max98926_dai_hw_params(struct snd_pcm_substream *substream,
 #define MAX98926_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
 		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops max98926_dai_ops = {
+static const struct snd_soc_dai_ops max98926_dai_ops = {
 	.set_fmt = max98926_dai_set_fmt,
 	.hw_params = max98926_dai_hw_params,
 };
@@ -496,7 +496,7 @@ static int max98926_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_max98926 = {
+static const struct snd_soc_codec_driver soc_codec_dev_max98926 = {
 	.probe	= max98926_probe,
 	.component_driver = {
 		.controls		= max98926_snd_controls,
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index b5ee29499e16..d9dbbe72f8ad 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -44,9 +44,9 @@ static struct reg_default max98927_reg[] = {
 	{MAX98927_R0011_CLK_MON,  0x00},
 	{MAX98927_R0012_WDOG_CTRL,  0x00},
 	{MAX98927_R0013_WDOG_RST,  0x00},
-	{MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH,  0x00},
-	{MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH,  0x00},
-	{MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS,  0x00},
+	{MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH,  0x75},
+	{MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH,  0x8c},
+	{MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS,  0x08},
 	{MAX98927_R0017_PIN_CFG,  0x55},
 	{MAX98927_R0018_PCM_RX_EN_A,  0x00},
 	{MAX98927_R0019_PCM_RX_EN_B,  0x00},
@@ -82,14 +82,14 @@ static struct reg_default max98927_reg[] = {
 	{MAX98927_R003A_AMP_EN,  0x00},
 	{MAX98927_R003B_SPK_SRC_SEL,  0x00},
 	{MAX98927_R003C_SPK_GAIN,  0x00},
-	{MAX98927_R003D_SSM_CFG,  0x01},
+	{MAX98927_R003D_SSM_CFG,  0x04},
 	{MAX98927_R003E_MEAS_EN,  0x00},
 	{MAX98927_R003F_MEAS_DSP_CFG,  0x04},
 	{MAX98927_R0040_BOOST_CTRL0,  0x00},
 	{MAX98927_R0041_BOOST_CTRL3,  0x00},
 	{MAX98927_R0042_BOOST_CTRL1,  0x00},
 	{MAX98927_R0043_MEAS_ADC_CFG,  0x00},
-	{MAX98927_R0044_MEAS_ADC_BASE_MSB,  0x00},
+	{MAX98927_R0044_MEAS_ADC_BASE_MSB,  0x01},
 	{MAX98927_R0045_MEAS_ADC_BASE_LSB,  0x00},
 	{MAX98927_R0046_ADC_CH0_DIVIDE,  0x00},
 	{MAX98927_R0047_ADC_CH1_DIVIDE,  0x00},
@@ -159,7 +159,7 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		mode = MAX98927_PCM_MASTER_MODE_MASTER;
 		break;
 	default:
-		dev_err(codec->dev, "DAI clock mode unsupported");
+		dev_err(codec->dev, "DAI clock mode unsupported\n");
 		return -EINVAL;
 	}
 
@@ -175,7 +175,7 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		invert = MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE;
 		break;
 	default:
-		dev_err(codec->dev, "DAI invert mode unsupported");
+		dev_err(codec->dev, "DAI invert mode unsupported\n");
 		return -EINVAL;
 	}
 
@@ -311,7 +311,7 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
 		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
 		break;
 	default:
-		dev_err(codec->dev, "format unsupported %d",
+		dev_err(codec->dev, "format unsupported %d\n",
 			params_format(params));
 		goto err;
 	}
@@ -418,11 +418,6 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w,
 		regmap_update_bits(max98927->regmap,
 			MAX98927_R003A_AMP_EN,
 			MAX98927_AMP_EN_MASK, 1);
-		/* enable VMON and IMON */
-		regmap_update_bits(max98927->regmap,
-			MAX98927_R003E_MEAS_EN,
-			MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN,
-			MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN);
 		regmap_update_bits(max98927->regmap,
 			MAX98927_R00FF_GLOBAL_SHDN,
 			MAX98927_GLOBAL_EN_MASK, 1);
@@ -434,10 +429,6 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w,
 		regmap_update_bits(max98927->regmap,
 			MAX98927_R003A_AMP_EN,
 			MAX98927_AMP_EN_MASK, 0);
-		/* disable VMON and IMON */
-		regmap_update_bits(max98927->regmap,
-			MAX98927_R003E_MEAS_EN,
-			MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN, 0);
 		break;
 	default:
 		return 0;
@@ -456,14 +447,24 @@ static const struct soc_enum dai_sel_enum =
 static const struct snd_kcontrol_new max98927_dai_controls =
 	SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
 
+static const struct snd_kcontrol_new max98927_vi_control =
+	SOC_DAPM_SINGLE("Switch", MAX98927_R003F_MEAS_DSP_CFG, 2, 1, 0);
+
 static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = {
-	SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN,
 		0, 0, max98927_dac_event,
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
 		&max98927_dai_controls),
 	SND_SOC_DAPM_OUTPUT("BE_OUT"),
+	SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture",  0,
+		MAX98927_R003E_MEAS_EN, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture",  0,
+		MAX98927_R003E_MEAS_EN, 1, 0),
+	SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
+		&max98927_vi_control),
+	SND_SOC_DAPM_SIGGEN("VMON"),
+	SND_SOC_DAPM_SIGGEN("IMON"),
 };
 
 static DECLARE_TLV_DB_SCALE(max98927_spk_tlv, 300, 300, 0);
@@ -495,6 +496,13 @@ static bool max98927_volatile_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
 	case MAX98927_R0001_INT_RAW1 ... MAX98927_R0009_INT_FLAG3:
+	case MAX98927_R004C_MEAS_ADC_CH0_READ:
+	case MAX98927_R004D_MEAS_ADC_CH1_READ:
+	case MAX98927_R004E_MEAS_ADC_CH2_READ:
+	case MAX98927_R0051_BROWNOUT_STATUS:
+	case MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ:
+	case MAX98927_R01FF_REV_ID:
+	case MAX98927_R0100_SOFT_RESET:
 		return true;
 	default:
 		return false;
@@ -543,11 +551,16 @@ static const struct snd_kcontrol_new max98927_snd_controls[] = {
 };
 
 static const struct snd_soc_dapm_route max98927_audio_map[] = {
-	{"Amp Enable", NULL, "DAI_OUT"},
+	/* Plabyack */
 	{"DAI Sel Mux", "Left", "Amp Enable"},
 	{"DAI Sel Mux", "Right", "Amp Enable"},
 	{"DAI Sel Mux", "LeftRight", "Amp Enable"},
 	{"BE_OUT", NULL, "DAI Sel Mux"},
+	/* Capture */
+	{ "VI Sense", "Switch", "VMON" },
+	{ "VI Sense", "Switch", "IMON" },
+	{ "Voltage Sense", NULL, "VI Sense" },
+	{ "Current Sense", NULL, "VI Sense" },
 };
 
 static struct snd_soc_dai_driver max98927_dai[] = {
@@ -577,7 +590,6 @@ static int max98927_probe(struct snd_soc_codec *codec)
 
 	max98927->codec = codec;
 	codec->control_data = max98927->regmap;
-	codec->cache_bypass = 1;
 
 	/* Software Reset */
 	regmap_write(max98927->regmap,
@@ -694,6 +706,31 @@ static int max98927_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int max98927_suspend(struct device *dev)
+{
+	struct max98927_priv *max98927 = dev_get_drvdata(dev);
+
+	regcache_cache_only(max98927->regmap, true);
+	regcache_mark_dirty(max98927->regmap);
+	return 0;
+}
+static int max98927_resume(struct device *dev)
+{
+	struct max98927_priv *max98927 = dev_get_drvdata(dev);
+
+	regmap_write(max98927->regmap,
+		MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
+	regcache_cache_only(max98927->regmap, false);
+	regcache_sync(max98927->regmap);
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops max98927_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(max98927_suspend, max98927_resume)
+};
+
 static const struct snd_soc_codec_driver soc_codec_dev_max98927 = {
 	.probe = max98927_probe,
 	.component_driver = {
@@ -721,14 +758,14 @@ static void max98927_slot_config(struct i2c_client *i2c,
 	struct max98927_priv *max98927)
 {
 	int value;
+	struct device *dev = &i2c->dev;
 
-	if (!of_property_read_u32(i2c->dev.of_node,
-		"vmon-slot-no", &value))
+	if (!device_property_read_u32(dev, "vmon-slot-no", &value))
 		max98927->v_l_slot = value & 0xF;
 	else
 		max98927->v_l_slot = 0;
-	if (!of_property_read_u32(i2c->dev.of_node,
-		"imon-slot-no", &value))
+
+	if (!device_property_read_u32(dev, "imon-slot-no", &value))
 		max98927->i_l_slot = value & 0xF;
 	else
 		max98927->i_l_slot = 1;
@@ -827,7 +864,7 @@ static struct i2c_driver max98927_i2c_driver = {
 		.name = "max98927",
 		.of_match_table = of_match_ptr(max98927_of_match),
 		.acpi_match_table = ACPI_PTR(max98927_acpi_match),
-		.pm = NULL,
+		.pm = &max98927_pm,
 	},
 	.probe  = max98927_i2c_probe,
 	.remove = max98927_i2c_remove,
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 90562703dcfd..4fd8d1dc4eef 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -733,7 +733,7 @@ static struct regmap *mc13783_get_regmap(struct device *dev)
 	return dev_get_regmap(dev->parent, NULL);
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
+static const struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
 	.probe		= mc13783_probe,
 	.remove		= mc13783_remove,
 	.get_regmap	= mc13783_get_regmap,
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index 69e5e18880c5..5cc960d8211e 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -537,7 +537,7 @@ static int ml26124_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
 	.probe =	ml26124_probe,
 	.set_bias_level = ml26124_set_bias_level,
 	.suspend_bias_off = true,
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
index a78802920c3c..549c269acc7d 100644
--- a/sound/soc/codecs/msm8916-wcd-analog.c
+++ b/sound/soc/codecs/msm8916-wcd-analog.c
@@ -12,9 +12,16 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
+#include <sound/jack.h>
 
 #define CDC_D_REVISION1			(0xf000)
 #define CDC_D_PERPH_SUBTYPE		(0xf005)
+#define CDC_D_INT_EN_SET		(0x015)
+#define CDC_D_INT_EN_CLR		(0x016)
+#define MBHC_SWITCH_INT			BIT(7)
+#define MBHC_MIC_ELECTRICAL_INS_REM_DET	BIT(6)
+#define MBHC_BUTTON_PRESS_DET		BIT(5)
+#define MBHC_BUTTON_RELEASE_DET		BIT(4)
 #define CDC_D_CDC_RST_CTL		(0xf046)
 #define RST_CTL_DIG_SW_RST_N_MASK	BIT(7)
 #define RST_CTL_DIG_SW_RST_N_RESET	0
@@ -36,7 +43,9 @@
 #define CDC_D_CDC_DIG_CLK_CTL		(0xf04A)
 #define DIG_CLK_CTL_RXD1_CLK_EN		BIT(0)
 #define DIG_CLK_CTL_RXD2_CLK_EN		BIT(1)
-#define DIG_CLK_CTL_RXD3_CLK_EN		BIT(3)
+#define DIG_CLK_CTL_RXD3_CLK_EN		BIT(2)
+#define DIG_CLK_CTL_D_MBHC_CLK_EN_MASK	BIT(3)
+#define DIG_CLK_CTL_D_MBHC_CLK_EN	BIT(3)
 #define DIG_CLK_CTL_TXD_CLK_EN		BIT(4)
 #define DIG_CLK_CTL_NCP_CLK_EN_MASK	BIT(6)
 #define DIG_CLK_CTL_NCP_CLK_EN		BIT(6)
@@ -93,8 +102,12 @@
 #define MICB_1_EN_TX3_GND_SEL_TX_GND	0
 
 #define CDC_A_MICB_1_VAL		(0xf141)
+#define MICB_MIN_VAL 1600
+#define MICB_STEP_SIZE 50
+#define MICB_VOLTAGE_REGVAL(v)		((v - MICB_MIN_VAL)/MICB_STEP_SIZE)
 #define MICB_1_VAL_MICB_OUT_VAL_MASK	GENMASK(7, 3)
 #define MICB_1_VAL_MICB_OUT_VAL_V2P70V	((0x16)  << 3)
+#define MICB_1_VAL_MICB_OUT_VAL_V1P80V	((0x4)  << 3)
 #define CDC_A_MICB_1_CTL		(0xf142)
 
 #define MICB_1_CTL_CFILT_REF_SEL_MASK		BIT(1)
@@ -128,8 +141,51 @@
 #define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND	0
 
 #define CDC_A_MICB_2_EN			(0xf144)
+#define CDC_A_MICB_2_EN_ENABLE		BIT(7)
+#define CDC_A_MICB_2_PULL_DOWN_EN_MASK	BIT(5)
+#define CDC_A_MICB_2_PULL_DOWN_EN	BIT(5)
 #define CDC_A_TX_1_2_ATEST_CTL_2	(0xf145)
 #define CDC_A_MASTER_BIAS_CTL		(0xf146)
+#define CDC_A_MBHC_DET_CTL_1		(0xf147)
+#define CDC_A_MBHC_DET_CTL_L_DET_EN			BIT(7)
+#define CDC_A_MBHC_DET_CTL_GND_DET_EN			BIT(6)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION	BIT(5)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_REMOVAL	(0)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK		BIT(5)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT		(5)
+#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO		BIT(4)
+#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MANUAL		BIT(3)
+#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MASK		GENMASK(4, 3)
+#define CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN			BIT(2)
+#define CDC_A_MBHC_DET_CTL_2		(0xf150)
+#define CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0	(BIT(7) | BIT(6))
+#define CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD	BIT(5)
+#define CDC_A_PLUG_TYPE_MASK				GENMASK(4, 3)
+#define CDC_A_HPHL_PLUG_TYPE_NO				BIT(4)
+#define CDC_A_GND_PLUG_TYPE_NO				BIT(3)
+#define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN_MASK	BIT(0)
+#define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN		BIT(0)
+#define CDC_A_MBHC_FSM_CTL		(0xf151)
+#define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN			BIT(7)
+#define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK		BIT(7)
+#define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA	(0x3 << 4)
+#define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK		GENMASK(6, 4)
+#define CDC_A_MBHC_DBNC_TIMER		(0xf152)
+#define CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS		BIT(3)
+#define CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS	(0x9 << 4)
+#define CDC_A_MBHC_BTN0_ZDET_CTL_0	(0xf153)
+#define CDC_A_MBHC_BTN1_ZDET_CTL_1	(0xf154)
+#define CDC_A_MBHC_BTN2_ZDET_CTL_2	(0xf155)
+#define CDC_A_MBHC_BTN3_CTL		(0xf156)
+#define CDC_A_MBHC_BTN4_CTL		(0xf157)
+#define CDC_A_MBHC_BTN_VREF_FINE_SHIFT	(2)
+#define CDC_A_MBHC_BTN_VREF_FINE_MASK	GENMASK(4, 2)
+#define CDC_A_MBHC_BTN_VREF_COARSE_MASK	GENMASK(7, 5)
+#define CDC_A_MBHC_BTN_VREF_COARSE_SHIFT (5)
+#define CDC_A_MBHC_BTN_VREF_MASK	(CDC_A_MBHC_BTN_VREF_COARSE_MASK | \
+					CDC_A_MBHC_BTN_VREF_FINE_MASK)
+#define CDC_A_MBHC_RESULT_1		(0xf158)
+#define CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK	GENMASK(4, 0)
 #define CDC_A_TX_1_EN			(0xf160)
 #define CDC_A_TX_2_EN			(0xf161)
 #define CDC_A_TX_1_2_TEST_CTL_1		(0xf162)
@@ -213,18 +269,37 @@
 #define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
 				    SNDRV_PCM_FMTBIT_S24_LE)
 
+static int btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+	       SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4;
+static int hs_jack_mask = SND_JACK_HEADPHONE | SND_JACK_HEADSET;
+
 static const char * const supply_names[] = {
 	"vdd-cdc-io",
 	"vdd-cdc-tx-rx-cx",
 };
 
+#define MBHC_MAX_BUTTONS	(5)
+
 struct pm8916_wcd_analog_priv {
 	u16 pmic_rev;
 	u16 codec_version;
+	bool	mbhc_btn_enabled;
+	/* special event to detect accessory type */
+	bool	mbhc_btn0_pressed;
+	bool	detect_accessory_type;
 	struct clk *mclk;
+	struct snd_soc_codec *codec;
 	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+	struct snd_soc_jack *jack;
+	bool hphl_jack_type_normally_open;
+	bool gnd_jack_type_normally_open;
+	/* Voltage threshold when internal current source of 100uA is used */
+	u32 vref_btn_cs[MBHC_MAX_BUTTONS];
+	/* Voltage threshold when microphone bias is ON */
+	u32 vref_btn_micb[MBHC_MAX_BUTTONS];
 	unsigned int micbias1_cap_mode;
 	unsigned int micbias2_cap_mode;
+	unsigned int micbias_mv;
 };
 
 static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
@@ -265,18 +340,25 @@ static const struct snd_kcontrol_new pm8916_wcd_analog_snd_controls[] = {
 
 static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec)
 {
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
 	snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
 			    MICB_1_CTL_EXT_PRECHARG_EN_MASK |
 			    MICB_1_CTL_INT_PRECHARG_BYP_MASK,
 			    MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL
 			    | MICB_1_CTL_EXT_PRECHARG_EN_ENABLE);
 
-	snd_soc_write(codec, CDC_A_MICB_1_VAL, MICB_1_VAL_MICB_OUT_VAL_V2P70V);
-	/*
-	 * Special headset needs MICBIAS as 2.7V so wait for
-	 * 50 msec for the MICBIAS to reach 2.7 volts.
-	 */
-	msleep(50);
+	if (wcd->micbias_mv) {
+		snd_soc_write(codec, CDC_A_MICB_1_VAL,
+			      MICB_VOLTAGE_REGVAL(wcd->micbias_mv));
+		/*
+		 * Special headset needs MICBIAS as 2.7V so wait for
+		 * 50 msec for the MICBIAS to reach 2.7 volts.
+		 */
+		if (wcd->micbias_mv >= 2700)
+			msleep(50);
+	}
+
 	snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
 			    MICB_1_CTL_EXT_PRECHARG_EN_MASK |
 			    MICB_1_CTL_INT_PRECHARG_BYP_MASK, 0);
@@ -361,6 +443,97 @@ static int pm8916_wcd_analog_enable_micbias_int1(struct
 						     wcd->micbias1_cap_mode);
 }
 
+static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
+{
+	struct snd_soc_codec *codec = wcd->codec;
+	u32 plug_type = 0;
+	u32 int_en_mask;
+
+	snd_soc_write(codec, CDC_A_MBHC_DET_CTL_1,
+		      CDC_A_MBHC_DET_CTL_L_DET_EN |
+		      CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION |
+		      CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO |
+		      CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN);
+
+	if (wcd->hphl_jack_type_normally_open)
+		plug_type |= CDC_A_HPHL_PLUG_TYPE_NO;
+
+	if (wcd->gnd_jack_type_normally_open)
+		plug_type |= CDC_A_GND_PLUG_TYPE_NO;
+
+	snd_soc_write(codec, CDC_A_MBHC_DET_CTL_2,
+		      CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 |
+		      CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD |
+		      plug_type |
+		      CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN);
+
+
+	snd_soc_write(codec, CDC_A_MBHC_DBNC_TIMER,
+		      CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS |
+		      CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS);
+
+	/* enable MBHC clock */
+	snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+			    DIG_CLK_CTL_D_MBHC_CLK_EN_MASK,
+			    DIG_CLK_CTL_D_MBHC_CLK_EN);
+
+	int_en_mask = MBHC_SWITCH_INT;
+	if (wcd->mbhc_btn_enabled)
+		int_en_mask |= MBHC_BUTTON_PRESS_DET | MBHC_BUTTON_RELEASE_DET;
+
+	snd_soc_update_bits(codec, CDC_D_INT_EN_CLR, int_en_mask, 0);
+	snd_soc_update_bits(codec, CDC_D_INT_EN_SET, int_en_mask, int_en_mask);
+	wcd->mbhc_btn0_pressed = false;
+	wcd->detect_accessory_type = true;
+}
+
+static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
+				      bool micbias2_enabled)
+{
+	struct snd_soc_codec *codec = priv->codec;
+	u32 coarse, fine, reg_val, reg_addr;
+	int *vrefs, i;
+
+	if (!micbias2_enabled) { /* use internal 100uA Current source */
+		/* Enable internal 2.2k Internal Rbias Resistor */
+		snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+				    MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
+				    MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
+		/* Remove pull down on MIC BIAS2 */
+		snd_soc_update_bits(codec, CDC_A_MICB_2_EN,
+				   CDC_A_MICB_2_PULL_DOWN_EN_MASK,
+				   0);
+		/* enable 100uA internal current source */
+		snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL,
+				    CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK,
+				    CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA);
+	}
+	snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL,
+			CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK,
+			CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN);
+
+	if (micbias2_enabled)
+		vrefs = &priv->vref_btn_micb[0];
+	else
+		vrefs = &priv->vref_btn_cs[0];
+
+	/* program vref ranges for all the buttons */
+	reg_addr = CDC_A_MBHC_BTN0_ZDET_CTL_0;
+	for (i = 0; i <  MBHC_MAX_BUTTONS; i++) {
+		/* split mv in to coarse parts of 100mv & fine parts of 12mv */
+		coarse = (vrefs[i] / 100);
+		fine = ((vrefs[i] % 100) / 12);
+		reg_val = (coarse << CDC_A_MBHC_BTN_VREF_COARSE_SHIFT) |
+			 (fine << CDC_A_MBHC_BTN_VREF_FINE_SHIFT);
+		snd_soc_update_bits(codec, reg_addr,
+			       CDC_A_MBHC_BTN_VREF_MASK,
+			       reg_val);
+		reg_addr++;
+	}
+
+	return 0;
+}
+
 static int pm8916_wcd_analog_enable_micbias_int2(struct
 						  snd_soc_dapm_widget
 						  *w, struct snd_kcontrol
@@ -369,6 +542,15 @@ static int pm8916_wcd_analog_enable_micbias_int2(struct
 	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
 
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		pm8916_mbhc_configure_bias(wcd, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		pm8916_mbhc_configure_bias(wcd, false);
+		break;
+	}
+
 	return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg,
 						     wcd->micbias2_cap_mode);
 }
@@ -536,6 +718,14 @@ static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec)
 		snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg,
 			      wcd_reg_defaults_2_0[reg].def);
 
+	priv->codec = codec;
+
+	snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL,
+			    RST_CTL_DIG_SW_RST_N_MASK,
+			    RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
+
+	pm8916_wcd_setup_mbhc(priv);
+
 	return 0;
 }
 
@@ -543,6 +733,9 @@ static int pm8916_wcd_analog_remove(struct snd_soc_codec *codec)
 {
 	struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev);
 
+	snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL,
+			    RST_CTL_DIG_SW_RST_N_MASK, 0);
+
 	return regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
 				      priv->supplies);
 }
@@ -731,32 +924,128 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0),
 };
 
+static int pm8916_wcd_analog_set_jack(struct snd_soc_codec *codec,
+				      struct snd_soc_jack *jack,
+				      void *data)
+{
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
+	wcd->jack = jack;
+
+	return 0;
+}
+
 static struct regmap *pm8916_get_regmap(struct device *dev)
 {
 	return dev_get_regmap(dev->parent, NULL);
 }
 
-static int pm8916_wcd_analog_startup(struct snd_pcm_substream *substream,
-				      struct snd_soc_dai *dai)
+static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg)
 {
-	snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL,
-			    RST_CTL_DIG_SW_RST_N_MASK,
-			    RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
+	struct pm8916_wcd_analog_priv *priv = arg;
 
-	return 0;
+	if (priv->detect_accessory_type) {
+		struct snd_soc_codec *codec = priv->codec;
+		u32 val = snd_soc_read(codec, CDC_A_MBHC_RESULT_1);
+
+		/* check if its BTN0 thats released */
+		if ((val != -1) && !(val & CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK))
+			priv->mbhc_btn0_pressed = false;
+
+	} else {
+		snd_soc_jack_report(priv->jack, 0, btn_mask);
+	}
+
+	return IRQ_HANDLED;
 }
 
-static void pm8916_wcd_analog_shutdown(struct snd_pcm_substream *substream,
-					 struct snd_soc_dai *dai)
+static irqreturn_t mbhc_btn_press_irq_handler(int irq, void *arg)
 {
-	snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL,
-			    RST_CTL_DIG_SW_RST_N_MASK, 0);
+	struct pm8916_wcd_analog_priv *priv = arg;
+	struct snd_soc_codec *codec = priv->codec;
+	u32 btn_result;
+
+	btn_result = snd_soc_read(codec, CDC_A_MBHC_RESULT_1) &
+				  CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK;
+
+	switch (btn_result) {
+	case 0xf:
+		snd_soc_jack_report(priv->jack, SND_JACK_BTN_4, btn_mask);
+		break;
+	case 0x7:
+		snd_soc_jack_report(priv->jack, SND_JACK_BTN_3, btn_mask);
+		break;
+	case 0x3:
+		snd_soc_jack_report(priv->jack, SND_JACK_BTN_2, btn_mask);
+		break;
+	case 0x1:
+		snd_soc_jack_report(priv->jack, SND_JACK_BTN_1, btn_mask);
+		break;
+	case 0x0:
+		/* handle BTN_0 specially for type detection */
+		if (priv->detect_accessory_type)
+			priv->mbhc_btn0_pressed = true;
+		else
+			snd_soc_jack_report(priv->jack,
+					    SND_JACK_BTN_0, btn_mask);
+		break;
+	default:
+		dev_err(codec->dev,
+			"Unexpected button press result (%x)", btn_result);
+		break;
+	}
+
+	return IRQ_HANDLED;
 }
 
-static struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = {
-	.startup = pm8916_wcd_analog_startup,
-	.shutdown = pm8916_wcd_analog_shutdown,
-};
+static irqreturn_t pm8916_mbhc_switch_irq_handler(int irq, void *arg)
+{
+	struct pm8916_wcd_analog_priv *priv = arg;
+	struct snd_soc_codec *codec = priv->codec;
+	bool ins = false;
+
+	if (snd_soc_read(codec, CDC_A_MBHC_DET_CTL_1) &
+				CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK)
+		ins = true;
+
+	/* Set the detection type appropriately */
+	snd_soc_update_bits(codec, CDC_A_MBHC_DET_CTL_1,
+			    CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK,
+			    (!ins << CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT));
+
+
+	if (ins) { /* hs insertion */
+		bool micbias_enabled = false;
+
+		if (snd_soc_read(codec, CDC_A_MICB_2_EN) &
+				CDC_A_MICB_2_EN_ENABLE)
+			micbias_enabled = true;
+
+		pm8916_mbhc_configure_bias(priv, micbias_enabled);
+
+		/*
+		 * if only a btn0 press event is receive just before
+		 * insert event then its a 3 pole headphone else if
+		 * both press and release event received then its
+		 * a headset.
+		 */
+		if (priv->mbhc_btn0_pressed)
+			snd_soc_jack_report(priv->jack,
+					    SND_JACK_HEADPHONE, hs_jack_mask);
+		else
+			snd_soc_jack_report(priv->jack,
+					    SND_JACK_HEADSET, hs_jack_mask);
+
+		priv->detect_accessory_type = false;
+
+	} else { /* removal */
+		snd_soc_jack_report(priv->jack, 0, hs_jack_mask);
+		priv->detect_accessory_type = true;
+		priv->mbhc_btn0_pressed = false;
+	}
+
+	return IRQ_HANDLED;
+}
 
 static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
 	[0] = {
@@ -769,7 +1058,6 @@ static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
 			    .channels_min = 1,
 			    .channels_max = 3,
 			    },
-	       .ops = &pm8916_wcd_analog_dai_ops,
 	       },
 	[1] = {
 	       .name = "pm8916_wcd_analog_pdm_tx",
@@ -781,13 +1069,13 @@ static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
 			   .channels_min = 1,
 			   .channels_max = 4,
 			   },
-	       .ops = &pm8916_wcd_analog_dai_ops,
 	       },
 };
 
-static struct snd_soc_codec_driver pm8916_wcd_analog = {
+static const struct snd_soc_codec_driver pm8916_wcd_analog = {
 	.probe = pm8916_wcd_analog_probe,
 	.remove = pm8916_wcd_analog_remove,
+	.set_jack = pm8916_wcd_analog_set_jack,
 	.get_regmap = pm8916_get_regmap,
 	.component_driver = {
 		.controls = pm8916_wcd_analog_snd_controls,
@@ -802,6 +1090,7 @@ static struct snd_soc_codec_driver pm8916_wcd_analog = {
 static int pm8916_wcd_analog_parse_dt(struct device *dev,
 				       struct pm8916_wcd_analog_priv *priv)
 {
+	int rval;
 
 	if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap"))
 		priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP;
@@ -813,6 +1102,42 @@ static int pm8916_wcd_analog_parse_dt(struct device *dev,
 	else
 		priv->micbias2_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP;
 
+	of_property_read_u32(dev->of_node, "qcom,micbias-lvl",
+			     &priv->micbias_mv);
+
+	if (of_property_read_bool(dev->of_node,
+				  "qcom,hphl-jack-type-normally-open"))
+		priv->hphl_jack_type_normally_open = true;
+	else
+		priv->hphl_jack_type_normally_open = false;
+
+	if (of_property_read_bool(dev->of_node,
+				  "qcom,gnd-jack-type-normally-open"))
+		priv->gnd_jack_type_normally_open = true;
+	else
+		priv->gnd_jack_type_normally_open = false;
+
+	priv->mbhc_btn_enabled = true;
+	rval = of_property_read_u32_array(dev->of_node,
+					  "qcom,mbhc-vthreshold-low",
+					  &priv->vref_btn_cs[0],
+					  MBHC_MAX_BUTTONS);
+	if (rval < 0) {
+		priv->mbhc_btn_enabled = false;
+	} else {
+		rval = of_property_read_u32_array(dev->of_node,
+						  "qcom,mbhc-vthreshold-high",
+						  &priv->vref_btn_micb[0],
+						  MBHC_MAX_BUTTONS);
+		if (rval < 0)
+			priv->mbhc_btn_enabled = false;
+	}
+
+	if (!priv->mbhc_btn_enabled)
+		dev_err(dev,
+			"DT property missing, MBHC btn detection disabled\n");
+
+
 	return 0;
 }
 
@@ -820,7 +1145,7 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
 {
 	struct pm8916_wcd_analog_priv *priv;
 	struct device *dev = &pdev->dev;
-	int ret, i;
+	int ret, i, irq;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -852,6 +1177,48 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	irq = platform_get_irq_byname(pdev, "mbhc_switch_int");
+	if (irq < 0) {
+		dev_err(dev, "failed to get mbhc switch irq\n");
+		return irq;
+	}
+
+	ret = devm_request_irq(dev, irq, pm8916_mbhc_switch_irq_handler,
+			       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+			       IRQF_ONESHOT,
+			       "mbhc switch irq", priv);
+	if (ret)
+		dev_err(dev, "cannot request mbhc switch irq\n");
+
+	if (priv->mbhc_btn_enabled) {
+		irq = platform_get_irq_byname(pdev, "mbhc_but_press_det");
+		if (irq < 0) {
+			dev_err(dev, "failed to get button press irq\n");
+			return irq;
+		}
+
+		ret = devm_request_irq(dev, irq, mbhc_btn_press_irq_handler,
+				       IRQF_TRIGGER_RISING |
+				       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				       "mbhc btn press irq", priv);
+		if (ret)
+			dev_err(dev, "cannot request mbhc button press irq\n");
+
+		irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det");
+		if (irq < 0) {
+			dev_err(dev, "failed to get button release irq\n");
+			return irq;
+		}
+
+		ret = devm_request_irq(dev, irq, mbhc_btn_release_irq_handler,
+				       IRQF_TRIGGER_RISING |
+				       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				       "mbhc btn release irq", priv);
+		if (ret)
+			dev_err(dev, "cannot request mbhc button release irq\n");
+
+	}
+
 	dev_set_drvdata(dev, priv);
 
 	return snd_soc_register_codec(dev, &pm8916_wcd_analog,
diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c
index f690442af8c9..66df8f810f0d 100644
--- a/sound/soc/codecs/msm8916-wcd-digital.c
+++ b/sound/soc/codecs/msm8916-wcd-digital.c
@@ -218,6 +218,8 @@ static const char *const rx_mix1_text[] = {
 static const char *const dec_mux_text[] = {
 	"ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2"
 };
+
+static const char *const cic_mux_text[] = { "AMIC", "DMIC" };
 static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" };
 static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
 
@@ -256,11 +258,21 @@ static const struct soc_enum dec1_mux_enum = SOC_ENUM_SINGLE(
 static const struct soc_enum dec2_mux_enum = SOC_ENUM_SINGLE(
 				LPASS_CDC_CONN_TX_B1_CTL, 3, 6, dec_mux_text);
 
+/* CIC */
+static const struct soc_enum cic1_mux_enum = SOC_ENUM_SINGLE(
+				LPASS_CDC_TX1_MUX_CTL, 0, 2, cic_mux_text);
+static const struct soc_enum cic2_mux_enum = SOC_ENUM_SINGLE(
+				LPASS_CDC_TX2_MUX_CTL, 0, 2, cic_mux_text);
+
 /* RDAC2 MUX */
 static const struct snd_kcontrol_new dec1_mux = SOC_DAPM_ENUM(
 				"DEC1 MUX Mux", dec1_mux_enum);
 static const struct snd_kcontrol_new dec2_mux = SOC_DAPM_ENUM(
 				"DEC2 MUX Mux",	dec2_mux_enum);
+static const struct snd_kcontrol_new cic1_mux = SOC_DAPM_ENUM(
+				"CIC1 MUX Mux", cic1_mux_enum);
+static const struct snd_kcontrol_new cic2_mux = SOC_DAPM_ENUM(
+				"CIC2 MUX Mux",	cic2_mux_enum);
 static const struct snd_kcontrol_new rx_mix1_inp1_mux = SOC_DAPM_ENUM(
 				"RX1 MIX1 INP1 Mux", rx_mix1_inp_enum[0]);
 static const struct snd_kcontrol_new rx_mix1_inp2_mux = SOC_DAPM_ENUM(
@@ -500,6 +512,8 @@ static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = {
 	SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
 			 &rx3_mix1_inp3_mux),
 
+	SND_SOC_DAPM_MUX("CIC1 MUX", SND_SOC_NOPM, 0, 0, &cic1_mux),
+	SND_SOC_DAPM_MUX("CIC2 MUX", SND_SOC_NOPM, 0, 0, &cic2_mux),
 	/* TX */
 	SND_SOC_DAPM_MIXER("ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -536,6 +550,8 @@ static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = {
 	/* Connectivity Clock */
 	SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, LPASS_CDC_CLK_OTHR_CTL, 2, 0,
 			      NULL, 0),
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
 
 };
 
@@ -568,6 +584,15 @@ static int msm8916_wcd_digital_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
+static int msm8916_wcd_digital_codec_set_sysclk(struct snd_soc_codec *codec,
+						int clk_id, int source,
+						unsigned int freq, int dir)
+{
+	struct msm8916_wcd_digital_priv *p = dev_get_drvdata(codec->dev);
+
+	return clk_set_rate(p->mclk, freq);
+}
+
 static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream,
 					 struct snd_pcm_hw_params *params,
 					 struct snd_soc_dai *dai)
@@ -646,6 +671,11 @@ static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = {
 	{"AIF1 Capture", NULL, "I2S TX2"},
 	{"AIF1 Capture", NULL, "I2S TX3"},
 
+	{"CIC1 MUX", "DMIC", "DEC1 MUX"},
+	{"CIC1 MUX", "AMIC", "DEC1 MUX"},
+	{"CIC2 MUX", "DMIC", "DEC2 MUX"},
+	{"CIC2 MUX", "AMIC", "DEC2 MUX"},
+
 	/* Decimator Inputs */
 	{"DEC1 MUX", "DMIC1", "DMIC1"},
 	{"DEC1 MUX", "DMIC2", "DMIC2"},
@@ -664,8 +694,8 @@ static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = {
 	{"DMIC1", NULL, "DMIC_CLK"},
 	{"DMIC2", NULL, "DMIC_CLK"},
 
-	{"I2S TX1", NULL, "DEC1 MUX"},
-	{"I2S TX2", NULL, "DEC2 MUX"},
+	{"I2S TX1", NULL, "CIC1 MUX"},
+	{"I2S TX2", NULL, "CIC2 MUX"},
 
 	{"I2S TX1", NULL, "TX_I2S_CLK"},
 	{"I2S TX2", NULL, "TX_I2S_CLK"},
@@ -788,7 +818,7 @@ static void msm8916_wcd_digital_shutdown(struct snd_pcm_substream *substream,
 			    LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 0);
 }
 
-static struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = {
+static const struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = {
 	.startup = msm8916_wcd_digital_startup,
 	.shutdown = msm8916_wcd_digital_shutdown,
 	.hw_params = msm8916_wcd_digital_hw_params,
@@ -821,8 +851,9 @@ static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = {
 	       },
 };
 
-static struct snd_soc_codec_driver msm8916_wcd_digital = {
+static const struct snd_soc_codec_driver msm8916_wcd_digital = {
 	.probe = msm8916_wcd_digital_codec_probe,
+	.set_sysclk = msm8916_wcd_digital_codec_set_sysclk,
 	.component_driver = {
 		.controls = msm8916_wcd_digital_snd_controls,
 		.num_controls = ARRAY_SIZE(msm8916_wcd_digital_snd_controls),
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
index c8bcb1db966d..f9c9933acffb 100644
--- a/sound/soc/codecs/nau8540.c
+++ b/sound/soc/codecs/nau8540.c
@@ -735,7 +735,7 @@ static int __maybe_unused nau8540_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver nau8540_codec_driver = {
+static const struct snd_soc_codec_driver nau8540_codec_driver = {
 	.set_sysclk = nau8540_set_sysclk,
 	.set_pll = nau8540_set_pll,
 	.suspend = nau8540_suspend,
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
index e45518629968..c8e2451ae0a3 100644
--- a/sound/soc/codecs/nau8810.c
+++ b/sound/soc/codecs/nau8810.c
@@ -808,7 +808,7 @@ static const struct regmap_config nau8810_regmap_config = {
 	.num_reg_defaults = ARRAY_SIZE(nau8810_reg_defaults),
 };
 
-static struct snd_soc_codec_driver nau8810_codec_driver = {
+static const struct snd_soc_codec_driver nau8810_codec_driver = {
 	.set_bias_level = nau8810_set_bias_level,
 	.suspend_bias_off = true,
 
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
index 3a309b18035e..0240759f951c 100644
--- a/sound/soc/codecs/nau8824.c
+++ b/sound/soc/codecs/nau8824.c
@@ -1469,7 +1469,7 @@ static int __maybe_unused nau8824_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver nau8824_codec_driver = {
+static const struct snd_soc_codec_driver nau8824_codec_driver = {
 	.probe = nau8824_codec_probe,
 	.set_sysclk = nau8824_set_sysclk,
 	.set_pll = nau8824_set_pll,
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index 46a30eaa7ace..714ce17da717 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -260,11 +260,11 @@ static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout)
 	if (timeout) {
 		ret = down_timeout(&nau8825->xtalk_sem, timeout);
 		if (ret < 0)
-			dev_warn(nau8825->dev, "Acquire semaphone timeout\n");
+			dev_warn(nau8825->dev, "Acquire semaphore timeout\n");
 	} else {
 		ret = down_interruptible(&nau8825->xtalk_sem);
 		if (ret < 0)
-			dev_warn(nau8825->dev, "Acquire semaphone fail\n");
+			dev_warn(nau8825->dev, "Acquire semaphore fail\n");
 	}
 
 	return ret;
@@ -1299,7 +1299,7 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
 	regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1,
 		NAU8825_I2S_DL_MASK, val_len);
 
-	/* Release the semaphone. */
+	/* Release the semaphore. */
 	nau8825_sema_release(nau8825);
 
 	return 0;
@@ -1361,7 +1361,7 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
 		NAU8825_I2S_MS_MASK, ctrl2_val);
 
-	/* Release the semaphone. */
+	/* Release the semaphore. */
 	nau8825_sema_release(nau8825);
 
 	return 0;
@@ -2140,7 +2140,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
 
 		break;
 	case NAU8825_CLK_MCLK:
-		/* Acquire the semaphone to synchronize the playback and
+		/* Acquire the semaphore to synchronize the playback and
 		 * interrupt handler. In order to avoid the playback inter-
 		 * fered by cross talk process, the driver make the playback
 		 * preparation halted until cross talk process finish.
@@ -2150,7 +2150,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
 		/* MCLK not changed by clock tree */
 		regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
 			NAU8825_CLK_MCLK_SRC_MASK, 0);
-		/* Release the semaphone. */
+		/* Release the semaphore. */
 		nau8825_sema_release(nau8825);
 
 		ret = nau8825_mclk_prepare(nau8825, freq);
@@ -2188,7 +2188,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
 
 		break;
 	case NAU8825_CLK_FLL_MCLK:
-		/* Acquire the semaphone to synchronize the playback and
+		/* Acquire the semaphore to synchronize the playback and
 		 * interrupt handler. In order to avoid the playback inter-
 		 * fered by cross talk process, the driver make the playback
 		 * preparation halted until cross talk process finish.
@@ -2201,7 +2201,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
 		regmap_update_bits(regmap, NAU8825_REG_FLL3,
 			NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
 			NAU8825_FLL_CLK_SRC_MCLK | 0);
-		/* Release the semaphone. */
+		/* Release the semaphore. */
 		nau8825_sema_release(nau8825);
 
 		ret = nau8825_mclk_prepare(nau8825, freq);
@@ -2210,7 +2210,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
 
 		break;
 	case NAU8825_CLK_FLL_BLK:
-		/* Acquire the semaphone to synchronize the playback and
+		/* Acquire the semaphore to synchronize the playback and
 		 * interrupt handler. In order to avoid the playback inter-
 		 * fered by cross talk process, the driver make the playback
 		 * preparation halted until cross talk process finish.
@@ -2226,7 +2226,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
 			NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
 			NAU8825_FLL_CLK_SRC_BLK |
 			(0xf << NAU8825_GAIN_ERR_SFT));
-		/* Release the semaphone. */
+		/* Release the semaphore. */
 		nau8825_sema_release(nau8825);
 
 		if (nau8825->mclk_freq) {
@@ -2236,7 +2236,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
 
 		break;
 	case NAU8825_CLK_FLL_FS:
-		/* Acquire the semaphone to synchronize the playback and
+		/* Acquire the semaphore to synchronize the playback and
 		 * interrupt handler. In order to avoid the playback inter-
 		 * fered by cross talk process, the driver make the playback
 		 * preparation halted until cross talk process finish.
@@ -2252,7 +2252,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
 			NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
 			NAU8825_FLL_CLK_SRC_FS |
 			(0xf << NAU8825_GAIN_ERR_SFT));
-		/* Release the semaphone. */
+		/* Release the semaphore. */
 		nau8825_sema_release(nau8825);
 
 		if (nau8825->mclk_freq) {
@@ -2388,7 +2388,7 @@ static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver nau8825_codec_driver = {
+static const struct snd_soc_codec_driver nau8825_codec_driver = {
 	.probe = nau8825_codec_probe,
 	.remove = nau8825_codec_remove,
 	.set_sysclk = nau8825_set_sysclk,
@@ -2563,7 +2563,7 @@ static int nau8825_i2c_probe(struct i2c_client *i2c,
 		return PTR_ERR(nau8825->regmap);
 	nau8825->dev = dev;
 	nau8825->irq = i2c->irq;
-	/* Initiate parameters, semaphone and work queue which are needed in
+	/* Initiate parameters, semaphore and work queue which are needed in
 	 * cross talk suppression measurment function.
 	 */
 	nau8825->xtalk_state = NAU8825_XTALK_DONE;
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index 0b14efab6280..c7e28dd2e815 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -288,7 +288,7 @@ static const struct regmap_config pcm1681_regmap = {
 	.readable_reg		= pcm1681_accessible_reg,
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_pcm1681 = {
+static const struct snd_soc_codec_driver soc_codec_dev_pcm1681 = {
 	.component_driver = {
 		.controls		= pcm1681_controls,
 		.num_controls		= ARRAY_SIZE(pcm1681_controls),
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
index b813a154ddd9..82a3d9db32cb 100644
--- a/sound/soc/codecs/pcm179x.c
+++ b/sound/soc/codecs/pcm179x.c
@@ -205,7 +205,7 @@ const struct regmap_config pcm179x_regmap_config = {
 };
 EXPORT_SYMBOL_GPL(pcm179x_regmap_config);
 
-static struct snd_soc_codec_driver soc_codec_dev_pcm179x = {
+static const struct snd_soc_codec_driver soc_codec_dev_pcm179x = {
 	.component_driver = {
 		.controls		= pcm179x_controls,
 		.num_controls		= ARRAY_SIZE(pcm179x_controls),
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
index 708af05486f6..e59d8ffb93bd 100644
--- a/sound/soc/codecs/pcm3008.c
+++ b/sound/soc/codecs/pcm3008.c
@@ -98,7 +98,7 @@ static struct snd_soc_dai_driver pcm3008_dai = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
+static const struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
 	.component_driver = {
 		.dapm_widgets		= pcm3008_dapm_widgets,
 		.num_dapm_widgets	= ARRAY_SIZE(pcm3008_dapm_widgets),
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 72b19e62f626..f1005a31c709 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -1344,7 +1344,7 @@ static struct snd_soc_dai_driver pcm512x_dai = {
 	.ops = &pcm512x_dai_ops,
 };
 
-static struct snd_soc_codec_driver pcm512x_codec_driver = {
+static const struct snd_soc_codec_driver pcm512x_codec_driver = {
 	.set_bias_level = pcm512x_set_bias_level,
 	.idle_bias_off = true,
 
diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c
new file mode 100644
index 000000000000..8f92e5c4dd9d
--- /dev/null
+++ b/sound/soc/codecs/rt274.c
@@ -0,0 +1,1229 @@
+/*
+ * rt274.c  --  RT274 ALSA SoC audio codec driver
+ *
+ * Copyright 2017 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/dmi.h>
+#include <linux/acpi.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 <sound/jack.h>
+#include <linux/workqueue.h>
+
+#include "rl6347a.h"
+#include "rt274.h"
+
+#define RT274_VENDOR_ID 0x10ec0274
+
+struct rt274_priv {
+	struct reg_default *index_cache;
+	int index_cache_size;
+	struct regmap *regmap;
+	struct snd_soc_codec *codec;
+	struct i2c_client *i2c;
+	struct snd_soc_jack *jack;
+	struct delayed_work jack_detect_work;
+	int sys_clk;
+	int clk_id;
+	int fs;
+	bool master;
+};
+
+static const struct reg_default rt274_index_def[] = {
+	{ 0x00, 0x1004 },
+	{ 0x01, 0xaaaa },
+	{ 0x02, 0x88aa },
+	{ 0x03, 0x0002 },
+	{ 0x04, 0xaa09 },
+	{ 0x05, 0x0700 },
+	{ 0x06, 0x6110 },
+	{ 0x07, 0x0200 },
+	{ 0x08, 0xa807 },
+	{ 0x09, 0x0021 },
+	{ 0x0a, 0x7770 },
+	{ 0x0b, 0x7770 },
+	{ 0x0c, 0x002b },
+	{ 0x0d, 0x2420 },
+	{ 0x0e, 0x65c0 },
+	{ 0x0f, 0x7770 },
+	{ 0x10, 0x0420 },
+	{ 0x11, 0x7418 },
+	{ 0x12, 0x6bd0 },
+	{ 0x13, 0x645f },
+	{ 0x14, 0x0400 },
+	{ 0x15, 0x8ccc },
+	{ 0x16, 0x4c50 },
+	{ 0x17, 0xff00 },
+	{ 0x18, 0x0003 },
+	{ 0x19, 0x2c11 },
+	{ 0x1a, 0x830b },
+	{ 0x1b, 0x4e4b },
+	{ 0x1c, 0x0000 },
+	{ 0x1d, 0x0000 },
+	{ 0x1e, 0x0000 },
+	{ 0x1f, 0x0000 },
+	{ 0x20, 0x51ff },
+	{ 0x21, 0x8000 },
+	{ 0x22, 0x8f00 },
+	{ 0x23, 0x88f4 },
+	{ 0x24, 0x0000 },
+	{ 0x25, 0x0000 },
+	{ 0x26, 0x0000 },
+	{ 0x27, 0x0000 },
+	{ 0x28, 0x0000 },
+	{ 0x29, 0x3000 },
+	{ 0x2a, 0x0000 },
+	{ 0x2b, 0x0000 },
+	{ 0x2c, 0x0f00 },
+	{ 0x2d, 0x100f },
+	{ 0x2e, 0x2902 },
+	{ 0x2f, 0xe280 },
+	{ 0x30, 0x1000 },
+	{ 0x31, 0x8400 },
+	{ 0x32, 0x5aaa },
+	{ 0x33, 0x8420 },
+	{ 0x34, 0xa20c },
+	{ 0x35, 0x096a },
+	{ 0x36, 0x5757 },
+	{ 0x37, 0xfe05 },
+	{ 0x38, 0x4901 },
+	{ 0x39, 0x110a },
+	{ 0x3a, 0x0010 },
+	{ 0x3b, 0x60d9 },
+	{ 0x3c, 0xf214 },
+	{ 0x3d, 0xc2ba },
+	{ 0x3e, 0xa928 },
+	{ 0x3f, 0x0000 },
+	{ 0x40, 0x9800 },
+	{ 0x41, 0x0000 },
+	{ 0x42, 0x2000 },
+	{ 0x43, 0x3d90 },
+	{ 0x44, 0x4900 },
+	{ 0x45, 0x5289 },
+	{ 0x46, 0x0004 },
+	{ 0x47, 0xa47a },
+	{ 0x48, 0xd049 },
+	{ 0x49, 0x0049 },
+	{ 0x4a, 0xa83b },
+	{ 0x4b, 0x0777 },
+	{ 0x4c, 0x065c },
+	{ 0x4d, 0x7fff },
+	{ 0x4e, 0x7fff },
+	{ 0x4f, 0x0000 },
+	{ 0x50, 0x0000 },
+	{ 0x51, 0x0000 },
+	{ 0x52, 0xbf5f },
+	{ 0x53, 0x3320 },
+	{ 0x54, 0xcc00 },
+	{ 0x55, 0x0000 },
+	{ 0x56, 0x3f00 },
+	{ 0x57, 0x0000 },
+	{ 0x58, 0x0000 },
+	{ 0x59, 0x0000 },
+	{ 0x5a, 0x1300 },
+	{ 0x5b, 0x005f },
+	{ 0x5c, 0x0000 },
+	{ 0x5d, 0x1001 },
+	{ 0x5e, 0x1000 },
+	{ 0x5f, 0x0000 },
+	{ 0x60, 0x5554 },
+	{ 0x61, 0xffc0 },
+	{ 0x62, 0xa000 },
+	{ 0x63, 0xd010 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x3fb1 },
+	{ 0x66, 0x1881 },
+	{ 0x67, 0xc810 },
+	{ 0x68, 0x2000 },
+	{ 0x69, 0xfff0 },
+	{ 0x6a, 0x0300 },
+	{ 0x6b, 0x5060 },
+	{ 0x6c, 0x0000 },
+	{ 0x6d, 0x0000 },
+	{ 0x6e, 0x0c25 },
+	{ 0x6f, 0x0c0b },
+	{ 0x70, 0x8000 },
+	{ 0x71, 0x4008 },
+	{ 0x72, 0x0000 },
+	{ 0x73, 0x0800 },
+	{ 0x74, 0xa28f },
+	{ 0x75, 0xa050 },
+	{ 0x76, 0x7fe8 },
+	{ 0x77, 0xdb8c },
+	{ 0x78, 0x0000 },
+	{ 0x79, 0x0000 },
+	{ 0x7a, 0x2a96 },
+	{ 0x7b, 0x800f },
+	{ 0x7c, 0x0200 },
+	{ 0x7d, 0x1600 },
+	{ 0x7e, 0x0000 },
+	{ 0x7f, 0x0000 },
+};
+#define INDEX_CACHE_SIZE ARRAY_SIZE(rt274_index_def)
+
+static const struct reg_default rt274_reg[] = {
+	{ 0x00170500, 0x00000400 },
+	{ 0x00220000, 0x00000031 },
+	{ 0x00239000, 0x00000057 },
+	{ 0x0023a000, 0x00000057 },
+	{ 0x00270500, 0x00000400 },
+	{ 0x00370500, 0x00000400 },
+	{ 0x00870500, 0x00000400 },
+	{ 0x00920000, 0x00000031 },
+	{ 0x00935000, 0x00000097 },
+	{ 0x00936000, 0x00000097 },
+	{ 0x00970500, 0x00000400 },
+	{ 0x00b37000, 0x00000400 },
+	{ 0x00b37200, 0x00000400 },
+	{ 0x00b37300, 0x00000400 },
+	{ 0x00c37000, 0x00000400 },
+	{ 0x00c37100, 0x00000400 },
+	{ 0x01270500, 0x00000400 },
+	{ 0x01370500, 0x00000400 },
+	{ 0x01371f00, 0x411111f0 },
+	{ 0x01937000, 0x00000000 },
+	{ 0x01970500, 0x00000400 },
+	{ 0x02050000, 0x0000001b },
+	{ 0x02139000, 0x00000080 },
+	{ 0x0213a000, 0x00000080 },
+	{ 0x02170100, 0x00000001 },
+	{ 0x02170500, 0x00000400 },
+	{ 0x02170700, 0x00000000 },
+	{ 0x02270100, 0x00000000 },
+	{ 0x02370100, 0x00000000 },
+	{ 0x01970700, 0x00000020 },
+	{ 0x00830000, 0x00000097 },
+	{ 0x00930000, 0x00000097 },
+	{ 0x01270700, 0x00000000 },
+};
+
+static bool rt274_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0 ... 0xff:
+	case RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID):
+	case RT274_GET_HP_SENSE:
+	case RT274_GET_MIC_SENSE:
+	case RT274_PROC_COEF:
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT0, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT1, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN1, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN1, 0):
+	case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN2, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC1, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC2, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE1, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE2, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_INLINE_CMD, 0):
+		return true;
+	default:
+		return false;
+	}
+
+
+}
+
+static bool rt274_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0 ... 0xff:
+	case RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID):
+	case RT274_GET_HP_SENSE:
+	case RT274_GET_MIC_SENSE:
+	case RT274_SET_AUDIO_POWER:
+	case RT274_SET_HPO_POWER:
+	case RT274_SET_DMIC1_POWER:
+	case RT274_LOUT_MUX:
+	case RT274_HPO_MUX:
+	case RT274_ADC0_MUX:
+	case RT274_ADC1_MUX:
+	case RT274_SET_MIC:
+	case RT274_SET_PIN_HPO:
+	case RT274_SET_PIN_LOUT3:
+	case RT274_SET_PIN_DMIC1:
+	case RT274_SET_AMP_GAIN_HPO:
+	case RT274_SET_DMIC2_DEFAULT:
+	case RT274_DAC0L_GAIN:
+	case RT274_DAC0R_GAIN:
+	case RT274_DAC1L_GAIN:
+	case RT274_DAC1R_GAIN:
+	case RT274_ADCL_GAIN:
+	case RT274_ADCR_GAIN:
+	case RT274_MIC_GAIN:
+	case RT274_HPOL_GAIN:
+	case RT274_HPOR_GAIN:
+	case RT274_LOUTL_GAIN:
+	case RT274_LOUTR_GAIN:
+	case RT274_DAC_FORMAT:
+	case RT274_ADC_FORMAT:
+	case RT274_COEF_INDEX:
+	case RT274_PROC_COEF:
+	case RT274_SET_AMP_GAIN_ADC_IN1:
+	case RT274_SET_AMP_GAIN_ADC_IN2:
+	case RT274_SET_POWER(RT274_DAC_OUT0):
+	case RT274_SET_POWER(RT274_DAC_OUT1):
+	case RT274_SET_POWER(RT274_ADC_IN1):
+	case RT274_SET_POWER(RT274_ADC_IN2):
+	case RT274_SET_POWER(RT274_DMIC2):
+	case RT274_SET_POWER(RT274_MIC):
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT0, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT1, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN1, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN1, 0):
+	case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN2, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC1, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC2, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE1, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE2, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_INLINE_CMD, 0):
+		return true;
+	default:
+		return false;
+	}
+}
+
+#ifdef CONFIG_PM
+static void rt274_index_sync(struct snd_soc_codec *codec)
+{
+	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	int i;
+
+	for (i = 0; i < INDEX_CACHE_SIZE; i++) {
+		snd_soc_write(codec, rt274->index_cache[i].reg,
+				  rt274->index_cache[i].def);
+	}
+}
+#endif
+
+static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic)
+{
+	unsigned int buf;
+
+	*hp = false;
+	*mic = false;
+
+	if (!rt274->codec)
+		return -EINVAL;
+
+	regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf);
+	*hp = buf & 0x80000000;
+	regmap_read(rt274->regmap, RT274_GET_MIC_SENSE, &buf);
+	*mic = buf & 0x80000000;
+
+	pr_debug("*hp = %d *mic = %d\n", *hp, *mic);
+
+	return 0;
+}
+
+static void rt274_jack_detect_work(struct work_struct *work)
+{
+	struct rt274_priv *rt274 =
+		container_of(work, struct rt274_priv, jack_detect_work.work);
+	int status = 0;
+	bool hp = false;
+	bool mic = false;
+
+	if (rt274_jack_detect(rt274, &hp, &mic) < 0)
+		return;
+
+	if (hp == true)
+		status |= SND_JACK_HEADPHONE;
+
+	if (mic == true)
+		status |= SND_JACK_MICROPHONE;
+
+	snd_soc_jack_report(rt274->jack, status,
+		SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+}
+
+static irqreturn_t rt274_irq(int irq, void *data);
+
+static int rt274_mic_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *jack,  void *data)
+{
+	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+	if (jack == NULL) {
+		/* Disable jack detection */
+		regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
+					RT274_IRQ_EN, RT274_IRQ_DIS);
+
+		return 0;
+	}
+	rt274->jack = jack;
+
+	regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
+				RT274_IRQ_EN, RT274_IRQ_EN);
+
+	/* Send an initial report */
+	rt274_irq(0, rt274);
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
+
+static const struct snd_kcontrol_new rt274_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT274_DAC0L_GAIN,
+			 RT274_DAC0R_GAIN, 0, 0x7f, 0, out_vol_tlv),
+	SOC_DOUBLE_R_TLV("DAC1 Playback Volume", RT274_DAC1L_GAIN,
+			 RT274_DAC1R_GAIN, 0, 0x7f, 0, out_vol_tlv),
+	SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT274_ADCL_GAIN,
+			    RT274_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv),
+	SOC_DOUBLE_R("ADC0 Capture Switch", RT274_ADCL_GAIN,
+			    RT274_ADCR_GAIN, RT274_MUTE_SFT, 1, 1),
+	SOC_SINGLE_TLV("AMIC Volume", RT274_MIC_GAIN,
+			    0, 0x3, 0, mic_vol_tlv),
+};
+
+static const struct snd_kcontrol_new hpol_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_HPOL_GAIN,
+			RT274_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpor_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_HPOR_GAIN,
+			RT274_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new loutl_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_LOUTL_GAIN,
+			RT274_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new loutr_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_LOUTR_GAIN,
+			RT274_MUTE_SFT, 1, 1);
+
+/* ADC0 source */
+static const char * const rt274_adc_src[] = {
+	"Mic", "Line1", "Line2", "Dmic"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt274_adc0_enum, RT274_ADC0_MUX, RT274_ADC_SEL_SFT,
+	rt274_adc_src);
+
+static const struct snd_kcontrol_new rt274_adc0_mux =
+	SOC_DAPM_ENUM("ADC 0 source", rt274_adc0_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt274_adc1_enum, RT274_ADC1_MUX, RT274_ADC_SEL_SFT,
+	rt274_adc_src);
+
+static const struct snd_kcontrol_new rt274_adc1_mux =
+	SOC_DAPM_ENUM("ADC 1 source", rt274_adc1_enum);
+
+static const char * const rt274_dac_src[] = {
+	"DAC OUT0", "DAC OUT1"
+};
+/* HP-OUT source */
+static SOC_ENUM_SINGLE_DECL(rt274_hpo_enum, RT274_HPO_MUX,
+				0, rt274_dac_src);
+
+static const struct snd_kcontrol_new rt274_hpo_mux =
+SOC_DAPM_ENUM("HPO source", rt274_hpo_enum);
+
+/* Line out source */
+static SOC_ENUM_SINGLE_DECL(rt274_lout_enum, RT274_LOUT_MUX,
+				0, rt274_dac_src);
+
+static const struct snd_kcontrol_new rt274_lout_mux =
+SOC_DAPM_ENUM("LOUT source", rt274_lout_enum);
+
+static const struct snd_soc_dapm_widget rt274_dapm_widgets[] = {
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC1 Pin"),
+	SND_SOC_DAPM_INPUT("DMIC2 Pin"),
+	SND_SOC_DAPM_INPUT("MIC"),
+	SND_SOC_DAPM_INPUT("LINE1"),
+	SND_SOC_DAPM_INPUT("LINE2"),
+
+	/* DMIC */
+	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC 0", NULL, RT274_SET_STREAMID_ADC1, 4, 0),
+	SND_SOC_DAPM_ADC("ADC 1", NULL, RT274_SET_STREAMID_ADC2, 4, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("ADC 0 Mux", SND_SOC_NOPM, 0, 0,
+		&rt274_adc0_mux),
+	SND_SOC_DAPM_MUX("ADC 1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt274_adc1_mux),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RXL", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF1RXR", "AIF1 Playback", 1, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TXL", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TXR", "AIF1 Capture", 1, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RXL", "AIF1 Playback", 2, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RXR", "AIF1 Playback", 3, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TXL", "AIF1 Capture", 2, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TXR", "AIF1 Capture", 3, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC 0", NULL, RT274_SET_STREAMID_DAC0, 4, 0),
+	SND_SOC_DAPM_DAC("DAC 1", NULL, RT274_SET_STREAMID_DAC1, 4, 0),
+
+	/* Output Mux */
+	SND_SOC_DAPM_MUX("HPO Mux", SND_SOC_NOPM, 0, 0, &rt274_hpo_mux),
+	SND_SOC_DAPM_MUX("LOUT Mux", SND_SOC_NOPM, 0, 0, &rt274_lout_mux),
+
+	SND_SOC_DAPM_SUPPLY("HP Power", RT274_SET_PIN_HPO,
+		RT274_SET_PIN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LOUT Power", RT274_SET_PIN_LOUT3,
+		RT274_SET_PIN_SFT, 0, NULL, 0),
+
+	/* Output Mixer */
+	SND_SOC_DAPM_PGA("DAC OUT0", SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_PGA("DAC OUT1", SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+
+	/* Output Pga */
+	SND_SOC_DAPM_SWITCH("LOUT L", SND_SOC_NOPM, 0, 0,
+		&loutl_enable_control),
+	SND_SOC_DAPM_SWITCH("LOUT R", SND_SOC_NOPM, 0, 0,
+		&loutr_enable_control),
+	SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0,
+		&hpol_enable_control),
+	SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0,
+		&hpor_enable_control),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPO Pin"),
+	SND_SOC_DAPM_OUTPUT("SPDIF"),
+	SND_SOC_DAPM_OUTPUT("LINE3"),
+};
+
+static const struct snd_soc_dapm_route rt274_dapm_routes[] = {
+	{"DMIC1", NULL, "DMIC1 Pin"},
+	{"DMIC2", NULL, "DMIC2 Pin"},
+
+	{"ADC 0 Mux", "Mic", "MIC"},
+	{"ADC 0 Mux", "Dmic", "DMIC1"},
+	{"ADC 0 Mux", "Line1", "LINE1"},
+	{"ADC 0 Mux", "Line2", "LINE2"},
+	{"ADC 1 Mux", "Mic", "MIC"},
+	{"ADC 1 Mux", "Dmic", "DMIC2"},
+	{"ADC 1 Mux", "Line1", "LINE1"},
+	{"ADC 1 Mux", "Line2", "LINE2"},
+
+	{"ADC 0", NULL, "ADC 0 Mux"},
+	{"ADC 1", NULL, "ADC 1 Mux"},
+
+	{"AIF1TXL", NULL, "ADC 0"},
+	{"AIF1TXR", NULL, "ADC 0"},
+	{"AIF2TXL", NULL, "ADC 1"},
+	{"AIF2TXR", NULL, "ADC 1"},
+
+	{"DAC 0", NULL, "AIF1RXL"},
+	{"DAC 0", NULL, "AIF1RXR"},
+	{"DAC 1", NULL, "AIF2RXL"},
+	{"DAC 1", NULL, "AIF2RXR"},
+
+	{"DAC OUT0", NULL, "DAC 0"},
+
+	{"DAC OUT1", NULL, "DAC 1"},
+
+	{"LOUT Mux", "DAC OUT0", "DAC OUT0"},
+	{"LOUT Mux", "DAC OUT1", "DAC OUT1"},
+
+	{"LOUT L", "Switch", "LOUT Mux"},
+	{"LOUT R", "Switch", "LOUT Mux"},
+	{"LOUT L", NULL, "LOUT Power"},
+	{"LOUT R", NULL, "LOUT Power"},
+
+	{"LINE3", NULL, "LOUT L"},
+	{"LINE3", NULL, "LOUT R"},
+
+	{"HPO Mux", "DAC OUT0", "DAC OUT0"},
+	{"HPO Mux", "DAC OUT1", "DAC OUT1"},
+
+	{"HPO L", "Switch", "HPO Mux"},
+	{"HPO R", "Switch", "HPO Mux"},
+	{"HPO L", NULL, "HP Power"},
+	{"HPO R", NULL, "HP Power"},
+
+	{"HPO Pin", NULL, "HPO L"},
+	{"HPO Pin", NULL, "HPO R"},
+};
+
+static int rt274_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val = 0;
+	int d_len_code = 0, c_len_code = 0;
+
+	switch (params_rate(params)) {
+	/* bit 14 0:48K 1:44.1K */
+	case 44100:
+	case 48000:
+		break;
+	default:
+		dev_err(codec->dev, "Unsupported sample rate %d\n",
+					params_rate(params));
+		return -EINVAL;
+	}
+	switch (rt274->sys_clk) {
+	case 12288000:
+	case 24576000:
+		if (params_rate(params) != 48000) {
+			dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n",
+					params_rate(params), rt274->sys_clk);
+			return -EINVAL;
+		}
+		break;
+	case 11289600:
+	case 22579200:
+		if (params_rate(params) != 44100) {
+			dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n",
+					params_rate(params), rt274->sys_clk);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	if (params_channels(params) <= 16) {
+		/* bit 3:0 Number of Channel */
+		val |= (params_channels(params) - 1);
+	} else {
+		dev_err(codec->dev, "Unsupported channels %d\n",
+					params_channels(params));
+		return -EINVAL;
+	}
+
+	switch (params_width(params)) {
+	/* bit 6:4 Bits per Sample */
+	case 16:
+		d_len_code = 0;
+		c_len_code = 0;
+		val |= (0x1 << 4);
+		break;
+	case 32:
+		d_len_code = 2;
+		c_len_code = 3;
+		val |= (0x4 << 4);
+		break;
+	case 20:
+		d_len_code = 1;
+		c_len_code = 1;
+		val |= (0x2 << 4);
+		break;
+	case 24:
+		d_len_code = 2;
+		c_len_code = 2;
+		val |= (0x3 << 4);
+		break;
+	case 8:
+		d_len_code = 3;
+		c_len_code = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rt274->master)
+		c_len_code = 0x3;
+
+	snd_soc_update_bits(codec,
+		RT274_I2S_CTRL1, 0xc018, d_len_code << 3 | c_len_code << 14);
+	dev_dbg(codec->dev, "format val = 0x%x\n", val);
+
+	snd_soc_update_bits(codec, RT274_DAC_FORMAT, 0x407f, val);
+	snd_soc_update_bits(codec, RT274_ADC_FORMAT, 0x407f, val);
+
+	return 0;
+}
+
+static int rt274_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		snd_soc_update_bits(codec,
+			RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_M);
+		rt274->master = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		snd_soc_update_bits(codec,
+			RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_S);
+		rt274->master = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		snd_soc_update_bits(codec, RT274_I2S_CTRL1,
+					RT274_I2S_FMT_MASK, RT274_I2S_FMT_I2S);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		snd_soc_update_bits(codec, RT274_I2S_CTRL1,
+					RT274_I2S_FMT_MASK, RT274_I2S_FMT_LJ);
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		snd_soc_update_bits(codec, RT274_I2S_CTRL1,
+					RT274_I2S_FMT_MASK, RT274_I2S_FMT_PCMA);
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		snd_soc_update_bits(codec, RT274_I2S_CTRL1,
+					RT274_I2S_FMT_MASK, RT274_I2S_FMT_PCMB);
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* bit 15 Stream Type 0:PCM 1:Non-PCM */
+	snd_soc_update_bits(codec, RT274_DAC_FORMAT, 0x8000, 0);
+	snd_soc_update_bits(codec, RT274_ADC_FORMAT, 0x8000, 0);
+
+	return 0;
+}
+
+static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+	switch (source) {
+	case RT274_PLL2_S_MCLK:
+		snd_soc_update_bits(codec, RT274_PLL2_CTRL,
+				RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_MCLK);
+		break;
+	default:
+		dev_warn(codec->dev, "invalid pll source, use BCLK\n");
+	case RT274_PLL2_S_BCLK:
+		snd_soc_update_bits(codec, RT274_PLL2_CTRL,
+				RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_BCLK);
+		break;
+	}
+
+	if (source == RT274_PLL2_S_BCLK) {
+		snd_soc_update_bits(codec, RT274_MCLK_CTRL,
+				(0x3 << 12), (0x3 << 12));
+		switch (rt274->fs) {
+		case 50:
+			snd_soc_write(codec, 0x7a, 0xaab6);
+			snd_soc_write(codec, 0x7b, 0x0301);
+			snd_soc_write(codec, 0x7c, 0x04fe);
+			break;
+		case 64:
+			snd_soc_write(codec, 0x7a, 0xaa96);
+			snd_soc_write(codec, 0x7b, 0x8003);
+			snd_soc_write(codec, 0x7c, 0x081e);
+			break;
+		case 128:
+			snd_soc_write(codec, 0x7a, 0xaa96);
+			snd_soc_write(codec, 0x7b, 0x8003);
+			snd_soc_write(codec, 0x7c, 0x080e);
+			break;
+		default:
+			dev_warn(codec->dev, "invalid freq_in, assume 4.8M\n");
+		case 100:
+			snd_soc_write(codec, 0x7a, 0xaab6);
+			snd_soc_write(codec, 0x7b, 0x0301);
+			snd_soc_write(codec, 0x7c, 0x047e);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int rt274_set_dai_sysclk(struct snd_soc_dai *dai,
+				int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	unsigned int clk_src, mclk_en;
+
+	dev_dbg(codec->dev, "%s freq=%d\n", __func__, freq);
+
+	switch (clk_id) {
+	case RT274_SCLK_S_MCLK:
+		mclk_en = RT274_MCLK_MODE_EN;
+		clk_src = RT274_CLK_SRC_MCLK;
+		break;
+	case RT274_SCLK_S_PLL1:
+		mclk_en = RT274_MCLK_MODE_DIS;
+		clk_src = RT274_CLK_SRC_MCLK;
+		break;
+	case RT274_SCLK_S_PLL2:
+		mclk_en = RT274_MCLK_MODE_EN;
+		clk_src = RT274_CLK_SRC_PLL2;
+		break;
+	default:
+		mclk_en = RT274_MCLK_MODE_DIS;
+		clk_src = RT274_CLK_SRC_MCLK;
+		dev_warn(codec->dev, "invalid sysclk source, use PLL1\n");
+		break;
+	}
+	snd_soc_update_bits(codec, RT274_MCLK_CTRL,
+			RT274_MCLK_MODE_MASK, mclk_en);
+	snd_soc_update_bits(codec, RT274_CLK_CTRL,
+			RT274_CLK_SRC_MASK, clk_src);
+
+	switch (freq) {
+	case 19200000:
+		if (clk_id == RT274_SCLK_S_MCLK) {
+			dev_err(codec->dev, "Should not use MCLK\n");
+			return -EINVAL;
+		}
+		snd_soc_update_bits(codec,
+			RT274_I2S_CTRL2, 0x40, 0x40);
+		break;
+	case 24000000:
+		if (clk_id == RT274_SCLK_S_MCLK) {
+			dev_err(codec->dev, "Should not use MCLK\n");
+			return -EINVAL;
+		}
+		snd_soc_update_bits(codec,
+			RT274_I2S_CTRL2, 0x40, 0x0);
+		break;
+	case 12288000:
+	case 11289600:
+		snd_soc_update_bits(codec,
+			RT274_MCLK_CTRL, 0x1fcf, 0x0008);
+		break;
+	case 24576000:
+	case 22579200:
+		snd_soc_update_bits(codec,
+			RT274_MCLK_CTRL, 0x1fcf, 0x1543);
+		break;
+	default:
+		dev_err(codec->dev, "Unsupported system clock\n");
+		return -EINVAL;
+	}
+
+	rt274->sys_clk = freq;
+	rt274->clk_id = clk_id;
+
+	return 0;
+}
+
+static int rt274_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+	rt274->fs = ratio;
+	if ((ratio / 50) == 0)
+		snd_soc_update_bits(codec,
+			RT274_I2S_CTRL1, 0x1000, 0x1000);
+	else
+		snd_soc_update_bits(codec,
+			RT274_I2S_CTRL1, 0x1000, 0x0);
+
+
+	return 0;
+}
+
+static int rt274_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			unsigned int rx_mask, int slots, int slot_width)
+
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	if (rx_mask || tx_mask) {
+		snd_soc_update_bits(codec,
+			RT274_I2S_CTRL1, RT274_TDM_EN, RT274_TDM_EN);
+	} else {
+		snd_soc_update_bits(codec,
+			RT274_I2S_CTRL1, RT274_TDM_EN, RT274_TDM_DIS);
+		return 0;
+	}
+
+	switch (slots) {
+	case 4:
+		snd_soc_update_bits(codec,
+			RT274_I2S_CTRL1, RT274_TDM_CH_NUM, RT274_TDM_4CH);
+		break;
+	case 2:
+		snd_soc_update_bits(codec,
+			RT274_I2S_CTRL1, RT274_TDM_CH_NUM, RT274_TDM_2CH);
+		break;
+	default:
+		dev_err(codec->dev,
+			"Support 2 or 4 slots TDM only\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt274_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		if (SND_SOC_BIAS_STANDBY ==
+			snd_soc_codec_get_bias_level(codec)) {
+			snd_soc_write(codec,
+				RT274_SET_AUDIO_POWER, AC_PWRST_D0);
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_write(codec,
+			RT274_SET_AUDIO_POWER, AC_PWRST_D3);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static irqreturn_t rt274_irq(int irq, void *data)
+{
+	struct rt274_priv *rt274 = data;
+	bool hp = false;
+	bool mic = false;
+	int ret, status = 0;
+
+	/* Clear IRQ */
+	regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
+				RT274_IRQ_CLR, RT274_IRQ_CLR);
+
+	ret = rt274_jack_detect(rt274, &hp, &mic);
+
+	if (ret == 0) {
+		if (hp == true)
+			status |= SND_JACK_HEADPHONE;
+
+		if (mic == true)
+			status |= SND_JACK_MICROPHONE;
+
+		snd_soc_jack_report(rt274->jack, status,
+			SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+
+		pm_wakeup_event(&rt274->i2c->dev, 300);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int rt274_probe(struct snd_soc_codec *codec)
+{
+	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+	rt274->codec = codec;
+
+	if (rt274->i2c->irq) {
+		INIT_DELAYED_WORK(&rt274->jack_detect_work,
+					rt274_jack_detect_work);
+		schedule_delayed_work(&rt274->jack_detect_work,
+					msecs_to_jiffies(1250));
+	}
+
+	return 0;
+}
+
+static int rt274_remove(struct snd_soc_codec *codec)
+{
+	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+	cancel_delayed_work_sync(&rt274->jack_detect_work);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt274_suspend(struct snd_soc_codec *codec)
+{
+	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+	regcache_cache_only(rt274->regmap, true);
+	regcache_mark_dirty(rt274->regmap);
+
+	return 0;
+}
+
+static int rt274_resume(struct snd_soc_codec *codec)
+{
+	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+	regcache_cache_only(rt274->regmap, false);
+	rt274_index_sync(codec);
+	regcache_sync(rt274->regmap);
+
+	return 0;
+}
+#else
+#define rt274_suspend NULL
+#define rt274_resume NULL
+#endif
+
+#define RT274_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define RT274_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 rt274_aif_dai_ops = {
+	.hw_params = rt274_hw_params,
+	.set_fmt = rt274_set_dai_fmt,
+	.set_sysclk = rt274_set_dai_sysclk,
+	.set_pll = rt274_set_dai_pll,
+	.set_bclk_ratio = rt274_set_bclk_ratio,
+	.set_tdm_slot = rt274_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver rt274_dai[] = {
+	{
+		.name = "rt274-aif1",
+		.id = RT274_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT274_STEREO_RATES,
+			.formats = RT274_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT274_STEREO_RATES,
+			.formats = RT274_FORMATS,
+		},
+		.ops = &rt274_aif_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static const struct snd_soc_codec_driver soc_codec_dev_rt274 = {
+	.probe = rt274_probe,
+	.remove = rt274_remove,
+	.suspend = rt274_suspend,
+	.resume = rt274_resume,
+	.set_bias_level = rt274_set_bias_level,
+	.idle_bias_off = true,
+	.component_driver = {
+		.controls		= rt274_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt274_snd_controls),
+		.dapm_widgets		= rt274_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt274_dapm_widgets),
+		.dapm_routes		= rt274_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt274_dapm_routes),
+	},
+	.set_jack = rt274_mic_detect,
+};
+
+static const struct regmap_config rt274_regmap = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.max_register = 0x05bfffff,
+	.volatile_reg = rt274_volatile_register,
+	.readable_reg = rt274_readable_register,
+	.reg_write = rl6347a_hw_write,
+	.reg_read = rl6347a_hw_read,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt274_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt274_reg),
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt274_of_match[] = {
+	{.compatible = "realtek,rt274"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt274_of_match);
+#endif
+
+static const struct i2c_device_id rt274_i2c_id[] = {
+	{"rt274", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, rt274_i2c_id);
+
+static const struct acpi_device_id rt274_acpi_match[] = {
+	{ "10EC0274", 0 },
+	{ "INT34C2", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt274_acpi_match);
+
+static int rt274_i2c_probe(struct i2c_client *i2c,
+			   const struct i2c_device_id *id)
+{
+	struct rt274_priv *rt274;
+
+	int ret;
+	unsigned int val;
+
+	rt274 = devm_kzalloc(&i2c->dev,	sizeof(*rt274),
+				GFP_KERNEL);
+	if (rt274 == NULL)
+		return -ENOMEM;
+
+	rt274->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt274_regmap);
+	if (IS_ERR(rt274->regmap)) {
+		ret = PTR_ERR(rt274->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt274->regmap,
+		RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &val);
+	if (val != RT274_VENDOR_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt274\n", val);
+		return -ENODEV;
+	}
+
+	rt274->index_cache = devm_kmemdup(&i2c->dev, rt274_index_def,
+					  sizeof(rt274_index_def), GFP_KERNEL);
+	if (!rt274->index_cache)
+		return -ENOMEM;
+
+	rt274->index_cache_size = INDEX_CACHE_SIZE;
+	rt274->i2c = i2c;
+	i2c_set_clientdata(i2c, rt274);
+
+	/* reset codec */
+	regmap_write(rt274->regmap, RT274_RESET, 0);
+	regmap_update_bits(rt274->regmap, 0x1a, 0x4000, 0x4000);
+
+	/* Set Pad PDB is floating */
+	regmap_update_bits(rt274->regmap, RT274_PAD_CTRL12, 0x3, 0x0);
+	regmap_write(rt274->regmap, RT274_COEF5b_INDEX, 0x01);
+	regmap_write(rt274->regmap, RT274_COEF5b_COEF, 0x8540);
+	regmap_update_bits(rt274->regmap, 0x6f, 0x0100, 0x0100);
+	/* Combo jack auto detect */
+	regmap_write(rt274->regmap, 0x4a, 0x201b);
+	/* Aux mode off */
+	regmap_update_bits(rt274->regmap, 0x6f, 0x3000, 0x2000);
+	/* HP DC Calibration */
+	regmap_update_bits(rt274->regmap, 0x6f, 0xf, 0x0);
+	/* Set NID=58h.Index 00h [15]= 1b; */
+	regmap_write(rt274->regmap, RT274_COEF58_INDEX, 0x00);
+	regmap_write(rt274->regmap, RT274_COEF58_COEF, 0xb888);
+	msleep(500);
+	regmap_update_bits(rt274->regmap, 0x6f, 0xf, 0xb);
+	regmap_write(rt274->regmap, RT274_COEF58_INDEX, 0x00);
+	regmap_write(rt274->regmap, RT274_COEF58_COEF, 0x3888);
+	/* Set pin widget */
+	regmap_write(rt274->regmap, RT274_SET_PIN_HPO, 0x40);
+	regmap_write(rt274->regmap, RT274_SET_PIN_LOUT3, 0x40);
+	regmap_write(rt274->regmap, RT274_SET_MIC, 0x20);
+	regmap_write(rt274->regmap, RT274_SET_PIN_DMIC1, 0x20);
+
+	regmap_update_bits(rt274->regmap, RT274_I2S_CTRL2, 0xc004, 0x4004);
+	regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
+				RT274_GPI2_SEL_MASK, RT274_GPI2_SEL_DMIC_CLK);
+
+	/* jack detection */
+	regmap_write(rt274->regmap, RT274_UNSOLICITED_HP_OUT, 0x81);
+	regmap_write(rt274->regmap, RT274_UNSOLICITED_MIC, 0x82);
+
+	if (rt274->i2c->irq) {
+		ret = request_threaded_irq(rt274->i2c->irq, NULL, rt274_irq,
+			IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt274", rt274);
+		if (ret != 0) {
+			dev_err(&i2c->dev,
+				"Failed to reguest IRQ: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt274,
+				     rt274_dai, ARRAY_SIZE(rt274_dai));
+
+	return ret;
+}
+
+static int rt274_i2c_remove(struct i2c_client *i2c)
+{
+	struct rt274_priv *rt274 = i2c_get_clientdata(i2c);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, rt274);
+	snd_soc_unregister_codec(&i2c->dev);
+
+	return 0;
+}
+
+
+static struct i2c_driver rt274_i2c_driver = {
+	.driver = {
+		   .name = "rt274",
+		   .acpi_match_table = ACPI_PTR(rt274_acpi_match),
+#ifdef CONFIG_OF
+		   .of_match_table = of_match_ptr(rt274_of_match),
+#endif
+		   },
+	.probe = rt274_i2c_probe,
+	.remove = rt274_i2c_remove,
+	.id_table = rt274_i2c_id,
+};
+
+module_i2c_driver(rt274_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT274 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt274.h b/sound/soc/codecs/rt274.h
new file mode 100644
index 000000000000..4fd1bcb73dba
--- /dev/null
+++ b/sound/soc/codecs/rt274.h
@@ -0,0 +1,217 @@
+/*
+ * rt274.h  --  RT274 ALSA SoC audio driver
+ *
+ * Copyright 2016 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 __RT274_H__
+#define __RT274_H__
+
+#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D)
+
+#define RT274_AUDIO_FUNCTION_GROUP			0x01
+#define RT274_DAC_OUT0					0x02
+#define RT274_DAC_OUT1					0x03
+#define RT274_ADC_IN2					0x08
+#define RT274_ADC_IN1					0x09
+#define RT274_DIG_CVT					0x0a
+#define RT274_DMIC1					0x12
+#define RT274_DMIC2					0x13
+#define RT274_MIC					0x19
+#define RT274_LINE1					0x1a
+#define RT274_LINE2					0x1b
+#define RT274_LINE3					0x16
+#define RT274_SPDIF					0x1e
+#define RT274_VENDOR_REGISTERS				0x20
+#define RT274_HP_OUT					0x21
+#define RT274_MIXER_IN1					0x22
+#define RT274_MIXER_IN2					0x23
+#define RT274_INLINE_CMD				0x55
+
+#define RT274_SET_PIN_SFT				6
+#define RT274_SET_PIN_ENABLE				0x40
+#define RT274_SET_PIN_DISABLE				0
+#define RT274_SET_EAPD_HIGH				0x2
+#define RT274_SET_EAPD_LOW				0
+
+#define RT274_MUTE_SFT					7
+
+/* Verb commands */
+#define RT274_RESET\
+	VERB_CMD(AC_VERB_SET_CODEC_RESET, RT274_AUDIO_FUNCTION_GROUP, 0)
+#define RT274_GET_PARAM(NID, PARAM) VERB_CMD(AC_VERB_PARAMETERS, NID, PARAM)
+#define RT274_SET_POWER(NID) VERB_CMD(AC_VERB_SET_POWER_STATE, NID, 0)
+#define RT274_SET_AUDIO_POWER RT274_SET_POWER(RT274_AUDIO_FUNCTION_GROUP)
+#define RT274_SET_HPO_POWER RT274_SET_POWER(RT274_HP_OUT)
+#define RT274_SET_DMIC1_POWER RT274_SET_POWER(RT274_DMIC1)
+#define RT274_LOUT_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_LINE3, 0)
+#define RT274_HPO_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_HP_OUT, 0)
+#define RT274_ADC0_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_MIXER_IN1, 0)
+#define RT274_ADC1_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_MIXER_IN2, 0)
+#define RT274_SET_MIC\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_MIC, 0)
+#define RT274_SET_PIN_LOUT3\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_LINE3, 0)
+#define RT274_SET_PIN_HPO\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_HP_OUT, 0)
+#define RT274_SET_PIN_DMIC1\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_DMIC1, 0)
+#define RT274_SET_PIN_SPDIF\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_SPDIF, 0)
+#define RT274_SET_PIN_DIG_CVT\
+	VERB_CMD(AC_VERB_SET_DIGI_CONVERT_1, RT274_DIG_CVT, 0)
+#define RT274_SET_AMP_GAIN_HPO\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_HP_OUT, 0)
+#define RT274_SET_AMP_GAIN_ADC_IN1\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0)
+#define RT274_SET_AMP_GAIN_ADC_IN2\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN2, 0)
+#define RT274_GET_HP_SENSE\
+	VERB_CMD(AC_VERB_GET_PIN_SENSE, RT274_HP_OUT, 0)
+#define RT274_GET_MIC_SENSE\
+	VERB_CMD(AC_VERB_GET_PIN_SENSE, RT274_MIC, 0)
+#define RT274_SET_DMIC2_DEFAULT\
+	VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT274_DMIC2, 0)
+#define RT274_SET_SPDIF_DEFAULT\
+	VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT274_SPDIF, 0)
+#define RT274_DAC0L_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0xa000)
+#define RT274_DAC0R_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0x9000)
+#define RT274_DAC1L_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0xa000)
+#define RT274_DAC1R_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0x9000)
+#define RT274_ADCL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0x6000)
+#define RT274_ADCR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0x5000)
+#define RT274_MIC_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_MIC, 0x7000)
+#define RT274_LOUTL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_LINE3, 0xa000)
+#define RT274_LOUTR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_LINE3, 0x9000)
+#define RT274_HPOL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_HP_OUT, 0xa000)
+#define RT274_HPOR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_HP_OUT, 0x9000)
+#define RT274_DAC_FORMAT\
+	VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT274_DAC_OUT0, 0)
+#define RT274_ADC_FORMAT\
+	VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT274_ADC_IN1, 0)
+#define RT274_COEF_INDEX\
+	VERB_CMD(AC_VERB_SET_COEF_INDEX, RT274_VENDOR_REGISTERS, 0)
+#define RT274_PROC_COEF\
+	VERB_CMD(AC_VERB_SET_PROC_COEF, RT274_VENDOR_REGISTERS, 0)
+#define RT274_UNSOLICITED_INLINE_CMD\
+	VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT274_INLINE_CMD, 0)
+#define RT274_UNSOLICITED_HP_OUT\
+	VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT274_HP_OUT, 0)
+#define RT274_UNSOLICITED_MIC\
+	VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT274_MIC, 0)
+#define RT274_COEF58_INDEX\
+	VERB_CMD(AC_VERB_SET_COEF_INDEX, 0x58, 0)
+#define RT274_COEF58_COEF\
+	VERB_CMD(AC_VERB_SET_PROC_COEF, 0x58, 0)
+#define RT274_COEF5b_INDEX\
+	VERB_CMD(AC_VERB_SET_COEF_INDEX, 0x5b, 0)
+#define RT274_COEF5b_COEF\
+	VERB_CMD(AC_VERB_SET_PROC_COEF, 0x5b, 0)
+#define RT274_SET_STREAMID_DAC0\
+	VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_DAC_OUT0, 0)
+#define RT274_SET_STREAMID_DAC1\
+	VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_DAC_OUT1, 0)
+#define RT274_SET_STREAMID_ADC1\
+	VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_ADC_IN1, 0)
+#define RT274_SET_STREAMID_ADC2\
+	VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_ADC_IN2, 0)
+
+/* Index registers */
+#define RT274_EAPD_GPIO_IRQ_CTRL	0x10
+#define RT274_PAD_CTRL12		0x35
+#define RT274_I2S_CTRL1			0x63
+#define RT274_I2S_CTRL2			0x64
+#define RT274_MCLK_CTRL			0x71
+#define RT274_CLK_CTRL			0x72
+#define RT274_PLL2_CTRL			0x7b
+
+
+/* EAPD GPIO IRQ control (Index 0x10) */
+#define RT274_IRQ_DIS		(0x0 << 13)
+#define RT274_IRQ_EN		(0x1 << 13)
+#define RT274_IRQ_CLR		(0x1 << 12)
+#define RT274_GPI2_SEL_MASK	(0x3 << 7)
+#define RT274_GPI2_SEL_GPIO2	(0x0 << 7)
+#define RT274_GPI2_SEL_I2S	(0x1 << 7)
+#define RT274_GPI2_SEL_DMIC_CLK	(0x2 << 7)
+#define RT274_GPI2_SEL_CBJ	(0x3 << 7)
+
+/* Front I2S_Interface control 1 (Index 0x63) */
+#define RT274_I2S_MODE_MASK	(0x1 << 11)
+#define RT274_I2S_MODE_S	(0x0 << 11)
+#define RT274_I2S_MODE_M	(0x1 << 11)
+#define RT274_TDM_DIS		(0x0 << 10)
+#define RT274_TDM_EN		(0x1 << 10)
+#define RT274_TDM_CH_NUM	(0x1 << 7)
+#define RT274_TDM_2CH		(0x0 << 7)
+#define RT274_TDM_4CH		(0x1 << 7)
+#define RT274_I2S_FMT_MASK	(0x3 << 8)
+#define RT274_I2S_FMT_I2S	(0x0 << 8)
+#define RT274_I2S_FMT_LJ	(0x1 << 8)
+#define RT274_I2S_FMT_PCMA	(0x2 << 8)
+#define RT274_I2S_FMT_PCMB	(0x3 << 8)
+
+/* MCLK clock domain control (Index 0x71) */
+#define RT274_MCLK_MODE_MASK	(0x1 << 14)
+#define RT274_MCLK_MODE_DIS	(0x0 << 14)
+#define RT274_MCLK_MODE_EN	(0x1 << 14)
+
+/* Clock control (Index 0x72) */
+#define RT274_CLK_SRC_MASK	(0x7 << 3)
+#define RT274_CLK_SRC_MCLK	(0x0 << 3)
+#define RT274_CLK_SRC_PLL2	(0x3 << 3)
+
+/* PLL2 control (Index 0x7b) */
+#define RT274_PLL2_SRC_MASK	(0x1 << 13)
+#define RT274_PLL2_SRC_MCLK	(0x0 << 13)
+#define RT274_PLL2_SRC_BCLK	(0x1 << 13)
+
+/* HP-OUT (0x21) */
+#define RT274_M_HP_MUX_SFT	14
+#define RT274_HP_SEL_MASK	0x1
+#define RT274_HP_SEL_SFT	0
+#define RT274_HP_SEL_F		0
+#define RT274_HP_SEL_S		1
+
+/* ADC (0x22) (0x23) */
+#define RT274_ADC_SEL_MASK	0x7
+#define RT274_ADC_SEL_SFT	0
+#define RT274_ADC_SEL_MIC	0
+#define RT274_ADC_SEL_LINE1	1
+#define RT274_ADC_SEL_LINE2	2
+#define RT274_ADC_SEL_DMIC	3
+
+#define RT274_SCLK_S_MCLK	0
+#define RT274_SCLK_S_PLL1	1
+#define RT274_SCLK_S_PLL2	2
+
+#define RT274_PLL2_S_MCLK	0
+#define RT274_PLL2_S_BCLK	1
+
+enum {
+	RT274_AIF1,
+	RT274_AIFS,
+};
+
+#endif /* __RT274_H__ */
+
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 7899a2cdeb42..af6325c78292 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -1046,7 +1046,7 @@ static struct snd_soc_dai_driver rt286_dai[] = {
 
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt286 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt286 = {
 	.probe = rt286_probe,
 	.remove = rt286_remove,
 	.suspend = rt286_suspend,
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index d9e96e65e1c4..ce963768449f 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -1113,7 +1113,7 @@ static struct snd_soc_dai_driver rt298_dai[] = {
 
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt298 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt298 = {
 	.probe = rt298_probe,
 	.remove = rt298_remove,
 	.suspend = rt298_suspend,
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 7ed62e8c80b4..ed6e5373916c 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -43,9 +43,7 @@ struct rt5514_dsp {
 	struct mutex dma_lock;
 	struct snd_pcm_substream *substream;
 	unsigned int buf_base, buf_limit, buf_rp;
-	size_t buf_size;
-	size_t dma_offset;
-	size_t dsp_offset;
+	size_t buf_size, get_size, dma_offset;
 };
 
 static const struct snd_pcm_hardware rt5514_spi_pcm_hardware = {
@@ -80,6 +78,8 @@ static void rt5514_spi_copy_work(struct work_struct *work)
 		container_of(work, struct rt5514_dsp, copy_work.work);
 	struct snd_pcm_runtime *runtime;
 	size_t period_bytes, truncated_bytes = 0;
+	unsigned int cur_wp, remain_data;
+	u8 buf[8];
 
 	mutex_lock(&rt5514_dsp->dma_lock);
 	if (!rt5514_dsp->substream) {
@@ -90,8 +90,24 @@ static void rt5514_spi_copy_work(struct work_struct *work)
 	runtime = rt5514_dsp->substream->runtime;
 	period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream);
 
-	if (rt5514_dsp->buf_size - rt5514_dsp->dsp_offset <  period_bytes)
-		period_bytes = rt5514_dsp->buf_size - rt5514_dsp->dsp_offset;
+	if (rt5514_dsp->get_size >= rt5514_dsp->buf_size) {
+		rt5514_spi_burst_read(RT5514_BUFFER_VOICE_WP, (u8 *)&buf,
+			sizeof(buf));
+		cur_wp = buf[0] | buf[1] << 8 | buf[2] << 16 |
+					buf[3] << 24;
+
+		if (cur_wp >= rt5514_dsp->buf_rp)
+			remain_data = (cur_wp - rt5514_dsp->buf_rp);
+		else
+			remain_data =
+				(rt5514_dsp->buf_limit - rt5514_dsp->buf_rp) +
+				(cur_wp - rt5514_dsp->buf_base);
+
+		if (remain_data < period_bytes) {
+			schedule_delayed_work(&rt5514_dsp->copy_work, 5);
+			goto done;
+		}
+	}
 
 	if (rt5514_dsp->buf_rp + period_bytes <= rt5514_dsp->buf_limit) {
 		rt5514_spi_burst_read(rt5514_dsp->buf_rp,
@@ -112,24 +128,62 @@ static void rt5514_spi_copy_work(struct work_struct *work)
 			runtime->dma_area + rt5514_dsp->dma_offset +
 			truncated_bytes, period_bytes - truncated_bytes);
 
-			rt5514_dsp->buf_rp = rt5514_dsp->buf_base +
-				period_bytes - truncated_bytes;
+		rt5514_dsp->buf_rp = rt5514_dsp->buf_base + period_bytes -
+			truncated_bytes;
 	}
 
+	rt5514_dsp->get_size += period_bytes;
 	rt5514_dsp->dma_offset += period_bytes;
 	if (rt5514_dsp->dma_offset >= runtime->dma_bytes)
 		rt5514_dsp->dma_offset = 0;
 
-	rt5514_dsp->dsp_offset += period_bytes;
-
 	snd_pcm_period_elapsed(rt5514_dsp->substream);
 
-	if (rt5514_dsp->dsp_offset < rt5514_dsp->buf_size)
-		schedule_delayed_work(&rt5514_dsp->copy_work, 5);
+	schedule_delayed_work(&rt5514_dsp->copy_work, 5);
+
 done:
 	mutex_unlock(&rt5514_dsp->dma_lock);
 }
 
+static irqreturn_t rt5514_spi_irq(int irq, void *data)
+{
+	struct rt5514_dsp *rt5514_dsp = data;
+	u8 buf[8];
+
+	rt5514_dsp->get_size = 0;
+
+	/**
+	 * The address area x1800XXXX is the register address, and it cannot
+	 * support spi burst read perfectly. So we use the spi burst read
+	 * individually to make sure the data correctly.
+	 */
+	rt5514_spi_burst_read(RT5514_BUFFER_VOICE_BASE, (u8 *)&buf,
+		sizeof(buf));
+	rt5514_dsp->buf_base = buf[0] | buf[1] << 8 | buf[2] << 16 |
+				buf[3] << 24;
+
+	rt5514_spi_burst_read(RT5514_BUFFER_VOICE_LIMIT, (u8 *)&buf,
+		sizeof(buf));
+	rt5514_dsp->buf_limit = buf[0] | buf[1] << 8 | buf[2] << 16 |
+				buf[3] << 24;
+
+	rt5514_spi_burst_read(RT5514_BUFFER_VOICE_WP, (u8 *)&buf,
+		sizeof(buf));
+	rt5514_dsp->buf_rp = buf[0] | buf[1] << 8 | buf[2] << 16 |
+				buf[3] << 24;
+
+	if (rt5514_dsp->buf_rp % 8)
+		rt5514_dsp->buf_rp = (rt5514_dsp->buf_rp / 8) * 8;
+
+	rt5514_dsp->buf_size = rt5514_dsp->buf_limit - rt5514_dsp->buf_base;
+
+	if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit &&
+		rt5514_dsp->buf_rp && rt5514_dsp->buf_size)
+		schedule_delayed_work(&rt5514_dsp->copy_work, 0);
+
+	return IRQ_HANDLED;
+}
+
 /* PCM for streaming audio from the DSP buffer */
 static int rt5514_spi_pcm_open(struct snd_pcm_substream *substream)
 {
@@ -150,6 +204,7 @@ static int rt5514_spi_hw_params(struct snd_pcm_substream *substream,
 	ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 			params_buffer_bytes(hw_params));
 	rt5514_dsp->substream = substream;
+	rt5514_dsp->dma_offset = 0;
 	mutex_unlock(&rt5514_dsp->dma_lock);
 
 	return ret;
@@ -170,59 +225,6 @@ static int rt5514_spi_hw_free(struct snd_pcm_substream *substream)
 	return snd_pcm_lib_free_vmalloc_buffer(substream);
 }
 
-static int rt5514_spi_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct rt5514_dsp *rt5514_dsp =
-			snd_soc_platform_get_drvdata(rtd->platform);
-	u8 buf[8];
-
-	rt5514_dsp->dma_offset = 0;
-	rt5514_dsp->dsp_offset = 0;
-
-	/**
-	 * The address area x1800XXXX is the register address, and it cannot
-	 * support spi burst read perfectly. So we use the spi burst read
-	 * individually to make sure the data correctly.
-	*/
-	rt5514_spi_burst_read(RT5514_BUFFER_VOICE_BASE, (u8 *)&buf,
-		sizeof(buf));
-	rt5514_dsp->buf_base = buf[0] | buf[1] << 8 | buf[2] << 16 |
-				buf[3] << 24;
-
-	rt5514_spi_burst_read(RT5514_BUFFER_VOICE_LIMIT, (u8 *)&buf,
-		sizeof(buf));
-	rt5514_dsp->buf_limit = buf[0] | buf[1] << 8 | buf[2] << 16 |
-				buf[3] << 24;
-
-	rt5514_spi_burst_read(RT5514_BUFFER_VOICE_RP, (u8 *)&buf,
-		sizeof(buf));
-	rt5514_dsp->buf_rp = buf[0] | buf[1] << 8 | buf[2] << 16 |
-				buf[3] << 24;
-
-	rt5514_spi_burst_read(RT5514_BUFFER_VOICE_SIZE, (u8 *)&buf,
-		sizeof(buf));
-	rt5514_dsp->buf_size = buf[0] | buf[1] << 8 | buf[2] << 16 |
-				buf[3] << 24;
-
-	return 0;
-}
-
-static int rt5514_spi_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct rt5514_dsp *rt5514_dsp =
-			snd_soc_platform_get_drvdata(rtd->platform);
-
-	if (cmd == SNDRV_PCM_TRIGGER_START) {
-		if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit &&
-			rt5514_dsp->buf_rp && rt5514_dsp->buf_size)
-			schedule_delayed_work(&rt5514_dsp->copy_work, 0);
-	}
-
-	return 0;
-}
-
 static snd_pcm_uframes_t rt5514_spi_pcm_pointer(
 		struct snd_pcm_substream *substream)
 {
@@ -238,8 +240,6 @@ static const struct snd_pcm_ops rt5514_spi_pcm_ops = {
 	.open		= rt5514_spi_pcm_open,
 	.hw_params	= rt5514_spi_hw_params,
 	.hw_free	= rt5514_spi_hw_free,
-	.trigger	= rt5514_spi_trigger,
-	.prepare	= rt5514_spi_prepare,
 	.pointer	= rt5514_spi_pcm_pointer,
 	.mmap		= snd_pcm_lib_mmap_vmalloc,
 	.page		= snd_pcm_lib_get_vmalloc_page,
@@ -248,6 +248,7 @@ static const struct snd_pcm_ops rt5514_spi_pcm_ops = {
 static int rt5514_spi_pcm_probe(struct snd_soc_platform *platform)
 {
 	struct rt5514_dsp *rt5514_dsp;
+	int ret;
 
 	rt5514_dsp = devm_kzalloc(platform->dev, sizeof(*rt5514_dsp),
 			GFP_KERNEL);
@@ -257,10 +258,21 @@ static int rt5514_spi_pcm_probe(struct snd_soc_platform *platform)
 	INIT_DELAYED_WORK(&rt5514_dsp->copy_work, rt5514_spi_copy_work);
 	snd_soc_platform_set_drvdata(platform, rt5514_dsp);
 
+	if (rt5514_spi->irq) {
+		ret = devm_request_threaded_irq(&rt5514_spi->dev,
+			rt5514_spi->irq, NULL, rt5514_spi_irq,
+			IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5514-spi",
+			rt5514_dsp);
+		if (ret)
+			dev_err(&rt5514_spi->dev,
+				"%s Failed to reguest IRQ: %d\n", __func__,
+				ret);
+	}
+
 	return 0;
 }
 
-static struct snd_soc_platform_driver rt5514_spi_platform = {
+static const struct snd_soc_platform_driver rt5514_spi_platform = {
 	.probe = rt5514_spi_pcm_probe,
 	.ops = &rt5514_spi_pcm_ops,
 };
diff --git a/sound/soc/codecs/rt5514-spi.h b/sound/soc/codecs/rt5514-spi.h
index f69b1cdf2f9b..a6434ee6ff03 100644
--- a/sound/soc/codecs/rt5514-spi.h
+++ b/sound/soc/codecs/rt5514-spi.h
@@ -17,10 +17,9 @@
 */
 #define RT5514_SPI_BUF_LEN		240
 
-#define RT5514_BUFFER_VOICE_BASE	0x18001034
-#define RT5514_BUFFER_VOICE_LIMIT	0x18001038
-#define RT5514_BUFFER_VOICE_RP		0x1800103c
-#define RT5514_BUFFER_VOICE_SIZE	0x18001040
+#define RT5514_BUFFER_VOICE_BASE	0x18000200
+#define RT5514_BUFFER_VOICE_LIMIT	0x18000204
+#define RT5514_BUFFER_VOICE_WP		0x1800020c
 
 /* SPI Command */
 enum {
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 1b6796c4c471..0945d212b8dc 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -31,7 +31,7 @@
 
 #include "rl6231.h"
 #include "rt5514.h"
-#if defined(CONFIG_SND_SOC_RT5514_SPI)
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
 #include "rt5514-spi.h"
 #endif
 
@@ -63,6 +63,9 @@ static const struct reg_sequence rt5514_patch[] = {
 	{RT5514_SRC_CTRL,		0x44000eee},
 	{RT5514_ANA_CTRL_LDO10,		0x00028604},
 	{RT5514_ANA_CTRL_ADCFED,	0x00000800},
+	{RT5514_ASRC_IN_CTRL1,		0x00000003},
+	{RT5514_DOWNFILTER0_CTRL3,	0x10000362},
+	{RT5514_DOWNFILTER1_CTRL3,	0x10000362},
 };
 
 static const struct reg_default rt5514_reg[] = {
@@ -88,10 +91,10 @@ static const struct reg_default rt5514_reg[] = {
 	{RT5514_DELAY_BUF_CTRL3,	0x00000000},
 	{RT5514_DOWNFILTER0_CTRL1,	0x00020c2f},
 	{RT5514_DOWNFILTER0_CTRL2,	0x00020c2f},
-	{RT5514_DOWNFILTER0_CTRL3,	0x00000362},
+	{RT5514_DOWNFILTER0_CTRL3,	0x10000362},
 	{RT5514_DOWNFILTER1_CTRL1,	0x00020c2f},
 	{RT5514_DOWNFILTER1_CTRL2,	0x00020c2f},
-	{RT5514_DOWNFILTER1_CTRL3,	0x00000362},
+	{RT5514_DOWNFILTER1_CTRL3,	0x10000362},
 	{RT5514_ANA_CTRL_LDO10,		0x00028604},
 	{RT5514_ANA_CTRL_LDO18_16,	0x02000345},
 	{RT5514_ANA_CTRL_ADC12,		0x0000a2a8},
@@ -311,7 +314,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
 
 			request_firmware(&fw, RT5514_FIRMWARE1, codec->dev);
 			if (fw) {
-#if defined(CONFIG_SND_SOC_RT5514_SPI)
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
 				rt5514_spi_burst_write(0x4ff60000, fw->data,
 					((fw->size/8)+1)*8);
 #else
@@ -324,7 +327,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
 
 			request_firmware(&fw, RT5514_FIRMWARE2, codec->dev);
 			if (fw) {
-#if defined(CONFIG_SND_SOC_RT5514_SPI)
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
 				rt5514_spi_burst_write(0x4ffc0000, fw->data,
 					((fw->size/8)+1)*8);
 #else
@@ -335,6 +338,39 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
 				fw = NULL;
 			}
 
+			if (rt5514->model_buf && rt5514->model_len) {
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
+				int ret;
+
+				ret = rt5514_spi_burst_write(0x4ff80000,
+					rt5514->model_buf,
+					((rt5514->model_len / 8) + 1) * 8);
+				if (ret) {
+					dev_err(codec->dev,
+						"Model load failed %d\n", ret);
+					return ret;
+				}
+#else
+				dev_err(codec->dev,
+					"No SPI driver for loading firmware\n");
+#endif
+			} else {
+				request_firmware(&fw, RT5514_FIRMWARE3,
+						 codec->dev);
+				if (fw) {
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
+					rt5514_spi_burst_write(0x4ff80000,
+						fw->data,
+						((fw->size/8)+1)*8);
+#else
+					dev_err(codec->dev,
+						"No SPI driver to load fw\n");
+#endif
+					release_firmware(fw);
+					fw = NULL;
+				}
+			}
+
 			/* DSP run */
 			regmap_write(rt5514->i2c_regmap, 0x18002f00,
 				0x00055148);
@@ -349,6 +385,34 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static int rt5514_hotword_model_put(struct snd_kcontrol *kcontrol,
+		const unsigned int __user *bytes, unsigned int size)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_codec *codec = rt5514->codec;
+	int ret = 0;
+
+	if (rt5514->model_buf || rt5514->model_len < size) {
+		if (rt5514->model_buf)
+			devm_kfree(codec->dev, rt5514->model_buf);
+		rt5514->model_buf = devm_kmalloc(codec->dev, size, GFP_KERNEL);
+		if (!rt5514->model_buf) {
+			ret = -ENOMEM;
+			goto done;
+		}
+	}
+
+	/* Skips the TLV header. */
+	bytes += 2;
+
+	if (copy_from_user(rt5514->model_buf, bytes, size))
+		ret = -EFAULT;
+done:
+	rt5514->model_len = (ret ? 0 : size);
+	return ret;
+}
+
 static const struct snd_kcontrol_new rt5514_snd_controls[] = {
 	SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST,
 		RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv),
@@ -360,6 +424,8 @@ static const struct snd_kcontrol_new rt5514_snd_controls[] = {
 		adc_vol_tlv),
 	SOC_SINGLE_EXT("DSP Voice Wake Up", SND_SOC_NOPM, 0, 1, 0,
 		rt5514_dsp_voice_wake_up_get, rt5514_dsp_voice_wake_up_put),
+	SND_SOC_BYTES_TLV("Hotword Model", 0x8504,
+		NULL, rt5514_hotword_model_put),
 };
 
 /* ADC Mixer*/
@@ -471,33 +537,13 @@ static int rt5514_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 		return 0;
 }
 
-static int rt5514_pre_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
+static int rt5514_i2s_use_asrc(struct snd_soc_dapm_widget *source,
+	struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
 
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		/**
-		 * If the DSP is enabled in start of recording, the DSP
-		 * should be disabled, and sync back to normal recording
-		 * settings to make sure recording properly.
-		*/
-		if (rt5514->dsp_enabled) {
-			rt5514->dsp_enabled = 0;
-			regmap_multi_reg_write(rt5514->i2c_regmap,
-				rt5514_i2c_patch, ARRAY_SIZE(rt5514_i2c_patch));
-			regcache_mark_dirty(rt5514->regmap);
-			regcache_sync(rt5514->regmap);
-		}
-		break;
-
-	default:
-		return 0;
-	}
-
-	return 0;
+	return (rt5514->sysclk > rt5514->lrck * 384);
 }
 
 static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = {
@@ -570,6 +616,10 @@ static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = {
 		RT5514_POW_PLL1_LDO_BIT, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("PLL1", RT5514_PWR_ANA2, RT5514_POW_PLL1_BIT, 0,
 		NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ASRC AD1", 1, RT5514_CLK_CTRL2,
+		RT5514_CLK_AD0_ASRC_EN_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ASRC AD2", 1, RT5514_CLK_CTRL2,
+		RT5514_CLK_AD1_ASRC_EN_BIT, 0, NULL, 0),
 
 	/* ADC Mux */
 	SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0,
@@ -607,8 +657,6 @@ static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = {
 
 	/* Audio Interface */
 	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
-
-	SND_SOC_DAPM_PRE("DAPM Pre", rt5514_pre_event),
 };
 
 static const struct snd_soc_dapm_route rt5514_dapm_routes[] = {
@@ -669,6 +717,7 @@ static const struct snd_soc_dapm_route rt5514_dapm_routes[] = {
 	{ "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR" },
 	{ "Stereo1 ADC MIX", NULL, "adc stereo1 filter" },
 	{ "adc stereo1 filter", NULL, "PLL1", rt5514_is_sys_clk_from_pll },
+	{ "adc stereo1 filter", NULL, "ASRC AD1", rt5514_i2s_use_asrc },
 
 	{ "Stereo2 DMIC Mux", "DMIC1", "DMIC1" },
 	{ "Stereo2 DMIC Mux", "DMIC2", "DMIC2" },
@@ -685,6 +734,7 @@ static const struct snd_soc_dapm_route rt5514_dapm_routes[] = {
 	{ "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR" },
 	{ "Stereo2 ADC MIX", NULL, "adc stereo2 filter" },
 	{ "adc stereo2 filter", NULL, "PLL1", rt5514_is_sys_clk_from_pll },
+	{ "adc stereo2 filter", NULL, "ASRC AD2", rt5514_i2s_use_asrc },
 
 	{ "AIF1TX", NULL, "Stereo1 ADC MIX"},
 	{ "AIF1TX", NULL, "Stereo2 ADC MIX"},
@@ -737,6 +787,9 @@ static int rt5514_hw_params(struct snd_pcm_substream *substream,
 
 	regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, RT5514_I2S_DL_MASK,
 		val_len);
+	regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL1,
+		RT5514_CLK_AD_ANA1_SEL_MASK,
+		(pre_div + 1) << RT5514_CLK_AD_ANA1_SEL_SFT);
 	regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL2,
 		RT5514_CLK_SYS_DIV_OUT_MASK | RT5514_SEL_ADC_OSR_MASK,
 		pre_div << RT5514_CLK_SYS_DIV_OUT_SFT |
@@ -902,11 +955,38 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
-	unsigned int val = 0;
+	unsigned int val = 0, val2 = 0;
 
 	if (rx_mask || tx_mask)
 		val |= RT5514_TDM_MODE;
 
+	switch (tx_mask) {
+	case 0x3:
+		val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH2 |
+			RT5514_TDM_DOCKING_START_SLOT0;
+		break;
+
+	case 0x30:
+		val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH2 |
+			RT5514_TDM_DOCKING_START_SLOT4;
+		break;
+
+	case 0xf:
+		val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH4 |
+			RT5514_TDM_DOCKING_START_SLOT0;
+		break;
+
+	case 0xf0:
+		val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH4 |
+			RT5514_TDM_DOCKING_START_SLOT4;
+		break;
+
+	default:
+		break;
+	}
+
+
+
 	switch (slots) {
 	case 4:
 		val |= RT5514_TDMSLOT_SEL_RX_4CH | RT5514_TDMSLOT_SEL_TX_4CH;
@@ -952,6 +1032,10 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 		RT5514_CH_LEN_RX_MASK | RT5514_CH_LEN_TX_MASK |
 		RT5514_TDM_MODE2, val);
 
+	regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL2,
+		RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH_MASK |
+		RT5514_TDM_DOCKING_START_MASK, val2);
+
 	return 0;
 }
 
@@ -975,6 +1059,24 @@ static int rt5514_set_bias_level(struct snd_soc_codec *codec,
 		}
 		break;
 
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+			/*
+			 * If the DSP is enabled in start of recording, the DSP
+			 * should be disabled, and sync back to normal recording
+			 * settings to make sure recording properly.
+			 */
+			if (rt5514->dsp_enabled) {
+				rt5514->dsp_enabled = 0;
+				regmap_multi_reg_write(rt5514->i2c_regmap,
+					rt5514_i2c_patch,
+					ARRAY_SIZE(rt5514_i2c_patch));
+				regcache_mark_dirty(rt5514->regmap);
+				regcache_sync(rt5514->regmap);
+			}
+		}
+		break;
+
 	default:
 		break;
 	}
@@ -1019,7 +1121,7 @@ static int rt5514_i2c_write(void *context, unsigned int reg, unsigned int val)
 #define RT5514_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
-struct snd_soc_dai_ops rt5514_aif_dai_ops = {
+static const struct snd_soc_dai_ops rt5514_aif_dai_ops = {
 	.hw_params = rt5514_hw_params,
 	.set_fmt = rt5514_set_dai_fmt,
 	.set_sysclk = rt5514_set_dai_sysclk,
@@ -1027,7 +1129,7 @@ struct snd_soc_dai_ops rt5514_aif_dai_ops = {
 	.set_tdm_slot = rt5514_set_tdm_slot,
 };
 
-struct snd_soc_dai_driver rt5514_dai[] = {
+static struct snd_soc_dai_driver rt5514_dai[] = {
 	{
 		.name = "rt5514-aif1",
 		.id = 0,
@@ -1042,7 +1144,7 @@ struct snd_soc_dai_driver rt5514_dai[] = {
 	}
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt5514 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5514 = {
 	.probe = rt5514_probe,
 	.idle_bias_off = true,
 	.set_bias_level = rt5514_set_bias_level,
@@ -1097,7 +1199,7 @@ MODULE_DEVICE_TABLE(of, rt5514_of_match);
 #endif
 
 #ifdef CONFIG_ACPI
-static struct acpi_device_id rt5514_acpi_match[] = {
+static const struct acpi_device_id rt5514_acpi_match[] = {
 	{ "10EC5514", 0},
 	{},
 };
diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h
index 02bc212a86d9..803311cb7e2a 100644
--- a/sound/soc/codecs/rt5514.h
+++ b/sound/soc/codecs/rt5514.h
@@ -37,6 +37,7 @@
 #define RT5514_PLL3_CALIB_CTRL5			0x2124
 #define RT5514_DELAY_BUF_CTRL1			0x2140
 #define RT5514_DELAY_BUF_CTRL3			0x2148
+#define RT5514_ASRC_IN_CTRL1			0x2180
 #define RT5514_DOWNFILTER0_CTRL1		0x2190
 #define RT5514_DOWNFILTER0_CTRL2		0x2194
 #define RT5514_DOWNFILTER0_CTRL3		0x2198
@@ -164,6 +165,18 @@
 #define RT5514_I2S_DL_24			(0x2 << 0)
 #define RT5514_I2S_DL_8				(0x3 << 0)
 
+/* RT5514_I2S_CTRL2 (0x2014) */
+#define RT5514_TDM_DOCKING_MODE			(0x1 << 31)
+#define RT5514_TDM_DOCKING_MODE_SFT		31
+#define RT5514_TDM_DOCKING_VALID_CH_MASK	(0x1 << 29)
+#define RT5514_TDM_DOCKING_VALID_CH_SFT		29
+#define RT5514_TDM_DOCKING_VALID_CH2		(0x0 << 29)
+#define RT5514_TDM_DOCKING_VALID_CH4		(0x1 << 29)
+#define RT5514_TDM_DOCKING_START_MASK		(0x1 << 28)
+#define RT5514_TDM_DOCKING_START_SFT		28
+#define RT5514_TDM_DOCKING_START_SLOT0		(0x0 << 28)
+#define RT5514_TDM_DOCKING_START_SLOT4		(0x1 << 28)
+
 /* RT5514_DIG_SOURCE_CTRL (0x20a4) */
 #define RT5514_AD1_DMIC_INPUT_SEL		(0x1 << 1)
 #define RT5514_AD1_DMIC_INPUT_SEL_SFT		1
@@ -185,8 +198,14 @@
 #define RT5514_CLK_AD0_EN_BIT			23
 #define RT5514_CLK_DMIC_OUT_SEL_MASK		(0x7 << 8)
 #define RT5514_CLK_DMIC_OUT_SEL_SFT		8
+#define RT5514_CLK_AD_ANA1_SEL_MASK		(0xf << 0)
+#define RT5514_CLK_AD_ANA1_SEL_SFT		0
 
 /* RT5514_CLK_CTRL2 (0x2108) */
+#define RT5514_CLK_AD1_ASRC_EN			(0x1 << 17)
+#define RT5514_CLK_AD1_ASRC_EN_BIT		17
+#define RT5514_CLK_AD0_ASRC_EN			(0x1 << 16)
+#define RT5514_CLK_AD0_ASRC_EN_BIT		16
 #define RT5514_CLK_SYS_DIV_OUT_MASK		(0x7 << 8)
 #define RT5514_CLK_SYS_DIV_OUT_SFT		8
 #define RT5514_SEL_ADC_OSR_MASK			(0x7 << 4)
@@ -236,6 +255,7 @@
 
 #define RT5514_FIRMWARE1	"rt5514_dsp_fw1.bin"
 #define RT5514_FIRMWARE2	"rt5514_dsp_fw2.bin"
+#define RT5514_FIRMWARE3	"rt5514_dsp_fw3.bin"
 
 /* System Clock Source */
 enum {
@@ -262,6 +282,8 @@ struct rt5514_priv {
 	int pll_in;
 	int pll_out;
 	int dsp_enabled;
+	u8 *model_buf;
+	unsigned int model_len;
 };
 
 #endif /* __RT5514_H__ */
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
index 7d6e0823f98f..c94e94fe8297 100644
--- a/sound/soc/codecs/rt5616.c
+++ b/sound/soc/codecs/rt5616.c
@@ -1265,7 +1265,7 @@ static int rt5616_resume(struct snd_soc_codec *codec)
 #define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
-static struct snd_soc_dai_ops rt5616_aif_dai_ops = {
+static const struct snd_soc_dai_ops rt5616_aif_dai_ops = {
 	.hw_params = rt5616_hw_params,
 	.set_fmt = rt5616_set_dai_fmt,
 	.set_sysclk = rt5616_set_dai_sysclk,
@@ -1294,7 +1294,7 @@ static struct snd_soc_dai_driver rt5616_dai[] = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt5616 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5616 = {
 	.probe = rt5616_probe,
 	.suspend = rt5616_suspend,
 	.resume = rt5616_resume,
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 0e418089c053..55b04c55fb4b 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -1653,7 +1653,7 @@ static struct snd_soc_dai_driver rt5631_dai[] = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
 	.probe = rt5631_probe,
 	.set_bias_level = rt5631_set_bias_level,
 	.suspend_bias_off = true,
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 1584ccc3a87b..438fe52a12df 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -2259,7 +2259,7 @@ static struct snd_soc_dai_driver rt5640_dai[] = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
 	.probe = rt5640_probe,
 	.remove = rt5640_remove,
 	.suspend = rt5640_suspend,
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 9ec58166f7c4..6a7778a44853 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3473,7 +3473,7 @@ static struct snd_soc_dai_driver rt5645_dai[] = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt5645 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5645 = {
 	.probe = rt5645_probe,
 	.remove = rt5645_remove,
 	.suspend = rt5645_suspend,
@@ -3559,7 +3559,7 @@ static const struct acpi_device_id rt5645_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
 #endif
 
-static struct rt5645_platform_data general_platform_data = {
+static const struct rt5645_platform_data general_platform_data = {
 	.dmic1_data_pin = RT5645_DMIC1_DISABLE,
 	.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
 	.jd_mode = 3,
@@ -3593,7 +3593,7 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
 	{ }
 };
 
-static struct rt5645_platform_data buddy_platform_data = {
+static const struct rt5645_platform_data buddy_platform_data = {
 	.dmic1_data_pin = RT5645_DMIC_DATA_GPIO5,
 	.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
 	.jd_mode = 3,
@@ -3610,7 +3610,7 @@ static struct dmi_system_id dmi_platform_intel_broadwell[] = {
 	{ }
 };
 
-static struct rt5645_platform_data gpd_win_platform_data = {
+static const struct rt5645_platform_data gpd_win_platform_data = {
 	.jd_mode = 3,
 	.inv_jd1_1 = true,
 };
@@ -3637,6 +3637,39 @@ static const struct dmi_system_id dmi_platform_gpd_win[] = {
 	{}
 };
 
+static struct rt5645_platform_data general_platform_data2 = {
+	.dmic1_data_pin = RT5645_DMIC_DATA_IN2N,
+	.dmic2_data_pin = RT5645_DMIC2_DISABLE,
+	.jd_mode = 3,
+	.inv_jd1_1 = true,
+};
+
+static struct dmi_system_id dmi_platform_asus_t100ha[] = {
+	{
+		.ident = "ASUS T100HAN",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "T100HAN"),
+		},
+	},
+	{ }
+};
+
+static struct rt5645_platform_data minix_z83_4_platform_data = {
+	.jd_mode = 3,
+};
+
+static struct dmi_system_id dmi_platform_minix_z83_4[] = {
+	{
+		.ident = "MINIX Z83-4",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MINIX"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
+		},
+	},
+	{ }
+};
+
 static bool rt5645_check_dp(struct device *dev)
 {
 	if (device_property_present(dev, "realtek,in2-differential") ||
@@ -3689,6 +3722,10 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 		rt5645->pdata = general_platform_data;
 	else if (dmi_check_system(dmi_platform_gpd_win))
 		rt5645->pdata = gpd_win_platform_data;
+	else if (dmi_check_system(dmi_platform_asus_t100ha))
+		rt5645->pdata = general_platform_data2;
+	else if (dmi_check_system(dmi_platform_minix_z83_4))
+		rt5645->pdata = minix_z83_4_platform_data;
 
 	if (quirk != -1) {
 		rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk);
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index db05b60d5002..da60b28ba3df 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -1664,7 +1664,7 @@ static struct snd_soc_dai_driver rt5651_dai[] = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt5651 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5651 = {
 	.probe = rt5651_probe,
 	.suspend = rt5651_suspend,
 	.resume = rt5651_resume,
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index 1b7060850340..71216db15eab 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -3730,7 +3730,7 @@ static struct snd_soc_dai_driver rt5659_dai[] = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt5659 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5659 = {
 	.probe = rt5659_probe,
 	.remove = rt5659_remove,
 	.suspend = rt5659_suspend,
@@ -4222,7 +4222,7 @@ MODULE_DEVICE_TABLE(of, rt5659_of_match);
 #endif
 
 #ifdef CONFIG_ACPI
-static struct acpi_device_id rt5659_acpi_match[] = {
+static const struct acpi_device_id rt5659_acpi_match[] = {
 	{ "10EC5658", 0, },
 	{ "10EC5659", 0, },
 	{ },
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
index c93490d77f2a..d22ef00e0d96 100644
--- a/sound/soc/codecs/rt5660.c
+++ b/sound/soc/codecs/rt5660.c
@@ -1197,7 +1197,7 @@ static struct snd_soc_dai_driver rt5660_dai[] = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt5660 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5660 = {
 	.probe = rt5660_probe,
 	.remove = rt5660_remove,
 	.suspend = rt5660_suspend,
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index a33202affeb1..ab9e0ebff5a7 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -40,6 +40,7 @@ enum {
 
 struct rt5663_priv {
 	struct snd_soc_codec *codec;
+	struct rt5663_platform_data pdata;
 	struct regmap *regmap;
 	struct delayed_work jack_detect_work;
 	struct snd_soc_jack *hs_jack;
@@ -57,6 +58,11 @@ struct rt5663_priv {
 	int jack_type;
 };
 
+static const struct reg_sequence rt5663_patch_list[] = {
+	{ 0x002a, 0x8020 },
+	{ 0x0086, 0x0028 },
+};
+
 static const struct reg_default rt5663_v2_reg[] = {
 	{ 0x0000, 0x0000 },
 	{ 0x0001, 0xc8c8 },
@@ -466,7 +472,7 @@ static const struct reg_default rt5663_reg[] = {
 	{ 0x0006, 0x1000 },
 	{ 0x000a, 0x0000 },
 	{ 0x0010, 0x000f },
-	{ 0x0015, 0x42c1 },
+	{ 0x0015, 0x42f1 },
 	{ 0x0016, 0x0000 },
 	{ 0x0018, 0x000b },
 	{ 0x0019, 0xafaf },
@@ -476,7 +482,7 @@ static const struct reg_default rt5663_reg[] = {
 	{ 0x0023, 0x0039 },
 	{ 0x0026, 0xc0c0 },
 	{ 0x0029, 0x8080 },
-	{ 0x002a, 0xa0a0 },
+	{ 0x002a, 0x8020 },
 	{ 0x002c, 0x000c },
 	{ 0x002d, 0x0000 },
 	{ 0x0040, 0x0808 },
@@ -504,12 +510,12 @@ static const struct reg_default rt5663_reg[] = {
 	{ 0x0082, 0x0000 },
 	{ 0x0083, 0x0000 },
 	{ 0x0084, 0x0000 },
-	{ 0x0086, 0x0008 },
+	{ 0x0086, 0x0028 },
 	{ 0x0087, 0x0000 },
 	{ 0x008a, 0x0000 },
 	{ 0x008b, 0x0000 },
 	{ 0x008c, 0x0003 },
-	{ 0x008e, 0x0004 },
+	{ 0x008e, 0x0008 },
 	{ 0x008f, 0x1000 },
 	{ 0x0090, 0x0646 },
 	{ 0x0091, 0x0e3e },
@@ -520,7 +526,7 @@ static const struct reg_default rt5663_reg[] = {
 	{ 0x0098, 0x0000 },
 	{ 0x009a, 0x0000 },
 	{ 0x009f, 0x0000 },
-	{ 0x00ae, 0x2000 },
+	{ 0x00ae, 0x6000 },
 	{ 0x00af, 0x0000 },
 	{ 0x00b6, 0x0000 },
 	{ 0x00b7, 0x0000 },
@@ -538,7 +544,7 @@ static const struct reg_default rt5663_reg[] = {
 	{ 0x00d9, 0x08f9 },
 	{ 0x00db, 0x0008 },
 	{ 0x00dc, 0x00c0 },
-	{ 0x00dd, 0x6724 },
+	{ 0x00dd, 0x6729 },
 	{ 0x00de, 0x3131 },
 	{ 0x00df, 0x0008 },
 	{ 0x00e0, 0x4000 },
@@ -578,7 +584,7 @@ static const struct reg_default rt5663_reg[] = {
 	{ 0x0116, 0x0000 },
 	{ 0x0117, 0x0f00 },
 	{ 0x0118, 0x0006 },
-	{ 0x0125, 0x2224 },
+	{ 0x0125, 0x2424 },
 	{ 0x0126, 0x5550 },
 	{ 0x0127, 0x0400 },
 	{ 0x0128, 0x7711 },
@@ -596,8 +602,8 @@ static const struct reg_default rt5663_reg[] = {
 	{ 0x0145, 0x0002 },
 	{ 0x0146, 0x0000 },
 	{ 0x0160, 0x0e80 },
-	{ 0x0161, 0x0020 },
-	{ 0x0162, 0x0080 },
+	{ 0x0161, 0x0080 },
+	{ 0x0162, 0x0200 },
 	{ 0x0163, 0x0800 },
 	{ 0x0164, 0x0000 },
 	{ 0x0165, 0x0000 },
@@ -676,8 +682,8 @@ static const struct reg_default rt5663_reg[] = {
 	{ 0x0251, 0x0000 },
 	{ 0x0252, 0x028a },
 	{ 0x02fa, 0x0000 },
-	{ 0x02fb, 0x0000 },
-	{ 0x02fc, 0x0000 },
+	{ 0x02fb, 0x00a4 },
+	{ 0x02fc, 0x0300 },
 	{ 0x0300, 0x0000 },
 	{ 0x03d0, 0x0000 },
 	{ 0x03d1, 0x0000 },
@@ -1508,7 +1514,7 @@ static int rt5663_v2_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 {
 	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
-	int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
+	int val, i = 0;
 
 	dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert);
 
@@ -1543,25 +1549,68 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 			RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN);
 		snd_soc_update_bits(codec, RT5663_IRQ_1,
 			RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN);
-		while (i < 5) {
-			msleep(sleep_time[i]);
-			val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) &
-				0x0003;
-			dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n",
-				__func__, val, sleep_time[i]);
-			i++;
-			if (val == 0x1 || val == 0x2 || val == 0x3)
+
+		while (true) {
+			regmap_read(rt5663->regmap, RT5663_INT_ST_2, &val);
+			if (!(val & 0x80))
+				usleep_range(10000, 10005);
+			else
 				break;
+
+			if (i > 200)
+				break;
+			i++;
 		}
+
+		val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) & 0x0003;
 		dev_dbg(codec->dev, "%s val = %d\n", __func__, val);
+
+		snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+			RT5663_OSW_HP_L_MASK | RT5663_OSW_HP_R_MASK,
+			RT5663_OSW_HP_L_EN | RT5663_OSW_HP_R_EN);
+
 		switch (val) {
 		case 1:
 		case 2:
 			rt5663->jack_type = SND_JACK_HEADSET;
 			rt5663_enable_push_button_irq(codec, true);
+
+			if (rt5663->pdata.dc_offset_l_manual_mic) {
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2,
+					rt5663->pdata.dc_offset_l_manual_mic >>
+					16);
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_3,
+					rt5663->pdata.dc_offset_l_manual_mic &
+					0xffff);
+			}
+
+			if (rt5663->pdata.dc_offset_r_manual_mic) {
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_5,
+					rt5663->pdata.dc_offset_r_manual_mic >>
+					16);
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_6,
+					rt5663->pdata.dc_offset_r_manual_mic &
+					0xffff);
+			}
 			break;
 		default:
 			rt5663->jack_type = SND_JACK_HEADPHONE;
+
+			if (rt5663->pdata.dc_offset_l_manual) {
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2,
+					rt5663->pdata.dc_offset_l_manual >> 16);
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_3,
+					rt5663->pdata.dc_offset_l_manual &
+					0xffff);
+			}
+
+			if (rt5663->pdata.dc_offset_r_manual) {
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_5,
+					rt5663->pdata.dc_offset_r_manual >> 16);
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_6,
+					rt5663->pdata.dc_offset_r_manual &
+					0xffff);
+			}
 			break;
 		}
 	} else {
@@ -1656,6 +1705,9 @@ static void rt5663_jack_detect_work(struct work_struct *work)
 			default:
 				dev_err(codec->dev, "Unknown CODEC Version\n");
 			}
+
+			/* Delay the jack insert report to avoid pop noise */
+			msleep(30);
 		} else {
 			/* jack is already in, report button event */
 			report = SND_JACK_HEADSET;
@@ -1953,13 +2005,9 @@ static const struct snd_kcontrol_new rt5663_adda_r_mix[] = {
 static const struct snd_kcontrol_new rt5663_sto1_dac_l_mix[] = {
 	SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER,
 			RT5663_M_DAC_L1_STO_L_SHIFT, 1, 1),
-	SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER,
-			RT5663_M_DAC_R1_STO_L_SHIFT, 1, 1),
 };
 
 static const struct snd_kcontrol_new rt5663_sto1_dac_r_mix[] = {
-	SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER,
-			RT5663_M_DAC_L1_STO_R_SHIFT, 1, 1),
 	SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER,
 			RT5663_M_DAC_R1_STO_R_SHIFT, 1, 1),
 };
@@ -2024,10 +2072,6 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
 				RT5663_HP_SIG_SRC1_SILENCE);
 		} else {
 			snd_soc_write(codec, RT5663_DEPOP_2, 0x3003);
-			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b,
-				0x000b);
-			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030,
-				0x0030);
 			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
 				RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_DIS);
 			snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371);
@@ -2036,6 +2080,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
 			snd_soc_write(codec, RT5663_ANA_BIAS_CUR_1, 0x7766);
 			snd_soc_write(codec, RT5663_HP_BIAS, 0xafaa);
 			snd_soc_write(codec, RT5663_CHARGE_PUMP_2, 0x7777);
+			snd_soc_update_bits(codec, RT5663_STO_DRE_1, 0x8000,
+				0x8000);
 			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000,
 				0x3000);
 		}
@@ -2050,9 +2096,36 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
 			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x0);
 			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
 				RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN);
-			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0);
-			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b,
-				0x000b);
+		}
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5663_charge_pump_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (rt5663->codec_ver == CODEC_VER_0) {
+			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030,
+				0x0030);
+			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003,
+				0x0003);
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		if (rt5663->codec_ver == CODEC_VER_0) {
+			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003, 0);
+			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0);
 		}
 		break;
 
@@ -2182,6 +2255,9 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = {
 	SND_SOC_DAPM_DAC("DAC R", NULL, SND_SOC_NOPM, 0, 0),
 
 	/* Headphone*/
+	SND_SOC_DAPM_SUPPLY("HP Charge Pump", SND_SOC_NOPM, 0, 0,
+		rt5663_charge_pump_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5663_hp_event,
 		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 
@@ -2330,14 +2406,13 @@ static const struct snd_soc_dapm_route rt5663_dapm_routes[] = {
 	{ "DAC R1", NULL, "ADDA MIXR" },
 
 	{ "STO1 DAC MIXL", "DAC L Switch", "DAC L1" },
-	{ "STO1 DAC MIXL", "DAC R Switch", "DAC R1" },
 	{ "STO1 DAC MIXL", NULL, "STO1 DAC L Power" },
 	{ "STO1 DAC MIXL", NULL, "STO1 DAC Filter" },
 	{ "STO1 DAC MIXR", "DAC R Switch", "DAC R1" },
-	{ "STO1 DAC MIXR", "DAC L Switch", "DAC L1" },
 	{ "STO1 DAC MIXR", NULL, "STO1 DAC R Power" },
 	{ "STO1 DAC MIXR", NULL, "STO1 DAC Filter" },
 
+	{ "HP Amp", NULL, "HP Charge Pump" },
 	{ "HP Amp", NULL, "DAC L" },
 	{ "HP Amp", NULL, "DAC R" },
 };
@@ -2860,7 +2935,7 @@ static int rt5663_resume(struct snd_soc_codec *codec)
 #define RT5663_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
-static struct snd_soc_dai_ops rt5663_aif_dai_ops = {
+static const struct snd_soc_dai_ops rt5663_aif_dai_ops = {
 	.hw_params = rt5663_hw_params,
 	.set_fmt = rt5663_set_dai_fmt,
 	.set_sysclk = rt5663_set_dai_sysclk,
@@ -2891,7 +2966,7 @@ static struct snd_soc_dai_driver rt5663_dai[] = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt5663 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5663 = {
 	.probe = rt5663_probe,
 	.remove = rt5663_remove,
 	.suspend = rt5663_suspend,
@@ -2956,7 +3031,7 @@ MODULE_DEVICE_TABLE(of, rt5663_of_match);
 #endif
 
 #ifdef CONFIG_ACPI
-static struct acpi_device_id rt5663_acpi_match[] = {
+static const struct acpi_device_id rt5663_acpi_match[] = {
 	{ "10EC5663", 0},
 	{},
 };
@@ -2986,47 +3061,76 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663)
 {
 	int value, count;
 
-	regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0280);
+	regmap_write(rt5663->regmap, RT5663_RESET, 0x0000);
+	msleep(20);
+	regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_4, 0x00a1);
+	regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0380);
 	regmap_write(rt5663->regmap, RT5663_GLB_CLK, 0x8000);
-	regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x8001);
+	regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1000);
 	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_write(rt5663->regmap, RT5663_PWR_DIG_2, 0x8400);
-	regmap_write(rt5663->regmap, RT5663_CHOP_ADC, 0x3000);
-	regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b);
-	regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x8df8);
-	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x0003);
-	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x018c);
-	regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1111);
+	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_PWR_ANLG_1, 0xa23b);
+	msleep(30);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf23b);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x8000);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x0008);
 	regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_1, 0xffff);
 	regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_2, 0xffff);
+	regmap_write(rt5663->regmap, RT5663_CBJ_1, 0x8c10);
+	regmap_write(rt5663->regmap, RT5663_IL_CMD_2, 0x00c1);
+	regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_1, 0xb880);
+	regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_2, 0x4110);
+	regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_2, 0x4118);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5663->regmap, RT5663_INT_ST_2, &value);
+		if (!(value & 0x80))
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (++count > 200)
+			break;
+	}
+
+	regmap_write(rt5663->regmap, RT5663_HP_IMP_SEN_19, 0x0000);
 	regmap_write(rt5663->regmap, RT5663_DEPOP_2, 0x3003);
+	regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x0038);
 	regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b);
+	regmap_write(rt5663->regmap, RT5663_PWR_DIG_2, 0x8400);
+	regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x8df8);
+	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_HP_CHARGE_PUMP_2, 0x1371);
 	regmap_write(rt5663->regmap, RT5663_DACREF_LDO, 0x3b0b);
-	regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x2080);
+	msleep(40);
+	regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x0000);
 	regmap_write(rt5663->regmap, RT5663_BYPASS_STO_DAC, 0x000c);
-	regmap_write(rt5663->regmap, RT5663_HP_BIAS, 0xabba);
+	regmap_write(rt5663->regmap, RT5663_HP_BIAS, 0xafaa);
 	regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_1, 0x2224);
 	regmap_write(rt5663->regmap, RT5663_HP_OUT_EN, 0x8088);
 	regmap_write(rt5663->regmap, RT5663_STO_DRE_9, 0x0017);
 	regmap_write(rt5663->regmap, RT5663_STO_DRE_10, 0x0017);
 	regmap_write(rt5663->regmap, RT5663_STO1_ADC_MIXER, 0x4040);
+	regmap_write(rt5663->regmap, RT5663_CHOP_ADC, 0x3000);
 	regmap_write(rt5663->regmap, RT5663_RECMIX, 0x0005);
 	regmap_write(rt5663->regmap, RT5663_ADDA_RST, 0xc000);
 	regmap_write(rt5663->regmap, RT5663_STO1_HPF_ADJ1, 0x3320);
 	regmap_write(rt5663->regmap, RT5663_HP_CALIB_2, 0x00c9);
 	regmap_write(rt5663->regmap, RT5663_DUMMY_1, 0x004c);
-	regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_1, 0x7766);
-	regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0x4702);
-	msleep(200);
+	regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_1, 0x1111);
+	regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0x4402);
+	regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_2, 0x3311);
 	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1, 0x0069);
-	regmap_write(rt5663->regmap, RT5663_HP_CALIB_3, 0x06c2);
-	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x7b00);
-	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xfb00);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_3, 0x06ce);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x6800);
+	regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_2, 0x1100);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_7, 0x0057);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xe800);
+
 	count = 0;
 	while (true) {
 		regmap_read(rt5663->regmap, RT5663_HP_CALIB_1_1, &value);
@@ -3039,11 +3143,56 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663)
 			return;
 		count++;
 	}
+
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x6200);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_7, 0x0059);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xe200);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5663->regmap, RT5663_HP_CALIB_1_1, &value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 200)
+			return;
+		count++;
+	}
+
+	regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_1, 0xb8e0);
+	usleep_range(10000, 10005);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0x003b);
+	usleep_range(10000, 10005);
+	regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x0000);
+	usleep_range(10000, 10005);
+	regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x000b);
+	usleep_range(10000, 10005);
+	regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x0008);
+	usleep_range(10000, 10005);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x0000);
+	usleep_range(10000, 10005);
+}
+
+static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev)
+{
+	device_property_read_u32(dev, "realtek,dc_offset_l_manual",
+		&rt5663->pdata.dc_offset_l_manual);
+	device_property_read_u32(dev, "realtek,dc_offset_r_manual",
+		&rt5663->pdata.dc_offset_r_manual);
+	device_property_read_u32(dev, "realtek,dc_offset_l_manual_mic",
+		&rt5663->pdata.dc_offset_l_manual_mic);
+	device_property_read_u32(dev, "realtek,dc_offset_r_manual_mic",
+		&rt5663->pdata.dc_offset_r_manual_mic);
+
+	return 0;
 }
 
 static int rt5663_i2c_probe(struct i2c_client *i2c,
 		    const struct i2c_device_id *id)
 {
+	struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev);
 	struct rt5663_priv *rt5663;
 	int ret;
 	unsigned int val;
@@ -3057,6 +3206,11 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, rt5663);
 
+	if (pdata)
+		rt5663->pdata = *pdata;
+	else
+		rt5663_parse_dp(rt5663, &i2c->dev);
+
 	regmap = devm_regmap_init_i2c(i2c, &temp_regmap);
 	if (IS_ERR(regmap)) {
 		ret = PTR_ERR(regmap);
@@ -3105,6 +3259,20 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
 	regmap_write(rt5663->regmap, RT5663_RESET, 0);
 	dev_dbg(&i2c->dev, "calibrate done\n");
 
+	switch (rt5663->codec_ver) {
+	case CODEC_VER_1:
+		break;
+	case CODEC_VER_0:
+		ret = regmap_register_patch(rt5663->regmap, rt5663_patch_list,
+					    ARRAY_SIZE(rt5663_patch_list));
+		if (ret != 0)
+			dev_warn(&i2c->dev,
+				"Failed to apply regmap patch: %d\n", ret);
+		break;
+	default:
+		dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__);
+	}
+
 	/* GPIO1 as IRQ */
 	regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5663_GP1_PIN_MASK,
 		RT5663_GP1_PIN_IRQ);
diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h
index 4621812c94d8..c5a9b69579ad 100644
--- a/sound/soc/codecs/rt5663.h
+++ b/sound/soc/codecs/rt5663.h
@@ -12,6 +12,8 @@
 #ifndef __RT5663_H__
 #define __RT5663_H__
 
+#include <sound/rt5663.h>
+
 /* Info */
 #define RT5663_RESET				0x0000
 #define RT5663_VENDOR_ID			0x00fd
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index d0a9490f97f1..f05d362c4e23 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -4411,12 +4411,12 @@ static int rt5665_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 		switch (dai->id) {
 		case RT5665_AIF2_1:
 		case RT5665_AIF2_2:
-			snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+			snd_soc_update_bits(codec, RT5665_ADDA_CLK_2,
 				RT5665_I2S_BCLK_MS2_MASK,
 				RT5665_I2S_BCLK_MS2_64);
 			break;
 		case RT5665_AIF3:
-			snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+			snd_soc_update_bits(codec, RT5665_ADDA_CLK_2,
 				RT5665_I2S_BCLK_MS3_MASK,
 				RT5665_I2S_BCLK_MS3_64);
 			break;
@@ -4605,7 +4605,7 @@ static struct snd_soc_dai_driver rt5665_dai[] = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt5665 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5665 = {
 	.probe = rt5665_probe,
 	.remove = rt5665_remove,
 	.suspend = rt5665_suspend,
diff --git a/sound/soc/codecs/rt5665.h b/sound/soc/codecs/rt5665.h
index 8f08acb9c446..5ddebd6a4a1b 100644
--- a/sound/soc/codecs/rt5665.h
+++ b/sound/soc/codecs/rt5665.h
@@ -1713,8 +1713,8 @@
 #define RT5665_GP6_PIN_MASK			(0x3 << 5)
 #define RT5665_GP6_PIN_SFT			5
 #define RT5665_GP6_PIN_GPIO6			(0x0 << 5)
-#define RT5665_GP6_PIN_BCLK3			(0x0 << 5)
-#define RT5665_GP6_PIN_PDM_SCL			(0x1 << 5)
+#define RT5665_GP6_PIN_BCLK3			(0x1 << 5)
+#define RT5665_GP6_PIN_PDM_SCL			(0x2 << 5)
 #define RT5665_GP7_PIN_MASK			(0x3 << 3)
 #define RT5665_GP7_PIN_SFT			3
 #define RT5665_GP7_PIN_GPIO7			(0x0 << 3)
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 0ec7985ed306..9545764ef3eb 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -567,7 +567,7 @@ int rt5670_set_jack_detect(struct snd_soc_codec *codec,
 
 	rt5670->jack = jack;
 	rt5670->hp_gpio.gpiod_dev = codec->dev;
-	rt5670->hp_gpio.name = "headphone detect";
+	rt5670->hp_gpio.name = "headset";
 	rt5670->hp_gpio.report = SND_JACK_HEADSET |
 		SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2;
 	rt5670->hp_gpio.debounce_time = 150;
@@ -1151,20 +1151,15 @@ static const char * const rt5670_stereo_adc1_src[] = {
 static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc1_enum, RT5670_STO1_ADC_MIXER,
 	RT5670_ADC_1_SRC_SFT, rt5670_stereo_adc1_src);
 
-static const struct snd_kcontrol_new rt5670_sto_adc_l1_mux =
-	SOC_DAPM_ENUM("Stereo1 ADC L1 source", rt5670_stereo1_adc1_enum);
-
-static const struct snd_kcontrol_new rt5670_sto_adc_r1_mux =
-	SOC_DAPM_ENUM("Stereo1 ADC R1 source", rt5670_stereo1_adc1_enum);
+static const struct snd_kcontrol_new rt5670_sto_adc_1_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC 1 Mux", rt5670_stereo1_adc1_enum);
 
 static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc1_enum, RT5670_STO2_ADC_MIXER,
 	RT5670_ADC_1_SRC_SFT, rt5670_stereo_adc1_src);
 
-static const struct snd_kcontrol_new rt5670_sto2_adc_l1_mux =
-	SOC_DAPM_ENUM("Stereo2 ADC L1 source", rt5670_stereo2_adc1_enum);
+static const struct snd_kcontrol_new rt5670_sto2_adc_1_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC 1 Mux", rt5670_stereo2_adc1_enum);
 
-static const struct snd_kcontrol_new rt5670_sto2_adc_r1_mux =
-	SOC_DAPM_ENUM("Stereo2 ADC R1 source", rt5670_stereo2_adc1_enum);
 
 /* MX-27 MX-26 [11] */
 static const char * const rt5670_stereo_adc2_src[] = {
@@ -1174,20 +1169,15 @@ static const char * const rt5670_stereo_adc2_src[] = {
 static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc2_enum, RT5670_STO1_ADC_MIXER,
 	RT5670_ADC_2_SRC_SFT, rt5670_stereo_adc2_src);
 
-static const struct snd_kcontrol_new rt5670_sto_adc_l2_mux =
-	SOC_DAPM_ENUM("Stereo1 ADC L2 source", rt5670_stereo1_adc2_enum);
-
-static const struct snd_kcontrol_new rt5670_sto_adc_r2_mux =
-	SOC_DAPM_ENUM("Stereo1 ADC R2 source", rt5670_stereo1_adc2_enum);
+static const struct snd_kcontrol_new rt5670_sto_adc_2_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC 2 Mux", rt5670_stereo1_adc2_enum);
 
 static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc2_enum, RT5670_STO2_ADC_MIXER,
 	RT5670_ADC_2_SRC_SFT, rt5670_stereo_adc2_src);
 
-static const struct snd_kcontrol_new rt5670_sto2_adc_l2_mux =
-	SOC_DAPM_ENUM("Stereo2 ADC L2 source", rt5670_stereo2_adc2_enum);
+static const struct snd_kcontrol_new rt5670_sto2_adc_2_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC 2 Mux", rt5670_stereo2_adc2_enum);
 
-static const struct snd_kcontrol_new rt5670_sto2_adc_r2_mux =
-	SOC_DAPM_ENUM("Stereo2 ADC R2 source", rt5670_stereo2_adc2_enum);
 
 /* MX-27 MX26 [10] */
 static const char * const rt5670_stereo_adc_src[] = {
@@ -1642,23 +1632,23 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
 	SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0,
 			 &rt5670_sto1_dmic_mux),
 	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
-			 &rt5670_sto_adc_l2_mux),
+			 &rt5670_sto_adc_2_mux),
 	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
-			 &rt5670_sto_adc_r2_mux),
+			 &rt5670_sto_adc_2_mux),
 	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
-			 &rt5670_sto_adc_l1_mux),
+			 &rt5670_sto_adc_1_mux),
 	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
-			 &rt5670_sto_adc_r1_mux),
+			 &rt5670_sto_adc_1_mux),
 	SND_SOC_DAPM_MUX("Stereo2 DMIC Mux", SND_SOC_NOPM, 0, 0,
 			 &rt5670_sto2_dmic_mux),
 	SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
-			 &rt5670_sto2_adc_l2_mux),
+			 &rt5670_sto2_adc_2_mux),
 	SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
-			 &rt5670_sto2_adc_r2_mux),
+			 &rt5670_sto2_adc_2_mux),
 	SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
-			 &rt5670_sto2_adc_l1_mux),
+			 &rt5670_sto2_adc_1_mux),
 	SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
-			 &rt5670_sto2_adc_r1_mux),
+			 &rt5670_sto2_adc_1_mux),
 	SND_SOC_DAPM_MUX("Stereo2 ADC LR Mux", SND_SOC_NOPM, 0, 0,
 			 &rt5670_sto2_adc_lr_mux),
 	SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0,
@@ -2743,6 +2733,7 @@ static struct snd_soc_dai_driver rt5670_dai[] = {
 			.formats = RT5670_FORMATS,
 		},
 		.ops = &rt5670_aif_dai_ops,
+		.symmetric_rates = 1,
 	},
 	{
 		.name = "rt5670-aif2",
@@ -2762,10 +2753,11 @@ static struct snd_soc_dai_driver rt5670_dai[] = {
 			.formats = RT5670_FORMATS,
 		},
 		.ops = &rt5670_aif_dai_ops,
+		.symmetric_rates = 1,
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt5670 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5670 = {
 	.probe = rt5670_probe,
 	.remove = rt5670_remove,
 	.suspend = rt5670_suspend,
@@ -2859,6 +2851,17 @@ static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode2[] = {
 	{}
 };
 
+static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode3[] = {
+	{
+		.ident = "Dell Venue 8 Pro 5855",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5855"),
+		},
+	},
+	{}
+};
+
 static int rt5670_i2c_probe(struct i2c_client *i2c,
 		    const struct i2c_device_id *id)
 {
@@ -2888,6 +2891,11 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
 		rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
 		rt5670->pdata.dev_gpio = true;
 		rt5670->pdata.jd_mode = 2;
+	} else if (dmi_check_system(dmi_platform_intel_bytcht_jdmode3)) {
+		rt5670->pdata.dmic_en = true;
+		rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
+		rt5670->pdata.dev_gpio = true;
+		rt5670->pdata.jd_mode = 3;
 	}
 
 	rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 36e530a36c82..0791fec398fb 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -21,6 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/firmware.h>
+#include <linux/of_device.h>
 #include <linux/property.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -779,9 +780,7 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
 	return 0;
 }
 
-static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
 static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
-static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
 static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
 static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
 static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0);
@@ -4624,35 +4623,27 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
 	struct regmap_irq_chip_data *data = rt5677->irq_data;
 	int irq;
 
-	if (offset >= RT5677_GPIO1 && offset <= RT5677_GPIO3) {
-		if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) ||
-			(rt5677->pdata.jd1_gpio == 2 &&
-				offset == RT5677_GPIO2) ||
-			(rt5677->pdata.jd1_gpio == 3 &&
-				offset == RT5677_GPIO3)) {
-			irq = RT5677_IRQ_JD1;
-		} else {
-			return -ENXIO;
-		}
-	}
-
-	if (offset >= RT5677_GPIO4 && offset <= RT5677_GPIO6) {
-		if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) ||
-			(rt5677->pdata.jd2_gpio == 2 &&
-				offset == RT5677_GPIO5) ||
-			(rt5677->pdata.jd2_gpio == 3 &&
-				offset == RT5677_GPIO6)) {
-			irq = RT5677_IRQ_JD2;
-		} else if ((rt5677->pdata.jd3_gpio == 1 &&
-				offset == RT5677_GPIO4) ||
-			(rt5677->pdata.jd3_gpio == 2 &&
-				offset == RT5677_GPIO5) ||
-			(rt5677->pdata.jd3_gpio == 3 &&
-				offset == RT5677_GPIO6)) {
-			irq = RT5677_IRQ_JD3;
-		} else {
-			return -ENXIO;
-		}
+	if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) ||
+		(rt5677->pdata.jd1_gpio == 2 &&
+			offset == RT5677_GPIO2) ||
+		(rt5677->pdata.jd1_gpio == 3 &&
+			offset == RT5677_GPIO3)) {
+		irq = RT5677_IRQ_JD1;
+	} else if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) ||
+		(rt5677->pdata.jd2_gpio == 2 &&
+			offset == RT5677_GPIO5) ||
+		(rt5677->pdata.jd2_gpio == 3 &&
+			offset == RT5677_GPIO6)) {
+		irq = RT5677_IRQ_JD2;
+	} else if ((rt5677->pdata.jd3_gpio == 1 &&
+			offset == RT5677_GPIO4) ||
+		(rt5677->pdata.jd3_gpio == 2 &&
+			offset == RT5677_GPIO5) ||
+		(rt5677->pdata.jd3_gpio == 3 &&
+			offset == RT5677_GPIO6)) {
+		irq = RT5677_IRQ_JD3;
+	} else {
+		return -ENXIO;
 	}
 
 	return regmap_irq_get_virq(data, irq);
@@ -4968,7 +4959,7 @@ static struct snd_soc_dai_driver rt5677_dai[] = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_rt5677 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5677 = {
 	.probe = rt5677_probe,
 	.remove = rt5677_remove,
 	.suspend = rt5677_suspend,
@@ -5026,18 +5017,16 @@ static const struct i2c_device_id rt5677_i2c_id[] = {
 MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
 
 static const struct of_device_id rt5677_of_match[] = {
-	{ .compatible = "realtek,rt5677", },
+	{ .compatible = "realtek,rt5677", RT5677 },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, rt5677_of_match);
 
-#ifdef CONFIG_ACPI
 static const struct acpi_device_id rt5677_acpi_match[] = {
 	{ "RT5677CE", RT5677 },
 	{ }
 };
 MODULE_DEVICE_TABLE(acpi, rt5677_acpi_match);
-#endif
 
 static void rt5677_read_acpi_properties(struct rt5677_priv *rt5677,
 		struct device *dev)
@@ -5147,7 +5136,6 @@ static void rt5677_free_irq(struct i2c_client *i2c)
 static int rt5677_i2c_probe(struct i2c_client *i2c,
 		    const struct i2c_device_id *id)
 {
-	struct rt5677_platform_data *pdata = dev_get_platdata(&i2c->dev);
 	struct rt5677_priv *rt5677;
 	int ret;
 	unsigned int val;
@@ -5159,16 +5147,25 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, rt5677);
 
-	rt5677->type = id->driver_data;
+	if (i2c->dev.of_node) {
+		const struct of_device_id *match_id;
+
+		match_id = of_match_device(rt5677_of_match, &i2c->dev);
+		if (match_id)
+			rt5677->type = (enum rt5677_type)match_id->data;
 
-	if (pdata)
-		rt5677->pdata = *pdata;
-	else if (i2c->dev.of_node)
 		rt5677_read_device_properties(rt5677, &i2c->dev);
-	else if (ACPI_HANDLE(&i2c->dev))
+	} else if (ACPI_HANDLE(&i2c->dev)) {
+		const struct acpi_device_id *acpi_id;
+
+		acpi_id = acpi_match_device(rt5677_acpi_match, &i2c->dev);
+		if (acpi_id)
+			rt5677->type = (enum rt5677_type)acpi_id->driver_data;
+
 		rt5677_read_acpi_properties(rt5677, &i2c->dev);
-	else
+	} else {
 		return -EINVAL;
+	}
 
 	/* pow-ldo2 and reset are optional. The codec pins may be statically
 	 * connected on the board without gpios. If the gpio device property
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h
index d46855a42c40..97239973edc4 100644
--- a/sound/soc/codecs/rt5677.h
+++ b/sound/soc/codecs/rt5677.h
@@ -12,7 +12,6 @@
 #ifndef __RT5677_H__
 #define __RT5677_H__
 
-#include <sound/rt5677.h>
 #include <linux/gpio/driver.h>
 #include <linux/gpio/consumer.h>
 
@@ -1761,6 +1760,35 @@ enum {
 	RT5677_I2S4_SOURCE = (0x1 << 18),
 };
 
+enum rt5677_dmic2_clk {
+	RT5677_DMIC_CLK1 = 0,
+	RT5677_DMIC_CLK2 = 1,
+};
+
+struct rt5677_platform_data {
+	/* IN1/IN2/LOUT1/LOUT2/LOUT3 can optionally be differential */
+	bool in1_diff;
+	bool in2_diff;
+	bool lout1_diff;
+	bool lout2_diff;
+	bool lout3_diff;
+	/* DMIC2 clock source selection */
+	enum rt5677_dmic2_clk dmic2_clk_pin;
+
+	/* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */
+	u8 gpio_config[6];
+
+	/* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */
+	unsigned int jd1_gpio;
+	/* jd2 and jd3 can select 0 ~ 3 as
+		OFF, GPIO4, GPIO5 and GPIO6 respectively */
+	unsigned int jd2_gpio;
+	unsigned int jd3_gpio;
+
+	/* Set MICBIAS1 VDD 1v8 or 3v3 */
+	bool micbias1_vdd_3v3;
+};
+
 struct rt5677_priv {
 	struct snd_soc_codec *codec;
 	struct rt5677_platform_data pdata;
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 8f6814c1eb6b..f2bb4feba3b6 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -409,7 +409,7 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
 static int avc_get_threshold(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	int db, i;
 	u16 reg = snd_soc_read(codec, SGTL5000_DAP_AVC_THRESHOLD);
 
@@ -442,7 +442,7 @@ static int avc_get_threshold(struct snd_kcontrol *kcontrol,
 static int avc_put_threshold(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	int db;
 	u16 reg;
 
@@ -1248,7 +1248,7 @@ static int sgtl5000_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver sgtl5000_driver = {
+static const struct snd_soc_codec_driver sgtl5000_driver = {
 	.probe = sgtl5000_probe,
 	.remove = sgtl5000_remove,
 	.set_bias_level = sgtl5000_set_bias_level,
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index 5344f4aa8fde..354dc0d64f11 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -236,7 +236,7 @@ static struct regmap *si476x_get_regmap(struct device *dev)
 	return dev_get_regmap(dev->parent, NULL);
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_si476x = {
+static const struct snd_soc_codec_driver soc_codec_dev_si476x = {
 	.get_regmap = si476x_get_regmap,
 	.component_driver = {
 		.dapm_widgets		= si476x_dapm_widgets,
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
index 6bfd25c289d1..7ae8c181d1a4 100644
--- a/sound/soc/codecs/sirf-audio-codec.c
+++ b/sound/soc/codecs/sirf-audio-codec.c
@@ -429,13 +429,15 @@ static int sirf_audio_codec_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = {
+static const struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = {
 	.probe = sirf_audio_codec_probe,
 	.remove = sirf_audio_codec_remove,
-	.dapm_widgets = sirf_audio_codec_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
-	.dapm_routes = sirf_audio_codec_map,
-	.num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map),
+	.component_driver = {
+		.dapm_widgets = sirf_audio_codec_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
+		.dapm_routes = sirf_audio_codec_map,
+		.num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map),
+	},
 	.idle_bias_off = true,
 };
 
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
index eae54c37cff9..887923e68849 100644
--- a/sound/soc/codecs/sn95031.c
+++ b/sound/soc/codecs/sn95031.c
@@ -883,7 +883,7 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver sn95031_codec = {
+static const struct snd_soc_codec_driver sn95031_codec = {
 	.probe		= sn95031_codec_probe,
 	.set_bias_level	= sn95031_set_vaud_bias,
 	.idle_bias_off	= true,
diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c
index 234f87b54838..7acd05140a81 100644
--- a/sound/soc/codecs/spdif_receiver.c
+++ b/sound/soc/codecs/spdif_receiver.c
@@ -37,7 +37,7 @@ static const struct snd_soc_dapm_route dir_routes[] = {
 			SNDRV_PCM_FMTBIT_S24_LE | \
 			SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
 
-static struct snd_soc_codec_driver soc_codec_spdif_dir = {
+static const struct snd_soc_codec_driver soc_codec_spdif_dir = {
 	.component_driver = {
 		.dapm_widgets		= dir_widgets,
 		.num_dapm_widgets	= ARRAY_SIZE(dir_widgets),
diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c
index ee367536a498..063a64ff82d3 100644
--- a/sound/soc/codecs/spdif_transmitter.c
+++ b/sound/soc/codecs/spdif_transmitter.c
@@ -37,7 +37,7 @@ static const struct snd_soc_dapm_route dit_routes[] = {
 	{ "spdif-out", NULL, "Playback" },
 };
 
-static struct snd_soc_codec_driver soc_codec_spdif_dit = {
+static const struct snd_soc_codec_driver soc_codec_spdif_dit = {
 	.component_driver = {
 		.dapm_widgets		= dit_widgets,
 		.num_dapm_widgets	= ARRAY_SIZE(dit_widgets),
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index 38a85f3adc80..15486fd16269 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -710,7 +710,7 @@ static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 			SSM2518_POWER1_NO_BCLK, val);
 }
 
-static struct snd_soc_codec_driver ssm2518_codec_driver = {
+static const struct snd_soc_codec_driver ssm2518_codec_driver = {
 	.set_bias_level = ssm2518_set_bias_level,
 	.set_sysclk = ssm2518_set_sysclk,
 	.idle_bias_off = true,
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 993bde29ca1b..9b341c23f62b 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -591,7 +591,7 @@ static int ssm260x_codec_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
 	.probe =	ssm260x_codec_probe,
 	.resume =	ssm2602_resume,
 	.set_bias_level = ssm2602_set_bias_level,
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
index a622623e8558..4afeddef7728 100644
--- a/sound/soc/codecs/ssm4567.c
+++ b/sound/soc/codecs/ssm4567.c
@@ -417,7 +417,7 @@ static struct snd_soc_dai_driver ssm4567_dai = {
 	.ops = &ssm4567_dai_ops,
 };
 
-static struct snd_soc_codec_driver ssm4567_codec_driver = {
+static const struct snd_soc_codec_driver ssm4567_codec_driver = {
 	.set_bias_level = ssm4567_set_bias_level,
 	.idle_bias_off = true,
 
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index 9de7fe8af255..c66363a2cac7 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -307,7 +307,7 @@ static int stac9766_codec_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
+static const struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
 	.component_driver = {
 		.controls		= stac9766_snd_ac97_controls,
 		.num_controls		= ARRAY_SIZE(stac9766_snd_ac97_controls),
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 8840f72f3c4a..49cf9bc32eb6 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -660,7 +660,7 @@ static int tas2552_resume(struct snd_soc_codec *codec)
 #define tas2552_resume NULL
 #endif
 
-static struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
+static const struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
 	.probe = tas2552_codec_probe,
 	.remove = tas2552_codec_remove,
 	.suspend =	tas2552_suspend,
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index b7de857abb16..199272d5cb6a 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -885,7 +885,7 @@ static int tas5086_remove(struct snd_soc_codec *codec)
 	return 0;
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
+static const struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
 	.probe			= tas5086_probe,
 	.remove			= tas5086_remove,
 	.suspend		= tas5086_soc_suspend,
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c
index c65b917598d2..a736a2a6976c 100644
--- a/sound/soc/codecs/tas5720.c
+++ b/sound/soc/codecs/tas5720.c
@@ -483,7 +483,7 @@ static const struct snd_soc_dapm_route tas5720_audio_map[] = {
 	{ "OUT", NULL, "DAC" },
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_tas5720 = {
+static const struct snd_soc_codec_driver soc_codec_dev_tas5720 = {
 	.probe = tas5720_codec_probe,
 	.remove = tas5720_codec_remove,
 	.suspend = tas5720_suspend,
@@ -507,7 +507,7 @@ static struct snd_soc_codec_driver soc_codec_dev_tas5720 = {
 #define TAS5720_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\
 			 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops tas5720_speaker_dai_ops = {
+static const struct snd_soc_dai_ops tas5720_speaker_dai_ops = {
 	.hw_params	= tas5720_hw_params,
 	.set_fmt	= tas5720_set_dai_fmt,
 	.set_tdm_slot	= tas5720_set_dai_tdm_slot,
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 628a8eeaab68..3d42138a7974 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -576,7 +576,7 @@ static int tlv320aic23_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
+static const struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
 	.probe = tlv320aic23_codec_probe,
 	.resume = tlv320aic23_resume,
 	.set_bias_level = tlv320aic23_set_bias_level,
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 14aa96d41719..89421caaeb70 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -319,7 +319,7 @@ static int aic26_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver aic26_soc_codec_dev = {
+static const struct snd_soc_codec_driver aic26_soc_codec_dev = {
 	.probe = aic26_probe,
 	.component_driver = {
 		.controls		= aic26_snd_controls,
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index d7d03c92cb8a..54a87a905eb6 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1185,7 +1185,7 @@ static int aic31xx_codec_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
+static const struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
 	.probe			= aic31xx_codec_probe,
 	.remove			= aic31xx_codec_remove,
 	.set_bias_level		= aic31xx_set_bias_level,
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 28fdfc5ec544..ccfc955321ae 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -792,7 +792,7 @@ static int aic32x4_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
+static const struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
 	.probe = aic32x4_codec_probe,
 	.set_bias_level = aic32x4_set_bias_level,
 	.suspend_bias_off = true,
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 29bf8c81ae02..405f4602888a 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1684,7 +1684,7 @@ static int aic3x_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
+static const struct snd_soc_codec_driver soc_codec_dev_aic3x = {
 	.set_bias_level = aic3x_set_bias_level,
 	.idle_bias_off = true,
 	.probe = aic3x_probe,
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 7bcf01efdf9a..5b94a151539c 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -1433,7 +1433,7 @@ static int dac33_soc_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
+static const struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
 	.read = dac33_read_reg_cache,
 	.write = dac33_write_locked,
 	.set_bias_level = dac33_set_bias_level,
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index a2104d68169d..d439c4c6fe50 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -2191,7 +2191,7 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
+static const struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
 	.probe = twl4030_soc_probe,
 	.remove = twl4030_soc_remove,
 	.read = twl4030_read,
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 2b6ad09e0886..0dc21f7e0af9 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -1155,7 +1155,7 @@ static int twl6040_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
+static const struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
 	.probe = twl6040_probe,
 	.remove = twl6040_remove,
 	.read = twl6040_read,
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 5fdee874406d..77c9cc4467b8 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -518,7 +518,7 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
+static const struct snd_soc_codec_driver soc_codec_dev_uda134x = {
 	.probe =        uda134x_soc_probe,
 	.set_bias_level = uda134x_set_bias_level,
 	.suspend_bias_off = true,
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 61cdc79840e7..926c81ae8185 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -720,7 +720,7 @@ static int uda1380_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
+static const struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
 	.probe =	uda1380_probe,
 	.read =		uda1380_read_reg_cache,
 	.write =	uda1380_write,
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index fcffb6e707d9..942f1644973e 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -480,7 +480,7 @@ static int wl1273_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
 	.probe = wl1273_probe,
 	.remove = wl1273_remove,
 
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 1fe358e6be61..72486bf072f2 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -2017,7 +2017,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
 	},
 };
 
-static struct snd_compr_ops wm5102_compr_ops = {
+static const struct snd_compr_ops wm5102_compr_ops = {
 	.open = wm5102_open,
 	.free = wm_adsp_compr_free,
 	.set_params = wm_adsp_compr_set_params,
@@ -2027,7 +2027,7 @@ static struct snd_compr_ops wm5102_compr_ops = {
 	.copy = wm_adsp_compr_copy,
 };
 
-static struct snd_soc_platform_driver wm5102_compr_platform = {
+static const struct snd_soc_platform_driver wm5102_compr_platform = {
 	.compr_ops = &wm5102_compr_ops,
 };
 
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 1bc942152eff..858a24fc28e8 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -2372,7 +2372,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
 	},
 };
 
-static struct snd_compr_ops wm5110_compr_ops = {
+static const struct snd_compr_ops wm5110_compr_ops = {
 	.open = wm5110_open,
 	.free = wm_adsp_compr_free,
 	.set_params = wm_adsp_compr_set_params,
@@ -2382,7 +2382,7 @@ static struct snd_compr_ops wm5110_compr_ops = {
 	.copy = wm_adsp_compr_copy,
 };
 
-static struct snd_soc_platform_driver wm5110_compr_platform = {
+static const struct snd_soc_platform_driver wm5110_compr_platform = {
 	.compr_ops = &wm5110_compr_ops,
 };
 
diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c
index 032fb7cf6cbd..51fad48892d3 100644
--- a/sound/soc/codecs/zx_aud96p22.c
+++ b/sound/soc/codecs/zx_aud96p22.c
@@ -261,7 +261,7 @@ static const struct snd_soc_dapm_route aud96p22_dapm_routes[] = {
 	{ "LINEOUTMN", NULL, "LD2" },
 };
 
-static struct snd_soc_codec_driver aud96p22_driver = {
+static const struct snd_soc_codec_driver aud96p22_driver = {
 	.component_driver = {
 		.controls = aud96p22_snd_controls,
 		.num_controls = ARRAY_SIZE(aud96p22_snd_controls),
@@ -312,7 +312,7 @@ static int aud96p22_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	return 0;
 }
 
-static struct snd_soc_dai_ops aud96p22_dai_ops = {
+static const struct snd_soc_dai_ops aud96p22_dai_ops = {
 	.set_fmt = aud96p22_set_fmt,
 };
 
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 56ec1d301ac2..f395bbc7c354 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -1602,8 +1602,6 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
 		pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
 				     GFP_KERNEL);
 		if (!pdata) {
-			dev_err(&pdev->dev,
-				"Failed to allocate memory for pdata\n");
 			ret = -ENOMEM;
 			return pdata;
 		}
@@ -1853,6 +1851,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 	mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev,
 					sizeof(u32) * mcasp->num_serializer,
 					GFP_KERNEL);
+	if (!mcasp->context.xrsr_regs) {
+		ret = -ENOMEM;
+		goto err;
+	}
 #endif
 	mcasp->serial_dir = pdata->serial_dir;
 	mcasp->version = pdata->version;
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
index c77d9218795a..5415b72393fa 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/davinci/davinci-vcif.c
@@ -210,11 +210,8 @@ static int davinci_vcif_probe(struct platform_device *pdev)
 	davinci_vcif_dev = devm_kzalloc(&pdev->dev,
 					sizeof(struct davinci_vcif_dev),
 					GFP_KERNEL);
-	if (!davinci_vcif_dev) {
-		dev_dbg(&pdev->dev,
-			"could not allocate memory for private data\n");
+	if (!davinci_vcif_dev)
 		return -ENOMEM;
-	}
 
 	/* DMA tx params */
 	davinci_vcif_dev->davinci_vc = davinci_vc;
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index 916067638180..e27e21f8569a 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -381,7 +381,7 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	return ret;
 }
 
-static struct snd_soc_dai_ops dw_i2s_dai_ops = {
+static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
 	.startup	= dw_i2s_startup,
 	.shutdown	= dw_i2s_shutdown,
 	.hw_params	= dw_i2s_hw_params,
@@ -617,10 +617,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
 	const char *clk_id;
 
 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
-	if (!dev) {
-		dev_warn(&pdev->dev, "kzalloc fail\n");
+	if (!dev)
 		return -ENOMEM;
-	}
 
 	dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
 	if (!dw_i2s_dai)
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 9998aea23597..2db4d0c80d33 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -683,7 +683,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 	snd_soc_card_set_drvdata(&priv->card, priv);
 
 	ret = devm_snd_soc_register_card(&pdev->dev, &priv->card);
-	if (ret)
+	if (ret && ret != -EPROBE_DEFER)
 		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
 
 asrc_fail:
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 8cfffa70c144..806d39927318 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -542,7 +542,7 @@ static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 	return 0;
 }
 
-static struct snd_soc_dai_ops fsl_asrc_dai_ops = {
+static const struct snd_soc_dai_ops fsl_asrc_dai_ops = {
 	.hw_params    = fsl_asrc_dai_hw_params,
 	.hw_free      = fsl_asrc_dai_hw_free,
 	.trigger      = fsl_asrc_dai_trigger,
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index 282d841840b1..e1b97e59275a 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -20,7 +20,7 @@
 
 #define FSL_ASRC_DMABUF_SIZE	(256 * 1024)
 
-static struct snd_pcm_hardware snd_imx_hardware = {
+static const struct snd_pcm_hardware snd_imx_hardware = {
 	.info = SNDRV_PCM_INFO_INTERLEAVED |
 		SNDRV_PCM_INFO_BLOCK_TRANSFER |
 		SNDRV_PCM_INFO_MMAP |
@@ -279,10 +279,8 @@ static int fsl_asrc_dma_startup(struct snd_pcm_substream *substream)
 	struct fsl_asrc_pair *pair;
 
 	pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL);
-	if (!pair) {
-		dev_err(dev, "failed to allocate pair\n");
+	if (!pair)
 		return -ENOMEM;
-	}
 
 	pair->asrc_priv = asrc_priv;
 
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index ccadefceeff2..0c11f434a374 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -63,7 +63,6 @@ struct dma_object {
 	struct ccsr_dma_channel __iomem *channel;
 	unsigned int irq;
 	bool assigned;
-	char path[1];
 };
 
 /*
@@ -870,7 +869,7 @@ static struct device_node *find_ssi_node(struct device_node *dma_channel_np)
 	return NULL;
 }
 
-static struct snd_pcm_ops fsl_dma_ops = {
+static const struct snd_pcm_ops fsl_dma_ops = {
 	.open   	= fsl_dma_open,
 	.close  	= fsl_dma_close,
 	.ioctl  	= snd_pcm_lib_ioctl,
@@ -897,20 +896,18 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
 
 	ret = of_address_to_resource(ssi_np, 0, &res);
 	if (ret) {
-		dev_err(&pdev->dev, "could not determine resources for %s\n",
-			ssi_np->full_name);
+		dev_err(&pdev->dev, "could not determine resources for %pOF\n",
+			ssi_np);
 		of_node_put(ssi_np);
 		return ret;
 	}
 
-	dma = kzalloc(sizeof(*dma) + strlen(np->full_name), GFP_KERNEL);
+	dma = kzalloc(sizeof(*dma), GFP_KERNEL);
 	if (!dma) {
-		dev_err(&pdev->dev, "could not allocate dma object\n");
 		of_node_put(ssi_np);
 		return -ENOMEM;
 	}
 
-	strcpy(dma->path, np->full_name);
 	dma->dai.ops = &fsl_dma_ops;
 	dma->dai.pcm_new = fsl_dma_new;
 	dma->dai.pcm_free = fsl_dma_free_dma_buffers;
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 809a069d490b..cef79a1a620b 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -620,7 +620,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
 	return 0;
 }
 
-static struct snd_soc_dai_ops fsl_esai_dai_ops = {
+static const struct snd_soc_dai_ops fsl_esai_dai_ops = {
 	.startup = fsl_esai_startup,
 	.shutdown = fsl_esai_shutdown,
 	.trigger = fsl_esai_trigger,
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 1ff467c9598a..7e6cc4da0088 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -626,7 +626,7 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static struct snd_soc_dai_ops fsl_spdif_dai_ops = {
+static const struct snd_soc_dai_ops fsl_spdif_dai_ops = {
 	.startup = fsl_spdif_startup,
 	.hw_params = fsl_spdif_hw_params,
 	.trigger = fsl_spdif_trigger,
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 173cb8496641..64598d1183f8 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1432,10 +1432,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 
 	ssi_private = devm_kzalloc(&pdev->dev, sizeof(*ssi_private),
 			GFP_KERNEL);
-	if (!ssi_private) {
-		dev_err(&pdev->dev, "could not allocate DAI object\n");
+	if (!ssi_private)
 		return -ENOMEM;
-	}
 
 	ssi_private->soc = of_id->data;
 	ssi_private->dev = &pdev->dev;
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index fc57da341d61..392d5eef356d 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -268,13 +268,13 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev,
 
 		ret = of_property_read_u32(child, "fsl,audmux-port", &port);
 		if (ret) {
-			dev_warn(&pdev->dev, "Failed to get fsl,audmux-port of child node \"%s\"\n",
-					child->full_name);
+			dev_warn(&pdev->dev, "Failed to get fsl,audmux-port of child node \"%pOF\"\n",
+					child);
 			continue;
 		}
 		if (!of_property_read_bool(child, "fsl,port-config")) {
-			dev_warn(&pdev->dev, "child node \"%s\" does not have property fsl,port-config\n",
-					child->full_name);
+			dev_warn(&pdev->dev, "child node \"%pOF\" does not have property fsl,port-config\n",
+					child);
 			continue;
 		}
 
@@ -292,15 +292,15 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev,
 		}
 
 		if (ret != -EOVERFLOW) {
-			dev_err(&pdev->dev, "Failed to read u32 at index %d of child %s\n",
-					i, child->full_name);
+			dev_err(&pdev->dev, "Failed to read u32 at index %d of child %pOF\n",
+					i, child);
 			continue;
 		}
 
 		if (audmux_type == IMX31_AUDMUX) {
 			if (i % 2) {
-				dev_err(&pdev->dev, "One pdcr value is missing in child node %s\n",
-						child->full_name);
+				dev_err(&pdev->dev, "One pdcr value is missing in child node %pOF\n",
+						child);
 				continue;
 			}
 			imx_audmux_v2_configure_port(port, ptcr, pdcr);
diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c
index 20e7400e2611..9953438086e4 100644
--- a/sound/soc/fsl/imx-es8328.c
+++ b/sound/soc/fsl/imx-es8328.c
@@ -203,9 +203,6 @@ static int imx_es8328_remove(struct platform_device *pdev)
 {
 	struct imx_es8328_data *data = platform_get_drvdata(pdev);
 
-	snd_soc_jack_free_gpios(&headset_jack, ARRAY_SIZE(headset_jack_gpios),
-				headset_jack_gpios);
-
 	snd_soc_unregister_card(&data->card);
 
 	return 0;
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 92410f7ca1fa..4e5fefee111e 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -154,7 +154,7 @@ static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream
 	return bytes_to_frames(substream->runtime, iprtd->offset);
 }
 
-static struct snd_pcm_hardware snd_imx_hardware = {
+static const struct snd_pcm_hardware snd_imx_hardware = {
 	.info = SNDRV_PCM_INFO_INTERLEAVED |
 		SNDRV_PCM_INFO_BLOCK_TRANSFER |
 		SNDRV_PCM_INFO_MMAP |
@@ -227,7 +227,7 @@ static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_pcm_ops imx_pcm_ops = {
+static const struct snd_pcm_ops imx_pcm_ops = {
 	.open		= snd_imx_open,
 	.close		= snd_imx_close,
 	.ioctl		= snd_pcm_lib_ioctl,
@@ -341,7 +341,7 @@ static void imx_pcm_fiq_free(struct snd_pcm *pcm)
 	imx_pcm_free(pcm);
 }
 
-static struct snd_soc_platform_driver imx_soc_platform_fiq = {
+static const struct snd_soc_platform_driver imx_soc_platform_fiq = {
 	.ops		= &imx_pcm_ops,
 	.pcm_new	= imx_pcm_fiq_new,
 	.pcm_free	= imx_pcm_fiq_free,
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index b95132e2f9dc..06790615e04e 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -527,6 +527,10 @@ static int imx_ssi_probe(struct platform_device *pdev)
 	}
 
 	ssi->irq = platform_get_irq(pdev, 0);
+	if (ssi->irq < 0) {
+		dev_err(&pdev->dev, "Failed to get IRQ: %d\n", ssi->irq);
+		return ssi->irq;
+	}
 
 	ssi->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(ssi->clk)) {
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 1f7e70bfbd55..e63029f1aabc 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -287,7 +287,7 @@ psc_dma_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static struct snd_pcm_ops psc_dma_ops = {
+static const struct snd_pcm_ops psc_dma_ops = {
 	.open		= psc_dma_open,
 	.close		= psc_dma_close,
 	.hw_free	= psc_dma_hw_free,
@@ -356,7 +356,7 @@ static void psc_dma_free(struct snd_pcm *pcm)
 	}
 }
 
-static struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
+static const struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
 	.ops		= &psc_dma_ops,
 	.pcm_new	= &psc_dma_new,
 	.pcm_free	= &psc_dma_free,
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 105ec3a6e30d..2f7c8cf6f123 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -95,7 +95,7 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
 	asoc_simple_card_clk_disable(&dai_props->codec_dai);
 }
 
-static struct snd_soc_ops asoc_graph_card_ops = {
+static const struct snd_soc_ops asoc_graph_card_ops = {
 	.startup = asoc_graph_card_startup,
 	.shutdown = asoc_graph_card_shutdown,
 };
@@ -224,9 +224,11 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
 
 	of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
 		ret = asoc_graph_card_dai_link_of(it.node, priv, idx++);
-		of_node_put(it.node);
-		if (ret < 0)
+		if (ret < 0) {
+			of_node_put(it.node);
+
 			return ret;
+		}
 	}
 
 	return asoc_simple_card_parse_card_name(card, NULL);
@@ -239,10 +241,8 @@ static int asoc_graph_get_dais_count(struct device *dev)
 	int count = 0;
 	int rc;
 
-	of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
+	of_for_each_phandle(&it, rc, node, "dais", NULL, 0)
 		count++;
-		of_node_put(it.node);
-	}
 
 	return count;
 }
diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c
index dcd2df37bc3b..06b6fcf0513e 100644
--- a/sound/soc/generic/audio-graph-scu-card.c
+++ b/sound/soc/generic/audio-graph-scu-card.c
@@ -56,7 +56,7 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
 	asoc_simple_card_clk_disable(dai_props);
 }
 
-static struct snd_soc_ops asoc_graph_card_ops = {
+static const struct snd_soc_ops asoc_graph_card_ops = {
 	.startup = asoc_graph_card_startup,
 	.shutdown = asoc_graph_card_shutdown,
 };
@@ -215,7 +215,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
 		codec_ep = of_graph_get_remote_endpoint(cpu_ep);
 		rcpu_ep  = of_graph_get_remote_endpoint(codec_ep);
 
-		of_node_put(cpu_port);
 		of_node_put(cpu_ep);
 		of_node_put(codec_ep);
 		of_node_put(rcpu_ep);
@@ -232,8 +231,10 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
 
 		ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
 							    NULL, &daifmt);
-		if (ret < 0)
+		if (ret < 0) {
+			of_node_put(cpu_port);
 			goto parse_of_err;
+		}
 	}
 
 	dai_idx = 0;
@@ -250,7 +251,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
 			codec_ep = of_graph_get_remote_endpoint(cpu_ep);
 			codec_port = of_graph_get_port_parent(codec_ep);
 
-			of_node_put(cpu_port);
 			of_node_put(cpu_ep);
 			of_node_put(codec_ep);
 			of_node_put(codec_port);
@@ -266,13 +266,17 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
 
 				/* Back-End (= Codec) */
 				ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0);
-				if (ret < 0)
+				if (ret < 0) {
+					of_node_put(cpu_port);
 					goto parse_of_err;
+				}
 			} else {
 				/* Front-End (= CPU) */
 				ret = asoc_graph_card_dai_link_of(cpu_ep, priv, daifmt, dai_idx++, 1);
-				if (ret < 0)
+				if (ret < 0) {
+					of_node_put(cpu_port);
 					goto parse_of_err;
+				}
 			}
 		}
 	}
@@ -306,7 +310,6 @@ static int asoc_graph_get_dais_count(struct device *dev)
 		codec_ep = of_graph_get_remote_endpoint(cpu_ep);
 		codec_port = of_graph_get_port_parent(codec_ep);
 
-		of_node_put(cpu_port);
 		of_node_put(cpu_ep);
 		of_node_put(codec_ep);
 		of_node_put(codec_port);
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 26d64fa40c9c..d72f7d58102f 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -132,7 +132,7 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
 
 	/* Parse the card name from DT */
 	ret = snd_soc_of_parse_card_name(card, "label");
-	if (ret < 0) {
+	if (ret < 0 || !card->name) {
 		char prop[128];
 
 		snprintf(prop, sizeof(prop), "%sname", prefix);
@@ -263,6 +263,9 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep)
 			id = i;
 		i++;
 	}
+
+	of_node_put(node);
+
 	if (id < 0)
 		return -ENODEV;
 
@@ -282,11 +285,6 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep,
 	if (!dai_name)
 		return 0;
 
-	/*
-	 * of_graph_get_port_parent() will call
-	 * of_node_put(). So, call of_node_get() here
-	 */
-	of_node_get(ep);
 	node = of_graph_get_port_parent(ep);
 
 	/* Get dai->name */
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index dfaf48ff88b0..6959a74a6f49 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -104,12 +104,6 @@ static int asoc_simple_card_init_jack(struct snd_soc_card *card,
 	return 0;
 }
 
-static void asoc_simple_card_remove_jack(struct asoc_simple_jack *sjack)
-{
-	if (gpio_is_valid(sjack->gpio.gpio))
-		snd_soc_jack_free_gpios(&sjack->jack, 1, &sjack->gpio);
-}
-
 static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -493,10 +487,6 @@ err:
 static int asoc_simple_card_remove(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
-
-	asoc_simple_card_remove_jack(&priv->hp_jack);
-	asoc_simple_card_remove_jack(&priv->mic_jack);
 
 	return asoc_simple_card_clean_reference(card);
 }
diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c
index b193d3beb253..0c8f86d4020e 100644
--- a/sound/soc/hisilicon/hi6210-i2s.c
+++ b/sound/soc/hisilicon/hi6210-i2s.c
@@ -517,7 +517,7 @@ static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai)
 }
 
 
-static struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
+static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
 	.trigger	= hi6210_i2s_trigger,
 	.hw_params	= hi6210_i2s_hw_params,
 	.set_fmt	= hi6210_i2s_set_fmt,
diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c
index 0389203f8560..567f9767fb73 100644
--- a/sound/soc/img/img-i2s-in.c
+++ b/sound/soc/img/img-i2s-in.c
@@ -443,7 +443,7 @@ static int img_i2s_in_probe(struct platform_device *pdev)
 		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE;
 	i2s->dai_driver.ops = &img_i2s_in_dai_ops;
 
-	rst = devm_reset_control_get(dev, "rst");
+	rst = devm_reset_control_get_exclusive(dev, "rst");
 	if (IS_ERR(rst)) {
 		if (PTR_ERR(rst) == -EPROBE_DEFER) {
 			ret = -EPROBE_DEFER;
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
index 5f997135a8ae..78b7f6cd675b 100644
--- a/sound/soc/img/img-i2s-out.c
+++ b/sound/soc/img/img-i2s-out.c
@@ -446,7 +446,7 @@ static int img_i2s_out_probe(struct platform_device *pdev)
 
 	i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
 
-	i2s->rst = devm_reset_control_get(&pdev->dev, "rst");
+	i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
 	if (IS_ERR(i2s->rst)) {
 		if (PTR_ERR(i2s->rst) != -EPROBE_DEFER)
 			dev_err(&pdev->dev, "No top level reset found\n");
diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c
index 33ceb207ee70..23b0f0f6ec9c 100644
--- a/sound/soc/img/img-parallel-out.c
+++ b/sound/soc/img/img-parallel-out.c
@@ -224,7 +224,7 @@ static int img_prl_out_probe(struct platform_device *pdev)
 
 	prl->base = base;
 
-	prl->rst = devm_reset_control_get(&pdev->dev, "rst");
+	prl->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
 	if (IS_ERR(prl->rst)) {
 		if (PTR_ERR(prl->rst) != -EPROBE_DEFER)
 			dev_err(&pdev->dev, "No top level reset found\n");
diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c
index 4d9953d318af..8adfd65d4390 100644
--- a/sound/soc/img/img-spdif-in.c
+++ b/sound/soc/img/img-spdif-in.c
@@ -727,7 +727,7 @@ static int img_spdif_in_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	rst = devm_reset_control_get(&pdev->dev, "rst");
+	rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
 	if (IS_ERR(rst)) {
 		if (PTR_ERR(rst) == -EPROBE_DEFER) {
 			ret = -EPROBE_DEFER;
diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c
index 08f93a5dadfe..383655da2e60 100644
--- a/sound/soc/img/img-spdif-out.c
+++ b/sound/soc/img/img-spdif-out.c
@@ -334,7 +334,7 @@ static int img_spdif_out_probe(struct platform_device *pdev)
 
 	spdif->base = base;
 
-	spdif->rst = devm_reset_control_get(&pdev->dev, "rst");
+	spdif->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
 	if (IS_ERR(spdif->rst)) {
 		if (PTR_ERR(spdif->rst) != -EPROBE_DEFER)
 			dev_err(&pdev->dev, "No top level reset found\n");
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index b301bfff1c09..b3c7f554ec30 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -255,11 +255,12 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
 
 config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
         tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
-        depends on X86_INTEL_LPSS && I2C
+        depends on X86_INTEL_LPSS && I2C && SPI
         select SND_SOC_INTEL_SST
         select SND_SOC_INTEL_SKYLAKE
         select SND_SOC_RT5663
         select SND_SOC_RT5514
+        select SND_SOC_RT5514_SPI
         select SND_SOC_MAX98927
         select SND_SOC_HDAC_HDMI
         help
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index b082b31023d5..43e7fdd19f29 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -76,7 +76,7 @@ int sst_unregister_dsp(struct sst_device *dev)
 }
 EXPORT_SYMBOL_GPL(sst_unregister_dsp);
 
-static struct snd_pcm_hardware sst_platform_pcm_hw = {
+static const struct snd_pcm_hardware sst_platform_pcm_hw = {
 	.info =	(SNDRV_PCM_INFO_INTERLEAVED |
 			SNDRV_PCM_INFO_DOUBLE |
 			SNDRV_PCM_INFO_PAUSE |
@@ -471,7 +471,7 @@ static void sst_disable_ssp(struct snd_pcm_substream *substream,
 	}
 }
 
-static struct snd_soc_dai_ops sst_media_dai_ops = {
+static const struct snd_soc_dai_ops sst_media_dai_ops = {
 	.startup = sst_media_open,
 	.shutdown = sst_media_close,
 	.prepare = sst_media_prepare,
@@ -480,11 +480,11 @@ static struct snd_soc_dai_ops sst_media_dai_ops = {
 	.mute_stream = sst_media_digital_mute,
 };
 
-static struct snd_soc_dai_ops sst_compr_dai_ops = {
+static const struct snd_soc_dai_ops sst_compr_dai_ops = {
 	.mute_stream = sst_media_digital_mute,
 };
 
-static struct snd_soc_dai_ops sst_be_dai_ops = {
+static const struct snd_soc_dai_ops sst_be_dai_ops = {
 	.startup = sst_enable_ssp,
 	.hw_params = sst_be_hw_params,
 	.set_fmt = sst_set_format,
@@ -705,7 +705,7 @@ static int sst_soc_probe(struct snd_soc_platform *platform)
 	return sst_dsp_init_v2_dpcm(platform);
 }
 
-static struct snd_soc_platform_driver sst_soc_platform_drv  = {
+static const struct snd_soc_platform_driver sst_soc_platform_drv  = {
 	.probe		= sst_soc_probe,
 	.ops		= &sst_platform_ops,
 	.compr_ops	= &sst_platform_compr_ops,
diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c
index ce689c5af5ab..71af5449be90 100644
--- a/sound/soc/intel/atom/sst/sst_drv_interface.c
+++ b/sound/soc/intel/atom/sst/sst_drv_interface.c
@@ -407,7 +407,7 @@ static int sst_cdev_caps(struct snd_compr_caps *caps)
 	return 0;
 }
 
-static struct snd_compr_codec_caps caps_mp3 = {
+static const struct snd_compr_codec_caps caps_mp3 = {
 	.num_descriptors = 1,
 	.descriptor[0].max_ch = 2,
 	.descriptor[0].sample_rates[0] = 48000,
@@ -424,7 +424,7 @@ static struct snd_compr_codec_caps caps_mp3 = {
 	.descriptor[0].formats = 0,
 };
 
-static struct snd_compr_codec_caps caps_aac = {
+static const struct snd_compr_codec_caps caps_aac = {
 	.num_descriptors = 2,
 	.descriptor[1].max_ch = 2,
 	.descriptor[0].sample_rates[0] = 48000,
diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c
index 3a0b3bf0af97..6906ee624cf6 100644
--- a/sound/soc/intel/atom/sst/sst_pci.c
+++ b/sound/soc/intel/atom/sst/sst_pci.c
@@ -181,7 +181,7 @@ static void intel_sst_remove(struct pci_dev *pci)
 }
 
 /* PCI Routines */
-static struct pci_device_id intel_sst_ids[] = {
+static const struct pci_device_id intel_sst_ids[] = {
 	{ PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
 	{ 0, }
 };
diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
index 4765ad474544..c54529320f07 100644
--- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c
+++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
@@ -309,7 +309,7 @@ static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
 	return snd_pcm_lib_default_mmap(substream, vma);
 }
 
-static struct snd_pcm_ops sst_byt_pcm_ops = {
+static const struct snd_pcm_ops sst_byt_pcm_ops = {
 	.open		= sst_byt_pcm_open,
 	.close		= sst_byt_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
@@ -395,7 +395,7 @@ static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
 	return 0;
 }
 
-static struct snd_soc_platform_driver byt_soc_platform = {
+static const struct snd_soc_platform_driver byt_soc_platform = {
 	.probe		= sst_byt_pcm_probe,
 	.remove		= sst_byt_pcm_remove,
 	.ops		= &sst_byt_pcm_ops,
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c
index 0c3a3cbcb884..7843104fadcb 100644
--- a/sound/soc/intel/boards/bxt_rt298.c
+++ b/sound/soc/intel/boards/bxt_rt298.c
@@ -114,7 +114,44 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
 	{ "iDisp2 Tx", NULL, "iDisp2_out"},
 	{ "hifi1", NULL, "iDisp1 Tx"},
 	{ "iDisp1 Tx", NULL, "iDisp1_out"},
+};
+
+static const struct snd_soc_dapm_route geminilake_rt298_map[] = {
+	/* speaker */
+	{"Speaker", NULL, "SPOR"},
+	{"Speaker", NULL, "SPOL"},
+
+	/* HP jack connectors - unknown if we have jack detect */
+	{"Headphone Jack", NULL, "HPO Pin"},
+
+	/* other jacks */
+	{"MIC1", NULL, "Mic Jack"},
+
+	/* digital mics */
+	{"DMIC1 Pin", NULL, "DMIC2"},
+	{"DMic", NULL, "SoC DMIC"},
+
+	{"HDMI1", NULL, "hif5-0 Output"},
+	{"HDMI2", NULL, "hif6-0 Output"},
+	{"HDMI2", NULL, "hif7-0 Output"},
+
+	/* CODEC BE connections */
+	{ "AIF1 Playback", NULL, "ssp2 Tx"},
+	{ "ssp2 Tx", NULL, "codec0_out"},
+	{ "ssp2 Tx", NULL, "codec1_out"},
+
+	{ "codec0_in", NULL, "ssp2 Rx" },
+	{ "ssp2 Rx", NULL, "AIF1 Capture" },
 
+	{ "dmic01_hifi", NULL, "DMIC01 Rx" },
+	{ "DMIC01 Rx", NULL, "Capture" },
+
+	{ "hifi3", NULL, "iDisp3 Tx"},
+	{ "iDisp3 Tx", NULL, "iDisp3_out"},
+	{ "hifi2", NULL, "iDisp2 Tx"},
+	{ "iDisp2 Tx", NULL, "iDisp2_out"},
+	{ "hifi1", NULL, "iDisp1 Tx"},
+	{ "iDisp1 Tx", NULL, "iDisp1_out"},
 };
 
 static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd)
@@ -492,7 +529,6 @@ static int bxt_card_late_probe(struct snd_soc_card *card)
 /* broxton audio machine driver for SPT + RT298S */
 static struct snd_soc_card broxton_rt298 = {
 	.name = "broxton-rt298",
-	.owner = THIS_MODULE,
 	.dai_link = broxton_rt298_dais,
 	.num_links = ARRAY_SIZE(broxton_rt298_dais),
 	.controls = broxton_controls,
@@ -506,9 +542,41 @@ static struct snd_soc_card broxton_rt298 = {
 
 };
 
+static struct snd_soc_card geminilake_rt298 = {
+	.name = "geminilake-rt298",
+	.dai_link = broxton_rt298_dais,
+	.num_links = ARRAY_SIZE(broxton_rt298_dais),
+	.controls = broxton_controls,
+	.num_controls = ARRAY_SIZE(broxton_controls),
+	.dapm_widgets = broxton_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
+	.dapm_routes = geminilake_rt298_map,
+	.num_dapm_routes = ARRAY_SIZE(geminilake_rt298_map),
+	.fully_routed = true,
+	.late_probe = bxt_card_late_probe,
+};
+
 static int broxton_audio_probe(struct platform_device *pdev)
 {
 	struct bxt_rt286_private *ctx;
+	struct snd_soc_card *card =
+			(struct snd_soc_card *)pdev->id_entry->driver_data;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) {
+		if (!strncmp(card->dai_link[i].codec_name, "i2c-INT343A:00",
+						I2C_NAME_SIZE)) {
+			if (!strncmp(card->name, "broxton-rt298",
+						PLATFORM_NAME_SIZE)) {
+				card->dai_link[i].name = "SSP5-Codec";
+				card->dai_link[i].cpu_dai_name = "SSP5 Pin";
+			} else if (!strncmp(card->name, "geminilake-rt298",
+						PLATFORM_NAME_SIZE)) {
+				card->dai_link[i].name = "SSP2-Codec";
+				card->dai_link[i].cpu_dai_name = "SSP2 Pin";
+			}
+		}
+	}
 
 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
 	if (!ctx)
@@ -516,18 +584,27 @@ static int broxton_audio_probe(struct platform_device *pdev)
 
 	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
 
-	broxton_rt298.dev = &pdev->dev;
-	snd_soc_card_set_drvdata(&broxton_rt298, ctx);
+	card->dev = &pdev->dev;
+	snd_soc_card_set_drvdata(card, ctx);
 
-	return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298);
+	return devm_snd_soc_register_card(&pdev->dev, card);
 }
 
+static const struct platform_device_id bxt_board_ids[] = {
+	{ .name = "bxt_alc298s_i2s", .driver_data =
+				(unsigned long)&broxton_rt298 },
+	{ .name = "glk_alc298s_i2s", .driver_data =
+				(unsigned long)&geminilake_rt298 },
+	{}
+};
+
 static struct platform_driver broxton_audio = {
 	.probe = broxton_audio_probe,
 	.driver = {
 		.name = "bxt_alc298s_i2s",
 		.pm = &snd_soc_pm_ops,
 	},
+	.id_table = bxt_board_ids,
 };
 module_platform_driver(broxton_audio)
 
@@ -537,3 +614,4 @@ MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>");
 MODULE_DESCRIPTION("Intel SST Audio for Broxton");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:bxt_alc298s_i2s");
+MODULE_ALIAS("platform:glk_alc298s_i2s");
diff --git a/sound/soc/intel/boards/byt-max98090.c b/sound/soc/intel/boards/byt-max98090.c
index 047be7fa0ce9..0f8b8209c020 100644
--- a/sound/soc/intel/boards/byt-max98090.c
+++ b/sound/soc/intel/boards/byt-max98090.c
@@ -173,20 +173,8 @@ static int byt_max98090_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int byt_max98090_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	struct byt_max98090_private *priv = snd_soc_card_get_drvdata(card);
-
-	snd_soc_jack_free_gpios(&priv->jack, ARRAY_SIZE(hs_jack_gpios),
-				hs_jack_gpios);
-
-	return 0;
-}
-
 static struct platform_driver byt_max98090_driver = {
 	.probe = byt_max98090_probe,
-	.remove = byt_max98090_remove,
 	.driver = {
 		.name = "byt-max98090",
 		.pm = &snd_soc_pm_ops,
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index bc2a52de06a3..f597d5582223 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -184,6 +184,13 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static const struct acpi_gpio_params headset_gpios = { 0, 0, false };
+
+static const struct acpi_gpio_mapping cht_rt5672_gpios[] = {
+	{ "headset-gpios", &headset_gpios, 1 },
+	{},
+};
+
 static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 {
 	int ret;
@@ -191,6 +198,9 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 	struct snd_soc_codec *codec = codec_dai->codec;
 	struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
 
+	if (devm_acpi_dev_add_driver_gpios(codec->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) {
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index f9ba97788157..7f7607420706 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -34,7 +34,7 @@
 #define MAXIM_DEV0_NAME "i2c-MX98927:00"
 #define MAXIM_DEV1_NAME "i2c-MX98927:01"
 
-static struct snd_soc_card kabylake_audio_card;
+static struct snd_soc_card *kabylake_audio_card;
 static const struct snd_pcm_hw_constraint_list *dmic_constraints;
 static struct snd_soc_jack skylake_hdmi[3];
 
@@ -52,6 +52,8 @@ struct kbl_rt5663_private {
 enum {
 	KBL_DPCM_AUDIO_PB = 0,
 	KBL_DPCM_AUDIO_CP,
+	KBL_DPCM_AUDIO_HS_PB,
+	KBL_DPCM_AUDIO_ECHO_REF_CP,
 	KBL_DPCM_AUDIO_REF_CP,
 	KBL_DPCM_AUDIO_DMIC_CP,
 	KBL_DPCM_AUDIO_HDMI1_PB,
@@ -72,8 +74,9 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
 	SND_SOC_DAPM_SPK("Left Spk", NULL),
 	SND_SOC_DAPM_SPK("Right Spk", NULL),
 	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
-	SND_SOC_DAPM_SPK("DP", NULL),
-	SND_SOC_DAPM_SPK("HDMI", NULL),
+	SND_SOC_DAPM_SPK("HDMI1", NULL),
+	SND_SOC_DAPM_SPK("HDMI2", NULL),
+	SND_SOC_DAPM_SPK("HDMI3", NULL),
 
 };
 
@@ -91,20 +94,22 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
 	{ "IN1N", NULL, "Headset Mic" },
 	{ "DMic", NULL, "SoC DMIC" },
 
-	{ "HDMI", NULL, "hif5 Output" },
-	{ "DP", NULL, "hif6 Output" },
-
 	/* CODEC BE connections */
 	{ "Left HiFi Playback", NULL, "ssp0 Tx" },
 	{ "Right HiFi Playback", NULL, "ssp0 Tx" },
-	{ "ssp0 Tx", NULL, "codec0_out" },
+	{ "ssp0 Tx", NULL, "spk_out" },
 
 	{ "AIF Playback", NULL, "ssp1 Tx" },
-	{ "ssp1 Tx", NULL, "codec1_out" },
+	{ "ssp1 Tx", NULL, "hs_out" },
 
-	{ "codec0_in", NULL, "ssp1 Rx" },
+	{ "hs_in", NULL, "ssp1 Rx" },
 	{ "ssp1 Rx", NULL, "AIF Capture" },
 
+	/* IV feedback path */
+	{ "codec0_fb_in", NULL, "ssp0 Rx"},
+	{ "ssp0 Rx", NULL, "Left HiFi Capture" },
+	{ "ssp0 Rx", NULL, "Right HiFi Capture" },
+
 	/* DMIC */
 	{ "dmic01_hifi", NULL, "DMIC01 Rx" },
 	{ "DMIC01 Rx", NULL, "DMIC AIF" },
@@ -117,6 +122,49 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
 	{ "iDisp1 Tx", NULL, "iDisp1_out"},
 };
 
+enum {
+	KBL_DPCM_AUDIO_5663_PB = 0,
+	KBL_DPCM_AUDIO_5663_CP,
+	KBL_DPCM_AUDIO_5663_HDMI1_PB,
+	KBL_DPCM_AUDIO_5663_HDMI2_PB,
+};
+
+static const struct snd_kcontrol_new kabylake_5663_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_SPK("DP", NULL),
+	SND_SOC_DAPM_SPK("HDMI", NULL),
+};
+
+static const struct snd_soc_dapm_route kabylake_5663_map[] = {
+	{ "Headphone Jack", NULL, "HPOL" },
+	{ "Headphone Jack", NULL, "HPOR" },
+
+	/* other jacks */
+	{ "IN1P", NULL, "Headset Mic" },
+	{ "IN1N", NULL, "Headset Mic" },
+
+	{ "HDMI", NULL, "hif5 Output" },
+	{ "DP", NULL, "hif6 Output" },
+
+	/* CODEC BE connections */
+	{ "AIF Playback", NULL, "ssp1 Tx" },
+	{ "ssp1 Tx", NULL, "codec1_out" },
+
+	{ "codec0_in", NULL, "ssp1 Rx" },
+	{ "ssp1 Rx", NULL, "AIF Capture" },
+
+	{ "hifi2", NULL, "iDisp2 Tx"},
+	{ "iDisp2 Tx", NULL, "iDisp2_out"},
+	{ "hifi1", NULL, "iDisp1 Tx"},
+	{ "iDisp1 Tx", NULL, "iDisp1_out"},
+};
+
 static struct snd_soc_codec_conf max98927_codec_conf[] = {
 	{
 		.dev_name = MAXIM_DEV0_NAME,
@@ -165,7 +213,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
 	 * Headset buttons map to the google Reference headset.
 	 * These can be configured by userspace.
 	 */
-	ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack",
+	ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack",
 			SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 			SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset,
 			NULL, 0);
@@ -173,8 +221,18 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
 		dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
 		return ret;
 	}
-
 	rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
+	return ret;
+}
+
+static int kabylake_rt5663_max98927_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret;
+
+	ret = kabylake_rt5663_codec_init(rtd);
+	if (ret)
+		return ret;
+
 	ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
 	if (ret) {
 		dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret);
@@ -184,7 +242,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
 	return ret;
 }
 
-static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
 {
 	struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
 	struct snd_soc_dai *dai = rtd->codec_dai;
@@ -194,7 +252,7 @@ static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
 	if (!pcm)
 		return -ENOMEM;
 
-	pcm->device = KBL_DPCM_AUDIO_HDMI1_PB;
+	pcm->device = device;
 	pcm->codec_dai = dai;
 
 	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
@@ -202,47 +260,36 @@ static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
-	struct snd_soc_dai *dai = rtd->codec_dai;
-	struct kbl_hdmi_pcm *pcm;
-
-	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
-	if (!pcm)
-		return -ENOMEM;
-
-	pcm->device = KBL_DPCM_AUDIO_HDMI2_PB;
-	pcm->codec_dai = dai;
-
-	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+	return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
+}
 
-	return 0;
+static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+	return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
 }
 
 static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
-	struct snd_soc_dai *dai = rtd->codec_dai;
-	struct kbl_hdmi_pcm *pcm;
-
-	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
-	if (!pcm)
-		return -ENOMEM;
-
-	pcm->device = KBL_DPCM_AUDIO_HDMI3_PB;
-	pcm->codec_dai = dai;
+	return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
+}
 
-	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+static int kabylake_5663_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+{
+	return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI1_PB);
+}
 
-	return 0;
+static int kabylake_5663_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+	return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI2_PB);
 }
 
 static unsigned int rates[] = {
 	48000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_rates = {
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
 	.count = ARRAY_SIZE(rates),
 	.list  = rates,
 	.mask = 0,
@@ -252,7 +299,7 @@ static unsigned int channels[] = {
 	2,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
 	.count = ARRAY_SIZE(channels),
 	.list = channels,
 	.mask = 0,
@@ -312,11 +359,13 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	int ret;
 
-	ret = snd_soc_dai_set_sysclk(codec_dai,
-			RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
 	/* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
-	rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1);
+	rt5663_sel_asrc_clk_src(codec_dai->codec,
+			RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
+			RT5663_CLK_SEL_I2S1_ASRC);
 
+	ret = snd_soc_dai_set_sysclk(codec_dai,
+			RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
 	if (ret < 0)
 		dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
 
@@ -381,7 +430,7 @@ static unsigned int rates_16000[] = {
 	16000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_16000 = {
+static const struct snd_pcm_hw_constraint_list constraints_16000 = {
 	.count = ARRAY_SIZE(rates_16000),
 	.list  = rates_16000,
 };
@@ -443,6 +492,28 @@ static struct snd_soc_dai_link kabylake_dais[] = {
 		.dpcm_capture = 1,
 		.ops = &kabylake_rt5663_fe_ops,
 	},
+	[KBL_DPCM_AUDIO_HS_PB] = {
+		.name = "Kbl Audio Headset Playback",
+		.stream_name = "Headset Audio",
+		.cpu_dai_name = "System Pin2",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.dpcm_playback = 1,
+		.nonatomic = 1,
+		.dynamic = 1,
+	},
+	[KBL_DPCM_AUDIO_ECHO_REF_CP] = {
+		.name = "Kbl Audio Echo Reference cap",
+		.stream_name = "Echoreference Capture",
+		.cpu_dai_name = "Echoref Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.init = NULL,
+		.capture_only = 1,
+		.nonatomic = 1,
+	},
 	[KBL_DPCM_AUDIO_REF_CP] = {
 		.name = "Kbl Audio Reference cap",
 		.stream_name = "Wake on Voice",
@@ -538,7 +609,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
 		.no_pcm = 1,
 		.codec_name = "i2c-10EC5663:00",
 		.codec_dai_name = KBL_REALTEK_CODEC_DAI,
-		.init = kabylake_rt5663_codec_init,
+		.init = kabylake_rt5663_max98927_codec_init,
 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 			SND_SOC_DAIFMT_CBS_CFS,
 		.ignore_pmdown_time = 1,
@@ -594,15 +665,119 @@ static struct snd_soc_dai_link kabylake_dais[] = {
 	},
 };
 
+static struct snd_soc_dai_link kabylake_5663_dais[] = {
+	/* Front End DAI links */
+	[KBL_DPCM_AUDIO_5663_PB] = {
+		.name = "Kbl Audio Port",
+		.stream_name = "Audio",
+		.cpu_dai_name = "System Pin",
+		.platform_name = "0000:00:1f.3",
+		.dynamic = 1,
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.nonatomic = 1,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.dpcm_playback = 1,
+		.ops = &kabylake_rt5663_fe_ops,
+	},
+	[KBL_DPCM_AUDIO_5663_CP] = {
+		.name = "Kbl Audio Capture Port",
+		.stream_name = "Audio Record",
+		.cpu_dai_name = "System Pin",
+		.platform_name = "0000:00:1f.3",
+		.dynamic = 1,
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.nonatomic = 1,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.dpcm_capture = 1,
+		.ops = &kabylake_rt5663_fe_ops,
+	},
+	[KBL_DPCM_AUDIO_5663_HDMI1_PB] = {
+		.name = "Kbl HDMI Port1",
+		.stream_name = "Hdmi1",
+		.cpu_dai_name = "HDMI1 Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.dpcm_playback = 1,
+		.init = NULL,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.nonatomic = 1,
+		.dynamic = 1,
+	},
+	[KBL_DPCM_AUDIO_5663_HDMI2_PB] = {
+		.name = "Kbl HDMI Port2",
+		.stream_name = "Hdmi2",
+		.cpu_dai_name = "HDMI2 Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.dpcm_playback = 1,
+		.init = NULL,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.nonatomic = 1,
+		.dynamic = 1,
+	},
+
+	/* Back End DAI links */
+	{
+		/* SSP1 - Codec */
+		.name = "SSP1-Codec",
+		.id = 0,
+		.cpu_dai_name = "SSP1 Pin",
+		.platform_name = "0000:00:1f.3",
+		.no_pcm = 1,
+		.codec_name = "i2c-10EC5663:00",
+		.codec_dai_name = KBL_REALTEK_CODEC_DAI,
+		.init = kabylake_rt5663_codec_init,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+		.ignore_pmdown_time = 1,
+		.be_hw_params_fixup = kabylake_ssp_fixup,
+		.ops = &kabylake_rt5663_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	{
+		.name = "iDisp1",
+		.id = 1,
+		.cpu_dai_name = "iDisp1 Pin",
+		.codec_name = "ehdaudio0D2",
+		.codec_dai_name = "intel-hdmi-hifi1",
+		.platform_name = "0000:00:1f.3",
+		.dpcm_playback = 1,
+		.init = kabylake_5663_hdmi1_init,
+		.no_pcm = 1,
+	},
+	{
+		.name = "iDisp2",
+		.id = 2,
+		.cpu_dai_name = "iDisp2 Pin",
+		.codec_name = "ehdaudio0D2",
+		.codec_dai_name = "intel-hdmi-hifi2",
+		.platform_name = "0000:00:1f.3",
+		.init = kabylake_5663_hdmi2_init,
+		.dpcm_playback = 1,
+		.no_pcm = 1,
+	},
+};
+
 #define NAME_SIZE	32
 static int kabylake_card_late_probe(struct snd_soc_card *card)
 {
 	struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card);
 	struct kbl_hdmi_pcm *pcm;
+	struct snd_soc_codec *codec = NULL;
 	int err, i = 0;
 	char jack_name[NAME_SIZE];
 
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+		codec = pcm->codec_dai->codec;
 		snprintf(jack_name, sizeof(jack_name),
 			"HDMI/DP, pcm=%d Jack", pcm->device);
 		err = snd_soc_card_jack_new(card, jack_name,
@@ -620,11 +795,14 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
 		i++;
 	}
 
-	return 0;
+	if (!codec)
+		return -EINVAL;
+
+	return hdac_hdmi_jack_port_init(codec, &card->dapm);
 }
 
 /* kabylake audio machine driver for SPT + RT5663 */
-static struct snd_soc_card kabylake_audio_card = {
+static struct snd_soc_card kabylake_audio_card_rt5663_m98927 = {
 	.name = "kblrt5663max",
 	.owner = THIS_MODULE,
 	.dai_link = kabylake_dais,
@@ -641,6 +819,22 @@ static struct snd_soc_card kabylake_audio_card = {
 	.late_probe = kabylake_card_late_probe,
 };
 
+/* kabylake audio machine driver for RT5663 */
+static struct snd_soc_card kabylake_audio_card_rt5663 = {
+	.name = "kblrt5663",
+	.owner = THIS_MODULE,
+	.dai_link = kabylake_5663_dais,
+	.num_links = ARRAY_SIZE(kabylake_5663_dais),
+	.controls = kabylake_5663_controls,
+	.num_controls = ARRAY_SIZE(kabylake_5663_controls),
+	.dapm_widgets = kabylake_5663_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(kabylake_5663_widgets),
+	.dapm_routes = kabylake_5663_map,
+	.num_dapm_routes = ARRAY_SIZE(kabylake_5663_map),
+	.fully_routed = true,
+	.late_probe = kabylake_card_late_probe,
+};
+
 static int kabylake_audio_probe(struct platform_device *pdev)
 {
 	struct kbl_rt5663_private *ctx;
@@ -652,19 +846,30 @@ static int kabylake_audio_probe(struct platform_device *pdev)
 
 	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
 
-	kabylake_audio_card.dev = &pdev->dev;
-	snd_soc_card_set_drvdata(&kabylake_audio_card, ctx);
+	kabylake_audio_card =
+		(struct snd_soc_card *)pdev->id_entry->driver_data;
+
+	kabylake_audio_card->dev = &pdev->dev;
+	snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
 
 	pdata = dev_get_drvdata(&pdev->dev);
 	if (pdata)
 		dmic_constraints = pdata->dmic_num == 2 ?
 			&constraints_dmic_2ch : &constraints_dmic_channels;
 
-	return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card);
+	return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
 }
 
 static const struct platform_device_id kbl_board_ids[] = {
-	{ .name = "kbl_rt5663_m98927" },
+	{
+		.name = "kbl_rt5663",
+		.driver_data = (kernel_ulong_t)&kabylake_audio_card_rt5663,
+	},
+	{
+		.name = "kbl_rt5663_m98927",
+		.driver_data =
+			(kernel_ulong_t)&kabylake_audio_card_rt5663_m98927,
+	},
 	{ }
 };
 
@@ -684,4 +889,5 @@ MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode");
 MODULE_AUTHOR("Naveen M <naveen.m@intel.com>");
 MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kbl_rt5663");
 MODULE_ALIAS("platform:kbl_rt5663_m98927");
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index 3fe4a0807095..88ff54220007 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -18,6 +18,7 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <sound/core.h>
@@ -62,7 +63,10 @@ struct kbl_codec_private {
 enum {
 	KBL_DPCM_AUDIO_PB = 0,
 	KBL_DPCM_AUDIO_CP,
+	KBL_DPCM_AUDIO_HS_PB,
+	KBL_DPCM_AUDIO_ECHO_REF_CP,
 	KBL_DPCM_AUDIO_DMIC_CP,
+	KBL_DPCM_AUDIO_RT5514_DSP,
 	KBL_DPCM_AUDIO_HDMI1_PB,
 	KBL_DPCM_AUDIO_HDMI2_PB,
 };
@@ -81,8 +85,8 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
 	SND_SOC_DAPM_SPK("Left Spk", NULL),
 	SND_SOC_DAPM_SPK("Right Spk", NULL),
 	SND_SOC_DAPM_MIC("DMIC", NULL),
-	SND_SOC_DAPM_SPK("DP", NULL),
-	SND_SOC_DAPM_SPK("HDMI", NULL),
+	SND_SOC_DAPM_SPK("HDMI1", NULL),
+	SND_SOC_DAPM_SPK("HDMI2", NULL),
 
 };
 
@@ -99,23 +103,25 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
 	{ "IN1P", NULL, "Headset Mic" },
 	{ "IN1N", NULL, "Headset Mic" },
 
-	{ "HDMI", NULL, "hif5 Output" },
-	{ "DP", NULL, "hif6 Output" },
-
 	/* CODEC BE connections */
 	{ "Left HiFi Playback", NULL, "ssp0 Tx" },
 	{ "Right HiFi Playback", NULL, "ssp0 Tx" },
-	{ "ssp0 Tx", NULL, "codec0_out" },
+	{ "ssp0 Tx", NULL, "spk_out" },
 
 	{ "AIF Playback", NULL, "ssp1 Tx" },
-	{ "ssp1 Tx", NULL, "codec1_out" },
+	{ "ssp1 Tx", NULL, "hs_out" },
 
-	{ "codec0_in", NULL, "ssp1 Rx" },
+	{ "hs_in", NULL, "ssp1 Rx" },
 	{ "ssp1 Rx", NULL, "AIF Capture" },
 
 	{ "codec1_in", NULL, "ssp0 Rx" },
 	{ "ssp0 Rx", NULL, "AIF1 Capture" },
 
+	/* IV feedback path */
+	{ "codec0_fb_in", NULL, "ssp0 Rx"},
+	{ "ssp0 Rx", NULL, "Left HiFi Capture" },
+	{ "ssp0 Rx", NULL, "Right HiFi Capture" },
+
 	/* DMIC */
 	{ "DMIC1L", NULL, "DMIC" },
 	{ "DMIC1R", NULL, "DMIC" },
@@ -173,6 +179,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
 	int ret;
 	struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
 	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_jack *jack;
 
 	/*
 	 * Headset buttons map to the google Reference headset.
@@ -187,6 +194,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
 		return ret;
 	}
 
+	jack = &ctx->kabylake_headset;
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
 	rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
 
 	ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC");
@@ -319,7 +332,9 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
 	int ret;
 
 	/* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
-	rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1);
+	rt5663_sel_asrc_clk_src(codec_dai->codec,
+			RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
+			RT5663_CLK_SEL_I2S1_ASRC);
 
 	ret = snd_soc_dai_set_sysclk(codec_dai,
 			RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
@@ -349,27 +364,25 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
 				return ret;
 			}
 
-			ret = snd_soc_dai_set_pll(codec_dai, 0,
-				RT5514_PLL1_S_BCLK, RT5514_AIF1_BCLK_FREQ,
-						RT5514_AIF1_SYSCLK_FREQ);
+			ret = snd_soc_dai_set_sysclk(codec_dai,
+				RT5514_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
 			if (ret < 0) {
-				dev_err(rtd->dev, "set bclk err: %d\n", ret);
+				dev_err(rtd->dev, "set sysclk err: %d\n", ret);
 				return ret;
 			}
-
-			ret = snd_soc_dai_set_sysclk(codec_dai,
-				RT5514_SCLK_S_PLL1, RT5514_AIF1_SYSCLK_FREQ,
-							SND_SOC_CLOCK_IN);
+		}
+		if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
+			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
 			if (ret < 0) {
-				dev_err(rtd->dev, "set sclk err: %d\n", ret);
+				dev_err(rtd->dev, "DEV0 TDM slot err:%d\n", ret);
 				return ret;
 			}
 		}
-		if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME) ||
-			!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
-			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF0, 3, 8, 16);
+
+		if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
+			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
 			if (ret < 0) {
-				dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
+				dev_err(rtd->dev, "DEV1 TDM slot err:%d\n", ret);
 				return ret;
 			}
 		}
@@ -449,6 +462,36 @@ static struct snd_soc_dai_link kabylake_dais[] = {
 		.dpcm_capture = 1,
 		.ops = &kabylake_rt5663_fe_ops,
 	},
+	[KBL_DPCM_AUDIO_HS_PB] = {
+		.name = "Kbl Audio Headset Playback",
+		.stream_name = "Headset Audio",
+		.cpu_dai_name = "System Pin2",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.dpcm_playback = 1,
+		.nonatomic = 1,
+		.dynamic = 1,
+	},
+	[KBL_DPCM_AUDIO_ECHO_REF_CP] = {
+		.name = "Kbl Audio Echo Reference cap",
+		.stream_name = "Echoreference Capture",
+		.cpu_dai_name = "Echoref Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.init = NULL,
+		.capture_only = 1,
+		.nonatomic = 1,
+	},
+	[KBL_DPCM_AUDIO_RT5514_DSP] = {
+		.name = "rt5514 dsp",
+		.stream_name = "Wake on Voice",
+		.cpu_dai_name = "spi-PRP0001:00",
+		.platform_name = "spi-PRP0001:00",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+	},
 	[KBL_DPCM_AUDIO_DMIC_CP] = {
 		.name = "Kbl Audio DMIC cap",
 		.stream_name = "dmiccap",
@@ -555,10 +598,12 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
 {
 	struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
 	struct kbl_hdmi_pcm *pcm;
+	struct snd_soc_codec *codec = NULL;
 	int err, i = 0;
 	char jack_name[NAME_SIZE];
 
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+		codec = pcm->codec_dai->codec;
 		err = snd_soc_card_jack_new(card, jack_name,
 				SND_JACK_AVOUT, &ctx->kabylake_hdmi[i],
 				NULL, 0);
@@ -572,7 +617,10 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
 		i++;
 	}
 
-	return 0;
+	if (!codec)
+		return -EINVAL;
+
+	return hdac_hdmi_jack_port_init(codec, &card->dapm);
 }
 
 /*
diff --git a/sound/soc/intel/boards/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c
index 4e08885f37aa..6f44acfb4aae 100644
--- a/sound/soc/intel/boards/mfld_machine.c
+++ b/sound/soc/intel/boards/mfld_machine.c
@@ -376,10 +376,8 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
 	/* audio interrupt base of SRAM location where
 	 * interrupts are stored by System FW */
 	mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
-	if (!mc_drv_ctx) {
-		pr_err("allocation failed\n");
+	if (!mc_drv_ctx)
 		return -ENOMEM;
-	}
 
 	irq_mem = platform_get_resource_byname(
 				pdev, IORESOURCE_MEM, "IRQ_BASE");
diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c
index 9e4094e2c6e3..c044400540ec 100644
--- a/sound/soc/intel/haswell/sst-haswell-pcm.c
+++ b/sound/soc/intel/haswell/sst-haswell-pcm.c
@@ -1135,7 +1135,7 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
 	return 0;
 }
 
-static struct snd_soc_platform_driver hsw_soc_platform = {
+static const struct snd_soc_platform_driver hsw_soc_platform = {
 	.probe		= hsw_pcm_probe,
 	.remove		= hsw_pcm_remove,
 	.ops		= &hsw_pcm_ops,
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile
index e7d77722d560..3380deb81015 100644
--- a/sound/soc/intel/skylake/Makefile
+++ b/sound/soc/intel/skylake/Makefile
@@ -8,7 +8,8 @@ endif
 obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
 
 # Skylake IPC Support
-snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \
-		skl-sst.o bxt-sst.o skl-sst-utils.o
+snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o \
+		skl-sst-cldma.o skl-sst.o bxt-sst.o cnl-sst.o \
+		skl-sst-utils.o
 
 obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c
index cf11b84888b9..4524211960e4 100644
--- a/sound/soc/intel/skylake/bxt-sst.c
+++ b/sound/soc/intel/skylake/bxt-sst.c
@@ -530,7 +530,7 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
 	return 0;
 }
 
-static struct skl_dsp_fw_ops bxt_fw_ops = {
+static const struct skl_dsp_fw_ops bxt_fw_ops = {
 	.set_state_D0 = bxt_set_dsp_D0,
 	.set_state_D3 = bxt_set_dsp_D3,
 	.set_state_D0i3 = bxt_schedule_dsp_D0i3,
@@ -581,10 +581,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
 	sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
 			SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
 
+	ret = skl_ipc_init(dev, skl);
+	if (ret) {
+		skl_dsp_free(sst);
+		return ret;
+	}
+
 	/* set the D0i3 check */
 	skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0;
 
-	skl->cores.count = 2;
 	skl->boot_complete = false;
 	init_waitqueue_head(&skl->boot_wait);
 	INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
@@ -629,11 +634,6 @@ void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
 		release_firmware(ctx->dsp->fw);
 	skl_freeup_uuid_list(ctx);
 	skl_ipc_free(&ctx->ipc);
-	ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
-
-	if (ctx->dsp->addr.lpe)
-		iounmap(ctx->dsp->addr.lpe);
-
 	ctx->dsp->ops->free(ctx->dsp);
 }
 EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup);
diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.c b/sound/soc/intel/skylake/cnl-sst-dsp.c
new file mode 100644
index 000000000000..2f8326707c21
--- /dev/null
+++ b/sound/soc/intel/skylake/cnl-sst-dsp.c
@@ -0,0 +1,274 @@
+/*
+ * cnl-sst-dsp.c - CNL SST library generic function
+ *
+ * Copyright (C) 2016-17, Intel Corporation.
+ * Author: Guneshwor Singh <guneshwor.o.singh@intel.com>
+ *
+ * Modified from:
+ *	SKL SST library generic function
+ *	Copyright (C) 2014-15, Intel Corporation.
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/device.h>
+#include "../common/sst-dsp.h"
+#include "../common/sst-ipc.h"
+#include "../common/sst-dsp-priv.h"
+#include "cnl-sst-dsp.h"
+
+/* various timeout values */
+#define CNL_DSP_PU_TO		50
+#define CNL_DSP_PD_TO		50
+#define CNL_DSP_RESET_TO	50
+
+static int
+cnl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
+{
+	/* update bits */
+	sst_dsp_shim_update_bits_unlocked(ctx,
+			CNL_ADSP_REG_ADSPCS, CNL_ADSPCS_CRST(core_mask),
+			CNL_ADSPCS_CRST(core_mask));
+
+	/* poll with timeout to check if operation successful */
+	return sst_dsp_register_poll(ctx,
+			CNL_ADSP_REG_ADSPCS,
+			CNL_ADSPCS_CRST(core_mask),
+			CNL_ADSPCS_CRST(core_mask),
+			CNL_DSP_RESET_TO,
+			"Set reset");
+}
+
+static int
+cnl_dsp_core_unset_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
+{
+	/* update bits */
+	sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
+					CNL_ADSPCS_CRST(core_mask), 0);
+
+	/* poll with timeout to check if operation successful */
+	return sst_dsp_register_poll(ctx,
+			CNL_ADSP_REG_ADSPCS,
+			CNL_ADSPCS_CRST(core_mask),
+			0,
+			CNL_DSP_RESET_TO,
+			"Unset reset");
+}
+
+static bool is_cnl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask)
+{
+	int val;
+	bool is_enable;
+
+	val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPCS);
+
+	is_enable = (val & CNL_ADSPCS_CPA(core_mask)) &&
+			(val & CNL_ADSPCS_SPA(core_mask)) &&
+			!(val & CNL_ADSPCS_CRST(core_mask)) &&
+			!(val & CNL_ADSPCS_CSTALL(core_mask));
+
+	dev_dbg(ctx->dev, "DSP core(s) enabled? %d: core_mask %#x\n",
+		is_enable, core_mask);
+
+	return is_enable;
+}
+
+static int cnl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask)
+{
+	/* stall core */
+	sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
+			CNL_ADSPCS_CSTALL(core_mask),
+			CNL_ADSPCS_CSTALL(core_mask));
+
+	/* set reset state */
+	return cnl_dsp_core_set_reset_state(ctx, core_mask);
+}
+
+static int cnl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask)
+{
+	int ret;
+
+	/* unset reset state */
+	ret = cnl_dsp_core_unset_reset_state(ctx, core_mask);
+	if (ret < 0)
+		return ret;
+
+	/* run core */
+	sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
+				CNL_ADSPCS_CSTALL(core_mask), 0);
+
+	if (!is_cnl_dsp_core_enable(ctx, core_mask)) {
+		cnl_dsp_reset_core(ctx, core_mask);
+		dev_err(ctx->dev, "DSP core mask %#x enable failed\n",
+			core_mask);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int cnl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask)
+{
+	/* update bits */
+	sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
+					  CNL_ADSPCS_SPA(core_mask),
+					  CNL_ADSPCS_SPA(core_mask));
+
+	/* poll with timeout to check if operation successful */
+	return sst_dsp_register_poll(ctx, CNL_ADSP_REG_ADSPCS,
+				    CNL_ADSPCS_CPA(core_mask),
+				    CNL_ADSPCS_CPA(core_mask),
+				    CNL_DSP_PU_TO,
+				    "Power up");
+}
+
+static int cnl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask)
+{
+	/* update bits */
+	sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
+					CNL_ADSPCS_SPA(core_mask), 0);
+
+	/* poll with timeout to check if operation successful */
+	return sst_dsp_register_poll(ctx,
+			CNL_ADSP_REG_ADSPCS,
+			CNL_ADSPCS_CPA(core_mask),
+			0,
+			CNL_DSP_PD_TO,
+			"Power down");
+}
+
+int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask)
+{
+	int ret;
+
+	/* power up */
+	ret = cnl_dsp_core_power_up(ctx, core_mask);
+	if (ret < 0) {
+		dev_dbg(ctx->dev, "DSP core mask %#x power up failed",
+			core_mask);
+		return ret;
+	}
+
+	return cnl_dsp_start_core(ctx, core_mask);
+}
+
+int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask)
+{
+	int ret;
+
+	ret = cnl_dsp_reset_core(ctx, core_mask);
+	if (ret < 0) {
+		dev_err(ctx->dev, "DSP core mask %#x reset failed\n",
+			core_mask);
+		return ret;
+	}
+
+	/* power down core*/
+	ret = cnl_dsp_core_power_down(ctx, core_mask);
+	if (ret < 0) {
+		dev_err(ctx->dev, "DSP core mask %#x power down failed\n",
+			core_mask);
+		return ret;
+	}
+
+	if (is_cnl_dsp_core_enable(ctx, core_mask)) {
+		dev_err(ctx->dev, "DSP core mask %#x disable failed\n",
+			core_mask);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id)
+{
+	struct sst_dsp *ctx = dev_id;
+	u32 val;
+	irqreturn_t ret = IRQ_NONE;
+
+	spin_lock(&ctx->spinlock);
+
+	val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS);
+	ctx->intr_status = val;
+
+	if (val == 0xffffffff) {
+		spin_unlock(&ctx->spinlock);
+		return IRQ_NONE;
+	}
+
+	if (val & CNL_ADSPIS_IPC) {
+		cnl_ipc_int_disable(ctx);
+		ret = IRQ_WAKE_THREAD;
+	}
+
+	spin_unlock(&ctx->spinlock);
+
+	return ret;
+}
+
+void cnl_dsp_free(struct sst_dsp *dsp)
+{
+	cnl_ipc_int_disable(dsp);
+
+	free_irq(dsp->irq, dsp);
+	cnl_ipc_op_int_disable(dsp);
+	cnl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK);
+}
+EXPORT_SYMBOL_GPL(cnl_dsp_free);
+
+void cnl_ipc_int_enable(struct sst_dsp *ctx)
+{
+	sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_ADSPIC,
+				 CNL_ADSPIC_IPC, CNL_ADSPIC_IPC);
+}
+
+void cnl_ipc_int_disable(struct sst_dsp *ctx)
+{
+	sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPIC,
+					  CNL_ADSPIC_IPC, 0);
+}
+
+void cnl_ipc_op_int_enable(struct sst_dsp *ctx)
+{
+	/* enable IPC DONE interrupt */
+	sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
+				 CNL_ADSP_REG_HIPCCTL_DONE,
+				 CNL_ADSP_REG_HIPCCTL_DONE);
+
+	/* enable IPC BUSY interrupt */
+	sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
+				 CNL_ADSP_REG_HIPCCTL_BUSY,
+				 CNL_ADSP_REG_HIPCCTL_BUSY);
+}
+
+void cnl_ipc_op_int_disable(struct sst_dsp *ctx)
+{
+	/* disable IPC DONE interrupt */
+	sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
+				 CNL_ADSP_REG_HIPCCTL_DONE, 0);
+
+	/* disable IPC BUSY interrupt */
+	sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
+				 CNL_ADSP_REG_HIPCCTL_BUSY, 0);
+}
+
+bool cnl_ipc_int_status(struct sst_dsp *ctx)
+{
+	return sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS) &
+							CNL_ADSPIS_IPC;
+}
+
+void cnl_ipc_free(struct sst_generic_ipc *ipc)
+{
+	cnl_ipc_op_int_disable(ipc->dsp);
+	sst_ipc_fini(ipc);
+}
diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.h b/sound/soc/intel/skylake/cnl-sst-dsp.h
new file mode 100644
index 000000000000..09bd218df5c4
--- /dev/null
+++ b/sound/soc/intel/skylake/cnl-sst-dsp.h
@@ -0,0 +1,112 @@
+/*
+ * Cannonlake SST DSP Support
+ *
+ * Copyright (C) 2016-17, Intel Corporation.
+ *
+ * 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 __CNL_SST_DSP_H__
+#define __CNL_SST_DSP_H__
+
+struct sst_dsp;
+struct skl_sst;
+struct sst_dsp_device;
+struct sst_generic_ipc;
+
+/* Intel HD Audio General DSP Registers */
+#define CNL_ADSP_GEN_BASE		0x0
+#define CNL_ADSP_REG_ADSPCS		(CNL_ADSP_GEN_BASE + 0x04)
+#define CNL_ADSP_REG_ADSPIC		(CNL_ADSP_GEN_BASE + 0x08)
+#define CNL_ADSP_REG_ADSPIS		(CNL_ADSP_GEN_BASE + 0x0c)
+
+/* Intel HD Audio Inter-Processor Communication Registers */
+#define CNL_ADSP_IPC_BASE               0xc0
+#define CNL_ADSP_REG_HIPCTDR            (CNL_ADSP_IPC_BASE + 0x00)
+#define CNL_ADSP_REG_HIPCTDA            (CNL_ADSP_IPC_BASE + 0x04)
+#define CNL_ADSP_REG_HIPCTDD            (CNL_ADSP_IPC_BASE + 0x08)
+#define CNL_ADSP_REG_HIPCIDR            (CNL_ADSP_IPC_BASE + 0x10)
+#define CNL_ADSP_REG_HIPCIDA            (CNL_ADSP_IPC_BASE + 0x14)
+#define CNL_ADSP_REG_HIPCIDD            (CNL_ADSP_IPC_BASE + 0x18)
+#define CNL_ADSP_REG_HIPCCTL            (CNL_ADSP_IPC_BASE + 0x28)
+
+/* HIPCTDR */
+#define CNL_ADSP_REG_HIPCTDR_BUSY	BIT(31)
+
+/* HIPCTDA */
+#define CNL_ADSP_REG_HIPCTDA_DONE	BIT(31)
+
+/* HIPCIDR */
+#define CNL_ADSP_REG_HIPCIDR_BUSY	BIT(31)
+
+/* HIPCIDA */
+#define CNL_ADSP_REG_HIPCIDA_DONE	BIT(31)
+
+/* CNL HIPCCTL */
+#define CNL_ADSP_REG_HIPCCTL_DONE	BIT(1)
+#define CNL_ADSP_REG_HIPCCTL_BUSY	BIT(0)
+
+/* CNL HIPCT */
+#define CNL_ADSP_REG_HIPCT_BUSY		BIT(31)
+
+/* Intel HD Audio SRAM Window 1 */
+#define CNL_ADSP_SRAM1_BASE		0xa0000
+
+#define CNL_ADSP_MMIO_LEN		0x10000
+
+#define CNL_ADSP_W0_STAT_SZ		0x1000
+
+#define CNL_ADSP_W0_UP_SZ		0x1000
+
+#define CNL_ADSP_W1_SZ			0x1000
+
+#define CNL_FW_STS_MASK			0xf
+
+#define CNL_ADSPIC_IPC			0x1
+#define CNL_ADSPIS_IPC			0x1
+
+#define CNL_DSP_CORES		4
+#define CNL_DSP_CORES_MASK	((1 << CNL_DSP_CORES) - 1)
+
+/* core reset - asserted high */
+#define CNL_ADSPCS_CRST_SHIFT	0
+#define CNL_ADSPCS_CRST(x)	(x << CNL_ADSPCS_CRST_SHIFT)
+
+/* core run/stall - when set to 1 core is stalled */
+#define CNL_ADSPCS_CSTALL_SHIFT	8
+#define CNL_ADSPCS_CSTALL(x)	(x << CNL_ADSPCS_CSTALL_SHIFT)
+
+/* set power active - when set to 1 turn core on */
+#define CNL_ADSPCS_SPA_SHIFT	16
+#define CNL_ADSPCS_SPA(x)	(x << CNL_ADSPCS_SPA_SHIFT)
+
+/* current power active - power status of cores, set by hardware */
+#define CNL_ADSPCS_CPA_SHIFT	24
+#define CNL_ADSPCS_CPA(x)	(x << CNL_ADSPCS_CPA_SHIFT)
+
+int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core);
+int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core);
+irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id);
+void cnl_dsp_free(struct sst_dsp *dsp);
+
+void cnl_ipc_int_enable(struct sst_dsp *ctx);
+void cnl_ipc_int_disable(struct sst_dsp *ctx);
+void cnl_ipc_op_int_enable(struct sst_dsp *ctx);
+void cnl_ipc_op_int_disable(struct sst_dsp *ctx);
+bool cnl_ipc_int_status(struct sst_dsp *ctx);
+void cnl_ipc_free(struct sst_generic_ipc *ipc);
+
+int cnl_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 cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx);
+void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
+
+#endif /*__CNL_SST_DSP_H__*/
diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c
new file mode 100644
index 000000000000..387de388ce29
--- /dev/null
+++ b/sound/soc/intel/skylake/cnl-sst.c
@@ -0,0 +1,497 @@
+/*
+ * cnl-sst.c - DSP library functions for CNL platform
+ *
+ * Copyright (C) 2016-17, Intel Corporation.
+ *
+ * Author: Guneshwor Singh <guneshwor.o.singh@intel.com>
+ *
+ * Modified from:
+ *	HDA DSP library functions for SKL platform
+ *	Copyright (C) 2014-15, Intel Corporation.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/device.h>
+
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+#include "../common/sst-ipc.h"
+#include "cnl-sst-dsp.h"
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
+
+#define CNL_FW_ROM_INIT		0x1
+#define CNL_FW_INIT		0x5
+#define CNL_IPC_PURGE		0x01004000
+#define CNL_INIT_TIMEOUT	300
+#define CNL_BASEFW_TIMEOUT	3000
+
+#define CNL_ADSP_SRAM0_BASE	0x80000
+
+/* Firmware status window */
+#define CNL_ADSP_FW_STATUS	CNL_ADSP_SRAM0_BASE
+#define CNL_ADSP_ERROR_CODE	(CNL_ADSP_FW_STATUS + 0x4)
+
+#define CNL_INSTANCE_ID		0
+#define CNL_BASE_FW_MODULE_ID	0
+#define CNL_ADSP_FW_HDR_OFFSET	0x2000
+#define CNL_ROM_CTRL_DMA_ID	0x9
+
+static int cnl_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize)
+{
+
+	int ret, stream_tag;
+
+	stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab);
+	if (stream_tag <= 0) {
+		dev_err(ctx->dev, "dma prepare failed: 0%#x\n", stream_tag);
+		return stream_tag;
+	}
+
+	ctx->dsp_ops.stream_tag = stream_tag;
+	memcpy(ctx->dmab.area, fwdata, fwsize);
+
+	/* purge FW request */
+	sst_dsp_shim_write(ctx, CNL_ADSP_REG_HIPCIDR,
+			   CNL_ADSP_REG_HIPCIDR_BUSY | (CNL_IPC_PURGE |
+			   ((stream_tag - 1) << CNL_ROM_CTRL_DMA_ID)));
+
+	ret = cnl_dsp_enable_core(ctx, SKL_DSP_CORE0_MASK);
+	if (ret < 0) {
+		dev_err(ctx->dev, "dsp boot core failed ret: %d\n", ret);
+		ret = -EIO;
+		goto base_fw_load_failed;
+	}
+
+	/* enable interrupt */
+	cnl_ipc_int_enable(ctx);
+	cnl_ipc_op_int_enable(ctx);
+
+	ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK,
+				    CNL_FW_ROM_INIT, CNL_INIT_TIMEOUT,
+				    "rom load");
+	if (ret < 0) {
+		dev_err(ctx->dev, "rom init timeout, ret: %d\n", ret);
+		goto base_fw_load_failed;
+	}
+
+	return 0;
+
+base_fw_load_failed:
+	ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag);
+	cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
+
+	return ret;
+}
+
+static int sst_transfer_fw_host_dma(struct sst_dsp *ctx)
+{
+	int ret;
+
+	ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag);
+	ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK,
+				    CNL_FW_INIT, CNL_BASEFW_TIMEOUT,
+				    "firmware boot");
+
+	ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag);
+	ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag);
+
+	return ret;
+}
+
+static int cnl_load_base_firmware(struct sst_dsp *ctx)
+{
+	struct firmware stripped_fw;
+	struct skl_sst *cnl = ctx->thread_context;
+	int ret;
+
+	if (!ctx->fw) {
+		ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
+		if (ret < 0) {
+			dev_err(ctx->dev, "request firmware failed: %d\n", ret);
+			goto cnl_load_base_firmware_failed;
+		}
+	}
+
+	/* parse uuids if first boot */
+	if (cnl->is_first_boot) {
+		ret = snd_skl_parse_uuids(ctx, ctx->fw,
+					  CNL_ADSP_FW_HDR_OFFSET, 0);
+		if (ret < 0)
+			goto cnl_load_base_firmware_failed;
+	}
+
+	stripped_fw.data = ctx->fw->data;
+	stripped_fw.size = ctx->fw->size;
+	skl_dsp_strip_extended_manifest(&stripped_fw);
+
+	ret = cnl_prepare_fw(ctx, stripped_fw.data, stripped_fw.size);
+	if (ret < 0) {
+		dev_err(ctx->dev, "prepare firmware failed: %d\n", ret);
+		goto cnl_load_base_firmware_failed;
+	}
+
+	ret = sst_transfer_fw_host_dma(ctx);
+	if (ret < 0) {
+		dev_err(ctx->dev, "transfer firmware failed: %d\n", ret);
+		cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
+		goto cnl_load_base_firmware_failed;
+	}
+
+	ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete,
+				 msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
+	if (ret == 0) {
+		dev_err(ctx->dev, "FW ready timed-out\n");
+		cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
+		ret = -EIO;
+		goto cnl_load_base_firmware_failed;
+	}
+
+	cnl->fw_loaded = true;
+
+	return 0;
+
+cnl_load_base_firmware_failed:
+	release_firmware(ctx->fw);
+	ctx->fw = NULL;
+
+	return ret;
+}
+
+static int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
+{
+	struct skl_sst *cnl = ctx->thread_context;
+	unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
+	struct skl_ipc_dxstate_info dx;
+	int ret;
+
+	if (!cnl->fw_loaded) {
+		cnl->boot_complete = false;
+		ret = cnl_load_base_firmware(ctx);
+		if (ret < 0) {
+			dev_err(ctx->dev, "fw reload failed: %d\n", ret);
+			return ret;
+		}
+
+		cnl->cores.state[core_id] = SKL_DSP_RUNNING;
+		return ret;
+	}
+
+	ret = cnl_dsp_enable_core(ctx, core_mask);
+	if (ret < 0) {
+		dev_err(ctx->dev, "enable dsp core %d failed: %d\n",
+			core_id, ret);
+		goto err;
+	}
+
+	if (core_id == SKL_DSP_CORE0_ID) {
+		/* enable interrupt */
+		cnl_ipc_int_enable(ctx);
+		cnl_ipc_op_int_enable(ctx);
+		cnl->boot_complete = false;
+
+		ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete,
+					 msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
+		if (ret == 0) {
+			dev_err(ctx->dev,
+				"dsp boot timeout, status=%#x error=%#x\n",
+				sst_dsp_shim_read(ctx, CNL_ADSP_FW_STATUS),
+				sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE));
+			goto err;
+		}
+	} else {
+		dx.core_mask = core_mask;
+		dx.dx_mask = core_mask;
+
+		ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID,
+				     CNL_BASE_FW_MODULE_ID, &dx);
+		if (ret < 0) {
+			dev_err(ctx->dev, "set_dx failed, core: %d ret: %d\n",
+				core_id, ret);
+			goto err;
+		}
+	}
+	cnl->cores.state[core_id] = SKL_DSP_RUNNING;
+
+	return 0;
+err:
+	cnl_dsp_disable_core(ctx, core_mask);
+
+	return ret;
+}
+
+static int cnl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
+{
+	struct skl_sst *cnl = ctx->thread_context;
+	unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
+	struct skl_ipc_dxstate_info dx;
+	int ret;
+
+	dx.core_mask = core_mask;
+	dx.dx_mask = SKL_IPC_D3_MASK;
+
+	ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID,
+			     CNL_BASE_FW_MODULE_ID, &dx);
+	if (ret < 0) {
+		dev_err(ctx->dev,
+			"dsp core %d to d3 failed; continue reset\n",
+			core_id);
+		cnl->fw_loaded = false;
+	}
+
+	/* disable interrupts if core 0 */
+	if (core_id == SKL_DSP_CORE0_ID) {
+		skl_ipc_op_int_disable(ctx);
+		skl_ipc_int_disable(ctx);
+	}
+
+	ret = cnl_dsp_disable_core(ctx, core_mask);
+	if (ret < 0) {
+		dev_err(ctx->dev, "disable dsp core %d failed: %d\n",
+			core_id, ret);
+		return ret;
+	}
+
+	cnl->cores.state[core_id] = SKL_DSP_RESET;
+
+	return ret;
+}
+
+static unsigned int cnl_get_errno(struct sst_dsp *ctx)
+{
+	return sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE);
+}
+
+static const struct skl_dsp_fw_ops cnl_fw_ops = {
+	.set_state_D0 = cnl_set_dsp_D0,
+	.set_state_D3 = cnl_set_dsp_D3,
+	.load_fw = cnl_load_base_firmware,
+	.get_fw_errcode = cnl_get_errno,
+};
+
+static struct sst_ops cnl_ops = {
+	.irq_handler = cnl_dsp_sst_interrupt,
+	.write = sst_shim32_write,
+	.read = sst_shim32_read,
+	.ram_read = sst_memcpy_fromio_32,
+	.ram_write = sst_memcpy_toio_32,
+	.free = cnl_dsp_free,
+};
+
+#define CNL_IPC_GLB_NOTIFY_RSP_SHIFT	29
+#define CNL_IPC_GLB_NOTIFY_RSP_MASK	0x1
+#define CNL_IPC_GLB_NOTIFY_RSP_TYPE(x)	(((x) >> CNL_IPC_GLB_NOTIFY_RSP_SHIFT) \
+					& CNL_IPC_GLB_NOTIFY_RSP_MASK)
+
+static irqreturn_t cnl_dsp_irq_thread_handler(int irq, void *context)
+{
+	struct sst_dsp *dsp = context;
+	struct skl_sst *cnl = sst_dsp_get_thread_context(dsp);
+	struct sst_generic_ipc *ipc = &cnl->ipc;
+	struct skl_ipc_header header = {0};
+	u32 hipcida, hipctdr, hipctdd;
+	int ipc_irq = 0;
+
+	/* here we handle ipc interrupts only */
+	if (!(dsp->intr_status & CNL_ADSPIS_IPC))
+		return IRQ_NONE;
+
+	hipcida = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDA);
+	hipctdr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDR);
+
+	/* reply message from dsp */
+	if (hipcida & CNL_ADSP_REG_HIPCIDA_DONE) {
+		sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL,
+			CNL_ADSP_REG_HIPCCTL_DONE, 0);
+
+		/* clear done bit - tell dsp operation is complete */
+		sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCIDA,
+			CNL_ADSP_REG_HIPCIDA_DONE, CNL_ADSP_REG_HIPCIDA_DONE);
+
+		ipc_irq = 1;
+
+		/* unmask done interrupt */
+		sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL,
+			CNL_ADSP_REG_HIPCCTL_DONE, CNL_ADSP_REG_HIPCCTL_DONE);
+	}
+
+	/* new message from dsp */
+	if (hipctdr & CNL_ADSP_REG_HIPCTDR_BUSY) {
+		hipctdd = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDD);
+		header.primary = hipctdr;
+		header.extension = hipctdd;
+		dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x",
+						header.primary);
+		dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x",
+						header.extension);
+
+		if (CNL_IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) {
+			/* Handle Immediate reply from DSP Core */
+			skl_ipc_process_reply(ipc, header);
+		} else {
+			dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n");
+			skl_ipc_process_notification(ipc, header);
+		}
+		/* clear busy interrupt */
+		sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDR,
+			CNL_ADSP_REG_HIPCTDR_BUSY, CNL_ADSP_REG_HIPCTDR_BUSY);
+
+		/* set done bit to ack dsp */
+		sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDA,
+			CNL_ADSP_REG_HIPCTDA_DONE, CNL_ADSP_REG_HIPCTDA_DONE);
+		ipc_irq = 1;
+	}
+
+	if (ipc_irq == 0)
+		return IRQ_NONE;
+
+	cnl_ipc_int_enable(dsp);
+
+	/* continue to send any remaining messages */
+	schedule_work(&ipc->kwork);
+
+	return IRQ_HANDLED;
+}
+
+static struct sst_dsp_device cnl_dev = {
+	.thread = cnl_dsp_irq_thread_handler,
+	.ops = &cnl_ops,
+};
+
+static void cnl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
+{
+	struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header);
+
+	if (msg->tx_size)
+		sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size);
+	sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDD,
+				    header->extension);
+	sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDR,
+				header->primary | CNL_ADSP_REG_HIPCIDR_BUSY);
+}
+
+static bool cnl_ipc_is_dsp_busy(struct sst_dsp *dsp)
+{
+	u32 hipcidr;
+
+	hipcidr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDR);
+
+	return (hipcidr & CNL_ADSP_REG_HIPCIDR_BUSY);
+}
+
+static int cnl_ipc_init(struct device *dev, struct skl_sst *cnl)
+{
+	struct sst_generic_ipc *ipc;
+	int err;
+
+	ipc = &cnl->ipc;
+	ipc->dsp = cnl->dsp;
+	ipc->dev = dev;
+
+	ipc->tx_data_max_size = CNL_ADSP_W1_SZ;
+	ipc->rx_data_max_size = CNL_ADSP_W0_UP_SZ;
+
+	err = sst_ipc_init(ipc);
+	if (err)
+		return err;
+
+	/*
+	 * overriding tx_msg and is_dsp_busy since
+	 * ipc registers are different for cnl
+	 */
+	ipc->ops.tx_msg = cnl_ipc_tx_msg;
+	ipc->ops.tx_data_copy = skl_ipc_tx_data_copy;
+	ipc->ops.is_dsp_busy = cnl_ipc_is_dsp_busy;
+
+	return 0;
+}
+
+int cnl_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 skl_sst *cnl;
+	struct sst_dsp *sst;
+	int ret;
+
+	ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &cnl_dev);
+	if (ret < 0) {
+		dev_err(dev, "%s: no device\n", __func__);
+		return ret;
+	}
+
+	cnl = *dsp;
+	sst = cnl->dsp;
+	sst->fw_ops = cnl_fw_ops;
+	sst->addr.lpe = mmio_base;
+	sst->addr.shim = mmio_base;
+	sst->addr.sram0_base = CNL_ADSP_SRAM0_BASE;
+	sst->addr.sram1_base = CNL_ADSP_SRAM1_BASE;
+	sst->addr.w0_stat_sz = CNL_ADSP_W0_STAT_SZ;
+	sst->addr.w0_up_sz = CNL_ADSP_W0_UP_SZ;
+
+	sst_dsp_mailbox_init(sst, (CNL_ADSP_SRAM0_BASE + CNL_ADSP_W0_STAT_SZ),
+			     CNL_ADSP_W0_UP_SZ, CNL_ADSP_SRAM1_BASE,
+			     CNL_ADSP_W1_SZ);
+
+	ret = cnl_ipc_init(dev, cnl);
+	if (ret) {
+		skl_dsp_free(sst);
+		return ret;
+	}
+
+	cnl->boot_complete = false;
+	init_waitqueue_head(&cnl->boot_wait);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cnl_sst_dsp_init);
+
+int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx)
+{
+	int ret;
+	struct sst_dsp *sst = ctx->dsp;
+
+	ret = ctx->dsp->fw_ops.load_fw(sst);
+	if (ret < 0) {
+		dev_err(dev, "load base fw failed: %d", ret);
+		return ret;
+	}
+
+	skl_dsp_init_core_state(sst);
+
+	ctx->is_first_boot = false;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cnl_sst_init_fw);
+
+void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
+{
+	if (ctx->dsp->fw)
+		release_firmware(ctx->dsp->fw);
+
+	skl_freeup_uuid_list(ctx);
+	cnl_ipc_free(&ctx->ipc);
+
+	ctx->dsp->ops->free(ctx->dsp);
+}
+EXPORT_SYMBOL_GPL(cnl_sst_dsp_cleanup);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Cannonlake IPC driver");
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index eca85827dbd2..89f70133c8e4 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -22,6 +22,7 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include "skl-sst-dsp.h"
+#include "cnl-sst-dsp.h"
 #include "skl-sst-ipc.h"
 #include "skl.h"
 #include "../common/sst-dsp.h"
@@ -201,6 +202,7 @@ static struct skl_dsp_loader_ops bxt_get_loader_ops(void)
 static const struct skl_dsp_ops dsp_ops[] = {
 	{
 		.id = 0x9d70,
+		.num_cores = 2,
 		.loader_ops = skl_get_loader_ops,
 		.init = skl_sst_dsp_init,
 		.init_fw = skl_sst_init_fw,
@@ -208,6 +210,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_fw = skl_sst_init_fw,
@@ -215,6 +218,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
 	},
 	{
 		.id = 0x5a98,
+		.num_cores = 2,
 		.loader_ops = bxt_get_loader_ops,
 		.init = bxt_sst_dsp_init,
 		.init_fw = bxt_sst_init_fw,
@@ -222,11 +226,20 @@ static const struct skl_dsp_ops dsp_ops[] = {
 	},
 	{
 		.id = 0x3198,
+		.num_cores = 2,
 		.loader_ops = bxt_get_loader_ops,
 		.init = bxt_sst_dsp_init,
 		.init_fw = bxt_sst_init_fw,
 		.cleanup = bxt_sst_dsp_cleanup
 	},
+	{
+		.id = 0x9dc8,
+		.num_cores = 4,
+		.loader_ops = bxt_get_loader_ops,
+		.init = cnl_sst_dsp_init,
+		.init_fw = cnl_sst_init_fw,
+		.cleanup = cnl_sst_dsp_cleanup
+	},
 };
 
 const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
@@ -249,6 +262,7 @@ int skl_init_dsp(struct skl *skl)
 	struct skl_dsp_loader_ops loader_ops;
 	int irq = bus->irq;
 	const struct skl_dsp_ops *ops;
+	struct skl_dsp_cores *cores;
 	int ret;
 
 	/* enable ppcap interrupt */
@@ -263,8 +277,10 @@ int skl_init_dsp(struct skl *skl)
 	}
 
 	ops = skl_get_dsp_ops(skl->pci->device);
-	if (!ops)
-		return -EIO;
+	if (!ops) {
+		ret = -EIO;
+		goto unmap_mmio;
+	}
 
 	loader_ops = ops->loader_ops();
 	ret = ops->init(bus->dev, mmio_base, irq,
@@ -272,11 +288,35 @@ int skl_init_dsp(struct skl *skl)
 				&skl->skl_sst);
 
 	if (ret < 0)
-		return ret;
+		goto unmap_mmio;
 
 	skl->skl_sst->dsp_ops = ops;
+	cores = &skl->skl_sst->cores;
+	cores->count = ops->num_cores;
+
+	cores->state = kcalloc(cores->count, sizeof(*cores->state), GFP_KERNEL);
+	if (!cores->state) {
+		ret = -ENOMEM;
+		goto unmap_mmio;
+	}
+
+	cores->usage_count = kcalloc(cores->count, sizeof(*cores->usage_count),
+				     GFP_KERNEL);
+	if (!cores->usage_count) {
+		ret = -ENOMEM;
+		goto free_core_state;
+	}
+
 	dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
 
+	return 0;
+
+free_core_state:
+	kfree(cores->state);
+
+unmap_mmio:
+	iounmap(mmio_base);
+
 	return ret;
 }
 
@@ -291,6 +331,9 @@ int skl_free_dsp(struct skl *skl)
 
 	ctx->dsp_ops->cleanup(bus->dev, ctx);
 
+	kfree(ctx->cores.state);
+	kfree(ctx->cores.usage_count);
+
 	if (ctx->dsp->addr.lpe)
 		iounmap(ctx->dsp->addr.lpe);
 
@@ -400,9 +443,12 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
 			struct skl_module_cfg *mconfig,
 			struct skl_base_cfg *base_cfg)
 {
-	struct skl_module_fmt *format = &mconfig->in_fmt[0];
+	struct skl_module *module = mconfig->module;
+	struct skl_module_res *res = &module->resources[mconfig->res_idx];
+	struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
+	struct skl_module_fmt *format = &fmt->inputs[0].fmt;
 
-	base_cfg->audio_fmt.number_of_channels = (u8)format->channels;
+	base_cfg->audio_fmt.number_of_channels = format->channels;
 
 	base_cfg->audio_fmt.s_freq = format->s_freq;
 	base_cfg->audio_fmt.bit_depth = format->bit_depth;
@@ -417,10 +463,10 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
 
 	base_cfg->audio_fmt.interleaving = format->interleaving_style;
 
-	base_cfg->cps = mconfig->mcps;
-	base_cfg->ibs = mconfig->ibs;
-	base_cfg->obs = mconfig->obs;
-	base_cfg->is_pages = mconfig->mem_pages;
+	base_cfg->cps = res->cps;
+	base_cfg->ibs = res->ibs;
+	base_cfg->obs = res->obs;
+	base_cfg->is_pages = res->is_pages;
 }
 
 /*
@@ -508,6 +554,9 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
 			struct skl_cpr_cfg *cpr_mconfig)
 {
 	u32 dma_io_buf;
+	struct skl_module_res *res;
+	int res_idx = mconfig->res_idx;
+	struct skl *skl = get_skl_ctx(ctx->dev);
 
 	cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig);
 
@@ -516,19 +565,27 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
 		return;
 	}
 
+	if (skl->nr_modules) {
+		res = &mconfig->module->resources[mconfig->res_idx];
+		cpr_mconfig->gtw_cfg.dma_buffer_size = res->dma_buffer_size;
+		goto skip_buf_size_calc;
+	} else {
+		res = &mconfig->module->resources[res_idx];
+	}
+
 	switch (mconfig->hw_conn_type) {
 	case SKL_CONN_SOURCE:
 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
-			dma_io_buf =  mconfig->ibs;
+			dma_io_buf =  res->ibs;
 		else
-			dma_io_buf =  mconfig->obs;
+			dma_io_buf =  res->obs;
 		break;
 
 	case SKL_CONN_SINK:
 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
-			dma_io_buf =  mconfig->obs;
+			dma_io_buf =  res->obs;
 		else
-			dma_io_buf =  mconfig->ibs;
+			dma_io_buf =  res->ibs;
 		break;
 
 	default:
@@ -540,6 +597,15 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
 	cpr_mconfig->gtw_cfg.dma_buffer_size =
 				mconfig->dma_buffer_size * dma_io_buf;
 
+	/* fallback to 2ms default value */
+	if (!cpr_mconfig->gtw_cfg.dma_buffer_size) {
+		if (mconfig->hw_conn_type == SKL_CONN_SOURCE)
+			cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->obs;
+		else
+			cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->ibs;
+	}
+
+skip_buf_size_calc:
 	cpr_mconfig->cpr_feature_mask = 0;
 	cpr_mconfig->gtw_cfg.config_length  = 0;
 
@@ -587,7 +653,9 @@ static void skl_setup_out_format(struct skl_sst *ctx,
 			struct skl_module_cfg *mconfig,
 			struct skl_audio_data_format *out_fmt)
 {
-	struct skl_module_fmt *format = &mconfig->out_fmt[0];
+	struct skl_module *module = mconfig->module;
+	struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
+	struct skl_module_fmt *format = &fmt->outputs[0].fmt;
 
 	out_fmt->number_of_channels = (u8)format->channels;
 	out_fmt->s_freq = format->s_freq;
@@ -612,7 +680,9 @@ static void skl_set_src_format(struct skl_sst *ctx,
 			struct skl_module_cfg *mconfig,
 			struct skl_src_module_cfg *src_mconfig)
 {
-	struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
+	struct skl_module *module = mconfig->module;
+	struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
+	struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
 
 	skl_set_base_module_format(ctx, mconfig,
 		(struct skl_base_cfg *)src_mconfig);
@@ -629,7 +699,9 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx,
 			struct skl_module_cfg *mconfig,
 			struct skl_up_down_mixer_cfg *mixer_mconfig)
 {
-	struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
+	struct skl_module *module = mconfig->module;
+	struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
+	struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
 	int i = 0;
 
 	skl_set_base_module_format(ctx,	mconfig,
@@ -942,7 +1014,7 @@ static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg
 {
 	dev_dbg(ctx->dev, "%s: src module_id = %d  src_instance=%d\n",
 		__func__, src_module->id.module_id, src_module->id.pvt_id);
-	dev_dbg(ctx->dev, "%s: dst_module=%d dst_instacne=%d\n", __func__,
+	dev_dbg(ctx->dev, "%s: dst_module=%d dst_instance=%d\n", __func__,
 		 dst_module->id.module_id, dst_module->id.pvt_id);
 
 	dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n",
@@ -962,8 +1034,8 @@ int skl_unbind_modules(struct skl_sst *ctx,
 	struct skl_ipc_bind_unbind_msg msg;
 	struct skl_module_inst_id src_id = src_mcfg->id;
 	struct skl_module_inst_id dst_id = dst_mcfg->id;
-	int in_max = dst_mcfg->max_in_queue;
-	int out_max = src_mcfg->max_out_queue;
+	int in_max = dst_mcfg->module->max_input_pins;
+	int out_max = src_mcfg->module->max_output_pins;
 	int src_index, dst_index, src_pin_state, dst_pin_state;
 
 	skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
@@ -1011,6 +1083,21 @@ int skl_unbind_modules(struct skl_sst *ctx,
 	return ret;
 }
 
+static void fill_pin_params(struct skl_audio_data_format *pin_fmt,
+				struct skl_module_fmt *format)
+{
+	pin_fmt->number_of_channels = format->channels;
+	pin_fmt->s_freq = format->s_freq;
+	pin_fmt->bit_depth = format->bit_depth;
+	pin_fmt->valid_bit_depth = format->valid_bit_depth;
+	pin_fmt->ch_cfg = format->ch_cfg;
+	pin_fmt->sample_type = format->sample_type;
+	pin_fmt->channel_map = format->ch_map;
+	pin_fmt->interleaving = format->interleaving_style;
+}
+
+#define CPR_SINK_FMT_PARAM_ID 2
+
 /*
  * Once a module is instantiated it need to be 'bind' with other modules in
  * the pipeline. For binding we need to find the module pins which are bind
@@ -1022,11 +1109,15 @@ int skl_bind_modules(struct skl_sst *ctx,
 			struct skl_module_cfg *src_mcfg,
 			struct skl_module_cfg *dst_mcfg)
 {
-	int ret;
+	int ret = 0;
 	struct skl_ipc_bind_unbind_msg msg;
-	int in_max = dst_mcfg->max_in_queue;
-	int out_max = src_mcfg->max_out_queue;
+	int in_max = dst_mcfg->module->max_input_pins;
+	int out_max = src_mcfg->module->max_output_pins;
 	int src_index, dst_index;
+	struct skl_module_fmt *format;
+	struct skl_cpr_pin_fmt pin_fmt;
+	struct skl_module *module;
+	struct skl_module_iface *fmt;
 
 	skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
 
@@ -1045,6 +1136,29 @@ int skl_bind_modules(struct skl_sst *ctx,
 		return -EINVAL;
 	}
 
+	/*
+	 * Copier module requires the separate large_config_set_ipc to
+	 * configure the pins other than 0
+	 */
+	if (src_mcfg->m_type == SKL_MODULE_TYPE_COPIER && src_index > 0) {
+		pin_fmt.sink_id = src_index;
+		module = src_mcfg->module;
+		fmt = &module->formats[src_mcfg->fmt_idx];
+
+		/* Input fmt is same as that of src module input cfg */
+		format = &fmt->inputs[0].fmt;
+		fill_pin_params(&(pin_fmt.src_fmt), format);
+
+		format = &fmt->outputs[src_index].fmt;
+		fill_pin_params(&(pin_fmt.dst_fmt), format);
+		ret = skl_set_module_params(ctx, (void *)&pin_fmt,
+					sizeof(struct skl_cpr_pin_fmt),
+					CPR_SINK_FMT_PARAM_ID, src_mcfg);
+
+		if (ret < 0)
+			goto out;
+	}
+
 	msg.dst_queue = dst_index;
 
 	dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n",
@@ -1062,11 +1176,12 @@ int skl_bind_modules(struct skl_sst *ctx,
 		src_mcfg->m_state = SKL_MODULE_BIND_DONE;
 		src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE;
 		dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE;
-	} else {
-		/* error case , if IPC fails, clear the queue index */
-		skl_free_queue(src_mcfg->m_out_pin, src_index);
-		skl_free_queue(dst_mcfg->m_in_pin, dst_index);
+		return ret;
 	}
+out:
+	/* error case , if IPC fails, clear the queue index */
+	skl_free_queue(src_mcfg->m_out_pin, src_index);
+	skl_free_queue(dst_mcfg->m_in_pin, dst_index);
 
 	return ret;
 }
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 0ebea34a4988..2b1e513b1680 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -33,7 +33,7 @@
 #define HDA_STEREO 2
 #define HDA_QUAD 4
 
-static struct snd_pcm_hardware azx_pcm_hw = {
+static const struct snd_pcm_hardware azx_pcm_hw = {
 	.info =			(SNDRV_PCM_INFO_MMAP |
 				 SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -628,7 +628,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static struct snd_soc_dai_ops skl_pcm_dai_ops = {
+static const struct snd_soc_dai_ops skl_pcm_dai_ops = {
 	.startup = skl_pcm_open,
 	.shutdown = skl_pcm_close,
 	.prepare = skl_pcm_prepare,
@@ -637,15 +637,15 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = {
 	.trigger = skl_pcm_trigger,
 };
 
-static struct snd_soc_dai_ops skl_dmic_dai_ops = {
+static const struct snd_soc_dai_ops skl_dmic_dai_ops = {
 	.hw_params = skl_be_hw_params,
 };
 
-static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
+static const struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
 	.hw_params = skl_be_hw_params,
 };
 
-static struct snd_soc_dai_ops skl_link_dai_ops = {
+static const struct snd_soc_dai_ops skl_link_dai_ops = {
 	.prepare = skl_link_pcm_prepare,
 	.hw_params = skl_link_hw_params,
 	.hw_free = skl_link_hw_free,
@@ -675,6 +675,32 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
 	},
 },
 {
+	.name = "System Pin2",
+	.ops = &skl_pcm_dai_ops,
+	.playback = {
+		.stream_name = "Headset Playback",
+		.channels_min = HDA_MONO,
+		.channels_max = HDA_STEREO,
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
+			SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+	},
+},
+{
+	.name = "Echoref Pin",
+	.ops = &skl_pcm_dai_ops,
+	.capture = {
+		.stream_name = "Echoreference Capture",
+		.channels_min = HDA_STEREO,
+		.channels_max = HDA_STEREO,
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
+			SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+	},
+},
+{
 	.name = "Reference Pin",
 	.ops = &skl_pcm_dai_ops,
 	.capture = {
@@ -1194,8 +1220,11 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
 static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig)
 {
 	struct skl_sst *ctx = skl->skl_sst;
+	struct skl_module_inst_id *pin_id;
+	uuid_le *uuid_mod, *uuid_tplg;
+	struct skl_module *skl_module;
 	struct uuid_module *module;
-	uuid_le *uuid_mod;
+	int i, ret = -EIO;
 
 	uuid_mod = (uuid_le *)mconfig->guid;
 
@@ -1207,12 +1236,45 @@ static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig)
 	list_for_each_entry(module, &ctx->uuid_list, list) {
 		if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
 			mconfig->id.module_id = module->id;
-			mconfig->is_loadable = module->is_loadable;
-			return 0;
+			if (mconfig->module)
+				mconfig->module->loadable = module->is_loadable;
+			ret = 0;
+			break;
+		}
+	}
+
+	if (ret)
+		return ret;
+
+	uuid_mod = &module->uuid;
+	ret = -EIO;
+	for (i = 0; i < skl->nr_modules; i++) {
+		skl_module = skl->modules[i];
+		uuid_tplg = &skl_module->uuid;
+		if (!uuid_le_cmp(*uuid_mod, *uuid_tplg)) {
+			mconfig->module = skl_module;
+			ret = 0;
+			break;
 		}
 	}
+	if (skl->nr_modules && ret)
+		return ret;
 
-	return -EIO;
+	list_for_each_entry(module, &ctx->uuid_list, list) {
+		for (i = 0; i < MAX_IN_QUEUE; i++) {
+			pin_id = &mconfig->m_in_pin[i].id;
+			if (!uuid_le_cmp(pin_id->mod_uuid, module->uuid))
+				pin_id->module_id = module->id;
+		}
+
+		for (i = 0; i < MAX_OUT_QUEUE; i++) {
+			pin_id = &mconfig->m_out_pin[i].id;
+			if (!uuid_le_cmp(pin_id->mod_uuid, module->uuid))
+				pin_id->module_id = module->id;
+		}
+	}
+
+	return 0;
 }
 
 static int skl_populate_modules(struct skl *skl)
@@ -1284,7 +1346,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
 
 	return 0;
 }
-static struct snd_soc_platform_driver skl_platform_drv  = {
+static const struct snd_soc_platform_driver skl_platform_drv  = {
 	.probe		= skl_platform_soc_probe,
 	.ops		= &skl_platform_ops,
 	.pcm_new	= skl_pcm_new,
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c
index 08332723c700..19ee1d4f3bdf 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.c
+++ b/sound/soc/intel/skylake/skl-sst-dsp.c
@@ -47,7 +47,7 @@ void skl_dsp_init_core_state(struct sst_dsp *ctx)
 	skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
 	skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1;
 
-	for (i = SKL_DSP_CORE0_ID + 1; i < SKL_DSP_CORES_MAX; i++) {
+	for (i = SKL_DSP_CORE0_ID + 1; i < skl->cores.count; i++) {
 		skl->cores.state[i] = SKL_DSP_RESET;
 		skl->cores.usage_count[i] = 0;
 	}
@@ -351,6 +351,8 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
 		return -EINVAL;
 	}
 
+	skl->cores.usage_count[core_id]++;
+
 	if (skl->cores.state[core_id] == SKL_DSP_RESET) {
 		ret = ctx->fw_ops.set_state_D0(ctx, core_id);
 		if (ret < 0) {
@@ -359,8 +361,6 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
 		}
 	}
 
-	skl->cores.usage_count[core_id]++;
-
 out:
 	dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
 			core_id, skl->cores.state[core_id],
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index 498b15345b1a..5234fafb758a 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -283,7 +283,7 @@ enum skl_ipc_module_msg {
 	IPC_MOD_SET_D0IX = 8
 };
 
-static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
+void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
 		size_t tx_size)
 {
 	if (tx_size)
@@ -347,7 +347,7 @@ out:
 
 }
 
-static int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
+int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
 		struct skl_ipc_header header)
 {
 	struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc);
@@ -406,7 +406,7 @@ static int skl_ipc_set_reply_error_code(u32 reply)
 	}
 }
 
-static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
+void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
 		struct skl_ipc_header header)
 {
 	struct ipc_message *msg;
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index e057da2713c6..55f2d2ce09df 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -44,12 +44,10 @@ struct skl_ipc_header {
 	u32 extension;
 };
 
-#define SKL_DSP_CORES_MAX  2
-
 struct skl_dsp_cores {
 	unsigned int count;
-	enum skl_dsp_states state[SKL_DSP_CORES_MAX];
-	int usage_count[SKL_DSP_CORES_MAX];
+	enum skl_dsp_states *state;
+	int *usage_count;
 };
 
 /**
@@ -214,4 +212,10 @@ void skl_ipc_free(struct sst_generic_ipc *ipc);
 int skl_ipc_init(struct device *dev, struct skl_sst *skl);
 void skl_clear_module_cnt(struct sst_dsp *ctx);
 
+void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
+		struct skl_ipc_header header);
+int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
+		struct skl_ipc_header header);
+void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
+		size_t tx_size);
 #endif /* __SKL_IPC_H */
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c
index 81ee251881b4..369ef7ce981c 100644
--- a/sound/soc/intel/skylake/skl-sst-utils.c
+++ b/sound/soc/intel/skylake/skl-sst-utils.c
@@ -368,7 +368,6 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
 {
 	struct skl_sst *skl;
 	struct sst_dsp *sst;
-	int ret;
 
 	skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
 	if (skl == NULL)
@@ -388,15 +387,12 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
 	sst->dsp_ops = dsp_ops;
 	init_waitqueue_head(&skl->mod_load_wait);
 	INIT_LIST_HEAD(&sst->module_list);
-	ret = skl_ipc_init(dev, skl);
-	if (ret)
-		return ret;
 
 	skl->is_first_boot = true;
 	if (dsp)
 		*dsp = skl;
 
-	return ret;
+	return 0;
 }
 
 int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo,
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
index aba9ea11ac74..a436abf2fe3f 100644
--- a/sound/soc/intel/skylake/skl-sst.c
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -503,7 +503,7 @@ static void skl_clear_module_table(struct sst_dsp *ctx)
 	}
 }
 
-static struct skl_dsp_fw_ops skl_fw_ops = {
+static const struct skl_dsp_fw_ops skl_fw_ops = {
 	.set_state_D0 = skl_set_dsp_D0,
 	.set_state_D3 = skl_set_dsp_D3,
 	.load_fw = skl_load_base_firmware,
@@ -512,7 +512,7 @@ static struct skl_dsp_fw_ops skl_fw_ops = {
 	.unload_mod = skl_unload_module,
 };
 
-static struct skl_dsp_fw_ops kbl_fw_ops = {
+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,
@@ -561,9 +561,13 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
 	sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
 			SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
 
-	sst->fw_ops = skl_fw_ops;
+	ret = skl_ipc_init(dev, skl);
+	if (ret) {
+		skl_dsp_free(sst);
+		return ret;
+	}
 
-	skl->cores.count = 2;
+	sst->fw_ops = skl_fw_ops;
 
 	return 0;
 }
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 68c3f121efc3..22f768ca3c73 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -49,6 +49,9 @@ static const int mic_quatro_list[][SKL_CH_QUATRO] = {
 {0, 1, 2, 3},
 };
 
+#define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
+	((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
+
 void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
 {
 	struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
@@ -153,8 +156,10 @@ static bool skl_is_pipe_mcps_avail(struct skl *skl,
 				struct skl_module_cfg *mconfig)
 {
 	struct skl_sst *ctx = skl->skl_sst;
+	u8 res_idx = mconfig->res_idx;
+	struct skl_module_res *res = &mconfig->module->resources[res_idx];
 
-	if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) {
+	if (skl->resource.mcps + res->cps > skl->resource.max_mcps) {
 		dev_err(ctx->dev,
 			"%s: module_id %d instance %d\n", __func__,
 			mconfig->id.module_id, mconfig->id.instance_id);
@@ -170,7 +175,10 @@ static bool skl_is_pipe_mcps_avail(struct skl *skl,
 static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
 				struct skl_module_cfg *mconfig)
 {
-	skl->resource.mcps += mconfig->mcps;
+	u8 res_idx = mconfig->res_idx;
+	struct skl_module_res *res = &mconfig->module->resources[res_idx];
+
+	skl->resource.mcps += res->cps;
 }
 
 /*
@@ -179,7 +187,11 @@ static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
 static void
 skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
 {
-	skl->resource.mcps -= mconfig->mcps;
+	u8 res_idx = mconfig->res_idx;
+	struct skl_module_res *res = &mconfig->module->resources[res_idx];
+
+	res = &mconfig->module->resources[res_idx];
+	skl->resource.mcps -= res->cps;
 }
 
 /*
@@ -195,17 +207,21 @@ skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig)
 static void skl_dump_mconfig(struct skl_sst *ctx,
 					struct skl_module_cfg *mcfg)
 {
+	struct skl_module_iface *iface = &mcfg->module->formats[0];
+
 	dev_dbg(ctx->dev, "Dumping config\n");
 	dev_dbg(ctx->dev, "Input Format:\n");
-	dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels);
-	dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq);
-	dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg);
-	dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth);
+	dev_dbg(ctx->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
+	dev_dbg(ctx->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
+	dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
+	dev_dbg(ctx->dev, "valid bit depth = %d\n",
+				iface->inputs[0].fmt.valid_bit_depth);
 	dev_dbg(ctx->dev, "Output Format:\n");
-	dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels);
-	dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq);
-	dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth);
-	dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg);
+	dev_dbg(ctx->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
+	dev_dbg(ctx->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
+	dev_dbg(ctx->dev, "valid bit depth = %d\n",
+				iface->outputs[0].fmt.valid_bit_depth);
+	dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
 }
 
 static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
@@ -273,8 +289,8 @@ static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
 	struct skl_module_fmt *in_fmt, *out_fmt;
 
 	/* Fixups will be applied to pin 0 only */
-	in_fmt = &m_cfg->in_fmt[0];
-	out_fmt = &m_cfg->out_fmt[0];
+	in_fmt = &m_cfg->module->formats[0].inputs[0].fmt;
+	out_fmt = &m_cfg->module->formats[0].outputs[0].fmt;
 
 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		if (is_fe) {
@@ -312,21 +328,23 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
 {
 	int multiplier = 1;
 	struct skl_module_fmt *in_fmt, *out_fmt;
+	struct skl_module_res *res;
 
 	/* Since fixups is applied to pin 0 only, ibs, obs needs
 	 * change for pin 0 only
 	 */
-	in_fmt = &mcfg->in_fmt[0];
-	out_fmt = &mcfg->out_fmt[0];
+	res = &mcfg->module->resources[0];
+	in_fmt = &mcfg->module->formats[0].inputs[0].fmt;
+	out_fmt = &mcfg->module->formats[0].outputs[0].fmt;
 
 	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
 		multiplier = 5;
 
-	mcfg->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
+	res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
 			in_fmt->channels * (in_fmt->bit_depth >> 3) *
 			multiplier;
 
-	mcfg->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
+	res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
 			out_fmt->channels * (out_fmt->bit_depth >> 3) *
 			multiplier;
 }
@@ -365,6 +383,8 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
 	struct nhlt_specific_cfg *cfg;
 	struct skl *skl = get_skl_ctx(ctx->dev);
 	u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
+	int fmt_idx = m_cfg->fmt_idx;
+	struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
 
 	/* check if we already have blob */
 	if (m_cfg->formats_config.caps_size > 0)
@@ -375,23 +395,23 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
 	case SKL_DEVICE_DMIC:
 		link_type = NHLT_LINK_DMIC;
 		dir = SNDRV_PCM_STREAM_CAPTURE;
-		s_freq = m_cfg->in_fmt[0].s_freq;
-		s_fmt = m_cfg->in_fmt[0].bit_depth;
-		ch = m_cfg->in_fmt[0].channels;
+		s_freq = m_iface->inputs[0].fmt.s_freq;
+		s_fmt = m_iface->inputs[0].fmt.bit_depth;
+		ch = m_iface->inputs[0].fmt.channels;
 		break;
 
 	case SKL_DEVICE_I2S:
 		link_type = NHLT_LINK_SSP;
 		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
 			dir = SNDRV_PCM_STREAM_PLAYBACK;
-			s_freq = m_cfg->out_fmt[0].s_freq;
-			s_fmt = m_cfg->out_fmt[0].bit_depth;
-			ch = m_cfg->out_fmt[0].channels;
+			s_freq = m_iface->outputs[0].fmt.s_freq;
+			s_fmt = m_iface->outputs[0].fmt.bit_depth;
+			ch = m_iface->outputs[0].fmt.channels;
 		} else {
 			dir = SNDRV_PCM_STREAM_CAPTURE;
-			s_freq = m_cfg->in_fmt[0].s_freq;
-			s_fmt = m_cfg->in_fmt[0].bit_depth;
-			ch = m_cfg->in_fmt[0].channels;
+			s_freq = m_iface->inputs[0].fmt.s_freq;
+			s_fmt = m_iface->inputs[0].fmt.bit_depth;
+			ch = m_iface->inputs[0].fmt.channels;
 		}
 		break;
 
@@ -549,6 +569,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
 	struct snd_soc_dapm_widget *w;
 	struct skl_module_cfg *mconfig;
 	struct skl_sst *ctx = skl->skl_sst;
+	u8 cfg_idx;
 	int ret = 0;
 
 	list_for_each_entry(w_module, &pipe->w_list, node) {
@@ -564,11 +585,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
 			return -EIO;
 		}
 
+		cfg_idx = mconfig->pipe->cur_config_idx;
+		mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
+		mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
+
 		/* check resource available */
 		if (!skl_is_pipe_mcps_avail(skl, mconfig))
 			return -ENOMEM;
 
-		if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
+		if (mconfig->module->loadable && ctx->dsp->fw_ops.load_mod) {
 			ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
 				mconfig->id.module_id, mconfig->guid);
 			if (ret < 0)
@@ -596,24 +621,35 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
 		if (mconfig->id.pvt_id < 0)
 			return ret;
 		skl_tplg_set_module_init_data(w);
+
+		ret = skl_dsp_get_core(ctx->dsp, mconfig->core_id);
+		if (ret < 0) {
+			dev_err(ctx->dev, "Failed to wake up core %d ret=%d\n",
+						mconfig->core_id, ret);
+			return ret;
+		}
+
 		ret = skl_init_module(ctx, mconfig);
 		if (ret < 0) {
 			skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
-			return ret;
+			goto err;
 		}
 		skl_tplg_alloc_pipe_mcps(skl, mconfig);
 		ret = skl_tplg_set_module_params(w, ctx);
 		if (ret < 0)
-			return ret;
+			goto err;
 	}
 
 	return 0;
+err:
+	skl_dsp_put_core(ctx->dsp, mconfig->core_id);
+	return ret;
 }
 
 static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
 	 struct skl_pipe *pipe)
 {
-	int ret;
+	int ret = 0;
 	struct skl_pipe_module *w_module = NULL;
 	struct skl_module_cfg *mconfig = NULL;
 
@@ -622,7 +658,7 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
 		mconfig  = w_module->w->priv;
 		uuid_mod = (uuid_le *)mconfig->guid;
 
-		if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod &&
+		if (mconfig->module->loadable && ctx->dsp->fw_ops.unload_mod &&
 			mconfig->m_state > SKL_MODULE_UNINIT) {
 			ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp,
 						mconfig->id.module_id);
@@ -630,10 +666,76 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
 				return -EIO;
 		}
 		skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
+
+		ret = skl_dsp_put_core(ctx->dsp, mconfig->core_id);
+		if (ret < 0) {
+			/* don't return; continue with other modules */
+			dev_err(ctx->dev, "Failed to sleep core %d ret=%d\n",
+				mconfig->core_id, ret);
+		}
 	}
 
 	/* no modules to unload in this path, so return */
-	return 0;
+	return ret;
+}
+
+/*
+ * Here, we select pipe format based on the pipe type and pipe
+ * direction to determine the current config index for the pipeline.
+ * The config index is then used to select proper module resources.
+ * Intermediate pipes currently have a fixed format hence we select the
+ * 0th configuratation by default for such pipes.
+ */
+static int
+skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig)
+{
+	struct skl_sst *ctx = skl->skl_sst;
+	struct skl_pipe *pipe = mconfig->pipe;
+	struct skl_pipe_params *params = pipe->p_params;
+	struct skl_path_config *pconfig = &pipe->configs[0];
+	struct skl_pipe_fmt *fmt = NULL;
+	bool in_fmt = false;
+	int i;
+
+	if (pipe->nr_cfgs == 0) {
+		pipe->cur_config_idx = 0;
+		return 0;
+	}
+
+	if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) {
+		dev_dbg(ctx->dev, "No conn_type detected, take 0th config\n");
+		pipe->cur_config_idx = 0;
+		pipe->memory_pages = pconfig->mem_pages;
+
+		return 0;
+	}
+
+	if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
+	     pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
+	     (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE &&
+	     pipe->direction == SNDRV_PCM_STREAM_CAPTURE))
+		in_fmt = true;
+
+	for (i = 0; i < pipe->nr_cfgs; i++) {
+		pconfig = &pipe->configs[i];
+		if (in_fmt)
+			fmt = &pconfig->in_fmt;
+		else
+			fmt = &pconfig->out_fmt;
+
+		if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
+				    fmt->channels, fmt->freq, fmt->bps)) {
+			pipe->cur_config_idx = i;
+			pipe->memory_pages = pconfig->mem_pages;
+			dev_dbg(ctx->dev, "Using pipe config: %d\n", i);
+
+			return 0;
+		}
+	}
+
+	dev_err(ctx->dev, "Invalid pipe config: %d %d %d for pipe: %d\n",
+		params->ch, params->s_freq, params->s_fmt, pipe->ppl_id);
+	return -EINVAL;
 }
 
 /*
@@ -655,6 +757,10 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
 	struct skl_sst *ctx = skl->skl_sst;
 	struct skl_module_deferred_bind *modules;
 
+	ret = skl_tplg_get_pipe_config(skl, mconfig);
+	if (ret < 0)
+		return ret;
+
 	/* check resource available */
 	if (!skl_is_pipe_mcps_avail(skl, mconfig))
 		return -EBUSY;
@@ -758,12 +864,12 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
 	 * check all out/in pins are in bind state.
 	 * if so set the module param
 	 */
-	for (i = 0; i < mcfg->max_out_queue; i++) {
+	for (i = 0; i < mcfg->module->max_output_pins; i++) {
 		if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
 			return 0;
 	}
 
-	for (i = 0; i < mcfg->max_in_queue; i++) {
+	for (i = 0; i < mcfg->module->max_input_pins; i++) {
 		if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
 			return 0;
 	}
@@ -814,7 +920,7 @@ static int skl_tplg_module_add_deferred_bind(struct skl *skl,
 	int i;
 
 	/* only supported for module with static pin connection */
-	for (i = 0; i < dst->max_in_queue; i++) {
+	for (i = 0; i < dst->module->max_input_pins; i++) {
 		struct skl_module_pin *pin = &dst->m_in_pin[i];
 
 		if (pin->is_dynamic)
@@ -925,7 +1031,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
 		}
 	}
 
-	if (!sink)
+	if (!sink && next_sink)
 		return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
 
 	return 0;
@@ -1074,7 +1180,7 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
 	if (ret)
 		return ret;
 
-	for (i = 0; i < sink_mconfig->max_in_queue; i++) {
+	for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
 		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
 			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
 			if (!src_mconfig)
@@ -1185,7 +1291,7 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
 	if (ret)
 		return ret;
 
-	for (i = 0; i < src_mconfig->max_out_queue; i++) {
+	for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
 		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
 			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
 			if (!sink_mconfig)
@@ -1479,14 +1585,22 @@ int skl_tplg_update_pipe_params(struct device *dev,
 			struct skl_module_cfg *mconfig,
 			struct skl_pipe_params *params)
 {
+	struct skl_module_res *res = &mconfig->module->resources[0];
+	struct skl *skl = get_skl_ctx(dev);
 	struct skl_module_fmt *format = NULL;
+	u8 cfg_idx = mconfig->pipe->cur_config_idx;
 
 	skl_tplg_fill_dma_id(mconfig, params);
+	mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
+	mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
+
+	if (skl->nr_modules)
+		return 0;
 
 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		format = &mconfig->in_fmt[0];
+		format = &mconfig->module->formats[0].inputs[0].fmt;
 	else
-		format = &mconfig->out_fmt[0];
+		format = &mconfig->module->formats[0].outputs[0].fmt;
 
 	/* set the hw_params */
 	format->s_freq = params->s_freq;
@@ -1514,11 +1628,11 @@ int skl_tplg_update_pipe_params(struct device *dev,
 	}
 
 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		mconfig->ibs = (format->s_freq / 1000) *
+		res->ibs = (format->s_freq / 1000) *
 				(format->channels) *
 				(format->bit_depth >> 3);
 	} else {
-		mconfig->obs = (format->s_freq / 1000) *
+		res->obs = (format->s_freq / 1000) *
 				(format->channels) *
 				(format->bit_depth >> 3);
 	}
@@ -1792,6 +1906,54 @@ static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
 	},
 };
 
+static int skl_tplg_fill_pipe_cfg(struct device *dev,
+			struct skl_pipe *pipe, u32 tkn,
+			u32 tkn_val, int conf_idx, int dir)
+{
+	struct skl_pipe_fmt *fmt;
+	struct skl_path_config *config;
+
+	switch (dir) {
+	case SKL_DIR_IN:
+		fmt = &pipe->configs[conf_idx].in_fmt;
+		break;
+
+	case SKL_DIR_OUT:
+		fmt = &pipe->configs[conf_idx].out_fmt;
+		break;
+
+	default:
+		dev_err(dev, "Invalid direction: %d\n", dir);
+		return -EINVAL;
+	}
+
+	config = &pipe->configs[conf_idx];
+
+	switch (tkn) {
+	case SKL_TKN_U32_CFG_FREQ:
+		fmt->freq = tkn_val;
+		break;
+
+	case SKL_TKN_U8_CFG_CHAN:
+		fmt->channels = tkn_val;
+		break;
+
+	case SKL_TKN_U8_CFG_BPS:
+		fmt->bps = tkn_val;
+		break;
+
+	case SKL_TKN_U32_PATH_MEM_PGS:
+		config->mem_pages = tkn_val;
+		break;
+
+	default:
+		dev_err(dev, "Invalid token config: %d\n", tkn);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int skl_tplg_fill_pipe_tkn(struct device *dev,
 			struct skl_pipe *pipe, u32 tkn,
 			u32 tkn_val)
@@ -1814,6 +1976,14 @@ static int skl_tplg_fill_pipe_tkn(struct device *dev,
 		pipe->lp_mode = tkn_val;
 		break;
 
+	case SKL_TKN_U32_PIPE_DIRECTION:
+		pipe->direction = tkn_val;
+		break;
+
+	case SKL_TKN_U32_NUM_CONFIGS:
+		pipe->nr_cfgs = tkn_val;
+		break;
+
 	default:
 		dev_err(dev, "Token not handled %d\n", tkn);
 		return -EINVAL;
@@ -1930,27 +2100,9 @@ static int skl_tplg_fill_pins_info(struct device *dev,
  * on the direction
  */
 static int skl_tplg_fill_fmt(struct device *dev,
-		struct skl_module_cfg *mconfig,	u32 tkn,
-		u32 value, u32 dir, u32 pin_count)
+		struct skl_module_fmt *dst_fmt,
+		u32 tkn, u32 value)
 {
-	struct skl_module_fmt *dst_fmt;
-
-	switch (dir) {
-	case SKL_DIR_IN:
-		dst_fmt = mconfig->in_fmt;
-		dst_fmt += pin_count;
-		break;
-
-	case SKL_DIR_OUT:
-		dst_fmt = mconfig->out_fmt;
-		dst_fmt += pin_count;
-		break;
-
-	default:
-		dev_err(dev, "Invalid direction value\n");
-		return -EINVAL;
-	}
-
 	switch (tkn) {
 	case SKL_TKN_U32_FMT_CH:
 		dst_fmt->channels  = value;
@@ -1992,6 +2144,32 @@ static int skl_tplg_fill_fmt(struct device *dev,
 	return 0;
 }
 
+static int skl_tplg_widget_fill_fmt(struct device *dev,
+		struct skl_module_iface *fmt,
+		u32 tkn, u32 val, u32 dir, int fmt_idx)
+{
+	struct skl_module_fmt *dst_fmt;
+
+	if (!fmt)
+		return -EINVAL;
+
+	switch (dir) {
+	case SKL_DIR_IN:
+		dst_fmt = &fmt->inputs[fmt_idx].fmt;
+		break;
+
+	case SKL_DIR_OUT:
+		dst_fmt = &fmt->outputs[fmt_idx].fmt;
+		break;
+
+	default:
+		dev_err(dev, "Invalid direction: %d\n", dir);
+		return -EINVAL;
+	}
+
+	return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
+}
+
 static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig,
 	      struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
 {
@@ -2015,6 +2193,108 @@ static void skl_tplg_fill_pin_dynamic_val(
 }
 
 /*
+ * Resource table in the manifest has pin specific resources
+ * like pin and pin buffer size
+ */
+static int skl_tplg_manifest_pin_res_tkn(struct device *dev,
+		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+		struct skl_module_res *res, int pin_idx, int dir)
+{
+	struct skl_module_pin_resources *m_pin;
+
+	switch (dir) {
+	case SKL_DIR_IN:
+		m_pin = &res->input[pin_idx];
+		break;
+
+	case SKL_DIR_OUT:
+		m_pin = &res->output[pin_idx];
+		break;
+
+	default:
+		dev_err(dev, "Invalid pin direction: %d\n", dir);
+		return -EINVAL;
+	}
+
+	switch (tkn_elem->token) {
+	case SKL_TKN_MM_U32_RES_PIN_ID:
+		m_pin->pin_index = tkn_elem->value;
+		break;
+
+	case SKL_TKN_MM_U32_PIN_BUF:
+		m_pin->buf_size = tkn_elem->value;
+		break;
+
+	default:
+		dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Fill module specific resources from the manifest's resource
+ * table like CPS, DMA size, mem_pages.
+ */
+static int skl_tplg_fill_res_tkn(struct device *dev,
+		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+		struct skl_module_res *res,
+		int pin_idx, int dir)
+{
+	int ret, tkn_count = 0;
+
+	if (!res)
+		return -EINVAL;
+
+	switch (tkn_elem->token) {
+	case SKL_TKN_MM_U32_CPS:
+		res->cps = tkn_elem->value;
+		break;
+
+	case SKL_TKN_MM_U32_DMA_SIZE:
+		res->dma_buffer_size = tkn_elem->value;
+		break;
+
+	case SKL_TKN_MM_U32_CPC:
+		res->cpc = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U32_MEM_PAGES:
+		res->is_pages = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U32_OBS:
+		res->obs = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U32_IBS:
+		res->ibs = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U32_MAX_MCPS:
+		res->cps = tkn_elem->value;
+		break;
+
+	case SKL_TKN_MM_U32_RES_PIN_ID:
+	case SKL_TKN_MM_U32_PIN_BUF:
+		ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
+						    pin_idx, dir);
+		if (ret < 0)
+			return ret;
+		break;
+
+	default:
+		dev_err(dev, "Not a res type token: %d", tkn_elem->token);
+		return -EINVAL;
+
+	}
+	tkn_count++;
+
+	return tkn_count;
+}
+
+/*
  * Parse tokens to fill up the module private data
  */
 static int skl_tplg_get_token(struct device *dev,
@@ -2024,49 +2304,54 @@ static int skl_tplg_get_token(struct device *dev,
 	int tkn_count = 0;
 	int ret;
 	static int is_pipe_exists;
-	static int pin_index, dir;
+	static int pin_index, dir, conf_idx;
+	struct skl_module_iface *iface = NULL;
+	struct skl_module_res *res = NULL;
+	int res_idx = mconfig->res_idx;
+	int fmt_idx = mconfig->fmt_idx;
+
+	/*
+	 * If the manifest structure contains no modules, fill all
+	 * the module data to 0th index.
+	 * res_idx and fmt_idx are default set to 0.
+	 */
+	if (skl->nr_modules == 0) {
+		res = &mconfig->module->resources[res_idx];
+		iface = &mconfig->module->formats[fmt_idx];
+	}
 
 	if (tkn_elem->token > SKL_TKN_MAX)
 		return -EINVAL;
 
 	switch (tkn_elem->token) {
 	case SKL_TKN_U8_IN_QUEUE_COUNT:
-		mconfig->max_in_queue = tkn_elem->value;
-		mconfig->m_in_pin = devm_kzalloc(dev, mconfig->max_in_queue *
-					sizeof(*mconfig->m_in_pin),
-					GFP_KERNEL);
-		if (!mconfig->m_in_pin)
-			return -ENOMEM;
-
+		mconfig->module->max_input_pins = tkn_elem->value;
 		break;
 
 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
-		mconfig->max_out_queue = tkn_elem->value;
-		mconfig->m_out_pin = devm_kzalloc(dev, mconfig->max_out_queue *
-					sizeof(*mconfig->m_out_pin),
-					GFP_KERNEL);
-
-		if (!mconfig->m_out_pin)
-			return -ENOMEM;
-
+		mconfig->module->max_output_pins = tkn_elem->value;
 		break;
 
 	case SKL_TKN_U8_DYN_IN_PIN:
 		if (!mconfig->m_in_pin)
+			mconfig->m_in_pin = devm_kzalloc(dev, MAX_IN_QUEUE *
+					sizeof(*mconfig->m_in_pin), GFP_KERNEL);
+		if (!mconfig->m_in_pin)
 			return -ENOMEM;
 
-		skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin,
-			mconfig->max_in_queue, tkn_elem->value);
-
+		skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
+					      tkn_elem->value);
 		break;
 
 	case SKL_TKN_U8_DYN_OUT_PIN:
 		if (!mconfig->m_out_pin)
+			mconfig->m_out_pin = devm_kzalloc(dev, MAX_IN_QUEUE *
+					sizeof(*mconfig->m_in_pin), GFP_KERNEL);
+		if (!mconfig->m_out_pin)
 			return -ENOMEM;
 
-		skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin,
-			mconfig->max_out_queue, tkn_elem->value);
-
+		skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
+					      tkn_elem->value);
 		break;
 
 	case SKL_TKN_U8_TIME_SLOT:
@@ -2094,19 +2379,13 @@ static int skl_tplg_get_token(struct device *dev,
 		break;
 
 	case SKL_TKN_U32_MEM_PAGES:
-		mconfig->mem_pages = tkn_elem->value;
-		break;
-
 	case SKL_TKN_U32_MAX_MCPS:
-		mconfig->mcps = tkn_elem->value;
-		break;
-
 	case SKL_TKN_U32_OBS:
-		mconfig->obs = tkn_elem->value;
-		break;
-
 	case SKL_TKN_U32_IBS:
-		mconfig->ibs = tkn_elem->value;
+		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, dir, pin_index);
+		if (ret < 0)
+			return ret;
+
 		break;
 
 	case SKL_TKN_U32_VBUS_ID:
@@ -2139,10 +2418,16 @@ static int skl_tplg_get_token(struct device *dev,
 
 		break;
 
+	case SKL_TKN_U32_PIPE_CONFIG_ID:
+		conf_idx = tkn_elem->value;
+		break;
+
 	case SKL_TKN_U32_PIPE_CONN_TYPE:
 	case SKL_TKN_U32_PIPE_PRIORITY:
 	case SKL_TKN_U32_PIPE_MEM_PGS:
 	case SKL_TKN_U32_PMODE:
+	case SKL_TKN_U32_PIPE_DIRECTION:
+	case SKL_TKN_U32_NUM_CONFIGS:
 		if (is_pipe_exists) {
 			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
 					tkn_elem->token, tkn_elem->value);
@@ -2152,6 +2437,27 @@ static int skl_tplg_get_token(struct device *dev,
 
 		break;
 
+	case SKL_TKN_U32_PATH_MEM_PGS:
+	case SKL_TKN_U32_CFG_FREQ:
+	case SKL_TKN_U8_CFG_CHAN:
+	case SKL_TKN_U8_CFG_BPS:
+		if (mconfig->pipe->nr_cfgs) {
+			ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
+					tkn_elem->token, tkn_elem->value,
+					conf_idx, dir);
+			if (ret < 0)
+				return ret;
+		}
+		break;
+
+	case SKL_TKN_CFG_MOD_RES_ID:
+		mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
+		break;
+
+	case SKL_TKN_CFG_MOD_FMT_ID:
+		mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
+		break;
+
 	/*
 	 * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
 	 * direction and the pin count. The first four bits represent
@@ -2172,7 +2478,7 @@ static int skl_tplg_get_token(struct device *dev,
 	case SKL_TKN_U32_FMT_INTERLEAVE:
 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
 	case SKL_TKN_U32_FMT_CH_MAP:
-		ret = skl_tplg_fill_fmt(dev, mconfig, tkn_elem->token,
+		ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
 				tkn_elem->value, dir, pin_index);
 
 		if (ret < 0)
@@ -2397,11 +2703,11 @@ static void skl_clear_pin_config(struct snd_soc_platform *platform,
 					strlen(platform->component.name))) {
 		mconfig = w->priv;
 		pipe = mconfig->pipe;
-		for (i = 0; i < mconfig->max_in_queue; i++) {
+		for (i = 0; i < mconfig->module->max_input_pins; i++) {
 			mconfig->m_in_pin[i].in_use = false;
 			mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
 		}
-		for (i = 0; i < mconfig->max_out_queue; i++) {
+		for (i = 0; i < mconfig->module->max_output_pins; i++) {
 			mconfig->m_out_pin[i].in_use = false;
 			mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
 		}
@@ -2460,6 +2766,13 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
 	if (!mconfig)
 		return -ENOMEM;
 
+	if (skl->nr_modules == 0) {
+		mconfig->module = devm_kzalloc(bus->dev,
+				sizeof(*mconfig->module), GFP_KERNEL);
+		if (!mconfig->module)
+			return -ENOMEM;
+	}
+
 	w->priv = mconfig;
 
 	/*
@@ -2602,13 +2915,13 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
 			str_elem->string,
 			ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
 		ref_count++;
-		tkn_count++;
 		break;
 
 	default:
 		dev_err(dev, "Not a string token %d\n", str_elem->token);
 		break;
 	}
+	tkn_count++;
 
 	return tkn_count;
 }
@@ -2634,26 +2947,236 @@ static int skl_tplg_get_str_tkn(struct device *dev,
 	return tkn_count;
 }
 
+static int skl_tplg_manifest_fill_fmt(struct device *dev,
+		struct skl_module_iface *fmt,
+		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+		u32 dir, int fmt_idx)
+{
+	struct skl_module_pin_fmt *dst_fmt;
+	struct skl_module_fmt *mod_fmt;
+	int ret;
+
+	if (!fmt)
+		return -EINVAL;
+
+	switch (dir) {
+	case SKL_DIR_IN:
+		dst_fmt = &fmt->inputs[fmt_idx];
+		break;
+
+	case SKL_DIR_OUT:
+		dst_fmt = &fmt->outputs[fmt_idx];
+		break;
+
+	default:
+		dev_err(dev, "Invalid direction: %d\n", dir);
+		return -EINVAL;
+	}
+
+	mod_fmt = &dst_fmt->fmt;
+
+	switch (tkn_elem->token) {
+	case SKL_TKN_MM_U32_INTF_PIN_ID:
+		dst_fmt->id = tkn_elem->value;
+		break;
+
+	default:
+		ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
+					tkn_elem->value);
+		if (ret < 0)
+			return ret;
+		break;
+	}
+
+	return 0;
+}
+
+static int skl_tplg_fill_mod_info(struct device *dev,
+		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+		struct skl_module *mod)
+{
+
+	if (!mod)
+		return -EINVAL;
+
+	switch (tkn_elem->token) {
+	case SKL_TKN_U8_IN_PIN_TYPE:
+		mod->input_pin_type = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U8_OUT_PIN_TYPE:
+		mod->output_pin_type = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U8_IN_QUEUE_COUNT:
+		mod->max_input_pins = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U8_OUT_QUEUE_COUNT:
+		mod->max_output_pins = tkn_elem->value;
+		break;
+
+	case SKL_TKN_MM_U8_NUM_RES:
+		mod->nr_resources = tkn_elem->value;
+		break;
+
+	case SKL_TKN_MM_U8_NUM_INTF:
+		mod->nr_interfaces = tkn_elem->value;
+		break;
+
+	default:
+		dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
 static int skl_tplg_get_int_tkn(struct device *dev,
 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
 		struct skl *skl)
 {
-	int tkn_count = 0;
+	int tkn_count = 0, ret;
+	static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
+	struct skl_module_res *res = NULL;
+	struct skl_module_iface *fmt = NULL;
+	struct skl_module *mod = NULL;
+	int i;
+
+	if (skl->modules) {
+		mod = skl->modules[mod_idx];
+		res = &mod->resources[res_val_idx];
+		fmt = &mod->formats[intf_val_idx];
+	}
 
 	switch (tkn_elem->token) {
 	case SKL_TKN_U32_LIB_COUNT:
 		skl->skl_sst->lib_count = tkn_elem->value;
-		tkn_count++;
+		break;
+
+	case SKL_TKN_U8_NUM_MOD:
+		skl->nr_modules = tkn_elem->value;
+		skl->modules = devm_kcalloc(dev, skl->nr_modules,
+				sizeof(*skl->modules), GFP_KERNEL);
+		if (!skl->modules)
+			return -ENOMEM;
+
+		for (i = 0; i < skl->nr_modules; i++) {
+			skl->modules[i] = devm_kzalloc(dev,
+					sizeof(struct skl_module), GFP_KERNEL);
+			if (!skl->modules[i])
+				return -ENOMEM;
+		}
+		break;
+
+	case SKL_TKN_MM_U8_MOD_IDX:
+		mod_idx = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U8_IN_PIN_TYPE:
+	case SKL_TKN_U8_OUT_PIN_TYPE:
+	case SKL_TKN_U8_IN_QUEUE_COUNT:
+	case SKL_TKN_U8_OUT_QUEUE_COUNT:
+	case SKL_TKN_MM_U8_NUM_RES:
+	case SKL_TKN_MM_U8_NUM_INTF:
+		ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
+		if (ret < 0)
+			return ret;
+		break;
+
+	case SKL_TKN_U32_DIR_PIN_COUNT:
+		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
+		pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
+		break;
+
+	case SKL_TKN_MM_U32_RES_ID:
+		if (!res)
+			return -EINVAL;
+
+		res->id = tkn_elem->value;
+		res_val_idx = tkn_elem->value;
+		break;
+
+	case SKL_TKN_MM_U32_FMT_ID:
+		if (!fmt)
+			return -EINVAL;
+
+		fmt->fmt_idx = tkn_elem->value;
+		intf_val_idx = tkn_elem->value;
+		break;
+
+	case SKL_TKN_MM_U32_CPS:
+	case SKL_TKN_MM_U32_DMA_SIZE:
+	case SKL_TKN_MM_U32_CPC:
+	case SKL_TKN_U32_MEM_PAGES:
+	case SKL_TKN_U32_OBS:
+	case SKL_TKN_U32_IBS:
+	case SKL_TKN_MM_U32_RES_PIN_ID:
+	case SKL_TKN_MM_U32_PIN_BUF:
+		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
+		if (ret < 0)
+			return ret;
+
+		break;
+
+	case SKL_TKN_MM_U32_NUM_IN_FMT:
+		if (!fmt)
+			return -EINVAL;
+
+		res->nr_input_pins = tkn_elem->value;
+		break;
+
+	case SKL_TKN_MM_U32_NUM_OUT_FMT:
+		if (!fmt)
+			return -EINVAL;
+
+		res->nr_output_pins = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U32_FMT_CH:
+	case SKL_TKN_U32_FMT_FREQ:
+	case SKL_TKN_U32_FMT_BIT_DEPTH:
+	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
+	case SKL_TKN_U32_FMT_CH_CONFIG:
+	case SKL_TKN_U32_FMT_INTERLEAVE:
+	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
+	case SKL_TKN_U32_FMT_CH_MAP:
+	case SKL_TKN_MM_U32_INTF_PIN_ID:
+		ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
+						 dir, pin_idx);
+		if (ret < 0)
+			return ret;
 		break;
 
 	default:
 		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
 		return -EINVAL;
 	}
+	tkn_count++;
 
 	return tkn_count;
 }
 
+static int skl_tplg_get_manifest_uuid(struct device *dev,
+				struct skl *skl,
+				struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
+{
+	static int ref_count;
+	struct skl_module *mod;
+
+	if (uuid_tkn->token == SKL_TKN_UUID) {
+		mod = skl->modules[ref_count];
+		memcpy(&mod->uuid, &uuid_tkn->uuid, sizeof(uuid_tkn->uuid));
+		ref_count++;
+	} else {
+		dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /*
  * Fill the manifest structure by parsing the tokens based on the
  * type.
@@ -2686,7 +3209,11 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
 			continue;
 
 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
-			dev_warn(dev, "no uuid tokens for skl tplf manifest\n");
+			ret = skl_tplg_get_manifest_uuid(dev, skl, array->uuid);
+			if (ret < 0)
+				return ret;
+
+			tuple_size += sizeof(*array->uuid);
 			continue;
 
 		default:
@@ -2703,14 +3230,12 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
 
 			tkn_count = tkn_count + ret;
 			tkn_elem++;
-			tuple_size += tkn_count *
-				sizeof(struct snd_soc_tplg_vendor_value_elem);
-			break;
 		}
+		tuple_size += (tkn_count * sizeof(*tkn_elem));
 		tkn_count = 0;
 	}
 
-	return 0;
+	return off;
 }
 
 /*
@@ -2733,11 +3258,10 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
 	num_blocks = ret;
 
 	off += array->size;
-	array = (struct snd_soc_tplg_vendor_array *)
-			(manifest->priv.data + off);
-
 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
 	while (num_blocks > 0) {
+		array = (struct snd_soc_tplg_vendor_array *)
+				(manifest->priv.data + off);
 		ret = skl_tplg_get_desc_blocks(dev, array);
 
 		if (ret < 0)
@@ -2771,6 +3295,7 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
 		} else {
 			return -EINVAL;
 		}
+		off += ret;
 	}
 
 	return 0;
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index c25e8868b84e..2717db92036b 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -44,6 +44,13 @@
 #define SKL_DEFAULT_MIC_SEL_GAIN	0x3FF
 #define SKL_MIC_SEL_SWITCH	0x3
 
+#define SKL_OUTPUT_PIN		0
+#define SKL_INPUT_PIN		1
+#define SKL_MAX_PATH_CONFIGS	8
+#define SKL_MAX_MODULES_IN_PIPE	8
+#define SKL_MAX_MODULE_FORMATS		32
+#define SKL_MAX_MODULE_RESOURCES	32
+
 enum skl_channel_index {
 	SKL_CHANNEL_LEFT = 0,
 	SKL_CHANNEL_RIGHT = 1,
@@ -131,6 +138,11 @@ struct skl_cpr_cfg {
 	struct skl_cpr_gtw_cfg gtw_cfg;
 } __packed;
 
+struct skl_cpr_pin_fmt {
+	u32 sink_id;
+	struct skl_audio_data_format src_fmt;
+	struct skl_audio_data_format dst_fmt;
+} __packed;
 
 struct skl_src_module_cfg {
 	struct skl_base_cfg base_cfg;
@@ -214,6 +226,7 @@ struct skl_kpb_params {
 };
 
 struct skl_module_inst_id {
+	uuid_le mod_uuid;
 	int module_id;
 	u32 instance_id;
 	int pvt_id;
@@ -266,6 +279,23 @@ struct skl_pipe_params {
 	unsigned int link_bps;
 };
 
+struct skl_pipe_fmt {
+	u32 freq;
+	u8 channels;
+	u8 bps;
+};
+
+struct skl_pipe_mcfg {
+	u8 res_idx;
+	u8 fmt_idx;
+};
+
+struct skl_path_config {
+	u8 mem_pages;
+	struct skl_pipe_fmt in_fmt;
+	struct skl_pipe_fmt out_fmt;
+};
+
 struct skl_pipe {
 	u8 ppl_id;
 	u8 pipe_priority;
@@ -274,6 +304,10 @@ struct skl_pipe {
 	u8 lp_mode;
 	struct skl_pipe_params *p_params;
 	enum skl_pipe_state state;
+	u8 direction;
+	u8 cur_config_idx;
+	u8 nr_cfgs;
+	struct skl_path_config configs[SKL_MAX_PATH_CONFIGS];
 	struct list_head w_list;
 	bool passthru;
 };
@@ -292,9 +326,57 @@ enum d0i3_capability {
 	SKL_D0I3_NON_STREAMING = 2,
 };
 
+struct skl_module_pin_fmt {
+	u8 id;
+	struct skl_module_fmt fmt;
+};
+
+struct skl_module_iface {
+	u8 fmt_idx;
+	u8 nr_in_fmt;
+	u8 nr_out_fmt;
+	struct skl_module_pin_fmt inputs[MAX_IN_QUEUE];
+	struct skl_module_pin_fmt outputs[MAX_OUT_QUEUE];
+};
+
+struct skl_module_pin_resources {
+	u8 pin_index;
+	u32 buf_size;
+};
+
+struct skl_module_res {
+	u8 id;
+	u32 is_pages;
+	u32 cps;
+	u32 ibs;
+	u32 obs;
+	u32 dma_buffer_size;
+	u32 cpc;
+	u8 nr_input_pins;
+	u8 nr_output_pins;
+	struct skl_module_pin_resources input[MAX_IN_QUEUE];
+	struct skl_module_pin_resources output[MAX_OUT_QUEUE];
+};
+
+struct skl_module {
+	uuid_le uuid;
+	u8 loadable;
+	u8 input_pin_type;
+	u8 output_pin_type;
+	u8 max_input_pins;
+	u8 max_output_pins;
+	u8 nr_resources;
+	u8 nr_interfaces;
+	struct skl_module_res resources[SKL_MAX_MODULE_RESOURCES];
+	struct skl_module_iface formats[SKL_MAX_MODULE_FORMATS];
+};
+
 struct skl_module_cfg {
 	u8 guid[16];
 	struct skl_module_inst_id id;
+	struct skl_module *module;
+	int res_idx;
+	int fmt_idx;
 	u8 domain;
 	bool homogenous_inputs;
 	bool homogenous_outputs;
@@ -329,6 +411,7 @@ struct skl_module_cfg {
 	enum skl_module_state m_state;
 	struct skl_pipe *pipe;
 	struct skl_specific_cfg formats_config;
+	struct skl_pipe_mcfg mod_cfg[SKL_MAX_MODULES_IN_PIPE];
 };
 
 struct skl_algo_data {
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 334917ee41cf..f94b484abb99 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -415,7 +415,7 @@ static int skl_free(struct hdac_ext_bus *ebus)
 	snd_hdac_ext_stop_streams(ebus);
 
 	if (bus->irq >= 0)
-		free_irq(bus->irq, (void *)bus);
+		free_irq(bus->irq, (void *)ebus);
 	snd_hdac_bus_free_stream_pages(bus);
 	snd_hdac_stream_free_all(ebus);
 	snd_hdac_link_free_all(ebus);
@@ -528,7 +528,7 @@ static int probe_codec(struct hdac_ext_bus *ebus, int addr)
 }
 
 /* Codec initialization */
-static int skl_codec_create(struct hdac_ext_bus *ebus)
+static void skl_codec_create(struct hdac_ext_bus *ebus)
 {
 	struct hdac_bus *bus = ebus_to_hbus(ebus);
 	int c, max_slots;
@@ -559,8 +559,6 @@ static int skl_codec_create(struct hdac_ext_bus *ebus)
 			}
 		}
 	}
-
-	return 0;
 }
 
 static const struct hdac_bus_ops bus_core_ops = {
@@ -612,9 +610,7 @@ static void skl_probe_work(struct work_struct *work)
 		dev_info(bus->dev, "no hda codecs found!\n");
 
 	/* create codec instances */
-	err = skl_codec_create(ebus);
-	if (err < 0)
-		goto out_err;
+	skl_codec_create(ebus);
 
 	if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
 		err = snd_hdac_display_power(bus, false);
@@ -702,6 +698,8 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
 		return -ENXIO;
 	}
 
+	skl_init_chip(bus, true);
+
 	snd_hdac_bus_parse_capabilities(bus);
 
 	if (skl_acquire_irq(ebus, 0) < 0)
@@ -879,12 +877,12 @@ static void skl_remove(struct pci_dev *pci)
 
 static struct sst_codecs skl_codecs = {
 	.num_codecs = 1,
-	.codecs = {"NAU88L25"}
+	.codecs = {"10508825"}
 };
 
 static struct sst_codecs kbl_codecs = {
 	.num_codecs = 1,
-	.codecs = {"NAU88L25"}
+	.codecs = {"10508825"}
 };
 
 static struct sst_codecs bxt_codecs = {
@@ -941,6 +939,7 @@ static struct sst_acpi_mach sst_bxtp_devdata[] = {
 		.machine_quirk = sst_acpi_codec_list,
 		.quirk_data = &bxt_codecs,
 	},
+	{}
 };
 
 static struct sst_acpi_mach sst_kbl_devdata[] = {
@@ -981,6 +980,11 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
 		.quirk_data = &kbl_poppy_codecs,
 		.pdata = &skl_dmic_data
 	},
+	{
+		.id = "10EC5663",
+		.drv_name = "kbl_rt5663",
+		.fw_filename = "intel/dsp_fw_kbl.bin",
+	},
 
 	{}
 };
@@ -991,6 +995,15 @@ static struct sst_acpi_mach sst_glk_devdata[] = {
 		.drv_name = "glk_alc298s_i2s",
 		.fw_filename = "intel/dsp_fw_glk.bin",
 	},
+	{}
+};
+
+static const struct sst_acpi_mach sst_cnl_devdata[] = {
+	{
+		.id = "INT34C2",
+		.drv_name = "cnl_rt274",
+		.fw_filename = "intel/dsp_fw_cnl.bin",
+	},
 };
 
 /* PCI IDs */
@@ -1007,6 +1020,9 @@ static const struct pci_device_id skl_ids[] = {
 	/* GLK */
 	{ PCI_DEVICE(0x8086, 0x3198),
 		.driver_data = (unsigned long)&sst_glk_devdata},
+	/* CNL */
+	{ PCI_DEVICE(0x8086, 0x9dc8),
+		.driver_data = (unsigned long)&sst_cnl_devdata},
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, skl_ids);
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index a6b134b4c037..8d9d6899f761 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -71,6 +71,8 @@ struct skl {
 	struct work_struct probe_work;
 
 	struct skl_debug *debugfs;
+	u8 nr_modules;
+	struct skl_module **modules;
 };
 
 #define skl_to_ebus(s)	(&(s)->ebus)
@@ -90,6 +92,7 @@ struct skl_machine_pdata {
 
 struct skl_dsp_ops {
 	int id;
+	unsigned int num_cores;
 	struct skl_dsp_loader_ops (*loader_ops)(void);
 	int (*init)(struct device *dev, void __iomem *mmio_base,
 			int irq, const char *fw_name,
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index 794a3499e567..99394c036998 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -133,6 +133,7 @@ static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
 {
 	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 	uint32_t conf, ctrl;
+	int ret;
 
 	if (dai->active)
 		return 0;
@@ -141,7 +142,9 @@ static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
 	ctrl |= JZ_AIC_CTRL_FLUSH;
 	jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
 
-	clk_prepare_enable(i2s->clk_i2s);
+	ret = clk_prepare_enable(i2s->clk_i2s);
+	if (ret)
+		return ret;
 
 	conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
 	conf |= JZ_AIC_CONF_ENABLE;
@@ -352,11 +355,18 @@ static int jz4740_i2s_resume(struct snd_soc_dai *dai)
 {
 	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 	uint32_t conf;
+	int ret;
 
-	clk_prepare_enable(i2s->clk_aic);
+	ret = clk_prepare_enable(i2s->clk_aic);
+	if (ret)
+		return ret;
 
 	if (dai->active) {
-		clk_prepare_enable(i2s->clk_i2s);
+		ret = clk_prepare_enable(i2s->clk_i2s);
+		if (ret) {
+			clk_disable_unprepare(i2s->clk_aic);
+			return ret;
+		}
 
 		conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
 		conf |= JZ_AIC_CONF_ENABLE;
@@ -387,8 +397,11 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
 {
 	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 	uint32_t conf;
+	int ret;
 
-	clk_prepare_enable(i2s->clk_aic);
+	ret = clk_prepare_enable(i2s->clk_aic);
+	if (ret)
+		return ret;
 
 	jz4740_i2c_init_pcm_config(i2s);
 	snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index dafd22e874e9..cf23af159acf 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -27,7 +27,7 @@ static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs)
 	return snd_soc_dai_get_drvdata(soc_runtime->cpu_dai);
 }
 
-static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
+static const struct snd_pcm_hardware kirkwood_dma_snd_hw = {
 	.info = SNDRV_PCM_INFO_INTERLEAVED |
 		SNDRV_PCM_INFO_MMAP |
 		SNDRV_PCM_INFO_MMAP_VALID |
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 3a36d60e1785..105a73cc5158 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -538,10 +538,9 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
 	int err;
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv) {
-		dev_err(&pdev->dev, "allocation failed\n");
+	if (!priv)
 		return -ENOMEM;
-	}
+
 	dev_set_drvdata(&pdev->dev, priv);
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -550,9 +549,9 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
 		return PTR_ERR(priv->io);
 
 	priv->irq = platform_get_irq(pdev, 0);
-	if (priv->irq <= 0) {
-		dev_err(&pdev->dev, "platform_get_irq failed\n");
-		return -ENXIO;
+	if (priv->irq < 0) {
+		dev_err(&pdev->dev, "platform_get_irq failed: %d\n", priv->irq);
+		return priv->irq;
 	}
 
 	if (np) {
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
index b815ecc6bbf6..affa7fb25dd9 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
@@ -75,7 +75,7 @@ int mt2701_init_clock(struct mtk_base_afe *afe)
 
 	for (i = 0; i < MT2701_CLOCK_NUM; i++) {
 		afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]);
-		if (IS_ERR(aud_clks[i])) {
+		if (IS_ERR(afe_priv->clocks[i])) {
 			dev_warn(afe->dev, "%s devm_clk_get %s fail\n",
 				 __func__, aud_clks[i]);
 			return PTR_ERR(aud_clks[i]);
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index bc5d4db94de6..8fda182f849b 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -595,7 +595,7 @@ static const struct snd_soc_dai_ops mt2701_afe_i2s_ops = {
 };
 
 /* MRG BE DAIs */
-static struct snd_soc_dai_ops mt2701_btmrg_ops = {
+static const struct snd_soc_dai_ops mt2701_btmrg_ops = {
 	.startup = mt2701_btmrg_startup,
 	.shutdown = mt2701_btmrg_shutdown,
 	.hw_params = mt2701_btmrg_hw_params,
@@ -1496,14 +1496,12 @@ static int mt2701_afe_runtime_resume(struct device *dev)
 
 static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
 {
-	int ret, i;
-	unsigned int irq_id;
 	struct mtk_base_afe *afe;
 	struct mt2701_afe_private *afe_priv;
 	struct resource *res;
 	struct device *dev;
+	int i, irq_id, ret;
 
-	ret = 0;
 	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
 	if (!afe)
 		return -ENOMEM;
@@ -1516,11 +1514,12 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
 	afe->dev = &pdev->dev;
 	dev = afe->dev;
 
-	irq_id = platform_get_irq(pdev, 0);
-	if (!irq_id) {
-		dev_err(dev, "%s no irq found\n", dev->of_node->name);
-		return -ENXIO;
+	irq_id = platform_get_irq_byname(pdev, "asys");
+	if (irq_id < 0) {
+		dev_err(dev, "unable to get ASYS IRQ\n");
+		return irq_id;
 	}
+
 	ret = devm_request_irq(dev, irq_id, mt2701_asys_isr,
 			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
 	if (ret) {
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
index 5e383eb456a4..99c15219dbc8 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
@@ -222,7 +222,6 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev)
 		mt8173_rt5650_rt5514_codecs[1].of_node;
 
 	card->dev = &pdev->dev;
-	platform_set_drvdata(pdev, card);
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret)
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
index fed1f15a39c2..42de84ca8c84 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
@@ -279,7 +279,6 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
 	}
 
 	card->dev = &pdev->dev;
-	platform_set_drvdata(pdev, card);
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret)
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index a78470839b65..e69c141d8ed4 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -311,7 +311,6 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 	card->dev = &pdev->dev;
-	platform_set_drvdata(pdev, card);
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret)
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index b42f301c6b96..156aa7c00787 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -125,7 +125,9 @@ static int mxs_saif_set_clk(struct mxs_saif *saif,
 	 *
 	 * If MCLK is not used, we just set saif clk to 512*fs.
 	 */
-	clk_prepare_enable(master_saif->clk);
+	ret = clk_prepare_enable(master_saif->clk);
+	if (ret)
+		return ret;
 
 	if (master_saif->mclk_in_use) {
 		switch (mclk / rate) {
@@ -388,6 +390,7 @@ static int mxs_saif_startup(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *cpu_dai)
 {
 	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+	int ret;
 
 	/* clear error status to 0 for each re-open */
 	saif->fifo_underrun = 0;
@@ -401,7 +404,9 @@ static int mxs_saif_startup(struct snd_pcm_substream *substream,
 	__raw_writel(BM_SAIF_CTRL_CLKGATE,
 		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
 
-	clk_prepare(saif->clk);
+	ret = clk_prepare(saif->clk);
+	if (ret)
+		return ret;
 
 	return 0;
 }
@@ -468,7 +473,9 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
 		if (ret)
 			return ret;
 
-		clk_prepare(master_saif->clk);
+		ret = clk_prepare(master_saif->clk);
+		if (ret)
+			return ret;
 	}
 
 	scr = __raw_readl(saif->base + SAIF_CTRL);
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index a96276e77332..2ed3240cc682 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -140,7 +140,6 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev)
 	}
 
 	card->dev = &pdev->dev;
-	platform_set_drvdata(pdev, card);
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret) {
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c
index 2cca055fd806..bd6dfa218d59 100644
--- a/sound/soc/nuc900/nuc900-pcm.c
+++ b/sound/soc/nuc900/nuc900-pcm.c
@@ -271,7 +271,7 @@ static int nuc900_dma_mmap(struct snd_pcm_substream *substream,
 			   runtime->dma_addr, runtime->dma_bytes);
 }
 
-static struct snd_pcm_ops nuc900_dma_ops = {
+static const struct snd_pcm_ops nuc900_dma_ops = {
 	.open		= nuc900_dma_open,
 	.close		= nuc900_dma_close,
 	.ioctl		= snd_pcm_lib_ioctl,
@@ -299,7 +299,7 @@ static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static struct snd_soc_platform_driver nuc900_soc_platform = {
+static const struct snd_soc_platform_driver nuc900_soc_platform = {
 	.ops		= &nuc900_dma_ops,
 	.pcm_new	= nuc900_dma_new,
 };
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 16cc95fa4573..6c49f3d6fd96 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -513,15 +513,6 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static int ams_delta_card_remove(struct snd_soc_card *card)
-{
-	snd_soc_jack_free_gpios(&ams_delta_hook_switch,
-			ARRAY_SIZE(ams_delta_hook_switch_gpios),
-			ams_delta_hook_switch_gpios);
-
-	return 0;
-}
-
 /* DAI glue - connects codec <--> CPU */
 static struct snd_soc_dai_link ams_delta_dai_link = {
 	.name = "CX20442",
@@ -540,7 +531,6 @@ static struct snd_soc_dai_link ams_delta_dai_link = {
 static struct snd_soc_card ams_delta_audio_card = {
 	.name = "AMS_DELTA",
 	.owner = THIS_MODULE,
-	.remove = ams_delta_card_remove,
 	.dai_link = &ams_delta_dai_link,
 	.num_links = 1,
 
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 94e9ff791f3a..aca2c43d0f03 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -162,7 +162,7 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream,
 			   runtime->dma_addr, runtime->dma_bytes);
 }
 
-static struct snd_pcm_ops omap_pcm_ops = {
+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,
@@ -243,7 +243,7 @@ out:
 	return ret;
 }
 
-static struct snd_soc_platform_driver omap_soc_platform = {
+static const struct snd_soc_platform_driver omap_soc_platform = {
 	.ops		= &omap_pcm_ops,
 	.pcm_new	= omap_pcm_new,
 	.pcm_free	= omap_pcm_free_dma_buffers,
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c
index a24b0dedabb9..cccc316743fa 100644
--- a/sound/soc/omap/omap-twl4030.c
+++ b/sound/soc/omap/omap-twl4030.c
@@ -208,18 +208,6 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
 	return ret;
 }
 
-static int omap_twl4030_card_remove(struct snd_soc_card *card)
-{
-	struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
-
-	if (priv->jack_detect > 0)
-		snd_soc_jack_free_gpios(&priv->hs_jack,
-					ARRAY_SIZE(hs_jack_gpios),
-					hs_jack_gpios);
-
-	return 0;
-}
-
 /* Digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
 	{
@@ -247,7 +235,6 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
 /* Audio machine driver */
 static struct snd_soc_card omap_twl4030_card = {
 	.owner = THIS_MODULE,
-	.remove = omap_twl4030_card_remove,
 	.dai_link = omap_twl4030_dai_links,
 	.num_links = ARRAY_SIZE(omap_twl4030_dai_links),
 
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 3aeb65feaea1..57448bd5ad77 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -311,14 +311,6 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
 	return err;
 }
 
-static int rx51_card_remove(struct snd_soc_card *card)
-{
-	snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
-				rx51_av_jack_gpios);
-
-	return 0;
-}
-
 /* Digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link rx51_dai[] = {
 	{
@@ -361,7 +353,6 @@ static struct snd_soc_codec_conf rx51_codec_conf[] = {
 static struct snd_soc_card rx51_sound_card = {
 	.name = "RX-51",
 	.owner = THIS_MODULE,
-	.remove = rx51_card_remove,
 	.dai_link = rx51_dai,
 	.num_links = ARRAY_SIZE(rx51_dai),
 	.aux_dev = rx51_aux_dev,
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 960744e46edc..484ab3c2ad67 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -1,6 +1,7 @@
 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/hx4700.c b/sound/soc/pxa/hx4700.c
index a9ac881c2e14..6cdef5d4954e 100644
--- a/sound/soc/pxa/hx4700.c
+++ b/sound/soc/pxa/hx4700.c
@@ -138,13 +138,6 @@ static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
 	return err;
 }
 
-static int hx4700_card_remove(struct snd_soc_card *card)
-{
-	snd_soc_jack_free_gpios(&hs_jack, 1, &hs_jack_gpio);
-
-	return 0;
-}
-
 /* hx4700 digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link hx4700_dai = {
 	.name = "ak4641",
@@ -163,7 +156,6 @@ static struct snd_soc_dai_link hx4700_dai = {
 static struct snd_soc_card snd_soc_card_hx4700 = {
 	.name			= "iPAQ hx4700",
 	.owner			= THIS_MODULE,
-	.remove			= hx4700_card_remove,
 	.dai_link		= &hx4700_dai,
 	.num_links		= 1,
 	.dapm_widgets		= hx4700_dapm_widgets,
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
index 5b5f1a442891..624d9bd5dadd 100644
--- a/sound/soc/pxa/mmp-pcm.c
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -131,7 +131,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
 		vma->vm_end - vma->vm_start, vma->vm_page_prot);
 }
 
-static struct snd_pcm_ops mmp_pcm_ops = {
+static const struct snd_pcm_ops mmp_pcm_ops = {
 	.open		= mmp_pcm_open,
 	.close		= snd_dmaengine_pcm_close_release_chan,
 	.ioctl		= snd_pcm_lib_ioctl,
@@ -211,7 +211,7 @@ err:
 	return ret;
 }
 
-static struct snd_soc_platform_driver mmp_soc_platform = {
+static const struct snd_soc_platform_driver mmp_soc_platform = {
 	.ops		= &mmp_pcm_ops,
 	.pcm_new	= mmp_pcm_new,
 	.pcm_free	= mmp_pcm_free_dma_buffers,
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c
index 9cc35012e6e5..64b85e30c1f8 100644
--- a/sound/soc/pxa/mmp-sspa.c
+++ b/sound/soc/pxa/mmp-sspa.c
@@ -380,7 +380,7 @@ static int mmp_sspa_probe(struct snd_soc_dai *dai)
 		SNDRV_PCM_FMTBIT_S24_LE | \
 		SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops mmp_sspa_dai_ops = {
+static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
 	.startup	= mmp_sspa_startup,
 	.shutdown	= mmp_sspa_shutdown,
 	.trigger	= mmp_sspa_trigger,
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index b51d7a0755d5..e64958d8bff0 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -45,7 +45,7 @@ static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static struct snd_pcm_ops pxa2xx_pcm_ops = {
+static const struct snd_pcm_ops pxa2xx_pcm_ops = {
 	.open		= __pxa2xx_pcm_open,
 	.close		= __pxa2xx_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
@@ -84,7 +84,7 @@ static int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	return ret;
 }
 
-static struct snd_soc_platform_driver pxa2xx_soc_platform = {
+static const struct snd_soc_platform_driver pxa2xx_soc_platform = {
 	.ops		= &pxa2xx_pcm_ops,
 	.pcm_new	= pxa2xx_soc_pcm_new,
 	.pcm_free	= pxa2xx_pcm_free_dma_buffers,
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
index d084d7468299..d49adc822a11 100644
--- a/sound/soc/qcom/apq8016_sbc.c
+++ b/sound/soc/qcom/apq8016_sbc.c
@@ -21,12 +21,16 @@
 #include <linux/platform_device.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
+#include <sound/jack.h>
 #include <sound/soc.h>
+#include <uapi/linux/input-event-codes.h>
 #include <dt-bindings/sound/apq8016-lpass.h>
 
 struct apq8016_sbc_data {
 	void __iomem *mic_iomux;
 	void __iomem *spkr_iomux;
+	struct snd_soc_jack jack;
+	bool jack_setup;
 	struct snd_soc_dai_link dai_link[];	/* dynamically allocated */
 };
 
@@ -34,13 +38,16 @@ struct apq8016_sbc_data {
 #define MIC_CTRL_QUA_WS_SLAVE_SEL_10	BIT(17)
 #define MIC_CTRL_TLMM_SCLK_EN		BIT(1)
 #define	SPKR_CTL_PRI_WS_SLAVE_SEL_11	(BIT(17) | BIT(16))
+#define DEFAULT_MCLK_RATE		9600000
 
 static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_codec *codec;
+	struct snd_soc_dai_link *dai_link = rtd->dai_link;
 	struct snd_soc_card *card = rtd->card;
 	struct apq8016_sbc_data *pdata = snd_soc_card_get_drvdata(card);
-	int rval = 0;
+	int i, rval;
 
 	switch (cpu_dai->id) {
 	case MI2S_PRIMARY:
@@ -63,12 +70,54 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd)
 
 	default:
 		dev_err(card->dev, "unsupported cpu dai configuration\n");
-		rval = -EINVAL;
-		break;
+		return -EINVAL;
+
+	}
+
+	if (!pdata->jack_setup) {
+		struct snd_jack *jack;
+
+		rval = snd_soc_card_jack_new(card, "Headset Jack",
+					     SND_JACK_HEADSET |
+					     SND_JACK_HEADPHONE |
+					     SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+					     SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+					     SND_JACK_BTN_4,
+					     &pdata->jack, NULL, 0);
+
+		if (rval < 0) {
+			dev_err(card->dev, "Unable to add Headphone Jack\n");
+			return rval;
+		}
 
+		jack = pdata->jack.jack;
+
+		snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_MEDIA);
+		snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+		snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+		snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+		pdata->jack_setup = true;
+	}
+
+	for (i = 0 ; i < dai_link->num_codecs; i++) {
+		struct snd_soc_dai *dai = rtd->codec_dais[i];
+
+		codec = dai->codec;
+		/* Set default mclk for internal codec */
+		rval = snd_soc_codec_set_sysclk(codec, 0, 0, DEFAULT_MCLK_RATE,
+				       SND_SOC_CLOCK_IN);
+		if (rval != 0 && rval != -ENOTSUPP) {
+			dev_warn(card->dev, "Failed to set mclk: %d\n", rval);
+			return rval;
+		}
+		rval = snd_soc_codec_set_jack(codec, &pdata->jack, NULL);
+		if (rval != 0 && rval != -ENOTSUPP) {
+			dev_warn(card->dev, "Failed to set jack: %d\n", rval);
+			return rval;
+		}
 	}
 
-	return rval;
+	return 0;
 }
 
 static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
@@ -191,7 +240,6 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev)
 	if (IS_ERR(data->spkr_iomux))
 		return PTR_ERR(data->spkr_iomux);
 
-	platform_set_drvdata(pdev, data);
 	snd_soc_card_set_drvdata(card, data);
 
 	return devm_snd_soc_register_card(&pdev->dev, card);
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 7aabf08de3d4..e1945e1772cd 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -32,7 +32,7 @@ struct lpass_pcm_data {
 #define LPASS_PLATFORM_BUFFER_SIZE	(16 * 1024)
 #define LPASS_PLATFORM_PERIODS		2
 
-static struct snd_pcm_hardware lpass_platform_pcm_hardware = {
+static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
 	.info			=	SNDRV_PCM_INFO_MMAP |
 					SNDRV_PCM_INFO_MMAP_VALID |
 					SNDRV_PCM_INFO_INTERLEAVED |
@@ -557,7 +557,7 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
 	}
 }
 
-static struct snd_soc_platform_driver lpass_platform_driver = {
+static const struct snd_soc_platform_driver lpass_platform_driver = {
 	.pcm_new	= lpass_platform_pcm_new,
 	.pcm_free	= lpass_platform_pcm_free,
 	.ops		= &lpass_platform_pcm_ops,
diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c
index c5207af14104..a9fa972466ad 100644
--- a/sound/soc/qcom/storm.c
+++ b/sound/soc/qcom/storm.c
@@ -99,7 +99,6 @@ static int storm_platform_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	card->dev = &pdev->dev;
-	platform_set_drvdata(pdev, card);
 
 	ret = snd_soc_of_parse_card_name(card, "qcom,model");
 	if (ret) {
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index c84487805876..b0825370d262 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -68,6 +68,8 @@ config SND_SOC_RK3399_GRU_SOUND
 	select SND_SOC_RT5514
 	select SND_SOC_DA7219
 	select SND_SOC_RT5514_SPI
+	select SND_SOC_HDMI_CODEC
+	select SND_SOC_DMIC
 	help
 	  Say Y or M here if you want to add support multiple codecs for SoC
 	  audio on Rockchip RK3399 GRU boards.
diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c
index dbc53e48c52c..fa44e3901336 100644
--- a/sound/soc/rockchip/rk3288_hdmi_analog.c
+++ b/sound/soc/rockchip/rk3288_hdmi_analog.c
@@ -147,7 +147,7 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime)
 	return 0;
 }
 
-static struct snd_soc_ops rk_ops = {
+static const struct snd_soc_ops rk_ops = {
 	.hw_params = rk_hw_params,
 };
 
@@ -272,8 +272,6 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	platform_set_drvdata(pdev, card);
-
 	return ret;
 }
 
diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c
index 3475c61a5fa0..0513fe480353 100644
--- a/sound/soc/rockchip/rk3399_gru_sound.c
+++ b/sound/soc/rockchip/rk3399_gru_sound.c
@@ -38,7 +38,7 @@
 
 #define SOUND_FS	256
 
-static unsigned int rt5514_dmic_delay;
+static unsigned int dmic_wakeup_delay;
 
 static struct snd_soc_jack rockchip_sound_jack;
 
@@ -126,7 +126,7 @@ static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* Wait for DMIC stable */
-	msleep(rt5514_dmic_delay);
+	msleep(dmic_wakeup_delay);
 
 	return 0;
 }
@@ -228,6 +228,67 @@ 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)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	unsigned int mclk;
+	int ret;
+
+	mclk = params_rate(params) * SOUND_FS;
+
+	ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0);
+	if (ret) {
+		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
+				__func__, mclk, ret);
+		return ret;
+	}
+
+	/* Wait for DMIC stable */
+	msleep(dmic_wakeup_delay);
+
+	return 0;
+}
+
 static const struct snd_soc_ops rockchip_sound_max98357a_ops = {
 	.hw_params = rockchip_sound_max98357a_hw_params,
 };
@@ -240,16 +301,70 @@ 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,
+};
+
+static struct snd_soc_card rockchip_sound_card = {
+	.name = "rk3399-gru-sound",
+	.owner = THIS_MODULE,
+	.dapm_widgets = rockchip_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
+	.dapm_routes = rockchip_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
+	.controls = rockchip_controls,
+	.num_controls = ARRAY_SIZE(rockchip_controls),
+};
+
 enum {
+	DAILINK_CDNDP,
+	DAILINK_DA7219,
+	DAILINK_DMIC,
 	DAILINK_MAX98357A,
 	DAILINK_RT5514,
-	DAILINK_DA7219,
 	DAILINK_RT5514_DSP,
 };
 
-#define DAILINK_ENTITIES	(DAILINK_DA7219 + 1)
+static const char * const dailink_compat[] = {
+	[DAILINK_CDNDP] = "rockchip,rk3399-cdn-dp",
+	[DAILINK_DA7219] = "dlg,da7219",
+	[DAILINK_DMIC] = "dmic-codec",
+	[DAILINK_MAX98357A] = "maxim,max98357a",
+	[DAILINK_RT5514] = "realtek,rt5514-i2c",
+	[DAILINK_RT5514_DSP] = "realtek,rt5514-spi",
+};
 
-static struct snd_soc_dai_link rockchip_dailinks[] = {
+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,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+	[DAILINK_DA7219] = {
+		.name = "DA7219",
+		.stream_name = "DA7219 PCM",
+		.codec_dai_name = "da7219-hifi",
+		.init = rockchip_sound_da7219_init,
+		.ops = &rockchip_sound_da7219_ops,
+		/* set da7219 as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+	[DAILINK_DMIC] = {
+		.name = "DMIC",
+		.stream_name = "DMIC PCM",
+		.codec_dai_name = "dmic-hifi",
+		.ops = &rockchip_sound_dmic_ops,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
 	[DAILINK_MAX98357A] = {
 		.name = "MAX98357A",
 		.stream_name = "MAX98357A PCM",
@@ -268,108 +383,95 @@ static struct snd_soc_dai_link rockchip_dailinks[] = {
 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 			SND_SOC_DAIFMT_CBS_CFS,
 	},
-	[DAILINK_DA7219] = {
-		.name = "DA7219",
-		.stream_name = "DA7219 PCM",
-		.codec_dai_name = "da7219-hifi",
-		.init = rockchip_sound_da7219_init,
-		.ops = &rockchip_sound_da7219_ops,
-		/* set da7219 as slave */
-		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-			SND_SOC_DAIFMT_CBS_CFS,
-	},
 	/* RT5514 DSP for voice wakeup via spi bus */
 	[DAILINK_RT5514_DSP] = {
 		.name = "RT5514 DSP",
 		.stream_name = "Wake on Voice",
-		.codec_name = "snd-soc-dummy",
-		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_dai_name = "rt5514-dsp-cpu-dai",
 	},
 };
 
-static struct snd_soc_card rockchip_sound_card = {
-	.name = "rk3399-gru-sound",
-	.owner = THIS_MODULE,
-	.dai_link = rockchip_dailinks,
-	.num_links =  ARRAY_SIZE(rockchip_dailinks),
-	.dapm_widgets = rockchip_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
-	.dapm_routes = rockchip_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
-	.controls = rockchip_controls,
-	.num_controls = ARRAY_SIZE(rockchip_controls),
-};
-
-static int rockchip_sound_match_stub(struct device *dev, void *data)
+static int rockchip_sound_codec_node_match(struct device_node *np_codec)
 {
-	return 1;
-}
+	int i;
 
-static int rockchip_sound_probe(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = &rockchip_sound_card;
-	struct device_node *cpu_node;
-	struct device *dev;
-	struct device_driver *drv;
-	int i, ret;
-
-	cpu_node = of_parse_phandle(pdev->dev.of_node, "rockchip,cpu", 0);
-	if (!cpu_node) {
-		dev_err(&pdev->dev, "Property 'rockchip,cpu' missing or invalid\n");
-		return -EINVAL;
+	for (i = 0; i < ARRAY_SIZE(dailink_compat); i++) {
+		if (of_device_is_compatible(np_codec, dailink_compat[i]))
+			return i;
 	}
+	return -1;
+}
 
-	for (i = 0; i < DAILINK_ENTITIES; i++) {
-		rockchip_dailinks[i].platform_of_node = cpu_node;
-		rockchip_dailinks[i].cpu_of_node = cpu_node;
-
-		rockchip_dailinks[i].codec_of_node =
-			of_parse_phandle(pdev->dev.of_node, "rockchip,codec", i);
-		if (!rockchip_dailinks[i].codec_of_node) {
-			dev_err(&pdev->dev,
-				"Property[%d] 'rockchip,codec' missing or invalid\n", i);
+static int rockchip_sound_of_parse_dais(struct device *dev,
+					struct snd_soc_card *card)
+{
+	struct device_node *np_cpu, *np_cpu0, *np_cpu1;
+	struct device_node *np_codec;
+	struct snd_soc_dai_link *dai;
+	int i, index;
+
+	card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais),
+				      GFP_KERNEL);
+	if (!card->dai_link)
+		return -ENOMEM;
+
+	np_cpu0 = of_parse_phandle(dev->of_node, "rockchip,cpu", 0);
+	np_cpu1 = of_parse_phandle(dev->of_node, "rockchip,cpu", 1);
+
+	card->num_links = 0;
+	for (i = 0; i < ARRAY_SIZE(rockchip_dais); i++) {
+		np_codec = of_parse_phandle(dev->of_node,
+					    "rockchip,codec", i);
+		if (!np_codec)
+			break;
+
+		if (!of_device_is_available(np_codec))
+			continue;
+
+		index = rockchip_sound_codec_node_match(np_codec);
+		if (index < 0)
+			continue;
+
+		np_cpu = (index == DAILINK_CDNDP) ? np_cpu1 : np_cpu0;
+		if (!np_cpu) {
+			dev_err(dev, "Missing 'rockchip,cpu' for %s\n",
+				rockchip_dais[index].name);
 			return -EINVAL;
 		}
-	}
 
-	/**
-	 * To acquire the spi driver of the rt5514 and set the dai-links names
-	 * for soc_bind_dai_link
-	 */
-	drv = driver_find("rt5514", &spi_bus_type);
-	if (!drv) {
-		dev_err(&pdev->dev, "Can not find the rt5514 driver at the spi bus\n");
-		return -EINVAL;
+		dai = &card->dai_link[card->num_links++];
+		*dai = rockchip_dais[index];
+
+		dai->codec_of_node = np_codec;
+		dai->platform_of_node = np_cpu;
+		dai->cpu_of_node = np_cpu;
 	}
 
-	dev = driver_find_device(drv, NULL, NULL, rockchip_sound_match_stub);
-	if (!dev) {
-		dev_err(&pdev->dev, "Can not find the rt5514 device\n");
-		return -ENODEV;
+	return 0;
+}
+
+static int rockchip_sound_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &rockchip_sound_card;
+	int ret;
+
+	ret = rockchip_sound_of_parse_dais(&pdev->dev, card);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to parse dais: %d\n", ret);
+		return ret;
 	}
 
-	/* Set DMIC delay */
-	ret = device_property_read_u32(&pdev->dev, "dmic-delay",
-					&rt5514_dmic_delay);
+	/* Set DMIC wakeup delay */
+	ret = device_property_read_u32(&pdev->dev, "dmic-wakeup-delay-ms",
+					&dmic_wakeup_delay);
 	if (ret) {
-		rt5514_dmic_delay = 0;
+		dmic_wakeup_delay = 0;
 		dev_dbg(&pdev->dev,
-			"no optional property 'dmic-delay' found, default: no delay\n");
+			"no optional property 'dmic-wakeup-delay-ms' found, default: no delay\n");
 	}
 
-	rockchip_dailinks[DAILINK_RT5514_DSP].cpu_name = kstrdup_const(dev_name(dev), GFP_KERNEL);
-	rockchip_dailinks[DAILINK_RT5514_DSP].cpu_dai_name = kstrdup_const(dev_name(dev), GFP_KERNEL);
-	rockchip_dailinks[DAILINK_RT5514_DSP].platform_name = kstrdup_const(dev_name(dev), GFP_KERNEL);
-
 	card->dev = &pdev->dev;
-	platform_set_drvdata(pdev, card);
-
-	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;
+	return devm_snd_soc_register_card(&pdev->dev, card);
 }
 
 static const struct of_device_id rockchip_sound_of_match[] = {
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 199338fdeda0..b6590467fd14 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -579,10 +579,8 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
 	int val;
 
 	i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
-	if (!i2s) {
-		dev_err(&pdev->dev, "Can't allocate rk_i2s_dev\n");
+	if (!i2s)
 		return -ENOMEM;
-	}
 
 	i2s->dev = &pdev->dev;
 
diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index c5ddeed97260..400e29edb1c9 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -249,7 +249,7 @@ static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai)
 	return 0;
 }
 
-static struct snd_soc_dai_ops rockchip_pdm_dai_ops = {
+static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = {
 	.set_fmt = rockchip_pdm_set_fmt,
 	.trigger = rockchip_pdm_trigger,
 	.hw_params = rockchip_pdm_hw_params,
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index 5f5825faeb2a..051935162d7b 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -170,14 +170,6 @@ static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static int h1940_uda1380_card_remove(struct snd_soc_card *card)
-{
-	snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
-		hp_jack_gpios);
-
-	return 0;
-}
-
 /* s3c24xx digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link h1940_uda1380_dai[] = {
 	{
@@ -197,7 +189,6 @@ static struct snd_soc_dai_link h1940_uda1380_dai[] = {
 static struct snd_soc_card h1940_asoc = {
 	.name = "h1940",
 	.owner = THIS_MODULE,
-	.remove = h1940_uda1380_card_remove,
 	.dai_link = h1940_uda1380_dai,
 	.num_links = ARRAY_SIZE(h1940_uda1380_dai),
 
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index af3ba4d4ccc5..10a4da06c0a1 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -50,6 +50,7 @@ struct samsung_i2s_variant_regs {
 
 struct samsung_i2s_dai_data {
 	u32 quirks;
+	unsigned int pcm_rates;
 	const struct samsung_i2s_variant_regs *i2s_variant_regs;
 };
 
@@ -550,7 +551,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
 				goto err;
 			}
 
-			clk_prepare_enable(i2s->op_clk);
+			ret = clk_prepare_enable(i2s->op_clk);
+			if (ret)
+				goto err;
 			i2s->rclk_srcrate = clk_get_rate(i2s->op_clk);
 
 			/* Over-ride the other's */
@@ -1076,13 +1079,13 @@ static const struct snd_soc_component_driver samsung_i2s_component = {
 	.name		= "samsung-i2s",
 };
 
-#define SAMSUNG_I2S_RATES	SNDRV_PCM_RATE_8000_96000
-
 #define SAMSUNG_I2S_FMTS	(SNDRV_PCM_FMTBIT_S8 | \
 					SNDRV_PCM_FMTBIT_S16_LE | \
 					SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
+static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev,
+				const struct samsung_i2s_dai_data *i2s_dai_data,
+				bool sec)
 {
 	struct i2s_dai *i2s;
 
@@ -1101,13 +1104,13 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
 	i2s->i2s_dai_drv.resume = i2s_resume;
 	i2s->i2s_dai_drv.playback.channels_min = 1;
 	i2s->i2s_dai_drv.playback.channels_max = 2;
-	i2s->i2s_dai_drv.playback.rates = SAMSUNG_I2S_RATES;
+	i2s->i2s_dai_drv.playback.rates = i2s_dai_data->pcm_rates;
 	i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS;
 
 	if (!sec) {
 		i2s->i2s_dai_drv.capture.channels_min = 1;
 		i2s->i2s_dai_drv.capture.channels_max = 2;
-		i2s->i2s_dai_drv.capture.rates = SAMSUNG_I2S_RATES;
+		i2s->i2s_dai_drv.capture.rates = i2s_dai_data->pcm_rates;
 		i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS;
 	}
 	return i2s;
@@ -1132,10 +1135,19 @@ static int i2s_runtime_suspend(struct device *dev)
 static int i2s_runtime_resume(struct device *dev)
 {
 	struct i2s_dai *i2s = dev_get_drvdata(dev);
+	int ret;
 
-	clk_prepare_enable(i2s->clk);
-	if (i2s->op_clk)
-		clk_prepare_enable(i2s->op_clk);
+	ret = clk_prepare_enable(i2s->clk);
+	if (ret)
+		return ret;
+
+	if (i2s->op_clk) {
+		ret = clk_prepare_enable(i2s->op_clk);
+		if (ret) {
+			clk_disable_unprepare(i2s->clk);
+			return ret;
+		}
+	}
 
 	writel(i2s->suspend_i2scon, i2s->addr + I2SCON);
 	writel(i2s->suspend_i2smod, i2s->addr + I2SMOD);
@@ -1242,7 +1254,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 		i2s_dai_data = (struct samsung_i2s_dai_data *)
 				platform_get_device_id(pdev)->driver_data;
 
-	pri_dai = i2s_alloc_dai(pdev, false);
+	pri_dai = i2s_alloc_dai(pdev, i2s_dai_data, false);
 	if (!pri_dai) {
 		dev_err(&pdev->dev, "Unable to alloc I2S_pri\n");
 		return -ENOMEM;
@@ -1316,7 +1328,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 		goto err_disable_clk;
 
 	if (quirks & QUIRK_SEC_DAI) {
-		sec_dai = i2s_alloc_dai(pdev, true);
+		sec_dai = i2s_alloc_dai(pdev, i2s_dai_data, true);
 		if (!sec_dai) {
 			dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
 			ret = -ENOMEM;
@@ -1376,13 +1388,9 @@ err_disable_clk:
 
 static int samsung_i2s_remove(struct platform_device *pdev)
 {
-	struct i2s_dai *pri_dai, *sec_dai;
+	struct i2s_dai *pri_dai;
 
 	pri_dai = dev_get_drvdata(&pdev->dev);
-	sec_dai = pri_dai->sec_dai;
-
-	pri_dai->sec_dai = NULL;
-	sec_dai->pri_dai = NULL;
 
 	pm_runtime_get_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
@@ -1452,29 +1460,34 @@ static const struct samsung_i2s_variant_regs i2sv5_i2s1_regs = {
 
 static const struct samsung_i2s_dai_data i2sv3_dai_type = {
 	.quirks = QUIRK_NO_MUXPSR,
+	.pcm_rates = SNDRV_PCM_RATE_8000_96000,
 	.i2s_variant_regs = &i2sv3_regs,
 };
 
 static const struct samsung_i2s_dai_data i2sv5_dai_type = {
 	.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
 			QUIRK_SUPPORTS_IDMA,
+	.pcm_rates = SNDRV_PCM_RATE_8000_96000,
 	.i2s_variant_regs = &i2sv3_regs,
 };
 
 static const struct samsung_i2s_dai_data i2sv6_dai_type = {
 	.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
 			QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA,
+	.pcm_rates = SNDRV_PCM_RATE_8000_96000,
 	.i2s_variant_regs = &i2sv6_regs,
 };
 
 static const struct samsung_i2s_dai_data i2sv7_dai_type = {
 	.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
 			QUIRK_SUPPORTS_TDM,
+	.pcm_rates = SNDRV_PCM_RATE_8000_192000,
 	.i2s_variant_regs = &i2sv7_regs,
 };
 
 static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = {
 	.quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR,
+	.pcm_rates = SNDRV_PCM_RATE_8000_96000,
 	.i2s_variant_regs = &i2sv5_i2s1_regs,
 };
 
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index 3e408158625d..a635df61f928 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -325,7 +325,7 @@ static int idma_close(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static struct snd_pcm_ops idma_ops = {
+static const struct snd_pcm_ops idma_ops = {
 	.open		= idma_open,
 	.close		= idma_close,
 	.ioctl		= snd_pcm_lib_ioctl,
@@ -399,7 +399,7 @@ void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr)
 }
 EXPORT_SYMBOL_GPL(idma_reg_addr_init);
 
-static struct snd_soc_platform_driver asoc_idma_platform = {
+static const struct snd_soc_platform_driver asoc_idma_platform = {
 	.ops = &idma_ops,
 	.pcm_new = idma_new,
 	.pcm_free = idma_free,
diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c
index 7fcb51faa2a0..529b10dc532b 100644
--- a/sound/soc/samsung/jive_wm8750.c
+++ b/sound/soc/samsung/jive_wm8750.c
@@ -79,7 +79,7 @@ static int jive_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static struct snd_soc_ops jive_ops = {
+static const struct snd_soc_ops jive_ops = {
 	.hw_params	= jive_hw_params,
 };
 
diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c
index 0c0b00e40646..44b6de5a331a 100644
--- a/sound/soc/samsung/odroid.c
+++ b/sound/soc/samsung/odroid.c
@@ -19,8 +19,8 @@ struct odroid_priv {
 	struct snd_soc_card card;
 	struct snd_soc_dai_link dai_link;
 
-	struct clk *pll;
-	struct clk *rclk;
+	struct clk *clk_i2s_bus;
+	struct clk *sclk_i2s;
 };
 
 static int odroid_card_startup(struct snd_pcm_substream *substream)
@@ -42,29 +42,34 @@ static int odroid_card_hw_params(struct snd_pcm_substream *substream,
 	switch (params_rate(params)) {
 	case 32000:
 	case 64000:
-		pll_freq = 131072000U;
+		pll_freq = 131072006U;
 		break;
 	case 44100:
 	case 88200:
 	case 176400:
-		pll_freq = 180633600U;
+		pll_freq = 180633609U;
 		break;
 	case 48000:
 	case 96000:
 	case 192000:
-		pll_freq = 196608000U;
+		pll_freq = 196608001U;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	ret = clk_set_rate(priv->pll, pll_freq + 1);
+	ret = clk_set_rate(priv->clk_i2s_bus, pll_freq / 2 + 1);
 	if (ret < 0)
 		return ret;
 
-	rclk_freq = params_rate(params) * 256 * 4;
+	/*
+	 *  We add 1 to the rclk_freq value in order to avoid too low clock
+	 *  frequency values due to the EPLL output frequency not being exact
+	 *  multiple of the audio sampling rate.
+	 */
+	rclk_freq = params_rate(params) * 256 + 1;
 
-	ret = clk_set_rate(priv->rclk, rclk_freq);
+	ret = clk_set_rate(priv->sclk_i2s, rclk_freq);
 	if (ret < 0)
 		return ret;
 
@@ -118,14 +123,6 @@ static int odroid_audio_probe(struct platform_device *pdev)
 
 	snd_soc_card_set_drvdata(card, priv);
 
-	priv->pll = devm_clk_get(dev, "epll");
-	if (IS_ERR(priv->pll))
-		return PTR_ERR(priv->pll);
-
-	priv->rclk = devm_clk_get(dev, "i2s_rclk");
-	if (IS_ERR(priv->rclk))
-		return PTR_ERR(priv->rclk);
-
 	ret = snd_soc_of_parse_card_name(card, "model");
 	if (ret < 0)
 		return ret;
@@ -171,14 +168,31 @@ static int odroid_audio_probe(struct platform_device *pdev)
 	link->name = "Primary";
 	link->stream_name = link->name;
 
+
+	priv->sclk_i2s = of_clk_get_by_name(link->cpu_of_node, "i2s_opclk1");
+	if (IS_ERR(priv->sclk_i2s)) {
+		ret = PTR_ERR(priv->sclk_i2s);
+		goto err_put_i2s_n;
+	}
+
+	priv->clk_i2s_bus = of_clk_get_by_name(link->cpu_of_node, "iis");
+	if (IS_ERR(priv->clk_i2s_bus)) {
+		ret = PTR_ERR(priv->clk_i2s_bus);
+		goto err_put_sclk;
+	}
+
 	ret = devm_snd_soc_register_card(dev, card);
 	if (ret < 0) {
 		dev_err(dev, "snd_soc_register_card() failed: %d\n", ret);
-		goto err_put_i2s_n;
+		goto err_put_clk_i2s;
 	}
 
 	return 0;
 
+err_put_clk_i2s:
+	clk_put(priv->clk_i2s_bus);
+err_put_sclk:
+	clk_put(priv->sclk_i2s);
 err_put_i2s_n:
 	of_node_put(link->cpu_of_node);
 err_put_codec_n:
@@ -192,6 +206,8 @@ static int odroid_audio_remove(struct platform_device *pdev)
 
 	of_node_put(priv->dai_link.cpu_of_node);
 	odroid_put_codec_of_nodes(&priv->dai_link);
+	clk_put(priv->sclk_i2s);
+	clk_put(priv->clk_i2s_bus);
 
 	return 0;
 }
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index d50a6377c23d..37f95eee1558 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -522,7 +522,9 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "failed to get audio-bus clock\n");
 		return PTR_ERR(pcm->cclk);
 	}
-	clk_prepare_enable(pcm->cclk);
+	ret = clk_prepare_enable(pcm->cclk);
+	if (ret)
+		return ret;
 
 	/* record our pcm structure for later use in the callbacks */
 	dev_set_drvdata(&pdev->dev, pcm);
@@ -533,7 +535,9 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
 		ret = PTR_ERR(pcm->pclk);
 		goto err_dis_cclk;
 	}
-	clk_prepare_enable(pcm->pclk);
+	ret = clk_prepare_enable(pcm->pclk);
+	if (ret)
+		goto err_dis_cclk;
 
 	s3c_pcm_stereo_in[pdev->id].addr = mem_res->start + S3C_PCM_RXFIFO;
 	s3c_pcm_stereo_out[pdev->id].addr = mem_res->start + S3C_PCM_TXFIFO;
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index fa096abe9e75..a064ca7d78c3 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -31,7 +31,6 @@
 #include "s3c24xx-i2s.h"
 
 static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
-static int rx1950_uda1380_card_remove(struct snd_soc_card *card);
 static int rx1950_startup(struct snd_pcm_substream *substream);
 static int rx1950_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params);
@@ -118,7 +117,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static struct snd_soc_card rx1950_asoc = {
 	.name = "rx1950",
 	.owner = THIS_MODULE,
-	.remove = rx1950_uda1380_card_remove,
 	.dai_link = rx1950_uda1380_dai,
 	.num_links = ARRAY_SIZE(rx1950_uda1380_dai),
 
@@ -219,14 +217,6 @@ static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static int rx1950_uda1380_card_remove(struct snd_soc_card *card)
-{
-	snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
-		hp_jack_gpios);
-
-	return 0;
-}
-
 static int __init rx1950_init(void)
 {
 	int ret;
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
index 8f42deaa184b..58c3e9bfc6b7 100644
--- a/sound/soc/samsung/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -27,7 +27,7 @@
 
 #undef S3C_IIS_V2_SUPPORTED
 
-#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) \
+#if defined(CONFIG_CPU_S3C2412) \
 	|| defined(CONFIG_ARCH_S3C64XX) || defined(CONFIG_CPU_S5PV210)
 #define S3C_IIS_V2_SUPPORTED
 #endif
@@ -634,11 +634,10 @@ int s3c_i2sv2_probe(struct snd_soc_dai *dai,
 	i2s->iis_pclk = clk_get(dev, "iis");
 	if (IS_ERR(i2s->iis_pclk)) {
 		dev_err(dev, "failed to get iis_clock\n");
-		iounmap(i2s->regs);
 		return -ENOENT;
 	}
 
-	clk_enable(i2s->iis_pclk);
+	clk_prepare_enable(i2s->iis_pclk);
 
 	/* Mark ourselves as in TXRX mode so we can run through our cleanup
 	 * process without warnings. */
@@ -652,6 +651,15 @@ int s3c_i2sv2_probe(struct snd_soc_dai *dai,
 }
 EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
 
+void s3c_i2sv2_cleanup(struct snd_soc_dai *dai,
+		      struct s3c_i2sv2_info *i2s)
+{
+	clk_disable_unprepare(i2s->iis_pclk);
+	clk_put(i2s->iis_pclk);
+	i2s->iis_pclk = NULL;
+}
+EXPORT_SYMBOL_GPL(s3c_i2sv2_cleanup);
+
 #ifdef CONFIG_PM
 static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
 {
diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h
index 182d80564e37..3fca20f7a853 100644
--- a/sound/soc/samsung/s3c-i2s-v2.h
+++ b/sound/soc/samsung/s3c-i2s-v2.h
@@ -92,6 +92,13 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
 			   unsigned long base);
 
 /**
+ * s3c_i2sv2_cleanup - cleanup resources allocated in s3c_i2sv2_probe
+ * @dai: The ASoC DAI structure supplied to the original probe.
+ * @i2s: Our local i2s structure to fill in.
+ */
+extern void s3c_i2sv2_cleanup(struct snd_soc_dai *dai,
+			      struct s3c_i2sv2_info *i2s);
+/**
  * s3c_i2sv2_register_component - register component and dai with soc core
  * @dev: DAI device
  * @id: DAI ID
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index 0a4718207e6e..cc0840fff5aa 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -65,26 +65,33 @@ static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
 	s3c2412_i2s.iis_cclk = devm_clk_get(dai->dev, "i2sclk");
 	if (IS_ERR(s3c2412_i2s.iis_cclk)) {
 		pr_err("failed to get i2sclk clock\n");
-		return PTR_ERR(s3c2412_i2s.iis_cclk);
+		ret = PTR_ERR(s3c2412_i2s.iis_cclk);
+		goto err;
 	}
 
 	/* Set MPLL as the source for IIS CLK */
 
 	clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
-	clk_prepare_enable(s3c2412_i2s.iis_cclk);
-
-	s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk;
+	ret = clk_prepare_enable(s3c2412_i2s.iis_cclk);
+	if (ret)
+		goto err;
 
 	/* Configure the I2S pins (GPE0...GPE4) in correct mode */
 	s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
 			      S3C_GPIO_PULL_NONE);
 
 	return 0;
+
+err:
+	s3c_i2sv2_cleanup(dai, &s3c2412_i2s);
+
+	return ret;
 }
 
 static int s3c2412_i2s_remove(struct snd_soc_dai *dai)
 {
 	clk_disable_unprepare(s3c2412_i2s.iis_cclk);
+	s3c_i2sv2_cleanup(dai, &s3c2412_i2s);
 
 	return 0;
 }
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 91e6871e5413..8d58d02183bf 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -340,6 +340,7 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
 
 static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
 {
+	int ret;
 	snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out,
 					&s3c24xx_i2s_pcm_stereo_in);
 
@@ -348,7 +349,9 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
 		pr_err("failed to get iis_clock\n");
 		return PTR_ERR(s3c24xx_i2s.iis_clk);
 	}
-	clk_prepare_enable(s3c24xx_i2s.iis_clk);
+	ret = clk_prepare_enable(s3c24xx_i2s.iis_clk);
+	if (ret)
+		return ret;
 
 	/* Configure the I2S pins (GPE0...GPE4) in correct mode */
 	s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
@@ -377,7 +380,11 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
 
 static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
 {
-	clk_prepare_enable(s3c24xx_i2s.iis_clk);
+	int ret;
+
+	ret = clk_prepare_enable(s3c24xx_i2s.iis_clk);
+	if (ret)
+		return ret;
 
 	writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
 	writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c
index dcc008d1e1ab..6de63f3e37d5 100644
--- a/sound/soc/samsung/s3c24xx_simtec.c
+++ b/sound/soc/samsung/s3c24xx_simtec.c
@@ -211,7 +211,7 @@ static int simtec_call_startup(struct s3c24xx_audio_simtec_pdata *pd)
 	return 0;
 }
 
-static struct snd_soc_ops simtec_snd_ops = {
+static const struct snd_soc_ops simtec_snd_ops = {
 	.hw_params	= simtec_hw_params,
 };
 
diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c
index 55538e333cc8..5fb3bab6bbfe 100644
--- a/sound/soc/samsung/s3c24xx_uda134x.c
+++ b/sound/soc/samsung/s3c24xx_uda134x.c
@@ -199,7 +199,7 @@ static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static struct snd_soc_ops s3c24xx_uda134x_ops = {
+static const struct snd_soc_ops s3c24xx_uda134x_ops = {
 	.startup = s3c24xx_uda134x_startup,
 	.shutdown = s3c24xx_uda134x_shutdown,
 	.hw_params = s3c24xx_uda134x_hw_params,
@@ -237,7 +237,6 @@ static int s3c24xx_uda134x_probe(struct platform_device *pdev)
 	mutex_init(&priv->clk_lock);
 
 	card->dev = &pdev->dev;
-	platform_set_drvdata(pdev, card);
 	snd_soc_card_set_drvdata(card, priv);
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
index 425ee2ba37f0..cf0f54e652c1 100644
--- a/sound/soc/samsung/smartq_wm8987.c
+++ b/sound/soc/samsung/smartq_wm8987.c
@@ -160,14 +160,6 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
 	return err;
 }
 
-static int smartq_wm8987_card_remove(struct snd_soc_card *card)
-{
-	snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios),
-				smartq_jack_gpios);
-
-	return 0;
-}
-
 static struct snd_soc_dai_link smartq_dai[] = {
 	{
 		.name		= "wm8987",
@@ -186,7 +178,6 @@ static struct snd_soc_dai_link smartq_dai[] = {
 static struct snd_soc_card snd_soc_smartq = {
 	.name = "SmartQ",
 	.owner = THIS_MODULE,
-	.remove = smartq_wm8987_card_remove,
 	.dai_link = smartq_dai,
 	.num_links = ARRAY_SIZE(smartq_dai),
 
diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c
index a2f2363fe1c2..7fc7cc6d1530 100644
--- a/sound/soc/samsung/smdk_spdif.c
+++ b/sound/soc/samsung/smdk_spdif.c
@@ -144,7 +144,7 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_ops smdk_spdif_ops = {
+static const struct snd_soc_ops smdk_spdif_ops = {
 	.hw_params = smdk_hw_params,
 };
 
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 779504f54bc0..cb59911e65c0 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -391,7 +391,9 @@ static int spdif_probe(struct platform_device *pdev)
 		ret = -ENOENT;
 		goto err0;
 	}
-	clk_prepare_enable(spdif->pclk);
+	ret = clk_prepare_enable(spdif->pclk);
+	if (ret)
+		goto err0;
 
 	spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif");
 	if (IS_ERR(spdif->sclk)) {
@@ -399,7 +401,9 @@ static int spdif_probe(struct platform_device *pdev)
 		ret = -ENOENT;
 		goto err1;
 	}
-	clk_prepare_enable(spdif->sclk);
+	ret = clk_prepare_enable(spdif->sclk);
+	if (ret)
+		goto err1;
 
 	/* Request S/PDIF Register's memory region */
 	if (!request_mem_region(mem_res->start,
diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c
index 24cc9d63ce87..68698f3d72f9 100644
--- a/sound/soc/samsung/tm2_wm5110.c
+++ b/sound/soc/samsung/tm2_wm5110.c
@@ -318,7 +318,7 @@ static const struct snd_kcontrol_new tm2_controls[] = {
 	SOC_DAPM_PIN_SWITCH("Headset Mic"),
 };
 
-const struct snd_soc_dapm_widget tm2_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget tm2_dapm_widgets[] = {
 	SND_SOC_DAPM_HP("HP", NULL),
 	SND_SOC_DAPM_SPK("SPK", NULL),
 	SND_SOC_DAPM_SPK("RCV", NULL),
@@ -521,7 +521,7 @@ static void tm2_pm_complete(struct device *dev)
 	tm2_start_sysclk(card);
 }
 
-const struct dev_pm_ops tm2_pm_ops = {
+static const struct dev_pm_ops tm2_pm_ops = {
 	.prepare	= tm2_pm_prepare,
 	.suspend	= snd_soc_suspend,
 	.resume		= snd_soc_resume,
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index 8fad4441c87d..1e7d417b53ef 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -89,7 +89,7 @@ struct camelot_pcm {
 #define DMABRG_PREALLOC_BUFFER		32 * 1024
 #define DMABRG_PREALLOC_BUFFER_MAX	32 * 1024
 
-static struct snd_pcm_hardware camelot_pcm_hardware = {
+static const struct snd_pcm_hardware camelot_pcm_hardware = {
 	.info = (SNDRV_PCM_INFO_MMAP |
 		SNDRV_PCM_INFO_INTERLEAVED |
 		SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -294,7 +294,7 @@ static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream)
 	return bytes_to_frames(runtime, pos);
 }
 
-static struct snd_pcm_ops camelot_pcm_ops = {
+static const struct snd_pcm_ops camelot_pcm_ops = {
 	.open		= camelot_pcm_open,
 	.close		= camelot_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
@@ -320,7 +320,7 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static struct snd_soc_platform_driver sh7760_soc_platform = {
+static const struct snd_soc_platform_driver sh7760_soc_platform = {
 	.ops		= &camelot_pcm_ops,
 	.pcm_new	= camelot_pcm_new,
 };
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 7c4bdd82bb95..6d3c7706d93f 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1710,7 +1710,7 @@ static const struct snd_soc_dai_ops fsi_dai_ops = {
  *		pcm ops
  */
 
-static struct snd_pcm_hardware fsi_pcm_hardware = {
+static const struct snd_pcm_hardware fsi_pcm_hardware = {
 	.info =		SNDRV_PCM_INFO_INTERLEAVED	|
 			SNDRV_PCM_INFO_MMAP		|
 			SNDRV_PCM_INFO_MMAP_VALID,
@@ -1755,7 +1755,7 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
 	return fsi_sample2frame(fsi, io->buff_sample_pos);
 }
 
-static struct snd_pcm_ops fsi_pcm_ops = {
+static const struct snd_pcm_ops fsi_pcm_ops = {
 	.open		= fsi_pcm_open,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= fsi_hw_params,
@@ -1818,7 +1818,7 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = {
 	},
 };
 
-static struct snd_soc_platform_driver fsi_soc_platform = {
+static const struct snd_soc_platform_driver fsi_soc_platform = {
 	.ops		= &fsi_pcm_ops,
 	.pcm_new	= fsi_pcm_new,
 };
@@ -1962,10 +1962,8 @@ static int fsi_probe(struct platform_device *pdev)
 	}
 
 	master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
-	if (!master) {
-		dev_err(&pdev->dev, "Could not allocate master\n");
+	if (!master)
 		return -ENOMEM;
-	}
 
 	master->base = devm_ioremap_nocache(&pdev->dev,
 					    res->start, resource_size(res));
@@ -2109,7 +2107,7 @@ static int fsi_resume(struct device *dev)
 	return 0;
 }
 
-static struct dev_pm_ops fsi_pm_ops = {
+static const struct dev_pm_ops fsi_pm_ops = {
 	.suspend		= fsi_suspend,
 	.resume			= fsi_resume,
 };
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index 84c51037a7d0..624aaf569fef 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -315,6 +315,8 @@ static const struct snd_soc_component_driver sh4_hac_component = {
 
 static int hac_soc_platform_probe(struct platform_device *pdev)
 {
+	int ret;
+
 	ret = snd_soc_set_ac97_ops(&hac_ac97_ops);
 	if (ret != 0)
 		return ret;
diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c
index 672bcd4c252b..ecb057ff9fbb 100644
--- a/sound/soc/sh/migor.c
+++ b/sound/soc/sh/migor.c
@@ -98,7 +98,7 @@ static int migor_hw_free(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static struct snd_soc_ops migor_dai_ops = {
+static const struct snd_soc_ops migor_dai_ops = {
 	.hw_params = migor_hw_params,
 	.hw_free = migor_hw_free,
 };
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 197cb3ec075f..938baff86ef2 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -586,10 +586,8 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
 	int ret;
 
 	adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
-	if (!adg) {
-		dev_err(dev, "ADG allocate failed\n");
+	if (!adg)
 		return -ENOMEM;
-	}
 
 	ret = rsnd_mod_init(priv, &adg->mod, &adg_ops,
 		      NULL, NULL, 0, 0);
@@ -610,6 +608,13 @@ void rsnd_adg_remove(struct rsnd_priv *priv)
 {
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct device_node *np = dev->of_node;
+	struct rsnd_adg *adg = priv->adg;
+	struct clk *clk;
+	int i;
+
+	for_each_rsnd_clkout(clk, adg, i)
+		if (adg->clkout[i])
+			clk_unregister_fixed_rate(adg->clkout[i]);
 
 	of_clk_del_provider(np);
 
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 3f2ced26ed37..107133297e8d 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -726,7 +726,6 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	case 2:
 	case 6:
 	case 8:
-	case 16:
 		/* TDM Extend Mode */
 		rsnd_rdai_channels_set(rdai, slots);
 		rsnd_rdai_ssi_lane_set(rdai, 1);
@@ -740,7 +739,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
 }
 
 static unsigned int rsnd_soc_hw_channels_list[] = {
-	2, 6, 8, 16,
+	2, 6, 8,
 };
 
 static unsigned int rsnd_soc_hw_rate_list[] = {
@@ -844,12 +843,28 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
 				ir, &ic);
 }
 
-static void rsnd_soc_hw_constraint(struct snd_pcm_runtime *runtime,
-				   struct snd_soc_dai *dai)
+static const struct snd_pcm_hardware rsnd_pcm_hardware = {
+	.info =		SNDRV_PCM_INFO_INTERLEAVED	|
+			SNDRV_PCM_INFO_MMAP		|
+			SNDRV_PCM_INFO_MMAP_VALID,
+	.buffer_bytes_max	= 64 * 1024,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 8192,
+	.periods_min		= 1,
+	.periods_max		= 32,
+	.fifo_size		= 256,
+};
+
+static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
 {
 	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+	struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
 	struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	unsigned int max_channels = rsnd_rdai_channels_get(rdai);
+	int ret;
 	int i;
 
 	/*
@@ -866,34 +881,26 @@ static void rsnd_soc_hw_constraint(struct snd_pcm_runtime *runtime,
 		constraint->count = i + 1;
 	}
 
+	snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware);
+
 	snd_pcm_hw_constraint_list(runtime, 0,
 				   SNDRV_PCM_HW_PARAM_CHANNELS, constraint);
 
+	snd_pcm_hw_constraint_integer(runtime,
+				      SNDRV_PCM_HW_PARAM_PERIODS);
+
 	/*
 	 * Sampling Rate / Channel Limitation
 	 * It depends on Clock Master Mode
 	 */
-	if (!rsnd_rdai_is_clk_master(rdai))
-		return;
-
-	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-			    rsnd_soc_hw_rule_rate, dai,
-			    SNDRV_PCM_HW_PARAM_CHANNELS, -1);
-	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-			    rsnd_soc_hw_rule_channels, dai,
-			    SNDRV_PCM_HW_PARAM_RATE, -1);
-}
-
-static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
-				struct snd_soc_dai *dai)
-{
-	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
-	struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-	int ret;
-
-	/* rsnd_io_to_runtime() is not yet enabled here */
-	rsnd_soc_hw_constraint(substream->runtime, dai);
+	if (rsnd_rdai_is_clk_master(rdai)) {
+		snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+				    rsnd_soc_hw_rule_rate, dai,
+				    SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+		snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+				    rsnd_soc_hw_rule_channels, dai,
+				    SNDRV_PCM_HW_PARAM_RATE, -1);
+	}
 
 	/*
 	 * call rsnd_dai_call without spinlock
@@ -1017,7 +1024,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
 	drv->playback.rates		= RSND_RATES;
 	drv->playback.formats		= RSND_FMTS;
 	drv->playback.channels_min	= 2;
-	drv->playback.channels_max	= 16;
+	drv->playback.channels_max	= 8;
 	drv->playback.stream_name	= rdai->playback.name;
 
 	snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
@@ -1025,7 +1032,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
 	drv->capture.rates		= RSND_RATES;
 	drv->capture.formats		= RSND_FMTS;
 	drv->capture.channels_min	= 2;
-	drv->capture.channels_max	= 16;
+	drv->capture.channels_max	= 8;
 	drv->capture.stream_name	= rdai->capture.name;
 
 	rdai->playback.rdai		= rdai;
@@ -1105,31 +1112,6 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
 /*
  *		pcm ops
  */
-static struct snd_pcm_hardware rsnd_pcm_hardware = {
-	.info =		SNDRV_PCM_INFO_INTERLEAVED	|
-			SNDRV_PCM_INFO_MMAP		|
-			SNDRV_PCM_INFO_MMAP_VALID,
-	.buffer_bytes_max	= 64 * 1024,
-	.period_bytes_min	= 32,
-	.period_bytes_max	= 8192,
-	.periods_min		= 1,
-	.periods_max		= 32,
-	.fifo_size		= 256,
-};
-
-static int rsnd_pcm_open(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	int ret = 0;
-
-	snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware);
-
-	ret = snd_pcm_hw_constraint_integer(runtime,
-					    SNDRV_PCM_HW_PARAM_PERIODS);
-
-	return ret;
-}
-
 static int rsnd_hw_params(struct snd_pcm_substream *substream,
 			 struct snd_pcm_hw_params *hw_params)
 {
@@ -1158,8 +1140,7 @@ static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
 	return pointer;
 }
 
-static struct snd_pcm_ops rsnd_pcm_ops = {
-	.open		= rsnd_pcm_open,
+static const struct snd_pcm_ops rsnd_pcm_ops = {
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= rsnd_hw_params,
 	.hw_free	= snd_pcm_lib_free_pages,
@@ -1169,11 +1150,10 @@ static struct snd_pcm_ops rsnd_pcm_ops = {
 /*
  *		snd_kcontrol
  */
-#define kcontrol_to_cfg(kctrl) ((struct rsnd_kctrl_cfg *)kctrl->private_value)
 static int rsnd_kctrl_info(struct snd_kcontrol *kctrl,
 			   struct snd_ctl_elem_info *uinfo)
 {
-	struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
+	struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
 
 	if (cfg->texts) {
 		uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -1199,7 +1179,7 @@ static int rsnd_kctrl_info(struct snd_kcontrol *kctrl,
 static int rsnd_kctrl_get(struct snd_kcontrol *kctrl,
 			  struct snd_ctl_elem_value *uc)
 {
-	struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
+	struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
 	int i;
 
 	for (i = 0; i < cfg->size; i++)
@@ -1214,8 +1194,7 @@ static int rsnd_kctrl_get(struct snd_kcontrol *kctrl,
 static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
 			  struct snd_ctl_elem_value *uc)
 {
-	struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
-	struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
+	struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
 	int i, change = 0;
 
 	if (!cfg->accept(cfg->io))
@@ -1232,7 +1211,7 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
 	}
 
 	if (change && cfg->update)
-		cfg->update(cfg->io, mod);
+		cfg->update(cfg->io, cfg->mod);
 
 	return change;
 }
@@ -1284,14 +1263,13 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
 		.index		= rtd->num,
 		.get		= rsnd_kctrl_get,
 		.put		= rsnd_kctrl_put,
-		.private_value	= (unsigned long)cfg,
 	};
 	int ret;
 
 	if (size > RSND_MAX_CHANNELS)
 		return -EINVAL;
 
-	kctrl = snd_ctl_new1(&knew, mod);
+	kctrl = snd_ctl_new1(&knew, cfg);
 	if (!kctrl)
 		return -ENOMEM;
 
@@ -1307,6 +1285,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
 	cfg->card	= card;
 	cfg->kctrl	= kctrl;
 	cfg->io		= io;
+	cfg->mod	= mod;
 
 	return 0;
 }
@@ -1339,7 +1318,7 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
 		PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
 }
 
-static struct snd_soc_platform_driver rsnd_soc_platform = {
+static const struct snd_soc_platform_driver rsnd_soc_platform = {
 	.ops		= &rsnd_pcm_ops,
 	.pcm_new	= rsnd_pcm_new,
 };
@@ -1422,10 +1401,8 @@ static int rsnd_probe(struct platform_device *pdev)
 	 *	init priv data
 	 */
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv) {
-		dev_err(dev, "priv allocate failed\n");
+	if (!priv)
 		return -ENODEV;
-	}
 
 	priv->pdev	= pdev;
 	priv->flags	= (unsigned long)of_device_get_match_data(dev);
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index 4ba8f2fe7a4c..e7f53f44165d 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -394,13 +394,16 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
 		clk = devm_clk_get(dev, name);
 		if (IS_ERR(clk)) {
 			ret = PTR_ERR(clk);
+			of_node_put(np);
 			goto rsnd_ctu_probe_done;
 		}
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
 				    clk, rsnd_mod_get_status, RSND_MOD_CTU, i);
-		if (ret)
+		if (ret) {
+			of_node_put(np);
 			goto rsnd_ctu_probe_done;
+		}
 
 		i++;
 	}
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 60aa5e96a49f..041ec1080d52 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -604,8 +604,8 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
 		dma_addr_t in_addr;
 	} dma_addrs[3][2][3] = {
 		/* SRC */
+		/* Capture */
 		{{{ 0,				0 },
-		  /* Capture */
 		  { RDMA_SRC_O_N(src, id),	RDMA_SRC_I_P(src, id) },
 		  { RDMA_CMD_O_N(src, id),	RDMA_SRC_I_P(src, id) } },
 		 /* Playback */
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 99d2d9459e75..1743ade3cc55 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -380,13 +380,16 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
 		clk = devm_clk_get(dev, name);
 		if (IS_ERR(clk)) {
 			ret = PTR_ERR(clk);
+			of_node_put(np);
 			goto rsnd_dvc_probe_done;
 		}
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
 				    clk, rsnd_mod_get_status, RSND_MOD_DVC, i);
-		if (ret)
+		if (ret) {
+			of_node_put(np);
 			goto rsnd_dvc_probe_done;
+		}
 
 		i++;
 	}
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index ee00e3516911..f04c4100043a 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -406,10 +406,8 @@ int rsnd_gen_probe(struct rsnd_priv *priv)
 	int ret;
 
 	gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
-	if (!gen) {
-		dev_err(dev, "GEN allocate failed\n");
+	if (!gen)
 		return -ENOMEM;
-	}
 
 	priv->gen = gen;
 
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
index 195fc7bb22af..6c4826c189a4 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/sh/rcar/mix.c
@@ -168,13 +168,16 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
 		clk = devm_clk_get(dev, name);
 		if (IS_ERR(clk)) {
 			ret = PTR_ERR(clk);
+			of_node_put(np);
 			goto rsnd_mix_probe_done;
 		}
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
 				    clk, rsnd_mod_get_status, RSND_MOD_MIX, i);
-		if (ret)
+		if (ret) {
+			of_node_put(np);
 			goto rsnd_mix_probe_done;
+		}
 
 		i++;
 	}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 99c57611df88..c5de71f2dc8c 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -614,6 +614,7 @@ struct rsnd_kctrl_cfg {
 	struct rsnd_dai_stream *io;
 	struct snd_card *card;
 	struct snd_kcontrol *kctrl;
+	struct rsnd_mod *mod;
 };
 
 #define RSND_MAX_CHANNELS	8
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 7aa239e28491..510b68a483b4 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -27,7 +27,6 @@ struct rsnd_src {
 #define RSND_SRC_NAME_SIZE 16
 
 #define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id)
-#define rsnd_src_to_dma(src) ((src)->dma)
 #define rsnd_src_nr(priv) ((priv)->src_nr)
 #define rsnd_src_sync_is_enabled(mod) (rsnd_mod_to_src(mod)->sen.val)
 
@@ -108,7 +107,6 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
 	int is_play = rsnd_io_is_play(io);
 
 	/*
-	 *
 	 * Playback
 	 * runtime_rate -> [SRC] -> convert_rate
 	 *
@@ -203,13 +201,13 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
 	use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod);
 
 	/*
-	 *	SRC_ADINR
+	 * SRC_ADINR
 	 */
 	adinr = rsnd_get_adinr_bit(mod, io) |
 		rsnd_runtime_channel_original(io);
 
 	/*
-	 *	SRC_IFSCR / SRC_IFSVR
+	 * SRC_IFSCR / SRC_IFSVR
 	 */
 	ifscr = 0;
 	fsrate = 0;
@@ -223,7 +221,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
 	}
 
 	/*
-	 *	SRC_SRCCR / SRC_ROUTE_MODE0
+	 * SRC_SRCCR / SRC_ROUTE_MODE0
 	 */
 	cr	= 0x00011110;
 	route	= 0x0;
@@ -581,20 +579,24 @@ int rsnd_src_probe(struct rsnd_priv *priv)
 		src->irq = irq_of_parse_and_map(np, 0);
 		if (!src->irq) {
 			ret = -EINVAL;
+			of_node_put(np);
 			goto rsnd_src_probe_done;
 		}
 
 		clk = devm_clk_get(dev, name);
 		if (IS_ERR(clk)) {
 			ret = PTR_ERR(clk);
+			of_node_put(np);
 			goto rsnd_src_probe_done;
 		}
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(src),
 				    &rsnd_src_ops, clk, rsnd_mod_get_status,
 				    RSND_MOD_SRC, i);
-		if (ret)
+		if (ret) {
+			of_node_put(np);
 			goto rsnd_src_probe_done;
+		}
 
 skip:
 		i++;
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 46feddd78ee2..fffc07e72627 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -72,6 +72,7 @@ struct rsnd_ssi {
 	u32 cr_own;
 	u32 cr_clk;
 	u32 cr_mode;
+	u32 cr_en;
 	u32 wsr;
 	int chan;
 	int rate;
@@ -89,6 +90,7 @@ struct rsnd_ssi {
 #define RSND_SSI_NO_BUSIF		(1 << 1) /* SSI+DMA without BUSIF */
 #define RSND_SSI_HDMI0			(1 << 2) /* for HDMI0 */
 #define RSND_SSI_HDMI1			(1 << 3) /* for HDMI1 */
+#define RSND_SSI_PROBED			(1 << 4)
 
 #define for_each_rsnd_ssi(pos, priv, i)					\
 	for (i = 0;							\
@@ -97,25 +99,27 @@ struct rsnd_ssi {
 	     i++)
 
 #define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id)
-#define rsnd_ssi_to_dma(mod) ((ssi)->dma)
 #define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
 #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
-#define rsnd_ssi_mode_flags(p) ((p)->flags)
+#define rsnd_ssi_flags_has(p, f) ((p)->flags & f)
+#define rsnd_ssi_flags_set(p, f) ((p)->flags |= f)
+#define rsnd_ssi_flags_del(p, f) ((p)->flags = ((p)->flags & ~f))
 #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
 #define rsnd_ssi_is_multi_slave(mod, io) \
 	(rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod)))
 #define rsnd_ssi_is_run_mods(mod, io) \
 	(rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
+#define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod))
 
 int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io)
 {
 	struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
-	if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI0)
+	if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI0))
 		return RSND_SSI_HDMI_PORT0;
 
-	if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI1)
+	if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI1))
 		return RSND_SSI_HDMI_PORT1;
 
 	return 0;
@@ -130,7 +134,7 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
 	if (!rsnd_ssi_is_dma_mode(mod))
 		return 0;
 
-	if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF))
+	if (!(rsnd_ssi_flags_has(ssi, RSND_SSI_NO_BUSIF)))
 		use_busif = 1;
 	if (rsnd_io_to_mod_src(io))
 		use_busif = 1;
@@ -255,7 +259,6 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-	struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
 	int chan = rsnd_runtime_channel_for_ssi(io);
 	int idx, ret;
 	unsigned int main_rate;
@@ -266,7 +269,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
 	if (!rsnd_rdai_is_clk_master(rdai))
 		return 0;
 
-	if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
+	if (!rsnd_ssi_can_output_clk(mod))
 		return 0;
 
 	if (rsnd_ssi_is_multi_slave(mod, io))
@@ -291,6 +294,16 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
 	if (ret < 0)
 		return ret;
 
+	/*
+	 * SSI clock will be output contiguously
+	 * by below settings.
+	 * This means, rsnd_ssi_master_clk_start()
+	 * and rsnd_ssi_register_setup() are necessary
+	 * for SSI parent
+	 *
+	 * SSICR  : FORCE, SCKD, SWSD
+	 * SSIWSR : CONT
+	 */
 	ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(idx);
 	ssi->wsr = CONT;
 	ssi->rate = rate;
@@ -307,12 +320,11 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod,
 {
 	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-	struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
 
 	if (!rsnd_rdai_is_clk_master(rdai))
 		return;
 
-	if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
+	if (!rsnd_ssi_can_output_clk(mod))
 		return;
 
 	if (ssi->usrcnt > 1)
@@ -335,6 +347,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
 	u32 wsr;
 	int is_tdm;
 
+	if (rsnd_ssi_is_parent(mod, io))
+		return;
+
 	is_tdm = rsnd_runtime_is_ssi_tdm(io);
 
 	/*
@@ -393,7 +408,8 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod)
 	rsnd_mod_write(mod, SSIWSR,	ssi->wsr);
 	rsnd_mod_write(mod, SSICR,	ssi->cr_own	|
 					ssi->cr_clk	|
-					ssi->cr_mode); /* without EN */
+					ssi->cr_mode	|
+					ssi->cr_en);
 }
 
 static void rsnd_ssi_pointer_init(struct rsnd_mod *mod,
@@ -472,8 +488,7 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
 	if (ret < 0)
 		return ret;
 
-	if (!rsnd_ssi_is_parent(mod, io))
-		rsnd_ssi_config_init(mod, io);
+	rsnd_ssi_config_init(mod, io);
 
 	rsnd_ssi_register_setup(mod);
 
@@ -544,6 +559,8 @@ static int rsnd_ssi_start(struct rsnd_mod *mod,
 			  struct rsnd_dai_stream *io,
 			  struct rsnd_priv *priv)
 {
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
 	if (!rsnd_ssi_is_run_mods(mod, io))
 		return 0;
 
@@ -554,7 +571,19 @@ static int rsnd_ssi_start(struct rsnd_mod *mod,
 	if (rsnd_ssi_multi_slaves_runtime(io))
 		return 0;
 
-	rsnd_mod_bset(mod, SSICR, EN, EN);
+	/*
+	 * EN is for data output.
+	 * SSI parent EN is not needed.
+	 */
+	if (rsnd_ssi_is_parent(mod, io))
+		return 0;
+
+	ssi->cr_en = EN;
+
+	rsnd_mod_write(mod, SSICR,	ssi->cr_own	|
+					ssi->cr_clk	|
+					ssi->cr_mode	|
+					ssi->cr_en);
 
 	return 0;
 }
@@ -569,13 +598,7 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
 	if (!rsnd_ssi_is_run_mods(mod, io))
 		return 0;
 
-	/*
-	 * don't stop if not last user
-	 * see also
-	 *	rsnd_ssi_start
-	 *	rsnd_ssi_interrupt
-	 */
-	if (ssi->usrcnt > 1)
+	if (rsnd_ssi_is_parent(mod, io))
 		return 0;
 
 	/*
@@ -595,6 +618,8 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
 	rsnd_mod_write(mod, SSICR, cr);	/* disabled all */
 	rsnd_ssi_status_check(mod, IIRQ);
 
+	ssi->cr_en = 0;
+
 	return 0;
 }
 
@@ -760,15 +785,47 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
 	/*
 	 * SSI might be called again as PIO fallback
 	 * It is easy to manual handling for IRQ request/free
+	 *
+	 * OTOH, this function might be called many times if platform is
+	 * using MIX. It needs xxx_attach() many times on xxx_probe().
+	 * Because of it, we can't control .probe/.remove calling count by
+	 * mod->status.
+	 * But it don't need to call request_irq() many times.
+	 * Let's control it by RSND_SSI_PROBED flag.
 	 */
-	ret = request_irq(ssi->irq,
-			  rsnd_ssi_interrupt,
-			  IRQF_SHARED,
-			  dev_name(dev), mod);
+	if (!rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) {
+		ret = request_irq(ssi->irq,
+				  rsnd_ssi_interrupt,
+				  IRQF_SHARED,
+				  dev_name(dev), mod);
+
+		rsnd_ssi_flags_set(ssi, RSND_SSI_PROBED);
+	}
 
 	return ret;
 }
 
+static int rsnd_ssi_common_remove(struct rsnd_mod *mod,
+				  struct rsnd_dai_stream *io,
+				  struct rsnd_priv *priv)
+{
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+	struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io);
+
+	/* Do nothing if non SSI (= SSI parent, multi SSI) mod */
+	if (pure_ssi_mod != mod)
+		return 0;
+
+	/* PIO will request IRQ again */
+	if (rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) {
+		free_irq(ssi->irq, mod);
+
+		rsnd_ssi_flags_del(ssi, RSND_SSI_PROBED);
+	}
+
+	return 0;
+}
+
 static int rsnd_ssi_pointer(struct rsnd_mod *mod,
 			    struct rsnd_dai_stream *io,
 			    snd_pcm_uframes_t *pointer)
@@ -784,6 +841,7 @@ static int rsnd_ssi_pointer(struct rsnd_mod *mod,
 static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
 	.name	= SSI_NAME,
 	.probe	= rsnd_ssi_common_probe,
+	.remove	= rsnd_ssi_common_remove,
 	.init	= rsnd_ssi_init,
 	.quit	= rsnd_ssi_quit,
 	.start	= rsnd_ssi_start,
@@ -818,23 +876,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
 	return ret;
 }
 
-static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
-			       struct rsnd_dai_stream *io,
-			       struct rsnd_priv *priv)
-{
-	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-	struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
-
-	/* Do nothing for SSI parent mod */
-	if (ssi_parent_mod == mod)
-		return 0;
-
-	/* PIO will request IRQ again */
-	free_irq(ssi->irq, mod);
-
-	return 0;
-}
-
 static int rsnd_ssi_fallback(struct rsnd_mod *mod,
 			     struct rsnd_dai_stream *io,
 			     struct rsnd_priv *priv)
@@ -876,7 +917,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
 	.name	= SSI_NAME,
 	.dma_req = rsnd_ssi_dma_req,
 	.probe	= rsnd_ssi_dma_probe,
-	.remove	= rsnd_ssi_dma_remove,
+	.remove	= rsnd_ssi_common_remove,
 	.init	= rsnd_ssi_init,
 	.quit	= rsnd_ssi_quit,
 	.start	= rsnd_ssi_start,
@@ -962,13 +1003,13 @@ static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
 	ssi  = rsnd_mod_to_ssi(mod);
 
 	if (strstr(remote_ep->full_name, "hdmi0")) {
-		ssi->flags |= RSND_SSI_HDMI0;
+		rsnd_ssi_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")) {
-		ssi->flags |= RSND_SSI_HDMI1;
+		rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI1);
 		dev_dbg(dev, "%s[%d] connected to HDMI1\n",
 			rsnd_mod_name(mod), rsnd_mod_id(mod));
 	}
@@ -1001,7 +1042,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
 {
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
-	return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
+	return !!(rsnd_ssi_flags_has(ssi, RSND_SSI_CLK_PIN_SHARE));
 }
 
 static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io,
@@ -1079,18 +1120,20 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
 		clk = devm_clk_get(dev, name);
 		if (IS_ERR(clk)) {
 			ret = PTR_ERR(clk);
+			of_node_put(np);
 			goto rsnd_ssi_probe_done;
 		}
 
 		if (of_get_property(np, "shared-pin", NULL))
-			ssi->flags |= RSND_SSI_CLK_PIN_SHARE;
+			rsnd_ssi_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
 
 		if (of_get_property(np, "no-busif", NULL))
-			ssi->flags |= RSND_SSI_NO_BUSIF;
+			rsnd_ssi_flags_set(ssi, RSND_SSI_NO_BUSIF);
 
 		ssi->irq = irq_of_parse_and_map(np, 0);
 		if (!ssi->irq) {
 			ret = -EINVAL;
+			of_node_put(np);
 			goto rsnd_ssi_probe_done;
 		}
 
@@ -1101,8 +1144,10 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
 				    rsnd_ssi_get_status, RSND_MOD_SSI, i);
-		if (ret)
+		if (ret) {
+			of_node_put(np);
 			goto rsnd_ssi_probe_done;
+		}
 
 		i++;
 	}
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index bed2c9c0004b..4d948757d300 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -250,7 +250,7 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
 {
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_ssiu *ssiu;
-	static struct rsnd_mod_ops *ops;
+	struct rsnd_mod_ops *ops;
 	int i, nr, ret;
 
 	/* same number to SSI */
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
index 4a22aadac294..160502947da2 100644
--- a/sound/soc/sh/siu_dai.c
+++ b/sound/soc/sh/siu_dai.c
@@ -333,7 +333,7 @@ static void siu_dai_spbstop(struct siu_port *port_info)
 /*		API functions		*/
 
 /* Playback and capture hardware properties are identical */
-static struct snd_pcm_hardware siu_dai_pcm_hw = {
+static const struct snd_pcm_hardware siu_dai_pcm_hw = {
 	.info			= SNDRV_PCM_INFO_INTERLEAVED,
 	.formats		= SNDRV_PCM_FMTBIT_S16,
 	.rates			= SNDRV_PCM_RATE_8000_48000,
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index 82902f56e82f..3118cb0ee3f2 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -593,7 +593,7 @@ static void siu_pcm_free(struct snd_pcm *pcm)
 	dev_dbg(pcm->card->dev, "%s\n", __func__);
 }
 
-static struct snd_pcm_ops siu_pcm_ops = {
+static const struct snd_pcm_ops siu_pcm_ops = {
 	.open		= siu_pcm_open,
 	.close		= siu_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 206f36bf43e8..2cb8d3b55fbc 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -737,9 +737,6 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 	}
 
 	/* check client and interface hw capabilities */
-	snprintf(new_name, sizeof(new_name), "%s %s-%d",
-			rtd->dai_link->stream_name, codec_dai->name, num);
-
 	if (codec_dai->driver->playback.channels_min)
 		playback = 1;
 	if (codec_dai->driver->capture.channels_min)
@@ -758,21 +755,18 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 		return -EINVAL;
 	}
 
-	if(playback)
+	if (playback)
 		direction = SND_COMPRESS_PLAYBACK;
 	else
 		direction = SND_COMPRESS_CAPTURE;
 
 	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
-	if (compr == NULL) {
-		snd_printk(KERN_ERR "Cannot allocate compr\n");
+	if (!compr)
 		return -ENOMEM;
-	}
 
 	compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
 				  GFP_KERNEL);
-	if (compr->ops == NULL) {
-		dev_err(rtd->card->dev, "Cannot allocate compressed ops\n");
+	if (!compr->ops) {
 		ret = -ENOMEM;
 		goto compr_err;
 	}
@@ -797,19 +791,18 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 		else if (rtd->dai_link->dpcm_capture)
 			be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
 		memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
-	} else
+	} else {
+		snprintf(new_name, sizeof(new_name), "%s %s-%d",
+			rtd->dai_link->stream_name, codec_dai->name, num);
+
 		memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
+	}
 
 	/* Add copy callback for not memory mapped DSPs */
 	if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
 		compr->ops->copy = soc_compr_copy;
 
 	mutex_init(&compr->lock);
-
-	snprintf(new_name, sizeof(new_name), "%s %s-%d",
-		 rtd->dai_link->stream_name,
-		 rtd->codec_dai->name, num);
-
 	ret = snd_compress_new(rtd->card->snd_card, num, direction,
 				new_name, compr);
 	if (ret < 0) {
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 921622a01944..e4ea5d4aa8d5 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -339,11 +339,12 @@ static void soc_cleanup_component_debugfs(struct snd_soc_component *component)
 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;
 
-	codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
-						 codec->component.debugfs_root,
-						 codec, &codec_reg_fops);
-	if (!codec->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");
 }
@@ -494,7 +495,7 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
 static void snd_soc_debugfs_init(void)
 {
 	snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
-	if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) {
+	if (IS_ERR_OR_NULL(snd_soc_debugfs_root)) {
 		pr_warn("ASoC: Failed to create debugfs directory\n");
 		snd_soc_debugfs_root = NULL;
 		return;
@@ -550,6 +551,54 @@ static inline void snd_soc_debugfs_exit(void)
 
 #endif
 
+static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd,
+			      struct snd_soc_component *component)
+{
+	struct snd_soc_rtdcom_list *rtdcom;
+	struct snd_soc_rtdcom_list *new_rtdcom;
+
+	for_each_rtdcom(rtd, rtdcom) {
+		/* already connected */
+		if (rtdcom->component == component)
+			return 0;
+	}
+
+	new_rtdcom = kmalloc(sizeof(*new_rtdcom), GFP_KERNEL);
+	if (!new_rtdcom)
+		return -ENOMEM;
+
+	new_rtdcom->component = component;
+	INIT_LIST_HEAD(&new_rtdcom->list);
+
+	list_add_tail(&new_rtdcom->list, &rtd->component_list);
+
+	return 0;
+}
+
+static void snd_soc_rtdcom_del_all(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_rtdcom_list *rtdcom1, *rtdcom2;
+
+	for_each_rtdcom_safe(rtd, rtdcom1, rtdcom2)
+		kfree(rtdcom1);
+
+	INIT_LIST_HEAD(&rtd->component_list);
+}
+
+struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd,
+						const char *driver_name)
+{
+	struct snd_soc_rtdcom_list *rtdcom;
+
+	for_each_rtdcom(rtd, rtdcom) {
+		if ((rtdcom->component->driver->name == driver_name) ||
+		    strcmp(rtdcom->component->driver->name, driver_name) == 0)
+			return rtdcom->component;
+	}
+
+	return NULL;
+}
+
 struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
 		const char *dai_link, int stream)
 {
@@ -574,6 +623,7 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
 	if (!rtd)
 		return NULL;
 
+	INIT_LIST_HEAD(&rtd->component_list);
 	rtd->card = card;
 	rtd->dai_link = dai_link;
 	rtd->codec_dais = kzalloc(sizeof(struct snd_soc_dai *) *
@@ -591,6 +641,7 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
 {
 	if (rtd && rtd->codec_dais)
 		kfree(rtd->codec_dais);
+	snd_soc_rtdcom_del_all(rtd);
 	kfree(rtd);
 }
 
@@ -949,7 +1000,7 @@ static struct snd_soc_component *soc_find_component(
 /**
  * snd_soc_find_dai - Find a registered DAI
  *
- * @dlc: name of the DAI and optional component info to match
+ * @dlc: name of the DAI or the DAI driver and optional component info to match
  *
  * This function will search all registered components and their DAIs to
  * find the DAI of the same name. The component's of_node and name
@@ -977,7 +1028,9 @@ struct snd_soc_dai *snd_soc_find_dai(
 		if (dlc->name && strcmp(component->name, dlc->name))
 			continue;
 		list_for_each_entry(dai, &component->dai_list, list) {
-			if (dlc->dai_name && strcmp(dai->name, dlc->dai_name))
+			if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)
+			    && (!dai->driver->name
+				|| strcmp(dai->driver->name, dlc->dai_name)))
 				continue;
 
 			return dai;
@@ -1049,6 +1102,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
 	struct snd_soc_pcm_runtime *rtd;
 	struct snd_soc_dai_link_component *codecs = dai_link->codecs;
 	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;
@@ -1076,6 +1130,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
 			dai_link->cpu_dai_name);
 		goto _err_defer;
 	}
+	snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component);
 
 	rtd->num_codecs = dai_link->num_codecs;
 
@@ -1088,6 +1143,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
 				codecs[i].dai_name);
 			goto _err_defer;
 		}
+		snd_soc_rtdcom_add(rtd, codec_dais[i]->component);
 	}
 
 	/* Single codec links expect codec and codec_dai in runtime data */
@@ -1100,6 +1156,23 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
 		platform_name = "snd-soc-dummy";
 
 	/* find one from the set of registered platforms */
+	list_for_each_entry(component, &component_list, list) {
+		platform_of_node = component->dev->of_node;
+		if (!platform_of_node && component->dev->parent->of_node)
+			platform_of_node = component->dev->parent->of_node;
+
+		if (dai_link->platform_of_node) {
+			if (platform_of_node != dai_link->platform_of_node)
+				continue;
+		} else {
+			if (strcmp(component->name, platform_name))
+				continue;
+		}
+
+		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)
@@ -1184,27 +1257,15 @@ static void soc_remove_link_dais(struct snd_soc_card *card,
 static void soc_remove_link_components(struct snd_soc_card *card,
 	struct snd_soc_pcm_runtime *rtd, int order)
 {
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
-	int i;
+	struct snd_soc_rtdcom_list *rtdcom;
 
-	/* remove the platform */
-	if (platform && platform->component.driver->remove_order == order)
-		soc_remove_component(&platform->component);
+	for_each_rtdcom(rtd, rtdcom) {
+		component = rtdcom->component;
 
-	/* remove the CODEC-side CODEC */
-	for (i = 0; i < rtd->num_codecs; i++) {
-		component = rtd->codec_dais[i]->component;
 		if (component->driver->remove_order == order)
 			soc_remove_component(component);
 	}
-
-	/* remove any CPU-side CODEC */
-	if (cpu_dai) {
-		if (cpu_dai->component->driver->remove_order == order)
-			soc_remove_component(cpu_dai->component);
-	}
 }
 
 static void soc_remove_dai_links(struct snd_soc_card *card)
@@ -1451,9 +1512,10 @@ static int soc_probe_component(struct snd_soc_card *card,
 
 	soc_init_component_debugfs(component);
 
-	if (component->dapm_widgets) {
-		ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets,
-			component->num_dapm_widgets);
+	if (component->driver->dapm_widgets) {
+		ret = snd_soc_dapm_new_controls(dapm,
+					component->driver->dapm_widgets,
+					component->driver->num_dapm_widgets);
 
 		if (ret != 0) {
 			dev_err(component->dev,
@@ -1495,12 +1557,14 @@ static int soc_probe_component(struct snd_soc_card *card,
 		}
 	}
 
-	if (component->controls)
-		snd_soc_add_component_controls(component, component->controls,
-				     component->num_controls);
-	if (component->dapm_routes)
-		snd_soc_dapm_add_routes(dapm, component->dapm_routes,
-					component->num_dapm_routes);
+	if (component->driver->controls)
+		snd_soc_add_component_controls(component,
+					       component->driver->controls,
+					       component->driver->num_controls);
+	if (component->driver->dapm_routes)
+		snd_soc_dapm_add_routes(dapm,
+					component->driver->dapm_routes,
+					component->driver->num_dapm_routes);
 
 	list_add(&dapm->list, &card->dapm_list);
 	list_add(&component->card_list, &card->component_dev_list);
@@ -1556,21 +1620,13 @@ static int soc_probe_link_components(struct snd_soc_card *card,
 			struct snd_soc_pcm_runtime *rtd,
 				     int order)
 {
-	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
-	int i, ret;
+	struct snd_soc_rtdcom_list *rtdcom;
+	int ret;
 
-	/* probe the CPU-side component, if it is a CODEC */
-	component = rtd->cpu_dai->component;
-	if (component->driver->probe_order == order) {
-		ret = soc_probe_component(card, component);
-		if (ret < 0)
-			return ret;
-	}
+	for_each_rtdcom(rtd, rtdcom) {
+		component = rtdcom->component;
 
-	/* probe the CODEC-side components */
-	for (i = 0; i < rtd->num_codecs; i++) {
-		component = rtd->codec_dais[i]->component;
 		if (component->driver->probe_order == order) {
 			ret = soc_probe_component(card, component);
 			if (ret < 0)
@@ -1578,13 +1634,6 @@ static int soc_probe_link_components(struct snd_soc_card *card,
 		}
 	}
 
-	/* probe the platform */
-	if (platform->component.driver->probe_order == order) {
-		ret = soc_probe_component(card, &platform->component);
-		if (ret < 0)
-			return ret;
-	}
-
 	return 0;
 }
 
@@ -2587,11 +2636,9 @@ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 {
 	if (dai->driver && dai->driver->ops->set_sysclk)
 		return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
-	else if (dai->codec && dai->codec->driver->set_sysclk)
-		return dai->codec->driver->set_sysclk(dai->codec, clk_id, 0,
-						      freq, dir);
-	else
-		return -ENOTSUPP;
+
+	return snd_soc_component_set_sysclk(dai->component, clk_id, 0,
+					    freq, dir);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
 
@@ -2617,6 +2664,32 @@ int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 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
+ * @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_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);
+
+	return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk);
+
+/**
  * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
  * @dai: DAI
  * @div_id: DAI specific clock divider ID
@@ -2652,11 +2725,9 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
 	if (dai->driver && dai->driver->ops->set_pll)
 		return dai->driver->ops->set_pll(dai, pll_id, source,
 					 freq_in, freq_out);
-	else if (dai->codec && dai->codec->driver->set_pll)
-		return dai->codec->driver->set_pll(dai->codec, pll_id, source,
-						   freq_in, freq_out);
-	else
-		return -EINVAL;
+
+	return snd_soc_component_set_pll(dai->component, pll_id, source,
+					 freq_in, freq_out);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
 
@@ -2681,6 +2752,33 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
 }
 EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll);
 
+/*
+ * snd_soc_component_set_pll - configure component PLL.
+ * @component: COMPONENT
+ * @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_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);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_set_pll);
+
 /**
  * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
  * @dai: DAI
@@ -3171,10 +3269,11 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
 	component->remove = component->driver->remove;
 	component->suspend = component->driver->suspend;
 	component->resume = component->driver->resume;
-	component->pcm_new = component->driver->pcm_new;
-	component->pcm_free = component->driver->pcm_free;
+	component->set_sysclk = component->driver->set_sysclk;
+	component->set_pll = component->driver->set_pll;
+	component->set_jack = component->driver->set_jack;
 
-	dapm = &component->dapm;
+	dapm = snd_soc_component_get_dapm(component);
 	dapm->dev = dev;
 	dapm->component = component;
 	dapm->bias_level = SND_SOC_BIAS_OFF;
@@ -3184,13 +3283,6 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
 	if (driver->stream_event)
 		dapm->stream_event = snd_soc_component_stream_event;
 
-	component->controls = driver->controls;
-	component->num_controls = driver->num_controls;
-	component->dapm_widgets = driver->dapm_widgets;
-	component->num_dapm_widgets = driver->num_dapm_widgets;
-	component->dapm_routes = driver->dapm_routes;
-	component->num_dapm_routes = driver->num_dapm_routes;
-
 	INIT_LIST_HEAD(&component->dai_list);
 	mutex_init(&component->io_mutex);
 
@@ -3282,67 +3374,79 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component)
 }
 
 int snd_soc_register_component(struct device *dev,
-			       const struct snd_soc_component_driver *cmpnt_drv,
+			       const struct snd_soc_component_driver *component_driver,
 			       struct snd_soc_dai_driver *dai_drv,
 			       int num_dai)
 {
-	struct snd_soc_component *cmpnt;
+	struct snd_soc_component *component;
 	int ret;
 
-	cmpnt = kzalloc(sizeof(*cmpnt), GFP_KERNEL);
-	if (!cmpnt) {
+	component = kzalloc(sizeof(*component), GFP_KERNEL);
+	if (!component) {
 		dev_err(dev, "ASoC: Failed to allocate memory\n");
 		return -ENOMEM;
 	}
 
-	ret = snd_soc_component_initialize(cmpnt, cmpnt_drv, dev);
+	ret = snd_soc_component_initialize(component, component_driver, dev);
 	if (ret)
 		goto err_free;
 
-	cmpnt->ignore_pmdown_time = true;
-	cmpnt->registered_as_component = true;
+	component->ignore_pmdown_time = true;
+	component->registered_as_component = true;
 
-	ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai, true);
+	ret = snd_soc_register_dais(component, dai_drv, num_dai, true);
 	if (ret < 0) {
 		dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);
 		goto err_cleanup;
 	}
 
-	snd_soc_component_add(cmpnt);
+	snd_soc_component_add(component);
 
 	return 0;
 
 err_cleanup:
-	snd_soc_component_cleanup(cmpnt);
+	snd_soc_component_cleanup(component);
 err_free:
-	kfree(cmpnt);
+	kfree(component);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_register_component);
 
 /**
- * snd_soc_unregister_component - Unregister a component from the ASoC core
+ * snd_soc_unregister_component - Unregister all related component
+ * from the ASoC core
  *
  * @dev: The device to unregister
  */
-void snd_soc_unregister_component(struct device *dev)
+static int __snd_soc_unregister_component(struct device *dev)
 {
-	struct snd_soc_component *cmpnt;
+	struct snd_soc_component *component;
+	int found = 0;
 
 	mutex_lock(&client_mutex);
-	list_for_each_entry(cmpnt, &component_list, list) {
-		if (dev == cmpnt->dev && cmpnt->registered_as_component)
-			goto found;
+	list_for_each_entry(component, &component_list, list) {
+		if (dev != component->dev ||
+		    !component->registered_as_component)
+			continue;
+
+		snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
+		snd_soc_component_del_unlocked(component);
+		found = 1;
+		break;
 	}
 	mutex_unlock(&client_mutex);
-	return;
 
-found:
-	snd_soc_tplg_component_remove(cmpnt, SND_SOC_TPLG_INDEX_ALL);
-	snd_soc_component_del_unlocked(cmpnt);
-	mutex_unlock(&client_mutex);
-	snd_soc_component_cleanup(cmpnt);
-	kfree(cmpnt);
+	if (found) {
+		snd_soc_component_cleanup(component);
+		kfree(component);
+	}
+
+	return found;
+}
+
+void snd_soc_unregister_component(struct device *dev)
+{
+	while (__snd_soc_unregister_component(dev));
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
 
@@ -3360,25 +3464,6 @@ static void snd_soc_platform_drv_remove(struct snd_soc_component *component)
 	platform->driver->remove(platform);
 }
 
-static int snd_soc_platform_drv_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_platform *platform = rtd->platform;
-
-	if (platform->driver->pcm_new)
-		return platform->driver->pcm_new(rtd);
-	else
-		return 0;
-}
-
-static void snd_soc_platform_drv_pcm_free(struct snd_pcm *pcm)
-{
-	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
-
-	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
@@ -3402,10 +3487,6 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
 		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";
@@ -3582,6 +3663,31 @@ static int snd_soc_codec_drv_read(struct snd_soc_component *component,
 	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)
 {
@@ -3633,6 +3739,12 @@ int snd_soc_register_codec(struct device *dev,
 		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);
@@ -4113,6 +4225,8 @@ int snd_soc_get_dai_id(struct device_node *ep)
 	}
 	mutex_unlock(&client_mutex);
 
+	of_node_put(node);
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_get_dai_id);
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 7daf21fee355..99902ae1a2d9 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -22,6 +22,12 @@
 #include <linux/suspend.h>
 #include <trace/events/asoc.h>
 
+struct jack_gpio_tbl {
+	int count;
+	struct snd_soc_jack *jack;
+	struct snd_soc_jack_gpio *gpios;
+};
+
 /**
  * snd_soc_codec_set_jack - configure codec jack.
  * @codec: CODEC
@@ -36,11 +42,33 @@ int snd_soc_codec_set_jack(struct snd_soc_codec *codec,
 	if (codec->driver->set_jack)
 		return codec->driver->set_jack(codec, jack, data);
 	else
-		return -EINVAL;
+		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
+ * @data: can be used if codec driver need extra data for configuring jack
+ *
+ * Configures and enables jack detection function.
+ */
+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);
+
+	return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_set_jack);
+
+/**
  * snd_soc_card_jack_new - Create a new jack
  * @card:  ASoC card
  * @id:    an identifying string for this jack
@@ -333,6 +361,28 @@ static int snd_soc_jack_pm_notifier(struct notifier_block *nb,
 	return NOTIFY_DONE;
 }
 
+static void jack_free_gpios(struct snd_soc_jack *jack, int count,
+			    struct snd_soc_jack_gpio *gpios)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		gpiod_unexport(gpios[i].desc);
+		unregister_pm_notifier(&gpios[i].pm_notifier);
+		free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]);
+		cancel_delayed_work_sync(&gpios[i].work);
+		gpiod_put(gpios[i].desc);
+		gpios[i].jack = NULL;
+	}
+}
+
+static void jack_devres_free_gpios(struct device *dev, void *res)
+{
+	struct jack_gpio_tbl *tbl = res;
+
+	jack_free_gpios(tbl->jack, tbl->count, tbl->gpios);
+}
+
 /**
  * snd_soc_jack_add_gpios - Associate GPIO pins with an ASoC jack
  *
@@ -347,6 +397,14 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
 			struct snd_soc_jack_gpio *gpios)
 {
 	int i, ret;
+	struct jack_gpio_tbl *tbl;
+
+	tbl = devres_alloc(jack_devres_free_gpios, sizeof(*tbl), GFP_KERNEL);
+	if (!tbl)
+		return -ENOMEM;
+	tbl->jack = jack;
+	tbl->count = count;
+	tbl->gpios = gpios;
 
 	for (i = 0; i < count; i++) {
 		if (!gpios[i].name) {
@@ -424,12 +482,14 @@ got_gpio:
 				      msecs_to_jiffies(gpios[i].debounce_time));
 	}
 
+	devres_add(jack->card->dev, tbl);
 	return 0;
 
 err:
 	gpio_free(gpios[i].gpio);
 undo:
-	snd_soc_jack_free_gpios(jack, i, gpios);
+	jack_free_gpios(jack, i, gpios);
+	devres_free(tbl);
 
 	return ret;
 }
@@ -471,16 +531,8 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpiods);
 void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
 			struct snd_soc_jack_gpio *gpios)
 {
-	int i;
-
-	for (i = 0; i < count; i++) {
-		gpiod_unexport(gpios[i].desc);
-		unregister_pm_notifier(&gpios[i].pm_notifier);
-		free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]);
-		cancel_delayed_work_sync(&gpios[i].work);
-		gpiod_put(gpios[i].desc);
-		gpios[i].jack = NULL;
-	}
+	jack_free_gpios(jack, count, gpios);
+	devres_destroy(jack->card->dev, jack_devres_free_gpios, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(snd_soc_jack_free_gpios);
 #endif	/* CONFIG_GPIOLIB */
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index dcc5ece08668..94b88b897c3b 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -181,6 +181,10 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
 		dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
 				be->dai_link->name, event, dir);
 
+		if ((event == SND_SOC_DAPM_STREAM_STOP) &&
+		    (be->dpcm[dir].users >= 1))
+			continue;
+
 		snd_soc_dapm_stream_event(be, dir, event);
 	}
 
@@ -450,6 +454,8 @@ 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;
 	struct snd_soc_dai *codec_dai;
 	const char *codec_dai_name = "multicodec";
@@ -458,10 +464,12 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 	pinctrl_pm_select_default_state(cpu_dai->dev);
 	for (i = 0; i < rtd->num_codecs; i++)
 		pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev);
-	pm_runtime_get_sync(cpu_dai->dev);
-	for (i = 0; i < rtd->num_codecs; i++)
-		pm_runtime_get_sync(rtd->codec_dais[i]->dev);
-	pm_runtime_get_sync(platform->dev);
+
+	for_each_rtdcom(rtd, rtdcom) {
+		component = rtdcom->component;
+
+		pm_runtime_get_sync(component->dev);
+	}
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
@@ -599,15 +607,13 @@ platform_err:
 out:
 	mutex_unlock(&rtd->pcm_mutex);
 
-	pm_runtime_mark_last_busy(platform->dev);
-	pm_runtime_put_autosuspend(platform->dev);
-	for (i = 0; i < rtd->num_codecs; i++) {
-		pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev);
-		pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev);
+	for_each_rtdcom(rtd, rtdcom) {
+		component = rtdcom->component;
+
+		pm_runtime_mark_last_busy(component->dev);
+		pm_runtime_put_autosuspend(component->dev);
 	}
 
-	pm_runtime_mark_last_busy(cpu_dai->dev);
-	pm_runtime_put_autosuspend(cpu_dai->dev);
 	for (i = 0; i < rtd->num_codecs; i++) {
 		if (!rtd->codec_dais[i]->active)
 			pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
@@ -655,6 +661,8 @@ 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;
 	struct snd_soc_dai *codec_dai;
 	int i;
@@ -711,17 +719,13 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
 
 	mutex_unlock(&rtd->pcm_mutex);
 
-	pm_runtime_mark_last_busy(platform->dev);
-	pm_runtime_put_autosuspend(platform->dev);
+	for_each_rtdcom(rtd, rtdcom) {
+		component = rtdcom->component;
 
-	for (i = 0; i < rtd->num_codecs; i++) {
-		pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev);
-		pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev);
+		pm_runtime_mark_last_busy(component->dev);
+		pm_runtime_put_autosuspend(component->dev);
 	}
 
-	pm_runtime_mark_last_busy(cpu_dai->dev);
-	pm_runtime_put_autosuspend(cpu_dai->dev);
-
 	for (i = 0; i < rtd->num_codecs; i++) {
 		if (!rtd->codec_dais[i]->active)
 			pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
@@ -2628,25 +2632,12 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
 	return ret;
 }
 
-static void soc_pcm_free(struct snd_pcm *pcm)
-{
-	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
-	struct snd_soc_component *component;
-
-	list_for_each_entry(component, &rtd->card->component_dev_list,
-			    card_list) {
-		if (component->pcm_free)
-			component->pcm_free(pcm);
-	}
-}
-
 /* 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;
 	struct snd_pcm *pcm;
 	char new_name[64];
 	int ret = 0, playback = 0, capture = 0;
@@ -2756,18 +2747,17 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 	if (capture)
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
 
-	list_for_each_entry(component, &rtd->card->component_dev_list, card_list) {
-		if (component->pcm_new) {
-			ret = component->pcm_new(rtd);
-			if (ret < 0) {
-				dev_err(component->dev,
-					"ASoC: pcm constructor failed: %d\n",
-					ret);
-				return ret;
-			}
+	if (platform->driver->pcm_new) {
+		ret = platform->driver->pcm_new(rtd);
+		if (ret < 0) {
+			dev_err(platform->dev,
+				"ASoC: pcm constructor failed: %d\n",
+				ret);
+			return ret;
 		}
 	}
-	pcm->private_free = soc_pcm_free;
+
+	pcm->private_free = platform->driver->pcm_free;
 out:
 	dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
 		 (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
@@ -3010,8 +3000,7 @@ void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
 		return;
 	}
 
-	rtd->debugfs_dpcm_state = debugfs_create_file("state", 0444,
-						rtd->debugfs_dpcm_root,
-						rtd, &dpcm_state_fops);
+	debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
+			    rtd, &dpcm_state_fops);
 }
 #endif
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index 0509902512cc..00383155d5f8 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -124,18 +124,6 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static int tegra_alc5632_card_remove(struct snd_soc_card *card)
-{
-	struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card);
-
-	if (gpio_is_valid(machine->gpio_hp_det)) {
-		snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, 1,
-					&tegra_alc5632_hp_jack_gpio);
-	}
-
-	return 0;
-}
-
 static struct snd_soc_dai_link tegra_alc5632_dai = {
 	.name = "ALC5632",
 	.stream_name = "ALC5632 PCM",
@@ -150,7 +138,6 @@ static struct snd_soc_dai_link tegra_alc5632_dai = {
 static struct snd_soc_card snd_soc_tegra_alc5632 = {
 	.name = "tegra-alc5632",
 	.owner = THIS_MODULE,
-	.remove = tegra_alc5632_card_remove,
 	.dai_link = &tegra_alc5632_dai,
 	.num_links = 1,
 	.controls = tegra_alc5632_controls,
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c
index c34a54d6e812..955067adf2d9 100644
--- a/sound/soc/tegra/tegra_max98090.c
+++ b/sound/soc/tegra/tegra_max98090.c
@@ -176,23 +176,6 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static int tegra_max98090_card_remove(struct snd_soc_card *card)
-{
-	struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
-
-	if (gpio_is_valid(machine->gpio_hp_det)) {
-		snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1,
-					&tegra_max98090_hp_jack_gpio);
-	}
-
-	if (gpio_is_valid(machine->gpio_mic_det)) {
-		snd_soc_jack_free_gpios(&tegra_max98090_mic_jack, 1,
-					&tegra_max98090_mic_jack_gpio);
-	}
-
-	return 0;
-}
-
 static struct snd_soc_dai_link tegra_max98090_dai = {
 	.name = "max98090",
 	.stream_name = "max98090 PCM",
@@ -206,7 +189,6 @@ static struct snd_soc_dai_link tegra_max98090_dai = {
 static struct snd_soc_card snd_soc_tegra_max98090 = {
 	.name = "tegra-max98090",
 	.owner = THIS_MODULE,
-	.remove = tegra_max98090_card_remove,
 	.dai_link = &tegra_max98090_dai,
 	.num_links = 1,
 	.controls = tegra_max98090_controls,
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
index 93a356802345..76ed6042d84d 100644
--- a/sound/soc/tegra/tegra_rt5640.c
+++ b/sound/soc/tegra/tegra_rt5640.c
@@ -126,18 +126,6 @@ static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static int tegra_rt5640_card_remove(struct snd_soc_card *card)
-{
-	struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
-
-	if (gpio_is_valid(machine->gpio_hp_det)) {
-		snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack, 1,
-					&tegra_rt5640_hp_jack_gpio);
-	}
-
-	return 0;
-}
-
 static struct snd_soc_dai_link tegra_rt5640_dai = {
 	.name = "RT5640",
 	.stream_name = "RT5640 PCM",
@@ -151,7 +139,6 @@ static struct snd_soc_dai_link tegra_rt5640_dai = {
 static struct snd_soc_card snd_soc_tegra_rt5640 = {
 	.name = "tegra-rt5640",
 	.owner = THIS_MODULE,
-	.remove = tegra_rt5640_card_remove,
 	.dai_link = &tegra_rt5640_dai,
 	.num_links = 1,
 	.controls = tegra_rt5640_controls,
diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c
index ebf58d0e0f10..dc5a295d61e5 100644
--- a/sound/soc/tegra/tegra_rt5677.c
+++ b/sound/soc/tegra/tegra_rt5677.c
@@ -169,23 +169,6 @@ static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static int tegra_rt5677_card_remove(struct snd_soc_card *card)
-{
-	struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card);
-
-	if (gpio_is_valid(machine->gpio_hp_det)) {
-		snd_soc_jack_free_gpios(&tegra_rt5677_hp_jack, 1,
-				&tegra_rt5677_hp_jack_gpio);
-	}
-
-	if (gpio_is_valid(machine->gpio_mic_present)) {
-		snd_soc_jack_free_gpios(&tegra_rt5677_mic_jack, 1,
-				&tegra_rt5677_mic_jack_gpio);
-	}
-
-	return 0;
-}
-
 static struct snd_soc_dai_link tegra_rt5677_dai = {
 	.name = "RT5677",
 	.stream_name = "RT5677 PCM",
@@ -199,7 +182,6 @@ static struct snd_soc_dai_link tegra_rt5677_dai = {
 static struct snd_soc_card snd_soc_tegra_rt5677 = {
 	.name = "tegra-rt5677",
 	.owner = THIS_MODULE,
-	.remove = tegra_rt5677_card_remove,
 	.dai_link = &tegra_rt5677_dai,
 	.num_links = 1,
 	.controls = tegra_rt5677_controls,
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index dbfb49298ae8..05f95944669a 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -203,12 +203,6 @@ static int tegra_wm8903_remove(struct snd_soc_card *card)
 		snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_codec *codec = codec_dai->codec;
-	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-
-	if (gpio_is_valid(machine->gpio_hp_det)) {
-		snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 1,
-					&tegra_wm8903_hp_jack_gpio);
-	}
 
 	wm8903_mic_detect(codec, NULL, 0, 0);
 
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index b50f68a439ce..ba9fc099cf67 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -33,6 +33,7 @@ static struct snd_soc_dai_link mop500_dai_links[] = {
 		.stream_name = "ab8500_0",
 		.cpu_dai_name = "ux500-msp-i2s.1",
 		.codec_dai_name = "ab8500-codec-dai.0",
+		.platform_name = "ux500-msp-i2s.1",
 		.codec_name = "ab8500-codec.0",
 		.init = mop500_ab8500_machine_init,
 		.ops = mop500_ab8500_ops,
@@ -42,6 +43,7 @@ static struct snd_soc_dai_link mop500_dai_links[] = {
 		.stream_name = "ab8500_1",
 		.cpu_dai_name = "ux500-msp-i2s.3",
 		.codec_dai_name = "ab8500-codec-dai.1",
+		.platform_name = "ux500-msp-i2s.3",
 		.codec_name = "ab8500-codec.0",
 		.init = NULL,
 		.ops = mop500_ab8500_ops,
@@ -85,6 +87,8 @@ static int mop500_of_probe(struct platform_device *pdev,
 	for (i = 0; i < 2; i++) {
 		mop500_dai_links[i].cpu_of_node = msp_np[i];
 		mop500_dai_links[i].cpu_dai_name = NULL;
+		mop500_dai_links[i].platform_of_node = msp_np[i];
+		mop500_dai_links[i].platform_name = NULL;
 		mop500_dai_links[i].codec_of_node = codec_np;
 		mop500_dai_links[i].codec_name = NULL;
 	}
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 082736c539bc..e630813c5008 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -542,6 +542,8 @@ int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 
 	if (size < sizeof(scale))
 		return -ENOMEM;
+	if (cval->min_mute)
+		scale[0] = SNDRV_CTL_TLVT_DB_MINMAX_MUTE;
 	scale[2] = cval->dBmin;
 	scale[3] = cval->dBmax;
 	if (copy_to_user(_tlv, scale, sizeof(scale)))
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 3417ef347e40..2b4b067646ab 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -64,6 +64,7 @@ struct usb_mixer_elem_info {
 	int cached;
 	int cache_val[MAX_CHANNELS];
 	u8 initialized;
+	u8 min_mute;
 	void *private_data;
 };
 
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index e3d1dec48ee4..e1e7ce9ab217 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -1878,6 +1878,12 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
 		if (unitid == 7 && cval->control == UAC_FU_VOLUME)
 			snd_dragonfly_quirk_db_scale(mixer, cval, kctl);
 		break;
+	/* lowest playback value is muted on C-Media devices */
+	case USB_ID(0x0d8c, 0x000c):
+	case USB_ID(0x0d8c, 0x0014):
+		if (strstr(kctl->id.name, "Playback"))
+			cval->min_mute = 1;
+		break;
 	}
 }
 
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index d7b0b0a3a2db..5d2a63248b1d 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1142,6 +1142,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
 	case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */
 	case USB_ID(0x05A3, 0x9420): /* ELP HD USB Camera */
 	case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
+	case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */
 	case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
 	case USB_ID(0x1de7, 0x0013): /* Phoenix Audio MT202exe */
 	case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */
@@ -1308,10 +1309,13 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
 	    && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
 		mdelay(20);
 
-	/* Zoom R16/24 needs a tiny delay here, otherwise requests like
-	 * get/set frequency return as failed despite actually succeeding.
+	/* Zoom R16/24, Logitech H650e, Jabra 550a needs a tiny delay here,
+	 * otherwise requests like get/set frequency return as failed despite
+	 * actually succeeding.
 	 */
-	if (chip->usb_id == USB_ID(0x1686, 0x00dd) &&
+	if ((chip->usb_id == USB_ID(0x1686, 0x00dd) ||
+	     chip->usb_id == USB_ID(0x046d, 0x0a46) ||
+	     chip->usb_id == USB_ID(0x0b0e, 0x0349)) &&
 	    (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
 		mdelay(1);
 }
@@ -1374,6 +1378,10 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
 			}
 		}
 		break;
+	case USB_ID(0x16d0, 0x0a23):
+		if (fp->altsetting == 2)
+			return SNDRV_PCM_FMTBIT_DSD_U32_BE;
+		break;
 
 	default:
 		break;