summary refs log tree commit diff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/core/rawmidi.c4
-rw-r--r--sound/core/timer.c34
-rw-r--r--sound/firewire/fireworks/fireworks.h1
-rw-r--r--sound/firewire/fireworks/fireworks_hwdep.c71
-rw-r--r--sound/firewire/fireworks/fireworks_proc.c4
-rw-r--r--sound/firewire/fireworks/fireworks_transaction.c5
-rw-r--r--sound/firewire/tascam/tascam-hwdep.c33
-rw-r--r--sound/hda/ext/hdac_ext_controller.c91
-rw-r--r--sound/hda/ext/hdac_ext_stream.c46
-rw-r--r--sound/hda/hdac_controller.c75
-rw-r--r--sound/pci/hda/hda_controller.c203
-rw-r--r--sound/pci/hda/hda_controller.h3
-rw-r--r--sound/pci/hda/hda_intel.c49
-rw-r--r--sound/pci/hda/patch_realtek.c22
-rw-r--r--sound/soc/amd/acp-pcm-dma.c2
-rw-r--r--sound/soc/atmel/atmel-classd.c6
-rw-r--r--sound/soc/atmel/atmel-pcm-pdc.c2
-rw-r--r--sound/soc/atmel/atmel-pdmic.c20
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c5
-rw-r--r--sound/soc/codecs/88pm860x-codec.c14
-rw-r--r--sound/soc/codecs/Kconfig18
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/ab8500-codec.c24
-rw-r--r--sound/soc/codecs/ac97.c10
-rw-r--r--sound/soc/codecs/ad1836.c14
-rw-r--r--sound/soc/codecs/ad193x.c14
-rw-r--r--sound/soc/codecs/ad1980.c14
-rw-r--r--sound/soc/codecs/ad73311.c10
-rw-r--r--sound/soc/codecs/adau1373.c14
-rw-r--r--sound/soc/codecs/adau1701.c15
-rw-r--r--sound/soc/codecs/adau1761.c14
-rw-r--r--sound/soc/codecs/adau1781.c14
-rw-r--r--sound/soc/codecs/adau1977.c14
-rw-r--r--sound/soc/codecs/adau7002.c10
-rw-r--r--sound/soc/codecs/adav80x.c14
-rw-r--r--sound/soc/codecs/ads117x.c10
-rw-r--r--sound/soc/codecs/ak4104.c15
-rw-r--r--sound/soc/codecs/ak4535.c14
-rw-r--r--sound/soc/codecs/ak4554.c10
-rw-r--r--sound/soc/codecs/ak4613.c14
-rw-r--r--sound/soc/codecs/ak4641.c14
-rw-r--r--sound/soc/codecs/ak4642.c14
-rw-r--r--sound/soc/codecs/ak4671.c14
-rw-r--r--sound/soc/codecs/ak5386.c10
-rw-r--r--sound/soc/codecs/alc5632.c14
-rw-r--r--sound/soc/codecs/arizona.c78
-rw-r--r--sound/soc/codecs/arizona.h17
-rw-r--r--sound/soc/codecs/bt-sco.c10
-rw-r--r--sound/soc/codecs/cq93vc.c6
-rw-r--r--sound/soc/codecs/cs35l32.c15
-rw-r--r--sound/soc/codecs/cs35l33.c15
-rw-r--r--sound/soc/codecs/cs4265.c15
-rw-r--r--sound/soc/codecs/cs4270.c14
-rw-r--r--sound/soc/codecs/cs4271.c14
-rw-r--r--sound/soc/codecs/cs42l51.c14
-rw-r--r--sound/soc/codecs/cs42l52.c15
-rw-r--r--sound/soc/codecs/cs42l56.c15
-rw-r--r--sound/soc/codecs/cs42l73.c19
-rw-r--r--sound/soc/codecs/cs42xx8.c14
-rw-r--r--sound/soc/codecs/cs4349.c15
-rw-r--r--sound/soc/codecs/cs47l24.c26
-rw-r--r--sound/soc/codecs/cs53l30.c23
-rw-r--r--sound/soc/codecs/cx20442.c10
-rw-r--r--sound/soc/codecs/da7210.c15
-rw-r--r--sound/soc/codecs/da7213.c149
-rw-r--r--sound/soc/codecs/da7213.h12
-rw-r--r--sound/soc/codecs/da7218.c49
-rw-r--r--sound/soc/codecs/da7218.h2
-rw-r--r--sound/soc/codecs/da7219-aad.c108
-rw-r--r--sound/soc/codecs/da7219-aad.h11
-rw-r--r--sound/soc/codecs/da7219.c95
-rw-r--r--sound/soc/codecs/da7219.h8
-rw-r--r--sound/soc/codecs/da732x.c14
-rw-r--r--sound/soc/codecs/da9055.c15
-rw-r--r--sound/soc/codecs/dmic.c10
-rw-r--r--sound/soc/codecs/es8328.c14
-rw-r--r--sound/soc/codecs/gtm601.c10
-rw-r--r--sound/soc/codecs/hdac_hdmi.c2
-rw-r--r--sound/soc/codecs/hdmi-codec.c79
-rw-r--r--sound/soc/codecs/inno_rk3036.c14
-rw-r--r--sound/soc/codecs/isabelle.c14
-rw-r--r--sound/soc/codecs/jz4740.c14
-rw-r--r--sound/soc/codecs/l3.c71
-rw-r--r--sound/soc/codecs/lm49453.c14
-rw-r--r--sound/soc/codecs/max98088.c14
-rw-r--r--sound/soc/codecs/max98095.c14
-rw-r--r--sound/soc/codecs/max98357a.c10
-rw-r--r--sound/soc/codecs/max98371.c2
-rw-r--r--sound/soc/codecs/max9850.c14
-rw-r--r--sound/soc/codecs/max9860.c14
-rw-r--r--sound/soc/codecs/max9867.c19
-rw-r--r--sound/soc/codecs/max98925.c14
-rw-r--r--sound/soc/codecs/max98926.c20
-rw-r--r--sound/soc/codecs/mc13783.c14
-rw-r--r--sound/soc/codecs/ml26124.c14
-rw-r--r--sound/soc/codecs/nau8810.c884
-rw-r--r--sound/soc/codecs/nau8810.h281
-rw-r--r--sound/soc/codecs/nau8825.c94
-rw-r--r--sound/soc/codecs/pcm1681.c14
-rw-r--r--sound/soc/codecs/pcm179x.c14
-rw-r--r--sound/soc/codecs/pcm3008.c10
-rw-r--r--sound/soc/codecs/pcm3168a.c14
-rw-r--r--sound/soc/codecs/pcm512x.c14
-rw-r--r--sound/soc/codecs/rt286.c14
-rw-r--r--sound/soc/codecs/rt298.c14
-rw-r--r--sound/soc/codecs/rt5514-spi.c2
-rw-r--r--sound/soc/codecs/rt5514.c20
-rw-r--r--sound/soc/codecs/rt5514.h4
-rw-r--r--sound/soc/codecs/rt5616.c23
-rw-r--r--sound/soc/codecs/rt5631.c14
-rw-r--r--sound/soc/codecs/rt5640.c17
-rw-r--r--sound/soc/codecs/rt5640.h1
-rw-r--r--sound/soc/codecs/rt5645.c14
-rw-r--r--sound/soc/codecs/rt5651.c14
-rw-r--r--sound/soc/codecs/rt5659.c41
-rw-r--r--sound/soc/codecs/rt5659.h7
-rw-r--r--sound/soc/codecs/rt5660.c1353
-rw-r--r--sound/soc/codecs/rt5660.h847
-rw-r--r--sound/soc/codecs/rt5663.c3218
-rw-r--r--sound/soc/codecs/rt5663.h1121
-rw-r--r--sound/soc/codecs/rt5670.c14
-rw-r--r--sound/soc/codecs/rt5677.c69
-rw-r--r--sound/soc/codecs/sgtl5000.c17
-rw-r--r--sound/soc/codecs/si476x.c10
-rw-r--r--sound/soc/codecs/sn95031.c14
-rw-r--r--sound/soc/codecs/spdif_receiver.c10
-rw-r--r--sound/soc/codecs/spdif_transmitter.c10
-rw-r--r--sound/soc/codecs/ssm2518.c14
-rw-r--r--sound/soc/codecs/ssm2602.c14
-rw-r--r--sound/soc/codecs/ssm4567.c14
-rw-r--r--sound/soc/codecs/sta32x.c14
-rw-r--r--sound/soc/codecs/sta350.c14
-rw-r--r--sound/soc/codecs/sta529.c6
-rw-r--r--sound/soc/codecs/stac9766.c14
-rw-r--r--sound/soc/codecs/sti-sas.c8
-rw-r--r--sound/soc/codecs/tas2552.c14
-rw-r--r--sound/soc/codecs/tas5086.c14
-rw-r--r--sound/soc/codecs/tas571x.c14
-rw-r--r--sound/soc/codecs/tas5720.c14
-rw-r--r--sound/soc/codecs/tfa9879.c15
-rw-r--r--sound/soc/codecs/tlv320aic23.c14
-rw-r--r--sound/soc/codecs/tlv320aic26.c14
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c218
-rw-r--r--sound/soc/codecs/tlv320aic31xx.h2
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c14
-rw-r--r--sound/soc/codecs/tlv320aic3x.c14
-rw-r--r--sound/soc/codecs/tlv320dac33.c31
-rw-r--r--sound/soc/codecs/tpa6130a2.c49
-rw-r--r--sound/soc/codecs/twl4030.c14
-rw-r--r--sound/soc/codecs/twl6040.c14
-rw-r--r--sound/soc/codecs/uda134x.c17
-rw-r--r--sound/soc/codecs/uda1380.c14
-rw-r--r--sound/soc/codecs/wl1273.c14
-rw-r--r--sound/soc/codecs/wm0010.c12
-rw-r--r--sound/soc/codecs/wm1250-ev1.c13
-rw-r--r--sound/soc/codecs/wm2000.c18
-rw-r--r--sound/soc/codecs/wm2200.c16
-rw-r--r--sound/soc/codecs/wm5100.c18
-rw-r--r--sound/soc/codecs/wm5102.c27
-rw-r--r--sound/soc/codecs/wm5110.c28
-rw-r--r--sound/soc/codecs/wm8350.c16
-rw-r--r--sound/soc/codecs/wm8400.c16
-rw-r--r--sound/soc/codecs/wm8510.c16
-rw-r--r--sound/soc/codecs/wm8523.c16
-rw-r--r--sound/soc/codecs/wm8580.c16
-rw-r--r--sound/soc/codecs/wm8711.c16
-rw-r--r--sound/soc/codecs/wm8727.c12
-rw-r--r--sound/soc/codecs/wm8728.c16
-rw-r--r--sound/soc/codecs/wm8731.c16
-rw-r--r--sound/soc/codecs/wm8737.c16
-rw-r--r--sound/soc/codecs/wm8741.c12
-rw-r--r--sound/soc/codecs/wm8750.c16
-rw-r--r--sound/soc/codecs/wm8753.c16
-rw-r--r--sound/soc/codecs/wm8770.c16
-rw-r--r--sound/soc/codecs/wm8776.c16
-rw-r--r--sound/soc/codecs/wm8782.c12
-rw-r--r--sound/soc/codecs/wm8804.c10
-rw-r--r--sound/soc/codecs/wm8900.c16
-rw-r--r--sound/soc/codecs/wm8903.c18
-rw-r--r--sound/soc/codecs/wm8904.c2
-rw-r--r--sound/soc/codecs/wm8940.c16
-rw-r--r--sound/soc/codecs/wm8955.c16
-rw-r--r--sound/soc/codecs/wm8960.c2
-rw-r--r--sound/soc/codecs/wm8961.c16
-rw-r--r--sound/soc/codecs/wm8962.c4
-rw-r--r--sound/soc/codecs/wm8971.c16
-rw-r--r--sound/soc/codecs/wm8974.c16
-rw-r--r--sound/soc/codecs/wm8978.c16
-rw-r--r--sound/soc/codecs/wm8983.c16
-rw-r--r--sound/soc/codecs/wm8985.c16
-rw-r--r--sound/soc/codecs/wm8988.c14
-rw-r--r--sound/soc/codecs/wm8990.c16
-rw-r--r--sound/soc/codecs/wm8991.c16
-rw-r--r--sound/soc/codecs/wm8993.c2
-rw-r--r--sound/soc/codecs/wm8994.c2
-rw-r--r--sound/soc/codecs/wm8995.c14
-rw-r--r--sound/soc/codecs/wm8996.c18
-rw-r--r--sound/soc/codecs/wm8997.c16
-rw-r--r--sound/soc/codecs/wm8998.c26
-rw-r--r--sound/soc/codecs/wm9081.c16
-rw-r--r--sound/soc/codecs/wm9090.c2
-rw-r--r--sound/soc/codecs/wm9705.c16
-rw-r--r--sound/soc/codecs/wm9712.c16
-rw-r--r--sound/soc/codecs/wm9713.c16
-rw-r--r--sound/soc/codecs/wm_adsp.c88
-rw-r--r--sound/soc/codecs/wm_adsp.h7
-rw-r--r--sound/soc/davinci/davinci-mcasp.c2
-rw-r--r--sound/soc/dwc/designware_i2s.c2
-rw-r--r--sound/soc/fsl/fsl_asrc.c12
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c2
-rw-r--r--sound/soc/fsl/fsl_esai.c8
-rw-r--r--sound/soc/fsl/fsl_sai.c6
-rw-r--r--sound/soc/fsl/fsl_spdif.c2
-rw-r--r--sound/soc/fsl/fsl_ssi.c2
-rw-r--r--sound/soc/generic/Kconfig8
-rw-r--r--sound/soc/generic/Makefile8
-rw-r--r--sound/soc/generic/simple-card-utils.c147
-rw-r--r--sound/soc/generic/simple-card.c305
-rw-r--r--sound/soc/generic/simple-scu-card.c345
-rw-r--r--sound/soc/img/pistachio-internal-dac.c14
-rw-r--r--sound/soc/intel/Kconfig12
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.c32
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.h6
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c2
-rw-r--r--sound/soc/intel/atom/sst/sst.c5
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c97
-rw-r--r--sound/soc/intel/atom/sst/sst_ipc.c3
-rw-r--r--sound/soc/intel/atom/sst/sst_pvt.c14
-rw-r--r--sound/soc/intel/boards/Makefile2
-rw-r--r--sound/soc/intel/boards/bdw-rt5677.c347
-rw-r--r--sound/soc/intel/boards/bxt_da7219_max98357a.c75
-rw-r--r--sound/soc/intel/boards/bxt_rt298.c14
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c507
-rw-r--r--sound/soc/intel/common/sst-acpi.c1
-rw-r--r--sound/soc/intel/haswell/sst-haswell-pcm.c2
-rw-r--r--sound/soc/intel/skylake/bxt-sst.c118
-rw-r--r--sound/soc/intel/skylake/skl-messages.c67
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c60
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.c4
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.h18
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c41
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.h12
-rw-r--r--sound/soc/intel/skylake/skl-sst-utils.c181
-rw-r--r--sound/soc/intel/skylake/skl-sst.c49
-rw-r--r--sound/soc/intel/skylake/skl-topology.c918
-rw-r--r--sound/soc/intel/skylake/skl-topology.h15
-rw-r--r--sound/soc/intel/skylake/skl-tplg-interface.h95
-rw-r--r--sound/soc/intel/skylake/skl.c10
-rw-r--r--sound/soc/intel/skylake/skl.h2
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c2
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.c5
-rw-r--r--sound/soc/omap/mcbsp.c3
-rw-r--r--sound/soc/omap/omap-abe-twl6040.c75
-rw-r--r--sound/soc/omap/omap-mcpdm.c22
-rw-r--r--sound/soc/omap/omap-pcm.c2
-rw-r--r--sound/soc/qcom/apq8016_sbc.c20
-rw-r--r--sound/soc/qcom/lpass-platform.c16
-rw-r--r--sound/soc/qcom/lpass.h2
-rw-r--r--sound/soc/rockchip/Kconfig12
-rw-r--r--sound/soc/rockchip/Makefile2
-rw-r--r--sound/soc/rockchip/rk3399_gru_sound.c397
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c10
-rw-r--r--sound/soc/rockchip/rockchip_spdif.c12
-rw-r--r--sound/soc/samsung/Kconfig57
-rw-r--r--sound/soc/samsung/ac97.c34
-rw-r--r--sound/soc/samsung/dma.h20
-rw-r--r--sound/soc/samsung/dmaengine.c31
-rw-r--r--sound/soc/samsung/i2s.c56
-rw-r--r--sound/soc/samsung/idma.c1
-rw-r--r--sound/soc/samsung/pcm.c26
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c3
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.h4
-rw-r--r--sound/soc/samsung/s3c2412-i2s.c24
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c24
-rw-r--r--sound/soc/samsung/s3c24xx_uda134x.c141
-rw-r--r--sound/soc/samsung/smdk_wm8580pcm.c1
-rw-r--r--sound/soc/samsung/smdk_wm8994pcm.c1
-rw-r--r--sound/soc/samsung/spdif.c12
-rw-r--r--sound/soc/sh/Kconfig6
-rw-r--r--sound/soc/sh/rcar/Makefile3
-rw-r--r--sound/soc/sh/rcar/core.c4
-rw-r--r--sound/soc/sh/rcar/rsrc-card.c486
-rw-r--r--sound/soc/sh/rcar/src.c6
-rw-r--r--sound/soc/sh/rcar/ssi.c2
-rw-r--r--sound/soc/soc-ac97.c2
-rw-r--r--sound/soc/soc-compress.c4
-rw-r--r--sound/soc/soc-core.c20
-rw-r--r--sound/soc/soc-dapm.c33
-rw-r--r--sound/soc/soc-ops.c2
-rw-r--r--sound/soc/soc-pcm.c13
-rw-r--r--sound/soc/soc-topology.c115
-rw-r--r--sound/soc/soc-utils.c2
-rw-r--r--sound/soc/sti/sti_uniperif.c130
-rw-r--r--sound/soc/sti/uniperif.h28
-rw-r--r--sound/soc/sti/uniperif_player.c83
-rw-r--r--sound/soc/sti/uniperif_reader.c46
-rw-r--r--sound/soc/sunxi/Kconfig1
-rw-r--r--sound/soc/sunxi/sun4i-codec.c60
-rw-r--r--sound/soc/sunxi/sun4i-spdif.c17
-rw-r--r--sound/soc/tegra/Kconfig11
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra_rt5640.c2
-rw-r--r--sound/soc/tegra/tegra_sgtl5000.c212
-rw-r--r--sound/usb/line6/pcm.c3
-rw-r--r--sound/usb/line6/pod.c12
-rw-r--r--sound/usb/quirks.c3
306 files changed, 14625 insertions, 3130 deletions
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 795437b10082..b450a27588c8 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -1633,11 +1633,13 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
 		return -EBUSY;
 	}
 	list_add_tail(&rmidi->list, &snd_rawmidi_devices);
+	mutex_unlock(&register_mutex);
 	err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
 				  rmidi->card, rmidi->device,
 				  &snd_rawmidi_f_ops, rmidi, &rmidi->dev);
 	if (err < 0) {
 		rmidi_err(rmidi, "unable to register\n");
+		mutex_lock(&register_mutex);
 		list_del(&rmidi->list);
 		mutex_unlock(&register_mutex);
 		return err;
@@ -1645,6 +1647,7 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
 	if (rmidi->ops && rmidi->ops->dev_register &&
 	    (err = rmidi->ops->dev_register(rmidi)) < 0) {
 		snd_unregister_device(&rmidi->dev);
+		mutex_lock(&register_mutex);
 		list_del(&rmidi->list);
 		mutex_unlock(&register_mutex);
 		return err;
@@ -1677,7 +1680,6 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
 		}
 	}
 #endif /* CONFIG_SND_OSSEMUL */
-	mutex_unlock(&register_mutex);
 	sprintf(name, "midi%d", rmidi->device);
 	entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root);
 	if (entry) {
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 9a6157ea6881..fc144f43faa6 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -35,6 +35,9 @@
 #include <sound/initval.h>
 #include <linux/kmod.h>
 
+/* internal flags */
+#define SNDRV_TIMER_IFLG_PAUSED		0x00010000
+
 #if IS_ENABLED(CONFIG_SND_HRTIMER)
 #define DEFAULT_TIMER_LIMIT 4
 #else
@@ -294,8 +297,21 @@ int snd_timer_open(struct snd_timer_instance **ti,
 		get_device(&timer->card->card_dev);
 	timeri->slave_class = tid->dev_sclass;
 	timeri->slave_id = slave_id;
-	if (list_empty(&timer->open_list_head) && timer->hw.open)
-		timer->hw.open(timer);
+
+	if (list_empty(&timer->open_list_head) && timer->hw.open) {
+		int err = timer->hw.open(timer);
+		if (err) {
+			kfree(timeri->owner);
+			kfree(timeri);
+
+			if (timer->card)
+				put_device(&timer->card->card_dev);
+			module_put(timer->module);
+			mutex_unlock(&register_mutex);
+			return err;
+		}
+	}
+
 	list_add_tail(&timeri->open_list, &timer->open_list_head);
 	snd_timer_check_master(timeri);
 	mutex_unlock(&register_mutex);
@@ -526,6 +542,10 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
 		}
 	}
 	timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START);
+	if (stop)
+		timeri->flags &= ~SNDRV_TIMER_IFLG_PAUSED;
+	else
+		timeri->flags |= SNDRV_TIMER_IFLG_PAUSED;
 	snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
 			  SNDRV_TIMER_EVENT_CONTINUE);
  unlock:
@@ -587,6 +607,10 @@ int snd_timer_stop(struct snd_timer_instance *timeri)
  */
 int snd_timer_continue(struct snd_timer_instance *timeri)
 {
+	/* timer can continue only after pause */
+	if (!(timeri->flags & SNDRV_TIMER_IFLG_PAUSED))
+		return -EINVAL;
+
 	if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
 		return snd_timer_start_slave(timeri, false);
 	else
@@ -813,6 +837,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
 	timer->tmr_subdevice = tid->subdevice;
 	if (id)
 		strlcpy(timer->id, id, sizeof(timer->id));
+	timer->sticks = 1;
 	INIT_LIST_HEAD(&timer->device_list);
 	INIT_LIST_HEAD(&timer->open_list_head);
 	INIT_LIST_HEAD(&timer->active_list_head);
@@ -1817,6 +1842,9 @@ static int snd_timer_user_continue(struct file *file)
 	tu = file->private_data;
 	if (!tu->timeri)
 		return -EBADFD;
+	/* start timer instead of continue if it's not used before */
+	if (!(tu->timeri->flags & SNDRV_TIMER_IFLG_PAUSED))
+		return snd_timer_user_start(file);
 	tu->timeri->lost = 0;
 	return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
 }
@@ -1958,6 +1986,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
 		tu->qused--;
 		spin_unlock_irq(&tu->qlock);
 
+		mutex_lock(&tu->ioctl_lock);
 		if (tu->tread) {
 			if (copy_to_user(buffer, &tu->tqueue[qhead],
 					 sizeof(struct snd_timer_tread)))
@@ -1967,6 +1996,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
 					 sizeof(struct snd_timer_read)))
 				err = -EFAULT;
 		}
+		mutex_unlock(&tu->ioctl_lock);
 
 		spin_lock_irq(&tu->qlock);
 		if (err < 0)
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h
index 03ed35237e2b..d73c12b8753d 100644
--- a/sound/firewire/fireworks/fireworks.h
+++ b/sound/firewire/fireworks/fireworks.h
@@ -108,7 +108,6 @@ struct snd_efw {
 	u8 *resp_buf;
 	u8 *pull_ptr;
 	u8 *push_ptr;
-	unsigned int resp_queues;
 };
 
 int snd_efw_transaction_cmd(struct fw_unit *unit,
diff --git a/sound/firewire/fireworks/fireworks_hwdep.c b/sound/firewire/fireworks/fireworks_hwdep.c
index 33df8655fe81..2e1d9a23920c 100644
--- a/sound/firewire/fireworks/fireworks_hwdep.c
+++ b/sound/firewire/fireworks/fireworks_hwdep.c
@@ -25,6 +25,7 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained,
 {
 	unsigned int length, till_end, type;
 	struct snd_efw_transaction *t;
+	u8 *pull_ptr;
 	long count = 0;
 
 	if (remained < sizeof(type) + sizeof(struct snd_efw_transaction))
@@ -38,8 +39,17 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained,
 	buf += sizeof(type);
 
 	/* write into buffer as many responses as possible */
-	while (efw->resp_queues > 0) {
-		t = (struct snd_efw_transaction *)(efw->pull_ptr);
+	spin_lock_irq(&efw->lock);
+
+	/*
+	 * When another task reaches here during this task's access to user
+	 * space, it picks up current position in buffer and can read the same
+	 * series of responses.
+	 */
+	pull_ptr = efw->pull_ptr;
+
+	while (efw->push_ptr != pull_ptr) {
+		t = (struct snd_efw_transaction *)(pull_ptr);
 		length = be32_to_cpu(t->length) * sizeof(__be32);
 
 		/* confirm enough space for this response */
@@ -49,26 +59,39 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained,
 		/* copy from ring buffer to user buffer */
 		while (length > 0) {
 			till_end = snd_efw_resp_buf_size -
-				(unsigned int)(efw->pull_ptr - efw->resp_buf);
+				(unsigned int)(pull_ptr - efw->resp_buf);
 			till_end = min_t(unsigned int, length, till_end);
 
-			if (copy_to_user(buf, efw->pull_ptr, till_end))
+			spin_unlock_irq(&efw->lock);
+
+			if (copy_to_user(buf, pull_ptr, till_end))
 				return -EFAULT;
 
-			efw->pull_ptr += till_end;
-			if (efw->pull_ptr >= efw->resp_buf +
-					     snd_efw_resp_buf_size)
-				efw->pull_ptr -= snd_efw_resp_buf_size;
+			spin_lock_irq(&efw->lock);
+
+			pull_ptr += till_end;
+			if (pull_ptr >= efw->resp_buf + snd_efw_resp_buf_size)
+				pull_ptr -= snd_efw_resp_buf_size;
 
 			length -= till_end;
 			buf += till_end;
 			count += till_end;
 			remained -= till_end;
 		}
-
-		efw->resp_queues--;
 	}
 
+	/*
+	 * All of tasks can read from the buffer nearly simultaneously, but the
+	 * last position for each task is different depending on the length of
+	 * given buffer. Here, for simplicity, a position of buffer is set by
+	 * the latest task. It's better for a listening application to allow one
+	 * thread to read from the buffer. Unless, each task can read different
+	 * sequence of responses depending on variation of buffer length.
+	 */
+	efw->pull_ptr = pull_ptr;
+
+	spin_unlock_irq(&efw->lock);
+
 	return count;
 }
 
@@ -76,14 +99,17 @@ static long
 hwdep_read_locked(struct snd_efw *efw, char __user *buf, long count,
 		  loff_t *offset)
 {
-	union snd_firewire_event event;
+	union snd_firewire_event event = {
+		.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
+	};
 
-	memset(&event, 0, sizeof(event));
+	spin_lock_irq(&efw->lock);
 
-	event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
 	event.lock_status.status = (efw->dev_lock_count > 0);
 	efw->dev_lock_changed = false;
 
+	spin_unlock_irq(&efw->lock);
+
 	count = min_t(long, count, sizeof(event.lock_status));
 
 	if (copy_to_user(buf, &event, count))
@@ -98,10 +124,15 @@ hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
 {
 	struct snd_efw *efw = hwdep->private_data;
 	DEFINE_WAIT(wait);
+	bool dev_lock_changed;
+	bool queued;
 
 	spin_lock_irq(&efw->lock);
 
-	while ((!efw->dev_lock_changed) && (efw->resp_queues == 0)) {
+	dev_lock_changed = efw->dev_lock_changed;
+	queued = efw->push_ptr != efw->pull_ptr;
+
+	while (!dev_lock_changed && !queued) {
 		prepare_to_wait(&efw->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
 		spin_unlock_irq(&efw->lock);
 		schedule();
@@ -109,15 +140,17 @@ hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
 		if (signal_pending(current))
 			return -ERESTARTSYS;
 		spin_lock_irq(&efw->lock);
+		dev_lock_changed = efw->dev_lock_changed;
+		queued = efw->push_ptr != efw->pull_ptr;
 	}
 
-	if (efw->dev_lock_changed)
+	spin_unlock_irq(&efw->lock);
+
+	if (dev_lock_changed)
 		count = hwdep_read_locked(efw, buf, count, offset);
-	else if (efw->resp_queues > 0)
+	else if (queued)
 		count = hwdep_read_resp_buf(efw, buf, count, offset);
 
-	spin_unlock_irq(&efw->lock);
-
 	return count;
 }
 
@@ -160,7 +193,7 @@ hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait)
 	poll_wait(file, &efw->hwdep_wait, wait);
 
 	spin_lock_irq(&efw->lock);
-	if (efw->dev_lock_changed || (efw->resp_queues > 0))
+	if (efw->dev_lock_changed || efw->pull_ptr != efw->push_ptr)
 		events = POLLIN | POLLRDNORM;
 	else
 		events = 0;
diff --git a/sound/firewire/fireworks/fireworks_proc.c b/sound/firewire/fireworks/fireworks_proc.c
index 0639dcb13f7d..beb0a0ffee57 100644
--- a/sound/firewire/fireworks/fireworks_proc.c
+++ b/sound/firewire/fireworks/fireworks_proc.c
@@ -188,8 +188,8 @@ proc_read_queues_state(struct snd_info_entry *entry,
 	else
 		consumed = (unsigned int)(efw->push_ptr - efw->pull_ptr);
 
-	snd_iprintf(buffer, "%d %d/%d\n",
-		    efw->resp_queues, consumed, snd_efw_resp_buf_size);
+	snd_iprintf(buffer, "%d/%d\n",
+		    consumed, snd_efw_resp_buf_size);
 }
 
 static void
diff --git a/sound/firewire/fireworks/fireworks_transaction.c b/sound/firewire/fireworks/fireworks_transaction.c
index f550808d1784..36a08ba51ec7 100644
--- a/sound/firewire/fireworks/fireworks_transaction.c
+++ b/sound/firewire/fireworks/fireworks_transaction.c
@@ -121,11 +121,11 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
 	size_t capacity, till_end;
 	struct snd_efw_transaction *t;
 
-	spin_lock_irq(&efw->lock);
-
 	t = (struct snd_efw_transaction *)data;
 	length = min_t(size_t, be32_to_cpu(t->length) * sizeof(u32), length);
 
+	spin_lock_irq(&efw->lock);
+
 	if (efw->push_ptr < efw->pull_ptr)
 		capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr);
 	else
@@ -155,7 +155,6 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
 	}
 
 	/* for hwdep */
-	efw->resp_queues++;
 	wake_up(&efw->hwdep_wait);
 
 	*rcode = RCODE_COMPLETE;
diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c
index 131267c3a042..106406cbfaa3 100644
--- a/sound/firewire/tascam/tascam-hwdep.c
+++ b/sound/firewire/tascam/tascam-hwdep.c
@@ -16,31 +16,14 @@
 
 #include "tascam.h"
 
-static long hwdep_read_locked(struct snd_tscm *tscm, char __user *buf,
-			      long count)
-{
-	union snd_firewire_event event;
-
-	memset(&event, 0, sizeof(event));
-
-	event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
-	event.lock_status.status = (tscm->dev_lock_count > 0);
-	tscm->dev_lock_changed = false;
-
-	count = min_t(long, count, sizeof(event.lock_status));
-
-	if (copy_to_user(buf, &event, count))
-		return -EFAULT;
-
-	return count;
-}
-
 static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
 		       loff_t *offset)
 {
 	struct snd_tscm *tscm = hwdep->private_data;
 	DEFINE_WAIT(wait);
-	union snd_firewire_event event;
+	union snd_firewire_event event = {
+		.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
+	};
 
 	spin_lock_irq(&tscm->lock);
 
@@ -54,10 +37,16 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
 		spin_lock_irq(&tscm->lock);
 	}
 
-	memset(&event, 0, sizeof(event));
-	count = hwdep_read_locked(tscm, buf, count);
+	event.lock_status.status = (tscm->dev_lock_count > 0);
+	tscm->dev_lock_changed = false;
+
 	spin_unlock_irq(&tscm->lock);
 
+	count = min_t(long, count, sizeof(event.lock_status));
+
+	if (copy_to_user(buf, &event, count))
+		return -EFAULT;
+
 	return count;
 }
 
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index 860f8cad6602..261469188566 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -29,81 +29,6 @@
  */
 #define HDAC_MAX_CAPS 10
 
-/**
- * snd_hdac_ext_bus_parse_capabilities - parse capablity structure
- * @ebus: the pointer to extended bus object
- *
- * Returns 0 if successful, or a negative error code.
- */
-int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus)
-{
-	unsigned int cur_cap;
-	unsigned int offset;
-	struct hdac_bus *bus = &ebus->bus;
-	unsigned int counter = 0;
-
-	offset = snd_hdac_chip_readl(bus, LLCH);
-
-	/* Lets walk the linked capabilities list */
-	do {
-		cur_cap = _snd_hdac_chip_read(l, bus, offset);
-
-		dev_dbg(bus->dev, "Capability version: 0x%x\n",
-				((cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF));
-
-		dev_dbg(bus->dev, "HDA capability ID: 0x%x\n",
-				(cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF);
-
-		switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) {
-		case AZX_ML_CAP_ID:
-			dev_dbg(bus->dev, "Found ML capability\n");
-			ebus->mlcap = bus->remap_addr + offset;
-			break;
-
-		case AZX_GTS_CAP_ID:
-			dev_dbg(bus->dev, "Found GTS capability offset=%x\n", offset);
-			ebus->gtscap = bus->remap_addr + offset;
-			break;
-
-		case AZX_PP_CAP_ID:
-			/* PP capability found, the Audio DSP is present */
-			dev_dbg(bus->dev, "Found PP capability offset=%x\n", offset);
-			ebus->ppcap = bus->remap_addr + offset;
-			break;
-
-		case AZX_SPB_CAP_ID:
-			/* SPIB capability found, handler function */
-			dev_dbg(bus->dev, "Found SPB capability\n");
-			ebus->spbcap = bus->remap_addr + offset;
-			break;
-
-		case AZX_DRSM_CAP_ID:
-			/* DMA resume  capability found, handler function */
-			dev_dbg(bus->dev, "Found DRSM capability\n");
-			ebus->drsmcap = bus->remap_addr + offset;
-			break;
-
-		default:
-			dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap);
-			break;
-		}
-
-		counter++;
-
-		if (counter > HDAC_MAX_CAPS) {
-			dev_err(bus->dev, "We exceeded HDAC Ext capablities!!!\n");
-			break;
-		}
-
-		/* read the offset of next capabiity */
-		offset = cur_cap & AZX_CAP_HDR_NXT_PTR_MASK;
-
-	} while (offset);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_parse_capabilities);
-
 /*
  * processing pipe helpers - these helpers are useful for dealing with HDA
  * new capability of processing pipelines
@@ -118,15 +43,15 @@ void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *ebus, bool enable)
 {
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->ppcap) {
+	if (!bus->ppcap) {
 		dev_err(bus->dev, "Address of PP capability is NULL");
 		return;
 	}
 
 	if (enable)
-		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN);
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN);
 	else
-		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0);
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable);
 
@@ -139,15 +64,15 @@ void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *ebus, bool enable)
 {
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->ppcap) {
+	if (!bus->ppcap) {
 		dev_err(bus->dev, "Address of PP capability is NULL\n");
 		return;
 	}
 
 	if (enable)
-		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE);
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE);
 	else
-		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0);
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable);
 
@@ -171,7 +96,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
 	struct hdac_ext_link *hlink;
 	struct hdac_bus *bus = &ebus->bus;
 
-	link_count = readl(ebus->mlcap + AZX_REG_ML_MLCD) + 1;
+	link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;
 
 	dev_dbg(bus->dev, "In %s Link count: %d\n", __func__, link_count);
 
@@ -181,7 +106,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
 			return -ENOMEM;
 		hlink->index = idx;
 		hlink->bus = bus;
-		hlink->ml_addr = ebus->mlcap + AZX_ML_BASE +
+		hlink->ml_addr = bus->mlcap + AZX_ML_BASE +
 					(AZX_ML_INTERVAL * idx);
 		hlink->lcaps  = readl(hlink->ml_addr + AZX_REG_ML_LCAP);
 		hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID);
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index 626f3bb24c55..2441273adcef 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -40,27 +40,27 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus,
 {
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (ebus->ppcap) {
-		stream->pphc_addr = ebus->ppcap + AZX_PPHC_BASE +
+	if (bus->ppcap) {
+		stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE +
 				AZX_PPHC_INTERVAL * idx;
 
-		stream->pplc_addr = ebus->ppcap + AZX_PPLC_BASE +
+		stream->pplc_addr = bus->ppcap + AZX_PPLC_BASE +
 				AZX_PPLC_MULTI * ebus->num_streams +
 				AZX_PPLC_INTERVAL * idx;
 	}
 
-	if (ebus->spbcap) {
-		stream->spib_addr = ebus->spbcap + AZX_SPB_BASE +
+	if (bus->spbcap) {
+		stream->spib_addr = bus->spbcap + AZX_SPB_BASE +
 					AZX_SPB_INTERVAL * idx +
 					AZX_SPB_SPIB;
 
-		stream->fifo_addr = ebus->spbcap + AZX_SPB_BASE +
+		stream->fifo_addr = bus->spbcap + AZX_SPB_BASE +
 					AZX_SPB_INTERVAL * idx +
 					AZX_SPB_MAXFIFO;
 	}
 
-	if (ebus->drsmcap)
-		stream->dpibr_addr = ebus->drsmcap + AZX_DRSM_BASE +
+	if (bus->drsmcap)
+		stream->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE +
 					AZX_DRSM_INTERVAL * idx;
 
 	stream->decoupled = false;
@@ -131,10 +131,10 @@ void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus,
 
 	spin_lock_irq(&bus->reg_lock);
 	if (decouple)
-		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0,
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0,
 				AZX_PPCTL_PROCEN(hstream->index));
 	else
-		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL,
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
 					AZX_PPCTL_PROCEN(hstream->index), 0);
 	stream->decoupled = decouple;
 	spin_unlock_irq(&bus->reg_lock);
@@ -255,7 +255,7 @@ hdac_ext_link_stream_assign(struct hdac_ext_bus *ebus,
 	struct hdac_stream *stream = NULL;
 	struct hdac_bus *hbus = &ebus->bus;
 
-	if (!ebus->ppcap) {
+	if (!hbus->ppcap) {
 		dev_err(hbus->dev, "stream type not supported\n");
 		return NULL;
 	}
@@ -296,7 +296,7 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
 	struct hdac_stream *stream = NULL;
 	struct hdac_bus *hbus = &ebus->bus;
 
-	if (!ebus->ppcap) {
+	if (!hbus->ppcap) {
 		dev_err(hbus->dev, "stream type not supported\n");
 		return NULL;
 	}
@@ -423,21 +423,21 @@ void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *ebus,
 	u32 register_mask = 0;
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->spbcap) {
+	if (!bus->spbcap) {
 		dev_err(bus->dev, "Address of SPB capability is NULL");
 		return;
 	}
 
 	mask |= (1 << index);
 
-	register_mask = readl(ebus->spbcap + AZX_REG_SPB_SPBFCCTL);
+	register_mask = readl(bus->spbcap + AZX_REG_SPB_SPBFCCTL);
 
 	mask |= register_mask;
 
 	if (enable)
-		snd_hdac_updatel(ebus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask);
+		snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask);
 	else
-		snd_hdac_updatel(ebus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
+		snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable);
 
@@ -452,7 +452,7 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
 {
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->spbcap) {
+	if (!bus->spbcap) {
 		dev_err(bus->dev, "Address of SPB capability is NULL");
 		return -EINVAL;
 	}
@@ -475,7 +475,7 @@ int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
 {
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->spbcap) {
+	if (!bus->spbcap) {
 		dev_err(bus->dev, "Address of SPB capability is NULL");
 		return -EINVAL;
 	}
@@ -515,21 +515,21 @@ void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
 	u32 register_mask = 0;
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->drsmcap) {
+	if (!bus->drsmcap) {
 		dev_err(bus->dev, "Address of DRSM capability is NULL");
 		return;
 	}
 
 	mask |= (1 << index);
 
-	register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL);
+	register_mask = readl(bus->drsmcap + AZX_REG_SPB_SPBFCCTL);
 
 	mask |= register_mask;
 
 	if (enable)
-		snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask);
+		snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, 0, mask);
 	else
-		snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
+		snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
 
@@ -544,7 +544,7 @@ int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
 {
 	struct hdac_bus *bus = &ebus->bus;
 
-	if (!ebus->drsmcap) {
+	if (!bus->drsmcap) {
 		dev_err(bus->dev, "Address of DRSM capability is NULL");
 		return -EINVAL;
 	}
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c
index 9fee464e5d49..043065867656 100644
--- a/sound/hda/hdac_controller.c
+++ b/sound/hda/hdac_controller.c
@@ -255,6 +255,81 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
 }
 EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response);
 
+#define HDAC_MAX_CAPS 10
+/**
+ * snd_hdac_bus_parse_capabilities - parse capability structure
+ * @bus: the pointer to bus object
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus)
+{
+	unsigned int cur_cap;
+	unsigned int offset;
+	unsigned int counter = 0;
+
+	offset = snd_hdac_chip_readl(bus, LLCH);
+
+	/* Lets walk the linked capabilities list */
+	do {
+		cur_cap = _snd_hdac_chip_read(l, bus, offset);
+
+		dev_dbg(bus->dev, "Capability version: 0x%x\n",
+			(cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF);
+
+		dev_dbg(bus->dev, "HDA capability ID: 0x%x\n",
+			(cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF);
+
+		switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) {
+		case AZX_ML_CAP_ID:
+			dev_dbg(bus->dev, "Found ML capability\n");
+			bus->mlcap = bus->remap_addr + offset;
+			break;
+
+		case AZX_GTS_CAP_ID:
+			dev_dbg(bus->dev, "Found GTS capability offset=%x\n", offset);
+			bus->gtscap = bus->remap_addr + offset;
+			break;
+
+		case AZX_PP_CAP_ID:
+			/* PP capability found, the Audio DSP is present */
+			dev_dbg(bus->dev, "Found PP capability offset=%x\n", offset);
+			bus->ppcap = bus->remap_addr + offset;
+			break;
+
+		case AZX_SPB_CAP_ID:
+			/* SPIB capability found, handler function */
+			dev_dbg(bus->dev, "Found SPB capability\n");
+			bus->spbcap = bus->remap_addr + offset;
+			break;
+
+		case AZX_DRSM_CAP_ID:
+			/* DMA resume  capability found, handler function */
+			dev_dbg(bus->dev, "Found DRSM capability\n");
+			bus->drsmcap = bus->remap_addr + offset;
+			break;
+
+		default:
+			dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap);
+			break;
+		}
+
+		counter++;
+
+		if (counter > HDAC_MAX_CAPS) {
+			dev_err(bus->dev, "We exceeded HDAC capabilities!!!\n");
+			break;
+		}
+
+		/* read the offset of next capability */
+		offset = cur_cap & AZX_CAP_HDR_NXT_PTR_MASK;
+
+	} while (offset);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_parse_capabilities);
+
 /*
  * Lowlevel interface
  */
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 27de8015717d..2ad3b447483f 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -27,6 +27,12 @@
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
+
+#ifdef CONFIG_X86
+/* for art-tsc conversion */
+#include <asm/tsc.h>
+#endif
+
 #include <sound/core.h>
 #include <sound/initval.h>
 #include "hda_controller.h"
@@ -337,12 +343,173 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
 			       azx_get_position(chip, azx_dev));
 }
 
+/*
+ * azx_scale64: Scale base by mult/div while not overflowing sanely
+ *
+ * Derived from scale64_check_overflow in kernel/time/timekeeping.c
+ *
+ * The tmestamps for a 48Khz stream can overflow after (2^64/10^9)/48K which
+ * is about 384307 ie ~4.5 days.
+ *
+ * This scales the calculation so that overflow will happen but after 2^64 /
+ * 48000 secs, which is pretty large!
+ *
+ * In caln below:
+ *	base may overflow, but since there isn’t any additional division
+ *	performed on base it’s OK
+ *	rem can’t overflow because both are 32-bit values
+ */
+
+#ifdef CONFIG_X86
+static u64 azx_scale64(u64 base, u32 num, u32 den)
+{
+	u64 rem;
+
+	rem = do_div(base, den);
+
+	base *= num;
+	rem *= num;
+
+	do_div(rem, den);
+
+	return base + rem;
+}
+
+static int azx_get_sync_time(ktime_t *device,
+		struct system_counterval_t *system, void *ctx)
+{
+	struct snd_pcm_substream *substream = ctx;
+	struct azx_dev *azx_dev = get_azx_dev(substream);
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	struct azx *chip = apcm->chip;
+	struct snd_pcm_runtime *runtime;
+	u64 ll_counter, ll_counter_l, ll_counter_h;
+	u64 tsc_counter, tsc_counter_l, tsc_counter_h;
+	u32 wallclk_ctr, wallclk_cycles;
+	bool direction;
+	u32 dma_select;
+	u32 timeout = 200;
+	u32 retry_count = 0;
+
+	runtime = substream->runtime;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		direction = 1;
+	else
+		direction = 0;
+
+	/* 0th stream tag is not used, so DMA ch 0 is for 1st stream tag */
+	do {
+		timeout = 100;
+		dma_select = (direction << GTSCC_CDMAS_DMA_DIR_SHIFT) |
+					(azx_dev->core.stream_tag - 1);
+		snd_hdac_chip_writel(azx_bus(chip), GTSCC, dma_select);
+
+		/* Enable the capture */
+		snd_hdac_chip_updatel(azx_bus(chip), GTSCC, 0, GTSCC_TSCCI_MASK);
+
+		while (timeout) {
+			if (snd_hdac_chip_readl(azx_bus(chip), GTSCC) &
+						GTSCC_TSCCD_MASK)
+				break;
+
+			timeout--;
+		}
+
+		if (!timeout) {
+			dev_err(chip->card->dev, "GTSCC capture Timedout!\n");
+			return -EIO;
+		}
+
+		/* Read wall clock counter */
+		wallclk_ctr = snd_hdac_chip_readl(azx_bus(chip), WALFCC);
+
+		/* Read TSC counter */
+		tsc_counter_l = snd_hdac_chip_readl(azx_bus(chip), TSCCL);
+		tsc_counter_h = snd_hdac_chip_readl(azx_bus(chip), TSCCU);
+
+		/* Read Link counter */
+		ll_counter_l = snd_hdac_chip_readl(azx_bus(chip), LLPCL);
+		ll_counter_h = snd_hdac_chip_readl(azx_bus(chip), LLPCU);
+
+		/* Ack: registers read done */
+		snd_hdac_chip_writel(azx_bus(chip), GTSCC, GTSCC_TSCCD_SHIFT);
+
+		tsc_counter = (tsc_counter_h << TSCCU_CCU_SHIFT) |
+						tsc_counter_l;
+
+		ll_counter = (ll_counter_h << LLPC_CCU_SHIFT) |	ll_counter_l;
+		wallclk_cycles = wallclk_ctr & WALFCC_CIF_MASK;
+
+		/*
+		 * An error occurs near frame "rollover". The clocks in
+		 * frame value indicates whether this error may have
+		 * occurred. Here we use the value of 10 i.e.,
+		 * HDA_MAX_CYCLE_OFFSET
+		 */
+		if (wallclk_cycles < HDA_MAX_CYCLE_VALUE - HDA_MAX_CYCLE_OFFSET
+					&& wallclk_cycles > HDA_MAX_CYCLE_OFFSET)
+			break;
+
+		/*
+		 * Sleep before we read again, else we may again get
+		 * value near to MAX_CYCLE. Try to sleep for different
+		 * amount of time so we dont hit the same number again
+		 */
+		udelay(retry_count++);
+
+	} while (retry_count != HDA_MAX_CYCLE_READ_RETRY);
+
+	if (retry_count == HDA_MAX_CYCLE_READ_RETRY) {
+		dev_err_ratelimited(chip->card->dev,
+			"Error in WALFCC cycle count\n");
+		return -EIO;
+	}
+
+	*device = ns_to_ktime(azx_scale64(ll_counter,
+				NSEC_PER_SEC, runtime->rate));
+	*device = ktime_add_ns(*device, (wallclk_cycles * NSEC_PER_SEC) /
+			       ((HDA_MAX_CYCLE_VALUE + 1) * runtime->rate));
+
+	*system = convert_art_to_tsc(tsc_counter);
+
+	return 0;
+}
+
+#else
+static int azx_get_sync_time(ktime_t *device,
+		struct system_counterval_t *system, void *ctx)
+{
+	return -ENXIO;
+}
+#endif
+
+static int azx_get_crosststamp(struct snd_pcm_substream *substream,
+			      struct system_device_crosststamp *xtstamp)
+{
+	return get_device_system_crosststamp(azx_get_sync_time,
+					substream, NULL, xtstamp);
+}
+
+static inline bool is_link_time_supported(struct snd_pcm_runtime *runtime,
+				struct snd_pcm_audio_tstamp_config *ts)
+{
+	if (runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME)
+		if (ts->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED)
+			return true;
+
+	return false;
+}
+
 static int azx_get_time_info(struct snd_pcm_substream *substream,
 			struct timespec *system_ts, struct timespec *audio_ts,
 			struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
 			struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
 {
 	struct azx_dev *azx_dev = get_azx_dev(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct system_device_crosststamp xtstamp;
+	int ret;
 	u64 nsec;
 
 	if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) &&
@@ -361,8 +528,37 @@ static int azx_get_time_info(struct snd_pcm_substream *substream,
 		audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */
 		audio_tstamp_report->accuracy = 42; /* 24 MHz WallClock == 42ns resolution */
 
-	} else
+	} else if (is_link_time_supported(runtime, audio_tstamp_config)) {
+
+		ret = azx_get_crosststamp(substream, &xtstamp);
+		if (ret)
+			return ret;
+
+		switch (runtime->tstamp_type) {
+		case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC:
+			return -EINVAL;
+
+		case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW:
+			*system_ts = ktime_to_timespec(xtstamp.sys_monoraw);
+			break;
+
+		default:
+			*system_ts = ktime_to_timespec(xtstamp.sys_realtime);
+			break;
+
+		}
+
+		*audio_ts = ktime_to_timespec(xtstamp.device);
+
+		audio_tstamp_report->actual_type =
+			SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED;
+		audio_tstamp_report->accuracy_report = 1;
+		/* 24 MHz WallClock == 42ns resolution */
+		audio_tstamp_report->accuracy = 42;
+
+	} else {
 		audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
+	}
 
 	return 0;
 }
@@ -412,6 +608,11 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
 		goto unlock;
 	}
 	runtime->private_data = azx_dev;
+
+	if (chip->gts_present)
+		azx_pcm_hw.info = azx_pcm_hw.info |
+			SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME;
+
 	runtime->hw = azx_pcm_hw;
 	runtime->hw.channels_min = hinfo->channels_min;
 	runtime->hw.channels_max = hinfo->channels_max;
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
index ec63bbf1ec6d..a50e0532622a 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/pci/hda/hda_controller.h
@@ -159,6 +159,9 @@ struct azx {
 	unsigned int region_requested:1;
 	unsigned int disabled:1; /* disabled by vga_switcheroo */
 
+	/* GTS present */
+	unsigned int gts_present:1;
+
 #ifdef CONFIG_SND_HDA_DSP_LOADER
 	struct azx_dev saved_azx_dev;
 #endif
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 89dacf9b4e6c..c3469f756ec2 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -54,6 +54,7 @@
 /* for snoop control */
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
 #endif
 #include <sound/core.h>
 #include <sound/initval.h>
@@ -906,20 +907,23 @@ static int azx_resume(struct device *dev)
 	struct snd_card *card = dev_get_drvdata(dev);
 	struct azx *chip;
 	struct hda_intel *hda;
+	struct hdac_bus *bus;
 
 	if (!card)
 		return 0;
 
 	chip = card->private_data;
 	hda = container_of(chip, struct hda_intel, chip);
+	bus = azx_bus(chip);
 	if (chip->disabled || hda->init_failed || !chip->running)
 		return 0;
 
-	if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
-		&& hda->need_i915_power) {
-		snd_hdac_display_power(azx_bus(chip), true);
-		snd_hdac_i915_set_bclk(azx_bus(chip));
+	if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+		snd_hdac_display_power(bus, true);
+		if (hda->need_i915_power)
+			snd_hdac_i915_set_bclk(bus);
 	}
+
 	if (chip->msi)
 		if (pci_enable_msi(pci) < 0)
 			chip->msi = 0;
@@ -929,6 +933,11 @@ static int azx_resume(struct device *dev)
 
 	hda_intel_init_chip(chip, true);
 
+	/* power down again for link-controlled chips */
+	if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
+	    !hda->need_i915_power)
+		snd_hdac_display_power(bus, false);
+
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 
 	trace_azx_resume(chip);
@@ -1008,6 +1017,7 @@ static int azx_runtime_resume(struct device *dev)
 
 	chip = card->private_data;
 	hda = container_of(chip, struct hda_intel, chip);
+	bus = azx_bus(chip);
 	if (chip->disabled || hda->init_failed)
 		return 0;
 
@@ -1015,15 +1025,9 @@ static int azx_runtime_resume(struct device *dev)
 		return 0;
 
 	if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
-		bus = azx_bus(chip);
-		if (hda->need_i915_power) {
-			snd_hdac_display_power(bus, true);
+		snd_hdac_display_power(bus, true);
+		if (hda->need_i915_power)
 			snd_hdac_i915_set_bclk(bus);
-		} else {
-			/* toggle codec wakeup bit for STATESTS read */
-			snd_hdac_set_codec_wakeup(bus, true);
-			snd_hdac_set_codec_wakeup(bus, false);
-		}
 	}
 
 	/* Read STATESTS before controller reset */
@@ -1043,6 +1047,11 @@ static int azx_runtime_resume(struct device *dev)
 	azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
 			~STATESTS_INT_MASK);
 
+	/* power down again for link-controlled chips */
+	if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
+	    !hda->need_i915_power)
+		snd_hdac_display_power(bus, false);
+
 	trace_azx_runtime_resume(chip);
 	return 0;
 }
@@ -1655,6 +1664,22 @@ static int azx_first_init(struct azx *chip)
 		return -ENXIO;
 	}
 
+	if (IS_SKL_PLUS(pci))
+		snd_hdac_bus_parse_capabilities(bus);
+
+	/*
+	 * Some Intel CPUs has always running timer (ART) feature and
+	 * controller may have Global time sync reporting capability, so
+	 * check both of these before declaring synchronized time reporting
+	 * capability SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME
+	 */
+	chip->gts_present = false;
+
+#ifdef CONFIG_X86
+	if (bus->ppcap && boot_cpu_has(X86_FEATURE_ART))
+		chip->gts_present = true;
+#endif
+
 	if (chip->msi) {
 		if (chip->driver_caps & AZX_DCAPS_NO_MSI64) {
 			dev_dbg(card->dev, "Disabling 64bit MSI\n");
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 574b1b48996f..575cefd8cc4a 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -4828,7 +4828,7 @@ enum {
 	ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
 	ALC292_FIXUP_TPT440_DOCK,
 	ALC292_FIXUP_TPT440,
-	ALC283_FIXUP_BXBT2807_MIC,
+	ALC283_FIXUP_HEADSET_MIC,
 	ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED,
 	ALC282_FIXUP_ASPIRE_V5_PINS,
 	ALC280_FIXUP_HP_GPIO4,
@@ -4855,6 +4855,7 @@ enum {
 	ALC221_FIXUP_HP_FRONT_MIC,
 	ALC292_FIXUP_TPT460,
 	ALC298_FIXUP_SPK_VOLUME,
+	ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5321,7 +5322,7 @@ static const struct hda_fixup alc269_fixups[] = {
 		.chained = true,
 		.chain_id = ALC292_FIXUP_TPT440_DOCK,
 	},
-	[ALC283_FIXUP_BXBT2807_MIC] = {
+	[ALC283_FIXUP_HEADSET_MIC] = {
 		.type = HDA_FIXUP_PINS,
 		.v.pins = (const struct hda_pintbl[]) {
 			{ 0x19, 0x04a110f0 },
@@ -5516,6 +5517,15 @@ static const struct hda_fixup alc269_fixups[] = {
 		.chained = true,
 		.chain_id = ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
 	},
+	[ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1b, 0x90170151 },
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+	},
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5560,6 +5570,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
 	SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
 	SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13 9350", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
+	SND_PCI_QUIRK(0x1028, 0x0706, "Dell Inspiron 7559", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
 	SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
 	SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
 	SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
@@ -5651,7 +5662,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN),
 	SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
 	SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
-	SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC),
+	SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
+	SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
 	SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
 	SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
 	SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
@@ -5894,6 +5906,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
 		{0x12, 0x90a60170},
 		{0x14, 0x90170120},
 		{0x21, 0x02211030}),
+	SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell Inspiron 5468", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+		{0x12, 0x90a60180},
+		{0x14, 0x90170120},
+		{0x21, 0x02211030}),
 	SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
 		ALC256_STANDARD_PINS),
 	SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index d1fb035f44db..504c7cd7f58a 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -897,7 +897,7 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static struct snd_pcm_ops acp_dma_ops = {
+static const struct snd_pcm_ops acp_dma_ops = {
 	.open = acp_dma_open,
 	.close = acp_dma_close,
 	.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index 6d9b8b44e2da..89ac5f5a93eb 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -308,9 +308,11 @@ static struct regmap *atmel_classd_codec_get_remap(struct device *dev)
 
 static struct snd_soc_codec_driver soc_codec_dev_classd = {
 	.probe		= atmel_classd_codec_probe,
-	.controls	= atmel_classd_snd_controls,
-	.num_controls	= ARRAY_SIZE(atmel_classd_snd_controls),
 	.get_regmap	= atmel_classd_codec_get_remap,
+	.component_driver = {
+		.controls		= atmel_classd_snd_controls,
+		.num_controls		= ARRAY_SIZE(atmel_classd_snd_controls),
+	},
 };
 
 /* codec dai component */
diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c
index da861b44413f..91b7069c3499 100644
--- a/sound/soc/atmel/atmel-pcm-pdc.c
+++ b/sound/soc/atmel/atmel-pcm-pdc.c
@@ -381,7 +381,7 @@ static int atmel_pcm_close(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static struct snd_pcm_ops atmel_pcm_ops = {
+static const struct snd_pcm_ops atmel_pcm_ops = {
 	.open		= atmel_pcm_open,
 	.close		= atmel_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c
index 5f56da60c92f..c917df7715d1 100644
--- a/sound/soc/atmel/atmel-pdmic.c
+++ b/sound/soc/atmel/atmel-pdmic.c
@@ -80,7 +80,7 @@ static struct atmel_pdmic_pdata *atmel_pdmic_dt_init(struct device *dev)
 
 	if (pdata->mic_max_freq < pdata->mic_min_freq) {
 		dev_err(dev,
-			"mic-max-freq should not less than mic-min-freq\n");
+			"mic-max-freq should not be less than mic-min-freq\n");
 		return ERR_PTR(-EINVAL);
 	}
 
@@ -115,8 +115,10 @@ static int atmel_pdmic_cpu_dai_startup(struct snd_pcm_substream *substream,
 		return ret;
 
 	ret =  clk_prepare_enable(dd->pclk);
-	if (ret)
+	if (ret) {
+		clk_disable_unprepare(dd->gclk);
 		return ret;
+	}
 
 	/* Clear all bits in the Control Register(PDMIC_CR) */
 	regmap_write(dd->regmap, PDMIC_CR, 0);
@@ -283,7 +285,7 @@ static const DECLARE_TLV_DB_RANGE(mic_gain_tlv,
 	8, ARRAY_SIZE(mic_gain_table)-1, TLV_DB_SCALE_ITEM(-6500, 100, 0),
 );
 
-int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol,
+static int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
@@ -357,8 +359,10 @@ static int atmel_pdmic_codec_probe(struct snd_soc_codec *codec)
 
 static struct snd_soc_codec_driver soc_codec_dev_pdmic = {
 	.probe		= atmel_pdmic_codec_probe,
-	.controls	= atmel_pdmic_snd_controls,
-	.num_controls	= ARRAY_SIZE(atmel_pdmic_snd_controls),
+	.component_driver = {
+		.controls		= atmel_pdmic_snd_controls,
+		.num_controls		= ARRAY_SIZE(atmel_pdmic_snd_controls),
+	},
 };
 
 /* codec dai component */
@@ -596,7 +600,7 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
 	dd->irq = platform_get_irq(pdev, 0);
 	if (dd->irq < 0) {
 		ret = dd->irq;
-		dev_err(dev, "failed to could not get irq: %d\n", ret);
+		dev_err(dev, "failed to get irq: %d\n", ret);
 		return ret;
 	}
 
@@ -614,7 +618,7 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	/* The gclk clock frequency must always be tree times
+	/* The gclk clock frequency must always be three times
 	 * lower than the pclk clock frequency
 	 */
 	ret = clk_set_rate(dd->gclk, clk_get_rate(dd->pclk)/3);
@@ -649,7 +653,7 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	/* Get the minimal and maximal sample rate that micphone supports */
+	/* Get the minimal and maximal sample rate that the microphone supports */
 	atmel_pdmic_get_sample_rate(dd, &rate_min, &rate_max);
 
 	/* register cpu dai */
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 54c09acd3fed..16e459aedffe 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -299,8 +299,9 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
 	clk_enable(ssc_p->ssc->clk);
 	ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk);
 
-	/* Reset the SSC to keep it at a clean status */
-	ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
+	/* Reset the SSC unless initialized to keep it in a clean state */
+	if (!ssc_p->initialized)
+		ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		dir = 0;
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index e8bed6b0c9db..b013a4c62b63 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -1361,12 +1361,14 @@ static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
 	.set_bias_level	= pm860x_set_bias_level,
 	.get_regmap	= pm860x_get_regmap,
 
-	.controls = pm860x_snd_controls,
-	.num_controls = ARRAY_SIZE(pm860x_snd_controls),
-	.dapm_widgets = pm860x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(pm860x_dapm_widgets),
-	.dapm_routes = pm860x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(pm860x_dapm_routes),
+	.component_driver = {
+		.controls		= pm860x_snd_controls,
+		.num_controls		= ARRAY_SIZE(pm860x_snd_controls),
+		.dapm_widgets		= pm860x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pm860x_dapm_widgets),
+		.dapm_routes		= pm860x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pm860x_dapm_routes),
+	},
 };
 
 static int pm860x_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 1cd6ab344d67..c67667bb970f 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -92,6 +92,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_MC13783 if MFD_MC13XXX
 	select SND_SOC_ML26124 if I2C
+	select SND_SOC_NAU8810 if I2C
 	select SND_SOC_NAU8825 if I2C
 	select SND_SOC_HDMI_CODEC
 	select SND_SOC_PCM1681 if I2C
@@ -112,6 +113,8 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_RT5645 if I2C
 	select SND_SOC_RT5651 if I2C
 	select SND_SOC_RT5659 if I2C
+	select SND_SOC_RT5660 if I2C
+	select SND_SOC_RT5663 if I2C
 	select SND_SOC_RT5670 if I2C
 	select SND_SOC_RT5677 if I2C && SPI_MASTER
 	select SND_SOC_SGTL5000 if I2C
@@ -645,6 +648,8 @@ config SND_SOC_RL6231
 	default y if SND_SOC_RT5645=y
 	default y if SND_SOC_RT5651=y
 	default y if SND_SOC_RT5659=y
+	default y if SND_SOC_RT5660=y
+	default y if SND_SOC_RT5663=y
 	default y if SND_SOC_RT5670=y
 	default y if SND_SOC_RT5677=y
 	default m if SND_SOC_RT5514=m
@@ -653,6 +658,8 @@ config SND_SOC_RL6231
 	default m if SND_SOC_RT5645=m
 	default m if SND_SOC_RT5651=m
 	default m if SND_SOC_RT5659=m
+	default m if SND_SOC_RT5660=m
+	default m if SND_SOC_RT5663=m
 	default m if SND_SOC_RT5670=m
 	default m if SND_SOC_RT5677=m
 
@@ -665,6 +672,7 @@ config SND_SOC_RL6347A
 
 config SND_SOC_RT286
 	tristate
+	select SND_SOC_RT5663
 	depends on I2C
 
 config SND_SOC_RT298
@@ -697,6 +705,12 @@ config SND_SOC_RT5651
 config SND_SOC_RT5659
 	tristate
 
+config SND_SOC_RT5660
+	tristate
+
+config SND_SOC_RT5663
+	tristate
+
 config SND_SOC_RT5670
 	tristate
 
@@ -1064,6 +1078,10 @@ config SND_SOC_MC13783
 config SND_SOC_ML26124
 	tristate
 
+config SND_SOC_NAU8810
+	tristate "Nuvoton Technology Corporation NAU88C10 CODEC"
+	depends on I2C
+
 config SND_SOC_NAU8825
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 58036af2c7d9..958cd4912fbc 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -86,6 +86,7 @@ snd-soc-max9850-objs := max9850.o
 snd-soc-max9860-objs := max9860.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
+snd-soc-nau8810-objs := nau8810.o
 snd-soc-nau8825-objs := nau8825.o
 snd-soc-hdmi-codec-objs := hdmi-codec.o
 snd-soc-pcm1681-objs := pcm1681.o
@@ -112,6 +113,8 @@ snd-soc-rt5640-objs := rt5640.o
 snd-soc-rt5645-objs := rt5645.o
 snd-soc-rt5651-objs := rt5651.o
 snd-soc-rt5659-objs := rt5659.o
+snd-soc-rt5660-objs := rt5660.o
+snd-soc-rt5663-objs := rt5663.o
 snd-soc-rt5670-objs := rt5670.o
 snd-soc-rt5677-objs := rt5677.o
 snd-soc-rt5677-spi-objs := rt5677-spi.o
@@ -307,6 +310,7 @@ obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MAX9860)	+= snd-soc-max9860.o
 obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
+obj-$(CONFIG_SND_SOC_NAU8810)   += snd-soc-nau8810.o
 obj-$(CONFIG_SND_SOC_NAU8825)   += snd-soc-nau8825.o
 obj-$(CONFIG_SND_SOC_HDMI_CODEC)	+= snd-soc-hdmi-codec.o
 obj-$(CONFIG_SND_SOC_PCM1681)	+= snd-soc-pcm1681.o
@@ -333,6 +337,8 @@ obj-$(CONFIG_SND_SOC_RT5640)	+= snd-soc-rt5640.o
 obj-$(CONFIG_SND_SOC_RT5645)	+= snd-soc-rt5645.o
 obj-$(CONFIG_SND_SOC_RT5651)	+= snd-soc-rt5651.o
 obj-$(CONFIG_SND_SOC_RT5659)	+= snd-soc-rt5659.o
+obj-$(CONFIG_SND_SOC_RT5660)	+= snd-soc-rt5660.o
+obj-$(CONFIG_SND_SOC_RT5663)	+= snd-soc-rt5663.o
 obj-$(CONFIG_SND_SOC_RT5670)	+= snd-soc-rt5670.o
 obj-$(CONFIG_SND_SOC_RT5677)	+= snd-soc-rt5677.o
 obj-$(CONFIG_SND_SOC_RT5677_SPI)	+= snd-soc-rt5677-spi.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 2fc89155f14a..935ff7cb71c5 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -2408,28 +2408,28 @@ static void ab8500_codec_of_probe(struct device *dev, struct device_node *np,
 {
 	u32 value;
 
-	if (of_get_property(np, "stericsson,amic1-type-single-ended", NULL))
+	if (of_property_read_bool(np, "stericsson,amic1-type-single-ended"))
 		codec->amics.mic1_type = AMIC_TYPE_SINGLE_ENDED;
 	else
 		codec->amics.mic1_type = AMIC_TYPE_DIFFERENTIAL;
 
-	if (of_get_property(np, "stericsson,amic2-type-single-ended", NULL))
+	if (of_property_read_bool(np, "stericsson,amic2-type-single-ended"))
 		codec->amics.mic2_type = AMIC_TYPE_SINGLE_ENDED;
 	else
 		codec->amics.mic2_type = AMIC_TYPE_DIFFERENTIAL;
 
 	/* Has a non-standard Vamic been requested? */
-	if (of_get_property(np, "stericsson,amic1a-bias-vamic2", NULL))
+	if (of_property_read_bool(np, "stericsson,amic1a-bias-vamic2"))
 		codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC2;
 	else
 		codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC1;
 
-	if (of_get_property(np, "stericsson,amic1b-bias-vamic2", NULL))
+	if (of_property_read_bool(np, "stericsson,amic1b-bias-vamic2"))
 		codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC2;
 	else
 		codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC1;
 
-	if (of_get_property(np, "stericsson,amic2-bias-vamic1", NULL))
+	if (of_property_read_bool(np, "stericsson,amic2-bias-vamic1"))
 		codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC1;
 	else
 		codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC2;
@@ -2525,12 +2525,14 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
 
 static struct snd_soc_codec_driver ab8500_codec_driver = {
 	.probe =		ab8500_codec_probe,
-	.controls =		ab8500_ctrls,
-	.num_controls =		ARRAY_SIZE(ab8500_ctrls),
-	.dapm_widgets =		ab8500_dapm_widgets,
-	.num_dapm_widgets =	ARRAY_SIZE(ab8500_dapm_widgets),
-	.dapm_routes =		ab8500_dapm_routes,
-	.num_dapm_routes =	ARRAY_SIZE(ab8500_dapm_routes),
+	.component_driver = {
+		.controls =		ab8500_ctrls,
+		.num_controls =		ARRAY_SIZE(ab8500_ctrls),
+		.dapm_widgets =		ab8500_dapm_widgets,
+		.num_dapm_widgets =	ARRAY_SIZE(ab8500_dapm_widgets),
+		.dapm_routes =		ab8500_dapm_routes,
+		.num_dapm_routes =	ARRAY_SIZE(ab8500_dapm_routes),
+	},
 };
 
 static int ab8500_codec_driver_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 5b3224c63943..f7f04c6be01e 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -117,10 +117,12 @@ static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
 	.suspend =	ac97_soc_suspend,
 	.resume =	ac97_soc_resume,
 
-	.dapm_widgets = ac97_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ac97_widgets),
-	.dapm_routes = ac97_routes,
-	.num_dapm_routes = ARRAY_SIZE(ac97_routes),
+	.component_driver = {
+		.dapm_widgets		= ac97_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ac97_widgets),
+		.dapm_routes		= ac97_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ac97_routes),
+	},
 };
 
 static int ac97_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index e2ce6c4d7ece..a478239aadac 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -327,12 +327,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
 	.suspend = ad1836_suspend,
 	.resume = ad1836_resume,
 
-	.controls = ad183x_controls,
-	.num_controls = ARRAY_SIZE(ad183x_controls),
-	.dapm_widgets = ad183x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ad183x_dapm_widgets),
-	.dapm_routes = ad183x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes),
+	.component_driver = {
+		.controls		= ad183x_controls,
+		.num_controls		= ARRAY_SIZE(ad183x_controls),
+		.dapm_widgets		= ad183x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ad183x_dapm_widgets),
+		.dapm_routes		= ad183x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ad183x_dapm_routes),
+	},
 };
 
 static const struct reg_default ad1836_reg_defaults[] = {
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index 3a3f3f2343d7..d643557d89a7 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -410,12 +410,14 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec)
 
 static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
 	.probe = ad193x_codec_probe,
-	.controls = ad193x_snd_controls,
-	.num_controls = ARRAY_SIZE(ad193x_snd_controls),
-	.dapm_widgets = ad193x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ad193x_dapm_widgets),
-	.dapm_routes = audio_paths,
-	.num_dapm_routes = ARRAY_SIZE(audio_paths),
+	.component_driver = {
+		.controls		= ad193x_snd_controls,
+		.num_controls		= ARRAY_SIZE(ad193x_snd_controls),
+		.dapm_widgets		= ad193x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ad193x_dapm_widgets),
+		.dapm_routes		= audio_paths,
+		.num_dapm_routes	= ARRAY_SIZE(audio_paths),
+	},
 };
 
 const struct regmap_config ad193x_regmap_config = {
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 9ef20dbccbe3..b7c1b9f4bf5f 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -299,12 +299,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
 	.probe = 	ad1980_soc_probe,
 	.remove = 	ad1980_soc_remove,
 
-	.controls = ad1980_snd_ac97_controls,
-	.num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls),
-	.dapm_widgets = ad1980_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets),
-	.dapm_routes = ad1980_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ad1980_dapm_routes),
+	.component_driver = {
+		.controls		= ad1980_snd_ac97_controls,
+		.num_controls		= ARRAY_SIZE(ad1980_snd_ac97_controls),
+		.dapm_widgets		= ad1980_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ad1980_dapm_widgets),
+		.dapm_routes		= ad1980_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ad1980_dapm_routes),
+	},
 };
 
 static int ad1980_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index a9400aef60b5..3e358a49442d 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -55,10 +55,12 @@ static struct snd_soc_dai_driver ad73311_dai = {
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_ad73311 = {
-	.dapm_widgets = ad73311_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ad73311_dapm_widgets),
-	.dapm_routes = ad73311_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ad73311_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= ad73311_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ad73311_dapm_widgets),
+		.dapm_routes		= ad73311_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ad73311_dapm_routes),
+	},
 };
 
 static int ad73311_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 1556b360fa15..8fa9045571ff 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -1466,12 +1466,14 @@ static struct snd_soc_codec_driver adau1373_codec_driver = {
 
 	.set_pll = adau1373_set_pll,
 
-	.controls = adau1373_controls,
-	.num_controls = ARRAY_SIZE(adau1373_controls),
-	.dapm_widgets = adau1373_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(adau1373_dapm_widgets),
-	.dapm_routes = adau1373_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(adau1373_dapm_routes),
+	.component_driver = {
+		.controls		= adau1373_controls,
+		.num_controls		= ARRAY_SIZE(adau1373_controls),
+		.dapm_widgets		= adau1373_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adau1373_dapm_widgets),
+		.dapm_routes		= adau1373_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adau1373_dapm_routes),
+	},
 };
 
 static int adau1373_i2c_probe(struct i2c_client *client,
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index de53c0d7bf10..3bad1bc8c00a 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -765,13 +765,14 @@ static struct snd_soc_codec_driver adau1701_codec_drv = {
 	.set_bias_level		= adau1701_set_bias_level,
 	.idle_bias_off		= true,
 
-	.controls		= adau1701_controls,
-	.num_controls		= ARRAY_SIZE(adau1701_controls),
-	.dapm_widgets		= adau1701_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(adau1701_dapm_widgets),
-	.dapm_routes		= adau1701_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(adau1701_dapm_routes),
-
+	.component_driver = {
+		.controls		= adau1701_controls,
+		.num_controls		= ARRAY_SIZE(adau1701_controls),
+		.dapm_widgets		= adau1701_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adau1701_dapm_widgets),
+		.dapm_routes		= adau1701_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adau1701_dapm_routes),
+	},
 	.set_sysclk		= adau1701_set_sysclk,
 };
 
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
index b95d29dbd13d..3bc3cc559dde 100644
--- a/sound/soc/codecs/adau1761.c
+++ b/sound/soc/codecs/adau1761.c
@@ -719,12 +719,14 @@ static const struct snd_soc_codec_driver adau1761_codec_driver = {
 	.set_bias_level	= adau1761_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = adau1761_controls,
-	.num_controls = ARRAY_SIZE(adau1761_controls),
-	.dapm_widgets = adau1x61_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(adau1x61_dapm_widgets),
-	.dapm_routes = adau1x61_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(adau1x61_dapm_routes),
+	.component_driver = {
+		.controls		= adau1761_controls,
+		.num_controls		= ARRAY_SIZE(adau1761_controls),
+		.dapm_widgets		= adau1x61_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adau1x61_dapm_widgets),
+		.dapm_routes		= adau1x61_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adau1x61_dapm_routes),
+	},
 };
 
 #define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c
index bc1bb56dae63..546071c6c0d0 100644
--- a/sound/soc/codecs/adau1781.c
+++ b/sound/soc/codecs/adau1781.c
@@ -432,12 +432,14 @@ static const struct snd_soc_codec_driver adau1781_codec_driver = {
 	.set_bias_level = adau1781_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = adau1781_controls,
-	.num_controls = ARRAY_SIZE(adau1781_controls),
-	.dapm_widgets = adau1781_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(adau1781_dapm_widgets),
-	.dapm_routes = adau1781_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(adau1781_dapm_routes),
+	.component_driver = {
+		.controls		= adau1781_controls,
+		.num_controls		= ARRAY_SIZE(adau1781_controls),
+		.dapm_widgets		= adau1781_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adau1781_dapm_widgets),
+		.dapm_routes		= adau1781_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adau1781_dapm_routes),
+	},
 };
 
 #define ADAU1781_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
index 9bdd15f408c1..b319db6a69f8 100644
--- a/sound/soc/codecs/adau1977.c
+++ b/sound/soc/codecs/adau1977.c
@@ -873,12 +873,14 @@ static struct snd_soc_codec_driver adau1977_codec_driver = {
 	.set_sysclk = adau1977_set_sysclk,
 	.idle_bias_off = true,
 
-	.controls = adau1977_snd_controls,
-	.num_controls = ARRAY_SIZE(adau1977_snd_controls),
-	.dapm_widgets = adau1977_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(adau1977_dapm_widgets),
-	.dapm_routes = adau1977_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes),
+	.component_driver = {
+		.controls		= adau1977_snd_controls,
+		.num_controls		= ARRAY_SIZE(adau1977_snd_controls),
+		.dapm_widgets		= adau1977_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adau1977_dapm_widgets),
+		.dapm_routes		= adau1977_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adau1977_dapm_routes),
+	},
 };
 
 static int adau1977_setup_micbias(struct adau1977 *adau1977)
diff --git a/sound/soc/codecs/adau7002.c b/sound/soc/codecs/adau7002.c
index 9df72c6adcca..6384c5491de8 100644
--- a/sound/soc/codecs/adau7002.c
+++ b/sound/soc/codecs/adau7002.c
@@ -39,10 +39,12 @@ static struct snd_soc_dai_driver adau7002_dai = {
 };
 
 static const struct snd_soc_codec_driver adau7002_codec_driver = {
-	.dapm_widgets = adau7002_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(adau7002_widgets),
-	.dapm_routes = adau7002_routes,
-	.num_dapm_routes = ARRAY_SIZE(adau7002_routes),
+	.component_driver = {
+		.dapm_widgets		= adau7002_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adau7002_widgets),
+		.dapm_routes		= adau7002_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adau7002_routes),
+	},
 };
 
 static int adau7002_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index acff8d62059c..6e793ebb5883 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -834,12 +834,14 @@ static struct snd_soc_codec_driver adav80x_codec_driver = {
 	.set_pll = adav80x_set_pll,
 	.set_sysclk = adav80x_set_sysclk,
 
-	.controls = adav80x_controls,
-	.num_controls = ARRAY_SIZE(adav80x_controls),
-	.dapm_widgets = adav80x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(adav80x_dapm_widgets),
-	.dapm_routes = adav80x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes),
+	.component_driver = {
+		.controls		= adav80x_controls,
+		.num_controls		= ARRAY_SIZE(adav80x_controls),
+		.dapm_widgets		= adav80x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(adav80x_dapm_widgets),
+		.dapm_routes		= adav80x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(adav80x_dapm_routes),
+	},
 };
 
 int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
index c5be1bdc2c9a..90c756d183b4 100644
--- a/sound/soc/codecs/ads117x.c
+++ b/sound/soc/codecs/ads117x.c
@@ -59,10 +59,12 @@ static struct snd_soc_dai_driver ads117x_dai = {
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_ads117x = {
-	.dapm_widgets = ads117x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ads117x_dapm_widgets),
-	.dapm_routes = ads117x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ads117x_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= ads117x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ads117x_dapm_widgets),
+		.dapm_routes		= ads117x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ads117x_dapm_routes),
+	},
 };
 
 static int ads117x_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 595d02d7602c..1a9d233c94d0 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -163,7 +163,10 @@ static struct snd_soc_dai_driver ak4104_dai = {
 		.stream_name = "Playback",
 		.channels_min = 2,
 		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_192000,
+		.rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+			 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+			 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE  |
 			   SNDRV_PCM_FMTBIT_S24_3LE |
 			   SNDRV_PCM_FMTBIT_S24_LE
@@ -245,10 +248,12 @@ static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
 	.suspend = ak4104_soc_suspend,
 	.resume = ak4104_soc_resume,
 
-	.dapm_widgets = ak4104_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets),
-	.dapm_routes = ak4104_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ak4104_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= ak4104_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4104_dapm_widgets),
+		.dapm_routes		= ak4104_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ak4104_dapm_routes),
+	}
 };
 
 static const struct regmap_config ak4104_regmap = {
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 54428c64387b..66cfffde9a12 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -395,12 +395,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
 	.set_bias_level = ak4535_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = ak4535_snd_controls,
-	.num_controls = ARRAY_SIZE(ak4535_snd_controls),
-	.dapm_widgets = ak4535_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
-	.dapm_routes = ak4535_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(ak4535_audio_map),
+	.component_driver = {
+		.controls		= ak4535_snd_controls,
+		.num_controls		= ARRAY_SIZE(ak4535_snd_controls),
+		.dapm_widgets		= ak4535_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4535_dapm_widgets),
+		.dapm_routes		= ak4535_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(ak4535_audio_map),
+	},
 };
 
 static int ak4535_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c
index 298dedc05140..b92c548b9d29 100644
--- a/sound/soc/codecs/ak4554.c
+++ b/sound/soc/codecs/ak4554.c
@@ -65,10 +65,12 @@ static struct snd_soc_dai_driver ak4554_dai = {
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_ak4554 = {
-	.dapm_widgets = ak4554_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ak4554_dapm_widgets),
-	.dapm_routes = ak4554_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ak4554_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= ak4554_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4554_dapm_widgets),
+		.dapm_routes		= ak4554_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ak4554_dapm_routes),
+	},
 };
 
 static int ak4554_soc_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 97798d250f08..e819dd8c82fd 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -458,12 +458,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
 	.suspend		= ak4613_suspend,
 	.resume			= ak4613_resume,
 	.set_bias_level		= ak4613_set_bias_level,
-	.controls		= ak4613_snd_controls,
-	.num_controls		= ARRAY_SIZE(ak4613_snd_controls),
-	.dapm_widgets		= ak4613_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(ak4613_dapm_widgets),
-	.dapm_routes		= ak4613_intercon,
-	.num_dapm_routes	= ARRAY_SIZE(ak4613_intercon),
+	.component_driver = {
+		.controls		= ak4613_snd_controls,
+		.num_controls		= ARRAY_SIZE(ak4613_snd_controls),
+		.dapm_widgets		= ak4613_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4613_dapm_widgets),
+		.dapm_routes		= ak4613_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(ak4613_intercon),
+	},
 };
 
 static void ak4613_parse_of(struct ak4613_priv *priv,
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index b14176f8d884..c91717d08513 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -505,12 +505,14 @@ static struct snd_soc_dai_driver ak4641_dai[] = {
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
-	.controls		= ak4641_snd_controls,
-	.num_controls		= ARRAY_SIZE(ak4641_snd_controls),
-	.dapm_widgets		= ak4641_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(ak4641_dapm_widgets),
-	.dapm_routes		= ak4641_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),
+	.component_driver = {
+		.controls		= ak4641_snd_controls,
+		.num_controls		= ARRAY_SIZE(ak4641_snd_controls),
+		.dapm_widgets		= ak4641_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4641_dapm_widgets),
+		.dapm_routes		= ak4641_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),
+	},
 	.set_bias_level		= ak4641_set_bias_level,
 	.suspend_bias_off	= true,
 };
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index cc941d66ec3d..2609f95b7d19 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -555,12 +555,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
 	.suspend		= ak4642_suspend,
 	.resume			= ak4642_resume,
 	.set_bias_level		= ak4642_set_bias_level,
-	.controls		= ak4642_snd_controls,
-	.num_controls		= ARRAY_SIZE(ak4642_snd_controls),
-	.dapm_widgets		= ak4642_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(ak4642_dapm_widgets),
-	.dapm_routes		= ak4642_intercon,
-	.num_dapm_routes	= ARRAY_SIZE(ak4642_intercon),
+	.component_driver = {
+		.controls		= ak4642_snd_controls,
+		.num_controls		= ARRAY_SIZE(ak4642_snd_controls),
+		.dapm_widgets		= ak4642_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4642_dapm_widgets),
+		.dapm_routes		= ak4642_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(ak4642_intercon),
+	},
 };
 
 static const struct regmap_config ak4642_regmap = {
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index c73a9f6914b6..6088afaabf62 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -612,12 +612,14 @@ static struct snd_soc_dai_driver ak4671_dai = {
 
 static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
 	.set_bias_level = ak4671_set_bias_level,
-	.controls = ak4671_snd_controls,
-	.num_controls = ARRAY_SIZE(ak4671_snd_controls),
-	.dapm_widgets = ak4671_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets),
-	.dapm_routes = ak4671_intercon,
-	.num_dapm_routes = ARRAY_SIZE(ak4671_intercon),
+	.component_driver = {
+		.controls		= ak4671_snd_controls,
+		.num_controls		= ARRAY_SIZE(ak4671_snd_controls),
+		.dapm_widgets		= ak4671_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak4671_dapm_widgets),
+		.dapm_routes		= ak4671_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(ak4671_intercon),
+	},
 };
 
 static const struct regmap_config ak4671_regmap = {
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
index afa95360826d..0ef2df223336 100644
--- a/sound/soc/codecs/ak5386.c
+++ b/sound/soc/codecs/ak5386.c
@@ -74,10 +74,12 @@ static struct snd_soc_codec_driver soc_codec_ak5386 = {
 	.remove = ak5386_soc_remove,
 	.suspend = ak5386_soc_suspend,
 	.resume = ak5386_soc_resume,
-	.dapm_widgets = ak5386_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets),
-	.dapm_routes = ak5386_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= ak5386_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ak5386_dapm_widgets),
+		.dapm_routes		= ak5386_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ak5386_dapm_routes),
+	},
 };
 
 static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index 4d3ba33eb6f9..adb80d8719bd 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -1072,12 +1072,14 @@ static const struct snd_soc_codec_driver soc_codec_device_alc5632 = {
 	.set_bias_level = alc5632_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = alc5632_snd_controls,
-	.num_controls = ARRAY_SIZE(alc5632_snd_controls),
-	.dapm_widgets = alc5632_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(alc5632_dapm_widgets),
-	.dapm_routes = alc5632_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(alc5632_dapm_routes),
+	.component_driver = {
+		.controls		= alc5632_snd_controls,
+		.num_controls		= ARRAY_SIZE(alc5632_snd_controls),
+		.dapm_widgets		= alc5632_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(alc5632_dapm_widgets),
+		.dapm_routes		= alc5632_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(alc5632_dapm_routes),
+	},
 };
 
 static const struct regmap_config alc5632_regmap = {
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index ecfdbfcae366..846ca079845f 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -109,7 +109,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
 		break;
 	}
 
-	return 0;
+	return arizona_out_ev(w, kcontrol, event);
 }
 
 static irqreturn_t arizona_thermal_warn(int irq, void *data)
@@ -159,12 +159,14 @@ static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
 static const struct snd_soc_dapm_widget arizona_spkl =
 	SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
 			   ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
-			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);
 
 static const struct snd_soc_dapm_widget arizona_spkr =
 	SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
 			   ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
-			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);
 
 int arizona_init_spk(struct snd_soc_codec *codec)
 {
@@ -864,6 +866,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 {
 	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona *arizona = priv->arizona;
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -877,6 +880,18 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 			priv->out_up_pending++;
 			priv->out_up_delay += 17;
 			break;
+		case ARIZONA_OUT4L_ENA_SHIFT:
+		case ARIZONA_OUT4R_ENA_SHIFT:
+			priv->out_up_pending++;
+			switch (arizona->type) {
+			case WM5102:
+			case WM8997:
+				break;
+			default:
+				priv->out_up_delay += 10;
+				break;
+			}
+			break;
 		default:
 			break;
 		}
@@ -889,8 +904,12 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 		case ARIZONA_OUT2R_ENA_SHIFT:
 		case ARIZONA_OUT3L_ENA_SHIFT:
 		case ARIZONA_OUT3R_ENA_SHIFT:
+		case ARIZONA_OUT4L_ENA_SHIFT:
+		case ARIZONA_OUT4R_ENA_SHIFT:
 			priv->out_up_pending--;
-			if (!priv->out_up_pending) {
+			if (!priv->out_up_pending && priv->out_up_delay) {
+				dev_dbg(codec->dev, "Power up delay: %d\n",
+					priv->out_up_delay);
 				msleep(priv->out_up_delay);
 				priv->out_up_delay = 0;
 			}
@@ -911,6 +930,21 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 			priv->out_down_pending++;
 			priv->out_down_delay++;
 			break;
+		case ARIZONA_OUT4L_ENA_SHIFT:
+		case ARIZONA_OUT4R_ENA_SHIFT:
+			priv->out_down_pending++;
+			switch (arizona->type) {
+			case WM5102:
+			case WM8997:
+				break;
+			case WM8998:
+			case WM1814:
+				priv->out_down_delay += 5;
+				break;
+			default:
+				priv->out_down_delay++;
+				break;
+			}
 		default:
 			break;
 		}
@@ -923,8 +957,12 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 		case ARIZONA_OUT2R_ENA_SHIFT:
 		case ARIZONA_OUT3L_ENA_SHIFT:
 		case ARIZONA_OUT3R_ENA_SHIFT:
+		case ARIZONA_OUT4L_ENA_SHIFT:
+		case ARIZONA_OUT4R_ENA_SHIFT:
 			priv->out_down_pending--;
-			if (!priv->out_down_pending) {
+			if (!priv->out_down_pending && priv->out_down_delay) {
+				dev_dbg(codec->dev, "Power down delay: %d\n",
+					priv->out_down_delay);
 				msleep(priv->out_down_delay);
 				priv->out_down_delay = 0;
 			}
@@ -1920,8 +1958,8 @@ static struct {
 
 struct arizona_fll_cfg {
 	int n;
-	int theta;
-	int lambda;
+	unsigned int theta;
+	unsigned int lambda;
 	int refdiv;
 	int outdiv;
 	int fratio;
@@ -2188,13 +2226,13 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
 				 ARIZONA_FLL1_CTRL_UPD | cfg->n);
 }
 
-static int arizona_is_enabled_fll(struct arizona_fll *fll)
+static int arizona_is_enabled_fll(struct arizona_fll *fll, int base)
 {
 	struct arizona *arizona = fll->arizona;
 	unsigned int reg;
 	int ret;
 
-	ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
+	ret = regmap_read(arizona->regmap, base + 1, &reg);
 	if (ret != 0) {
 		arizona_fll_err(fll, "Failed to read current state: %d\n",
 				ret);
@@ -2208,21 +2246,24 @@ static int arizona_enable_fll(struct arizona_fll *fll)
 {
 	struct arizona *arizona = fll->arizona;
 	bool use_sync = false;
-	int already_enabled = arizona_is_enabled_fll(fll);
+	int already_enabled = arizona_is_enabled_fll(fll, fll->base);
+	int sync_enabled = arizona_is_enabled_fll(fll, fll->base + 0x10);
 	struct arizona_fll_cfg cfg;
 	int i;
 	unsigned int val;
 
 	if (already_enabled < 0)
 		return already_enabled;
+	if (sync_enabled < 0)
+		return sync_enabled;
 
 	if (already_enabled) {
 		/* Facilitate smooth refclk across the transition */
-		regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
-					 ARIZONA_FLL1_GAIN_MASK, 0);
 		regmap_update_bits(fll->arizona->regmap, fll->base + 1,
 				   ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
 		udelay(32);
+		regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
+					 ARIZONA_FLL1_GAIN_MASK, 0);
 	}
 
 	/*
@@ -2233,6 +2274,10 @@ static int arizona_enable_fll(struct arizona_fll *fll)
 	    fll->ref_src != fll->sync_src) {
 		arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
 
+		/* Ref path hardcodes lambda to 65536 when sync is on */
+		if (fll->sync_src >= 0 && cfg.lambda)
+			cfg.theta = (cfg.theta * (1 << 16)) / cfg.lambda;
+
 		arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
 				  false);
 		if (fll->sync_src >= 0) {
@@ -2255,6 +2300,9 @@ static int arizona_enable_fll(struct arizona_fll *fll)
 		return -EINVAL;
 	}
 
+	if (already_enabled && !!sync_enabled != use_sync)
+		arizona_fll_warn(fll, "Synchroniser changed on active FLL\n");
+
 	/*
 	 * Increase the bandwidth if we're not using a low frequency
 	 * sync source.
@@ -2268,14 +2316,14 @@ static int arizona_enable_fll(struct arizona_fll *fll)
 					 ARIZONA_FLL1_SYNC_BW);
 
 	if (!already_enabled)
-		pm_runtime_get(arizona->dev);
+		pm_runtime_get_sync(arizona->dev);
 
-	regmap_update_bits_async(arizona->regmap, fll->base + 1,
-				 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
 	if (use_sync)
 		regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
 					 ARIZONA_FLL1_SYNC_ENA,
 					 ARIZONA_FLL1_SYNC_ENA);
+	regmap_update_bits_async(arizona->regmap, fll->base + 1,
+				 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
 
 	if (already_enabled)
 		regmap_update_bits_async(arizona->regmap, fll->base + 1,
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 69da1ef3a17c..850aa338ba29 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -190,20 +190,21 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
 
 #define ARIZONA_DSP_ROUTES(name) \
 	{ name, NULL, name " Preloader"}, \
-	{ name " Preloader", NULL, name " Aux 1" }, \
-	{ name " Preloader", NULL, name " Aux 2" }, \
-	{ name " Preloader", NULL, name " Aux 3" }, \
-	{ name " Preloader", NULL, name " Aux 4" }, \
-	{ name " Preloader", NULL, name " Aux 5" }, \
-	{ name " Preloader", NULL, name " Aux 6" }, \
+	{ name " Preloader", NULL, "SYSCLK" }, \
+	{ name, NULL, name " Aux 1" }, \
+	{ name, NULL, name " Aux 2" }, \
+	{ name, NULL, name " Aux 3" }, \
+	{ name, NULL, name " Aux 4" }, \
+	{ name, NULL, name " Aux 5" }, \
+	{ name, NULL, name " Aux 6" }, \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \
-	ARIZONA_MIXER_ROUTES(name " Preloader", name "L"), \
-	ARIZONA_MIXER_ROUTES(name " Preloader", name "R")
+	ARIZONA_MIXER_ROUTES(name, name "L"), \
+	ARIZONA_MIXER_ROUTES(name, name "R")
 
 #define ARIZONA_EQ_CONTROL(xname, xbase)                      \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,   \
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
index 2a8d0ee141d4..8014e697d540 100644
--- a/sound/soc/codecs/bt-sco.c
+++ b/sound/soc/codecs/bt-sco.c
@@ -63,10 +63,12 @@ static struct snd_soc_dai_driver bt_sco_dai[] = {
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
-	.dapm_widgets = bt_sco_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets),
-	.dapm_routes = bt_sco_routes,
-	.num_dapm_routes = ARRAY_SIZE(bt_sco_routes),
+	.component_driver = {
+		.dapm_widgets		= bt_sco_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(bt_sco_widgets),
+		.dapm_routes		= bt_sco_routes,
+		.num_dapm_routes	= ARRAY_SIZE(bt_sco_routes),
+	},
 };
 
 static int bt_sco_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index 1c895a53001d..7a2d9a2ee427 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -131,8 +131,10 @@ static struct regmap *cq93vc_get_regmap(struct device *dev)
 static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
 	.set_bias_level = cq93vc_set_bias_level,
 	.get_regmap = cq93vc_get_regmap,
-	.controls = cq93vc_snd_controls,
-	.num_controls = ARRAY_SIZE(cq93vc_snd_controls),
+	.component_driver = {
+		.controls = cq93vc_snd_controls,
+		.num_controls = ARRAY_SIZE(cq93vc_snd_controls),
+	},
 };
 
 static int cq93vc_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index 287d13740be4..7e9806206648 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -231,13 +231,14 @@ static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec,
 static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
 	.set_sysclk = cs35l32_codec_set_sysclk,
 
-	.dapm_widgets = cs35l32_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs35l32_dapm_widgets),
-	.dapm_routes = cs35l32_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cs35l32_audio_map),
-
-	.controls = cs35l32_snd_controls,
-	.num_controls = ARRAY_SIZE(cs35l32_snd_controls),
+	.component_driver = {
+		.controls		= cs35l32_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs35l32_snd_controls),
+		.dapm_widgets		= cs35l32_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs35l32_dapm_widgets),
+		.dapm_routes		= cs35l32_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cs35l32_audio_map),
+	},
 };
 
 /* Current and threshold powerup sequence Pg37 in datasheet */
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c
index 6f9c1addcd7f..6df29fa30fb9 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -837,13 +837,14 @@ static struct snd_soc_codec_driver soc_codec_dev_cs35l33 = {
 	.set_bias_level = cs35l33_set_bias_level,
 	.set_sysclk = cs35l33_codec_set_sysclk,
 
-	.dapm_widgets = cs35l33_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs35l33_dapm_widgets),
-	.dapm_routes = cs35l33_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cs35l33_audio_map),
-	.controls = cs35l33_snd_controls,
-	.num_controls = ARRAY_SIZE(cs35l33_snd_controls),
-
+	.component_driver = {
+		.controls		= cs35l33_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs35l33_snd_controls),
+		.dapm_widgets		= cs35l33_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs35l33_dapm_widgets),
+		.dapm_routes		= cs35l33_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cs35l33_audio_map),
+	},
 	.idle_bias_off = true,
 };
 
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index 55db19ddc5ff..fd966bb851cb 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -547,13 +547,14 @@ static struct snd_soc_dai_driver cs4265_dai[] = {
 static const struct snd_soc_codec_driver soc_codec_cs4265 = {
 	.set_bias_level = cs4265_set_bias_level,
 
-	.dapm_widgets = cs4265_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs4265_dapm_widgets),
-	.dapm_routes = cs4265_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cs4265_audio_map),
-
-	.controls = cs4265_snd_controls,
-	.num_controls = ARRAY_SIZE(cs4265_snd_controls),
+	.component_driver = {
+		.controls		= cs4265_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs4265_snd_controls),
+		.dapm_widgets		= cs4265_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs4265_dapm_widgets),
+		.dapm_routes		= cs4265_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cs4265_audio_map),
+	},
 };
 
 static const struct regmap_config cs4265_regmap = {
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index e07807d96b68..18baea2f7d65 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -617,12 +617,14 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
 	.suspend =		cs4270_soc_suspend,
 	.resume =		cs4270_soc_resume,
 
-	.controls =		cs4270_snd_controls,
-	.num_controls =		ARRAY_SIZE(cs4270_snd_controls),
-	.dapm_widgets =		cs4270_dapm_widgets,
-	.num_dapm_widgets =	ARRAY_SIZE(cs4270_dapm_widgets),
-	.dapm_routes =		cs4270_dapm_routes,
-	.num_dapm_routes =	ARRAY_SIZE(cs4270_dapm_routes),
+	.component_driver = {
+		.controls =		cs4270_snd_controls,
+		.num_controls =		ARRAY_SIZE(cs4270_snd_controls),
+		.dapm_widgets =		cs4270_dapm_widgets,
+		.num_dapm_widgets =	ARRAY_SIZE(cs4270_dapm_widgets),
+		.dapm_routes =		cs4270_dapm_routes,
+		.num_dapm_routes =	ARRAY_SIZE(cs4270_dapm_routes),
+	},
 };
 
 /*
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index 0c0010b25421..8c0f3b89b5bc 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -645,12 +645,14 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
 	.suspend		= cs4271_soc_suspend,
 	.resume			= cs4271_soc_resume,
 
-	.controls		= cs4271_snd_controls,
-	.num_controls		= ARRAY_SIZE(cs4271_snd_controls),
-	.dapm_widgets		= cs4271_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(cs4271_dapm_widgets),
-	.dapm_routes		= cs4271_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(cs4271_dapm_routes),
+	.component_driver = {
+		.controls		= cs4271_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs4271_snd_controls),
+		.dapm_widgets		= cs4271_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs4271_dapm_widgets),
+		.dapm_routes		= cs4271_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(cs4271_dapm_routes),
+	},
 };
 
 static int cs4271_common_probe(struct device *dev,
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 35488f14e237..96cfe38943cd 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -507,12 +507,14 @@ static int cs42l51_codec_probe(struct snd_soc_codec *codec)
 static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
 	.probe = cs42l51_codec_probe,
 
-	.controls = cs42l51_snd_controls,
-	.num_controls = ARRAY_SIZE(cs42l51_snd_controls),
-	.dapm_widgets = cs42l51_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs42l51_dapm_widgets),
-	.dapm_routes = cs42l51_routes,
-	.num_dapm_routes = ARRAY_SIZE(cs42l51_routes),
+	.component_driver = {
+		.controls		= cs42l51_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs42l51_snd_controls),
+		.dapm_widgets		= cs42l51_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs42l51_dapm_widgets),
+		.dapm_routes		= cs42l51_routes,
+		.num_dapm_routes	= ARRAY_SIZE(cs42l51_routes),
+	},
 };
 
 const struct regmap_config cs42l51_regmap = {
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 47b97fcefb0b..0d9c4a57301b 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -1056,13 +1056,14 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
 	.set_bias_level = cs42l52_set_bias_level,
 	.suspend_bias_off = true,
 
-	.dapm_widgets = cs42l52_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets),
-	.dapm_routes = cs42l52_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cs42l52_audio_map),
-
-	.controls = cs42l52_snd_controls,
-	.num_controls = ARRAY_SIZE(cs42l52_snd_controls),
+	.component_driver = {
+		.controls		= cs42l52_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs42l52_snd_controls),
+		.dapm_widgets		= cs42l52_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs42l52_dapm_widgets),
+		.dapm_routes		= cs42l52_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cs42l52_audio_map),
+	},
 };
 
 /* Current and threshold powerup sequence Pg37 */
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index eec1ff853b98..54c1768bc818 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -1121,13 +1121,14 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
 	.set_bias_level = cs42l56_set_bias_level,
 	.suspend_bias_off = true,
 
-	.dapm_widgets = cs42l56_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets),
-	.dapm_routes = cs42l56_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cs42l56_audio_map),
-
-	.controls = cs42l56_snd_controls,
-	.num_controls = ARRAY_SIZE(cs42l56_snd_controls),
+	.component_driver = {
+		.controls		= cs42l56_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs42l56_snd_controls),
+		.dapm_widgets		= cs42l56_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs42l56_dapm_widgets),
+		.dapm_routes		= cs42l56_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cs42l56_audio_map),
+	},
 };
 
 static const struct regmap_config cs42l56_regmap = {
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 42a8fd4e1f9b..71ba5605495f 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -794,7 +794,7 @@ struct cs42l73_mclk_div {
 	u8 mmcc;
 };
 
-static struct cs42l73_mclk_div cs42l73_mclk_coeffs[] = {
+static const struct cs42l73_mclk_div cs42l73_mclk_coeffs[] = {
 	/* MCLK, Sample Rate, xMMCC[5:0] */
 	{5644800, 11025, 0x30},
 	{5644800, 22050, 0x20},
@@ -844,7 +844,7 @@ struct cs42l73_mclkx_div {
 	u8 mclkdiv;
 };
 
-static struct cs42l73_mclkx_div cs42l73_mclkx_coeffs[] = {
+static const struct cs42l73_mclkx_div cs42l73_mclkx_coeffs[] = {
 	{5644800,  1, 0},	/* 5644800 */
 	{6000000,  1, 0},	/* 6000000 */
 	{6144000,  1, 0},	/* 6144000 */
@@ -1257,13 +1257,14 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
 	.set_bias_level = cs42l73_set_bias_level,
 	.suspend_bias_off = true,
 
-	.dapm_widgets = cs42l73_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs42l73_dapm_widgets),
-	.dapm_routes = cs42l73_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cs42l73_audio_map),
-
-	.controls = cs42l73_snd_controls,
-	.num_controls = ARRAY_SIZE(cs42l73_snd_controls),
+	.component_driver = {
+		.controls		= cs42l73_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs42l73_snd_controls),
+		.dapm_widgets		= cs42l73_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs42l73_dapm_widgets),
+		.dapm_routes		= cs42l73_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cs42l73_audio_map),
+	},
 };
 
 static const struct regmap_config cs42l73_regmap = {
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
index 1179101b2b05..b4d87379d2bc 100644
--- a/sound/soc/codecs/cs42xx8.c
+++ b/sound/soc/codecs/cs42xx8.c
@@ -411,12 +411,14 @@ static const struct snd_soc_codec_driver cs42xx8_driver = {
 	.probe = cs42xx8_codec_probe,
 	.idle_bias_off = true,
 
-	.controls = cs42xx8_snd_controls,
-	.num_controls = ARRAY_SIZE(cs42xx8_snd_controls),
-	.dapm_widgets = cs42xx8_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets),
-	.dapm_routes = cs42xx8_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes),
+	.component_driver = {
+		.controls		= cs42xx8_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs42xx8_snd_controls),
+		.dapm_widgets		= cs42xx8_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs42xx8_dapm_widgets),
+		.dapm_routes		= cs42xx8_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(cs42xx8_dapm_routes),
+	},
 };
 
 const struct cs42xx8_driver_data cs42448_data = {
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index 0ac8fc5ed4ae..231ca935cdf3 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -256,13 +256,14 @@ static struct snd_soc_dai_driver cs4349_dai = {
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_cs4349 = {
-	.controls		= cs4349_snd_controls,
-	.num_controls		= ARRAY_SIZE(cs4349_snd_controls),
-
-	.dapm_widgets		= cs4349_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(cs4349_dapm_widgets),
-	.dapm_routes		= cs4349_routes,
-	.num_dapm_routes	= ARRAY_SIZE(cs4349_routes),
+	.component_driver = {
+		.controls		= cs4349_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs4349_snd_controls),
+		.dapm_widgets		= cs4349_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs4349_dapm_widgets),
+		.dapm_routes		= cs4349_routes,
+		.num_dapm_routes	= ARRAY_SIZE(cs4349_routes),
+	},
 };
 
 static const struct regmap_config cs4349_regmap = {
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index 954a4f5d3338..5b22564f037c 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -746,6 +746,16 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = {
 	{ "IN2L", NULL, "SYSCLK" },
 	{ "IN2R", NULL, "SYSCLK" },
 
+	{ "ASRC1L", NULL, "SYSCLK" },
+	{ "ASRC1R", NULL, "SYSCLK" },
+	{ "ASRC2L", NULL, "SYSCLK" },
+	{ "ASRC2R", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "ASYNCCLK" },
+	{ "ASRC1R", NULL, "ASYNCCLK" },
+	{ "ASRC2L", NULL, "ASYNCCLK" },
+	{ "ASRC2R", NULL, "ASYNCCLK" },
+
 	{ "MICBIAS1", NULL, "MICVDD" },
 	{ "MICBIAS2", NULL, "MICVDD" },
 
@@ -804,7 +814,6 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = {
 	{ "AIF3 Capture", NULL, "SYSCLK" },
 
 	{ "Voice Control DSP", NULL, "DSP3" },
-	{ "Voice Control DSP", NULL, "SYSCLK" },
 
 	{ "IN1L PGA", NULL, "IN1L" },
 	{ "IN1R PGA", NULL, "IN1R" },
@@ -813,7 +822,6 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = {
 	{ "IN2R PGA", NULL, "IN2R" },
 
 	{ "Audio Trace DSP", NULL, "DSP2" },
-	{ "Audio Trace DSP", NULL, "SYSCLK" },
 
 	ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
 	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
@@ -1190,12 +1198,14 @@ static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
 	.set_sysclk = arizona_set_sysclk,
 	.set_pll = cs47l24_set_fll,
 
-	.controls = cs47l24_snd_controls,
-	.num_controls = ARRAY_SIZE(cs47l24_snd_controls),
-	.dapm_widgets = cs47l24_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs47l24_dapm_widgets),
-	.dapm_routes = cs47l24_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes),
+	.component_driver = {
+		.controls		= cs47l24_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs47l24_snd_controls),
+		.dapm_widgets		= cs47l24_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs47l24_dapm_widgets),
+		.dapm_routes		= cs47l24_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(cs47l24_dapm_routes),
+	},
 };
 
 static struct snd_compr_ops cs47l24_compr_ops = {
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index 2c0d9c430a8c..cb47fb595ff4 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -466,7 +466,7 @@ struct cs53l30_mclk_div {
 	u8 mclk_int_scale;
 };
 
-static struct cs53l30_mclk_div cs53l30_mclk_coeffs[] = {
+static const struct cs53l30_mclk_div cs53l30_mclk_coeffs[] = {
 	/* NOTE: Enable MCLK_INT_SCALE to save power. */
 
 	/* MCLK, Sample Rate, asp_rate, internal_fs_ratio, mclk_int_scale */
@@ -511,7 +511,7 @@ struct cs53l30_mclkx_div {
 	u8 mclkdiv;
 };
 
-static struct cs53l30_mclkx_div cs53l30_mclkx_coeffs[] = {
+static const struct cs53l30_mclkx_div cs53l30_mclkx_coeffs[] = {
 	{5644800,  1, CS53L30_MCLK_DIV_BY_1},
 	{6000000,  1, CS53L30_MCLK_DIV_BY_1},
 	{6144000,  1, CS53L30_MCLK_DIV_BY_1},
@@ -897,13 +897,14 @@ static struct snd_soc_codec_driver cs53l30_driver = {
 	.set_bias_level = cs53l30_set_bias_level,
 	.idle_bias_off = true,
 
-	.dapm_widgets = cs53l30_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cs53l30_dapm_widgets),
-	.dapm_routes = cs53l30_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(cs53l30_dapm_routes),
-
-	.controls = cs53l30_snd_controls,
-	.num_controls = ARRAY_SIZE(cs53l30_snd_controls),
+	.component_driver = {
+		.controls		= cs53l30_snd_controls,
+		.num_controls		= ARRAY_SIZE(cs53l30_snd_controls),
+		.dapm_widgets		= cs53l30_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cs53l30_dapm_widgets),
+		.dapm_routes		= cs53l30_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(cs53l30_dapm_routes),
+	},
 };
 
 static struct regmap_config cs53l30_regmap = {
@@ -999,8 +1000,8 @@ static int cs53l30_i2c_probe(struct i2c_client *client,
 	/* Check if MCLK provided */
 	cs53l30->mclk = devm_clk_get(dev, "mclk");
 	if (IS_ERR(cs53l30->mclk)) {
-		if (PTR_ERR(cs53l30->mclk) == -EPROBE_DEFER) {
-			ret = -EPROBE_DEFER;
+		if (PTR_ERR(cs53l30->mclk) != -ENOENT) {
+			ret = PTR_ERR(cs53l30->mclk);
 			goto error;
 		}
 		/* Otherwise mark the mclk pointer to NULL */
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index fb3885fe0afb..2c12471e42a6 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -407,10 +407,12 @@ static struct snd_soc_codec_driver cx20442_codec_dev = {
 	.reg_word_size = sizeof(u8),
 	.read = cx20442_read_reg_cache,
 	.write = cx20442_write,
-	.dapm_widgets = cx20442_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets),
-	.dapm_routes = cx20442_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(cx20442_audio_map),
+	.component_driver = {
+		.dapm_widgets		= cx20442_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(cx20442_dapm_widgets),
+		.dapm_routes		= cx20442_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(cx20442_audio_map),
+	},
 };
 
 static int cx20442_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index af23a61b7b28..17053dfc94cf 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -1167,13 +1167,14 @@ static int da7210_probe(struct snd_soc_codec *codec)
 static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
 	.probe			= da7210_probe,
 
-	.controls		= da7210_snd_controls,
-	.num_controls		= ARRAY_SIZE(da7210_snd_controls),
-
-	.dapm_widgets		= da7210_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(da7210_dapm_widgets),
-	.dapm_routes		= da7210_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(da7210_audio_map),
+	.component_driver = {
+		.controls		= da7210_snd_controls,
+		.num_controls		= ARRAY_SIZE(da7210_snd_controls),
+		.dapm_widgets		= da7210_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(da7210_dapm_widgets),
+		.dapm_routes		= da7210_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(da7210_audio_map),
+	},
 };
 
 #if IS_ENABLED(CONFIG_I2C)
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index e5527bc570ae..12da55882c06 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -750,11 +750,18 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w,
 		snd_soc_update_bits(codec, DA7213_PC_COUNT,
 				    DA7213_PC_FREERUN_MASK, 0);
 
-		/* Slave mode, if SRM not enabled no need for status checks */
+		/* If SRM not enabled then nothing more to do */
 		pll_ctrl = snd_soc_read(codec, DA7213_PLL_CTRL);
 		if (!(pll_ctrl & DA7213_PLL_SRM_EN))
 			return 0;
 
+		/* Assist 32KHz mode PLL lock */
+		if (pll_ctrl & DA7213_PLL_32K_MODE) {
+			snd_soc_write(codec, 0xF0, 0x8B);
+			snd_soc_write(codec, 0xF2, 0x03);
+			snd_soc_write(codec, 0xF0, 0x00);
+		}
+
 		/* Check SRM has locked */
 		do {
 			pll_status = snd_soc_read(codec, DA7213_PLL_STATUS);
@@ -771,6 +778,14 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w,
 
 		return 0;
 	case SND_SOC_DAPM_POST_PMD:
+		/* Revert 32KHz PLL lock udpates if applied previously */
+		pll_ctrl = snd_soc_read(codec, DA7213_PLL_CTRL);
+		if (pll_ctrl & DA7213_PLL_32K_MODE) {
+			snd_soc_write(codec, 0xF0, 0x8B);
+			snd_soc_write(codec, 0xF2, 0x01);
+			snd_soc_write(codec, 0xF0, 0x00);
+		}
+
 		/* PC free-running */
 		snd_soc_update_bits(codec, DA7213_PC_COUNT,
 				    DA7213_PC_FREERUN_MASK,
@@ -1247,8 +1262,8 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	/* By default only 32 BCLK per WCLK is supported */
-	dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_32;
+	/* By default only 64 BCLK per WCLK is supported */
+	dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_64;
 
 	snd_soc_write(codec, DA7213_DAI_CLK_MODE, dai_clk_mode);
 	snd_soc_update_bits(codec, DA7213_DAI_CTRL, DA7213_DAI_FORMAT_MASK,
@@ -1297,10 +1312,13 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 
 	switch (clk_id) {
 	case DA7213_CLKSRC_MCLK:
-		da7213->mclk_squarer_en = false;
+		snd_soc_update_bits(codec, DA7213_PLL_CTRL,
+				    DA7213_PLL_MCLK_SQR_EN, 0);
 		break;
 	case DA7213_CLKSRC_MCLK_SQR:
-		da7213->mclk_squarer_en = true;
+		snd_soc_update_bits(codec, DA7213_PLL_CTRL,
+				    DA7213_PLL_MCLK_SQR_EN,
+				    DA7213_PLL_MCLK_SQR_EN);
 		break;
 	default:
 		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
@@ -1324,7 +1342,7 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-/* Supported PLL input frequencies are 5MHz - 54MHz. */
+/* Supported PLL input frequencies are 32KHz, 5MHz - 54MHz. */
 static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 			      int source, unsigned int fref, unsigned int fout)
 {
@@ -1336,22 +1354,26 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	u32 freq_ref;
 	u64 frac_div;
 
-	/* Reset PLL configuration */
-	snd_soc_write(codec, DA7213_PLL_CTRL, 0);
-
-	pll_ctrl = 0;
-
 	/* Workout input divider based on MCLK rate */
 	if (da7213->mclk_rate == 32768) {
+		if (!da7213->master) {
+			dev_err(codec->dev,
+				"32KHz only valid if codec is clock master\n");
+			return -EINVAL;
+		}
+
 		/* 32KHz PLL Mode */
 		indiv_bits = DA7213_PLL_INDIV_9_TO_18_MHZ;
 		indiv = DA7213_PLL_INDIV_9_TO_18_MHZ_VAL;
+		source = DA7213_SYSCLK_PLL_32KHZ;
 		freq_ref = 3750000;
-		pll_ctrl |= DA7213_PLL_32K_MODE;
+
 	} else {
-		/* 5 - 54MHz MCLK */
 		if (da7213->mclk_rate < 5000000) {
-			goto pll_err;
+			dev_err(codec->dev,
+				"PLL input clock %d below valid range\n",
+				da7213->mclk_rate);
+			return -EINVAL;
 		} else if (da7213->mclk_rate <= 9000000) {
 			indiv_bits = DA7213_PLL_INDIV_5_TO_9_MHZ;
 			indiv = DA7213_PLL_INDIV_5_TO_9_MHZ_VAL;
@@ -1365,32 +1387,44 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 			indiv_bits = DA7213_PLL_INDIV_36_TO_54_MHZ;
 			indiv = DA7213_PLL_INDIV_36_TO_54_MHZ_VAL;
 		} else {
-			goto pll_err;
+			dev_err(codec->dev,
+				"PLL input clock %d above valid range\n",
+				da7213->mclk_rate);
+			return -EINVAL;
 		}
 		freq_ref = (da7213->mclk_rate / indiv);
 	}
 
-	pll_ctrl |= indiv_bits;
+	pll_ctrl = indiv_bits;
 
-	/* PLL Bypass mode */
-	if (source == DA7213_SYSCLK_MCLK) {
-		snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl);
+	/* Configure PLL */
+	switch (source) {
+	case DA7213_SYSCLK_MCLK:
+		snd_soc_update_bits(codec, DA7213_PLL_CTRL,
+				    DA7213_PLL_INDIV_MASK |
+				    DA7213_PLL_MODE_MASK, pll_ctrl);
 		return 0;
-	}
+	case DA7213_SYSCLK_PLL:
+		break;
+	case DA7213_SYSCLK_PLL_SRM:
+		pll_ctrl |= DA7213_PLL_SRM_EN;
+		fout = DA7213_PLL_FREQ_OUT_94310400;
+		break;
+	case DA7213_SYSCLK_PLL_32KHZ:
+		if (da7213->mclk_rate != 32768) {
+			dev_err(codec->dev,
+				"32KHz mode only valid with 32KHz MCLK\n");
+			return -EINVAL;
+		}
 
-	/*
-	 * If Codec is slave and SRM enabled,
-	 * freq_out is (98304000 + 90316800)/2 = 94310400
-	 */
-	if (!da7213->master && da7213->srm_en) {
+		pll_ctrl |= DA7213_PLL_32K_MODE | DA7213_PLL_SRM_EN;
 		fout = DA7213_PLL_FREQ_OUT_94310400;
-		pll_ctrl |= DA7213_PLL_SRM_EN;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid PLL config\n");
+		return -EINVAL;
 	}
 
-	/* Enable MCLK squarer if required */
-	if (da7213->mclk_squarer_en)
-		pll_ctrl |= DA7213_PLL_MCLK_SQR_EN;
-
 	/* Calculate dividers for PLL */
 	pll_integer = fout / freq_ref;
 	frac_div = (u64)(fout % freq_ref) * 8192ULL;
@@ -1405,14 +1439,19 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 
 	/* Enable PLL */
 	pll_ctrl |= DA7213_PLL_EN;
-	snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl);
+	snd_soc_update_bits(codec, DA7213_PLL_CTRL,
+			    DA7213_PLL_INDIV_MASK | DA7213_PLL_MODE_MASK,
+			    pll_ctrl);
+
+	/* Assist 32KHz mode PLL lock */
+	if (source == DA7213_SYSCLK_PLL_32KHZ) {
+		snd_soc_write(codec, 0xF0, 0x8B);
+		snd_soc_write(codec, 0xF1, 0x03);
+		snd_soc_write(codec, 0xF1, 0x01);
+		snd_soc_write(codec, 0xF0, 0x00);
+	}
 
 	return 0;
-
-pll_err:
-	dev_err(codec_dai->dev, "Unsupported PLL input frequency %d\n",
-		da7213->mclk_rate);
-	return -EINVAL;
 }
 
 /* DAI operations */
@@ -1454,11 +1493,10 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-	case SND_SOC_BIAS_PREPARE:
 		break;
-	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			/* MCLK */
+	case SND_SOC_BIAS_PREPARE:
+		/* Enable MCLK for transition to ON state */
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
 			if (da7213->mclk) {
 				ret = clk_prepare_enable(da7213->mclk);
 				if (ret) {
@@ -1467,21 +1505,24 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
 					return ret;
 				}
 			}
-
+		}
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			/* Enable VMID reference & master bias */
 			snd_soc_update_bits(codec, DA7213_REFERENCES,
 					    DA7213_VMID_EN | DA7213_BIAS_EN,
 					    DA7213_VMID_EN | DA7213_BIAS_EN);
+		} else {
+			/* Remove MCLK */
+			if (da7213->mclk)
+				clk_disable_unprepare(da7213->mclk);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* Disable VMID reference & master bias */
 		snd_soc_update_bits(codec, DA7213_REFERENCES,
 				    DA7213_VMID_EN | DA7213_BIAS_EN, 0);
-
-		/* MCLK */
-		if (da7213->mclk)
-			clk_disable_unprepare(da7213->mclk);
 		break;
 	}
 	return 0;
@@ -1605,9 +1646,6 @@ static int da7213_probe(struct snd_soc_codec *codec)
 			    DA7213_ALC_CALIB_MODE_MAN, 0);
 	da7213->alc_calib_auto = true;
 
-	/* Default to using SRM for slave mode */
-	da7213->srm_en = true;
-
 	/* Default PC counter to free-running */
 	snd_soc_update_bits(codec, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK,
 			    DA7213_PC_FREERUN_MASK);
@@ -1740,13 +1778,14 @@ static struct snd_soc_codec_driver soc_codec_dev_da7213 = {
 	.probe			= da7213_probe,
 	.set_bias_level		= da7213_set_bias_level,
 
-	.controls		= da7213_snd_controls,
-	.num_controls		= ARRAY_SIZE(da7213_snd_controls),
-
-	.dapm_widgets		= da7213_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(da7213_dapm_widgets),
-	.dapm_routes		= da7213_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(da7213_audio_map),
+	.component_driver = {
+		.controls		= da7213_snd_controls,
+		.num_controls		= ARRAY_SIZE(da7213_snd_controls),
+		.dapm_widgets		= da7213_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(da7213_dapm_widgets),
+		.dapm_routes		= da7213_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(da7213_audio_map),
+	},
 };
 
 static const struct regmap_config da7213_regmap_config = {
diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h
index fbb7a356a501..16ef56f77cd4 100644
--- a/sound/soc/codecs/da7213.h
+++ b/sound/soc/codecs/da7213.h
@@ -172,6 +172,7 @@
 #define DA7213_PLL_32K_MODE					(0x1 << 5)
 #define DA7213_PLL_SRM_EN					(0x1 << 6)
 #define DA7213_PLL_EN						(0x1 << 7)
+#define DA7213_PLL_MODE_MASK					(0x7 << 5)
 
 /* DA7213_DAI_CLK_MODE = 0x28 */
 #define DA7213_DAI_BCLKS_PER_WCLK_32				(0x0 << 0)
@@ -499,8 +500,6 @@
 #define DA7213_ALC_AVG_ITERATIONS	5
 
 /* PLL related */
-#define DA7213_SYSCLK_MCLK			0
-#define DA7213_SYSCLK_PLL			1
 #define DA7213_PLL_FREQ_OUT_90316800		90316800
 #define DA7213_PLL_FREQ_OUT_98304000		98304000
 #define DA7213_PLL_FREQ_OUT_94310400		94310400
@@ -515,6 +514,13 @@ enum da7213_clk_src {
 	DA7213_CLKSRC_MCLK_SQR,
 };
 
+enum da7213_sys_clk {
+	DA7213_SYSCLK_MCLK = 0,
+	DA7213_SYSCLK_PLL,
+	DA7213_SYSCLK_PLL_SRM,
+	DA7213_SYSCLK_PLL_32KHZ
+};
+
 /* Codec private data */
 struct da7213_priv {
 	struct regmap *regmap;
@@ -522,8 +528,6 @@ struct da7213_priv {
 	unsigned int mclk_rate;
 	int clk_src;
 	bool master;
-	bool mclk_squarer_en;
-	bool srm_en;
 	bool alc_calib_auto;
 	bool alc_en;
 	struct da7213_platform_data *pdata;
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index 99ce23e113bf..c69e97654fc6 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -1819,7 +1819,7 @@ static int da7218_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	if (da7218->mclk_rate == freq)
 		return 0;
 
-	if (((freq < 2000000) && (freq != 32768)) || (freq > 54000000)) {
+	if ((freq < 2000000) || (freq > 54000000)) {
 		dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
 			freq);
 		return -EINVAL;
@@ -1866,11 +1866,8 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	u32 freq_ref;
 	u64 frac_div;
 
-	/* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */
-	if (da7218->mclk_rate == 32768) {
-		indiv_bits = DA7218_PLL_INDIV_9_TO_18_MHZ;
-		indiv = DA7218_PLL_INDIV_9_TO_18_MHZ_VAL;
-	} else if (da7218->mclk_rate < 2000000) {
+	/* Verify 2MHz - 54MHz MCLK provided, and set input divider */
+	if (da7218->mclk_rate < 2000000) {
 		dev_err(codec->dev, "PLL input clock %d below valid range\n",
 			da7218->mclk_rate);
 		return -EINVAL;
@@ -1911,9 +1908,6 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	case DA7218_SYSCLK_PLL_SRM:
 		pll_ctrl |= DA7218_PLL_MODE_SRM;
 		break;
-	case DA7218_SYSCLK_PLL_32KHZ:
-		pll_ctrl |= DA7218_PLL_MODE_32KHZ;
-		break;
 	default:
 		dev_err(codec->dev, "Invalid PLL config\n");
 		return -EINVAL;
@@ -2589,20 +2583,22 @@ static int da7218_set_bias_level(struct snd_soc_codec *codec,
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-	case SND_SOC_BIAS_PREPARE:
 		break;
-	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			/* MCLK */
+	case SND_SOC_BIAS_PREPARE:
+		/* Enable MCLK for transition to ON state */
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
 			if (da7218->mclk) {
 				ret = clk_prepare_enable(da7218->mclk);
 				if (ret) {
-					dev_err(codec->dev,
-						"Failed to enable mclk\n");
+					dev_err(codec->dev, "Failed to enable mclk\n");
 					return ret;
 				}
 			}
+		}
 
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			/* Master bias */
 			snd_soc_update_bits(codec, DA7218_REFERENCES,
 					    DA7218_BIAS_EN_MASK,
@@ -2612,6 +2608,10 @@ static int da7218_set_bias_level(struct snd_soc_codec *codec,
 			snd_soc_update_bits(codec, DA7218_LDO_CTRL,
 					    DA7218_LDO_EN_MASK,
 					    DA7218_LDO_EN_MASK);
+		} else {
+			/* Remove MCLK */
+			if (da7218->mclk)
+				clk_disable_unprepare(da7218->mclk);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
@@ -2625,10 +2625,6 @@ static int da7218_set_bias_level(struct snd_soc_codec *codec,
 			snd_soc_update_bits(codec, DA7218_REFERENCES,
 					    DA7218_BIAS_EN_MASK, 0);
 		}
-
-		/* MCLK */
-		if (da7218->mclk)
-			clk_disable_unprepare(da7218->mclk);
 		break;
 	}
 
@@ -3045,13 +3041,14 @@ static struct snd_soc_codec_driver soc_codec_dev_da7218 = {
 	.resume			= da7218_resume,
 	.set_bias_level		= da7218_set_bias_level,
 
-	.controls		= da7218_snd_controls,
-	.num_controls		= ARRAY_SIZE(da7218_snd_controls),
-
-	.dapm_widgets		= da7218_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(da7218_dapm_widgets),
-	.dapm_routes		= da7218_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(da7218_audio_map),
+	.component_driver = {
+		.controls		= da7218_snd_controls,
+		.num_controls		= ARRAY_SIZE(da7218_snd_controls),
+		.dapm_widgets		= da7218_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(da7218_dapm_widgets),
+		.dapm_routes		= da7218_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(da7218_audio_map),
+	},
 };
 
 
diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h
index 477cd37723cf..4f7ec21069a4 100644
--- a/sound/soc/codecs/da7218.h
+++ b/sound/soc/codecs/da7218.h
@@ -888,7 +888,6 @@
 #define DA7218_PLL_MODE_BYPASS		(0x0 << 6)
 #define DA7218_PLL_MODE_NORMAL		(0x1 << 6)
 #define DA7218_PLL_MODE_SRM		(0x2 << 6)
-#define DA7218_PLL_MODE_32KHZ		(0x3 << 6)
 
 /* DA7218_PLL_FRAC_TOP = 0x92 */
 #define DA7218_PLL_FBDIV_FRAC_TOP_SHIFT	0
@@ -1371,7 +1370,6 @@ enum da7218_sys_clk {
 	DA7218_SYSCLK_MCLK = 0,
 	DA7218_SYSCLK_PLL,
 	DA7218_SYSCLK_PLL_SRM,
-	DA7218_SYSCLK_PLL_32KHZ
 };
 
 enum da7218_dev_id {
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
index f0057cd223a4..2b8914dd5990 100644
--- a/sound/soc/codecs/da7219-aad.c
+++ b/sound/soc/codecs/da7219-aad.c
@@ -13,6 +13,7 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 #include <linux/i2c.h>
 #include <linux/property.h>
 #include <linux/pm_wakeirq.h>
@@ -114,13 +115,38 @@ static void da7219_aad_hptest_work(struct work_struct *work)
 	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 
 	u16 tonegen_freq_hptest;
-	u8 accdet_cfg8;
-	int report = 0;
+	u8 pll_srm_sts, gain_ramp_ctrl, accdet_cfg8;
+	int report = 0, ret = 0;
 
 	/* Lock DAPM and any Kcontrols that are affected by this test */
 	snd_soc_dapm_mutex_lock(dapm);
 	mutex_lock(&da7219->lock);
 
+	/* Ensure MCLK is available for HP test procedure */
+	if (da7219->mclk) {
+		ret = clk_prepare_enable(da7219->mclk);
+		if (ret) {
+			dev_err(codec->dev, "Failed to enable mclk - %d\n", ret);
+			mutex_unlock(&da7219->lock);
+			snd_soc_dapm_mutex_unlock(dapm);
+			return;
+		}
+	}
+
+	/*
+	 * If MCLK not present, then we're using the internal oscillator and
+	 * require different frequency settings to achieve the same result.
+	 */
+	pll_srm_sts = snd_soc_read(codec, DA7219_PLL_SRM_STS);
+	if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK)
+		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);
+	else
+		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC);
+
+	/* Ensure gain ramping at fastest rate */
+	gain_ramp_ctrl = snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL);
+	snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8);
+
 	/* Bypass cache so it saves current settings */
 	regcache_cache_bypass(da7219->regmap, true);
 
@@ -183,9 +209,15 @@ static void da7219_aad_hptest_work(struct work_struct *work)
 	snd_soc_write(codec, DA7219_HP_R_CTRL,
 		      DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
 
+	/*
+	 * If we're running from the internal oscillator then give audio paths
+	 * time to settle before running test.
+	 */
+	if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
+		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
+
 	/* Configure & start Tone Generator */
 	snd_soc_write(codec, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK);
-	tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);
 	regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
 			 &tonegen_freq_hptest, sizeof(tonegen_freq_hptest));
 	snd_soc_update_bits(codec, DA7219_TONE_GEN_CFG2,
@@ -244,12 +276,26 @@ static void da7219_aad_hptest_work(struct work_struct *work)
 	snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8,
 			    DA7219_HPTEST_EN_MASK, 0);
 
+	/*
+	 * If we're running from the internal oscillator then give audio paths
+	 * time to settle before allowing headphones to be driven as required.
+	 */
+	if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
+		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
+
+	/* Restore gain ramping rate */
+	snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl);
+
 	/* Drive Headphones/lineout */
 	snd_soc_update_bits(codec, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK,
 			    DA7219_HP_L_AMP_OE_MASK);
 	snd_soc_update_bits(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK,
 			    DA7219_HP_R_AMP_OE_MASK);
 
+	/* Remove MCLK, if previously enabled */
+	if (da7219->mclk)
+		clk_disable_unprepare(da7219->mclk);
+
 	mutex_unlock(&da7219->lock);
 	snd_soc_dapm_mutex_unlock(dapm);
 
@@ -751,6 +797,62 @@ static void da7219_aad_handle_pdata(struct snd_soc_codec *codec)
 
 
 /*
+ * Suspend/Resume
+ */
+
+void da7219_aad_suspend(struct snd_soc_codec *codec)
+{
+	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_aad_priv *da7219_aad = da7219->aad;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	u8 micbias_ctrl;
+
+	if (da7219_aad->jack) {
+		/* Disable jack detection during suspend */
+		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+				    DA7219_ACCDET_EN_MASK, 0);
+
+		/*
+		 * If we have a 4-pole jack inserted, then micbias will be
+		 * enabled. We can disable micbias here, and keep a note to
+		 * re-enable it on resume. If jack removal occurred during
+		 * suspend then this will be dealt with through the IRQ handler.
+		 */
+		if (da7219_aad->jack_inserted) {
+			micbias_ctrl = snd_soc_read(codec, DA7219_MICBIAS_CTRL);
+			if (micbias_ctrl & DA7219_MICBIAS1_EN_MASK) {
+				snd_soc_dapm_disable_pin(dapm, "Mic Bias");
+				snd_soc_dapm_sync(dapm);
+				da7219_aad->micbias_resume_enable = true;
+			}
+		}
+	}
+}
+
+void da7219_aad_resume(struct snd_soc_codec *codec)
+{
+	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_aad_priv *da7219_aad = da7219->aad;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+	if (da7219_aad->jack) {
+		/* Re-enable micbias if previously enabled for 4-pole jack */
+		if (da7219_aad->jack_inserted &&
+		    da7219_aad->micbias_resume_enable) {
+			snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
+			snd_soc_dapm_sync(dapm);
+			da7219_aad->micbias_resume_enable = false;
+		}
+
+		/* Re-enable jack detection */
+		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+				    DA7219_ACCDET_EN_MASK,
+				    DA7219_ACCDET_EN_MASK);
+	}
+}
+
+
+/*
  * Init/Exit
  */
 
diff --git a/sound/soc/codecs/da7219-aad.h b/sound/soc/codecs/da7219-aad.h
index 4fccf677cd06..117a3d7ccd31 100644
--- a/sound/soc/codecs/da7219-aad.h
+++ b/sound/soc/codecs/da7219-aad.h
@@ -176,8 +176,10 @@
 #define DA7219_AAD_MICBIAS_CHK_DELAY	10
 #define DA7219_AAD_MICBIAS_CHK_RETRIES	5
 
-#define DA7219_AAD_HPTEST_RAMP_FREQ	0x28
-#define DA7219_AAD_HPTEST_PERIOD	65
+#define DA7219_AAD_HPTEST_RAMP_FREQ		0x28
+#define DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC	0x4D
+#define DA7219_AAD_HPTEST_PERIOD		65
+#define DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY	20
 
 enum da7219_aad_event_regs {
 	DA7219_AAD_IRQ_REG_A = 0,
@@ -199,12 +201,17 @@ struct da7219_aad_priv {
 	struct work_struct hptest_work;
 
 	struct snd_soc_jack *jack;
+	bool micbias_resume_enable;
 	bool jack_inserted;
 };
 
 /* AAD control */
 void da7219_aad_jack_det(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
 
+/* Suspend/Resume */
+void da7219_aad_suspend(struct snd_soc_codec *codec);
+void da7219_aad_resume(struct snd_soc_codec *codec);
+
 /* Init/Exit */
 int da7219_aad_init(struct snd_soc_codec *codec);
 void da7219_aad_exit(struct snd_soc_codec *codec);
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 50ea94317cb3..1152aa5e7c39 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -801,7 +801,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
 				++i;
 				msleep(50);
 			}
-		} while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock));
+		} while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock));
 
 		if (!srm_lock)
 			dev_warn(codec->dev, "SRM failed to lock\n");
@@ -1482,6 +1482,8 @@ static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_codec *codec)
 	if (!pdata)
 		return NULL;
 
+	pdata->wakeup_source = device_property_read_bool(dev, "wakeup-source");
+
 	if (device_property_read_u32(dev, "dlg,micbias-lvl", &of_val32) >= 0)
 		pdata->micbias_lvl = da7219_fw_micbias_lvl(dev, of_val32);
 	else
@@ -1508,11 +1510,10 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec,
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-	case SND_SOC_BIAS_PREPARE:
 		break;
-	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			/* MCLK */
+	case SND_SOC_BIAS_PREPARE:
+		/* Enable MCLK for transition to ON state */
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
 			if (da7219->mclk) {
 				ret = clk_prepare_enable(da7219->mclk);
 				if (ret) {
@@ -1521,22 +1522,28 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec,
 					return ret;
 				}
 			}
+		}
 
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
 			/* Master bias */
 			snd_soc_update_bits(codec, DA7219_REFERENCES,
 					    DA7219_BIAS_EN_MASK,
 					    DA7219_BIAS_EN_MASK);
+
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) {
+			/* Remove MCLK */
+			if (da7219->mclk)
+				clk_disable_unprepare(da7219->mclk);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
-		/* Only disable master bias if jack detection not active */
-		if (!da7219->aad->jack)
+		/* Only disable master bias if we're not a wake-up source */
+		if (!da7219->wakeup_source)
 			snd_soc_update_bits(codec, DA7219_REFERENCES,
 					    DA7219_BIAS_EN_MASK, 0);
 
-		/* MCLK */
-		if (da7219->mclk)
-			clk_disable_unprepare(da7219->mclk);
 		break;
 	}
 
@@ -1599,6 +1606,8 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec)
 	if (pdata) {
 		u8 micbias_lvl = 0;
 
+		da7219->wakeup_source = pdata->wakeup_source;
+
 		/* Mic Bias voltages */
 		switch (pdata->micbias_lvl) {
 		case DA7219_MICBIAS_1_6V:
@@ -1733,11 +1742,11 @@ static int da7219_suspend(struct snd_soc_codec *codec)
 {
 	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	/* Suspend AAD if we're not a wake-up source */
+	if (!da7219->wakeup_source)
+		da7219_aad_suspend(codec);
 
-	/* Put device into standby mode if jack detection disabled */
-	if (!da7219->aad->jack)
-		snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, 0);
+	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
 	return 0;
 }
@@ -1746,13 +1755,12 @@ static int da7219_resume(struct snd_soc_codec *codec)
 {
 	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 
-	/* Put device into active mode if previously pushed to standby */
-	if (!da7219->aad->jack)
-		snd_soc_write(codec, DA7219_SYSTEM_ACTIVE,
-			      DA7219_SYSTEM_ACTIVE_MASK);
-
 	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
+	/* Resume AAD if previously suspended */
+	if (!da7219->wakeup_source)
+		da7219_aad_resume(codec);
+
 	return 0;
 }
 #else
@@ -1767,13 +1775,14 @@ static struct snd_soc_codec_driver soc_codec_dev_da7219 = {
 	.resume			= da7219_resume,
 	.set_bias_level		= da7219_set_bias_level,
 
-	.controls		= da7219_snd_controls,
-	.num_controls		= ARRAY_SIZE(da7219_snd_controls),
-
-	.dapm_widgets		= da7219_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(da7219_dapm_widgets),
-	.dapm_routes		= da7219_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(da7219_audio_map),
+	.component_driver = {
+		.controls		= da7219_snd_controls,
+		.num_controls		= ARRAY_SIZE(da7219_snd_controls),
+		.dapm_widgets		= da7219_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(da7219_dapm_widgets),
+		.dapm_routes		= da7219_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(da7219_audio_map),
+	},
 };
 
 
@@ -1921,7 +1930,8 @@ static int da7219_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
 	struct da7219_priv *da7219;
-	int ret;
+	unsigned int system_active, system_status;
+	int i, ret;
 
 	da7219 = devm_kzalloc(&i2c->dev, sizeof(struct da7219_priv),
 			      GFP_KERNEL);
@@ -1937,6 +1947,37 @@ static int da7219_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
+	regcache_cache_bypass(da7219->regmap, true);
+
+	/* Disable audio paths if still active from previous start */
+	regmap_read(da7219->regmap, DA7219_SYSTEM_ACTIVE, &system_active);
+	if (system_active) {
+		regmap_write(da7219->regmap, DA7219_GAIN_RAMP_CTRL,
+			     DA7219_GAIN_RAMP_RATE_NOMINAL);
+		regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_INPUT, 0x00);
+		regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_OUTPUT, 0x01);
+
+		for (i = 0; i < DA7219_SYS_STAT_CHECK_RETRIES; ++i) {
+			regmap_read(da7219->regmap, DA7219_SYSTEM_STATUS,
+				    &system_status);
+			if (!system_status)
+				break;
+
+			msleep(DA7219_SYS_STAT_CHECK_DELAY);
+		}
+	}
+
+	/* Soft reset codec */
+	regmap_write_bits(da7219->regmap, DA7219_ACCDET_CONFIG_1,
+			  DA7219_ACCDET_EN_MASK, 0);
+	regmap_write_bits(da7219->regmap, DA7219_CIF_CTRL,
+			  DA7219_CIF_REG_SOFT_RESET_MASK,
+			  DA7219_CIF_REG_SOFT_RESET_MASK);
+	regmap_write_bits(da7219->regmap, DA7219_SYSTEM_ACTIVE,
+			  DA7219_SYSTEM_ACTIVE_MASK, 0);
+
+	regcache_cache_bypass(da7219->regmap, false);
+
 	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da7219,
 				     &da7219_dai, 1);
 	if (ret < 0) {
diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h
index ff2a2f02ce40..66d3bad86739 100644
--- a/sound/soc/codecs/da7219.h
+++ b/sound/soc/codecs/da7219.h
@@ -224,6 +224,7 @@
 #define DA7219_PLL_SRM_STATE_MASK	(0xF << 0)
 #define DA7219_PLL_SRM_STATUS_SHIFT	4
 #define DA7219_PLL_SRM_STATUS_MASK	(0xF << 4)
+#define DA7219_PLL_SRM_STS_MCLK		(0x1 << 4)
 #define DA7219_PLL_SRM_STS_SRM_LOCK	(0x1 << 7)
 
 /* DA7219_DIG_ROUTING_DAI = 0x2A */
@@ -576,6 +577,8 @@
 /* DA7219_GAIN_RAMP_CTRL = 0x92 */
 #define DA7219_GAIN_RAMP_RATE_SHIFT	0
 #define DA7219_GAIN_RAMP_RATE_MASK	(0x3 << 0)
+#define DA7219_GAIN_RAMP_RATE_X8	(0x0 << 0)
+#define DA7219_GAIN_RAMP_RATE_NOMINAL	(0x1 << 0)
 #define DA7219_GAIN_RAMP_RATE_MAX	4
 
 /* DA7219_PC_COUNT = 0x94 */
@@ -770,6 +773,10 @@
 /* SRM */
 #define DA7219_SRM_CHECK_RETRIES	8
 
+/* System Controller */
+#define DA7219_SYS_STAT_CHECK_RETRIES	6
+#define DA7219_SYS_STAT_CHECK_DELAY	50
+
 enum da7219_clk_src {
 	DA7219_CLKSRC_MCLK = 0,
 	DA7219_CLKSRC_MCLK_SQR,
@@ -796,6 +803,7 @@ struct da7219_priv {
 	struct da7219_aad_priv *aad;
 	struct da7219_pdata *pdata;
 
+	bool wakeup_source;
 	struct regulator_bulk_data supplies[DA7219_NUM_SUPPLIES];
 	struct regmap *regmap;
 	struct mutex lock;
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index 461506a4ca6a..c1cc1c1c28f2 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -1501,12 +1501,14 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
 
 static struct snd_soc_codec_driver soc_codec_dev_da732x = {
 	.set_bias_level		= da732x_set_bias_level,
-	.controls		= da732x_snd_controls,
-	.num_controls		= ARRAY_SIZE(da732x_snd_controls),
-	.dapm_widgets		= da732x_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(da732x_dapm_widgets),
-	.dapm_routes		= da732x_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(da732x_dapm_routes),
+	.component_driver = {
+		.controls		= da732x_snd_controls,
+		.num_controls		= ARRAY_SIZE(da732x_snd_controls),
+		.dapm_widgets		= da732x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(da732x_dapm_widgets),
+		.dapm_routes		= da732x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(da732x_dapm_routes),
+	},
 	.set_pll		= da732x_set_dai_pll,
 };
 
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index 0b2ede8db978..4efb5f897a0c 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -1455,13 +1455,14 @@ static struct snd_soc_codec_driver soc_codec_dev_da9055 = {
 	.probe			= da9055_probe,
 	.set_bias_level		= da9055_set_bias_level,
 
-	.controls		= da9055_snd_controls,
-	.num_controls		= ARRAY_SIZE(da9055_snd_controls),
-
-	.dapm_widgets		= da9055_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(da9055_dapm_widgets),
-	.dapm_routes		= da9055_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(da9055_audio_map),
+	.component_driver = {
+		.controls		= da9055_snd_controls,
+		.num_controls		= ARRAY_SIZE(da9055_snd_controls),
+		.dapm_widgets		= da9055_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(da9055_dapm_widgets),
+		.dapm_routes		= da9055_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(da9055_audio_map),
+	},
 };
 
 static const struct regmap_config da9055_regmap_config = {
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index fde53251c047..c82b9dc41e9a 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -51,10 +51,12 @@ static const struct snd_soc_dapm_route intercon[] = {
 };
 
 static struct snd_soc_codec_driver soc_dmic = {
-	.dapm_widgets = dmic_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets),
-	.dapm_routes = intercon,
-	.num_dapm_routes = ARRAY_SIZE(intercon),
+	.component_driver = {
+		.dapm_widgets		= dmic_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(dmic_dapm_widgets),
+		.dapm_routes		= intercon,
+		.num_dapm_routes	= ARRAY_SIZE(intercon),
+	},
 };
 
 static int dmic_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index 2086d7107622..37722194b107 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -823,12 +823,14 @@ static struct snd_soc_codec_driver es8328_codec_driver = {
 	.set_bias_level	  = es8328_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls	  = es8328_snd_controls,
-	.num_controls	  = ARRAY_SIZE(es8328_snd_controls),
-	.dapm_widgets	  = es8328_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(es8328_dapm_widgets),
-	.dapm_routes	  = es8328_dapm_routes,
-	.num_dapm_routes  = ARRAY_SIZE(es8328_dapm_routes),
+	.component_driver = {
+		.controls		= es8328_snd_controls,
+		.num_controls		= ARRAY_SIZE(es8328_snd_controls),
+		.dapm_widgets		= es8328_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(es8328_dapm_widgets),
+		.dapm_routes		= es8328_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(es8328_dapm_routes),
+	},
 };
 
 int es8328_probe(struct device *dev, struct regmap *regmap)
diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c
index 0b80052996d3..926b1a4e37d4 100644
--- a/sound/soc/codecs/gtm601.c
+++ b/sound/soc/codecs/gtm601.c
@@ -52,10 +52,12 @@ static struct snd_soc_dai_driver gtm601_dai = {
 };
 
 static const struct snd_soc_codec_driver soc_codec_dev_gtm601 = {
-	.dapm_widgets = gtm601_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(gtm601_dapm_widgets),
-	.dapm_routes = gtm601_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(gtm601_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= gtm601_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(gtm601_dapm_widgets),
+		.dapm_routes		= gtm601_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(gtm601_dapm_routes),
+	},
 };
 
 static int gtm601_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 4e181b270d95..c602c4960924 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -614,7 +614,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
 			(!pin->eld.eld_valid)) {
 
 		dev_warn(&hdac->hdac.dev,
-			"Failed: montior present? %d ELD valid?: %d for pin: %d\n",
+			"Failed: monitor present? %d ELD valid?: %d for pin: %d\n",
 			pin->eld.monitor_present, pin->eld.eld_valid, pin->nid);
 
 		return 0;
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index f27d115626db..b904492d7744 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -24,6 +24,15 @@
 
 #include <drm/drm_crtc.h> /* This is only to get MAX_ELD_BYTES */
 
+struct hdmi_device {
+	struct device *dev;
+	struct list_head list;
+	int cnt;
+};
+#define pos_to_hdmi_device(pos)	container_of((pos), struct hdmi_device, list)
+LIST_HEAD(hdmi_device_list);
+
+#define DAI_NAME_SIZE 16
 struct hdmi_codec_priv {
 	struct hdmi_codec_pdata hcd;
 	struct snd_soc_dai_driver *daidrv;
@@ -320,7 +329,6 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = {
 			 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
 
 static struct snd_soc_dai_driver hdmi_i2s_dai = {
-	.name = "i2s-hifi",
 	.id = DAI_ID_I2S,
 	.playback = {
 		.stream_name = "Playback",
@@ -334,7 +342,6 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = {
 };
 
 static const struct snd_soc_dai_driver hdmi_spdif_dai = {
-	.name = "spdif-hifi",
 	.id = DAI_ID_SPDIF,
 	.playback = {
 		.stream_name = "Playback",
@@ -346,13 +353,37 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
 	.ops = &hdmi_dai_ops,
 };
 
+static char hdmi_dai_name[][DAI_NAME_SIZE] = {
+	"hdmi-hifi.0",
+	"hdmi-hifi.1",
+	"hdmi-hifi.2",
+	"hdmi-hifi.3",
+};
+
+static int hdmi_of_xlate_dai_name(struct snd_soc_component *component,
+				  struct of_phandle_args *args,
+				  const char **dai_name)
+{
+	int id = args->args[0];
+
+	if (id < ARRAY_SIZE(hdmi_dai_name)) {
+		*dai_name = hdmi_dai_name[id];
+		return 0;
+	}
+
+	return -EAGAIN;
+}
+
 static struct snd_soc_codec_driver hdmi_codec = {
-	.controls = hdmi_controls,
-	.num_controls = ARRAY_SIZE(hdmi_controls),
-	.dapm_widgets = hdmi_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
-	.dapm_routes = hdmi_routes,
-	.num_dapm_routes = ARRAY_SIZE(hdmi_routes),
+	.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,
+		.num_dapm_routes	= ARRAY_SIZE(hdmi_routes),
+		.of_xlate_dai_name	= hdmi_of_xlate_dai_name,
+	},
 };
 
 static int hdmi_codec_probe(struct platform_device *pdev)
@@ -360,6 +391,8 @@ static int hdmi_codec_probe(struct platform_device *pdev)
 	struct hdmi_codec_pdata *hcd = pdev->dev.platform_data;
 	struct device *dev = &pdev->dev;
 	struct hdmi_codec_priv *hcp;
+	struct hdmi_device *hd;
+	struct list_head *pos;
 	int dai_count, i = 0;
 	int ret;
 
@@ -381,6 +414,31 @@ static int hdmi_codec_probe(struct platform_device *pdev)
 	if (!hcp)
 		return -ENOMEM;
 
+	hd = NULL;
+	list_for_each(pos, &hdmi_device_list) {
+		struct hdmi_device *tmp = pos_to_hdmi_device(pos);
+
+		if (tmp->dev == dev->parent) {
+			hd = tmp;
+			break;
+		}
+	}
+
+	if (!hd) {
+		hd = devm_kzalloc(dev, sizeof(*hd), GFP_KERNEL);
+		if (!hd)
+			return -ENOMEM;
+
+		hd->dev = dev->parent;
+
+		list_add_tail(&hd->list, &hdmi_device_list);
+	}
+
+	if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) {
+		dev_err(dev, "too many hdmi codec are deteced\n");
+		return -EINVAL;
+	}
+
 	hcp->hcd = *hcd;
 	mutex_init(&hcp->current_stream_lock);
 
@@ -393,11 +451,14 @@ static int hdmi_codec_probe(struct platform_device *pdev)
 		hcp->daidrv[i] = hdmi_i2s_dai;
 		hcp->daidrv[i].playback.channels_max =
 			hcd->max_i2s_channels;
+		hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++];
 		i++;
 	}
 
-	if (hcd->spdif)
+	if (hcd->spdif) {
 		hcp->daidrv[i] = hdmi_spdif_dai;
+		hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++];
+	}
 
 	ret = snd_soc_register_codec(dev, &hdmi_codec, hcp->daidrv,
 				     dai_count);
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
index 9b6e8840a1b5..b918ba5c8ce5 100644
--- a/sound/soc/codecs/inno_rk3036.c
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -380,12 +380,14 @@ static struct snd_soc_codec_driver rk3036_codec_driver = {
 	.probe			= rk3036_codec_probe,
 	.remove			= rk3036_codec_remove,
 	.set_bias_level		= rk3036_codec_set_bias_level,
-	.controls		= rk3036_codec_dapm_controls,
-	.num_controls		= ARRAY_SIZE(rk3036_codec_dapm_controls),
-	.dapm_routes		= rk3036_codec_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(rk3036_codec_dapm_routes),
-	.dapm_widgets		= rk3036_codec_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(rk3036_codec_dapm_widgets),
+	.component_driver = {
+		.controls		= rk3036_codec_dapm_controls,
+		.num_controls		= ARRAY_SIZE(rk3036_codec_dapm_controls),
+		.dapm_routes		= rk3036_codec_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rk3036_codec_dapm_routes),
+		.dapm_widgets		= rk3036_codec_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rk3036_codec_dapm_widgets),
+	},
 };
 
 static const struct regmap_config rk3036_codec_regmap_config = {
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index be448373d39a..a4b0eded984a 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -1089,12 +1089,14 @@ static struct snd_soc_dai_driver isabelle_dai[] = {
 
 static struct snd_soc_codec_driver soc_codec_dev_isabelle = {
 	.set_bias_level = isabelle_set_bias_level,
-	.controls = isabelle_snd_controls,
-	.num_controls = ARRAY_SIZE(isabelle_snd_controls),
-	.dapm_widgets = isabelle_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(isabelle_dapm_widgets),
-	.dapm_routes = isabelle_intercon,
-	.num_dapm_routes = ARRAY_SIZE(isabelle_intercon),
+	.component_driver = {
+		.controls		= isabelle_snd_controls,
+		.num_controls		= ARRAY_SIZE(isabelle_snd_controls),
+		.dapm_widgets		= isabelle_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(isabelle_dapm_widgets),
+		.dapm_routes		= isabelle_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(isabelle_intercon),
+	},
 	.idle_bias_off = true,
 };
 
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 1f5ab99956ed..0290fab383da 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -298,12 +298,14 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
 	.set_bias_level = jz4740_codec_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = jz4740_codec_controls,
-	.num_controls = ARRAY_SIZE(jz4740_codec_controls),
-	.dapm_widgets = jz4740_codec_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(jz4740_codec_dapm_widgets),
-	.dapm_routes = jz4740_codec_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes),
+	.component_driver = {
+		.controls		= jz4740_codec_controls,
+		.num_controls		= ARRAY_SIZE(jz4740_codec_controls),
+		.dapm_widgets		= jz4740_codec_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(jz4740_codec_dapm_widgets),
+		.dapm_routes		= jz4740_codec_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(jz4740_codec_dapm_routes),
+	},
 };
 
 static const struct regmap_config jz4740_codec_regmap_config = {
diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c
index 5353af58862c..a10ea3c716c6 100644
--- a/sound/soc/codecs/l3.c
+++ b/sound/soc/codecs/l3.c
@@ -20,6 +20,8 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
 
 #include <sound/l3.h>
 
@@ -32,11 +34,11 @@ static void sendbyte(struct l3_pins *adap, unsigned int byte)
 	int i;
 
 	for (i = 0; i < 8; i++) {
-		adap->setclk(0);
+		adap->setclk(adap, 0);
 		udelay(adap->data_hold);
-		adap->setdat(byte & 1);
+		adap->setdat(adap, byte & 1);
 		udelay(adap->data_setup);
-		adap->setclk(1);
+		adap->setclk(adap, 1);
 		udelay(adap->clock_high);
 		byte >>= 1;
 	}
@@ -55,10 +57,10 @@ static void sendbytes(struct l3_pins *adap, const u8 *buf,
 	for (i = 0; i < len; i++) {
 		if (i) {
 			udelay(adap->mode_hold);
-			adap->setmode(0);
+			adap->setmode(adap, 0);
 			udelay(adap->mode);
 		}
-		adap->setmode(1);
+		adap->setmode(adap, 1);
 		udelay(adap->mode_setup);
 		sendbyte(adap, buf[i]);
 	}
@@ -66,26 +68,71 @@ static void sendbytes(struct l3_pins *adap, const u8 *buf,
 
 int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len)
 {
-	adap->setclk(1);
-	adap->setdat(1);
-	adap->setmode(1);
+	adap->setclk(adap, 1);
+	adap->setdat(adap, 1);
+	adap->setmode(adap, 1);
 	udelay(adap->mode);
 
-	adap->setmode(0);
+	adap->setmode(adap, 0);
 	udelay(adap->mode_setup);
 	sendbyte(adap, addr);
 	udelay(adap->mode_hold);
 
 	sendbytes(adap, data, len);
 
-	adap->setclk(1);
-	adap->setdat(1);
-	adap->setmode(0);
+	adap->setclk(adap, 1);
+	adap->setdat(adap, 1);
+	adap->setmode(adap, 0);
 
 	return len;
 }
 EXPORT_SYMBOL_GPL(l3_write);
 
+
+static void l3_set_clk(struct l3_pins *adap, int val)
+{
+	gpio_set_value(adap->gpio_clk, val);
+}
+
+static void l3_set_data(struct l3_pins *adap, int val)
+{
+	gpio_set_value(adap->gpio_data, val);
+}
+
+static void l3_set_mode(struct l3_pins *adap, int val)
+{
+	gpio_set_value(adap->gpio_mode, val);
+}
+
+int l3_set_gpio_ops(struct device *dev, struct l3_pins *adap)
+{
+	int ret;
+
+	if (!adap->use_gpios)
+		return -EINVAL;
+
+	ret = devm_gpio_request_one(dev, adap->gpio_data,
+				GPIOF_OUT_INIT_LOW, "l3_data");
+	if (ret < 0)
+		return ret;
+	adap->setdat = l3_set_data;
+
+	ret = devm_gpio_request_one(dev, adap->gpio_clk,
+				GPIOF_OUT_INIT_LOW, "l3_clk");
+	if (ret < 0)
+		return ret;
+	adap->setclk = l3_set_clk;
+
+	ret = devm_gpio_request_one(dev, adap->gpio_mode,
+				GPIOF_OUT_INIT_LOW, "l3_mode");
+	if (ret < 0)
+		return ret;
+	adap->setmode = l3_set_mode;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(l3_set_gpio_ops);
+
 MODULE_DESCRIPTION("L3 bit-banging driver");
 MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index 9af5640e3446..8d413c2677cc 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1391,12 +1391,14 @@ static struct snd_soc_dai_driver lm49453_dai[] = {
 
 static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
 	.set_bias_level = lm49453_set_bias_level,
-	.controls = lm49453_snd_controls,
-	.num_controls = ARRAY_SIZE(lm49453_snd_controls),
-	.dapm_widgets = lm49453_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(lm49453_dapm_widgets),
-	.dapm_routes = lm49453_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(lm49453_audio_map),
+	.component_driver = {
+		.controls		= lm49453_snd_controls,
+		.num_controls		= ARRAY_SIZE(lm49453_snd_controls),
+		.dapm_widgets		= lm49453_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(lm49453_dapm_widgets),
+		.dapm_routes		= lm49453_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(lm49453_audio_map),
+	},
 	.idle_bias_off = true,
 };
 
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index fc22804cabc5..72f77455582e 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -1704,12 +1704,14 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
 	.set_bias_level = max98088_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = max98088_snd_controls,
-	.num_controls = ARRAY_SIZE(max98088_snd_controls),
-	.dapm_widgets = max98088_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets),
-	.dapm_routes = max98088_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(max98088_audio_map),
+	.component_driver = {
+		.controls		= max98088_snd_controls,
+		.num_controls		= ARRAY_SIZE(max98088_snd_controls),
+		.dapm_widgets		= max98088_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max98088_dapm_widgets),
+		.dapm_routes		= max98088_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(max98088_audio_map),
+	},
 };
 
 static int max98088_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 3577003f39cf..6f8a757876ed 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -2108,12 +2108,14 @@ static struct snd_soc_codec_driver soc_codec_dev_max98095 = {
 	.suspend = max98095_suspend,
 	.resume  = max98095_resume,
 	.set_bias_level = max98095_set_bias_level,
-	.controls = max98095_snd_controls,
-	.num_controls = ARRAY_SIZE(max98095_snd_controls),
-	.dapm_widgets	  = max98095_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets),
-	.dapm_routes     = max98095_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(max98095_audio_map),
+	.component_driver = {
+		.controls		= max98095_snd_controls,
+		.num_controls		= ARRAY_SIZE(max98095_snd_controls),
+		.dapm_widgets		= max98095_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max98095_dapm_widgets),
+		.dapm_routes		= max98095_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(max98095_audio_map),
+	},
 };
 
 static int max98095_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index 5b1dfb1518fb..6a6b68a4cb52 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -74,10 +74,12 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec)
 
 static struct snd_soc_codec_driver max98357a_codec_driver = {
 	.probe			= max98357a_codec_probe,
-	.dapm_widgets		= max98357a_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(max98357a_dapm_widgets),
-	.dapm_routes		= max98357a_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(max98357a_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= max98357a_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max98357a_dapm_widgets),
+		.dapm_routes		= max98357a_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(max98357a_dapm_routes),
+	},
 };
 
 static const struct snd_soc_dai_ops max98357a_dai_ops = {
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
index cf0a39bb631a..781be9ba8dba 100644
--- a/sound/soc/codecs/max98371.c
+++ b/sound/soc/codecs/max98371.c
@@ -412,6 +412,7 @@ static int max98371_i2c_remove(struct i2c_client *client)
 
 static const struct i2c_device_id max98371_i2c_id[] = {
 	{ "max98371", 0 },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, max98371_i2c_id);
@@ -425,7 +426,6 @@ MODULE_DEVICE_TABLE(of, max98371_of_match);
 static struct i2c_driver max98371_i2c_driver = {
 	.driver = {
 		.name = "max98371",
-		.owner = THIS_MODULE,
 		.pm = NULL,
 		.of_match_table = of_match_ptr(max98371_of_match),
 	},
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index c14a79d026a1..0610840733d1 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -306,12 +306,14 @@ static struct snd_soc_codec_driver soc_codec_dev_max9850 = {
 	.set_bias_level = max9850_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = max9850_controls,
-	.num_controls = ARRAY_SIZE(max9850_controls),
-	.dapm_widgets = max9850_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max9850_dapm_widgets),
-	.dapm_routes = max9850_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(max9850_dapm_routes),
+	.component_driver = {
+		.controls		= max9850_controls,
+		.num_controls		= ARRAY_SIZE(max9850_controls),
+		.dapm_widgets		= max9850_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max9850_dapm_widgets),
+		.dapm_routes		= max9850_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(max9850_dapm_routes),
+	},
 };
 
 static int max9850_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index 68074c92a7c0..499bdbfd0a2d 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -538,12 +538,14 @@ static struct snd_soc_codec_driver max9860_codec_driver = {
 	.set_bias_level = max9860_set_bias_level,
 	.idle_bias_off = true,
 
-	.controls = max9860_controls,
-	.num_controls = ARRAY_SIZE(max9860_controls),
-	.dapm_widgets = max9860_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max9860_dapm_widgets),
-	.dapm_routes = max9860_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(max9860_dapm_routes),
+	.component_driver = {
+		.controls		= max9860_controls,
+		.num_controls		= ARRAY_SIZE(max9860_controls),
+		.dapm_widgets		= max9860_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max9860_dapm_widgets),
+		.dapm_routes		= max9860_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(max9860_dapm_routes),
+	},
 };
 
 #ifdef CONFIG_PM
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index 2a22fddeb6af..42e2e407e287 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -38,11 +38,10 @@ static DECLARE_TLV_DB_SCALE(max9860_capture_tlv, -600, 200, 0);
 static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1);
 static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1);
 static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1);
-static const unsigned int max98088_micboost_tlv[] = {
-	TLV_DB_RANGE_HEAD(2),
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max98088_micboost_tlv,
 	0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
 	2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
-};
+);
 
 static const struct snd_kcontrol_new max9867_snd_controls[] = {
 	SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL,
@@ -417,12 +416,14 @@ static int max9867_probe(struct snd_soc_codec *codec)
 
 static struct snd_soc_codec_driver max9867_codec = {
 	.probe = max9867_probe,
-	.controls = max9867_snd_controls,
-	.num_controls = ARRAY_SIZE(max9867_snd_controls),
-	.dapm_routes = max9867_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(max9867_audio_map),
-	.dapm_widgets = max9867_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets),
+	.component_driver = {
+		.controls		= max9867_snd_controls,
+		.num_controls		= ARRAY_SIZE(max9867_snd_controls),
+		.dapm_routes		= max9867_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(max9867_audio_map),
+		.dapm_widgets		= max9867_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max9867_dapm_widgets),
+	},
 };
 
 static bool max9867_volatile_register(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
index 5990de317999..327eaa25c9bd 100644
--- a/sound/soc/codecs/max98925.c
+++ b/sound/soc/codecs/max98925.c
@@ -540,12 +540,14 @@ static int max98925_probe(struct snd_soc_codec *codec)
 
 static const struct snd_soc_codec_driver soc_codec_dev_max98925 = {
 	.probe            = max98925_probe,
-	.controls = max98925_snd_controls,
-	.num_controls = ARRAY_SIZE(max98925_snd_controls),
-	.dapm_routes = max98925_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(max98925_audio_map),
-	.dapm_widgets = max98925_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max98925_dapm_widgets),
+	.component_driver = {
+		.controls		= max98925_snd_controls,
+		.num_controls		= ARRAY_SIZE(max98925_snd_controls),
+		.dapm_routes		= max98925_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(max98925_audio_map),
+		.dapm_widgets		= max98925_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max98925_dapm_widgets),
+	},
 };
 
 static const struct regmap_config max98925_regmap = {
diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c
index 8d14adae5cc5..1eff7e0b092e 100644
--- a/sound/soc/codecs/max98926.c
+++ b/sound/soc/codecs/max98926.c
@@ -347,7 +347,7 @@ static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		max98926_set_sense_data(max98926);
 		break;
 	default:
-		dev_err(codec->dev, "DAI clock mode unsupported");
+		dev_err(codec->dev, "DAI clock mode unsupported\n");
 		return -EINVAL;
 	}
 
@@ -364,7 +364,7 @@ static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		invert = MAX98926_DAI_BCI_MASK | MAX98926_DAI_WCI_MASK;
 		break;
 	default:
-		dev_err(codec->dev, "DAI invert mode unsupported");
+		dev_err(codec->dev, "DAI invert mode unsupported\n");
 		return -EINVAL;
 	}
 
@@ -408,7 +408,7 @@ static int max98926_dai_hw_params(struct snd_pcm_substream *substream,
 		max98926->ch_size = 32;
 		break;
 	default:
-		dev_dbg(codec->dev, "format unsupported %d",
+		dev_dbg(codec->dev, "format unsupported %d\n",
 			params_format(params));
 		return -EINVAL;
 	}
@@ -498,12 +498,14 @@ static int max98926_probe(struct snd_soc_codec *codec)
 
 static struct snd_soc_codec_driver soc_codec_dev_max98926 = {
 	.probe	= max98926_probe,
-	.controls = max98926_snd_controls,
-	.num_controls = ARRAY_SIZE(max98926_snd_controls),
-	.dapm_routes = max98926_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(max98926_audio_map),
-	.dapm_widgets = max98926_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(max98926_dapm_widgets),
+	.component_driver = {
+		.controls		= max98926_snd_controls,
+		.num_controls		= ARRAY_SIZE(max98926_snd_controls),
+		.dapm_routes		= max98926_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(max98926_audio_map),
+		.dapm_widgets		= max98926_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(max98926_dapm_widgets),
+	},
 };
 
 static const struct regmap_config max98926_regmap = {
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 3e770cbe7f0f..90562703dcfd 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -737,12 +737,14 @@ static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
 	.probe		= mc13783_probe,
 	.remove		= mc13783_remove,
 	.get_regmap	= mc13783_get_regmap,
-	.controls	= mc13783_control_list,
-	.num_controls	= ARRAY_SIZE(mc13783_control_list),
-	.dapm_widgets	= mc13783_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(mc13783_dapm_widgets),
-	.dapm_routes	= mc13783_routes,
-	.num_dapm_routes = ARRAY_SIZE(mc13783_routes),
+	.component_driver = {
+		.controls		= mc13783_control_list,
+		.num_controls		= ARRAY_SIZE(mc13783_control_list),
+		.dapm_widgets		= mc13783_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(mc13783_dapm_widgets),
+		.dapm_routes		= mc13783_routes,
+		.num_dapm_routes	= ARRAY_SIZE(mc13783_routes),
+	},
 };
 
 static int __init mc13783_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index f561c78b9e0e..69e5e18880c5 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -541,12 +541,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
 	.probe =	ml26124_probe,
 	.set_bias_level = ml26124_set_bias_level,
 	.suspend_bias_off = true,
-	.dapm_widgets = ml26124_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets),
-	.dapm_routes = ml26124_intercon,
-	.num_dapm_routes = ARRAY_SIZE(ml26124_intercon),
-	.controls = ml26124_snd_controls,
-	.num_controls = ARRAY_SIZE(ml26124_snd_controls),
+	.component_driver = {
+		.controls		= ml26124_snd_controls,
+		.num_controls		= ARRAY_SIZE(ml26124_snd_controls),
+		.dapm_widgets		= ml26124_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ml26124_dapm_widgets),
+		.dapm_routes		= ml26124_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(ml26124_intercon),
+	},
 };
 
 static const struct regmap_config ml26124_i2c_regmap = {
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
new file mode 100644
index 000000000000..e45518629968
--- /dev/null
+++ b/sound/soc/codecs/nau8810.c
@@ -0,0 +1,884 @@
+/*
+ * nau8810.c  --  NAU8810 ALSA Soc Audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ *
+ * Author: David Lin <ctlin0@nuvoton.com>
+ *
+ * Based on WM8974.c
+ *
+ * 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/pm.h>
+#include <linux/i2c.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/initval.h>
+#include <sound/tlv.h>
+
+#include "nau8810.h"
+
+#define NAU_PLL_FREQ_MAX 100000000
+#define NAU_PLL_FREQ_MIN 90000000
+#define NAU_PLL_REF_MAX 33000000
+#define NAU_PLL_REF_MIN 8000000
+#define NAU_PLL_OPTOP_MIN 6
+
+
+static const int nau8810_mclk_scaler[] = { 10, 15, 20, 30, 40, 60, 80, 120 };
+
+static const struct reg_default nau8810_reg_defaults[] = {
+	{ NAU8810_REG_POWER1, 0x0000 },
+	{ NAU8810_REG_POWER2, 0x0000 },
+	{ NAU8810_REG_POWER3, 0x0000 },
+	{ NAU8810_REG_IFACE, 0x0050 },
+	{ NAU8810_REG_COMP, 0x0000 },
+	{ NAU8810_REG_CLOCK, 0x0140 },
+	{ NAU8810_REG_SMPLR, 0x0000 },
+	{ NAU8810_REG_DAC, 0x0000 },
+	{ NAU8810_REG_DACGAIN, 0x00FF },
+	{ NAU8810_REG_ADC, 0x0100 },
+	{ NAU8810_REG_ADCGAIN, 0x00FF },
+	{ NAU8810_REG_EQ1, 0x012C },
+	{ NAU8810_REG_EQ2, 0x002C },
+	{ NAU8810_REG_EQ3, 0x002C },
+	{ NAU8810_REG_EQ4, 0x002C },
+	{ NAU8810_REG_EQ5, 0x002C },
+	{ NAU8810_REG_DACLIM1, 0x0032 },
+	{ NAU8810_REG_DACLIM2, 0x0000 },
+	{ NAU8810_REG_NOTCH1, 0x0000 },
+	{ NAU8810_REG_NOTCH2, 0x0000 },
+	{ NAU8810_REG_NOTCH3, 0x0000 },
+	{ NAU8810_REG_NOTCH4, 0x0000 },
+	{ NAU8810_REG_ALC1, 0x0038 },
+	{ NAU8810_REG_ALC2, 0x000B },
+	{ NAU8810_REG_ALC3, 0x0032 },
+	{ NAU8810_REG_NOISEGATE, 0x0000 },
+	{ NAU8810_REG_PLLN, 0x0008 },
+	{ NAU8810_REG_PLLK1, 0x000C },
+	{ NAU8810_REG_PLLK2, 0x0093 },
+	{ NAU8810_REG_PLLK3, 0x00E9 },
+	{ NAU8810_REG_ATTEN, 0x0000 },
+	{ NAU8810_REG_INPUT_SIGNAL, 0x0003 },
+	{ NAU8810_REG_PGAGAIN, 0x0010 },
+	{ NAU8810_REG_ADCBOOST, 0x0100 },
+	{ NAU8810_REG_OUTPUT, 0x0002 },
+	{ NAU8810_REG_SPKMIX, 0x0001 },
+	{ NAU8810_REG_SPKGAIN, 0x0039 },
+	{ NAU8810_REG_MONOMIX, 0x0001 },
+	{ NAU8810_REG_POWER4, 0x0000 },
+	{ NAU8810_REG_TSLOTCTL1, 0x0000 },
+	{ NAU8810_REG_TSLOTCTL2, 0x0020 },
+	{ NAU8810_REG_DEVICE_REVID, 0x0000 },
+	{ NAU8810_REG_I2C_DEVICEID, 0x001A },
+	{ NAU8810_REG_ADDITIONID, 0x00CA },
+	{ NAU8810_REG_RESERVE, 0x0124 },
+	{ NAU8810_REG_OUTCTL, 0x0001 },
+	{ NAU8810_REG_ALC1ENHAN1, 0x0010 },
+	{ NAU8810_REG_ALC1ENHAN2, 0x0000 },
+	{ NAU8810_REG_MISCCTL, 0x0000 },
+	{ NAU8810_REG_OUTTIEOFF, 0x0000 },
+	{ NAU8810_REG_AGCP2POUT, 0x0000 },
+	{ NAU8810_REG_AGCPOUT, 0x0000 },
+	{ NAU8810_REG_AMTCTL, 0x0000 },
+	{ NAU8810_REG_OUTTIEOFFMAN, 0x0000 },
+};
+
+static bool nau8810_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8810_REG_RESET ... NAU8810_REG_SMPLR:
+	case NAU8810_REG_DAC ... NAU8810_REG_DACGAIN:
+	case NAU8810_REG_ADC ... NAU8810_REG_ADCGAIN:
+	case NAU8810_REG_EQ1 ... NAU8810_REG_EQ5:
+	case NAU8810_REG_DACLIM1 ... NAU8810_REG_DACLIM2:
+	case NAU8810_REG_NOTCH1 ... NAU8810_REG_NOTCH4:
+	case NAU8810_REG_ALC1 ... NAU8810_REG_ATTEN:
+	case NAU8810_REG_INPUT_SIGNAL ... NAU8810_REG_PGAGAIN:
+	case NAU8810_REG_ADCBOOST:
+	case NAU8810_REG_OUTPUT ... NAU8810_REG_SPKMIX:
+	case NAU8810_REG_SPKGAIN:
+	case NAU8810_REG_MONOMIX:
+	case NAU8810_REG_POWER4 ... NAU8810_REG_TSLOTCTL2:
+	case NAU8810_REG_DEVICE_REVID ... NAU8810_REG_RESERVE:
+	case NAU8810_REG_OUTCTL ... NAU8810_REG_ALC1ENHAN2:
+	case NAU8810_REG_MISCCTL:
+	case NAU8810_REG_OUTTIEOFF ... NAU8810_REG_OUTTIEOFFMAN:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool nau8810_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8810_REG_RESET ... NAU8810_REG_SMPLR:
+	case NAU8810_REG_DAC ... NAU8810_REG_DACGAIN:
+	case NAU8810_REG_ADC ... NAU8810_REG_ADCGAIN:
+	case NAU8810_REG_EQ1 ... NAU8810_REG_EQ5:
+	case NAU8810_REG_DACLIM1 ... NAU8810_REG_DACLIM2:
+	case NAU8810_REG_NOTCH1 ... NAU8810_REG_NOTCH4:
+	case NAU8810_REG_ALC1 ... NAU8810_REG_ATTEN:
+	case NAU8810_REG_INPUT_SIGNAL ... NAU8810_REG_PGAGAIN:
+	case NAU8810_REG_ADCBOOST:
+	case NAU8810_REG_OUTPUT ... NAU8810_REG_SPKMIX:
+	case NAU8810_REG_SPKGAIN:
+	case NAU8810_REG_MONOMIX:
+	case NAU8810_REG_POWER4 ... NAU8810_REG_TSLOTCTL2:
+	case NAU8810_REG_OUTCTL ... NAU8810_REG_ALC1ENHAN2:
+	case NAU8810_REG_MISCCTL:
+	case NAU8810_REG_OUTTIEOFF ... NAU8810_REG_OUTTIEOFFMAN:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool nau8810_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8810_REG_RESET:
+	case NAU8810_REG_DEVICE_REVID ... NAU8810_REG_RESERVE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/* The EQ parameters get function is to get the 5 band equalizer control.
+ * The regmap raw read can't work here because regmap doesn't provide
+ * value format for value width of 9 bits. Therefore, the driver reads data
+ * from cache and makes value format according to the endianness of
+ * bytes type control element.
+ */
+static int nau8810_eq_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+	int i, reg, reg_val;
+	u16 *val;
+
+	val = (u16 *)ucontrol->value.bytes.data;
+	reg = NAU8810_REG_EQ1;
+	for (i = 0; i < params->max / sizeof(u16); i++) {
+		regmap_read(nau8810->regmap, reg + i, &reg_val);
+		/* conversion of 16-bit integers between native CPU format
+		 * and big endian format
+		 */
+		reg_val = cpu_to_be16(reg_val);
+		memcpy(val + i, &reg_val, sizeof(reg_val));
+	}
+
+	return 0;
+}
+
+/* The EQ parameters put function is to make configuration of 5 band equalizer
+ * control. These configuration includes central frequency, equalizer gain,
+ * cut-off frequency, bandwidth control, and equalizer path.
+ * The regmap raw write can't work here because regmap doesn't provide
+ * register and value format for register with address 7 bits and value 9 bits.
+ * Therefore, the driver makes value format according to the endianness of
+ * bytes type control element and writes data to codec.
+ */
+static int nau8810_eq_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+	void *data;
+	u16 *val, value;
+	int i, reg, ret;
+
+	data = kmemdup(ucontrol->value.bytes.data,
+		params->max, GFP_KERNEL | GFP_DMA);
+	if (!data)
+		return -ENOMEM;
+
+	val = (u16 *)data;
+	reg = NAU8810_REG_EQ1;
+	for (i = 0; i < params->max / sizeof(u16); i++) {
+		/* conversion of 16-bit integers between native CPU format
+		 * and big endian format
+		 */
+		value = be16_to_cpu(*(val + i));
+		ret = regmap_write(nau8810->regmap, reg + i, value);
+		if (ret) {
+			dev_err(codec->dev, "EQ configuration fail, register: %x ret: %d\n",
+				reg + i, ret);
+			kfree(data);
+			return ret;
+		}
+	}
+	kfree(data);
+
+	return 0;
+}
+
+static const char * const nau8810_companding[] = {
+	"Off", "NC", "u-law", "A-law" };
+
+static const struct soc_enum nau8810_companding_adc_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_COMP, NAU8810_ADCCM_SFT,
+		ARRAY_SIZE(nau8810_companding), nau8810_companding);
+
+static const struct soc_enum nau8810_companding_dac_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_COMP, NAU8810_DACCM_SFT,
+		ARRAY_SIZE(nau8810_companding), nau8810_companding);
+
+static const char * const nau8810_deemp[] = {
+	"None", "32kHz", "44.1kHz", "48kHz" };
+
+static const struct soc_enum nau8810_deemp_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_DAC, NAU8810_DEEMP_SFT,
+		ARRAY_SIZE(nau8810_deemp), nau8810_deemp);
+
+static const char * const nau8810_eqmode[] = {"Capture", "Playback" };
+
+static const struct soc_enum nau8810_eqmode_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_EQ1, NAU8810_EQM_SFT,
+		ARRAY_SIZE(nau8810_eqmode), nau8810_eqmode);
+
+static const char * const nau8810_alc[] = {"Normal", "Limiter" };
+
+static const struct soc_enum nau8810_alc_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_ALC3, NAU8810_ALCM_SFT,
+		ARRAY_SIZE(nau8810_alc), nau8810_alc);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0);
+
+static const struct snd_kcontrol_new nau8810_snd_controls[] = {
+	SOC_ENUM("ADC Companding", nau8810_companding_adc_enum),
+	SOC_ENUM("DAC Companding", nau8810_companding_dac_enum),
+	SOC_ENUM("DAC De-emphasis", nau8810_deemp_enum),
+
+	SOC_ENUM("EQ Function", nau8810_eqmode_enum),
+	SND_SOC_BYTES_EXT("EQ Parameters", 10,
+		  nau8810_eq_get, nau8810_eq_put),
+
+	SOC_SINGLE("DAC Inversion Switch", NAU8810_REG_DAC,
+		NAU8810_DACPL_SFT, 1, 0),
+	SOC_SINGLE_TLV("Playback Volume", NAU8810_REG_DACGAIN,
+		NAU8810_DACGAIN_SFT, 0xff, 0, digital_tlv),
+
+	SOC_SINGLE("High Pass Filter Switch", NAU8810_REG_ADC,
+		NAU8810_HPFEN_SFT, 1, 0),
+	SOC_SINGLE("High Pass Cut Off", NAU8810_REG_ADC,
+		NAU8810_HPF_SFT, 0x7, 0),
+
+	SOC_SINGLE("ADC Inversion Switch", NAU8810_REG_ADC,
+		NAU8810_ADCPL_SFT, 1, 0),
+	SOC_SINGLE_TLV("Capture Volume", NAU8810_REG_ADCGAIN,
+		NAU8810_ADCGAIN_SFT, 0xff, 0, digital_tlv),
+
+	SOC_SINGLE_TLV("EQ1 Volume", NAU8810_REG_EQ1,
+		NAU8810_EQ1GC_SFT, 0x18, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ2 Volume", NAU8810_REG_EQ2,
+		NAU8810_EQ2GC_SFT, 0x18, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ3 Volume", NAU8810_REG_EQ3,
+		NAU8810_EQ3GC_SFT, 0x18, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ4 Volume", NAU8810_REG_EQ4,
+		NAU8810_EQ4GC_SFT, 0x18, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ5 Volume", NAU8810_REG_EQ5,
+		NAU8810_EQ5GC_SFT, 0x18, 1, eq_tlv),
+
+	SOC_SINGLE("DAC Limiter Switch", NAU8810_REG_DACLIM1,
+		NAU8810_DACLIMEN_SFT, 1, 0),
+	SOC_SINGLE("DAC Limiter Decay", NAU8810_REG_DACLIM1,
+		NAU8810_DACLIMDCY_SFT, 0xf, 0),
+	SOC_SINGLE("DAC Limiter Attack", NAU8810_REG_DACLIM1,
+		NAU8810_DACLIMATK_SFT, 0xf, 0),
+	SOC_SINGLE("DAC Limiter Threshold", NAU8810_REG_DACLIM2,
+		NAU8810_DACLIMTHL_SFT, 0x7, 0),
+	SOC_SINGLE("DAC Limiter Boost", NAU8810_REG_DACLIM2,
+		NAU8810_DACLIMBST_SFT, 0xf, 0),
+
+	SOC_ENUM("ALC Mode", nau8810_alc_enum),
+	SOC_SINGLE("ALC Enable Switch", NAU8810_REG_ALC1,
+		NAU8810_ALCEN_SFT, 1, 0),
+	SOC_SINGLE("ALC Max Volume", NAU8810_REG_ALC1,
+		NAU8810_ALCMXGAIN_SFT, 0x7, 0),
+	SOC_SINGLE("ALC Min Volume", NAU8810_REG_ALC1,
+		NAU8810_ALCMINGAIN_SFT, 0x7, 0),
+	SOC_SINGLE("ALC ZC Switch", NAU8810_REG_ALC2,
+		NAU8810_ALCZC_SFT, 1, 0),
+	SOC_SINGLE("ALC Hold", NAU8810_REG_ALC2,
+		NAU8810_ALCHT_SFT, 0xf, 0),
+	SOC_SINGLE("ALC Target", NAU8810_REG_ALC2,
+		NAU8810_ALCSL_SFT, 0xf, 0),
+	SOC_SINGLE("ALC Decay", NAU8810_REG_ALC3,
+		NAU8810_ALCDCY_SFT, 0xf, 0),
+	SOC_SINGLE("ALC Attack", NAU8810_REG_ALC3,
+		NAU8810_ALCATK_SFT, 0xf, 0),
+	SOC_SINGLE("ALC Noise Gate Switch", NAU8810_REG_NOISEGATE,
+		NAU8810_ALCNEN_SFT, 1, 0),
+	SOC_SINGLE("ALC Noise Gate Threshold", NAU8810_REG_NOISEGATE,
+		NAU8810_ALCNTH_SFT, 0x7, 0),
+
+	SOC_SINGLE("PGA ZC Switch", NAU8810_REG_PGAGAIN,
+		NAU8810_PGAZC_SFT, 1, 0),
+	SOC_SINGLE_TLV("PGA Volume", NAU8810_REG_PGAGAIN,
+		NAU8810_PGAGAIN_SFT, 0x3f, 0, inpga_tlv),
+
+	SOC_SINGLE("Speaker ZC Switch", NAU8810_REG_SPKGAIN,
+		NAU8810_SPKZC_SFT, 1, 0),
+	SOC_SINGLE("Speaker Mute Switch", NAU8810_REG_SPKGAIN,
+		NAU8810_SPKMT_SFT, 1, 0),
+	SOC_SINGLE_TLV("Speaker Volume", NAU8810_REG_SPKGAIN,
+		NAU8810_SPKGAIN_SFT, 0x3f, 0, spk_tlv),
+
+	SOC_SINGLE("Capture Boost(+20dB)", NAU8810_REG_ADCBOOST,
+		NAU8810_PGABST_SFT, 1, 0),
+	SOC_SINGLE("Mono Mute Switch", NAU8810_REG_MONOMIX,
+		NAU8810_MOUTMXMT_SFT, 1, 0),
+
+	SOC_SINGLE("DAC Oversampling Rate(128x) Switch", NAU8810_REG_DAC,
+		NAU8810_DACOS_SFT, 1, 0),
+	SOC_SINGLE("ADC Oversampling Rate(128x) Switch", NAU8810_REG_ADC,
+		NAU8810_ADCOS_SFT, 1, 0),
+};
+
+/* Speaker Output Mixer */
+static const struct snd_kcontrol_new nau8810_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", NAU8810_REG_SPKMIX,
+		NAU8810_BYPSPK_SFT, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", NAU8810_REG_SPKMIX,
+		NAU8810_DACSPK_SFT, 1, 0),
+};
+
+/* Mono Output Mixer */
+static const struct snd_kcontrol_new nau8810_mono_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", NAU8810_REG_MONOMIX,
+		NAU8810_BYPMOUT_SFT, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", NAU8810_REG_MONOMIX,
+		NAU8810_DACMOUT_SFT, 1, 0),
+};
+
+/* PGA Mute */
+static const struct snd_kcontrol_new nau8810_inpga_mute[] = {
+	SOC_DAPM_SINGLE("PGA Mute Switch", NAU8810_REG_PGAGAIN,
+		NAU8810_PGAMT_SFT, 1, 0),
+};
+
+/* Input PGA */
+static const struct snd_kcontrol_new nau8810_inpga[] = {
+	SOC_DAPM_SINGLE("MicN Switch", NAU8810_REG_INPUT_SIGNAL,
+		NAU8810_NMICPGA_SFT, 1, 0),
+	SOC_DAPM_SINGLE("MicP Switch", NAU8810_REG_INPUT_SIGNAL,
+		NAU8810_PMICPGA_SFT, 1, 0),
+};
+
+/* Mic Input boost vol */
+static const struct snd_kcontrol_new nau8810_mic_boost_controls =
+	SOC_DAPM_SINGLE("Mic Volume", NAU8810_REG_ADCBOOST,
+		NAU8810_PMICBSTGAIN_SFT, 0x7, 0);
+
+/* Loopback Switch */
+static const struct snd_kcontrol_new nau8810_loopback =
+	SOC_DAPM_SINGLE("Switch", NAU8810_REG_COMP,
+		NAU8810_ADDAP_SFT, 1, 0);
+
+static int check_mclk_select_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	unsigned int value;
+
+	regmap_read(nau8810->regmap, NAU8810_REG_CLOCK, &value);
+	return (value & NAU8810_CLKM_MASK);
+}
+
+static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Speaker Mixer", NAU8810_REG_POWER3,
+		NAU8810_SPKMX_EN_SFT, 0, &nau8810_speaker_mixer_controls[0],
+		ARRAY_SIZE(nau8810_speaker_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono Mixer", NAU8810_REG_POWER3,
+		NAU8810_MOUTMX_EN_SFT, 0, &nau8810_mono_mixer_controls[0],
+		ARRAY_SIZE(nau8810_mono_mixer_controls)),
+	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", NAU8810_REG_POWER3,
+		NAU8810_DAC_EN_SFT, 0),
+	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", NAU8810_REG_POWER2,
+		NAU8810_ADC_EN_SFT, 0),
+	SND_SOC_DAPM_PGA("SpkN Out", NAU8810_REG_POWER3,
+		NAU8810_NSPK_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SpkP Out", NAU8810_REG_POWER3,
+		NAU8810_PSPK_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out", NAU8810_REG_POWER3,
+		NAU8810_MOUT_EN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("Input PGA", NAU8810_REG_POWER2,
+		NAU8810_PGA_EN_SFT, 0, nau8810_inpga,
+		ARRAY_SIZE(nau8810_inpga)),
+	SND_SOC_DAPM_MIXER("Input Boost Stage", NAU8810_REG_POWER2,
+		NAU8810_BST_EN_SFT, 0, nau8810_inpga_mute,
+		ARRAY_SIZE(nau8810_inpga_mute)),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", NAU8810_REG_POWER1,
+		NAU8810_MICBIAS_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL", NAU8810_REG_POWER1,
+		NAU8810_PLL_EN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("Digital Loopback", SND_SOC_NOPM, 0, 0,
+		&nau8810_loopback),
+
+	SND_SOC_DAPM_INPUT("MICN"),
+	SND_SOC_DAPM_INPUT("MICP"),
+	SND_SOC_DAPM_OUTPUT("MONOOUT"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+};
+
+static const struct snd_soc_dapm_route nau8810_dapm_routes[] = {
+	{"DAC", NULL, "PLL", check_mclk_select_pll},
+
+	/* Mono output mixer */
+	{"Mono Mixer", "PCM Playback Switch", "DAC"},
+	{"Mono Mixer", "Line Bypass Switch", "Input Boost Stage"},
+
+	/* Speaker output mixer */
+	{"Speaker Mixer", "PCM Playback Switch", "DAC"},
+	{"Speaker Mixer", "Line Bypass Switch", "Input Boost Stage"},
+
+	/* Outputs */
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONOOUT", NULL, "Mono Out"},
+	{"SpkN Out", NULL, "Speaker Mixer"},
+	{"SpkP Out", NULL, "Speaker Mixer"},
+	{"SPKOUTN", NULL, "SpkN Out"},
+	{"SPKOUTP", NULL, "SpkP Out"},
+
+	/* Input Boost Stage */
+	{"ADC", NULL, "Input Boost Stage"},
+	{"ADC", NULL, "PLL", check_mclk_select_pll},
+	{"Input Boost Stage", NULL, "Input PGA"},
+	{"Input Boost Stage", NULL, "MICP"},
+
+	/* Input PGA */
+	{"Input PGA", NULL, "Mic Bias"},
+	{"Input PGA", "MicN Switch", "MICN"},
+	{"Input PGA", "MicP Switch", "MICP"},
+
+	/* Digital Looptack */
+	{"Digital Loopback", "Switch", "ADC"},
+	{"DAC", NULL, "Digital Loopback"},
+};
+
+static int nau8810_set_sysclk(struct snd_soc_dai *dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+
+	nau8810->clk_id = clk_id;
+	nau8810->sysclk = freq;
+	dev_dbg(nau8810->dev, "master sysclk %dHz, source %s\n",
+		freq, clk_id == NAU8810_SCLK_PLL ? "PLL" : "MCLK");
+
+	return 0;
+}
+
+static int nau88l0_calc_pll(unsigned int pll_in,
+	unsigned int fs, struct nau8810_pll *pll_param)
+{
+	u64 f2, f2_max, pll_ratio;
+	int i, scal_sel;
+
+	if (pll_in > NAU_PLL_REF_MAX || pll_in < NAU_PLL_REF_MIN)
+		return -EINVAL;
+
+	f2_max = 0;
+	scal_sel = ARRAY_SIZE(nau8810_mclk_scaler);
+	for (i = 0; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) {
+		f2 = 256 * fs * 4 * nau8810_mclk_scaler[i] / 10;
+		if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX &&
+			f2_max < f2) {
+			f2_max = f2;
+			scal_sel = i;
+		}
+	}
+	if (ARRAY_SIZE(nau8810_mclk_scaler) == scal_sel)
+		return -EINVAL;
+	pll_param->mclk_scaler = scal_sel;
+	f2 = f2_max;
+
+	/* Calculate the PLL 4-bit integer input and the PLL 24-bit fractional
+	 * input; round up the 24+4bit.
+	 */
+	pll_ratio = div_u64(f2 << 28, pll_in);
+	pll_param->pre_factor = 0;
+	if (((pll_ratio >> 28) & 0xF) < NAU_PLL_OPTOP_MIN) {
+		pll_ratio <<= 1;
+		pll_param->pre_factor = 1;
+	}
+	pll_param->pll_int = (pll_ratio >> 28) & 0xF;
+	pll_param->pll_frac = ((pll_ratio & 0xFFFFFFF) >> 4);
+
+	return 0;
+}
+
+static int nau8810_set_pll(struct snd_soc_dai *codec_dai, int pll_id,
+	int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct regmap *map = nau8810->regmap;
+	struct nau8810_pll *pll_param = &nau8810->pll;
+	int ret, fs;
+
+	fs = freq_out / 256;
+	ret = nau88l0_calc_pll(freq_in, fs, pll_param);
+	if (ret < 0) {
+		dev_err(nau8810->dev, "Unsupported input clock %d\n", freq_in);
+		return ret;
+	}
+	dev_info(nau8810->dev, "pll_int=%x pll_frac=%x mclk_scaler=%x pre_factor=%x\n",
+		pll_param->pll_int, pll_param->pll_frac, pll_param->mclk_scaler,
+		pll_param->pre_factor);
+
+	regmap_update_bits(map, NAU8810_REG_PLLN,
+		NAU8810_PLLMCLK_DIV2 | NAU8810_PLLN_MASK,
+		(pll_param->pre_factor ? NAU8810_PLLMCLK_DIV2 : 0) |
+		pll_param->pll_int);
+	regmap_write(map, NAU8810_REG_PLLK1,
+		(pll_param->pll_frac >> NAU8810_PLLK1_SFT) &
+		NAU8810_PLLK1_MASK);
+	regmap_write(map, NAU8810_REG_PLLK2,
+		(pll_param->pll_frac >> NAU8810_PLLK2_SFT) &
+		NAU8810_PLLK2_MASK);
+	regmap_write(map, NAU8810_REG_PLLK3,
+		pll_param->pll_frac & NAU8810_PLLK3_MASK);
+	regmap_update_bits(map, NAU8810_REG_CLOCK, NAU8810_MCLKSEL_MASK,
+		pll_param->mclk_scaler << NAU8810_MCLKSEL_SFT);
+	regmap_update_bits(map, NAU8810_REG_CLOCK,
+		NAU8810_CLKM_MASK, NAU8810_CLKM_PLL);
+
+	return 0;
+}
+
+static int nau8810_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	u16 ctrl1_val = 0, ctrl2_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ctrl2_val |= NAU8810_CLKIO_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		ctrl1_val |= NAU8810_AIFMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ctrl1_val |= NAU8810_AIFMT_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ctrl1_val |= NAU8810_AIFMT_PCM_A;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		ctrl1_val |= NAU8810_BCLKP_IB | NAU8810_FSP_IF;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		ctrl1_val |= NAU8810_BCLKP_IB;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		ctrl1_val |= NAU8810_FSP_IF;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_IFACE,
+		NAU8810_AIFMT_MASK | NAU8810_FSP_IF |
+		NAU8810_BCLKP_IB, ctrl1_val);
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK,
+		NAU8810_CLKIO_MASK, ctrl2_val);
+
+	return 0;
+}
+
+static int nau8810_mclk_clkdiv(struct nau8810 *nau8810, int rate)
+{
+	int i, sclk, imclk = rate * 256, div = 0;
+
+	if (!nau8810->sysclk) {
+		dev_err(nau8810->dev, "Make mclk div configuration fail because of invalid system clock\n");
+		return -EINVAL;
+	}
+
+	/* Configure the master clock prescaler div to make system
+	 * clock to approximate the internal master clock (IMCLK);
+	 * and large or equal to IMCLK.
+	 */
+	for (i = 1; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) {
+		sclk = (nau8810->sysclk * 10) /
+			nau8810_mclk_scaler[i];
+		if (sclk < imclk)
+			break;
+		div = i;
+	}
+	dev_dbg(nau8810->dev,
+		"master clock prescaler %x for fs %d\n", div, rate);
+
+	/* master clock from MCLK and disable PLL */
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK,
+		NAU8810_MCLKSEL_MASK, (div << NAU8810_MCLKSEL_SFT));
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK,
+		NAU8810_CLKM_MASK, NAU8810_CLKM_MCLK);
+
+	return 0;
+}
+
+static int nau8810_pcm_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 nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	int val_len = 0, val_rate = 0, ret = 0;
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len |= NAU8810_WLEN_20;
+		break;
+	case 24:
+		val_len |= NAU8810_WLEN_24;
+		break;
+	case 32:
+		val_len |= NAU8810_WLEN_32;
+		break;
+	}
+
+	switch (params_rate(params)) {
+	case 8000:
+		val_rate |= NAU8810_SMPLR_8K;
+		break;
+	case 11025:
+		val_rate |= NAU8810_SMPLR_12K;
+		break;
+	case 16000:
+		val_rate |= NAU8810_SMPLR_16K;
+		break;
+	case 22050:
+		val_rate |= NAU8810_SMPLR_24K;
+		break;
+	case 32000:
+		val_rate |= NAU8810_SMPLR_32K;
+		break;
+	case 44100:
+	case 48000:
+		break;
+	}
+
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_IFACE,
+		NAU8810_WLEN_MASK, val_len);
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_SMPLR,
+		NAU8810_SMPLR_MASK, val_rate);
+
+	/* If the master clock is from MCLK, provide the runtime FS for driver
+	 * to get the master clock prescaler configuration.
+	 */
+	if (nau8810->clk_id == NAU8810_SCLK_MCLK) {
+		ret = nau8810_mclk_clkdiv(nau8810, params_rate(params));
+		if (ret < 0)
+			dev_err(nau8810->dev, "MCLK div configuration fail\n");
+	}
+
+	return ret;
+}
+
+static int nau8810_set_bias_level(struct snd_soc_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct regmap *map = nau8810->regmap;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		regmap_update_bits(map, NAU8810_REG_POWER1,
+			NAU8810_REFIMP_MASK, NAU8810_REFIMP_80K);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		regmap_update_bits(map, NAU8810_REG_POWER1,
+			NAU8810_IOBUF_EN | NAU8810_ABIAS_EN,
+			NAU8810_IOBUF_EN | NAU8810_ABIAS_EN);
+
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+			regcache_sync(map);
+			regmap_update_bits(map, NAU8810_REG_POWER1,
+				NAU8810_REFIMP_MASK, NAU8810_REFIMP_3K);
+			mdelay(100);
+		}
+		regmap_update_bits(map, NAU8810_REG_POWER1,
+			NAU8810_REFIMP_MASK, NAU8810_REFIMP_300K);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		regmap_write(map, NAU8810_REG_POWER1, 0);
+		regmap_write(map, NAU8810_REG_POWER2, 0);
+		regmap_write(map, NAU8810_REG_POWER3, 0);
+		break;
+	}
+
+	return 0;
+}
+
+
+#define NAU8810_RATES (SNDRV_PCM_RATE_8000_48000)
+
+#define NAU8810_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops nau8810_ops = {
+	.hw_params = nau8810_pcm_hw_params,
+	.set_fmt = nau8810_set_dai_fmt,
+	.set_sysclk = nau8810_set_sysclk,
+	.set_pll = nau8810_set_pll,
+};
+
+static struct snd_soc_dai_driver nau8810_dai = {
+	.name = "nau8810-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,   /* Only 1 channel of data */
+		.rates = NAU8810_RATES,
+		.formats = NAU8810_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,   /* Only 1 channel of data */
+		.rates = NAU8810_RATES,
+		.formats = NAU8810_FORMATS,
+	},
+	.ops = &nau8810_ops,
+	.symmetric_rates = 1,
+};
+
+static const struct regmap_config nau8810_regmap_config = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = NAU8810_REG_MAX,
+	.readable_reg = nau8810_readable_reg,
+	.writeable_reg = nau8810_writeable_reg,
+	.volatile_reg = nau8810_volatile_reg,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = nau8810_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(nau8810_reg_defaults),
+};
+
+static struct snd_soc_codec_driver nau8810_codec_driver = {
+	.set_bias_level = nau8810_set_bias_level,
+	.suspend_bias_off = true,
+
+	.component_driver = {
+		.controls = nau8810_snd_controls,
+		.num_controls = ARRAY_SIZE(nau8810_snd_controls),
+		.dapm_widgets = nau8810_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(nau8810_dapm_widgets),
+		.dapm_routes = nau8810_dapm_routes,
+		.num_dapm_routes = ARRAY_SIZE(nau8810_dapm_routes),
+	},
+};
+
+static int nau8810_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct nau8810 *nau8810 = dev_get_platdata(dev);
+
+	if (!nau8810) {
+		nau8810 = devm_kzalloc(dev, sizeof(*nau8810), GFP_KERNEL);
+		if (!nau8810)
+			return -ENOMEM;
+	}
+	i2c_set_clientdata(i2c, nau8810);
+
+	nau8810->regmap = devm_regmap_init_i2c(i2c, &nau8810_regmap_config);
+	if (IS_ERR(nau8810->regmap))
+		return PTR_ERR(nau8810->regmap);
+	nau8810->dev = dev;
+
+	regmap_write(nau8810->regmap, NAU8810_REG_RESET, 0x00);
+
+	return snd_soc_register_codec(dev,
+		&nau8810_codec_driver, &nau8810_dai, 1);
+}
+
+static int nau8810_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id nau8810_i2c_id[] = {
+	{ "nau8810", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, nau8810_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8810_of_match[] = {
+	{ .compatible = "nuvoton,nau8810", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, nau8810_of_match);
+#endif
+
+static struct i2c_driver nau8810_i2c_driver = {
+	.driver = {
+		.name = "nau8810",
+		.of_match_table = of_match_ptr(nau8810_of_match),
+	},
+	.probe =    nau8810_i2c_probe,
+	.remove =   nau8810_i2c_remove,
+	.id_table = nau8810_i2c_id,
+};
+
+module_i2c_driver(nau8810_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC NAU8810 driver");
+MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/nau8810.h b/sound/soc/codecs/nau8810.h
new file mode 100644
index 000000000000..df882658ca91
--- /dev/null
+++ b/sound/soc/codecs/nau8810.h
@@ -0,0 +1,281 @@
+/*
+ * NAU8810 ALSA SoC audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ * Author: David Lin <ctlin0@nuvoton.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 __NAU8810_H__
+#define __NAU8810_H__
+
+#define NAU8810_REG_RESET		0x00
+#define NAU8810_REG_POWER1		0x01
+#define NAU8810_REG_POWER2		0x02
+#define NAU8810_REG_POWER3		0x03
+#define NAU8810_REG_IFACE		0x04
+#define NAU8810_REG_COMP		0x05
+#define NAU8810_REG_CLOCK		0x06
+#define NAU8810_REG_SMPLR		0x07
+#define NAU8810_REG_DAC		0x0A
+#define NAU8810_REG_DACGAIN		0x0B
+#define NAU8810_REG_ADC		0x0E
+#define NAU8810_REG_ADCGAIN		0x0F
+#define NAU8810_REG_EQ1		0x12
+#define NAU8810_REG_EQ2		0x13
+#define NAU8810_REG_EQ3		0x14
+#define NAU8810_REG_EQ4		0x15
+#define NAU8810_REG_EQ5		0x16
+#define NAU8810_REG_DACLIM1		0x18
+#define NAU8810_REG_DACLIM2		0x19
+#define NAU8810_REG_NOTCH1		0x1B
+#define NAU8810_REG_NOTCH2		0x1C
+#define NAU8810_REG_NOTCH3		0x1D
+#define NAU8810_REG_NOTCH4		0x1E
+#define NAU8810_REG_ALC1		0x20
+#define NAU8810_REG_ALC2		0x21
+#define NAU8810_REG_ALC3		0x22
+#define NAU8810_REG_NOISEGATE		0x23
+#define NAU8810_REG_PLLN		0x24
+#define NAU8810_REG_PLLK1		0x25
+#define NAU8810_REG_PLLK2		0x26
+#define NAU8810_REG_PLLK3		0x27
+#define NAU8810_REG_ATTEN		0x28
+#define NAU8810_REG_INPUT_SIGNAL	0x2C
+#define NAU8810_REG_PGAGAIN		0x2D
+#define NAU8810_REG_ADCBOOST		0x2F
+#define NAU8810_REG_OUTPUT		0x31
+#define NAU8810_REG_SPKMIX		0x32
+#define NAU8810_REG_SPKGAIN		0x36
+#define NAU8810_REG_MONOMIX		0x38
+#define NAU8810_REG_POWER4		0x3A
+#define NAU8810_REG_TSLOTCTL1		0x3B
+#define NAU8810_REG_TSLOTCTL2		0x3C
+#define NAU8810_REG_DEVICE_REVID	0x3E
+#define NAU8810_REG_I2C_DEVICEID	0x3F
+#define NAU8810_REG_ADDITIONID	0x40
+#define NAU8810_REG_RESERVE		0x41
+#define NAU8810_REG_OUTCTL		0x45
+#define NAU8810_REG_ALC1ENHAN1	0x46
+#define NAU8810_REG_ALC1ENHAN2	0x47
+#define NAU8810_REG_MISCCTL		0x49
+#define NAU8810_REG_OUTTIEOFF		0x4B
+#define NAU8810_REG_AGCP2POUT	0x4C
+#define NAU8810_REG_AGCPOUT		0x4D
+#define NAU8810_REG_AMTCTL		0x4E
+#define NAU8810_REG_OUTTIEOFFMAN	0x4F
+#define NAU8810_REG_MAX		NAU8810_REG_OUTTIEOFFMAN
+
+
+/* NAU8810_REG_POWER1 (0x1) */
+#define NAU8810_DCBUF_EN		(0x1 << 8)
+#define NAU8810_PLL_EN_SFT		5
+#define NAU8810_MICBIAS_EN_SFT	4
+#define NAU8810_ABIAS_EN		(0x1 << 3)
+#define NAU8810_IOBUF_EN		(0x1 << 2)
+#define NAU8810_REFIMP_MASK		0x3
+#define NAU8810_REFIMP_DIS		0x0
+#define NAU8810_REFIMP_80K		0x1
+#define NAU8810_REFIMP_300K		0x2
+#define NAU8810_REFIMP_3K		0x3
+
+/* NAU8810_REG_POWER2 (0x2) */
+#define NAU8810_BST_EN_SFT		4
+#define NAU8810_PGA_EN_SFT		2
+#define NAU8810_ADC_EN_SFT		0
+
+/* NAU8810_REG_POWER3 (0x3) */
+#define NAU8810_DAC_EN_SFT		0
+#define NAU8810_SPKMX_EN_SFT		2
+#define NAU8810_MOUTMX_EN_SFT	3
+#define NAU8810_PSPK_EN_SFT		5
+#define NAU8810_NSPK_EN_SFT		6
+#define NAU8810_MOUT_EN_SFT		7
+
+/* NAU8810_REG_IFACE (0x4) */
+#define NAU8810_AIFMT_SFT		3
+#define NAU8810_AIFMT_MASK		(0x3 << NAU8810_AIFMT_SFT)
+#define NAU8810_AIFMT_RIGHT		(0x0 << NAU8810_AIFMT_SFT)
+#define NAU8810_AIFMT_LEFT		(0x1 << NAU8810_AIFMT_SFT)
+#define NAU8810_AIFMT_I2S		(0x2 << NAU8810_AIFMT_SFT)
+#define NAU8810_AIFMT_PCM_A		(0x3 << NAU8810_AIFMT_SFT)
+#define NAU8810_WLEN_SFT		5
+#define NAU8810_WLEN_MASK		(0x3 << NAU8810_WLEN_SFT)
+#define NAU8810_WLEN_16		(0x0 << NAU8810_WLEN_SFT)
+#define NAU8810_WLEN_20		(0x1 << NAU8810_WLEN_SFT)
+#define NAU8810_WLEN_24		(0x2 << NAU8810_WLEN_SFT)
+#define NAU8810_WLEN_32		(0x3 << NAU8810_WLEN_SFT)
+#define NAU8810_FSP_IF			(0x1 << 7)
+#define NAU8810_BCLKP_IB		(0x1 << 8)
+
+/* NAU8810_REG_COMP (0x5) */
+#define NAU8810_ADDAP_SFT		0
+#define NAU8810_ADCCM_SFT		1
+#define NAU8810_DACCM_SFT		3
+
+/* NAU8810_REG_CLOCK (0x6) */
+#define NAU8810_CLKIO_MASK		0x1
+#define NAU8810_CLKIO_SLAVE		0x0
+#define NAU8810_CLKIO_MASTER		0x1
+#define NAU8810_BCLKSEL_SFT		2
+#define NAU8810_BCLKSEL_MASK		(0x7 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_1		(0x0 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_2		(0x1 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_4		(0x2 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_8		(0x3 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_16		(0x4 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_32		(0x5 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_MCLKSEL_SFT		5
+#define NAU8810_MCLKSEL_MASK		(0x7 << NAU8810_MCLKSEL_SFT)
+#define NAU8810_CLKM_SFT		8
+#define NAU8810_CLKM_MASK		(0x1 << NAU8810_CLKM_SFT)
+#define NAU8810_CLKM_MCLK		(0x0 << NAU8810_CLKM_SFT)
+#define NAU8810_CLKM_PLL		(0x1 << NAU8810_CLKM_SFT)
+
+/* NAU8810_REG_SMPLR (0x7) */
+#define NAU8810_SMPLR_SFT		1
+#define NAU8810_SMPLR_MASK		(0x7 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_48K		(0x0 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_32K		(0x1 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_24K		(0x2 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_16K		(0x3 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_12K		(0x4 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_8K		(0x5 << NAU8810_SMPLR_SFT)
+
+/* NAU8810_REG_DAC (0xA) */
+#define NAU8810_DACPL_SFT		0
+#define NAU8810_DACOS_SFT		3
+#define NAU8810_DEEMP_SFT		4
+
+/* NAU8810_REG_DACGAIN (0xB) */
+#define NAU8810_DACGAIN_SFT		0
+
+/* NAU8810_REG_ADC (0xE) */
+#define NAU8810_ADCPL_SFT		0
+#define NAU8810_ADCOS_SFT		3
+#define NAU8810_HPF_SFT		4
+#define NAU8810_HPFEN_SFT		8
+
+/* NAU8810_REG_ADCGAIN (0xF) */
+#define NAU8810_ADCGAIN_SFT		0
+
+/* NAU8810_REG_EQ1 (0x12) */
+#define NAU8810_EQ1GC_SFT		0
+#define NAU8810_EQ1CF_SFT		5
+#define NAU8810_EQM_SFT		8
+
+/* NAU8810_REG_EQ2 (0x13) */
+#define NAU8810_EQ2GC_SFT		0
+#define NAU8810_EQ2CF_SFT		5
+#define NAU8810_EQ2BW_SFT		8
+
+/* NAU8810_REG_EQ3 (0x14) */
+#define NAU8810_EQ3GC_SFT		0
+#define NAU8810_EQ3CF_SFT		5
+#define NAU8810_EQ3BW_SFT		8
+
+/* NAU8810_REG_EQ4 (0x15) */
+#define NAU8810_EQ4GC_SFT		0
+#define NAU8810_EQ4CF_SFT		5
+#define NAU8810_EQ4BW_SFT		8
+
+/* NAU8810_REG_EQ5 (0x16) */
+#define NAU8810_EQ5GC_SFT		0
+#define NAU8810_EQ5CF_SFT		5
+
+/* NAU8810_REG_DACLIM1 (0x18) */
+#define NAU8810_DACLIMATK_SFT		0
+#define NAU8810_DACLIMDCY_SFT		4
+#define NAU8810_DACLIMEN_SFT		8
+
+/* NAU8810_REG_DACLIM2 (0x19) */
+#define NAU8810_DACLIMBST_SFT		0
+#define NAU8810_DACLIMTHL_SFT		4
+
+/* NAU8810_REG_ALC1 (0x20) */
+#define NAU8810_ALCMINGAIN_SFT	0
+#define NAU8810_ALCMXGAIN_SFT		3
+#define NAU8810_ALCEN_SFT		8
+
+/* NAU8810_REG_ALC2 (0x21) */
+#define NAU8810_ALCSL_SFT		0
+#define NAU8810_ALCHT_SFT		4
+#define NAU8810_ALCZC_SFT		8
+
+/* NAU8810_REG_ALC3 (0x22) */
+#define NAU8810_ALCATK_SFT		0
+#define NAU8810_ALCDCY_SFT		4
+#define NAU8810_ALCM_SFT		8
+
+/* NAU8810_REG_NOISEGATE (0x23) */
+#define NAU8810_ALCNTH_SFT		0
+#define NAU8810_ALCNEN_SFT		3
+
+/* NAU8810_REG_PLLN (0x24) */
+#define NAU8810_PLLN_MASK		0xF
+#define NAU8810_PLLMCLK_DIV2		(0x1 << 4)
+
+/* NAU8810_REG_PLLK1 (0x25) */
+#define NAU8810_PLLK1_SFT		18
+#define NAU8810_PLLK1_MASK		0x3F
+
+/* NAU8810_REG_PLLK2 (0x26) */
+#define NAU8810_PLLK2_SFT		9
+#define NAU8810_PLLK2_MASK		0x1FF
+
+/* NAU8810_REG_PLLK3 (0x27) */
+#define NAU8810_PLLK3_MASK		0x1FF
+
+/* NAU8810_REG_INPUT_SIGNAL (0x2C) */
+#define NAU8810_PMICPGA_SFT		0
+#define NAU8810_NMICPGA_SFT		1
+
+/* NAU8810_REG_PGAGAIN (0x2D) */
+#define NAU8810_PGAGAIN_SFT		0
+#define NAU8810_PGAMT_SFT		6
+#define NAU8810_PGAZC_SFT		7
+
+/* NAU8810_REG_ADCBOOST (0x2F) */
+#define NAU8810_PMICBSTGAIN_SFT	4
+#define NAU8810_PGABST_SFT		8
+
+/* NAU8810_REG_SPKMIX (0x32) */
+#define NAU8810_DACSPK_SFT		0
+#define NAU8810_BYPSPK_SFT		1
+
+/* NAU8810_REG_SPKGAIN (0x36) */
+#define NAU8810_SPKGAIN_SFT		0
+#define NAU8810_SPKMT_SFT		6
+#define NAU8810_SPKZC_SFT		7
+
+/* NAU8810_REG_MONOMIX (0x38) */
+#define NAU8810_DACMOUT_SFT		0
+#define NAU8810_BYPMOUT_SFT		1
+#define NAU8810_MOUTMXMT_SFT		6
+
+
+/* System Clock Source */
+enum {
+	NAU8810_SCLK_MCLK,
+	NAU8810_SCLK_PLL,
+};
+
+struct nau8810_pll {
+	int pre_factor;
+	int mclk_scaler;
+	int pll_frac;
+	int pll_int;
+};
+
+struct nau8810 {
+	struct device *dev;
+	struct regmap *regmap;
+	struct nau8810_pll pll;
+	int sysclk;
+	int clk_id;
+};
+
+#endif
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index 5c9707ac4bbf..e643be91d762 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -212,31 +212,6 @@ static const unsigned short logtable[256] = {
 	0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
 };
 
-static struct snd_soc_dai *nau8825_get_codec_dai(struct nau8825 *nau8825)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(nau8825->dapm);
-	struct snd_soc_component *component = &codec->component;
-	struct snd_soc_dai *codec_dai, *_dai;
-
-	list_for_each_entry_safe(codec_dai, _dai, &component->dai_list, list) {
-		if (!strncmp(codec_dai->name, NUVOTON_CODEC_DAI,
-			strlen(NUVOTON_CODEC_DAI)))
-			return codec_dai;
-	}
-	return NULL;
-}
-
-static bool nau8825_dai_is_active(struct nau8825 *nau8825)
-{
-	struct snd_soc_dai *codec_dai = nau8825_get_codec_dai(nau8825);
-
-	if (codec_dai) {
-		if (codec_dai->playback_active || codec_dai->capture_active)
-			return true;
-	}
-	return false;
-}
-
 /**
  * nau8825_sema_acquire - acquire the semaphore of nau88l25
  * @nau8825:  component to register the codec private data with
@@ -250,19 +225,26 @@ static bool nau8825_dai_is_active(struct nau8825 *nau8825)
  * Acquires the semaphore without jiffies. If no more tasks are allowed
  * to acquire the semaphore, calling this function will put the task to
  * sleep until the semaphore is released.
- * It returns if the semaphore was acquired.
+ * If the semaphore is not released within the specified number of jiffies,
+ * this function returns -ETIME.
+ * If the sleep is interrupted by a signal, this function will return -EINTR.
+ * It returns 0 if the semaphore was acquired successfully.
  */
-static void nau8825_sema_acquire(struct nau8825 *nau8825, long timeout)
+static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout)
 {
 	int ret;
 
-	if (timeout)
+	if (timeout) {
 		ret = down_timeout(&nau8825->xtalk_sem, timeout);
-	else
+		if (ret < 0)
+			dev_warn(nau8825->dev, "Acquire semaphone timeout\n");
+	} else {
 		ret = down_interruptible(&nau8825->xtalk_sem);
+		if (ret < 0)
+			dev_warn(nau8825->dev, "Acquire semaphone fail\n");
+	}
 
-	if (ret < 0)
-		dev_warn(nau8825->dev, "Acquire semaphone fail\n");
+	return ret;
 }
 
 /**
@@ -1205,6 +1187,8 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
 	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
 	unsigned int val_len = 0;
 
+	nau8825_sema_acquire(nau8825, 2 * HZ);
+
 	switch (params_width(params)) {
 	case 16:
 		val_len |= NAU8825_I2S_DL_16;
@@ -1225,6 +1209,9 @@ 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. */
+	nau8825_sema_release(nau8825);
+
 	return 0;
 }
 
@@ -1234,6 +1221,8 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
 	unsigned int ctrl1_val = 0, ctrl2_val = 0;
 
+	nau8825_sema_acquire(nau8825, 2 * HZ);
+
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
 		ctrl2_val |= NAU8825_I2S_MS_MASTER;
@@ -1282,6 +1271,9 @@ 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. */
+	nau8825_sema_release(nau8825);
+
 	return 0;
 }
 
@@ -1611,8 +1603,11 @@ static irqreturn_t nau8825_interrupt(int irq, void *data)
 					 * cess and restore changes if process
 					 * is ongoing when ejection.
 					 */
+					int ret;
 					nau8825->xtalk_protect = true;
-					nau8825_sema_acquire(nau8825, 0);
+					ret = nau8825_sema_acquire(nau8825, 0);
+					if (ret < 0)
+						nau8825->xtalk_protect = false;
 				}
 				/* Startup cross talk detection process */
 				nau8825->xtalk_state = NAU8825_XTALK_PREPARE;
@@ -1912,7 +1907,7 @@ static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs,
 	/* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional
 	 * input based on FDCO, FREF and FLL ratio.
 	 */
-	fvco = div_u64(fvco << 16, fref * fll_param->ratio);
+	fvco = div_u64(fvco_max << 16, fref * fll_param->ratio);
 	fll_param->fll_int = (fvco >> 16) & 0x3FF;
 	fll_param->fll_frac = fvco & 0xFFFF;
 	return 0;
@@ -2238,23 +2233,14 @@ static int __maybe_unused nau8825_suspend(struct snd_soc_codec *codec)
 static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec)
 {
 	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	int ret;
 
 	regcache_cache_only(nau8825->regmap, false);
 	regcache_sync(nau8825->regmap);
-	if (nau8825_is_jack_inserted(nau8825->regmap)) {
-		/* If the jack is inserted, we need to check whether the play-
-		 * back is active before suspend. If active, the driver has to
-		 * raise the protection for cross talk function to avoid the
-		 * playback recovers before cross talk process finish. Other-
-		 * wise, the playback will be interfered by cross talk func-
-		 * tion. It is better to apply hardware related parameters
-		 * before starting playback or record.
-		 */
-		if (nau8825_dai_is_active(nau8825)) {
-			nau8825->xtalk_protect = true;
-			nau8825_sema_acquire(nau8825, 0);
-		}
-	}
+	nau8825->xtalk_protect = true;
+	ret = nau8825_sema_acquire(nau8825, 0);
+	if (ret < 0)
+		nau8825->xtalk_protect = false;
 	enable_irq(nau8825->irq);
 
 	return 0;
@@ -2270,12 +2256,14 @@ static struct snd_soc_codec_driver nau8825_codec_driver = {
 	.suspend = nau8825_suspend,
 	.resume = nau8825_resume,
 
-	.controls = nau8825_controls,
-	.num_controls = ARRAY_SIZE(nau8825_controls),
-	.dapm_widgets = nau8825_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(nau8825_dapm_widgets),
-	.dapm_routes = nau8825_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(nau8825_dapm_routes),
+	.component_driver = {
+		.controls		= nau8825_controls,
+		.num_controls		= ARRAY_SIZE(nau8825_controls),
+		.dapm_widgets		= nau8825_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(nau8825_dapm_widgets),
+		.dapm_routes		= nau8825_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(nau8825_dapm_routes),
+	},
 };
 
 static void nau8825_reset_chip(struct regmap *regmap)
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index 33e1fc2d1598..0b14efab6280 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -289,12 +289,14 @@ static const struct regmap_config pcm1681_regmap = {
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_pcm1681 = {
-	.controls		= pcm1681_controls,
-	.num_controls		= ARRAY_SIZE(pcm1681_controls),
-	.dapm_widgets		= pcm1681_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(pcm1681_dapm_widgets),
-	.dapm_routes		= pcm1681_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(pcm1681_dapm_routes),
+	.component_driver = {
+		.controls		= pcm1681_controls,
+		.num_controls		= ARRAY_SIZE(pcm1681_controls),
+		.dapm_widgets		= pcm1681_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pcm1681_dapm_widgets),
+		.dapm_routes		= pcm1681_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pcm1681_dapm_routes),
+	},
 };
 
 static const struct i2c_device_id pcm1681_i2c_id[] = {
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
index 88fbdd184aa0..b813a154ddd9 100644
--- a/sound/soc/codecs/pcm179x.c
+++ b/sound/soc/codecs/pcm179x.c
@@ -206,12 +206,14 @@ const struct regmap_config pcm179x_regmap_config = {
 EXPORT_SYMBOL_GPL(pcm179x_regmap_config);
 
 static struct snd_soc_codec_driver soc_codec_dev_pcm179x = {
-	.controls		= pcm179x_controls,
-	.num_controls		= ARRAY_SIZE(pcm179x_controls),
-	.dapm_widgets		= pcm179x_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(pcm179x_dapm_widgets),
-	.dapm_routes		= pcm179x_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(pcm179x_dapm_routes),
+	.component_driver = {
+		.controls		= pcm179x_controls,
+		.num_controls		= ARRAY_SIZE(pcm179x_controls),
+		.dapm_widgets		= pcm179x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pcm179x_dapm_widgets),
+		.dapm_routes		= pcm179x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pcm179x_dapm_routes),
+	},
 };
 
 int pcm179x_common_init(struct device *dev, struct regmap *regmap)
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
index 8fb445f33f6f..708af05486f6 100644
--- a/sound/soc/codecs/pcm3008.c
+++ b/sound/soc/codecs/pcm3008.c
@@ -99,10 +99,12 @@ static struct snd_soc_dai_driver pcm3008_dai = {
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
-	.dapm_widgets = pcm3008_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(pcm3008_dapm_widgets),
-	.dapm_routes = pcm3008_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(pcm3008_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= pcm3008_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pcm3008_dapm_widgets),
+		.dapm_routes		= pcm3008_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pcm3008_dapm_routes),
+	},
 };
 
 static int pcm3008_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index 992a77edcd5d..39bc02d5bc5d 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -599,12 +599,14 @@ EXPORT_SYMBOL_GPL(pcm3168a_regmap);
 
 static const struct snd_soc_codec_driver pcm3168a_driver = {
 	.idle_bias_off = true,
-	.controls = pcm3168a_snd_controls,
-	.num_controls = ARRAY_SIZE(pcm3168a_snd_controls),
-	.dapm_widgets = pcm3168a_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(pcm3168a_dapm_widgets),
-	.dapm_routes = pcm3168a_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes)
+	.component_driver = {
+		.controls		= pcm3168a_snd_controls,
+		.num_controls		= ARRAY_SIZE(pcm3168a_snd_controls),
+		.dapm_widgets		= pcm3168a_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pcm3168a_dapm_widgets),
+		.dapm_routes		= pcm3168a_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pcm3168a_dapm_routes)
+	},
 };
 
 int pcm3168a_probe(struct device *dev, struct regmap *regmap)
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 047c48953a20..72b19e62f626 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -1348,12 +1348,14 @@ static struct snd_soc_codec_driver pcm512x_codec_driver = {
 	.set_bias_level = pcm512x_set_bias_level,
 	.idle_bias_off = true,
 
-	.controls = pcm512x_controls,
-	.num_controls = ARRAY_SIZE(pcm512x_controls),
-	.dapm_widgets = pcm512x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets),
-	.dapm_routes = pcm512x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes),
+	.component_driver = {
+		.controls		= pcm512x_controls,
+		.num_controls		= ARRAY_SIZE(pcm512x_controls),
+		.dapm_widgets		= pcm512x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pcm512x_dapm_widgets),
+		.dapm_routes		= pcm512x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pcm512x_dapm_routes),
+	},
 };
 
 static const struct regmap_range_cfg pcm512x_range = {
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 74c0e4eb3788..9c365a7f758d 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -1053,12 +1053,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt286 = {
 	.resume = rt286_resume,
 	.set_bias_level = rt286_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt286_snd_controls,
-	.num_controls = ARRAY_SIZE(rt286_snd_controls),
-	.dapm_widgets = rt286_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt286_dapm_widgets),
-	.dapm_routes = rt286_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt286_dapm_routes),
+	.component_driver = {
+		.controls		= rt286_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt286_snd_controls),
+		.dapm_widgets		= rt286_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt286_dapm_widgets),
+		.dapm_routes		= rt286_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt286_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt286_regmap = {
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index f80cfe4d2ef2..55558643166f 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -1095,12 +1095,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt298 = {
 	.resume = rt298_resume,
 	.set_bias_level = rt298_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt298_snd_controls,
-	.num_controls = ARRAY_SIZE(rt298_snd_controls),
-	.dapm_widgets = rt298_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt298_dapm_widgets),
-	.dapm_routes = rt298_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt298_dapm_routes),
+	.component_driver = {
+		.controls		= rt298_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt298_snd_controls),
+		.dapm_widgets		= rt298_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt298_dapm_widgets),
+		.dapm_routes		= rt298_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt298_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt298_regmap = {
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 77ff8ebe6dfb..09103aab0cb2 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -236,7 +236,7 @@ static snd_pcm_uframes_t rt5514_spi_pcm_pointer(
 	return bytes_to_frames(runtime, rt5514_dsp->dma_offset);
 }
 
-static struct snd_pcm_ops rt5514_spi_pcm_ops = {
+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,
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 7162f05101d9..f24b7cfd3a89 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -278,7 +278,7 @@ static const DECLARE_TLV_DB_RANGE(bst_tlv,
 	8, 8, TLV_DB_SCALE_ITEM(1700, 0, 0)
 );
 
-static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
 
 static int rt5514_dsp_voice_wake_up_get(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
@@ -352,10 +352,10 @@ 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),
 	SOC_DOUBLE_R_TLV("ADC1 Capture Volume", RT5514_DOWNFILTER0_CTRL1,
-		RT5514_DOWNFILTER0_CTRL2, RT5514_AD_GAIN_SFT, 127, 0,
+		RT5514_DOWNFILTER0_CTRL2, RT5514_AD_GAIN_SFT, 63, 0,
 		adc_vol_tlv),
 	SOC_DOUBLE_R_TLV("ADC2 Capture Volume", RT5514_DOWNFILTER1_CTRL1,
-		RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 127, 0,
+		RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 63, 0,
 		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),
@@ -1023,12 +1023,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5514 = {
 	.probe = rt5514_probe,
 	.idle_bias_off = true,
 	.set_bias_level = rt5514_set_bias_level,
-	.controls = rt5514_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5514_snd_controls),
-	.dapm_widgets = rt5514_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5514_dapm_widgets),
-	.dapm_routes = rt5514_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5514_dapm_routes),
+	.component_driver = {
+		.controls		= rt5514_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5514_snd_controls),
+		.dapm_widgets		= rt5514_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5514_dapm_widgets),
+		.dapm_routes		= rt5514_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5514_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt5514_i2c_regmap = {
diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h
index 68883c68e999..229de0e2c88c 100644
--- a/sound/soc/codecs/rt5514.h
+++ b/sound/soc/codecs/rt5514.h
@@ -196,8 +196,8 @@
 #define RT5514_AD_AD_MIX_BIT			10
 #define RT5514_AD_AD_MUTE			(0x1 << 7)
 #define RT5514_AD_AD_MUTE_BIT			7
-#define RT5514_AD_GAIN_MASK			(0x7f << 0)
-#define RT5514_AD_GAIN_SFT			0
+#define RT5514_AD_GAIN_MASK			(0x3f << 1)
+#define RT5514_AD_GAIN_SFT			1
 
 /*  RT5514_ANA_CTRL_MICBST (0x2220) */
 #define RT5514_SEL_BSTL_MASK			(0xf << 4)
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
index f527b5b2817b..d1f273b24991 100644
--- a/sound/soc/codecs/rt5616.c
+++ b/sound/soc/codecs/rt5616.c
@@ -294,8 +294,7 @@ static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
 static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
 
 /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
-static unsigned int bst_tlv[] = {
-	TLV_DB_RANGE_HEAD(7),
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(bst_tlv,
 	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
 	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
 	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
@@ -303,7 +302,7 @@ static unsigned int bst_tlv[] = {
 	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
 	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
 	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
-};
+);
 
 static const struct snd_kcontrol_new rt5616_snd_controls[] = {
 	/* Headphone Output Volume */
@@ -1267,14 +1266,14 @@ 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)
 
-struct snd_soc_dai_ops rt5616_aif_dai_ops = {
+static 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,
 	.set_pll = rt5616_set_dai_pll,
 };
 
-struct snd_soc_dai_driver rt5616_dai[] = {
+static struct snd_soc_dai_driver rt5616_dai[] = {
 	{
 		.name = "rt5616-aif1",
 		.id = RT5616_AIF1,
@@ -1302,12 +1301,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5616 = {
 	.resume = rt5616_resume,
 	.set_bias_level = rt5616_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt5616_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5616_snd_controls),
-	.dapm_widgets = rt5616_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5616_dapm_widgets),
-	.dapm_routes = rt5616_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5616_dapm_routes),
+	.component_driver = {
+		.controls		= rt5616_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5616_snd_controls),
+		.dapm_widgets		= rt5616_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5616_dapm_widgets),
+		.dapm_routes		= rt5616_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5616_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt5616_regmap = {
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 1be2bab7dee3..0e418089c053 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -1657,12 +1657,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
 	.probe = rt5631_probe,
 	.set_bias_level = rt5631_set_bias_level,
 	.suspend_bias_off = true,
-	.controls = rt5631_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5631_snd_controls),
-	.dapm_widgets = rt5631_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5631_dapm_widgets),
-	.dapm_routes = rt5631_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5631_dapm_routes),
+	.component_driver = {
+		.controls		= rt5631_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5631_snd_controls),
+		.dapm_widgets		= rt5631_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5631_dapm_widgets),
+		.dapm_routes		= rt5631_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5631_dapm_routes),
+	},
 };
 
 static const struct i2c_device_id rt5631_i2c_id[] = {
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 09e8988bbb2d..3cc1135fc2cd 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -1870,6 +1870,9 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
 	case RT5640_SCLK_S_PLL1:
 		reg_val |= RT5640_SCLK_SRC_PLL1;
 		break;
+	case RT5640_SCLK_S_RCCLK:
+		reg_val |= RT5640_SCLK_SRC_RCCLK;
+		break;
 	default:
 		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
@@ -2261,12 +2264,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
 	.resume = rt5640_resume,
 	.set_bias_level = rt5640_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt5640_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5640_snd_controls),
-	.dapm_widgets = rt5640_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5640_dapm_widgets),
-	.dapm_routes = rt5640_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5640_dapm_routes),
+	.component_driver = {
+		.controls		= rt5640_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5640_snd_controls),
+		.dapm_widgets		= rt5640_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5640_dapm_widgets),
+		.dapm_routes		= rt5640_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5640_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt5640_regmap = {
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index 58b664b06c16..90c88711c72a 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -984,6 +984,7 @@
 #define RT5640_SCLK_SRC_SFT			14
 #define RT5640_SCLK_SRC_MCLK			(0x0 << 14)
 #define RT5640_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5640_SCLK_SRC_RCCLK			(0x2 << 14)
 #define RT5640_PLL1_SRC_MASK			(0x3 << 12)
 #define RT5640_PLL1_SRC_SFT			12
 #define RT5640_PLL1_SRC_MCLK			(0x0 << 12)
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 490bfe661346..10c2a564a715 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3484,12 +3484,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5645 = {
 	.resume = rt5645_resume,
 	.set_bias_level = rt5645_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt5645_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5645_snd_controls),
-	.dapm_widgets = rt5645_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5645_dapm_widgets),
-	.dapm_routes = rt5645_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes),
+	.component_driver = {
+		.controls		= rt5645_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5645_snd_controls),
+		.dapm_widgets		= rt5645_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5645_dapm_widgets),
+		.dapm_routes		= rt5645_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5645_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt5645_regmap = {
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index 7a6197042423..f5d34153e21f 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -1712,12 +1712,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5651 = {
 	.resume = rt5651_resume,
 	.set_bias_level = rt5651_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt5651_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5651_snd_controls),
-	.dapm_widgets = rt5651_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5651_dapm_widgets),
-	.dapm_routes = rt5651_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes),
+	.component_driver = {
+		.controls		= rt5651_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5651_snd_controls),
+		.dapm_widgets		= rt5651_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5651_dapm_widgets),
+		.dapm_routes		= rt5651_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5651_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt5651_regmap = {
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index 1b30914c2d91..db54550aed60 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -9,6 +9,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -3565,7 +3566,9 @@ static int rt5659_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 static int rt5659_set_bias_level(struct snd_soc_codec *codec,
 			enum snd_soc_bias_level level)
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	int ret;
 
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
@@ -3582,6 +3585,17 @@ static int rt5659_set_bias_level(struct snd_soc_codec *codec,
 			RT5659_PWR_FV1 | RT5659_PWR_FV2);
 		break;
 
+	case SND_SOC_BIAS_STANDBY:
+		if (dapm->bias_level == SND_SOC_BIAS_OFF) {
+			ret = clk_prepare_enable(rt5659->mclk);
+			if (ret) {
+				dev_err(codec->dev,
+					"failed to enable MCLK: %d\n", ret);
+				return ret;
+			}
+		}
+		break;
+
 	case SND_SOC_BIAS_OFF:
 		regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1,
 			RT5659_PWR_LDO, 0);
@@ -3591,6 +3605,7 @@ static int rt5659_set_bias_level(struct snd_soc_codec *codec,
 			RT5659_PWR_MB | RT5659_PWR_VREF2);
 		regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC,
 			RT5659_DIG_GATE_CTRL, 0);
+		clk_disable_unprepare(rt5659->mclk);
 		break;
 
 	default:
@@ -3722,12 +3737,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5659 = {
 	.resume = rt5659_resume,
 	.set_bias_level = rt5659_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt5659_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5659_snd_controls),
-	.dapm_widgets = rt5659_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5659_dapm_widgets),
-	.dapm_routes = rt5659_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5659_dapm_routes),
+	.component_driver = {
+		.controls		= rt5659_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5659_snd_controls),
+		.dapm_widgets		= rt5659_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5659_dapm_widgets),
+		.dapm_routes		= rt5659_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5659_dapm_routes),
+	},
 };
 
 
@@ -4020,6 +4037,15 @@ static int rt5659_i2c_probe(struct i2c_client *i2c,
 
 	regmap_write(rt5659->regmap, RT5659_RESET, 0);
 
+	/* Check if MCLK provided */
+	rt5659->mclk = devm_clk_get(&i2c->dev, "mclk");
+	if (IS_ERR(rt5659->mclk)) {
+		if (PTR_ERR(rt5659->mclk) != -ENOENT)
+			return PTR_ERR(rt5659->mclk);
+		/* Otherwise mark the mclk pointer to NULL */
+		rt5659->mclk = NULL;
+	}
+
 	rt5659_calibrate(rt5659);
 
 	/* line in diff mode*/
@@ -4163,6 +4189,9 @@ static int rt5659_i2c_probe(struct i2c_client *i2c,
 		if (ret)
 			dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
 
+		/* Enable IRQ output for GPIO1 pin any way */
+		regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+				   RT5659_GP1_PIN_MASK, RT5659_GP1_PIN_IRQ);
 	}
 
 	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659,
diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h
index d31c9e5bcec8..8f1aeef08489 100644
--- a/sound/soc/codecs/rt5659.h
+++ b/sound/soc/codecs/rt5659.h
@@ -180,9 +180,9 @@
 #define RT5659_IRQ_CTRL_1			0x00b6
 #define RT5659_IRQ_CTRL_2			0x00b7
 #define RT5659_IRQ_CTRL_3			0x00b8
-#define RT5659_IRQ_CTRL_4			0x00b9
-#define RT5659_IRQ_CTRL_5			0x00ba
-#define RT5659_IRQ_CTRL_6			0x00bb
+#define RT5659_IRQ_CTRL_4			0x00ba
+#define RT5659_IRQ_CTRL_5			0x00bb
+#define RT5659_IRQ_CTRL_6			0x00bc
 #define RT5659_INT_ST_1				0x00be
 #define RT5659_INT_ST_2				0x00bf
 #define RT5659_GPIO_CTRL_1			0x00c0
@@ -1796,6 +1796,7 @@ struct rt5659_priv {
 	struct gpio_desc *gpiod_reset;
 	struct snd_soc_jack *hs_jack;
 	struct delayed_work jack_detect_work;
+	struct clk *mclk;
 
 	int sysclk;
 	int sysclk_src;
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
new file mode 100644
index 000000000000..9f0933ced804
--- /dev/null
+++ b/sound/soc/codecs/rt5660.c
@@ -0,0 +1,1353 @@
+/*
+ * rt5660.c  --  RT5660 ALSA SoC audio codec driver
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@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/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.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 "rl6231.h"
+#include "rt5660.h"
+
+#define RT5660_DEVICE_ID 0x6338
+
+#define RT5660_PR_RANGE_BASE (0xff + 1)
+#define RT5660_PR_SPACING 0x100
+
+#define RT5660_PR_BASE (RT5660_PR_RANGE_BASE + (0 * RT5660_PR_SPACING))
+
+static const struct regmap_range_cfg rt5660_ranges[] = {
+	{ .name = "PR", .range_min = RT5660_PR_BASE,
+	  .range_max = RT5660_PR_BASE + 0xf3,
+	  .selector_reg = RT5660_PRIV_INDEX,
+	  .selector_mask = 0xff,
+	  .selector_shift = 0x0,
+	  .window_start = RT5660_PRIV_DATA,
+	  .window_len = 0x1, },
+};
+
+static const struct reg_sequence rt5660_patch[] = {
+	{ RT5660_ALC_PGA_CTRL2,		0x44c3 },
+	{ RT5660_PR_BASE + 0x3d,	0x2600 },
+};
+
+static const struct reg_default rt5660_reg[] = {
+	{ 0x00, 0x0000 },
+	{ 0x01, 0xc800 },
+	{ 0x02, 0xc8c8 },
+	{ 0x0d, 0x1010 },
+	{ 0x0e, 0x1010 },
+	{ 0x19, 0xafaf },
+	{ 0x1c, 0x2f2f },
+	{ 0x1e, 0x0000 },
+	{ 0x27, 0x6060 },
+	{ 0x29, 0x8080 },
+	{ 0x2a, 0x4242 },
+	{ 0x2f, 0x0000 },
+	{ 0x3b, 0x0000 },
+	{ 0x3c, 0x007f },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x007f },
+	{ 0x45, 0xe000 },
+	{ 0x46, 0x003e },
+	{ 0x48, 0xf800 },
+	{ 0x4a, 0x0004 },
+	{ 0x4d, 0x0000 },
+	{ 0x4e, 0x0000 },
+	{ 0x4f, 0x01ff },
+	{ 0x50, 0x0000 },
+	{ 0x51, 0x0000 },
+	{ 0x52, 0x01ff },
+	{ 0x61, 0x0000 },
+	{ 0x62, 0x0000 },
+	{ 0x63, 0x00c0 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x0000 },
+	{ 0x66, 0x0000 },
+	{ 0x70, 0x8000 },
+	{ 0x73, 0x7000 },
+	{ 0x74, 0x3c00 },
+	{ 0x75, 0x2800 },
+	{ 0x80, 0x0000 },
+	{ 0x81, 0x0000 },
+	{ 0x82, 0x0000 },
+	{ 0x8c, 0x0228 },
+	{ 0x8d, 0xa000 },
+	{ 0x8e, 0x0000 },
+	{ 0x92, 0x0000 },
+	{ 0x93, 0x3000 },
+	{ 0xa1, 0x0059 },
+	{ 0xa2, 0x0001 },
+	{ 0xa3, 0x5c80 },
+	{ 0xa4, 0x0146 },
+	{ 0xa5, 0x1f1f },
+	{ 0xa6, 0x78c6 },
+	{ 0xa7, 0xe5ec },
+	{ 0xa8, 0xba61 },
+	{ 0xa9, 0x3c78 },
+	{ 0xaa, 0x8ae2 },
+	{ 0xab, 0xe5ec },
+	{ 0xac, 0xc600 },
+	{ 0xad, 0xba61 },
+	{ 0xae, 0x17ed },
+	{ 0xb0, 0x2080 },
+	{ 0xb1, 0x0000 },
+	{ 0xb3, 0x001f },
+	{ 0xb4, 0x020c },
+	{ 0xb5, 0x1f00 },
+	{ 0xb6, 0x0000 },
+	{ 0xb7, 0x4000 },
+	{ 0xbb, 0x0000 },
+	{ 0xbd, 0x0000 },
+	{ 0xbe, 0x0000 },
+	{ 0xbf, 0x0100 },
+	{ 0xc0, 0x0000 },
+	{ 0xc2, 0x0000 },
+	{ 0xd3, 0xa220 },
+	{ 0xd9, 0x0809 },
+	{ 0xda, 0x0000 },
+	{ 0xe0, 0x8000 },
+	{ 0xe1, 0x0200 },
+	{ 0xe2, 0x8000 },
+	{ 0xe3, 0x0200 },
+	{ 0xe4, 0x0f20 },
+	{ 0xe5, 0x001f },
+	{ 0xe6, 0x020c },
+	{ 0xe7, 0x1f00 },
+	{ 0xe8, 0x0000 },
+	{ 0xe9, 0x4000 },
+	{ 0xea, 0x00a6 },
+	{ 0xeb, 0x04c3 },
+	{ 0xec, 0x27c8 },
+	{ 0xed, 0x7418 },
+	{ 0xee, 0xbf50 },
+	{ 0xef, 0x0045 },
+	{ 0xf0, 0x0007 },
+	{ 0xfa, 0x0000 },
+	{ 0xfd, 0x0000 },
+	{ 0xfe, 0x10ec },
+	{ 0xff, 0x6338 },
+};
+
+static bool rt5660_volatile_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5660_ranges); i++)
+		if ((reg >= rt5660_ranges[i].window_start &&
+		     reg <= rt5660_ranges[i].window_start +
+		     rt5660_ranges[i].window_len) ||
+		    (reg >= rt5660_ranges[i].range_min &&
+		     reg <= rt5660_ranges[i].range_max))
+			return true;
+
+	switch (reg) {
+	case RT5660_RESET:
+	case RT5660_PRIV_DATA:
+	case RT5660_EQ_CTRL1:
+	case RT5660_IRQ_CTRL2:
+	case RT5660_INT_IRQ_ST:
+	case RT5660_VENDOR_ID:
+	case RT5660_VENDOR_ID1:
+	case RT5660_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5660_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5660_ranges); i++)
+		if ((reg >= rt5660_ranges[i].window_start &&
+		     reg <= rt5660_ranges[i].window_start +
+		     rt5660_ranges[i].window_len) ||
+		    (reg >= rt5660_ranges[i].range_min &&
+		     reg <= rt5660_ranges[i].range_max))
+			return true;
+
+	switch (reg) {
+	case RT5660_RESET:
+	case RT5660_SPK_VOL:
+	case RT5660_LOUT_VOL:
+	case RT5660_IN1_IN2:
+	case RT5660_IN3_IN4:
+	case RT5660_DAC1_DIG_VOL:
+	case RT5660_STO1_ADC_DIG_VOL:
+	case RT5660_ADC_BST_VOL1:
+	case RT5660_STO1_ADC_MIXER:
+	case RT5660_AD_DA_MIXER:
+	case RT5660_STO_DAC_MIXER:
+	case RT5660_DIG_INF1_DATA:
+	case RT5660_REC_L1_MIXER:
+	case RT5660_REC_L2_MIXER:
+	case RT5660_REC_R1_MIXER:
+	case RT5660_REC_R2_MIXER:
+	case RT5660_LOUT_MIXER:
+	case RT5660_SPK_MIXER:
+	case RT5660_SPO_MIXER:
+	case RT5660_SPO_CLSD_RATIO:
+	case RT5660_OUT_L_GAIN1:
+	case RT5660_OUT_L_GAIN2:
+	case RT5660_OUT_L1_MIXER:
+	case RT5660_OUT_R_GAIN1:
+	case RT5660_OUT_R_GAIN2:
+	case RT5660_OUT_R1_MIXER:
+	case RT5660_PWR_DIG1:
+	case RT5660_PWR_DIG2:
+	case RT5660_PWR_ANLG1:
+	case RT5660_PWR_ANLG2:
+	case RT5660_PWR_MIXER:
+	case RT5660_PWR_VOL:
+	case RT5660_PRIV_INDEX:
+	case RT5660_PRIV_DATA:
+	case RT5660_I2S1_SDP:
+	case RT5660_ADDA_CLK1:
+	case RT5660_ADDA_CLK2:
+	case RT5660_DMIC_CTRL1:
+	case RT5660_GLB_CLK:
+	case RT5660_PLL_CTRL1:
+	case RT5660_PLL_CTRL2:
+	case RT5660_CLSD_AMP_OC_CTRL:
+	case RT5660_CLSD_AMP_CTRL:
+	case RT5660_LOUT_AMP_CTRL:
+	case RT5660_SPK_AMP_SPKVDD:
+	case RT5660_MICBIAS:
+	case RT5660_CLSD_OUT_CTRL1:
+	case RT5660_CLSD_OUT_CTRL2:
+	case RT5660_DIPOLE_MIC_CTRL1:
+	case RT5660_DIPOLE_MIC_CTRL2:
+	case RT5660_DIPOLE_MIC_CTRL3:
+	case RT5660_DIPOLE_MIC_CTRL4:
+	case RT5660_DIPOLE_MIC_CTRL5:
+	case RT5660_DIPOLE_MIC_CTRL6:
+	case RT5660_DIPOLE_MIC_CTRL7:
+	case RT5660_DIPOLE_MIC_CTRL8:
+	case RT5660_DIPOLE_MIC_CTRL9:
+	case RT5660_DIPOLE_MIC_CTRL10:
+	case RT5660_DIPOLE_MIC_CTRL11:
+	case RT5660_DIPOLE_MIC_CTRL12:
+	case RT5660_EQ_CTRL1:
+	case RT5660_EQ_CTRL2:
+	case RT5660_DRC_AGC_CTRL1:
+	case RT5660_DRC_AGC_CTRL2:
+	case RT5660_DRC_AGC_CTRL3:
+	case RT5660_DRC_AGC_CTRL4:
+	case RT5660_DRC_AGC_CTRL5:
+	case RT5660_JD_CTRL:
+	case RT5660_IRQ_CTRL1:
+	case RT5660_IRQ_CTRL2:
+	case RT5660_INT_IRQ_ST:
+	case RT5660_GPIO_CTRL1:
+	case RT5660_GPIO_CTRL2:
+	case RT5660_WIND_FILTER_CTRL1:
+	case RT5660_SV_ZCD1:
+	case RT5660_SV_ZCD2:
+	case RT5660_DRC1_LM_CTRL1:
+	case RT5660_DRC1_LM_CTRL2:
+	case RT5660_DRC2_LM_CTRL1:
+	case RT5660_DRC2_LM_CTRL2:
+	case RT5660_MULTI_DRC_CTRL:
+	case RT5660_DRC2_CTRL1:
+	case RT5660_DRC2_CTRL2:
+	case RT5660_DRC2_CTRL3:
+	case RT5660_DRC2_CTRL4:
+	case RT5660_DRC2_CTRL5:
+	case RT5660_ALC_PGA_CTRL1:
+	case RT5660_ALC_PGA_CTRL2:
+	case RT5660_ALC_PGA_CTRL3:
+	case RT5660_ALC_PGA_CTRL4:
+	case RT5660_ALC_PGA_CTRL5:
+	case RT5660_ALC_PGA_CTRL6:
+	case RT5660_ALC_PGA_CTRL7:
+	case RT5660_GEN_CTRL1:
+	case RT5660_GEN_CTRL2:
+	case RT5660_GEN_CTRL3:
+	case RT5660_VENDOR_ID:
+	case RT5660_VENDOR_ID1:
+	case RT5660_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(rt5660_out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rt5660_dac_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(rt5660_adc_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(rt5660_adc_bst_tlv, 0, 1200, 0);
+static const DECLARE_TLV_DB_SCALE(rt5660_bst_tlv, -1200, 75, 0);
+
+static const struct snd_kcontrol_new rt5660_snd_controls[] = {
+	/* Speaker Output Volume */
+	SOC_SINGLE("Speaker Playback Switch", RT5660_SPK_VOL, RT5660_L_MUTE_SFT,
+		1, 1),
+	SOC_SINGLE_TLV("Speaker Playback Volume", RT5660_SPK_VOL,
+		RT5660_L_VOL_SFT, 39, 1, rt5660_out_vol_tlv),
+
+	/* OUTPUT Control */
+	SOC_DOUBLE("OUT Playback Switch", RT5660_LOUT_VOL, RT5660_L_MUTE_SFT,
+		RT5660_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("OUT Playback Volume", RT5660_LOUT_VOL, RT5660_L_VOL_SFT,
+		RT5660_R_VOL_SFT, 39, 1, rt5660_out_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5660_DAC1_DIG_VOL,
+		RT5660_DAC_L1_VOL_SFT, RT5660_DAC_R1_VOL_SFT, 87, 0,
+		rt5660_dac_vol_tlv),
+
+	/* IN1/IN2/IN3 Control */
+	SOC_SINGLE_TLV("IN1 Boost Volume", RT5660_IN1_IN2, RT5660_BST_SFT1, 69,
+		0, rt5660_bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost Volume", RT5660_IN1_IN2, RT5660_BST_SFT2, 69,
+		0, rt5660_bst_tlv),
+	SOC_SINGLE_TLV("IN3 Boost Volume", RT5660_IN3_IN4, RT5660_BST_SFT3, 69,
+		0, rt5660_bst_tlv),
+
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC Capture Switch", RT5660_STO1_ADC_DIG_VOL,
+		RT5660_L_MUTE_SFT, RT5660_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("ADC Capture Volume", RT5660_STO1_ADC_DIG_VOL,
+		RT5660_ADC_L_VOL_SFT, RT5660_ADC_R_VOL_SFT, 63, 0,
+		rt5660_adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5660_ADC_BST_VOL1,
+		RT5660_STO1_ADC_L_BST_SFT, RT5660_STO1_ADC_R_BST_SFT, 3, 0,
+		rt5660_adc_bst_tlv),
+};
+
+/**
+ * rt5660_set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ */
+static int rt5660_set_dmic_clk(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 rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	int idx, rate;
+
+	rate = rt5660->sysclk / rl6231_get_pre_div(rt5660->regmap,
+		RT5660_ADDA_CLK1, RT5660_I2S_PD1_SFT);
+	idx = rl6231_calc_dmic_clk(rate);
+	if (idx < 0)
+		dev_err(codec->dev, "Failed to set DMIC clock\n");
+	else
+		snd_soc_update_bits(codec, RT5660_DMIC_CTRL1,
+			RT5660_DMIC_CLK_MASK, idx << RT5660_DMIC_CLK_SFT);
+
+	return idx;
+}
+
+static int rt5660_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	unsigned int val;
+
+	val = snd_soc_read(codec, RT5660_GLB_CLK);
+	val &= RT5660_SCLK_SRC_MASK;
+	if (val == RT5660_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5660_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5660_STO1_ADC_MIXER,
+			RT5660_M_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5660_STO1_ADC_MIXER,
+			RT5660_M_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5660_STO1_ADC_MIXER,
+			RT5660_M_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5660_STO1_ADC_MIXER,
+			RT5660_M_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5660_AD_DA_MIXER,
+			RT5660_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5660_AD_DA_MIXER,
+			RT5660_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5660_AD_DA_MIXER,
+			RT5660_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5660_AD_DA_MIXER,
+			RT5660_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_sto_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5660_STO_DAC_MIXER,
+			RT5660_M_DAC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5660_STO_DAC_MIXER,
+			RT5660_M_DAC_R1_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_sto_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5660_STO_DAC_MIXER,
+			RT5660_M_DAC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5660_STO_DAC_MIXER,
+			RT5660_M_DAC_L1_STO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5660_rec_l_mix[] = {
+	SOC_DAPM_SINGLE("BST3 Switch", RT5660_REC_L2_MIXER,
+			RT5660_M_BST3_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5660_REC_L2_MIXER,
+			RT5660_M_BST2_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_REC_L2_MIXER,
+			RT5660_M_BST1_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUT MIXL Switch", RT5660_REC_L2_MIXER,
+			RT5660_M_OM_L_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_rec_r_mix[] = {
+	SOC_DAPM_SINGLE("BST3 Switch", RT5660_REC_R2_MIXER,
+			RT5660_M_BST3_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5660_REC_R2_MIXER,
+			RT5660_M_BST2_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_REC_R2_MIXER,
+			RT5660_M_BST1_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUT MIXR Switch", RT5660_REC_R2_MIXER,
+			RT5660_M_OM_R_RM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_spk_mix[] = {
+	SOC_DAPM_SINGLE("BST3 Switch", RT5660_SPK_MIXER,
+			RT5660_M_BST3_SM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_SPK_MIXER,
+			RT5660_M_BST1_SM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Switch", RT5660_SPK_MIXER,
+			RT5660_M_DACL_SM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACR Switch", RT5660_SPK_MIXER,
+			RT5660_M_DACR_SM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTMIXL Switch", RT5660_SPK_MIXER,
+			RT5660_M_OM_L_SM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_out_l_mix[] = {
+	SOC_DAPM_SINGLE("BST3 Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_BST3_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_BST2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIXL Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_RM_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACR Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_DAC_R_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_DAC_L_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_out_r_mix[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_BST2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_BST1_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIXR Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_RM_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACR Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_DAC_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_DAC_L_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_spo_mix[] = {
+	SOC_DAPM_SINGLE("DACR Switch", RT5660_SPO_MIXER,
+			RT5660_M_DAC_R_SPM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Switch", RT5660_SPO_MIXER,
+			RT5660_M_DAC_L_SPM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("SPKVOL Switch", RT5660_SPO_MIXER,
+			RT5660_M_SV_SPM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_SPO_MIXER,
+			RT5660_M_BST1_SPM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_lout_mix[] = {
+	SOC_DAPM_SINGLE("DAC Switch", RT5660_LOUT_MIXER,
+			RT5660_M_DAC1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTMIX Switch", RT5660_LOUT_MIXER,
+			RT5660_M_LOVOL_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new spk_vol_control =
+	SOC_DAPM_SINGLE("Switch", RT5660_SPK_VOL,
+		RT5660_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_l_vol_control =
+	SOC_DAPM_SINGLE("Switch", RT5660_LOUT_VOL,
+		RT5660_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_vol_control =
+	SOC_DAPM_SINGLE("Switch", RT5660_LOUT_VOL,
+		RT5660_VOL_R_SFT, 1, 1);
+
+/* Interface data select */
+static const char * const rt5660_data_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(rt5660_if1_dac_enum,
+	RT5660_DIG_INF1_DATA, RT5660_IF1_DAC_IN_SFT, rt5660_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5660_if1_adc_enum,
+	RT5660_DIG_INF1_DATA, RT5660_IF1_ADC_IN_SFT, rt5660_data_select);
+
+static const struct snd_kcontrol_new rt5660_if1_dac_swap_mux =
+	SOC_DAPM_ENUM("IF1 DAC Swap Source", rt5660_if1_dac_enum);
+
+static const struct snd_kcontrol_new rt5660_if1_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC Swap Source", rt5660_if1_adc_enum);
+
+static int rt5660_lout_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, RT5660_LOUT_AMP_CTRL,
+			RT5660_LOUT_CO_MASK | RT5660_LOUT_CB_MASK,
+			RT5660_LOUT_CO_EN | RT5660_LOUT_CB_PU);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, RT5660_LOUT_AMP_CTRL,
+			RT5660_LOUT_CO_MASK | RT5660_LOUT_CB_MASK,
+			RT5660_LOUT_CO_DIS | RT5660_LOUT_CB_PD);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5660_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5660_PWR_ANLG1,
+		RT5660_PWR_LDO2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5660_PWR_ANLG2,
+		RT5660_PWR_PLL_BIT, 0, NULL, 0),
+
+	/* MICBIAS */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5660_PWR_ANLG2,
+			RT5660_PWR_MB1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5660_PWR_ANLG2,
+			RT5660_PWR_MB2_BIT, 0, NULL, 0),
+
+	/* Input Side */
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN3P"),
+	SND_SOC_DAPM_INPUT("IN3N"),
+
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+		rt5660_set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC Power", RT5660_DMIC_CTRL1,
+		RT5660_DMIC_1_EN_SFT, 0, NULL, 0),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1", RT5660_PWR_ANLG2, RT5660_PWR_BST1_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("BST2", RT5660_PWR_ANLG2, RT5660_PWR_BST2_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("BST3", RT5660_PWR_ANLG2, RT5660_PWR_BST3_BIT, 0,
+		NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIXL", RT5660_PWR_MIXER, RT5660_PWR_RM_L_BIT,
+			0, rt5660_rec_l_mix, ARRAY_SIZE(rt5660_rec_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIXR", RT5660_PWR_MIXER, RT5660_PWR_RM_R_BIT,
+			0, rt5660_rec_r_mix, ARRAY_SIZE(rt5660_rec_r_mix)),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC L power", RT5660_PWR_DIG1,
+			RT5660_PWR_ADC_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC R power", RT5660_PWR_DIG1,
+			RT5660_PWR_ADC_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC clock", RT5660_PR_BASE + RT5660_CHOP_DAC_ADC,
+			12, 0, NULL, 0),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("adc stereo1 filter", RT5660_PWR_DIG2,
+		RT5660_PWR_ADC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5660_sto1_adc_l_mix, ARRAY_SIZE(rt5660_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5660_sto1_adc_r_mix, ARRAY_SIZE(rt5660_sto1_adc_r_mix)),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("Stereo1 ADC MIXL", NULL, RT5660_STO1_ADC_DIG_VOL,
+		RT5660_L_MUTE_SFT, 1),
+	SND_SOC_DAPM_ADC("Stereo1 ADC MIXR", NULL, RT5660_STO1_ADC_DIG_VOL,
+		RT5660_R_MUTE_SFT, 1),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5660_PWR_DIG1, RT5660_PWR_I2S1_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("IF1 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5660_if1_dac_swap_mux),
+	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("IF1 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5660_if1_adc_swap_mux),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, rt5660_dac_l_mix,
+		ARRAY_SIZE(rt5660_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, rt5660_dac_r_mix,
+		ARRAY_SIZE(rt5660_dac_r_mix)),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5660_PWR_DIG2,
+		RT5660_PWR_DAC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5660_sto_dac_l_mix, ARRAY_SIZE(rt5660_sto_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5660_sto_dac_r_mix, ARRAY_SIZE(rt5660_sto_dac_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC L1", NULL, RT5660_PWR_DIG1,
+			RT5660_PWR_DAC_L1_BIT, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, RT5660_PWR_DIG1,
+			RT5660_PWR_DAC_R1_BIT, 0),
+
+	/* OUT Mixer */
+	SND_SOC_DAPM_MIXER("SPK MIX", RT5660_PWR_MIXER, RT5660_PWR_SM_BIT,
+		0, rt5660_spk_mix, ARRAY_SIZE(rt5660_spk_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5660_PWR_MIXER, RT5660_PWR_OM_L_BIT,
+		0, rt5660_out_l_mix, ARRAY_SIZE(rt5660_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5660_PWR_MIXER, RT5660_PWR_OM_R_BIT,
+		0, rt5660_out_r_mix, ARRAY_SIZE(rt5660_out_r_mix)),
+
+	/* Output Volume */
+	SND_SOC_DAPM_SWITCH("SPKVOL", RT5660_PWR_VOL,
+		RT5660_PWR_SV_BIT, 0, &spk_vol_control),
+	SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("LOUTVOL", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_SWITCH("LOUTVOL L", SND_SOC_NOPM,
+		RT5660_PWR_LV_L_BIT, 0, &lout_l_vol_control),
+	SND_SOC_DAPM_SWITCH("LOUTVOL R", SND_SOC_NOPM,
+		RT5660_PWR_LV_R_BIT, 0, &lout_r_vol_control),
+
+	/* HPO/LOUT/Mono Mixer */
+	SND_SOC_DAPM_MIXER("SPO MIX", SND_SOC_NOPM, 0,
+		0, rt5660_spo_mix, ARRAY_SIZE(rt5660_spo_mix)),
+	SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0,
+		rt5660_lout_mix, ARRAY_SIZE(rt5660_lout_mix)),
+	SND_SOC_DAPM_SUPPLY("VREF HP", RT5660_GEN_CTRL1,
+		RT5660_PWR_VREF_HP_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("LOUT amp", 1, RT5660_PWR_ANLG1,
+		RT5660_PWR_HA_BIT, 0, rt5660_lout_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("SPK amp", 1, RT5660_PWR_DIG1,
+		RT5660_PWR_CLS_D_BIT, 0, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+	SND_SOC_DAPM_OUTPUT("SPO"),
+};
+
+static const struct snd_soc_dapm_route rt5660_dapm_routes[] = {
+	{ "MICBIAS1", NULL, "LDO2" },
+	{ "MICBIAS2", NULL, "LDO2" },
+
+	{ "BST1", NULL, "IN1P" },
+	{ "BST1", NULL, "IN1N" },
+	{ "BST2", NULL, "IN2P" },
+	{ "BST3", NULL, "IN3P" },
+	{ "BST3", NULL, "IN3N" },
+
+	{ "RECMIXL", "BST3 Switch", "BST3" },
+	{ "RECMIXL", "BST2 Switch", "BST2" },
+	{ "RECMIXL", "BST1 Switch", "BST1" },
+	{ "RECMIXL", "OUT MIXL Switch", "OUT MIXL" },
+
+	{ "RECMIXR", "BST3 Switch", "BST3" },
+	{ "RECMIXR", "BST2 Switch", "BST2" },
+	{ "RECMIXR", "BST1 Switch", "BST1" },
+	{ "RECMIXR", "OUT MIXR Switch", "OUT MIXR" },
+
+	{ "ADC L", NULL, "RECMIXL" },
+	{ "ADC L", NULL, "ADC L power" },
+	{ "ADC L", NULL, "ADC clock" },
+	{ "ADC R", NULL, "RECMIXR" },
+	{ "ADC R", NULL, "ADC R power" },
+	{ "ADC R", NULL, "ADC clock" },
+
+	{"DMIC L1", NULL, "DMIC CLK"},
+	{"DMIC L1", NULL, "DMIC Power"},
+	{"DMIC R1", NULL, "DMIC CLK"},
+	{"DMIC R1", NULL, "DMIC Power"},
+
+	{ "Sto1 ADC MIXL", "ADC1 Switch", "ADC L" },
+	{ "Sto1 ADC MIXL", "ADC2 Switch", "DMIC L1" },
+	{ "Sto1 ADC MIXR", "ADC1 Switch", "ADC R" },
+	{ "Sto1 ADC MIXR", "ADC2 Switch", "DMIC R1" },
+
+	{ "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
+	{ "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" },
+	{ "adc stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll },
+
+	{ "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
+	{ "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" },
+	{ "adc stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll },
+
+	{ "IF1 ADC", NULL, "Stereo1 ADC MIXL" },
+	{ "IF1 ADC", NULL, "Stereo1 ADC MIXR" },
+	{ "IF1 ADC", NULL, "I2S1" },
+
+	{ "IF1 ADC Swap Mux", "L/R", "IF1 ADC" },
+	{ "IF1 ADC Swap Mux", "R/L", "IF1 ADC" },
+	{ "IF1 ADC Swap Mux", "L/L", "IF1 ADC" },
+	{ "IF1 ADC Swap Mux", "R/R", "IF1 ADC" },
+	{ "AIF1TX", NULL, "IF1 ADC Swap Mux" },
+
+	{ "IF1 DAC", NULL, "AIF1RX" },
+	{ "IF1 DAC", NULL, "I2S1" },
+
+	{ "IF1 DAC Swap Mux", "L/R", "IF1 DAC" },
+	{ "IF1 DAC Swap Mux", "R/L", "IF1 DAC" },
+	{ "IF1 DAC Swap Mux", "L/L", "IF1 DAC" },
+	{ "IF1 DAC Swap Mux", "R/R", "IF1 DAC" },
+
+	{ "IF1 DAC L", NULL, "IF1 DAC Swap Mux" },
+	{ "IF1 DAC R", NULL, "IF1 DAC Swap Mux" },
+
+	{ "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" },
+	{ "DAC1 MIXL", "DAC1 Switch", "IF1 DAC L" },
+	{ "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR" },
+	{ "DAC1 MIXR", "DAC1 Switch", "IF1 DAC R" },
+
+	{ "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXL", NULL, "dac stereo1 filter" },
+	{ "dac stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll },
+	{ "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXR", NULL, "dac stereo1 filter" },
+	{ "dac stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll },
+
+	{ "DAC L1", NULL, "Stereo DAC MIXL" },
+	{ "DAC R1", NULL, "Stereo DAC MIXR" },
+
+	{ "SPK MIX", "BST3 Switch", "BST3" },
+	{ "SPK MIX", "BST1 Switch", "BST1" },
+	{ "SPK MIX", "DACL Switch", "DAC L1" },
+	{ "SPK MIX", "DACR Switch", "DAC R1" },
+	{ "SPK MIX", "OUTMIXL Switch", "OUT MIXL" },
+
+	{ "OUT MIXL", "BST3 Switch", "BST3" },
+	{ "OUT MIXL", "BST2 Switch", "BST2" },
+	{ "OUT MIXL", "BST1 Switch", "BST1" },
+	{ "OUT MIXL", "RECMIXL Switch", "RECMIXL" },
+	{ "OUT MIXL", "DACR Switch", "DAC R1" },
+	{ "OUT MIXL", "DACL Switch", "DAC L1" },
+
+	{ "OUT MIXR", "BST2 Switch", "BST2" },
+	{ "OUT MIXR", "BST1 Switch", "BST1" },
+	{ "OUT MIXR", "RECMIXR Switch", "RECMIXR" },
+	{ "OUT MIXR", "DACR Switch", "DAC R1" },
+	{ "OUT MIXR", "DACL Switch", "DAC L1" },
+
+	{ "SPO MIX", "DACR Switch", "DAC R1" },
+	{ "SPO MIX", "DACL Switch", "DAC L1" },
+	{ "SPO MIX", "SPKVOL Switch", "SPKVOL" },
+	{ "SPO MIX", "BST1 Switch", "BST1" },
+
+	{ "SPKVOL", "Switch", "SPK MIX" },
+	{ "LOUTVOL L", "Switch", "OUT MIXL" },
+	{ "LOUTVOL R", "Switch", "OUT MIXR" },
+
+	{ "LOUTVOL", NULL, "LOUTVOL L" },
+	{ "LOUTVOL", NULL, "LOUTVOL R" },
+
+	{ "DAC 1", NULL, "DAC L1" },
+	{ "DAC 1", NULL, "DAC R1" },
+
+	{ "LOUT MIX", "DAC Switch", "DAC 1" },
+	{ "LOUT MIX", "OUTMIX Switch", "LOUTVOL" },
+
+	{ "LOUT amp", NULL, "LOUT MIX" },
+	{ "LOUT amp", NULL, "VREF HP" },
+	{ "LOUTL", NULL, "LOUT amp" },
+	{ "LOUTR", NULL, "LOUT amp" },
+
+	{ "SPK amp", NULL, "SPO MIX" },
+	{ "SPO", NULL, "SPK amp" },
+};
+
+static int rt5660_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 rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int pre_div, bclk_ms, frame_size;
+
+	rt5660->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5660->sysclk, rt5660->lrck[dai->id]);
+	if (pre_div < 0) {
+		dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+			rt5660->lrck[dai->id], dai->id);
+		return -EINVAL;
+	}
+
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+		return frame_size;
+	}
+
+	if (frame_size > 32)
+		bclk_ms = 1;
+	else
+		bclk_ms = 0;
+
+	rt5660->bclk[dai->id] = rt5660->lrck[dai->id] * (32 << bclk_ms);
+
+	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+		rt5660->bclk[dai->id], rt5660->lrck[dai->id]);
+	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+				bclk_ms, pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len |= RT5660_I2S_DL_20;
+		break;
+	case 24:
+		val_len |= RT5660_I2S_DL_24;
+		break;
+	case 8:
+		val_len |= RT5660_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5660_AIF1:
+		mask_clk = RT5660_I2S_BCLK_MS1_MASK | RT5660_I2S_PD1_MASK;
+		val_clk = bclk_ms << RT5660_I2S_BCLK_MS1_SFT |
+			pre_div << RT5660_I2S_PD1_SFT;
+		snd_soc_update_bits(codec, RT5660_I2S1_SDP, RT5660_I2S_DL_MASK,
+			val_len);
+		snd_soc_update_bits(codec, RT5660_ADDA_CLK1, mask_clk, val_clk);
+		break;
+
+	default:
+		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5660_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5660->master[dai->id] = 1;
+		break;
+
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5660_I2S_MS_S;
+		rt5660->master[dai->id] = 0;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5660_I2S_BP_INV;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5660_I2S_DF_LEFT;
+		break;
+
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5660_I2S_DF_PCM_A;
+		break;
+
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val  |= RT5660_I2S_DF_PCM_B;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5660_AIF1:
+		snd_soc_update_bits(codec, RT5660_I2S1_SDP,
+			RT5660_I2S_MS_MASK | RT5660_I2S_BP_MASK |
+			RT5660_I2S_DF_MASK, reg_val);
+		break;
+
+	default:
+		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5660_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	unsigned int reg_val = 0;
+
+	if (freq == rt5660->sysclk && clk_id == rt5660->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5660_SCLK_S_MCLK:
+		reg_val |= RT5660_SCLK_SRC_MCLK;
+		break;
+
+	case RT5660_SCLK_S_PLL1:
+		reg_val |= RT5660_SCLK_SRC_PLL1;
+		break;
+
+	case RT5660_SCLK_S_RCCLK:
+		reg_val |= RT5660_SCLK_SRC_RCCLK;
+		break;
+
+	default:
+		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, RT5660_GLB_CLK, RT5660_SCLK_SRC_MASK,
+		reg_val);
+
+	rt5660->sysclk = freq;
+	rt5660->sysclk_src = clk_id;
+
+	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+	return 0;
+}
+
+static int rt5660_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 rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5660->pll_src && freq_in == rt5660->pll_in &&
+		freq_out == rt5660->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(codec->dev, "PLL disabled\n");
+
+		rt5660->pll_in = 0;
+		rt5660->pll_out = 0;
+		snd_soc_update_bits(codec, RT5660_GLB_CLK,
+			RT5660_SCLK_SRC_MASK, RT5660_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5660_PLL1_S_MCLK:
+		snd_soc_update_bits(codec, RT5660_GLB_CLK,
+			RT5660_PLL1_SRC_MASK, RT5660_PLL1_SRC_MCLK);
+		break;
+
+	case RT5660_PLL1_S_BCLK:
+		snd_soc_update_bits(codec, RT5660_GLB_CLK,
+			RT5660_PLL1_SRC_MASK, RT5660_PLL1_SRC_BCLK1);
+		break;
+
+	default:
+		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_write(codec, RT5660_PLL_CTRL1,
+		pll_code.n_code << RT5660_PLL_N_SFT | pll_code.k_code);
+	snd_soc_write(codec, RT5660_PLL_CTRL2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5660_PLL_M_SFT |
+		pll_code.m_bp << RT5660_PLL_M_BP_SFT);
+
+	rt5660->pll_in = freq_in;
+	rt5660->pll_out = freq_out;
+	rt5660->pll_src = source;
+
+	return 0;
+}
+
+static int rt5660_set_bias_level(struct snd_soc_codec *codec,
+			enum snd_soc_bias_level level)
+{
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_update_bits(codec, RT5660_GEN_CTRL1,
+			RT5660_DIG_GATE_CTRL, RT5660_DIG_GATE_CTRL);
+
+		if (IS_ERR(rt5660->mclk))
+			break;
+
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) {
+			clk_disable_unprepare(rt5660->mclk);
+		} else {
+			ret = clk_prepare_enable(rt5660->mclk);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+			snd_soc_update_bits(codec, RT5660_PWR_ANLG1,
+				RT5660_PWR_VREF1 | RT5660_PWR_MB |
+				RT5660_PWR_BG | RT5660_PWR_VREF2,
+				RT5660_PWR_VREF1 | RT5660_PWR_MB |
+				RT5660_PWR_BG | RT5660_PWR_VREF2);
+			usleep_range(10000, 15000);
+			snd_soc_update_bits(codec, RT5660_PWR_ANLG1,
+				RT5660_PWR_FV1 | RT5660_PWR_FV2,
+				RT5660_PWR_FV1 | RT5660_PWR_FV2);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, RT5660_GEN_CTRL1,
+			RT5660_DIG_GATE_CTRL, 0);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5660_probe(struct snd_soc_codec *codec)
+{
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+
+	rt5660->codec = codec;
+
+	return 0;
+}
+
+static int rt5660_remove(struct snd_soc_codec *codec)
+{
+	return snd_soc_write(codec, RT5660_RESET, 0);
+}
+
+#ifdef CONFIG_PM
+static int rt5660_suspend(struct snd_soc_codec *codec)
+{
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+
+	regcache_cache_only(rt5660->regmap, true);
+	regcache_mark_dirty(rt5660->regmap);
+
+	return 0;
+}
+
+static int rt5660_resume(struct snd_soc_codec *codec)
+{
+	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+
+	if (rt5660->pdata.poweroff_codec_in_suspend)
+		usleep_range(350000, 400000);
+
+	regcache_cache_only(rt5660->regmap, false);
+	regcache_sync(rt5660->regmap);
+
+	return 0;
+}
+#else
+#define rt5660_suspend NULL
+#define rt5660_resume NULL
+#endif
+
+#define RT5660_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5660_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 rt5660_aif_dai_ops = {
+	.hw_params = rt5660_hw_params,
+	.set_fmt = rt5660_set_dai_fmt,
+	.set_sysclk = rt5660_set_dai_sysclk,
+	.set_pll = rt5660_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5660_dai[] = {
+	{
+		.name = "rt5660-aif1",
+		.id = RT5660_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5660_STEREO_RATES,
+			.formats = RT5660_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5660_STEREO_RATES,
+			.formats = RT5660_FORMATS,
+		},
+		.ops = &rt5660_aif_dai_ops,
+	},
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5660 = {
+	.probe = rt5660_probe,
+	.remove = rt5660_remove,
+	.suspend = rt5660_suspend,
+	.resume = rt5660_resume,
+	.set_bias_level = rt5660_set_bias_level,
+	.idle_bias_off = true,
+	.component_driver = {
+		.controls		= rt5660_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5660_snd_controls),
+		.dapm_widgets		= rt5660_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5660_dapm_widgets),
+		.dapm_routes		= rt5660_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5660_dapm_routes),
+	},
+};
+
+static const struct regmap_config rt5660_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.use_single_rw = true,
+
+	.max_register = RT5660_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5660_ranges) *
+					       RT5660_PR_SPACING),
+	.volatile_reg = rt5660_volatile_register,
+	.readable_reg = rt5660_readable_register,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5660_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5660_reg),
+	.ranges = rt5660_ranges,
+	.num_ranges = ARRAY_SIZE(rt5660_ranges),
+};
+
+static const struct i2c_device_id rt5660_i2c_id[] = {
+	{ "rt5660", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5660_i2c_id);
+
+static const struct of_device_id rt5660_of_match[] = {
+	{ .compatible = "realtek,rt5660", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5660_of_match);
+
+static const struct acpi_device_id rt5660_acpi_match[] = {
+	{ "10EC5660", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, rt5660_acpi_match);
+
+static int rt5660_parse_dt(struct rt5660_priv *rt5660, struct device *dev)
+{
+	rt5660->pdata.in1_diff = device_property_read_bool(dev,
+					"realtek,in1-differential");
+	rt5660->pdata.in3_diff = device_property_read_bool(dev,
+					"realtek,in3-differential");
+	rt5660->pdata.poweroff_codec_in_suspend = device_property_read_bool(dev,
+					"realtek,poweroff-in-suspend");
+	device_property_read_u32(dev, "realtek,dmic1-data-pin",
+		&rt5660->pdata.dmic1_data_pin);
+
+	return 0;
+}
+
+static int rt5660_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5660_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt5660_priv *rt5660;
+	int ret;
+	unsigned int val;
+
+	rt5660 = devm_kzalloc(&i2c->dev, sizeof(struct rt5660_priv),
+		GFP_KERNEL);
+
+	if (rt5660 == NULL)
+		return -ENOMEM;
+
+	/* Check if MCLK provided */
+	rt5660->mclk = devm_clk_get(&i2c->dev, "mclk");
+	if (PTR_ERR(rt5660->mclk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	i2c_set_clientdata(i2c, rt5660);
+
+	if (pdata)
+		rt5660->pdata = *pdata;
+	else if (i2c->dev.of_node)
+		rt5660_parse_dt(rt5660, &i2c->dev);
+
+	rt5660->regmap = devm_regmap_init_i2c(i2c, &rt5660_regmap);
+	if (IS_ERR(rt5660->regmap)) {
+		ret = PTR_ERR(rt5660->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt5660->regmap, RT5660_VENDOR_ID2, &val);
+	if (val != RT5660_DEVICE_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5660\n", val);
+		return -ENODEV;
+	}
+
+	regmap_write(rt5660->regmap, RT5660_RESET, 0);
+
+	ret = regmap_register_patch(rt5660->regmap, rt5660_patch,
+				    ARRAY_SIZE(rt5660_patch));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	if (rt5660->pdata.dmic1_data_pin) {
+		regmap_update_bits(rt5660->regmap, RT5660_GPIO_CTRL1,
+			RT5660_GP1_PIN_MASK, RT5660_GP1_PIN_DMIC1_SCL);
+
+		if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_GPIO2)
+			regmap_update_bits(rt5660->regmap, RT5660_DMIC_CTRL1,
+				RT5660_SEL_DMIC_DATA_MASK,
+				RT5660_SEL_DMIC_DATA_GPIO2);
+		else if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_IN1P)
+			regmap_update_bits(rt5660->regmap, RT5660_DMIC_CTRL1,
+				RT5660_SEL_DMIC_DATA_MASK,
+				RT5660_SEL_DMIC_DATA_IN1P);
+	}
+
+	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5660,
+				      rt5660_dai, ARRAY_SIZE(rt5660_dai));
+}
+
+static int rt5660_i2c_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_codec(&i2c->dev);
+
+	return 0;
+}
+
+static struct i2c_driver rt5660_i2c_driver = {
+	.driver = {
+		.name = "rt5660",
+		.acpi_match_table = ACPI_PTR(rt5660_acpi_match),
+		.of_match_table = of_match_ptr(rt5660_of_match),
+	},
+	.probe = rt5660_i2c_probe,
+	.remove   = rt5660_i2c_remove,
+	.id_table = rt5660_i2c_id,
+};
+module_i2c_driver(rt5660_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5660 driver");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5660.h b/sound/soc/codecs/rt5660.h
new file mode 100644
index 000000000000..6cdb9269ec9e
--- /dev/null
+++ b/sound/soc/codecs/rt5660.h
@@ -0,0 +1,847 @@
+/*
+ * rt5660.h  --  RT5660 ALSA SoC audio driver
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@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 _RT5660_H
+#define _RT5660_H
+
+#include <linux/clk.h>
+#include <sound/rt5660.h>
+
+/* Info */
+#define RT5660_RESET				0x00
+#define RT5660_VENDOR_ID			0xfd
+#define RT5660_VENDOR_ID1			0xfe
+#define RT5660_VENDOR_ID2			0xff
+/*  I/O - Output */
+#define RT5660_SPK_VOL				0x01
+#define RT5660_LOUT_VOL				0x02
+/* I/O - Input */
+#define RT5660_IN1_IN2				0x0d
+#define RT5660_IN3_IN4				0x0e
+/* I/O - ADC/DAC/DMIC */
+#define RT5660_DAC1_DIG_VOL			0x19
+#define RT5660_STO1_ADC_DIG_VOL			0x1c
+#define RT5660_ADC_BST_VOL1			0x1e
+/* Mixer - D-D */
+#define RT5660_STO1_ADC_MIXER			0x27
+#define RT5660_AD_DA_MIXER			0x29
+#define RT5660_STO_DAC_MIXER			0x2a
+#define RT5660_DIG_INF1_DATA			0x2f
+/* Mixer - ADC */
+#define RT5660_REC_L1_MIXER			0x3b
+#define RT5660_REC_L2_MIXER			0x3c
+#define RT5660_REC_R1_MIXER			0x3d
+#define RT5660_REC_R2_MIXER			0x3e
+/* Mixer - DAC */
+#define RT5660_LOUT_MIXER			0x45
+#define RT5660_SPK_MIXER			0x46
+#define RT5660_SPO_MIXER			0x48
+#define RT5660_SPO_CLSD_RATIO			0x4a
+#define RT5660_OUT_L_GAIN1			0x4d
+#define RT5660_OUT_L_GAIN2			0x4e
+#define RT5660_OUT_L1_MIXER			0x4f
+#define RT5660_OUT_R_GAIN1			0x50
+#define RT5660_OUT_R_GAIN2			0x51
+#define RT5660_OUT_R1_MIXER			0x52
+/* Power */
+#define RT5660_PWR_DIG1				0x61
+#define RT5660_PWR_DIG2				0x62
+#define RT5660_PWR_ANLG1			0x63
+#define RT5660_PWR_ANLG2			0x64
+#define RT5660_PWR_MIXER			0x65
+#define RT5660_PWR_VOL				0x66
+/* Private Register Control */
+#define RT5660_PRIV_INDEX			0x6a
+#define RT5660_PRIV_DATA			0x6c
+/* Format - ADC/DAC */
+#define RT5660_I2S1_SDP				0x70
+#define RT5660_ADDA_CLK1			0x73
+#define RT5660_ADDA_CLK2			0x74
+#define RT5660_DMIC_CTRL1			0x75
+/* Function - Analog */
+#define RT5660_GLB_CLK				0x80
+#define RT5660_PLL_CTRL1			0x81
+#define RT5660_PLL_CTRL2			0x82
+#define RT5660_CLSD_AMP_OC_CTRL			0x8c
+#define RT5660_CLSD_AMP_CTRL			0x8d
+#define RT5660_LOUT_AMP_CTRL			0x8e
+#define RT5660_SPK_AMP_SPKVDD			0x92
+#define RT5660_MICBIAS				0x93
+#define RT5660_CLSD_OUT_CTRL1			0xa1
+#define RT5660_CLSD_OUT_CTRL2			0xa2
+#define RT5660_DIPOLE_MIC_CTRL1			0xa3
+#define RT5660_DIPOLE_MIC_CTRL2			0xa4
+#define RT5660_DIPOLE_MIC_CTRL3			0xa5
+#define RT5660_DIPOLE_MIC_CTRL4			0xa6
+#define RT5660_DIPOLE_MIC_CTRL5			0xa7
+#define RT5660_DIPOLE_MIC_CTRL6			0xa8
+#define RT5660_DIPOLE_MIC_CTRL7			0xa9
+#define RT5660_DIPOLE_MIC_CTRL8			0xaa
+#define RT5660_DIPOLE_MIC_CTRL9			0xab
+#define RT5660_DIPOLE_MIC_CTRL10		0xac
+#define RT5660_DIPOLE_MIC_CTRL11		0xad
+#define RT5660_DIPOLE_MIC_CTRL12		0xae
+/* Function - Digital */
+#define RT5660_EQ_CTRL1				0xb0
+#define RT5660_EQ_CTRL2				0xb1
+#define RT5660_DRC_AGC_CTRL1			0xb3
+#define RT5660_DRC_AGC_CTRL2			0xb4
+#define RT5660_DRC_AGC_CTRL3			0xb5
+#define RT5660_DRC_AGC_CTRL4			0xb6
+#define RT5660_DRC_AGC_CTRL5			0xb7
+#define RT5660_JD_CTRL				0xbb
+#define RT5660_IRQ_CTRL1			0xbd
+#define RT5660_IRQ_CTRL2			0xbe
+#define RT5660_INT_IRQ_ST			0xbf
+#define RT5660_GPIO_CTRL1			0xc0
+#define RT5660_GPIO_CTRL2			0xc2
+#define RT5660_WIND_FILTER_CTRL1		0xd3
+#define RT5660_SV_ZCD1				0xd9
+#define RT5660_SV_ZCD2				0xda
+#define RT5660_DRC1_LM_CTRL1			0xe0
+#define RT5660_DRC1_LM_CTRL2			0xe1
+#define RT5660_DRC2_LM_CTRL1			0xe2
+#define RT5660_DRC2_LM_CTRL2			0xe3
+#define RT5660_MULTI_DRC_CTRL			0xe4
+#define RT5660_DRC2_CTRL1			0xe5
+#define RT5660_DRC2_CTRL2			0xe6
+#define RT5660_DRC2_CTRL3			0xe7
+#define RT5660_DRC2_CTRL4			0xe8
+#define RT5660_DRC2_CTRL5			0xe9
+#define RT5660_ALC_PGA_CTRL1			0xea
+#define RT5660_ALC_PGA_CTRL2			0xeb
+#define RT5660_ALC_PGA_CTRL3			0xec
+#define RT5660_ALC_PGA_CTRL4			0xed
+#define RT5660_ALC_PGA_CTRL5			0xee
+#define RT5660_ALC_PGA_CTRL6			0xef
+#define RT5660_ALC_PGA_CTRL7			0xf0
+
+/* General Control */
+#define RT5660_GEN_CTRL1			0xfa
+#define RT5660_GEN_CTRL2			0xfb
+#define RT5660_GEN_CTRL3			0xfc
+
+/* Index of Codec Private Register definition */
+#define RT5660_CHOP_DAC_ADC			0x3d
+
+/* Global Definition */
+#define RT5660_L_MUTE				(0x1 << 15)
+#define RT5660_L_MUTE_SFT			15
+#define RT5660_VOL_L_MUTE			(0x1 << 14)
+#define RT5660_VOL_L_SFT			14
+#define RT5660_R_MUTE				(0x1 << 7)
+#define RT5660_R_MUTE_SFT			7
+#define RT5660_VOL_R_MUTE			(0x1 << 6)
+#define RT5660_VOL_R_SFT			6
+#define RT5660_L_VOL_MASK			(0x3f << 8)
+#define RT5660_L_VOL_SFT			8
+#define RT5660_R_VOL_MASK			(0x3f)
+#define RT5660_R_VOL_SFT			0
+
+/* IN1 and IN2 Control (0x0d) */
+#define RT5660_IN_DF1				(0x1 << 15)
+#define RT5660_IN_SFT1				15
+#define RT5660_BST_MASK1			(0x7f << 8)
+#define RT5660_BST_SFT1				8
+#define RT5660_IN_DF2				(0x1 << 7)
+#define RT5660_IN_SFT2				7
+#define RT5660_BST_MASK2			(0x7f << 0)
+#define RT5660_BST_SFT2				0
+
+/* IN3 and IN4 Control (0x0e) */
+#define RT5660_IN_DF3				(0x1 << 15)
+#define RT5660_IN_SFT3				15
+#define RT5660_BST_MASK3			(0x7f << 8)
+#define RT5660_BST_SFT3				8
+#define RT5660_IN_DF4				(0x1 << 7)
+#define RT5660_IN_SFT4				7
+#define RT5660_BST_MASK4			(0x7f << 0)
+#define RT5660_BST_SFT4				0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5660_DAC_L1_VOL_MASK			(0x7f << 9)
+#define RT5660_DAC_L1_VOL_SFT			9
+#define RT5660_DAC_R1_VOL_MASK			(0x7f << 1)
+#define RT5660_DAC_R1_VOL_SFT			1
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5660_ADC_L_VOL_MASK			(0x3f << 9)
+#define RT5660_ADC_L_VOL_SFT			9
+#define RT5660_ADC_R_VOL_MASK			(0x3f << 1)
+#define RT5660_ADC_R_VOL_SFT			1
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5660_STO1_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5660_STO1_ADC_L_BST_SFT		14
+#define RT5660_STO1_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5660_STO1_ADC_R_BST_SFT		12
+
+/* Stereo ADC Mixer Control (0x27) */
+#define RT5660_M_ADC_L1				(0x1 << 14)
+#define RT5660_M_ADC_L1_SFT			14
+#define RT5660_M_ADC_L2				(0x1 << 13)
+#define RT5660_M_ADC_L2_SFT			13
+#define RT5660_M_ADC_R1				(0x1 << 6)
+#define RT5660_M_ADC_R1_SFT			6
+#define RT5660_M_ADC_R2				(0x1 << 5)
+#define RT5660_M_ADC_R2_SFT			5
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5660_M_ADCMIX_L			(0x1 << 15)
+#define RT5660_M_ADCMIX_L_SFT			15
+#define RT5660_M_DAC1_L				(0x1 << 14)
+#define RT5660_M_DAC1_L_SFT			14
+#define RT5660_M_ADCMIX_R			(0x1 << 7)
+#define RT5660_M_ADCMIX_R_SFT			7
+#define RT5660_M_DAC1_R				(0x1 << 6)
+#define RT5660_M_DAC1_R_SFT			6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5660_M_DAC_L1				(0x1 << 14)
+#define RT5660_M_DAC_L1_SFT			14
+#define RT5660_DAC_L1_STO_L_VOL_MASK		(0x1 << 13)
+#define RT5660_DAC_L1_STO_L_VOL_SFT		13
+#define RT5660_M_DAC_R1_STO_L			(0x1 << 9)
+#define RT5660_M_DAC_R1_STO_L_SFT		9
+#define RT5660_DAC_R1_STO_L_VOL_MASK		(0x1 << 8)
+#define RT5660_DAC_R1_STO_L_VOL_SFT		8
+#define RT5660_M_DAC_R1				(0x1 << 6)
+#define RT5660_M_DAC_R1_SFT			6
+#define RT5660_DAC_R1_STO_R_VOL_MASK		(0x1 << 5)
+#define RT5660_DAC_R1_STO_R_VOL_SFT		5
+#define RT5660_M_DAC_L1_STO_R			(0x1 << 1)
+#define RT5660_M_DAC_L1_STO_R_SFT		1
+#define RT5660_DAC_L1_STO_R_VOL_MASK		(0x1)
+#define RT5660_DAC_L1_STO_R_VOL_SFT		0
+
+/* Digital Interface Data Control (0x2f) */
+#define RT5660_IF1_DAC_IN_SEL			(0x3 << 14)
+#define RT5660_IF1_DAC_IN_SFT			14
+#define RT5660_IF1_ADC_IN_SEL			(0x3 << 12)
+#define RT5660_IF1_ADC_IN_SFT			12
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5660_G_BST3_RM_L_MASK			(0x7 << 4)
+#define RT5660_G_BST3_RM_L_SFT			4
+#define RT5660_G_BST2_RM_L_MASK			(0x7 << 1)
+#define RT5660_G_BST2_RM_L_SFT			1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5660_G_BST1_RM_L_MASK			(0x7 << 13)
+#define RT5660_G_BST1_RM_L_SFT			13
+#define RT5660_G_OM_L_RM_L_MASK			(0x7 << 10)
+#define RT5660_G_OM_L_RM_L_SFT			10
+#define RT5660_M_BST3_RM_L			(0x1 << 3)
+#define RT5660_M_BST3_RM_L_SFT			3
+#define RT5660_M_BST2_RM_L			(0x1 << 2)
+#define RT5660_M_BST2_RM_L_SFT			2
+#define RT5660_M_BST1_RM_L			(0x1 << 1)
+#define RT5660_M_BST1_RM_L_SFT			1
+#define RT5660_M_OM_L_RM_L			(0x1)
+#define RT5660_M_OM_L_RM_L_SFT			0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5660_G_BST3_RM_R_MASK			(0x7 << 4)
+#define RT5660_G_BST3_RM_R_SFT			4
+#define RT5660_G_BST2_RM_R_MASK			(0x7 << 1)
+#define RT5660_G_BST2_RM_R_SFT			1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5660_G_BST1_RM_R_MASK			(0x7 << 13)
+#define RT5660_G_BST1_RM_R_SFT			13
+#define RT5660_G_OM_R_RM_R_MASK			(0x7 << 10)
+#define RT5660_G_OM_R_RM_R_SFT			10
+#define RT5660_M_BST3_RM_R			(0x1 << 3)
+#define RT5660_M_BST3_RM_R_SFT			3
+#define RT5660_M_BST2_RM_R			(0x1 << 2)
+#define RT5660_M_BST2_RM_R_SFT			2
+#define RT5660_M_BST1_RM_R			(0x1 << 1)
+#define RT5660_M_BST1_RM_R_SFT			1
+#define RT5660_M_OM_R_RM_R			(0x1)
+#define RT5660_M_OM_R_RM_R_SFT			0
+
+/* LOUTMIX Control (0x45) */
+#define RT5660_M_DAC1_LM			(0x1 << 14)
+#define RT5660_M_DAC1_LM_SFT			14
+#define RT5660_M_LOVOL_M			(0x1 << 13)
+#define RT5660_M_LOVOL_LM_SFT			13
+
+/* SPK Mixer Control (0x46) */
+#define RT5660_G_BST3_SM_MASK			(0x3 << 14)
+#define RT5660_G_BST3_SM_SFT			14
+#define RT5660_G_BST1_SM_MASK			(0x3 << 12)
+#define RT5660_G_BST1_SM_SFT			12
+#define RT5660_G_DACl_SM_MASK			(0x3 << 10)
+#define RT5660_G_DACl_SM_SFT			10
+#define RT5660_G_DACR_SM_MASK			(0x3 << 8)
+#define RT5660_G_DACR_SM_SFT			8
+#define RT5660_G_OM_L_SM_MASK			(0x3 << 6)
+#define RT5660_G_OM_L_SM_SFT			6
+#define RT5660_M_DACR_SM			(0x1 << 5)
+#define RT5660_M_DACR_SM_SFT			5
+#define RT5660_M_BST1_SM			(0x1 << 4)
+#define RT5660_M_BST1_SM_SFT			4
+#define RT5660_M_BST3_SM			(0x1 << 3)
+#define RT5660_M_BST3_SM_SFT			3
+#define RT5660_M_DACL_SM			(0x1 << 2)
+#define RT5660_M_DACL_SM_SFT			2
+#define RT5660_M_OM_L_SM			(0x1 << 1)
+#define RT5660_M_OM_L_SM_SFT			1
+
+/* SPOMIX Control (0x48) */
+#define RT5660_M_DAC_R_SPM			(0x1 << 14)
+#define RT5660_M_DAC_R_SPM_SFT			14
+#define RT5660_M_DAC_L_SPM			(0x1 << 13)
+#define RT5660_M_DAC_L_SPM_SFT			13
+#define RT5660_M_SV_SPM				(0x1 << 12)
+#define RT5660_M_SV_SPM_SFT			12
+#define RT5660_M_BST1_SPM			(0x1 << 11)
+#define RT5660_M_BST1_SPM_SFT			11
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5660_G_BST3_OM_L_MASK			(0x7 << 13)
+#define RT5660_G_BST3_OM_L_SFT			13
+#define RT5660_G_BST2_OM_L_MASK			(0x7 << 10)
+#define RT5660_G_BST2_OM_L_SFT			10
+#define RT5660_G_BST1_OM_L_MASK			(0x7 << 7)
+#define RT5660_G_BST1_OM_L_SFT			7
+#define RT5660_G_RM_L_OM_L_MASK			(0x7 << 1)
+#define RT5660_G_RM_L_OM_L_SFT			1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5660_G_DAC_R1_OM_L_MASK		(0x7 << 10)
+#define RT5660_G_DAC_R1_OM_L_SFT		10
+#define RT5660_G_DAC_L1_OM_L_MASK		(0x7 << 7)
+#define RT5660_G_DAC_L1_OM_L_SFT		7
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5660_M_BST3_OM_L			(0x1 << 5)
+#define RT5660_M_BST3_OM_L_SFT			5
+#define RT5660_M_BST2_OM_L			(0x1 << 4)
+#define RT5660_M_BST2_OM_L_SFT			4
+#define RT5660_M_BST1_OM_L			(0x1 << 3)
+#define RT5660_M_BST1_OM_L_SFT			3
+#define RT5660_M_RM_L_OM_L			(0x1 << 2)
+#define RT5660_M_RM_L_OM_L_SFT			2
+#define RT5660_M_DAC_R_OM_L			(0x1 << 1)
+#define RT5660_M_DAC_R_OM_L_SFT			1
+#define RT5660_M_DAC_L_OM_L			(0x1)
+#define RT5660_M_DAC_L_OM_L_SFT			0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5660_G_BST2_OM_R_MASK			(0x7 << 10)
+#define RT5660_G_BST2_OM_R_SFT			10
+#define RT5660_G_BST1_OM_R_MASK			(0x7 << 7)
+#define RT5660_G_BST1_OM_R_SFT			7
+#define RT5660_G_RM_R_OM_R_MASK			(0x7 << 1)
+#define RT5660_G_RM_R_OM_R_SFT			1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5660_G_DAC_L_OM_R_MASK		(0x7 << 10)
+#define RT5660_G_DAC_L_OM_R_SFT			10
+#define RT5660_G_DAC_R_OM_R_MASK		(0x7 << 7)
+#define RT5660_G_DAC_R_OM_R_SFT			7
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5660_M_BST2_OM_R			(0x1 << 4)
+#define RT5660_M_BST2_OM_R_SFT			4
+#define RT5660_M_BST1_OM_R			(0x1 << 3)
+#define RT5660_M_BST1_OM_R_SFT			3
+#define RT5660_M_RM_R_OM_R			(0x1 << 2)
+#define RT5660_M_RM_R_OM_R_SFT			2
+#define RT5660_M_DAC_L_OM_R			(0x1 << 1)
+#define RT5660_M_DAC_L_OM_R_SFT			1
+#define RT5660_M_DAC_R_OM_R			(0x1)
+#define RT5660_M_DAC_R_OM_R_SFT			0
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5660_PWR_I2S1				(0x1 << 15)
+#define RT5660_PWR_I2S1_BIT			15
+#define RT5660_PWR_DAC_L1			(0x1 << 12)
+#define RT5660_PWR_DAC_L1_BIT			12
+#define RT5660_PWR_DAC_R1			(0x1 << 11)
+#define RT5660_PWR_DAC_R1_BIT			11
+#define RT5660_PWR_ADC_L			(0x1 << 2)
+#define RT5660_PWR_ADC_L_BIT			2
+#define RT5660_PWR_ADC_R			(0x1 << 1)
+#define RT5660_PWR_ADC_R_BIT			1
+#define RT5660_PWR_CLS_D			(0x1)
+#define RT5660_PWR_CLS_D_BIT			0
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5660_PWR_ADC_S1F			(0x1 << 15)
+#define RT5660_PWR_ADC_S1F_BIT			15
+#define RT5660_PWR_DAC_S1F			(0x1 << 11)
+#define RT5660_PWR_DAC_S1F_BIT			11
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5660_PWR_VREF1			(0x1 << 15)
+#define RT5660_PWR_VREF1_BIT			15
+#define RT5660_PWR_FV1				(0x1 << 14)
+#define RT5660_PWR_FV1_BIT			14
+#define RT5660_PWR_MB				(0x1 << 13)
+#define RT5660_PWR_MB_BIT			13
+#define RT5660_PWR_BG				(0x1 << 11)
+#define RT5660_PWR_BG_BIT			11
+#define RT5660_PWR_HP_L				(0x1 << 7)
+#define RT5660_PWR_HP_L_BIT			7
+#define RT5660_PWR_HP_R				(0x1 << 6)
+#define RT5660_PWR_HP_R_BIT			6
+#define RT5660_PWR_HA				(0x1 << 5)
+#define RT5660_PWR_HA_BIT			5
+#define RT5660_PWR_VREF2			(0x1 << 4)
+#define RT5660_PWR_VREF2_BIT			4
+#define RT5660_PWR_FV2				(0x1 << 3)
+#define RT5660_PWR_FV2_BIT			3
+#define RT5660_PWR_LDO2				(0x1 << 2)
+#define RT5660_PWR_LDO2_BIT			2
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5660_PWR_BST1				(0x1 << 15)
+#define RT5660_PWR_BST1_BIT			15
+#define RT5660_PWR_BST2				(0x1 << 14)
+#define RT5660_PWR_BST2_BIT			14
+#define RT5660_PWR_BST3				(0x1 << 13)
+#define RT5660_PWR_BST3_BIT			13
+#define RT5660_PWR_MB1				(0x1 << 11)
+#define RT5660_PWR_MB1_BIT			11
+#define RT5660_PWR_MB2				(0x1 << 10)
+#define RT5660_PWR_MB2_BIT			10
+#define RT5660_PWR_PLL				(0x1 << 9)
+#define RT5660_PWR_PLL_BIT			9
+
+/* Power Management for Mixer (0x65) */
+#define RT5660_PWR_OM_L				(0x1 << 15)
+#define RT5660_PWR_OM_L_BIT			15
+#define RT5660_PWR_OM_R				(0x1 << 14)
+#define RT5660_PWR_OM_R_BIT			14
+#define RT5660_PWR_SM				(0x1 << 13)
+#define RT5660_PWR_SM_BIT			13
+#define RT5660_PWR_RM_L				(0x1 << 11)
+#define RT5660_PWR_RM_L_BIT			11
+#define RT5660_PWR_RM_R				(0x1 << 10)
+#define RT5660_PWR_RM_R_BIT			10
+
+/* Power Management for Volume (0x66) */
+#define RT5660_PWR_SV				(0x1 << 15)
+#define RT5660_PWR_SV_BIT			15
+#define RT5660_PWR_LV_L				(0x1 << 11)
+#define RT5660_PWR_LV_L_BIT			11
+#define RT5660_PWR_LV_R				(0x1 << 10)
+#define RT5660_PWR_LV_R_BIT			10
+
+/* I2S1 Audio Serial Data Port Control (0x70) */
+#define RT5660_I2S_MS_MASK			(0x1 << 15)
+#define RT5660_I2S_MS_SFT			15
+#define RT5660_I2S_MS_M				(0x0 << 15)
+#define RT5660_I2S_MS_S				(0x1 << 15)
+#define RT5660_I2S_O_CP_MASK			(0x3 << 10)
+#define RT5660_I2S_O_CP_SFT			10
+#define RT5660_I2S_O_CP_OFF			(0x0 << 10)
+#define RT5660_I2S_O_CP_U_LAW			(0x1 << 10)
+#define RT5660_I2S_O_CP_A_LAW			(0x2 << 10)
+#define RT5660_I2S_I_CP_MASK			(0x3 << 8)
+#define RT5660_I2S_I_CP_SFT			8
+#define RT5660_I2S_I_CP_OFF			(0x0 << 8)
+#define RT5660_I2S_I_CP_U_LAW			(0x1 << 8)
+#define RT5660_I2S_I_CP_A_LAW			(0x2 << 8)
+#define RT5660_I2S_BP_MASK			(0x1 << 7)
+#define RT5660_I2S_BP_SFT			7
+#define RT5660_I2S_BP_NOR			(0x0 << 7)
+#define RT5660_I2S_BP_INV			(0x1 << 7)
+#define RT5660_I2S_DL_MASK			(0x3 << 2)
+#define RT5660_I2S_DL_SFT			2
+#define RT5660_I2S_DL_16			(0x0 << 2)
+#define RT5660_I2S_DL_20			(0x1 << 2)
+#define RT5660_I2S_DL_24			(0x2 << 2)
+#define RT5660_I2S_DL_8				(0x3 << 2)
+#define RT5660_I2S_DF_MASK			(0x3)
+#define RT5660_I2S_DF_SFT			0
+#define RT5660_I2S_DF_I2S			(0x0)
+#define RT5660_I2S_DF_LEFT			(0x1)
+#define RT5660_I2S_DF_PCM_A			(0x2)
+#define RT5660_I2S_DF_PCM_B			(0x3)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5660_I2S_BCLK_MS1_MASK		(0x1 << 15)
+#define RT5660_I2S_BCLK_MS1_SFT			15
+#define RT5660_I2S_BCLK_MS1_32			(0x0 << 15)
+#define RT5660_I2S_BCLK_MS1_64			(0x1 << 15)
+#define RT5660_I2S_PD1_MASK			(0x7 << 12)
+#define RT5660_I2S_PD1_SFT			12
+#define RT5660_I2S_PD1_1			(0x0 << 12)
+#define RT5660_I2S_PD1_2			(0x1 << 12)
+#define RT5660_I2S_PD1_3			(0x2 << 12)
+#define RT5660_I2S_PD1_4			(0x3 << 12)
+#define RT5660_I2S_PD1_6			(0x4 << 12)
+#define RT5660_I2S_PD1_8			(0x5 << 12)
+#define RT5660_I2S_PD1_12			(0x6 << 12)
+#define RT5660_I2S_PD1_16			(0x7 << 12)
+#define RT5660_DAC_OSR_MASK			(0x3 << 2)
+#define RT5660_DAC_OSR_SFT			2
+#define RT5660_DAC_OSR_128			(0x0 << 2)
+#define RT5660_DAC_OSR_64			(0x1 << 2)
+#define RT5660_DAC_OSR_32			(0x2 << 2)
+#define RT5660_DAC_OSR_16			(0x3 << 2)
+#define RT5660_ADC_OSR_MASK			(0x3)
+#define RT5660_ADC_OSR_SFT			0
+#define RT5660_ADC_OSR_128			(0x0)
+#define RT5660_ADC_OSR_64			(0x1)
+#define RT5660_ADC_OSR_32			(0x2)
+#define RT5660_ADC_OSR_16			(0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5660_RESET_ADF			(0x1 << 13)
+#define RT5660_RESET_ADF_SFT			13
+#define RT5660_RESET_DAF			(0x1 << 12)
+#define RT5660_RESET_DAF_SFT			12
+#define RT5660_DAHPF_EN				(0x1 << 11)
+#define RT5660_DAHPF_EN_SFT			11
+#define RT5660_ADHPF_EN				(0x1 << 10)
+#define RT5660_ADHPF_EN_SFT			10
+
+/* Digital Microphone Control (0x75) */
+#define RT5660_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5660_DMIC_1_EN_SFT			15
+#define RT5660_DMIC_1_DIS			(0x0 << 15)
+#define RT5660_DMIC_1_EN			(0x1 << 15)
+#define RT5660_DMIC_1L_LH_MASK			(0x1 << 13)
+#define RT5660_DMIC_1L_LH_SFT			13
+#define RT5660_DMIC_1L_LH_RISING		(0x0 << 13)
+#define RT5660_DMIC_1L_LH_FALLING		(0x1 << 13)
+#define RT5660_DMIC_1R_LH_MASK			(0x1 << 12)
+#define RT5660_DMIC_1R_LH_SFT			12
+#define RT5660_DMIC_1R_LH_RISING		(0x0 << 12)
+#define RT5660_DMIC_1R_LH_FALLING		(0x1 << 12)
+#define RT5660_SEL_DMIC_DATA_MASK		(0x1 << 11)
+#define RT5660_SEL_DMIC_DATA_SFT		11
+#define RT5660_SEL_DMIC_DATA_GPIO2		(0x0 << 11)
+#define RT5660_SEL_DMIC_DATA_IN1P		(0x1 << 11)
+#define RT5660_DMIC_CLK_MASK			(0x7 << 5)
+#define RT5660_DMIC_CLK_SFT			5
+
+/* Global Clock Control (0x80) */
+#define RT5660_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5660_SCLK_SRC_SFT			14
+#define RT5660_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5660_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5660_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5660_PLL1_SRC_MASK			(0x3 << 12)
+#define RT5660_PLL1_SRC_SFT			12
+#define RT5660_PLL1_SRC_MCLK			(0x0 << 12)
+#define RT5660_PLL1_SRC_BCLK1			(0x1 << 12)
+#define RT5660_PLL1_SRC_RCCLK			(0x2 << 12)
+#define RT5660_PLL1_PD_MASK			(0x1 << 3)
+#define RT5660_PLL1_PD_SFT			3
+#define RT5660_PLL1_PD_1			(0x0 << 3)
+#define RT5660_PLL1_PD_2			(0x1 << 3)
+
+#define RT5660_PLL_INP_MAX			40000000
+#define RT5660_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5660_PLL_N_MAX			0x1ff
+#define RT5660_PLL_N_MASK			(RT5660_PLL_N_MAX << 7)
+#define RT5660_PLL_N_SFT			7
+#define RT5660_PLL_K_MAX			0x1f
+#define RT5660_PLL_K_MASK			(RT5660_PLL_K_MAX)
+#define RT5660_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5660_PLL_M_MAX			0xf
+#define RT5660_PLL_M_MASK			(RT5660_PLL_M_MAX << 12)
+#define RT5660_PLL_M_SFT			12
+#define RT5660_PLL_M_BP				(0x1 << 11)
+#define RT5660_PLL_M_BP_SFT			11
+
+/* Class D Over Current Control (0x8c) */
+#define RT5660_CLSD_OC_MASK			(0x1 << 9)
+#define RT5660_CLSD_OC_SFT			9
+#define RT5660_CLSD_OC_PU			(0x0 << 9)
+#define RT5660_CLSD_OC_PD			(0x1 << 9)
+#define RT5660_AUTO_PD_MASK			(0x1 << 8)
+#define RT5660_AUTO_PD_SFT			8
+#define RT5660_AUTO_PD_DIS			(0x0 << 8)
+#define RT5660_AUTO_PD_EN			(0x1 << 8)
+#define RT5660_CLSD_OC_TH_MASK			(0x3f)
+#define RT5660_CLSD_OC_TH_SFT			0
+
+/* Class D Output Control (0x8d) */
+#define RT5660_CLSD_RATIO_MASK			(0xf << 12)
+#define RT5660_CLSD_RATIO_SFT			12
+
+/* Lout Amp Control 1 (0x8e) */
+#define RT5660_LOUT_CO_MASK			(0x1 << 4)
+#define RT5660_LOUT_CO_SFT			4
+#define RT5660_LOUT_CO_DIS			(0x0 << 4)
+#define RT5660_LOUT_CO_EN			(0x1 << 4)
+#define RT5660_LOUT_CB_MASK			(0x1)
+#define RT5660_LOUT_CB_SFT			0
+#define RT5660_LOUT_CB_PD			(0x0)
+#define RT5660_LOUT_CB_PU			(0x1)
+
+/* SPKVDD detection control (0x92) */
+#define RT5660_SPKVDD_DET_MASK			(0x1 << 15)
+#define RT5660_SPKVDD_DET_SFT			15
+#define RT5660_SPKVDD_DET_DIS			(0x0 << 15)
+#define RT5660_SPKVDD_DET_EN			(0x1 << 15)
+#define RT5660_SPK_AG_MASK			(0x1 << 14)
+#define RT5660_SPK_AG_SFT			14
+#define RT5660_SPK_AG_DIS			(0x0 << 14)
+#define RT5660_SPK_AG_EN			(0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5660_MIC1_BS_MASK			(0x1 << 15)
+#define RT5660_MIC1_BS_SFT			15
+#define RT5660_MIC1_BS_9AV			(0x0 << 15)
+#define RT5660_MIC1_BS_75AV			(0x1 << 15)
+#define RT5660_MIC2_BS_MASK			(0x1 << 14)
+#define RT5660_MIC2_BS_SFT			14
+#define RT5660_MIC2_BS_9AV			(0x0 << 14)
+#define RT5660_MIC2_BS_75AV			(0x1 << 14)
+#define RT5660_MIC1_OVCD_MASK			(0x1 << 11)
+#define RT5660_MIC1_OVCD_SFT			11
+#define RT5660_MIC1_OVCD_DIS			(0x0 << 11)
+#define RT5660_MIC1_OVCD_EN			(0x1 << 11)
+#define RT5660_MIC1_OVTH_MASK			(0x3 << 9)
+#define RT5660_MIC1_OVTH_SFT			9
+#define RT5660_MIC1_OVTH_600UA			(0x0 << 9)
+#define RT5660_MIC1_OVTH_1500UA			(0x1 << 9)
+#define RT5660_MIC1_OVTH_2000UA			(0x2 << 9)
+#define RT5660_MIC2_OVCD_MASK			(0x1 << 8)
+#define RT5660_MIC2_OVCD_SFT			8
+#define RT5660_MIC2_OVCD_DIS			(0x0 << 8)
+#define RT5660_MIC2_OVCD_EN			(0x1 << 8)
+#define RT5660_MIC2_OVTH_MASK			(0x3 << 6)
+#define RT5660_MIC2_OVTH_SFT			6
+#define RT5660_MIC2_OVTH_600UA			(0x0 << 6)
+#define RT5660_MIC2_OVTH_1500UA			(0x1 << 6)
+#define RT5660_MIC2_OVTH_2000UA			(0x2 << 6)
+#define RT5660_PWR_CLK25M_MASK			(0x1 << 4)
+#define RT5660_PWR_CLK25M_SFT			4
+#define RT5660_PWR_CLK25M_PD			(0x0 << 4)
+#define RT5660_PWR_CLK25M_PU			(0x1 << 4)
+
+/* EQ Control 1 (0xb0) */
+#define RT5660_EQ_SRC_MASK			(0x1 << 15)
+#define RT5660_EQ_SRC_SFT			15
+#define RT5660_EQ_SRC_DAC			(0x0 << 15)
+#define RT5660_EQ_SRC_ADC			(0x1 << 15)
+#define RT5660_EQ_UPD				(0x1 << 14)
+#define RT5660_EQ_UPD_BIT			14
+
+/* Jack Detect Control (0xbb) */
+#define RT5660_JD_MASK				(0x3 << 14)
+#define RT5660_JD_SFT				14
+#define RT5660_JD_DIS				(0x0 << 14)
+#define RT5660_JD_GPIO1				(0x1 << 14)
+#define RT5660_JD_GPIO2				(0x2 << 14)
+#define RT5660_JD_LOUT_MASK			(0x1 << 11)
+#define RT5660_JD_LOUT_SFT			11
+#define RT5660_JD_LOUT_DIS			(0x0 << 11)
+#define RT5660_JD_LOUT_EN			(0x1 << 11)
+#define RT5660_JD_LOUT_TRG_MASK			(0x1 << 10)
+#define RT5660_JD_LOUT_TRG_SFT			10
+#define RT5660_JD_LOUT_TRG_LO			(0x0 << 10)
+#define RT5660_JD_LOUT_TRG_HI			(0x1 << 10)
+#define RT5660_JD_SPO_MASK			(0x1 << 9)
+#define RT5660_JD_SPO_SFT			9
+#define RT5660_JD_SPO_DIS			(0x0 << 9)
+#define RT5660_JD_SPO_EN			(0x1 << 9)
+#define RT5660_JD_SPO_TRG_MASK			(0x1 << 8)
+#define RT5660_JD_SPO_TRG_SFT			8
+#define RT5660_JD_SPO_TRG_LO			(0x0 << 8)
+#define RT5660_JD_SPO_TRG_HI			(0x1 << 8)
+
+/* IRQ Control 1 (0xbd) */
+#define RT5660_IRQ_JD_MASK			(0x1 << 15)
+#define RT5660_IRQ_JD_SFT			15
+#define RT5660_IRQ_JD_BP			(0x0 << 15)
+#define RT5660_IRQ_JD_NOR			(0x1 << 15)
+#define RT5660_IRQ_OT_MASK			(0x1 << 14)
+#define RT5660_IRQ_OT_SFT			14
+#define RT5660_IRQ_OT_BP			(0x0 << 14)
+#define RT5660_IRQ_OT_NOR			(0x1 << 14)
+#define RT5660_JD_STKY_MASK			(0x1 << 13)
+#define RT5660_JD_STKY_SFT			13
+#define RT5660_JD_STKY_DIS			(0x0 << 13)
+#define RT5660_JD_STKY_EN			(0x1 << 13)
+#define RT5660_OT_STKY_MASK			(0x1 << 12)
+#define RT5660_OT_STKY_SFT			12
+#define RT5660_OT_STKY_DIS			(0x0 << 12)
+#define RT5660_OT_STKY_EN			(0x1 << 12)
+#define RT5660_JD_P_MASK			(0x1 << 11)
+#define RT5660_JD_P_SFT				11
+#define RT5660_JD_P_NOR				(0x0 << 11)
+#define RT5660_JD_P_INV				(0x1 << 11)
+#define RT5660_OT_P_MASK			(0x1 << 10)
+#define RT5660_OT_P_SFT				10
+#define RT5660_OT_P_NOR				(0x0 << 10)
+#define RT5660_OT_P_INV				(0x1 << 10)
+
+/* IRQ Control 2 (0xbe) */
+#define RT5660_IRQ_MB1_OC_MASK			(0x1 << 15)
+#define RT5660_IRQ_MB1_OC_SFT			15
+#define RT5660_IRQ_MB1_OC_BP			(0x0 << 15)
+#define RT5660_IRQ_MB1_OC_NOR			(0x1 << 15)
+#define RT5660_IRQ_MB2_OC_MASK			(0x1 << 14)
+#define RT5660_IRQ_MB2_OC_SFT			14
+#define RT5660_IRQ_MB2_OC_BP			(0x0 << 14)
+#define RT5660_IRQ_MB2_OC_NOR			(0x1 << 14)
+#define RT5660_MB1_OC_STKY_MASK			(0x1 << 11)
+#define RT5660_MB1_OC_STKY_SFT			11
+#define RT5660_MB1_OC_STKY_DIS			(0x0 << 11)
+#define RT5660_MB1_OC_STKY_EN			(0x1 << 11)
+#define RT5660_MB2_OC_STKY_MASK			(0x1 << 10)
+#define RT5660_MB2_OC_STKY_SFT			10
+#define RT5660_MB2_OC_STKY_DIS			(0x0 << 10)
+#define RT5660_MB2_OC_STKY_EN			(0x1 << 10)
+#define RT5660_MB1_OC_P_MASK			(0x1 << 7)
+#define RT5660_MB1_OC_P_SFT			7
+#define RT5660_MB1_OC_P_NOR			(0x0 << 7)
+#define RT5660_MB1_OC_P_INV			(0x1 << 7)
+#define RT5660_MB2_OC_P_MASK			(0x1 << 6)
+#define RT5660_MB2_OC_P_SFT			6
+#define RT5660_MB2_OC_P_NOR			(0x0 << 6)
+#define RT5660_MB2_OC_P_INV			(0x1 << 6)
+#define RT5660_MB1_OC_CLR			(0x1 << 3)
+#define RT5660_MB1_OC_CLR_SFT			3
+#define RT5660_MB2_OC_CLR			(0x1 << 2)
+#define RT5660_MB2_OC_CLR_SFT			2
+
+/* GPIO Control 1 (0xc0) */
+#define RT5660_GP2_PIN_MASK			(0x1 << 14)
+#define RT5660_GP2_PIN_SFT			14
+#define RT5660_GP2_PIN_GPIO2			(0x0 << 14)
+#define RT5660_GP2_PIN_DMIC1_SDA		(0x1 << 14)
+#define RT5660_GP1_PIN_MASK			(0x3 << 12)
+#define RT5660_GP1_PIN_SFT			12
+#define RT5660_GP1_PIN_GPIO1			(0x0 << 12)
+#define RT5660_GP1_PIN_DMIC1_SCL		(0x1 << 12)
+#define RT5660_GP1_PIN_IRQ			(0x2 << 12)
+#define RT5660_GPIO_M_MASK			(0x1 << 9)
+#define RT5660_GPIO_M_SFT			9
+#define RT5660_GPIO_M_FLT			(0x0 << 9)
+#define RT5660_GPIO_M_PH			(0x1 << 9)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5660_GP2_PF_MASK			(0x1 << 5)
+#define RT5660_GP2_PF_SFT			5
+#define RT5660_GP2_PF_IN			(0x0 << 5)
+#define RT5660_GP2_PF_OUT			(0x1 << 5)
+#define RT5660_GP2_OUT_MASK			(0x1 << 4)
+#define RT5660_GP2_OUT_SFT			4
+#define RT5660_GP2_OUT_LO			(0x0 << 4)
+#define RT5660_GP2_OUT_HI			(0x1 << 4)
+#define RT5660_GP2_P_MASK			(0x1 << 3)
+#define RT5660_GP2_P_SFT			3
+#define RT5660_GP2_P_NOR			(0x0 << 3)
+#define RT5660_GP2_P_INV			(0x1 << 3)
+#define RT5660_GP1_PF_MASK			(0x1 << 2)
+#define RT5660_GP1_PF_SFT			2
+#define RT5660_GP1_PF_IN			(0x0 << 2)
+#define RT5660_GP1_PF_OUT			(0x1 << 2)
+#define RT5660_GP1_OUT_MASK			(0x1 << 1)
+#define RT5660_GP1_OUT_SFT			1
+#define RT5660_GP1_OUT_LO			(0x0 << 1)
+#define RT5660_GP1_OUT_HI			(0x1 << 1)
+#define RT5660_GP1_P_MASK			(0x1)
+#define RT5660_GP1_P_SFT			0
+#define RT5660_GP1_P_NOR			(0x0)
+#define RT5660_GP1_P_INV			(0x1)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5660_SV_MASK				(0x1 << 15)
+#define RT5660_SV_SFT				15
+#define RT5660_SV_DIS				(0x0 << 15)
+#define RT5660_SV_EN				(0x1 << 15)
+#define RT5660_SPO_SV_MASK			(0x1 << 14)
+#define RT5660_SPO_SV_SFT			14
+#define RT5660_SPO_SV_DIS			(0x0 << 14)
+#define RT5660_SPO_SV_EN			(0x1 << 14)
+#define RT5660_OUT_SV_MASK			(0x1 << 12)
+#define RT5660_OUT_SV_SFT			12
+#define RT5660_OUT_SV_DIS			(0x0 << 12)
+#define RT5660_OUT_SV_EN			(0x1 << 12)
+#define RT5660_ZCD_DIG_MASK			(0x1 << 11)
+#define RT5660_ZCD_DIG_SFT			11
+#define RT5660_ZCD_DIG_DIS			(0x0 << 11)
+#define RT5660_ZCD_DIG_EN			(0x1 << 11)
+#define RT5660_ZCD_MASK				(0x1 << 10)
+#define RT5660_ZCD_SFT				10
+#define RT5660_ZCD_PD				(0x0 << 10)
+#define RT5660_ZCD_PU				(0x1 << 10)
+#define RT5660_SV_DLY_MASK			(0xf)
+#define RT5660_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5660_ZCD_SPO_MASK			(0x1 << 15)
+#define RT5660_ZCD_SPO_SFT			15
+#define RT5660_ZCD_SPO_DIS			(0x0 << 15)
+#define RT5660_ZCD_SPO_EN			(0x1 << 15)
+#define RT5660_ZCD_OMR_MASK			(0x1 << 8)
+#define RT5660_ZCD_OMR_SFT			8
+#define RT5660_ZCD_OMR_DIS			(0x0 << 8)
+#define RT5660_ZCD_OMR_EN			(0x1 << 8)
+#define RT5660_ZCD_OML_MASK			(0x1 << 7)
+#define RT5660_ZCD_OML_SFT			7
+#define RT5660_ZCD_OML_DIS			(0x0 << 7)
+#define RT5660_ZCD_OML_EN			(0x1 << 7)
+#define RT5660_ZCD_SPM_MASK			(0x1 << 6)
+#define RT5660_ZCD_SPM_SFT			6
+#define RT5660_ZCD_SPM_DIS			(0x0 << 6)
+#define RT5660_ZCD_SPM_EN			(0x1 << 6)
+#define RT5660_ZCD_RMR_MASK			(0x1 << 5)
+#define RT5660_ZCD_RMR_SFT			5
+#define RT5660_ZCD_RMR_DIS			(0x0 << 5)
+#define RT5660_ZCD_RMR_EN			(0x1 << 5)
+#define RT5660_ZCD_RML_MASK			(0x1 << 4)
+#define RT5660_ZCD_RML_SFT			4
+#define RT5660_ZCD_RML_DIS			(0x0 << 4)
+#define RT5660_ZCD_RML_EN			(0x1 << 4)
+
+/* General Control 1 (0xfa) */
+#define RT5660_PWR_VREF_HP			(0x1 << 11)
+#define RT5660_PWR_VREF_HP_SFT			11
+#define RT5660_DIG_GATE_CTRL			(0x1)
+#define RT5660_DIG_GATE_CTRL_SFT		0
+
+/* System Clock Source */
+#define RT5660_SCLK_S_MCLK			0
+#define RT5660_SCLK_S_PLL1			1
+#define RT5660_SCLK_S_RCCLK			2
+
+/* PLL1 Source */
+#define RT5660_PLL1_S_MCLK			0
+#define RT5660_PLL1_S_BCLK			1
+
+enum {
+	RT5660_AIF1,
+	RT5660_AIFS,
+};
+
+struct rt5660_priv {
+	struct snd_soc_codec *codec;
+	struct rt5660_platform_data pdata;
+	struct regmap *regmap;
+	struct clk *mclk;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5660_AIFS];
+	int bclk[RT5660_AIFS];
+	int master[RT5660_AIFS];
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+};
+
+#endif
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
new file mode 100644
index 000000000000..01a18d88f1eb
--- /dev/null
+++ b/sound/soc/codecs/rt5663.c
@@ -0,0 +1,3218 @@
+/*
+ * rt5663.c  --  RT5668/RT5663 ALSA SoC audio codec driver
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Jack Yu <jack.yu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt5663.h"
+#include "rl6231.h"
+
+#define RT5668_DEVICE_ID 0x6451
+#define RT5663_DEVICE_ID 0x6406
+
+enum {
+	CODEC_TYPE_RT5668,
+	CODEC_TYPE_RT5663,
+};
+
+struct rt5663_priv {
+	struct snd_soc_codec *codec;
+	struct regmap *regmap;
+	struct delayed_work jack_detect_work;
+	struct snd_soc_jack *hs_jack;
+	struct timer_list btn_check_timer;
+
+	int codec_type;
+	int sysclk;
+	int sysclk_src;
+	int lrck;
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	int jack_type;
+};
+
+static const struct reg_default rt5668_reg[] = {
+	{ 0x0000, 0x0000 },
+	{ 0x0001, 0xc8c8 },
+	{ 0x0002, 0x8080 },
+	{ 0x0003, 0x8000 },
+	{ 0x0004, 0xc80a },
+	{ 0x0005, 0x0000 },
+	{ 0x0006, 0x0000 },
+	{ 0x0007, 0x0000 },
+	{ 0x000a, 0x0000 },
+	{ 0x000b, 0x0000 },
+	{ 0x000c, 0x0000 },
+	{ 0x000d, 0x0000 },
+	{ 0x000f, 0x0808 },
+	{ 0x0010, 0x4000 },
+	{ 0x0011, 0x0000 },
+	{ 0x0012, 0x1404 },
+	{ 0x0013, 0x1000 },
+	{ 0x0014, 0xa00a },
+	{ 0x0015, 0x0404 },
+	{ 0x0016, 0x0404 },
+	{ 0x0017, 0x0011 },
+	{ 0x0018, 0xafaf },
+	{ 0x0019, 0xafaf },
+	{ 0x001a, 0xafaf },
+	{ 0x001b, 0x0011 },
+	{ 0x001c, 0x2f2f },
+	{ 0x001d, 0x2f2f },
+	{ 0x001e, 0x2f2f },
+	{ 0x001f, 0x0000 },
+	{ 0x0020, 0x0000 },
+	{ 0x0021, 0x0000 },
+	{ 0x0022, 0x5757 },
+	{ 0x0023, 0x0039 },
+	{ 0x0024, 0x000b },
+	{ 0x0026, 0xc0c0 },
+	{ 0x0027, 0xc0c0 },
+	{ 0x0028, 0xc0c0 },
+	{ 0x0029, 0x8080 },
+	{ 0x002a, 0xaaaa },
+	{ 0x002b, 0xaaaa },
+	{ 0x002c, 0xaba8 },
+	{ 0x002d, 0x0000 },
+	{ 0x002e, 0x0000 },
+	{ 0x002f, 0x0000 },
+	{ 0x0030, 0x0000 },
+	{ 0x0031, 0x5000 },
+	{ 0x0032, 0x0000 },
+	{ 0x0033, 0x0000 },
+	{ 0x0034, 0x0000 },
+	{ 0x0035, 0x0000 },
+	{ 0x003a, 0x0000 },
+	{ 0x003b, 0x0000 },
+	{ 0x003c, 0x00ff },
+	{ 0x003d, 0x0000 },
+	{ 0x003e, 0x00ff },
+	{ 0x003f, 0x0000 },
+	{ 0x0040, 0x0000 },
+	{ 0x0041, 0x00ff },
+	{ 0x0042, 0x0000 },
+	{ 0x0043, 0x00ff },
+	{ 0x0044, 0x0c0c },
+	{ 0x0049, 0xc00b },
+	{ 0x004a, 0x0000 },
+	{ 0x004b, 0x031f },
+	{ 0x004d, 0x0000 },
+	{ 0x004e, 0x001f },
+	{ 0x004f, 0x0000 },
+	{ 0x0050, 0x001f },
+	{ 0x0052, 0xf000 },
+	{ 0x0061, 0x0000 },
+	{ 0x0062, 0x0000 },
+	{ 0x0063, 0x003e },
+	{ 0x0064, 0x0000 },
+	{ 0x0065, 0x0000 },
+	{ 0x0066, 0x003f },
+	{ 0x0067, 0x0000 },
+	{ 0x006b, 0x0000 },
+	{ 0x006d, 0xff00 },
+	{ 0x006e, 0x2808 },
+	{ 0x006f, 0x000a },
+	{ 0x0070, 0x8000 },
+	{ 0x0071, 0x8000 },
+	{ 0x0072, 0x8000 },
+	{ 0x0073, 0x7000 },
+	{ 0x0074, 0x7770 },
+	{ 0x0075, 0x0002 },
+	{ 0x0076, 0x0001 },
+	{ 0x0078, 0x00f0 },
+	{ 0x0079, 0x0000 },
+	{ 0x007a, 0x0000 },
+	{ 0x007b, 0x0000 },
+	{ 0x007c, 0x0000 },
+	{ 0x007d, 0x0123 },
+	{ 0x007e, 0x4500 },
+	{ 0x007f, 0x8003 },
+	{ 0x0080, 0x0000 },
+	{ 0x0081, 0x0000 },
+	{ 0x0082, 0x0000 },
+	{ 0x0083, 0x0000 },
+	{ 0x0084, 0x0000 },
+	{ 0x0085, 0x0000 },
+	{ 0x0086, 0x0008 },
+	{ 0x0087, 0x0000 },
+	{ 0x0088, 0x0000 },
+	{ 0x0089, 0x0000 },
+	{ 0x008a, 0x0000 },
+	{ 0x008b, 0x0000 },
+	{ 0x008c, 0x0003 },
+	{ 0x008e, 0x0060 },
+	{ 0x008f, 0x1000 },
+	{ 0x0091, 0x0c26 },
+	{ 0x0092, 0x0073 },
+	{ 0x0093, 0x0000 },
+	{ 0x0094, 0x0080 },
+	{ 0x0098, 0x0000 },
+	{ 0x0099, 0x0000 },
+	{ 0x009a, 0x0007 },
+	{ 0x009f, 0x0000 },
+	{ 0x00a0, 0x0000 },
+	{ 0x00a1, 0x0002 },
+	{ 0x00a2, 0x0001 },
+	{ 0x00a3, 0x0002 },
+	{ 0x00a4, 0x0001 },
+	{ 0x00ae, 0x2040 },
+	{ 0x00af, 0x0000 },
+	{ 0x00b6, 0x0000 },
+	{ 0x00b7, 0x0000 },
+	{ 0x00b8, 0x0000 },
+	{ 0x00b9, 0x0000 },
+	{ 0x00ba, 0x0002 },
+	{ 0x00bb, 0x0000 },
+	{ 0x00be, 0x0000 },
+	{ 0x00c0, 0x0000 },
+	{ 0x00c1, 0x0aaa },
+	{ 0x00c2, 0xaa80 },
+	{ 0x00c3, 0x0003 },
+	{ 0x00c4, 0x0000 },
+	{ 0x00d0, 0x0000 },
+	{ 0x00d1, 0x2244 },
+	{ 0x00d2, 0x0000 },
+	{ 0x00d3, 0x3300 },
+	{ 0x00d4, 0x2200 },
+	{ 0x00d9, 0x0809 },
+	{ 0x00da, 0x0000 },
+	{ 0x00db, 0x0008 },
+	{ 0x00dc, 0x00c0 },
+	{ 0x00dd, 0x6724 },
+	{ 0x00de, 0x3131 },
+	{ 0x00df, 0x0008 },
+	{ 0x00e0, 0x4000 },
+	{ 0x00e1, 0x3131 },
+	{ 0x00e2, 0x600c },
+	{ 0x00ea, 0xb320 },
+	{ 0x00eb, 0x0000 },
+	{ 0x00ec, 0xb300 },
+	{ 0x00ed, 0x0000 },
+	{ 0x00ee, 0xb320 },
+	{ 0x00ef, 0x0000 },
+	{ 0x00f0, 0x0201 },
+	{ 0x00f1, 0x0ddd },
+	{ 0x00f2, 0x0ddd },
+	{ 0x00f6, 0x0000 },
+	{ 0x00f7, 0x0000 },
+	{ 0x00f8, 0x0000 },
+	{ 0x00fa, 0x0000 },
+	{ 0x00fb, 0x0000 },
+	{ 0x00fc, 0x0000 },
+	{ 0x00fd, 0x0000 },
+	{ 0x00fe, 0x10ec },
+	{ 0x00ff, 0x6451 },
+	{ 0x0100, 0xaaaa },
+	{ 0x0101, 0x000a },
+	{ 0x010a, 0xaaaa },
+	{ 0x010b, 0xa0a0 },
+	{ 0x010c, 0xaeae },
+	{ 0x010d, 0xaaaa },
+	{ 0x010e, 0xaaaa },
+	{ 0x010f, 0xaaaa },
+	{ 0x0110, 0xe002 },
+	{ 0x0111, 0xa602 },
+	{ 0x0112, 0xaaaa },
+	{ 0x0113, 0x2000 },
+	{ 0x0117, 0x0f00 },
+	{ 0x0125, 0x0420 },
+	{ 0x0132, 0x0000 },
+	{ 0x0133, 0x0000 },
+	{ 0x0136, 0x5555 },
+	{ 0x0137, 0x5540 },
+	{ 0x0138, 0x3700 },
+	{ 0x0139, 0x79a1 },
+	{ 0x013a, 0x2020 },
+	{ 0x013b, 0x2020 },
+	{ 0x013c, 0x2005 },
+	{ 0x013f, 0x0000 },
+	{ 0x0145, 0x0002 },
+	{ 0x0146, 0x0000 },
+	{ 0x0147, 0x0000 },
+	{ 0x0148, 0x0000 },
+	{ 0x0160, 0x4ec0 },
+	{ 0x0161, 0x0080 },
+	{ 0x0162, 0x0200 },
+	{ 0x0163, 0x0800 },
+	{ 0x0164, 0x0000 },
+	{ 0x0165, 0x0000 },
+	{ 0x0166, 0x0000 },
+	{ 0x0167, 0x000f },
+	{ 0x0168, 0x000f },
+	{ 0x0170, 0x4e80 },
+	{ 0x0171, 0x0080 },
+	{ 0x0172, 0x0200 },
+	{ 0x0173, 0x0800 },
+	{ 0x0174, 0x00ff },
+	{ 0x0175, 0x0000 },
+	{ 0x0190, 0x4131 },
+	{ 0x0191, 0x4131 },
+	{ 0x0192, 0x4131 },
+	{ 0x0193, 0x4131 },
+	{ 0x0194, 0x0000 },
+	{ 0x0195, 0x0000 },
+	{ 0x0196, 0x0000 },
+	{ 0x0197, 0x0000 },
+	{ 0x0198, 0x0000 },
+	{ 0x0199, 0x0000 },
+	{ 0x01a0, 0x1e64 },
+	{ 0x01a1, 0x06a3 },
+	{ 0x01a2, 0x0000 },
+	{ 0x01a3, 0x0000 },
+	{ 0x01a4, 0x0000 },
+	{ 0x01a5, 0x0000 },
+	{ 0x01a6, 0x0000 },
+	{ 0x01a7, 0x0000 },
+	{ 0x01a8, 0x0000 },
+	{ 0x01a9, 0x0000 },
+	{ 0x01aa, 0x0000 },
+	{ 0x01ab, 0x0000 },
+	{ 0x01b5, 0x0000 },
+	{ 0x01b6, 0x01c3 },
+	{ 0x01b7, 0x02a0 },
+	{ 0x01b8, 0x03e9 },
+	{ 0x01b9, 0x1389 },
+	{ 0x01ba, 0xc351 },
+	{ 0x01bb, 0x0009 },
+	{ 0x01bc, 0x0018 },
+	{ 0x01bd, 0x002a },
+	{ 0x01be, 0x004c },
+	{ 0x01bf, 0x0097 },
+	{ 0x01c0, 0x433d },
+	{ 0x01c1, 0x0000 },
+	{ 0x01c2, 0x0000 },
+	{ 0x01c3, 0x0000 },
+	{ 0x01c4, 0x0000 },
+	{ 0x01c5, 0x0000 },
+	{ 0x01c6, 0x0000 },
+	{ 0x01c7, 0x0000 },
+	{ 0x01c8, 0x40af },
+	{ 0x01c9, 0x0702 },
+	{ 0x01ca, 0x0000 },
+	{ 0x01cb, 0x0000 },
+	{ 0x01cc, 0x5757 },
+	{ 0x01cd, 0x5757 },
+	{ 0x01ce, 0x5757 },
+	{ 0x01cf, 0x5757 },
+	{ 0x01d0, 0x5757 },
+	{ 0x01d1, 0x5757 },
+	{ 0x01d2, 0x5757 },
+	{ 0x01d3, 0x5757 },
+	{ 0x01d4, 0x5757 },
+	{ 0x01d5, 0x5757 },
+	{ 0x01d6, 0x003c },
+	{ 0x01da, 0x0000 },
+	{ 0x01db, 0x0000 },
+	{ 0x01dc, 0x0000 },
+	{ 0x01de, 0x7c00 },
+	{ 0x01df, 0x0320 },
+	{ 0x01e0, 0x06a1 },
+	{ 0x01e1, 0x0000 },
+	{ 0x01e2, 0x0000 },
+	{ 0x01e3, 0x0000 },
+	{ 0x01e4, 0x0000 },
+	{ 0x01e5, 0x0000 },
+	{ 0x01e6, 0x0001 },
+	{ 0x01e7, 0x0000 },
+	{ 0x01e8, 0x0000 },
+	{ 0x01ea, 0x0000 },
+	{ 0x01eb, 0x0000 },
+	{ 0x01ec, 0x0000 },
+	{ 0x01ed, 0x0000 },
+	{ 0x01ee, 0x0000 },
+	{ 0x01ef, 0x0000 },
+	{ 0x01f0, 0x0000 },
+	{ 0x01f1, 0x0000 },
+	{ 0x01f2, 0x0000 },
+	{ 0x01f3, 0x0000 },
+	{ 0x01f4, 0x0000 },
+	{ 0x0200, 0x0000 },
+	{ 0x0201, 0x0000 },
+	{ 0x0202, 0x0000 },
+	{ 0x0203, 0x0000 },
+	{ 0x0204, 0x0000 },
+	{ 0x0205, 0x0000 },
+	{ 0x0206, 0x0000 },
+	{ 0x0207, 0x0000 },
+	{ 0x0208, 0x0000 },
+	{ 0x0210, 0x60b1 },
+	{ 0x0211, 0xa000 },
+	{ 0x0212, 0x024c },
+	{ 0x0213, 0xf7ff },
+	{ 0x0214, 0x024c },
+	{ 0x0215, 0x0102 },
+	{ 0x0216, 0x00a3 },
+	{ 0x0217, 0x0048 },
+	{ 0x0218, 0x92c0 },
+	{ 0x0219, 0x0000 },
+	{ 0x021a, 0x00c8 },
+	{ 0x021b, 0x0020 },
+	{ 0x02fa, 0x0000 },
+	{ 0x02fb, 0x0000 },
+	{ 0x02fc, 0x0000 },
+	{ 0x02ff, 0x0110 },
+	{ 0x0300, 0x001f },
+	{ 0x0301, 0x032c },
+	{ 0x0302, 0x5f21 },
+	{ 0x0303, 0x4000 },
+	{ 0x0304, 0x4000 },
+	{ 0x0305, 0x06d5 },
+	{ 0x0306, 0x8000 },
+	{ 0x0307, 0x0700 },
+	{ 0x0310, 0x4560 },
+	{ 0x0311, 0xa4a8 },
+	{ 0x0312, 0x7418 },
+	{ 0x0313, 0x0000 },
+	{ 0x0314, 0x0006 },
+	{ 0x0315, 0xffff },
+	{ 0x0316, 0xc400 },
+	{ 0x0317, 0x0000 },
+	{ 0x0330, 0x00a6 },
+	{ 0x0331, 0x04c3 },
+	{ 0x0332, 0x27c8 },
+	{ 0x0333, 0xbf50 },
+	{ 0x0334, 0x0045 },
+	{ 0x0335, 0x0007 },
+	{ 0x0336, 0x7418 },
+	{ 0x0337, 0x0501 },
+	{ 0x0338, 0x0000 },
+	{ 0x0339, 0x0010 },
+	{ 0x033a, 0x1010 },
+	{ 0x03c0, 0x7e00 },
+	{ 0x03c1, 0x8000 },
+	{ 0x03c2, 0x8000 },
+	{ 0x03c3, 0x8000 },
+	{ 0x03c4, 0x8000 },
+	{ 0x03c5, 0x8000 },
+	{ 0x03c6, 0x8000 },
+	{ 0x03c7, 0x8000 },
+	{ 0x03c8, 0x8000 },
+	{ 0x03c9, 0x8000 },
+	{ 0x03ca, 0x8000 },
+	{ 0x03cb, 0x8000 },
+	{ 0x03cc, 0x8000 },
+	{ 0x03d0, 0x0000 },
+	{ 0x03d1, 0x0000 },
+	{ 0x03d2, 0x0000 },
+	{ 0x03d3, 0x0000 },
+	{ 0x03d4, 0x2000 },
+	{ 0x03d5, 0x2000 },
+	{ 0x03d6, 0x0000 },
+	{ 0x03d7, 0x0000 },
+	{ 0x03d8, 0x2000 },
+	{ 0x03d9, 0x2000 },
+	{ 0x03da, 0x2000 },
+	{ 0x03db, 0x2000 },
+	{ 0x03dc, 0x0000 },
+	{ 0x03dd, 0x0000 },
+	{ 0x03de, 0x0000 },
+	{ 0x03df, 0x2000 },
+	{ 0x03e0, 0x0000 },
+	{ 0x03e1, 0x0000 },
+	{ 0x03e2, 0x0000 },
+	{ 0x03e3, 0x0000 },
+	{ 0x03e4, 0x0000 },
+	{ 0x03e5, 0x0000 },
+	{ 0x03e6, 0x0000 },
+	{ 0x03e7, 0x0000 },
+	{ 0x03e8, 0x0000 },
+	{ 0x03e9, 0x0000 },
+	{ 0x03ea, 0x0000 },
+	{ 0x03eb, 0x0000 },
+	{ 0x03ec, 0x0000 },
+	{ 0x03ed, 0x0000 },
+	{ 0x03ee, 0x0000 },
+	{ 0x03ef, 0x0000 },
+	{ 0x03f0, 0x0800 },
+	{ 0x03f1, 0x0800 },
+	{ 0x03f2, 0x0800 },
+	{ 0x03f3, 0x0800 },
+	{ 0x03fe, 0x0000 },
+	{ 0x03ff, 0x0000 },
+	{ 0x07f0, 0x0000 },
+	{ 0x07fa, 0x0000 },
+};
+
+static const struct reg_default rt5663_reg[] = {
+	{ 0x0000, 0x0000 },
+	{ 0x0002, 0x0008 },
+	{ 0x0005, 0x1000 },
+	{ 0x0006, 0x1000 },
+	{ 0x000a, 0x0000 },
+	{ 0x0010, 0x000f },
+	{ 0x0015, 0x42c1 },
+	{ 0x0016, 0x0000 },
+	{ 0x0018, 0x000b },
+	{ 0x0019, 0xafaf },
+	{ 0x001c, 0x2f2f },
+	{ 0x001f, 0x0000 },
+	{ 0x0022, 0x5757 },
+	{ 0x0023, 0x0039 },
+	{ 0x0026, 0xc0c0 },
+	{ 0x0029, 0x8080 },
+	{ 0x002a, 0xa0a0 },
+	{ 0x002c, 0x000c },
+	{ 0x002d, 0x0000 },
+	{ 0x0040, 0x0808 },
+	{ 0x0061, 0x0000 },
+	{ 0x0062, 0x0000 },
+	{ 0x0063, 0x003e },
+	{ 0x0064, 0x0000 },
+	{ 0x0065, 0x0000 },
+	{ 0x0066, 0x0000 },
+	{ 0x006b, 0x0000 },
+	{ 0x006e, 0x0000 },
+	{ 0x006f, 0x0000 },
+	{ 0x0070, 0x8020 },
+	{ 0x0073, 0x1000 },
+	{ 0x0074, 0xe400 },
+	{ 0x0075, 0x0002 },
+	{ 0x0076, 0x0001 },
+	{ 0x0077, 0x00f0 },
+	{ 0x0078, 0x0000 },
+	{ 0x0079, 0x0000 },
+	{ 0x007a, 0x0123 },
+	{ 0x007b, 0x8003 },
+	{ 0x0080, 0x0000 },
+	{ 0x0081, 0x0000 },
+	{ 0x0082, 0x0000 },
+	{ 0x0083, 0x0000 },
+	{ 0x0084, 0x0000 },
+	{ 0x0086, 0x0008 },
+	{ 0x0087, 0x0000 },
+	{ 0x008a, 0x0000 },
+	{ 0x008b, 0x0000 },
+	{ 0x008c, 0x0003 },
+	{ 0x008e, 0x0004 },
+	{ 0x008f, 0x1000 },
+	{ 0x0090, 0x0646 },
+	{ 0x0091, 0x0e3e },
+	{ 0x0092, 0x1071 },
+	{ 0x0093, 0x0000 },
+	{ 0x0094, 0x0080 },
+	{ 0x0097, 0x0000 },
+	{ 0x0098, 0x0000 },
+	{ 0x009a, 0x0000 },
+	{ 0x009f, 0x0000 },
+	{ 0x00ae, 0x2000 },
+	{ 0x00af, 0x0000 },
+	{ 0x00b6, 0x0000 },
+	{ 0x00b7, 0x0000 },
+	{ 0x00b8, 0x0000 },
+	{ 0x00ba, 0x0000 },
+	{ 0x00bb, 0x0000 },
+	{ 0x00be, 0x0000 },
+	{ 0x00bf, 0x0000 },
+	{ 0x00c0, 0x0000 },
+	{ 0x00c1, 0x0000 },
+	{ 0x00c5, 0x0000 },
+	{ 0x00cb, 0xa02f },
+	{ 0x00cc, 0x0000 },
+	{ 0x00cd, 0x0e02 },
+	{ 0x00d9, 0x08f9 },
+	{ 0x00db, 0x0008 },
+	{ 0x00dc, 0x00c0 },
+	{ 0x00dd, 0x6724 },
+	{ 0x00de, 0x3131 },
+	{ 0x00df, 0x0008 },
+	{ 0x00e0, 0x4000 },
+	{ 0x00e1, 0x3131 },
+	{ 0x00e2, 0x0043 },
+	{ 0x00e4, 0x400b },
+	{ 0x00e5, 0x8031 },
+	{ 0x00e6, 0x3080 },
+	{ 0x00e7, 0x4100 },
+	{ 0x00e8, 0x1400 },
+	{ 0x00e9, 0xe00a },
+	{ 0x00ea, 0x0404 },
+	{ 0x00eb, 0x0404 },
+	{ 0x00ec, 0xb320 },
+	{ 0x00ed, 0x0000 },
+	{ 0x00f4, 0x0000 },
+	{ 0x00f6, 0x0000 },
+	{ 0x00f8, 0x0000 },
+	{ 0x00fa, 0x8000 },
+	{ 0x00fd, 0x0001 },
+	{ 0x00fe, 0x10ec },
+	{ 0x00ff, 0x6406 },
+	{ 0x0100, 0xa0a0 },
+	{ 0x0108, 0x4444 },
+	{ 0x0109, 0x4444 },
+	{ 0x010a, 0xaaaa },
+	{ 0x010b, 0x00a0 },
+	{ 0x010c, 0x8aaa },
+	{ 0x010d, 0xaaaa },
+	{ 0x010e, 0x2aaa },
+	{ 0x010f, 0x002a },
+	{ 0x0110, 0xa0a4 },
+	{ 0x0111, 0x4602 },
+	{ 0x0112, 0x0101 },
+	{ 0x0113, 0x2000 },
+	{ 0x0114, 0x0000 },
+	{ 0x0116, 0x0000 },
+	{ 0x0117, 0x0f00 },
+	{ 0x0118, 0x0006 },
+	{ 0x0125, 0x2224 },
+	{ 0x0126, 0x5550 },
+	{ 0x0127, 0x0400 },
+	{ 0x0128, 0x7711 },
+	{ 0x0132, 0x0004 },
+	{ 0x0137, 0x5441 },
+	{ 0x0139, 0x79a1 },
+	{ 0x013a, 0x30c0 },
+	{ 0x013b, 0x2000 },
+	{ 0x013c, 0x2005 },
+	{ 0x013d, 0x30c0 },
+	{ 0x013e, 0x0000 },
+	{ 0x0140, 0x3700 },
+	{ 0x0141, 0x1f00 },
+	{ 0x0144, 0x0000 },
+	{ 0x0145, 0x0002 },
+	{ 0x0146, 0x0000 },
+	{ 0x0160, 0x0e80 },
+	{ 0x0161, 0x0020 },
+	{ 0x0162, 0x0080 },
+	{ 0x0163, 0x0800 },
+	{ 0x0164, 0x0000 },
+	{ 0x0165, 0x0000 },
+	{ 0x0166, 0x0000 },
+	{ 0x0167, 0x1417 },
+	{ 0x0168, 0x0017 },
+	{ 0x0169, 0x0017 },
+	{ 0x0180, 0x2000 },
+	{ 0x0181, 0x0000 },
+	{ 0x0182, 0x0000 },
+	{ 0x0183, 0x2000 },
+	{ 0x0184, 0x0000 },
+	{ 0x0185, 0x0000 },
+	{ 0x01b0, 0x4b30 },
+	{ 0x01b1, 0x0000 },
+	{ 0x01b2, 0xd870 },
+	{ 0x01b3, 0x0000 },
+	{ 0x01b4, 0x0030 },
+	{ 0x01b5, 0x5757 },
+	{ 0x01b6, 0x5757 },
+	{ 0x01b7, 0x5757 },
+	{ 0x01b8, 0x5757 },
+	{ 0x01c0, 0x433d },
+	{ 0x01c1, 0x0540 },
+	{ 0x01c2, 0x0000 },
+	{ 0x01c3, 0x0000 },
+	{ 0x01c4, 0x0000 },
+	{ 0x01c5, 0x0009 },
+	{ 0x01c6, 0x0018 },
+	{ 0x01c7, 0x002a },
+	{ 0x01c8, 0x004c },
+	{ 0x01c9, 0x0097 },
+	{ 0x01ca, 0x01c3 },
+	{ 0x01cb, 0x03e9 },
+	{ 0x01cc, 0x1389 },
+	{ 0x01cd, 0xc351 },
+	{ 0x01ce, 0x0000 },
+	{ 0x01cf, 0x0000 },
+	{ 0x01d0, 0x0000 },
+	{ 0x01d1, 0x0000 },
+	{ 0x01d2, 0x0000 },
+	{ 0x01d3, 0x003c },
+	{ 0x01d4, 0x5757 },
+	{ 0x01d5, 0x5757 },
+	{ 0x01d6, 0x5757 },
+	{ 0x01d7, 0x5757 },
+	{ 0x01d8, 0x5757 },
+	{ 0x01d9, 0x5757 },
+	{ 0x01da, 0x0000 },
+	{ 0x01db, 0x0000 },
+	{ 0x01dd, 0x0009 },
+	{ 0x01de, 0x7f00 },
+	{ 0x01df, 0x00c8 },
+	{ 0x01e0, 0x0691 },
+	{ 0x01e1, 0x0000 },
+	{ 0x01e2, 0x0000 },
+	{ 0x01e3, 0x0000 },
+	{ 0x01e4, 0x0000 },
+	{ 0x01e5, 0x0040 },
+	{ 0x01e6, 0x0000 },
+	{ 0x01e7, 0x0000 },
+	{ 0x01e8, 0x0000 },
+	{ 0x01ea, 0x0000 },
+	{ 0x01eb, 0x0000 },
+	{ 0x01ec, 0x0000 },
+	{ 0x01ed, 0x0000 },
+	{ 0x01ee, 0x0000 },
+	{ 0x01ef, 0x0000 },
+	{ 0x01f0, 0x0000 },
+	{ 0x01f1, 0x0000 },
+	{ 0x01f2, 0x0000 },
+	{ 0x0200, 0x0000 },
+	{ 0x0201, 0x2244 },
+	{ 0x0202, 0xaaaa },
+	{ 0x0250, 0x8010 },
+	{ 0x0251, 0x0000 },
+	{ 0x0252, 0x028a },
+	{ 0x02fa, 0x0000 },
+	{ 0x02fb, 0x0000 },
+	{ 0x02fc, 0x0000 },
+	{ 0x0300, 0x0000 },
+	{ 0x03d0, 0x0000 },
+	{ 0x03d1, 0x0000 },
+	{ 0x03d2, 0x0000 },
+	{ 0x03d3, 0x0000 },
+	{ 0x03d4, 0x2000 },
+	{ 0x03d5, 0x2000 },
+	{ 0x03d6, 0x0000 },
+	{ 0x03d7, 0x0000 },
+	{ 0x03d8, 0x2000 },
+	{ 0x03d9, 0x2000 },
+	{ 0x03da, 0x2000 },
+	{ 0x03db, 0x2000 },
+	{ 0x03dc, 0x0000 },
+	{ 0x03dd, 0x0000 },
+	{ 0x03de, 0x0000 },
+	{ 0x03df, 0x2000 },
+	{ 0x03e0, 0x0000 },
+	{ 0x03e1, 0x0000 },
+	{ 0x03e2, 0x0000 },
+	{ 0x03e3, 0x0000 },
+	{ 0x03e4, 0x0000 },
+	{ 0x03e5, 0x0000 },
+	{ 0x03e6, 0x0000 },
+	{ 0x03e7, 0x0000 },
+	{ 0x03e8, 0x0000 },
+	{ 0x03e9, 0x0000 },
+	{ 0x03ea, 0x0000 },
+	{ 0x03eb, 0x0000 },
+	{ 0x03ec, 0x0000 },
+	{ 0x03ed, 0x0000 },
+	{ 0x03ee, 0x0000 },
+	{ 0x03ef, 0x0000 },
+	{ 0x03f0, 0x0800 },
+	{ 0x03f1, 0x0800 },
+	{ 0x03f2, 0x0800 },
+	{ 0x03f3, 0x0800 },
+};
+
+static bool rt5663_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5663_RESET:
+	case RT5663_SIL_DET_CTL:
+	case RT5663_HP_IMP_GAIN_2:
+	case RT5663_AD_DA_MIXER:
+	case RT5663_FRAC_DIV_2:
+	case RT5663_MICBIAS_1:
+	case RT5663_ASRC_11_2:
+	case RT5663_ADC_EQ_1:
+	case RT5663_INT_ST_1:
+	case RT5663_INT_ST_2:
+	case RT5663_GPIO_STA:
+	case RT5663_SIN_GEN_1:
+	case RT5663_IL_CMD_1:
+	case RT5663_IL_CMD_5:
+	case RT5663_IL_CMD_PWRSAV1:
+	case RT5663_EM_JACK_TYPE_1:
+	case RT5663_EM_JACK_TYPE_2:
+	case RT5663_EM_JACK_TYPE_3:
+	case RT5663_JD_CTRL2:
+	case RT5663_VENDOR_ID:
+	case RT5663_VENDOR_ID_1:
+	case RT5663_VENDOR_ID_2:
+	case RT5663_PLL_INT_REG:
+	case RT5663_SOFT_RAMP:
+	case RT5663_STO_DRE_1:
+	case RT5663_STO_DRE_5:
+	case RT5663_STO_DRE_6:
+	case RT5663_STO_DRE_7:
+	case RT5663_MIC_DECRO_1:
+	case RT5663_MIC_DECRO_4:
+	case RT5663_HP_IMP_SEN_1:
+	case RT5663_HP_IMP_SEN_3:
+	case RT5663_HP_IMP_SEN_4:
+	case RT5663_HP_IMP_SEN_5:
+	case RT5663_HP_CALIB_1_1:
+	case RT5663_HP_CALIB_9:
+	case RT5663_HP_CALIB_ST1:
+	case RT5663_HP_CALIB_ST2:
+	case RT5663_HP_CALIB_ST3:
+	case RT5663_HP_CALIB_ST4:
+	case RT5663_HP_CALIB_ST5:
+	case RT5663_HP_CALIB_ST6:
+	case RT5663_HP_CALIB_ST7:
+	case RT5663_HP_CALIB_ST8:
+	case RT5663_HP_CALIB_ST9:
+	case RT5663_ANA_JD:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5663_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5663_RESET:
+	case RT5663_HP_OUT_EN:
+	case RT5663_HP_LCH_DRE:
+	case RT5663_HP_RCH_DRE:
+	case RT5663_CALIB_BST:
+	case RT5663_RECMIX:
+	case RT5663_SIL_DET_CTL:
+	case RT5663_PWR_SAV_SILDET:
+	case RT5663_SIDETONE_CTL:
+	case RT5663_STO1_DAC_DIG_VOL:
+	case RT5663_STO1_ADC_DIG_VOL:
+	case RT5663_STO1_BOOST:
+	case RT5663_HP_IMP_GAIN_1:
+	case RT5663_HP_IMP_GAIN_2:
+	case RT5663_STO1_ADC_MIXER:
+	case RT5663_AD_DA_MIXER:
+	case RT5663_STO_DAC_MIXER:
+	case RT5663_DIG_SIDE_MIXER:
+	case RT5663_BYPASS_STO_DAC:
+	case RT5663_CALIB_REC_MIX:
+	case RT5663_PWR_DIG_1:
+	case RT5663_PWR_DIG_2:
+	case RT5663_PWR_ANLG_1:
+	case RT5663_PWR_ANLG_2:
+	case RT5663_PWR_ANLG_3:
+	case RT5663_PWR_MIXER:
+	case RT5663_SIG_CLK_DET:
+	case RT5663_PRE_DIV_GATING_1:
+	case RT5663_PRE_DIV_GATING_2:
+	case RT5663_I2S1_SDP:
+	case RT5663_ADDA_CLK_1:
+	case RT5663_ADDA_RST:
+	case RT5663_FRAC_DIV_1:
+	case RT5663_FRAC_DIV_2:
+	case RT5663_TDM_1:
+	case RT5663_TDM_2:
+	case RT5663_TDM_3:
+	case RT5663_TDM_4:
+	case RT5663_TDM_5:
+	case RT5663_GLB_CLK:
+	case RT5663_PLL_1:
+	case RT5663_PLL_2:
+	case RT5663_ASRC_1:
+	case RT5663_ASRC_2:
+	case RT5663_ASRC_4:
+	case RT5663_DUMMY_REG:
+	case RT5663_ASRC_8:
+	case RT5663_ASRC_9:
+	case RT5663_ASRC_11:
+	case RT5663_DEPOP_1:
+	case RT5663_DEPOP_2:
+	case RT5663_DEPOP_3:
+	case RT5663_HP_CHARGE_PUMP_1:
+	case RT5663_HP_CHARGE_PUMP_2:
+	case RT5663_MICBIAS_1:
+	case RT5663_RC_CLK:
+	case RT5663_ASRC_11_2:
+	case RT5663_DUMMY_REG_2:
+	case RT5663_REC_PATH_GAIN:
+	case RT5663_AUTO_1MRC_CLK:
+	case RT5663_ADC_EQ_1:
+	case RT5663_ADC_EQ_2:
+	case RT5663_IRQ_1:
+	case RT5663_IRQ_2:
+	case RT5663_IRQ_3:
+	case RT5663_IRQ_4:
+	case RT5663_IRQ_5:
+	case RT5663_INT_ST_1:
+	case RT5663_INT_ST_2:
+	case RT5663_GPIO_1:
+	case RT5663_GPIO_2:
+	case RT5663_GPIO_STA:
+	case RT5663_SIN_GEN_1:
+	case RT5663_SIN_GEN_2:
+	case RT5663_SIN_GEN_3:
+	case RT5663_SOF_VOL_ZC1:
+	case RT5663_IL_CMD_1:
+	case RT5663_IL_CMD_2:
+	case RT5663_IL_CMD_3:
+	case RT5663_IL_CMD_4:
+	case RT5663_IL_CMD_5:
+	case RT5663_IL_CMD_6:
+	case RT5663_IL_CMD_7:
+	case RT5663_IL_CMD_8:
+	case RT5663_IL_CMD_PWRSAV1:
+	case RT5663_IL_CMD_PWRSAV2:
+	case RT5663_EM_JACK_TYPE_1:
+	case RT5663_EM_JACK_TYPE_2:
+	case RT5663_EM_JACK_TYPE_3:
+	case RT5663_EM_JACK_TYPE_4:
+	case RT5663_EM_JACK_TYPE_5:
+	case RT5663_EM_JACK_TYPE_6:
+	case RT5663_STO1_HPF_ADJ1:
+	case RT5663_STO1_HPF_ADJ2:
+	case RT5663_FAST_OFF_MICBIAS:
+	case RT5663_JD_CTRL1:
+	case RT5663_JD_CTRL2:
+	case RT5663_DIG_MISC:
+	case RT5663_VENDOR_ID:
+	case RT5663_VENDOR_ID_1:
+	case RT5663_VENDOR_ID_2:
+	case RT5663_DIG_VOL_ZCD:
+	case RT5663_ANA_BIAS_CUR_1:
+	case RT5663_ANA_BIAS_CUR_2:
+	case RT5663_ANA_BIAS_CUR_3:
+	case RT5663_ANA_BIAS_CUR_4:
+	case RT5663_ANA_BIAS_CUR_5:
+	case RT5663_ANA_BIAS_CUR_6:
+	case RT5663_BIAS_CUR_5:
+	case RT5663_BIAS_CUR_6:
+	case RT5663_BIAS_CUR_7:
+	case RT5663_BIAS_CUR_8:
+	case RT5663_DACREF_LDO:
+	case RT5663_DUMMY_REG_3:
+	case RT5663_BIAS_CUR_9:
+	case RT5663_DUMMY_REG_4:
+	case RT5663_VREFADJ_OP:
+	case RT5663_VREF_RECMIX:
+	case RT5663_CHARGE_PUMP_1:
+	case RT5663_CHARGE_PUMP_1_2:
+	case RT5663_CHARGE_PUMP_1_3:
+	case RT5663_CHARGE_PUMP_2:
+	case RT5663_DIG_IN_PIN1:
+	case RT5663_PAD_DRV_CTL:
+	case RT5663_PLL_INT_REG:
+	case RT5663_CHOP_DAC_L:
+	case RT5663_CHOP_ADC:
+	case RT5663_CALIB_ADC:
+	case RT5663_CHOP_DAC_R:
+	case RT5663_DUMMY_CTL_DACLR:
+	case RT5663_DUMMY_REG_5:
+	case RT5663_SOFT_RAMP:
+	case RT5663_TEST_MODE_1:
+	case RT5663_TEST_MODE_2:
+	case RT5663_TEST_MODE_3:
+	case RT5663_STO_DRE_1:
+	case RT5663_STO_DRE_2:
+	case RT5663_STO_DRE_3:
+	case RT5663_STO_DRE_4:
+	case RT5663_STO_DRE_5:
+	case RT5663_STO_DRE_6:
+	case RT5663_STO_DRE_7:
+	case RT5663_STO_DRE_8:
+	case RT5663_STO_DRE_9:
+	case RT5663_STO_DRE_10:
+	case RT5663_MIC_DECRO_1:
+	case RT5663_MIC_DECRO_2:
+	case RT5663_MIC_DECRO_3:
+	case RT5663_MIC_DECRO_4:
+	case RT5663_MIC_DECRO_5:
+	case RT5663_MIC_DECRO_6:
+	case RT5663_HP_DECRO_1:
+	case RT5663_HP_DECRO_2:
+	case RT5663_HP_DECRO_3:
+	case RT5663_HP_DECRO_4:
+	case RT5663_HP_DECOUP:
+	case RT5663_HP_IMP_SEN_MAP8:
+	case RT5663_HP_IMP_SEN_MAP9:
+	case RT5663_HP_IMP_SEN_MAP10:
+	case RT5663_HP_IMP_SEN_MAP11:
+	case RT5663_HP_IMP_SEN_1:
+	case RT5663_HP_IMP_SEN_2:
+	case RT5663_HP_IMP_SEN_3:
+	case RT5663_HP_IMP_SEN_4:
+	case RT5663_HP_IMP_SEN_5:
+	case RT5663_HP_IMP_SEN_6:
+	case RT5663_HP_IMP_SEN_7:
+	case RT5663_HP_IMP_SEN_8:
+	case RT5663_HP_IMP_SEN_9:
+	case RT5663_HP_IMP_SEN_10:
+	case RT5663_HP_IMP_SEN_11:
+	case RT5663_HP_IMP_SEN_12:
+	case RT5663_HP_IMP_SEN_13:
+	case RT5663_HP_IMP_SEN_14:
+	case RT5663_HP_IMP_SEN_15:
+	case RT5663_HP_IMP_SEN_16:
+	case RT5663_HP_IMP_SEN_17:
+	case RT5663_HP_IMP_SEN_18:
+	case RT5663_HP_IMP_SEN_19:
+	case RT5663_HP_IMPSEN_DIG5:
+	case RT5663_HP_IMPSEN_MAP1:
+	case RT5663_HP_IMPSEN_MAP2:
+	case RT5663_HP_IMPSEN_MAP3:
+	case RT5663_HP_IMPSEN_MAP4:
+	case RT5663_HP_IMPSEN_MAP5:
+	case RT5663_HP_IMPSEN_MAP7:
+	case RT5663_HP_LOGIC_1:
+	case RT5663_HP_LOGIC_2:
+	case RT5663_HP_CALIB_1:
+	case RT5663_HP_CALIB_1_1:
+	case RT5663_HP_CALIB_2:
+	case RT5663_HP_CALIB_3:
+	case RT5663_HP_CALIB_4:
+	case RT5663_HP_CALIB_5:
+	case RT5663_HP_CALIB_5_1:
+	case RT5663_HP_CALIB_6:
+	case RT5663_HP_CALIB_7:
+	case RT5663_HP_CALIB_9:
+	case RT5663_HP_CALIB_10:
+	case RT5663_HP_CALIB_11:
+	case RT5663_HP_CALIB_ST1:
+	case RT5663_HP_CALIB_ST2:
+	case RT5663_HP_CALIB_ST3:
+	case RT5663_HP_CALIB_ST4:
+	case RT5663_HP_CALIB_ST5:
+	case RT5663_HP_CALIB_ST6:
+	case RT5663_HP_CALIB_ST7:
+	case RT5663_HP_CALIB_ST8:
+	case RT5663_HP_CALIB_ST9:
+	case RT5663_HP_AMP_DET:
+	case RT5663_DUMMY_REG_6:
+	case RT5663_HP_BIAS:
+	case RT5663_CBJ_1:
+	case RT5663_CBJ_2:
+	case RT5663_CBJ_3:
+	case RT5663_DUMMY_1:
+	case RT5663_DUMMY_2:
+	case RT5663_DUMMY_3:
+	case RT5663_ANA_JD:
+	case RT5663_ADC_LCH_LPF1_A1:
+	case RT5663_ADC_RCH_LPF1_A1:
+	case RT5663_ADC_LCH_LPF1_H0:
+	case RT5663_ADC_RCH_LPF1_H0:
+	case RT5663_ADC_LCH_BPF1_A1:
+	case RT5663_ADC_RCH_BPF1_A1:
+	case RT5663_ADC_LCH_BPF1_A2:
+	case RT5663_ADC_RCH_BPF1_A2:
+	case RT5663_ADC_LCH_BPF1_H0:
+	case RT5663_ADC_RCH_BPF1_H0:
+	case RT5663_ADC_LCH_BPF2_A1:
+	case RT5663_ADC_RCH_BPF2_A1:
+	case RT5663_ADC_LCH_BPF2_A2:
+	case RT5663_ADC_RCH_BPF2_A2:
+	case RT5663_ADC_LCH_BPF2_H0:
+	case RT5663_ADC_RCH_BPF2_H0:
+	case RT5663_ADC_LCH_BPF3_A1:
+	case RT5663_ADC_RCH_BPF3_A1:
+	case RT5663_ADC_LCH_BPF3_A2:
+	case RT5663_ADC_RCH_BPF3_A2:
+	case RT5663_ADC_LCH_BPF3_H0:
+	case RT5663_ADC_RCH_BPF3_H0:
+	case RT5663_ADC_LCH_BPF4_A1:
+	case RT5663_ADC_RCH_BPF4_A1:
+	case RT5663_ADC_LCH_BPF4_A2:
+	case RT5663_ADC_RCH_BPF4_A2:
+	case RT5663_ADC_LCH_BPF4_H0:
+	case RT5663_ADC_RCH_BPF4_H0:
+	case RT5663_ADC_LCH_HPF1_A1:
+	case RT5663_ADC_RCH_HPF1_A1:
+	case RT5663_ADC_LCH_HPF1_H0:
+	case RT5663_ADC_RCH_HPF1_H0:
+	case RT5663_ADC_EQ_PRE_VOL_L:
+	case RT5663_ADC_EQ_PRE_VOL_R:
+	case RT5663_ADC_EQ_POST_VOL_L:
+	case RT5663_ADC_EQ_POST_VOL_R:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5668_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5663_RESET:
+	case RT5668_CBJ_TYPE_2:
+	case RT5668_PDM_OUT_CTL:
+	case RT5668_PDM_I2C_DATA_CTL1:
+	case RT5668_PDM_I2C_DATA_CTL4:
+	case RT5668_ALC_BK_GAIN:
+	case RT5663_PLL_2:
+	case RT5663_MICBIAS_1:
+	case RT5663_ADC_EQ_1:
+	case RT5663_INT_ST_1:
+	case RT5668_GPIO_STA:
+	case RT5663_IL_CMD_1:
+	case RT5663_IL_CMD_5:
+	case RT5668_A_JD_CTRL:
+	case RT5663_JD_CTRL2:
+	case RT5663_VENDOR_ID:
+	case RT5663_VENDOR_ID_1:
+	case RT5663_VENDOR_ID_2:
+	case RT5663_STO_DRE_1:
+	case RT5663_STO_DRE_5:
+	case RT5663_STO_DRE_6:
+	case RT5663_STO_DRE_7:
+	case RT5668_MONO_DYNA_6:
+	case RT5668_STO1_SIL_DET:
+	case RT5668_MONOL_SIL_DET:
+	case RT5668_MONOR_SIL_DET:
+	case RT5668_STO2_DAC_SIL:
+	case RT5668_MONO_AMP_CAL_ST1:
+	case RT5668_MONO_AMP_CAL_ST2:
+	case RT5668_MONO_AMP_CAL_ST3:
+	case RT5668_MONO_AMP_CAL_ST4:
+	case RT5663_HP_IMP_SEN_2:
+	case RT5663_HP_IMP_SEN_3:
+	case RT5663_HP_IMP_SEN_4:
+	case RT5663_HP_IMP_SEN_10:
+	case RT5663_HP_CALIB_1:
+	case RT5663_HP_CALIB_10:
+	case RT5663_HP_CALIB_ST1:
+	case RT5663_HP_CALIB_ST4:
+	case RT5663_HP_CALIB_ST5:
+	case RT5663_HP_CALIB_ST6:
+	case RT5663_HP_CALIB_ST7:
+	case RT5663_HP_CALIB_ST8:
+	case RT5663_HP_CALIB_ST9:
+	case RT5668_HP_CALIB_ST10:
+	case RT5668_HP_CALIB_ST11:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5668_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5668_LOUT_CTRL:
+	case RT5668_HP_AMP_2:
+	case RT5668_MONO_OUT:
+	case RT5668_MONO_GAIN:
+	case RT5668_AEC_BST:
+	case RT5668_IN1_IN2:
+	case RT5668_IN3_IN4:
+	case RT5668_INL1_INR1:
+	case RT5668_CBJ_TYPE_2:
+	case RT5668_CBJ_TYPE_3:
+	case RT5668_CBJ_TYPE_4:
+	case RT5668_CBJ_TYPE_5:
+	case RT5668_CBJ_TYPE_8:
+	case RT5668_DAC3_DIG_VOL:
+	case RT5668_DAC3_CTRL:
+	case RT5668_MONO_ADC_DIG_VOL:
+	case RT5668_STO2_ADC_DIG_VOL:
+	case RT5668_MONO_ADC_BST_GAIN:
+	case RT5668_STO2_ADC_BST_GAIN:
+	case RT5668_SIDETONE_CTRL:
+	case RT5668_MONO1_ADC_MIXER:
+	case RT5668_STO2_ADC_MIXER:
+	case RT5668_MONO_DAC_MIXER:
+	case RT5668_DAC2_SRC_CTRL:
+	case RT5668_IF_3_4_DATA_CTL:
+	case RT5668_IF_5_DATA_CTL:
+	case RT5668_PDM_OUT_CTL:
+	case RT5668_PDM_I2C_DATA_CTL1:
+	case RT5668_PDM_I2C_DATA_CTL2:
+	case RT5668_PDM_I2C_DATA_CTL3:
+	case RT5668_PDM_I2C_DATA_CTL4:
+	case RT5668_RECMIX1_NEW:
+	case RT5668_RECMIX1L_0:
+	case RT5668_RECMIX1L:
+	case RT5668_RECMIX1R_0:
+	case RT5668_RECMIX1R:
+	case RT5668_RECMIX2_NEW:
+	case RT5668_RECMIX2_L_2:
+	case RT5668_RECMIX2_R:
+	case RT5668_RECMIX2_R_2:
+	case RT5668_CALIB_REC_LR:
+	case RT5668_ALC_BK_GAIN:
+	case RT5668_MONOMIX_GAIN:
+	case RT5668_MONOMIX_IN_GAIN:
+	case RT5668_OUT_MIXL_GAIN:
+	case RT5668_OUT_LMIX_IN_GAIN:
+	case RT5668_OUT_RMIX_IN_GAIN:
+	case RT5668_OUT_RMIX_IN_GAIN1:
+	case RT5668_LOUT_MIXER_CTRL:
+	case RT5668_PWR_VOL:
+	case RT5668_ADCDAC_RST:
+	case RT5668_I2S34_SDP:
+	case RT5668_I2S5_SDP:
+	case RT5668_TDM_5:
+	case RT5668_TDM_6:
+	case RT5668_TDM_7:
+	case RT5668_TDM_8:
+	case RT5668_ASRC_3:
+	case RT5668_ASRC_6:
+	case RT5668_ASRC_7:
+	case RT5668_PLL_TRK_13:
+	case RT5668_I2S_M_CLK_CTL:
+	case RT5668_FDIV_I2S34_M_CLK:
+	case RT5668_FDIV_I2S34_M_CLK2:
+	case RT5668_FDIV_I2S5_M_CLK:
+	case RT5668_FDIV_I2S5_M_CLK2:
+	case RT5668_IRQ_4:
+	case RT5668_GPIO_3:
+	case RT5668_GPIO_4:
+	case RT5668_GPIO_STA:
+	case RT5668_HP_AMP_DET1:
+	case RT5668_HP_AMP_DET2:
+	case RT5668_HP_AMP_DET3:
+	case RT5668_MID_BD_HP_AMP:
+	case RT5668_LOW_BD_HP_AMP:
+	case RT5668_SOF_VOL_ZC2:
+	case RT5668_ADC_STO2_ADJ1:
+	case RT5668_ADC_STO2_ADJ2:
+	case RT5668_A_JD_CTRL:
+	case RT5668_JD1_TRES_CTRL:
+	case RT5668_JD2_TRES_CTRL:
+	case RT5668_JD_CTRL2:
+	case RT5668_DUM_REG_2:
+	case RT5668_DUM_REG_3:
+	case RT5663_VENDOR_ID:
+	case RT5663_VENDOR_ID_1:
+	case RT5663_VENDOR_ID_2:
+	case RT5668_DACADC_DIG_VOL2:
+	case RT5668_DIG_IN_PIN2:
+	case RT5668_PAD_DRV_CTL1:
+	case RT5668_SOF_RAM_DEPOP:
+	case RT5668_VOL_TEST:
+	case RT5668_TEST_MODE_3:
+	case RT5668_TEST_MODE_4:
+	case RT5663_STO_DRE_9:
+	case RT5668_MONO_DYNA_1:
+	case RT5668_MONO_DYNA_2:
+	case RT5668_MONO_DYNA_3:
+	case RT5668_MONO_DYNA_4:
+	case RT5668_MONO_DYNA_5:
+	case RT5668_MONO_DYNA_6:
+	case RT5668_STO1_SIL_DET:
+	case RT5668_MONOL_SIL_DET:
+	case RT5668_MONOR_SIL_DET:
+	case RT5668_STO2_DAC_SIL:
+	case RT5668_PWR_SAV_CTL1:
+	case RT5668_PWR_SAV_CTL2:
+	case RT5668_PWR_SAV_CTL3:
+	case RT5668_PWR_SAV_CTL4:
+	case RT5668_PWR_SAV_CTL5:
+	case RT5668_PWR_SAV_CTL6:
+	case RT5668_MONO_AMP_CAL1:
+	case RT5668_MONO_AMP_CAL2:
+	case RT5668_MONO_AMP_CAL3:
+	case RT5668_MONO_AMP_CAL4:
+	case RT5668_MONO_AMP_CAL5:
+	case RT5668_MONO_AMP_CAL6:
+	case RT5668_MONO_AMP_CAL7:
+	case RT5668_MONO_AMP_CAL_ST1:
+	case RT5668_MONO_AMP_CAL_ST2:
+	case RT5668_MONO_AMP_CAL_ST3:
+	case RT5668_MONO_AMP_CAL_ST4:
+	case RT5668_MONO_AMP_CAL_ST5:
+	case RT5668_HP_IMP_SEN_13:
+	case RT5668_HP_IMP_SEN_14:
+	case RT5668_HP_IMP_SEN_6:
+	case RT5668_HP_IMP_SEN_7:
+	case RT5668_HP_IMP_SEN_8:
+	case RT5668_HP_IMP_SEN_9:
+	case RT5668_HP_IMP_SEN_10:
+	case RT5668_HP_LOGIC_3:
+	case RT5668_HP_CALIB_ST10:
+	case RT5668_HP_CALIB_ST11:
+	case RT5668_PRO_REG_TBL_4:
+	case RT5668_PRO_REG_TBL_5:
+	case RT5668_PRO_REG_TBL_6:
+	case RT5668_PRO_REG_TBL_7:
+	case RT5668_PRO_REG_TBL_8:
+	case RT5668_PRO_REG_TBL_9:
+	case RT5668_SAR_ADC_INL_1:
+	case RT5668_SAR_ADC_INL_2:
+	case RT5668_SAR_ADC_INL_3:
+	case RT5668_SAR_ADC_INL_4:
+	case RT5668_SAR_ADC_INL_5:
+	case RT5668_SAR_ADC_INL_6:
+	case RT5668_SAR_ADC_INL_7:
+	case RT5668_SAR_ADC_INL_8:
+	case RT5668_SAR_ADC_INL_9:
+	case RT5668_SAR_ADC_INL_10:
+	case RT5668_SAR_ADC_INL_11:
+	case RT5668_SAR_ADC_INL_12:
+	case RT5668_DRC_CTRL_1:
+	case RT5668_DRC1_CTRL_2:
+	case RT5668_DRC1_CTRL_3:
+	case RT5668_DRC1_CTRL_4:
+	case RT5668_DRC1_CTRL_5:
+	case RT5668_DRC1_CTRL_6:
+	case RT5668_DRC1_HD_CTRL_1:
+	case RT5668_DRC1_HD_CTRL_2:
+	case RT5668_DRC1_PRI_REG_1:
+	case RT5668_DRC1_PRI_REG_2:
+	case RT5668_DRC1_PRI_REG_3:
+	case RT5668_DRC1_PRI_REG_4:
+	case RT5668_DRC1_PRI_REG_5:
+	case RT5668_DRC1_PRI_REG_6:
+	case RT5668_DRC1_PRI_REG_7:
+	case RT5668_DRC1_PRI_REG_8:
+	case RT5668_ALC_PGA_CTL_1:
+	case RT5668_ALC_PGA_CTL_2:
+	case RT5668_ALC_PGA_CTL_3:
+	case RT5668_ALC_PGA_CTL_4:
+	case RT5668_ALC_PGA_CTL_5:
+	case RT5668_ALC_PGA_CTL_6:
+	case RT5668_ALC_PGA_CTL_7:
+	case RT5668_ALC_PGA_CTL_8:
+	case RT5668_ALC_PGA_REG_1:
+	case RT5668_ALC_PGA_REG_2:
+	case RT5668_ALC_PGA_REG_3:
+	case RT5668_ADC_EQ_RECOV_1:
+	case RT5668_ADC_EQ_RECOV_2:
+	case RT5668_ADC_EQ_RECOV_3:
+	case RT5668_ADC_EQ_RECOV_4:
+	case RT5668_ADC_EQ_RECOV_5:
+	case RT5668_ADC_EQ_RECOV_6:
+	case RT5668_ADC_EQ_RECOV_7:
+	case RT5668_ADC_EQ_RECOV_8:
+	case RT5668_ADC_EQ_RECOV_9:
+	case RT5668_ADC_EQ_RECOV_10:
+	case RT5668_ADC_EQ_RECOV_11:
+	case RT5668_ADC_EQ_RECOV_12:
+	case RT5668_ADC_EQ_RECOV_13:
+	case RT5668_VID_HIDDEN:
+	case RT5668_VID_CUSTOMER:
+	case RT5668_SCAN_MODE:
+	case RT5668_I2C_BYPA:
+		return true;
+	case RT5663_TDM_1:
+	case RT5663_DEPOP_3:
+	case RT5663_ASRC_11_2:
+	case RT5663_INT_ST_2:
+	case RT5663_GPIO_STA:
+	case RT5663_SIN_GEN_1:
+	case RT5663_SIN_GEN_2:
+	case RT5663_SIN_GEN_3:
+	case RT5663_IL_CMD_PWRSAV1:
+	case RT5663_IL_CMD_PWRSAV2:
+	case RT5663_EM_JACK_TYPE_1:
+	case RT5663_EM_JACK_TYPE_2:
+	case RT5663_EM_JACK_TYPE_3:
+	case RT5663_EM_JACK_TYPE_4:
+	case RT5663_FAST_OFF_MICBIAS:
+	case RT5663_ANA_BIAS_CUR_1:
+	case RT5663_ANA_BIAS_CUR_2:
+	case RT5663_BIAS_CUR_9:
+	case RT5663_DUMMY_REG_4:
+	case RT5663_VREF_RECMIX:
+	case RT5663_CHARGE_PUMP_1_2:
+	case RT5663_CHARGE_PUMP_1_3:
+	case RT5663_CHARGE_PUMP_2:
+	case RT5663_CHOP_DAC_R:
+	case RT5663_DUMMY_CTL_DACLR:
+	case RT5663_DUMMY_REG_5:
+	case RT5663_SOFT_RAMP:
+	case RT5663_TEST_MODE_1:
+	case RT5663_STO_DRE_10:
+	case RT5663_MIC_DECRO_1:
+	case RT5663_MIC_DECRO_2:
+	case RT5663_MIC_DECRO_3:
+	case RT5663_MIC_DECRO_4:
+	case RT5663_MIC_DECRO_5:
+	case RT5663_MIC_DECRO_6:
+	case RT5663_HP_DECRO_1:
+	case RT5663_HP_DECRO_2:
+	case RT5663_HP_DECRO_3:
+	case RT5663_HP_DECRO_4:
+	case RT5663_HP_DECOUP:
+	case RT5663_HP_IMPSEN_MAP4:
+	case RT5663_HP_IMPSEN_MAP5:
+	case RT5663_HP_IMPSEN_MAP7:
+	case RT5663_HP_CALIB_1:
+	case RT5663_CBJ_1:
+	case RT5663_CBJ_2:
+	case RT5663_CBJ_3:
+		return false;
+	default:
+		return rt5663_readable_register(dev, reg);
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(rt5663_hp_vol_tlv, -2400, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rt5668_hp_vol_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(in_bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5663_if1_adc_data_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5663_if1_adc_enum, RT5663_TDM_2,
+	RT5663_DATA_SWAP_ADCDAT1_SHIFT, rt5663_if1_adc_data_select);
+
+static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec,
+	bool enable)
+{
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	if (enable) {
+		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+			RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_EN);
+		/* reset in-line command */
+		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+			RT5668_RESET_4BTN_INL_MASK,
+			RT5668_RESET_4BTN_INL_RESET);
+		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+			RT5668_RESET_4BTN_INL_MASK,
+			RT5668_RESET_4BTN_INL_NOR);
+		switch (rt5663->codec_type) {
+		case CODEC_TYPE_RT5668:
+			snd_soc_update_bits(codec, RT5663_IRQ_3,
+				RT5668_EN_IRQ_INLINE_MASK,
+				RT5668_EN_IRQ_INLINE_NOR);
+			break;
+		case CODEC_TYPE_RT5663:
+			snd_soc_update_bits(codec, RT5663_IRQ_2,
+				RT5663_EN_IRQ_INLINE_MASK,
+				RT5663_EN_IRQ_INLINE_NOR);
+			break;
+		default:
+			dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+		}
+	} else {
+		switch (rt5663->codec_type) {
+		case CODEC_TYPE_RT5668:
+			snd_soc_update_bits(codec, RT5663_IRQ_3,
+				RT5668_EN_IRQ_INLINE_MASK,
+				RT5668_EN_IRQ_INLINE_BYP);
+			break;
+		case CODEC_TYPE_RT5663:
+			snd_soc_update_bits(codec, RT5663_IRQ_2,
+				RT5663_EN_IRQ_INLINE_MASK,
+				RT5663_EN_IRQ_INLINE_BYP);
+			break;
+		default:
+			dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+		}
+		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+			RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_DIS);
+		/* reset in-line command */
+		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+			RT5668_RESET_4BTN_INL_MASK,
+			RT5668_RESET_4BTN_INL_RESET);
+		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+			RT5668_RESET_4BTN_INL_MASK,
+			RT5668_RESET_4BTN_INL_NOR);
+	}
+}
+
+/**
+ * rt5668_jack_detect - Detect headset.
+ * @codec: SoC audio codec device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+
+static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec);
+	int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
+
+	dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert);
+	if (jack_insert) {
+		snd_soc_write(codec, RT5668_CBJ_TYPE_2, 0x8040);
+		snd_soc_write(codec, RT5668_CBJ_TYPE_3, 0x1484);
+
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2");
+		snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_force_enable_pin(dapm, "CBJ Power");
+		snd_soc_dapm_sync(dapm);
+		snd_soc_update_bits(codec, RT5663_RC_CLK,
+			RT5668_DIG_1M_CLK_MASK, RT5668_DIG_1M_CLK_EN);
+		snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x8);
+
+		while (i < 5) {
+			msleep(sleep_time[i]);
+			val = snd_soc_read(codec, RT5668_CBJ_TYPE_2) & 0x0003;
+			if (val == 0x1 || val == 0x2 || val == 0x3)
+				break;
+			dev_dbg(codec->dev, "%s: MX-0011 val=%x sleep %d\n",
+				__func__, val, sleep_time[i]);
+			i++;
+		}
+		dev_dbg(codec->dev, "%s val = %d\n", __func__, val);
+		switch (val) {
+		case 1:
+		case 2:
+			rt5668->jack_type = SND_JACK_HEADSET;
+			rt5663_enable_push_button_irq(codec, true);
+			break;
+		default:
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
+			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+			snd_soc_dapm_disable_pin(dapm, "CBJ Power");
+			snd_soc_dapm_sync(dapm);
+			rt5668->jack_type = SND_JACK_HEADPHONE;
+			break;
+		}
+	} else {
+		snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x0);
+
+		if (rt5668->jack_type == SND_JACK_HEADSET) {
+			rt5663_enable_push_button_irq(codec, false);
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
+			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+			snd_soc_dapm_disable_pin(dapm, "CBJ Power");
+			snd_soc_dapm_sync(dapm);
+		}
+		rt5668->jack_type = 0;
+	}
+
+	dev_dbg(codec->dev, "jack_type = %d\n", rt5668->jack_type);
+	return rt5668->jack_type;
+}
+
+/**
+ * rt5663_jack_detect - Detect headset.
+ * @codec: SoC audio codec device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+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};
+
+	dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert);
+
+	if (jack_insert) {
+		snd_soc_update_bits(codec, RT5663_DIG_MISC,
+			RT5668_DIG_GATE_CTRL_MASK, RT5668_DIG_GATE_CTRL_EN);
+		snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+			RT5663_SI_HP_MASK | RT5668_OSW_HP_L_MASK |
+			RT5668_OSW_HP_R_MASK, RT5663_SI_HP_EN |
+			RT5668_OSW_HP_L_DIS | RT5668_OSW_HP_R_DIS);
+		snd_soc_update_bits(codec, RT5663_DUMMY_1,
+			RT5663_EMB_CLK_MASK | RT5663_HPA_CPL_BIAS_MASK |
+			RT5663_HPA_CPR_BIAS_MASK, RT5663_EMB_CLK_EN |
+			RT5663_HPA_CPL_BIAS_1 | RT5663_HPA_CPR_BIAS_1);
+		snd_soc_update_bits(codec, RT5663_CBJ_1,
+			RT5663_INBUF_CBJ_BST1_MASK | RT5663_CBJ_SENSE_BST1_MASK,
+			RT5663_INBUF_CBJ_BST1_ON | RT5663_CBJ_SENSE_BST1_L);
+		snd_soc_update_bits(codec, RT5663_IL_CMD_2,
+			RT5663_PWR_MIC_DET_MASK, RT5663_PWR_MIC_DET_ON);
+		/* BST1 power on for JD */
+		snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+			RT5668_PWR_BST1_MASK, RT5668_PWR_BST1_ON);
+		snd_soc_update_bits(codec, RT5663_EM_JACK_TYPE_1,
+			RT5663_CBJ_DET_MASK | RT5663_EXT_JD_MASK |
+			RT5663_POL_EXT_JD_MASK, RT5663_CBJ_DET_EN |
+			RT5663_EXT_JD_EN | RT5663_POL_EXT_JD_EN);
+		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+			RT5668_PWR_MB_MASK | RT5668_LDO1_DVO_MASK |
+			RT5668_AMP_HP_MASK, RT5668_PWR_MB |
+			RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X);
+		snd_soc_update_bits(codec, RT5663_AUTO_1MRC_CLK,
+			RT5668_IRQ_POW_SAV_MASK, RT5668_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;
+			i++;
+			if (val == 0x1 || val == 0x2 || val == 0x3)
+				break;
+			dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n",
+				__func__, val, sleep_time[i]);
+		}
+		dev_dbg(codec->dev, "%s val = %d\n", __func__, val);
+		switch (val) {
+		case 1:
+		case 2:
+			rt5663->jack_type = SND_JACK_HEADSET;
+			rt5663_enable_push_button_irq(codec, true);
+			break;
+		default:
+			rt5663->jack_type = SND_JACK_HEADPHONE;
+			break;
+		}
+	} else {
+		if (rt5663->jack_type == SND_JACK_HEADSET)
+			rt5663_enable_push_button_irq(codec, false);
+		rt5663->jack_type = 0;
+	}
+
+	dev_dbg(codec->dev, "jack_type = %d\n", rt5663->jack_type);
+	return rt5663->jack_type;
+}
+
+static int rt5663_button_detect(struct snd_soc_codec *codec)
+{
+	int btn_type, val;
+
+	val = snd_soc_read(codec, RT5663_IL_CMD_5);
+	dev_dbg(codec->dev, "%s: val=0x%x\n", __func__, val);
+	btn_type = val & 0xfff0;
+	snd_soc_write(codec, RT5663_IL_CMD_5, val);
+
+	return btn_type;
+}
+
+static irqreturn_t rt5663_irq(int irq, void *data)
+{
+	struct rt5663_priv *rt5663 = data;
+
+	dev_dbg(rt5663->codec->dev, "%s IRQ queue work\n", __func__);
+
+	queue_delayed_work(system_wq, &rt5663->jack_detect_work,
+		msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+int rt5663_set_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *hs_jack)
+{
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	rt5663->hs_jack = hs_jack;
+
+	rt5663_irq(0, rt5663);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5663_set_jack_detect);
+
+static bool rt5663_check_jd_status(struct snd_soc_codec *codec)
+{
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	int val = snd_soc_read(codec, RT5663_INT_ST_1);
+
+	dev_dbg(codec->dev, "%s val=%x\n", __func__, val);
+
+	/* JD1 */
+	switch (rt5663->codec_type) {
+	case CODEC_TYPE_RT5668:
+		return !(val & 0x2000);
+	case CODEC_TYPE_RT5663:
+		return !(val & 0x1000);
+	default:
+		dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+	}
+
+	return false;
+}
+
+static void rt5663_jack_detect_work(struct work_struct *work)
+{
+	struct rt5663_priv *rt5663 =
+		container_of(work, struct rt5663_priv, jack_detect_work.work);
+	struct snd_soc_codec *codec = rt5663->codec;
+	int btn_type, report = 0;
+
+	if (!codec)
+		return;
+
+	if (rt5663_check_jd_status(codec)) {
+		/* jack in */
+		if (rt5663->jack_type == 0) {
+			/* jack was out, report jack type */
+			switch (rt5663->codec_type) {
+			case CODEC_TYPE_RT5668:
+				report = rt5668_jack_detect(rt5663->codec, 1);
+				break;
+			case CODEC_TYPE_RT5663:
+				report = rt5663_jack_detect(rt5663->codec, 1);
+				break;
+			default:
+				dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+			}
+		} else {
+			/* jack is already in, report button event */
+			report = SND_JACK_HEADSET;
+			btn_type = rt5663_button_detect(rt5663->codec);
+			/**
+			 * rt5663 can report three kinds of button behavior,
+			 * one click, double click and hold. However,
+			 * currently we will report button pressed/released
+			 * event. So all the three button behaviors are
+			 * treated as button pressed.
+			 */
+			switch (btn_type) {
+			case 0x8000:
+			case 0x4000:
+			case 0x2000:
+				report |= SND_JACK_BTN_0;
+				break;
+			case 0x1000:
+			case 0x0800:
+			case 0x0400:
+				report |= SND_JACK_BTN_1;
+				break;
+			case 0x0200:
+			case 0x0100:
+			case 0x0080:
+				report |= SND_JACK_BTN_2;
+				break;
+			case 0x0040:
+			case 0x0020:
+			case 0x0010:
+				report |= SND_JACK_BTN_3;
+				break;
+			case 0x0000: /* unpressed */
+				break;
+			default:
+				btn_type = 0;
+				dev_err(rt5663->codec->dev,
+					"Unexpected button code 0x%04x\n",
+					btn_type);
+				break;
+			}
+			/* button release or spurious interrput*/
+			if (btn_type == 0)
+				report =  rt5663->jack_type;
+		}
+	} else {
+		/* jack out */
+		switch (rt5663->codec_type) {
+		case CODEC_TYPE_RT5668:
+			report = rt5668_jack_detect(rt5663->codec, 0);
+			break;
+		case CODEC_TYPE_RT5663:
+			report = rt5663_jack_detect(rt5663->codec, 0);
+			break;
+		default:
+			dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+		}
+	}
+	dev_dbg(codec->dev, "%s jack report: 0x%04x\n", __func__, report);
+	snd_soc_jack_report(rt5663->hs_jack, report, SND_JACK_HEADSET |
+			    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			    SND_JACK_BTN_2 | SND_JACK_BTN_3);
+}
+
+static const struct snd_kcontrol_new rt5663_snd_controls[] = {
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC Playback Volume", RT5663_STO1_DAC_DIG_VOL,
+		RT5668_DAC_L1_VOL_SHIFT + 1, RT5668_DAC_R1_VOL_SHIFT + 1,
+		87, 0, dac_vol_tlv),
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC Capture Switch", RT5663_STO1_ADC_DIG_VOL,
+		RT5668_ADC_L_MUTE_SHIFT, RT5668_ADC_R_MUTE_SHIFT, 1, 1),
+	SOC_DOUBLE_TLV("ADC Capture Volume", RT5663_STO1_ADC_DIG_VOL,
+		RT5668_ADC_L_VOL_SHIFT + 1, RT5668_ADC_R_VOL_SHIFT + 1,
+		63, 0, adc_vol_tlv),
+};
+
+static const struct snd_kcontrol_new rt5668_specific_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_HP_LCH_DRE,
+		RT5663_HP_RCH_DRE, RT5668_GAIN_HP_SHIFT, 15, 1,
+		rt5668_hp_vol_tlv),
+	/* Mic Boost Volume */
+	SOC_SINGLE_TLV("IN1 Capture Volume", RT5668_AEC_BST,
+		RT5668_GAIN_CBJ_SHIFT, 8, 0, in_bst_tlv),
+};
+
+static const struct snd_kcontrol_new rt5663_specific_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_STO_DRE_9,
+		RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_SHIFT, 23, 1,
+		rt5663_hp_vol_tlv),
+	/* Mic Boost Volume*/
+	SOC_SINGLE_TLV("IN1 Capture Volume", RT5663_CBJ_2,
+		RT5663_GAIN_BST1_SHIFT, 8, 0, in_bst_tlv),
+	/* Data Swap for Slot0/1 in ADCDAT1 */
+	SOC_ENUM("IF1 ADC Data Swap", rt5663_if1_adc_enum),
+};
+
+static int rt5663_is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
+	struct snd_soc_dapm_widget *sink)
+{
+	unsigned int val;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	val = snd_soc_read(codec, RT5663_GLB_CLK);
+	val &= RT5663_SCLK_SRC_MASK;
+	if (val == RT5663_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int rt5663_is_using_asrc(struct snd_soc_dapm_widget *w,
+	struct snd_soc_dapm_widget *sink)
+{
+	unsigned int reg, shift, val;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	if (rt5663->codec_type == CODEC_TYPE_RT5668) {
+		switch (w->shift) {
+		case RT5668_ADC_STO1_ASRC_SHIFT:
+			reg = RT5668_ASRC_3;
+			shift = RT5668_AD_STO1_TRACK_SHIFT;
+			break;
+		case RT5668_DAC_STO1_ASRC_SHIFT:
+			reg = RT5663_ASRC_2;
+			shift = RT5668_DA_STO1_TRACK_SHIFT;
+			break;
+		default:
+			return 0;
+		}
+	} else {
+		switch (w->shift) {
+		case RT5663_ADC_STO1_ASRC_SHIFT:
+			reg = RT5663_ASRC_2;
+			shift = RT5663_AD_STO1_TRACK_SHIFT;
+			break;
+		case RT5663_DAC_STO1_ASRC_SHIFT:
+			reg = RT5663_ASRC_2;
+			shift = RT5663_DA_STO1_TRACK_SHIFT;
+			break;
+		default:
+			return 0;
+		}
+	}
+
+	val = (snd_soc_read(codec, reg) >> shift) & 0x7;
+
+	if (val)
+		return 1;
+
+	return 0;
+}
+
+static int rt5663_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(source->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	int da_asrc_en, ad_asrc_en;
+
+	da_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) &
+		RT5663_DA_STO1_TRACK_MASK) ? 1 : 0;
+	switch (rt5663->codec_type) {
+	case CODEC_TYPE_RT5668:
+		ad_asrc_en = (snd_soc_read(codec, RT5668_ASRC_3) &
+			RT5668_AD_STO1_TRACK_MASK) ? 1 : 0;
+		break;
+	case CODEC_TYPE_RT5663:
+		ad_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) &
+			RT5663_AD_STO1_TRACK_MASK) ? 1 : 0;
+		break;
+	default:
+		dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+		return 1;
+	}
+
+	if (da_asrc_en || ad_asrc_en)
+		if (rt5663->sysclk > rt5663->lrck * 384)
+			return 1;
+
+	dev_err(codec->dev, "sysclk < 384 x fs, disable i2s asrc\n");
+
+	return 0;
+}
+
+/**
+ * rt5663_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @codec: SoC audio codec device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5668 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec,
+		unsigned int filter_mask, unsigned int clk_src)
+{
+	struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec);
+	unsigned int asrc2_mask = 0;
+	unsigned int asrc2_value = 0;
+	unsigned int asrc3_mask = 0;
+	unsigned int asrc3_value = 0;
+
+	switch (clk_src) {
+	case RT5663_CLK_SEL_SYS:
+	case RT5663_CLK_SEL_I2S1_ASRC:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (filter_mask & RT5663_DA_STEREO_FILTER) {
+		asrc2_mask |= RT5668_DA_STO1_TRACK_MASK;
+		asrc2_value |= clk_src << RT5668_DA_STO1_TRACK_SHIFT;
+	}
+
+	if (filter_mask & RT5663_AD_STEREO_FILTER) {
+		switch (rt5668->codec_type) {
+		case CODEC_TYPE_RT5668:
+			asrc3_mask |= RT5668_AD_STO1_TRACK_MASK;
+			asrc3_value |= clk_src << RT5668_AD_STO1_TRACK_SHIFT;
+			break;
+		case CODEC_TYPE_RT5663:
+			asrc2_mask |= RT5663_AD_STO1_TRACK_MASK;
+			asrc2_value |= clk_src << RT5663_AD_STO1_TRACK_SHIFT;
+			break;
+		default:
+			dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+		}
+	}
+
+	if (asrc2_mask)
+		snd_soc_update_bits(codec, RT5663_ASRC_2, asrc2_mask,
+			asrc2_value);
+
+	if (asrc3_mask)
+		snd_soc_update_bits(codec, RT5668_ASRC_3, asrc3_mask,
+			asrc3_value);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5663_sel_asrc_clk_src);
+
+/* Analog Mixer */
+static const struct snd_kcontrol_new rt5668_recmix1l[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1L,
+		RT5668_RECMIX1L_BST2_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 CBJ Switch", RT5668_RECMIX1L,
+		RT5668_RECMIX1L_BST1_CBJ_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_recmix1r[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1R,
+		RT5668_RECMIX1R_BST2_SHIFT, 1, 1),
+};
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5663_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_L1_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_L2_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_R1_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_R2_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_adda_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC L Switch", RT5663_AD_DA_MIXER,
+			RT5668_M_ADCMIX_L_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L Switch", RT5663_AD_DA_MIXER,
+			RT5668_M_DAC1_L_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_adda_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC R Switch", RT5663_AD_DA_MIXER,
+			RT5668_M_ADCMIX_R_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R Switch", RT5663_AD_DA_MIXER,
+			RT5668_M_DAC1_R_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_sto1_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER,
+			RT5668_M_DAC_L1_STO_L_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER,
+			RT5668_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,
+			RT5668_M_DAC_L1_STO_R_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER,
+			RT5668_M_DAC_R1_STO_R_SHIFT, 1, 1),
+};
+
+/* Out Switch */
+static const struct snd_kcontrol_new rt5668_hpo_switch =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5668_HP_AMP_2,
+		RT5668_EN_DAC_HPO_SHIFT, 1, 0);
+
+/* Stereo ADC source */
+static const char * const rt5668_sto1_adc_src[] = {
+	"ADC L", "ADC R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcl_enum, RT5663_STO1_ADC_MIXER,
+	RT5668_STO1_ADC_L_SRC_SHIFT, rt5668_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adcl_mux =
+	SOC_DAPM_ENUM("STO1 ADC L Mux", rt5668_sto1_adcl_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcr_enum, RT5663_STO1_ADC_MIXER,
+	RT5668_STO1_ADC_R_SRC_SHIFT, rt5668_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adcr_mux =
+	SOC_DAPM_ENUM("STO1 ADC R Mux", rt5668_sto1_adcr_enum);
+
+/* RT5663: Analog DACL1 input source */
+static const char * const rt5663_alg_dacl_src[] = {
+	"DAC L", "STO DAC MIXL"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5663_alg_dacl_enum, RT5663_BYPASS_STO_DAC,
+	RT5663_DACL1_SRC_SHIFT, rt5663_alg_dacl_src);
+
+static const struct snd_kcontrol_new rt5663_alg_dacl_mux =
+	SOC_DAPM_ENUM("DAC L Mux", rt5663_alg_dacl_enum);
+
+/* RT5663: Analog DACR1 input source */
+static const char * const rt5663_alg_dacr_src[] = {
+	"DAC R", "STO DAC MIXR"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5663_alg_dacr_enum, RT5663_BYPASS_STO_DAC,
+	RT5663_DACR1_SRC_SHIFT, rt5663_alg_dacr_src);
+
+static const struct snd_kcontrol_new rt5663_alg_dacr_mux =
+	SOC_DAPM_ENUM("DAC R Mux", rt5663_alg_dacr_enum);
+
+static int rt5663_hp_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_POST_PMU:
+		if (rt5663->codec_type == CODEC_TYPE_RT5668) {
+			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+				RT5668_SEL_PM_HP_SHIFT, RT5668_SEL_PM_HP_HIGH);
+			snd_soc_update_bits(codec, RT5663_HP_LOGIC_2,
+				RT5668_HP_SIG_SRC1_MASK,
+				RT5668_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,
+				RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_DIS);
+			snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371);
+			snd_soc_write(codec, RT5663_HP_BIAS, 0xabba);
+			snd_soc_write(codec, RT5663_CHARGE_PUMP_1, 0x2224);
+			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_DEPOP_1, 0x3000,
+				0x3000);
+		}
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		if (rt5663->codec_type == CODEC_TYPE_RT5668) {
+			snd_soc_update_bits(codec, RT5663_HP_LOGIC_2,
+				RT5668_HP_SIG_SRC1_MASK,
+				RT5668_HP_SIG_SRC1_REG);
+		} else {
+			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x0);
+			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+				RT5668_OVCD_HP_MASK, RT5668_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 rt5668_bst2_power(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+			RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK,
+			RT5668_PWR_BST2 | RT5668_PWR_BST2_OP);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+			RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5663_pre_div_power(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0xff00);
+		snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0xfffc);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0x0000);
+		snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0x0000);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("PLL", RT5663_PWR_ANLG_3, RT5668_PWR_PLL_SHIFT, 0,
+		NULL, 0),
+
+	/* micbias */
+	SND_SOC_DAPM_MICBIAS("MICBIAS1", RT5663_PWR_ANLG_2,
+		RT5668_PWR_MB1_SHIFT, 0),
+	SND_SOC_DAPM_MICBIAS("MICBIAS2", RT5663_PWR_ANLG_2,
+		RT5668_PWR_MB2_SHIFT, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+
+	/* REC Mixer Power */
+	SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5663_PWR_ANLG_2,
+		RT5668_PWR_RECMIX1_SHIFT, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SUPPLY("ADC L Power", RT5663_PWR_DIG_1,
+		RT5668_PWR_ADC_L1_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Clock", RT5663_CHOP_ADC,
+		RT5668_CKGEN_ADCC_SHIFT, 0, NULL, 0),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_MIXER("STO1 ADC MIXL", SND_SOC_NOPM,
+		0, 0, rt5663_sto1_adc_l_mix,
+		ARRAY_SIZE(rt5663_sto1_adc_l_mix)),
+
+	/* ADC Filter Power */
+	SND_SOC_DAPM_SUPPLY("STO1 ADC Filter", RT5663_PWR_DIG_2,
+		RT5668_PWR_ADC_S1F_SHIFT, 0, NULL, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S", RT5663_PWR_DIG_1, RT5668_PWR_I2S1_SHIFT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("IF DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIFTX", "AIF Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("ADDA MIXL", SND_SOC_NOPM, 0, 0, rt5663_adda_l_mix,
+		ARRAY_SIZE(rt5663_adda_l_mix)),
+	SND_SOC_DAPM_MIXER("ADDA MIXR", SND_SOC_NOPM, 0, 0, rt5663_adda_r_mix,
+		ARRAY_SIZE(rt5663_adda_r_mix)),
+	SND_SOC_DAPM_PGA("DAC L1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC R1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("STO1 DAC Filter", RT5663_PWR_DIG_2,
+		RT5668_PWR_DAC_S1F_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("STO1 DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5663_sto1_dac_l_mix, ARRAY_SIZE(rt5663_sto1_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("STO1 DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5663_sto1_dac_r_mix, ARRAY_SIZE(rt5663_sto1_dac_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_SUPPLY("STO1 DAC L Power", RT5663_PWR_DIG_1,
+		RT5668_PWR_DAC_L1_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("STO1 DAC R Power", RT5663_PWR_DIG_1,
+		RT5668_PWR_DAC_R1_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC R", NULL, SND_SOC_NOPM, 0, 0),
+
+	/* Headphone*/
+	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),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_widget rt5668_specific_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5663_PWR_ANLG_3,
+		RT5668_PWR_LDO2_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5668_PWR_VOL,
+		RT5668_PWR_MIC_DET_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO DAC", RT5663_PWR_DIG_1,
+		RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1,
+		RT5668_I2S1_ASRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1,
+		RT5668_DAC_STO1_ASRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1,
+		RT5668_ADC_STO1_ASRC_SHIFT, 0, NULL, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CBJ Power", RT5663_PWR_ANLG_3,
+		RT5668_PWR_CBJ_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST2 Power", SND_SOC_NOPM, 0, 0,
+		rt5668_bst2_power, SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5668_recmix1l,
+		ARRAY_SIZE(rt5668_recmix1l)),
+	SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5668_recmix1r,
+		ARRAY_SIZE(rt5668_recmix1r)),
+	SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5663_PWR_ANLG_2,
+		RT5668_PWR_RECMIX2_SHIFT, 0, NULL, 0),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SUPPLY("ADC R Power", RT5663_PWR_DIG_1,
+		RT5668_PWR_ADC_R1_SHIFT, 0, NULL, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_PGA("STO1 ADC L1", RT5663_STO1_ADC_MIXER,
+		RT5668_STO1_ADC_L1_SRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("STO1 ADC R1", RT5663_STO1_ADC_MIXER,
+		RT5668_STO1_ADC_R1_SRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("STO1 ADC L2", RT5663_STO1_ADC_MIXER,
+		RT5668_STO1_ADC_L2_SRC_SHIFT, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("STO1 ADC R2", RT5663_STO1_ADC_MIXER,
+		RT5668_STO1_ADC_R2_SRC_SHIFT, 1, NULL, 0),
+
+	SND_SOC_DAPM_MUX("STO1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adcl_mux),
+	SND_SOC_DAPM_MUX("STO1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adcr_mux),
+
+	/* ADC Mix */
+	SND_SOC_DAPM_MIXER("STO1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5668_sto1_adc_r_mix, ARRAY_SIZE(rt5668_sto1_adc_r_mix)),
+
+	/* Analog DAC Clock */
+	SND_SOC_DAPM_SUPPLY("DAC Clock", RT5663_CHOP_DAC_L,
+		RT5668_CKGEN_DAC1_SHIFT, 0, NULL, 0),
+
+	/* Headphone out */
+	SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0,
+		&rt5668_hpo_switch),
+};
+
+static const struct snd_soc_dapm_widget rt5663_specific_dapm_widgets[] = {
+	/* System Clock Pre Divider Gating */
+	SND_SOC_DAPM_SUPPLY("Pre Div Power", SND_SOC_NOPM, 0, 0,
+		rt5663_pre_div_power, SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+
+	/* LDO */
+	SND_SOC_DAPM_SUPPLY("LDO ADC", RT5663_PWR_DIG_1,
+		RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1,
+		RT5663_I2S1_ASRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1,
+		RT5663_DAC_STO1_ASRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1,
+		RT5663_ADC_STO1_ASRC_SHIFT, 0, NULL, 0),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* STO ADC */
+	SND_SOC_DAPM_PGA("STO1 ADC L1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("STO1 ADC L2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Analog DAC source */
+	SND_SOC_DAPM_MUX("DAC L Mux", SND_SOC_NOPM, 0, 0, &rt5663_alg_dacl_mux),
+	SND_SOC_DAPM_MUX("DAC R Mux", SND_SOC_NOPM, 0, 0, &rt5663_alg_dacr_mux),
+};
+
+static const struct snd_soc_dapm_route rt5663_dapm_routes[] = {
+	/* PLL */
+	{ "I2S", NULL, "PLL", rt5663_is_sys_clk_from_pll },
+
+	/* ASRC */
+	{ "STO1 ADC Filter", NULL, "ADC ASRC", rt5663_is_using_asrc },
+	{ "STO1 DAC Filter", NULL, "DAC ASRC", rt5663_is_using_asrc },
+	{ "I2S", NULL, "I2S ASRC", rt5663_i2s_use_asrc },
+
+	{ "ADC L", NULL, "ADC L Power" },
+	{ "ADC L", NULL, "ADC Clock" },
+
+	{ "STO1 ADC L2", NULL, "STO1 DAC MIXL" },
+
+	{ "STO1 ADC MIXL", "ADC1 Switch", "STO1 ADC L1" },
+	{ "STO1 ADC MIXL", "ADC2 Switch", "STO1 ADC L2" },
+	{ "STO1 ADC MIXL", NULL, "STO1 ADC Filter" },
+
+	{ "IF1 ADC1", NULL, "STO1 ADC MIXL" },
+	{ "IF ADC", NULL, "IF1 ADC1" },
+	{ "AIFTX", NULL, "IF ADC" },
+	{ "AIFTX", NULL, "I2S" },
+
+	{ "AIFRX", NULL, "I2S" },
+	{ "IF DAC", NULL, "AIFRX" },
+	{ "IF1 DAC1 L", NULL, "IF DAC" },
+	{ "IF1 DAC1 R", NULL, "IF DAC" },
+
+	{ "ADDA MIXL", "ADC L Switch", "STO1 ADC MIXL" },
+	{ "ADDA MIXL", "DAC L Switch", "IF1 DAC1 L" },
+	{ "ADDA MIXL", NULL, "STO1 DAC Filter" },
+	{ "ADDA MIXL", NULL, "STO1 DAC L Power" },
+	{ "ADDA MIXR", "DAC R Switch", "IF1 DAC1 R" },
+	{ "ADDA MIXR", NULL, "STO1 DAC Filter" },
+	{ "ADDA MIXR", NULL, "STO1 DAC R Power" },
+
+	{ "DAC L1", NULL, "ADDA MIXL" },
+	{ "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, "DAC L" },
+	{ "HP Amp", NULL, "DAC R" },
+};
+
+static const struct snd_soc_dapm_route rt5668_specific_dapm_routes[] = {
+	{ "MICBIAS1", NULL, "LDO2" },
+	{ "MICBIAS2", NULL, "LDO2" },
+
+	{ "BST1 CBJ", NULL, "IN1P" },
+	{ "BST1 CBJ", NULL, "IN1N" },
+	{ "BST1 CBJ", NULL, "CBJ Power" },
+
+	{ "BST2", NULL, "IN2P" },
+	{ "BST2", NULL, "IN2N" },
+	{ "BST2", NULL, "BST2 Power" },
+
+	{ "RECMIX1L", "BST2 Switch", "BST2" },
+	{ "RECMIX1L", "BST1 CBJ Switch", "BST1 CBJ" },
+	{ "RECMIX1L", NULL, "RECMIX1L Power" },
+	{ "RECMIX1R", "BST2 Switch", "BST2" },
+	{ "RECMIX1R", NULL, "RECMIX1R Power" },
+
+	{ "ADC L", NULL, "RECMIX1L" },
+	{ "ADC R", NULL, "RECMIX1R" },
+	{ "ADC R", NULL, "ADC R Power" },
+	{ "ADC R", NULL, "ADC Clock" },
+
+	{ "STO1 ADC L Mux", "ADC L", "ADC L" },
+	{ "STO1 ADC L Mux", "ADC R", "ADC R" },
+	{ "STO1 ADC L1", NULL, "STO1 ADC L Mux" },
+
+	{ "STO1 ADC R Mux", "ADC L", "ADC L" },
+	{ "STO1 ADC R Mux", "ADC R", "ADC R" },
+	{ "STO1 ADC R1", NULL, "STO1 ADC R Mux" },
+	{ "STO1 ADC R2", NULL, "STO1 DAC MIXR" },
+
+	{ "STO1 ADC MIXR", "ADC1 Switch", "STO1 ADC R1" },
+	{ "STO1 ADC MIXR", "ADC2 Switch", "STO1 ADC R2" },
+	{ "STO1 ADC MIXR", NULL, "STO1 ADC Filter" },
+
+	{ "IF1 ADC1", NULL, "STO1 ADC MIXR" },
+
+	{ "ADDA MIXR", "ADC R Switch", "STO1 ADC MIXR" },
+
+	{ "DAC L", NULL, "STO1 DAC MIXL" },
+	{ "DAC L", NULL, "LDO DAC" },
+	{ "DAC L", NULL, "DAC Clock" },
+	{ "DAC R", NULL, "STO1 DAC MIXR" },
+	{ "DAC R", NULL, "LDO DAC" },
+	{ "DAC R", NULL, "DAC Clock" },
+
+	{ "HPO Playback", "Switch", "HP Amp" },
+	{ "HPOL", NULL, "HPO Playback" },
+	{ "HPOR", NULL, "HPO Playback" },
+};
+
+static const struct snd_soc_dapm_route rt5663_specific_dapm_routes[] = {
+	{ "I2S", NULL, "Pre Div Power" },
+
+	{ "BST1", NULL, "IN1P" },
+	{ "BST1", NULL, "IN1N" },
+	{ "BST1", NULL, "RECMIX1L Power" },
+
+	{ "ADC L", NULL, "BST1" },
+
+	{ "STO1 ADC L1", NULL, "ADC L" },
+
+	{ "DAC L Mux", "DAC L",  "DAC L1" },
+	{ "DAC L Mux", "STO DAC MIXL", "STO1 DAC MIXL" },
+	{ "DAC R Mux", "DAC R",  "DAC R1"},
+	{ "DAC R Mux", "STO DAC MIXR", "STO1 DAC MIXR" },
+
+	{ "DAC L", NULL, "DAC L Mux" },
+	{ "DAC R", NULL, "DAC R Mux" },
+
+	{ "HPOL", NULL, "HP Amp" },
+	{ "HPOR", NULL, "HP Amp" },
+};
+
+static int rt5663_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 rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val_len = 0;
+	int pre_div;
+
+	rt5663->lrck = params_rate(params);
+
+	dev_dbg(dai->dev, "bclk is %dHz and sysclk is %dHz\n",
+		rt5663->lrck, rt5663->sysclk);
+
+	pre_div = rl6231_get_clk_info(rt5663->sysclk, rt5663->lrck);
+	if (pre_div < 0) {
+		dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+			rt5663->lrck, dai->id);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "pre_div is %d for iis %d\n", pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 8:
+		val_len = RT5668_I2S_DL_8;
+		break;
+	case 16:
+		val_len = RT5668_I2S_DL_16;
+		break;
+	case 20:
+		val_len = RT5668_I2S_DL_20;
+		break;
+	case 24:
+		val_len = RT5668_I2S_DL_24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, RT5663_I2S1_SDP,
+		RT5668_I2S_DL_MASK, val_len);
+
+	snd_soc_update_bits(codec, RT5663_ADDA_CLK_1,
+		RT5668_I2S_PD1_MASK, pre_div << RT5668_I2S_PD1_SHIFT);
+
+	return 0;
+}
+
+static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5668_I2S_MS_S;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5668_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5668_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5668_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5668_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, RT5663_I2S1_SDP, RT5668_I2S_MS_MASK |
+		RT5668_I2S_BP_MASK | RT5668_I2S_DF_MASK, reg_val);
+
+	return 0;
+}
+
+static int rt5663_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+	unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	unsigned int reg_val = 0;
+
+	if (freq == rt5663->sysclk && clk_id == rt5663->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5663_SCLK_S_MCLK:
+		reg_val |= RT5663_SCLK_SRC_MCLK;
+		break;
+	case RT5663_SCLK_S_PLL1:
+		reg_val |= RT5663_SCLK_SRC_PLL1;
+		break;
+	case RT5663_SCLK_S_RCCLK:
+		reg_val |= RT5663_SCLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5668_SCLK_SRC_MASK,
+		reg_val);
+	rt5663->sysclk = freq;
+	rt5663->sysclk_src = clk_id;
+
+	dev_dbg(codec->dev, "Sysclk is %dHz and clock id is %d\n",
+		freq, clk_id);
+
+	return 0;
+}
+
+static int rt5663_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 rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct rl6231_pll_code pll_code;
+	int ret;
+	int mask, shift, val;
+
+	if (source == rt5663->pll_src && freq_in == rt5663->pll_in &&
+	    freq_out == rt5663->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(codec->dev, "PLL disabled\n");
+
+		rt5663->pll_in = 0;
+		rt5663->pll_out = 0;
+		snd_soc_update_bits(codec, RT5663_GLB_CLK,
+			RT5663_SCLK_SRC_MASK, RT5663_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (rt5663->codec_type) {
+	case CODEC_TYPE_RT5668:
+		mask = RT5668_PLL1_SRC_MASK;
+		shift = RT5668_PLL1_SRC_SHIFT;
+		break;
+	case CODEC_TYPE_RT5663:
+		mask = RT5663_PLL1_SRC_MASK;
+		shift = RT5663_PLL1_SRC_SHIFT;
+		break;
+	default:
+		dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+		return -EINVAL;
+	}
+
+	switch (source) {
+	case RT5663_PLL1_S_MCLK:
+		val = 0x0;
+		break;
+	case RT5663_PLL1_S_BCLK1:
+		val = 0x1;
+		break;
+	default:
+		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+	snd_soc_update_bits(codec, RT5663_GLB_CLK, mask, (val << shift));
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", pll_code.m_bp,
+		(pll_code.m_bp ? 0 : pll_code.m_code), pll_code.n_code,
+		pll_code.k_code);
+
+	snd_soc_write(codec, RT5663_PLL_1,
+		pll_code.n_code << RT5668_PLL_N_SHIFT | pll_code.k_code);
+	snd_soc_write(codec, RT5663_PLL_2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SHIFT |
+		pll_code.m_bp << RT5668_PLL_M_BP_SHIFT);
+
+	rt5663->pll_in = freq_in;
+	rt5663->pll_out = freq_out;
+	rt5663->pll_src = source;
+
+	return 0;
+}
+
+static int rt5663_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;
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val = 0, reg;
+
+	if (rx_mask || tx_mask)
+		val |= RT5668_TDM_MODE_TDM;
+
+	switch (slots) {
+	case 4:
+		val |= RT5668_TDM_IN_CH_4;
+		val |= RT5668_TDM_OUT_CH_4;
+		break;
+	case 6:
+		val |= RT5668_TDM_IN_CH_6;
+		val |= RT5668_TDM_OUT_CH_6;
+		break;
+	case 8:
+		val |= RT5668_TDM_IN_CH_8;
+		val |= RT5668_TDM_OUT_CH_8;
+		break;
+	case 2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (slot_width) {
+	case 20:
+		val |= RT5668_TDM_IN_LEN_20;
+		val |= RT5668_TDM_OUT_LEN_20;
+		break;
+	case 24:
+		val |= RT5668_TDM_IN_LEN_24;
+		val |= RT5668_TDM_OUT_LEN_24;
+		break;
+	case 32:
+		val |= RT5668_TDM_IN_LEN_32;
+		val |= RT5668_TDM_OUT_LEN_32;
+		break;
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (rt5663->codec_type) {
+	case CODEC_TYPE_RT5668:
+		reg = RT5663_TDM_2;
+		break;
+	case CODEC_TYPE_RT5663:
+		reg = RT5663_TDM_1;
+		break;
+	default:
+		dev_err(codec->dev, "Unknown CODEC_TYPE\n");
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, reg, RT5668_TDM_MODE_MASK |
+		RT5668_TDM_IN_CH_MASK | RT5668_TDM_OUT_CH_MASK |
+		RT5668_TDM_IN_LEN_MASK | RT5668_TDM_OUT_LEN_MASK, val);
+
+	return 0;
+}
+
+static int rt5663_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	unsigned int reg;
+
+	dev_dbg(codec->dev, "%s ratio = %d\n", __func__, ratio);
+
+	if (rt5663->codec_type == CODEC_TYPE_RT5668)
+		reg = RT5668_TDM_8;
+	else
+		reg = RT5663_TDM_5;
+
+	switch (ratio) {
+	case 32:
+		snd_soc_update_bits(codec, reg,
+			RT5663_TDM_LENGTN_MASK,
+			RT5663_TDM_LENGTN_16);
+		break;
+	case 40:
+		snd_soc_update_bits(codec, reg,
+			RT5663_TDM_LENGTN_MASK,
+			RT5663_TDM_LENGTN_20);
+		break;
+	case 48:
+		snd_soc_update_bits(codec, reg,
+			RT5663_TDM_LENGTN_MASK,
+			RT5663_TDM_LENGTN_24);
+		break;
+	case 64:
+		snd_soc_update_bits(codec, reg,
+			RT5663_TDM_LENGTN_MASK,
+			RT5663_TDM_LENGTN_32);
+		break;
+	default:
+		dev_err(codec->dev, "Invalid ratio!\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5663_set_bias_level(struct snd_soc_codec *codec,
+			enum snd_soc_bias_level level)
+{
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+			RT5668_PWR_FV1_MASK | RT5668_PWR_FV2_MASK,
+			RT5668_PWR_FV1 | RT5668_PWR_FV2);
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		if (rt5663->codec_type == CODEC_TYPE_RT5668) {
+			snd_soc_update_bits(codec, RT5663_DIG_MISC,
+				RT5668_DIG_GATE_CTRL_MASK,
+				RT5668_DIG_GATE_CTRL_EN);
+			snd_soc_update_bits(codec, RT5663_SIG_CLK_DET,
+				RT5668_EN_ANA_CLK_DET_MASK |
+				RT5668_PWR_CLK_DET_MASK,
+				RT5668_EN_ANA_CLK_DET_AUTO |
+				RT5668_PWR_CLK_DET_EN);
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (rt5663->codec_type == CODEC_TYPE_RT5668)
+			snd_soc_update_bits(codec, RT5663_DIG_MISC,
+				RT5668_DIG_GATE_CTRL_MASK,
+				RT5668_DIG_GATE_CTRL_DIS);
+		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+			RT5668_PWR_VREF1_MASK | RT5668_PWR_VREF2_MASK |
+			RT5668_PWR_FV1_MASK | RT5668_PWR_FV2_MASK |
+			RT5668_PWR_MB_MASK, RT5668_PWR_VREF1 |
+			RT5668_PWR_VREF2 | RT5668_PWR_MB);
+		usleep_range(10000, 10005);
+		if (rt5663->codec_type == CODEC_TYPE_RT5668) {
+			snd_soc_update_bits(codec, RT5663_SIG_CLK_DET,
+				RT5668_EN_ANA_CLK_DET_MASK |
+				RT5668_PWR_CLK_DET_MASK,
+				RT5668_EN_ANA_CLK_DET_DIS |
+				RT5668_PWR_CLK_DET_DIS);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+			RT5668_PWR_VREF1_MASK | RT5668_PWR_VREF2_MASK |
+			RT5668_PWR_FV1 | RT5668_PWR_FV2, 0x0);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5663_probe(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	rt5663->codec = codec;
+
+	switch (rt5663->codec_type) {
+	case CODEC_TYPE_RT5668:
+		snd_soc_dapm_new_controls(dapm,
+			rt5668_specific_dapm_widgets,
+			ARRAY_SIZE(rt5668_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm,
+			rt5668_specific_dapm_routes,
+			ARRAY_SIZE(rt5668_specific_dapm_routes));
+		snd_soc_add_codec_controls(codec, rt5668_specific_controls,
+			ARRAY_SIZE(rt5668_specific_controls));
+		break;
+	case CODEC_TYPE_RT5663:
+		snd_soc_dapm_new_controls(dapm,
+			rt5663_specific_dapm_widgets,
+			ARRAY_SIZE(rt5663_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm,
+			rt5663_specific_dapm_routes,
+			ARRAY_SIZE(rt5663_specific_dapm_routes));
+		snd_soc_add_codec_controls(codec, rt5663_specific_controls,
+			ARRAY_SIZE(rt5663_specific_controls));
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5663_remove(struct snd_soc_codec *codec)
+{
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	regmap_write(rt5663->regmap, RT5663_RESET, 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5663_suspend(struct snd_soc_codec *codec)
+{
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	regcache_cache_only(rt5663->regmap, true);
+	regcache_mark_dirty(rt5663->regmap);
+
+	return 0;
+}
+
+static int rt5663_resume(struct snd_soc_codec *codec)
+{
+	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+	regcache_cache_only(rt5663->regmap, false);
+	regcache_sync(rt5663->regmap);
+
+	return 0;
+}
+#else
+#define rt5663_suspend NULL
+#define rt5663_resume NULL
+#endif
+
+#define RT5663_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#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 = {
+	.hw_params = rt5663_hw_params,
+	.set_fmt = rt5663_set_dai_fmt,
+	.set_sysclk = rt5663_set_dai_sysclk,
+	.set_pll = rt5663_set_dai_pll,
+	.set_tdm_slot = rt5663_set_tdm_slot,
+	.set_bclk_ratio = rt5663_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5663_dai[] = {
+	{
+		.name = "rt5663-aif",
+		.id = RT5663_AIF,
+		.playback = {
+			.stream_name = "AIF Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5663_STEREO_RATES,
+			.formats = RT5663_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5663_STEREO_RATES,
+			.formats = RT5663_FORMATS,
+		},
+		.ops = &rt5663_aif_dai_ops,
+	},
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5663 = {
+	.probe = rt5663_probe,
+	.remove = rt5663_remove,
+	.suspend = rt5663_suspend,
+	.resume = rt5663_resume,
+	.set_bias_level = rt5663_set_bias_level,
+	.idle_bias_off = true,
+	.component_driver = {
+		.controls = rt5663_snd_controls,
+		.num_controls = ARRAY_SIZE(rt5663_snd_controls),
+		.dapm_widgets = rt5663_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(rt5663_dapm_widgets),
+		.dapm_routes = rt5663_dapm_routes,
+		.num_dapm_routes = ARRAY_SIZE(rt5663_dapm_routes),
+	}
+};
+
+static const struct regmap_config rt5668_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = 0x07fa,
+	.volatile_reg = rt5668_volatile_register,
+	.readable_reg = rt5668_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5668_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5668_reg),
+};
+
+static const struct regmap_config rt5663_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = 0x03f3,
+	.volatile_reg = rt5663_volatile_register,
+	.readable_reg = rt5663_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5663_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5663_reg),
+};
+
+static const struct regmap_config temp_regmap = {
+	.name = "nocache",
+	.reg_bits = 16,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = 0x03f3,
+	.cache_type = REGCACHE_NONE,
+};
+
+static const struct i2c_device_id rt5663_i2c_id[] = {
+	{ "rt5668", 0 },
+	{ "rt5663", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, rt5663_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5663_of_match[] = {
+	{ .compatible = "realtek,rt5668", },
+	{ .compatible = "realtek,rt5663", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5663_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static struct acpi_device_id rt5663_acpi_match[] = {
+	{ "10EC5668", 0},
+	{ "10EC5663", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt5663_acpi_match);
+#endif
+
+static void rt5668_calibrate(struct rt5663_priv *rt5668)
+{
+	regmap_write(rt5668->regmap, RT5663_BIAS_CUR_8, 0xa402);
+	regmap_write(rt5668->regmap, RT5663_PWR_DIG_1, 0x0100);
+	regmap_write(rt5668->regmap, RT5663_RECMIX, 0x4040);
+	regmap_write(rt5668->regmap, RT5663_DIG_MISC, 0x0001);
+	regmap_write(rt5668->regmap, RT5663_RC_CLK, 0x0380);
+	regmap_write(rt5668->regmap, RT5663_GLB_CLK, 0x8000);
+	regmap_write(rt5668->regmap, RT5663_ADDA_CLK_1, 0x1000);
+	regmap_write(rt5668->regmap, RT5663_CHOP_DAC_L, 0x3030);
+	regmap_write(rt5668->regmap, RT5663_CALIB_ADC, 0x3c05);
+	regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xa23e);
+	msleep(40);
+	regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xf23e);
+	regmap_write(rt5668->regmap, RT5663_HP_CALIB_2, 0x0321);
+	regmap_write(rt5668->regmap, RT5663_HP_CALIB_1, 0xfc00);
+	msleep(500);
+}
+
+static void rt5663_calibrate(struct rt5663_priv *rt5668)
+{
+	int value, count;
+
+	regmap_write(rt5668->regmap, RT5663_RC_CLK, 0x0280);
+	regmap_write(rt5668->regmap, RT5663_GLB_CLK, 0x8000);
+	regmap_write(rt5668->regmap, RT5663_DIG_MISC, 0x8001);
+	regmap_write(rt5668->regmap, RT5663_VREF_RECMIX, 0x0032);
+	regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xa2be);
+	msleep(20);
+	regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xf2be);
+	regmap_write(rt5668->regmap, RT5663_PWR_DIG_2, 0x8400);
+	regmap_write(rt5668->regmap, RT5663_CHOP_ADC, 0x3000);
+	regmap_write(rt5668->regmap, RT5663_DEPOP_1, 0x003b);
+	regmap_write(rt5668->regmap, RT5663_PWR_DIG_1, 0x8df8);
+	regmap_write(rt5668->regmap, RT5663_PWR_ANLG_2, 0x0003);
+	regmap_write(rt5668->regmap, RT5663_PWR_ANLG_3, 0x018c);
+	regmap_write(rt5668->regmap, RT5663_ADDA_CLK_1, 0x1111);
+	regmap_write(rt5668->regmap, RT5663_PRE_DIV_GATING_1, 0xffff);
+	regmap_write(rt5668->regmap, RT5663_PRE_DIV_GATING_2, 0xffff);
+	regmap_write(rt5668->regmap, RT5663_DEPOP_2, 0x3003);
+	regmap_write(rt5668->regmap, RT5663_DEPOP_1, 0x003b);
+	regmap_write(rt5668->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32);
+	regmap_write(rt5668->regmap, RT5663_HP_CHARGE_PUMP_2, 0x1371);
+	regmap_write(rt5668->regmap, RT5663_DACREF_LDO, 0x3b0b);
+	regmap_write(rt5668->regmap, RT5663_STO_DAC_MIXER, 0x2080);
+	regmap_write(rt5668->regmap, RT5663_BYPASS_STO_DAC, 0x000c);
+	regmap_write(rt5668->regmap, RT5663_HP_BIAS, 0xabba);
+	regmap_write(rt5668->regmap, RT5663_CHARGE_PUMP_1, 0x2224);
+	regmap_write(rt5668->regmap, RT5663_HP_OUT_EN, 0x8088);
+	regmap_write(rt5668->regmap, RT5663_STO_DRE_9, 0x0017);
+	regmap_write(rt5668->regmap, RT5663_STO_DRE_10, 0x0017);
+	regmap_write(rt5668->regmap, RT5663_STO1_ADC_MIXER, 0x4040);
+	regmap_write(rt5668->regmap, RT5663_RECMIX, 0x0005);
+	regmap_write(rt5668->regmap, RT5663_ADDA_RST, 0xc000);
+	regmap_write(rt5668->regmap, RT5663_STO1_HPF_ADJ1, 0x3320);
+	regmap_write(rt5668->regmap, RT5663_HP_CALIB_2, 0x00c9);
+	regmap_write(rt5668->regmap, RT5663_DUMMY_1, 0x004c);
+	regmap_write(rt5668->regmap, RT5663_ANA_BIAS_CUR_1, 0x7766);
+	regmap_write(rt5668->regmap, RT5663_BIAS_CUR_8, 0x4702);
+	msleep(200);
+	regmap_write(rt5668->regmap, RT5663_HP_CALIB_1, 0x0069);
+	regmap_write(rt5668->regmap, RT5663_HP_CALIB_3, 0x06c2);
+	regmap_write(rt5668->regmap, RT5663_HP_CALIB_1_1, 0x7b00);
+	regmap_write(rt5668->regmap, RT5663_HP_CALIB_1_1, 0xfb00);
+	count = 0;
+	while (true) {
+		regmap_read(rt5668->regmap, RT5663_HP_CALIB_1_1, &value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 200)
+			return;
+		count++;
+	}
+}
+
+static int rt5663_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5663_priv *rt5663;
+	int ret;
+	unsigned int val;
+	struct regmap *regmap;
+
+	rt5663 = devm_kzalloc(&i2c->dev, sizeof(struct rt5663_priv),
+		GFP_KERNEL);
+
+	if (rt5663 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5663);
+
+	regmap = devm_regmap_init_i2c(i2c, &temp_regmap);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n",
+			ret);
+		return ret;
+	}
+	regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
+	switch (val) {
+	case RT5668_DEVICE_ID:
+		rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5668_regmap);
+		rt5663->codec_type = CODEC_TYPE_RT5668;
+		break;
+	case RT5663_DEVICE_ID:
+		rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_regmap);
+		rt5663->codec_type = CODEC_TYPE_RT5663;
+		break;
+	default:
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5663 or rt5668\n",
+			val);
+		return -ENODEV;
+	}
+
+	if (IS_ERR(rt5663->regmap)) {
+		ret = PTR_ERR(rt5663->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	/* reset and calibrate */
+	regmap_write(rt5663->regmap, RT5663_RESET, 0);
+	regcache_cache_bypass(rt5663->regmap, true);
+	switch (rt5663->codec_type) {
+	case CODEC_TYPE_RT5668:
+		rt5668_calibrate(rt5663);
+		break;
+	case CODEC_TYPE_RT5663:
+		rt5663_calibrate(rt5663);
+		break;
+	default:
+		dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__);
+	}
+	regcache_cache_bypass(rt5663->regmap, false);
+	regmap_write(rt5663->regmap, RT5663_RESET, 0);
+	dev_dbg(&i2c->dev, "calibrate done\n");
+
+	/* GPIO1 as IRQ */
+	regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5668_GP1_PIN_MASK,
+		RT5668_GP1_PIN_IRQ);
+	/* 4btn inline command debounce */
+	regmap_update_bits(rt5663->regmap, RT5663_IL_CMD_5,
+		RT5668_4BTN_CLK_DEB_MASK, RT5668_4BTN_CLK_DEB_65MS);
+
+	switch (rt5663->codec_type) {
+	case CODEC_TYPE_RT5668:
+		regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0xa402);
+		/* JD1 */
+		regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK,
+			RT5668_IRQ_POW_SAV_MASK | RT5668_IRQ_POW_SAV_JD1_MASK,
+			RT5668_IRQ_POW_SAV_EN | RT5668_IRQ_POW_SAV_JD1_EN);
+		regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_2,
+			RT5668_PWR_JD1_MASK, RT5668_PWR_JD1);
+		regmap_update_bits(rt5663->regmap, RT5663_IRQ_1,
+			RT5668_EN_CB_JD_MASK, RT5668_EN_CB_JD_EN);
+
+		regmap_update_bits(rt5663->regmap, RT5663_HP_LOGIC_2,
+			RT5668_HP_SIG_SRC1_MASK, RT5668_HP_SIG_SRC1_REG);
+		regmap_update_bits(rt5663->regmap, RT5663_RECMIX,
+			RT5668_VREF_BIAS_MASK | RT5668_CBJ_DET_MASK |
+			RT5668_DET_TYPE_MASK, RT5668_VREF_BIAS_REG |
+			RT5668_CBJ_DET_EN | RT5668_DET_TYPE_QFN);
+		/* Set GPIO4 and GPIO8 as input for combo jack */
+		regmap_update_bits(rt5663->regmap, RT5663_GPIO_2,
+			RT5668_GP4_PIN_CONF_MASK, RT5668_GP4_PIN_CONF_INPUT);
+		regmap_update_bits(rt5663->regmap, RT5668_GPIO_3,
+			RT5668_GP8_PIN_CONF_MASK, RT5668_GP8_PIN_CONF_INPUT);
+		regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_1,
+			RT5668_LDO1_DVO_MASK | RT5668_AMP_HP_MASK,
+			RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X);
+			break;
+	case CODEC_TYPE_RT5663:
+		regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032);
+		regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be);
+		msleep(20);
+		regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be);
+		regmap_update_bits(rt5663->regmap, RT5663_GPIO_2,
+			RT5663_GP1_PIN_CONF_MASK, RT5663_GP1_PIN_CONF_OUTPUT);
+		/* DACREF LDO control */
+		regmap_update_bits(rt5663->regmap, RT5663_DACREF_LDO, 0x3e0e,
+			0x3a0a);
+		regmap_update_bits(rt5663->regmap, RT5663_RECMIX,
+			RT5663_RECMIX1_BST1_MASK, RT5663_RECMIX1_BST1_ON);
+		regmap_update_bits(rt5663->regmap, RT5663_TDM_2,
+			RT5663_DATA_SWAP_ADCDAT1_MASK,
+			RT5663_DATA_SWAP_ADCDAT1_LL);
+			break;
+	default:
+		dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__);
+	}
+
+	INIT_DELAYED_WORK(&rt5663->jack_detect_work, rt5663_jack_detect_work);
+
+	if (i2c->irq) {
+		ret = request_irq(i2c->irq, rt5663_irq,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			| IRQF_ONESHOT, "rt5663", rt5663);
+		if (ret)
+			dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n",
+				__func__, ret);
+	}
+
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5663,
+			rt5663_dai, ARRAY_SIZE(rt5663_dai));
+
+	if (ret) {
+		if (i2c->irq)
+			free_irq(i2c->irq, rt5663);
+	}
+
+	return ret;
+}
+
+static int rt5663_i2c_remove(struct i2c_client *i2c)
+{
+	struct rt5663_priv *rt5663 = i2c_get_clientdata(i2c);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, rt5663);
+
+	snd_soc_unregister_codec(&i2c->dev);
+
+	return 0;
+}
+
+static void rt5663_i2c_shutdown(struct i2c_client *client)
+{
+	struct rt5663_priv *rt5663 = i2c_get_clientdata(client);
+
+	regmap_write(rt5663->regmap, RT5663_RESET, 0);
+}
+
+static struct i2c_driver rt5663_i2c_driver = {
+	.driver = {
+		.name = "rt5663",
+		.acpi_match_table = ACPI_PTR(rt5663_acpi_match),
+		.of_match_table = of_match_ptr(rt5663_of_match),
+	},
+	.probe = rt5663_i2c_probe,
+	.remove = rt5663_i2c_remove,
+	.shutdown = rt5663_i2c_shutdown,
+	.id_table = rt5663_i2c_id,
+};
+module_i2c_driver(rt5663_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5663 driver");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h
new file mode 100644
index 000000000000..2cc8f28080f6
--- /dev/null
+++ b/sound/soc/codecs/rt5663.h
@@ -0,0 +1,1121 @@
+/*
+ * rt5663.h  --  RT5663 ALSA SoC audio driver
+ *
+ * Copyright 2016 Realtek Microelectronics
+ * Author: Jack Yu <jack.yu@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 __RT5663_H__
+#define __RT5663_H__
+
+/* Info */
+#define RT5663_RESET				0x0000
+#define RT5663_VENDOR_ID			0x00fd
+#define RT5663_VENDOR_ID_1			0x00fe
+#define RT5663_VENDOR_ID_2			0x00ff
+
+#define RT5668_LOUT_CTRL			0x0001
+#define RT5668_HP_AMP_2				0x0003
+#define RT5668_MONO_OUT				0x0004
+#define RT5668_MONO_GAIN			0x0007
+
+#define RT5668_AEC_BST				0x000b
+#define RT5668_IN1_IN2				0x000c
+#define RT5668_IN3_IN4				0x000d
+#define RT5668_INL1_INR1			0x000f
+#define RT5668_CBJ_TYPE_2			0x0011
+#define RT5668_CBJ_TYPE_3			0x0012
+#define RT5668_CBJ_TYPE_4			0x0013
+#define RT5668_CBJ_TYPE_5			0x0014
+#define RT5668_CBJ_TYPE_8			0x0017
+
+/* I/O - ADC/DAC/DMIC */
+#define RT5668_DAC3_DIG_VOL			0x001a
+#define RT5668_DAC3_CTRL			0x001b
+#define RT5668_MONO_ADC_DIG_VOL			0x001d
+#define RT5668_STO2_ADC_DIG_VOL			0x001e
+#define RT5668_MONO_ADC_BST_GAIN		0x0020
+#define RT5668_STO2_ADC_BST_GAIN		0x0021
+#define RT5668_SIDETONE_CTRL			0x0024
+/* Mixer - D-D */
+#define RT5668_MONO1_ADC_MIXER			0x0027
+#define RT5668_STO2_ADC_MIXER			0x0028
+#define RT5668_MONO_DAC_MIXER			0x002b
+#define RT5668_DAC2_SRC_CTRL			0x002e
+#define RT5668_IF_3_4_DATA_CTL			0x002f
+#define RT5668_IF_5_DATA_CTL			0x0030
+#define RT5668_PDM_OUT_CTL			0x0031
+#define RT5668_PDM_I2C_DATA_CTL1		0x0032
+#define RT5668_PDM_I2C_DATA_CTL2		0x0033
+#define RT5668_PDM_I2C_DATA_CTL3		0x0034
+#define RT5668_PDM_I2C_DATA_CTL4		0x0035
+
+/*Mixer - Analog*/
+#define RT5668_RECMIX1_NEW			0x003a
+#define RT5668_RECMIX1L_0			0x003b
+#define RT5668_RECMIX1L				0x003c
+#define RT5668_RECMIX1R_0			0x003d
+#define RT5668_RECMIX1R				0x003e
+#define RT5668_RECMIX2_NEW			0x003f
+#define RT5668_RECMIX2_L_2			0x0041
+#define RT5668_RECMIX2_R			0x0042
+#define RT5668_RECMIX2_R_2			0x0043
+#define RT5668_CALIB_REC_LR			0x0044
+#define RT5668_ALC_BK_GAIN			0x0049
+#define RT5668_MONOMIX_GAIN			0x004a
+#define RT5668_MONOMIX_IN_GAIN			0x004b
+#define RT5668_OUT_MIXL_GAIN			0x004d
+#define RT5668_OUT_LMIX_IN_GAIN			0x004e
+#define RT5668_OUT_RMIX_IN_GAIN			0x004f
+#define RT5668_OUT_RMIX_IN_GAIN1		0x0050
+#define RT5668_LOUT_MIXER_CTRL			0x0052
+/* Power */
+#define RT5668_PWR_VOL				0x0067
+
+#define RT5668_ADCDAC_RST			0x006d
+/* Format - ADC/DAC */
+#define RT5668_I2S34_SDP			0x0071
+#define RT5668_I2S5_SDP				0x0072
+/* Format - TDM Control */
+#define RT5668_TDM_5				0x007c
+#define RT5668_TDM_6				0x007d
+#define RT5668_TDM_7				0x007e
+#define RT5668_TDM_8				0x007f
+
+/* Function - Analog */
+#define RT5668_ASRC_3				0x0085
+#define RT5668_ASRC_6				0x0088
+#define RT5668_ASRC_7				0x0089
+#define RT5668_PLL_TRK_13			0x0099
+#define RT5668_I2S_M_CLK_CTL			0x00a0
+#define RT5668_FDIV_I2S34_M_CLK			0x00a1
+#define RT5668_FDIV_I2S34_M_CLK2		0x00a2
+#define RT5668_FDIV_I2S5_M_CLK			0x00a3
+#define RT5668_FDIV_I2S5_M_CLK2			0x00a4
+
+/* Function - Digital */
+#define RT5668_IRQ_4				0x00b9
+#define RT5668_GPIO_3				0x00c2
+#define RT5668_GPIO_4				0x00c3
+#define RT5668_GPIO_STA				0x00c4
+#define RT5668_HP_AMP_DET1			0x00d0
+#define RT5668_HP_AMP_DET2			0x00d1
+#define RT5668_HP_AMP_DET3			0x00d2
+#define RT5668_MID_BD_HP_AMP			0x00d3
+#define RT5668_LOW_BD_HP_AMP			0x00d4
+#define RT5668_SOF_VOL_ZC2			0x00da
+#define RT5668_ADC_STO2_ADJ1			0x00ee
+#define RT5668_ADC_STO2_ADJ2			0x00ef
+/* General Control */
+#define RT5668_A_JD_CTRL			0x00f0
+#define RT5668_JD1_TRES_CTRL			0x00f1
+#define RT5668_JD2_TRES_CTRL			0x00f2
+#define RT5668_JD_CTRL2				0x00f7
+#define RT5668_DUM_REG_2			0x00fb
+#define RT5668_DUM_REG_3			0x00fc
+
+
+#define RT5668_DACADC_DIG_VOL2			0x0101
+#define RT5668_DIG_IN_PIN2			0x0133
+#define RT5668_PAD_DRV_CTL1			0x0136
+#define RT5668_SOF_RAM_DEPOP			0x0138
+#define RT5668_VOL_TEST				0x013f
+#define RT5668_TEST_MODE_3			0x0147
+#define RT5668_TEST_MODE_4			0x0148
+#define RT5668_MONO_DYNA_1			0x0170
+#define RT5668_MONO_DYNA_2			0x0171
+#define RT5668_MONO_DYNA_3			0x0172
+#define RT5668_MONO_DYNA_4			0x0173
+#define RT5668_MONO_DYNA_5			0x0174
+#define RT5668_MONO_DYNA_6			0x0175
+#define RT5668_STO1_SIL_DET			0x0190
+#define RT5668_MONOL_SIL_DET			0x0191
+#define RT5668_MONOR_SIL_DET			0x0192
+#define RT5668_STO2_DAC_SIL			0x0193
+#define RT5668_PWR_SAV_CTL1			0x0194
+#define RT5668_PWR_SAV_CTL2			0x0195
+#define RT5668_PWR_SAV_CTL3			0x0196
+#define RT5668_PWR_SAV_CTL4			0x0197
+#define RT5668_PWR_SAV_CTL5			0x0198
+#define RT5668_PWR_SAV_CTL6			0x0199
+#define RT5668_MONO_AMP_CAL1			0x01a0
+#define RT5668_MONO_AMP_CAL2			0x01a1
+#define RT5668_MONO_AMP_CAL3			0x01a2
+#define RT5668_MONO_AMP_CAL4			0x01a3
+#define RT5668_MONO_AMP_CAL5			0x01a4
+#define RT5668_MONO_AMP_CAL6			0x01a5
+#define RT5668_MONO_AMP_CAL7			0x01a6
+#define RT5668_MONO_AMP_CAL_ST1			0x01a7
+#define RT5668_MONO_AMP_CAL_ST2			0x01a8
+#define RT5668_MONO_AMP_CAL_ST3			0x01a9
+#define RT5668_MONO_AMP_CAL_ST4			0x01aa
+#define RT5668_MONO_AMP_CAL_ST5			0x01ab
+#define RT5668_HP_IMP_SEN_13			0x01b9
+#define RT5668_HP_IMP_SEN_14			0x01ba
+#define RT5668_HP_IMP_SEN_6			0x01bb
+#define RT5668_HP_IMP_SEN_7			0x01bc
+#define RT5668_HP_IMP_SEN_8			0x01bd
+#define RT5668_HP_IMP_SEN_9			0x01be
+#define RT5668_HP_IMP_SEN_10			0x01bf
+#define RT5668_HP_LOGIC_3			0x01dc
+#define RT5668_HP_CALIB_ST10			0x01f3
+#define RT5668_HP_CALIB_ST11			0x01f4
+#define RT5668_PRO_REG_TBL_4			0x0203
+#define RT5668_PRO_REG_TBL_5			0x0204
+#define RT5668_PRO_REG_TBL_6			0x0205
+#define RT5668_PRO_REG_TBL_7			0x0206
+#define RT5668_PRO_REG_TBL_8			0x0207
+#define RT5668_PRO_REG_TBL_9			0x0208
+#define RT5668_SAR_ADC_INL_1			0x0210
+#define RT5668_SAR_ADC_INL_2			0x0211
+#define RT5668_SAR_ADC_INL_3			0x0212
+#define RT5668_SAR_ADC_INL_4			0x0213
+#define RT5668_SAR_ADC_INL_5			0x0214
+#define RT5668_SAR_ADC_INL_6			0x0215
+#define RT5668_SAR_ADC_INL_7			0x0216
+#define RT5668_SAR_ADC_INL_8			0x0217
+#define RT5668_SAR_ADC_INL_9			0x0218
+#define RT5668_SAR_ADC_INL_10			0x0219
+#define RT5668_SAR_ADC_INL_11			0x021a
+#define RT5668_SAR_ADC_INL_12			0x021b
+#define RT5668_DRC_CTRL_1			0x02ff
+#define RT5668_DRC1_CTRL_2			0x0301
+#define RT5668_DRC1_CTRL_3			0x0302
+#define RT5668_DRC1_CTRL_4			0x0303
+#define RT5668_DRC1_CTRL_5			0x0304
+#define RT5668_DRC1_CTRL_6			0x0305
+#define RT5668_DRC1_HD_CTRL_1			0x0306
+#define RT5668_DRC1_HD_CTRL_2			0x0307
+#define RT5668_DRC1_PRI_REG_1			0x0310
+#define RT5668_DRC1_PRI_REG_2			0x0311
+#define RT5668_DRC1_PRI_REG_3			0x0312
+#define RT5668_DRC1_PRI_REG_4			0x0313
+#define RT5668_DRC1_PRI_REG_5			0x0314
+#define RT5668_DRC1_PRI_REG_6			0x0315
+#define RT5668_DRC1_PRI_REG_7			0x0316
+#define RT5668_DRC1_PRI_REG_8			0x0317
+#define RT5668_ALC_PGA_CTL_1			0x0330
+#define RT5668_ALC_PGA_CTL_2			0x0331
+#define RT5668_ALC_PGA_CTL_3			0x0332
+#define RT5668_ALC_PGA_CTL_4			0x0333
+#define RT5668_ALC_PGA_CTL_5			0x0334
+#define RT5668_ALC_PGA_CTL_6			0x0335
+#define RT5668_ALC_PGA_CTL_7			0x0336
+#define RT5668_ALC_PGA_CTL_8			0x0337
+#define RT5668_ALC_PGA_REG_1			0x0338
+#define RT5668_ALC_PGA_REG_2			0x0339
+#define RT5668_ALC_PGA_REG_3			0x033a
+#define RT5668_ADC_EQ_RECOV_1			0x03c0
+#define RT5668_ADC_EQ_RECOV_2			0x03c1
+#define RT5668_ADC_EQ_RECOV_3			0x03c2
+#define RT5668_ADC_EQ_RECOV_4			0x03c3
+#define RT5668_ADC_EQ_RECOV_5			0x03c4
+#define RT5668_ADC_EQ_RECOV_6			0x03c5
+#define RT5668_ADC_EQ_RECOV_7			0x03c6
+#define RT5668_ADC_EQ_RECOV_8			0x03c7
+#define RT5668_ADC_EQ_RECOV_9			0x03c8
+#define RT5668_ADC_EQ_RECOV_10			0x03c9
+#define RT5668_ADC_EQ_RECOV_11			0x03ca
+#define RT5668_ADC_EQ_RECOV_12			0x03cb
+#define RT5668_ADC_EQ_RECOV_13			0x03cc
+#define RT5668_VID_HIDDEN			0x03fe
+#define RT5668_VID_CUSTOMER			0x03ff
+#define RT5668_SCAN_MODE			0x07f0
+#define RT5668_I2C_BYPA				0x07fa
+
+/* Headphone Amp Control 2 (0x0003) */
+#define RT5668_EN_DAC_HPO_MASK			(0x1 << 14)
+#define RT5668_EN_DAC_HPO_SHIFT			14
+#define RT5668_EN_DAC_HPO_DIS			(0x0 << 14)
+#define RT5668_EN_DAC_HPO_EN			(0x1 << 14)
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5668_GAIN_HP				(0x1f << 8)
+#define RT5668_GAIN_HP_SHIFT			8
+
+/* AEC BST Control (0x000b) */
+#define RT5668_GAIN_CBJ_MASK			(0xf << 8)
+#define RT5668_GAIN_CBJ_SHIFT			8
+
+/* IN1 Control / MIC GND REF (0x000c) */
+#define RT5668_IN1_DF_MASK			(0x1 << 15)
+#define RT5668_IN1_DF_SHIFT			15
+
+/* Combo Jack and Type Detection Control 1 (0x0010) */
+#define RT5668_CBJ_DET_MASK			(0x1 << 15)
+#define RT5668_CBJ_DET_SHIFT			15
+#define RT5668_CBJ_DET_DIS			(0x0 << 15)
+#define RT5668_CBJ_DET_EN			(0x1 << 15)
+#define RT5668_DET_TYPE_MASK			(0x1 << 12)
+#define RT5668_DET_TYPE_SHIFT			12
+#define RT5668_DET_TYPE_WLCSP			(0x0 << 12)
+#define RT5668_DET_TYPE_QFN			(0x1 << 12)
+#define RT5668_VREF_BIAS_MASK			(0x1 << 6)
+#define RT5668_VREF_BIAS_SHIFT			6
+#define RT5668_VREF_BIAS_FSM			(0x0 << 6)
+#define RT5668_VREF_BIAS_REG			(0x1 << 6)
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5668_RECMIX1L_BST1_CBJ		(0x1 << 7)
+#define RT5668_RECMIX1L_BST1_CBJ_SHIFT		7
+#define RT5668_RECMIX1L_BST2			(0x1 << 4)
+#define RT5668_RECMIX1L_BST2_SHIFT		4
+
+/* REC Right Mixer Control 2 (0x003e) */
+#define RT5668_RECMIX1R_BST2			(0x1 << 4)
+#define RT5668_RECMIX1R_BST2_SHIFT		4
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5668_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5668_DAC_L1_VOL_SHIFT			8
+#define RT5668_DAC_R1_VOL_MASK			(0xff)
+#define RT5668_DAC_R1_VOL_SHIFT			0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5668_ADC_L_MUTE_MASK			(0x1 << 15)
+#define RT5668_ADC_L_MUTE_SHIFT			15
+#define RT5668_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5668_ADC_L_VOL_SHIFT			8
+#define RT5668_ADC_R_MUTE_MASK			(0x1 << 7)
+#define RT5668_ADC_R_MUTE_SHIFT			7
+#define RT5668_ADC_R_VOL_MASK			(0x7f)
+#define RT5668_ADC_R_VOL_SHIFT			0
+
+/* Stereo ADC Mixer Control (0x0026) */
+#define RT5668_M_STO1_ADC_L1			(0x1 << 15)
+#define RT5668_M_STO1_ADC_L1_SHIFT		15
+#define RT5668_M_STO1_ADC_L2			(0x1 << 14)
+#define RT5668_M_STO1_ADC_L2_SHIFT		14
+#define RT5668_STO1_ADC_L1_SRC			(0x1 << 13)
+#define RT5668_STO1_ADC_L1_SRC_SHIFT		13
+#define RT5668_STO1_ADC_L2_SRC			(0x1 << 12)
+#define RT5668_STO1_ADC_L2_SRC_SHIFT		12
+#define RT5668_STO1_ADC_L_SRC			(0x3 << 10)
+#define RT5668_STO1_ADC_L_SRC_SHIFT		10
+#define RT5668_M_STO1_ADC_R1			(0x1 << 7)
+#define RT5668_M_STO1_ADC_R1_SHIFT		7
+#define RT5668_M_STO1_ADC_R2			(0x1 << 6)
+#define RT5668_M_STO1_ADC_R2_SHIFT		6
+#define RT5668_STO1_ADC_R1_SRC			(0x1 << 5)
+#define RT5668_STO1_ADC_R1_SRC_SHIFT		5
+#define RT5668_STO1_ADC_R2_SRC			(0x1 << 4)
+#define RT5668_STO1_ADC_R2_SRC_SHIFT		4
+#define RT5668_STO1_ADC_R_SRC			(0x3 << 2)
+#define RT5668_STO1_ADC_R_SRC_SHIFT		2
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5668_M_ADCMIX_L			(0x1 << 15)
+#define RT5668_M_ADCMIX_L_SHIFT			15
+#define RT5668_M_DAC1_L				(0x1 << 14)
+#define RT5668_M_DAC1_L_SHIFT			14
+#define RT5668_M_ADCMIX_R			(0x1 << 7)
+#define RT5668_M_ADCMIX_R_SHIFT			7
+#define RT5668_M_DAC1_R				(0x1 << 6)
+#define RT5668_M_DAC1_R_SHIFT			6
+
+/* Stereo DAC Mixer Control (0x002a) */
+#define RT5668_M_DAC_L1_STO_L			(0x1 << 15)
+#define RT5668_M_DAC_L1_STO_L_SHIFT		15
+#define RT5668_M_DAC_R1_STO_L			(0x1 << 13)
+#define RT5668_M_DAC_R1_STO_L_SHIFT		13
+#define RT5668_M_DAC_L1_STO_R			(0x1 << 7)
+#define RT5668_M_DAC_L1_STO_R_SHIFT		7
+#define RT5668_M_DAC_R1_STO_R			(0x1 << 5)
+#define RT5668_M_DAC_R1_STO_R_SHIFT		5
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5668_PWR_I2S1				(0x1 << 15)
+#define RT5668_PWR_I2S1_SHIFT			15
+#define RT5668_PWR_DAC_L1			(0x1 << 11)
+#define RT5668_PWR_DAC_L1_SHIFT			11
+#define RT5668_PWR_DAC_R1			(0x1 << 10)
+#define RT5668_PWR_DAC_R1_SHIFT			10
+#define RT5668_PWR_LDO_DACREF_MASK		(0x1 << 8)
+#define RT5668_PWR_LDO_DACREF_SHIFT		8
+#define RT5668_PWR_LDO_DACREF_ON		(0x1 << 8)
+#define RT5668_PWR_LDO_DACREF_DOWN		(0x0 << 8)
+#define RT5668_PWR_LDO_SHIFT			8
+#define RT5668_PWR_ADC_L1			(0x1 << 4)
+#define RT5668_PWR_ADC_L1_SHIFT			4
+#define RT5668_PWR_ADC_R1			(0x1 << 3)
+#define RT5668_PWR_ADC_R1_SHIFT			3
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5668_PWR_ADC_S1F			(0x1 << 15)
+#define RT5668_PWR_ADC_S1F_SHIFT		15
+#define RT5668_PWR_DAC_S1F			(0x1 << 10)
+#define RT5668_PWR_DAC_S1F_SHIFT		10
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5668_PWR_VREF1			(0x1 << 15)
+#define RT5668_PWR_VREF1_MASK			(0x1 << 15)
+#define RT5668_PWR_VREF1_SHIFT			15
+#define RT5668_PWR_FV1				(0x1 << 14)
+#define RT5668_PWR_FV1_MASK			(0x1 << 14)
+#define RT5668_PWR_FV1_SHIFT			14
+#define RT5668_PWR_VREF2			(0x1 << 13)
+#define RT5668_PWR_VREF2_MASK			(0x1 << 13)
+#define RT5668_PWR_VREF2_SHIFT			13
+#define RT5668_PWR_FV2				(0x1 << 12)
+#define RT5668_PWR_FV2_MASK			(0x1 << 12)
+#define RT5668_PWR_FV2_SHIFT			12
+#define RT5668_PWR_MB				(0x1 << 9)
+#define RT5668_PWR_MB_MASK			(0x1 << 9)
+#define RT5668_PWR_MB_SHIFT			9
+#define RT5668_AMP_HP_MASK			(0x3 << 2)
+#define RT5668_AMP_HP_SHIFT			2
+#define RT5668_AMP_HP_1X			(0x0 << 2)
+#define RT5668_AMP_HP_3X			(0x1 << 2)
+#define RT5668_AMP_HP_5X			(0x3 << 2)
+#define RT5668_LDO1_DVO_MASK			(0x3)
+#define RT5668_LDO1_DVO_SHIFT			0
+#define RT5668_LDO1_DVO_0_9V			(0x0)
+#define RT5668_LDO1_DVO_1_0V			(0x1)
+#define RT5668_LDO1_DVO_1_2V			(0x2)
+#define RT5668_LDO1_DVO_1_4V			(0x3)
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5668_PWR_BST1				(0x1 << 15)
+#define RT5668_PWR_BST1_MASK			(0x1 << 15)
+#define RT5668_PWR_BST1_SHIFT			15
+#define RT5668_PWR_BST1_OFF			(0x0 << 15)
+#define RT5668_PWR_BST1_ON			(0x1 << 15)
+#define RT5668_PWR_BST2				(0x1 << 14)
+#define RT5668_PWR_BST2_MASK			(0x1 << 14)
+#define RT5668_PWR_BST2_SHIFT			14
+#define RT5668_PWR_MB1				(0x1 << 11)
+#define RT5668_PWR_MB1_SHIFT			11
+#define RT5668_PWR_MB2				(0x1 << 10)
+#define RT5668_PWR_MB2_SHIFT			10
+#define RT5668_PWR_BST2_OP			(0x1 << 6)
+#define RT5668_PWR_BST2_OP_MASK			(0x1 << 6)
+#define RT5668_PWR_BST2_OP_SHIFT		6
+#define RT5668_PWR_JD1				(0x1 << 3)
+#define RT5668_PWR_JD1_MASK			(0x1 << 3)
+#define RT5668_PWR_JD1_SHIFT			3
+#define RT5668_PWR_JD2				(0x1 << 2)
+#define RT5668_PWR_JD2_MASK			(0x1 << 2)
+#define RT5668_PWR_JD2_SHIFT			2
+#define RT5668_PWR_RECMIX1			(0x1 << 1)
+#define RT5668_PWR_RECMIX1_SHIFT		1
+#define RT5668_PWR_RECMIX2			(0x1)
+#define RT5668_PWR_RECMIX2_SHIFT		0
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5668_PWR_CBJ_MASK			(0x1 << 9)
+#define RT5668_PWR_CBJ_SHIFT			9
+#define RT5668_PWR_CBJ_OFF			(0x0 << 9)
+#define RT5668_PWR_CBJ_ON			(0x1 << 9)
+#define RT5668_PWR_PLL				(0x1 << 6)
+#define RT5668_PWR_PLL_SHIFT			6
+#define RT5668_PWR_LDO2				(0x1 << 2)
+#define RT5668_PWR_LDO2_SHIFT			2
+
+/* Power Management for Volume (0x0067) */
+#define RT5668_PWR_MIC_DET			(0x1 << 5)
+#define RT5668_PWR_MIC_DET_SHIFT		5
+
+/* MCLK and System Clock Detection Control (0x006b) */
+#define RT5668_EN_ANA_CLK_DET_MASK		(0x1 << 15)
+#define RT5668_EN_ANA_CLK_DET_SHIFT		15
+#define RT5668_EN_ANA_CLK_DET_DIS		(0x0 << 15)
+#define RT5668_EN_ANA_CLK_DET_AUTO		(0x1 << 15)
+#define RT5668_PWR_CLK_DET_MASK			(0x1)
+#define RT5668_PWR_CLK_DET_SHIFT		0
+#define RT5668_PWR_CLK_DET_DIS			(0x0)
+#define RT5668_PWR_CLK_DET_EN			(0x1)
+
+/* I2S1 Audio Serial Data Port Control (0x0070) */
+#define RT5668_I2S_MS_MASK			(0x1 << 15)
+#define RT5668_I2S_MS_SHIFT			15
+#define RT5668_I2S_MS_M				(0x0 << 15)
+#define RT5668_I2S_MS_S				(0x1 << 15)
+#define RT5668_I2S_BP_MASK			(0x1 << 8)
+#define RT5668_I2S_BP_SHIFT			8
+#define RT5668_I2S_BP_NOR			(0x0 << 8)
+#define RT5668_I2S_BP_INV			(0x1 << 8)
+#define RT5668_I2S_DL_MASK			(0x3 << 4)
+#define RT5668_I2S_DL_SHIFT			4
+#define RT5668_I2S_DL_16			(0x0 << 4)
+#define RT5668_I2S_DL_20			(0x1 << 4)
+#define RT5668_I2S_DL_24			(0x2 << 4)
+#define RT5668_I2S_DL_8				(0x3 << 4)
+#define RT5668_I2S_DF_MASK			(0x7)
+#define RT5668_I2S_DF_SHIFT			0
+#define RT5668_I2S_DF_I2S			(0x0)
+#define RT5668_I2S_DF_LEFT			(0x1)
+#define RT5668_I2S_DF_PCM_A			(0x2)
+#define RT5668_I2S_DF_PCM_B			(0x3)
+#define RT5668_I2S_DF_PCM_A_N			(0x6)
+#define RT5668_I2S_DF_PCM_B_N			(0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5668_I2S_PD1_MASK			(0x7 << 12)
+#define RT5668_I2S_PD1_SHIFT			12
+#define RT5668_M_I2S_DIV_MASK			(0x7 << 8)
+#define RT5668_M_I2S_DIV_SHIFT			8
+#define RT5668_CLK_SRC_MASK			(0x3 << 4)
+#define RT5668_CLK_SRC_MCLK			(0x0 << 4)
+#define RT5668_CLK_SRC_PLL_OUT			(0x1 << 4)
+#define RT5668_CLK_SRC_DIV			(0x2 << 4)
+#define RT5668_CLK_SRC_RC			(0x3 << 4)
+#define RT5668_DAC_OSR_MASK			(0x3 << 2)
+#define RT5668_DAC_OSR_SHIFT			2
+#define RT5668_DAC_OSR_128			(0x0 << 2)
+#define RT5668_DAC_OSR_64			(0x1 << 2)
+#define RT5668_DAC_OSR_32			(0x2 << 2)
+#define RT5668_ADC_OSR_MASK			(0x3)
+#define RT5668_ADC_OSR_SHIFT			0
+#define RT5668_ADC_OSR_128			(0x0)
+#define RT5668_ADC_OSR_64			(0x1)
+#define RT5668_ADC_OSR_32			(0x2)
+
+/* TDM1 control 1 (0x0078) */
+#define RT5668_TDM_MODE_MASK			(0x1 << 15)
+#define RT5668_TDM_MODE_SHIFT			15
+#define RT5668_TDM_MODE_I2S			(0x0 << 15)
+#define RT5668_TDM_MODE_TDM			(0x1 << 15)
+#define RT5668_TDM_IN_CH_MASK			(0x3 << 10)
+#define RT5668_TDM_IN_CH_SHIFT			10
+#define RT5668_TDM_IN_CH_2			(0x0 << 10)
+#define RT5668_TDM_IN_CH_4			(0x1 << 10)
+#define RT5668_TDM_IN_CH_6			(0x2 << 10)
+#define RT5668_TDM_IN_CH_8			(0x3 << 10)
+#define RT5668_TDM_OUT_CH_MASK			(0x3 << 8)
+#define RT5668_TDM_OUT_CH_SHIFT			8
+#define RT5668_TDM_OUT_CH_2			(0x0 << 8)
+#define RT5668_TDM_OUT_CH_4			(0x1 << 8)
+#define RT5668_TDM_OUT_CH_6			(0x2 << 8)
+#define RT5668_TDM_OUT_CH_8			(0x3 << 8)
+#define RT5668_TDM_IN_LEN_MASK			(0x3 << 6)
+#define RT5668_TDM_IN_LEN_SHIFT			6
+#define RT5668_TDM_IN_LEN_16			(0x0 << 6)
+#define RT5668_TDM_IN_LEN_20			(0x1 << 6)
+#define RT5668_TDM_IN_LEN_24			(0x2 << 6)
+#define RT5668_TDM_IN_LEN_32			(0x3 << 6)
+#define RT5668_TDM_OUT_LEN_MASK			(0x3 << 4)
+#define RT5668_TDM_OUT_LEN_SHIFT		4
+#define RT5668_TDM_OUT_LEN_16			(0x0 << 4)
+#define RT5668_TDM_OUT_LEN_20			(0x1 << 4)
+#define RT5668_TDM_OUT_LEN_24			(0x2 << 4)
+#define RT5668_TDM_OUT_LEN_32			(0x3 << 4)
+
+/* Global Clock Control (0x0080) */
+#define RT5668_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5668_SCLK_SRC_SHIFT			14
+#define RT5668_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5668_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5668_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5668_PLL1_SRC_MASK			(0x7 << 8)
+#define RT5668_PLL1_SRC_SHIFT			8
+#define RT5668_PLL1_SRC_MCLK			(0x0 << 8)
+#define RT5668_PLL1_SRC_BCLK1			(0x1 << 8)
+#define RT5668_PLL1_PD_MASK			(0x1 << 4)
+#define RT5668_PLL1_PD_SHIFT			4
+
+#define RT5668_PLL_INP_MAX			40000000
+#define RT5668_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5668_PLL_N_MAX			0x001ff
+#define RT5668_PLL_N_MASK			(RT5668_PLL_N_MAX << 7)
+#define RT5668_PLL_N_SHIFT			7
+#define RT5668_PLL_K_MAX			0x001f
+#define RT5668_PLL_K_MASK			(RT5668_PLL_K_MAX)
+#define RT5668_PLL_K_SHIFT			0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5668_PLL_M_MAX			0x00f
+#define RT5668_PLL_M_MASK			(RT5668_PLL_M_MAX << 12)
+#define RT5668_PLL_M_SHIFT			12
+#define RT5668_PLL_M_BP				(0x1 << 11)
+#define RT5668_PLL_M_BP_SHIFT			11
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5668_I2S1_ASRC_MASK			(0x1 << 13)
+#define RT5668_I2S1_ASRC_SHIFT			13
+#define RT5668_DAC_STO1_ASRC_MASK		(0x1 << 12)
+#define RT5668_DAC_STO1_ASRC_SHIFT		12
+#define RT5668_ADC_STO1_ASRC_MASK		(0x1 << 4)
+#define RT5668_ADC_STO1_ASRC_SHIFT		4
+
+/* PLL tracking mode 2 (0x0084)*/
+#define RT5668_DA_STO1_TRACK_MASK		(0x7 << 12)
+#define RT5668_DA_STO1_TRACK_SHIFT		12
+#define RT5668_DA_STO1_TRACK_SYSCLK		(0x0 << 12)
+#define RT5668_DA_STO1_TRACK_I2S1		(0x1 << 12)
+
+/* PLL tracking mode 3 (0x0085)*/
+#define RT5668_AD_STO1_TRACK_MASK		(0x7 << 12)
+#define RT5668_AD_STO1_TRACK_SHIFT		12
+#define RT5668_AD_STO1_TRACK_SYSCLK		(0x0 << 12)
+#define RT5668_AD_STO1_TRACK_I2S1		(0x1 << 12)
+
+/* HPOUT Charge pump control 1 (0x0091) */
+#define RT5668_OSW_HP_L_MASK			(0x1 << 11)
+#define RT5668_OSW_HP_L_SHIFT			11
+#define RT5668_OSW_HP_L_EN			(0x1 << 11)
+#define RT5668_OSW_HP_L_DIS			(0x0 << 11)
+#define RT5668_OSW_HP_R_MASK			(0x1 << 10)
+#define RT5668_OSW_HP_R_SHIFT			10
+#define RT5668_OSW_HP_R_EN			(0x1 << 10)
+#define RT5668_OSW_HP_R_DIS			(0x0 << 10)
+#define RT5668_SEL_PM_HP_MASK			(0x3 << 8)
+#define RT5668_SEL_PM_HP_SHIFT			8
+#define RT5668_SEL_PM_HP_0_6			(0x0 << 8)
+#define RT5668_SEL_PM_HP_0_9			(0x1 << 8)
+#define RT5668_SEL_PM_HP_1_8			(0x2 << 8)
+#define RT5668_SEL_PM_HP_HIGH			(0x3 << 8)
+#define RT5668_OVCD_HP_MASK			(0x1 << 2)
+#define RT5668_OVCD_HP_SHIFT			2
+#define RT5668_OVCD_HP_EN			(0x1 << 2)
+#define RT5668_OVCD_HP_DIS			(0x0 << 2)
+
+/* RC Clock Control (0x0094) */
+#define RT5668_DIG_25M_CLK_MASK			(0x1 << 9)
+#define RT5668_DIG_25M_CLK_SHIFT		9
+#define RT5668_DIG_25M_CLK_DIS			(0x0 << 9)
+#define RT5668_DIG_25M_CLK_EN			(0x1 << 9)
+#define RT5668_DIG_1M_CLK_MASK			(0x1 << 8)
+#define RT5668_DIG_1M_CLK_SHIFT			8
+#define RT5668_DIG_1M_CLK_DIS			(0x0 << 8)
+#define RT5668_DIG_1M_CLK_EN			(0x1 << 8)
+
+/* Auto Turn On 1M RC CLK (0x009f) */
+#define RT5668_IRQ_POW_SAV_MASK			(0x1 << 15)
+#define RT5668_IRQ_POW_SAV_SHIFT		15
+#define RT5668_IRQ_POW_SAV_DIS			(0x0 << 15)
+#define RT5668_IRQ_POW_SAV_EN			(0x1 << 15)
+#define RT5668_IRQ_POW_SAV_JD1_MASK		(0x1 << 14)
+#define RT5668_IRQ_POW_SAV_JD1_SHIFT		14
+#define RT5668_IRQ_POW_SAV_JD1_DIS		(0x0 << 14)
+#define RT5668_IRQ_POW_SAV_JD1_EN		(0x1 << 14)
+
+/* IRQ Control 1 (0x00b6) */
+#define RT5668_EN_CB_JD_MASK			(0x1 << 3)
+#define RT5668_EN_CB_JD_SHIFT			3
+#define RT5668_EN_CB_JD_EN			(0x1 << 3)
+#define RT5668_EN_CB_JD_DIS			(0x0 << 3)
+
+/* IRQ Control 3 (0x00b8) */
+#define RT5668_EN_IRQ_INLINE_MASK		(0x1 << 6)
+#define RT5668_EN_IRQ_INLINE_SHIFT		6
+#define RT5668_EN_IRQ_INLINE_BYP		(0x0 << 6)
+#define RT5668_EN_IRQ_INLINE_NOR		(0x1 << 6)
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5668_GP1_PIN_MASK			(0x1 << 15)
+#define RT5668_GP1_PIN_SHIFT			15
+#define RT5668_GP1_PIN_GPIO1			(0x0 << 15)
+#define RT5668_GP1_PIN_IRQ			(0x1 << 15)
+
+/* GPIO Control 2 (0x00c1) */
+#define RT5668_GP4_PIN_CONF_MASK		(0x1 << 5)
+#define RT5668_GP4_PIN_CONF_SHIFT		5
+#define RT5668_GP4_PIN_CONF_INPUT		(0x0 << 5)
+#define RT5668_GP4_PIN_CONF_OUTPUT		(0x1 << 5)
+
+/* GPIO Control 2 (0x00c2) */
+#define RT5668_GP8_PIN_CONF_MASK		(0x1 << 13)
+#define RT5668_GP8_PIN_CONF_SHIFT		13
+#define RT5668_GP8_PIN_CONF_INPUT		(0x0 << 13)
+#define RT5668_GP8_PIN_CONF_OUTPUT		(0x1 << 13)
+
+/* 4 Buttons Inline Command Function 1 (0x00df) */
+#define RT5668_4BTN_CLK_DEB_MASK		(0x3 << 2)
+#define RT5668_4BTN_CLK_DEB_SHIFT		2
+#define RT5668_4BTN_CLK_DEB_8MS			(0x0 << 2)
+#define RT5668_4BTN_CLK_DEB_16MS		(0x1 << 2)
+#define RT5668_4BTN_CLK_DEB_32MS		(0x2 << 2)
+#define RT5668_4BTN_CLK_DEB_65MS		(0x3 << 2)
+
+/* Inline Command Function 6 (0x00e0) */
+#define RT5668_EN_4BTN_INL_MASK			(0x1 << 15)
+#define RT5668_EN_4BTN_INL_SHIFT		15
+#define RT5668_EN_4BTN_INL_DIS			(0x0 << 15)
+#define RT5668_EN_4BTN_INL_EN			(0x1 << 15)
+#define RT5668_RESET_4BTN_INL_MASK		(0x1 << 14)
+#define RT5668_RESET_4BTN_INL_SHIFT		14
+#define RT5668_RESET_4BTN_INL_RESET		(0x0 << 14)
+#define RT5668_RESET_4BTN_INL_NOR		(0x1 << 14)
+
+/* Digital Misc Control (0x00fa) */
+#define RT5668_DIG_GATE_CTRL_MASK		0x1
+#define RT5668_DIG_GATE_CTRL_SHIFT		(0)
+#define RT5668_DIG_GATE_CTRL_DIS		0x0
+#define RT5668_DIG_GATE_CTRL_EN			0x1
+
+/* Chopper and Clock control for DAC L (0x013a)*/
+#define RT5668_CKXEN_DAC1_MASK			(0x1 << 13)
+#define RT5668_CKXEN_DAC1_SHIFT			13
+#define RT5668_CKGEN_DAC1_MASK			(0x1 << 12)
+#define RT5668_CKGEN_DAC1_SHIFT			12
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5668_CKXEN_ADCC_MASK			(0x1 << 13)
+#define RT5668_CKXEN_ADCC_SHIFT			13
+#define RT5668_CKGEN_ADCC_MASK			(0x1 << 12)
+#define RT5668_CKGEN_ADCC_SHIFT			12
+
+/* HP Behavior Logic Control 2 (0x01db) */
+#define RT5668_HP_SIG_SRC1_MASK			(0x3)
+#define RT5668_HP_SIG_SRC1_SHIFT		0
+#define RT5668_HP_SIG_SRC1_HP_DC		(0x0)
+#define RT5668_HP_SIG_SRC1_HP_CALIB		(0x1)
+#define RT5668_HP_SIG_SRC1_REG			(0x2)
+#define RT5668_HP_SIG_SRC1_SILENCE		(0x3)
+
+/* RT5663 specific register */
+#define RT5663_HP_OUT_EN			0x0002
+#define RT5663_HP_LCH_DRE			0x0005
+#define RT5663_HP_RCH_DRE			0x0006
+#define RT5663_CALIB_BST			0x000a
+#define RT5663_RECMIX				0x0010
+#define RT5663_SIL_DET_CTL			0x0015
+#define RT5663_PWR_SAV_SILDET			0x0016
+#define RT5663_SIDETONE_CTL			0x0018
+#define RT5663_STO1_DAC_DIG_VOL			0x0019
+#define RT5663_STO1_ADC_DIG_VOL			0x001c
+#define RT5663_STO1_BOOST			0x001f
+#define RT5663_HP_IMP_GAIN_1			0x0022
+#define RT5663_HP_IMP_GAIN_2			0x0023
+#define RT5663_STO1_ADC_MIXER			0x0026
+#define RT5663_AD_DA_MIXER			0x0029
+#define RT5663_STO_DAC_MIXER			0x002a
+#define RT5663_DIG_SIDE_MIXER			0x002c
+#define RT5663_BYPASS_STO_DAC			0x002d
+#define RT5663_CALIB_REC_MIX			0x0040
+#define RT5663_PWR_DIG_1			0x0061
+#define RT5663_PWR_DIG_2			0x0062
+#define RT5663_PWR_ANLG_1			0x0063
+#define RT5663_PWR_ANLG_2			0x0064
+#define RT5663_PWR_ANLG_3			0x0065
+#define RT5663_PWR_MIXER			0x0066
+#define RT5663_SIG_CLK_DET			0x006b
+#define RT5663_PRE_DIV_GATING_1			0x006e
+#define RT5663_PRE_DIV_GATING_2			0x006f
+#define RT5663_I2S1_SDP				0x0070
+#define RT5663_ADDA_CLK_1			0x0073
+#define RT5663_ADDA_RST				0x0074
+#define RT5663_FRAC_DIV_1			0x0075
+#define RT5663_FRAC_DIV_2			0x0076
+#define RT5663_TDM_1				0x0077
+#define RT5663_TDM_2				0x0078
+#define RT5663_TDM_3				0x0079
+#define RT5663_TDM_4				0x007a
+#define RT5663_TDM_5				0x007b
+#define RT5663_GLB_CLK				0x0080
+#define RT5663_PLL_1				0x0081
+#define RT5663_PLL_2				0x0082
+#define RT5663_ASRC_1				0x0083
+#define RT5663_ASRC_2				0x0084
+#define RT5663_ASRC_4				0x0086
+#define RT5663_DUMMY_REG			0x0087
+#define RT5663_ASRC_8				0x008a
+#define RT5663_ASRC_9				0x008b
+#define RT5663_ASRC_11				0x008c
+#define RT5663_DEPOP_1				0x008e
+#define RT5663_DEPOP_2				0x008f
+#define RT5663_DEPOP_3				0x0090
+#define RT5663_HP_CHARGE_PUMP_1			0x0091
+#define RT5663_HP_CHARGE_PUMP_2			0x0092
+#define RT5663_MICBIAS_1			0x0093
+#define RT5663_RC_CLK				0x0094
+#define RT5663_ASRC_11_2			0x0097
+#define RT5663_DUMMY_REG_2			0x0098
+#define RT5663_REC_PATH_GAIN			0x009a
+#define RT5663_AUTO_1MRC_CLK			0x009f
+#define RT5663_ADC_EQ_1				0x00ae
+#define RT5663_ADC_EQ_2				0x00af
+#define RT5663_IRQ_1				0x00b6
+#define RT5663_IRQ_2				0x00b7
+#define RT5663_IRQ_3				0x00b8
+#define RT5663_IRQ_4				0x00ba
+#define RT5663_IRQ_5				0x00bb
+#define RT5663_INT_ST_1				0x00be
+#define RT5663_INT_ST_2				0x00bf
+#define RT5663_GPIO_1				0x00c0
+#define RT5663_GPIO_2				0x00c1
+#define RT5663_GPIO_STA				0x00c5
+#define RT5663_SIN_GEN_1			0x00cb
+#define RT5663_SIN_GEN_2			0x00cc
+#define RT5663_SIN_GEN_3			0x00cd
+#define RT5663_SOF_VOL_ZC1			0x00d9
+#define RT5663_IL_CMD_1				0x00db
+#define RT5663_IL_CMD_2				0x00dc
+#define RT5663_IL_CMD_3				0x00dd
+#define RT5663_IL_CMD_4				0x00de
+#define RT5663_IL_CMD_5				0x00df
+#define RT5663_IL_CMD_6				0x00e0
+#define RT5663_IL_CMD_7				0x00e1
+#define RT5663_IL_CMD_8				0x00e2
+#define RT5663_IL_CMD_PWRSAV1			0x00e4
+#define RT5663_IL_CMD_PWRSAV2			0x00e5
+#define RT5663_EM_JACK_TYPE_1			0x00e6
+#define RT5663_EM_JACK_TYPE_2			0x00e7
+#define RT5663_EM_JACK_TYPE_3			0x00e8
+#define RT5663_EM_JACK_TYPE_4			0x00e9
+#define RT5663_EM_JACK_TYPE_5			0x00ea
+#define RT5663_EM_JACK_TYPE_6			0x00eb
+#define RT5663_STO1_HPF_ADJ1			0x00ec
+#define RT5663_STO1_HPF_ADJ2			0x00ed
+#define RT5663_FAST_OFF_MICBIAS			0x00f4
+#define RT5663_JD_CTRL1				0x00f6
+#define RT5663_JD_CTRL2				0x00f8
+#define RT5663_DIG_MISC				0x00fa
+#define RT5663_DIG_VOL_ZCD			0x0100
+#define RT5663_ANA_BIAS_CUR_1			0x0108
+#define RT5663_ANA_BIAS_CUR_2			0x0109
+#define RT5663_ANA_BIAS_CUR_3			0x010a
+#define RT5663_ANA_BIAS_CUR_4			0x010b
+#define RT5663_ANA_BIAS_CUR_5			0x010c
+#define RT5663_ANA_BIAS_CUR_6			0x010d
+#define RT5663_BIAS_CUR_5			0x010e
+#define RT5663_BIAS_CUR_6			0x010f
+#define RT5663_BIAS_CUR_7			0x0110
+#define RT5663_BIAS_CUR_8			0x0111
+#define RT5663_DACREF_LDO			0x0112
+#define RT5663_DUMMY_REG_3			0x0113
+#define RT5663_BIAS_CUR_9			0x0114
+#define RT5663_DUMMY_REG_4			0x0116
+#define RT5663_VREFADJ_OP			0x0117
+#define RT5663_VREF_RECMIX			0x0118
+#define RT5663_CHARGE_PUMP_1			0x0125
+#define RT5663_CHARGE_PUMP_1_2			0x0126
+#define RT5663_CHARGE_PUMP_1_3			0x0127
+#define RT5663_CHARGE_PUMP_2			0x0128
+#define RT5663_DIG_IN_PIN1			0x0132
+#define RT5663_PAD_DRV_CTL			0x0137
+#define RT5663_PLL_INT_REG			0x0139
+#define RT5663_CHOP_DAC_L			0x013a
+#define RT5663_CHOP_ADC				0x013b
+#define RT5663_CALIB_ADC			0x013c
+#define RT5663_CHOP_DAC_R			0x013d
+#define RT5663_DUMMY_CTL_DACLR			0x013e
+#define RT5663_DUMMY_REG_5			0x0140
+#define RT5663_SOFT_RAMP			0x0141
+#define RT5663_TEST_MODE_1			0x0144
+#define RT5663_TEST_MODE_2			0x0145
+#define RT5663_TEST_MODE_3			0x0146
+#define RT5663_STO_DRE_1			0x0160
+#define RT5663_STO_DRE_2			0x0161
+#define RT5663_STO_DRE_3			0x0162
+#define RT5663_STO_DRE_4			0x0163
+#define RT5663_STO_DRE_5			0x0164
+#define RT5663_STO_DRE_6			0x0165
+#define RT5663_STO_DRE_7			0x0166
+#define RT5663_STO_DRE_8			0x0167
+#define RT5663_STO_DRE_9			0x0168
+#define RT5663_STO_DRE_10			0x0169
+#define RT5663_MIC_DECRO_1			0x0180
+#define RT5663_MIC_DECRO_2			0x0181
+#define RT5663_MIC_DECRO_3			0x0182
+#define RT5663_MIC_DECRO_4			0x0183
+#define RT5663_MIC_DECRO_5			0x0184
+#define RT5663_MIC_DECRO_6			0x0185
+#define RT5663_HP_DECRO_1			0x01b0
+#define RT5663_HP_DECRO_2			0x01b1
+#define RT5663_HP_DECRO_3			0x01b2
+#define RT5663_HP_DECRO_4			0x01b3
+#define RT5663_HP_DECOUP			0x01b4
+#define RT5663_HP_IMP_SEN_MAP8			0x01b5
+#define RT5663_HP_IMP_SEN_MAP9			0x01b6
+#define RT5663_HP_IMP_SEN_MAP10			0x01b7
+#define RT5663_HP_IMP_SEN_MAP11			0x01b8
+#define RT5663_HP_IMP_SEN_1			0x01c0
+#define RT5663_HP_IMP_SEN_2			0x01c1
+#define RT5663_HP_IMP_SEN_3			0x01c2
+#define RT5663_HP_IMP_SEN_4			0x01c3
+#define RT5663_HP_IMP_SEN_5			0x01c4
+#define RT5663_HP_IMP_SEN_6			0x01c5
+#define RT5663_HP_IMP_SEN_7			0x01c6
+#define RT5663_HP_IMP_SEN_8			0x01c7
+#define RT5663_HP_IMP_SEN_9			0x01c8
+#define RT5663_HP_IMP_SEN_10			0x01c9
+#define RT5663_HP_IMP_SEN_11			0x01ca
+#define RT5663_HP_IMP_SEN_12			0x01cb
+#define RT5663_HP_IMP_SEN_13			0x01cc
+#define RT5663_HP_IMP_SEN_14			0x01cd
+#define RT5663_HP_IMP_SEN_15			0x01ce
+#define RT5663_HP_IMP_SEN_16			0x01cf
+#define RT5663_HP_IMP_SEN_17			0x01d0
+#define RT5663_HP_IMP_SEN_18			0x01d1
+#define RT5663_HP_IMP_SEN_19			0x01d2
+#define RT5663_HP_IMPSEN_DIG5			0x01d3
+#define RT5663_HP_IMPSEN_MAP1			0x01d4
+#define RT5663_HP_IMPSEN_MAP2			0x01d5
+#define RT5663_HP_IMPSEN_MAP3			0x01d6
+#define RT5663_HP_IMPSEN_MAP4			0x01d7
+#define RT5663_HP_IMPSEN_MAP5			0x01d8
+#define RT5663_HP_IMPSEN_MAP7			0x01d9
+#define RT5663_HP_LOGIC_1			0x01da
+#define RT5663_HP_LOGIC_2			0x01db
+#define RT5663_HP_CALIB_1			0x01dd
+#define RT5663_HP_CALIB_1_1			0x01de
+#define RT5663_HP_CALIB_2			0x01df
+#define RT5663_HP_CALIB_3			0x01e0
+#define RT5663_HP_CALIB_4			0x01e1
+#define RT5663_HP_CALIB_5			0x01e2
+#define RT5663_HP_CALIB_5_1			0x01e3
+#define RT5663_HP_CALIB_6			0x01e4
+#define RT5663_HP_CALIB_7			0x01e5
+#define RT5663_HP_CALIB_9			0x01e6
+#define RT5663_HP_CALIB_10			0x01e7
+#define RT5663_HP_CALIB_11			0x01e8
+#define RT5663_HP_CALIB_ST1			0x01ea
+#define RT5663_HP_CALIB_ST2			0x01eb
+#define RT5663_HP_CALIB_ST3			0x01ec
+#define RT5663_HP_CALIB_ST4			0x01ed
+#define RT5663_HP_CALIB_ST5			0x01ee
+#define RT5663_HP_CALIB_ST6			0x01ef
+#define RT5663_HP_CALIB_ST7			0x01f0
+#define RT5663_HP_CALIB_ST8			0x01f1
+#define RT5663_HP_CALIB_ST9			0x01f2
+#define RT5663_HP_AMP_DET			0x0200
+#define RT5663_DUMMY_REG_6			0x0201
+#define RT5663_HP_BIAS				0x0202
+#define RT5663_CBJ_1				0x0250
+#define RT5663_CBJ_2				0x0251
+#define RT5663_CBJ_3				0x0252
+#define RT5663_DUMMY_1				0x02fa
+#define RT5663_DUMMY_2				0x02fb
+#define RT5663_DUMMY_3				0x02fc
+#define RT5663_ANA_JD				0x0300
+#define RT5663_ADC_LCH_LPF1_A1			0x03d0
+#define RT5663_ADC_RCH_LPF1_A1			0x03d1
+#define RT5663_ADC_LCH_LPF1_H0			0x03d2
+#define RT5663_ADC_RCH_LPF1_H0			0x03d3
+#define RT5663_ADC_LCH_BPF1_A1			0x03d4
+#define RT5663_ADC_RCH_BPF1_A1			0x03d5
+#define RT5663_ADC_LCH_BPF1_A2			0x03d6
+#define RT5663_ADC_RCH_BPF1_A2			0x03d7
+#define RT5663_ADC_LCH_BPF1_H0			0x03d8
+#define RT5663_ADC_RCH_BPF1_H0			0x03d9
+#define RT5663_ADC_LCH_BPF2_A1			0x03da
+#define RT5663_ADC_RCH_BPF2_A1			0x03db
+#define RT5663_ADC_LCH_BPF2_A2			0x03dc
+#define RT5663_ADC_RCH_BPF2_A2			0x03dd
+#define RT5663_ADC_LCH_BPF2_H0			0x03de
+#define RT5663_ADC_RCH_BPF2_H0			0x03df
+#define RT5663_ADC_LCH_BPF3_A1			0x03e0
+#define RT5663_ADC_RCH_BPF3_A1			0x03e1
+#define RT5663_ADC_LCH_BPF3_A2			0x03e2
+#define RT5663_ADC_RCH_BPF3_A2			0x03e3
+#define RT5663_ADC_LCH_BPF3_H0			0x03e4
+#define RT5663_ADC_RCH_BPF3_H0			0x03e5
+#define RT5663_ADC_LCH_BPF4_A1			0x03e6
+#define RT5663_ADC_RCH_BPF4_A1			0x03e7
+#define RT5663_ADC_LCH_BPF4_A2			0x03e8
+#define RT5663_ADC_RCH_BPF4_A2			0x03e9
+#define RT5663_ADC_LCH_BPF4_H0			0x03ea
+#define RT5663_ADC_RCH_BPF4_H0			0x03eb
+#define RT5663_ADC_LCH_HPF1_A1			0x03ec
+#define RT5663_ADC_RCH_HPF1_A1			0x03ed
+#define RT5663_ADC_LCH_HPF1_H0			0x03ee
+#define RT5663_ADC_RCH_HPF1_H0			0x03ef
+#define RT5663_ADC_EQ_PRE_VOL_L			0x03f0
+#define RT5663_ADC_EQ_PRE_VOL_R			0x03f1
+#define RT5663_ADC_EQ_POST_VOL_L		0x03f2
+#define RT5663_ADC_EQ_POST_VOL_R		0x03f3
+
+/* RT5663: RECMIX Control (0x0010) */
+#define RT5663_RECMIX1_BST1_MASK		(0x1)
+#define RT5663_RECMIX1_BST1_SHIFT		0
+#define RT5663_RECMIX1_BST1_ON			(0x0)
+#define RT5663_RECMIX1_BST1_OFF			(0x1)
+
+/* RT5663: Bypass Stereo1 DAC Mixer Control (0x002d) */
+#define RT5663_DACL1_SRC_MASK			(0x1 << 3)
+#define RT5663_DACL1_SRC_SHIFT			3
+#define RT5663_DACR1_SRC_MASK			(0x1 << 2)
+#define RT5663_DACR1_SRC_SHIFT			2
+
+/* RT5663: TDM control 2 (0x0078) */
+#define RT5663_DATA_SWAP_ADCDAT1_MASK		(0x3 << 14)
+#define RT5663_DATA_SWAP_ADCDAT1_SHIFT		14
+#define RT5663_DATA_SWAP_ADCDAT1_LR		(0x0 << 14)
+#define RT5663_DATA_SWAP_ADCDAT1_RL		(0x1 << 14)
+#define RT5663_DATA_SWAP_ADCDAT1_LL		(0x2 << 14)
+#define RT5663_DATA_SWAP_ADCDAT1_RR		(0x3 << 14)
+
+/* RT5663: TDM control 5 (0x007b) */
+#define RT5663_TDM_LENGTN_MASK			(0x3)
+#define RT5663_TDM_LENGTN_SHIFT			0
+#define RT5663_TDM_LENGTN_16			(0x0)
+#define RT5663_TDM_LENGTN_20			(0x1)
+#define RT5663_TDM_LENGTN_24			(0x2)
+#define RT5663_TDM_LENGTN_32			(0x3)
+
+/* RT5663: Global Clock Control (0x0080) */
+#define RT5663_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5663_SCLK_SRC_SHIFT			14
+#define RT5663_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5663_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5663_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5663_PLL1_SRC_MASK			(0x7 << 11)
+#define RT5663_PLL1_SRC_SHIFT			11
+#define RT5663_PLL1_SRC_MCLK			(0x0 << 11)
+#define RT5663_PLL1_SRC_BCLK1			(0x1 << 11)
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5663_I2S1_ASRC_MASK			(0x1 << 11)
+#define RT5663_I2S1_ASRC_SHIFT			11
+#define RT5663_DAC_STO1_ASRC_MASK		(0x1 << 10)
+#define RT5663_DAC_STO1_ASRC_SHIFT		10
+#define RT5663_ADC_STO1_ASRC_MASK		(0x1 << 3)
+#define RT5663_ADC_STO1_ASRC_SHIFT		3
+
+/* PLL tracking mode 2 (0x0084)*/
+#define RT5663_DA_STO1_TRACK_MASK		(0x7 << 12)
+#define RT5663_DA_STO1_TRACK_SHIFT		12
+#define RT5663_DA_STO1_TRACK_SYSCLK		(0x0 << 12)
+#define RT5663_DA_STO1_TRACK_I2S1		(0x1 << 12)
+#define RT5663_AD_STO1_TRACK_MASK		(0x7)
+#define RT5663_AD_STO1_TRACK_SHIFT		0
+#define RT5663_AD_STO1_TRACK_SYSCLK		(0x0)
+#define RT5663_AD_STO1_TRACK_I2S1		(0x1)
+
+/* RT5663: HPOUT Charge pump control 1 (0x0091) */
+#define RT5663_SI_HP_MASK			(0x1 << 12)
+#define RT5663_SI_HP_SHIFT			12
+#define RT5663_SI_HP_EN				(0x1 << 12)
+#define RT5663_SI_HP_DIS			(0x0 << 12)
+
+/* RT5663: GPIO Control 2 (0x00b6) */
+#define RT5663_GP1_PIN_CONF_MASK		(0x1 << 2)
+#define RT5663_GP1_PIN_CONF_SHIFT		2
+#define RT5663_GP1_PIN_CONF_OUTPUT		(0x1 << 2)
+#define RT5663_GP1_PIN_CONF_INPUT		(0x0 << 2)
+
+/* RT5663: GPIO Control 2 (0x00b7) */
+#define RT5663_EN_IRQ_INLINE_MASK		(0x1 << 3)
+#define RT5663_EN_IRQ_INLINE_SHIFT		3
+#define RT5663_EN_IRQ_INLINE_NOR		(0x1 << 3)
+#define RT5663_EN_IRQ_INLINE_BYP		(0x0 << 3)
+
+/* RT5663: IRQ Control 1 (0x00c1) */
+#define RT5663_EN_IRQ_JD1_MASK			(0x1 << 6)
+#define RT5663_EN_IRQ_JD1_SHIFT			6
+#define RT5663_EN_IRQ_JD1_EN			(0x1 << 6)
+#define RT5663_EN_IRQ_JD1_DIS			(0x0 << 6)
+
+/* RT5663: Inline Command Function 2 (0x00dc) */
+#define RT5663_PWR_MIC_DET_MASK			(0x1)
+#define RT5663_PWR_MIC_DET_SHIFT		0
+#define RT5663_PWR_MIC_DET_ON			(0x1)
+#define RT5663_PWR_MIC_DET_OFF			(0x0)
+
+/* RT5663: Embeeded Jack and Type Detection Control 1 (0x00e6)*/
+#define RT5663_CBJ_DET_MASK			(0x1 << 15)
+#define RT5663_CBJ_DET_SHIFT			15
+#define RT5663_CBJ_DET_DIS			(0x0 << 15)
+#define RT5663_CBJ_DET_EN			(0x1 << 15)
+#define RT5663_EXT_JD_MASK			(0x1 << 11)
+#define RT5663_EXT_JD_SHIFT			11
+#define RT5663_EXT_JD_EN			(0x1 << 11)
+#define RT5663_EXT_JD_DIS			(0x0 << 11)
+#define RT5663_POL_EXT_JD_MASK			(0x1 << 10)
+#define RT5663_POL_EXT_JD_SHIFT			10
+#define RT5663_POL_EXT_JD_EN			(0x1 << 10)
+#define RT5663_POL_EXT_JD_DIS			(0x0 << 10)
+
+/* RT5663: DACREF LDO Control (0x0112)*/
+#define RT5663_PWR_LDO_DACREFL_MASK		(0x1 << 9)
+#define RT5663_PWR_LDO_DACREFL_SHIFT		9
+#define RT5663_PWR_LDO_DACREFR_MASK		(0x1 << 1)
+#define RT5663_PWR_LDO_DACREFR_SHIFT		1
+
+/* RT5663: Stereo Dynamic Range Enhancement Control 9 (0x0168, 0x0169)*/
+#define RT5663_DRE_GAIN_HP_MASK			(0x1f)
+#define RT5663_DRE_GAIN_HP_SHIFT		0
+
+/* RT5663: Combo Jack Control (0x0250) */
+#define RT5663_INBUF_CBJ_BST1_MASK		(0x1 << 11)
+#define RT5663_INBUF_CBJ_BST1_SHIFT		11
+#define RT5663_INBUF_CBJ_BST1_ON		(0x1 << 11)
+#define RT5663_INBUF_CBJ_BST1_OFF		(0x0 << 11)
+#define RT5663_CBJ_SENSE_BST1_MASK		(0x1 << 10)
+#define RT5663_CBJ_SENSE_BST1_SHIFT		10
+#define RT5663_CBJ_SENSE_BST1_L			(0x1 << 10)
+#define RT5663_CBJ_SENSE_BST1_R			(0x0 << 10)
+
+/* RT5663: Combo Jack Control (0x0251) */
+#define RT5663_GAIN_BST1_MASK			(0xf)
+#define RT5663_GAIN_BST1_SHIFT			0
+
+/* RT5663: Dummy register 1 (0x02fa) */
+#define RT5663_EMB_CLK_MASK			(0x1 << 9)
+#define RT5663_EMB_CLK_SHIFT			9
+#define RT5663_EMB_CLK_EN			(0x1 << 9)
+#define RT5663_EMB_CLK_DIS			(0x0 << 9)
+#define RT5663_HPA_CPL_BIAS_MASK		(0x7 << 6)
+#define RT5663_HPA_CPL_BIAS_SHIFT		6
+#define RT5663_HPA_CPL_BIAS_0_5			(0x0 << 6)
+#define RT5663_HPA_CPL_BIAS_1			(0x1 << 6)
+#define RT5663_HPA_CPL_BIAS_2			(0x2 << 6)
+#define RT5663_HPA_CPL_BIAS_3			(0x3 << 6)
+#define RT5663_HPA_CPL_BIAS_4_1			(0x4 << 6)
+#define RT5663_HPA_CPL_BIAS_4_2			(0x5 << 6)
+#define RT5663_HPA_CPL_BIAS_6			(0x6 << 6)
+#define RT5663_HPA_CPL_BIAS_8			(0x7 << 6)
+#define RT5663_HPA_CPR_BIAS_MASK		(0x7 << 3)
+#define RT5663_HPA_CPR_BIAS_SHIFT		3
+#define RT5663_HPA_CPR_BIAS_0_5			(0x0 << 3)
+#define RT5663_HPA_CPR_BIAS_1			(0x1 << 3)
+#define RT5663_HPA_CPR_BIAS_2			(0x2 << 3)
+#define RT5663_HPA_CPR_BIAS_3			(0x3 << 3)
+#define RT5663_HPA_CPR_BIAS_4_1			(0x4 << 3)
+#define RT5663_HPA_CPR_BIAS_4_2			(0x5 << 3)
+#define RT5663_HPA_CPR_BIAS_6			(0x6 << 3)
+#define RT5663_HPA_CPR_BIAS_8			(0x7 << 3)
+#define RT5663_DUMMY_BIAS_MASK			(0x7)
+#define RT5663_DUMMY_BIAS_SHIFT			0
+#define RT5663_DUMMY_BIAS_0_5			(0x0)
+#define RT5663_DUMMY_BIAS_1			(0x1)
+#define RT5663_DUMMY_BIAS_2			(0x2)
+#define RT5663_DUMMY_BIAS_3			(0x3)
+#define RT5663_DUMMY_BIAS_4_1			(0x4)
+#define RT5663_DUMMY_BIAS_4_2			(0x5)
+#define RT5663_DUMMY_BIAS_6			(0x6)
+#define RT5663_DUMMY_BIAS_8			(0x7)
+
+
+/* System Clock Source */
+enum {
+	RT5663_SCLK_S_MCLK,
+	RT5663_SCLK_S_PLL1,
+	RT5663_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+	RT5663_PLL1_S_MCLK,
+	RT5663_PLL1_S_BCLK1,
+};
+
+enum {
+	RT5663_AIF,
+	RT5663_AIFS,
+};
+
+/* asrc clock source */
+enum {
+	RT5663_CLK_SEL_SYS = 0x0,
+	RT5663_CLK_SEL_I2S1_ASRC = 0x1,
+};
+
+/* filter mask */
+enum {
+	RT5663_DA_STEREO_FILTER = 0x1,
+	RT5663_AD_STEREO_FILTER = 0x2,
+};
+
+int rt5663_set_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *hs_jack);
+int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec,
+	unsigned int filter_mask, unsigned int clk_src);
+
+#endif /* __RT5663_H__ */
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 8ef467f64f03..49caf1393aeb 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -2777,12 +2777,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5670 = {
 	.resume = rt5670_resume,
 	.set_bias_level = rt5670_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt5670_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5670_snd_controls),
-	.dapm_widgets = rt5670_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5670_dapm_widgets),
-	.dapm_routes = rt5670_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5670_dapm_routes),
+	.component_driver = {
+		.controls		= rt5670_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5670_snd_controls),
+		.dapm_widgets		= rt5670_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5670_dapm_widgets),
+		.dapm_routes		= rt5670_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5670_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt5670_regmap = {
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index da9483c1c6fb..abc802a5a479 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -9,6 +9,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/acpi.h>
 #include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -40,6 +41,15 @@
 
 #define RT5677_PR_BASE (RT5677_PR_RANGE_BASE + (0 * RT5677_PR_SPACING))
 
+/* GPIO indexes defined by ACPI */
+enum {
+	RT5677_GPIO_PLUG_DET		= 0,
+	RT5677_GPIO_MIC_PRESENT_L	= 1,
+	RT5677_GPIO_HOTWORD_DET_L	= 2,
+	RT5677_GPIO_DSP_INT		= 3,
+	RT5677_GPIO_HP_AMP_SHDN_L	= 4,
+};
+
 static const struct regmap_range_cfg rt5677_ranges[] = {
 	{
 		.name = "PR",
@@ -4657,7 +4667,7 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
 	return regmap_irq_get_virq(data, irq);
 }
 
-static struct gpio_chip rt5677_template_chip = {
+static const struct gpio_chip rt5677_template_chip = {
 	.label			= "rt5677",
 	.owner			= THIS_MODULE,
 	.direction_output	= rt5677_gpio_direction_out,
@@ -4974,12 +4984,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5677 = {
 	.resume = rt5677_resume,
 	.set_bias_level = rt5677_set_bias_level,
 	.idle_bias_off = true,
-	.controls = rt5677_snd_controls,
-	.num_controls = ARRAY_SIZE(rt5677_snd_controls),
-	.dapm_widgets = rt5677_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(rt5677_dapm_widgets),
-	.dapm_routes = rt5677_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes),
+	.component_driver = {
+		.controls		= rt5677_snd_controls,
+		.num_controls		= ARRAY_SIZE(rt5677_snd_controls),
+		.dapm_widgets		= rt5677_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(rt5677_dapm_widgets),
+		.dapm_routes		= rt5677_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(rt5677_dapm_routes),
+	},
 };
 
 static const struct regmap_config rt5677_regmap_physical = {
@@ -5018,10 +5030,47 @@ static const struct regmap_config rt5677_regmap = {
 static const struct i2c_device_id rt5677_i2c_id[] = {
 	{ "rt5677", RT5677 },
 	{ "rt5676", RT5676 },
+	{ "RT5677CE:00", RT5677 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
 
+static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false };
+static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false };
+static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false };
+
+static const struct acpi_gpio_mapping bdw_rt5677_gpios[] = {
+	{ "plug-det-gpios", &plug_det_gpio, 1 },
+	{ "mic-present-gpios", &mic_present_gpio, 1 },
+	{ "headphone-enable-gpios", &headphone_enable_gpio, 1 },
+	{ NULL },
+};
+
+static void rt5677_read_acpi_properties(struct rt5677_priv *rt5677,
+		struct device *dev)
+{
+	int ret;
+	u32 val;
+
+	ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev),
+			bdw_rt5677_gpios);
+	if (ret)
+		dev_warn(dev, "Failed to add driver gpios\n");
+
+	if (!device_property_read_u32(dev, "DCLK", &val))
+		rt5677->pdata.dmic2_clk_pin = val;
+
+	rt5677->pdata.in1_diff = device_property_read_bool(dev, "IN1");
+	rt5677->pdata.in2_diff = device_property_read_bool(dev, "IN2");
+	rt5677->pdata.lout1_diff = device_property_read_bool(dev, "OUT1");
+	rt5677->pdata.lout2_diff = device_property_read_bool(dev, "OUT2");
+	rt5677->pdata.lout3_diff = device_property_read_bool(dev, "OUT3");
+
+	device_property_read_u32(dev, "JD1", &rt5677->pdata.jd1_gpio);
+	device_property_read_u32(dev, "JD2", &rt5677->pdata.jd2_gpio);
+	device_property_read_u32(dev, "JD3", &rt5677->pdata.jd3_gpio);
+}
+
 static void rt5677_read_device_properties(struct rt5677_priv *rt5677,
 		struct device *dev)
 {
@@ -5127,8 +5176,12 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 
 	if (pdata)
 		rt5677->pdata = *pdata;
-	else
+	else if (i2c->dev.of_node)
 		rt5677_read_device_properties(rt5677, &i2c->dev);
+	else if (ACPI_HANDLE(&i2c->dev))
+		rt5677_read_acpi_properties(rt5677, &i2c->dev);
+	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/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 527b759c1562..1589325855bc 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -411,6 +411,8 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
 			0, 8,
 			0x7f, 1,
 			headphone_volume),
+	SOC_SINGLE("Headphone Playback Switch", SGTL5000_CHIP_ANA_CTRL,
+			4, 1, 1),
 	SOC_SINGLE("Headphone Playback ZC Switch", SGTL5000_CHIP_ANA_CTRL,
 			5, 1, 0),
 
@@ -423,6 +425,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
 			SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT,
 			0x1f, 1,
 			lineout_volume),
+	SOC_SINGLE("Lineout Playback Switch", SGTL5000_CHIP_ANA_CTRL, 8, 1, 1),
 };
 
 /* mute the codec used by alsa core */
@@ -1151,12 +1154,14 @@ static struct snd_soc_codec_driver sgtl5000_driver = {
 	.remove = sgtl5000_remove,
 	.set_bias_level = sgtl5000_set_bias_level,
 	.suspend_bias_off = true,
-	.controls = sgtl5000_snd_controls,
-	.num_controls = ARRAY_SIZE(sgtl5000_snd_controls),
-	.dapm_widgets = sgtl5000_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(sgtl5000_dapm_widgets),
-	.dapm_routes = sgtl5000_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(sgtl5000_dapm_routes),
+	.component_driver = {
+		.controls		= sgtl5000_snd_controls,
+		.num_controls		= ARRAY_SIZE(sgtl5000_snd_controls),
+		.dapm_widgets		= sgtl5000_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(sgtl5000_dapm_widgets),
+		.dapm_routes		= sgtl5000_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(sgtl5000_dapm_routes),
+	},
 };
 
 static const struct regmap_config sgtl5000_regmap = {
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index a8402d0af0ea..5344f4aa8fde 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -238,10 +238,12 @@ static struct regmap *si476x_get_regmap(struct device *dev)
 
 static struct snd_soc_codec_driver soc_codec_dev_si476x = {
 	.get_regmap = si476x_get_regmap,
-	.dapm_widgets = si476x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets),
-	.dapm_routes = si476x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(si476x_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= si476x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(si476x_dapm_widgets),
+		.dapm_routes		= si476x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(si476x_dapm_routes),
+	},
 };
 
 static int si476x_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
index 3a7de0159f24..eae54c37cff9 100644
--- a/sound/soc/codecs/sn95031.c
+++ b/sound/soc/codecs/sn95031.c
@@ -888,12 +888,14 @@ static struct snd_soc_codec_driver sn95031_codec = {
 	.set_bias_level	= sn95031_set_vaud_bias,
 	.idle_bias_off	= true,
 
-	.controls	= sn95031_snd_controls,
-	.num_controls	= ARRAY_SIZE(sn95031_snd_controls),
-	.dapm_widgets	= sn95031_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(sn95031_dapm_widgets),
-	.dapm_routes	= sn95031_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(sn95031_audio_map),
+	.component_driver = {
+		.controls		= sn95031_snd_controls,
+		.num_controls		= ARRAY_SIZE(sn95031_snd_controls),
+		.dapm_widgets		= sn95031_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(sn95031_dapm_widgets),
+		.dapm_routes		= sn95031_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(sn95031_audio_map),
+	},
 };
 
 static int sn95031_device_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c
index 3ec41ccbf4e2..234f87b54838 100644
--- a/sound/soc/codecs/spdif_receiver.c
+++ b/sound/soc/codecs/spdif_receiver.c
@@ -38,10 +38,12 @@ static const struct snd_soc_dapm_route dir_routes[] = {
 			SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
 
 static struct snd_soc_codec_driver soc_codec_spdif_dir = {
-	.dapm_widgets = dir_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(dir_widgets),
-	.dapm_routes = dir_routes,
-	.num_dapm_routes = ARRAY_SIZE(dir_routes),
+	.component_driver = {
+		.dapm_widgets		= dir_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(dir_widgets),
+		.dapm_routes		= dir_routes,
+		.num_dapm_routes	= ARRAY_SIZE(dir_routes),
+	},
 };
 
 static struct snd_soc_dai_driver dir_stub_dai = {
diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c
index ef634a9ad673..ee367536a498 100644
--- a/sound/soc/codecs/spdif_transmitter.c
+++ b/sound/soc/codecs/spdif_transmitter.c
@@ -38,10 +38,12 @@ static const struct snd_soc_dapm_route dit_routes[] = {
 };
 
 static struct snd_soc_codec_driver soc_codec_spdif_dit = {
-	.dapm_widgets = dit_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(dit_widgets),
-	.dapm_routes = dit_routes,
-	.num_dapm_routes = ARRAY_SIZE(dit_routes),
+	.component_driver = {
+		.dapm_widgets		= dit_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(dit_widgets),
+		.dapm_routes		= dit_routes,
+		.num_dapm_routes	= ARRAY_SIZE(dit_routes),
+	},
 };
 
 static struct snd_soc_dai_driver dit_stub_dai = {
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index e2e0bfa7ec20..38a85f3adc80 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -715,12 +715,14 @@ static struct snd_soc_codec_driver ssm2518_codec_driver = {
 	.set_sysclk = ssm2518_set_sysclk,
 	.idle_bias_off = true,
 
-	.controls = ssm2518_snd_controls,
-	.num_controls = ARRAY_SIZE(ssm2518_snd_controls),
-	.dapm_widgets = ssm2518_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ssm2518_dapm_widgets),
-	.dapm_routes = ssm2518_routes,
-	.num_dapm_routes = ARRAY_SIZE(ssm2518_routes),
+	.component_driver = {
+		.controls		= ssm2518_snd_controls,
+		.num_controls		= ARRAY_SIZE(ssm2518_snd_controls),
+		.dapm_widgets		= ssm2518_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ssm2518_dapm_widgets),
+		.dapm_routes		= ssm2518_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ssm2518_routes),
+	},
 };
 
 static const struct regmap_config ssm2518_regmap_config = {
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 4452fea0b118..993bde29ca1b 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -597,12 +597,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
 	.set_bias_level = ssm2602_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = ssm260x_snd_controls,
-	.num_controls = ARRAY_SIZE(ssm260x_snd_controls),
-	.dapm_widgets = ssm260x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ssm260x_dapm_widgets),
-	.dapm_routes = ssm260x_routes,
-	.num_dapm_routes = ARRAY_SIZE(ssm260x_routes),
+	.component_driver = {
+		.controls		= ssm260x_snd_controls,
+		.num_controls		= ARRAY_SIZE(ssm260x_snd_controls),
+		.dapm_widgets		= ssm260x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ssm260x_dapm_widgets),
+		.dapm_routes		= ssm260x_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ssm260x_routes),
+	},
 };
 
 static bool ssm2602_register_volatile(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
index 080c78e88e10..2bb5a11c9ba1 100644
--- a/sound/soc/codecs/ssm4567.c
+++ b/sound/soc/codecs/ssm4567.c
@@ -421,12 +421,14 @@ static struct snd_soc_codec_driver ssm4567_codec_driver = {
 	.set_bias_level = ssm4567_set_bias_level,
 	.idle_bias_off = true,
 
-	.controls = ssm4567_snd_controls,
-	.num_controls = ARRAY_SIZE(ssm4567_snd_controls),
-	.dapm_widgets = ssm4567_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(ssm4567_dapm_widgets),
-	.dapm_routes = ssm4567_routes,
-	.num_dapm_routes = ARRAY_SIZE(ssm4567_routes),
+	.component_driver = {
+		.controls		= ssm4567_snd_controls,
+		.num_controls		= ARRAY_SIZE(ssm4567_snd_controls),
+		.dapm_widgets		= ssm4567_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(ssm4567_dapm_widgets),
+		.dapm_routes		= ssm4567_routes,
+		.num_dapm_routes	= ARRAY_SIZE(ssm4567_routes),
+	},
 };
 
 static const struct regmap_config ssm4567_regmap_config = {
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index a9844b2ac829..0790ae8530d9 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -991,12 +991,14 @@ static const struct snd_soc_codec_driver sta32x_codec = {
 	.remove =		sta32x_remove,
 	.set_bias_level =	sta32x_set_bias_level,
 	.suspend_bias_off =	true,
-	.controls =		sta32x_snd_controls,
-	.num_controls =		ARRAY_SIZE(sta32x_snd_controls),
-	.dapm_widgets =		sta32x_dapm_widgets,
-	.num_dapm_widgets =	ARRAY_SIZE(sta32x_dapm_widgets),
-	.dapm_routes =		sta32x_dapm_routes,
-	.num_dapm_routes =	ARRAY_SIZE(sta32x_dapm_routes),
+	.component_driver = {
+		.controls =		sta32x_snd_controls,
+		.num_controls =		ARRAY_SIZE(sta32x_snd_controls),
+		.dapm_widgets =		sta32x_dapm_widgets,
+		.num_dapm_widgets =	ARRAY_SIZE(sta32x_dapm_widgets),
+		.dapm_routes =		sta32x_dapm_routes,
+		.num_dapm_routes =	ARRAY_SIZE(sta32x_dapm_routes),
+	},
 };
 
 static const struct regmap_config sta32x_regmap = {
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index 33a4612f0a07..9644c20f44e3 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -1057,12 +1057,14 @@ static const struct snd_soc_codec_driver sta350_codec = {
 	.remove =		sta350_remove,
 	.set_bias_level =	sta350_set_bias_level,
 	.suspend_bias_off =	true,
-	.controls =		sta350_snd_controls,
-	.num_controls =		ARRAY_SIZE(sta350_snd_controls),
-	.dapm_widgets =		sta350_dapm_widgets,
-	.num_dapm_widgets =	ARRAY_SIZE(sta350_dapm_widgets),
-	.dapm_routes =		sta350_dapm_routes,
-	.num_dapm_routes =	ARRAY_SIZE(sta350_dapm_routes),
+	.component_driver = {
+		.controls =		sta350_snd_controls,
+		.num_controls =		ARRAY_SIZE(sta350_snd_controls),
+		.dapm_widgets =		sta350_dapm_widgets,
+		.num_dapm_widgets =	ARRAY_SIZE(sta350_dapm_widgets),
+		.dapm_routes =		sta350_dapm_routes,
+		.num_dapm_routes =	ARRAY_SIZE(sta350_dapm_routes),
+	},
 };
 
 static const struct regmap_config sta350_regmap = {
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 2cdaca943a8c..d4b384e4b266 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -317,8 +317,10 @@ static const struct snd_soc_codec_driver sta529_codec_driver = {
 	.set_bias_level = sta529_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = sta529_snd_controls,
-	.num_controls = ARRAY_SIZE(sta529_snd_controls),
+	.component_driver = {
+		.controls		= sta529_snd_controls,
+		.num_controls		= ARRAY_SIZE(sta529_snd_controls),
+	},
 };
 
 static const struct regmap_config sta529_regmap = {
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index 0945c51df003..27f30d352867 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -85,10 +85,10 @@ static SOC_ENUM_SINGLE_DECL(stac9766_boost2_enum,
 static SOC_ENUM_SINGLE_DECL(stac9766_stereo_mic_enum,
 			    AC97_STAC_STEREO_MIC, 2, stac9766_stereo_mic);
 
-static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0);
-static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250);
-static const DECLARE_TLV_DB_LINEAR(beep_tlv, -4500, 0);
-static const DECLARE_TLV_DB_LINEAR(mix_tlv, -3450, 1200);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(master_tlv, -4650, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(record_tlv,     0, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(beep_tlv,   -4500, 300, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(mix_tlv,    -3450, 150, 0);
 
 static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = {
 	SOC_DOUBLE_TLV("Speaker Volume", AC97_MASTER, 8, 0, 31, 1, master_tlv),
@@ -320,8 +320,10 @@ static int stac9766_codec_remove(struct snd_soc_codec *codec)
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
-	.controls = stac9766_snd_ac97_controls,
-	.num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls),
+	.component_driver = {
+		.controls		= stac9766_snd_ac97_controls,
+		.num_controls		= ARRAY_SIZE(stac9766_snd_ac97_controls),
+	},
 	.write = stac9766_ac97_write,
 	.read = stac9766_ac97_read,
 	.set_bias_level = stac9766_set_bias_level,
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
index 160d61a66204..7b31ee9b82bc 100644
--- a/sound/soc/codecs/sti-sas.c
+++ b/sound/soc/codecs/sti-sas.c
@@ -591,11 +591,11 @@ static int sti_sas_driver_probe(struct platform_device *pdev)
 	sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
 
 	/* Set dapms*/
-	sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
-	sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
+	sti_sas_driver.component_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
+	sti_sas_driver.component_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
 
-	sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes;
-	sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
+	sti_sas_driver.component_driver.dapm_routes = drvdata->dev_data->dapm_routes;
+	sti_sas_driver.component_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
 
 	/* Store context */
 	dev_set_drvdata(&pdev->dev, drvdata);
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index cc1d3981fa4b..baf455e8c2f7 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -667,12 +667,14 @@ static struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
 	.resume = tas2552_resume,
 	.ignore_pmdown_time = true,
 
-	.controls = tas2552_snd_controls,
-	.num_controls = ARRAY_SIZE(tas2552_snd_controls),
-	.dapm_widgets = tas2552_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(tas2552_dapm_widgets),
-	.dapm_routes = tas2552_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(tas2552_audio_map),
+	.component_driver = {
+		.controls		= tas2552_snd_controls,
+		.num_controls		= ARRAY_SIZE(tas2552_snd_controls),
+		.dapm_widgets		= tas2552_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(tas2552_dapm_widgets),
+		.dapm_routes		= tas2552_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(tas2552_audio_map),
+	},
 };
 
 static const struct regmap_config tas2552_regmap_config = {
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index 1666ea697647..b7de857abb16 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -890,12 +890,14 @@ static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
 	.remove			= tas5086_remove,
 	.suspend		= tas5086_soc_suspend,
 	.resume			= tas5086_soc_resume,
-	.controls		= tas5086_controls,
-	.num_controls		= ARRAY_SIZE(tas5086_controls),
-	.dapm_widgets		= tas5086_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(tas5086_dapm_widgets),
-	.dapm_routes		= tas5086_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(tas5086_dapm_routes),
+	.component_driver = {
+		.controls		= tas5086_controls,
+		.num_controls		= ARRAY_SIZE(tas5086_controls),
+		.dapm_widgets		= tas5086_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(tas5086_dapm_widgets),
+		.dapm_routes		= tas5086_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(tas5086_dapm_routes),
+	},
 };
 
 static const struct i2c_device_id tas5086_i2c_id[] = {
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c
index d8baca3f8413..df5e5cb33baa 100644
--- a/sound/soc/codecs/tas571x.c
+++ b/sound/soc/codecs/tas571x.c
@@ -658,10 +658,12 @@ static const struct snd_soc_codec_driver tas571x_codec = {
 	.set_bias_level = tas571x_set_bias_level,
 	.idle_bias_off = true,
 
-	.dapm_widgets = tas571x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(tas571x_dapm_widgets),
-	.dapm_routes = tas571x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(tas571x_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= tas571x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(tas571x_dapm_widgets),
+		.dapm_routes		= tas571x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(tas571x_dapm_routes),
+	},
 };
 
 static struct snd_soc_dai_driver tas571x_dai = {
@@ -754,8 +756,8 @@ static int tas571x_i2c_probe(struct i2c_client *client,
 
 
 	memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver));
-	priv->codec_driver.controls = priv->chip->controls;
-	priv->codec_driver.num_controls = priv->chip->num_controls;
+	priv->codec_driver.component_driver.controls = priv->chip->controls;
+	priv->codec_driver.component_driver.num_controls = priv->chip->num_controls;
 
 	if (priv->chip->vol_reg_size == 2) {
 		/*
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c
index f54fb46b77c2..c65b917598d2 100644
--- a/sound/soc/codecs/tas5720.c
+++ b/sound/soc/codecs/tas5720.c
@@ -489,12 +489,14 @@ static struct snd_soc_codec_driver soc_codec_dev_tas5720 = {
 	.suspend = tas5720_suspend,
 	.resume = tas5720_resume,
 
-	.controls = tas5720_snd_controls,
-	.num_controls = ARRAY_SIZE(tas5720_snd_controls),
-	.dapm_widgets = tas5720_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets),
-	.dapm_routes = tas5720_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(tas5720_audio_map),
+	.component_driver = {
+		.controls		= tas5720_snd_controls,
+		.num_controls		= ARRAY_SIZE(tas5720_snd_controls),
+		.dapm_widgets		= tas5720_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(tas5720_dapm_widgets),
+		.dapm_routes		= tas5720_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(tas5720_audio_map),
+	},
 };
 
 /* PCM rates supported by the TAS5720 driver */
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
index cb5310d89c0f..95e0a7abeb7a 100644
--- a/sound/soc/codecs/tfa9879.c
+++ b/sound/soc/codecs/tfa9879.c
@@ -231,13 +231,14 @@ static const struct snd_soc_dapm_route tfa9879_dapm_routes[] = {
 };
 
 static const struct snd_soc_codec_driver tfa9879_codec = {
-	.controls = tfa9879_controls,
-	.num_controls = ARRAY_SIZE(tfa9879_controls),
-
-	.dapm_widgets = tfa9879_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(tfa9879_dapm_widgets),
-	.dapm_routes = tfa9879_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(tfa9879_dapm_routes),
+	.component_driver = {
+		.controls		= tfa9879_controls,
+		.num_controls		= ARRAY_SIZE(tfa9879_controls),
+		.dapm_widgets		= tfa9879_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(tfa9879_dapm_widgets),
+		.dapm_routes		= tfa9879_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(tfa9879_dapm_routes),
+	},
 };
 
 static const struct regmap_config tfa9879_regmap = {
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index cd8c02b6e4de..410cae0f2060 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -583,12 +583,14 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
 	.set_bias_level = tlv320aic23_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = tlv320aic23_snd_controls,
-	.num_controls = ARRAY_SIZE(tlv320aic23_snd_controls),
-	.dapm_widgets = tlv320aic23_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
-	.dapm_routes = tlv320aic23_intercon,
-	.num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),
+	.component_driver = {
+		.controls		= tlv320aic23_snd_controls,
+		.num_controls		= ARRAY_SIZE(tlv320aic23_snd_controls),
+		.dapm_widgets		= tlv320aic23_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(tlv320aic23_dapm_widgets),
+		.dapm_routes		= tlv320aic23_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(tlv320aic23_intercon),
+	},
 };
 
 int tlv320aic23_probe(struct device *dev, struct regmap *regmap)
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 2c904d7150ad..14aa96d41719 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -321,12 +321,14 @@ static int aic26_probe(struct snd_soc_codec *codec)
 
 static struct snd_soc_codec_driver aic26_soc_codec_dev = {
 	.probe = aic26_probe,
-	.controls = aic26_snd_controls,
-	.num_controls = ARRAY_SIZE(aic26_snd_controls),
-	.dapm_widgets = tlv320aic26_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(tlv320aic26_dapm_widgets),
-	.dapm_routes = tlv320aic26_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(tlv320aic26_dapm_routes),
+	.component_driver = {
+		.controls		= aic26_snd_controls,
+		.num_controls		= ARRAY_SIZE(aic26_snd_controls),
+		.dapm_widgets		= tlv320aic26_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(tlv320aic26_dapm_widgets),
+		.dapm_routes		= tlv320aic26_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(tlv320aic26_dapm_routes),
+	},
 };
 
 static const struct regmap_config aic26_regmap = {
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 3c5e1df01c19..be1a64bfd320 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -273,10 +273,20 @@ static const DECLARE_TLV_DB_SCALE(sp_vol_tlv, -6350, 50, 0);
 /*
  * controls to be exported to the user space
  */
-static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
+static const struct snd_kcontrol_new common31xx_snd_controls[] = {
 	SOC_DOUBLE_R_S_TLV("DAC Playback Volume", AIC31XX_LDACVOL,
 			   AIC31XX_RDACVOL, 0, -127, 48, 7, 0, dac_vol_tlv),
 
+	SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN,
+		     AIC31XX_HPRGAIN, 2, 1, 0),
+	SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN,
+			 AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv),
+
+	SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL,
+			 AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
 	SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1,
 		       adc_fgain_tlv),
 
@@ -286,14 +296,6 @@ static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
 
 	SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0,
 		       119, 0, mic_pga_tlv),
-
-	SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN,
-		     AIC31XX_HPRGAIN, 2, 1, 0),
-	SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN,
-			 AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv),
-
-	SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL,
-			 AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv),
 };
 
 static const struct snd_kcontrol_new aic311x_snd_controls[] = {
@@ -397,17 +399,28 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-static const struct snd_kcontrol_new left_output_switches[] = {
+static const struct snd_kcontrol_new aic31xx_left_output_switches[] = {
 	SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0),
 	SOC_DAPM_SINGLE("From MIC1LP", AIC31XX_DACMIXERROUTE, 5, 1, 0),
 	SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 4, 1, 0),
 };
 
-static const struct snd_kcontrol_new right_output_switches[] = {
+static const struct snd_kcontrol_new aic31xx_right_output_switches[] = {
 	SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0),
 	SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 1, 1, 0),
 };
 
+static const struct snd_kcontrol_new dac31xx_left_output_switches[] = {
+	SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0),
+	SOC_DAPM_SINGLE("From AIN1", AIC31XX_DACMIXERROUTE, 5, 1, 0),
+	SOC_DAPM_SINGLE("From AIN2", AIC31XX_DACMIXERROUTE, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac31xx_right_output_switches[] = {
+	SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0),
+	SOC_DAPM_SINGLE("From AIN2", AIC31XX_DACMIXERROUTE, 1, 1, 0),
+};
+
 static const struct snd_kcontrol_new p_term_mic1lp =
 	SOC_DAPM_ENUM("MIC1LP P-Terminal", mic1lp_p_enum);
 
@@ -457,7 +470,7 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget common31xx_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
 
 	SND_SOC_DAPM_MUX("DAC Left Input",
@@ -473,14 +486,7 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
 			   AIC31XX_DACSETUP, 6, 0, aic31xx_dapm_power_event,
 			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
-	/* Output Mixers */
-	SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
-			   left_output_switches,
-			   ARRAY_SIZE(left_output_switches)),
-	SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
-			   right_output_switches,
-			   ARRAY_SIZE(right_output_switches)),
-
+	/* HP */
 	SND_SOC_DAPM_SWITCH("HP Left", SND_SOC_NOPM, 0, 0,
 			    &aic31xx_dapm_hpl_switch),
 	SND_SOC_DAPM_SWITCH("HP Right", SND_SOC_NOPM, 0, 0,
@@ -494,10 +500,34 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
 			       NULL, 0, aic31xx_dapm_power_event,
 			       SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
 
-	/* ADC */
-	SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0,
-			   aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
-			   SND_SOC_DAPM_POST_PMD),
+	/* Mic Bias */
+	SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+static const struct snd_soc_dapm_widget dac31xx_dapm_widgets[] = {
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("AIN1"),
+	SND_SOC_DAPM_INPUT("AIN2"),
+
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
+			   dac31xx_left_output_switches,
+			   ARRAY_SIZE(dac31xx_left_output_switches)),
+	SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
+			   dac31xx_right_output_switches,
+			   ARRAY_SIZE(dac31xx_right_output_switches)),
+};
+
+static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("MIC1LP"),
+	SND_SOC_DAPM_INPUT("MIC1RP"),
+	SND_SOC_DAPM_INPUT("MIC1LM"),
 
 	/* Input Selection to MIC_PGA */
 	SND_SOC_DAPM_MUX("MIC1LP P-Terminal", SND_SOC_NOPM, 0, 0,
@@ -507,24 +537,25 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
 	SND_SOC_DAPM_MUX("MIC1LM P-Terminal", SND_SOC_NOPM, 0, 0,
 			 &p_term_mic1lm),
 
+	/* ADC */
+	SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0,
+			   aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+
 	SND_SOC_DAPM_MUX("MIC1LM M-Terminal", SND_SOC_NOPM, 0, 0,
 			 &m_term_mic1lm),
+
 	/* Enabling & Disabling MIC Gain Ctl */
 	SND_SOC_DAPM_PGA("MIC_GAIN_CTL", AIC31XX_MICPGA,
 			 7, 1, NULL, 0),
 
-	/* Mic Bias */
-	SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event,
-			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-
-	/* Outputs */
-	SND_SOC_DAPM_OUTPUT("HPL"),
-	SND_SOC_DAPM_OUTPUT("HPR"),
-
-	/* Inputs */
-	SND_SOC_DAPM_INPUT("MIC1LP"),
-	SND_SOC_DAPM_INPUT("MIC1RP"),
-	SND_SOC_DAPM_INPUT("MIC1LM"),
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
+			   aic31xx_left_output_switches,
+			   ARRAY_SIZE(aic31xx_left_output_switches)),
+	SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
+			   aic31xx_right_output_switches,
+			   ARRAY_SIZE(aic31xx_right_output_switches)),
 };
 
 static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = {
@@ -554,7 +585,7 @@ static const struct snd_soc_dapm_widget aic310x_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route
-aic31xx_audio_map[] = {
+common31xx_audio_map[] = {
 	/* DAC Input Routing */
 	{"DAC Left Input", "Left Data", "DAC IN"},
 	{"DAC Left Input", "Right Data", "DAC IN"},
@@ -565,6 +596,31 @@ aic31xx_audio_map[] = {
 	{"DAC Left", NULL, "DAC Left Input"},
 	{"DAC Right", NULL, "DAC Right Input"},
 
+	/* HPL path */
+	{"HP Left", "Switch", "Output Left"},
+	{"HPL Driver", NULL, "HP Left"},
+	{"HPL", NULL, "HPL Driver"},
+
+	/* HPR path */
+	{"HP Right", "Switch", "Output Right"},
+	{"HPR Driver", NULL, "HP Right"},
+	{"HPR", NULL, "HPR Driver"},
+};
+
+static const struct snd_soc_dapm_route
+dac31xx_audio_map[] = {
+	/* Left Output */
+	{"Output Left", "From Left DAC", "DAC Left"},
+	{"Output Left", "From AIN1", "AIN1"},
+	{"Output Left", "From AIN2", "AIN2"},
+
+	/* Right Output */
+	{"Output Right", "From Right DAC", "DAC Right"},
+	{"Output Right", "From AIN2", "AIN2"},
+};
+
+static const struct snd_soc_dapm_route
+aic31xx_audio_map[] = {
 	/* Mic input */
 	{"MIC1LP P-Terminal", "FFR 10 Ohm", "MIC1LP"},
 	{"MIC1LP P-Terminal", "FFR 20 Ohm", "MIC1LP"},
@@ -595,16 +651,6 @@ aic31xx_audio_map[] = {
 	/* Right Output */
 	{"Output Right", "From Right DAC", "DAC Right"},
 	{"Output Right", "From MIC1RP", "MIC1RP"},
-
-	/* HPL path */
-	{"HP Left", "Switch", "Output Left"},
-	{"HPL Driver", NULL, "HP Left"},
-	{"HPL", NULL, "HPL Driver"},
-
-	/* HPR path */
-	{"HP Right", "Switch", "Output Right"},
-	{"HPR Driver", NULL, "HP Right"},
-	{"HPR", NULL, "HPR Driver"},
 };
 
 static const struct snd_soc_dapm_route
@@ -633,6 +679,13 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec)
 	int ret = 0;
 	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
 
+	if (!(aic31xx->pdata.codec_type & DAC31XX_BIT))
+		ret = snd_soc_add_codec_controls(
+			codec, aic31xx_snd_controls,
+			ARRAY_SIZE(aic31xx_snd_controls));
+	if (ret)
+		return ret;
+
 	if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT)
 		ret = snd_soc_add_codec_controls(
 			codec, aic311x_snd_controls,
@@ -651,6 +704,30 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec)
 	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
 	int ret = 0;
 
+	if (aic31xx->pdata.codec_type & DAC31XX_BIT) {
+		ret = snd_soc_dapm_new_controls(
+			dapm, dac31xx_dapm_widgets,
+			ARRAY_SIZE(dac31xx_dapm_widgets));
+		if (ret)
+			return ret;
+
+		ret = snd_soc_dapm_add_routes(dapm, dac31xx_audio_map,
+					      ARRAY_SIZE(dac31xx_audio_map));
+		if (ret)
+			return ret;
+	} else {
+		ret = snd_soc_dapm_new_controls(
+			dapm, aic31xx_dapm_widgets,
+			ARRAY_SIZE(aic31xx_dapm_widgets));
+		if (ret)
+			return ret;
+
+		ret = snd_soc_dapm_add_routes(dapm, aic31xx_audio_map,
+					      ARRAY_SIZE(aic31xx_audio_map));
+		if (ret)
+			return ret;
+	}
+
 	if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
 		ret = snd_soc_dapm_new_controls(
 			dapm, aic311x_dapm_widgets,
@@ -1114,12 +1191,14 @@ static struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
 	.set_bias_level		= aic31xx_set_bias_level,
 	.suspend_bias_off	= true,
 
-	.controls		= aic31xx_snd_controls,
-	.num_controls		= ARRAY_SIZE(aic31xx_snd_controls),
-	.dapm_widgets		= aic31xx_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(aic31xx_dapm_widgets),
-	.dapm_routes		= aic31xx_audio_map,
-	.num_dapm_routes	= ARRAY_SIZE(aic31xx_audio_map),
+	.component_driver = {
+		.controls		= common31xx_snd_controls,
+		.num_controls		= ARRAY_SIZE(common31xx_snd_controls),
+		.dapm_widgets		= common31xx_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(common31xx_dapm_widgets),
+		.dapm_routes		= common31xx_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(common31xx_audio_map),
+	},
 };
 
 static const struct snd_soc_dai_ops aic31xx_dai_ops = {
@@ -1129,19 +1208,34 @@ static const struct snd_soc_dai_ops aic31xx_dai_ops = {
 	.digital_mute	= aic31xx_dac_mute,
 };
 
+static struct snd_soc_dai_driver dac31xx_dai_driver[] = {
+	{
+		.name = "tlv32dac31xx-hifi",
+		.playback = {
+			.stream_name	 = "Playback",
+			.channels_min	 = 2,
+			.channels_max	 = 2,
+			.rates		 = AIC31XX_RATES,
+			.formats	 = AIC31XX_FORMATS,
+		},
+		.ops = &aic31xx_dai_ops,
+		.symmetric_rates = 1,
+	}
+};
+
 static struct snd_soc_dai_driver aic31xx_dai_driver[] = {
 	{
 		.name = "tlv320aic31xx-hifi",
 		.playback = {
 			.stream_name	 = "Playback",
-			.channels_min	 = 1,
+			.channels_min	 = 2,
 			.channels_max	 = 2,
 			.rates		 = AIC31XX_RATES,
 			.formats	 = AIC31XX_FORMATS,
 		},
 		.capture = {
 			.stream_name	 = "Capture",
-			.channels_min	 = 1,
+			.channels_min	 = 2,
 			.channels_max	 = 2,
 			.rates		 = AIC31XX_RATES,
 			.formats	 = AIC31XX_FORMATS,
@@ -1259,9 +1353,16 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
 	if (ret)
 		return ret;
 
-	return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx,
-				     aic31xx_dai_driver,
-				     ARRAY_SIZE(aic31xx_dai_driver));
+	if (aic31xx->pdata.codec_type & DAC31XX_BIT)
+		return snd_soc_register_codec(&i2c->dev,
+				&soc_codec_driver_aic31xx,
+				dac31xx_dai_driver,
+				ARRAY_SIZE(dac31xx_dai_driver));
+	else
+		return snd_soc_register_codec(&i2c->dev,
+				&soc_codec_driver_aic31xx,
+				aic31xx_dai_driver,
+				ARRAY_SIZE(aic31xx_dai_driver));
 }
 
 static int aic31xx_i2c_remove(struct i2c_client *i2c)
@@ -1277,6 +1378,7 @@ static const struct i2c_device_id aic31xx_i2c_id[] = {
 	{ "tlv320aic3110", AIC3110 },
 	{ "tlv320aic3120", AIC3120 },
 	{ "tlv320aic3111", AIC3111 },
+	{ "tlv320dac3100", DAC3100 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index ac9b146526eb..5acd5b69fb83 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -24,12 +24,14 @@
 
 #define AIC31XX_STEREO_CLASS_D_BIT	0x1
 #define AIC31XX_MINIDSP_BIT		0x2
+#define DAC31XX_BIT			0x4
 
 enum aic31xx_type {
 	AIC3100	= 0,
 	AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
 	AIC3120 = AIC31XX_MINIDSP_BIT,
 	AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT),
+	DAC3100 = DAC31XX_BIT,
 };
 
 struct aic31xx_pdata {
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 85d4978d0384..28fdfc5ec544 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -797,12 +797,14 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
 	.set_bias_level = aic32x4_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = aic32x4_snd_controls,
-	.num_controls = ARRAY_SIZE(aic32x4_snd_controls),
-	.dapm_widgets = aic32x4_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets),
-	.dapm_routes = aic32x4_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),
+	.component_driver = {
+		.controls		= aic32x4_snd_controls,
+		.num_controls		= ARRAY_SIZE(aic32x4_snd_controls),
+		.dapm_widgets		= aic32x4_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(aic32x4_dapm_widgets),
+		.dapm_routes		= aic32x4_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(aic32x4_dapm_routes),
+	},
 };
 
 static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index a564759845f9..5a8d96ec058c 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1670,12 +1670,14 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
 	.idle_bias_off = true,
 	.probe = aic3x_probe,
 	.remove = aic3x_remove,
-	.controls = aic3x_snd_controls,
-	.num_controls = ARRAY_SIZE(aic3x_snd_controls),
-	.dapm_widgets = aic3x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets),
-	.dapm_routes = intercon,
-	.num_dapm_routes = ARRAY_SIZE(intercon),
+	.component_driver = {
+		.controls		= aic3x_snd_controls,
+		.num_controls		= ARRAY_SIZE(aic3x_snd_controls),
+		.dapm_widgets		= aic3x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(aic3x_dapm_widgets),
+		.dapm_routes		= intercon,
+		.num_dapm_routes	= ARRAY_SIZE(intercon),
+	},
 };
 
 /*
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index f7a6ce7e5fb1..7bcf01efdf9a 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -90,7 +90,6 @@ static const char *dac33_supply_names[DAC33_NUM_SUPPLIES] = {
 
 struct tlv320dac33_priv {
 	struct mutex mutex;
-	struct workqueue_struct *dac33_wq;
 	struct work_struct work;
 	struct snd_soc_codec *codec;
 	struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
@@ -771,7 +770,7 @@ static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
 
 	/* Do not schedule the workqueue in Mode7 */
 	if (dac33->fifo_mode != DAC33_FIFO_MODE7)
-		queue_work(dac33->dac33_wq, &dac33->work);
+		schedule_work(&dac33->work);
 
 	return IRQ_HANDLED;
 }
@@ -1127,7 +1126,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		if (dac33->fifo_mode) {
 			dac33->state = DAC33_PREFILL;
-			queue_work(dac33->dac33_wq, &dac33->work);
+			schedule_work(&dac33->work);
 		}
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
@@ -1135,7 +1134,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		if (dac33->fifo_mode) {
 			dac33->state = DAC33_FLUSH;
-			queue_work(dac33->dac33_wq, &dac33->work);
+			schedule_work(&dac33->work);
 		}
 		break;
 	default:
@@ -1410,14 +1409,6 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
 			dac33->irq = -1;
 		}
 		if (dac33->irq != -1) {
-			/* Setup work queue */
-			dac33->dac33_wq =
-				create_singlethread_workqueue("tlv320dac33");
-			if (dac33->dac33_wq == NULL) {
-				free_irq(dac33->irq, codec);
-				return -ENOMEM;
-			}
-
 			INIT_WORK(&dac33->work, dac33_work);
 		}
 	}
@@ -1437,7 +1428,7 @@ static int dac33_soc_remove(struct snd_soc_codec *codec)
 
 	if (dac33->irq >= 0) {
 		free_irq(dac33->irq, dac33->codec);
-		destroy_workqueue(dac33->dac33_wq);
+		flush_work(&dac33->work);
 	}
 	return 0;
 }
@@ -1453,12 +1444,14 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
 	.probe = dac33_soc_probe,
 	.remove = dac33_soc_remove,
 
-	.controls = dac33_snd_controls,
-	.num_controls = ARRAY_SIZE(dac33_snd_controls),
-	.dapm_widgets = dac33_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(dac33_dapm_widgets),
-	.dapm_routes = audio_map,
-	.num_dapm_routes = ARRAY_SIZE(audio_map),
+	.component_driver = {
+		.controls		= dac33_snd_controls,
+		.num_controls		= ARRAY_SIZE(dac33_snd_controls),
+		.dapm_widgets		= dac33_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(dac33_dapm_widgets),
+		.dapm_routes		= audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(audio_map),
+	},
 };
 
 #define DAC33_RATES	(SNDRV_PCM_RATE_44100 | \
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index f1ea052a822e..3b6faed91d7e 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -52,7 +52,7 @@ struct tpa6130a2_data {
 
 static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable)
 {
-	int ret;
+	int ret = 0, ret2;
 
 	if (enable) {
 		ret = regulator_enable(data->supply);
@@ -64,20 +64,34 @@ static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable)
 		/* Power on */
 		if (data->power_gpio >= 0)
 			gpio_set_value(data->power_gpio, 1);
+
+		/* Sync registers */
+		regcache_cache_only(data->regmap, false);
+		ret = regcache_sync(data->regmap);
+		if (ret != 0) {
+			dev_err(data->dev,
+				"Failed to sync registers: %d\n", ret);
+			goto regcache_sync_failed;
+		}
 	} else {
+		/* Powered off device does not retain registers. While device
+		 * is off, any register updates (i.e. volume changes) should
+		 * happen in cache only.
+		 */
+		regcache_mark_dirty(data->regmap);
+regcache_sync_failed:
+		regcache_cache_only(data->regmap, true);
+
 		/* Power off */
 		if (data->power_gpio >= 0)
 			gpio_set_value(data->power_gpio, 0);
 
-		ret = regulator_disable(data->supply);
-		if (ret != 0) {
+		ret2 = regulator_disable(data->supply);
+		if (ret2 != 0) {
 			dev_err(data->dev,
-				"Failed to disable supply: %d\n", ret);
-			return ret;
+				"Failed to disable supply: %d\n", ret2);
+			return ret ? ret : ret2;
 		}
-
-		/* device regs does not match the cache state anymore */
-		regcache_mark_dirty(data->regmap);
 	}
 
 	return ret;
@@ -88,25 +102,14 @@ static int tpa6130a2_power_event(struct snd_soc_dapm_widget *w,
 {
 	struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
 	struct tpa6130a2_data *data = snd_soc_component_get_drvdata(c);
-	int ret;
 
-	/* before widget power up */
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
-		/* Turn on the chip */
-		tpa6130a2_power(data, true);
-		/* Sync the registers */
-		ret = regcache_sync(data->regmap);
-		if (ret < 0) {
-			dev_err(c->dev, "Failed to initialize chip\n");
-			tpa6130a2_power(data, false);
-			return ret;
-		}
-	/* after widget power down */
+		/* Before widget power up: turn chip on, sync registers */
+		return tpa6130a2_power(data, true);
 	} else {
-		tpa6130a2_power(data, false);
+		/* After widget power down: turn chip off */
+		return tpa6130a2_power(data, false);
 	}
-
-	return 0;
 }
 
 /*
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index a5a4e9f75c57..a2104d68169d 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -2199,12 +2199,14 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
 	.set_bias_level = twl4030_set_bias_level,
 	.idle_bias_off = true,
 
-	.controls = twl4030_snd_controls,
-	.num_controls = ARRAY_SIZE(twl4030_snd_controls),
-	.dapm_widgets = twl4030_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(twl4030_dapm_widgets),
-	.dapm_routes = intercon,
-	.num_dapm_routes = ARRAY_SIZE(intercon),
+	.component_driver = {
+		.controls		= twl4030_snd_controls,
+		.num_controls		= ARRAY_SIZE(twl4030_snd_controls),
+		.dapm_widgets		= twl4030_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(twl4030_dapm_widgets),
+		.dapm_routes		= intercon,
+		.num_dapm_routes	= ARRAY_SIZE(intercon),
+	},
 };
 
 static int twl4030_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 1f7081043566..748036e851ea 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -1156,12 +1156,14 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
 	.suspend_bias_off = true,
 	.ignore_pmdown_time = true,
 
-	.controls = twl6040_snd_controls,
-	.num_controls = ARRAY_SIZE(twl6040_snd_controls),
-	.dapm_widgets = twl6040_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets),
-	.dapm_routes = intercon,
-	.num_dapm_routes = ARRAY_SIZE(intercon),
+	.component_driver = {
+		.controls		= twl6040_snd_controls,
+		.num_controls		= ARRAY_SIZE(twl6040_snd_controls),
+		.dapm_widgets		= twl6040_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(twl6040_dapm_widgets),
+		.dapm_routes		= intercon,
+		.num_dapm_routes	= ARRAY_SIZE(intercon),
+	},
 };
 
 static int twl6040_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index e4c694c758b8..5fdee874406d 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -523,10 +523,12 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
 	.set_bias_level = uda134x_set_bias_level,
 	.suspend_bias_off = true,
 
-	.dapm_widgets = uda134x_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets),
-	.dapm_routes = uda134x_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= uda134x_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(uda134x_dapm_widgets),
+		.dapm_routes		= uda134x_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(uda134x_dapm_routes),
+	},
 };
 
 static const struct regmap_config uda134x_regmap_config = {
@@ -544,6 +546,7 @@ static int uda134x_codec_probe(struct platform_device *pdev)
 {
 	struct uda134x_platform_data *pd = pdev->dev.platform_data;
 	struct uda134x_priv *uda134x;
+	int ret;
 
 	if (!pd) {
 		dev_err(&pdev->dev, "Missing L3 bitbang function\n");
@@ -557,6 +560,12 @@ static int uda134x_codec_probe(struct platform_device *pdev)
 	uda134x->pd = pd;
 	platform_set_drvdata(pdev, uda134x);
 
+	if (pd->l3.use_gpios) {
+		ret = l3_set_gpio_ops(&pdev->dev, &uda134x->pd->l3);
+		if (ret < 0)
+			return ret;
+	}
+
 	uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd,
 		&uda134x_regmap_config);
 	if (IS_ERR(uda134x->regmap))
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 35f0469ebb16..533e3bb444e4 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -765,12 +765,14 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
 	.reg_cache_default = uda1380_reg,
 	.reg_cache_step = 1,
 
-	.controls = uda1380_snd_controls,
-	.num_controls = ARRAY_SIZE(uda1380_snd_controls),
-	.dapm_widgets = uda1380_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
-	.dapm_routes = uda1380_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes),
+	.component_driver = {
+		.controls		= uda1380_snd_controls,
+		.num_controls		= ARRAY_SIZE(uda1380_snd_controls),
+		.dapm_widgets		= uda1380_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(uda1380_dapm_widgets),
+		.dapm_routes		= uda1380_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(uda1380_dapm_routes),
+	},
 };
 
 #if IS_ENABLED(CONFIG_I2C)
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index 1b79778098d2..fcffb6e707d9 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -484,12 +484,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
 	.probe = wl1273_probe,
 	.remove = wl1273_remove,
 
-	.controls = wl1273_controls,
-	.num_controls = ARRAY_SIZE(wl1273_controls),
-	.dapm_widgets = wl1273_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets),
-	.dapm_routes = wl1273_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wl1273_dapm_routes),
+	.component_driver = {
+		.controls		= wl1273_controls,
+		.num_controls		= ARRAY_SIZE(wl1273_controls),
+		.dapm_widgets		= wl1273_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wl1273_dapm_widgets),
+		.dapm_routes		= wl1273_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wl1273_dapm_routes),
+	},
 };
 
 static int wl1273_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index e3c34bdc2772..0eb5dcf4c29d 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -789,16 +789,18 @@ static int wm0010_set_sysclk(struct snd_soc_codec *codec, int source,
 
 static int wm0010_probe(struct snd_soc_codec *codec);
 
-static struct snd_soc_codec_driver soc_codec_dev_wm0010 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm0010 = {
 	.probe = wm0010_probe,
 	.set_bias_level = wm0010_set_bias_level,
 	.set_sysclk = wm0010_set_sysclk,
 	.idle_bias_off = true,
 
-	.dapm_widgets = wm0010_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm0010_dapm_widgets),
-	.dapm_routes = wm0010_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm0010_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= wm0010_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm0010_dapm_widgets),
+		.dapm_routes		= wm0010_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm0010_dapm_routes),
+	},
 };
 
 #define WM0010_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
index ec45c5b220b1..cf5f0580df6a 100644
--- a/sound/soc/codecs/wm1250-ev1.c
+++ b/sound/soc/codecs/wm1250-ev1.c
@@ -141,12 +141,13 @@ static struct snd_soc_dai_driver wm1250_ev1_dai = {
 	.ops = &wm1250_ev1_ops,
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
-	.dapm_widgets = wm1250_ev1_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm1250_ev1_dapm_widgets),
-	.dapm_routes = wm1250_ev1_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm1250_ev1_dapm_routes),
-
+static const struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
+	.component_driver = {
+		.dapm_widgets		= wm1250_ev1_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm1250_ev1_dapm_widgets),
+		.dapm_routes		= wm1250_ev1_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm1250_ev1_dapm_routes),
+	},
 	.set_bias_level = wm1250_ev1_set_bias_level,
 	.idle_bias_off = true,
 };
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index a67ea10f41a1..23cde3a0dc11 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -581,7 +581,7 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000,
 	if (anc_transitions[i].dest == ANC_OFF)
 		clk_disable_unprepare(wm2000->mclk);
 
-	return ret;
+	return 0;
 }
 
 static int wm2000_anc_set_mode(struct wm2000_priv *wm2000)
@@ -799,18 +799,20 @@ static int wm2000_remove(struct snd_soc_codec *codec)
 	return wm2000_anc_transition(wm2000, ANC_OFF);
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm2000 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm2000 = {
 	.probe = wm2000_probe,
 	.remove = wm2000_remove,
 	.suspend = wm2000_suspend,
 	.resume = wm2000_resume,
 
-	.dapm_widgets = wm2000_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm2000_dapm_widgets),
-	.dapm_routes = wm2000_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(wm2000_audio_map),
-	.controls = wm2000_controls,
-	.num_controls = ARRAY_SIZE(wm2000_controls),
+	.component_driver = {
+		.controls		= wm2000_controls,
+		.num_controls		= ARRAY_SIZE(wm2000_controls),
+		.dapm_widgets		= wm2000_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm2000_dapm_widgets),
+		.dapm_routes		= wm2000_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(wm2000_audio_map),
+	},
 };
 
 static int wm2000_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index fd1439ecb50a..606bf88abfc4 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -2103,7 +2103,7 @@ static struct snd_soc_dai_driver wm2200_dai = {
 	.ops = &wm2200_dai_ops,
 };
 
-static struct snd_soc_codec_driver soc_codec_wm2200 = {
+static const struct snd_soc_codec_driver soc_codec_wm2200 = {
 	.probe = wm2200_probe,
 
 	.idle_bias_off = true,
@@ -2111,12 +2111,14 @@ static struct snd_soc_codec_driver soc_codec_wm2200 = {
 	.set_sysclk = wm2200_set_sysclk,
 	.set_pll = wm2200_set_fll,
 
-	.controls = wm2200_snd_controls,
-	.num_controls = ARRAY_SIZE(wm2200_snd_controls),
-	.dapm_widgets = wm2200_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm2200_dapm_widgets),
-	.dapm_routes = wm2200_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm2200_dapm_routes),
+	.component_driver = {
+		.controls		= wm2200_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm2200_snd_controls),
+		.dapm_widgets		= wm2200_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm2200_dapm_widgets),
+		.dapm_routes		= wm2200_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm2200_dapm_routes),
+	},
 };
 
 static irqreturn_t wm2200_irq(int irq, void *data)
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 512a9d25fe6f..560575000cc5 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2285,7 +2285,7 @@ static int wm5100_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 				  (1 << WM5100_GP1_DIR_SHIFT));
 }
 
-static struct gpio_chip wm5100_template_chip = {
+static const struct gpio_chip wm5100_template_chip = {
 	.label			= "wm5100",
 	.owner			= THIS_MODULE,
 	.direction_output	= wm5100_gpio_direction_out,
@@ -2381,7 +2381,7 @@ static int wm5100_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
 	.probe =	wm5100_probe,
 	.remove =	wm5100_remove,
 
@@ -2390,12 +2390,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
 	.idle_bias_off = 1,
 
 	.seq_notifier = wm5100_seq_notifier,
-	.controls = wm5100_snd_controls,
-	.num_controls = ARRAY_SIZE(wm5100_snd_controls),
-	.dapm_widgets = wm5100_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm5100_dapm_widgets),
-	.dapm_routes = wm5100_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm5100_dapm_routes),
+	.component_driver = {
+		.controls		= wm5100_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm5100_snd_controls),
+		.dapm_widgets		= wm5100_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm5100_dapm_widgets),
+		.dapm_routes		= wm5100_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm5100_dapm_routes),
+	},
 };
 
 static const struct regmap_config wm5100_regmap = {
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 846deed6af41..93876c6d48ee 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -1521,6 +1521,16 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
 	{ "IN3L", NULL, "SYSCLK" },
 	{ "IN3R", NULL, "SYSCLK" },
 
+	{ "ASRC1L", NULL, "SYSCLK" },
+	{ "ASRC1R", NULL, "SYSCLK" },
+	{ "ASRC2L", NULL, "SYSCLK" },
+	{ "ASRC2R", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "ASYNCCLK" },
+	{ "ASRC1R", NULL, "ASYNCCLK" },
+	{ "ASRC2L", NULL, "ASYNCCLK" },
+	{ "ASRC2R", NULL, "ASYNCCLK" },
+
 	{ "MICBIAS1", NULL, "MICVDD" },
 	{ "MICBIAS2", NULL, "MICVDD" },
 	{ "MICBIAS3", NULL, "MICVDD" },
@@ -1600,7 +1610,6 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
 	{ "Slim3 Capture", NULL, "SYSCLK" },
 
 	{ "Audio Trace DSP", NULL, "DSP1" },
-	{ "Audio Trace DSP", NULL, "SYSCLK" },
 
 	{ "IN1L PGA", NULL, "IN1L" },
 	{ "IN1R PGA", NULL, "IN1R" },
@@ -1990,7 +1999,7 @@ static struct regmap *wm5102_get_regmap(struct device *dev)
 	return priv->core.arizona->regmap;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
 	.probe = wm5102_codec_probe,
 	.remove = wm5102_codec_remove,
 	.get_regmap = wm5102_get_regmap,
@@ -2000,12 +2009,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
 	.set_sysclk = arizona_set_sysclk,
 	.set_pll = wm5102_set_fll,
 
-	.controls = wm5102_snd_controls,
-	.num_controls = ARRAY_SIZE(wm5102_snd_controls),
-	.dapm_widgets = wm5102_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm5102_dapm_widgets),
-	.dapm_routes = wm5102_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes),
+	.component_driver = {
+		.controls		= wm5102_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm5102_snd_controls),
+		.dapm_widgets		= wm5102_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm5102_dapm_widgets),
+		.dapm_routes		= wm5102_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm5102_dapm_routes),
+	},
 };
 
 static struct snd_compr_ops wm5102_compr_ops = {
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 156547026a40..06bae3b23fce 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -1745,6 +1745,16 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
 	{ "IN4L", NULL, "SYSCLK" },
 	{ "IN4R", NULL, "SYSCLK" },
 
+	{ "ASRC1L", NULL, "SYSCLK" },
+	{ "ASRC1R", NULL, "SYSCLK" },
+	{ "ASRC2L", NULL, "SYSCLK" },
+	{ "ASRC2R", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "ASYNCCLK" },
+	{ "ASRC1R", NULL, "ASYNCCLK" },
+	{ "ASRC2L", NULL, "ASYNCCLK" },
+	{ "ASRC2R", NULL, "ASYNCCLK" },
+
 	{ "MICBIAS1", NULL, "MICVDD" },
 	{ "MICBIAS2", NULL, "MICVDD" },
 	{ "MICBIAS3", NULL, "MICVDD" },
@@ -1832,10 +1842,8 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
 	{ "Slim3 Capture", NULL, "SYSCLK" },
 
 	{ "Voice Control DSP", NULL, "DSP3" },
-	{ "Voice Control DSP", NULL, "SYSCLK" },
 
 	{ "Audio Trace DSP", NULL, "DSP1" },
-	{ "Audio Trace DSP", NULL, "SYSCLK" },
 
 	{ "IN1L PGA", NULL, "IN1L" },
 	{ "IN1R PGA", NULL, "IN1R" },
@@ -2347,7 +2355,7 @@ static struct regmap *wm5110_get_regmap(struct device *dev)
 	return priv->core.arizona->regmap;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
 	.probe = wm5110_codec_probe,
 	.remove = wm5110_codec_remove,
 	.get_regmap = wm5110_get_regmap,
@@ -2357,12 +2365,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
 	.set_sysclk = arizona_set_sysclk,
 	.set_pll = wm5110_set_fll,
 
-	.controls = wm5110_snd_controls,
-	.num_controls = ARRAY_SIZE(wm5110_snd_controls),
-	.dapm_widgets = wm5110_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm5110_dapm_widgets),
-	.dapm_routes = wm5110_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes),
+	.component_driver = {
+		.controls		= wm5110_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm5110_snd_controls),
+		.dapm_widgets		= wm5110_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm5110_dapm_widgets),
+		.dapm_routes		= wm5110_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm5110_dapm_routes),
+	},
 };
 
 static struct snd_compr_ops wm5110_compr_ops = {
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index ffbf3df8ae97..2efc5b41ad0f 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1587,19 +1587,21 @@ static struct regmap *wm8350_get_regmap(struct device *dev)
 	return wm8350->regmap;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
 	.probe =	wm8350_codec_probe,
 	.remove =	wm8350_codec_remove,
 	.get_regmap =	wm8350_get_regmap,
 	.set_bias_level = wm8350_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8350_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8350_snd_controls),
-	.dapm_widgets = wm8350_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8350_dapm_widgets),
-	.dapm_routes = wm8350_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8350_dapm_routes),
+	.component_driver = {
+		.controls		= wm8350_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8350_snd_controls),
+		.dapm_widgets		= wm8350_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8350_dapm_widgets),
+		.dapm_routes		= wm8350_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8350_dapm_routes),
+	},
 };
 
 static int wm8350_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index b1d346aa4696..6c59fb933bd6 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -1332,19 +1332,21 @@ static struct regmap *wm8400_get_regmap(struct device *dev)
 	return wm8400->regmap;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
 	.probe =	wm8400_codec_probe,
 	.remove =	wm8400_codec_remove,
 	.get_regmap =	wm8400_get_regmap,
 	.set_bias_level = wm8400_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8400_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8400_snd_controls),
-	.dapm_widgets = wm8400_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8400_dapm_widgets),
-	.dapm_routes = wm8400_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8400_dapm_routes),
+	.component_driver = {
+		.controls		= wm8400_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8400_snd_controls),
+		.dapm_widgets		= wm8400_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8400_dapm_widgets),
+		.dapm_routes		= wm8400_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8400_dapm_routes),
+	},
 };
 
 static int wm8400_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 99e40e629cca..119ceac684ae 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -581,17 +581,19 @@ static int wm8510_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
 	.probe =	wm8510_probe,
 	.set_bias_level = wm8510_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8510_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8510_snd_controls),
-	.dapm_widgets = wm8510_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8510_dapm_widgets),
-	.dapm_routes = wm8510_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8510_dapm_routes),
+	.component_driver = {
+		.controls		= wm8510_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8510_snd_controls),
+		.dapm_widgets		= wm8510_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8510_dapm_widgets),
+		.dapm_routes		= wm8510_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8510_dapm_routes),
+	},
 };
 
 static const struct of_device_id wm8510_of_match[] = {
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index aa287a3965e7..deb2e075428e 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -413,17 +413,19 @@ static int wm8523_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8523 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8523 = {
 	.probe =	wm8523_probe,
 	.set_bias_level = wm8523_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8523_controls,
-	.num_controls = ARRAY_SIZE(wm8523_controls),
-	.dapm_widgets = wm8523_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8523_dapm_widgets),
-	.dapm_routes = wm8523_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8523_dapm_routes),
+	.component_driver = {
+		.controls		= wm8523_controls,
+		.num_controls		= ARRAY_SIZE(wm8523_controls),
+		.dapm_widgets		= wm8523_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8523_dapm_widgets),
+		.dapm_routes		= wm8523_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8523_dapm_routes),
+	},
 };
 
 static const struct of_device_id wm8523_of_match[] = {
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 66602bf02f6e..faa7287a5253 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -899,17 +899,19 @@ static int wm8580_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
 	.probe =	wm8580_probe,
 	.remove =	wm8580_remove,
 	.set_bias_level = wm8580_set_bias_level,
 
-	.controls = wm8580_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8580_snd_controls),
-	.dapm_widgets = wm8580_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8580_dapm_widgets),
-	.dapm_routes = wm8580_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8580_dapm_routes),
+	.component_driver = {
+		.controls		= wm8580_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8580_snd_controls),
+		.dapm_widgets		= wm8580_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8580_dapm_widgets),
+		.dapm_routes		= wm8580_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8580_dapm_routes),
+	},
 };
 
 static const struct of_device_id wm8580_of_match[] = {
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index c759ec068e97..2b376c9c99af 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -367,17 +367,19 @@ static int wm8711_probe(struct snd_soc_codec *codec)
 
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
 	.probe =	wm8711_probe,
 	.set_bias_level = wm8711_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8711_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8711_snd_controls),
-	.dapm_widgets = wm8711_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8711_dapm_widgets),
-	.dapm_routes = wm8711_intercon,
-	.num_dapm_routes = ARRAY_SIZE(wm8711_intercon),
+	.component_driver = {
+		.controls		= wm8711_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8711_snd_controls),
+		.dapm_widgets		= wm8711_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8711_dapm_widgets),
+		.dapm_routes		= wm8711_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(wm8711_intercon),
+	},
 };
 
 static const struct of_device_id wm8711_of_match[] = {
diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c
index bb25a75f92a2..7fde077a014b 100644
--- a/sound/soc/codecs/wm8727.c
+++ b/sound/soc/codecs/wm8727.c
@@ -53,11 +53,13 @@ static struct snd_soc_dai_driver wm8727_dai = {
 		},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8727 = {
-	.dapm_widgets = wm8727_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8727_dapm_widgets),
-	.dapm_routes = wm8727_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8727_dapm_routes),
+static const struct snd_soc_codec_driver soc_codec_dev_wm8727 = {
+	.component_driver = {
+		.dapm_widgets		= wm8727_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8727_dapm_widgets),
+		.dapm_routes		= wm8727_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8727_dapm_routes),
+	},
 };
 
 static int wm8727_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 1564e6926527..797cc6e7c70f 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -211,16 +211,18 @@ static struct snd_soc_dai_driver wm8728_dai = {
 	.ops = &wm8728_dai_ops,
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
 	.set_bias_level = wm8728_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8728_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8728_snd_controls),
-	.dapm_widgets = wm8728_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8728_dapm_widgets),
-	.dapm_routes = wm8728_intercon,
-	.num_dapm_routes = ARRAY_SIZE(wm8728_intercon),
+	.component_driver = {
+		.controls		= wm8728_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8728_snd_controls),
+		.dapm_widgets		= wm8728_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8728_dapm_widgets),
+		.dapm_routes		= wm8728_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(wm8728_intercon),
+	},
 };
 
 static const struct of_device_id wm8728_of_match[] = {
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index d18261a44256..4f9a1eb28120 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -628,16 +628,18 @@ err_regulator_enable:
 	return ret;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
 	.set_bias_level = wm8731_set_bias_level,
 	.suspend_bias_off = true,
 
-	.dapm_widgets = wm8731_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
-	.dapm_routes = wm8731_intercon,
-	.num_dapm_routes = ARRAY_SIZE(wm8731_intercon),
-	.controls =	wm8731_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8731_snd_controls),
+	.component_driver = {
+		.controls		= wm8731_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8731_snd_controls),
+		.dapm_widgets		= wm8731_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8731_dapm_widgets),
+		.dapm_routes		= wm8731_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(wm8731_intercon),
+	},
 };
 
 static const struct of_device_id wm8731_of_match[] = {
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index e7807601e675..f0cb1c4afe3c 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -573,17 +573,19 @@ err_get:
 	return ret;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8737 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8737 = {
 	.probe		= wm8737_probe,
 	.set_bias_level = wm8737_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8737_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8737_snd_controls),
-	.dapm_widgets = wm8737_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8737_dapm_widgets),
-	.dapm_routes = intercon,
-	.num_dapm_routes = ARRAY_SIZE(intercon),
+	.component_driver = {
+		.controls		= wm8737_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8737_snd_controls),
+		.dapm_widgets		= wm8737_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8737_dapm_widgets),
+		.dapm_routes		= intercon,
+		.num_dapm_routes	= ARRAY_SIZE(intercon),
+	},
 };
 
 static const struct of_device_id wm8737_of_match[] = {
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index 36ef91fe0511..565d477cd790 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -497,15 +497,17 @@ static int wm8741_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
 	.probe =	wm8741_probe,
 	.remove =	wm8741_remove,
 	.resume =	wm8741_resume,
 
-	.dapm_widgets = wm8741_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8741_dapm_widgets),
-	.dapm_routes = wm8741_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8741_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= wm8741_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8741_dapm_widgets),
+		.dapm_routes		= wm8741_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8741_dapm_routes),
+	},
 };
 
 static const struct of_device_id wm8741_of_match[] = {
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index bd9dcd2161bc..0da2bbaf06d1 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -708,17 +708,19 @@ static int wm8750_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8750 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8750 = {
 	.probe =	wm8750_probe,
 	.set_bias_level = wm8750_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8750_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8750_snd_controls),
-	.dapm_widgets = wm8750_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
-	.dapm_routes = wm8750_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8750_dapm_routes),
+	.component_driver = {
+		.controls		= wm8750_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8750_snd_controls),
+		.dapm_widgets		= wm8750_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8750_dapm_widgets),
+		.dapm_routes		= wm8750_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8750_dapm_routes),
+	},
 };
 
 static const struct of_device_id wm8750_of_match[] = {
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index cdcc91282e8a..9bdf5447f6f6 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1478,18 +1478,20 @@ static int wm8753_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8753 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8753 = {
 	.probe =	wm8753_probe,
 	.resume =	wm8753_resume,
 	.set_bias_level = wm8753_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8753_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8753_snd_controls),
-	.dapm_widgets = wm8753_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8753_dapm_widgets),
-	.dapm_routes = wm8753_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8753_dapm_routes),
+	.component_driver = {
+		.controls		= wm8753_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8753_snd_controls),
+		.dapm_widgets		= wm8753_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8753_dapm_widgets),
+		.dapm_routes		= wm8753_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8753_dapm_routes),
+	},
 };
 
 static const struct of_device_id wm8753_of_match[] = {
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
index df6178464b00..d6edcbbdec12 100644
--- a/sound/soc/codecs/wm8770.c
+++ b/sound/soc/codecs/wm8770.c
@@ -608,17 +608,19 @@ err_reg_enable:
 	return ret;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8770 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8770 = {
 	.probe = wm8770_probe,
 	.set_bias_level = wm8770_set_bias_level,
 	.idle_bias_off = true,
 
-	.controls = wm8770_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8770_snd_controls),
-	.dapm_widgets = wm8770_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8770_dapm_widgets),
-	.dapm_routes = wm8770_intercon,
-	.num_dapm_routes = ARRAY_SIZE(wm8770_intercon),
+	.component_driver = {
+		.controls		= wm8770_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8770_snd_controls),
+		.dapm_widgets		= wm8770_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8770_dapm_widgets),
+		.dapm_routes		= wm8770_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(wm8770_intercon),
+	},
 };
 
 static const struct of_device_id wm8770_of_match[] = {
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index 5af44f9a8cf2..ae30480b3976 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -425,17 +425,19 @@ static int wm8776_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
 	.probe = 	wm8776_probe,
 	.set_bias_level = wm8776_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8776_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8776_snd_controls),
-	.dapm_widgets = wm8776_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8776_dapm_widgets),
-	.dapm_routes = routes,
-	.num_dapm_routes = ARRAY_SIZE(routes),
+	.component_driver = {
+		.controls		= wm8776_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8776_snd_controls),
+		.dapm_widgets		= wm8776_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8776_dapm_widgets),
+		.dapm_routes		= routes,
+		.num_dapm_routes	= ARRAY_SIZE(routes),
+	},
 };
 
 static const struct of_device_id wm8776_of_match[] = {
diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c
index fb55fd845d27..bcda21018505 100644
--- a/sound/soc/codecs/wm8782.c
+++ b/sound/soc/codecs/wm8782.c
@@ -50,11 +50,13 @@ static struct snd_soc_dai_driver wm8782_dai = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8782 = {
-	.dapm_widgets = wm8782_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8782_dapm_widgets),
-	.dapm_routes = wm8782_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8782_dapm_routes),
+static const struct snd_soc_codec_driver soc_codec_dev_wm8782 = {
+	.component_driver = {
+		.dapm_widgets		= wm8782_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8782_dapm_widgets),
+		.dapm_routes		= wm8782_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8782_dapm_routes),
+	},
 };
 
 static int wm8782_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 8d914702cae4..af95d648265b 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -545,10 +545,12 @@ static struct snd_soc_dai_driver wm8804_dai = {
 static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
 	.idle_bias_off = true,
 
-	.dapm_widgets = wm8804_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8804_dapm_widgets),
-	.dapm_routes = wm8804_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8804_dapm_routes),
+	.component_driver = {
+		.dapm_widgets		= wm8804_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8804_dapm_widgets),
+		.dapm_routes		= wm8804_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8804_dapm_routes),
+	},
 };
 
 const struct regmap_config wm8804_regmap_config = {
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 5d8dca88d612..c77b49a29311 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -1208,18 +1208,20 @@ static int wm8900_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
 	.probe =	wm8900_probe,
 	.suspend =	wm8900_suspend,
 	.resume =	wm8900_resume,
 	.set_bias_level = wm8900_set_bias_level,
 
-	.controls = wm8900_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8900_snd_controls),
-	.dapm_widgets = wm8900_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8900_dapm_widgets),
-	.dapm_routes = wm8900_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8900_dapm_routes),
+	.component_driver = {
+		.controls		= wm8900_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8900_snd_controls),
+		.dapm_widgets		= wm8900_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8900_dapm_widgets),
+		.dapm_routes		= wm8900_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8900_dapm_routes),
+	},
 };
 
 static const struct regmap_config wm8900_regmap = {
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index a26ca490cf31..6e887c2c42b1 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1830,7 +1830,7 @@ static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 			   !!value << WM8903_GP1_LVL_SHIFT);
 }
 
-static struct gpio_chip wm8903_template_chip = {
+static const struct gpio_chip wm8903_template_chip = {
 	.label			= "wm8903",
 	.owner			= THIS_MODULE,
 	.request		= wm8903_gpio_request,
@@ -1874,18 +1874,20 @@ static void wm8903_free_gpio(struct wm8903_priv *wm8903)
 }
 #endif
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
 	.resume =	wm8903_resume,
 	.set_bias_level = wm8903_set_bias_level,
 	.seq_notifier = wm8903_seq_notifier,
 	.suspend_bias_off = true,
 
-	.controls = wm8903_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8903_snd_controls),
-	.dapm_widgets = wm8903_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8903_dapm_widgets),
-	.dapm_routes = wm8903_intercon,
-	.num_dapm_routes = ARRAY_SIZE(wm8903_intercon),
+	.component_driver = {
+		.controls		= wm8903_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8903_snd_controls),
+		.dapm_widgets		= wm8903_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8903_dapm_widgets),
+		.dapm_routes		= wm8903_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(wm8903_intercon),
+	},
 };
 
 static const struct regmap_config wm8903_regmap = {
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index edd7a7709194..4fd350e8420d 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -2086,7 +2086,7 @@ static int wm8904_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8904 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8904 = {
 	.probe =	wm8904_probe,
 	.remove =	wm8904_remove,
 	.set_bias_level = wm8904_set_bias_level,
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 1c600819f768..b5935625feeb 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -723,17 +723,19 @@ static int wm8940_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
 	.probe =	wm8940_probe,
 	.set_bias_level = wm8940_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls =     wm8940_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8940_snd_controls),
-	.dapm_widgets = wm8940_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8940_dapm_widgets),
-	.dapm_routes =  wm8940_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8940_dapm_routes),
+	.component_driver = {
+		.controls		= wm8940_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8940_snd_controls),
+		.dapm_widgets		= wm8940_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8940_dapm_widgets),
+		.dapm_routes		= wm8940_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8940_dapm_routes),
+	},
 };
 
 static const struct regmap_config wm8940_regmap = {
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 9db00d53abe7..1edc7b1df31d 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -940,17 +940,19 @@ err_enable:
 	return ret;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8955 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8955 = {
 	.probe =	wm8955_probe,
 	.set_bias_level = wm8955_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls =	wm8955_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8955_snd_controls),
-	.dapm_widgets = wm8955_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8955_dapm_widgets),
-	.dapm_routes =	wm8955_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8955_dapm_routes),
+	.component_driver = {
+		.controls		= wm8955_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8955_snd_controls),
+		.dapm_widgets		= wm8955_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8955_dapm_widgets),
+		.dapm_routes		= wm8955_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8955_dapm_routes),
+	},
 };
 
 static const struct regmap_config wm8955_regmap = {
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index d7f444f87460..be3244361210 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -1264,7 +1264,7 @@ static int wm8960_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
 	.probe =	wm8960_probe,
 	.set_bias_level = wm8960_set_bias_level,
 	.suspend_bias_off = true,
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index e30446a04740..e23ceac76015 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -882,18 +882,20 @@ static int wm8961_resume(struct snd_soc_codec *codec)
 #define wm8961_resume NULL
 #endif
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8961 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8961 = {
 	.probe =	wm8961_probe,
 	.resume =	wm8961_resume,
 	.set_bias_level = wm8961_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8961_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8961_snd_controls),
-	.dapm_widgets = wm8961_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8961_dapm_widgets),
-	.dapm_routes = audio_paths,
-	.num_dapm_routes = ARRAY_SIZE(audio_paths),
+	.component_driver = {
+		.controls		= wm8961_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8961_snd_controls),
+		.dapm_widgets		= wm8961_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8961_dapm_widgets),
+		.dapm_routes		= audio_paths,
+		.num_dapm_routes	= ARRAY_SIZE(audio_paths),
+	},
 };
 
 static const struct regmap_config wm8961_regmap = {
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index f3109da24769..a0dd7b05b7d6 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -3357,7 +3357,7 @@ static int wm8962_gpio_direction_out(struct gpio_chip *chip,
 	return 0;
 }
 
-static struct gpio_chip wm8962_template_chip = {
+static const struct gpio_chip wm8962_template_chip = {
 	.label			= "wm8962",
 	.owner			= THIS_MODULE,
 	.request		= wm8962_gpio_request,
@@ -3479,7 +3479,7 @@ static int wm8962_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
 	.probe =	wm8962_probe,
 	.remove =	wm8962_remove,
 	.set_bias_level = wm8962_set_bias_level,
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 2cdde32c43c6..887d31cf3945 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -649,17 +649,19 @@ static int wm8971_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8971 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8971 = {
 	.probe =	wm8971_probe,
 	.set_bias_level = wm8971_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8971_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8971_snd_controls),
-	.dapm_widgets = wm8971_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8971_dapm_widgets),
-	.dapm_routes = wm8971_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8971_dapm_routes),
+	.component_driver = {
+		.controls		= wm8971_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8971_snd_controls),
+		.dapm_widgets		= wm8971_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8971_dapm_widgets),
+		.dapm_routes		= wm8971_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8971_dapm_routes),
+	},
 };
 
 static const struct regmap_config wm8971_regmap = {
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index dc8c3b1ebb6f..d414ddd6e197 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -676,17 +676,19 @@ static int wm8974_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
 	.probe = 	wm8974_probe,
 	.set_bias_level = wm8974_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8974_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8974_snd_controls),
-	.dapm_widgets = wm8974_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8974_dapm_widgets),
-	.dapm_routes = wm8974_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8974_dapm_routes),
+	.component_driver = {
+		.controls		= wm8974_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8974_snd_controls),
+		.dapm_widgets		= wm8974_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8974_dapm_widgets),
+		.dapm_routes		= wm8974_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8974_dapm_routes),
+	},
 };
 
 static int wm8974_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index d36d6001fbb7..90b2d418ef60 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -993,18 +993,20 @@ static int wm8978_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8978 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8978 = {
 	.probe =	wm8978_probe,
 	.suspend =	wm8978_suspend,
 	.resume =	wm8978_resume,
 	.set_bias_level = wm8978_set_bias_level,
 
-	.controls = wm8978_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8978_snd_controls),
-	.dapm_widgets = wm8978_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8978_dapm_widgets),
-	.dapm_routes = wm8978_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8978_dapm_routes),
+	.component_driver = {
+		.controls		= wm8978_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8978_snd_controls),
+		.dapm_widgets		= wm8978_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8978_dapm_widgets),
+		.dapm_routes		= wm8978_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8978_dapm_routes),
+	},
 };
 
 static const struct regmap_config wm8978_regmap_config = {
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index 0c002a5712cb..bfdbe72ee687 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -976,16 +976,18 @@ static struct snd_soc_dai_driver wm8983_dai = {
 	.symmetric_rates = 1
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8983 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8983 = {
 	.probe = wm8983_probe,
 	.set_bias_level = wm8983_set_bias_level,
 	.suspend_bias_off = true,
-	.controls = wm8983_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8983_snd_controls),
-	.dapm_widgets = wm8983_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8983_dapm_widgets),
-	.dapm_routes = wm8983_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(wm8983_audio_map),
+	.component_driver = {
+		.controls		= wm8983_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8983_snd_controls),
+		.dapm_widgets		= wm8983_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8983_dapm_widgets),
+		.dapm_routes		= wm8983_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(wm8983_audio_map),
+	},
 };
 
 static const struct regmap_config wm8983_regmap = {
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 7347abff4b2c..05344f974ff3 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -1105,17 +1105,19 @@ static struct snd_soc_dai_driver wm8985_dai = {
 	.symmetric_rates = 1
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8985 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8985 = {
 	.probe = wm8985_probe,
 	.set_bias_level = wm8985_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8985_common_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8985_common_snd_controls),
-	.dapm_widgets = wm8985_common_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8985_common_dapm_widgets),
-	.dapm_routes = wm8985_common_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8985_common_dapm_routes),
+	.component_driver = {
+		.controls		= wm8985_common_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8985_common_snd_controls),
+		.dapm_widgets		= wm8985_common_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8985_common_dapm_widgets),
+		.dapm_routes		= wm8985_common_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8985_common_dapm_routes),
+	},
 };
 
 static const struct regmap_config wm8985_regmap = {
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 895721a256f0..b0d0219532f2 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -817,12 +817,14 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
 	.set_bias_level = wm8988_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8988_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8988_snd_controls),
-	.dapm_widgets = wm8988_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8988_dapm_widgets),
-	.dapm_routes = wm8988_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8988_dapm_routes),
+	.component_driver = {
+		.controls		= wm8988_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8988_snd_controls),
+		.dapm_widgets		= wm8988_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8988_dapm_widgets),
+		.dapm_routes		= wm8988_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8988_dapm_routes),
+	},
 };
 
 static const struct regmap_config wm8988_regmap = {
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 23ecd30d8bca..a8945001e696 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -1294,17 +1294,19 @@ static int wm8990_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
 	.probe =	wm8990_probe,
 	.set_bias_level = wm8990_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls =	wm8990_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8990_snd_controls),
-	.dapm_widgets = wm8990_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8990_dapm_widgets),
-	.dapm_routes =	wm8990_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8990_dapm_routes),
+	.component_driver = {
+		.controls		= wm8990_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8990_snd_controls),
+		.dapm_widgets		= wm8990_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8990_dapm_widgets),
+		.dapm_routes		= wm8990_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8990_dapm_routes),
+	},
 };
 
 static const struct regmap_config wm8990_regmap = {
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index c9ee0ac6a654..984379040794 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -1232,16 +1232,18 @@ static struct snd_soc_dai_driver wm8991_dai = {
 	.ops = &wm8991_ops
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8991 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8991 = {
 	.set_bias_level = wm8991_set_bias_level,
 	.suspend_bias_off = true,
 
-	.controls = wm8991_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8991_snd_controls),
-	.dapm_widgets = wm8991_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8991_dapm_widgets),
-	.dapm_routes = wm8991_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8991_dapm_routes),
+	.component_driver = {
+		.controls		= wm8991_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8991_snd_controls),
+		.dapm_widgets		= wm8991_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8991_dapm_widgets),
+		.dapm_routes		= wm8991_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8991_dapm_routes),
+	},
 };
 
 static const struct regmap_config wm8991_regmap = {
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 8668c4c391b0..195f7bf6eb22 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -1613,7 +1613,7 @@ static const struct regmap_config wm8993_regmap = {
 	.num_reg_defaults = ARRAY_SIZE(wm8993_reg_defaults),
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8993 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8993 = {
 	.probe = 	wm8993_probe,
 	.suspend =	wm8993_suspend,
 	.resume =	wm8993_resume,
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index a18aecb49935..3896523b71e9 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -4439,7 +4439,7 @@ static struct regmap *wm8994_get_regmap(struct device *dev)
 	return control->regmap;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
 	.probe =	wm8994_codec_probe,
 	.remove =	wm8994_codec_remove,
 	.suspend =	wm8994_codec_suspend,
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 24500bafb0a8..19b08a5cae62 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -2192,12 +2192,14 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
 	.set_bias_level = wm8995_set_bias_level,
 	.idle_bias_off = true,
 
-	.controls = wm8995_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8995_snd_controls),
-	.dapm_widgets = wm8995_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8995_dapm_widgets),
-	.dapm_routes = wm8995_intercon,
-	.num_dapm_routes = ARRAY_SIZE(wm8995_intercon),
+	.component_driver = {
+		.controls		= wm8995_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8995_snd_controls),
+		.dapm_widgets		= wm8995_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8995_dapm_widgets),
+		.dapm_routes		= wm8995_intercon,
+		.num_dapm_routes	= ARRAY_SIZE(wm8995_intercon),
+	},
 };
 
 static const struct regmap_config wm8995_regmap = {
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index a73044251218..8affa4969120 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -2184,7 +2184,7 @@ static int wm8996_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 				  (1 << WM8996_GP1_DIR_SHIFT));
 }
 
-static struct gpio_chip wm8996_template_chip = {
+static const struct gpio_chip wm8996_template_chip = {
 	.label			= "wm8996",
 	.owner			= THIS_MODULE,
 	.direction_output	= wm8996_gpio_direction_out,
@@ -2684,18 +2684,20 @@ static int wm8996_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8996 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8996 = {
 	.probe =	wm8996_probe,
 	.remove =	wm8996_remove,
 	.set_bias_level = wm8996_set_bias_level,
 	.idle_bias_off	= true,
 	.seq_notifier = wm8996_seq_notifier,
-	.controls = wm8996_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8996_snd_controls),
-	.dapm_widgets = wm8996_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8996_dapm_widgets),
-	.dapm_routes = wm8996_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8996_dapm_routes),
+	.component_driver = {
+		.controls		= wm8996_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8996_snd_controls),
+		.dapm_widgets		= wm8996_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8996_dapm_widgets),
+		.dapm_routes		= wm8996_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8996_dapm_routes),
+	},
 	.set_pll = wm8996_set_fll,
 };
 
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index 6b0785b5a5c5..2f2821b3382f 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -1095,7 +1095,7 @@ static struct regmap *wm8997_get_regmap(struct device *dev)
 	return priv->core.arizona->regmap;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8997 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8997 = {
 	.probe = wm8997_codec_probe,
 	.remove = wm8997_codec_remove,
 	.get_regmap =   wm8997_get_regmap,
@@ -1105,12 +1105,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8997 = {
 	.set_sysclk = arizona_set_sysclk,
 	.set_pll = wm8997_set_fll,
 
-	.controls = wm8997_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8997_snd_controls),
-	.dapm_widgets = wm8997_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8997_dapm_widgets),
-	.dapm_routes = wm8997_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8997_dapm_routes),
+	.component_driver = {
+		.controls		= wm8997_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8997_snd_controls),
+		.dapm_widgets		= wm8997_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8997_dapm_widgets),
+		.dapm_routes		= wm8997_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8997_dapm_routes),
+	},
 };
 
 static int wm8997_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
index 3a5c896a2d13..bcc2e1060a6c 100644
--- a/sound/soc/codecs/wm8998.c
+++ b/sound/soc/codecs/wm8998.c
@@ -966,6 +966,16 @@ static const struct snd_soc_dapm_route wm8998_dapm_routes[] = {
 	{ "IN2A", NULL, "SYSCLK" },
 	{ "IN2B", NULL, "SYSCLK" },
 
+	{ "ASRC1L", NULL, "SYSCLK" },
+	{ "ASRC1R", NULL, "SYSCLK" },
+	{ "ASRC2L", NULL, "SYSCLK" },
+	{ "ASRC2R", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "ASYNCCLK" },
+	{ "ASRC1R", NULL, "ASYNCCLK" },
+	{ "ASRC2L", NULL, "ASYNCCLK" },
+	{ "ASRC2R", NULL, "ASYNCCLK" },
+
 	{ "SPD1", NULL, "SYSCLK" },
 	{ "SPD1", NULL, "SPD1TX1" },
 	{ "SPD1", NULL, "SPD1TX2" },
@@ -1351,7 +1361,7 @@ static struct regmap *wm8998_get_regmap(struct device *dev)
 	return priv->core.arizona->regmap;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8998 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8998 = {
 	.probe = wm8998_codec_probe,
 	.remove = wm8998_codec_remove,
 	.get_regmap = wm8998_get_regmap,
@@ -1361,12 +1371,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8998 = {
 	.set_sysclk = arizona_set_sysclk,
 	.set_pll = wm8998_set_fll,
 
-	.controls = wm8998_snd_controls,
-	.num_controls = ARRAY_SIZE(wm8998_snd_controls),
-	.dapm_widgets = wm8998_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm8998_dapm_widgets),
-	.dapm_routes = wm8998_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(wm8998_dapm_routes),
+	.component_driver = {
+		.controls		= wm8998_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm8998_snd_controls),
+		.dapm_widgets		= wm8998_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm8998_dapm_widgets),
+		.dapm_routes		= wm8998_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(wm8998_dapm_routes),
+	},
 };
 
 static int wm8998_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 363b3b667616..856867ec2813 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -1274,7 +1274,7 @@ static int wm9081_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
 	.probe = 	wm9081_probe,
 
 	.set_sysclk = wm9081_set_sysclk,
@@ -1282,12 +1282,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
 
 	.idle_bias_off = true,
 
-	.controls         = wm9081_snd_controls,
-	.num_controls     = ARRAY_SIZE(wm9081_snd_controls),
-	.dapm_widgets	  = wm9081_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm9081_dapm_widgets),
-	.dapm_routes     = wm9081_audio_paths,
-	.num_dapm_routes = ARRAY_SIZE(wm9081_audio_paths),
+	.component_driver = {
+		.controls		= wm9081_snd_controls,
+		.num_controls		= ARRAY_SIZE(wm9081_snd_controls),
+		.dapm_widgets		= wm9081_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm9081_dapm_widgets),
+		.dapm_routes		= wm9081_audio_paths,
+		.num_dapm_routes	= ARRAY_SIZE(wm9081_audio_paths),
+	},
 };
 
 static const struct regmap_config wm9081_regmap = {
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index 5d737290f547..5a131385cb2f 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -550,7 +550,7 @@ static int wm9090_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm9090 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm9090 = {
 	.probe = 	wm9090_probe,
 	.set_bias_level = wm9090_set_bias_level,
 	.suspend_bias_off = true,
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index 744842c76a60..dcdd055db57b 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -352,7 +352,7 @@ static int wm9705_soc_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
 	.probe = 	wm9705_soc_probe,
 	.remove = 	wm9705_soc_remove,
 	.suspend =	wm9705_soc_suspend,
@@ -364,12 +364,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
 	.reg_cache_step = 2,
 	.reg_cache_default = wm9705_reg,
 
-	.controls = wm9705_snd_ac97_controls,
-	.num_controls = ARRAY_SIZE(wm9705_snd_ac97_controls),
-	.dapm_widgets = wm9705_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets),
-	.dapm_routes = wm9705_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(wm9705_audio_map),
+	.component_driver = {
+		.controls		= wm9705_snd_ac97_controls,
+		.num_controls		= ARRAY_SIZE(wm9705_snd_ac97_controls),
+		.dapm_widgets		= wm9705_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm9705_dapm_widgets),
+		.dapm_routes		= wm9705_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(wm9705_audio_map),
+	},
 };
 
 static int wm9705_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 488a92224249..557709eac698 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -669,7 +669,7 @@ static int wm9712_soc_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
 	.probe = 	wm9712_soc_probe,
 	.remove = 	wm9712_soc_remove,
 	.resume =	wm9712_soc_resume,
@@ -682,12 +682,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
 	.reg_cache_step = 2,
 	.reg_cache_default = wm9712_reg,
 
-	.controls = wm9712_snd_ac97_controls,
-	.num_controls = ARRAY_SIZE(wm9712_snd_ac97_controls),
-	.dapm_widgets = wm9712_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets),
-	.dapm_routes = wm9712_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(wm9712_audio_map),
+	.component_driver = {
+		.controls		= wm9712_snd_ac97_controls,
+		.num_controls		= ARRAY_SIZE(wm9712_snd_ac97_controls),
+		.dapm_widgets		= wm9712_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm9712_dapm_widgets),
+		.dapm_routes		= wm9712_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(wm9712_audio_map),
+	},
 };
 
 static int wm9712_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 9849643ef809..e4301ddb1b84 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -1235,19 +1235,21 @@ static int wm9713_soc_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
 	.probe = 	wm9713_soc_probe,
 	.remove = 	wm9713_soc_remove,
 	.suspend =	wm9713_soc_suspend,
 	.resume = 	wm9713_soc_resume,
 	.set_bias_level = wm9713_set_bias_level,
 
-	.controls = wm9713_snd_ac97_controls,
-	.num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls),
-	.dapm_widgets = wm9713_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets),
-	.dapm_routes = wm9713_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(wm9713_audio_map),
+	.component_driver = {
+		.controls		= wm9713_snd_ac97_controls,
+		.num_controls		= ARRAY_SIZE(wm9713_snd_ac97_controls),
+		.dapm_widgets		= wm9713_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(wm9713_dapm_widgets),
+		.dapm_routes		= wm9713_audio_map,
+		.num_dapm_routes	= ARRAY_SIZE(wm9713_audio_map),
+	},
 };
 
 static int wm9713_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 21fbe7d07063..b943dde8dbe5 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -480,7 +480,7 @@ static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
 
 	mutex_lock(&dsp->pwr_lock);
 
-	if (!dsp->wmfw_file_name || !dsp->running)
+	if (!dsp->wmfw_file_name || !dsp->booted)
 		ret = 0;
 	else
 		ret = simple_read_from_buffer(user_buf, count, ppos,
@@ -500,7 +500,7 @@ static ssize_t wm_adsp_debugfs_bin_read(struct file *file,
 
 	mutex_lock(&dsp->pwr_lock);
 
-	if (!dsp->bin_file_name || !dsp->running)
+	if (!dsp->bin_file_name || !dsp->booted)
 		ret = 0;
 	else
 		ret = simple_read_from_buffer(user_buf, count, ppos,
@@ -554,6 +554,9 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
 	if (!root)
 		goto err;
 
+	if (!debugfs_create_bool("booted", S_IRUGO, root, &dsp->booted))
+		goto err;
+
 	if (!debugfs_create_bool("running", S_IRUGO, root, &dsp->running))
 		goto err;
 
@@ -637,7 +640,7 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
 
 	mutex_lock(&dsp[e->shift_l].pwr_lock);
 
-	if (dsp[e->shift_l].running || dsp[e->shift_l].compr)
+	if (dsp[e->shift_l].booted || dsp[e->shift_l].compr)
 		ret = -EBUSY;
 	else
 		dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
@@ -789,7 +792,7 @@ static int wm_coeff_put(struct snd_kcontrol *kctl,
 	memcpy(ctl->cache, p, ctl->len);
 
 	ctl->set = 1;
-	if (ctl->enabled)
+	if (ctl->enabled && ctl->dsp->running)
 		ret = wm_coeff_write_control(ctl, p, ctl->len);
 
 	mutex_unlock(&ctl->dsp->pwr_lock);
@@ -811,7 +814,7 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
 		ret = -EFAULT;
 	} else {
 		ctl->set = 1;
-		if (ctl->enabled)
+		if (ctl->enabled && ctl->dsp->running)
 			ret = wm_coeff_write_control(ctl, ctl->cache, size);
 	}
 
@@ -871,12 +874,12 @@ static int wm_coeff_get(struct snd_kcontrol *kctl,
 	mutex_lock(&ctl->dsp->pwr_lock);
 
 	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
-		if (ctl->enabled)
+		if (ctl->enabled && ctl->dsp->running)
 			ret = wm_coeff_read_control(ctl, p, ctl->len);
 		else
 			ret = -EPERM;
 	} else {
-		if (!ctl->flags && ctl->enabled)
+		if (!ctl->flags && ctl->enabled && ctl->dsp->running)
 			ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
 
 		memcpy(p, ctl->cache, ctl->len);
@@ -898,12 +901,12 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
 	mutex_lock(&ctl->dsp->pwr_lock);
 
 	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
-		if (ctl->enabled)
+		if (ctl->enabled && ctl->dsp->running)
 			ret = wm_coeff_read_control(ctl, ctl->cache, size);
 		else
 			ret = -EPERM;
 	} else {
-		if (!ctl->flags && ctl->enabled)
+		if (!ctl->flags && ctl->enabled && ctl->dsp->running)
 			ret = wm_coeff_read_control(ctl, ctl->cache, size);
 	}
 
@@ -2166,13 +2169,20 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
 		if (ret != 0)
 			goto err_ena;
 
+		dsp->booted = true;
+
 		/* Start the core running */
 		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
 				   ADSP1_CORE_ENA | ADSP1_START,
 				   ADSP1_CORE_ENA | ADSP1_START);
+
+		dsp->running = true;
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
+		dsp->running = false;
+		dsp->booted = false;
+
 		/* Halt the core */
 		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
 				   ADSP1_CORE_ENA | ADSP1_START, 0);
@@ -2227,7 +2237,7 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
 		if (val & ADSP2_RAM_RDY)
 			break;
 
-		msleep(1);
+		usleep_range(250, 500);
 	}
 
 	if (!(val & ADSP2_RAM_RDY)) {
@@ -2249,6 +2259,11 @@ static void wm_adsp2_boot_work(struct work_struct *work)
 
 	mutex_lock(&dsp->pwr_lock);
 
+	ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+				 ADSP2_MEM_ENA, ADSP2_MEM_ENA);
+	if (ret != 0)
+		goto err_mutex;
+
 	ret = wm_adsp2_ena(dsp);
 	if (ret != 0)
 		goto err_mutex;
@@ -2270,13 +2285,14 @@ static void wm_adsp2_boot_work(struct work_struct *work)
 	if (ret != 0)
 		goto err_ena;
 
-	/* Sync set controls */
-	ret = wm_coeff_sync_controls(dsp);
+	dsp->booted = true;
+
+	/* Turn DSP back off until we are ready to run */
+	ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+				 ADSP2_SYS_ENA, 0);
 	if (ret != 0)
 		goto err_ena;
 
-	dsp->running = true;
-
 	mutex_unlock(&dsp->pwr_lock);
 
 	return;
@@ -2307,6 +2323,7 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
 	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
 	struct wm_adsp *dsp = &dsps[w->shift];
+	struct wm_coeff_ctl *ctl;
 
 	dsp->card = codec->component.card;
 
@@ -2315,6 +2332,24 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
 		wm_adsp2_set_dspclk(dsp, freq);
 		queue_work(system_unbound_wq, &dsp->boot_work);
 		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		wm_adsp_debugfs_clear(dsp);
+
+		dsp->fw_id = 0;
+		dsp->fw_id_version = 0;
+
+		dsp->booted = false;
+
+		regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+				   ADSP2_MEM_ENA, 0);
+
+		list_for_each_entry(ctl, &dsp->ctl_list, list)
+			ctl->enabled = 0;
+
+		wm_adsp_free_alg_regions(dsp);
+
+		adsp_dbg(dsp, "Shutdown complete\n");
+		break;
 	default:
 		break;
 	}
@@ -2329,16 +2364,24 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
 	struct wm_adsp *dsp = &dsps[w->shift];
-	struct wm_coeff_ctl *ctl;
 	int ret;
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		flush_work(&dsp->boot_work);
 
-		if (!dsp->running)
+		if (!dsp->booted)
 			return -EIO;
 
+		ret = wm_adsp2_ena(dsp);
+		if (ret != 0)
+			goto err;
+
+		/* Sync set controls */
+		ret = wm_coeff_sync_controls(dsp);
+		if (ret != 0)
+			goto err;
+
 		ret = regmap_update_bits(dsp->regmap,
 					 dsp->base + ADSP2_CONTROL,
 					 ADSP2_CORE_ENA | ADSP2_START,
@@ -2346,6 +2389,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 		if (ret != 0)
 			goto err;
 
+		dsp->running = true;
+
 		mutex_lock(&dsp->pwr_lock);
 
 		if (wm_adsp_fw[dsp->fw].num_caps != 0)
@@ -2361,10 +2406,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 
 		mutex_lock(&dsp->pwr_lock);
 
-		wm_adsp_debugfs_clear(dsp);
-
-		dsp->fw_id = 0;
-		dsp->fw_id_version = 0;
 		dsp->running = false;
 
 		regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
@@ -2378,17 +2419,12 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 		regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
 				   ADSP2_SYS_ENA, 0);
 
-		list_for_each_entry(ctl, &dsp->ctl_list, list)
-			ctl->enabled = 0;
-
-		wm_adsp_free_alg_regions(dsp);
-
 		if (wm_adsp_fw[dsp->fw].num_caps != 0)
 			wm_adsp_buffer_free(dsp);
 
 		mutex_unlock(&dsp->pwr_lock);
 
-		adsp_dbg(dsp, "Shutdown complete\n");
+		adsp_dbg(dsp, "Execution stopped\n");
 		break;
 
 	default:
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index be3b5bcb7f17..362dd7ce60d8 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -61,6 +61,8 @@ struct wm_adsp {
 
 	int fw;
 	int fw_ver;
+
+	bool booted;
 	bool running;
 
 	struct list_head ctl_list;
@@ -85,9 +87,10 @@ struct wm_adsp {
 		wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
 
 #define WM_ADSP2(wname, num, event_fn) \
-{	.id = snd_soc_dapm_dai_link, .name = wname " Preloader", \
+{	.id = snd_soc_dapm_supply, .name = wname " Preloader", \
 	.reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \
-	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }, \
+	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \
+	.subseq = 100, /* Ensure we run after SYSCLK supply widget */ }, \
 {	.id = snd_soc_dapm_out_drv, .name = wname, \
 	.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 05c2d33aa74d..3c5a9804d3f5 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -1218,7 +1218,7 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
 
 	snd_mask_none(&nfmt);
 
-	for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
+	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
 		if (snd_mask_test(fmt, i)) {
 			uint sbits = snd_pcm_format_width(i);
 			int ppm;
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index dc97f4349e66..2998954a1c74 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -577,7 +577,6 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
 		dev->capability |= DWC_I2S_PLAY;
 		dev->play_dma_data.dt.addr = res->start + I2S_TXDMA;
 		dev->play_dma_data.dt.addr_width = bus_widths[idx];
-		dev->play_dma_data.dt.chan_name = "TX";
 		dev->play_dma_data.dt.fifo_size = fifo_depth *
 			(fifo_width[idx2]) >> 8;
 		dev->play_dma_data.dt.maxburst = 16;
@@ -588,7 +587,6 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
 		dev->capability |= DWC_I2S_RECORD;
 		dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA;
 		dev->capture_dma_data.dt.addr_width = bus_widths[idx];
-		dev->capture_dma_data.dt.chan_name = "RX";
 		dev->capture_dma_data.dt.fifo_size = fifo_depth *
 			(fifo_width[idx2] >> 8);
 		dev->capture_dma_data.dt.maxburst = 16;
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index c1a0e01cb8e7..1d82f68305c3 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -726,7 +726,7 @@ static const struct regmap_config fsl_asrc_regmap_config = {
 	.readable_reg = fsl_asrc_readable_reg,
 	.volatile_reg = fsl_asrc_volatile_reg,
 	.writeable_reg = fsl_asrc_writeable_reg,
-	.cache_type = REGCACHE_RBTREE,
+	.cache_type = REGCACHE_FLAT,
 };
 
 /**
@@ -879,7 +879,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx35-asrc")) {
+	if (of_device_is_compatible(np, "fsl,imx35-asrc")) {
 		asrc_priv->channel_bits = 3;
 		clk_map[IN] = input_clk_map_imx35;
 		clk_map[OUT] = output_clk_map_imx35;
@@ -892,7 +892,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 	ret = fsl_asrc_init(asrc_priv);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to init asrc %d\n", ret);
-		return -EINVAL;
+		return ret;
 	}
 
 	asrc_priv->channel_avail = 10;
@@ -901,14 +901,14 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 				   &asrc_priv->asrc_rate);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to get output rate\n");
-		return -EINVAL;
+		return ret;
 	}
 
 	ret = of_property_read_u32(np, "fsl,asrc-width",
 				   &asrc_priv->asrc_width);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to get output width\n");
-		return -EINVAL;
+		return ret;
 	}
 
 	if (asrc_priv->asrc_width != 16 && asrc_priv->asrc_width != 24) {
@@ -933,8 +933,6 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	dev_info(&pdev->dev, "driver registered\n");
-
 	return 0;
 }
 
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index ffc000bc1f15..dc30d780f874 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -322,7 +322,7 @@ static snd_pcm_uframes_t fsl_asrc_dma_pcm_pointer(struct snd_pcm_substream *subs
 	return bytes_to_frames(substream->runtime, pair->pos);
 }
 
-static struct snd_pcm_ops fsl_asrc_dma_pcm_ops = {
+static const struct snd_pcm_ops fsl_asrc_dma_pcm_ops = {
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= fsl_asrc_dma_hw_params,
 	.hw_free	= fsl_asrc_dma_hw_free,
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 26a90e12ede4..38bfd46f4ad8 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -77,19 +77,19 @@ static irqreturn_t esai_isr(int irq, void *devid)
 	regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr);
 
 	if (esr & ESAI_ESR_TINIT_MASK)
-		dev_dbg(&pdev->dev, "isr: Transmition Initialized\n");
+		dev_dbg(&pdev->dev, "isr: Transmission Initialized\n");
 
 	if (esr & ESAI_ESR_RFF_MASK)
 		dev_warn(&pdev->dev, "isr: Receiving overrun\n");
 
 	if (esr & ESAI_ESR_TFE_MASK)
-		dev_warn(&pdev->dev, "isr: Transmition underrun\n");
+		dev_warn(&pdev->dev, "isr: Transmission underrun\n");
 
 	if (esr & ESAI_ESR_TLS_MASK)
 		dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n");
 
 	if (esr & ESAI_ESR_TDE_MASK)
-		dev_dbg(&pdev->dev, "isr: Transmition data exception\n");
+		dev_dbg(&pdev->dev, "isr: Transmission data exception\n");
 
 	if (esr & ESAI_ESR_TED_MASK)
 		dev_dbg(&pdev->dev, "isr: Transmitting even slots\n");
@@ -781,7 +781,7 @@ static const struct regmap_config fsl_esai_regmap_config = {
 	.readable_reg = fsl_esai_readable_reg,
 	.volatile_reg = fsl_esai_volatile_reg,
 	.writeable_reg = fsl_esai_writeable_reg,
-	.cache_type = REGCACHE_RBTREE,
+	.cache_type = REGCACHE_FLAT,
 };
 
 static int fsl_esai_probe(struct platform_device *pdev)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 2147994ab46f..9fadf7e31c5f 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -801,8 +801,8 @@ static int fsl_sai_probe(struct platform_device *pdev)
 
 	sai->pdev = pdev;
 
-	if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai") ||
-	    of_device_is_compatible(pdev->dev.of_node, "fsl,imx6ul-sai"))
+	if (of_device_is_compatible(np, "fsl,imx6sx-sai") ||
+	    of_device_is_compatible(np, "fsl,imx6ul-sai"))
 		sai->sai_on_imx = true;
 
 	sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
@@ -883,7 +883,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
 	}
 
 	if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) &&
-	    of_device_is_compatible(pdev->dev.of_node, "fsl,imx6ul-sai")) {
+	    of_device_is_compatible(np, "fsl,imx6ul-sai")) {
 		gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr");
 		if (IS_ERR(gpr)) {
 			dev_err(&pdev->dev, "cannot find iomuxc registers\n");
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index beec7934a265..1ff467c9598a 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -1103,7 +1103,7 @@ static const struct regmap_config fsl_spdif_regmap_config = {
 	.readable_reg = fsl_spdif_readable_reg,
 	.volatile_reg = fsl_spdif_volatile_reg,
 	.writeable_reg = fsl_spdif_writeable_reg,
-	.cache_type = REGCACHE_RBTREE,
+	.cache_type = REGCACHE_FLAT,
 };
 
 static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index bedec4a32581..50349437d961 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -182,7 +182,7 @@ static const struct regmap_config fsl_ssi_regconfig = {
 	.volatile_reg = fsl_ssi_volatile_reg,
 	.precious_reg = fsl_ssi_precious_reg,
 	.writeable_reg = fsl_ssi_writeable_reg,
-	.cache_type = REGCACHE_RBTREE,
+	.cache_type = REGCACHE_FLAT,
 };
 
 struct fsl_ssi_soc_data {
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
index c01c5dd68601..d023959b8cd6 100644
--- a/sound/soc/generic/Kconfig
+++ b/sound/soc/generic/Kconfig
@@ -6,3 +6,11 @@ config SND_SIMPLE_CARD
 	select SND_SIMPLE_CARD_UTILS
 	help
 	  This option enables generic simple sound card support
+
+config SND_SIMPLE_SCU_CARD
+	tristate "ASoC Simple SCU sound card support"
+	depends on OF
+	select SND_SIMPLE_CARD_UTILS
+	help
+	  This option enables generic simple SCU sound card support.
+	  It supports DPCM of multi CPU single Codec system.
diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile
index 45602ca8536e..ee750f3023ba 100644
--- a/sound/soc/generic/Makefile
+++ b/sound/soc/generic/Makefile
@@ -1,5 +1,7 @@
-obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) := simple-card-utils.o
-
+snd-soc-simple-card-utils-objs	:= simple-card-utils.o
 snd-soc-simple-card-objs	:= simple-card.o
+snd-soc-simple-scu-card-objs	:= simple-scu-card.o
 
-obj-$(CONFIG_SND_SIMPLE_CARD)	+= snd-soc-simple-card.o
+obj-$(CONFIG_SND_SIMPLE_CARD_UTILS)	+= snd-soc-simple-card-utils.o
+obj-$(CONFIG_SND_SIMPLE_CARD)		+= snd-soc-simple-card.o
+obj-$(CONFIG_SND_SIMPLE_SCU_CARD)	+= snd-soc-simple-scu-card.o
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index d89a9a1b2471..1cb39309f5d5 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -7,6 +7,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/clk.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <sound/simple_card_utils.h>
 
@@ -95,3 +97,148 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
 	return 0;
 }
 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
+
+int asoc_simple_card_parse_clk(struct device_node *node,
+			       struct device_node *dai_of_node,
+			       struct asoc_simple_dai *simple_dai)
+{
+	struct clk *clk;
+	u32 val;
+
+	/*
+	 * Parse dai->sysclk come from "clocks = <&xxx>"
+	 * (if system has common clock)
+	 *  or "system-clock-frequency = <xxx>"
+	 *  or device's module clock.
+	 */
+	clk = of_clk_get(node, 0);
+	if (!IS_ERR(clk)) {
+		simple_dai->sysclk = clk_get_rate(clk);
+		simple_dai->clk = clk;
+	} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
+		simple_dai->sysclk = val;
+	} else {
+		clk = of_clk_get(dai_of_node, 0);
+		if (!IS_ERR(clk))
+			simple_dai->sysclk = clk_get_rate(clk);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk);
+
+int asoc_simple_card_parse_dai(struct device_node *node,
+				    struct device_node **dai_of_node,
+				    const char **dai_name,
+				    const char *list_name,
+				    const char *cells_name,
+				    int *is_single_link)
+{
+	struct of_phandle_args args;
+	int ret;
+
+	if (!node)
+		return 0;
+
+	/*
+	 * Get node via "sound-dai = <&phandle port>"
+	 * it will be used as xxx_of_node on soc_bind_dai_link()
+	 */
+	ret = of_parse_phandle_with_args(node, list_name, cells_name, 0, &args);
+	if (ret)
+		return ret;
+
+	/* Get dai->name */
+	if (dai_name) {
+		ret = snd_soc_of_get_dai_name(node, dai_name);
+		if (ret < 0)
+			return ret;
+	}
+
+	*dai_of_node = args.np;
+
+	if (is_single_link)
+		*is_single_link = !args.args_count;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai);
+
+int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
+			      struct asoc_simple_dai *simple_dai)
+{
+	int ret;
+
+	if (simple_dai->sysclk) {
+		ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk, 0);
+		if (ret && ret != -ENOTSUPP) {
+			dev_err(dai->dev, "simple-card: set_sysclk error\n");
+			return ret;
+		}
+	}
+
+	if (simple_dai->slots) {
+		ret = snd_soc_dai_set_tdm_slot(dai,
+					       simple_dai->tx_slot_mask,
+					       simple_dai->rx_slot_mask,
+					       simple_dai->slots,
+					       simple_dai->slot_width);
+		if (ret && ret != -ENOTSUPP) {
+			dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai);
+
+int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link)
+{
+	if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name)
+		return -EINVAL;
+
+	/* Assumes platform == cpu */
+	if (!dai_link->platform_of_node)
+		dai_link->platform_of_node = dai_link->cpu_of_node;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink);
+
+void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
+				       int is_single_links)
+{
+	/*
+	 * In soc_bind_dai_link() will check cpu name after
+	 * of_node matching if dai_link has cpu_dai_name.
+	 * but, it will never match if name was created by
+	 * fmt_single_name() remove cpu_dai_name if cpu_args
+	 * was 0. See:
+	 *	fmt_single_name()
+	 *	fmt_multiple_name()
+	 */
+	if (is_single_links)
+		dai_link->cpu_dai_name = NULL;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_cpu);
+
+int asoc_simple_card_clean_reference(struct snd_soc_card *card)
+{
+	struct snd_soc_dai_link *dai_link;
+	int num_links;
+
+	for (num_links = 0, dai_link = card->dai_link;
+	     num_links < card->num_links;
+	     num_links++, dai_link++) {
+		of_node_put(dai_link->cpu_of_node);
+		of_node_put(dai_link->codec_of_node);
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);
+
+/* Module information */
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 43295f024982..f608f8d23f3d 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -37,13 +37,15 @@ struct simple_card_data {
 	unsigned int mclk_fs;
 	struct asoc_simple_jack hp_jack;
 	struct asoc_simple_jack mic_jack;
-	struct snd_soc_dai_link dai_link[];	/* dynamically allocated */
+	struct snd_soc_dai_link *dai_link;
 };
 
 #define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
-#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
-#define simple_priv_to_props(priv, i) ((priv)->dai_props + i)
+#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
+#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
 
+#define DAI	"sound-dai"
+#define CELL	"#sound-dai-cells"
 #define PREFIX	"simple-audio-card,"
 
 #define asoc_simple_card_init_hp(card, sjack, prefix)\
@@ -112,13 +114,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
 	struct simple_dai_props *dai_props =
-		&priv->dai_props[rtd->num];
+		simple_priv_to_props(priv, rtd->num);
 	int ret;
 
 	ret = clk_prepare_enable(dai_props->cpu_dai.clk);
 	if (ret)
 		return ret;
-	
+
 	ret = clk_prepare_enable(dai_props->codec_dai.clk);
 	if (ret)
 		clk_disable_unprepare(dai_props->cpu_dai.clk);
@@ -131,7 +133,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
 	struct simple_dai_props *dai_props =
-		&priv->dai_props[rtd->num];
+		simple_priv_to_props(priv, rtd->num);
 
 	clk_disable_unprepare(dai_props->cpu_dai.clk);
 
@@ -145,7 +147,8 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
-	struct simple_dai_props *dai_props = &priv->dai_props[rtd->num];
+	struct simple_dai_props *dai_props =
+		simple_priv_to_props(priv, rtd->num);
 	unsigned int mclk, mclk_fs = 0;
 	int ret = 0;
 
@@ -177,51 +180,20 @@ static struct snd_soc_ops asoc_simple_card_ops = {
 	.hw_params = asoc_simple_card_hw_params,
 };
 
-static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
-				       struct asoc_simple_dai *set)
-{
-	int ret;
-
-	if (set->sysclk) {
-		ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
-		if (ret && ret != -ENOTSUPP) {
-			dev_err(dai->dev, "simple-card: set_sysclk error\n");
-			goto err;
-		}
-	}
-
-	if (set->slots) {
-		ret = snd_soc_dai_set_tdm_slot(dai,
-					       set->tx_slot_mask,
-					       set->rx_slot_mask,
-						set->slots,
-						set->slot_width);
-		if (ret && ret != -ENOTSUPP) {
-			dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
-			goto err;
-		}
-	}
-
-	ret = 0;
-
-err:
-	return ret;
-}
-
 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
 	struct snd_soc_dai *codec = rtd->codec_dai;
 	struct snd_soc_dai *cpu = rtd->cpu_dai;
-	struct simple_dai_props *dai_props;
+	struct simple_dai_props *dai_props =
+		simple_priv_to_props(priv, rtd->num);
 	int ret;
 
-	dai_props = &priv->dai_props[rtd->num];
-	ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
+	ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
 	if (ret < 0)
 		return ret;
 
-	ret = __asoc_simple_card_dai_init(cpu, &dai_props->cpu_dai);
+	ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
 	if (ret < 0)
 		return ret;
 
@@ -236,78 +208,6 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static int
-asoc_simple_card_sub_parse_of(struct device_node *np,
-			      struct asoc_simple_dai *dai,
-			      struct device_node **p_node,
-			      const char **name,
-			      int *args_count)
-{
-	struct of_phandle_args args;
-	struct clk *clk;
-	u32 val;
-	int ret;
-
-	if (!np)
-		return 0;
-
-	/*
-	 * Get node via "sound-dai = <&phandle port>"
-	 * it will be used as xxx_of_node on soc_bind_dai_link()
-	 */
-	ret = of_parse_phandle_with_args(np, "sound-dai",
-					 "#sound-dai-cells", 0, &args);
-	if (ret)
-		return ret;
-
-	*p_node = args.np;
-
-	if (args_count)
-		*args_count = args.args_count;
-
-	/* Get dai->name */
-	if (name) {
-		ret = snd_soc_of_get_dai_name(np, name);
-		if (ret < 0)
-			return ret;
-	}
-
-	if (!dai)
-		return 0;
-
-	/* Parse TDM slot */
-	ret = snd_soc_of_parse_tdm_slot(np, &dai->tx_slot_mask,
-					&dai->rx_slot_mask,
-					&dai->slots, &dai->slot_width);
-	if (ret)
-		return ret;
-
-	/*
-	 * Parse dai->sysclk come from "clocks = <&xxx>"
-	 * (if system has common clock)
-	 *  or "system-clock-frequency = <xxx>"
-	 *  or device's module clock.
-	 */
-	if (of_property_read_bool(np, "clocks")) {
-		clk = of_clk_get(np, 0);
-		if (IS_ERR(clk)) {
-			ret = PTR_ERR(clk);
-			return ret;
-		}
-
-		dai->sysclk = clk_get_rate(clk);
-		dai->clk = clk;
-	} else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
-		dai->sysclk = val;
-	} else {
-		clk = of_clk_get(args.np, 0);
-		if (!IS_ERR(clk))
-			dai->sysclk = clk_get_rate(clk);
-	}
-
-	return 0;
-}
-
 static int asoc_simple_card_dai_link_of(struct device_node *node,
 					struct simple_card_data *priv,
 					int idx,
@@ -316,13 +216,14 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
 	struct device *dev = simple_priv_to_dev(priv);
 	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
 	struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
+	struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
+	struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
 	struct device_node *cpu = NULL;
 	struct device_node *plat = NULL;
 	struct device_node *codec = NULL;
 	char prop[128];
 	char *prefix = "";
-	int ret, cpu_args;
-	u32 val;
+	int ret, single_cpu;
 
 	/* For single DAI link & old style of DT node */
 	if (is_top_level_node)
@@ -348,36 +249,46 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
 	if (ret < 0)
 		goto dai_link_of_err;
 
-	if (!of_property_read_u32(node, "mclk-fs", &val))
-		dai_props->mclk_fs = val;
+	of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
 
-	ret = asoc_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai,
-					    &dai_link->cpu_of_node,
-					    &dai_link->cpu_dai_name,
-					    &cpu_args);
+	ret = asoc_simple_card_parse_cpu(cpu, dai_link,
+					 DAI, CELL, &single_cpu);
 	if (ret < 0)
 		goto dai_link_of_err;
 
-	ret = asoc_simple_card_sub_parse_of(codec, &dai_props->codec_dai,
-					    &dai_link->codec_of_node,
-					    &dai_link->codec_dai_name, NULL);
+	ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
 	if (ret < 0)
 		goto dai_link_of_err;
 
-	ret = asoc_simple_card_sub_parse_of(plat, NULL,
-					    &dai_link->platform_of_node,
-					    NULL, NULL);
+	ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
 	if (ret < 0)
 		goto dai_link_of_err;
 
-	if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
-		ret = -EINVAL;
+	ret = snd_soc_of_parse_tdm_slot(cpu,	&cpu_dai->tx_slot_mask,
+						&cpu_dai->rx_slot_mask,
+						&cpu_dai->slots,
+						&cpu_dai->slot_width);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	ret = snd_soc_of_parse_tdm_slot(codec,	&codec_dai->tx_slot_mask,
+						&codec_dai->rx_slot_mask,
+						&codec_dai->slots,
+						&codec_dai->slot_width);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	ret = asoc_simple_card_parse_clk_cpu(cpu, dai_link, cpu_dai);
+	if (ret < 0)
 		goto dai_link_of_err;
-	}
 
-	/* Assumes platform == cpu */
-	if (!dai_link->platform_of_node)
-		dai_link->platform_of_node = dai_link->cpu_of_node;
+	ret = asoc_simple_card_parse_clk_codec(codec, dai_link, codec_dai);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	ret = asoc_simple_card_canonicalize_dailink(dai_link);
+	if (ret < 0)
+		goto dai_link_of_err;
 
 	ret = asoc_simple_card_set_dailink_name(dev, dai_link,
 						"%s-%s",
@@ -398,17 +309,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
 		dai_link->codec_dai_name,
 		dai_props->codec_dai.sysclk);
 
-	/*
-	 * In soc_bind_dai_link() will check cpu name after
-	 * of_node matching if dai_link has cpu_dai_name.
-	 * but, it will never match if name was created by
-	 * fmt_single_name() remove cpu_dai_name if cpu_args
-	 * was 0. See:
-	 *	fmt_single_name()
-	 *	fmt_multiple_name()
-	 */
-	if (!cpu_args)
-		dai_link->cpu_dai_name = NULL;
+	asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
 
 dai_link_of_err:
 	of_node_put(cpu);
@@ -417,22 +318,54 @@ dai_link_of_err:
 	return ret;
 }
 
+static int asoc_simple_card_parse_aux_devs(struct device_node *node,
+					   struct simple_card_data *priv)
+{
+	struct device *dev = simple_priv_to_dev(priv);
+	struct device_node *aux_node;
+	int i, n, len;
+
+	if (!of_find_property(node, PREFIX "aux-devs", &len))
+		return 0;		/* Ok to have no aux-devs */
+
+	n = len / sizeof(__be32);
+	if (n <= 0)
+		return -EINVAL;
+
+	priv->snd_card.aux_dev = devm_kzalloc(dev,
+			n * sizeof(*priv->snd_card.aux_dev), GFP_KERNEL);
+	if (!priv->snd_card.aux_dev)
+		return -ENOMEM;
+
+	for (i = 0; i < n; i++) {
+		aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
+		if (!aux_node)
+			return -EINVAL;
+		priv->snd_card.aux_dev[i].codec_of_node = aux_node;
+	}
+
+	priv->snd_card.num_aux_devs = n;
+	return 0;
+}
+
 static int asoc_simple_card_parse_of(struct device_node *node,
 				     struct simple_card_data *priv)
 {
 	struct device *dev = simple_priv_to_dev(priv);
-	u32 val;
+	struct device_node *dai_link;
 	int ret;
 
 	if (!node)
 		return -EINVAL;
 
+	dai_link = of_get_child_by_name(node, PREFIX "dai-link");
+
 	/* The off-codec widgets */
 	if (of_property_read_bool(node, PREFIX "widgets")) {
 		ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
 					PREFIX "widgets");
 		if (ret)
-			return ret;
+			goto card_parse_end;
 	}
 
 	/* DAPM routes */
@@ -440,16 +373,14 @@ static int asoc_simple_card_parse_of(struct device_node *node,
 		ret = snd_soc_of_parse_audio_routing(&priv->snd_card,
 					PREFIX "routing");
 		if (ret)
-			return ret;
+			goto card_parse_end;
 	}
 
 	/* Factor to mclk, used in hw_params() */
-	ret = of_property_read_u32(node, PREFIX "mclk-fs", &val);
-	if (ret == 0)
-		priv->mclk_fs = val;
+	of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
 
 	/* Single/Muti DAI link(s) & New style of DT node */
-	if (of_get_child_by_name(node, PREFIX "dai-link")) {
+	if (dai_link) {
 		struct device_node *np = NULL;
 		int i = 0;
 
@@ -459,7 +390,7 @@ static int asoc_simple_card_parse_of(struct device_node *node,
 							   i, false);
 			if (ret < 0) {
 				of_node_put(np);
-				return ret;
+				goto card_parse_end;
 			}
 			i++;
 		}
@@ -467,66 +398,55 @@ static int asoc_simple_card_parse_of(struct device_node *node,
 		/* For single DAI link & old style of DT node */
 		ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
 		if (ret < 0)
-			return ret;
+			goto card_parse_end;
 	}
 
 	ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX);
-	if (ret)
-		return ret;
+	if (ret < 0)
+		goto card_parse_end;
 
-	return 0;
-}
+	ret = asoc_simple_card_parse_aux_devs(node, priv);
 
-/* Decrease the reference count of the device nodes */
-static int asoc_simple_card_unref(struct snd_soc_card *card)
-{
-	struct snd_soc_dai_link *dai_link;
-	int num_links;
+card_parse_end:
+	of_node_put(dai_link);
 
-	for (num_links = 0, dai_link = card->dai_link;
-	     num_links < card->num_links;
-	     num_links++, dai_link++) {
-		of_node_put(dai_link->cpu_of_node);
-		of_node_put(dai_link->codec_of_node);
-	}
-	return 0;
+	return ret;
 }
 
 static int asoc_simple_card_probe(struct platform_device *pdev)
 {
 	struct simple_card_data *priv;
 	struct snd_soc_dai_link *dai_link;
+	struct simple_dai_props *dai_props;
 	struct device_node *np = pdev->dev.of_node;
 	struct device *dev = &pdev->dev;
-	int num_links, ret;
+	int num, ret;
 
 	/* Get the number of DAI links */
 	if (np && of_get_child_by_name(np, PREFIX "dai-link"))
-		num_links = of_get_child_count(np);
+		num = of_get_child_count(np);
 	else
-		num_links = 1;
+		num = 1;
 
 	/* Allocate the private data and the DAI link array */
-	priv = devm_kzalloc(dev,
-			sizeof(*priv) + sizeof(*dai_link) * num_links,
-			GFP_KERNEL);
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
-	/* Init snd_soc_card */
-	priv->snd_card.owner = THIS_MODULE;
-	priv->snd_card.dev = dev;
-	dai_link = priv->dai_link;
-	priv->snd_card.dai_link = dai_link;
-	priv->snd_card.num_links = num_links;
-
-	/* Get room for the other properties */
-	priv->dai_props = devm_kzalloc(dev,
-			sizeof(*priv->dai_props) * num_links,
-			GFP_KERNEL);
-	if (!priv->dai_props)
+	dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
+	dai_link  = devm_kzalloc(dev, sizeof(*dai_link)  * num, GFP_KERNEL);
+	if (!dai_props || !dai_link)
 		return -ENOMEM;
 
+	priv->dai_props			= dai_props;
+	priv->dai_link			= dai_link;
+
+	/* Init snd_soc_card */
+	priv->snd_card.owner		= THIS_MODULE;
+	priv->snd_card.dev		= dev;
+	priv->snd_card.dai_link		= priv->dai_link;
+	priv->snd_card.num_links	= num;
+
 	if (np && of_device_is_available(np)) {
 
 		ret = asoc_simple_card_parse_of(np, priv);
@@ -567,7 +487,6 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
 					sizeof(priv->dai_props->cpu_dai));
 		memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
 					sizeof(priv->dai_props->codec_dai));
-
 	}
 
 	snd_soc_card_set_drvdata(&priv->snd_card, priv);
@@ -575,9 +494,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
 	ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
 	if (ret >= 0)
 		return ret;
-
 err:
-	asoc_simple_card_unref(&priv->snd_card);
+	asoc_simple_card_clean_reference(&priv->snd_card);
+
 	return ret;
 }
 
@@ -589,7 +508,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev)
 	asoc_simple_card_remove_jack(&priv->hp_jack);
 	asoc_simple_card_remove_jack(&priv->mic_jack);
 
-	return asoc_simple_card_unref(card);
+	return asoc_simple_card_clean_reference(card);
 }
 
 static const struct of_device_id asoc_simple_of_match[] = {
@@ -611,6 +530,6 @@ static struct platform_driver asoc_simple_card = {
 module_platform_driver(asoc_simple_card);
 
 MODULE_ALIAS("platform:asoc-simple-card");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("ASoC Simple Sound Card");
 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c
new file mode 100644
index 000000000000..b9973a56bcb0
--- /dev/null
+++ b/sound/soc/generic/simple-scu-card.c
@@ -0,0 +1,345 @@
+/*
+ * ASoC simple SCU sound card support
+ *
+ * Copyright (C) 2015 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * based on ${LINUX}/sound/soc/generic/simple-card.c
+ *
+ * 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/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/simple_card_utils.h>
+
+struct asoc_simple_card_priv {
+	struct snd_soc_card snd_card;
+	struct snd_soc_codec_conf codec_conf;
+	struct asoc_simple_dai *dai_props;
+	struct snd_soc_dai_link *dai_link;
+	u32 convert_rate;
+	u32 convert_channels;
+};
+
+#define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
+#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
+#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
+
+#define DAI	"sound-dai"
+#define CELL	"#sound-dai-cells"
+#define PREFIX	"simple-audio-card,"
+
+static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct asoc_simple_card_priv *priv =	snd_soc_card_get_drvdata(rtd->card);
+	struct asoc_simple_dai *dai_props =
+		simple_priv_to_props(priv, rtd->num);
+
+	return clk_prepare_enable(dai_props->clk);
+}
+
+static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct asoc_simple_card_priv *priv =	snd_soc_card_get_drvdata(rtd->card);
+	struct asoc_simple_dai *dai_props =
+		simple_priv_to_props(priv, rtd->num);
+
+	clk_disable_unprepare(dai_props->clk);
+}
+
+static struct snd_soc_ops asoc_simple_card_ops = {
+	.startup = asoc_simple_card_startup,
+	.shutdown = asoc_simple_card_shutdown,
+};
+
+static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_dai *dai;
+	struct snd_soc_dai_link *dai_link;
+	struct asoc_simple_dai *dai_props;
+	int num = rtd->num;
+
+	dai_link	= simple_priv_to_link(priv, num);
+	dai_props	= simple_priv_to_props(priv, num);
+	dai		= dai_link->dynamic ?
+				rtd->cpu_dai :
+				rtd->codec_dai;
+
+	return asoc_simple_card_init_dai(dai, dai_props);
+}
+
+static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_interval *rate = hw_param_interval(params,
+						      SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	if (priv->convert_rate)
+		rate->min =
+		rate->max = priv->convert_rate;
+
+	if (priv->convert_channels)
+		channels->min =
+		channels->max = priv->convert_channels;
+
+	return 0;
+}
+
+static int asoc_simple_card_parse_links(struct device_node *np,
+					struct asoc_simple_card_priv *priv,
+					unsigned int daifmt,
+					int idx, bool is_fe)
+{
+	struct device *dev = simple_priv_to_dev(priv);
+	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
+	struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, idx);
+	int ret;
+
+	if (is_fe) {
+		int is_single_links = 0;
+
+		/* BE is dummy */
+		dai_link->codec_of_node		= NULL;
+		dai_link->codec_dai_name	= "snd-soc-dummy-dai";
+		dai_link->codec_name		= "snd-soc-dummy";
+
+		/* FE settings */
+		dai_link->dynamic		= 1;
+		dai_link->dpcm_merged_format	= 1;
+
+		ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
+						 &is_single_links);
+		if (ret)
+			return ret;
+
+		ret = asoc_simple_card_parse_clk_cpu(np, dai_link, dai_props);
+		if (ret < 0)
+			return ret;
+
+		ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+							"fe.%s",
+							dai_link->cpu_dai_name);
+		if (ret < 0)
+			return ret;
+
+		asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
+	} else {
+		/* FE is dummy */
+		dai_link->cpu_of_node		= NULL;
+		dai_link->cpu_dai_name		= "snd-soc-dummy-dai";
+		dai_link->cpu_name		= "snd-soc-dummy";
+
+		/* BE settings */
+		dai_link->no_pcm		= 1;
+		dai_link->be_hw_params_fixup	= asoc_simple_card_be_hw_params_fixup;
+
+		ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
+		if (ret < 0)
+			return ret;
+
+		ret = asoc_simple_card_parse_clk_codec(np, dai_link, dai_props);
+		if (ret < 0)
+			return ret;
+
+		ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+							"be.%s",
+							dai_link->codec_dai_name);
+		if (ret < 0)
+			return ret;
+
+		snd_soc_of_parse_audio_prefix(&priv->snd_card,
+					      &priv->codec_conf,
+					      dai_link->codec_of_node,
+					      PREFIX "prefix");
+	}
+
+	ret = snd_soc_of_parse_tdm_slot(np,
+					&dai_props->tx_slot_mask,
+					&dai_props->rx_slot_mask,
+					&dai_props->slots,
+					&dai_props->slot_width);
+	if (ret)
+		return ret;
+
+	ret = asoc_simple_card_canonicalize_dailink(dai_link);
+	if (ret < 0)
+		return ret;
+
+	dai_link->dai_fmt		= daifmt;
+	dai_link->dpcm_playback		= 1;
+	dai_link->dpcm_capture		= 1;
+	dai_link->ops			= &asoc_simple_card_ops;
+	dai_link->init			= asoc_simple_card_dai_init;
+
+	dev_dbg(dev, "\t%s / %04x / %d\n",
+		dai_link->name,
+		dai_link->dai_fmt,
+		dai_props->sysclk);
+
+	return 0;
+}
+
+static int asoc_simple_card_dai_link_of(struct device_node *node,
+				 struct asoc_simple_card_priv *priv)
+{
+	struct device *dev = simple_priv_to_dev(priv);
+	struct device_node *np;
+	unsigned int daifmt = 0;
+	int ret, i;
+	bool is_fe;
+
+	/* find 1st codec */
+	np = of_get_child_by_name(node, PREFIX "codec");
+	if (!np)
+		return -ENODEV;
+
+	ret = asoc_simple_card_parse_daifmt(dev, node, np,
+					    PREFIX, &daifmt);
+	if (ret < 0)
+		return ret;
+
+	i = 0;
+	for_each_child_of_node(node, np) {
+		is_fe = false;
+		if (strcmp(np->name, PREFIX "cpu") == 0)
+			is_fe = true;
+
+		ret = asoc_simple_card_parse_links(np, priv, daifmt, i, is_fe);
+		if (ret < 0)
+			return ret;
+		i++;
+	}
+
+	return 0;
+}
+
+static int asoc_simple_card_parse_of(struct device_node *node,
+			      struct asoc_simple_card_priv *priv,
+			      struct device *dev)
+{
+	struct asoc_simple_dai *props;
+	struct snd_soc_dai_link *links;
+	int ret;
+	int num;
+
+	if (!node)
+		return -EINVAL;
+
+	num = of_get_child_count(node);
+	props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL);
+	links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL);
+	if (!props || !links)
+		return -ENOMEM;
+
+	priv->dai_props	= props;
+	priv->dai_link	= links;
+
+	/* Init snd_soc_card */
+	priv->snd_card.owner			= THIS_MODULE;
+	priv->snd_card.dev			= dev;
+	priv->snd_card.dai_link			= priv->dai_link;
+	priv->snd_card.num_links		= num;
+	priv->snd_card.codec_conf		= &priv->codec_conf;
+	priv->snd_card.num_configs		= 1;
+
+	ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing");
+	if (ret < 0)
+		return ret;
+
+	/* sampling rate convert */
+	of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate);
+
+	/* channels transfer */
+	of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels);
+
+	ret = asoc_simple_card_dai_link_of(node, priv);
+	if (ret < 0)
+		return ret;
+
+	ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(dev, "New card: %s\n",
+		priv->snd_card.name ? priv->snd_card.name : "");
+	dev_dbg(dev, "convert_rate     %d\n", priv->convert_rate);
+	dev_dbg(dev, "convert_channels %d\n", priv->convert_channels);
+
+	return 0;
+}
+
+static int asoc_simple_card_probe(struct platform_device *pdev)
+{
+	struct asoc_simple_card_priv *priv;
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	/* Allocate the private data */
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	ret = asoc_simple_card_parse_of(np, priv, dev);
+	if (ret < 0) {
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "parse error %d\n", ret);
+		goto err;
+	}
+
+	snd_soc_card_set_drvdata(&priv->snd_card, priv);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
+	if (ret >= 0)
+		return ret;
+err:
+	asoc_simple_card_clean_reference(&priv->snd_card);
+
+	return ret;
+}
+
+static int asoc_simple_card_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	return asoc_simple_card_clean_reference(card);
+}
+
+static const struct of_device_id asoc_simple_of_match[] = {
+	{ .compatible = "renesas,rsrc-card", },
+	{ .compatible = "simple-scu-audio-card", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
+
+static struct platform_driver asoc_simple_card = {
+	.driver = {
+		.name = "simple-scu-audio-card",
+		.of_match_table = asoc_simple_of_match,
+	},
+	.probe = asoc_simple_card_probe,
+	.remove = asoc_simple_card_remove,
+};
+
+module_platform_driver(asoc_simple_card);
+
+MODULE_ALIAS("platform:asoc-simple-scu-card");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASoC Simple SCU Sound Card");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c
index 162a0fd68c7b..53e11c6d4e22 100644
--- a/sound/soc/img/pistachio-internal-dac.c
+++ b/sound/soc/img/pistachio-internal-dac.c
@@ -134,12 +134,14 @@ static int pistachio_internal_dac_codec_probe(struct snd_soc_codec *codec)
 static const struct snd_soc_codec_driver pistachio_internal_dac_driver = {
 	.probe = pistachio_internal_dac_codec_probe,
 	.idle_bias_off = true,
-	.controls = pistachio_internal_dac_snd_controls,
-	.num_controls = ARRAY_SIZE(pistachio_internal_dac_snd_controls),
-	.dapm_widgets = pistachio_internal_dac_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(pistachio_internal_dac_widgets),
-	.dapm_routes = pistachio_internal_dac_routes,
-	.num_dapm_routes = ARRAY_SIZE(pistachio_internal_dac_routes),
+	.component_driver = {
+		.controls		= pistachio_internal_dac_snd_controls,
+		.num_controls		= ARRAY_SIZE(pistachio_internal_dac_snd_controls),
+		.dapm_widgets		= pistachio_internal_dac_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(pistachio_internal_dac_widgets),
+		.dapm_routes		= pistachio_internal_dac_routes,
+		.num_dapm_routes	= ARRAY_SIZE(pistachio_internal_dac_routes),
+	},
 };
 
 static int pistachio_internal_dac_probe(struct platform_device *pdev)
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index a20c3dfbcb5d..26eb5a0a5575 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -25,6 +25,7 @@ config SND_SST_IPC_ACPI
 	tristate
 	select SND_SST_IPC
 	select SND_SOC_INTEL_SST
+	select IOSF_MBI
 
 config SND_SOC_INTEL_SST
 	tristate
@@ -120,6 +121,17 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
 	  This adds audio driver for Intel Baytrail platform based boards
 	  with the MAX98090 audio codec.
 
+config SND_SOC_INTEL_BDW_RT5677_MACH
+	tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec"
+	depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC
+	depends on DW_DMAC_CORE=y
+	select SND_SOC_INTEL_SST
+	select SND_SOC_INTEL_HASWELL
+	select SND_SOC_RT5677
+	help
+	  This adds support for Intel Broadwell platform based boards with
+	  the RT5677 audio codec.
+
 config SND_SOC_INTEL_BROADWELL_MACH
 	tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
 	depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index 98720a93de8a..0838478c4c3f 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -1,4 +1,4 @@
-/*
+ /*
  *  sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld
  *
  *  Copyright (C) 2013-14 Intel Corp
@@ -534,6 +534,7 @@ static const DECLARE_TLV_DB_SCALE(sst_gain_tlv_common, SST_GAIN_MIN_VALUE * 10,
 
 /* Look up table to convert MIXER SW bit regs to SWM inputs */
 static const uint swm_mixer_input_ids[SST_SWM_INPUT_COUNT] = {
+	[SST_IP_MODEM]		= SST_SWM_IN_MODEM,
 	[SST_IP_CODEC0]		= SST_SWM_IN_CODEC0,
 	[SST_IP_CODEC1]		= SST_SWM_IN_CODEC1,
 	[SST_IP_LOOP0]		= SST_SWM_IN_SPROT_LOOP,
@@ -674,6 +675,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w,
 /* SBA mixers - 16 inputs */
 #define SST_SBA_DECLARE_MIX_CONTROLS(kctl_name)							\
 	static const struct snd_kcontrol_new kctl_name[] = {					\
+		SOC_DAPM_SINGLE("modem_in Switch", SND_SOC_NOPM, SST_IP_MODEM, 1, 0),		\
 		SOC_DAPM_SINGLE("codec_in0 Switch", SND_SOC_NOPM, SST_IP_CODEC0, 1, 0),		\
 		SOC_DAPM_SINGLE("codec_in1 Switch", SND_SOC_NOPM, SST_IP_CODEC1, 1, 0),		\
 		SOC_DAPM_SINGLE("sprot_loop_in Switch", SND_SOC_NOPM, SST_IP_LOOP0, 1, 0),	\
@@ -684,6 +686,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w,
 	}
 
 #define SST_SBA_MIXER_GRAPH_MAP(mix_name)			\
+	{ mix_name, "modem_in Switch",	"modem_in" },		\
 	{ mix_name, "codec_in0 Switch",	"codec_in0" },		\
 	{ mix_name, "codec_in1 Switch",	"codec_in1" },		\
 	{ mix_name, "sprot_loop_in Switch",	"sprot_loop_in" },	\
@@ -713,6 +716,7 @@ SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls);
 SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls);
 SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls);
 SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_modem_controls);
 
 /*
  * sst_handle_vb_timer - Start/Stop the DSP scheduler
@@ -931,17 +935,26 @@ void sst_fill_ssp_defaults(struct snd_soc_dai *dai)
 int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable)
 {
 	struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
-	const struct sst_ssp_config *config;
+	int ssp_id;
 
 	dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id);
 
+	if (strcmp(id, "ssp0-port") == 0)
+		ssp_id = SSP_MODEM;
+	else if (strcmp(id, "ssp2-port") == 0)
+		ssp_id = SSP_CODEC;
+	else {
+		dev_dbg(dai->dev, "port %s is not supported\n", id);
+		return -1;
+	}
+
 	SST_FILL_DEFAULT_DESTINATION(drv->ssp_cmd.header.dst);
 	drv->ssp_cmd.header.command_id = SBA_HW_SET_SSP;
 	drv->ssp_cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp)
 				- sizeof(struct sst_dsp_header);
 
-	config = &sst_ssp_configs;
-	dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id);
+	drv->ssp_cmd.selection = ssp_id;
+	dev_dbg(dai->dev, "ssp_id: %u\n", ssp_id);
 
 	if (enable)
 		drv->ssp_cmd.switch_state = SST_SWITCH_ON;
@@ -1047,8 +1060,10 @@ static int sst_set_media_loop(struct snd_soc_dapm_widget *w,
 }
 
 static const struct snd_soc_dapm_widget sst_dapm_widgets[] = {
+	SST_AIF_IN("modem_in", sst_set_be_modules),
 	SST_AIF_IN("codec_in0", sst_set_be_modules),
 	SST_AIF_IN("codec_in1", sst_set_be_modules),
+	SST_AIF_OUT("modem_out", sst_set_be_modules),
 	SST_AIF_OUT("codec_out0", sst_set_be_modules),
 	SST_AIF_OUT("codec_out1", sst_set_be_modules),
 
@@ -1103,6 +1118,9 @@ static const struct snd_soc_dapm_widget sst_dapm_widgets[] = {
 		      sst_mix_codec0_controls, sst_swm_mixer_event),
 	SST_SWM_MIXER("codec_out1 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC1,
 		      sst_mix_codec1_controls, sst_swm_mixer_event),
+	SST_SWM_MIXER("modem_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MODEM,
+		      sst_mix_modem_controls, sst_swm_mixer_event),
+
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
@@ -1148,6 +1166,9 @@ static const struct snd_soc_dapm_route intercon[] = {
 	SST_SBA_MIXER_GRAPH_MAP("codec_out0 mix 0"),
 	{"codec_out1", NULL, "codec_out1 mix 0"},
 	SST_SBA_MIXER_GRAPH_MAP("codec_out1 mix 0"),
+	{"modem_out", NULL, "modem_out mix 0"},
+	SST_SBA_MIXER_GRAPH_MAP("modem_out mix 0"),
+
 
 };
 static const char * const slot_names[] = {
@@ -1217,6 +1238,9 @@ static const struct snd_kcontrol_new sst_gain_controls[] = {
 	SST_GAIN("media_loop2_out", SST_PATH_INDEX_MEDIA_LOOP2_OUT, SST_TASK_SBA, 0, &sst_gains[13]),
 	SST_GAIN("sprot_loop_out", SST_PATH_INDEX_SPROT_LOOP_OUT, SST_TASK_SBA, 0, &sst_gains[14]),
 	SST_VOLUME("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[15]),
+	SST_GAIN("modem_in", SST_PATH_INDEX_MODEM_IN, SST_TASK_SBA, 0, &sst_gains[16]),
+	SST_GAIN("modem_out", SST_PATH_INDEX_MODEM_OUT, SST_TASK_SBA, 0, &sst_gains[17]),
+
 };
 
 #define SST_GAIN_NUM_CONTROLS 3
diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h
index e0113112f668..351d81469685 100644
--- a/sound/soc/intel/atom/sst-atom-controls.h
+++ b/sound/soc/intel/atom/sst-atom-controls.h
@@ -35,6 +35,8 @@ enum {
 /* define a bit for each mixer input */
 #define SST_MIX_IP(x)		(x)
 
+#define SST_IP_MODEM		SST_MIX_IP(0)
+#define SST_IP_BT		SST_MIX_IP(1)
 #define SST_IP_CODEC0		SST_MIX_IP(2)
 #define SST_IP_CODEC1		SST_MIX_IP(3)
 #define SST_IP_LOOP0		SST_MIX_IP(4)
@@ -63,6 +65,7 @@ enum {
  * Audio DSP Path Ids. Specified by the audio DSP FW
  */
 enum sst_path_index {
+	SST_PATH_INDEX_MODEM_OUT                = (0x00 << SST_PATH_ID_SHIFT),
 	SST_PATH_INDEX_CODEC_OUT0               = (0x02 << SST_PATH_ID_SHIFT),
 	SST_PATH_INDEX_CODEC_OUT1               = (0x03 << SST_PATH_ID_SHIFT),
 
@@ -80,6 +83,7 @@ enum sst_path_index {
 
 
 	/* Start of input paths */
+	SST_PATH_INDEX_MODEM_IN                 = (0x80 << SST_PATH_ID_SHIFT),
 	SST_PATH_INDEX_CODEC_IN0                = (0x82 << SST_PATH_ID_SHIFT),
 	SST_PATH_INDEX_CODEC_IN1                = (0x83 << SST_PATH_ID_SHIFT),
 
@@ -105,6 +109,7 @@ enum sst_path_index {
  * path IDs
  */
 enum sst_swm_inputs {
+	SST_SWM_IN_MODEM	= (SST_PATH_INDEX_MODEM_IN	  | SST_DEFAULT_CELL_NBR),
 	SST_SWM_IN_CODEC0	= (SST_PATH_INDEX_CODEC_IN0	  | SST_DEFAULT_CELL_NBR),
 	SST_SWM_IN_CODEC1	= (SST_PATH_INDEX_CODEC_IN1	  | SST_DEFAULT_CELL_NBR),
 	SST_SWM_IN_SPROT_LOOP	= (SST_PATH_INDEX_SPROT_LOOP_IN	  | SST_DEFAULT_CELL_NBR),
@@ -124,6 +129,7 @@ enum sst_swm_inputs {
  * path IDs
  */
 enum sst_swm_outputs {
+	SST_SWM_OUT_MODEM	= (SST_PATH_INDEX_MODEM_OUT	  | SST_DEFAULT_CELL_NBR),
 	SST_SWM_OUT_CODEC0	= (SST_PATH_INDEX_CODEC_OUT0	  | SST_DEFAULT_CELL_NBR),
 	SST_SWM_OUT_CODEC1	= (SST_PATH_INDEX_CODEC_OUT1	  | SST_DEFAULT_CELL_NBR),
 	SST_SWM_OUT_SPROT_LOOP	= (SST_PATH_INDEX_SPROT_LOOP_OUT  | SST_DEFAULT_CELL_NBR),
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index 52ed434cbca6..25c6d87c818e 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -670,7 +670,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer
 	return str_info->buffer_ptr;
 }
 
-static struct snd_pcm_ops sst_platform_ops = {
+static const struct snd_pcm_ops sst_platform_ops = {
 	.open = sst_platform_open,
 	.ioctl = snd_pcm_lib_ioctl,
 	.trigger = sst_platform_pcm_trigger,
diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c
index a4b458e77089..9b6e27385dc9 100644
--- a/sound/soc/intel/atom/sst/sst.c
+++ b/sound/soc/intel/atom/sst/sst.c
@@ -190,7 +190,8 @@ int sst_driver_ops(struct intel_sst_drv *sst)
 
 	default:
 		dev_err(sst->dev,
-			"SST Driver capablities missing for dev_id: %x", sst->dev_id);
+			"SST Driver capabilities missing for dev_id: %x",
+			sst->dev_id);
 		return -EINVAL;
 	};
 }
@@ -441,7 +442,7 @@ static int intel_sst_suspend(struct device *dev)
 		struct stream_info *stream = &ctx->streams[i];
 
 		if (stream->status == STREAM_RUNNING) {
-			dev_err(dev, "stream %d is running, cant susupend, abort\n", i);
+			dev_err(dev, "stream %d is running, can't suspend, abort\n", i);
 			return -EBUSY;
 		}
 	}
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index 4d3184971227..ba5c0d71720a 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -39,6 +39,8 @@
 #include <acpi/platform/aclinux.h>
 #include <acpi/actypes.h>
 #include <acpi/acpi_bus.h>
+#include <asm/cpu_device_id.h>
+#include <asm/iosf_mbi.h>
 #include "../sst-mfld-platform.h"
 #include "../../common/sst-dsp.h"
 #include "../../common/sst-acpi.h"
@@ -113,6 +115,28 @@ static const struct sst_res_info byt_rvp_res_info = {
 	.acpi_ipc_irq_index = 5,
 };
 
+/* BYTCR has different BIOS from BYT */
+static const struct sst_res_info bytcr_res_info = {
+	.shim_offset = 0x140000,
+	.shim_size = 0x000100,
+	.shim_phy_addr = SST_BYT_SHIM_PHY_ADDR,
+	.ssp0_offset = 0xa0000,
+	.ssp0_size = 0x1000,
+	.dma0_offset = 0x98000,
+	.dma0_size = 0x4000,
+	.dma1_offset = 0x9c000,
+	.dma1_size = 0x4000,
+	.iram_offset = 0x0c0000,
+	.iram_size = 0x14000,
+	.dram_offset = 0x100000,
+	.dram_size = 0x28000,
+	.mbox_offset = 0x144000,
+	.mbox_size = 0x1000,
+	.acpi_lpe_res_index = 0,
+	.acpi_ddr_index = 2,
+	.acpi_ipc_irq_index = 0
+};
+
 static struct sst_platform_info byt_rvp_platform_data = {
 	.probe_data = &byt_fwparse_info,
 	.ipc_info = &byt_ipc_info,
@@ -142,7 +166,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
 	rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
 					ctx->pdata->res_info->acpi_lpe_res_index);
 	if (!rsrc) {
-		dev_err(ctx->dev, "Invalid SHIM base from IFWI");
+		dev_err(ctx->dev, "Invalid SHIM base from IFWI\n");
 		return -EIO;
 	}
 	dev_info(ctx->dev, "LPE base: %#x size:%#x", (unsigned int) rsrc->start,
@@ -154,7 +178,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
 	ctx->iram = devm_ioremap_nocache(ctx->dev, ctx->iram_base,
 					 ctx->pdata->res_info->iram_size);
 	if (!ctx->iram) {
-		dev_err(ctx->dev, "unable to map IRAM");
+		dev_err(ctx->dev, "unable to map IRAM\n");
 		return -EIO;
 	}
 
@@ -164,7 +188,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
 	ctx->dram = devm_ioremap_nocache(ctx->dev, ctx->dram_base,
 					 ctx->pdata->res_info->dram_size);
 	if (!ctx->dram) {
-		dev_err(ctx->dev, "unable to map DRAM");
+		dev_err(ctx->dev, "unable to map DRAM\n");
 		return -EIO;
 	}
 
@@ -173,7 +197,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
 	ctx->shim = devm_ioremap_nocache(ctx->dev, ctx->shim_phy_add,
 					ctx->pdata->res_info->shim_size);
 	if (!ctx->shim) {
-		dev_err(ctx->dev, "unable to map SHIM");
+		dev_err(ctx->dev, "unable to map SHIM\n");
 		return -EIO;
 	}
 
@@ -186,7 +210,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
 	ctx->mailbox = devm_ioremap_nocache(ctx->dev, ctx->mailbox_add,
 					    ctx->pdata->res_info->mbox_size);
 	if (!ctx->mailbox) {
-		dev_err(ctx->dev, "unable to map mailbox");
+		dev_err(ctx->dev, "unable to map mailbox\n");
 		return -EIO;
 	}
 
@@ -196,7 +220,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
 	rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
 					ctx->pdata->res_info->acpi_ddr_index);
 	if (!rsrc) {
-		dev_err(ctx->dev, "Invalid DDR base from IFWI");
+		dev_err(ctx->dev, "Invalid DDR base from IFWI\n");
 		return -EIO;
 	}
 	ctx->ddr_base = rsrc->start;
@@ -205,7 +229,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
 	ctx->ddr = devm_ioremap_nocache(ctx->dev, ctx->ddr_base,
 					resource_size(rsrc));
 	if (!ctx->ddr) {
-		dev_err(ctx->dev, "unable to map DDR");
+		dev_err(ctx->dev, "unable to map DDR\n");
 		return -EIO;
 	}
 
@@ -215,6 +239,46 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
 	return 0;
 }
 
+
+static int is_byt_cr(struct device *dev, bool *bytcr)
+{
+	int status = 0;
+
+	if (IS_ENABLED(CONFIG_IOSF_MBI)) {
+		static const struct x86_cpu_id cpu_ids[] = {
+			{ X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */
+			{}
+		};
+		u32 bios_status;
+
+		if (!x86_match_cpu(cpu_ids) || !iosf_mbi_available()) {
+			/* bail silently */
+			return status;
+		}
+
+		status = iosf_mbi_read(BT_MBI_UNIT_PMC, /* 0x04 PUNIT */
+				       MBI_REG_READ, /* 0x10 */
+				       0x006, /* BIOS_CONFIG */
+				       &bios_status);
+
+		if (status) {
+			dev_err(dev, "could not read PUNIT BIOS_CONFIG\n");
+		} else {
+			/* bits 26:27 mirror PMIC options */
+			bios_status = (bios_status >> 26) & 3;
+
+			if ((bios_status == 1) || (bios_status == 3))
+				*bytcr = true;
+			else
+				dev_info(dev, "BYT-CR not detected\n");
+		}
+	} else {
+		dev_info(dev, "IOSF_MBI not enabled, no BYT-CR detection\n");
+	}
+	return status;
+}
+
+
 static int sst_acpi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -226,11 +290,12 @@ static int sst_acpi_probe(struct platform_device *pdev)
 	struct platform_device *plat_dev;
 	struct sst_platform_info *pdata;
 	unsigned int dev_id;
+	bool bytcr = false;
 
 	id = acpi_match_device(dev->driver->acpi_match_table, dev);
 	if (!id)
 		return -ENODEV;
-	dev_dbg(dev, "for %s", id->id);
+	dev_dbg(dev, "for %s\n", id->id);
 
 	mach = (struct sst_acpi_mach *)id->driver_data;
 	mach = sst_acpi_find_machine(mach);
@@ -251,6 +316,18 @@ static int sst_acpi_probe(struct platform_device *pdev)
 
 	dev_dbg(dev, "ACPI device id: %x\n", dev_id);
 
+	ret = sst_alloc_drv_context(&ctx, dev, dev_id);
+	if (ret < 0)
+		return ret;
+
+	ret = is_byt_cr(dev, &bytcr);
+	if (!((ret < 0) || (bytcr == false))) {
+		dev_info(dev, "Detected Baytrail-CR platform\n");
+
+		/* override resource info */
+		byt_rvp_platform_data.res_info = &bytcr_res_info;
+	}
+
 	plat_dev = platform_device_register_data(dev, pdata->platform, -1,
 						NULL, 0);
 	if (IS_ERR(plat_dev)) {
@@ -271,10 +348,6 @@ static int sst_acpi_probe(struct platform_device *pdev)
 		return PTR_ERR(mdev);
 	}
 
-	ret = sst_alloc_drv_context(&ctx, dev, dev_id);
-	if (ret < 0)
-		return ret;
-
 	/* Fill sst platform data */
 	ctx->pdata = pdata;
 	strcpy(ctx->firmware_name, mach->fw_filename);
diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c
index 8afa6fe7b0b0..bfc889950bb2 100644
--- a/sound/soc/intel/atom/sst/sst_ipc.c
+++ b/sound/soc/intel/atom/sst/sst_ipc.c
@@ -267,6 +267,9 @@ static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx,
 				"Period elapsed rcvd for pipe id 0x%x\n",
 				pipe_id);
 			stream = &sst_drv_ctx->streams[str_id];
+			/* If stream is dropped, skip processing this message*/
+			if (stream->status == STREAM_INIT)
+				break;
 			if (stream->period_elapsed)
 				stream->period_elapsed(stream->pcm_substream);
 			if (stream->compr_cb)
diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c
index adb32fefd693..b1e6b8f34a6a 100644
--- a/sound/soc/intel/atom/sst/sst_pvt.c
+++ b/sound/soc/intel/atom/sst/sst_pvt.c
@@ -279,17 +279,15 @@ int sst_prepare_and_post_msg(struct intel_sst_drv *sst,
 
 	if (response) {
 		ret = sst_wait_timeout(sst, block);
-		if (ret < 0) {
+		if (ret < 0)
 			goto out;
-		} else if(block->data) {
-			if (!data)
-				goto out;
-			*data = kzalloc(block->size, GFP_KERNEL);
-			if (!(*data)) {
+
+		if (data && block->data) {
+			*data = kmemdup(block->data, block->size, GFP_KERNEL);
+			if (!*data) {
 				ret = -ENOMEM;
 				goto out;
-			} else
-				memcpy(data, (void *) block->data, block->size);
+			}
 		}
 	}
 out:
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index dac03a06bfd8..5639f10774e6 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -1,6 +1,7 @@
 snd-soc-sst-haswell-objs := haswell.o
 snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
 snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
+snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o
 snd-soc-sst-broadwell-objs := broadwell.o
 snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o
 snd-soc-sst-bxt-rt298-objs := bxt_rt298.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o
 obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o
 obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
+obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
 obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
new file mode 100644
index 000000000000..547e6705bf6d
--- /dev/null
+++ b/sound/soc/intel/boards/bdw-rt5677.c
@@ -0,0 +1,347 @@
+/*
+ * ASoC machine driver for Intel Broadwell platforms with RT5677 codec
+ *
+ * Copyright (c) 2014, The Chromium OS Authors.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+
+#include "../common/sst-dsp.h"
+#include "../haswell/sst-haswell-ipc.h"
+
+#include "../../codecs/rt5677.h"
+
+struct bdw_rt5677_priv {
+	struct gpio_desc *gpio_hp_en;
+	struct snd_soc_codec *codec;
+};
+
+static int bdw_rt5677_event_hp(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *k, int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card);
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		msleep(70);
+
+	gpiod_set_value_cansleep(bdw_rt5677->gpio_hp_en,
+		SND_SOC_DAPM_EVENT_ON(event));
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget bdw_rt5677_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone", bdw_rt5677_event_hp),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Local DMICs", NULL),
+	SND_SOC_DAPM_MIC("Remote DMICs", NULL),
+};
+
+static const struct snd_soc_dapm_route bdw_rt5677_map[] = {
+	/* Speakers */
+	{"Speaker", NULL, "PDM1L"},
+	{"Speaker", NULL, "PDM1R"},
+
+	/* Headset jack connectors */
+	{"Headphone", NULL, "LOUT1"},
+	{"Headphone", NULL, "LOUT2"},
+	{"IN1P", NULL, "Headset Mic"},
+	{"IN1N", NULL, "Headset Mic"},
+
+	/* Digital MICs
+	 * Local DMICs: the two DMICs on the mainboard
+	 * Remote DMICs: the two DMICs on the camera module
+	 */
+	{"DMIC L1", NULL, "Remote DMICs"},
+	{"DMIC R1", NULL, "Remote DMICs"},
+	{"DMIC L2", NULL, "Local DMICs"},
+	{"DMIC R2", NULL, "Local DMICs"},
+
+	/* CODEC BE connections */
+	{"SSP0 CODEC IN", NULL, "AIF1 Capture"},
+	{"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
+};
+
+static const struct snd_kcontrol_new bdw_rt5677_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Speaker"),
+	SOC_DAPM_PIN_SWITCH("Headphone"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Local DMICs"),
+	SOC_DAPM_PIN_SWITCH("Remote DMICs"),
+};
+
+
+static struct snd_soc_jack headphone_jack;
+static struct snd_soc_jack mic_jack;
+
+static struct snd_soc_jack_pin headphone_jack_pin = {
+	.pin	= "Headphone",
+	.mask	= SND_JACK_HEADPHONE,
+};
+
+static struct snd_soc_jack_pin mic_jack_pin = {
+	.pin	= "Headset Mic",
+	.mask	= SND_JACK_MICROPHONE,
+};
+
+static struct snd_soc_jack_gpio headphone_jack_gpio = {
+	.name			= "plug-det",
+	.report			= SND_JACK_HEADPHONE,
+	.debounce_time		= 200,
+};
+
+static struct snd_soc_jack_gpio mic_jack_gpio = {
+	.name			= "mic-present",
+	.report			= SND_JACK_MICROPHONE,
+	.debounce_time		= 200,
+	.invert			= 1,
+};
+
+static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	/* The ADSP will covert the FE rate to 48k, stereo */
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	/* set SSP0 to 16 bit */
+	snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
+				    SNDRV_PCM_HW_PARAM_FIRST_MASK],
+				    SNDRV_PCM_FORMAT_S16_LE);
+	return 0;
+}
+
+static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_MCLK, 24576000,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set codec sysclk configuration\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static struct snd_soc_ops bdw_rt5677_ops = {
+	.hw_params = bdw_rt5677_hw_params,
+};
+
+static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
+	struct sst_hsw *broadwell = pdata->dsp;
+	int ret;
+
+	/* Set ADSP SSP port settings */
+	ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
+		SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
+		SST_HSW_DEVICE_CLOCK_MASTER, 9);
+	if (ret < 0) {
+		dev_err(rtd->dev, "error: failed to set device config\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct bdw_rt5677_priv *bdw_rt5677 =
+			snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+	/* Enable codec ASRC function for Stereo DAC/Stereo1 ADC/DMIC/I2S1.
+	 * The ASRC clock source is clk_i2s1_asrc.
+	 */
+	rt5677_sel_asrc_clk_src(codec, RT5677_DA_STEREO_FILTER |
+			RT5677_AD_STEREO1_FILTER | RT5677_I2S1_SOURCE,
+			RT5677_CLK_SEL_I2S1_ASRC);
+
+	/* Request rt5677 GPIO for headphone amp control */
+	bdw_rt5677->gpio_hp_en = devm_gpiod_get_index(codec->dev,
+			"headphone-enable", 0, 0);
+	if (IS_ERR(bdw_rt5677->gpio_hp_en)) {
+		dev_err(codec->dev, "Can't find HP_AMP_SHDN_L gpio\n");
+		return PTR_ERR(bdw_rt5677->gpio_hp_en);
+	}
+	gpiod_direction_output(bdw_rt5677->gpio_hp_en, 0);
+
+	/* Create and initialize headphone jack */
+	if (!snd_soc_card_jack_new(rtd->card, "Headphone Jack",
+			SND_JACK_HEADPHONE, &headphone_jack,
+			&headphone_jack_pin, 1)) {
+		headphone_jack_gpio.gpiod_dev = codec->dev;
+		if (snd_soc_jack_add_gpios(&headphone_jack, 1,
+				&headphone_jack_gpio))
+			dev_err(codec->dev, "Can't add headphone jack gpio\n");
+	} else {
+		dev_err(codec->dev, "Can't create headphone jack\n");
+	}
+
+	/* Create and initialize mic jack */
+	if (!snd_soc_card_jack_new(rtd->card, "Mic Jack",
+			SND_JACK_MICROPHONE, &mic_jack,
+			&mic_jack_pin, 1)) {
+		mic_jack_gpio.gpiod_dev = codec->dev;
+		if (snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio))
+			dev_err(codec->dev, "Can't add mic jack gpio\n");
+	} else {
+		dev_err(codec->dev, "Can't create mic jack\n");
+	}
+	bdw_rt5677->codec = codec;
+
+	snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+	return 0;
+}
+
+/* broadwell digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link bdw_rt5677_dais[] = {
+	/* Front End DAI links */
+	{
+		.name = "System PCM",
+		.stream_name = "System Playback/Capture",
+		.cpu_dai_name = "System Pin",
+		.platform_name = "haswell-pcm-audio",
+		.dynamic = 1,
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.init = bdw_rt5677_rtd_init,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST
+		},
+		.dpcm_capture = 1,
+		.dpcm_playback = 1,
+	},
+
+	/* Back End DAI links */
+	{
+		/* SSP0 - Codec */
+		.name = "Codec",
+		.id = 0,
+		.cpu_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "snd-soc-dummy",
+		.no_pcm = 1,
+		.codec_name = "i2c-RT5677CE:00",
+		.codec_dai_name = "rt5677-aif1",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.be_hw_params_fixup = broadwell_ssp0_fixup,
+		.ops = &bdw_rt5677_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.init = bdw_rt5677_init,
+	},
+};
+
+static int bdw_rt5677_suspend_pre(struct snd_soc_card *card)
+{
+	struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card);
+	struct snd_soc_dapm_context *dapm;
+
+	if (bdw_rt5677->codec) {
+		dapm = snd_soc_codec_get_dapm(bdw_rt5677->codec);
+		snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+	}
+	return 0;
+}
+
+static int bdw_rt5677_resume_post(struct snd_soc_card *card)
+{
+	struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card);
+	struct snd_soc_dapm_context *dapm;
+
+	if (bdw_rt5677->codec) {
+		dapm = snd_soc_codec_get_dapm(bdw_rt5677->codec);
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+	}
+	return 0;
+}
+
+/* ASoC machine driver for Broadwell DSP + RT5677 */
+static struct snd_soc_card bdw_rt5677_card = {
+	.name = "bdw-rt5677",
+	.owner = THIS_MODULE,
+	.dai_link = bdw_rt5677_dais,
+	.num_links = ARRAY_SIZE(bdw_rt5677_dais),
+	.dapm_widgets = bdw_rt5677_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(bdw_rt5677_widgets),
+	.dapm_routes = bdw_rt5677_map,
+	.num_dapm_routes = ARRAY_SIZE(bdw_rt5677_map),
+	.controls = bdw_rt5677_controls,
+	.num_controls = ARRAY_SIZE(bdw_rt5677_controls),
+	.fully_routed = true,
+	.suspend_pre = bdw_rt5677_suspend_pre,
+	.resume_post = bdw_rt5677_resume_post,
+};
+
+static int bdw_rt5677_probe(struct platform_device *pdev)
+{
+	struct bdw_rt5677_priv *bdw_rt5677;
+
+	bdw_rt5677_card.dev = &pdev->dev;
+
+	/* Allocate driver private struct */
+	bdw_rt5677 = devm_kzalloc(&pdev->dev, sizeof(struct bdw_rt5677_priv),
+		GFP_KERNEL);
+	if (!bdw_rt5677) {
+		dev_err(&pdev->dev, "Can't allocate bdw_rt5677\n");
+		return -ENOMEM;
+	}
+
+	snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677);
+
+	return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card);
+}
+
+static struct platform_driver bdw_rt5677_audio = {
+	.probe = bdw_rt5677_probe,
+	.driver = {
+		.name = "bdw-rt5677",
+	},
+};
+
+module_platform_driver(bdw_rt5677_audio)
+
+/* Module information */
+MODULE_AUTHOR("Ben Zhang");
+MODULE_DESCRIPTION("Intel Broadwell RT5677 machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bdw-rt5677");
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c
index 3774b117d365..6532b8f0ab2f 100644
--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
+++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c
@@ -37,6 +37,7 @@ enum {
 	BXT_DPCM_AUDIO_PB = 0,
 	BXT_DPCM_AUDIO_CP,
 	BXT_DPCM_AUDIO_REF_CP,
+	BXT_DPCM_AUDIO_DMIC_CP,
 	BXT_DPCM_AUDIO_HDMI1_PB,
 	BXT_DPCM_AUDIO_HDMI2_PB,
 	BXT_DPCM_AUDIO_HDMI3_PB,
@@ -252,10 +253,56 @@ static struct snd_soc_ops broxton_da7219_ops = {
 	.hw_free = broxton_da7219_hw_free,
 };
 
+static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *channels = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_CHANNELS);
+	channels->min = channels->max = DUAL_CHANNEL;
+
+	return 0;
+}
+
+static int broxton_dmic_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	runtime->hw.channels_max = DUAL_CHANNEL;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+			&constraints_channels);
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static const struct snd_soc_ops broxton_dmic_ops = {
+	.startup = broxton_dmic_startup,
+};
+
+static const unsigned int rates_16000[] = {
+	16000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_16000 = {
+	.count = ARRAY_SIZE(rates_16000),
+	.list  = rates_16000,
+};
+
+static int broxton_refcap_startup(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE,
+			&constraints_16000);
+};
+
+static struct snd_soc_ops broxton_refcap_ops = {
+	.startup = broxton_refcap_startup,
+};
+
 /* broxton digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link broxton_dais[] = {
 	/* Front End DAI links */
-	[BXT_DPCM_AUDIO_PB]
+	[BXT_DPCM_AUDIO_PB] =
 	{
 		.name = "Bxt Audio Port",
 		.stream_name = "Audio",
@@ -271,7 +318,7 @@ static struct snd_soc_dai_link broxton_dais[] = {
 		.dpcm_playback = 1,
 		.ops = &broxton_da7219_fe_ops,
 	},
-	[BXT_DPCM_AUDIO_CP]
+	[BXT_DPCM_AUDIO_CP] =
 	{
 		.name = "Bxt Audio Capture Port",
 		.stream_name = "Audio Record",
@@ -286,7 +333,7 @@ static struct snd_soc_dai_link broxton_dais[] = {
 		.dpcm_capture = 1,
 		.ops = &broxton_da7219_fe_ops,
 	},
-	[BXT_DPCM_AUDIO_REF_CP]
+	[BXT_DPCM_AUDIO_REF_CP] =
 	{
 		.name = "Bxt Audio Reference cap",
 		.stream_name = "Refcap",
@@ -299,8 +346,23 @@ static struct snd_soc_dai_link broxton_dais[] = {
 		.ignore_suspend = 1,
 		.nonatomic = 1,
 		.dynamic = 1,
+		.ops = &broxton_refcap_ops,
+	},
+	[BXT_DPCM_AUDIO_DMIC_CP]
+	{
+		.name = "Bxt Audio DMIC cap",
+		.stream_name = "dmiccap",
+		.cpu_dai_name = "DMIC Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:0e.0",
+		.init = NULL,
+		.dpcm_capture = 1,
+		.nonatomic = 1,
+		.dynamic = 1,
+		.ops = &broxton_dmic_ops,
 	},
-	[BXT_DPCM_AUDIO_HDMI1_PB]
+	[BXT_DPCM_AUDIO_HDMI1_PB] =
 	{
 		.name = "Bxt HDMI Port1",
 		.stream_name = "Hdmi1",
@@ -313,7 +375,7 @@ static struct snd_soc_dai_link broxton_dais[] = {
 		.nonatomic = 1,
 		.dynamic = 1,
 	},
-	[BXT_DPCM_AUDIO_HDMI2_PB]
+	[BXT_DPCM_AUDIO_HDMI2_PB] =
 	{
 		.name = "Bxt HDMI Port2",
 		.stream_name = "Hdmi2",
@@ -326,7 +388,7 @@ static struct snd_soc_dai_link broxton_dais[] = {
 		.nonatomic = 1,
 		.dynamic = 1,
 	},
-	[BXT_DPCM_AUDIO_HDMI3_PB]
+	[BXT_DPCM_AUDIO_HDMI3_PB] =
 	{
 		.name = "Bxt HDMI Port3",
 		.stream_name = "Hdmi3",
@@ -382,6 +444,7 @@ static struct snd_soc_dai_link broxton_dais[] = {
 		.codec_dai_name = "dmic-hifi",
 		.platform_name = "0000:00:0e.0",
 		.ignore_suspend = 1,
+		.be_hw_params_fixup = broxton_dmic_fixup,
 		.dpcm_capture = 1,
 		.no_pcm = 1,
 	},
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c
index 253d7bfbf511..d610bdca1608 100644
--- a/sound/soc/intel/boards/bxt_rt298.c
+++ b/sound/soc/intel/boards/bxt_rt298.c
@@ -271,7 +271,7 @@ static const struct snd_soc_ops broxton_rt286_fe_ops = {
 /* broxton digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link broxton_rt298_dais[] = {
 	/* Front End DAI links */
-	[BXT_DPCM_AUDIO_PB]
+	[BXT_DPCM_AUDIO_PB] =
 	{
 		.name = "Bxt Audio Port",
 		.stream_name = "Audio",
@@ -286,7 +286,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
 		.dpcm_playback = 1,
 		.ops = &broxton_rt286_fe_ops,
 	},
-	[BXT_DPCM_AUDIO_CP]
+	[BXT_DPCM_AUDIO_CP] =
 	{
 		.name = "Bxt Audio Capture Port",
 		.stream_name = "Audio Record",
@@ -300,7 +300,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
 		.dpcm_capture = 1,
 		.ops = &broxton_rt286_fe_ops,
 	},
-	[BXT_DPCM_AUDIO_REF_CP]
+	[BXT_DPCM_AUDIO_REF_CP] =
 	{
 		.name = "Bxt Audio Reference cap",
 		.stream_name = "refcap",
@@ -313,7 +313,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
 		.nonatomic = 1,
 		.dynamic = 1,
 	},
-	[BXT_DPCM_AUDIO_DMIC_CP]
+	[BXT_DPCM_AUDIO_DMIC_CP] =
 	{
 		.name = "Bxt Audio DMIC cap",
 		.stream_name = "dmiccap",
@@ -327,7 +327,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
 		.dynamic = 1,
 		.ops = &broxton_dmic_ops,
 	},
-	[BXT_DPCM_AUDIO_HDMI1_PB]
+	[BXT_DPCM_AUDIO_HDMI1_PB] =
 	{
 		.name = "Bxt HDMI Port1",
 		.stream_name = "Hdmi1",
@@ -340,7 +340,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
 		.nonatomic = 1,
 		.dynamic = 1,
 	},
-	[BXT_DPCM_AUDIO_HDMI2_PB]
+	[BXT_DPCM_AUDIO_HDMI2_PB] =
 	{
 		.name = "Bxt HDMI Port2",
 		.stream_name = "Hdmi2",
@@ -353,7 +353,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
 		.nonatomic = 1,
 		.dynamic = 1,
 	},
-	[BXT_DPCM_AUDIO_HDMI3_PB]
+	[BXT_DPCM_AUDIO_HDMI3_PB] =
 	{
 		.name = "Bxt HDMI Port3",
 		.stream_name = "Hdmi3",
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 88efb62439ba..bff77a1f27fc 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -24,6 +24,9 @@
 #include <linux/device.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
+#include <asm/cpu_device_id.h>
+#include <asm/platform_sst_audio.h>
+#include <linux/clk.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -31,42 +34,153 @@
 #include "../../codecs/rt5640.h"
 #include "../atom/sst-atom-controls.h"
 #include "../common/sst-acpi.h"
+#include "../common/sst-dsp.h"
 
 enum {
 	BYT_RT5640_DMIC1_MAP,
 	BYT_RT5640_DMIC2_MAP,
 	BYT_RT5640_IN1_MAP,
+	BYT_RT5640_IN3_MAP,
 };
 
 #define BYT_RT5640_MAP(quirk)	((quirk) & 0xff)
 #define BYT_RT5640_DMIC_EN	BIT(16)
+#define BYT_RT5640_MONO_SPEAKER BIT(17)
+#define BYT_RT5640_DIFF_MIC     BIT(18) /* defaut is single-ended */
+#define BYT_RT5640_SSP2_AIF2     BIT(19) /* default is using AIF1  */
+#define BYT_RT5640_SSP0_AIF1     BIT(20)
+#define BYT_RT5640_SSP0_AIF2     BIT(21)
+#define BYT_RT5640_MCLK_EN	BIT(22)
+#define BYT_RT5640_MCLK_25MHZ	BIT(23)
+
+struct byt_rt5640_private {
+	struct clk *mclk;
+};
 
 static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
-					BYT_RT5640_DMIC_EN;
+					BYT_RT5640_DMIC_EN |
+					BYT_RT5640_MCLK_EN;
+
+static void log_quirks(struct device *dev)
+{
+	if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_DMIC1_MAP)
+		dev_info(dev, "quirk DMIC1_MAP enabled");
+	if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_DMIC2_MAP)
+		dev_info(dev, "quirk DMIC2_MAP enabled");
+	if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_IN1_MAP)
+		dev_info(dev, "quirk IN1_MAP enabled");
+	if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_IN3_MAP)
+		dev_info(dev, "quirk IN3_MAP enabled");
+	if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN)
+		dev_info(dev, "quirk DMIC enabled");
+	if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER)
+		dev_info(dev, "quirk MONO_SPEAKER enabled");
+	if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
+		dev_info(dev, "quirk DIFF_MIC enabled");
+	if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2)
+		dev_info(dev, "quirk SSP2_AIF2 enabled");
+	if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1)
+		dev_info(dev, "quirk SSP0_AIF1 enabled");
+	if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)
+		dev_info(dev, "quirk SSP0_AIF2 enabled");
+	if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN)
+		dev_info(dev, "quirk MCLK_EN enabled");
+	if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ)
+		dev_info(dev, "quirk MCLK_25MHZ enabled");
+}
+
+
+#define BYT_CODEC_DAI1	"rt5640-aif1"
+#define BYT_CODEC_DAI2	"rt5640-aif2"
+
+static inline struct snd_soc_dai *byt_get_codec_dai(struct snd_soc_card *card)
+{
+	struct snd_soc_pcm_runtime *rtd;
+
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+		if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI1,
+			     strlen(BYT_CODEC_DAI1)))
+			return rtd->codec_dai;
+		if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI2,
+				strlen(BYT_CODEC_DAI2)))
+			return rtd->codec_dai;
+
+	}
+	return NULL;
+}
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct snd_soc_dai *codec_dai;
+	struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
+	int ret;
+
+	codec_dai = byt_get_codec_dai(card);
+	if (!codec_dai) {
+		dev_err(card->dev,
+			"Codec dai not found; Unable to set platform clock\n");
+		return -EIO;
+	}
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) {
+			ret = clk_prepare_enable(priv->mclk);
+			if (ret < 0) {
+				dev_err(card->dev,
+					"could not configure MCLK state");
+				return ret;
+			}
+		}
+		ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
+					     48000 * 512,
+					     SND_SOC_CLOCK_IN);
+	} else {
+		/*
+		 * Set codec clock source to internal clock before
+		 * turning off the platform clock. Codec needs clock
+		 * for Jack detection and button press
+		 */
+		ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_RCCLK,
+					     0,
+					     SND_SOC_CLOCK_IN);
+		if (!ret) {
+			if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk)
+				clk_disable_unprepare(priv->mclk);
+		}
+	}
+
+	if (ret < 0) {
+		dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
 
 static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
 	SND_SOC_DAPM_HP("Headphone", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
 	SND_SOC_DAPM_MIC("Internal Mic", NULL),
 	SND_SOC_DAPM_SPK("Speaker", NULL),
+	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+			    platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+
 };
 
 static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
-	{"AIF1 Playback", NULL, "ssp2 Tx"},
-	{"ssp2 Tx", NULL, "codec_out0"},
-	{"ssp2 Tx", NULL, "codec_out1"},
-	{"codec_in0", NULL, "ssp2 Rx"},
-	{"codec_in1", NULL, "ssp2 Rx"},
-	{"ssp2 Rx", NULL, "AIF1 Capture"},
+	{"Headphone", NULL, "Platform Clock"},
+	{"Headset Mic", NULL, "Platform Clock"},
+	{"Internal Mic", NULL, "Platform Clock"},
+	{"Speaker", NULL, "Platform Clock"},
 
 	{"Headset Mic", NULL, "MICBIAS1"},
 	{"IN2P", NULL, "Headset Mic"},
 	{"Headphone", NULL, "HPOL"},
 	{"Headphone", NULL, "HPOR"},
-	{"Speaker", NULL, "SPOLP"},
-	{"Speaker", NULL, "SPOLN"},
-	{"Speaker", NULL, "SPORP"},
-	{"Speaker", NULL, "SPORN"},
 };
 
 static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
@@ -82,6 +196,59 @@ static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
 	{"IN1P", NULL, "Internal Mic"},
 };
 
+static const struct snd_soc_dapm_route byt_rt5640_intmic_in3_map[] = {
+	{"Internal Mic", NULL, "MICBIAS1"},
+	{"IN3P", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_ssp2_aif1_map[] = {
+	{"ssp2 Tx", NULL, "codec_out0"},
+	{"ssp2 Tx", NULL, "codec_out1"},
+	{"codec_in0", NULL, "ssp2 Rx"},
+	{"codec_in1", NULL, "ssp2 Rx"},
+
+	{"AIF1 Playback", NULL, "ssp2 Tx"},
+	{"ssp2 Rx", NULL, "AIF1 Capture"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_ssp2_aif2_map[] = {
+	{"ssp2 Tx", NULL, "codec_out0"},
+	{"ssp2 Tx", NULL, "codec_out1"},
+	{"codec_in0", NULL, "ssp2 Rx"},
+	{"codec_in1", NULL, "ssp2 Rx"},
+
+	{"AIF2 Playback", NULL, "ssp2 Tx"},
+	{"ssp2 Rx", NULL, "AIF2 Capture"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_ssp0_aif1_map[] = {
+	{"ssp0 Tx", NULL, "modem_out"},
+	{"modem_in", NULL, "ssp0 Rx"},
+
+	{"AIF1 Playback", NULL, "ssp0 Tx"},
+	{"ssp0 Rx", NULL, "AIF1 Capture"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_ssp0_aif2_map[] = {
+	{"ssp0 Tx", NULL, "modem_out"},
+	{"modem_in", NULL, "ssp0 Rx"},
+
+	{"AIF2 Playback", NULL, "ssp0 Tx"},
+	{"ssp0 Rx", NULL, "AIF2 Capture"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_stereo_spk_map[] = {
+	{"Speaker", NULL, "SPOLP"},
+	{"Speaker", NULL, "SPOLN"},
+	{"Speaker", NULL, "SPORP"},
+	{"Speaker", NULL, "SPORN"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_mono_spk_map[] = {
+	{"Speaker", NULL, "SPOLP"},
+	{"Speaker", NULL, "SPOLN"},
+};
+
 static const struct snd_kcontrol_new byt_rt5640_controls[] = {
 	SOC_DAPM_PIN_SWITCH("Headphone"),
 	SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -96,19 +263,46 @@ static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	int ret;
 
-	snd_soc_dai_set_bclk_ratio(codec_dai, 50);
-
 	ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
 				     params_rate(params) * 512,
 				     SND_SOC_CLOCK_IN);
+
 	if (ret < 0) {
 		dev_err(rtd->dev, "can't set codec clock %d\n", ret);
 		return ret;
 	}
 
-	ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
-				  params_rate(params) * 50,
-				  params_rate(params) * 512);
+	if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) {
+		/* use bitclock as PLL input */
+		if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) ||
+			(byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
+
+			/* 2x16 bit slots on SSP0 */
+			ret = snd_soc_dai_set_pll(codec_dai, 0,
+						RT5640_PLL1_S_BCLK1,
+						params_rate(params) * 32,
+						params_rate(params) * 512);
+		} else {
+			/* 2x15 bit slots on SSP2 */
+			ret = snd_soc_dai_set_pll(codec_dai, 0,
+						RT5640_PLL1_S_BCLK1,
+						params_rate(params) * 50,
+						params_rate(params) * 512);
+		}
+	} else {
+		if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) {
+			ret = snd_soc_dai_set_pll(codec_dai, 0,
+						RT5640_PLL1_S_MCLK,
+						25000000,
+						params_rate(params) * 512);
+		} else {
+			ret = snd_soc_dai_set_pll(codec_dai, 0,
+						RT5640_PLL1_S_MCLK,
+						19200000,
+						params_rate(params) * 512);
+		}
+	}
+
 	if (ret < 0) {
 		dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
 		return ret;
@@ -127,27 +321,73 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
 	{
 		.callback = byt_rt5640_quirk_cb,
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+		},
+		.driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
+						 BYT_RT5640_MCLK_EN),
+	},
+	{
+		.callback = byt_rt5640_quirk_cb,
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"),
 		},
-		.driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
+		.driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
+						 BYT_RT5640_MONO_SPEAKER |
+						 BYT_RT5640_DIFF_MIC |
+						 BYT_RT5640_SSP0_AIF2 |
+						 BYT_RT5640_MCLK_EN
+						 ),
 	},
 	{
 		.callback = byt_rt5640_quirk_cb,
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "DellInc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "DellInc."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
 		},
 		.driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
+						 BYT_RT5640_DMIC_EN |
+						 BYT_RT5640_MCLK_EN),
+	},
+	{
+		.callback = byt_rt5640_quirk_cb,
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"),
+		},
+		.driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
+						 BYT_RT5640_MCLK_EN),
+	},
+	{
+		.callback = byt_rt5640_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
+		},
+		.driver_data = (unsigned long *)(BYT_RT5640_DMIC1_MAP |
 						 BYT_RT5640_DMIC_EN),
 	},
 	{
 		.callback = byt_rt5640_quirk_cb,
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"),
+			DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
+			DMI_MATCH(DMI_BOARD_NAME, "tPAD"),
 		},
-		.driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
+		.driver_data = (unsigned long *)(BYT_RT5640_IN3_MAP |
+						BYT_RT5640_MCLK_EN |
+						BYT_RT5640_SSP0_AIF1),
+	},
+	{
+		.callback = byt_rt5640_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
+		},
+		.driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
+						 BYT_RT5640_MCLK_EN |
+						 BYT_RT5640_SSP0_AIF1),
+
 	},
 	{}
 };
@@ -158,13 +398,18 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 	struct snd_soc_codec *codec = runtime->codec;
 	struct snd_soc_card *card = runtime->card;
 	const struct snd_soc_dapm_route *custom_map;
+	struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
 	int num_routes;
 
 	card->dapm.idle_bias_off = true;
 
 	rt5640_sel_asrc_clk_src(codec,
 				RT5640_DA_STEREO_FILTER |
-				RT5640_AD_STEREO_FILTER,
+				RT5640_DA_MONO_L_FILTER	|
+				RT5640_DA_MONO_R_FILTER	|
+				RT5640_AD_STEREO_FILTER	|
+				RT5640_AD_MONO_L_FILTER	|
+				RT5640_AD_MONO_R_FILTER,
 				RT5640_CLK_SEL_ASRC);
 
 	ret = snd_soc_add_card_controls(card, byt_rt5640_controls,
@@ -179,6 +424,10 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 		custom_map = byt_rt5640_intmic_in1_map;
 		num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map);
 		break;
+	case BYT_RT5640_IN3_MAP:
+		custom_map = byt_rt5640_intmic_in3_map;
+		num_routes = ARRAY_SIZE(byt_rt5640_intmic_in3_map);
+		break;
 	case BYT_RT5640_DMIC2_MAP:
 		custom_map = byt_rt5640_intmic_dmic2_map;
 		num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
@@ -192,6 +441,43 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 	if (ret)
 		return ret;
 
+	if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) {
+		ret = snd_soc_dapm_add_routes(&card->dapm,
+					byt_rt5640_ssp2_aif2_map,
+					ARRAY_SIZE(byt_rt5640_ssp2_aif2_map));
+	} else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) {
+		ret = snd_soc_dapm_add_routes(&card->dapm,
+					byt_rt5640_ssp0_aif1_map,
+					ARRAY_SIZE(byt_rt5640_ssp0_aif1_map));
+	} else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2) {
+		ret = snd_soc_dapm_add_routes(&card->dapm,
+					byt_rt5640_ssp0_aif2_map,
+					ARRAY_SIZE(byt_rt5640_ssp0_aif2_map));
+	} else {
+		ret = snd_soc_dapm_add_routes(&card->dapm,
+					byt_rt5640_ssp2_aif1_map,
+					ARRAY_SIZE(byt_rt5640_ssp2_aif1_map));
+	}
+	if (ret)
+		return ret;
+
+	if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) {
+		ret = snd_soc_dapm_add_routes(&card->dapm,
+					byt_rt5640_mono_spk_map,
+					ARRAY_SIZE(byt_rt5640_mono_spk_map));
+	} else {
+		ret = snd_soc_dapm_add_routes(&card->dapm,
+					byt_rt5640_stereo_spk_map,
+					ARRAY_SIZE(byt_rt5640_stereo_spk_map));
+	}
+	if (ret)
+		return ret;
+
+	if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) {
+		snd_soc_update_bits(codec,  RT5640_IN1_IN2, RT5640_IN_DF1,
+				    RT5640_IN_DF1);
+	}
+
 	if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
 		ret = rt5640_dmic_enable(codec, 0, 0);
 		if (ret)
@@ -201,6 +487,30 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 	snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
 	snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
 
+	if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) {
+		/*
+		 * The firmware might enable the clock at
+		 * boot (this information may or may not
+		 * be reflected in the enable clock register).
+		 * To change the rate we must disable the clock
+		 * first to cover these cases. Due to common
+		 * clock framework restrictions that do not allow
+		 * to disable a clock that has not been enabled,
+		 * we need to enable the clock first.
+		 */
+		ret = clk_prepare_enable(priv->mclk);
+		if (!ret)
+			clk_disable_unprepare(priv->mclk);
+
+		if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ)
+			ret = clk_set_rate(priv->mclk, 25000000);
+		else
+			ret = clk_set_rate(priv->mclk, 19200000);
+
+		if (ret)
+			dev_err(card->dev, "unable to set MCLK rate\n");
+	}
+
 	return ret;
 }
 
@@ -221,34 +531,63 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
 						SNDRV_PCM_HW_PARAM_CHANNELS);
 	int ret;
 
-	/* The DSP will covert the FE rate to 48k, stereo, 24bits */
+	/* The DSP will covert the FE rate to 48k, stereo */
 	rate->min = rate->max = 48000;
 	channels->min = channels->max = 2;
 
-	/* set SSP2 to 24-bit */
-	params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+	if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) ||
+		(byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
+
+		/* set SSP0 to 16-bit */
+		params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+
+		/*
+		 * Default mode for SSP configuration is TDM 4 slot, override config
+		 * with explicit setting to I2S 2ch 16-bit. The word length is set with
+		 * dai_set_tdm_slot() since there is no other API exposed
+		 */
+		ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
+					SND_SOC_DAIFMT_I2S     |
+					SND_SOC_DAIFMT_NB_IF   |
+					SND_SOC_DAIFMT_CBS_CFS
+			);
+		if (ret < 0) {
+			dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
+			return ret;
+		}
 
-	/*
-	 * Default mode for SSP configuration is TDM 4 slot, override config
-	 * with explicit setting to I2S 2ch 24-bit. The word length is set with
-	 * dai_set_tdm_slot() since there is no other API exposed
-	 */
-	ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
-				  SND_SOC_DAIFMT_I2S     |
-				  SND_SOC_DAIFMT_NB_IF   |
-				  SND_SOC_DAIFMT_CBS_CFS
-				  );
-	if (ret < 0) {
-		dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
-		return ret;
-	}
+		ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16);
+		if (ret < 0) {
+			dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
+			return ret;
+		}
 
-	ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
-	if (ret < 0) {
-		dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
-		return ret;
-	}
+	} else {
+
+		/* set SSP2 to 24-bit */
+		params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+
+		/*
+		 * Default mode for SSP configuration is TDM 4 slot, override config
+		 * with explicit setting to I2S 2ch 24-bit. The word length is set with
+		 * dai_set_tdm_slot() since there is no other API exposed
+		 */
+		ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
+					SND_SOC_DAIFMT_I2S     |
+					SND_SOC_DAIFMT_NB_IF   |
+					SND_SOC_DAIFMT_CBS_CFS
+			);
+		if (ret < 0) {
+			dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
+			return ret;
+		}
 
+		ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
+		if (ret < 0) {
+			dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
+			return ret;
+		}
+	}
 	return 0;
 }
 
@@ -305,10 +644,10 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
 	{
 		.name = "SSP2-Codec",
 		.id = 1,
-		.cpu_dai_name = "ssp2-port",
+		.cpu_dai_name = "ssp2-port", /* overwritten for ssp0 routing */
 		.platform_name = "sst-mfld-platform",
 		.no_pcm = 1,
-		.codec_dai_name = "rt5640-aif1",
+		.codec_dai_name = "rt5640-aif1", /* changed w/ quirk */
 		.codec_name = "i2c-10EC5640:00", /* overwritten with HID */
 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 						| SND_SOC_DAIFMT_CBS_CFS,
@@ -335,6 +674,21 @@ static struct snd_soc_card byt_rt5640_card = {
 };
 
 static char byt_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
+static char byt_rt5640_codec_aif_name[12]; /*  = "rt5640-aif[1|2]" */
+static char byt_rt5640_cpu_dai_name[10]; /*  = "ssp[0|2]-port" */
+
+static bool is_valleyview(void)
+{
+	static const struct x86_cpu_id cpu_ids[] = {
+		{ X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */
+		{}
+	};
+
+	if (!x86_match_cpu(cpu_ids))
+		return false;
+	return true;
+}
+
 
 static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 {
@@ -343,10 +697,16 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 	const char *i2c_name = NULL;
 	int i;
 	int dai_index;
+	struct byt_rt5640_private *priv;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
+	if (!priv)
+		return -ENOMEM;
 
 	/* register the soc card */
 	byt_rt5640_card.dev = &pdev->dev;
 	mach = byt_rt5640_card.dev->platform_data;
+	snd_soc_card_set_drvdata(&byt_rt5640_card, priv);
 
 	/* fix index of codec dai */
 	dai_index = MERR_DPCM_COMPR + 1;
@@ -366,8 +726,57 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 		byt_rt5640_dais[dai_index].codec_name = byt_rt5640_codec_name;
 	}
 
+	/*
+	 * swap SSP0 if bytcr is detected
+	 * (will be overridden if DMI quirk is detected)
+	 */
+	if (is_valleyview()) {
+		struct sst_platform_info *p_info = mach->pdata;
+		const struct sst_res_info *res_info = p_info->res_info;
+
+		/* TODO: use CHAN package info from BIOS to detect AIF1/AIF2 */
+		if (res_info->acpi_ipc_irq_index == 0) {
+			byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2;
+		}
+	}
+
 	/* check quirks before creating card */
 	dmi_check_system(byt_rt5640_quirk_table);
+	log_quirks(&pdev->dev);
+
+	if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) ||
+	    (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
+
+		/* fixup codec aif name */
+		snprintf(byt_rt5640_codec_aif_name,
+			sizeof(byt_rt5640_codec_aif_name),
+			"%s", "rt5640-aif2");
+
+		byt_rt5640_dais[dai_index].codec_dai_name =
+			byt_rt5640_codec_aif_name;
+	}
+
+	if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) ||
+	    (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
+
+		/* fixup cpu dai name name */
+		snprintf(byt_rt5640_cpu_dai_name,
+			sizeof(byt_rt5640_cpu_dai_name),
+			"%s", "ssp0-port");
+
+		byt_rt5640_dais[dai_index].cpu_dai_name =
+			byt_rt5640_cpu_dai_name;
+	}
+
+	if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && (is_valleyview())) {
+		priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
+		if (IS_ERR(priv->mclk)) {
+			dev_err(&pdev->dev,
+				"Failed to get MCLK from pmc_plt_clk_3: %ld\n",
+				PTR_ERR(priv->mclk));
+			return PTR_ERR(priv->mclk);
+		}
+	}
 
 	ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
 
diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c
index 2c5eda14d510..1285cc597b6b 100644
--- a/sound/soc/intel/common/sst-acpi.c
+++ b/sound/soc/intel/common/sst-acpi.c
@@ -199,6 +199,7 @@ static struct sst_acpi_desc sst_acpi_haswell_desc = {
 
 static struct sst_acpi_mach broadwell_machines[] = {
 	{ "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL },
+	{ "RT5677CE", "bdw-rt5677", "intel/IntcSST2.bin", NULL, NULL, NULL },
 	{}
 };
 
diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c
index 3154525c2b83..9e4094e2c6e3 100644
--- a/sound/soc/intel/haswell/sst-haswell-pcm.c
+++ b/sound/soc/intel/haswell/sst-haswell-pcm.c
@@ -871,7 +871,7 @@ out:
 	return ret;
 }
 
-static struct snd_pcm_ops hsw_pcm_ops = {
+static const struct snd_pcm_ops hsw_pcm_ops = {
 	.open		= hsw_pcm_open,
 	.close		= hsw_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c
index 2663781278aa..1d251d59bcb9 100644
--- a/sound/soc/intel/skylake/bxt-sst.c
+++ b/sound/soc/intel/skylake/bxt-sst.c
@@ -23,6 +23,7 @@
 #include "../common/sst-dsp.h"
 #include "../common/sst-dsp-priv.h"
 #include "skl-sst-ipc.h"
+#include "skl-tplg-interface.h"
 
 #define BXT_BASEFW_TIMEOUT	3000
 #define BXT_INIT_TIMEOUT	500
@@ -40,11 +41,73 @@
 #define BXT_INSTANCE_ID 0
 #define BXT_BASE_FW_MODULE_ID 0
 
+#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000
+
 static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
 {
 	 return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE);
 }
 
+static int
+bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo)
+{
+	struct snd_dma_buffer dmab;
+	struct skl_sst *skl = ctx->thread_context;
+	const struct firmware *fw = NULL;
+	struct firmware stripped_fw;
+	int ret = 0, i, dma_id, stream_tag;
+
+	/* library indices start from 1 to N. 0 represents base FW */
+	for (i = 1; i < minfo->lib_count; i++) {
+		ret = request_firmware(&fw, minfo->lib[i].name, ctx->dev);
+		if (ret < 0) {
+			dev_err(ctx->dev, "Request lib %s failed:%d\n",
+					minfo->lib[i].name, ret);
+			return ret;
+		}
+
+		if (skl->is_first_boot) {
+			ret = snd_skl_parse_uuids(ctx, fw,
+					BXT_ADSP_FW_BIN_HDR_OFFSET, i);
+			if (ret < 0)
+				goto load_library_failed;
+		}
+
+		stripped_fw.data = fw->data;
+		stripped_fw.size = fw->size;
+		skl_dsp_strip_extended_manifest(&stripped_fw);
+
+		stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40,
+					stripped_fw.size, &dmab);
+		if (stream_tag <= 0) {
+			dev_err(ctx->dev, "Lib prepare DMA err: %x\n",
+					stream_tag);
+			ret = stream_tag;
+			goto load_library_failed;
+		}
+
+		dma_id = stream_tag - 1;
+		memcpy(dmab.area, stripped_fw.data, stripped_fw.size);
+
+		ctx->dsp_ops.trigger(ctx->dev, true, stream_tag);
+		ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i);
+		if (ret < 0)
+			dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n",
+					minfo->lib[i].name, ret);
+
+		ctx->dsp_ops.trigger(ctx->dev, false, stream_tag);
+		ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag);
+		release_firmware(fw);
+		fw = NULL;
+	}
+
+	return ret;
+
+load_library_failed:
+	release_firmware(fw);
+	return ret;
+}
+
 /*
  * First boot sequence has some extra steps. Core 0 waits for power
  * status on core 1, so power up core 1 also momentarily, keep it in
@@ -157,8 +220,6 @@ static int sst_transfer_fw_host_dma(struct sst_dsp *ctx)
 	return ret;
 }
 
-#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000
-
 static int bxt_load_base_firmware(struct sst_dsp *ctx)
 {
 	struct firmware stripped_fw;
@@ -175,9 +236,12 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx)
 	if (ctx->fw == NULL)
 		goto sst_load_base_firmware_failed;
 
-	ret = snd_skl_parse_uuids(ctx, BXT_ADSP_FW_BIN_HDR_OFFSET);
-	if (ret < 0)
-		goto sst_load_base_firmware_failed;
+	/* prase uuids on first boot */
+	if (skl->is_first_boot) {
+		ret = snd_skl_parse_uuids(ctx, ctx->fw, BXT_ADSP_FW_BIN_HDR_OFFSET, 0);
+		if (ret < 0)
+			goto sst_load_base_firmware_failed;
+	}
 
 	stripped_fw.data = ctx->fw->data;
 	stripped_fw.size = ctx->fw->size;
@@ -230,12 +294,23 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
 	int ret;
 	struct skl_ipc_dxstate_info dx;
 	unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
+	struct skl_dfw_manifest *minfo = &skl->manifest;
 
 	if (skl->fw_loaded == false) {
 		skl->boot_complete = false;
 		ret = bxt_load_base_firmware(ctx);
-		if (ret < 0)
+		if (ret < 0) {
 			dev_err(ctx->dev, "reload fw failed: %d\n", ret);
+			return ret;
+		}
+
+		if (minfo->lib_count > 1) {
+			ret = bxt_load_library(ctx, minfo);
+			if (ret < 0) {
+				dev_err(ctx->dev, "reload libs failed: %d\n", ret);
+				return ret;
+			}
+		}
 		return ret;
 	}
 
@@ -329,7 +404,7 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
 
 	ret = skl_dsp_disable_core(ctx, core_mask);
 	if (ret < 0) {
-		dev_err(ctx->dev, "Failed to disable core %d", ret);
+		dev_err(ctx->dev, "Failed to disable core %d\n", ret);
 		return ret;
 	}
 	skl->cores.state[core_id] = SKL_DSP_RESET;
@@ -341,6 +416,7 @@ static struct skl_dsp_fw_ops bxt_fw_ops = {
 	.set_state_D3 = bxt_set_dsp_D3,
 	.load_fw = bxt_load_base_firmware,
 	.get_fw_errcode = bxt_get_errorcode,
+	.load_library = bxt_load_library,
 };
 
 static struct sst_ops skl_ops = {
@@ -397,22 +473,40 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
 	skl->cores.count = 2;
 	skl->boot_complete = false;
 	init_waitqueue_head(&skl->boot_wait);
+	skl->is_first_boot = true;
+
+	if (dsp)
+		*dsp = skl;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
+
+int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx)
+{
+	int ret;
+	struct sst_dsp *sst = ctx->dsp;
 
 	ret = sst->fw_ops.load_fw(sst);
 	if (ret < 0) {
-		dev_err(dev, "Load base fw failed: %x", ret);
+		dev_err(dev, "Load base fw failed: %x\n", ret);
 		return ret;
 	}
 
 	skl_dsp_init_core_state(sst);
 
-	if (dsp)
-		*dsp = skl;
+	if (ctx->manifest.lib_count > 1) {
+		ret = sst->fw_ops.load_library(sst, &ctx->manifest);
+		if (ret < 0) {
+			dev_err(dev, "Load Library failed : %x\n", ret);
+			return ret;
+		}
+	}
+	ctx->is_first_boot = false;
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
-
+EXPORT_SYMBOL_GPL(bxt_sst_init_fw);
 
 void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
 {
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 44ab595ce21a..805b7f2173f3 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -203,32 +203,35 @@ static const struct skl_dsp_ops dsp_ops[] = {
 		.id = 0x9d70,
 		.loader_ops = skl_get_loader_ops,
 		.init = skl_sst_dsp_init,
+		.init_fw = skl_sst_init_fw,
 		.cleanup = skl_sst_dsp_cleanup
 	},
 	{
 		.id = 0x9d71,
 		.loader_ops = skl_get_loader_ops,
 		.init = skl_sst_dsp_init,
+		.init_fw = skl_sst_init_fw,
 		.cleanup = skl_sst_dsp_cleanup
 	},
 	{
 		.id = 0x5a98,
 		.loader_ops = bxt_get_loader_ops,
 		.init = bxt_sst_dsp_init,
+		.init_fw = bxt_sst_init_fw,
 		.cleanup = bxt_sst_dsp_cleanup
 	},
 };
 
-static int skl_get_dsp_ops(int pci_id)
+const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
 {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(dsp_ops); i++) {
 		if (dsp_ops[i].id == pci_id)
-			return i;
+			return &dsp_ops[i];
 	}
 
-	return -EINVAL;
+	return NULL;
 }
 
 int skl_init_dsp(struct skl *skl)
@@ -238,7 +241,8 @@ int skl_init_dsp(struct skl *skl)
 	struct hdac_bus *bus = ebus_to_hbus(ebus);
 	struct skl_dsp_loader_ops loader_ops;
 	int irq = bus->irq;
-	int ret, index;
+	const struct skl_dsp_ops *ops;
+	int ret;
 
 	/* enable ppcap interrupt */
 	snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true);
@@ -251,18 +255,18 @@ int skl_init_dsp(struct skl *skl)
 		return -ENXIO;
 	}
 
-	index  = skl_get_dsp_ops(skl->pci->device);
-	if (index  < 0)
-		return -EINVAL;
+	ops = skl_get_dsp_ops(skl->pci->device);
+	if (!ops)
+		return -EIO;
 
-	loader_ops = dsp_ops[index].loader_ops();
-	ret = dsp_ops[index].init(bus->dev, mmio_base, irq,
-			skl->fw_name, loader_ops, &skl->skl_sst);
+	loader_ops = ops->loader_ops();
+	ret = ops->init(bus->dev, mmio_base, irq,
+				skl->fw_name, loader_ops,
+				&skl->skl_sst);
 
 	if (ret < 0)
 		return ret;
 
-	skl_dsp_enable_notification(skl->skl_sst, false);
 	dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
 
 	return ret;
@@ -273,16 +277,16 @@ int skl_free_dsp(struct skl *skl)
 	struct hdac_ext_bus *ebus = &skl->ebus;
 	struct hdac_bus *bus = ebus_to_hbus(ebus);
 	struct skl_sst *ctx = skl->skl_sst;
-	int index;
+	const struct skl_dsp_ops *ops;
 
 	/* disable  ppcap interrupt */
 	snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false);
 
-	index = skl_get_dsp_ops(skl->pci->device);
-	if (index  < 0)
+	ops = skl_get_dsp_ops(skl->pci->device);
+	if (!ops)
 		return -EIO;
 
-	dsp_ops[index].cleanup(bus->dev, ctx);
+	ops->cleanup(bus->dev, ctx);
 
 	if (ctx->dsp->addr.lpe)
 		iounmap(ctx->dsp->addr.lpe);
@@ -296,7 +300,7 @@ int skl_suspend_dsp(struct skl *skl)
 	int ret;
 
 	/* if ppcap is not supported return 0 */
-	if (!skl->ebus.ppcap)
+	if (!skl->ebus.bus.ppcap)
 		return 0;
 
 	ret = skl_dsp_sleep(ctx->dsp);
@@ -316,13 +320,17 @@ int skl_resume_dsp(struct skl *skl)
 	int ret;
 
 	/* if ppcap is not supported return 0 */
-	if (!skl->ebus.ppcap)
+	if (!skl->ebus.bus.ppcap)
 		return 0;
 
 	/* enable ppcap interrupt */
 	snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true);
 	snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true);
 
+	/* check if DSP 1st boot is done */
+	if (skl->skl_sst->is_first_boot == true)
+		return 0;
+
 	ret = skl_dsp_wake(ctx->dsp);
 	if (ret < 0)
 		return ret;
@@ -672,6 +680,7 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx,
 		return param_size;
 
 	case SKL_MODULE_TYPE_BASE_OUTFMT:
+	case SKL_MODULE_TYPE_KPB:
 		return sizeof(struct skl_base_outfmt_cfg);
 
 	default:
@@ -725,6 +734,7 @@ static int skl_set_module_format(struct skl_sst *ctx,
 		break;
 
 	case SKL_MODULE_TYPE_BASE_OUTFMT:
+	case SKL_MODULE_TYPE_KPB:
 		skl_set_base_outfmt_format(ctx, module_config, *param_data);
 		break;
 
@@ -779,6 +789,7 @@ static int skl_alloc_queue(struct skl_module_pin *mpin,
 				mpin[i].in_use = true;
 				mpin[i].id.module_id = id.module_id;
 				mpin[i].id.instance_id = id.instance_id;
+				mpin[i].id.pvt_id = id.pvt_id;
 				mpin[i].tgt_mcfg = tgt_cfg;
 				return i;
 			}
@@ -802,6 +813,7 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index)
 		mpin[q_index].in_use = false;
 		mpin[q_index].id.module_id = 0;
 		mpin[q_index].id.instance_id = 0;
+		mpin[q_index].id.pvt_id = 0;
 	}
 	mpin[q_index].pin_state = SKL_PIN_UNBIND;
 	mpin[q_index].tgt_mcfg = NULL;
@@ -842,7 +854,7 @@ int skl_init_module(struct skl_sst *ctx,
 	struct skl_ipc_init_instance_msg msg;
 
 	dev_dbg(ctx->dev, "%s: module_id = %d instance=%d\n", __func__,
-		 mconfig->id.module_id, mconfig->id.instance_id);
+		 mconfig->id.module_id, mconfig->id.pvt_id);
 
 	if (mconfig->pipe->state != SKL_PIPE_CREATED) {
 		dev_err(ctx->dev, "Pipe not created state= %d pipe_id= %d\n",
@@ -858,10 +870,11 @@ int skl_init_module(struct skl_sst *ctx,
 	}
 
 	msg.module_id = mconfig->id.module_id;
-	msg.instance_id = mconfig->id.instance_id;
+	msg.instance_id = mconfig->id.pvt_id;
 	msg.ppl_instance_id = mconfig->pipe->ppl_id;
 	msg.param_data_size = module_config_size;
 	msg.core_id = mconfig->core_id;
+	msg.domain = mconfig->domain;
 
 	ret = skl_ipc_init_instance(&ctx->ipc, &msg, param_data);
 	if (ret < 0) {
@@ -878,9 +891,9 @@ static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg
 	*src_module, struct skl_module_cfg *dst_module)
 {
 	dev_dbg(ctx->dev, "%s: src module_id = %d  src_instance=%d\n",
-		__func__, src_module->id.module_id, src_module->id.instance_id);
+		__func__, src_module->id.module_id, src_module->id.pvt_id);
 	dev_dbg(ctx->dev, "%s: dst_module=%d dst_instacne=%d\n", __func__,
-		 dst_module->id.module_id, dst_module->id.instance_id);
+		 dst_module->id.module_id, dst_module->id.pvt_id);
 
 	dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n",
 		src_module->m_state, dst_module->m_state);
@@ -927,9 +940,9 @@ int skl_unbind_modules(struct skl_sst *ctx,
 		return 0;
 
 	msg.module_id = src_mcfg->id.module_id;
-	msg.instance_id = src_mcfg->id.instance_id;
+	msg.instance_id = src_mcfg->id.pvt_id;
 	msg.dst_module_id = dst_mcfg->id.module_id;
-	msg.dst_instance_id = dst_mcfg->id.instance_id;
+	msg.dst_instance_id = dst_mcfg->id.pvt_id;
 	msg.bind = false;
 
 	ret = skl_ipc_bind_unbind(&ctx->ipc, &msg);
@@ -988,9 +1001,9 @@ int skl_bind_modules(struct skl_sst *ctx,
 			 msg.src_queue, msg.dst_queue);
 
 	msg.module_id = src_mcfg->id.module_id;
-	msg.instance_id = src_mcfg->id.instance_id;
+	msg.instance_id = src_mcfg->id.pvt_id;
 	msg.dst_module_id = dst_mcfg->id.module_id;
-	msg.dst_instance_id = dst_mcfg->id.instance_id;
+	msg.dst_instance_id = dst_mcfg->id.pvt_id;
 	msg.bind = true;
 
 	ret = skl_ipc_bind_unbind(&ctx->ipc, &msg);
@@ -1168,7 +1181,7 @@ int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size,
 	struct skl_ipc_large_config_msg msg;
 
 	msg.module_id = mcfg->id.module_id;
-	msg.instance_id = mcfg->id.instance_id;
+	msg.instance_id = mcfg->id.pvt_id;
 	msg.param_data_size = size;
 	msg.large_param_id = param_id;
 
@@ -1181,7 +1194,7 @@ int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
 	struct skl_ipc_large_config_msg msg;
 
 	msg.module_id = mcfg->id.module_id;
-	msg.instance_id = mcfg->id.instance_id;
+	msg.instance_id = mcfg->id.pvt_id;
 	msg.param_data_size = size;
 	msg.large_param_id = param_id;
 
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 6e05bf8622f7..58c728662600 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -106,7 +106,7 @@ static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus,
 
 static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus)
 {
-	if (ebus->ppcap)
+	if ((ebus_to_hbus(ebus))->ppcap)
 		return HDAC_EXT_STREAM_TYPE_HOST;
 	else
 		return HDAC_EXT_STREAM_TYPE_COUPLED;
@@ -188,7 +188,7 @@ static int skl_get_format(struct snd_pcm_substream *substream,
 	struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
 	int format_val = 0;
 
-	if (ebus->ppcap) {
+	if ((ebus_to_hbus(ebus))->ppcap) {
 		struct snd_pcm_runtime *runtime = substream->runtime;
 
 		format_val = snd_hdac_calc_stream_format(runtime->rate,
@@ -648,7 +648,8 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
 		.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,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
 	},
 	.capture = {
 		.stream_name = "System Capture",
@@ -1020,7 +1021,7 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
 {
 	struct hdac_ext_bus *ebus = get_bus_ctx(substream);
 
-	if (!ebus->ppcap)
+	if (!(ebus_to_hbus(ebus))->ppcap)
 		return skl_coupled_trigger(substream, cmd);
 
 	return 0;
@@ -1093,7 +1094,7 @@ static int skl_get_time_info(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static struct snd_pcm_ops skl_platform_ops = {
+static const struct snd_pcm_ops skl_platform_ops = {
 	.open = skl_platform_open,
 	.ioctl = snd_pcm_lib_ioctl,
 	.trigger = skl_platform_pcm_trigger,
@@ -1138,20 +1139,67 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	return retval;
 }
 
+static int skl_populate_modules(struct skl *skl)
+{
+	struct skl_pipeline *p;
+	struct skl_pipe_module *m;
+	struct snd_soc_dapm_widget *w;
+	struct skl_module_cfg *mconfig;
+	int ret;
+
+	list_for_each_entry(p, &skl->ppl_list, node) {
+		list_for_each_entry(m, &p->pipe->w_list, node) {
+
+			w = m->w;
+			mconfig = w->priv;
+
+			ret = snd_skl_get_module_info(skl->skl_sst, mconfig);
+			if (ret < 0) {
+				dev_err(skl->skl_sst->dev,
+					"query module info failed:%d\n", ret);
+				goto err;
+			}
+		}
+	}
+err:
+	return ret;
+}
+
 static int skl_platform_soc_probe(struct snd_soc_platform *platform)
 {
 	struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev);
 	struct skl *skl = ebus_to_skl(ebus);
+	const struct skl_dsp_ops *ops;
 	int ret;
 
-	if (ebus->ppcap) {
+	pm_runtime_get_sync(platform->dev);
+	if ((ebus_to_hbus(ebus))->ppcap) {
 		ret = skl_tplg_init(platform, ebus);
 		if (ret < 0) {
 			dev_err(platform->dev, "Failed to init topology!\n");
 			return ret;
 		}
 		skl->platform = platform;
+
+		/* load the firmwares, since all is set */
+		ops = skl_get_dsp_ops(skl->pci->device);
+		if (!ops)
+			return -EIO;
+
+		if (skl->skl_sst->is_first_boot == false) {
+			dev_err(platform->dev, "DSP reports first boot done!!!\n");
+			return -EIO;
+		}
+
+		ret = ops->init_fw(platform->dev, skl->skl_sst);
+		if (ret < 0) {
+			dev_err(platform->dev, "Failed to boot first fw: %d\n", ret);
+			return ret;
+		}
+		skl_populate_modules(skl);
 	}
+	pm_runtime_mark_last_busy(platform->dev);
+	pm_runtime_put_autosuspend(platform->dev);
 
 	return 0;
 }
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c
index da2329d17f4d..efa2532114ba 100644
--- a/sound/soc/intel/skylake/skl-sst-cldma.c
+++ b/sound/soc/intel/skylake/skl-sst-cldma.c
@@ -341,14 +341,14 @@ int skl_cldma_prepare(struct sst_dsp *ctx)
 	ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev,
 			&ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize);
 	if (ret < 0) {
-		dev_err(ctx->dev, "Alloc buffer for base fw failed: %x", ret);
+		dev_err(ctx->dev, "Alloc buffer for base fw failed: %x\n", ret);
 		return ret;
 	}
 	/* Setup Code loader BDL */
 	ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev,
 			&ctx->cl_dev.dmab_bdl, PAGE_SIZE);
 	if (ret < 0) {
-		dev_err(ctx->dev, "Alloc buffer for blde failed: %x", ret);
+		dev_err(ctx->dev, "Alloc buffer for blde failed: %x\n", ret);
 		ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
 		return ret;
 	}
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
index 0f8629ef79ac..b9e71d051fb1 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -20,6 +20,7 @@
 #include <sound/memalloc.h>
 #include "skl-sst-cldma.h"
 #include "skl-tplg-interface.h"
+#include "skl-topology.h"
 
 struct sst_dsp;
 struct skl_sst;
@@ -133,6 +134,8 @@ enum skl_dsp_states {
 struct skl_dsp_fw_ops {
 	int (*load_fw)(struct sst_dsp  *ctx);
 	/* FW module parser/loader */
+	int (*load_library)(struct sst_dsp *ctx,
+		struct skl_dfw_manifest *minfo);
 	int (*parse_fw)(struct sst_dsp *ctx);
 	int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id);
 	int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id);
@@ -203,12 +206,21 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
 int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
 		const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
 		struct skl_sst **dsp);
+int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx);
+int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx);
 void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
 void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
 
-int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid,
-		struct skl_dfw_module *dfw_config);
-int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset);
+int snd_skl_get_module_info(struct skl_sst *ctx,
+				struct skl_module_cfg *mconfig);
+int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
+				unsigned int offset, int index);
+int skl_get_pvt_id(struct skl_sst *ctx,
+				struct skl_module_cfg *mconfig);
+int skl_put_pvt_id(struct skl_sst *ctx,
+				struct skl_module_cfg *mconfig);
+int skl_get_pvt_instance_id_map(struct skl_sst *ctx,
+				int module_id, int instance_id);
 void skl_freeup_uuid_list(struct skl_sst *ctx);
 
 int skl_dsp_strip_extended_manifest(struct firmware *fw);
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index 96f2f6889b18..0bd01e62622c 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -114,6 +114,11 @@
 #define IPC_CORE_ID(x)			(((x) & IPC_CORE_ID_MASK) \
 					<< IPC_CORE_ID_SHIFT)
 
+#define IPC_DOMAIN_SHIFT                28
+#define IPC_DOMAIN_MASK                 0x1
+#define IPC_DOMAIN(x)                   (((x) & IPC_DOMAIN_MASK) \
+					<< IPC_DOMAIN_SHIFT)
+
 /* Bind/Unbind message extension register */
 #define IPC_DST_MOD_ID_SHIFT		0
 #define IPC_DST_MOD_ID(x)		(((x) & IPC_MOD_ID_MASK) \
@@ -190,6 +195,7 @@ enum skl_ipc_glb_type {
 	IPC_GLB_GET_PPL_CONTEXT_SIZE = 21,
 	IPC_GLB_SAVE_PPL = 22,
 	IPC_GLB_RESTORE_PPL = 23,
+	IPC_GLB_LOAD_LIBRARY = 24,
 	IPC_GLB_NOTIFY = 26,
 	IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */
 };
@@ -338,7 +344,7 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
 			break;
 
 		default:
-			dev_err(ipc->dev, "ipc: Unhandled error msg=%x",
+			dev_err(ipc->dev, "ipc: Unhandled error msg=%x\n",
 						header.primary);
 			break;
 		}
@@ -379,13 +385,13 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
 		break;
 
 	default:
-		dev_err(ipc->dev, "Unknown ipc reply: 0x%x", reply);
+		dev_err(ipc->dev, "Unknown ipc reply: 0x%x\n", reply);
 		msg->errno = -EINVAL;
 		break;
 	}
 
 	if (reply != IPC_GLB_REPLY_SUCCESS) {
-		dev_err(ipc->dev, "ipc FW reply: reply=%d", reply);
+		dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply);
 		dev_err(ipc->dev, "FW Error Code: %u\n",
 			ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
 	}
@@ -434,9 +440,9 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context)
 		hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE);
 		header.primary = hipct;
 		header.extension = hipcte;
-		dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x",
+		dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x\n",
 						header.primary);
-		dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x",
+		dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x\n",
 						header.extension);
 
 		if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) {
@@ -704,6 +710,7 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc,
 	header.extension = IPC_CORE_ID(msg->core_id);
 	header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id);
 	header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size);
+	header.extension |= IPC_DOMAIN(msg->domain);
 
 	dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
 			 header.primary, header.extension);
@@ -742,7 +749,7 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc,
 			 header.extension);
 	ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
 	if (ret < 0) {
-		dev_err(ipc->dev, "ipc: bind/unbind faileden");
+		dev_err(ipc->dev, "ipc: bind/unbind failed\n");
 		return ret;
 	}
 
@@ -902,3 +909,25 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(skl_ipc_get_large_config);
+
+int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
+				u8 dma_id, u8 table_id)
+{
+	struct skl_ipc_header header = {0};
+	u64 *ipc_header = (u64 *)(&header);
+	int ret = 0;
+
+	header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
+	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+	header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_LIBRARY);
+	header.primary |= IPC_MOD_INSTANCE_ID(table_id);
+	header.primary |= IPC_MOD_ID(dma_id);
+
+	ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
+
+	if (ret < 0)
+		dev_err(ipc->dev, "ipc: load lib failed\n");
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library);
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index 2e3d4e80ef97..0334ed4af031 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -66,7 +66,7 @@ struct skl_sst {
 
 	/* callback for miscbdge */
 	void (*enable_miscbdcge)(struct device *dev, bool enable);
-	/*Is CGCTL.MISCBDCGE disabled*/
+	/* Is CGCTL.MISCBDCGE disabled */
 	bool miscbdcg_disabled;
 
 	/* Populate module information */
@@ -75,8 +75,14 @@ struct skl_sst {
 	/* Is firmware loaded */
 	bool fw_loaded;
 
+	/* first boot ? */
+	bool is_first_boot;
+
 	/* multi-core */
 	struct skl_dsp_cores cores;
+
+	/* tplg manifest */
+	struct skl_dfw_manifest manifest;
 };
 
 struct skl_ipc_init_instance_msg {
@@ -85,6 +91,7 @@ struct skl_ipc_init_instance_msg {
 	u16 param_data_size;
 	u8 ppl_instance_id;
 	u8 core_id;
+	u8 domain;
 };
 
 struct skl_ipc_bind_unbind_msg {
@@ -145,6 +152,9 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
 int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
 		struct skl_ipc_large_config_msg *msg, u32 *param);
 
+int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
+			u8 dma_id, u8 table_id);
+
 void skl_ipc_int_enable(struct sst_dsp *dsp);
 void skl_ipc_op_int_enable(struct sst_dsp *ctx);
 void skl_ipc_op_int_disable(struct sst_dsp *ctx);
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c
index 25fcb796bd86..8dc03039b311 100644
--- a/sound/soc/intel/skylake/skl-sst-utils.c
+++ b/sound/soc/intel/skylake/skl-sst-utils.c
@@ -28,11 +28,6 @@
 /* FW Extended Manifest Header id = $AE1 */
 #define SKL_EXT_MANIFEST_HEADER_MAGIC   0x31454124
 
-struct skl_dfw_module_mod {
-	char name[100];
-	struct skl_dfw_module skl_dfw_mod;
-};
-
 struct UUID {
 	u8 id[16];
 };
@@ -99,10 +94,15 @@ struct adsp_fw_hdr {
 	u32 load_offset;
 } __packed;
 
+#define MAX_INSTANCE_BUFF 2
+
 struct uuid_module {
 	uuid_le uuid;
 	int id;
 	int is_loadable;
+	int max_instance;
+	u64 pvt_id[MAX_INSTANCE_BUFF];
+	int *instance_id;
 
 	struct list_head list;
 };
@@ -115,18 +115,23 @@ struct skl_ext_manifest_hdr {
 	u32 entries;
 };
 
-int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid,
-			struct skl_dfw_module *dfw_config)
+int snd_skl_get_module_info(struct skl_sst *ctx,
+				struct skl_module_cfg *mconfig)
 {
 	struct uuid_module *module;
 	uuid_le *uuid_mod;
 
-	uuid_mod = (uuid_le *)uuid;
+	uuid_mod = (uuid_le *)mconfig->guid;
+
+	if (list_empty(&ctx->uuid_list)) {
+		dev_err(ctx->dev, "Module list is empty\n");
+		return -EINVAL;
+	}
 
 	list_for_each_entry(module, &ctx->uuid_list, list) {
 		if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
-			dfw_config->module_id = module->id;
-			dfw_config->is_loadable = module->is_loadable;
+			mconfig->id.module_id = module->id;
+			mconfig->is_loadable = module->is_loadable;
 
 			return 0;
 		}
@@ -136,15 +141,154 @@ int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid,
 }
 EXPORT_SYMBOL_GPL(snd_skl_get_module_info);
 
+static int skl_get_pvtid_map(struct uuid_module *module, int instance_id)
+{
+	int pvt_id;
+
+	for (pvt_id = 0; pvt_id < module->max_instance; pvt_id++) {
+		if (module->instance_id[pvt_id] == instance_id)
+			return pvt_id;
+	}
+	return -EINVAL;
+}
+
+int skl_get_pvt_instance_id_map(struct skl_sst *ctx,
+				int module_id, int instance_id)
+{
+	struct uuid_module *module;
+
+	list_for_each_entry(module, &ctx->uuid_list, list) {
+		if (module->id == module_id)
+			return skl_get_pvtid_map(module, instance_id);
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(skl_get_pvt_instance_id_map);
+
+static inline int skl_getid_32(struct uuid_module *module, u64 *val,
+				int word1_mask, int word2_mask)
+{
+	int index, max_inst, pvt_id;
+	u32 mask_val;
+
+	max_inst =  module->max_instance;
+	mask_val = (u32)(*val >> word1_mask);
+
+	if (mask_val != 0xffffffff) {
+		index = ffz(mask_val);
+		pvt_id = index + word1_mask + word2_mask;
+		if (pvt_id <= (max_inst - 1)) {
+			*val |= 1 << (index + word1_mask);
+			return pvt_id;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static inline int skl_pvtid_128(struct uuid_module *module)
+{
+	int j, i, word1_mask, word2_mask = 0, pvt_id;
+
+	for (j = 0; j < MAX_INSTANCE_BUFF; j++) {
+		word1_mask = 0;
+
+		for (i = 0; i < 2; i++) {
+			pvt_id = skl_getid_32(module, &module->pvt_id[j],
+						word1_mask, word2_mask);
+			if (pvt_id >= 0)
+				return pvt_id;
+
+			word1_mask += 32;
+			if ((word1_mask + word2_mask) >= module->max_instance)
+				return -EINVAL;
+		}
+
+		word2_mask += 64;
+		if (word2_mask >= module->max_instance)
+			return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * skl_get_pvt_id: generate a private id for use as module id
+ *
+ * @ctx: driver context
+ * @mconfig: module configuration data
+ *
+ * This generates a 128 bit private unique id for a module TYPE so that
+ * module instance is unique
+ */
+int skl_get_pvt_id(struct skl_sst *ctx, struct skl_module_cfg *mconfig)
+{
+	struct uuid_module *module;
+	uuid_le *uuid_mod;
+	int pvt_id;
+
+	uuid_mod = (uuid_le *)mconfig->guid;
+
+	list_for_each_entry(module, &ctx->uuid_list, list) {
+		if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
+
+			pvt_id = skl_pvtid_128(module);
+			if (pvt_id >= 0) {
+				module->instance_id[pvt_id] =
+						mconfig->id.instance_id;
+				return pvt_id;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(skl_get_pvt_id);
+
+/**
+ * skl_put_pvt_id: free up the private id allocated
+ *
+ * @ctx: driver context
+ * @mconfig: module configuration data
+ *
+ * This frees a 128 bit private unique id previously generated
+ */
+int skl_put_pvt_id(struct skl_sst *ctx, struct skl_module_cfg *mconfig)
+{
+	int i;
+	uuid_le *uuid_mod;
+	struct uuid_module *module;
+
+	uuid_mod = (uuid_le *)mconfig->guid;
+	list_for_each_entry(module, &ctx->uuid_list, list) {
+		if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
+
+			if (mconfig->id.pvt_id != 0)
+				i = (mconfig->id.pvt_id) / 64;
+			else
+				i = 0;
+
+			module->pvt_id[i] &= ~(1 << (mconfig->id.pvt_id));
+			mconfig->id.pvt_id = -1;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(skl_put_pvt_id);
+
 /*
  * Parse the firmware binary to get the UUID, module id
  * and loadable flags
  */
-int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset)
+int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
+			unsigned int offset, int index)
 {
 	struct adsp_fw_hdr *adsp_hdr;
 	struct adsp_module_entry *mod_entry;
-	int i, num_entry;
+	int i, num_entry, size;
 	uuid_le *uuid_bin;
 	const char *buf;
 	struct skl_sst *skl = ctx->thread_context;
@@ -153,8 +297,8 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset)
 	unsigned int safe_file;
 
 	/* Get the FW pointer to derive ADSP header */
-	stripped_fw.data = ctx->fw->data;
-	stripped_fw.size = ctx->fw->size;
+	stripped_fw.data = fw->data;
+	stripped_fw.size = fw->size;
 
 	skl_dsp_strip_extended_manifest(&stripped_fw);
 
@@ -205,8 +349,15 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset)
 		uuid_bin = (uuid_le *)mod_entry->uuid.id;
 		memcpy(&module->uuid, uuid_bin, sizeof(module->uuid));
 
-		module->id = i;
+		module->id = (i | (index << 12));
 		module->is_loadable = mod_entry->type.load_type;
+		module->max_instance = mod_entry->instance_max_count;
+		size = sizeof(int) * mod_entry->instance_max_count;
+		module->instance_id = devm_kzalloc(ctx->dev, size, GFP_KERNEL);
+		if (!module->instance_id) {
+			kfree(module);
+			return -ENOMEM;
+		}
 
 		list_add_tail(&module->list, &skl->uuid_list);
 
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
index 588f899ceb65..8fc3178bc79c 100644
--- a/sound/soc/intel/skylake/skl-sst.c
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -88,13 +88,15 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
 		}
 	}
 
-	ret = snd_skl_parse_uuids(ctx, SKL_ADSP_FW_BIN_HDR_OFFSET);
-	if (ret < 0) {
-		dev_err(ctx->dev,
-				"UUID parsing err: %d\n", ret);
-		release_firmware(ctx->fw);
-		skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
-		return ret;
+	/* prase uuids on first boot */
+	if (skl->is_first_boot) {
+		ret = snd_skl_parse_uuids(ctx, ctx->fw, SKL_ADSP_FW_BIN_HDR_OFFSET, 0);
+		if (ret < 0) {
+			dev_err(ctx->dev, "UUID parsing err: %d\n", ret);
+			release_firmware(ctx->fw);
+			skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
+			return ret;
+		}
 	}
 
 	/* check for extended manifest */
@@ -105,13 +107,13 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
 
 	ret = skl_dsp_boot(ctx);
 	if (ret < 0) {
-		dev_err(ctx->dev, "Boot dsp core failed ret: %d", ret);
+		dev_err(ctx->dev, "Boot dsp core failed ret: %d\n", ret);
 		goto skl_load_base_firmware_failed;
 	}
 
 	ret = skl_cldma_prepare(ctx);
 	if (ret < 0) {
-		dev_err(ctx->dev, "CL dma prepare failed : %d", ret);
+		dev_err(ctx->dev, "CL dma prepare failed : %d\n", ret);
 		goto skl_load_base_firmware_failed;
 	}
 
@@ -484,25 +486,32 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
 		return ret;
 
 	skl->cores.count = 2;
+	skl->is_first_boot = true;
+
+	if (dsp)
+		*dsp = skl;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
+
+int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx)
+{
+	int ret;
+	struct sst_dsp *sst = ctx->dsp;
 
 	ret = sst->fw_ops.load_fw(sst);
 	if (ret < 0) {
-		dev_err(dev, "Load base fw failed : %d", ret);
-		goto cleanup;
+		dev_err(dev, "Load base fw failed : %d\n", ret);
+		return ret;
 	}
 
 	skl_dsp_init_core_state(sst);
+	ctx->is_first_boot = false;
 
-	if (dsp)
-		*dsp = skl;
-
-	return ret;
-
-cleanup:
-	skl_sst_dsp_cleanup(dev, skl);
-	return ret;
+	return 0;
 }
-EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
+EXPORT_SYMBOL_GPL(skl_sst_init_fw);
 
 void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
 {
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index cc0150fc2601..b5b1934d8550 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -21,6 +21,7 @@
 #include <linux/firmware.h>
 #include <sound/soc.h>
 #include <sound/soc-topology.h>
+#include <uapi/sound/snd_sst_tokens.h>
 #include "skl-sst-dsp.h"
 #include "skl-sst-ipc.h"
 #include "skl-topology.h"
@@ -32,6 +33,8 @@
 #define SKL_CH_FIXUP_MASK		(1 << 0)
 #define SKL_RATE_FIXUP_MASK		(1 << 1)
 #define SKL_FMT_FIXUP_MASK		(1 << 2)
+#define SKL_IN_DIR_BIT_MASK		BIT(0)
+#define SKL_PIN_COUNT_MASK		GENMASK(7, 4)
 
 /*
  * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
@@ -473,6 +476,14 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
 		w = w_module->w;
 		mconfig = w->priv;
 
+		/* check if module ids are populated */
+		if (mconfig->id.module_id < 0) {
+			dev_err(skl->skl_sst->dev,
+					"module %pUL id not populated\n",
+					(uuid_le *)mconfig->guid);
+			return -EIO;
+		}
+
 		/* check resource available */
 		if (!skl_is_pipe_mcps_avail(skl, mconfig))
 			return -ENOMEM;
@@ -494,12 +505,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
 		 * FE/BE params
 		 */
 		skl_tplg_update_module_params(w, ctx);
-
+		mconfig->id.pvt_id = skl_get_pvt_id(ctx, mconfig);
+		if (mconfig->id.pvt_id < 0)
+			return ret;
 		skl_tplg_set_module_init_data(w);
 		ret = skl_init_module(ctx, mconfig);
-		if (ret < 0)
+		if (ret < 0) {
+			skl_put_pvt_id(ctx, mconfig);
 			return ret;
-
+		}
 		skl_tplg_alloc_pipe_mcps(skl, mconfig);
 		ret = skl_tplg_set_module_params(w, ctx);
 		if (ret < 0)
@@ -512,6 +526,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
 static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
 	 struct skl_pipe *pipe)
 {
+	int ret;
 	struct skl_pipe_module *w_module = NULL;
 	struct skl_module_cfg *mconfig = NULL;
 
@@ -519,9 +534,13 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
 		mconfig  = w_module->w->priv;
 
 		if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod &&
-			mconfig->m_state > SKL_MODULE_UNINIT)
-			return ctx->dsp->fw_ops.unload_mod(ctx->dsp,
+			mconfig->m_state > SKL_MODULE_UNINIT) {
+			ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp,
 						mconfig->id.module_id);
+			if (ret < 0)
+				return -EIO;
+		}
+		skl_put_pvt_id(ctx, mconfig);
 	}
 
 	/* no modules to unload in this path, so return */
@@ -588,6 +607,26 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
+static int skl_fill_sink_instance_id(struct skl_sst *ctx,
+				struct skl_algo_data *alg_data)
+{
+	struct skl_kpb_params *params = (struct skl_kpb_params *)alg_data->params;
+	struct skl_mod_inst_map *inst;
+	int i, pvt_id;
+
+	inst = params->map;
+
+	for (i = 0; i < params->num_modules; i++) {
+		pvt_id = skl_get_pvt_instance_id_map(ctx,
+					inst->mod_id, inst->inst_id);
+		if (pvt_id < 0)
+			return -EINVAL;
+		inst->inst_id = pvt_id;
+		inst++;
+	}
+	return 0;
+}
+
 /*
  * Some modules require params to be set after the module is bound to
  * all pins connected.
@@ -636,6 +675,8 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
 			bc = (struct skl_algo_data *)sb->dobj.private;
 
 			if (bc->set_params == SKL_PARAM_BIND) {
+				if (mconfig->m_type == SKL_MODULE_TYPE_KPB)
+					skl_fill_sink_instance_id(ctx, bc);
 				ret = skl_set_module_params(ctx,
 						(u32 *)bc->params, bc->max,
 						bc->param_id, mconfig);
@@ -1460,85 +1501,570 @@ static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
 					skl_tplg_tlv_control_set},
 };
 
-/*
- * The topology binary passes the pin info for a module so initialize the pin
- * info passed into module instance
- */
-static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin,
-						struct skl_module_pin *m_pin,
-						bool is_dynamic, int max_pin)
+static int skl_tplg_fill_pipe_tkn(struct device *dev,
+			struct skl_pipe *pipe, u32 tkn,
+			u32 tkn_val)
 {
-	int i;
 
-	for (i = 0; i < max_pin; i++) {
-		m_pin[i].id.module_id = dfw_pin[i].module_id;
-		m_pin[i].id.instance_id = dfw_pin[i].instance_id;
-		m_pin[i].in_use = false;
-		m_pin[i].is_dynamic = is_dynamic;
-		m_pin[i].pin_state = SKL_PIN_UNBIND;
+	switch (tkn) {
+	case SKL_TKN_U32_PIPE_CONN_TYPE:
+		pipe->conn_type = tkn_val;
+		break;
+
+	case SKL_TKN_U32_PIPE_PRIORITY:
+		pipe->pipe_priority = tkn_val;
+		break;
+
+	case SKL_TKN_U32_PIPE_MEM_PGS:
+		pipe->memory_pages = tkn_val;
+		break;
+
+	default:
+		dev_err(dev, "Token not handled %d\n", tkn);
+		return -EINVAL;
 	}
+
+	return 0;
 }
 
 /*
- * Add pipeline from topology binary into driver pipeline list
- *
- * If already added we return that instance
- * Otherwise we create a new instance and add into driver list
+ * Add pipeline by parsing the relevant tokens
+ * Return an existing pipe if the pipe already exists.
  */
-static struct skl_pipe *skl_tplg_add_pipe(struct device *dev,
-			struct skl *skl, struct skl_dfw_pipe *dfw_pipe)
+static int skl_tplg_add_pipe(struct device *dev,
+		struct skl_module_cfg *mconfig, struct skl *skl,
+		struct snd_soc_tplg_vendor_value_elem *tkn_elem)
 {
 	struct skl_pipeline *ppl;
 	struct skl_pipe *pipe;
 	struct skl_pipe_params *params;
 
 	list_for_each_entry(ppl, &skl->ppl_list, node) {
-		if (ppl->pipe->ppl_id == dfw_pipe->pipe_id)
-			return ppl->pipe;
+		if (ppl->pipe->ppl_id == tkn_elem->value) {
+			mconfig->pipe = ppl->pipe;
+			return EEXIST;
+		}
 	}
 
 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
 	if (!ppl)
-		return NULL;
+		return -ENOMEM;
 
 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
 	if (!pipe)
-		return NULL;
+		return -ENOMEM;
 
 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
 	if (!params)
-		return NULL;
+		return -ENOMEM;
 
-	pipe->ppl_id = dfw_pipe->pipe_id;
-	pipe->memory_pages = dfw_pipe->memory_pages;
-	pipe->pipe_priority = dfw_pipe->pipe_priority;
-	pipe->conn_type = dfw_pipe->conn_type;
-	pipe->state = SKL_PIPE_INVALID;
 	pipe->p_params = params;
+	pipe->ppl_id = tkn_elem->value;
 	INIT_LIST_HEAD(&pipe->w_list);
 
 	ppl->pipe = pipe;
 	list_add(&ppl->node, &skl->ppl_list);
 
-	return ppl->pipe;
+	mconfig->pipe = pipe;
+	mconfig->pipe->state = SKL_PIPE_INVALID;
+
+	return 0;
+}
+
+static int skl_tplg_fill_pin(struct device *dev, u32 tkn,
+			struct skl_module_pin *m_pin,
+			int pin_index, u32 value)
+{
+	switch (tkn) {
+	case SKL_TKN_U32_PIN_MOD_ID:
+		m_pin[pin_index].id.module_id = value;
+		break;
+
+	case SKL_TKN_U32_PIN_INST_ID:
+		m_pin[pin_index].id.instance_id = value;
+		break;
+
+	default:
+		dev_err(dev, "%d Not a pin token\n", value);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Parse for pin config specific tokens to fill up the
+ * module private data
+ */
+static int skl_tplg_fill_pins_info(struct device *dev,
+		struct skl_module_cfg *mconfig,
+		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+		int dir, int pin_count)
+{
+	int ret;
+	struct skl_module_pin *m_pin;
+
+	switch (dir) {
+	case SKL_DIR_IN:
+		m_pin = mconfig->m_in_pin;
+		break;
+
+	case SKL_DIR_OUT:
+		m_pin = mconfig->m_out_pin;
+		break;
+
+	default:
+		dev_err(dev, "Invalid direction value\n");
+		return -EINVAL;
+	}
+
+	ret = skl_tplg_fill_pin(dev, tkn_elem->token,
+			m_pin, pin_count, tkn_elem->value);
+
+	if (ret < 0)
+		return ret;
+
+	m_pin[pin_count].in_use = false;
+	m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
+
+	return 0;
+}
+
+/*
+ * Fill up input/output module config format based
+ * 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;
+
+	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;
+		break;
+
+	case SKL_TKN_U32_FMT_FREQ:
+		dst_fmt->s_freq = value;
+		break;
+
+	case SKL_TKN_U32_FMT_BIT_DEPTH:
+		dst_fmt->bit_depth = value;
+		break;
+
+	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
+		dst_fmt->valid_bit_depth = value;
+		break;
+
+	case SKL_TKN_U32_FMT_CH_CONFIG:
+		dst_fmt->ch_cfg = value;
+		break;
+
+	case SKL_TKN_U32_FMT_INTERLEAVE:
+		dst_fmt->interleaving_style = value;
+		break;
+
+	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
+		dst_fmt->sample_type = value;
+		break;
+
+	case SKL_TKN_U32_FMT_CH_MAP:
+		dst_fmt->ch_map = value;
+		break;
+
+	default:
+		dev_err(dev, "Invalid token %d\n", tkn);
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
-static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt,
-				struct skl_dfw_module_fmt *src_fmt,
-				int pins)
+static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig,
+	      struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
+{
+	if (uuid_tkn->token == SKL_TKN_UUID)
+		memcpy(&mconfig->guid, &uuid_tkn->uuid, 16);
+	else {
+		dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void skl_tplg_fill_pin_dynamic_val(
+		struct skl_module_pin *mpin, u32 pin_count, u32 value)
 {
 	int i;
 
-	for (i = 0; i < pins; i++) {
-		dst_fmt[i].channels  = src_fmt[i].channels;
-		dst_fmt[i].s_freq = src_fmt[i].freq;
-		dst_fmt[i].bit_depth = src_fmt[i].bit_depth;
-		dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth;
-		dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg;
-		dst_fmt[i].ch_map = src_fmt[i].ch_map;
-		dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style;
-		dst_fmt[i].sample_type = src_fmt[i].sample_type;
+	for (i = 0; i < pin_count; i++)
+		mpin[i].is_dynamic = value;
+}
+
+/*
+ * Parse tokens to fill up the module private data
+ */
+static int skl_tplg_get_token(struct device *dev,
+		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+		struct skl *skl, struct skl_module_cfg *mconfig)
+{
+	int tkn_count = 0;
+	int ret;
+	static int is_pipe_exists;
+	static int pin_index, dir;
+
+	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;
+
+		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;
+
+		break;
+
+	case SKL_TKN_U8_DYN_IN_PIN:
+		if (!mconfig->m_in_pin)
+			return -ENOMEM;
+
+		skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin,
+			mconfig->max_in_queue, tkn_elem->value);
+
+		break;
+
+	case SKL_TKN_U8_DYN_OUT_PIN:
+		if (!mconfig->m_out_pin)
+			return -ENOMEM;
+
+		skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin,
+			mconfig->max_out_queue, tkn_elem->value);
+
+		break;
+
+	case SKL_TKN_U8_TIME_SLOT:
+		mconfig->time_slot = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U8_CORE_ID:
+		mconfig->core_id = tkn_elem->value;
+
+	case SKL_TKN_U8_MOD_TYPE:
+		mconfig->m_type = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U8_DEV_TYPE:
+		mconfig->dev_type = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U8_HW_CONN_TYPE:
+		mconfig->hw_conn_type = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U16_MOD_INST_ID:
+		mconfig->id.instance_id =
+		tkn_elem->value;
+		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;
+		break;
+
+	case SKL_TKN_U32_VBUS_ID:
+		mconfig->vbus_id = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U32_PARAMS_FIXUP:
+		mconfig->params_fixup = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U32_CONVERTER:
+		mconfig->converter = tkn_elem->value;
+		break;
+
+	case SKL_TKN_U32_PIPE_ID:
+		ret = skl_tplg_add_pipe(dev,
+				mconfig, skl, tkn_elem);
+
+		if (ret < 0)
+			return is_pipe_exists;
+
+		if (ret == EEXIST)
+			is_pipe_exists = 1;
+
+		break;
+
+	case SKL_TKN_U32_PIPE_CONN_TYPE:
+	case SKL_TKN_U32_PIPE_PRIORITY:
+	case SKL_TKN_U32_PIPE_MEM_PGS:
+		if (is_pipe_exists) {
+			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
+					tkn_elem->token, tkn_elem->value);
+			if (ret < 0)
+				return ret;
+		}
+
+		break;
+
+	/*
+	 * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
+	 * direction and the pin count. The first four bits represent
+	 * direction and next four the pin count.
+	 */
+	case SKL_TKN_U32_DIR_PIN_COUNT:
+		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
+		pin_index = (tkn_elem->value &
+			SKL_PIN_COUNT_MASK) >> 4;
+
+		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:
+		ret = skl_tplg_fill_fmt(dev, mconfig, tkn_elem->token,
+				tkn_elem->value, dir, pin_index);
+
+		if (ret < 0)
+			return ret;
+
+		break;
+
+	case SKL_TKN_U32_PIN_MOD_ID:
+	case SKL_TKN_U32_PIN_INST_ID:
+		ret = skl_tplg_fill_pins_info(dev,
+				mconfig, tkn_elem, dir,
+				pin_index);
+		if (ret < 0)
+			return ret;
+
+		break;
+
+	case SKL_TKN_U32_CAPS_SIZE:
+		mconfig->formats_config.caps_size =
+			tkn_elem->value;
+
+		break;
+
+	case SKL_TKN_U32_PROC_DOMAIN:
+		mconfig->domain =
+			tkn_elem->value;
+
+		break;
+
+	case SKL_TKN_U8_IN_PIN_TYPE:
+	case SKL_TKN_U8_OUT_PIN_TYPE:
+	case SKL_TKN_U8_CONN_TYPE:
+		break;
+
+	default:
+		dev_err(dev, "Token %d not handled\n",
+				tkn_elem->token);
+		return -EINVAL;
+	}
+
+	tkn_count++;
+
+	return tkn_count;
+}
+
+/*
+ * Parse the vendor array for specific tokens to construct
+ * module private data
+ */
+static int skl_tplg_get_tokens(struct device *dev,
+		char *pvt_data,	struct skl *skl,
+		struct skl_module_cfg *mconfig, int block_size)
+{
+	struct snd_soc_tplg_vendor_array *array;
+	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
+	int tkn_count = 0, ret;
+	int off = 0, tuple_size = 0;
+
+	if (block_size <= 0)
+		return -EINVAL;
+
+	while (tuple_size < block_size) {
+		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
+
+		off += array->size;
+
+		switch (array->type) {
+		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
+			dev_warn(dev, "no string tokens expected for skl tplg\n");
+			continue;
+
+		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
+			ret = skl_tplg_get_uuid(dev, mconfig, array->uuid);
+			if (ret < 0)
+				return ret;
+
+			tuple_size += sizeof(*array->uuid);
+
+			continue;
+
+		default:
+			tkn_elem = array->value;
+			tkn_count = 0;
+			break;
+		}
+
+		while (tkn_count <= (array->num_elems - 1)) {
+			ret = skl_tplg_get_token(dev, tkn_elem,
+					skl, mconfig);
+
+			if (ret < 0)
+				return ret;
+
+			tkn_count = tkn_count + ret;
+			tkn_elem++;
+		}
+
+		tuple_size += tkn_count * sizeof(*tkn_elem);
+	}
+
+	return 0;
+}
+
+/*
+ * Every data block is preceded by a descriptor to read the number
+ * of data blocks, they type of the block and it's size
+ */
+static int skl_tplg_get_desc_blocks(struct device *dev,
+		struct snd_soc_tplg_vendor_array *array)
+{
+	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
+
+	tkn_elem = array->value;
+
+	switch (tkn_elem->token) {
+	case SKL_TKN_U8_NUM_BLOCKS:
+	case SKL_TKN_U8_BLOCK_TYPE:
+	case SKL_TKN_U16_BLOCK_SIZE:
+		return tkn_elem->value;
+
+	default:
+		dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token);
+		break;
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * Parse the private data for the token and corresponding value.
+ * The private data can have multiple data blocks. So, a data block
+ * is preceded by a descriptor for number of blocks and a descriptor
+ * for the type and size of the suceeding data block.
+ */
+static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
+				struct skl *skl, struct device *dev,
+				struct skl_module_cfg *mconfig)
+{
+	struct snd_soc_tplg_vendor_array *array;
+	int num_blocks, block_size = 0, block_type, off = 0;
+	char *data;
+	int ret;
+
+	/* Read the NUM_DATA_BLOCKS descriptor */
+	array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
+	ret = skl_tplg_get_desc_blocks(dev, array);
+	if (ret < 0)
+		return ret;
+	num_blocks = ret;
+
+	off += array->size;
+	array = (struct snd_soc_tplg_vendor_array *)(tplg_w->priv.data + off);
+
+	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
+	while (num_blocks > 0) {
+		ret = skl_tplg_get_desc_blocks(dev, array);
+
+		if (ret < 0)
+			return ret;
+		block_type = ret;
+		off += array->size;
+
+		array = (struct snd_soc_tplg_vendor_array *)
+			(tplg_w->priv.data + off);
+
+		ret = skl_tplg_get_desc_blocks(dev, array);
+
+		if (ret < 0)
+			return ret;
+		block_size = ret;
+		off += array->size;
+
+		array = (struct snd_soc_tplg_vendor_array *)
+			(tplg_w->priv.data + off);
+
+		data = (tplg_w->priv.data + off);
+
+		if (block_type == SKL_TYPE_TUPLE) {
+			ret = skl_tplg_get_tokens(dev, data,
+					skl, mconfig, block_size);
+
+			if (ret < 0)
+				return ret;
+
+			--num_blocks;
+		} else {
+			if (mconfig->formats_config.caps_size > 0)
+				memcpy(mconfig->formats_config.caps, data,
+					mconfig->formats_config.caps_size);
+			--num_blocks;
+		}
 	}
+
+	return 0;
 }
 
 static void skl_clear_pin_config(struct snd_soc_platform *platform,
@@ -1606,9 +2132,6 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
 	struct skl *skl = ebus_to_skl(ebus);
 	struct hdac_bus *bus = ebus_to_hbus(ebus);
 	struct skl_module_cfg *mconfig;
-	struct skl_pipe *pipe;
-	struct skl_dfw_module *dfw_config =
-				(struct skl_dfw_module *)tplg_w->priv.data;
 
 	if (!tplg_w->priv.size)
 		goto bind_event;
@@ -1619,76 +2142,17 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
 		return -ENOMEM;
 
 	w->priv = mconfig;
-	memcpy(&mconfig->guid, &dfw_config->uuid, 16);
 
-	ret = snd_skl_get_module_info(skl->skl_sst, mconfig->guid, dfw_config);
+	/*
+	 * module binary can be loaded later, so set it to query when
+	 * module is load for a use case
+	 */
+	mconfig->id.module_id = -1;
+
+	/* Parse private data for tuples */
+	ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
 	if (ret < 0)
 		return ret;
-
-	mconfig->id.module_id = dfw_config->module_id;
-	mconfig->id.instance_id = dfw_config->instance_id;
-	mconfig->mcps = dfw_config->max_mcps;
-	mconfig->ibs = dfw_config->ibs;
-	mconfig->obs = dfw_config->obs;
-	mconfig->core_id = dfw_config->core_id;
-	mconfig->max_in_queue = dfw_config->max_in_queue;
-	mconfig->max_out_queue = dfw_config->max_out_queue;
-	mconfig->is_loadable = dfw_config->is_loadable;
-	skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt,
-						MODULE_MAX_IN_PINS);
-	skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt,
-						MODULE_MAX_OUT_PINS);
-
-	mconfig->params_fixup = dfw_config->params_fixup;
-	mconfig->converter = dfw_config->converter;
-	mconfig->m_type = dfw_config->module_type;
-	mconfig->vbus_id = dfw_config->vbus_id;
-	mconfig->mem_pages = dfw_config->mem_pages;
-
-	pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe);
-	if (pipe)
-		mconfig->pipe = pipe;
-
-	mconfig->dev_type = dfw_config->dev_type;
-	mconfig->hw_conn_type = dfw_config->hw_conn_type;
-	mconfig->time_slot = dfw_config->time_slot;
-	mconfig->formats_config.caps_size = dfw_config->caps.caps_size;
-
-	mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) *
-						sizeof(*mconfig->m_in_pin),
-						GFP_KERNEL);
-	if (!mconfig->m_in_pin)
-		return -ENOMEM;
-
-	mconfig->m_out_pin = devm_kzalloc(bus->dev, (mconfig->max_out_queue) *
-						sizeof(*mconfig->m_out_pin),
-						GFP_KERNEL);
-	if (!mconfig->m_out_pin)
-		return -ENOMEM;
-
-	skl_fill_module_pin_info(dfw_config->in_pin, mconfig->m_in_pin,
-						dfw_config->is_dynamic_in_pin,
-						mconfig->max_in_queue);
-
-	skl_fill_module_pin_info(dfw_config->out_pin, mconfig->m_out_pin,
-						 dfw_config->is_dynamic_out_pin,
-							mconfig->max_out_queue);
-
-
-	if (mconfig->formats_config.caps_size == 0)
-		goto bind_event;
-
-	mconfig->formats_config.caps = (u32 *)devm_kzalloc(bus->dev,
-			mconfig->formats_config.caps_size, GFP_KERNEL);
-
-	if (mconfig->formats_config.caps == NULL)
-		return -ENOMEM;
-
-	memcpy(mconfig->formats_config.caps, dfw_config->caps.caps,
-						 dfw_config->caps.caps_size);
-	mconfig->formats_config.param_id = dfw_config->caps.param_id;
-	mconfig->formats_config.set_params = dfw_config->caps.set_params;
-
 bind_event:
 	if (tplg_w->event_type == 0) {
 		dev_dbg(bus->dev, "ASoC: No event handler required\n");
@@ -1767,11 +2231,229 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
 	return 0;
 }
 
+static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
+		struct snd_soc_tplg_vendor_string_elem *str_elem,
+		struct skl_dfw_manifest *minfo)
+{
+	int tkn_count = 0;
+	static int ref_count;
+
+	switch (str_elem->token) {
+	case SKL_TKN_STR_LIB_NAME:
+		if (ref_count > minfo->lib_count - 1) {
+			ref_count = 0;
+			return -EINVAL;
+		}
+
+		strncpy(minfo->lib[ref_count].name, str_elem->string,
+				ARRAY_SIZE(minfo->lib[ref_count].name));
+		ref_count++;
+		tkn_count++;
+		break;
+
+	default:
+		dev_err(dev, "Not a string token %d\n", str_elem->token);
+		break;
+	}
+
+	return tkn_count;
+}
+
+static int skl_tplg_get_str_tkn(struct device *dev,
+		struct snd_soc_tplg_vendor_array *array,
+		struct skl_dfw_manifest *minfo)
+{
+	int tkn_count = 0, ret;
+	struct snd_soc_tplg_vendor_string_elem *str_elem;
+
+	str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
+	while (tkn_count < array->num_elems) {
+		ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, minfo);
+		str_elem++;
+
+		if (ret < 0)
+			return ret;
+
+		tkn_count = tkn_count + ret;
+	}
+
+	return tkn_count;
+}
+
+static int skl_tplg_get_int_tkn(struct device *dev,
+		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+		struct skl_dfw_manifest *minfo)
+{
+	int tkn_count = 0;
+
+	switch (tkn_elem->token) {
+	case SKL_TKN_U32_LIB_COUNT:
+		minfo->lib_count = tkn_elem->value;
+		tkn_count++;
+		break;
+
+	default:
+		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
+		return -EINVAL;
+	}
+
+	return tkn_count;
+}
+
+/*
+ * Fill the manifest structure by parsing the tokens based on the
+ * type.
+ */
+static int skl_tplg_get_manifest_tkn(struct device *dev,
+		char *pvt_data, struct skl_dfw_manifest *minfo,
+		int block_size)
+{
+	int tkn_count = 0, ret;
+	int off = 0, tuple_size = 0;
+	struct snd_soc_tplg_vendor_array *array;
+	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
+
+	if (block_size <= 0)
+		return -EINVAL;
+
+	while (tuple_size < block_size) {
+		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
+		off += array->size;
+		switch (array->type) {
+		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
+			ret = skl_tplg_get_str_tkn(dev, array, minfo);
+
+			if (ret < 0)
+				return ret;
+			tkn_count += ret;
+
+			tuple_size += tkn_count *
+				sizeof(struct snd_soc_tplg_vendor_string_elem);
+			continue;
+
+		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
+			dev_warn(dev, "no uuid tokens for skl tplf manifest\n");
+			continue;
+
+		default:
+			tkn_elem = array->value;
+			tkn_count = 0;
+			break;
+		}
+
+		while (tkn_count <= array->num_elems - 1) {
+			ret = skl_tplg_get_int_tkn(dev,
+					tkn_elem, minfo);
+			if (ret < 0)
+				return ret;
+
+			tkn_count = tkn_count + ret;
+			tkn_elem++;
+			tuple_size += tkn_count *
+				sizeof(struct snd_soc_tplg_vendor_value_elem);
+			break;
+		}
+		tkn_count = 0;
+	}
+
+	return 0;
+}
+
+/*
+ * Parse manifest private data for tokens. The private data block is
+ * preceded by descriptors for type and size of data block.
+ */
+static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
+			struct device *dev, struct skl_dfw_manifest *minfo)
+{
+	struct snd_soc_tplg_vendor_array *array;
+	int num_blocks, block_size = 0, block_type, off = 0;
+	char *data;
+	int ret;
+
+	/* Read the NUM_DATA_BLOCKS descriptor */
+	array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
+	ret = skl_tplg_get_desc_blocks(dev, array);
+	if (ret < 0)
+		return ret;
+	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) {
+		ret = skl_tplg_get_desc_blocks(dev, array);
+
+		if (ret < 0)
+			return ret;
+		block_type = ret;
+		off += array->size;
+
+		array = (struct snd_soc_tplg_vendor_array *)
+			(manifest->priv.data + off);
+
+		ret = skl_tplg_get_desc_blocks(dev, array);
+
+		if (ret < 0)
+			return ret;
+		block_size = ret;
+		off += array->size;
+
+		array = (struct snd_soc_tplg_vendor_array *)
+			(manifest->priv.data + off);
+
+		data = (manifest->priv.data + off);
+
+		if (block_type == SKL_TYPE_TUPLE) {
+			ret = skl_tplg_get_manifest_tkn(dev, data, minfo,
+					block_size);
+
+			if (ret < 0)
+				return ret;
+
+			--num_blocks;
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int skl_manifest_load(struct snd_soc_component *cmpnt,
+				struct snd_soc_tplg_manifest *manifest)
+{
+	struct skl_dfw_manifest *minfo;
+	struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
+	struct hdac_bus *bus = ebus_to_hbus(ebus);
+	struct skl *skl = ebus_to_skl(ebus);
+	int ret = 0;
+
+	/* proceed only if we have private data defined */
+	if (manifest->priv.size == 0)
+		return 0;
+
+	minfo = &skl->skl_sst->manifest;
+
+	skl_tplg_get_manifest_data(manifest, bus->dev, minfo);
+
+	if (minfo->lib_count > HDA_MAX_LIB) {
+		dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
+					minfo->lib_count);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 static struct snd_soc_tplg_ops skl_tplg_ops  = {
 	.widget_load = skl_tplg_widget_load,
 	.control_load = skl_tplg_control_load,
 	.bytes_ext_ops = skl_tlv_ops,
 	.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
+	.manifest = skl_manifest_load,
 };
 
 /*
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 22d3ef83817d..a519360f42a6 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -133,7 +133,7 @@ struct skl_i2s_config_blob {
 struct skl_dma_control {
 	u32 node_id;
 	u32 config_length;
-	u32 config_data[1];
+	u32 config_data[0];
 } __packed;
 
 struct skl_cpr_cfg {
@@ -215,9 +215,20 @@ struct skl_module_fmt {
 
 struct skl_module_cfg;
 
+struct skl_mod_inst_map {
+	u16 mod_id;
+	u16 inst_id;
+};
+
+struct skl_kpb_params {
+	u32 num_modules;
+	struct skl_mod_inst_map map[0];
+};
+
 struct skl_module_inst_id {
-	u32 module_id;
+	int module_id;
 	u32 instance_id;
+	int pvt_id;
 };
 
 enum skl_module_pin_state {
diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h
index a32e5e9cc530..2f6281e056d6 100644
--- a/sound/soc/intel/skylake/skl-tplg-interface.h
+++ b/sound/soc/intel/skylake/skl-tplg-interface.h
@@ -80,7 +80,8 @@ enum skl_module_type {
 	SKL_MODULE_TYPE_UPDWMIX,
 	SKL_MODULE_TYPE_SRCINT,
 	SKL_MODULE_TYPE_ALGO,
-	SKL_MODULE_TYPE_BASE_OUTFMT
+	SKL_MODULE_TYPE_BASE_OUTFMT,
+	SKL_MODULE_TYPE_KPB,
 };
 
 enum skl_core_affinity {
@@ -148,84 +149,34 @@ enum skl_module_param_type {
 	SKL_PARAM_BIND
 };
 
-struct skl_dfw_module_pin {
-	u16 module_id;
-	u16 instance_id;
-} __packed;
-
-struct skl_dfw_module_fmt {
-	u32 channels;
-	u32 freq;
-	u32 bit_depth;
-	u32 valid_bit_depth;
-	u32 ch_cfg;
-	u32 interleaving_style;
-	u32 sample_type;
-	u32 ch_map;
-} __packed;
-
-struct skl_dfw_module_caps {
+struct skl_dfw_algo_data {
 	u32 set_params:2;
 	u32 rsvd:30;
 	u32 param_id;
-	u32 caps_size;
-	u32 caps[HDA_SST_CFG_MAX];
-};
-
-struct skl_dfw_pipe {
-	u8 pipe_id;
-	u8 pipe_priority;
-	u16 conn_type:4;
-	u16 rsvd:4;
-	u16 memory_pages:8;
+	u32 max;
+	char params[0];
 } __packed;
 
-struct skl_dfw_module {
-	u8 uuid[16];
-
-	u16 module_id;
-	u16 instance_id;
-	u32 max_mcps;
-	u32 mem_pages;
-	u32 obs;
-	u32 ibs;
-	u32 vbus_id;
-
-	u32 max_in_queue:8;
-	u32 max_out_queue:8;
-	u32 time_slot:8;
-	u32 core_id:4;
-	u32 rsvd1:4;
-
-	u32 module_type:8;
-	u32 conn_type:4;
-	u32 dev_type:4;
-	u32 hw_conn_type:4;
-	u32 rsvd2:12;
-
-	u32 params_fixup:8;
-	u32 converter:8;
-	u32 input_pin_type:1;
-	u32 output_pin_type:1;
-	u32 is_dynamic_in_pin:1;
-	u32 is_dynamic_out_pin:1;
-	u32 is_loadable:1;
-	u32 rsvd3:11;
-
-	struct skl_dfw_pipe pipe;
-	struct skl_dfw_module_fmt in_fmt[MAX_IN_QUEUE];
-	struct skl_dfw_module_fmt out_fmt[MAX_OUT_QUEUE];
-	struct skl_dfw_module_pin in_pin[MAX_IN_QUEUE];
-	struct skl_dfw_module_pin out_pin[MAX_OUT_QUEUE];
-	struct skl_dfw_module_caps caps;
+#define LIB_NAME_LENGTH	128
+#define HDA_MAX_LIB	16
+
+struct lib_info {
+	char name[LIB_NAME_LENGTH];
 } __packed;
 
-struct skl_dfw_algo_data {
-	u32 set_params:2;
-	u32 rsvd:30;
-	u32 param_id;
-	u32 max;
-	char params[0];
+struct skl_dfw_manifest {
+	u32 lib_count;
+	struct lib_info lib[HDA_MAX_LIB];
 } __packed;
 
+enum skl_tkn_dir {
+	SKL_DIR_IN,
+	SKL_DIR_OUT
+};
+
+enum skl_tuple_type {
+	SKL_TYPE_TUPLE,
+	SKL_TYPE_DATA
+};
+
 #endif
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index cd59536a761d..2989c164dafe 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -587,7 +587,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
 		return -ENXIO;
 	}
 
-	snd_hdac_ext_bus_parse_capabilities(ebus);
+	snd_hdac_bus_parse_capabilities(bus);
 
 	if (skl_acquire_irq(ebus, 0) < 0)
 		return -EBUSY;
@@ -672,8 +672,10 @@ static int skl_probe(struct pci_dev *pci,
 
 	skl->nhlt = skl_nhlt_init(bus->dev);
 
-	if (skl->nhlt == NULL)
+	if (skl->nhlt == NULL) {
+		err = -ENODEV;
 		goto out_free;
+	}
 
 	skl_nhlt_update_topology_bin(skl);
 
@@ -682,7 +684,7 @@ static int skl_probe(struct pci_dev *pci,
 	skl_dmic_data.dmic_num = skl_get_dmic_geo(skl);
 
 	/* check if dsp is there */
-	if (ebus->ppcap) {
+	if (bus->ppcap) {
 		err = skl_machine_device_register(skl,
 				  (void *)pci_id->driver_data);
 		if (err < 0)
@@ -696,7 +698,7 @@ static int skl_probe(struct pci_dev *pci,
 		skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
 
 	}
-	if (ebus->mlcap)
+	if (bus->mlcap)
 		snd_hdac_ext_bus_get_ml_capabilities(ebus);
 
 	/* create device for soc dmic */
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 9064e5b0d676..5d4fbb094c48 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -105,6 +105,7 @@ struct skl_dsp_ops {
 			int irq, const char *fw_name,
 			struct skl_dsp_loader_ops loader_ops,
 			struct skl_sst **skl_sst);
+	int (*init_fw)(struct device *dev, struct skl_sst *ctx);
 	void (*cleanup)(struct device *dev, struct skl_sst *ctx);
 };
 
@@ -123,4 +124,5 @@ int skl_free_dsp(struct skl *skl);
 int skl_suspend_dsp(struct skl *skl);
 int skl_resume_dsp(struct skl *skl);
 void skl_cleanup_resources(struct skl *skl);
+const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id);
 #endif /* __SOUND_SOC_SKL_H */
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index dbfdfe99c69d..dafd22e874e9 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -242,7 +242,7 @@ static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
 	return count;
 }
 
-static struct snd_pcm_ops kirkwood_dma_ops = {
+static const struct snd_pcm_ops kirkwood_dma_ops = {
 	.open =		kirkwood_dma_open,
 	.close =        kirkwood_dma_close,
 	.ioctl =	snd_pcm_lib_ioctl,
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
index b788791b0a35..ac231d33d8fe 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
@@ -23,7 +23,8 @@
 
 #define AFE_BASE_END_OFFSET 8
 
-int mtk_regmap_update_bits(struct regmap *map, int reg, unsigned int mask,
+static int mtk_regmap_update_bits(struct regmap *map, int reg,
+			   unsigned int mask,
 			   unsigned int val)
 {
 	if (reg < 0)
@@ -31,7 +32,7 @@ int mtk_regmap_update_bits(struct regmap *map, int reg, unsigned int mask,
 	return regmap_update_bits(map, reg, mask, val);
 }
 
-int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
+static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
 {
 	if (reg < 0)
 		return 0;
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
index 76ce33199bf9..06fec5699cc8 100644
--- a/sound/soc/omap/mcbsp.c
+++ b/sound/soc/omap/mcbsp.c
@@ -221,7 +221,8 @@ void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
 
 	/* Enable TX/RX sync error interrupts by default */
 	if (mcbsp->irq)
-		MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN);
+		MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN |
+			    RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN);
 }
 
 /**
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index 0843a68f277c..89fe95e877db 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -38,10 +38,10 @@
 struct abe_twl6040 {
 	int	jack_detection;	/* board can detect jack events */
 	int	mclk_freq;	/* MCLK frequency speed for twl6040 */
-
-	struct platform_device *dmic_codec_dev;
 };
 
+struct platform_device *dmic_codec_dev;
+
 static int omap_abe_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 {
@@ -258,8 +258,6 @@ static int omap_abe_probe(struct platform_device *pdev)
 	if (priv == NULL)
 		return -ENOMEM;
 
-	priv->dmic_codec_dev = ERR_PTR(-EINVAL);
-
 	if (snd_soc_of_parse_card_name(card, "ti,model")) {
 		dev_err(&pdev->dev, "Card name is not provided\n");
 		return -ENODEV;
@@ -284,13 +282,6 @@ static int omap_abe_probe(struct platform_device *pdev)
 		num_links = 2;
 		abe_twl6040_dai_links[1].cpu_of_node = dai_node;
 		abe_twl6040_dai_links[1].platform_of_node = dai_node;
-
-		priv->dmic_codec_dev = platform_device_register_simple(
-						"dmic-codec", -1, NULL, 0);
-		if (IS_ERR(priv->dmic_codec_dev)) {
-			dev_err(&pdev->dev, "Can't instantiate dmic-codec\n");
-			return PTR_ERR(priv->dmic_codec_dev);
-		}
 	} else {
 		num_links = 1;
 	}
@@ -299,16 +290,14 @@ static int omap_abe_probe(struct platform_device *pdev)
 	of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq);
 	if (!priv->mclk_freq) {
 		dev_err(&pdev->dev, "MCLK frequency not provided\n");
-		ret = -EINVAL;
-		goto err_unregister;
+		return -EINVAL;
 	}
 
 	card->fully_routed = 1;
 
 	if (!priv->mclk_freq) {
 		dev_err(&pdev->dev, "MCLK frequency missing\n");
-		ret = -ENODEV;
-		goto err_unregister;
+		return -ENODEV;
 	}
 
 	card->dai_link = abe_twl6040_dai_links;
@@ -316,35 +305,14 @@ static int omap_abe_probe(struct platform_device *pdev)
 
 	snd_soc_card_set_drvdata(card, priv);
 
-	ret = snd_soc_register_card(card);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
 			ret);
-		goto err_unregister;
-	}
-
-	return 0;
-
-err_unregister:
-	if (!IS_ERR(priv->dmic_codec_dev))
-		platform_device_unregister(priv->dmic_codec_dev);
 
 	return ret;
 }
 
-static int omap_abe_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
-
-	snd_soc_unregister_card(card);
-
-	if (!IS_ERR(priv->dmic_codec_dev))
-		platform_device_unregister(priv->dmic_codec_dev);
-
-	return 0;
-}
-
 static const struct of_device_id omap_abe_of_match[] = {
 	{.compatible = "ti,abe-twl6040", },
 	{ },
@@ -358,10 +326,35 @@ static struct platform_driver omap_abe_driver = {
 		.of_match_table = omap_abe_of_match,
 	},
 	.probe = omap_abe_probe,
-	.remove = omap_abe_remove,
 };
 
-module_platform_driver(omap_abe_driver);
+static int __init omap_abe_init(void)
+{
+	int ret;
+
+	dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL,
+							 0);
+	if (IS_ERR(dmic_codec_dev)) {
+		pr_err("%s: dmic-codec device registration failed\n", __func__);
+		return PTR_ERR(dmic_codec_dev);
+	}
+
+	ret = platform_driver_register(&omap_abe_driver);
+	if (ret) {
+		pr_err("%s: platform driver registration failed\n", __func__);
+		platform_device_unregister(dmic_codec_dev);
+	}
+
+	return ret;
+}
+module_init(omap_abe_init);
+
+static void __exit omap_abe_exit(void)
+{
+	platform_driver_unregister(&omap_abe_driver);
+	platform_device_unregister(dmic_codec_dev);
+}
+module_exit(omap_abe_exit);
 
 MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
 MODULE_DESCRIPTION("ALSA SoC for OMAP boards with ABE and twl6040 codec");
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index e7cdc51fd806..64609c77a79d 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -31,7 +31,6 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/irq.h>
-#include <linux/clk.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
 #include <linux/of_device.h>
@@ -55,7 +54,6 @@ struct omap_mcpdm {
 	unsigned long phys_base;
 	void __iomem *io_base;
 	int irq;
-	struct clk *pdmclk;
 
 	struct mutex mutex;
 
@@ -390,15 +388,14 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
 	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
-	clk_prepare_enable(mcpdm->pdmclk);
 	pm_runtime_enable(mcpdm->dev);
 
 	/* Disable lines while request is ongoing */
 	pm_runtime_get_sync(mcpdm->dev);
 	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
 
-	ret = devm_request_irq(mcpdm->dev, mcpdm->irq, omap_mcpdm_irq_handler,
-				0, "McPDM", (void *)mcpdm);
+	ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, 0, "McPDM",
+			  (void *)mcpdm);
 
 	pm_runtime_put_sync(mcpdm->dev);
 
@@ -423,9 +420,9 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai)
 {
 	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
 
+	free_irq(mcpdm->irq, (void *)mcpdm);
 	pm_runtime_disable(mcpdm->dev);
 
-	clk_disable_unprepare(mcpdm->pdmclk);
 	return 0;
 }
 
@@ -445,8 +442,6 @@ static int omap_mcpdm_suspend(struct snd_soc_dai *dai)
 		mcpdm->pm_active_count++;
 	}
 
-	clk_disable_unprepare(mcpdm->pdmclk);
-
 	return 0;
 }
 
@@ -454,8 +449,6 @@ static int omap_mcpdm_resume(struct snd_soc_dai *dai)
 {
 	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
 
-	clk_prepare_enable(mcpdm->pdmclk);
-
 	if (mcpdm->pm_active_count) {
 		while (mcpdm->pm_active_count--)
 			pm_runtime_get_sync(mcpdm->dev);
@@ -549,15 +542,6 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
 
 	mcpdm->dev = &pdev->dev;
 
-	mcpdm->pdmclk = devm_clk_get(&pdev->dev, "pdmclk");
-	if (IS_ERR(mcpdm->pdmclk)) {
-		if (PTR_ERR(mcpdm->pdmclk) == -EPROBE_DEFER)
-			return -EPROBE_DEFER;
-		dev_warn(&pdev->dev, "Error getting pdmclk (%ld)!\n",
-			 PTR_ERR(mcpdm->pdmclk));
-		mcpdm->pdmclk = NULL;
-	}
-
 	ret =  devm_snd_soc_register_component(&pdev->dev,
 					       &omap_mcpdm_component,
 					       &omap_mcpdm_dai, 1);
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index a84f677234f0..94e9ff791f3a 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -58,7 +58,7 @@ static void omap_pcm_limit_supported_formats(void)
 {
 	int i;
 
-	for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
+	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
 		switch (snd_pcm_format_physical_width(i)) {
 		case 8:
 		case 16:
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
index 1289543c8fb2..07f91e918b23 100644
--- a/sound/soc/qcom/apq8016_sbc.c
+++ b/sound/soc/qcom/apq8016_sbc.c
@@ -85,6 +85,15 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
 		return ERR_PTR(ret);
 	}
 
+	/* DAPM routes */
+	if (of_property_read_bool(node, "qcom,audio-routing")) {
+		ret = snd_soc_of_parse_audio_routing(card,
+					"qcom,audio-routing");
+		if (ret)
+			return ERR_PTR(ret);
+	}
+
+
 	/* Populate links */
 	num_links = of_get_child_count(node);
 
@@ -147,6 +156,15 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
 	return data;
 }
 
+static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = {
+
+	SND_SOC_DAPM_MIC("Handset Mic", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Secondary Mic", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+};
+
 static int apq8016_sbc_platform_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -159,6 +177,8 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	card->dev = dev;
+	card->dapm_widgets = apq8016_sbc_dapm_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(apq8016_sbc_dapm_widgets);
 	data = apq8016_sbc_parse_of(card);
 	if (IS_ERR(data)) {
 		dev_err(&pdev->dev, "Error resolving dai links: %ld\n",
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index db000c6987a1..e2ff538a8aa5 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -84,9 +84,9 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_pcm_data *pcm_data = drvdata->private_data;
 	struct lpass_variant *v = drvdata->variant;
 	snd_pcm_format_t format = params_format(params);
 	unsigned int channels = params_channels(params);
@@ -177,9 +177,9 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_pcm_data *pcm_data = drvdata->private_data;
 	struct lpass_variant *v = drvdata->variant;
 	unsigned int reg;
 	int ret;
@@ -201,9 +201,9 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_pcm_data *pcm_data = drvdata->private_data;
 	struct lpass_variant *v = drvdata->variant;
 	int ret, ch, dir = substream->stream;
 
@@ -255,9 +255,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		int cmd)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_pcm_data *pcm_data = drvdata->private_data;
 	struct lpass_variant *v = drvdata->variant;
 	int ret, ch, dir = substream->stream;
 
@@ -331,9 +331,9 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 		struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 			snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_pcm_data *pcm_data = drvdata->private_data;
 	struct lpass_variant *v = drvdata->variant;
 	unsigned int base_addr, curr_addr;
 	int ret, ch, dir = substream->stream;
@@ -372,7 +372,7 @@ static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream,
 			runtime->dma_bytes);
 }
 
-static struct snd_pcm_ops lpass_platform_pcm_ops = {
+static const struct snd_pcm_ops lpass_platform_pcm_ops = {
 	.open		= lpass_platform_pcmops_open,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= lpass_platform_pcmops_hw_params,
@@ -483,7 +483,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 		return -ENOMEM;
 
 	data->i2s_port = cpu_dai->driver->id;
-	snd_soc_pcm_set_drvdata(soc_runtime, data);
+	drvdata->private_data = data;
 
 	psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
 	if (psubstream) {
@@ -570,8 +570,8 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
 		substream = pcm->streams[i].substream;
 		if (substream) {
 			rt = substream->private_data;
-			data = snd_soc_pcm_get_drvdata(rt);
 			drvdata = snd_soc_platform_get_drvdata(rt->platform);
+			data = drvdata->private_data;
 
 			ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 				? data->rdma_ch
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 30714ad1e138..35b3cea8207d 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -58,6 +58,8 @@ struct lpass_data {
 	/* 8016 specific */
 	struct clk *pcnoc_mport_clk;
 	struct clk *pcnoc_sway_clk;
+
+	void *private_data;
 };
 
 /* Vairant data per each SOC */
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index f1e0c703e0d2..c783f9a22595 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -41,3 +41,15 @@ config SND_SOC_ROCKCHIP_RT5645
 	help
 	  Say Y or M here if you want to add support for SoC audio on Rockchip
 	  boards using the RT5645/RT5650 codec, such as Veyron.
+
+config SND_SOC_RK3399_GRU_SOUND
+	tristate "ASoC support multiple codecs for Rockchip RK3399 GRU boards"
+	depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && CLKDEV_LOOKUP && SPI
+	select SND_SOC_ROCKCHIP_I2S
+	select SND_SOC_MAX98357A
+	select SND_SOC_RT5514
+	select SND_SOC_DA7219
+	select SND_SOC_RT5514_SPI
+	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/Makefile b/sound/soc/rockchip/Makefile
index c0bf560125f3..84e5c7c700e7 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
 
 snd-soc-rockchip-max98090-objs := rockchip_max98090.o
 snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
+snd-soc-rk3399-gru-sound-objs := rk3399_gru_sound.o
 
 obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
+obj-$(CONFIG_SND_SOC_RK3399_GRU_SOUND) += snd-soc-rk3399-gru-sound.o
diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c
new file mode 100644
index 000000000000..9ed735a6cf49
--- /dev/null
+++ b/sound/soc/rockchip/rk3399_gru_sound.c
@@ -0,0 +1,397 @@
+/*
+ * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219
+ *
+ * Copyright (c) 2016, ROCKCHIP CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/input.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "rockchip_i2s.h"
+#include "../codecs/da7219.h"
+#include "../codecs/da7219-aad.h"
+#include "../codecs/rt5514.h"
+
+#define DRV_NAME "rk3399-gru-sound"
+
+#define SOUND_FS	256
+
+unsigned int rt5514_dmic_delay;
+
+static struct snd_soc_jack rockchip_sound_jack;
+
+static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphones", NULL),
+	SND_SOC_DAPM_SPK("Speakers", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Int Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route rockchip_dapm_routes[] = {
+	/* Input Lines */
+	{"MIC", NULL, "Headset Mic"},
+	{"DMIC1L", NULL, "Int Mic"},
+	{"DMIC1R", NULL, "Int Mic"},
+
+	/* Output Lines */
+	{"Headphones", NULL, "HPL"},
+	{"Headphones", NULL, "HPR"},
+	{"Speakers", NULL, "Speaker"},
+};
+
+static const struct snd_kcontrol_new rockchip_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphones"),
+	SOC_DAPM_PIN_SWITCH("Speakers"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Int Mic"),
+};
+
+static int rockchip_sound_max98357a_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;
+
+	/* max98357a supports these sample rates */
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		mclk = params_rate(params) * SOUND_FS;
+		break;
+	default:
+		dev_err(rtd->card->dev, "%s() doesn't support this sample rate: %d\n",
+				__func__, params_rate(params));
+		return -EINVAL;
+	}
+
+	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;
+	}
+
+	return 0;
+}
+
+static int rockchip_sound_rt5514_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;
+	unsigned int mclk;
+	int ret;
+
+	mclk = params_rate(params) * SOUND_FS;
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+				     SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,
+				     mclk, SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
+				__func__, params_rate(params) * 512, ret);
+		return ret;
+	}
+
+	/* Wait for DMIC stable */
+	msleep(rt5514_dmic_delay);
+
+	return 0;
+}
+
+static int rockchip_sound_da7219_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;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec_dais[0]->codec;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret;
+
+	/* We need default MCLK and PLL settings for the accessory detection */
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 12288000,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Init can't set codec clock in %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Init can't set pll sysclk mclk %d\n", ret);
+		return ret;
+	}
+
+	/* Enable Headset and 4 Buttons Jack detection */
+	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+				    SND_JACK_HEADSET | SND_JACK_LINEOUT |
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
+				    &rockchip_sound_jack, NULL, 0);
+
+	if (ret) {
+		dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);
+		return ret;
+	}
+
+	snd_jack_set_key(rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_MEDIA);
+	snd_jack_set_key(
+		rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+	snd_jack_set_key(
+		rockchip_sound_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+	snd_jack_set_key(
+		rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+
+	da7219_aad_jack_det(codec, &rockchip_sound_jack);
+
+	return 0;
+}
+
+static struct snd_soc_ops rockchip_sound_max98357a_ops = {
+	.hw_params = rockchip_sound_max98357a_hw_params,
+};
+
+static struct snd_soc_ops rockchip_sound_rt5514_ops = {
+	.hw_params = rockchip_sound_rt5514_hw_params,
+};
+
+static struct snd_soc_ops rockchip_sound_da7219_ops = {
+	.hw_params = rockchip_sound_da7219_hw_params,
+};
+
+enum {
+	DAILINK_MAX98357A,
+	DAILINK_RT5514,
+	DAILINK_DA7219,
+	DAILINK_RT5514_DSP,
+};
+
+#define DAILINK_ENTITIES	(DAILINK_DA7219 + 1)
+
+static struct snd_soc_dai_link rockchip_dailinks[] = {
+	[DAILINK_MAX98357A] = {
+		.name = "MAX98357A",
+		.stream_name = "MAX98357A PCM",
+		.codec_dai_name = "HiFi",
+		.ops = &rockchip_sound_max98357a_ops,
+		/* set max98357a as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+	[DAILINK_RT5514] = {
+		.name = "RT5514",
+		.stream_name = "RT5514 PCM",
+		.codec_dai_name = "rt5514-aif1",
+		.ops = &rockchip_sound_rt5514_ops,
+		/* set rt5514 as slave */
+		.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",
+	},
+};
+
+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)
+{
+	return 1;
+}
+
+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 < 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);
+			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;
+	}
+
+	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;
+	}
+
+	/* Set DMIC delay */
+	ret = device_property_read_u32(&pdev->dev, "dmic-delay",
+					&rt5514_dmic_delay);
+	if (ret) {
+		rt5514_dmic_delay = 0;
+		dev_dbg(&pdev->dev,
+			"no optional property 'dmic-delay' 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;
+}
+
+static const struct of_device_id rockchip_sound_of_match[] = {
+	{ .compatible = "rockchip,rk3399-gru-sound", },
+	{},
+};
+
+static struct platform_driver rockchip_sound_driver = {
+	.probe = rockchip_sound_probe,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = rockchip_sound_of_match,
+#ifdef CONFIG_PM
+		.pm = &snd_soc_pm_ops,
+#endif
+	},
+};
+
+module_platform_driver(rockchip_sound_driver);
+
+MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 652e8c5ea166..974915cb4c4f 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -57,6 +57,7 @@ static int i2s_runtime_suspend(struct device *dev)
 {
 	struct rk_i2s_dev *i2s = dev_get_drvdata(dev);
 
+	regcache_cache_only(i2s->regmap, true);
 	clk_disable_unprepare(i2s->mclk);
 
 	return 0;
@@ -73,7 +74,14 @@ static int i2s_runtime_resume(struct device *dev)
 		return ret;
 	}
 
-	return 0;
+	regcache_cache_only(i2s->regmap, false);
+	regcache_mark_dirty(i2s->regmap);
+
+	ret = regcache_sync(i2s->regmap);
+	if (ret)
+		clk_disable_unprepare(i2s->mclk);
+
+	return ret;
 }
 
 static inline struct rk_i2s_dev *to_info(struct snd_soc_dai *dai)
diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index 4ca265737eda..fa8101d1e16f 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -65,6 +65,7 @@ static int __maybe_unused rk_spdif_runtime_suspend(struct device *dev)
 {
 	struct rk_spdif_dev *spdif = dev_get_drvdata(dev);
 
+	regcache_cache_only(spdif->regmap, true);
 	clk_disable_unprepare(spdif->mclk);
 	clk_disable_unprepare(spdif->hclk);
 
@@ -88,7 +89,16 @@ static int __maybe_unused rk_spdif_runtime_resume(struct device *dev)
 		return ret;
 	}
 
-	return 0;
+	regcache_cache_only(spdif->regmap, false);
+	regcache_mark_dirty(spdif->regmap);
+
+	ret = regcache_sync(spdif->regmap);
+	if (ret) {
+		clk_disable_unprepare(spdif->mclk);
+		clk_disable_unprepare(spdif->hclk);
+	}
+
+	return ret;
 }
 
 static int rk_spdif_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 7b722b0094d9..f6023b46c107 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,12 +1,14 @@
-config SND_SOC_SAMSUNG
+menuconfig SND_SOC_SAMSUNG
 	tristate "ASoC support for Samsung"
 	depends on (PLAT_SAMSUNG || ARCH_EXYNOS)
 	select SND_SOC_GENERIC_DMAENGINE_PCM
-	help
+	---help---
 	  Say Y or M if you want to add support for codecs attached to
 	  the Samsung SoCs' Audio interfaces. You will also need to
 	  select the audio interfaces to support below.
 
+if SND_SOC_SAMSUNG
+
 config SND_S3C24XX_I2S
 	tristate
 
@@ -18,22 +20,22 @@ config SND_S3C2412_SOC_I2S
 	select SND_S3C_I2SV2_SOC
 
 config SND_SAMSUNG_PCM
-	tristate
+	tristate "Samsung PCM interface support"
 
 config SND_SAMSUNG_AC97
 	tristate
 	select SND_SOC_AC97_BUS
 
 config SND_SAMSUNG_SPDIF
-	tristate
+	tristate "Samsung SPDIF transmitter support"
 	select SND_SOC_SPDIF
 
 config SND_SAMSUNG_I2S
-	tristate
+	tristate "Samsung I2S interface support"
 
 config SND_SOC_SAMSUNG_NEO1973_WM8753
 	tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)"
-	depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02
+	depends on MACH_NEO1973_GTA02
 	select SND_S3C24XX_I2S
 	select SND_SOC_WM8753
 	select SND_SOC_BT_SCO
@@ -43,7 +45,7 @@ config SND_SOC_SAMSUNG_NEO1973_WM8753
 
 config SND_SOC_SAMSUNG_JIVE_WM8750
 	tristate "SoC I2S Audio support for Jive"
-	depends on SND_SOC_SAMSUNG && MACH_JIVE && I2C
+	depends on MACH_JIVE && I2C
 	select SND_SOC_WM8750
 	select SND_S3C2412_SOC_I2S
 	help
@@ -51,7 +53,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
 
 config SND_SOC_SAMSUNG_SMDK_WM8580
 	tristate "SoC I2S Audio support for WM8580 on SMDK"
-	depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
+	depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110
 	depends on I2C
 	select SND_SOC_WM8580
 	select SND_SAMSUNG_I2S
@@ -60,7 +62,6 @@ config SND_SOC_SAMSUNG_SMDK_WM8580
 
 config SND_SOC_SAMSUNG_SMDK_WM8994
 	tristate "SoC I2S Audio support for WM8994 on SMDK"
-	depends on SND_SOC_SAMSUNG
 	depends on I2C=y
 	select MFD_WM8994
 	select SND_SOC_WM8994
@@ -70,7 +71,7 @@ config SND_SOC_SAMSUNG_SMDK_WM8994
 
 config SND_SOC_SAMSUNG_SMDK2443_WM9710
 	tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
-	depends on SND_SOC_SAMSUNG && MACH_SMDK2443
+	depends on MACH_SMDK2443
 	select AC97_BUS
 	select SND_SOC_AC97_CODEC
 	select SND_SAMSUNG_AC97
@@ -80,7 +81,7 @@ config SND_SOC_SAMSUNG_SMDK2443_WM9710
 
 config SND_SOC_SAMSUNG_LN2440SBC_ALC650
 	tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
-	depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
+	depends on ARCH_S3C24XX
 	select AC97_BUS
 	select SND_SOC_AC97_CODEC
 	select SND_SAMSUNG_AC97
@@ -90,7 +91,7 @@ config SND_SOC_SAMSUNG_LN2440SBC_ALC650
 
 config SND_SOC_SAMSUNG_S3C24XX_UDA134X
 	tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
-	depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
+	depends on ARCH_S3C24XX
 	select SND_S3C24XX_I2S
 	select SND_SOC_L3
 	select SND_SOC_UDA134X
@@ -102,21 +103,21 @@ config SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
 	tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
-	depends on SND_SOC_SAMSUNG && ARCH_S3C24XX && I2C
+	depends on ARCH_S3C24XX && I2C
 	select SND_S3C24XX_I2S
 	select SND_SOC_TLV320AIC23_I2C
 	select SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_SIMTEC_HERMES
 	tristate "SoC I2S Audio support for Simtec Hermes board"
-	depends on SND_SOC_SAMSUNG && ARCH_S3C24XX && I2C
+	depends on ARCH_S3C24XX && I2C
 	select SND_S3C24XX_I2S
 	select SND_SOC_TLV320AIC3X
 	select SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_H1940_UDA1380
 	tristate "Audio support for the HP iPAQ H1940"
-	depends on SND_SOC_SAMSUNG && ARCH_H1940 && I2C
+	depends on ARCH_H1940 && I2C
 	select SND_S3C24XX_I2S
 	select SND_SOC_UDA1380
 	help
@@ -124,7 +125,7 @@ config SND_SOC_SAMSUNG_H1940_UDA1380
 
 config SND_SOC_SAMSUNG_RX1950_UDA1380
 	tristate "Audio support for the HP iPAQ RX1950"
-	depends on SND_SOC_SAMSUNG && MACH_RX1950 && I2C
+	depends on MACH_RX1950 && I2C
 	select SND_S3C24XX_I2S
 	select SND_SOC_UDA1380
 	help
@@ -132,7 +133,7 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380
 
 config SND_SOC_SAMSUNG_SMDK_WM9713
 	tristate "SoC AC97 Audio support for SMDK with WM9713"
-	depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
+	depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110
 	select SND_SOC_WM9713
 	select SND_SAMSUNG_AC97
 	help
@@ -140,20 +141,19 @@ config SND_SOC_SAMSUNG_SMDK_WM9713
 
 config SND_SOC_SMARTQ
 	tristate "SoC I2S Audio support for SmartQ board"
-	depends on SND_SOC_SAMSUNG && MACH_SMARTQ && I2C
+	depends on MACH_SMARTQ && I2C
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM8750
 
 config SND_SOC_SAMSUNG_SMDK_SPDIF
 	tristate "SoC S/PDIF Audio support for SMDK"
-	depends on SND_SOC_SAMSUNG
 	select SND_SAMSUNG_SPDIF
 	help
 	  Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
 
 config SND_SOC_SMDK_WM8580_PCM
 	tristate "SoC PCM Audio support for WM8580 on SMDK"
-	depends on SND_SOC_SAMSUNG && (MACH_SMDKV210 || MACH_SMDKC110)
+	depends on MACH_SMDKV210 || MACH_SMDKC110
 	depends on I2C
 	select SND_SOC_WM8580
 	select SND_SAMSUNG_PCM
@@ -162,7 +162,6 @@ config SND_SOC_SMDK_WM8580_PCM
 
 config SND_SOC_SMDK_WM8994_PCM
 	tristate "SoC PCM Audio support for WM8994 on SMDK"
-	depends on SND_SOC_SAMSUNG
 	depends on I2C=y
 	select MFD_WM8994
 	select SND_SOC_WM8994
@@ -172,7 +171,7 @@ config SND_SOC_SMDK_WM8994_PCM
 
 config SND_SOC_SPEYSIDE
 	tristate "Audio support for Wolfson Speyside"
-	depends on SND_SOC_SAMSUNG && I2C && SPI_MASTER
+	depends on I2C && SPI_MASTER
 	depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM8996
@@ -182,14 +181,14 @@ config SND_SOC_SPEYSIDE
 
 config SND_SOC_TOBERMORY
 	tristate "Audio support for Wolfson Tobermory"
-	depends on SND_SOC_SAMSUNG && INPUT && I2C
+	depends on INPUT && I2C
 	depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM8962
 
 config SND_SOC_BELLS
 	tristate "Audio support for Wolfson Bells"
-	depends on SND_SOC_SAMSUNG && MFD_ARIZONA && I2C && SPI_MASTER
+	depends on MFD_ARIZONA && I2C && SPI_MASTER
 	depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM5102
@@ -200,7 +199,7 @@ config SND_SOC_BELLS
 
 config SND_SOC_LOWLAND
 	tristate "Audio support for Wolfson Lowland"
-	depends on SND_SOC_SAMSUNG && I2C
+	depends on I2C
 	depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM5100
@@ -208,7 +207,7 @@ config SND_SOC_LOWLAND
 
 config SND_SOC_LITTLEMILL
 	tristate "Audio support for Wolfson Littlemill"
-	depends on SND_SOC_SAMSUNG && I2C
+	depends on I2C
 	depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
 	select SND_SAMSUNG_I2S
 	select MFD_WM8994
@@ -216,7 +215,7 @@ config SND_SOC_LITTLEMILL
 
 config SND_SOC_SNOW
 	tristate "Audio support for Google Snow boards"
-	depends on SND_SOC_SAMSUNG && I2C
+	depends on I2C
 	select SND_SOC_MAX98090
 	select SND_SOC_MAX98095
 	select SND_SAMSUNG_I2S
@@ -226,6 +225,8 @@ config SND_SOC_SNOW
 
 config SND_SOC_ARNDALE_RT5631_ALC5631
         tristate "Audio support for RT5631(ALC5631) on Arndale Board"
-        depends on SND_SOC_SAMSUNG && I2C
+        depends on I2C
         select SND_SAMSUNG_I2S
         select SND_SOC_RT5631
+
+endif #SND_SOC_SAMSUNG
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index 547d31032088..97d6700b1009 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -38,16 +38,16 @@ struct s3c_ac97_info {
 };
 static struct s3c_ac97_info s3c_ac97;
 
-static struct s3c_dma_params s3c_ac97_pcm_out = {
-	.dma_size	= 4,
+static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_out = {
+	.addr_width	= 4,
 };
 
-static struct s3c_dma_params s3c_ac97_pcm_in = {
-	.dma_size	= 4,
+static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_in = {
+	.addr_width	= 4,
 };
 
-static struct s3c_dma_params s3c_ac97_mic_in = {
-	.dma_size	= 4,
+static struct snd_dmaengine_dai_dma_data s3c_ac97_mic_in = {
+	.addr_width	= 4,
 };
 
 static void s3c_ac97_activate(struct snd_ac97 *ac97)
@@ -74,7 +74,7 @@ static void s3c_ac97_activate(struct snd_ac97 *ac97)
 	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
 	if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
-		pr_err("AC97: Unable to activate!");
+		pr_err("AC97: Unable to activate!\n");
 }
 
 static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
@@ -100,7 +100,7 @@ static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
 	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
 	if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
-		pr_err("AC97: Unable to read!");
+		pr_err("AC97: Unable to read!\n");
 
 	stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
 	addr = (stat >> 16) & 0x7f;
@@ -137,7 +137,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
 	if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
-		pr_err("AC97: Unable to write!");
+		pr_err("AC97: Unable to write!\n");
 
 	ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
 	ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
@@ -273,14 +273,14 @@ static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
 
 static int s3c_ac97_dai_probe(struct snd_soc_dai *dai)
 {
-	samsung_asoc_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in);
+	snd_soc_dai_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in);
 
 	return 0;
 }
 
 static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai)
 {
-	samsung_asoc_init_dma_data(dai, NULL, &s3c_ac97_mic_in);
+	snd_soc_dai_init_dma_data(dai, NULL, &s3c_ac97_mic_in);
 
 	return 0;
 }
@@ -346,12 +346,12 @@ static int s3c_ac97_probe(struct platform_device *pdev)
 	if (IS_ERR(s3c_ac97.regs))
 		return PTR_ERR(s3c_ac97.regs);
 
-	s3c_ac97_pcm_out.slave = ac97_pdata->dma_playback;
-	s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
-	s3c_ac97_pcm_in.slave = ac97_pdata->dma_capture;
-	s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
-	s3c_ac97_mic_in.slave = ac97_pdata->dma_capture_mic;
-	s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
+	s3c_ac97_pcm_out.filter_data = ac97_pdata->dma_playback;
+	s3c_ac97_pcm_out.addr = mem_res->start + S3C_AC97_PCM_DATA;
+	s3c_ac97_pcm_in.filter_data = ac97_pdata->dma_capture;
+	s3c_ac97_pcm_in.addr = mem_res->start + S3C_AC97_PCM_DATA;
+	s3c_ac97_mic_in.filter_data = ac97_pdata->dma_capture_mic;
+	s3c_ac97_mic_in.addr = mem_res->start + S3C_AC97_MIC_DATA;
 
 	init_completion(&s3c_ac97.done);
 	mutex_init(&s3c_ac97.lock);
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h
index 3830f297e0b6..7ae580d677c8 100644
--- a/sound/soc/samsung/dma.h
+++ b/sound/soc/samsung/dma.h
@@ -1,6 +1,4 @@
 /*
- *  dma.h --
- *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
  *  Free Software Foundation;  either version 2 of the  License, or (at your
@@ -9,27 +7,15 @@
  *  ALSA PCM interface for the Samsung SoC
  */
 
-#ifndef _S3C_AUDIO_H
-#define _S3C_AUDIO_H
+#ifndef _SAMSUNG_DMA_H
+#define _SAMSUNG_DMA_H
 
 #include <sound/dmaengine_pcm.h>
-#include <linux/dmaengine.h>
-
-struct s3c_dma_params {
-	void *slave;				/* Channel ID */
-	dma_addr_t dma_addr;
-	int dma_size;			/* Size of the DMA transfer */
-	char *ch_name;
-	struct snd_dmaengine_dai_dma_data dma_data;
-};
 
-void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
-				struct s3c_dma_params *playback,
-				struct s3c_dma_params *capture);
 /*
  * @tx, @rx arguments can be NULL if the DMA channel names are "tx", "rx",
  * otherwise actual DMA channel names must be passed to this function.
  */
 int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter,
 				       const char *tx, const char *rx);
-#endif
+#endif /* _SAMSUNG_DMA_H */
diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c
index 2c87f380bfc4..9104c98deeb7 100644
--- a/sound/soc/samsung/dmaengine.c
+++ b/sound/soc/samsung/dmaengine.c
@@ -16,49 +16,18 @@
  */
 
 #include <linux/module.h>
-#include <linux/amba/pl08x.h>
-#include <linux/platform_data/dma-s3c24xx.h>
-
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/dmaengine_pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dai.h>
 
 #include "dma.h"
 
-void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
-				struct s3c_dma_params *playback,
-				struct s3c_dma_params *capture)
-{
-	struct snd_dmaengine_dai_dma_data *playback_data = NULL;
-	struct snd_dmaengine_dai_dma_data *capture_data = NULL;
-
-	if (playback) {
-		playback_data = &playback->dma_data;
-		playback_data->filter_data = playback->slave;
-		playback_data->chan_name = playback->ch_name;
-		playback_data->addr = playback->dma_addr;
-		playback_data->addr_width = playback->dma_size;
-	}
-	if (capture) {
-		capture_data = &capture->dma_data;
-		capture_data->filter_data = capture->slave;
-		capture_data->chan_name = capture->ch_name;
-		capture_data->addr = capture->dma_addr;
-		capture_data->addr_width = capture->dma_size;
-	}
-
-	snd_soc_dai_init_dma_data(dai, playback_data, capture_data);
-}
-EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
-
 int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter,
 				       const char *tx, const char *rx)
 {
 	unsigned int flags = SND_DMAENGINE_PCM_FLAG_COMPAT;
-
 	struct snd_dmaengine_pcm_config *pcm_conf;
 
 	pcm_conf = devm_kzalloc(dev, sizeof(*pcm_conf), GFP_KERNEL);
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 50635ee8ff20..7e32cf4581f8 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -87,9 +87,9 @@ struct i2s_dai {
 	/* Driver for this DAI */
 	struct snd_soc_dai_driver i2s_dai_drv;
 	/* DMA parameters */
-	struct s3c_dma_params dma_playback;
-	struct s3c_dma_params dma_capture;
-	struct s3c_dma_params idma_playback;
+	struct snd_dmaengine_dai_dma_data dma_playback;
+	struct snd_dmaengine_dai_dma_data dma_capture;
+	struct snd_dmaengine_dai_dma_data idma_playback;
 	dma_filter_fn filter;
 	u32	quirks;
 	u32	suspend_i2smod;
@@ -692,15 +692,15 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
 		break;
 	case 2:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			i2s->dma_playback.dma_size = 4;
+			i2s->dma_playback.addr_width = 4;
 		else
-			i2s->dma_capture.dma_size = 4;
+			i2s->dma_capture.addr_width = 4;
 		break;
 	case 1:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			i2s->dma_playback.dma_size = 2;
+			i2s->dma_playback.addr_width = 2;
 		else
-			i2s->dma_capture.dma_size = 2;
+			i2s->dma_capture.addr_width = 2;
 
 		break;
 	default:
@@ -754,7 +754,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
 	writel(mod, i2s->addr + I2SMOD);
 	spin_unlock_irqrestore(i2s->lock, flags);
 
-	samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
+	snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
 
 	i2s->frmclk = params_rate(params);
 
@@ -991,10 +991,10 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
 	unsigned long flags;
 
 	if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */
-		samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback,
+		snd_soc_dai_init_dma_data(dai, &other->sec_dai->dma_playback,
 					   NULL);
 	} else {
-		samsung_asoc_init_dma_data(dai, &i2s->dma_playback,
+		snd_soc_dai_init_dma_data(dai, &i2s->dma_playback,
 					   &i2s->dma_capture);
 
 		if (i2s->quirks & QUIRK_NEED_RSTCLR)
@@ -1002,7 +1002,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
 
 		if (i2s->quirks & QUIRK_SUPPORTS_IDMA)
 			idma_reg_addr_init(i2s->addr,
-					i2s->sec_dai->idma_playback.dma_addr);
+					i2s->sec_dai->idma_playback.addr);
 	}
 
 	/* Reset any constraint on RFS and BFS */
@@ -1262,8 +1262,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 			return -EINVAL;
 		}
 
-		pri_dai->dma_playback.slave = i2s_pdata->dma_playback;
-		pri_dai->dma_capture.slave = i2s_pdata->dma_capture;
+		pri_dai->dma_playback.filter_data = i2s_pdata->dma_playback;
+		pri_dai->dma_capture.filter_data = i2s_pdata->dma_capture;
 		pri_dai->filter = i2s_pdata->dma_filter;
 
 		if (&i2s_pdata->type)
@@ -1302,12 +1302,12 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
 		return ret;
 	}
-	pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
-	pri_dai->dma_capture.dma_addr = regs_base + I2SRXD;
-	pri_dai->dma_playback.ch_name = "tx";
-	pri_dai->dma_capture.ch_name = "rx";
-	pri_dai->dma_playback.dma_size = 4;
-	pri_dai->dma_capture.dma_size = 4;
+	pri_dai->dma_playback.addr = regs_base + I2STXD;
+	pri_dai->dma_capture.addr = regs_base + I2SRXD;
+	pri_dai->dma_playback.chan_name = "tx";
+	pri_dai->dma_capture.chan_name = "rx";
+	pri_dai->dma_playback.addr_width = 4;
+	pri_dai->dma_capture.addr_width = 4;
 	pri_dai->quirks = quirks;
 	pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs;
 
@@ -1318,31 +1318,33 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 		sec_dai = i2s_alloc_dai(pdev, true);
 		if (!sec_dai) {
 			dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto err_disable_clk;
 		}
 
 		sec_dai->lock = &pri_dai->spinlock;
 		sec_dai->variant_regs = pri_dai->variant_regs;
-		sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
-		sec_dai->dma_playback.ch_name = "tx-sec";
+		sec_dai->dma_playback.addr = regs_base + I2STXDS;
+		sec_dai->dma_playback.chan_name = "tx-sec";
 
 		if (!np) {
-			sec_dai->dma_playback.slave = i2s_pdata->dma_play_sec;
+			sec_dai->dma_playback.filter_data = i2s_pdata->dma_play_sec;
 			sec_dai->filter = i2s_pdata->dma_filter;
 		}
 
-		sec_dai->dma_playback.dma_size = 4;
+		sec_dai->dma_playback.addr_width = 4;
 		sec_dai->addr = pri_dai->addr;
 		sec_dai->clk = pri_dai->clk;
 		sec_dai->quirks = quirks;
-		sec_dai->idma_playback.dma_addr = idma_addr;
+		sec_dai->idma_playback.addr = idma_addr;
 		sec_dai->pri_dai = pri_dai;
 		pri_dai->sec_dai = sec_dai;
 	}
 
 	if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
 		dev_err(&pdev->dev, "Unable to configure gpio\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_disable_clk;
 	}
 
 	ret = devm_snd_soc_register_component(&pri_dai->pdev->dev,
@@ -1366,6 +1368,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 err_free_dai:
 	if (sec_dai)
 		i2s_free_sec_dai(sec_dai);
+err_disable_clk:
+	clk_disable_unprepare(pri_dai->clk);
 	return ret;
 }
 
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index 4ed29ffc1c54..3e408158625d 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -22,7 +22,6 @@
 
 #include "i2s.h"
 #include "idma.h"
-#include "dma.h"
 #include "i2s-regs.h"
 
 #define ST_RUNNING		(1<<0)
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index 490c1a87fd66..43e367a9acc3 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -127,25 +127,25 @@ struct s3c_pcm_info {
 	struct clk	*pclk;
 	struct clk	*cclk;
 
-	struct s3c_dma_params	*dma_playback;
-	struct s3c_dma_params	*dma_capture;
+	struct snd_dmaengine_dai_dma_data *dma_playback;
+	struct snd_dmaengine_dai_dma_data *dma_capture;
 };
 
-static struct s3c_dma_params s3c_pcm_stereo_out[] = {
+static struct snd_dmaengine_dai_dma_data s3c_pcm_stereo_out[] = {
 	[0] = {
-		.dma_size	= 4,
+		.addr_width	= 4,
 	},
 	[1] = {
-		.dma_size	= 4,
+		.addr_width	= 4,
 	},
 };
 
-static struct s3c_dma_params s3c_pcm_stereo_in[] = {
+static struct snd_dmaengine_dai_dma_data s3c_pcm_stereo_in[] = {
 	[0] = {
-		.dma_size	= 4,
+		.addr_width	= 4,
 	},
 	[1] = {
-		.dma_size	= 4,
+		.addr_width	= 4,
 	},
 };
 
@@ -552,15 +552,13 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
 	}
 	clk_prepare_enable(pcm->pclk);
 
-	s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
-							+ S3C_PCM_RXFIFO;
-	s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
-							+ S3C_PCM_TXFIFO;
+	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;
 
 	filter = NULL;
 	if (pcm_pdata) {
-		s3c_pcm_stereo_in[pdev->id].slave = pcm_pdata->dma_capture;
-		s3c_pcm_stereo_out[pdev->id].slave = pcm_pdata->dma_playback;
+		s3c_pcm_stereo_in[pdev->id].filter_data = pcm_pdata->dma_capture;
+		s3c_pcm_stereo_out[pdev->id].filter_data = pcm_pdata->dma_playback;
 		filter = pcm_pdata->dma_filter;
 	}
 
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
index bf8ae79b0fd2..644f186fd35c 100644
--- a/sound/soc/samsung/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -24,7 +24,6 @@
 
 #include "regs-i2s-v2.h"
 #include "s3c-i2s-v2.h"
-#include "dma.h"
 
 #undef S3C_IIS_V2_SUPPORTED
 
@@ -302,7 +301,7 @@ static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct s3c_i2sv2_info *i2s = to_info(dai);
-	struct s3c_dma_params *dma_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
 	u32 iismod;
 
 	pr_debug("Entered %s\n", __func__);
diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h
index d0684145ed1f..182d80564e37 100644
--- a/sound/soc/samsung/s3c-i2s-v2.h
+++ b/sound/soc/samsung/s3c-i2s-v2.h
@@ -60,8 +60,8 @@ struct s3c_i2sv2_info {
 
 	unsigned char	 master;
 
-	struct s3c_dma_params	*dma_playback;
-	struct s3c_dma_params	*dma_capture;
+	struct snd_dmaengine_dai_dma_data *dma_playback;
+	struct snd_dmaengine_dai_dma_data *dma_capture;
 
 	u32		 suspend_iismod;
 	u32		 suspend_iiscon;
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index d45dffb297d8..3e89fbc0c51d 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -34,14 +34,14 @@
 
 #include <linux/platform_data/asoc-s3c.h>
 
-static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = {
-	.ch_name	= "tx",
-	.dma_size	= 4,
+static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_out = {
+	.chan_name	= "tx",
+	.addr_width	= 4,
 };
 
-static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
-	.ch_name	= "rx",
-	.dma_size	= 4,
+static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_in = {
+	.chan_name	= "rx",
+	.addr_width	= 4,
 };
 
 static struct s3c_i2sv2_info s3c2412_i2s;
@@ -52,8 +52,8 @@ static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
 
 	pr_debug("Entered %s\n", __func__);
 
-	samsung_asoc_init_dma_data(dai, &s3c2412_i2s_pcm_stereo_out,
-		&s3c2412_i2s_pcm_stereo_in);
+	snd_soc_dai_init_dma_data(dai, &s3c2412_i2s_pcm_stereo_out,
+					&s3c2412_i2s_pcm_stereo_in);
 
 	ret = s3c_i2sv2_probe(dai, &s3c2412_i2s, S3C2410_PA_IIS);
 	if (ret)
@@ -163,10 +163,10 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
 	if (IS_ERR(s3c2412_i2s.regs))
 		return PTR_ERR(s3c2412_i2s.regs);
 
-	s3c2412_i2s_pcm_stereo_out.dma_addr = res->start + S3C2412_IISTXD;
-	s3c2412_i2s_pcm_stereo_out.slave = pdata->dma_playback;
-	s3c2412_i2s_pcm_stereo_in.dma_addr = res->start + S3C2412_IISRXD;
-	s3c2412_i2s_pcm_stereo_in.slave = pdata->dma_capture;
+	s3c2412_i2s_pcm_stereo_out.addr = res->start + S3C2412_IISTXD;
+	s3c2412_i2s_pcm_stereo_out.filter_data = pdata->dma_playback;
+	s3c2412_i2s_pcm_stereo_in.addr = res->start + S3C2412_IISRXD;
+	s3c2412_i2s_pcm_stereo_in.filter_data = pdata->dma_capture;
 
 	ret = s3c_i2sv2_register_component(&pdev->dev, -1,
 					   &s3c2412_i2s_component,
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 3e76f2a75a24..c78a936a3099 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -32,14 +32,14 @@
 
 #include <linux/platform_data/asoc-s3c.h>
 
-static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = {
-	.ch_name	= "tx",
-	.dma_size	= 2,
+static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = {
+	.chan_name	= "tx",
+	.addr_width	= 2,
 };
 
-static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = {
-	.ch_name	= "rx",
-	.dma_size	= 2,
+static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_in = {
+	.chan_name	= "rx",
+	.addr_width	= 2,
 };
 
 struct s3c24xx_i2s_info {
@@ -360,8 +360,8 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
 {
 	pr_debug("Entered %s\n", __func__);
 
-	samsung_asoc_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out,
-		&s3c24xx_i2s_pcm_stereo_in);
+	snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out,
+					&s3c24xx_i2s_pcm_stereo_in);
 
 	s3c24xx_i2s.iis_clk = devm_clk_get(dai->dev, "iis");
 	if (IS_ERR(s3c24xx_i2s.iis_clk)) {
@@ -469,10 +469,10 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
 	if (IS_ERR(s3c24xx_i2s.regs))
 		return PTR_ERR(s3c24xx_i2s.regs);
 
-	s3c24xx_i2s_pcm_stereo_out.dma_addr = res->start + S3C2410_IISFIFO;
-	s3c24xx_i2s_pcm_stereo_out.slave = pdata->dma_playback;
-	s3c24xx_i2s_pcm_stereo_in.dma_addr = res->start + S3C2410_IISFIFO;
-	s3c24xx_i2s_pcm_stereo_in.slave = pdata->dma_capture;
+	s3c24xx_i2s_pcm_stereo_out.addr = res->start + S3C2410_IISFIFO;
+	s3c24xx_i2s_pcm_stereo_out.filter_data = pdata->dma_playback;
+	s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO;
+	s3c24xx_i2s_pcm_stereo_in.filter_data = pdata->dma_capture;
 
 	ret = devm_snd_soc_register_component(&pdev->dev,
 			&s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c
index 50849e137fc0..7853fbe6ccc9 100644
--- a/sound/soc/samsung/s3c24xx_uda134x.c
+++ b/sound/soc/samsung/s3c24xx_uda134x.c
@@ -54,28 +54,27 @@ static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
 };
 #endif
 
-static struct platform_device *s3c24xx_uda134x_snd_device;
-
 static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
 {
-	int ret = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 #ifdef ENFORCE_RATES
 	struct snd_pcm_runtime *runtime = substream->runtime;
 #endif
+	int ret = 0;
 
 	mutex_lock(&clk_lock);
-	pr_debug("%s %d\n", __func__, clk_users);
+
 	if (clk_users == 0) {
-		xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal");
+		xtal = clk_get(rtd->dev, "xtal");
 		if (IS_ERR(xtal)) {
-			printk(KERN_ERR "%s cannot get xtal\n", __func__);
+			dev_err(rtd->dev, "%s cannot get xtal\n", __func__);
 			ret = PTR_ERR(xtal);
 		} else {
-			pclk = clk_get(&s3c24xx_uda134x_snd_device->dev,
-				       "pclk");
+			pclk = clk_get(cpu_dai->dev, "iis");
 			if (IS_ERR(pclk)) {
-				printk(KERN_ERR "%s cannot get pclk\n",
-				       __func__);
+				dev_err(rtd->dev, "%s cannot get pclk\n",
+					__func__);
 				clk_put(xtal);
 				ret = PTR_ERR(pclk);
 			}
@@ -101,8 +100,8 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
 						 SNDRV_PCM_HW_PARAM_RATE,
 						 &hw_constraints_rates);
 		if (ret < 0)
-			printk(KERN_ERR "%s cannot set constraints\n",
-			       __func__);
+			dev_err(rtd->dev, "%s cannot set constraints\n",
+				__func__);
 #endif
 	}
 	return ret;
@@ -111,7 +110,6 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
 static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
 {
 	mutex_lock(&clk_lock);
-	pr_debug("%s %d\n", __func__, clk_users);
 	clk_users -= 1;
 	if (clk_users == 0) {
 		clk_put(xtal);
@@ -158,18 +156,19 @@ static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
 		clk_source = S3C24XX_CLKSRC_PCLK;
 		div = bi % 33;
 	}
-	pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi);
+
+	dev_dbg(rtd->dev, "%s desired rate %lu, %d\n", __func__, rate, bi);
 
 	clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
-	pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__,
-		 fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
-		 clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
-		 div, clk, err);
+
+	dev_dbg(rtd->dev, "%s will use: %s %s %d sysclk %d err %ld\n", __func__,
+		fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
+		clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
+		div, clk, err);
 
 	if ((err * 100 / rate) > 5) {
-		printk(KERN_ERR "S3C24XX_UDA134X: effective frequency "
-		       "too different from desired (%ld%%)\n",
-		       err * 100 / rate);
+		dev_err(rtd->dev, "effective frequency too different "
+				  "from desired (%ld%%)\n", err * 100 / rate);
 		return -EINVAL;
 	}
 
@@ -226,115 +225,27 @@ static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
 	.num_links = 1,
 };
 
-static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins;
-
-static void setdat(int v)
-{
-	gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0);
-}
-
-static void setclk(int v)
-{
-	gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0);
-}
-
-static void setmode(int v)
-{
-	gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
-}
-
-/* FIXME - This must be codec platform data but in which board file ?? */
-static struct uda134x_platform_data s3c24xx_uda134x = {
-	.l3 = {
-		.setdat = setdat,
-		.setclk = setclk,
-		.setmode = setmode,
-		.data_hold = 1,
-		.data_setup = 1,
-		.clock_high = 1,
-		.mode_hold = 1,
-		.mode = 1,
-		.mode_setup = 1,
-	},
-};
-
-static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
-{
-	if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
-		printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
-		       "l3 %s pin already in use", fun);
-		return -EBUSY;
-	}
-	gpio_direction_output(pin, 0);
-	return 0;
-}
-
 static int s3c24xx_uda134x_probe(struct platform_device *pdev)
 {
+	struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x;
 	int ret;
 
-	printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n");
+	platform_set_drvdata(pdev, card);
+	card->dev = &pdev->dev;
 
-	s3c24xx_uda134x_l3_pins = pdev->dev.platform_data;
-	if (s3c24xx_uda134x_l3_pins == NULL) {
-		printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
-		       "unable to find platform data\n");
-		return -ENODEV;
-	}
-	s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power;
-	s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model;
-
-	if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data,
-				      "data") < 0)
-		return -EBUSY;
-	if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk,
-				      "clk") < 0) {
-		gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
-		return -EBUSY;
-	}
-	if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode,
-				      "mode") < 0) {
-		gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
-		gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
-		return -EBUSY;
-	}
-
-	s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!s3c24xx_uda134x_snd_device) {
-		printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
-		       "Unable to register\n");
-		return -ENOMEM;
-	}
-
-	platform_set_drvdata(s3c24xx_uda134x_snd_device,
-			     &snd_soc_s3c24xx_uda134x);
-	platform_device_add_data(s3c24xx_uda134x_snd_device, &s3c24xx_uda134x, sizeof(s3c24xx_uda134x));
-	ret = platform_device_add(s3c24xx_uda134x_snd_device);
-	if (ret) {
-		printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
-		platform_device_put(s3c24xx_uda134x_snd_device);
-	}
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "failed to register card: %d\n", ret);
 
 	return ret;
 }
 
-static int s3c24xx_uda134x_remove(struct platform_device *pdev)
-{
-	platform_device_unregister(s3c24xx_uda134x_snd_device);
-	gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
-	gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
-	gpio_free(s3c24xx_uda134x_l3_pins->l3_mode);
-	return 0;
-}
-
 static struct platform_driver s3c24xx_uda134x_driver = {
 	.probe  = s3c24xx_uda134x_probe,
-	.remove = s3c24xx_uda134x_remove,
 	.driver = {
 		.name = "s3c24xx_uda134x",
 	},
 };
-
 module_platform_driver(s3c24xx_uda134x_driver);
 
 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c
index 6deec5234c92..a6d223310c67 100644
--- a/sound/soc/samsung/smdk_wm8580pcm.c
+++ b/sound/soc/samsung/smdk_wm8580pcm.c
@@ -16,7 +16,6 @@
 #include <asm/mach-types.h>
 
 #include "../codecs/wm8580.h"
-#include "dma.h"
 #include "pcm.h"
 
 /*
diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c
index b1c89ec2d999..2e621496be8b 100644
--- a/sound/soc/samsung/smdk_wm8994pcm.c
+++ b/sound/soc/samsung/smdk_wm8994pcm.c
@@ -15,7 +15,6 @@
 #include <sound/pcm_params.h>
 
 #include "../codecs/wm8994.h"
-#include "dma.h"
 #include "pcm.h"
 
 /*
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 0cb9c8567546..26c1fbed4d35 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -90,10 +90,10 @@ struct samsung_spdif_info {
 	u32		saved_clkcon;
 	u32		saved_con;
 	u32		saved_cstas;
-	struct s3c_dma_params	*dma_playback;
+	struct snd_dmaengine_dai_dma_data *dma_playback;
 };
 
-static struct s3c_dma_params spdif_stereo_out;
+static struct snd_dmaengine_dai_dma_data spdif_stereo_out;
 static struct samsung_spdif_info spdif_info;
 
 static inline struct samsung_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
@@ -179,7 +179,7 @@ static int spdif_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
 	void __iomem *regs = spdif->regs;
-	struct s3c_dma_params *dma_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
 	u32 con, clkcon, cstas;
 	unsigned long flags;
 	int i, ratio;
@@ -425,11 +425,11 @@ static int spdif_probe(struct platform_device *pdev)
 		goto err4;
 	}
 
-	spdif_stereo_out.dma_size = 2;
-	spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
+	spdif_stereo_out.addr_width = 2;
+	spdif_stereo_out.addr = mem_res->start + DATA_OUTBUF;
 	filter = NULL;
 	if (spdif_pdata) {
-		spdif_stereo_out.slave = spdif_pdata->dma_playback;
+		spdif_stereo_out.filter_data = spdif_pdata->dma_playback;
 		filter = spdif_pdata->dma_filter;
 	}
 
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 9311f119feb5..6db6405d952f 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -42,12 +42,6 @@ config SND_SOC_RCAR
 	help
 	  This option enables R-Car SRU/SCU/SSIU/SSI sound support
 
-config SND_SOC_RSRC_CARD
-	tristate "Renesas Sampling Rate Convert Sound Card"
-	select SND_SIMPLE_CARD_UTILS
-	help
-	  This option enables simple sound if you need sampling rate convert
-
 ##
 ## Boards
 ##
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index a89ddf758695..9c3d5aed99d1 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,5 +1,2 @@
 snd-soc-rcar-objs	:= core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o
 obj-$(CONFIG_SND_SOC_RCAR)	+= snd-soc-rcar.o
-
-snd-soc-rsrc-card-objs	:= rsrc-card.o
-obj-$(CONFIG_SND_SOC_RSRC_CARD)	+= snd-soc-rsrc-card.o
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 3351a701c60e..f18141098b50 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -110,6 +110,7 @@ MODULE_DEVICE_TABLE(of, rsnd_of_match);
 /*
  *	rsnd_mod functions
  */
+#ifdef DEBUG
 void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
 {
 	if (mod->type != type) {
@@ -120,6 +121,7 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
 			 rsnd_mod_name(mod), rsnd_mod_id(mod));
 	}
 }
+#endif
 
 char *rsnd_mod_name(struct rsnd_mod *mod)
 {
@@ -574,6 +576,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
 		rsnd_dai_stream_init(io, substream);
 
 		ret = rsnd_dai_call(init, io, priv);
@@ -590,6 +593,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
 		ret = rsnd_dai_call(irq, io, priv, 0);
 
 		ret |= rsnd_dai_call(stop, io, priv);
diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c
deleted file mode 100644
index fa37f842b62f..000000000000
--- a/sound/soc/sh/rcar/rsrc-card.c
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * Renesas Sampling Rate Convert Sound Card for DPCM
- *
- * Copyright (C) 2015 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * based on ${LINUX}/sound/soc/generic/simple-card.c
- *
- * 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/clk.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/string.h>
-#include <sound/jack.h>
-#include <sound/soc.h>
-#include <sound/soc-dai.h>
-#include <sound/simple_card_utils.h>
-
-struct rsrc_card_of_data {
-	const char *prefix;
-	const struct snd_soc_dapm_route *routes;
-	int num_routes;
-};
-
-static const struct snd_soc_dapm_route routes_ssi0_ak4642[] = {
-	{"ak4642 Playback", NULL, "DAI0 Playback"},
-	{"DAI0 Capture", NULL, "ak4642 Capture"},
-};
-
-static const struct rsrc_card_of_data routes_of_ssi0_ak4642 = {
-	.prefix		= "ak4642",
-	.routes		= routes_ssi0_ak4642,
-	.num_routes	= ARRAY_SIZE(routes_ssi0_ak4642),
-};
-
-static const struct of_device_id rsrc_card_of_match[] = {
-	{ .compatible = "renesas,rsrc-card,lager",	.data = &routes_of_ssi0_ak4642 },
-	{ .compatible = "renesas,rsrc-card,koelsch",	.data = &routes_of_ssi0_ak4642 },
-	{ .compatible = "renesas,rsrc-card", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, rsrc_card_of_match);
-
-#define IDX_CPU		0
-#define IDX_CODEC	1
-struct rsrc_card_priv {
-	struct snd_soc_card snd_card;
-	struct snd_soc_codec_conf codec_conf;
-	struct asoc_simple_dai *dai_props;
-	struct snd_soc_dai_link *dai_link;
-	u32 convert_rate;
-	u32 convert_channels;
-};
-
-#define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev)
-#define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
-#define rsrc_priv_to_props(priv, i) ((priv)->dai_props + (i))
-
-static int rsrc_card_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct rsrc_card_priv *priv =	snd_soc_card_get_drvdata(rtd->card);
-	struct asoc_simple_dai *dai_props =
-		rsrc_priv_to_props(priv, rtd->num);
-
-	return clk_prepare_enable(dai_props->clk);
-}
-
-static void rsrc_card_shutdown(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct rsrc_card_priv *priv =	snd_soc_card_get_drvdata(rtd->card);
-	struct asoc_simple_dai *dai_props =
-		rsrc_priv_to_props(priv, rtd->num);
-
-	clk_disable_unprepare(dai_props->clk);
-}
-
-static struct snd_soc_ops rsrc_card_ops = {
-	.startup = rsrc_card_startup,
-	.shutdown = rsrc_card_shutdown,
-};
-
-static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
-	struct snd_soc_dai *dai;
-	struct snd_soc_dai_link *dai_link;
-	struct asoc_simple_dai *dai_props;
-	int num = rtd->num;
-	int ret;
-
-	dai_link	= rsrc_priv_to_link(priv, num);
-	dai_props	= rsrc_priv_to_props(priv, num);
-	dai		= dai_link->dynamic ?
-				rtd->cpu_dai :
-				rtd->codec_dai;
-
-	if (dai_props->sysclk) {
-		ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0);
-		if (ret && ret != -ENOTSUPP) {
-			dev_err(dai->dev, "set_sysclk error\n");
-			goto err;
-		}
-	}
-
-	if (dai_props->slots) {
-		ret = snd_soc_dai_set_tdm_slot(dai,
-					       dai_props->tx_slot_mask,
-					       dai_props->rx_slot_mask,
-					       dai_props->slots,
-					       dai_props->slot_width);
-		if (ret && ret != -ENOTSUPP) {
-			dev_err(dai->dev, "set_tdm_slot error\n");
-			goto err;
-		}
-	}
-
-	ret = 0;
-
-err:
-	return ret;
-}
-
-static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					struct snd_pcm_hw_params *params)
-{
-	struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
-	struct snd_interval *rate = hw_param_interval(params,
-						      SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-						SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	if (priv->convert_rate)
-		rate->min =
-		rate->max = priv->convert_rate;
-
-	if (priv->convert_channels)
-		channels->min =
-		channels->max = priv->convert_channels;
-
-	return 0;
-}
-
-static int rsrc_card_parse_links(struct device_node *np,
-				 struct rsrc_card_priv *priv,
-				 int idx, bool is_fe)
-{
-	struct device *dev = rsrc_priv_to_dev(priv);
-	struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
-	struct asoc_simple_dai *dai_props = rsrc_priv_to_props(priv, idx);
-	struct of_phandle_args args;
-	int ret;
-
-	/*
-	 * Get node via "sound-dai = <&phandle port>"
-	 * it will be used as xxx_of_node on soc_bind_dai_link()
-	 */
-	ret = of_parse_phandle_with_args(np, "sound-dai",
-					 "#sound-dai-cells", 0, &args);
-	if (ret)
-		return ret;
-
-	/* Parse TDM slot */
-	ret = snd_soc_of_parse_tdm_slot(np,
-					&dai_props->tx_slot_mask,
-					&dai_props->rx_slot_mask,
-					&dai_props->slots,
-					&dai_props->slot_width);
-	if (ret)
-		return ret;
-
-	if (is_fe) {
-		/* BE is dummy */
-		dai_link->codec_of_node		= NULL;
-		dai_link->codec_dai_name	= "snd-soc-dummy-dai";
-		dai_link->codec_name		= "snd-soc-dummy";
-
-		/* FE settings */
-		dai_link->dynamic		= 1;
-		dai_link->dpcm_merged_format	= 1;
-		dai_link->cpu_of_node		= args.np;
-		ret = snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name);
-		if (ret < 0)
-			return ret;
-
-		ret = asoc_simple_card_set_dailink_name(dev, dai_link,
-							"fe.%s",
-							dai_link->cpu_dai_name);
-		if (ret < 0)
-			return ret;
-
-		/*
-		 * In soc_bind_dai_link() will check cpu name after
-		 * of_node matching if dai_link has cpu_dai_name.
-		 * but, it will never match if name was created by
-		 * fmt_single_name() remove cpu_dai_name if cpu_args
-		 * was 0. See:
-		 *	fmt_single_name()
-		 *	fmt_multiple_name()
-		 */
-		if (!args.args_count)
-			dai_link->cpu_dai_name = NULL;
-	} else {
-		const struct rsrc_card_of_data *of_data;
-
-		of_data = of_device_get_match_data(dev);
-
-		/* FE is dummy */
-		dai_link->cpu_of_node		= NULL;
-		dai_link->cpu_dai_name		= "snd-soc-dummy-dai";
-		dai_link->cpu_name		= "snd-soc-dummy";
-
-		/* BE settings */
-		dai_link->no_pcm		= 1;
-		dai_link->be_hw_params_fixup	= rsrc_card_be_hw_params_fixup;
-		dai_link->codec_of_node		= args.np;
-		ret = snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
-		if (ret < 0)
-			return ret;
-
-		ret = asoc_simple_card_set_dailink_name(dev, dai_link,
-							"be.%s",
-							dai_link->codec_dai_name);
-		if (ret < 0)
-			return ret;
-
-		/* additional name prefix */
-		if (of_data) {
-			priv->codec_conf.of_node = dai_link->codec_of_node;
-			priv->codec_conf.name_prefix = of_data->prefix;
-		} else {
-			snd_soc_of_parse_audio_prefix(&priv->snd_card,
-						      &priv->codec_conf,
-						      dai_link->codec_of_node,
-						      "audio-prefix");
-		}
-	}
-
-	/* Simple Card assumes platform == cpu */
-	dai_link->platform_of_node	= dai_link->cpu_of_node;
-	dai_link->dpcm_playback		= 1;
-	dai_link->dpcm_capture		= 1;
-	dai_link->ops			= &rsrc_card_ops;
-	dai_link->init			= rsrc_card_dai_init;
-
-	return 0;
-}
-
-static int rsrc_card_parse_clk(struct device_node *np,
-			       struct rsrc_card_priv *priv,
-			       int idx, bool is_fe)
-{
-	struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
-	struct asoc_simple_dai *dai_props = rsrc_priv_to_props(priv, idx);
-	struct clk *clk;
-	struct device_node *of_np = is_fe ?	dai_link->cpu_of_node :
-						dai_link->codec_of_node;
-	u32 val;
-
-	/*
-	 * Parse dai->sysclk come from "clocks = <&xxx>"
-	 * (if system has common clock)
-	 *  or "system-clock-frequency = <xxx>"
-	 *  or device's module clock.
-	 */
-	if (of_property_read_bool(np, "clocks")) {
-		clk = of_clk_get(np, 0);
-		if (IS_ERR(clk))
-			return PTR_ERR(clk);
-
-		dai_props->sysclk = clk_get_rate(clk);
-		dai_props->clk = clk;
-	} else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
-		dai_props->sysclk = val;
-	} else {
-		clk = of_clk_get(of_np, 0);
-		if (!IS_ERR(clk))
-			dai_props->sysclk = clk_get_rate(clk);
-	}
-
-	return 0;
-}
-
-static int rsrc_card_dai_sub_link_of(struct device_node *node,
-				     struct device_node *np,
-				     struct rsrc_card_priv *priv,
-				     int idx, bool is_fe)
-{
-	struct device *dev = rsrc_priv_to_dev(priv);
-	struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
-	struct asoc_simple_dai *dai_props = rsrc_priv_to_props(priv, idx);
-	int ret;
-
-	ret = rsrc_card_parse_links(np, priv, idx, is_fe);
-	if (ret < 0)
-		return ret;
-
-	ret = rsrc_card_parse_clk(np, priv, idx, is_fe);
-	if (ret < 0)
-		return ret;
-
-	dev_dbg(dev, "\t%s / %04x / %d\n",
-		dai_link->name,
-		dai_link->dai_fmt,
-		dai_props->sysclk);
-
-	return ret;
-}
-
-static int rsrc_card_dai_link_of(struct device_node *node,
-				 struct rsrc_card_priv *priv)
-{
-	struct device *dev = rsrc_priv_to_dev(priv);
-	struct snd_soc_dai_link *dai_link;
-	struct device_node *np;
-	unsigned int daifmt = 0;
-	int ret, i;
-	bool is_fe;
-
-	/* find 1st codec */
-	i = 0;
-	for_each_child_of_node(node, np) {
-		dai_link = rsrc_priv_to_link(priv, i);
-
-		if (strcmp(np->name, "codec") == 0) {
-			ret = asoc_simple_card_parse_daifmt(dev, node, np,
-							    NULL, &daifmt);
-			if (ret < 0)
-				return ret;
-			break;
-		}
-		i++;
-	}
-
-	i = 0;
-	for_each_child_of_node(node, np) {
-		dai_link = rsrc_priv_to_link(priv, i);
-		dai_link->dai_fmt = daifmt;
-
-		is_fe = false;
-		if (strcmp(np->name, "cpu") == 0)
-			is_fe = true;
-
-		ret = rsrc_card_dai_sub_link_of(node, np, priv, i, is_fe);
-		if (ret < 0)
-			return ret;
-		i++;
-	}
-
-	return 0;
-}
-
-static int rsrc_card_parse_of(struct device_node *node,
-			      struct rsrc_card_priv *priv,
-			      struct device *dev)
-{
-	const struct rsrc_card_of_data *of_data = of_device_get_match_data(dev);
-	struct asoc_simple_dai *props;
-	struct snd_soc_dai_link *links;
-	int ret;
-	int num;
-
-	if (!node)
-		return -EINVAL;
-
-	num = of_get_child_count(node);
-	props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL);
-	links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL);
-	if (!props || !links)
-		return -ENOMEM;
-
-	priv->dai_props	= props;
-	priv->dai_link	= links;
-
-	/* Init snd_soc_card */
-	priv->snd_card.owner			= THIS_MODULE;
-	priv->snd_card.dev			= dev;
-	priv->snd_card.dai_link			= priv->dai_link;
-	priv->snd_card.num_links		= num;
-	priv->snd_card.codec_conf		= &priv->codec_conf;
-	priv->snd_card.num_configs		= 1;
-
-	if (of_data) {
-		priv->snd_card.of_dapm_routes		= of_data->routes;
-		priv->snd_card.num_of_dapm_routes	= of_data->num_routes;
-	} else {
-		snd_soc_of_parse_audio_routing(&priv->snd_card,
-					       "audio-routing");
-	}
-
-	/* sampling rate convert */
-	of_property_read_u32(node, "convert-rate", &priv->convert_rate);
-
-	/* channels transfer */
-	of_property_read_u32(node, "convert-channels", &priv->convert_channels);
-
-	dev_dbg(dev, "New rsrc-audio-card: %s\n",
-		priv->snd_card.name ? priv->snd_card.name : "");
-	dev_dbg(dev, "SRC : convert_rate     %d\n", priv->convert_rate);
-	dev_dbg(dev, "CTU : convert_channels %d\n", priv->convert_channels);
-
-	ret = rsrc_card_dai_link_of(node, priv);
-	if (ret < 0)
-		return ret;
-
-	ret = asoc_simple_card_parse_card_name(&priv->snd_card, "card-");
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-/* Decrease the reference count of the device nodes */
-static int rsrc_card_unref(struct snd_soc_card *card)
-{
-	struct snd_soc_dai_link *dai_link;
-	int num_links;
-
-	for (num_links = 0, dai_link = card->dai_link;
-	     num_links < card->num_links;
-	     num_links++, dai_link++) {
-		of_node_put(dai_link->cpu_of_node);
-		of_node_put(dai_link->codec_of_node);
-	}
-	return 0;
-}
-
-static int rsrc_card_probe(struct platform_device *pdev)
-{
-	struct rsrc_card_priv *priv;
-	struct device_node *np = pdev->dev.of_node;
-	struct device *dev = &pdev->dev;
-	int ret;
-
-	/* Allocate the private data */
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	ret = rsrc_card_parse_of(np, priv, dev);
-	if (ret < 0) {
-		if (ret != -EPROBE_DEFER)
-			dev_err(dev, "parse error %d\n", ret);
-		goto err;
-	}
-
-	snd_soc_card_set_drvdata(&priv->snd_card, priv);
-
-	ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
-	if (ret >= 0)
-		return ret;
-err:
-	rsrc_card_unref(&priv->snd_card);
-
-	return ret;
-}
-
-static int rsrc_card_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	return rsrc_card_unref(card);
-}
-
-static struct platform_driver rsrc_card = {
-	.driver = {
-		.name = "renesas-src-audio-card",
-		.of_match_table = rsrc_card_of_match,
-	},
-	.probe = rsrc_card_probe,
-	.remove = rsrc_card_remove,
-};
-
-module_platform_driver(rsrc_card);
-
-MODULE_ALIAS("platform:renesas-src-audio-card");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Renesas Sampling Rate Convert Sound Card");
-MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index e39f916d0f2f..969a5169de25 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -226,8 +226,12 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
 	ifscr = 0;
 	fsrate = 0;
 	if (fin != fout) {
+		u64 n;
+
 		ifscr = 1;
-		fsrate = 0x0400000 / fout * fin;
+		n = (u64)0x0400000 * fin;
+		do_div(n, fout);
+		fsrate = n;
 	}
 
 	/*
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 5f848f054745..6cb6db005fc4 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -928,7 +928,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
 		}
 
 		ops = &rsnd_ssi_non_ops;
-		if (of_get_property(np, "pio-transfer", NULL))
+		if (of_property_read_bool(np, "pio-transfer"))
 			ops = &rsnd_ssi_pio_ops;
 		else
 			ops = &rsnd_ssi_dma_ops;
diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c
index bc4a55bb3fd9..6c8b0b0c56ec 100644
--- a/sound/soc/soc-ac97.c
+++ b/sound/soc/soc-ac97.c
@@ -116,7 +116,7 @@ static int snd_soc_ac97_gpio_direction_out(struct gpio_chip *chip,
 	return snd_soc_update_bits(codec, AC97_GPIO_CFG, 1 << offset, 0);
 }
 
-static struct gpio_chip snd_soc_ac97_gpio_chip = {
+static const struct gpio_chip snd_soc_ac97_gpio_chip = {
 	.label			= "snd_soc_ac97",
 	.owner			= THIS_MODULE,
 	.request		= snd_soc_ac97_gpio_request,
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index d2df46c14c68..bf7b52fce597 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -121,7 +121,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 
 		dpcm_be_disconnect(fe, stream);
 		fe->dpcm[stream].runtime = NULL;
-		goto fe_err;
+		goto path_err;
 	}
 
 	dpcm_clear_pending_state(fe, stream);
@@ -136,6 +136,8 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 
 	return 0;
 
+path_err:
+	dpcm_path_put(&list);
 fe_err:
 	if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
 		fe->dai_link->compr_ops->shutdown(cstream);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 16369cad4803..c0bbcd903261 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1056,7 +1056,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
 	if (!rtd->platform) {
 		dev_err(card->dev, "ASoC: platform %s not registered\n",
 			dai_link->platform_name);
-		return -EPROBE_DEFER;
+		goto _err_defer;
 	}
 
 	soc_add_pcm_runtime(card, rtd);
@@ -2083,14 +2083,13 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card)
 	/* remove auxiliary devices */
 	soc_remove_aux_devices(card);
 
+	snd_soc_dapm_free(&card->dapm);
 	soc_cleanup_card_debugfs(card);
 
 	/* remove the card */
 	if (card->remove)
 		card->remove(card);
 
-	snd_soc_dapm_free(&card->dapm);
-
 	snd_card_free(card->snd_card);
 	return 0;
 
@@ -3333,19 +3332,6 @@ int snd_soc_register_codec(struct device *dev,
 	if (ret)
 		goto err_free;
 
-	if (codec_drv->controls) {
-		codec->component.controls = codec_drv->controls;
-		codec->component.num_controls = codec_drv->num_controls;
-	}
-	if (codec_drv->dapm_widgets) {
-		codec->component.dapm_widgets = codec_drv->dapm_widgets;
-		codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets;
-	}
-	if (codec_drv->dapm_routes) {
-		codec->component.dapm_routes = codec_drv->dapm_routes;
-		codec->component.num_dapm_routes = codec_drv->num_dapm_routes;
-	}
-
 	if (codec_drv->probe)
 		codec->component.probe = snd_soc_codec_drv_probe;
 	if (codec_drv->remove)
@@ -3733,7 +3719,7 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
 	 * SND_SOC_DAIFMT_CLOCK_MASK area
 	 */
 	snprintf(prop, sizeof(prop), "%scontinuous-clock", prefix);
-	if (of_get_property(np, prop, NULL))
+	if (of_property_read_bool(np, prop))
 		format |= SND_SOC_DAIFMT_CONT;
 	else
 		format |= SND_SOC_DAIFMT_GATED;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 8698c26773b3..3bbe32ee4630 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -823,6 +823,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
 			case snd_soc_dapm_switch:
 			case snd_soc_dapm_mixer:
 			case snd_soc_dapm_pga:
+			case snd_soc_dapm_out_drv:
 				wname_in_long_name = true;
 				kcname_in_long_name = true;
 				break;
@@ -1169,7 +1170,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
  * @custom_stop_condition: (optional) a function meant to stop the widget graph
  *                         walk based on custom logic.
  *
- * Queries DAPM graph as to whether an valid audio stream path exists for
+ * Queries DAPM graph as to whether a valid audio stream path exists for
  * the initial stream specified by name. This takes into account
  * current mixer and mux kcontrol settings. Creates list of valid widgets.
  *
@@ -1294,8 +1295,7 @@ static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
 	return w->new_power;
 }
 
-/* Generic check to see if a widget should be powered.
- */
+/* Generic check to see if a widget should be powered. */
 static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
 {
 	int in, out;
@@ -1646,7 +1646,7 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
 	struct snd_soc_dapm_context *d = data;
 	int ret;
 
-	/* If we're off and we're not supposed to be go into STANDBY */
+	/* If we're off and we're not supposed to go into STANDBY */
 	if (d->bias_level == SND_SOC_BIAS_OFF &&
 	    d->target_bias_level != SND_SOC_BIAS_OFF) {
 		if (d->dev)
@@ -1798,7 +1798,7 @@ static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
  * A complete path is a route that has valid endpoints i.e.:-
  *
  *  o DAC to output pin.
- *  o Input Pin to ADC.
+ *  o Input pin to ADC.
  *  o Input pin to Output pin (bypass, sidetone)
  *  o DAC to ADC (loopback).
  */
@@ -2114,7 +2114,7 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
  * soc_dapm_connect_path() - Connects or disconnects a path
  * @path: The path to update
  * @connect: The new connect state of the path. True if the path is connected,
- *  false if it is disconneted.
+ *  false if it is disconnected.
  * @reason: The reason why the path changed (for debugging only)
  */
 static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
@@ -2233,7 +2233,7 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
 		if (w->dapm != dapm)
 			continue;
 
-		/* only display widgets that burnm power */
+		/* only display widgets that burn power */
 		switch (w->id) {
 		case snd_soc_dapm_hp:
 		case snd_soc_dapm_mic:
@@ -2461,7 +2461,7 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
 
 	switch (w->id) {
 	case snd_soc_dapm_input:
-		/* On a fully routed card a input is never a source */
+		/* On a fully routed card an input is never a source */
 		if (w->dapm->card->fully_routed)
 			return;
 		ep = SND_SOC_DAPM_EP_SOURCE;
@@ -3049,6 +3049,9 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
 	}
 	mutex_unlock(&card->dapm_mutex);
 
+	if (ret)
+		return ret;
+
 	if (invert)
 		ucontrol->value.integer.value[0] = max - val;
 	else
@@ -3200,7 +3203,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
 	if (e->shift_l != e->shift_r) {
 		if (item[1] > e->items)
 			return -EINVAL;
-		val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l;
+		val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
 		mask |= e->mask << e->shift_r;
 	}
 
@@ -3445,7 +3448,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
 		w->endpoints[dir] = -1;
 	}
 
-	/* machine layer set ups unconnected pins and insertions */
+	/* machine layer sets up unconnected pins and insertions */
 	w->connected = 1;
 	return w;
 }
@@ -3493,6 +3496,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 	const struct snd_soc_pcm_stream *config = w->params + w->params_select;
 	struct snd_pcm_substream substream;
 	struct snd_pcm_hw_params *params = NULL;
+	struct snd_pcm_runtime *runtime = NULL;
 	u64 fmt;
 	int ret;
 
@@ -3541,6 +3545,14 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 
 	memset(&substream, 0, sizeof(substream));
 
+	/* Allocate a dummy snd_pcm_runtime for startup() and other ops() */
+	runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
+	if (!runtime) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	substream.runtime = runtime;
+
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		substream.stream = SNDRV_PCM_STREAM_CAPTURE;
@@ -3606,6 +3618,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 	}
 
 out:
+	kfree(runtime);
 	kfree(params);
 	return ret;
 }
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index a513a34a51d2..9fc1a7bb8b95 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -77,7 +77,7 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
 	item = snd_soc_enum_val_to_item(e, val);
 	ucontrol->value.enumerated.item[0] = item;
 	if (e->shift_l != e->shift_r) {
-		val = (reg_val >> e->shift_l) & e->mask;
+		val = (reg_val >> e->shift_r) & e->mask;
 		item = snd_soc_enum_val_to_item(e, val);
 		ucontrol->value.enumerated.item[1] = item;
 	}
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 60d702f8b9f0..d56a16a0f6fa 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1694,6 +1694,9 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
 		struct snd_soc_pcm_runtime *rtd = be_substream->private_data;
 		int i;
 
+		if (rtd->dai_link->be_hw_params_fixup)
+			continue;
+
 		if (soc_pcm_has_symmetry(be_substream))
 			be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
 
@@ -1790,7 +1793,7 @@ int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
 			continue;
 
 		dev_dbg(be->dev, "ASoC: close BE %s\n",
-			dpcm->fe->dai_link->name);
+			be->dai_link->name);
 
 		soc_pcm_close(be_substream);
 		be_substream->runtime = NULL;
@@ -1856,7 +1859,7 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
 			continue;
 
 		dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
-			dpcm->fe->dai_link->name);
+			be->dai_link->name);
 
 		soc_pcm_hw_free(be_substream);
 
@@ -1934,7 +1937,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
 			continue;
 
 		dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
-			dpcm->fe->dai_link->name);
+			be->dai_link->name);
 
 		ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
 		if (ret < 0) {
@@ -2014,7 +2017,7 @@ static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
 	int ret;
 
 	dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
-			dpcm->fe->dai_link->name, cmd);
+			dpcm->be->dai_link->name, cmd);
 
 	ret = soc_pcm_trigger(substream, cmd);
 	if (ret < 0)
@@ -2229,7 +2232,7 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
 			continue;
 
 		dev_dbg(be->dev, "ASoC: prepare BE %s\n",
-			dpcm->fe->dai_link->name);
+			be->dai_link->name);
 
 		ret = soc_pcm_prepare(be_substream);
 		if (ret < 0) {
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index ee7f15aa46fc..6b05047a4134 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -48,9 +48,10 @@
 #define SOC_TPLG_PASS_PCM_DAI		4
 #define SOC_TPLG_PASS_GRAPH		5
 #define SOC_TPLG_PASS_PINS		6
+#define SOC_TPLG_PASS_BE_DAI		7
 
 #define SOC_TPLG_PASS_START	SOC_TPLG_PASS_MANIFEST
-#define SOC_TPLG_PASS_END	SOC_TPLG_PASS_PINS
+#define SOC_TPLG_PASS_END	SOC_TPLG_PASS_BE_DAI
 
 struct soc_tplg {
 	const struct firmware *fw;
@@ -1475,6 +1476,7 @@ widget:
 	if (widget == NULL) {
 		dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n",
 			w->name);
+		ret = -ENOMEM;
 		goto hdr_err;
 	}
 
@@ -1554,6 +1556,25 @@ static void set_stream_info(struct snd_soc_pcm_stream *stream,
 	stream->rate_min = caps->rate_min;
 	stream->rate_max = caps->rate_max;
 	stream->formats = caps->formats;
+	stream->sig_bits = caps->sig_bits;
+}
+
+static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
+			  unsigned int flag_mask, unsigned int flags)
+{
+	if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES)
+		dai_drv->symmetric_rates =
+			flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES ? 1 : 0;
+
+	if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS)
+		dai_drv->symmetric_channels =
+			flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS ?
+			1 : 0;
+
+	if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS)
+		dai_drv->symmetric_samplebits =
+			flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS ?
+			1 : 0;
 }
 
 static int soc_tplg_dai_create(struct soc_tplg *tplg,
@@ -1690,8 +1711,96 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
 	return 0;
 }
 
+/* *
+ * soc_tplg_be_dai_config - Find and configure an existing BE DAI.
+ * @tplg: topology context
+ * @be: topology BE DAI configs.
+ *
+ * The BE dai should already be registered by the platform driver. The
+ * platform driver should specify the BE DAI name and ID for matching.
+ */
+static int soc_tplg_be_dai_config(struct soc_tplg *tplg,
+				  struct snd_soc_tplg_be_dai *be)
+{
+	struct snd_soc_dai_link_component dai_component = {0};
+	struct snd_soc_dai *dai;
+	struct snd_soc_dai_driver *dai_drv;
+	struct snd_soc_pcm_stream *stream;
+	struct snd_soc_tplg_stream_caps *caps;
+	int ret;
+
+	dai_component.dai_name = be->dai_name;
+	dai = snd_soc_find_dai(&dai_component);
+	if (!dai) {
+		dev_err(tplg->dev, "ASoC: BE DAI %s not registered\n",
+			be->dai_name);
+		return -EINVAL;
+	}
+
+	if (be->dai_id != dai->id) {
+		dev_err(tplg->dev, "ASoC: BE DAI %s id mismatch\n",
+			be->dai_name);
+		return -EINVAL;
+	}
+
+	dai_drv = dai->driver;
+	if (!dai_drv)
+		return -EINVAL;
+
+	if (be->playback) {
+		stream = &dai_drv->playback;
+		caps = &be->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
+		set_stream_info(stream, caps);
+	}
+
+	if (be->capture) {
+		stream = &dai_drv->capture;
+		caps = &be->caps[SND_SOC_TPLG_STREAM_CAPTURE];
+		set_stream_info(stream, caps);
+	}
+
+	if (be->flag_mask)
+		set_dai_flags(dai_drv, be->flag_mask, be->flags);
+
+	/* pass control to component driver for optional further init */
+	ret = soc_tplg_dai_load(tplg, dai_drv);
+	if (ret < 0) {
+		dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg,
+				      struct snd_soc_tplg_hdr *hdr)
+{
+	struct snd_soc_tplg_be_dai *be;
+	int count = hdr->count;
+	int i;
+
+	if (tplg->pass != SOC_TPLG_PASS_BE_DAI)
+		return 0;
+
+	/* config the existing BE DAIs */
+	for (i = 0; i < count; i++) {
+		be = (struct snd_soc_tplg_be_dai *)tplg->pos;
+		if (be->size != sizeof(*be)) {
+			dev_err(tplg->dev, "ASoC: invalid BE DAI size\n");
+			return -EINVAL;
+		}
+
+		soc_tplg_be_dai_config(tplg, be);
+		tplg->pos += (sizeof(*be) + be->priv.size);
+	}
+
+	dev_dbg(tplg->dev, "ASoC: Configure %d BE DAIs\n", count);
+	return 0;
+}
+
+
 static int soc_tplg_manifest_load(struct soc_tplg *tplg,
-	struct snd_soc_tplg_hdr *hdr)
+				  struct snd_soc_tplg_hdr *hdr)
 {
 	struct snd_soc_tplg_manifest *manifest;
 
@@ -1793,6 +1902,8 @@ static int soc_tplg_load_header(struct soc_tplg *tplg,
 		return soc_tplg_dapm_widget_elems_load(tplg, hdr);
 	case SND_SOC_TPLG_TYPE_PCM:
 		return soc_tplg_pcm_elems_load(tplg, hdr);
+	case SND_SOC_TPLG_TYPE_BE_DAI:
+		return soc_tplg_be_dai_elems_load(tplg, hdr);
 	case SND_SOC_TPLG_TYPE_MANIFEST:
 		return soc_tplg_manifest_load(tplg, hdr);
 	default:
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index 53dd085d3ee2..393e8f0fe2cc 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -80,7 +80,7 @@ static int dummy_dma_open(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static struct snd_pcm_ops dummy_dma_ops = {
+static const struct snd_pcm_ops dummy_dma_ops = {
 	.open		= dummy_dma_open,
 	.ioctl		= snd_pcm_lib_ioctl,
 };
diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c
index 488ef4ed8fba..549fac349fa0 100644
--- a/sound/soc/sti/sti_uniperif.c
+++ b/sound/soc/sti/sti_uniperif.c
@@ -19,6 +19,84 @@
 #define UNIPERIF_MAX_FRAME_SZ 0x20
 #define UNIPERIF_ALLOWED_FRAME_SZ (0x08 | 0x10 | 0x18 | UNIPERIF_MAX_FRAME_SZ)
 
+struct sti_uniperiph_dev_data {
+	unsigned int id; /* Nb available player instances */
+	unsigned int version; /* player IP version */
+	unsigned int stream;
+	const char *dai_names;
+	enum uniperif_type type;
+};
+
+static const struct sti_uniperiph_dev_data sti_uniplayer_hdmi = {
+	.id = 0,
+	.version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0,
+	.stream = SNDRV_PCM_STREAM_PLAYBACK,
+	.dai_names = "Uni Player #0 (HDMI)",
+	.type = SND_ST_UNIPERIF_TYPE_HDMI
+};
+
+static const struct sti_uniperiph_dev_data sti_uniplayer_pcm_out = {
+	.id = 1,
+	.version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0,
+	.stream = SNDRV_PCM_STREAM_PLAYBACK,
+	.dai_names = "Uni Player #1 (PCM OUT)",
+	.type = SND_ST_UNIPERIF_TYPE_PCM | SND_ST_UNIPERIF_TYPE_TDM,
+};
+
+static const struct sti_uniperiph_dev_data sti_uniplayer_dac = {
+	.id = 2,
+	.version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0,
+	.stream = SNDRV_PCM_STREAM_PLAYBACK,
+	.dai_names = "Uni Player #2 (DAC)",
+	.type = SND_ST_UNIPERIF_TYPE_PCM,
+};
+
+static const struct sti_uniperiph_dev_data sti_uniplayer_spdif = {
+	.id = 3,
+	.version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0,
+	.stream = SNDRV_PCM_STREAM_PLAYBACK,
+	.dai_names = "Uni Player #3 (SPDIF)",
+	.type = SND_ST_UNIPERIF_TYPE_SPDIF
+};
+
+static const struct sti_uniperiph_dev_data sti_unireader_pcm_in = {
+	.id = 0,
+	.version = SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0,
+	.stream = SNDRV_PCM_STREAM_CAPTURE,
+	.dai_names = "Uni Reader #0 (PCM IN)",
+	.type = SND_ST_UNIPERIF_TYPE_PCM | SND_ST_UNIPERIF_TYPE_TDM,
+};
+
+static const struct sti_uniperiph_dev_data sti_unireader_hdmi_in = {
+	.id = 1,
+	.version = SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0,
+	.stream = SNDRV_PCM_STREAM_CAPTURE,
+	.dai_names = "Uni Reader #1 (HDMI IN)",
+	.type = SND_ST_UNIPERIF_TYPE_PCM,
+};
+
+static const struct of_device_id snd_soc_sti_match[] = {
+	{ .compatible = "st,stih407-uni-player-hdmi",
+	  .data = &sti_uniplayer_hdmi
+	},
+	{ .compatible = "st,stih407-uni-player-pcm-out",
+	  .data = &sti_uniplayer_pcm_out
+	},
+	{ .compatible = "st,stih407-uni-player-dac",
+	  .data = &sti_uniplayer_dac
+	},
+	{ .compatible = "st,stih407-uni-player-spdif",
+	  .data = &sti_uniplayer_spdif
+	},
+	{ .compatible = "st,stih407-uni-reader-pcm_in",
+	  .data = &sti_unireader_pcm_in
+	},
+	{ .compatible = "st,stih407-uni-reader-hdmi",
+	  .data = &sti_unireader_hdmi_in
+	},
+	{},
+};
+
 int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 			       unsigned int rx_mask, int slots,
 			       int slot_width)
@@ -167,8 +245,8 @@ static int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai)
 		 * Uniperipheral instance ID
 		 */
 		ctrl = &uni->snd_ctrls[i];
-		ctrl->index = uni->info->id;
-		ctrl->device = uni->info->id;
+		ctrl->index = uni->id;
+		ctrl->device = uni->id;
 	}
 
 	return snd_soc_add_dai_controls(dai, uni->snd_ctrls, uni->num_ctrls);
@@ -186,7 +264,7 @@ int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream,
 	struct snd_dmaengine_dai_dma_data *dma_data;
 	int transfer_size;
 
-	if (uni->info->type == SND_ST_UNIPERIF_TYPE_TDM)
+	if (uni->type == SND_ST_UNIPERIF_TYPE_TDM)
 		/* transfer size = user frame size (in 32-bits FIFO cell) */
 		transfer_size = snd_soc_params_to_frame_size(params) / 32;
 	else
@@ -235,7 +313,7 @@ static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai)
 	struct uniperif *uni = priv->dai_data.uni;
 	int ret;
 
-	if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) {
+	if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		ret = uni_player_resume(uni);
 		if (ret)
 			return ret;
@@ -256,7 +334,7 @@ static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai)
 	struct sti_uniperiph_dai *dai_data = &priv->dai_data;
 
 	/* DMA settings*/
-	if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player"))
+	if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK)
 		snd_soc_dai_init_dma_data(dai, &dai_data->dma_data, NULL);
 	else
 		snd_soc_dai_init_dma_data(dai, NULL, &dai_data->dma_data);
@@ -280,25 +358,32 @@ static const struct snd_soc_component_driver sti_uniperiph_dai_component = {
 static int sti_uniperiph_cpu_dai_of(struct device_node *node,
 				    struct sti_uniperiph_data *priv)
 {
-	const char *str;
-	int ret;
 	struct device *dev = &priv->pdev->dev;
 	struct sti_uniperiph_dai *dai_data = &priv->dai_data;
 	struct snd_soc_dai_driver *dai = priv->dai;
 	struct snd_soc_pcm_stream *stream;
 	struct uniperif *uni;
+	const struct of_device_id *of_id;
+	const struct sti_uniperiph_dev_data *dev_data;
+	const char *mode;
+
+	/* Populate data structure depending on compatibility */
+	of_id = of_match_node(snd_soc_sti_match, node);
+	if (!of_id->data) {
+		dev_err(dev, "data associated to device is missing");
+		return -EINVAL;
+	}
+	dev_data = (struct sti_uniperiph_dev_data *)of_id->data;
 
 	uni = devm_kzalloc(dev, sizeof(*uni), GFP_KERNEL);
 	if (!uni)
 		return -ENOMEM;
 
+	uni->id = dev_data->id;
+	uni->ver = dev_data->version;
+
 	*dai = sti_uniperiph_dai_template;
-	ret = of_property_read_string(node, "dai-name", &str);
-	if (ret < 0) {
-		dev_err(dev, "%s: dai name missing.\n", __func__);
-		return -EINVAL;
-	}
-	dai->name = str;
+	dai->name = dev_data->dai_names;
 
 	/* Get resources */
 	uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0);
@@ -322,9 +407,20 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node,
 		return -ENXIO;
 	}
 
+	uni->type = dev_data->type;
+
+	/* check if player should be configured for tdm */
+	if (dev_data->type & SND_ST_UNIPERIF_TYPE_TDM) {
+		if (!of_property_read_string(node, "st,tdm-mode", &mode))
+			uni->type = SND_ST_UNIPERIF_TYPE_TDM;
+		else
+			uni->type = SND_ST_UNIPERIF_TYPE_PCM;
+	}
+
 	dai_data->uni = uni;
+	dai_data->stream = dev_data->stream;
 
-	if (of_device_is_compatible(node, "st,sti-uni-player")) {
+	if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		uni_player_init(priv->pdev, uni);
 		stream = &dai->playback;
 	} else {
@@ -376,12 +472,6 @@ static int sti_uniperiph_probe(struct platform_device *pdev)
 					       &dmaengine_pcm_config, 0);
 }
 
-static const struct of_device_id snd_soc_sti_match[] = {
-	{ .compatible = "st,sti-uni-player", },
-	{ .compatible = "st,sti-uni-reader", },
-	{},
-};
-
 static struct platform_driver sti_uniperiph_driver = {
 	.driver = {
 		.name = "sti-uniperiph-dai",
diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h
index eb9933c62ad6..1993c655fb79 100644
--- a/sound/soc/sti/uniperif.h
+++ b/sound/soc/sti/uniperif.h
@@ -1220,16 +1220,16 @@
 #define UNIPERIF_FIFO_FRAMES		4  /* FDMA trigger limit in frames */
 
 #define UNIPERIF_TYPE_IS_HDMI(p) \
-	((p)->info->type == SND_ST_UNIPERIF_TYPE_HDMI)
+	((p)->type == SND_ST_UNIPERIF_TYPE_HDMI)
 #define UNIPERIF_TYPE_IS_PCM(p) \
-	((p)->info->type == SND_ST_UNIPERIF_TYPE_PCM)
+	((p)->type == SND_ST_UNIPERIF_TYPE_PCM)
 #define UNIPERIF_TYPE_IS_SPDIF(p) \
-	((p)->info->type == SND_ST_UNIPERIF_TYPE_SPDIF)
+	((p)->type == SND_ST_UNIPERIF_TYPE_SPDIF)
 #define UNIPERIF_TYPE_IS_IEC958(p) \
 	(UNIPERIF_TYPE_IS_HDMI(p) || \
 		UNIPERIF_TYPE_IS_SPDIF(p))
 #define UNIPERIF_TYPE_IS_TDM(p) \
-	((p)->info->type == SND_ST_UNIPERIF_TYPE_TDM)
+	((p)->type == SND_ST_UNIPERIF_TYPE_TDM)
 
 /*
  * Uniperipheral IP revisions
@@ -1249,11 +1249,11 @@ enum uniperif_version {
 };
 
 enum uniperif_type {
-	SND_ST_UNIPERIF_TYPE_NONE,
-	SND_ST_UNIPERIF_TYPE_HDMI,
-	SND_ST_UNIPERIF_TYPE_PCM,
-	SND_ST_UNIPERIF_TYPE_SPDIF,
-	SND_ST_UNIPERIF_TYPE_TDM
+	SND_ST_UNIPERIF_TYPE_NONE	= 0x00,
+	SND_ST_UNIPERIF_TYPE_HDMI	= 0x01,
+	SND_ST_UNIPERIF_TYPE_PCM	= 0x02,
+	SND_ST_UNIPERIF_TYPE_SPDIF	= 0x04,
+	SND_ST_UNIPERIF_TYPE_TDM	= 0x08
 };
 
 enum uniperif_state {
@@ -1278,12 +1278,6 @@ enum uniperif_word_pos {
 	WORD_MAX
 };
 
-struct uniperif_info {
-	int id; /* instance value of the uniperipheral IP */
-	enum uniperif_type type;
-	int underflow_enabled;		/* Underflow recovery mode */
-};
-
 struct uniperif_iec958_settings {
 	enum uniperif_iec958_encoding_mode encoding_mode;
 	struct snd_aes_iec958 iec958;
@@ -1298,8 +1292,10 @@ struct dai_tdm_slot {
 
 struct uniperif {
 	/* System information */
-	struct uniperif_info *info;
+	enum uniperif_type type;
+	int underflow_enabled; /* Underflow recovery mode */
 	struct device *dev;
+	int id; /* instance value of the uniperipheral IP */
 	int ver; /* IP version, used by register access macros */
 	struct regmap_field *clk_sel;
 	struct regmap_field *valid_sel;
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c
index 1ac2db205a0d..1bc8ebc2528e 100644
--- a/sound/soc/sti/uniperif_player.c
+++ b/sound/soc/sti/uniperif_player.c
@@ -100,7 +100,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
 		dev_err(player->dev, "FIFO underflow error detected");
 
 		/* Interrupt is just for information when underflow recovery */
-		if (player->info->underflow_enabled) {
+		if (player->underflow_enabled) {
 			/* Update state to underflow */
 			player->state = UNIPERIF_STATE_UNDERFLOW;
 
@@ -134,7 +134,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
 
 	/* Check for underflow recovery done */
 	if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) {
-		if (!player->info->underflow_enabled) {
+		if (!player->underflow_enabled) {
 			dev_err(player->dev, "unexpected Underflow recovering");
 			return -EPERM;
 		}
@@ -764,7 +764,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream,
 	}
 
 	/* Calculate transfer size (in fifo cells and bytes) for frame count */
-	if (player->info->type == SND_ST_UNIPERIF_TYPE_TDM) {
+	if (player->type == SND_ST_UNIPERIF_TYPE_TDM) {
 		/* transfer size = user frame size (in 32 bits FIFO cell) */
 		transfer_size =
 			sti_uniperiph_get_user_frame_size(runtime) / 4;
@@ -794,7 +794,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream,
 	SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit);
 
 	/* Uniperipheral setup depends on player type */
-	switch (player->info->type) {
+	switch (player->type) {
 	case SND_ST_UNIPERIF_TYPE_HDMI:
 		ret = uni_player_prepare_iec958(player, runtime);
 		break;
@@ -884,7 +884,7 @@ static int uni_player_start(struct uniperif *player)
 	SET_UNIPERIF_ITM_BSET_FIFO_ERROR(player);
 
 	/* Enable underflow recovery interrupts */
-	if (player->info->underflow_enabled) {
+	if (player->underflow_enabled) {
 		SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(player);
 		SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player);
 	}
@@ -893,8 +893,10 @@ static int uni_player_start(struct uniperif *player)
 	SET_UNIPERIF_SOFT_RST_SOFT_RST(player);
 
 	ret = reset_player(player);
-	if (ret < 0)
+	if (ret < 0) {
+		clk_disable_unprepare(player->clk);
 		return ret;
+	}
 
 	/*
 	 * Does not use IEC61937 features of the uniperipheral hardware.
@@ -1021,8 +1023,8 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev,
 	struct reg_field regfield[2] = {
 		/* PCM_CLK_SEL */
 		REG_FIELD(SYS_CFG_AUDIO_GLUE,
-			  8 + player->info->id,
-			  8 + player->info->id),
+			  8 + player->id,
+			  8 + player->id),
 		/* PCMP_VALID_SEL */
 		REG_FIELD(SYS_CFG_AUDIO_GLUE, 0, 1)
 	};
@@ -1040,60 +1042,6 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev,
 	return 0;
 }
 
-static int uni_player_parse_dt(struct platform_device *pdev,
-			       struct uniperif *player)
-{
-	struct uniperif_info *info;
-	struct device *dev = &pdev->dev;
-	struct device_node *pnode = pdev->dev.of_node;
-	const char *mode;
-
-	/* Allocate memory for the info structure */
-	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-
-	if (of_property_read_u32(pnode, "st,version", &player->ver) ||
-	    player->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) {
-		dev_err(dev, "Unknown uniperipheral version ");
-		return -EINVAL;
-	}
-	/* Underflow recovery is only supported on later ip revisions */
-	if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
-		info->underflow_enabled = 1;
-
-	if (of_property_read_u32(pnode, "st,uniperiph-id", &info->id)) {
-		dev_err(dev, "uniperipheral id not defined");
-		return -EINVAL;
-	}
-
-	/* Read the device mode property */
-	if (of_property_read_string(pnode, "st,mode", &mode)) {
-		dev_err(dev, "uniperipheral mode not defined");
-		return -EINVAL;
-	}
-
-	if (strcasecmp(mode, "hdmi") == 0)
-		info->type = SND_ST_UNIPERIF_TYPE_HDMI;
-	else if (strcasecmp(mode, "pcm") == 0)
-		info->type = SND_ST_UNIPERIF_TYPE_PCM;
-	else if (strcasecmp(mode, "spdif") == 0)
-		info->type = SND_ST_UNIPERIF_TYPE_SPDIF;
-	else if (strcasecmp(mode, "tdm") == 0)
-		info->type = SND_ST_UNIPERIF_TYPE_TDM;
-	else
-		info->type = SND_ST_UNIPERIF_TYPE_NONE;
-
-	/* Save the info structure */
-	player->info = info;
-
-	/* Get PCM_CLK_SEL & PCMP_VALID_SEL from audio-glue-ctrl SoC reg */
-	if (uni_player_parse_dt_audio_glue(pdev, player))
-		return -EINVAL;
-
-	return 0;
-}
-
 static const struct snd_soc_dai_ops uni_player_dai_ops = {
 		.startup = uni_player_startup,
 		.shutdown = uni_player_shutdown,
@@ -1114,13 +1062,18 @@ int uni_player_init(struct platform_device *pdev,
 	player->state = UNIPERIF_STATE_STOPPED;
 	player->dai_ops = &uni_player_dai_ops;
 
-	ret = uni_player_parse_dt(pdev, player);
+	/* Get PCM_CLK_SEL & PCMP_VALID_SEL from audio-glue-ctrl SoC reg */
+	ret = uni_player_parse_dt_audio_glue(pdev, player);
 
 	if (ret < 0) {
 		dev_err(player->dev, "Failed to parse DeviceTree");
 		return ret;
 	}
 
+	/* Underflow recovery is only supported on later ip revisions */
+	if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
+		player->underflow_enabled = 1;
+
 	if (UNIPERIF_TYPE_IS_TDM(player))
 		player->hw = &uni_tdm_hw;
 	else
@@ -1144,8 +1097,8 @@ int uni_player_init(struct platform_device *pdev,
 
 	/* connect to I2S/TDM TX bus */
 	if (player->valid_sel &&
-	    (player->info->id == UNIPERIF_PLAYER_I2S_OUT)) {
-		ret = regmap_field_write(player->valid_sel, player->info->id);
+	    (player->id == UNIPERIF_PLAYER_I2S_OUT)) {
+		ret = regmap_field_write(player->valid_sel, player->id);
 		if (ret) {
 			dev_err(player->dev,
 				"%s: unable to connect to tdm bus", __func__);
diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c
index eb74a328c928..0e1c3ee56675 100644
--- a/sound/soc/sti/uniperif_reader.c
+++ b/sound/soc/sti/uniperif_reader.c
@@ -13,6 +13,7 @@
 
 #include "uniperif.h"
 
+#define UNIPERIF_READER_I2S_IN 0 /* reader id connected to I2S/TDM TX bus */
 /*
  * Note: snd_pcm_hardware is linked to DMA controller but is declared here to
  * integrate unireader capability in term of rate and supported channels
@@ -195,7 +196,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream,
 	}
 
 	/* Calculate transfer size (in fifo cells and bytes) for frame count */
-	if (reader->info->type == SND_ST_UNIPERIF_TYPE_TDM) {
+	if (reader->type == SND_ST_UNIPERIF_TYPE_TDM) {
 		/* transfer size = unip frame size (in 32 bits FIFO cell) */
 		transfer_size =
 			sti_uniperiph_get_user_frame_size(runtime) / 4;
@@ -280,7 +281,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream,
 	SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(reader);
 
 	/* Enable underflow recovery interrupts */
-	if (reader->info->underflow_enabled) {
+	if (reader->underflow_enabled) {
 		SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(reader);
 		SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(reader);
 	}
@@ -394,41 +395,6 @@ static void uni_reader_shutdown(struct snd_pcm_substream *substream,
 	}
 }
 
-static int uni_reader_parse_dt(struct platform_device *pdev,
-			       struct uniperif *reader)
-{
-	struct uniperif_info *info;
-	struct device_node *node = pdev->dev.of_node;
-	const char *mode;
-
-	/* Allocate memory for the info structure */
-	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-
-	if (of_property_read_u32(node, "st,version", &reader->ver) ||
-	    reader->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) {
-		dev_err(&pdev->dev, "Unknown uniperipheral version ");
-		return -EINVAL;
-	}
-
-	/* Read the device mode property */
-	if (of_property_read_string(node, "st,mode", &mode)) {
-		dev_err(&pdev->dev, "uniperipheral mode not defined");
-		return -EINVAL;
-	}
-
-	if (strcasecmp(mode, "tdm") == 0)
-		info->type = SND_ST_UNIPERIF_TYPE_TDM;
-	else
-		info->type = SND_ST_UNIPERIF_TYPE_PCM;
-
-	/* Save the info structure */
-	reader->info = info;
-
-	return 0;
-}
-
 static const struct snd_soc_dai_ops uni_reader_dai_ops = {
 		.startup = uni_reader_startup,
 		.shutdown = uni_reader_shutdown,
@@ -448,12 +414,6 @@ int uni_reader_init(struct platform_device *pdev,
 	reader->state = UNIPERIF_STATE_STOPPED;
 	reader->dai_ops = &uni_reader_dai_ops;
 
-	ret = uni_reader_parse_dt(pdev, reader);
-	if (ret < 0) {
-		dev_err(reader->dev, "Failed to parse DeviceTree");
-		return ret;
-	}
-
 	if (UNIPERIF_TYPE_IS_TDM(reader))
 		reader->hw = &uni_tdm_hw;
 	else
diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 2a954bd01fd8..dd2368297fd3 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -1,4 +1,5 @@
 menu "Allwinner SoC Audio support"
+	depends on ARCH_SUNXI || COMPILE_TEST
 
 config SND_SUN4I_CODEC
 	tristate "Allwinner A10 Codec Support"
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 44f170c73b06..e047ec06d538 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -96,8 +96,8 @@
 /* Other various ADC registers */
 #define SUN4I_CODEC_DAC_TXCNT			(0x30)
 #define SUN4I_CODEC_ADC_RXCNT			(0x34)
-#define SUN4I_CODEC_AC_SYS_VERI			(0x38)
-#define SUN4I_CODEC_AC_MIC_PHONE_CAL		(0x3c)
+#define SUN7I_CODEC_AC_DAC_CAL			(0x38)
+#define SUN7I_CODEC_AC_MIC_PHONE_CAL		(0x3c)
 
 struct sun4i_codec {
 	struct device	*dev;
@@ -509,7 +509,7 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute =
 
 static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1);
 
-static const struct snd_kcontrol_new sun4i_codec_widgets[] = {
+static const struct snd_kcontrol_new sun4i_codec_controls[] = {
 	SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
 		       SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
 		       sun4i_codec_pa_volume_scale),
@@ -628,12 +628,14 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
 };
 
 static struct snd_soc_codec_driver sun4i_codec_codec = {
-	.controls		= sun4i_codec_widgets,
-	.num_controls		= ARRAY_SIZE(sun4i_codec_widgets),
-	.dapm_widgets		= sun4i_codec_codec_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
-	.dapm_routes		= sun4i_codec_codec_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
+	.component_driver = {
+		.controls		= sun4i_codec_controls,
+		.num_controls		= ARRAY_SIZE(sun4i_codec_controls),
+		.dapm_widgets		= sun4i_codec_codec_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
+		.dapm_routes		= sun4i_codec_codec_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
+	},
 };
 
 static const struct snd_soc_component_driver sun4i_codec_component = {
@@ -680,12 +682,37 @@ static const struct regmap_config sun4i_codec_regmap_config = {
 	.reg_bits	= 32,
 	.reg_stride	= 4,
 	.val_bits	= 32,
-	.max_register	= SUN4I_CODEC_AC_MIC_PHONE_CAL,
+	.max_register	= SUN4I_CODEC_ADC_RXCNT,
+};
+
+static const struct regmap_config sun7i_codec_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register	= SUN7I_CODEC_AC_MIC_PHONE_CAL,
+};
+
+struct sun4i_codec_quirks {
+	const struct regmap_config *regmap_config;
+};
+
+static const struct sun4i_codec_quirks sun4i_codec_quirks = {
+	.regmap_config = &sun4i_codec_regmap_config,
+};
+
+static const struct sun4i_codec_quirks sun7i_codec_quirks = {
+	.regmap_config = &sun7i_codec_regmap_config,
 };
 
 static const struct of_device_id sun4i_codec_of_match[] = {
-	{ .compatible = "allwinner,sun4i-a10-codec" },
-	{ .compatible = "allwinner,sun7i-a20-codec" },
+	{
+		.compatible = "allwinner,sun4i-a10-codec",
+		.data = &sun4i_codec_quirks,
+	},
+	{
+		.compatible = "allwinner,sun7i-a20-codec",
+		.data = &sun7i_codec_quirks,
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
@@ -758,6 +785,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
 {
 	struct snd_soc_card *card;
 	struct sun4i_codec *scodec;
+	const struct sun4i_codec_quirks *quirks;
 	struct resource *res;
 	void __iomem *base;
 	int ret;
@@ -775,8 +803,14 @@ static int sun4i_codec_probe(struct platform_device *pdev)
 		return PTR_ERR(base);
 	}
 
+	quirks = of_device_get_match_data(&pdev->dev);
+	if (quirks == NULL) {
+		dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
+		return -ENODEV;
+	}
+
 	scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
-					     &sun4i_codec_regmap_config);
+					       quirks->regmap_config);
 	if (IS_ERR(scodec->regmap)) {
 		dev_err(&pdev->dev, "Failed to create our regmap\n");
 		return PTR_ERR(scodec->regmap);
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index 0b04fb02125c..88fbb3a1e660 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/reset.h>
 #include <sound/dmaengine_pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -162,6 +163,7 @@ struct sun4i_spdif_dev {
 	struct platform_device *pdev;
 	struct clk *spdif_clk;
 	struct clk *apb_clk;
+	struct reset_control *rst;
 	struct snd_soc_dai_driver cpu_dai_drv;
 	struct regmap *regmap;
 	struct snd_dmaengine_dai_dma_data dma_params_tx;
@@ -411,6 +413,7 @@ static const struct snd_soc_dapm_route dit_routes[] = {
 
 static const struct of_device_id sun4i_spdif_of_match[] = {
 	{ .compatible = "allwinner,sun4i-a10-spdif", },
+	{ .compatible = "allwinner,sun6i-a31-spdif", },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
@@ -482,11 +485,23 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
 	}
 
 	host->dma_params_tx.addr = res->start + SUN4I_SPDIF_TXFIFO;
-	host->dma_params_tx.maxburst = 4;
+	host->dma_params_tx.maxburst = 8;
 	host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 
 	platform_set_drvdata(pdev, host);
 
+	if (of_device_is_compatible(pdev->dev.of_node,
+				    "allwinner,sun6i-a31-spdif")) {
+		host->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
+		if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) {
+			ret = -EPROBE_DEFER;
+			dev_err(&pdev->dev, "Failed to get reset: %d\n", ret);
+			goto err_disable_apb_clk;
+		}
+		if (!IS_ERR(host->rst))
+			reset_control_deassert(host->rst);
+	}
+
 	ret = devm_snd_soc_register_component(&pdev->dev,
 				&sun4i_spdif_component, &sun4i_spdif_dai, 1);
 	if (ret)
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index a6768f832c6f..efbe8d4c019e 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -138,3 +138,14 @@ config SND_SOC_TEGRA_RT5677
 	help
 	  Say Y or M here if you want to add support for SoC audio on Tegra
 	  boards using the RT5677 codec, such as Ryu.
+
+config SND_SOC_TEGRA_SGTL5000
+	tristate "SoC Audio support for Tegra boards using a SGTL5000 codec"
+	depends on SND_SOC_TEGRA && I2C && GPIOLIB
+	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+	select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
+	select SND_SOC_SGTL5000
+	help
+	  Say Y or M here if you want to add support for SoC audio on Tegra
+	  boards using the SGTL5000 codec, such as Apalis T30, Apalis TK1 or
+	  Colibri T30.
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 9171655ad843..f214a3fd0024 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -26,6 +26,7 @@ snd-soc-tegra-wm9712-objs := tegra_wm9712.o
 snd-soc-tegra-trimslice-objs := trimslice.o
 snd-soc-tegra-alc5632-objs := tegra_alc5632.o
 snd-soc-tegra-max98090-objs := tegra_max98090.o
+snd-soc-tegra-sgtl5000-objs := tegra_sgtl5000.o
 
 obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
 obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o
@@ -35,3 +36,4 @@ obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o
 obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
 obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
 obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o
+obj-$(CONFIG_SND_SOC_TEGRA_SGTL5000) += snd-soc-tegra-sgtl5000.o
\ No newline at end of file
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
index 773daecaa5e8..e5ef4e9c4ac5 100644
--- a/sound/soc/tegra/tegra_rt5640.c
+++ b/sound/soc/tegra/tegra_rt5640.c
@@ -1,5 +1,5 @@
 /*
-* tegra_rt5640.c - Tegra machine ASoC driver for boards using WM8903 codec.
+* tegra_rt5640.c - Tegra machine ASoC driver for boards using RT5640 codec.
  *
  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
  *
diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c
new file mode 100644
index 000000000000..1e76869dd488
--- /dev/null
+++ b/sound/soc/tegra/tegra_sgtl5000.c
@@ -0,0 +1,212 @@
+/*
+ * tegra_sgtl5000.c - Tegra machine ASoC driver for boards using SGTL5000 codec
+ *
+ * Author: Marcel Ziswiler <marcel@ziswiler.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/sgtl5000.h"
+
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-sgtl5000"
+
+struct tegra_sgtl5000 {
+	struct tegra_asoc_utils_data util_data;
+};
+
+static int tegra_sgtl5000_hw_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_card *card = rtd->card;
+	struct tegra_sgtl5000 *machine = snd_soc_card_get_drvdata(card);
+	int srate, mclk;
+	int err;
+
+	srate = params_rate(params);
+	switch (srate) {
+	case 11025:
+	case 22050:
+	case 44100:
+	case 88200:
+		mclk = 11289600;
+		break;
+	default:
+		mclk = 12288000;
+		break;
+	}
+
+	err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+	if (err < 0) {
+		dev_err(card->dev, "Can't configure clocks\n");
+		return err;
+	}
+
+	err = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk,
+				     SND_SOC_CLOCK_IN);
+	if (err < 0) {
+		dev_err(card->dev, "codec_dai clock not set\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops tegra_sgtl5000_ops = {
+	.hw_params = tegra_sgtl5000_hw_params,
+};
+
+static const struct snd_soc_dapm_widget tegra_sgtl5000_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In Jack", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static struct snd_soc_dai_link tegra_sgtl5000_dai = {
+	.name = "sgtl5000",
+	.stream_name = "HiFi",
+	.codec_dai_name = "sgtl5000",
+	.ops = &tegra_sgtl5000_ops,
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_tegra_sgtl5000 = {
+	.name = "tegra-sgtl5000",
+	.owner = THIS_MODULE,
+	.dai_link = &tegra_sgtl5000_dai,
+	.num_links = 1,
+	.dapm_widgets = tegra_sgtl5000_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tegra_sgtl5000_dapm_widgets),
+	.fully_routed = true,
+};
+
+static int tegra_sgtl5000_driver_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct snd_soc_card *card = &snd_soc_tegra_sgtl5000;
+	struct tegra_sgtl5000 *machine;
+	int ret;
+
+	machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_sgtl5000),
+			       GFP_KERNEL);
+	if (!machine) {
+		dev_err(&pdev->dev, "Can't allocate tegra_sgtl5000 struct\n");
+		return -ENOMEM;
+	}
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+	snd_soc_card_set_drvdata(card, machine);
+
+	ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+	if (ret)
+		goto err;
+
+	ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+	if (ret)
+		goto err;
+
+	tegra_sgtl5000_dai.codec_of_node = of_parse_phandle(np,
+			"nvidia,audio-codec", 0);
+	if (!tegra_sgtl5000_dai.codec_of_node) {
+		dev_err(&pdev->dev,
+			"Property 'nvidia,audio-codec' missing or invalid\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	tegra_sgtl5000_dai.cpu_of_node = of_parse_phandle(np,
+			"nvidia,i2s-controller", 0);
+	if (!tegra_sgtl5000_dai.cpu_of_node) {
+		dev_err(&pdev->dev,
+			"Property 'nvidia,i2s-controller' missing/invalid\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	tegra_sgtl5000_dai.platform_of_node = tegra_sgtl5000_dai.cpu_of_node;
+
+	ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+	if (ret)
+		goto err;
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+			ret);
+		goto err_fini_utils;
+	}
+
+	return 0;
+
+err_fini_utils:
+	tegra_asoc_utils_fini(&machine->util_data);
+err:
+	return ret;
+}
+
+static int tegra_sgtl5000_driver_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct tegra_sgtl5000 *machine = snd_soc_card_get_drvdata(card);
+	int ret;
+
+	ret = snd_soc_unregister_card(card);
+
+	tegra_asoc_utils_fini(&machine->util_data);
+
+	return ret;
+}
+
+static const struct of_device_id tegra_sgtl5000_of_match[] = {
+	{ .compatible = "nvidia,tegra-audio-sgtl5000", },
+	{ /* sentinel */ },
+};
+
+static struct platform_driver tegra_sgtl5000_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = tegra_sgtl5000_of_match,
+	},
+	.probe = tegra_sgtl5000_driver_probe,
+	.remove = tegra_sgtl5000_driver_remove,
+};
+module_platform_driver(tegra_sgtl5000_driver);
+
+MODULE_AUTHOR("Marcel Ziswiler <marcel@ziswiler.com>");
+MODULE_DESCRIPTION("Tegra SGTL5000 machine ASoC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_sgtl5000_of_match);
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c
index 204cc074adb9..41aa3355e920 100644
--- a/sound/usb/line6/pcm.c
+++ b/sound/usb/line6/pcm.c
@@ -55,7 +55,6 @@ static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
 		err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE);
 		if (err < 0) {
 			line6pcm->impulse_volume = 0;
-			line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);
 			return err;
 		}
 	} else {
@@ -211,7 +210,9 @@ static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction,
 	spin_lock_irqsave(&pstr->lock, flags);
 	clear_bit(type, &pstr->running);
 	if (!pstr->running) {
+		spin_unlock_irqrestore(&pstr->lock, flags);
 		line6_unlink_audio_urbs(line6pcm, pstr);
+		spin_lock_irqsave(&pstr->lock, flags);
 		if (direction == SNDRV_PCM_STREAM_CAPTURE) {
 			line6pcm->prev_fbuf = NULL;
 			line6pcm->prev_fsize = 0;
diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c
index daf81d169a42..45dd34874f43 100644
--- a/sound/usb/line6/pod.c
+++ b/sound/usb/line6/pod.c
@@ -244,8 +244,8 @@ static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
 static ssize_t serial_number_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
-	struct usb_interface *interface = to_usb_interface(dev);
-	struct usb_line6_pod *pod = usb_get_intfdata(interface);
+	struct snd_card *card = dev_to_snd_card(dev);
+	struct usb_line6_pod *pod = card->private_data;
 
 	return sprintf(buf, "%u\n", pod->serial_number);
 }
@@ -256,8 +256,8 @@ static ssize_t serial_number_show(struct device *dev,
 static ssize_t firmware_version_show(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
-	struct usb_interface *interface = to_usb_interface(dev);
-	struct usb_line6_pod *pod = usb_get_intfdata(interface);
+	struct snd_card *card = dev_to_snd_card(dev);
+	struct usb_line6_pod *pod = card->private_data;
 
 	return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
 		       pod->firmware_version % 100);
@@ -269,8 +269,8 @@ static ssize_t firmware_version_show(struct device *dev,
 static ssize_t device_id_show(struct device *dev,
 			      struct device_attribute *attr, char *buf)
 {
-	struct usb_interface *interface = to_usb_interface(dev);
-	struct usb_line6_pod *pod = usb_get_intfdata(interface);
+	struct snd_card *card = dev_to_snd_card(dev);
+	struct usb_line6_pod *pod = card->private_data;
 
 	return sprintf(buf, "%d\n", pod->device_id);
 }
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 6adde457b602..152292e5ee2b 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1128,6 +1128,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
 {
 	/* devices which do not support reading the sample rate. */
 	switch (chip->usb_id) {
+	case USB_ID(0x041E, 0x4080): /* Creative Live Cam VF0610 */
 	case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema  */
 	case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */
 	case USB_ID(0x045E, 0x076E): /* MS Lifecam HD-5001 */
@@ -1138,7 +1139,9 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
 	case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */
 	case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */
 	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(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
 	case USB_ID(0x1de7, 0x0013): /* Phoenix Audio MT202exe */
 	case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */
 	case USB_ID(0x1de7, 0x0114): /* Phoenix Audio MT202pcs */