summary refs log tree commit diff
path: root/sound
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2015-10-26 11:15:54 +0900
committerMark Brown <broonie@kernel.org>2015-10-26 11:15:54 +0900
commit7c9c29eefa8ba503a34bac4ca4fb27083b78b726 (patch)
treeeb3bb499ebd185341f2b8266757c572fe42766cc /sound
parent32b88194f71d6ae7768a29f87fbba454728273ee (diff)
parent4922e7a1b767fcf6f29ce121ad74e424f4045eff (diff)
downloadlinux-7c9c29eefa8ba503a34bac4ca4fb27083b78b726.tar.gz
Merge tag 'asoc-v4.3-rc2' into asoc-next
ASoC: Updates for v4.4

A first batch of updates targetted at v4.4.  There are no substantial
core fixes here, the biggest block of changes is updates to the rcar
drivers and the addition of a CODEC driver for the AK4613.

# gpg: Signature made Fri 25 Sep 2015 05:37:06 KST using RSA key ID 5D5487D0
# gpg: key CD7BEEBC: no public key for trusted key - skipped
# gpg: key CD7BEEBC marked as ultimately trusted
# gpg: key AF88CD16: no public key for trusted key - skipped
# gpg: key AF88CD16 marked as ultimately trusted
# gpg: key 16005C11: no public key for trusted key - skipped
# gpg: key 16005C11 marked as ultimately trusted
# gpg: key 5621E907: no public key for trusted key - skipped
# gpg: key 5621E907 marked as ultimately trusted
# gpg: key 5C6153AD: no public key for trusted key - skipped
# gpg: key 5C6153AD marked as ultimately trusted
# gpg: Good signature from "Mark Brown <broonie@sirena.org.uk>"
# gpg:                 aka "Mark Brown <broonie@debian.org>"
# gpg:                 aka "Mark Brown <broonie@kernel.org>"
# gpg:                 aka "Mark Brown <broonie@tardis.ed.ac.uk>"
# gpg:                 aka "Mark Brown <broonie@linaro.org>"
# gpg:                 aka "Mark Brown <Mark.Brown@linaro.org>"
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/atmel/atmel_wm8904.c1
-rw-r--r--sound/soc/au1x/db1000.c10
-rw-r--r--sound/soc/au1x/db1200.c10
-rw-r--r--sound/soc/blackfin/bf5xx-ad1836.c11
-rw-r--r--sound/soc/blackfin/bfin-eval-adau1373.c12
-rw-r--r--sound/soc/blackfin/bfin-eval-adau1701.c12
-rw-r--r--sound/soc/blackfin/bfin-eval-adav80x.c12
-rw-r--r--sound/soc/codecs/Kconfig9
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/ak4613.c497
-rw-r--r--sound/soc/codecs/ak4642.c153
-rw-r--r--sound/soc/codecs/arizona.c16
-rw-r--r--sound/soc/codecs/arizona.h2
-rw-r--r--sound/soc/codecs/hdmi.c109
-rw-r--r--sound/soc/codecs/rt5645.c35
-rw-r--r--sound/soc/codecs/rt5645.h6
-rw-r--r--sound/soc/codecs/tlv320aic3x.c30
-rw-r--r--sound/soc/codecs/wm5110.c187
-rw-r--r--sound/soc/davinci/davinci-mcasp.c305
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c1
-rw-r--r--sound/soc/fsl/fsl_sai.c1
-rw-r--r--sound/soc/generic/simple-card.c8
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c17
-rw-r--r--sound/soc/intel/boards/broadwell.c9
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c33
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c1
-rw-r--r--sound/soc/kirkwood/armada-370-db.c1
-rw-r--r--sound/soc/mediatek/mt8173-max98090.c11
-rw-r--r--sound/soc/mediatek/mt8173-rt5650-rt5676.c11
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c6
-rw-r--r--sound/soc/pxa/brownstone.c9
-rw-r--r--sound/soc/pxa/corgi.c11
-rw-r--r--sound/soc/pxa/e740_wm9705.c5
-rw-r--r--sound/soc/pxa/e750_wm9705.c5
-rw-r--r--sound/soc/pxa/e800_wm9712.c5
-rw-r--r--sound/soc/pxa/hx4700.c4
-rw-r--r--sound/soc/pxa/imote2.c11
-rw-r--r--sound/soc/pxa/mioa701_wm9713.c11
-rw-r--r--sound/soc/pxa/palm27x.c9
-rw-r--r--sound/soc/pxa/poodle.c11
-rw-r--r--sound/soc/pxa/pxa-ssp.c1
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c1
-rw-r--r--sound/soc/pxa/spitz.c5
-rw-r--r--sound/soc/pxa/tosa.c5
-rw-r--r--sound/soc/pxa/ttc-dkb.c12
-rw-r--r--sound/soc/qcom/lpass-cpu.c3
-rw-r--r--sound/soc/rockchip/Kconfig4
-rw-r--r--sound/soc/sh/Kconfig1
-rw-r--r--sound/soc/sh/rcar/adg.c303
-rw-r--r--sound/soc/sh/rcar/core.c12
-rw-r--r--sound/soc/sh/rcar/ctu.c6
-rw-r--r--sound/soc/sh/rcar/dvc.c6
-rw-r--r--sound/soc/sh/rcar/mix.c6
-rw-r--r--sound/soc/sh/rcar/rsnd.h15
-rw-r--r--sound/soc/sh/rcar/src.c17
-rw-r--r--sound/soc/sh/rcar/ssi.c98
-rw-r--r--sound/soc/sh/siu_dai.c85
-rw-r--r--sound/soc/soc-core.c25
-rw-r--r--sound/soc/soc-pcm.c49
-rw-r--r--sound/soc/sunxi/Kconfig11
-rw-r--r--sound/soc/sunxi/Makefile2
-rw-r--r--sound/soc/sunxi/sun4i-codec.c719
-rw-r--r--sound/soc/ux500/mop500.c1
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c1
66 files changed, 2250 insertions, 741 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 225bfda414e9..7de792b06007 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -58,6 +58,7 @@ source "sound/soc/sh/Kconfig"
 source "sound/soc/sirf/Kconfig"
 source "sound/soc/spear/Kconfig"
 source "sound/soc/sti/Kconfig"
+source "sound/soc/sunxi/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
 source "sound/soc/ux500/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 134aca150a50..af0a5714e107 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_SND_SOC)	+= sh/
 obj-$(CONFIG_SND_SOC)	+= sirf/
 obj-$(CONFIG_SND_SOC)	+= spear/
 obj-$(CONFIG_SND_SOC)	+= sti/
+obj-$(CONFIG_SND_SOC)	+= sunxi/
 obj-$(CONFIG_SND_SOC)	+= tegra/
 obj-$(CONFIG_SND_SOC)	+= txx9/
 obj-$(CONFIG_SND_SOC)	+= ux500/
diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c
index aa354e1c6ff7..1933bcd46cca 100644
--- a/sound/soc/atmel/atmel_wm8904.c
+++ b/sound/soc/atmel/atmel_wm8904.c
@@ -176,6 +176,7 @@ static const struct of_device_id atmel_asoc_wm8904_dt_ids[] = {
 	{ .compatible = "atmel,asoc-wm8904", },
 	{ }
 };
+MODULE_DEVICE_TABLE(of, atmel_asoc_wm8904_dt_ids);
 #endif
 
 static struct platform_driver atmel_asoc_wm8904_driver = {
diff --git a/sound/soc/au1x/db1000.c b/sound/soc/au1x/db1000.c
index 452f404abfd2..e97c32798e98 100644
--- a/sound/soc/au1x/db1000.c
+++ b/sound/soc/au1x/db1000.c
@@ -38,14 +38,7 @@ static int db1000_audio_probe(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = &db1000_ac97;
 	card->dev = &pdev->dev;
-	return snd_soc_register_card(card);
-}
-
-static int db1000_audio_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	snd_soc_unregister_card(card);
-	return 0;
+	return devm_snd_soc_register_card(&pdev->dev, card);
 }
 
 static struct platform_driver db1000_audio_driver = {
@@ -54,7 +47,6 @@ static struct platform_driver db1000_audio_driver = {
 		.pm	= &snd_soc_pm_ops,
 	},
 	.probe		= db1000_audio_probe,
-	.remove		= db1000_audio_remove,
 };
 
 module_platform_driver(db1000_audio_driver);
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index 8c907ebea189..5c73061d912a 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -178,14 +178,7 @@ static int db1200_audio_probe(struct platform_device *pdev)
 
 	card = db1200_cards[pid->driver_data];
 	card->dev = &pdev->dev;
-	return snd_soc_register_card(card);
-}
-
-static int db1200_audio_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	snd_soc_unregister_card(card);
-	return 0;
+	return devm_snd_soc_register_card(&pdev->dev, card);
 }
 
 static struct platform_driver db1200_audio_driver = {
@@ -195,7 +188,6 @@ static struct platform_driver db1200_audio_driver = {
 	},
 	.id_table	= db1200_pids,
 	.probe		= db1200_audio_probe,
-	.remove		= db1200_audio_remove,
 };
 
 module_platform_driver(db1200_audio_driver);
diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c
index 5bf1501e5e3c..864df2616e10 100644
--- a/sound/soc/blackfin/bf5xx-ad1836.c
+++ b/sound/soc/blackfin/bf5xx-ad1836.c
@@ -87,27 +87,18 @@ static int bf5xx_ad1836_driver_probe(struct platform_device *pdev)
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 
-	ret = snd_soc_register_card(card);
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret)
 		dev_err(&pdev->dev, "Failed to register card\n");
 	return ret;
 }
 
-static int bf5xx_ad1836_driver_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
-	return 0;
-}
-
 static struct platform_driver bf5xx_ad1836_driver = {
 	.driver = {
 		.name = "bfin-snd-ad1836",
 		.pm = &snd_soc_pm_ops,
 	},
 	.probe = bf5xx_ad1836_driver_probe,
-	.remove = bf5xx_ad1836_driver_remove,
 };
 module_platform_driver(bf5xx_ad1836_driver);
 
diff --git a/sound/soc/blackfin/bfin-eval-adau1373.c b/sound/soc/blackfin/bfin-eval-adau1373.c
index 523baf5820d7..72ac78988426 100644
--- a/sound/soc/blackfin/bfin-eval-adau1373.c
+++ b/sound/soc/blackfin/bfin-eval-adau1373.c
@@ -154,16 +154,7 @@ static int bfin_eval_adau1373_probe(struct platform_device *pdev)
 
 	card->dev = &pdev->dev;
 
-	return snd_soc_register_card(&bfin_eval_adau1373);
-}
-
-static int bfin_eval_adau1373_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
-
-	return 0;
+	return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1373);
 }
 
 static struct platform_driver bfin_eval_adau1373_driver = {
@@ -172,7 +163,6 @@ static struct platform_driver bfin_eval_adau1373_driver = {
 		.pm = &snd_soc_pm_ops,
 	},
 	.probe = bfin_eval_adau1373_probe,
-	.remove = bfin_eval_adau1373_remove,
 };
 
 module_platform_driver(bfin_eval_adau1373_driver);
diff --git a/sound/soc/blackfin/bfin-eval-adau1701.c b/sound/soc/blackfin/bfin-eval-adau1701.c
index f9e926dfd4ef..5c67f72cf9a9 100644
--- a/sound/soc/blackfin/bfin-eval-adau1701.c
+++ b/sound/soc/blackfin/bfin-eval-adau1701.c
@@ -94,16 +94,7 @@ static int bfin_eval_adau1701_probe(struct platform_device *pdev)
 
 	card->dev = &pdev->dev;
 
-	return snd_soc_register_card(&bfin_eval_adau1701);
-}
-
-static int bfin_eval_adau1701_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
-
-	return 0;
+	return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1701);
 }
 
 static struct platform_driver bfin_eval_adau1701_driver = {
@@ -112,7 +103,6 @@ static struct platform_driver bfin_eval_adau1701_driver = {
 		.pm = &snd_soc_pm_ops,
 	},
 	.probe = bfin_eval_adau1701_probe,
-	.remove = bfin_eval_adau1701_remove,
 };
 
 module_platform_driver(bfin_eval_adau1701_driver);
diff --git a/sound/soc/blackfin/bfin-eval-adav80x.c b/sound/soc/blackfin/bfin-eval-adav80x.c
index 27eee66afdb2..1037477d10b2 100644
--- a/sound/soc/blackfin/bfin-eval-adav80x.c
+++ b/sound/soc/blackfin/bfin-eval-adav80x.c
@@ -119,16 +119,7 @@ static int bfin_eval_adav80x_probe(struct platform_device *pdev)
 
 	card->dev = &pdev->dev;
 
-	return snd_soc_register_card(&bfin_eval_adav80x);
-}
-
-static int bfin_eval_adav80x_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
-
-	return 0;
+	return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adav80x);
 }
 
 static const struct platform_device_id bfin_eval_adav80x_ids[] = {
@@ -144,7 +135,6 @@ static struct platform_driver bfin_eval_adav80x_driver = {
 		.pm = &snd_soc_pm_ops,
 	},
 	.probe = bfin_eval_adav80x_probe,
-	.remove = bfin_eval_adav80x_remove,
 	.id_table = bfin_eval_adav80x_ids,
 };
 
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 0c9733ecd17f..70e5a75901aa 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -36,6 +36,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_AK4104 if SPI_MASTER
 	select SND_SOC_AK4535 if I2C
 	select SND_SOC_AK4554
+	select SND_SOC_AK4613 if I2C
 	select SND_SOC_AK4641 if I2C
 	select SND_SOC_AK4642 if I2C
 	select SND_SOC_AK4671 if I2C
@@ -79,7 +80,6 @@ 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_HDMI_CODEC
 	select SND_SOC_PCM1681 if I2C
 	select SND_SOC_PCM1792A if SPI_MASTER
 	select SND_SOC_PCM3008
@@ -319,6 +319,10 @@ config SND_SOC_AK4535
 config SND_SOC_AK4554
 	tristate "AKM AK4554 CODEC"
 
+config SND_SOC_AK4613
+	tristate "AKM AK4613 CODEC"
+	depends on I2C
+
 config SND_SOC_AK4641
 	tristate
 
@@ -442,9 +446,6 @@ config SND_SOC_BT_SCO
 config SND_SOC_DMIC
 	tristate
 
-config SND_SOC_HDMI_CODEC
-       tristate "HDMI stub CODEC"
-
 config SND_SOC_ES8328
 	tristate "Everest Semi ES8328 CODEC"
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 4a32077954ae..be1491acb6ae 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -26,6 +26,7 @@ snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-ak4554-objs := ak4554.o
+snd-soc-ak4613-objs := ak4613.o
 snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
@@ -72,7 +73,6 @@ snd-soc-max98925-objs := max98925.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
-snd-soc-hdmi-codec-objs := hdmi.o
 snd-soc-pcm1681-objs := pcm1681.o
 snd-soc-pcm1792a-codec-objs := pcm1792a.o
 snd-soc-pcm3008-objs := pcm3008.o
@@ -216,6 +216,7 @@ obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_AK4554)	+= snd-soc-ak4554.o
+obj-$(CONFIG_SND_SOC_AK4613)	+= snd-soc-ak4613.o
 obj-$(CONFIG_SND_SOC_AK4641)	+= snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
@@ -264,7 +265,6 @@ obj-$(CONFIG_SND_SOC_MAX98925)	+= snd-soc-max98925.o
 obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
-obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
 obj-$(CONFIG_SND_SOC_PCM1681)	+= snd-soc-pcm1681.o
 obj-$(CONFIG_SND_SOC_PCM1792A)	+= snd-soc-pcm1792a-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
new file mode 100644
index 000000000000..07a266460ec3
--- /dev/null
+++ b/sound/soc/codecs/ak4613.c
@@ -0,0 +1,497 @@
+/*
+ * ak4613.c  --  Asahi Kasei ALSA Soc Audio driver
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * Based on ak4642.c by Kuninori Morimoto
+ * Based on wm8731.c by Richard Purdie
+ * Based on ak4535.c by Richard Purdie
+ * Based on wm8753.c by Liam Girdwood
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#define PW_MGMT1	0x00 /* Power Management 1 */
+#define PW_MGMT2	0x01 /* Power Management 2 */
+#define PW_MGMT3	0x02 /* Power Management 3 */
+#define CTRL1		0x03 /* Control 1 */
+#define CTRL2		0x04 /* Control 2 */
+#define DEMP1		0x05 /* De-emphasis1 */
+#define DEMP2		0x06 /* De-emphasis2 */
+#define OFD		0x07 /* Overflow Detect */
+#define ZRD		0x08 /* Zero Detect */
+#define ICTRL		0x09 /* Input Control */
+#define OCTRL		0x0a /* Output Control */
+#define LOUT1		0x0b /* LOUT1 Volume Control */
+#define ROUT1		0x0c /* ROUT1 Volume Control */
+#define LOUT2		0x0d /* LOUT2 Volume Control */
+#define ROUT2		0x0e /* ROUT2 Volume Control */
+#define LOUT3		0x0f /* LOUT3 Volume Control */
+#define ROUT3		0x10 /* ROUT3 Volume Control */
+#define LOUT4		0x11 /* LOUT4 Volume Control */
+#define ROUT4		0x12 /* ROUT4 Volume Control */
+#define LOUT5		0x13 /* LOUT5 Volume Control */
+#define ROUT5		0x14 /* ROUT5 Volume Control */
+#define LOUT6		0x15 /* LOUT6 Volume Control */
+#define ROUT6		0x16 /* ROUT6 Volume Control */
+
+/* PW_MGMT1 */
+#define RSTN		BIT(0)
+#define PMDAC		BIT(1)
+#define PMADC		BIT(2)
+#define PMVR		BIT(3)
+
+/* PW_MGMT2 */
+#define PMAD_ALL	0x7
+
+/* PW_MGMT3 */
+#define PMDA_ALL	0x3f
+
+/* CTRL1 */
+#define DIF0		BIT(3)
+#define DIF1		BIT(4)
+#define DIF2		BIT(5)
+#define TDM0		BIT(6)
+#define TDM1		BIT(7)
+#define NO_FMT		(0xff)
+#define FMT_MASK	(0xf8)
+
+/* CTRL2 */
+#define DFS_NORMAL_SPEED	(0 << 2)
+#define DFS_DOUBLE_SPEED	(1 << 2)
+#define DFS_QUAD_SPEED		(2 << 2)
+
+struct ak4613_priv {
+	struct mutex lock;
+
+	unsigned int fmt;
+	u8 fmt_ctrl;
+	int cnt;
+};
+
+struct ak4613_formats {
+	unsigned int width;
+	unsigned int fmt;
+};
+
+struct ak4613_interface {
+	struct ak4613_formats capture;
+	struct ak4613_formats playback;
+};
+
+/*
+ * Playback Volume
+ *
+ * max : 0x00 : 0 dB
+ *       ( 0.5 dB step )
+ * min : 0xFE : -127.0 dB
+ * mute: 0xFF
+ */
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12750, 50, 1);
+
+static const struct snd_kcontrol_new ak4613_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Digital Playback Volume1", LOUT1, ROUT1,
+			 0, 0xFF, 1, out_tlv),
+	SOC_DOUBLE_R_TLV("Digital Playback Volume2", LOUT2, ROUT2,
+			 0, 0xFF, 1, out_tlv),
+	SOC_DOUBLE_R_TLV("Digital Playback Volume3", LOUT3, ROUT3,
+			 0, 0xFF, 1, out_tlv),
+	SOC_DOUBLE_R_TLV("Digital Playback Volume4", LOUT4, ROUT4,
+			 0, 0xFF, 1, out_tlv),
+	SOC_DOUBLE_R_TLV("Digital Playback Volume5", LOUT5, ROUT5,
+			 0, 0xFF, 1, out_tlv),
+	SOC_DOUBLE_R_TLV("Digital Playback Volume6", LOUT6, ROUT6,
+			 0, 0xFF, 1, out_tlv),
+};
+
+static const struct reg_default ak4613_reg[] = {
+	{ 0x0,  0x0f }, { 0x1,  0x07 }, { 0x2,  0x3f }, { 0x3,  0x20 },
+	{ 0x4,  0x20 }, { 0x5,  0x55 }, { 0x6,  0x05 }, { 0x7,  0x07 },
+	{ 0x8,  0x0f }, { 0x9,  0x07 }, { 0xa,  0x3f }, { 0xb,  0x00 },
+	{ 0xc,  0x00 }, { 0xd,  0x00 }, { 0xe,  0x00 }, { 0xf,  0x00 },
+	{ 0x10, 0x00 }, { 0x11, 0x00 }, { 0x12, 0x00 }, { 0x13, 0x00 },
+	{ 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 },
+};
+
+#define AUDIO_IFACE_IDX_TO_VAL(i) (i << 3)
+#define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt }
+static const struct ak4613_interface ak4613_iface[] = {
+	/* capture */				/* playback */
+	[0] = {	AUDIO_IFACE(24, LEFT_J),	AUDIO_IFACE(16, RIGHT_J) },
+	[1] = {	AUDIO_IFACE(24, LEFT_J),	AUDIO_IFACE(20, RIGHT_J) },
+	[2] = {	AUDIO_IFACE(24, LEFT_J),	AUDIO_IFACE(24, RIGHT_J) },
+	[3] = {	AUDIO_IFACE(24, LEFT_J),	AUDIO_IFACE(24, LEFT_J) },
+	[4] = {	AUDIO_IFACE(24, I2S),		AUDIO_IFACE(24, I2S) },
+};
+
+static const struct regmap_config ak4613_regmap_cfg = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= 0x16,
+	.reg_defaults		= ak4613_reg,
+	.num_reg_defaults	= ARRAY_SIZE(ak4613_reg),
+};
+
+static const struct of_device_id ak4613_of_match[] = {
+	{ .compatible = "asahi-kasei,ak4613",	.data = &ak4613_regmap_cfg },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ak4613_of_match);
+
+static const struct i2c_device_id ak4613_i2c_id[] = {
+	{ "ak4613", (kernel_ulong_t)&ak4613_regmap_cfg },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ak4613_i2c_id);
+
+static const struct snd_soc_dapm_widget ak4613_dapm_widgets[] = {
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("LOUT1"),
+	SND_SOC_DAPM_OUTPUT("LOUT2"),
+	SND_SOC_DAPM_OUTPUT("LOUT3"),
+	SND_SOC_DAPM_OUTPUT("LOUT4"),
+	SND_SOC_DAPM_OUTPUT("LOUT5"),
+	SND_SOC_DAPM_OUTPUT("LOUT6"),
+
+	SND_SOC_DAPM_OUTPUT("ROUT1"),
+	SND_SOC_DAPM_OUTPUT("ROUT2"),
+	SND_SOC_DAPM_OUTPUT("ROUT3"),
+	SND_SOC_DAPM_OUTPUT("ROUT4"),
+	SND_SOC_DAPM_OUTPUT("ROUT5"),
+	SND_SOC_DAPM_OUTPUT("ROUT6"),
+
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("LIN1"),
+	SND_SOC_DAPM_INPUT("LIN2"),
+
+	SND_SOC_DAPM_INPUT("RIN1"),
+	SND_SOC_DAPM_INPUT("RIN2"),
+
+	/* DAC */
+	SND_SOC_DAPM_DAC("DAC1", NULL, PW_MGMT3, 0, 0),
+	SND_SOC_DAPM_DAC("DAC2", NULL, PW_MGMT3, 1, 0),
+	SND_SOC_DAPM_DAC("DAC3", NULL, PW_MGMT3, 2, 0),
+	SND_SOC_DAPM_DAC("DAC4", NULL, PW_MGMT3, 3, 0),
+	SND_SOC_DAPM_DAC("DAC5", NULL, PW_MGMT3, 4, 0),
+	SND_SOC_DAPM_DAC("DAC6", NULL, PW_MGMT3, 5, 0),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("ADC1", NULL, PW_MGMT2, 0, 0),
+	SND_SOC_DAPM_ADC("ADC2", NULL, PW_MGMT2, 1, 0),
+};
+
+static const struct snd_soc_dapm_route ak4613_intercon[] = {
+	{"LOUT1", NULL, "DAC1"},
+	{"LOUT2", NULL, "DAC2"},
+	{"LOUT3", NULL, "DAC3"},
+	{"LOUT4", NULL, "DAC4"},
+	{"LOUT5", NULL, "DAC5"},
+	{"LOUT6", NULL, "DAC6"},
+
+	{"ROUT1", NULL, "DAC1"},
+	{"ROUT2", NULL, "DAC2"},
+	{"ROUT3", NULL, "DAC3"},
+	{"ROUT4", NULL, "DAC4"},
+	{"ROUT5", NULL, "DAC5"},
+	{"ROUT6", NULL, "DAC6"},
+
+	{"DAC1", NULL, "Playback"},
+	{"DAC2", NULL, "Playback"},
+	{"DAC3", NULL, "Playback"},
+	{"DAC4", NULL, "Playback"},
+	{"DAC5", NULL, "Playback"},
+	{"DAC6", NULL, "Playback"},
+
+	{"Capture", NULL, "ADC1"},
+	{"Capture", NULL, "ADC2"},
+
+	{"ADC1", NULL, "LIN1"},
+	{"ADC2", NULL, "LIN2"},
+
+	{"ADC1", NULL, "RIN1"},
+	{"ADC2", NULL, "RIN2"},
+};
+
+static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct device *dev = codec->dev;
+
+	mutex_lock(&priv->lock);
+	priv->cnt--;
+	if (priv->cnt < 0) {
+		dev_err(dev, "unexpected counter error\n");
+		priv->cnt = 0;
+	}
+	if (!priv->cnt)
+		priv->fmt_ctrl = NO_FMT;
+	mutex_unlock(&priv->lock);
+}
+
+static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	fmt &= SND_SOC_DAIFMT_FORMAT_MASK;
+
+	switch (fmt) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_I2S:
+		priv->fmt = fmt;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ak4613_dai_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 ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+	const struct ak4613_formats *fmts;
+	struct device *dev = codec->dev;
+	unsigned int width = params_width(params);
+	unsigned int fmt = priv->fmt;
+	unsigned int rate;
+	int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	int i, ret;
+	u8 fmt_ctrl, ctrl2;
+
+	rate = params_rate(params);
+	switch (rate) {
+	case 32000:
+	case 44100:
+	case 48000:
+		ctrl2 = DFS_NORMAL_SPEED;
+		break;
+	case 88200:
+	case 96000:
+		ctrl2 = DFS_DOUBLE_SPEED;
+		break;
+	case 176400:
+	case 192000:
+		ctrl2 = DFS_QUAD_SPEED;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * FIXME
+	 *
+	 * It doesn't support TDM at this point
+	 */
+	fmt_ctrl = NO_FMT;
+	for (i = 0; i < ARRAY_SIZE(ak4613_iface); i++) {
+		fmts = (is_play) ?	&ak4613_iface[i].playback :
+					&ak4613_iface[i].capture;
+
+		if (fmts->fmt != fmt)
+			continue;
+
+		if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
+			if (fmts->width != width)
+				continue;
+		} else {
+			if (fmts->width < width)
+				continue;
+		}
+
+		fmt_ctrl = AUDIO_IFACE_IDX_TO_VAL(i);
+		break;
+	}
+
+	ret = -EINVAL;
+	if (fmt_ctrl == NO_FMT)
+		goto hw_params_end;
+
+	mutex_lock(&priv->lock);
+	if ((priv->fmt_ctrl == NO_FMT) ||
+	    (priv->fmt_ctrl == fmt_ctrl)) {
+		priv->fmt_ctrl = fmt_ctrl;
+		priv->cnt++;
+		ret = 0;
+	}
+	mutex_unlock(&priv->lock);
+
+	if (ret < 0)
+		goto hw_params_end;
+
+	snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl);
+	snd_soc_write(codec, CTRL2, ctrl2);
+
+hw_params_end:
+	if (ret < 0)
+		dev_warn(dev, "unsupported data width/format combination\n");
+
+	return ret;
+}
+
+static int ak4613_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u8 mgmt1 = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		mgmt1 |= RSTN;
+		/* fall through */
+	case SND_SOC_BIAS_PREPARE:
+		mgmt1 |= PMADC | PMDAC;
+		/* fall through */
+	case SND_SOC_BIAS_STANDBY:
+		mgmt1 |= PMVR;
+		/* fall through */
+	case SND_SOC_BIAS_OFF:
+	default:
+		break;
+	}
+
+	snd_soc_write(codec, PW_MGMT1, mgmt1);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ak4613_dai_ops = {
+	.shutdown	= ak4613_dai_shutdown,
+	.set_fmt	= ak4613_dai_set_fmt,
+	.hw_params	= ak4613_dai_hw_params,
+};
+
+#define AK4613_PCM_RATE		(SNDRV_PCM_RATE_32000  |\
+				 SNDRV_PCM_RATE_44100  |\
+				 SNDRV_PCM_RATE_48000  |\
+				 SNDRV_PCM_RATE_64000  |\
+				 SNDRV_PCM_RATE_88200  |\
+				 SNDRV_PCM_RATE_96000  |\
+				 SNDRV_PCM_RATE_176400 |\
+				 SNDRV_PCM_RATE_192000)
+#define AK4613_PCM_FMTBIT	(SNDRV_PCM_FMTBIT_S16_LE |\
+				 SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver ak4613_dai = {
+	.name = "ak4613-hifi",
+	.playback = {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= AK4613_PCM_RATE,
+		.formats	= AK4613_PCM_FMTBIT,
+	},
+	.capture = {
+		.stream_name	= "Capture",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= AK4613_PCM_RATE,
+		.formats	= AK4613_PCM_FMTBIT,
+	},
+	.ops = &ak4613_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int ak4613_resume(struct snd_soc_codec *codec)
+{
+	struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
+
+	regcache_mark_dirty(regmap);
+	return regcache_sync(regmap);
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
+	.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),
+};
+
+static int ak4613_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct device_node *np = dev->of_node;
+	const struct regmap_config *regmap_cfg;
+	struct regmap *regmap;
+	struct ak4613_priv *priv;
+
+	regmap_cfg = NULL;
+	if (np) {
+		const struct of_device_id *of_id;
+
+		of_id = of_match_device(ak4613_of_match, dev);
+		if (of_id)
+			regmap_cfg = of_id->data;
+	} else {
+		regmap_cfg = (const struct regmap_config *)id->driver_data;
+	}
+
+	if (!regmap_cfg)
+		return -EINVAL;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->fmt_ctrl		= NO_FMT;
+	priv->cnt		= 0;
+
+	mutex_init(&priv->lock);
+
+	i2c_set_clientdata(i2c, priv);
+
+	regmap = devm_regmap_init_i2c(i2c, regmap_cfg);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return snd_soc_register_codec(dev, &soc_codec_dev_ak4613,
+				      &ak4613_dai, 1);
+}
+
+static int ak4613_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static struct i2c_driver ak4613_i2c_driver = {
+	.driver = {
+		.name = "ak4613-codec",
+		.owner = THIS_MODULE,
+		.of_match_table = ak4613_of_match,
+	},
+	.probe		= ak4613_i2c_probe,
+	.remove		= ak4613_i2c_remove,
+	.id_table	= ak4613_i2c_id,
+};
+
+module_i2c_driver(ak4613_i2c_driver);
+
+MODULE_DESCRIPTION("Soc AK4613 driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 4a90143d0e90..cda27c22812a 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -23,6 +23,8 @@
  * AK4648 is tested.
  */
 
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
@@ -128,11 +130,8 @@
 #define I2S		(3 << 0)
 
 /* MD_CTL2 */
-#define FS0		(1 << 0)
-#define FS1		(1 << 1)
-#define FS2		(1 << 2)
-#define FS3		(1 << 5)
-#define FS_MASK		(FS0 | FS1 | FS2 | FS3)
+#define FSs(val)	(((val & 0x7) << 0) | ((val & 0x8) << 2))
+#define PSs(val)	((val & 0x3) << 6)
 
 /* MD_CTL3 */
 #define BST1		(1 << 3)
@@ -147,6 +146,7 @@ struct ak4642_drvdata {
 
 struct ak4642_priv {
 	const struct ak4642_drvdata *drvdata;
+	struct clk *mcko;
 };
 
 /*
@@ -430,56 +430,56 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	return 0;
 }
 
+static int ak4642_set_mcko(struct snd_soc_codec *codec,
+			   u32 frequency)
+{
+	u32 fs_list[] = {
+		[0] = 8000,
+		[1] = 12000,
+		[2] = 16000,
+		[3] = 24000,
+		[4] = 7350,
+		[5] = 11025,
+		[6] = 14700,
+		[7] = 22050,
+		[10] = 32000,
+		[11] = 48000,
+		[14] = 29400,
+		[15] = 44100,
+	};
+	u32 ps_list[] = {
+		[0] = 256,
+		[1] = 128,
+		[2] = 64,
+		[3] = 32
+	};
+	int ps, fs;
+
+	for (ps = 0; ps < ARRAY_SIZE(ps_list); ps++) {
+		for (fs = 0; fs < ARRAY_SIZE(fs_list); fs++) {
+			if (frequency == ps_list[ps] * fs_list[fs]) {
+				snd_soc_write(codec, MD_CTL2,
+					      PSs(ps) | FSs(fs));
+				return 0;
+			}
+		}
+	}
+
+	return 0;
+}
+
 static int ak4642_dai_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;
-	u8 rate;
+	struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
+	u32 rate = clk_get_rate(priv->mcko);
 
-	switch (params_rate(params)) {
-	case 7350:
-		rate = FS2;
-		break;
-	case 8000:
-		rate = 0;
-		break;
-	case 11025:
-		rate = FS2 | FS0;
-		break;
-	case 12000:
-		rate = FS0;
-		break;
-	case 14700:
-		rate = FS2 | FS1;
-		break;
-	case 16000:
-		rate = FS1;
-		break;
-	case 22050:
-		rate = FS2 | FS1 | FS0;
-		break;
-	case 24000:
-		rate = FS1 | FS0;
-		break;
-	case 29400:
-		rate = FS3 | FS2 | FS1;
-		break;
-	case 32000:
-		rate = FS3 | FS1;
-		break;
-	case 44100:
-		rate = FS3 | FS2 | FS1 | FS0;
-		break;
-	case 48000:
-		rate = FS3 | FS1 | FS0;
-		break;
-	default:
-		return -EINVAL;
-	}
-	snd_soc_update_bits(codec, MD_CTL2, FS_MASK, rate);
+	if (!rate)
+		rate = params_rate(params) * 256;
 
-	return 0;
+	return ak4642_set_mcko(codec, rate);
 }
 
 static int ak4642_set_bias_level(struct snd_soc_codec *codec,
@@ -532,7 +532,18 @@ static int ak4642_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
+static int ak4642_probe(struct snd_soc_codec *codec)
+{
+	struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	if (priv->mcko)
+		ak4642_set_mcko(codec, clk_get_rate(priv->mcko));
+
+	return 0;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
+	.probe			= ak4642_probe,
 	.resume			= ak4642_resume,
 	.set_bias_level		= ak4642_set_bias_level,
 	.controls		= ak4642_snd_controls,
@@ -580,19 +591,54 @@ static const struct ak4642_drvdata ak4648_drvdata = {
 	.extended_frequencies = 1,
 };
 
+#ifdef CONFIG_COMMON_CLK
+static struct clk *ak4642_of_parse_mcko(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct clk *clk;
+	const char *clk_name = np->name;
+	const char *parent_clk_name = NULL;
+	u32 rate;
+
+	if (of_property_read_u32(np, "clock-frequency", &rate))
+		return NULL;
+
+	if (of_property_read_bool(np, "clocks"))
+		parent_clk_name = of_clk_get_parent_name(np, 0);
+
+	of_property_read_string(np, "clock-output-names", &clk_name);
+
+	clk = clk_register_fixed_rate(dev, clk_name, parent_clk_name,
+				      (parent_clk_name) ? 0 : CLK_IS_ROOT,
+				      rate);
+	if (!IS_ERR(clk))
+		of_clk_add_provider(np, of_clk_src_simple_get, clk);
+
+	return clk;
+}
+#else
+#define ak4642_of_parse_mcko(d) 0
+#endif
+
 static const struct of_device_id ak4642_of_match[];
 static int ak4642_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
-	struct device_node *np = i2c->dev.of_node;
+	struct device *dev = &i2c->dev;
+	struct device_node *np = dev->of_node;
 	const struct ak4642_drvdata *drvdata = NULL;
 	struct regmap *regmap;
 	struct ak4642_priv *priv;
+	struct clk *mcko = NULL;
 
 	if (np) {
 		const struct of_device_id *of_id;
 
-		of_id = of_match_device(ak4642_of_match, &i2c->dev);
+		mcko = ak4642_of_parse_mcko(dev);
+		if (IS_ERR(mcko))
+			mcko = NULL;
+
+		of_id = of_match_device(ak4642_of_match, dev);
 		if (of_id)
 			drvdata = of_id->data;
 	} else {
@@ -600,15 +646,16 @@ static int ak4642_i2c_probe(struct i2c_client *i2c,
 	}
 
 	if (!drvdata) {
-		dev_err(&i2c->dev, "Unknown device type\n");
+		dev_err(dev, "Unknown device type\n");
 		return -EINVAL;
 	}
 
-	priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
 	priv->drvdata = drvdata;
+	priv->mcko = mcko;
 
 	i2c_set_clientdata(i2c, priv);
 
@@ -616,7 +663,7 @@ static int ak4642_i2c_probe(struct i2c_client *i2c,
 	if (IS_ERR(regmap))
 		return PTR_ERR(regmap);
 
-	return snd_soc_register_codec(&i2c->dev,
+	return snd_soc_register_codec(dev,
 				      &soc_codec_dev_ak4642, &ak4642_dai, 1);
 }
 
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 8a2221ab3d10..ac21b85ff75f 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -147,6 +147,8 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
 						   0x4f5, 0x0da);
 		}
 		break;
+	default:
+		break;
 	}
 
 	return 0;
@@ -689,6 +691,15 @@ static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
 				    ARIZONA_IN_VU, val);
 }
 
+bool arizona_input_analog(struct snd_soc_codec *codec, int shift)
+{
+	unsigned int reg = ARIZONA_IN1L_CONTROL + ((shift / 2) * 8);
+	unsigned int val = snd_soc_read(codec, reg);
+
+	return !(val & ARIZONA_IN1_MODE_MASK);
+}
+EXPORT_SYMBOL_GPL(arizona_input_analog);
+
 int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
 		  int event)
 {
@@ -725,6 +736,9 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
 		reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
 		if (reg == 0)
 			arizona_in_set_vu(codec, 0);
+		break;
+	default:
+		break;
 	}
 
 	return 0;
@@ -806,6 +820,8 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 			break;
 		}
 		break;
+	default:
+		break;
 	}
 
 	return 0;
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index ada0a418ff4b..7b68d05a0939 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -294,4 +294,6 @@ extern int arizona_init_dai(struct arizona_priv *priv, int dai);
 int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
 			    bool diff);
 
+extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift);
+
 #endif
diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c
deleted file mode 100644
index bd42ad34e004..000000000000
--- a/sound/soc/codecs/hdmi.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * ALSA SoC codec driver for HDMI audio codecs.
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
- * Author: Ricardo Neri <ricardo.neri@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-#include <linux/module.h>
-#include <sound/soc.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-
-#define DRV_NAME "hdmi-audio-codec"
-
-static const struct snd_soc_dapm_widget hdmi_widgets[] = {
-	SND_SOC_DAPM_INPUT("RX"),
-	SND_SOC_DAPM_OUTPUT("TX"),
-};
-
-static const struct snd_soc_dapm_route hdmi_routes[] = {
-	{ "Capture", NULL, "RX" },
-	{ "TX", NULL, "Playback" },
-};
-
-static struct snd_soc_dai_driver hdmi_codec_dai = {
-	.name = "hdmi-hifi",
-	.playback = {
-		.stream_name = "Playback",
-		.channels_min = 2,
-		.channels_max = 8,
-		.rates = SNDRV_PCM_RATE_32000 |
-			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
-			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
-			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE |
-			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
-		.sig_bits = 24,
-	},
-	.capture = {
-		.stream_name = "Capture",
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_32000 |
-			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
-			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
-			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE |
-			SNDRV_PCM_FMTBIT_S24_LE,
-	},
-
-};
-
-#ifdef CONFIG_OF
-static const struct of_device_id hdmi_audio_codec_ids[] = {
-	{ .compatible = "linux,hdmi-audio", },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, hdmi_audio_codec_ids);
-#endif
-
-static struct snd_soc_codec_driver hdmi_codec = {
-	.dapm_widgets = hdmi_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
-	.dapm_routes = hdmi_routes,
-	.num_dapm_routes = ARRAY_SIZE(hdmi_routes),
-	.ignore_pmdown_time = true,
-};
-
-static int hdmi_codec_probe(struct platform_device *pdev)
-{
-	return snd_soc_register_codec(&pdev->dev, &hdmi_codec,
-			&hdmi_codec_dai, 1);
-}
-
-static int hdmi_codec_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
-static struct platform_driver hdmi_codec_driver = {
-	.driver		= {
-		.name	= DRV_NAME,
-		.of_match_table = of_match_ptr(hdmi_audio_codec_ids),
-	},
-
-	.probe		= hdmi_codec_probe,
-	.remove		= hdmi_codec_remove,
-};
-
-module_platform_driver(hdmi_codec_driver);
-
-MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
-MODULE_DESCRIPTION("ASoC generic HDMI codec driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 5c101af0ac63..080cc1ce3963 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -2829,6 +2829,9 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 			snd_soc_dapm_sync(dapm);
 			rt5645->jack_type = SND_JACK_HEADPHONE;
 		}
+		if (rt5645->pdata.jd_invert)
+			regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+				RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
 	} else { /* jack out */
 		rt5645->jack_type = 0;
 
@@ -2847,6 +2850,9 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 			snd_soc_dapm_disable_pin(dapm, "LDO2");
 		snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
 		snd_soc_dapm_sync(dapm);
+		if (rt5645->pdata.jd_invert)
+			regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+				RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
 	}
 
 	return rt5645->jack_type;
@@ -3212,6 +3218,32 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
 	{ }
 };
 
+static struct rt5645_platform_data buddy_platform_data = {
+	.dmic1_data_pin = RT5645_DMIC_DATA_GPIO5,
+	.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
+	.jd_mode = 3,
+	.jd_invert = true,
+};
+
+static int buddy_quirk_cb(const struct dmi_system_id *id)
+{
+	rt5645_pdata = &buddy_platform_data;
+
+	return 1;
+}
+
+static struct dmi_system_id dmi_platform_intel_broadwell[] __initdata = {
+	{
+		.ident = "Chrome Buddy",
+		.callback = buddy_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "Buddy"),
+		},
+	},
+	{ }
+};
+
+
 static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev)
 {
 	rt5645->pdata.in2_diff = device_property_read_bool(dev,
@@ -3244,7 +3276,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 
 	if (pdata)
 		rt5645->pdata = *pdata;
-	else if (dmi_check_system(dmi_platform_intel_braswell))
+	else if (dmi_check_system(dmi_platform_intel_braswell) ||
+			dmi_check_system(dmi_platform_intel_broadwell))
 		rt5645->pdata = *rt5645_pdata;
 	else
 		rt5645_parse_dt(rt5645, &i2c->dev);
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index 8c964cfb120d..61bc8ab77646 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -779,8 +779,6 @@
 #define RT5645_PWR_CLS_D_R_BIT			9
 #define RT5645_PWR_CLS_D_L			(0x1 << 8)
 #define RT5645_PWR_CLS_D_L_BIT			8
-#define RT5645_PWR_ADC_R			(0x1 << 1)
-#define RT5645_PWR_ADC_R_BIT			1
 #define RT5645_PWR_DAC_L2			(0x1 << 7)
 #define RT5645_PWR_DAC_L2_BIT			7
 #define RT5645_PWR_DAC_R2			(0x1 << 6)
@@ -1628,6 +1626,10 @@
 #define RT5645_OT_P_NOR				(0x0 << 10)
 #define RT5645_OT_P_INV				(0x1 << 10)
 #define RT5645_IRQ_JD_1_1_EN			(0x1 << 9)
+#define RT5645_JD_1_1_MASK			(0x1 << 7)
+#define RT5645_JD_1_1_SFT			7
+#define RT5645_JD_1_1_NOR			(0x0 << 7)
+#define RT5645_JD_1_1_INV			(0x1 << 7)
 
 /* IRQ Control 2 (0xbe) */
 #define RT5645_IRQ_MB1_OC_MASK			(0x1 << 15)
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 8739126a1f6f..a564759845f9 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -80,6 +80,7 @@ struct aic3x_priv {
 	unsigned int sysclk;
 	unsigned int dai_fmt;
 	unsigned int tdm_delay;
+	unsigned int slot_width;
 	struct list_head list;
 	int master;
 	int gpio_reset;
@@ -1025,10 +1026,14 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
 	u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
 	u16 d, pll_d = 1;
 	int clk;
+	int width = aic3x->slot_width;
+
+	if (!width)
+		width = params_width(params);
 
 	/* select data word length */
 	data = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
-	switch (params_width(params)) {
+	switch (width) {
 	case 16:
 		break;
 	case 20:
@@ -1170,12 +1175,16 @@ static int aic3x_prepare(struct snd_pcm_substream *substream,
 	struct snd_soc_codec *codec = dai->codec;
 	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
 	int delay = 0;
+	int width = aic3x->slot_width;
+
+	if (!width)
+		width = substream->runtime->sample_bits;
 
 	/* TDM slot selection only valid in DSP_A/_B mode */
 	if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_A)
-		delay += (aic3x->tdm_delay + 1);
+		delay += (aic3x->tdm_delay*width + 1);
 	else if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_B)
-		delay += aic3x->tdm_delay;
+		delay += aic3x->tdm_delay*width;
 
 	/* Configure data delay */
 	snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
@@ -1296,7 +1305,20 @@ static int aic3x_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	aic3x->tdm_delay = lsb * slot_width;
+	switch (slot_width) {
+	case 16:
+	case 20:
+	case 24:
+	case 32:
+		break;
+	default:
+		dev_err(codec->dev, "Unsupported slot width %d\n", slot_width);
+		return -EINVAL;
+	}
+
+
+	aic3x->tdm_delay = lsb;
+	aic3x->slot_width = slot_width;
 
 	/* DOUT in high-impedance on inactive bit clocks */
 	snd_soc_update_bits(codec, AIC3X_ASD_INTF_CTRLA,
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 9756578fc752..c04c0bc6f58a 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -38,6 +38,12 @@
 struct wm5110_priv {
 	struct arizona_priv core;
 	struct arizona_fll fll[2];
+
+	unsigned int in_value;
+	int in_pre_pending;
+	int in_post_pending;
+
+	unsigned int in_pga_cache[6];
 };
 
 static const struct wm_adsp_region wm5110_dsp1_regions[] = {
@@ -428,6 +434,127 @@ err:
 	return ret;
 }
 
+static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_card *card = dapm->card;
+	int ret;
+
+	/*
+	 * PGA Volume is also used as part of the enable sequence, so
+	 * usage of it should be avoided whilst that is running.
+	 */
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+	ret = snd_soc_get_volsw_range(kcontrol, ucontrol);
+
+	mutex_unlock(&card->dapm_mutex);
+
+	return ret;
+}
+
+static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_card *card = dapm->card;
+	int ret;
+
+	/*
+	 * PGA Volume is also used as part of the enable sequence, so
+	 * usage of it should be avoided whilst that is running.
+	 */
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+	ret = snd_soc_put_volsw_range(kcontrol, ucontrol);
+
+	mutex_unlock(&card->dapm_mutex);
+
+	return ret;
+}
+
+static int wm5110_in_analog_ev(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 arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct wm5110_priv *wm5110 = snd_soc_codec_get_drvdata(codec);
+	struct arizona *arizona = priv->arizona;
+	unsigned int reg, mask;
+	struct reg_sequence analog_seq[] = {
+		{ 0x80, 0x3 },
+		{ 0x35d, 0 },
+		{ 0x80, 0x0 },
+	};
+
+	reg = ARIZONA_IN1L_CONTROL + ((w->shift ^ 0x1) * 4);
+	mask = ARIZONA_IN1L_PGA_VOL_MASK;
+
+	switch (event) {
+	case SND_SOC_DAPM_WILL_PMU:
+		wm5110->in_value |= 0x3 << ((w->shift ^ 0x1) * 2);
+		wm5110->in_pre_pending++;
+		wm5110->in_post_pending++;
+		return 0;
+	case SND_SOC_DAPM_PRE_PMU:
+		wm5110->in_pga_cache[w->shift] = snd_soc_read(codec, reg);
+
+		snd_soc_update_bits(codec, reg, mask,
+				    0x40 << ARIZONA_IN1L_PGA_VOL_SHIFT);
+
+		wm5110->in_pre_pending--;
+		if (wm5110->in_pre_pending == 0) {
+			analog_seq[1].def = wm5110->in_value;
+			regmap_multi_reg_write_bypassed(arizona->regmap,
+							analog_seq,
+							ARRAY_SIZE(analog_seq));
+
+			msleep(55);
+
+			wm5110->in_value = 0;
+		}
+
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, reg, mask,
+				    wm5110->in_pga_cache[w->shift]);
+
+		wm5110->in_post_pending--;
+		if (wm5110->in_post_pending == 0)
+			regmap_multi_reg_write_bypassed(arizona->regmap,
+							analog_seq,
+							ARRAY_SIZE(analog_seq));
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int wm5110_in_ev(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 arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona *arizona = priv->arizona;
+
+	switch (arizona->rev) {
+	case 0 ... 4:
+		if (arizona_input_analog(codec, w->shift))
+			wm5110_in_analog_ev(w, kcontrol, event);
+
+		break;
+	default:
+		break;
+	}
+
+	return arizona_in_ev(w, kcontrol, event);
+}
+
 static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
 static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
 static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
@@ -454,18 +581,24 @@ SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
 SOC_ENUM("IN3 OSR", arizona_in_dmic_osr[2]),
 SOC_ENUM("IN4 OSR", arizona_in_dmic_osr[3]),
 
-SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
-		     ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
-SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
-		     ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
-SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
-		     ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
-SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
-		     ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
-SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
-		     ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
-SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
-		     ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
+			 ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+			 wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
+			 ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+			 wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
+			 ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+			 wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
+			 ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+			 wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
+			 ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+			 wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
+			 ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+			 wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
 
 SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum),
 
@@ -896,29 +1029,35 @@ SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
 SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"),
 
 SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
-		   0, NULL, 0, arizona_in_ev,
+		   0, NULL, 0, wm5110_in_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_WILL_PMU),
 SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
-		   0, NULL, 0, arizona_in_ev,
+		   0, NULL, 0, wm5110_in_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_WILL_PMU),
 SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
-		   0, NULL, 0, arizona_in_ev,
+		   0, NULL, 0, wm5110_in_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_WILL_PMU),
 SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
-		   0, NULL, 0, arizona_in_ev,
+		   0, NULL, 0, wm5110_in_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_WILL_PMU),
 SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
-		   0, NULL, 0, arizona_in_ev,
+		   0, NULL, 0, wm5110_in_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_WILL_PMU),
 SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
-		   0, NULL, 0, arizona_in_ev,
+		   0, NULL, 0, wm5110_in_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_WILL_PMU),
 SND_SOC_DAPM_PGA_E("IN4L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4L_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 7d45d98a861f..4495a40a9468 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -80,12 +80,13 @@ struct davinci_mcasp {
 
 	/* McASP specific data */
 	int	tdm_slots;
+	u32	tdm_mask[2];
+	int	slot_width;
 	u8	op_mode;
 	u8	num_serializer;
 	u8	*serial_dir;
 	u8	version;
 	u8	bclk_div;
-	u16	bclk_lrclk_ratio;
 	int	streams;
 	u32	irq_request[2];
 	int	dma_request[2];
@@ -556,8 +557,21 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
 			mcasp->bclk_div = div;
 		break;
 
-	case 2:		/* BCLK/LRCLK ratio */
-		mcasp->bclk_lrclk_ratio = div;
+	case 2:	/*
+		 * BCLK/LRCLK ratio descries how many bit-clock cycles
+		 * fit into one frame. The clock ratio is given for a
+		 * full period of data (for I2S format both left and
+		 * right channels), so it has to be divided by number
+		 * of tdm-slots (for I2S - divided by 2).
+		 * Instead of storing this ratio, we calculate a new
+		 * tdm_slot width by dividing the the ratio by the
+		 * number of configured tdm slots.
+		 */
+		mcasp->slot_width = div / mcasp->tdm_slots;
+		if (div % mcasp->tdm_slots)
+			dev_warn(mcasp->dev,
+				 "%s(): BCLK/LRCLK %d is not divisible by %d tdm slots",
+				 __func__, div, mcasp->tdm_slots);
 		break;
 
 	default:
@@ -596,12 +610,92 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	return 0;
 }
 
+/* All serializers must have equal number of channels */
+static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream,
+				       int serializers)
+{
+	struct snd_pcm_hw_constraint_list *cl = &mcasp->chconstr[stream];
+	unsigned int *list = (unsigned int *) cl->list;
+	int slots = mcasp->tdm_slots;
+	int i, count = 0;
+
+	if (mcasp->tdm_mask[stream])
+		slots = hweight32(mcasp->tdm_mask[stream]);
+
+	for (i = 2; i <= slots; i++)
+		list[count++] = i;
+
+	for (i = 2; i <= serializers; i++)
+		list[count++] = i*slots;
+
+	cl->count = count;
+
+	return 0;
+}
+
+static int davinci_mcasp_set_ch_constraints(struct davinci_mcasp *mcasp)
+{
+	int rx_serializers = 0, tx_serializers = 0, ret, i;
+
+	for (i = 0; i < mcasp->num_serializer; i++)
+		if (mcasp->serial_dir[i] == TX_MODE)
+			tx_serializers++;
+		else if (mcasp->serial_dir[i] == RX_MODE)
+			rx_serializers++;
+
+	ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK,
+					  tx_serializers);
+	if (ret)
+		return ret;
+
+	ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE,
+					  rx_serializers);
+
+	return ret;
+}
+
+
+static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
+				      unsigned int tx_mask,
+				      unsigned int rx_mask,
+				      int slots, int slot_width)
+{
+	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+
+	dev_dbg(mcasp->dev,
+		 "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n",
+		 __func__, tx_mask, rx_mask, slots, slot_width);
+
+	if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
+		dev_err(mcasp->dev,
+			"Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n",
+			tx_mask, rx_mask, slots);
+		return -EINVAL;
+	}
+
+	if (slot_width &&
+	    (slot_width < 8 || slot_width > 32 || slot_width % 4 != 0)) {
+		dev_err(mcasp->dev, "%s: Unsupported slot_width %d\n",
+			__func__, slot_width);
+		return -EINVAL;
+	}
+
+	mcasp->tdm_slots = slots;
+	mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = rx_mask;
+	mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = tx_mask;
+	mcasp->slot_width = slot_width;
+
+	return davinci_mcasp_set_ch_constraints(mcasp);
+}
+
 static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
-				       int word_length)
+				       int sample_width)
 {
 	u32 fmt;
-	u32 tx_rotate = (word_length / 4) & 0x7;
-	u32 mask = (1ULL << word_length) - 1;
+	u32 tx_rotate = (sample_width / 4) & 0x7;
+	u32 mask = (1ULL << sample_width) - 1;
+	u32 slot_width = sample_width;
+
 	/*
 	 * For captured data we should not rotate, inversion and masking is
 	 * enoguh to get the data to the right position:
@@ -614,28 +708,23 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
 	u32 rx_rotate = 0;
 
 	/*
-	 * if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv()
-	 * callback, take it into account here. That allows us to for example
-	 * send 32 bits per channel to the codec, while only 16 of them carry
-	 * audio payload.
-	 * The clock ratio is given for a full period of data (for I2S format
-	 * both left and right channels), so it has to be divided by number of
-	 * tdm-slots (for I2S - divided by 2).
+	 * Setting the tdm slot width either with set_clkdiv() or
+	 * set_tdm_slot() allows us to for example send 32 bits per
+	 * channel to the codec, while only 16 of them carry audio
+	 * payload.
 	 */
-	if (mcasp->bclk_lrclk_ratio) {
-		u32 slot_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots;
-
+	if (mcasp->slot_width) {
 		/*
-		 * When we have more bclk then it is needed for the data, we
-		 * need to use the rotation to move the received samples to have
-		 * correct alignment.
+		 * When we have more bclk then it is needed for the
+		 * data, we need to use the rotation to move the
+		 * received samples to have correct alignment.
 		 */
-		rx_rotate = (slot_length - word_length) / 4;
-		word_length = slot_length;
+		slot_width = mcasp->slot_width;
+		rx_rotate = (slot_width - sample_width) / 4;
 	}
 
 	/* mapping of the XSSZ bit-field as described in the datasheet */
-	fmt = (word_length >> 1) - 1;
+	fmt = (slot_width >> 1) - 1;
 
 	if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
@@ -776,33 +865,50 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
 
 	/*
 	 * If more than one serializer is needed, then use them with
-	 * their specified tdm_slots count. Otherwise, one serializer
-	 * can cope with the transaction using as many slots as channels
-	 * in the stream, requires channels symmetry
+	 * all the specified tdm_slots. Otherwise, one serializer can
+	 * cope with the transaction using just as many slots as there
+	 * are channels in the stream.
 	 */
-	active_serializers = (channels + total_slots - 1) / total_slots;
-	if (active_serializers == 1)
-		active_slots = channels;
-	else
-		active_slots = total_slots;
-
-	for (i = 0; i < active_slots; i++)
-		mask |= (1 << i);
+	if (mcasp->tdm_mask[stream]) {
+		active_slots = hweight32(mcasp->tdm_mask[stream]);
+		active_serializers = (channels + active_slots - 1) /
+			active_slots;
+		if (active_serializers == 1) {
+			active_slots = channels;
+			for (i = 0; i < total_slots; i++) {
+				if ((1 << i) & mcasp->tdm_mask[stream]) {
+					mask |= (1 << i);
+					if (--active_slots <= 0)
+						break;
+				}
+			}
+		}
+	} else {
+		active_serializers = (channels + total_slots - 1) / total_slots;
+		if (active_serializers == 1)
+			active_slots = channels;
+		else
+			active_slots = total_slots;
 
+		for (i = 0; i < active_slots; i++)
+			mask |= (1 << i);
+	}
 	mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
 
 	if (!mcasp->dat_port)
 		busel = TXSEL;
 
-	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
-	mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
-	mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
-		       FSXMOD(total_slots), FSXMOD(0x1FF));
-
-	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
-	mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
-	mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
-		       FSRMOD(total_slots), FSRMOD(0x1FF));
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
+		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
+		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+			       FSXMOD(total_slots), FSXMOD(0x1FF));
+	} else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+		mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
+		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
+		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
+			       FSRMOD(total_slots), FSRMOD(0x1FF));
+	}
 
 	return 0;
 }
@@ -922,6 +1028,9 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
 		int sbits = params_width(params);
 		int ppm, div;
 
+		if (mcasp->slot_width)
+			sbits = mcasp->slot_width;
+
 		div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*slots,
 						 &ppm);
 		if (ppm)
@@ -1027,6 +1136,9 @@ static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params,
 	struct snd_interval range;
 	int i;
 
+	if (rd->mcasp->slot_width)
+		sbits = rd->mcasp->slot_width;
+
 	snd_interval_any(&range);
 	range.empty = 1;
 
@@ -1069,10 +1181,14 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
 
 	for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
 		if (snd_mask_test(fmt, i)) {
-			uint bclk_freq = snd_pcm_format_width(i)*slots*rate;
+			uint sbits = snd_pcm_format_width(i);
 			int ppm;
 
-			davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
+			if (rd->mcasp->slot_width)
+				sbits = rd->mcasp->slot_width;
+
+			davinci_mcasp_calc_clk_div(rd->mcasp, sbits*slots*rate,
+						   &ppm);
 			if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
 				snd_mask_set(&nfmt, i);
 				count++;
@@ -1094,6 +1210,10 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
 					&mcasp->ruledata[substream->stream];
 	u32 max_channels = 0;
 	int i, dir;
+	int tdm_slots = mcasp->tdm_slots;
+
+	if (mcasp->tdm_mask[substream->stream])
+		tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]);
 
 	mcasp->substreams[substream->stream] = substream;
 
@@ -1114,7 +1234,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
 			max_channels++;
 	}
 	ruledata->serializers = max_channels;
-	max_channels *= mcasp->tdm_slots;
+	max_channels *= tdm_slots;
 	/*
 	 * If the already active stream has less channels than the calculated
 	 * limnit based on the seirializers * tdm_slots, we need to use that as
@@ -1124,15 +1244,25 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
 	 */
 	if (mcasp->channels && mcasp->channels < max_channels)
 		max_channels = mcasp->channels;
+	/*
+	 * But we can always allow channels upto the amount of
+	 * the available tdm_slots.
+	 */
+	if (max_channels < tdm_slots)
+		max_channels = tdm_slots;
 
 	snd_pcm_hw_constraint_minmax(substream->runtime,
 				     SNDRV_PCM_HW_PARAM_CHANNELS,
 				     2, max_channels);
 
-	if (mcasp->chconstr[substream->stream].count)
-		snd_pcm_hw_constraint_list(substream->runtime,
-					   0, SNDRV_PCM_HW_PARAM_CHANNELS,
-					   &mcasp->chconstr[substream->stream]);
+	snd_pcm_hw_constraint_list(substream->runtime,
+				   0, SNDRV_PCM_HW_PARAM_CHANNELS,
+				   &mcasp->chconstr[substream->stream]);
+
+	if (mcasp->slot_width)
+		snd_pcm_hw_constraint_minmax(substream->runtime,
+					     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+					     8, mcasp->slot_width);
 
 	/*
 	 * If we rely on implicit BCLK divider setting we should
@@ -1184,6 +1314,7 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
 	.set_fmt	= davinci_mcasp_set_dai_fmt,
 	.set_clkdiv	= davinci_mcasp_set_clkdiv,
 	.set_sysclk	= davinci_mcasp_set_sysclk,
+	.set_tdm_slot	= davinci_mcasp_set_tdm_slot,
 };
 
 static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
@@ -1514,59 +1645,6 @@ nodata:
 	return  pdata;
 }
 
-/* All serializers must have equal number of channels */
-static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp,
-				       struct snd_pcm_hw_constraint_list *cl,
-				       int serializers)
-{
-	unsigned int *list;
-	int i, count = 0;
-
-	if (serializers <= 1)
-		return 0;
-
-	list = devm_kzalloc(mcasp->dev, sizeof(unsigned int) *
-			    (mcasp->tdm_slots + serializers - 2),
-			    GFP_KERNEL);
-	if (!list)
-		return -ENOMEM;
-
-	for (i = 2; i <= mcasp->tdm_slots; i++)
-		list[count++] = i;
-
-	for (i = 2; i <= serializers; i++)
-		list[count++] = i*mcasp->tdm_slots;
-
-	cl->count = count;
-	cl->list = list;
-
-	return 0;
-}
-
-
-static int davinci_mcasp_init_ch_constraints(struct davinci_mcasp *mcasp)
-{
-	int rx_serializers = 0, tx_serializers = 0, ret, i;
-
-	for (i = 0; i < mcasp->num_serializer; i++)
-		if (mcasp->serial_dir[i] == TX_MODE)
-			tx_serializers++;
-		else if (mcasp->serial_dir[i] == RX_MODE)
-			rx_serializers++;
-
-	ret = davinci_mcasp_ch_constraint(mcasp, &mcasp->chconstr[
-						  SNDRV_PCM_STREAM_PLAYBACK],
-					  tx_serializers);
-	if (ret)
-		return ret;
-
-	ret = davinci_mcasp_ch_constraint(mcasp, &mcasp->chconstr[
-						  SNDRV_PCM_STREAM_CAPTURE],
-					  rx_serializers);
-
-	return ret;
-}
-
 enum {
 	PCM_EDMA,
 	PCM_SDMA,
@@ -1783,7 +1861,28 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 		mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
 	}
 
-	ret = davinci_mcasp_init_ch_constraints(mcasp);
+	/* Allocate memory for long enough list for all possible
+	 * scenarios. Maximum number tdm slots is 32 and there cannot
+	 * be more serializers than given in the configuration.  The
+	 * serializer directions could be taken into account, but it
+	 * would make code much more complex and save only couple of
+	 * bytes.
+	 */
+	mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list =
+		devm_kzalloc(mcasp->dev, sizeof(unsigned int) *
+			     (32 + mcasp->num_serializer - 2),
+			     GFP_KERNEL);
+
+	mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list =
+		devm_kzalloc(mcasp->dev, sizeof(unsigned int) *
+			     (32 + mcasp->num_serializer - 2),
+			     GFP_KERNEL);
+
+	if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list ||
+	    !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list)
+		return -ENOMEM;
+
+	ret = davinci_mcasp_set_ch_constraints(mcasp);
 	if (ret)
 		goto err;
 
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 96f55ae75c71..0901d5e20df2 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -593,6 +593,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = {
 	{ .compatible = "fsl,imx-audio-wm8960", },
 	{}
 };
+MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids);
 
 static struct platform_driver fsl_asoc_card_driver = {
 	.probe = fsl_asoc_card_probe,
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index a18fd92c4a85..9366b5a42e1d 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -801,6 +801,7 @@ static const struct of_device_id fsl_sai_ids[] = {
 	{ .compatible = "fsl,imx6sx-sai", },
 	{ /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, fsl_sai_ids);
 
 static struct platform_driver fsl_sai_driver = {
 	.probe = fsl_sai_probe,
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 3ff76d419436..54c33204541f 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -151,7 +151,9 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
 	}
 
 	if (set->slots) {
-		ret = snd_soc_dai_set_tdm_slot(dai, 0, 0,
+		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) {
@@ -243,7 +245,9 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
 		return ret;
 
 	/* Parse TDM slot */
-	ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
+	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;
 
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index 683e50116152..5e9c316c142a 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -368,23 +368,6 @@ static void sst_media_close(struct snd_pcm_substream *substream,
 	kfree(stream);
 }
 
-static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai,
-					       struct snd_pcm_substream *substream)
-{
-	struct sst_data *sst = snd_soc_dai_get_drvdata(dai);
-	struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map;
-	struct sst_runtime_stream *stream =
-			substream->runtime->private_data;
-	u32 str_id = stream->stream_info.str_id;
-	unsigned int pipe_id;
-
-	pipe_id = map[str_id].device_id;
-
-	dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n",
-			pipe_id, str_id);
-	return pipe_id;
-}
-
 static int sst_media_prepare(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c
index 8bafaf6ceab1..3f8a1e10bed0 100644
--- a/sound/soc/intel/boards/broadwell.c
+++ b/sound/soc/intel/boards/broadwell.c
@@ -266,18 +266,11 @@ static int broadwell_audio_probe(struct platform_device *pdev)
 {
 	broadwell_rt286.dev = &pdev->dev;
 
-	return snd_soc_register_card(&broadwell_rt286);
-}
-
-static int broadwell_audio_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_card(&broadwell_rt286);
-	return 0;
+	return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
 }
 
 static struct platform_driver broadwell_audio = {
 	.probe = broadwell_audio_probe,
-	.remove = broadwell_audio_remove,
 	.driver = {
 		.name = "broadwell-audio",
 	},
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 7d617bf493bc..bea26730873c 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -510,17 +510,6 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
 	},
 },
 {
-	.name = "DMIC23 Pin",
-	.ops = &skl_dmic_dai_ops,
-	.capture = {
-		.stream_name = "DMIC23 Rx",
-		.channels_min = HDA_STEREO,
-		.channels_max = HDA_STEREO,
-		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
-	},
-},
-{
 	.name = "HD-Codec Pin",
 	.ops = &skl_link_dai_ops,
 	.playback = {
@@ -538,28 +527,6 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	},
 },
-{
-	.name = "HD-Codec-SPK Pin",
-	.ops = &skl_link_dai_ops,
-	.playback = {
-		.stream_name = "HD-Codec-SPK Tx",
-		.channels_min = HDA_STEREO,
-		.channels_max = HDA_STEREO,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-},
-{
-	.name = "HD-Codec-AMIC Pin",
-	.ops = &skl_link_dai_ops,
-	.capture = {
-		.stream_name = "HD-Codec-AMIC Rx",
-		.channels_min = HDA_STEREO,
-		.channels_max = HDA_STEREO,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-},
 };
 
 static int skl_platform_open(struct snd_pcm_substream *substream)
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index b05fb1c1a848..794a3499e567 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -485,6 +485,7 @@ static const struct of_device_id jz4740_of_matches[] = {
 	{ .compatible = "ingenic,jz4780-i2s", .data = (void *)JZ_I2S_JZ4780 },
 	{ /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, jz4740_of_matches);
 #endif
 
 static int jz4740_i2s_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/kirkwood/armada-370-db.c b/sound/soc/kirkwood/armada-370-db.c
index de7563bdc5c2..e0304d544f26 100644
--- a/sound/soc/kirkwood/armada-370-db.c
+++ b/sound/soc/kirkwood/armada-370-db.c
@@ -130,6 +130,7 @@ static const struct of_device_id a370db_dt_ids[] = {
 	{ .compatible = "marvell,a370db-audio" },
 	{ },
 };
+MODULE_DEVICE_TABLE(of, a370db_dt_ids);
 
 static struct platform_driver a370db_driver = {
 	.driver		= {
diff --git a/sound/soc/mediatek/mt8173-max98090.c b/sound/soc/mediatek/mt8173-max98090.c
index 684e8a78bed0..71a1a35047ba 100644
--- a/sound/soc/mediatek/mt8173-max98090.c
+++ b/sound/soc/mediatek/mt8173-max98090.c
@@ -179,21 +179,13 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev)
 	}
 	card->dev = &pdev->dev;
 
-	ret = snd_soc_register_card(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 int mt8173_max98090_dev_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
-	return 0;
-}
-
 static const struct of_device_id mt8173_max98090_dt_match[] = {
 	{ .compatible = "mediatek,mt8173-max98090", },
 	{ }
@@ -209,7 +201,6 @@ static struct platform_driver mt8173_max98090_driver = {
 #endif
 	},
 	.probe = mt8173_max98090_dev_probe,
-	.remove = mt8173_max98090_dev_remove,
 };
 
 module_platform_driver(mt8173_max98090_driver);
diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173-rt5650-rt5676.c
index 86cf9752f18a..50ba538eccb3 100644
--- a/sound/soc/mediatek/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173-rt5650-rt5676.c
@@ -246,21 +246,13 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 
-	ret = snd_soc_register_card(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 int mt8173_rt5650_rt5676_dev_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
-	return 0;
-}
-
 static const struct of_device_id mt8173_rt5650_rt5676_dt_match[] = {
 	{ .compatible = "mediatek,mt8173-rt5650-rt5676", },
 	{ }
@@ -276,7 +268,6 @@ static struct platform_driver mt8173_rt5650_rt5676_driver = {
 #endif
 	},
 	.probe = mt8173_rt5650_rt5676_dev_probe,
-	.remove = mt8173_rt5650_rt5676_dev_remove,
 };
 
 module_platform_driver(mt8173_rt5650_rt5676_driver);
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index 6e6fce6a14ba..2b23ffbac6b1 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -142,7 +142,7 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev)
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 
-	ret = snd_soc_register_card(card);
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
 			ret);
@@ -154,12 +154,8 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev)
 
 static int mxs_sgtl5000_remove(struct platform_device *pdev)
 {
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
 	mxs_saif_put_mclk(0);
 
-	snd_soc_unregister_card(card);
-
 	return 0;
 }
 
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c
index 2b26318bc200..6147e86e9b0f 100644
--- a/sound/soc/pxa/brownstone.c
+++ b/sound/soc/pxa/brownstone.c
@@ -116,26 +116,19 @@ static int brownstone_probe(struct platform_device *pdev)
 	int ret;
 
 	brownstone.dev = &pdev->dev;
-	ret = snd_soc_register_card(&brownstone);
+	ret = devm_snd_soc_register_card(&pdev->dev, &brownstone);
 	if (ret)
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 				ret);
 	return ret;
 }
 
-static int brownstone_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_card(&brownstone);
-	return 0;
-}
-
 static struct platform_driver mmp_driver = {
 	.driver		= {
 		.name	= "brownstone-audio",
 		.pm     = &snd_soc_pm_ops,
 	},
 	.probe		= brownstone_probe,
-	.remove		= brownstone_remove,
 };
 
 module_platform_driver(mmp_driver);
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 3580d10c9f28..c97dc13d3608 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -295,28 +295,19 @@ static int corgi_probe(struct platform_device *pdev)
 
 	card->dev = &pdev->dev;
 
-	ret = snd_soc_register_card(card);
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret)
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 			ret);
 	return ret;
 }
 
-static int corgi_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
-	return 0;
-}
-
 static struct platform_driver corgi_driver = {
 	.driver		= {
 		.name	= "corgi-audio",
 		.pm     = &snd_soc_pm_ops,
 	},
 	.probe		= corgi_probe,
-	.remove		= corgi_remove,
 };
 
 module_platform_driver(corgi_driver);
diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c
index d72e124a3676..1de876529aa1 100644
--- a/sound/soc/pxa/e740_wm9705.c
+++ b/sound/soc/pxa/e740_wm9705.c
@@ -138,7 +138,7 @@ static int e740_probe(struct platform_device *pdev)
 
 	card->dev = &pdev->dev;
 
-	ret = snd_soc_register_card(card);
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 			ret);
@@ -149,10 +149,7 @@ static int e740_probe(struct platform_device *pdev)
 
 static int e740_remove(struct platform_device *pdev)
 {
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
 	gpio_free_array(e740_audio_gpios, ARRAY_SIZE(e740_audio_gpios));
-	snd_soc_unregister_card(card);
 	return 0;
 }
 
diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c
index 48f2d7c2e68c..b7eb7cd5df7d 100644
--- a/sound/soc/pxa/e750_wm9705.c
+++ b/sound/soc/pxa/e750_wm9705.c
@@ -120,7 +120,7 @@ static int e750_probe(struct platform_device *pdev)
 
 	card->dev = &pdev->dev;
 
-	ret = snd_soc_register_card(card);
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 			ret);
@@ -131,10 +131,7 @@ static int e750_probe(struct platform_device *pdev)
 
 static int e750_remove(struct platform_device *pdev)
 {
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
 	gpio_free_array(e750_audio_gpios, ARRAY_SIZE(e750_audio_gpios));
-	snd_soc_unregister_card(card);
 	return 0;
 }
 
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c
index 45d4bd46fff6..41bf71466a7b 100644
--- a/sound/soc/pxa/e800_wm9712.c
+++ b/sound/soc/pxa/e800_wm9712.c
@@ -119,7 +119,7 @@ static int e800_probe(struct platform_device *pdev)
 
 	card->dev = &pdev->dev;
 
-	ret = snd_soc_register_card(card);
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 			ret);
@@ -130,10 +130,7 @@ static int e800_probe(struct platform_device *pdev)
 
 static int e800_remove(struct platform_device *pdev)
 {
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
 	gpio_free_array(e800_audio_gpios, ARRAY_SIZE(e800_audio_gpios));
-	snd_soc_unregister_card(card);
 	return 0;
 }
 
diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c
index 9f8be7cd567e..ecbf2873b7ff 100644
--- a/sound/soc/pxa/hx4700.c
+++ b/sound/soc/pxa/hx4700.c
@@ -193,7 +193,7 @@ static int hx4700_audio_probe(struct platform_device *pdev)
 		return ret;
 
 	snd_soc_card_hx4700.dev = &pdev->dev;
-	ret = snd_soc_register_card(&snd_soc_card_hx4700);
+	ret = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_hx4700);
 	if (ret)
 		gpio_free_array(hx4700_audio_gpios,
 				ARRAY_SIZE(hx4700_audio_gpios));
@@ -203,8 +203,6 @@ static int hx4700_audio_probe(struct platform_device *pdev)
 
 static int hx4700_audio_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_card(&snd_soc_card_hx4700);
-
 	gpio_set_value(GPIO92_HX4700_HP_DRIVER, 0);
 	gpio_set_value(GPIO107_HX4700_SPK_nSD, 0);
 
diff --git a/sound/soc/pxa/imote2.c b/sound/soc/pxa/imote2.c
index 29fabbfd21f1..9d0e40771ef5 100644
--- a/sound/soc/pxa/imote2.c
+++ b/sound/soc/pxa/imote2.c
@@ -72,28 +72,19 @@ static int imote2_probe(struct platform_device *pdev)
 
 	card->dev = &pdev->dev;
 
-	ret = snd_soc_register_card(card);
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret)
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 			ret);
 	return ret;
 }
 
-static int imote2_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
-	return 0;
-}
-
 static struct platform_driver imote2_driver = {
 	.driver		= {
 		.name	= "imote2-audio",
 		.pm     = &snd_soc_pm_ops,
 	},
 	.probe		= imote2_probe,
-	.remove		= imote2_remove,
 };
 
 module_platform_driver(imote2_driver);
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index a9615a574546..29bc60e85e92 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -181,7 +181,7 @@ static int mioa701_wm9713_probe(struct platform_device *pdev)
 		return -ENODEV;
 
 	mioa701.dev = &pdev->dev;
-	rc =  snd_soc_register_card(&mioa701);
+	rc = devm_snd_soc_register_card(&pdev->dev, &mioa701);
 	if (!rc)
 		dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will"
 			 "lead to overheating and possible destruction of your device."
@@ -189,17 +189,8 @@ static int mioa701_wm9713_probe(struct platform_device *pdev)
 	return rc;
 }
 
-static int mioa701_wm9713_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
-	return 0;
-}
-
 static struct platform_driver mioa701_wm9713_driver = {
 	.probe		= mioa701_wm9713_probe,
-	.remove		= mioa701_wm9713_remove,
 	.driver		= {
 		.name		= "mioa701-wm9713",
 		.pm     = &snd_soc_pm_ops,
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c
index c20bbc042425..4e74d9573f03 100644
--- a/sound/soc/pxa/palm27x.c
+++ b/sound/soc/pxa/palm27x.c
@@ -140,22 +140,15 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
 
 	palm27x_asoc.dev = &pdev->dev;
 
-	ret = snd_soc_register_card(&palm27x_asoc);
+	ret = devm_snd_soc_register_card(&pdev->dev, &palm27x_asoc);
 	if (ret)
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 			ret);
 	return ret;
 }
 
-static int palm27x_asoc_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_card(&palm27x_asoc);
-	return 0;
-}
-
 static struct platform_driver palm27x_wm9712_driver = {
 	.probe		= palm27x_asoc_probe,
-	.remove		= palm27x_asoc_remove,
 	.driver		= {
 		.name		= "palm27x-asoc",
 		.pm     = &snd_soc_pm_ops,
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index 80b457ac522a..84d0e2e50808 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -267,28 +267,19 @@ static int poodle_probe(struct platform_device *pdev)
 
 	card->dev = &pdev->dev;
 
-	ret = snd_soc_register_card(card);
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret)
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 			ret);
 	return ret;
 }
 
-static int poodle_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
-	return 0;
-}
-
 static struct platform_driver poodle_driver = {
 	.driver		= {
 		.name	= "poodle-audio",
 		.pm     = &snd_soc_pm_ops,
 	},
 	.probe		= poodle_probe,
-	.remove		= poodle_remove,
 };
 
 module_platform_driver(poodle_driver);
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 3da485ec1de7..da03fad1b9cd 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -809,6 +809,7 @@ static const struct of_device_id pxa_ssp_of_ids[] = {
 	{ .compatible = "mrvl,pxa-ssp-dai" },
 	{}
 };
+MODULE_DEVICE_TABLE(of, pxa_ssp_of_ids);
 #endif
 
 static int asoc_ssp_probe(struct platform_device *pdev)
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index 831ee37d2e3e..29a3fdbb7b59 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -132,6 +132,7 @@ static const struct of_device_id snd_soc_pxa_audio_match[] = {
 	{ .compatible   = "mrvl,pxa-pcm-audio" },
 	{ }
 };
+MODULE_DEVICE_TABLE(of, snd_soc_pxa_audio_match);
 #endif
 
 static struct platform_driver pxa_pcm_driver = {
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index 461123ad5ff2..b00222620fd0 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -305,7 +305,7 @@ static int spitz_probe(struct platform_device *pdev)
 
 	card->dev = &pdev->dev;
 
-	ret = snd_soc_register_card(card);
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 			ret);
@@ -322,9 +322,6 @@ err1:
 
 static int spitz_remove(struct platform_device *pdev)
 {
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
 	gpio_free(spitz_mic_gpio);
 	return 0;
 }
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index f59f566551ef..49518dd642aa 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -233,7 +233,7 @@ static int tosa_probe(struct platform_device *pdev)
 
 	card->dev = &pdev->dev;
 
-	ret = snd_soc_register_card(card);
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 			ret);
@@ -244,10 +244,7 @@ static int tosa_probe(struct platform_device *pdev)
 
 static int tosa_remove(struct platform_device *pdev)
 {
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
 	gpio_free(TOSA_GPIO_L_MUTE);
-	snd_soc_unregister_card(card);
 	return 0;
 }
 
diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c
index 1753c7d9e760..65c20f779177 100644
--- a/sound/soc/pxa/ttc-dkb.c
+++ b/sound/soc/pxa/ttc-dkb.c
@@ -128,7 +128,7 @@ static int ttc_dkb_probe(struct platform_device *pdev)
 
 	card->dev = &pdev->dev;
 
-	ret = snd_soc_register_card(card);
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret)
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 			ret);
@@ -136,22 +136,12 @@ static int ttc_dkb_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static int ttc_dkb_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
-
-	return 0;
-}
-
 static struct platform_driver ttc_dkb_driver = {
 	.driver		= {
 		.name	= "ttc-dkb-audio",
 		.pm     = &snd_soc_pm_ops,
 	},
 	.probe		= ttc_dkb_probe,
-	.remove		= ttc_dkb_remove,
 };
 
 module_platform_driver(ttc_dkb_driver);
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 97bc2023f08a..e5101e0d2d37 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -438,7 +438,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 		if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
 			dev_err(&pdev->dev,
 				"%s() error getting mi2s-bit-clk: %ld\n",
-				__func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));
+				__func__,
+				PTR_ERR(drvdata->mi2s_bit_clk[dai_id]));
 			return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
 		}
 	}
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index 58bae8e2cf5f..570905709d3a 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -17,7 +17,7 @@ config SND_SOC_ROCKCHIP_I2S
 
 config SND_SOC_ROCKCHIP_MAX98090
 	tristate "ASoC support for Rockchip boards using a MAX98090 codec"
-	depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB
+	depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && CLKDEV_LOOKUP
 	select SND_SOC_ROCKCHIP_I2S
 	select SND_SOC_MAX98090
 	select SND_SOC_TS3A227E
@@ -27,7 +27,7 @@ config SND_SOC_ROCKCHIP_MAX98090
 
 config SND_SOC_ROCKCHIP_RT5645
 	tristate "ASoC support for Rockchip boards using a RT5645/RT5650 codec"
-	depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB
+	depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && CLKDEV_LOOKUP
 	select SND_SOC_ROCKCHIP_I2S
 	select SND_SOC_RT5645
 	help
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 07114b0b0dc1..6ca90aaf141f 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU
 config SND_SOC_RCAR
 	tristate "R-Car series SRU/SCU/SSIU/SSI support"
 	depends on DMA_OF
+	depends on COMMON_CLK
 	select SND_SIMPLE_CARD
 	select REGMAP_MMIO
 	help
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index fefc881dbac2..c4ebbb7a7b6f 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -7,7 +7,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
-#include <linux/sh_clk.h>
+#include <linux/clk-provider.h>
 #include "rsnd.h"
 
 #define CLKA	0
@@ -16,12 +16,26 @@
 #define CLKI	3
 #define CLKMAX	4
 
+#define CLKOUT	0
+#define CLKOUT1	1
+#define CLKOUT2	2
+#define CLKOUT3	3
+#define CLKOUTMAX 4
+
+#define BRRx_MASK(x) (0x3FF & x)
+
+static struct rsnd_mod_ops adg_ops = {
+	.name = "adg",
+};
+
 struct rsnd_adg {
 	struct clk *clk[CLKMAX];
+	struct clk *clkout[CLKOUTMAX];
+	struct clk_onecell_data onecell;
+	struct rsnd_mod mod;
 
-	int rbga_rate_for_441khz_div_6;	/* RBGA */
-	int rbgb_rate_for_48khz_div_6;	/* RBGB */
-	u32 ckr;
+	int rbga_rate_for_441khz; /* RBGA */
+	int rbgb_rate_for_48khz;  /* RBGB */
 };
 
 #define for_each_rsnd_clk(pos, adg, i)		\
@@ -29,8 +43,28 @@ struct rsnd_adg {
 	     (i < CLKMAX) &&			\
 	     ((pos) = adg->clk[i]);		\
 	     i++)
+#define for_each_rsnd_clkout(pos, adg, i)	\
+	for (i = 0;				\
+	     (i < CLKOUTMAX) &&			\
+	     ((pos) = adg->clkout[i]);	\
+	     i++)
 #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
 
+static u32 rsnd_adg_calculate_rbgx(unsigned long div)
+{
+	int i, ratio;
+
+	if (!div)
+		return 0;
+
+	for (i = 3; i >= 0; i--) {
+		ratio = 2 << (i * 2);
+		if (0 == (div % ratio))
+			return (u32)((i << 8) | ((div / ratio) - 1));
+	}
+
+	return ~0;
+}
 
 static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
 {
@@ -60,6 +94,9 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
 int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
 				 struct rsnd_dai_stream *io)
 {
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
 	int id = rsnd_mod_id(mod);
 	int shift = (id % 2) ? 16 : 0;
 	u32 mask, val;
@@ -69,21 +106,26 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
 	val  = val	<< shift;
 	mask = 0xffff	<< shift;
 
-	rsnd_mod_bset(mod, CMDOUT_TIMSEL, mask, val);
+	rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val);
 
 	return 0;
 }
 
-static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *mod,
+static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *src_mod,
 					struct rsnd_dai_stream *io,
 					u32 timsel)
 {
+	struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
+	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
 	int is_play = rsnd_io_is_play(io);
-	int id = rsnd_mod_id(mod);
+	int id = rsnd_mod_id(src_mod);
 	int shift = (id % 2) ? 16 : 0;
 	u32 mask, ws;
 	u32 in, out;
 
+	rsnd_mod_confirm_src(src_mod);
+
 	ws = rsnd_adg_ssi_ws_timing_gen2(io);
 
 	in  = (is_play) ? timsel : ws;
@@ -95,37 +137,38 @@ static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *mod,
 
 	switch (id / 2) {
 	case 0:
-		rsnd_mod_bset(mod, SRCIN_TIMSEL0,  mask, in);
-		rsnd_mod_bset(mod, SRCOUT_TIMSEL0, mask, out);
+		rsnd_mod_bset(adg_mod, SRCIN_TIMSEL0,  mask, in);
+		rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL0, mask, out);
 		break;
 	case 1:
-		rsnd_mod_bset(mod, SRCIN_TIMSEL1,  mask, in);
-		rsnd_mod_bset(mod, SRCOUT_TIMSEL1, mask, out);
+		rsnd_mod_bset(adg_mod, SRCIN_TIMSEL1,  mask, in);
+		rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL1, mask, out);
 		break;
 	case 2:
-		rsnd_mod_bset(mod, SRCIN_TIMSEL2,  mask, in);
-		rsnd_mod_bset(mod, SRCOUT_TIMSEL2, mask, out);
+		rsnd_mod_bset(adg_mod, SRCIN_TIMSEL2,  mask, in);
+		rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL2, mask, out);
 		break;
 	case 3:
-		rsnd_mod_bset(mod, SRCIN_TIMSEL3,  mask, in);
-		rsnd_mod_bset(mod, SRCOUT_TIMSEL3, mask, out);
+		rsnd_mod_bset(adg_mod, SRCIN_TIMSEL3,  mask, in);
+		rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL3, mask, out);
 		break;
 	case 4:
-		rsnd_mod_bset(mod, SRCIN_TIMSEL4,  mask, in);
-		rsnd_mod_bset(mod, SRCOUT_TIMSEL4, mask, out);
+		rsnd_mod_bset(adg_mod, SRCIN_TIMSEL4,  mask, in);
+		rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL4, mask, out);
 		break;
 	}
 
 	return 0;
 }
 
-int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
+int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *src_mod,
 				  struct rsnd_dai_stream *io,
 				  unsigned int src_rate,
 				  unsigned int dst_rate)
 {
-	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
 	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
 	struct device *dev = rsnd_priv_to_dev(priv);
 	int idx, sel, div, step, ret;
 	u32 val, en;
@@ -134,10 +177,12 @@ int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
 		clk_get_rate(adg->clk[CLKA]),	/* 0000: CLKA */
 		clk_get_rate(adg->clk[CLKB]),	/* 0001: CLKB */
 		clk_get_rate(adg->clk[CLKC]),	/* 0010: CLKC */
-		adg->rbga_rate_for_441khz_div_6,/* 0011: RBGA */
-		adg->rbgb_rate_for_48khz_div_6,	/* 0100: RBGB */
+		adg->rbga_rate_for_441khz,	/* 0011: RBGA */
+		adg->rbgb_rate_for_48khz,	/* 0100: RBGB */
 	};
 
+	rsnd_mod_confirm_src(src_mod);
+
 	min = ~0;
 	val = 0;
 	en = 0;
@@ -175,25 +220,27 @@ int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
 		return -EIO;
 	}
 
-	ret = rsnd_adg_set_src_timsel_gen2(mod, io, val);
+	ret = rsnd_adg_set_src_timsel_gen2(src_mod, io, val);
 	if (ret < 0) {
 		dev_err(dev, "timsel error\n");
 		return ret;
 	}
 
-	rsnd_mod_bset(mod, DIV_EN, en, en);
+	rsnd_mod_bset(adg_mod, DIV_EN, en, en);
 
 	dev_dbg(dev, "convert rate %d <-> %d\n", src_rate, dst_rate);
 
 	return 0;
 }
 
-int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
+int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *src_mod,
 				     struct rsnd_dai_stream *io)
 {
 	u32 val = rsnd_adg_ssi_ws_timing_gen2(io);
 
-	return rsnd_adg_set_src_timsel_gen2(mod, io, val);
+	rsnd_mod_confirm_src(src_mod);
+
+	return rsnd_adg_set_src_timsel_gen2(src_mod, io, val);
 }
 
 int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
@@ -202,6 +249,7 @@ int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
 				  unsigned int dst_rate)
 {
 	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
 	struct device *dev = rsnd_priv_to_dev(priv);
 	int idx, sel, div, shift;
 	u32 mask, val;
@@ -211,8 +259,8 @@ int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
 		clk_get_rate(adg->clk[CLKB]),	/* 001: CLKB */
 		clk_get_rate(adg->clk[CLKC]),	/* 010: CLKC */
 		0,				/* 011: MLBCLK (not used) */
-		adg->rbga_rate_for_441khz_div_6,/* 100: RBGA */
-		adg->rbgb_rate_for_48khz_div_6,	/* 101: RBGB */
+		adg->rbga_rate_for_441khz,	/* 100: RBGA */
+		adg->rbgb_rate_for_48khz,	/* 101: RBGB */
 	};
 
 	/* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */
@@ -238,13 +286,13 @@ find_rate:
 
 	switch (id / 4) {
 	case 0:
-		rsnd_mod_bset(mod, AUDIO_CLK_SEL3, mask, val);
+		rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL3, mask, val);
 		break;
 	case 1:
-		rsnd_mod_bset(mod, AUDIO_CLK_SEL4, mask, val);
+		rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL4, mask, val);
 		break;
 	case 2:
-		rsnd_mod_bset(mod, AUDIO_CLK_SEL5, mask, val);
+		rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL5, mask, val);
 		break;
 	}
 
@@ -257,12 +305,17 @@ find_rate:
 	return 0;
 }
 
-static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val)
+static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
 {
-	int id = rsnd_mod_id(mod);
+	struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
+	int id = rsnd_mod_id(ssi_mod);
 	int shift = (id % 4) * 8;
 	u32 mask = 0xFF << shift;
 
+	rsnd_mod_confirm_ssi(ssi_mod);
+
 	val = val << shift;
 
 	/*
@@ -274,13 +327,13 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val)
 
 	switch (id / 4) {
 	case 0:
-		rsnd_mod_bset(mod, AUDIO_CLK_SEL0, mask, val);
+		rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL0, mask, val);
 		break;
 	case 1:
-		rsnd_mod_bset(mod, AUDIO_CLK_SEL1, mask, val);
+		rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL1, mask, val);
 		break;
 	case 2:
-		rsnd_mod_bset(mod, AUDIO_CLK_SEL2, mask, val);
+		rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val);
 		break;
 	}
 }
@@ -326,14 +379,14 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
 	}
 
 	/*
-	 * find 1/6 clock from BRGA/BRGB
+	 * find divided clock from BRGA/BRGB
 	 */
-	if (rate == adg->rbga_rate_for_441khz_div_6) {
+	if (rate  == adg->rbga_rate_for_441khz) {
 		data = 0x10;
 		goto found_clock;
 	}
 
-	if (rate == adg->rbgb_rate_for_48khz_div_6) {
+	if (rate == adg->rbgb_rate_for_48khz) {
 		data = 0x20;
 		goto found_clock;
 	}
@@ -342,29 +395,60 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
 
 found_clock:
 
-	/* see rsnd_adg_ssi_clk_init() */
-	rsnd_mod_bset(mod, SSICKR, 0x00FF0000, adg->ckr);
-	rsnd_mod_write(mod, BRRA,  0x00000002); /* 1/6 */
-	rsnd_mod_write(mod, BRRB,  0x00000002); /* 1/6 */
-
 	/*
 	 * This "mod" = "ssi" here.
 	 * we can get "ssi id" from mod
 	 */
 	rsnd_adg_set_ssi_clk(mod, data);
 
-	dev_dbg(dev, "ADG: ssi%d selects clk%d = %d",
-		rsnd_mod_id(mod), i, rate);
+	dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
+		rsnd_mod_name(mod), rsnd_mod_id(mod),
+		data, rate);
 
 	return 0;
 }
 
-static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
+static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
+			       struct rsnd_adg *adg)
 {
+	struct device *dev = rsnd_priv_to_dev(priv);
 	struct clk *clk;
-	unsigned long rate;
-	u32 ckr;
+	static const char * const clk_name[] = {
+		[CLKA]	= "clk_a",
+		[CLKB]	= "clk_b",
+		[CLKC]	= "clk_c",
+		[CLKI]	= "clk_i",
+	};
 	int i;
+
+	for (i = 0; i < CLKMAX; i++) {
+		clk = devm_clk_get(dev, clk_name[i]);
+		adg->clk[i] = IS_ERR(clk) ? NULL : clk;
+	}
+
+	for_each_rsnd_clk(clk, adg, i)
+		dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
+}
+
+static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
+				struct rsnd_adg *adg)
+{
+	struct clk *clk;
+	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct device_node *np = dev->of_node;
+	u32 ckr, rbgx, rbga, rbgb;
+	u32 rate, req_rate, div;
+	uint32_t count = 0;
+	unsigned long req_48kHz_rate, req_441kHz_rate;
+	int i;
+	const char *parent_clk_name = NULL;
+	static const char * const clkout_name[] = {
+		[CLKOUT]  = "audio_clkout",
+		[CLKOUT1] = "audio_clkout1",
+		[CLKOUT2] = "audio_clkout2",
+		[CLKOUT3] = "audio_clkout3",
+	};
 	int brg_table[] = {
 		[CLKA] = 0x0,
 		[CLKB] = 0x1,
@@ -372,19 +456,34 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
 		[CLKI] = 0x2,
 	};
 
+	of_property_read_u32(np, "#clock-cells", &count);
+
+	/*
+	 * ADG supports BRRA/BRRB output only
+	 * this means all clkout0/1/2/3 will be same rate
+	 */
+	of_property_read_u32(np, "clock-frequency", &req_rate);
+	req_48kHz_rate = 0;
+	req_441kHz_rate = 0;
+	if (0 == (req_rate % 44100))
+		req_441kHz_rate = req_rate;
+	if (0 == (req_rate % 48000))
+		req_48kHz_rate = req_rate;
+
 	/*
 	 * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
 	 * have 44.1kHz or 48kHz base clocks for now.
 	 *
 	 * SSI itself can divide parent clock by 1/1 - 1/16
-	 * So,  BRGA outputs 44.1kHz base parent clock 1/32,
-	 * and, BRGB outputs 48.0kHz base parent clock 1/32 here.
 	 * see
 	 *	rsnd_adg_ssi_clk_try_start()
+	 *	rsnd_ssi_master_clk_start()
 	 */
 	ckr = 0;
-	adg->rbga_rate_for_441khz_div_6 = 0;
-	adg->rbgb_rate_for_48khz_div_6  = 0;
+	rbga = 2; /* default 1/6 */
+	rbgb = 2; /* default 1/6 */
+	adg->rbga_rate_for_441khz	= 0;
+	adg->rbgb_rate_for_48khz	= 0;
 	for_each_rsnd_clk(clk, adg, i) {
 		rate = clk_get_rate(clk);
 
@@ -392,19 +491,86 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
 			continue;
 
 		/* RBGA */
-		if (!adg->rbga_rate_for_441khz_div_6 && (0 == rate % 44100)) {
-			adg->rbga_rate_for_441khz_div_6 = rate / 6;
-			ckr |= brg_table[i] << 20;
+		if (!adg->rbga_rate_for_441khz && (0 == rate % 44100)) {
+			div = 6;
+			if (req_441kHz_rate)
+				div = rate / req_441kHz_rate;
+			rbgx = rsnd_adg_calculate_rbgx(div);
+			if (BRRx_MASK(rbgx) == rbgx) {
+				rbga = rbgx;
+				adg->rbga_rate_for_441khz = rate / div;
+				ckr |= brg_table[i] << 20;
+				if (req_441kHz_rate)
+					parent_clk_name = __clk_get_name(clk);
+			}
 		}
 
 		/* RBGB */
-		if (!adg->rbgb_rate_for_48khz_div_6 && (0 == rate % 48000)) {
-			adg->rbgb_rate_for_48khz_div_6 = rate / 6;
-			ckr |= brg_table[i] << 16;
+		if (!adg->rbgb_rate_for_48khz && (0 == rate % 48000)) {
+			div = 6;
+			if (req_48kHz_rate)
+				div = rate / req_48kHz_rate;
+			rbgx = rsnd_adg_calculate_rbgx(div);
+			if (BRRx_MASK(rbgx) == rbgx) {
+				rbgb = rbgx;
+				adg->rbgb_rate_for_48khz = rate / div;
+				ckr |= brg_table[i] << 16;
+				if (req_48kHz_rate) {
+					parent_clk_name = __clk_get_name(clk);
+					ckr |= 0x80000000;
+				}
+			}
+		}
+	}
+
+	/*
+	 * ADG supports BRRA/BRRB output only.
+	 * this means all clkout0/1/2/3 will be * same rate
+	 */
+
+	/*
+	 * for clkout
+	 */
+	if (!count) {
+		clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT],
+					      parent_clk_name,
+					      (parent_clk_name) ?
+					      0 : CLK_IS_ROOT, req_rate);
+		if (!IS_ERR(clk)) {
+			adg->clkout[CLKOUT] = clk;
+			of_clk_add_provider(np, of_clk_src_simple_get, clk);
+		}
+	}
+	/*
+	 * for clkout0/1/2/3
+	 */
+	else {
+		for (i = 0; i < CLKOUTMAX; i++) {
+			clk = clk_register_fixed_rate(dev, clkout_name[i],
+						      parent_clk_name,
+						      (parent_clk_name) ?
+						      0 : CLK_IS_ROOT,
+						      req_rate);
+			if (!IS_ERR(clk)) {
+				adg->onecell.clks	= adg->clkout;
+				adg->onecell.clk_num	= CLKOUTMAX;
+
+				adg->clkout[i] = clk;
+
+				of_clk_add_provider(np, of_clk_src_onecell_get,
+						    &adg->onecell);
+			}
 		}
 	}
 
-	adg->ckr = ckr;
+	rsnd_mod_bset(adg_mod, SSICKR, 0x00FF0000, ckr);
+	rsnd_mod_write(adg_mod, BRRA,  rbga);
+	rsnd_mod_write(adg_mod, BRRB,  rbgb);
+
+	for_each_rsnd_clkout(clk, adg, i)
+		dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk));
+	dev_dbg(dev, "SSICKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
+		ckr, rbga, rbgb);
 }
 
 int rsnd_adg_probe(struct platform_device *pdev,
@@ -413,8 +579,6 @@ int rsnd_adg_probe(struct platform_device *pdev,
 {
 	struct rsnd_adg *adg;
 	struct device *dev = rsnd_priv_to_dev(priv);
-	struct clk *clk;
-	int i;
 
 	adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
 	if (!adg) {
@@ -422,15 +586,16 @@ int rsnd_adg_probe(struct platform_device *pdev,
 		return -ENOMEM;
 	}
 
-	adg->clk[CLKA]	= devm_clk_get(dev, "clk_a");
-	adg->clk[CLKB]	= devm_clk_get(dev, "clk_b");
-	adg->clk[CLKC]	= devm_clk_get(dev, "clk_c");
-	adg->clk[CLKI]	= devm_clk_get(dev, "clk_i");
-
-	for_each_rsnd_clk(clk, adg, i)
-		dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
+	/*
+	 * ADG is special module.
+	 * Use ADG mod without rsnd_mod_init() to make debug easy
+	 * for rsnd_write/rsnd_read
+	 */
+	adg->mod.ops = &adg_ops;
+	adg->mod.priv = priv;
 
-	rsnd_adg_ssi_clk_init(priv, adg);
+	rsnd_adg_get_clkin(priv, adg);
+	rsnd_adg_get_clkout(priv, adg);
 
 	priv->adg = adg;
 
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index f3feed5ce9b6..eec294da81e3 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -110,6 +110,7 @@ static const struct rsnd_of_data rsnd_of_data_gen2 = {
 static const struct of_device_id rsnd_of_match[] = {
 	{ .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 },
 	{ .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 },
+	{ .compatible = "renesas,rcar_sound-gen3", .data = &rsnd_of_data_gen2 }, /* gen2 compatible */
 	{},
 };
 MODULE_DEVICE_TABLE(of, rsnd_of_match);
@@ -126,6 +127,17 @@ MODULE_DEVICE_TABLE(of, rsnd_of_match);
 #define rsnd_info_id(priv, io, name) \
 	((io)->info->name - priv->info->name##_info)
 
+void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
+{
+	if (mod->type != type) {
+		struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+		struct device *dev = rsnd_priv_to_dev(priv);
+
+		dev_warn(dev, "%s[%d] is not your expected module\n",
+			 rsnd_mod_name(mod), rsnd_mod_id(mod));
+	}
+}
+
 /*
  *	rsnd_mod functions
  */
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index 05498bba5874..a3e7c716e1f7 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -66,7 +66,7 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
 	if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
 		id = 0;
 
-	return &((struct rsnd_ctu *)(priv->ctu) + id)->mod;
+	return rsnd_mod_get((struct rsnd_ctu *)(priv->ctu) + id);
 }
 
 static void rsnd_of_parse_ctu(struct platform_device *pdev,
@@ -150,7 +150,7 @@ int rsnd_ctu_probe(struct platform_device *pdev,
 
 		ctu->info = &info->ctu_info[i];
 
-		ret = rsnd_mod_init(priv, &ctu->mod, &rsnd_ctu_ops,
+		ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
 				    clk, RSND_MOD_CTU, i);
 		if (ret)
 			return ret;
@@ -166,6 +166,6 @@ void rsnd_ctu_remove(struct platform_device *pdev,
 	int i;
 
 	for_each_rsnd_ctu(ctu, priv, i) {
-		rsnd_mod_quit(&ctu->mod);
+		rsnd_mod_quit(rsnd_mod_get(ctu));
 	}
 }
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 57796387d482..8d8eee6350c9 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -282,7 +282,7 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
 	if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))
 		id = 0;
 
-	return &((struct rsnd_dvc *)(priv->dvc) + id)->mod;
+	return rsnd_mod_get((struct rsnd_dvc *)(priv->dvc) + id);
 }
 
 static void rsnd_of_parse_dvc(struct platform_device *pdev,
@@ -361,7 +361,7 @@ int rsnd_dvc_probe(struct platform_device *pdev,
 
 		dvc->info = &info->dvc_info[i];
 
-		ret = rsnd_mod_init(priv, &dvc->mod, &rsnd_dvc_ops,
+		ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
 			      clk, RSND_MOD_DVC, i);
 		if (ret)
 			return ret;
@@ -377,6 +377,6 @@ void rsnd_dvc_remove(struct platform_device *pdev,
 	int i;
 
 	for_each_rsnd_dvc(dvc, priv, i) {
-		rsnd_mod_quit(&dvc->mod);
+		rsnd_mod_quit(rsnd_mod_get(dvc));
 	}
 }
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
index 0d5c102db6f5..8544403ffb26 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/sh/rcar/mix.c
@@ -99,7 +99,7 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
 	if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
 		id = 0;
 
-	return &((struct rsnd_mix *)(priv->mix) + id)->mod;
+	return rsnd_mod_get((struct rsnd_mix *)(priv->mix) + id);
 }
 
 static void rsnd_of_parse_mix(struct platform_device *pdev,
@@ -179,7 +179,7 @@ int rsnd_mix_probe(struct platform_device *pdev,
 
 		mix->info = &info->mix_info[i];
 
-		ret = rsnd_mod_init(priv, &mix->mod, &rsnd_mix_ops,
+		ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
 				    clk, RSND_MOD_MIX, i);
 		if (ret)
 			return ret;
@@ -195,6 +195,6 @@ void rsnd_mix_remove(struct platform_device *pdev,
 	int i;
 
 	for_each_rsnd_mix(mix, priv, i) {
-		rsnd_mod_quit(&mix->mod);
+		rsnd_mod_quit(rsnd_mod_get(mix));
 	}
 }
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 7a0e52b4640a..e4068d78616c 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -214,6 +214,7 @@ struct rsnd_dma {
 };
 #define rsnd_dma_to_dmaen(dma)	(&(dma)->dma.en)
 #define rsnd_dma_to_dmapp(dma)	(&(dma)->dma.pp)
+#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
 
 void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
 void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
@@ -225,8 +226,6 @@ int rsnd_dma_probe(struct platform_device *pdev,
 struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
 					  struct rsnd_mod *mod, char *name);
 
-#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
-
 /*
  *	R-Car sound mod
  */
@@ -332,6 +331,7 @@ struct rsnd_mod {
 #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
 #define rsnd_mod_hw_start(mod)	clk_enable((mod)->clk)
 #define rsnd_mod_hw_stop(mod)	clk_disable((mod)->clk)
+#define rsnd_mod_get(ip)	(&(ip)->mod)
 
 int rsnd_mod_init(struct rsnd_priv *priv,
 		  struct rsnd_mod *mod,
@@ -627,4 +627,15 @@ void rsnd_dvc_remove(struct platform_device *pdev,
 		     struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
 
+#ifdef DEBUG
+void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
+#define rsnd_mod_confirm_ssi(mssi)	rsnd_mod_make_sure(mssi, RSND_MOD_SSI)
+#define rsnd_mod_confirm_src(msrc)	rsnd_mod_make_sure(msrc, RSND_MOD_SRC)
+#define rsnd_mod_confirm_dvc(mdvc)	rsnd_mod_make_sure(mdvc, RSND_MOD_DVC)
+#else
+#define rsnd_mod_confirm_ssi(mssi)
+#define rsnd_mod_confirm_src(msrc)
+#define rsnd_mod_confirm_dvc(mdvc)
+#endif
+
 #endif
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 89a18e102feb..ca7a20f03c9b 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -918,11 +918,10 @@ static void rsnd_src_reconvert_update(struct rsnd_dai_stream *io,
 	rsnd_mod_write(mod, SRC_IFSVR, fsrate);
 }
 
-static int rsnd_src_pcm_new(struct rsnd_mod *mod,
+static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod,
 			    struct rsnd_dai_stream *io,
 			    struct snd_soc_pcm_runtime *rtd)
 {
-	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
 	struct rsnd_src *src = rsnd_mod_to_src(mod);
 	int ret;
@@ -932,12 +931,6 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
 	 */
 
 	/*
-	 * Gen1 is not supported
-	 */
-	if (rsnd_is_gen1(priv))
-		return 0;
-
-	/*
 	 * SRC sync convert needs clock master
 	 */
 	if (!rsnd_rdai_is_clk_master(rdai))
@@ -975,7 +968,7 @@ static struct rsnd_mod_ops rsnd_src_gen2_ops = {
 	.start	= rsnd_src_start_gen2,
 	.stop	= rsnd_src_stop_gen2,
 	.hw_params = rsnd_src_hw_params,
-	.pcm_new = rsnd_src_pcm_new,
+	.pcm_new = rsnd_src_pcm_new_gen2,
 };
 
 struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
@@ -983,7 +976,7 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
 	if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv)))
 		id = 0;
 
-	return &((struct rsnd_src *)(priv->src) + id)->mod;
+	return rsnd_mod_get((struct rsnd_src *)(priv->src) + id);
 }
 
 static void rsnd_of_parse_src(struct platform_device *pdev,
@@ -1078,7 +1071,7 @@ int rsnd_src_probe(struct platform_device *pdev,
 
 		src->info = &info->src_info[i];
 
-		ret = rsnd_mod_init(priv, &src->mod, ops, clk, RSND_MOD_SRC, i);
+		ret = rsnd_mod_init(priv, rsnd_mod_get(src), ops, clk, RSND_MOD_SRC, i);
 		if (ret)
 			return ret;
 	}
@@ -1093,6 +1086,6 @@ void rsnd_src_remove(struct platform_device *pdev,
 	int i;
 
 	for_each_rsnd_src(src, priv, i) {
-		rsnd_mod_quit(&src->mod);
+		rsnd_mod_quit(rsnd_mod_get(src));
 	}
 }
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index d45b9a7e324e..5e05f9422073 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -128,10 +128,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
 	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
 	struct device *dev = rsnd_priv_to_dev(priv);
-	int i, j, ret;
-	int adg_clk_div_table[] = {
-		1, 6, /* see adg.c */
-	};
+	struct rsnd_mod *mod = rsnd_mod_get(ssi);
+	int j, ret;
 	int ssi_clk_mul_table[] = {
 		1, 2, 4, 8, 16, 6, 12,
 	};
@@ -141,28 +139,25 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
 	/*
 	 * Find best clock, and try to start ADG
 	 */
-	for (i = 0; i < ARRAY_SIZE(adg_clk_div_table); i++) {
-		for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
-
-			/*
-			 * this driver is assuming that
-			 * system word is 64fs (= 2 x 32bit)
-			 * see rsnd_ssi_init()
-			 */
-			main_rate = rate / adg_clk_div_table[i]
-				* 32 * 2 * ssi_clk_mul_table[j];
-
-			ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate);
-			if (0 == ret) {
-				ssi->cr_clk	= FORCE | SWL_32 |
-						  SCKD | SWSD | CKDV(j);
-
-				dev_dbg(dev, "%s[%d] outputs %u Hz\n",
-					rsnd_mod_name(&ssi->mod),
-					rsnd_mod_id(&ssi->mod), rate);
-
-				return 0;
-			}
+	for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
+
+		/*
+		 * this driver is assuming that
+		 * system word is 64fs (= 2 x 32bit)
+		 * see rsnd_ssi_init()
+		 */
+		main_rate = rate * 32 * 2 * ssi_clk_mul_table[j];
+
+		ret = rsnd_adg_ssi_clk_try_start(mod, main_rate);
+		if (0 == ret) {
+			ssi->cr_clk	= FORCE | SWL_32 |
+				SCKD | SWSD | CKDV(j);
+
+			dev_dbg(dev, "%s[%d] outputs %u Hz\n",
+				rsnd_mod_name(mod),
+				rsnd_mod_id(mod), rate);
+
+			return 0;
 		}
 	}
 
@@ -172,8 +167,10 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
 
 static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
 {
+	struct rsnd_mod *mod = rsnd_mod_get(ssi);
+
 	ssi->cr_clk = 0;
-	rsnd_adg_ssi_clk_stop(&ssi->mod);
+	rsnd_adg_ssi_clk_stop(mod);
 }
 
 static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
@@ -182,11 +179,12 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
 	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
 	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_mod *mod = rsnd_mod_get(ssi);
 	u32 cr_mode;
 	u32 cr;
 
 	if (0 == ssi->usrcnt) {
-		rsnd_mod_hw_start(&ssi->mod);
+		rsnd_mod_hw_start(mod);
 
 		if (rsnd_rdai_is_clk_master(rdai)) {
 			struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
@@ -198,7 +196,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
 		}
 	}
 
-	if (rsnd_ssi_is_dma_mode(&ssi->mod)) {
+	if (rsnd_ssi_is_dma_mode(mod)) {
 		cr_mode = UIEN | OIEN |	/* over/under run */
 			  DMEN;		/* DMA : enable DMA */
 	} else {
@@ -210,24 +208,25 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
 		cr_mode		|
 		EN;
 
-	rsnd_mod_write(&ssi->mod, SSICR, cr);
+	rsnd_mod_write(mod, SSICR, cr);
 
 	/* enable WS continue */
 	if (rsnd_rdai_is_clk_master(rdai))
-		rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
+		rsnd_mod_write(mod, SSIWSR, CONT);
 
 	/* clear error status */
-	rsnd_mod_write(&ssi->mod, SSISR, 0);
+	rsnd_mod_write(mod, SSISR, 0);
 
 	ssi->usrcnt++;
 
 	dev_dbg(dev, "%s[%d] hw started\n",
-		rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod));
+		rsnd_mod_name(mod), rsnd_mod_id(mod));
 }
 
 static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi)
 {
-	struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+	struct rsnd_mod *mod = rsnd_mod_get(ssi);
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
 	struct device *dev = rsnd_priv_to_dev(priv);
 	u32 cr;
@@ -247,15 +246,15 @@ static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi)
 		cr  =	ssi->cr_own	|
 			ssi->cr_clk;
 
-		rsnd_mod_write(&ssi->mod, SSICR, cr | EN);
-		rsnd_ssi_status_check(&ssi->mod, DIRQ);
+		rsnd_mod_write(mod, SSICR, cr | EN);
+		rsnd_ssi_status_check(mod, DIRQ);
 
 		/*
 		 * disable SSI,
 		 * and, wait idle state
 		 */
-		rsnd_mod_write(&ssi->mod, SSICR, cr);	/* disabled all */
-		rsnd_ssi_status_check(&ssi->mod, IIRQ);
+		rsnd_mod_write(mod, SSICR, cr);	/* disabled all */
+		rsnd_ssi_status_check(mod, IIRQ);
 
 		if (rsnd_rdai_is_clk_master(rdai)) {
 			struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
@@ -266,13 +265,13 @@ static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi)
 				rsnd_ssi_master_clk_stop(ssi);
 		}
 
-		rsnd_mod_hw_stop(&ssi->mod);
+		rsnd_mod_hw_stop(mod);
 
 		ssi->chan = 0;
 	}
 
 	dev_dbg(dev, "%s[%d] hw stopped\n",
-		rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod));
+		rsnd_mod_name(mod), rsnd_mod_id(mod));
 }
 
 /*
@@ -371,7 +370,7 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
 	/* It will be removed on rsnd_ssi_hw_stop */
 	ssi->chan = chan;
 	if (ssi_parent)
-		return rsnd_ssi_hw_params(&ssi_parent->mod, io,
+		return rsnd_ssi_hw_params(rsnd_mod_get(ssi_parent), io,
 					  substream, params);
 
 	return 0;
@@ -379,12 +378,14 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
 
 static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
 {
+	struct rsnd_mod *mod = rsnd_mod_get(ssi);
+
 	/* under/over flow error */
 	if (status & (UIRQ | OIRQ)) {
 		ssi->err++;
 
 		/* clear error status */
-		rsnd_mod_write(&ssi->mod, SSISR, 0);
+		rsnd_mod_write(mod, SSISR, 0);
 	}
 }
 
@@ -656,7 +657,7 @@ struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
 	if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
 		id = 0;
 
-	return &((struct rsnd_ssi *)(priv->ssi) + id)->mod;
+	return rsnd_mod_get((struct rsnd_ssi *)(priv->ssi) + id);
 }
 
 int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
@@ -668,10 +669,12 @@ int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
 
 static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi)
 {
-	if (!rsnd_ssi_is_pin_sharing(&ssi->mod))
+	struct rsnd_mod *mod = rsnd_mod_get(ssi);
+
+	if (!rsnd_ssi_is_pin_sharing(mod))
 		return;
 
-	switch (rsnd_mod_id(&ssi->mod)) {
+	switch (rsnd_mod_id(mod)) {
 	case 1:
 	case 2:
 		ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0));
@@ -794,7 +797,8 @@ int rsnd_ssi_probe(struct platform_device *pdev,
 		else if (rsnd_ssi_pio_available(ssi))
 			ops = &rsnd_ssi_pio_ops;
 
-		ret = rsnd_mod_init(priv, &ssi->mod, ops, clk, RSND_MOD_SSI, i);
+		ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
+				    RSND_MOD_SSI, i);
 		if (ret)
 			return ret;
 
@@ -811,6 +815,6 @@ void rsnd_ssi_remove(struct platform_device *pdev,
 	int i;
 
 	for_each_rsnd_ssi(ssi, priv, i) {
-		rsnd_mod_quit(&ssi->mod);
+		rsnd_mod_quit(rsnd_mod_get(ssi));
 	}
 }
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
index abb0d956231c..76b2ab8c2b4a 100644
--- a/sound/soc/sh/siu_dai.c
+++ b/sound/soc/sh/siu_dai.c
@@ -738,7 +738,7 @@ static int siu_probe(struct platform_device *pdev)
 	struct siu_info *info;
 	int ret;
 
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	info = devm_kmalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 	siu_i2s_data = info;
@@ -746,7 +746,7 @@ static int siu_probe(struct platform_device *pdev)
 
 	ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
 	if (ret)
-		goto ereqfw;
+		return ret;
 
 	/*
 	 * Loaded firmware is "const" - read only, but we have to modify it in
@@ -757,89 +757,52 @@ static int siu_probe(struct platform_device *pdev)
 	release_firmware(fw_entry);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -ENODEV;
-		goto egetres;
-	}
+	if (!res)
+		return -ENODEV;
 
-	region = request_mem_region(res->start, resource_size(res),
-				    pdev->name);
+	region = devm_request_mem_region(&pdev->dev, res->start,
+					 resource_size(res), pdev->name);
 	if (!region) {
 		dev_err(&pdev->dev, "SIU region already claimed\n");
-		ret = -EBUSY;
-		goto ereqmemreg;
+		return -EBUSY;
 	}
 
-	ret = -ENOMEM;
-	info->pram = ioremap(res->start, PRAM_SIZE);
+	info->pram = devm_ioremap(&pdev->dev, res->start, PRAM_SIZE);
 	if (!info->pram)
-		goto emappram;
-	info->xram = ioremap(res->start + XRAM_OFFSET, XRAM_SIZE);
+		return -ENOMEM;
+	info->xram = devm_ioremap(&pdev->dev, res->start + XRAM_OFFSET,
+				  XRAM_SIZE);
 	if (!info->xram)
-		goto emapxram;
-	info->yram = ioremap(res->start + YRAM_OFFSET, YRAM_SIZE);
+		return -ENOMEM;
+	info->yram = devm_ioremap(&pdev->dev, res->start + YRAM_OFFSET,
+				  YRAM_SIZE);
 	if (!info->yram)
-		goto emapyram;
-	info->reg = ioremap(res->start + REG_OFFSET, resource_size(res) -
-			    REG_OFFSET);
+		return -ENOMEM;
+	info->reg = devm_ioremap(&pdev->dev, res->start + REG_OFFSET,
+			    resource_size(res) - REG_OFFSET);
 	if (!info->reg)
-		goto emapreg;
+		return -ENOMEM;
 
 	dev_set_drvdata(&pdev->dev, info);
 
 	/* register using ARRAY version so we can keep dai name */
-	ret = snd_soc_register_component(&pdev->dev, &siu_i2s_component,
-					 &siu_i2s_dai, 1);
+	ret = devm_snd_soc_register_component(&pdev->dev, &siu_i2s_component,
+					      &siu_i2s_dai, 1);
 	if (ret < 0)
-		goto edaiinit;
+		return ret;
 
-	ret = snd_soc_register_platform(&pdev->dev, &siu_platform);
+	ret = devm_snd_soc_register_platform(&pdev->dev, &siu_platform);
 	if (ret < 0)
-		goto esocregp;
+		return ret;
 
 	pm_runtime_enable(&pdev->dev);
 
-	return ret;
-
-esocregp:
-	snd_soc_unregister_component(&pdev->dev);
-edaiinit:
-	iounmap(info->reg);
-emapreg:
-	iounmap(info->yram);
-emapyram:
-	iounmap(info->xram);
-emapxram:
-	iounmap(info->pram);
-emappram:
-	release_mem_region(res->start, resource_size(res));
-ereqmemreg:
-egetres:
-ereqfw:
-	kfree(info);
-
-	return ret;
+	return 0;
 }
 
 static int siu_remove(struct platform_device *pdev)
 {
-	struct siu_info *info = dev_get_drvdata(&pdev->dev);
-	struct resource *res;
-
 	pm_runtime_disable(&pdev->dev);
-
-	snd_soc_unregister_platform(&pdev->dev);
-	snd_soc_unregister_component(&pdev->dev);
-
-	iounmap(info->reg);
-	iounmap(info->yram);
-	iounmap(info->xram);
-	iounmap(info->pram);
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res)
-		release_mem_region(res->start, resource_size(res));
-	kfree(info);
-
 	return 0;
 }
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 6173d15236c3..3b471f9c98c6 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3291,13 +3291,38 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
 
+static int snd_soc_of_get_slot_mask(struct device_node *np,
+				    const char *prop_name,
+				    unsigned int *mask)
+{
+	u32 val;
+	const __be32 *of_slot_mask = of_get_property(np, prop_name, &val);
+	int i;
+
+	if (!of_slot_mask)
+		return 0;
+	val /= sizeof(u32);
+	for (i = 0; i < val; i++)
+		if (be32_to_cpup(&of_slot_mask[i]))
+			*mask |= (1 << i);
+
+	return val;
+}
+
 int snd_soc_of_parse_tdm_slot(struct device_node *np,
+			      unsigned int *tx_mask,
+			      unsigned int *rx_mask,
 			      unsigned int *slots,
 			      unsigned int *slot_width)
 {
 	u32 val;
 	int ret;
 
+	if (tx_mask)
+		snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", tx_mask);
+	if (rx_mask)
+		snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask);
+
 	if (of_property_read_bool(np, "dai-tdm-slot-num")) {
 		ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
 		if (ret)
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 70e4b9d8bdcd..317395824cd7 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -34,6 +34,24 @@
 
 #define DPCM_MAX_BE_USERS	8
 
+/*
+ * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
+ *
+ * Returns true if the DAI supports the indicated stream type.
+ */
+static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream)
+{
+	struct snd_soc_pcm_stream *codec_stream;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		codec_stream = &dai->driver->playback;
+	else
+		codec_stream = &dai->driver->capture;
+
+	/* If the codec specifies any rate at all, it supports the stream. */
+	return codec_stream->rates;
+}
+
 /**
  * snd_soc_runtime_activate() - Increment active count for PCM runtime components
  * @rtd: ASoC PCM runtime that is activated
@@ -371,6 +389,20 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
 
 	/* first calculate min/max only for CODECs in the DAI link */
 	for (i = 0; i < rtd->num_codecs; i++) {
+
+		/*
+		 * Skip CODECs which don't support the current stream type.
+		 * Otherwise, since the rate, channel, and format values will
+		 * zero in that case, we would have no usable settings left,
+		 * causing the resulting setup to fail.
+		 * At least one CODEC should match, otherwise we should have
+		 * bailed out on a higher level, since there would be no
+		 * CODEC to support the transfer direction in that case.
+		 */
+		if (!snd_soc_dai_stream_valid(rtd->codec_dais[i],
+					      substream->stream))
+			continue;
+
 		codec_dai_drv = rtd->codec_dais[i]->driver;
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 			codec_stream = &codec_dai_drv->playback;
@@ -827,6 +859,23 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
 		struct snd_pcm_hw_params codec_params;
 
+		/*
+		 * Skip CODECs which don't support the current stream type,
+		 * the idea being that if a CODEC is not used for the currently
+		 * set up transfer direction, it should not need to be
+		 * configured, especially since the configuration used might
+		 * not even be supported by that CODEC. There may be cases
+		 * however where a CODEC needs to be set up although it is
+		 * actually not being used for the transfer, e.g. if a
+		 * capture-only CODEC is acting as an LRCLK and/or BCLK master
+		 * for the DAI link including a playback-only CODEC.
+		 * If this becomes necessary, we will have to augment the
+		 * machine driver setup with information on how to act, so
+		 * we can do the right thing here.
+		 */
+		if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
+			continue;
+
 		/* copy params for each codec */
 		codec_params = *params;
 
diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
new file mode 100644
index 000000000000..84c72ec6ad73
--- /dev/null
+++ b/sound/soc/sunxi/Kconfig
@@ -0,0 +1,11 @@
+menu "Allwinner SoC Audio support"
+
+config SND_SUN4I_CODEC
+	tristate "Allwinner A10 Codec Support"
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	select REGMAP_MMIO
+	help
+	  Select Y or M to add support for the Codec embedded in the Allwinner
+	  A10 and affiliated SoCs.
+
+endmenu
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
new file mode 100644
index 000000000000..ea8a08c881d6
--- /dev/null
+++ b/sound/soc/sunxi/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
+
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
new file mode 100644
index 000000000000..8d59d83b5aa4
--- /dev/null
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -0,0 +1,719 @@
+/*
+ * Copyright 2014 Emilio López <emilio@elopez.com.ar>
+ * Copyright 2014 Jon Smirl <jonsmirl@gmail.com>
+ * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * Based on the Allwinner SDK driver, released under the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/dmaengine_pcm.h>
+
+/* Codec DAC register offsets and bit fields */
+#define SUN4I_CODEC_DAC_DPC			(0x00)
+#define SUN4I_CODEC_DAC_DPC_EN_DA			(31)
+#define SUN4I_CODEC_DAC_DPC_DVOL			(12)
+#define SUN4I_CODEC_DAC_FIFOC			(0x04)
+#define SUN4I_CODEC_DAC_FIFOC_DAC_FS			(29)
+#define SUN4I_CODEC_DAC_FIFOC_FIR_VERSION		(28)
+#define SUN4I_CODEC_DAC_FIFOC_SEND_LASAT		(26)
+#define SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE		(24)
+#define SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT		(21)
+#define SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL		(8)
+#define SUN4I_CODEC_DAC_FIFOC_MONO_EN			(6)
+#define SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS		(5)
+#define SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN		(4)
+#define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH		(0)
+#define SUN4I_CODEC_DAC_FIFOS			(0x08)
+#define SUN4I_CODEC_DAC_TXDATA			(0x0c)
+#define SUN4I_CODEC_DAC_ACTL			(0x10)
+#define SUN4I_CODEC_DAC_ACTL_DACAENR			(31)
+#define SUN4I_CODEC_DAC_ACTL_DACAENL			(30)
+#define SUN4I_CODEC_DAC_ACTL_MIXEN			(29)
+#define SUN4I_CODEC_DAC_ACTL_LDACLMIXS			(15)
+#define SUN4I_CODEC_DAC_ACTL_RDACRMIXS			(14)
+#define SUN4I_CODEC_DAC_ACTL_LDACRMIXS			(13)
+#define SUN4I_CODEC_DAC_ACTL_DACPAS			(8)
+#define SUN4I_CODEC_DAC_ACTL_MIXPAS			(7)
+#define SUN4I_CODEC_DAC_ACTL_PA_MUTE			(6)
+#define SUN4I_CODEC_DAC_ACTL_PA_VOL			(0)
+#define SUN4I_CODEC_DAC_TUNE			(0x14)
+#define SUN4I_CODEC_DAC_DEBUG			(0x18)
+
+/* Codec ADC register offsets and bit fields */
+#define SUN4I_CODEC_ADC_FIFOC			(0x1c)
+#define SUN4I_CODEC_ADC_FIFOC_EN_AD			(28)
+#define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE		(24)
+#define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL		(8)
+#define SUN4I_CODEC_ADC_FIFOC_MONO_EN			(7)
+#define SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS		(6)
+#define SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN		(4)
+#define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH		(0)
+#define SUN4I_CODEC_ADC_FIFOS			(0x20)
+#define SUN4I_CODEC_ADC_RXDATA			(0x24)
+#define SUN4I_CODEC_ADC_ACTL			(0x28)
+#define SUN4I_CODEC_ADC_ACTL_ADC_R_EN			(31)
+#define SUN4I_CODEC_ADC_ACTL_ADC_L_EN			(30)
+#define SUN4I_CODEC_ADC_ACTL_PREG1EN			(29)
+#define SUN4I_CODEC_ADC_ACTL_PREG2EN			(28)
+#define SUN4I_CODEC_ADC_ACTL_VMICEN			(27)
+#define SUN4I_CODEC_ADC_ACTL_VADCG			(20)
+#define SUN4I_CODEC_ADC_ACTL_ADCIS			(17)
+#define SUN4I_CODEC_ADC_ACTL_PA_EN			(4)
+#define SUN4I_CODEC_ADC_ACTL_DDE			(3)
+#define SUN4I_CODEC_ADC_DEBUG			(0x2c)
+
+/* 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)
+
+struct sun4i_codec {
+	struct device	*dev;
+	struct regmap	*regmap;
+	struct clk	*clk_apb;
+	struct clk	*clk_module;
+
+	struct snd_dmaengine_dai_dma_data	playback_dma_data;
+};
+
+static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
+{
+	/*
+	 * FIXME: according to the BSP, we might need to drive a PA
+	 *        GPIO high here on some boards
+	 */
+
+	/* Flush TX FIFO */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
+			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
+
+	/* Enable DAC DRQ */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+			   BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
+			   BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
+}
+
+static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
+{
+	/*
+	 * FIXME: according to the BSP, we might need to drive a PA
+	 *        GPIO low here on some boards
+	 */
+
+	/* Disable DAC DRQ */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+			   BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
+			   0);
+}
+
+static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return -ENOTSUPP;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		sun4i_codec_start_playback(scodec);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		sun4i_codec_stop_playback(scodec);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+	u32 val;
+
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return -ENOTSUPP;
+
+	/* Flush the TX FIFO */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
+			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
+
+	/* Set TX FIFO Empty Trigger Level */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+			   0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL,
+			   0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL);
+
+	if (substream->runtime->rate > 32000)
+		/* Use 64 bits FIR filter */
+		val = 0;
+	else
+		/* Use 32 bits FIR filter */
+		val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION);
+
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+			   BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION),
+			   val);
+
+	/* Send zeros when we have an underrun */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+			   BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT),
+			   0);
+
+	return 0;
+}
+
+static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params)
+{
+	unsigned int rate = params_rate(params);
+
+	switch (rate) {
+	case 176400:
+	case 88200:
+	case 44100:
+	case 33075:
+	case 22050:
+	case 14700:
+	case 11025:
+	case 7350:
+		return 22579200;
+
+	case 192000:
+	case 96000:
+	case 48000:
+	case 32000:
+	case 24000:
+	case 16000:
+	case 12000:
+	case 8000:
+		return 24576000;
+
+	default:
+		return 0;
+	}
+}
+
+static int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
+{
+	unsigned int rate = params_rate(params);
+
+	switch (rate) {
+	case 192000:
+	case 176400:
+		return 6;
+
+	case 96000:
+	case 88200:
+		return 7;
+
+	case 48000:
+	case 44100:
+		return 0;
+
+	case 32000:
+	case 33075:
+		return 1;
+
+	case 24000:
+	case 22050:
+		return 2;
+
+	case 16000:
+	case 14700:
+		return 3;
+
+	case 12000:
+	case 11025:
+		return 4;
+
+	case 8000:
+	case 7350:
+		return 5;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+	unsigned long clk_freq;
+	int hwrate;
+	u32 val;
+
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return -ENOTSUPP;
+
+	clk_freq = sun4i_codec_get_mod_freq(params);
+	if (!clk_freq)
+		return -EINVAL;
+
+	if (clk_set_rate(scodec->clk_module, clk_freq))
+		return -EINVAL;
+
+	hwrate = sun4i_codec_get_hw_rate(params);
+	if (hwrate < 0)
+		return hwrate;
+
+	/* Set DAC sample rate */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+			   7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS,
+			   hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS);
+
+	/* Set the number of channels we want to use */
+	if (params_channels(params) == 1)
+		val = BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN);
+	else
+		val = 0;
+
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+			   BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN),
+			   val);
+
+	/* Set the number of sample bits to either 16 or 24 bits */
+	if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
+		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
+				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
+
+		/* Set TX FIFO mode to padding the LSBs with 0 */
+		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
+				   0);
+
+		scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	} else {
+		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
+				   0);
+
+		/* Set TX FIFO mode to repeat the MSB */
+		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
+				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
+
+		scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+	}
+
+	return 0;
+}
+
+static int sun4i_codec_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+
+	/*
+	 * Stop issuing DRQ when we have room for less than 16 samples
+	 * in our TX FIFO
+	 */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+			   3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT,
+			   3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT);
+
+	return clk_prepare_enable(scodec->clk_module);
+}
+
+static void sun4i_codec_shutdown(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+
+	clk_disable_unprepare(scodec->clk_module);
+}
+
+static const struct snd_soc_dai_ops sun4i_codec_dai_ops = {
+	.startup	= sun4i_codec_startup,
+	.shutdown	= sun4i_codec_shutdown,
+	.trigger	= sun4i_codec_trigger,
+	.hw_params	= sun4i_codec_hw_params,
+	.prepare	= sun4i_codec_prepare,
+};
+
+static struct snd_soc_dai_driver sun4i_codec_dai = {
+	.name	= "Codec",
+	.ops	= &sun4i_codec_dai_ops,
+	.playback = {
+		.stream_name	= "Codec Playback",
+		.channels_min	= 1,
+		.channels_max	= 2,
+		.rate_min	= 8000,
+		.rate_max	= 192000,
+		.rates		= SNDRV_PCM_RATE_8000_48000 |
+				  SNDRV_PCM_RATE_96000 |
+				  SNDRV_PCM_RATE_192000 |
+				  SNDRV_PCM_RATE_KNOT,
+		.formats	= SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S32_LE,
+		.sig_bits	= 24,
+	},
+};
+
+/*** Codec ***/
+static const struct snd_kcontrol_new sun4i_codec_pa_mute =
+	SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL,
+			SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0);
+
+static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1);
+
+static const struct snd_kcontrol_new sun4i_codec_widgets[] = {
+	SOC_SINGLE_TLV("PA Volume", SUN4I_CODEC_DAC_ACTL,
+		       SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
+		       sun4i_codec_pa_volume_scale),
+};
+
+static const struct snd_kcontrol_new sun4i_codec_left_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
+			SUN4I_CODEC_DAC_ACTL_LDACLMIXS, 1, 0),
+};
+
+static const struct snd_kcontrol_new sun4i_codec_right_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Right DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
+			SUN4I_CODEC_DAC_ACTL_RDACRMIXS, 1, 0),
+	SOC_DAPM_SINGLE("Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
+			SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0),
+};
+
+static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
+			SUN4I_CODEC_DAC_ACTL_DACPAS, 1, 0),
+	SOC_DAPM_SINGLE("Mixer Playback Switch", SUN4I_CODEC_DAC_ACTL,
+			SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = {
+	/* Digital parts of the DACs */
+	SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC,
+			    SUN4I_CODEC_DAC_DPC_EN_DA, 0,
+			    NULL, 0),
+
+	/* Analog parts of the DACs */
+	SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
+			 SUN4I_CODEC_DAC_ACTL_DACAENL, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
+			 SUN4I_CODEC_DAC_ACTL_DACAENR, 0),
+
+	/* Mixers */
+	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+			   sun4i_codec_left_mixer_controls,
+			   ARRAY_SIZE(sun4i_codec_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+			   sun4i_codec_right_mixer_controls,
+			   ARRAY_SIZE(sun4i_codec_right_mixer_controls)),
+
+	/* Global Mixer Enable */
+	SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL,
+			    SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0),
+
+	/* Pre-Amplifier */
+	SND_SOC_DAPM_MIXER("Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
+			   SUN4I_CODEC_ADC_ACTL_PA_EN, 0,
+			   sun4i_codec_pa_mixer_controls,
+			   ARRAY_SIZE(sun4i_codec_pa_mixer_controls)),
+	SND_SOC_DAPM_SWITCH("Pre-Amplifier Mute", SND_SOC_NOPM, 0, 0,
+			    &sun4i_codec_pa_mute),
+
+	SND_SOC_DAPM_OUTPUT("HP Right"),
+	SND_SOC_DAPM_OUTPUT("HP Left"),
+};
+
+static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = {
+	/* Left DAC Routes */
+	{ "Left DAC", NULL, "DAC" },
+
+	/* Right DAC Routes */
+	{ "Right DAC", NULL, "DAC" },
+
+	/* Right Mixer Routes */
+	{ "Right Mixer", NULL, "Mixer Enable" },
+	{ "Right Mixer", "Left DAC Playback Switch", "Left DAC" },
+	{ "Right Mixer", "Right DAC Playback Switch", "Right DAC" },
+
+	/* Left Mixer Routes */
+	{ "Left Mixer", NULL, "Mixer Enable" },
+	{ "Left Mixer", "Left DAC Playback Switch", "Left DAC" },
+
+	/* Pre-Amplifier Mixer Routes */
+	{ "Pre-Amplifier", "Mixer Playback Switch", "Left Mixer" },
+	{ "Pre-Amplifier", "Mixer Playback Switch", "Right Mixer" },
+	{ "Pre-Amplifier", "DAC Playback Switch", "Left DAC" },
+	{ "Pre-Amplifier", "DAC Playback Switch", "Right DAC" },
+
+	/* PA -> HP path */
+	{ "Pre-Amplifier Mute", "Switch", "Pre-Amplifier" },
+	{ "HP Right", NULL, "Pre-Amplifier Mute" },
+	{ "HP Left", NULL, "Pre-Amplifier Mute" },
+};
+
+static struct snd_soc_codec_driver sun4i_codec_codec = {
+	.controls		= sun4i_codec_widgets,
+	.num_controls		= ARRAY_SIZE(sun4i_codec_widgets),
+	.dapm_widgets		= sun4i_codec_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_dapm_widgets),
+	.dapm_routes		= sun4i_codec_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(sun4i_codec_dapm_routes),
+};
+
+static const struct snd_soc_component_driver sun4i_codec_component = {
+	.name = "sun4i-codec",
+};
+
+#define SUN4I_CODEC_RATES	SNDRV_PCM_RATE_8000_192000
+#define SUN4I_CODEC_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
+				 SNDRV_PCM_FMTBIT_S32_LE)
+
+static int sun4i_codec_dai_probe(struct snd_soc_dai *dai)
+{
+	struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
+	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
+
+	snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data,
+				  NULL);
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver dummy_cpu_dai = {
+	.name	= "sun4i-codec-cpu-dai",
+	.probe	= sun4i_codec_dai_probe,
+	.playback = {
+		.stream_name	= "Playback",
+		.channels_min	= 1,
+		.channels_max	= 2,
+		.rates		= SUN4I_CODEC_RATES,
+		.formats	= SUN4I_CODEC_FORMATS,
+		.sig_bits	= 24,
+	},
+};
+
+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,
+};
+
+static const struct of_device_id sun4i_codec_of_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-codec" },
+	{ .compatible = "allwinner,sun7i-a20-codec" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
+
+static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
+							int *num_links)
+{
+	struct snd_soc_dai_link *link = devm_kzalloc(dev, sizeof(*link),
+						     GFP_KERNEL);
+	if (!link)
+		return NULL;
+
+	link->name		= "cdc";
+	link->stream_name	= "CDC PCM";
+	link->codec_dai_name	= "Codec";
+	link->cpu_dai_name	= dev_name(dev);
+	link->codec_name	= dev_name(dev);
+	link->platform_name	= dev_name(dev);
+	link->dai_fmt		= SND_SOC_DAIFMT_I2S;
+
+	*num_links = 1;
+
+	return link;
+};
+
+static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
+{
+	struct snd_soc_card *card;
+	int ret;
+
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return NULL;
+
+	card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
+	if (!card->dai_link)
+		return NULL;
+
+	card->dev		= dev;
+	card->name		= "sun4i-codec";
+
+	ret = snd_soc_of_parse_audio_routing(card, "routing");
+	if (ret) {
+		dev_err(dev, "Failed to create our audio routing\n");
+		return NULL;
+	}
+
+	return card;
+};
+
+static int sun4i_codec_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card;
+	struct sun4i_codec *scodec;
+	struct resource *res;
+	void __iomem *base;
+	int ret;
+
+	scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
+	if (!scodec)
+		return -ENOMEM;
+
+	scodec->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base)) {
+		dev_err(&pdev->dev, "Failed to map the registers\n");
+		return PTR_ERR(base);
+	}
+
+	scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+					     &sun4i_codec_regmap_config);
+	if (IS_ERR(scodec->regmap)) {
+		dev_err(&pdev->dev, "Failed to create our regmap\n");
+		return PTR_ERR(scodec->regmap);
+	}
+
+	/* Get the clocks from the DT */
+	scodec->clk_apb = devm_clk_get(&pdev->dev, "apb");
+	if (IS_ERR(scodec->clk_apb)) {
+		dev_err(&pdev->dev, "Failed to get the APB clock\n");
+		return PTR_ERR(scodec->clk_apb);
+	}
+
+	scodec->clk_module = devm_clk_get(&pdev->dev, "codec");
+	if (IS_ERR(scodec->clk_module)) {
+		dev_err(&pdev->dev, "Failed to get the module clock\n");
+		return PTR_ERR(scodec->clk_module);
+	}
+
+	/* Enable the bus clock */
+	if (clk_prepare_enable(scodec->clk_apb)) {
+		dev_err(&pdev->dev, "Failed to enable the APB clock\n");
+		return -EINVAL;
+	}
+
+	/* DMA configuration for TX FIFO */
+	scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA;
+	scodec->playback_dma_data.maxburst = 4;
+	scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+	ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec,
+				     &sun4i_codec_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register our codec\n");
+		goto err_clk_disable;
+	}
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &sun4i_codec_component,
+					      &dummy_cpu_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register our DAI\n");
+		goto err_unregister_codec;
+	}
+
+	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
+		goto err_unregister_codec;
+	}
+
+	card = sun4i_codec_create_card(&pdev->dev);
+	if (!card) {
+		dev_err(&pdev->dev, "Failed to create our card\n");
+		goto err_unregister_codec;
+	}
+
+	platform_set_drvdata(pdev, card);
+	snd_soc_card_set_drvdata(card, scodec);
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register our card\n");
+		goto err_unregister_codec;
+	}
+
+	return 0;
+
+err_unregister_codec:
+	snd_soc_unregister_codec(&pdev->dev);
+err_clk_disable:
+	clk_disable_unprepare(scodec->clk_apb);
+	return ret;
+}
+
+static int sun4i_codec_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
+
+	snd_soc_unregister_card(card);
+	snd_soc_unregister_codec(&pdev->dev);
+	clk_disable_unprepare(scodec->clk_apb);
+
+	return 0;
+}
+
+static struct platform_driver sun4i_codec_driver = {
+	.driver = {
+		.name = "sun4i-codec",
+		.of_match_table = sun4i_codec_of_match,
+	},
+	.probe = sun4i_codec_probe,
+	.remove = sun4i_codec_remove,
+};
+module_platform_driver(sun4i_codec_driver);
+
+MODULE_DESCRIPTION("Allwinner A10 codec driver");
+MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index 4e0c0e502ade..ba9fc099cf67 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -152,6 +152,7 @@ static const struct of_device_id snd_soc_mop500_match[] = {
 	{ .compatible = "stericsson,snd-soc-mop500", },
 	{},
 };
+MODULE_DEVICE_TABLE(of, snd_soc_mop500_match);
 
 static struct platform_driver snd_soc_mop500_driver = {
 	.driver = {
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index f5df08ded770..6ba8ae9ecc7a 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -843,6 +843,7 @@ static const struct of_device_id ux500_msp_i2s_match[] = {
 	{ .compatible = "stericsson,ux500-msp-i2s", },
 	{},
 };
+MODULE_DEVICE_TABLE(of, ux500_msp_i2s_match);
 
 static struct platform_driver msp_i2s_driver = {
 	.driver = {