Merge tag 'asoc-v3.15-3' into asoc-linus

ASoC: Updates for v3.15

A few more updates for the merge window:

 - Fixes for the simple-card DAI format DT mess.
 - A new driver for Cirrus cs42xx8 devices.
 - DT support for a couple more devices.
 - A revert of a previous buggy fix for soc-pcm, plus a few more fixes
   and cleanups.

# gpg: Signature made Sun 23 Mar 2014 16:56:11 GMT using RSA key ID 7EA229BD
# 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>"
diff --git a/Documentation/devicetree/bindings/sound/armada-370db-audio.txt b/Documentation/devicetree/bindings/sound/armada-370db-audio.txt
index 3893b4d..bf984d2 100644
--- a/Documentation/devicetree/bindings/sound/armada-370db-audio.txt
+++ b/Documentation/devicetree/bindings/sound/armada-370db-audio.txt
@@ -11,14 +11,17 @@
  * marvell,audio-controller: a phandle that points to the audio
    controller of the Armada 370 SoC.
 
- * marvell,audio-codec: a phandle that points to the analog audio
-   codec connected to the Armada 370 SoC.
+ * marvell,audio-codec: a set of three phandles that points to:
+
+    1/ the analog audio codec connected to the Armada 370 SoC
+    2/ the S/PDIF transceiver
+    3/ the S/PDIF receiver
 
 Example:
 
 	sound {
 	      compatible = "marvell,a370db-audio";
 	      marvell,audio-controller = <&audio_controller>;
-	      marvell,audio-codec = <&audio_codec>;
+	      marvell,audio-codec = <&audio_codec &spdif_out &spdif_in>;
 	      status = "okay";
 	};
diff --git a/Documentation/devicetree/bindings/sound/cs42xx8.txt b/Documentation/devicetree/bindings/sound/cs42xx8.txt
new file mode 100644
index 0000000..f631fbc
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cs42xx8.txt
@@ -0,0 +1,28 @@
+CS42448/CS42888 audio CODEC
+
+Required properties:
+
+  - compatible : must contain one of "cirrus,cs42448" and "cirrus,cs42888"
+
+  - reg : the I2C address of the device for I2C
+
+  - clocks : a list of phandles + clock-specifiers, one for each entry in
+    clock-names
+
+  - clock-names : must contain "mclk"
+
+  - VA-supply, VD-supply, VLS-supply, VLC-supply: power supplies for the device,
+    as covered in Documentation/devicetree/bindings/regulator/regulator.txt
+
+Example:
+
+codec: cs42888@48 {
+	compatible = "cirrus,cs42888";
+	reg = <0x48>;
+	clocks = <&codec_mclk 0>;
+	clock-names = "mclk";
+	VA-supply = <&reg_audio>;
+	VD-supply = <&reg_audio>;
+	VLS-supply = <&reg_audio>;
+	VLC-supply = <&reg_audio>;
+};
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
new file mode 100644
index 0000000..7c6d33f
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -0,0 +1,96 @@
+Renesas R-Car sound
+
+Required properties:
+- compatible			: "renesas,rcar_sound-gen1" if generation1
+				  "renesas,rcar_sound-gen2" if generation2
+- reg				: Should contain the register physical address.
+				  required register is
+				   SRU/ADG/SSI      if generation1
+				   SRU/ADG/SSIU/SSI if generation2
+- rcar_sound,ssi		: SSI subnode
+- rcar_sound,scu		: SCU subnode
+- rcar_sound,dai		: DAI subnode
+
+SSI subnode properties:
+- interrupts			: Should contain SSI interrupt for PIO transfer
+- shared-pin			: if shared clock pin
+
+DAI subnode properties:
+- playback			: list of playback modules
+- capture			: list of capture  modules
+
+Example:
+
+rcar_sound: rcar_sound@0xffd90000 {
+	#sound-dai-cells = <1>;
+	compatible = "renesas,rcar_sound-gen2";
+	reg =	<0 0xec500000 0 0x1000>, /* SCU */
+		<0 0xec5a0000 0 0x100>,  /* ADG */
+		<0 0xec540000 0 0x1000>, /* SSIU */
+		<0 0xec541000 0 0x1280>; /* SSI */
+
+	rcar_sound,src {
+		src0: src@0 { };
+		src1: src@1 { };
+		src2: src@2 { };
+		src3: src@3 { };
+		src4: src@4 { };
+		src5: src@5 { };
+		src6: src@6 { };
+		src7: src@7 { };
+		src8: src@8 { };
+		src9: src@9 { };
+	};
+
+	rcar_sound,ssi {
+		ssi0: ssi@0 {
+			interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
+		};
+		ssi1: ssi@1 {
+			interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
+		};
+		ssi2: ssi@2 {
+			interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
+		};
+		ssi3: ssi@3 {
+			interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
+		};
+		ssi4: ssi@4 {
+			interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
+		};
+		ssi5: ssi@5 {
+			interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
+		};
+		ssi6: ssi@6 {
+			interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
+		};
+		ssi7: ssi@7 {
+			interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
+		};
+		ssi8: ssi@8 {
+			interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
+		};
+		ssi9: ssi@9 {
+			interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
+		};
+	};
+
+	rcar_sound,dai {
+		dai0 {
+			playback = <&ssi5 &src5>;
+			capture  = <&ssi6>;
+		};
+		dai1 {
+			playback = <&ssi3>;
+		};
+		dai2 {
+			capture  = <&ssi4>;
+		};
+		dai3 {
+			playback = <&ssi7>;
+		};
+		dai4 {
+			capture  = <&ssi8>;
+		};
+	};
+};
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
index b30c222..881914b1 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-card.txt
@@ -43,6 +43,12 @@
 					  clock node (= common clock), or "system-clock-frequency"
 					  (if system doens't support common clock)
 
+Note:
+ * For 'format', 'frame-master', 'bitclock-master', 'bitclock-inversion' and
+   'frame-inversion', the simple card will use the settings of CODEC for both
+   CPU and CODEC sides as we need to keep the settings identical for both ends
+   of the link.
+
 Example:
 
 sound {
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index 93533e2..9323854 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -988,14 +988,12 @@
 	.card		= "FSI2A-WM8978",
 	.codec		= "wm8978.0-001a",
 	.platform	= "sh_fsi2",
-	.daifmt		= SND_SOC_DAIFMT_I2S,
+	.daifmt		= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
 	.cpu_dai = {
 		.name	= "fsia-dai",
-		.fmt	= SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
 	},
 	.codec_dai = {
 		.name	= "wm8978-hifi",
-		.fmt	= SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF,
 		.sysclk	= 12288000,
 	},
 };
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
index bc40b85..03dc3ac 100644
--- a/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -589,14 +589,12 @@
 	.card		= "FSI2A-AK4648",
 	.codec		= "ak4642-codec.0-0012",
 	.platform	= "sh_fsi2",
-	.daifmt		= SND_SOC_DAIFMT_LEFT_J,
+	.daifmt		= SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
 	.cpu_dai = {
 		.name	= "fsia-dai",
-		.fmt	= SND_SOC_DAIFMT_CBS_CFS,
 	},
 	.codec_dai = {
 		.name	= "ak4642-hifi",
-		.fmt	= SND_SOC_DAIFMT_CBM_CFM,
 		.sysclk	= 11289600,
 	},
 };
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 3aba037..0ff4d8e 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -509,9 +509,9 @@
 	.card		= "FSI2B-HDMI",
 	.codec		= "sh-mobile-hdmi",
 	.platform	= "sh_fsi2",
+	.daifmt		= SND_SOC_DAIFMT_CBS_CFS,
 	.cpu_dai = {
 		.name	= "fsib-dai",
-		.fmt	= SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF,
 	},
 	.codec_dai = {
 		.name	= "sh_mobile_hdmi-hifi",
@@ -905,14 +905,12 @@
 	.card		= "FSI2A-AK4643",
 	.codec		= "ak4642-codec.0-0013",
 	.platform	= "sh_fsi2",
-	.daifmt		= SND_SOC_DAIFMT_LEFT_J,
+	.daifmt		= SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
 	.cpu_dai = {
 		.name	= "fsia-dai",
-		.fmt	= SND_SOC_DAIFMT_CBS_CFS,
 	},
 	.codec_dai = {
 		.name	= "ak4642-hifi",
-		.fmt	= SND_SOC_DAIFMT_CBM_CFM,
 		.sysclk	= 11289600,
 	},
 };
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 5bc3a15..85d5255 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -861,14 +861,12 @@
 	.card		= "FSIB-DA7210",
 	.codec		= "da7210.0-001a",
 	.platform	= "sh_fsi.0",
-	.daifmt		= SND_SOC_DAIFMT_I2S,
+	.daifmt		= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
 	.cpu_dai = {
 		.name	= "fsib-dai",
-		.fmt	= SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
 	},
 	.codec_dai = {
 		.name	= "da7210-hifi",
-		.fmt	= SND_SOC_DAIFMT_CBM_CFM,
 	},
 };
 
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 21e4230..1162bc6 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -304,14 +304,12 @@
 	.card		= "FSIA-AK4642",
 	.codec		= "ak4642-codec.0-0012",
 	.platform	= "sh_fsi.0",
-	.daifmt		= SND_SOC_DAIFMT_LEFT_J,
+	.daifmt		= SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
 	.cpu_dai = {
 		.name	= "fsia-dai",
-		.fmt	= SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
 	},
 	.codec_dai = {
 		.name	= "ak4642-hifi",
-		.fmt	= SND_SOC_DAIFMT_CBM_CFM,
 		.sysclk	= 11289600,
 	},
 };
diff --git a/include/sound/soc.h b/include/sound/soc.h
index f7de629..0b83168 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1107,6 +1107,19 @@
 	const unsigned int *values;
 };
 
+/**
+ * snd_soc_component_to_codec() - Casts a component to the CODEC it is embedded in
+ * @component: The component to cast to a CODEC
+ *
+ * This function must only be used on components that are known to be CODECs.
+ * Otherwise the behavior is undefined.
+ */
+static inline struct snd_soc_codec *snd_soc_component_to_codec(
+	struct snd_soc_component *component)
+{
+	return container_of(component, struct snd_soc_codec, component);
+}
+
 /* codec IO */
 unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
 unsigned int snd_soc_write(struct snd_soc_codec *codec,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 1a8ff1e..f0e8401 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -44,6 +44,7 @@
 	select SND_SOC_CS42L73 if I2C
 	select SND_SOC_CS4270 if I2C
 	select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_CS42XX8_I2C if I2C
 	select SND_SOC_CX20442 if TTY
 	select SND_SOC_DA7210 if I2C
 	select SND_SOC_DA7213 if I2C
@@ -304,6 +305,15 @@
 	tristate "Cirrus Logic CS4271 CODEC"
 	depends on SND_SOC_I2C_AND_SPI
 
+config SND_SOC_CS42XX8
+	tristate
+
+config SND_SOC_CS42XX8_I2C
+	tristate "Cirrus Logic CS42448/CS42888 CODEC (I2C)"
+	depends on I2C
+	select SND_SOC_CS42XX8
+	select REGMAP_I2C
+
 config SND_SOC_CX20442
 	tristate
 	depends on TTY
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 73df822..3c4d275 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -30,6 +30,8 @@
 snd-soc-cs42l73-objs := cs42l73.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cs4271-objs := cs4271.o
+snd-soc-cs42xx8-objs := cs42xx8.o
+snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
 snd-soc-da7213-objs := da7213.o
@@ -179,6 +181,8 @@
 obj-$(CONFIG_SND_SOC_CS42L73)	+= snd-soc-cs42l73.o
 obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CS4271)	+= snd-soc-cs4271.o
+obj-$(CONFIG_SND_SOC_CS42XX8)	+= snd-soc-cs42xx8.o
+obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
 obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DA7213)	+= snd-soc-da7213.o
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 1870620..6c0da2b 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -106,9 +106,8 @@
 
 static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
 static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
-/* This is a lie. after -102 db, it stays at -102 */
-/* maybe a range would be better */
-static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0);
 
 static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
 static const char *chan_mix[] = {
@@ -122,7 +121,7 @@
 static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
 	SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
 			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
-			6, 0x19, 0x7F, adc_pcm_tlv),
+			0, 0x19, 0x7F, adc_pcm_tlv),
 	SOC_DOUBLE_R("PCM Playback Switch",
 			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
 	SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
@@ -130,7 +129,7 @@
 			0, 0x34, 0xE4, aout_tlv),
 	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
 			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
-			6, 0x19, 0x7F, adc_pcm_tlv),
+			0, 0x19, 0x7F, adc_pcm_tlv),
 	SOC_DOUBLE_R("ADC Mixer Switch",
 			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
 	SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index ff45400..f0ca6be 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -341,7 +341,7 @@
 static const unsigned int swap_values[] = { 0, 1, 3 };
 
 static const struct soc_enum adca_swap_enum =
-	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 1,
+	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 3,
 			      ARRAY_SIZE(left_swap_text),
 			      left_swap_text,
 			      swap_values);
@@ -350,7 +350,7 @@
 	SOC_DAPM_ENUM("Route", adca_swap_enum);
 
 static const struct soc_enum pcma_swap_enum =
-	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 1,
+	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 3,
 			      ARRAY_SIZE(left_swap_text),
 			      left_swap_text,
 			      swap_values);
@@ -359,7 +359,7 @@
 	SOC_DAPM_ENUM("Route", pcma_swap_enum);
 
 static const struct soc_enum adcb_swap_enum =
-	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 1,
+	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 3,
 			      ARRAY_SIZE(right_swap_text),
 			      right_swap_text,
 			      swap_values);
@@ -368,7 +368,7 @@
 	SOC_DAPM_ENUM("Route", adcb_swap_enum);
 
 static const struct soc_enum pcmb_swap_enum =
-	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 1,
+	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 3,
 			      ARRAY_SIZE(right_swap_text),
 			      right_swap_text,
 			      swap_values);
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index b2906c6..0ee60a1 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -319,7 +319,7 @@
 static const unsigned int cs42l73_mono_mix_values[] = { 0, 1, 2 };
 
 static const struct soc_enum spk_asp_enum =
-	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 1,
+	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 3,
 			      ARRAY_SIZE(cs42l73_mono_mix_texts),
 			      cs42l73_mono_mix_texts,
 			      cs42l73_mono_mix_values);
@@ -337,7 +337,7 @@
 	SOC_DAPM_ENUM("Route", spk_xsp_enum);
 
 static const struct soc_enum esl_asp_enum =
-	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 5,
+	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 3,
 			      ARRAY_SIZE(cs42l73_mono_mix_texts),
 			      cs42l73_mono_mix_texts,
 			      cs42l73_mono_mix_values);
@@ -346,7 +346,7 @@
 	SOC_DAPM_ENUM("Route", esl_asp_enum);
 
 static const struct soc_enum esl_xsp_enum =
-	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 7,
+	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 3,
 			      ARRAY_SIZE(cs42l73_mono_mix_texts),
 			      cs42l73_mono_mix_texts,
 			      cs42l73_mono_mix_values);
diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c
new file mode 100644
index 0000000..657dce2
--- /dev/null
+++ b/sound/soc/codecs/cs42xx8-i2c.c
@@ -0,0 +1,64 @@
+/*
+ * Cirrus Logic CS42448/CS42888 Audio CODEC DAI I2C driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+
+#include "cs42xx8.h"
+
+static int cs42xx8_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	u32 ret = cs42xx8_probe(&i2c->dev,
+			devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config));
+	if (ret)
+		return ret;
+
+	pm_runtime_enable(&i2c->dev);
+	pm_request_idle(&i2c->dev);
+
+	return 0;
+}
+
+static int cs42xx8_i2c_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_codec(&i2c->dev);
+	pm_runtime_disable(&i2c->dev);
+
+	return 0;
+}
+
+static struct i2c_device_id cs42xx8_i2c_id[] = {
+	{"cs42448", (kernel_ulong_t)&cs42448_data},
+	{"cs42888", (kernel_ulong_t)&cs42888_data},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
+
+static struct i2c_driver cs42xx8_i2c_driver = {
+	.driver = {
+		.name = "cs42xx8",
+		.owner = THIS_MODULE,
+		.pm = &cs42xx8_pm,
+	},
+	.probe = cs42xx8_i2c_probe,
+	.remove = cs42xx8_i2c_remove,
+	.id_table = cs42xx8_i2c_id,
+};
+
+module_i2c_driver(cs42xx8_i2c_driver);
+
+MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec I2C Driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
new file mode 100644
index 0000000..082299a
--- /dev/null
+++ b/sound/soc/codecs/cs42xx8.c
@@ -0,0 +1,602 @@
+/*
+ * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "cs42xx8.h"
+
+#define CS42XX8_NUM_SUPPLIES 4
+static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {
+	"VA",
+	"VD",
+	"VLS",
+	"VLC",
+};
+
+#define CS42XX8_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
+			 SNDRV_PCM_FMTBIT_S20_3LE | \
+			 SNDRV_PCM_FMTBIT_S24_LE | \
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+/* codec private data */
+struct cs42xx8_priv {
+	struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];
+	const struct cs42xx8_driver_data *drvdata;
+	struct regmap *regmap;
+	struct clk *clk;
+
+	bool slave_mode;
+	unsigned long sysclk;
+};
+
+/* -127.5dB to 0dB with step of 0.5dB */
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+/* -64dB to 24dB with step of 0.5dB */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);
+
+static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };
+static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",
+					"Soft Ramp", "Soft Ramp on Zero Cross" };
+
+static const struct soc_enum adc1_single_enum =
+	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);
+static const struct soc_enum adc2_single_enum =
+	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);
+static const struct soc_enum adc3_single_enum =
+	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);
+static const struct soc_enum dac_szc_enum =
+	SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);
+static const struct soc_enum adc_szc_enum =
+	SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);
+
+static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,
+			 CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,
+			 CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,
+			 CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,
+			 CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),
+	SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,
+			   CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),
+	SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,
+			   CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),
+	SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),
+	SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),
+	SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),
+	SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),
+	SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),
+	SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),
+	SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),
+	SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),
+	SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),
+	SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),
+	SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),
+	SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),
+	SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),
+	SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),
+	SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),
+	SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),
+};
+
+static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {
+	SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,
+			   CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),
+	SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),
+	SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),
+};
+
+static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),
+	SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),
+	SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),
+	SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),
+
+	SND_SOC_DAPM_OUTPUT("AOUT1L"),
+	SND_SOC_DAPM_OUTPUT("AOUT1R"),
+	SND_SOC_DAPM_OUTPUT("AOUT2L"),
+	SND_SOC_DAPM_OUTPUT("AOUT2R"),
+	SND_SOC_DAPM_OUTPUT("AOUT3L"),
+	SND_SOC_DAPM_OUTPUT("AOUT3R"),
+	SND_SOC_DAPM_OUTPUT("AOUT4L"),
+	SND_SOC_DAPM_OUTPUT("AOUT4R"),
+
+	SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),
+	SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),
+
+	SND_SOC_DAPM_INPUT("AIN1L"),
+	SND_SOC_DAPM_INPUT("AIN1R"),
+	SND_SOC_DAPM_INPUT("AIN2L"),
+	SND_SOC_DAPM_INPUT("AIN2R"),
+
+	SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {
+	SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),
+
+	SND_SOC_DAPM_INPUT("AIN3L"),
+	SND_SOC_DAPM_INPUT("AIN3R"),
+};
+
+static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {
+	/* Playback */
+	{ "AOUT1L", NULL, "DAC1" },
+	{ "AOUT1R", NULL, "DAC1" },
+	{ "DAC1", NULL, "PWR" },
+
+	{ "AOUT2L", NULL, "DAC2" },
+	{ "AOUT2R", NULL, "DAC2" },
+	{ "DAC2", NULL, "PWR" },
+
+	{ "AOUT3L", NULL, "DAC3" },
+	{ "AOUT3R", NULL, "DAC3" },
+	{ "DAC3", NULL, "PWR" },
+
+	{ "AOUT4L", NULL, "DAC4" },
+	{ "AOUT4R", NULL, "DAC4" },
+	{ "DAC4", NULL, "PWR" },
+
+	/* Capture */
+	{ "ADC1", NULL, "AIN1L" },
+	{ "ADC1", NULL, "AIN1R" },
+	{ "ADC1", NULL, "PWR" },
+
+	{ "ADC2", NULL, "AIN2L" },
+	{ "ADC2", NULL, "AIN2R" },
+	{ "ADC2", NULL, "PWR" },
+};
+
+static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
+	/* Capture */
+	{ "ADC3", NULL, "AIN3L" },
+	{ "ADC3", NULL, "AIN3R" },
+	{ "ADC3", NULL, "PWR" },
+};
+
+struct cs42xx8_ratios {
+	unsigned int ratio;
+	unsigned char speed;
+	unsigned char mclk;
+};
+
+static const struct cs42xx8_ratios cs42xx8_ratios[] = {
+	{ 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) },
+	{ 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) },
+	{ 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) },
+	{ 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) },
+	{ 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) },
+	{ 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) },
+	{ 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) },
+	{ 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) },
+	{ 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) }
+};
+
+static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+
+	cs42xx8->sysclk = freq;
+
+	return 0;
+}
+
+static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			       unsigned int format)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+	u32 val;
+
+	/* Set DAI format */
+	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_LEFT_J:
+		val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;
+		break;
+	default:
+		dev_err(codec->dev, "unsupported dai format\n");
+		return -EINVAL;
+	}
+
+	regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,
+			   CS42XX8_INTF_DAC_DIF_MASK |
+			   CS42XX8_INTF_ADC_DIF_MASK, val);
+
+	/* Set master/slave audio interface */
+	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		cs42xx8->slave_mode = true;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		cs42xx8->slave_mode = false;
+		break;
+	default:
+		dev_err(codec->dev, "unsupported master/slave mode\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	u32 ratio = cs42xx8->sysclk / params_rate(params);
+	u32 i, fm, val, mask;
+
+	for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
+		if (cs42xx8_ratios[i].ratio == ratio)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(cs42xx8_ratios)) {
+		dev_err(codec->dev, "unsupported sysclk ratio\n");
+		return -EINVAL;
+	}
+
+	mask = CS42XX8_FUNCMOD_MFREQ_MASK;
+	val = cs42xx8_ratios[i].mclk;
+
+	fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed;
+
+	regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
+			   CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
+			   CS42XX8_FUNCMOD_xC_FM(tx, fm) | val);
+
+	return 0;
+}
+
+static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+
+	regmap_update_bits(cs42xx8->regmap, CS42XX8_DACMUTE,
+			   CS42XX8_DACMUTE_ALL, mute ? CS42XX8_DACMUTE_ALL : 0);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
+	.set_fmt	= cs42xx8_set_dai_fmt,
+	.set_sysclk	= cs42xx8_set_dai_sysclk,
+	.hw_params	= cs42xx8_hw_params,
+	.digital_mute	= cs42xx8_digital_mute,
+};
+
+static struct snd_soc_dai_driver cs42xx8_dai = {
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = CS42XX8_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = CS42XX8_FORMATS,
+	},
+	.ops = &cs42xx8_dai_ops,
+};
+
+static const struct reg_default cs42xx8_reg[] = {
+	{ 0x01, 0x01 },   /* Chip I.D. and Revision Register */
+	{ 0x02, 0x00 },   /* Power Control */
+	{ 0x03, 0xF0 },   /* Functional Mode */
+	{ 0x04, 0x46 },   /* Interface Formats */
+	{ 0x05, 0x00 },   /* ADC Control & DAC De-Emphasis */
+	{ 0x06, 0x10 },   /* Transition Control */
+	{ 0x07, 0x00 },   /* DAC Channel Mute */
+	{ 0x08, 0x00 },   /* Volume Control AOUT1 */
+	{ 0x09, 0x00 },   /* Volume Control AOUT2 */
+	{ 0x0a, 0x00 },   /* Volume Control AOUT3 */
+	{ 0x0b, 0x00 },   /* Volume Control AOUT4 */
+	{ 0x0c, 0x00 },   /* Volume Control AOUT5 */
+	{ 0x0d, 0x00 },   /* Volume Control AOUT6 */
+	{ 0x0e, 0x00 },   /* Volume Control AOUT7 */
+	{ 0x0f, 0x00 },   /* Volume Control AOUT8 */
+	{ 0x10, 0x00 },   /* DAC Channel Invert */
+	{ 0x11, 0x00 },   /* Volume Control AIN1 */
+	{ 0x12, 0x00 },   /* Volume Control AIN2 */
+	{ 0x13, 0x00 },   /* Volume Control AIN3 */
+	{ 0x14, 0x00 },   /* Volume Control AIN4 */
+	{ 0x15, 0x00 },   /* Volume Control AIN5 */
+	{ 0x16, 0x00 },   /* Volume Control AIN6 */
+	{ 0x17, 0x00 },   /* ADC Channel Invert */
+	{ 0x18, 0x00 },   /* Status Control */
+	{ 0x1a, 0x00 },   /* Status Mask */
+	{ 0x1b, 0x00 },   /* MUTEC Pin Control */
+};
+
+static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42XX8_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42XX8_CHIPID:
+	case CS42XX8_STATUS:
+		return false;
+	default:
+		return true;
+	}
+}
+
+const struct regmap_config cs42xx8_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS42XX8_LASTREG,
+	.reg_defaults = cs42xx8_reg,
+	.num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
+	.volatile_reg = cs42xx8_volatile_register,
+	.writeable_reg = cs42xx8_writeable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
+
+static int cs42xx8_codec_probe(struct snd_soc_codec *codec)
+{
+	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	switch (cs42xx8->drvdata->num_adcs) {
+	case 3:
+		snd_soc_add_codec_controls(codec, cs42xx8_adc3_snd_controls,
+					ARRAY_SIZE(cs42xx8_adc3_snd_controls));
+		snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,
+					ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes,
+					ARRAY_SIZE(cs42xx8_adc3_dapm_routes));
+		break;
+	default:
+		break;
+	}
+
+	/* Mute all DAC channels */
+	regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL);
+
+	return 0;
+}
+
+static const struct snd_soc_codec_driver cs42xx8_driver = {
+	.probe = cs42xx8_codec_probe,
+	.idle_bias_off = true,
+
+	.controls = cs42xx8_snd_controls,
+	.num_controls = ARRAY_SIZE(cs42xx8_snd_controls),
+	.dapm_widgets = cs42xx8_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets),
+	.dapm_routes = cs42xx8_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes),
+};
+
+const struct cs42xx8_driver_data cs42448_data = {
+	.name = "cs42448",
+	.num_adcs = 3,
+};
+EXPORT_SYMBOL_GPL(cs42448_data);
+
+const struct cs42xx8_driver_data cs42888_data = {
+	.name = "cs42888",
+	.num_adcs = 2,
+};
+EXPORT_SYMBOL_GPL(cs42888_data);
+
+const struct of_device_id cs42xx8_of_match[] = {
+	{ .compatible = "cirrus,cs42448", .data = &cs42448_data, },
+	{ .compatible = "cirrus,cs42888", .data = &cs42888_data, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
+EXPORT_SYMBOL_GPL(cs42xx8_of_match);
+
+int cs42xx8_probe(struct device *dev, struct regmap *regmap)
+{
+	const struct of_device_id *of_id = of_match_device(cs42xx8_of_match, dev);
+	struct cs42xx8_priv *cs42xx8;
+	int ret, val, i;
+
+	cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);
+	if (cs42xx8 == NULL)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, cs42xx8);
+
+	if (of_id)
+		cs42xx8->drvdata = of_id->data;
+
+	if (!cs42xx8->drvdata) {
+		dev_err(dev, "failed to find driver data\n");
+		return -EINVAL;
+	}
+
+	cs42xx8->clk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(cs42xx8->clk)) {
+		dev_err(dev, "failed to get the clock: %ld\n",
+				PTR_ERR(cs42xx8->clk));
+		return -EINVAL;
+	}
+
+	cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
+
+	for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)
+		cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev,
+			ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);
+	if (ret) {
+		dev_err(dev, "failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
+				    cs42xx8->supplies);
+	if (ret) {
+		dev_err(dev, "failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	/* Make sure hardware reset done */
+	msleep(5);
+
+	cs42xx8->regmap = regmap;
+	if (IS_ERR(cs42xx8->regmap)) {
+		ret = PTR_ERR(cs42xx8->regmap);
+		dev_err(dev, "failed to allocate regmap: %d\n", ret);
+		goto err_enable;
+	}
+
+	/*
+	 * We haven't marked the chip revision as volatile due to
+	 * sharing a register with the right input volume; explicitly
+	 * bypass the cache to read it.
+	 */
+	regcache_cache_bypass(cs42xx8->regmap, true);
+
+	/* Validate the chip ID */
+	regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
+	if (val < 0) {
+		dev_err(dev, "failed to get device ID: %x", val);
+		ret = -EINVAL;
+		goto err_enable;
+	}
+
+	/* The top four bits of the chip ID should be 0000 */
+	if ((val & CS42XX8_CHIPID_CHIP_ID_MASK) != 0x00) {
+		dev_err(dev, "unmatched chip ID: %d\n",
+				val & CS42XX8_CHIPID_CHIP_ID_MASK);
+		ret = -EINVAL;
+		goto err_enable;
+	}
+
+	dev_info(dev, "found device, revision %X\n",
+			val & CS42XX8_CHIPID_REV_ID_MASK);
+
+	regcache_cache_bypass(cs42xx8->regmap, false);
+
+	cs42xx8_dai.name = cs42xx8->drvdata->name;
+
+	/* Each adc supports stereo input */
+	cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;
+
+	ret = snd_soc_register_codec(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
+	if (ret) {
+		dev_err(dev, "failed to register codec:%d\n", ret);
+		goto err_enable;
+	}
+
+	regcache_cache_only(cs42xx8->regmap, true);
+
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
+			       cs42xx8->supplies);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cs42xx8_probe);
+
+#ifdef CONFIG_PM_RUNTIME
+static int cs42xx8_runtime_resume(struct device *dev)
+{
+	struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(cs42xx8->clk);
+	if (ret) {
+		dev_err(dev, "failed to enable mclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
+				    cs42xx8->supplies);
+	if (ret) {
+		dev_err(dev, "failed to enable supplies: %d\n", ret);
+		goto err_clk;
+	}
+
+	/* Make sure hardware reset done */
+	msleep(5);
+
+	regcache_cache_only(cs42xx8->regmap, false);
+
+	ret = regcache_sync(cs42xx8->regmap);
+	if (ret) {
+		dev_err(dev, "failed to sync regmap: %d\n", ret);
+		goto err_bulk;
+	}
+
+	return 0;
+
+err_bulk:
+	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
+			       cs42xx8->supplies);
+err_clk:
+	clk_disable_unprepare(cs42xx8->clk);
+
+	return ret;
+}
+
+static int cs42xx8_runtime_suspend(struct device *dev)
+{
+	struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
+
+	regcache_cache_only(cs42xx8->regmap, true);
+
+	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
+			       cs42xx8->supplies);
+
+	clk_disable_unprepare(cs42xx8->clk);
+
+	return 0;
+}
+#endif
+
+const struct dev_pm_ops cs42xx8_pm = {
+	SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(cs42xx8_pm);
+
+MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h
new file mode 100644
index 0000000..da0b94a
--- /dev/null
+++ b/sound/soc/codecs/cs42xx8.h
@@ -0,0 +1,238 @@
+/*
+ * cs42xx8.h - Cirrus Logic CS42448/CS42888 Audio CODEC driver header file
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _CS42XX8_H
+#define _CS42XX8_H
+
+struct cs42xx8_driver_data {
+	char name[32];
+	int num_adcs;
+};
+
+extern const struct dev_pm_ops cs42xx8_pm;
+extern const struct cs42xx8_driver_data cs42448_data;
+extern const struct cs42xx8_driver_data cs42888_data;
+extern const struct regmap_config cs42xx8_regmap_config;
+int cs42xx8_probe(struct device *dev, struct regmap *regmap);
+
+/* CS42888 register map */
+#define CS42XX8_CHIPID				0x01	/* Chip ID */
+#define CS42XX8_PWRCTL				0x02	/* Power Control */
+#define CS42XX8_FUNCMOD				0x03	/* Functional Mode */
+#define CS42XX8_INTF				0x04	/* Interface Formats */
+#define CS42XX8_ADCCTL				0x05	/* ADC Control */
+#define CS42XX8_TXCTL				0x06	/* Transition Control */
+#define CS42XX8_DACMUTE				0x07	/* DAC Mute Control */
+#define CS42XX8_VOLAOUT1			0x08	/* Volume Control AOUT1 */
+#define CS42XX8_VOLAOUT2			0x09	/* Volume Control AOUT2 */
+#define CS42XX8_VOLAOUT3			0x0A	/* Volume Control AOUT3 */
+#define CS42XX8_VOLAOUT4			0x0B	/* Volume Control AOUT4 */
+#define CS42XX8_VOLAOUT5			0x0C	/* Volume Control AOUT5 */
+#define CS42XX8_VOLAOUT6			0x0D	/* Volume Control AOUT6 */
+#define CS42XX8_VOLAOUT7			0x0E	/* Volume Control AOUT7 */
+#define CS42XX8_VOLAOUT8			0x0F	/* Volume Control AOUT8 */
+#define CS42XX8_DACINV				0x10	/* DAC Channel Invert */
+#define CS42XX8_VOLAIN1				0x11	/* Volume Control AIN1 */
+#define CS42XX8_VOLAIN2				0x12	/* Volume Control AIN2 */
+#define CS42XX8_VOLAIN3				0x13	/* Volume Control AIN3 */
+#define CS42XX8_VOLAIN4				0x14	/* Volume Control AIN4 */
+#define CS42XX8_VOLAIN5				0x15	/* Volume Control AIN5 */
+#define CS42XX8_VOLAIN6				0x16	/* Volume Control AIN6 */
+#define CS42XX8_ADCINV				0x17	/* ADC Channel Invert */
+#define CS42XX8_STATUSCTL			0x18	/* Status Control */
+#define CS42XX8_STATUS				0x19	/* Status */
+#define CS42XX8_STATUSM				0x1A	/* Status Mask */
+#define CS42XX8_MUTEC				0x1B	/* MUTEC Pin Control */
+
+#define CS42XX8_FIRSTREG			CS42XX8_CHIPID
+#define CS42XX8_LASTREG				CS42XX8_MUTEC
+#define CS42XX8_NUMREGS				(CS42XX8_LASTREG - CS42XX8_FIRSTREG + 1)
+#define CS42XX8_I2C_INCR			0x80
+
+/* Chip I.D. and Revision Register (Address 01h) */
+#define CS42XX8_CHIPID_CHIP_ID_MASK		0xF0
+#define CS42XX8_CHIPID_REV_ID_MASK		0x0F
+
+/* Power Control (Address 02h) */
+#define CS42XX8_PWRCTL_PDN_ADC3_SHIFT		7
+#define CS42XX8_PWRCTL_PDN_ADC3_MASK		(1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC3			(1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC2_SHIFT		6
+#define CS42XX8_PWRCTL_PDN_ADC2_MASK		(1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC2			(1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC1_SHIFT		5
+#define CS42XX8_PWRCTL_PDN_ADC1_MASK		(1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC1			(1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC4_SHIFT		4
+#define CS42XX8_PWRCTL_PDN_DAC4_MASK		(1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC4			(1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC3_SHIFT		3
+#define CS42XX8_PWRCTL_PDN_DAC3_MASK		(1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC3			(1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC2_SHIFT		2
+#define CS42XX8_PWRCTL_PDN_DAC2_MASK		(1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC2			(1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC1_SHIFT		1
+#define CS42XX8_PWRCTL_PDN_DAC1_MASK		(1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC1			(1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_SHIFT		0
+#define CS42XX8_PWRCTL_PDN_MASK			(1 << CS42XX8_PWRCTL_PDN_SHIFT)
+#define CS42XX8_PWRCTL_PDN			(1 << CS42XX8_PWRCTL_PDN_SHIFT)
+
+/* Functional Mode (Address 03h) */
+#define CS42XX8_FUNCMOD_DAC_FM_SHIFT		6
+#define CS42XX8_FUNCMOD_DAC_FM_WIDTH		2
+#define CS42XX8_FUNCMOD_DAC_FM_MASK		(((1 << CS42XX8_FUNCMOD_DAC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_DAC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_DAC_FM(v)		((v) << CS42XX8_FUNCMOD_DAC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_ADC_FM_SHIFT		4
+#define CS42XX8_FUNCMOD_ADC_FM_WIDTH		2
+#define CS42XX8_FUNCMOD_ADC_FM_MASK		(((1 << CS42XX8_FUNCMOD_ADC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_ADC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_ADC_FM(v)		((v) << CS42XX8_FUNCMOD_ADC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_xC_FM_MASK(x)		((x) ? CS42XX8_FUNCMOD_DAC_FM_MASK : CS42XX8_FUNCMOD_ADC_FM_MASK)
+#define CS42XX8_FUNCMOD_xC_FM(x, v)		((x) ? CS42XX8_FUNCMOD_DAC_FM(v) : CS42XX8_FUNCMOD_ADC_FM(v))
+#define CS42XX8_FUNCMOD_MFREQ_SHIFT		1
+#define CS42XX8_FUNCMOD_MFREQ_WIDTH		3
+#define CS42XX8_FUNCMOD_MFREQ_MASK		(((1 << CS42XX8_FUNCMOD_MFREQ_WIDTH) - 1) << CS42XX8_FUNCMOD_MFREQ_SHIFT)
+#define CS42XX8_FUNCMOD_MFREQ_256(s)		((0 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_384(s)		((1 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_512(s)		((2 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_768(s)		((3 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_1024(s)		((4 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+
+#define CS42XX8_FM_SINGLE			0
+#define CS42XX8_FM_DOUBLE			1
+#define CS42XX8_FM_QUAD				2
+#define CS42XX8_FM_AUTO				3
+
+/* Interface Formats (Address 04h) */
+#define CS42XX8_INTF_FREEZE_SHIFT		7
+#define CS42XX8_INTF_FREEZE_MASK		(1 << CS42XX8_INTF_FREEZE_SHIFT)
+#define CS42XX8_INTF_FREEZE			(1 << CS42XX8_INTF_FREEZE_SHIFT)
+#define CS42XX8_INTF_AUX_DIF_SHIFT		6
+#define CS42XX8_INTF_AUX_DIF_MASK		(1 << CS42XX8_INTF_AUX_DIF_SHIFT)
+#define CS42XX8_INTF_AUX_DIF			(1 << CS42XX8_INTF_AUX_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_SHIFT		3
+#define CS42XX8_INTF_DAC_DIF_WIDTH		3
+#define CS42XX8_INTF_DAC_DIF_MASK		(((1 << CS42XX8_INTF_DAC_DIF_WIDTH) - 1) << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_LEFTJ		(0 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_I2S		(1 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_RIGHTJ		(2 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_RIGHTJ_16		(3 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_ONELINE_20		(4 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_ONELINE_24		(6 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_TDM		(7 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_SHIFT		0
+#define CS42XX8_INTF_ADC_DIF_WIDTH		3
+#define CS42XX8_INTF_ADC_DIF_MASK		(((1 << CS42XX8_INTF_ADC_DIF_WIDTH) - 1) << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_LEFTJ		(0 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_I2S		(1 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_RIGHTJ		(2 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_RIGHTJ_16		(3 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_ONELINE_20		(4 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_ONELINE_24		(6 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_TDM		(7 << CS42XX8_INTF_ADC_DIF_SHIFT)
+
+/* ADC Control & DAC De-Emphasis (Address 05h) */
+#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT	7
+#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_MASK	(1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT)
+#define CS42XX8_ADCCTL_ADC_HPF_FREEZE		(1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT)
+#define CS42XX8_ADCCTL_DAC_DEM_SHIFT		5
+#define CS42XX8_ADCCTL_DAC_DEM_MASK		(1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT)
+#define CS42XX8_ADCCTL_DAC_DEM			(1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT)
+#define CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT	4
+#define CS42XX8_ADCCTL_ADC1_SINGLE_MASK		(1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC1_SINGLE		(1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT	3
+#define CS42XX8_ADCCTL_ADC2_SINGLE_MASK		(1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC2_SINGLE		(1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT	2
+#define CS42XX8_ADCCTL_ADC3_SINGLE_MASK		(1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC3_SINGLE		(1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_AIN5_MUX_SHIFT		1
+#define CS42XX8_ADCCTL_AIN5_MUX_MASK		(1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT)
+#define CS42XX8_ADCCTL_AIN5_MUX			(1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT)
+#define CS42XX8_ADCCTL_AIN6_MUX_SHIFT		0
+#define CS42XX8_ADCCTL_AIN6_MUX_MASK		(1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT)
+#define CS42XX8_ADCCTL_AIN6_MUX			(1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT)
+
+/* Transition Control (Address 06h) */
+#define CS42XX8_TXCTL_DAC_SNGVOL_SHIFT		7
+#define CS42XX8_TXCTL_DAC_SNGVOL_MASK		(1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_DAC_SNGVOL		(1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_SHIFT		5
+#define CS42XX8_TXCTL_DAC_SZC_WIDTH		2
+#define CS42XX8_TXCTL_DAC_SZC_MASK		(((1 << CS42XX8_TXCTL_DAC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_IC		(0 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_ZC		(1 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_SR		(2 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_SRZC		(3 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_AMUTE_SHIFT		4
+#define CS42XX8_TXCTL_AMUTE_MASK		(1 << CS42XX8_TXCTL_AMUTE_SHIFT)
+#define CS42XX8_TXCTL_AMUTE			(1 << CS42XX8_TXCTL_AMUTE_SHIFT)
+#define CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT		3
+#define CS42XX8_TXCTL_MUTE_ADC_SP_MASK		(1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT)
+#define CS42XX8_TXCTL_MUTE_ADC_SP		(1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT)
+#define CS42XX8_TXCTL_ADC_SNGVOL_SHIFT		2
+#define CS42XX8_TXCTL_ADC_SNGVOL_MASK		(1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_ADC_SNGVOL		(1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_SHIFT		0
+#define CS42XX8_TXCTL_ADC_SZC_MASK		(((1 << CS42XX8_TXCTL_ADC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_IC		(0 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_ZC		(1 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_SR		(2 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_SRZC		(3 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+
+/* DAC Channel Mute (Address 07h) */
+#define CS42XX8_DACMUTE_AOUT(n)			(0x1 << n)
+#define CS42XX8_DACMUTE_ALL			0xff
+
+/* Status Control (Address 18h)*/
+#define CS42XX8_STATUSCTL_INI_SHIFT		2
+#define CS42XX8_STATUSCTL_INI_WIDTH		2
+#define CS42XX8_STATUSCTL_INI_MASK		(((1 << CS42XX8_STATUSCTL_INI_WIDTH) - 1) << CS42XX8_STATUSCTL_INI_SHIFT)
+#define CS42XX8_STATUSCTL_INT_ACTIVE_HIGH	(0 << CS42XX8_STATUSCTL_INI_SHIFT)
+#define CS42XX8_STATUSCTL_INT_ACTIVE_LOW	(1 << CS42XX8_STATUSCTL_INI_SHIFT)
+#define CS42XX8_STATUSCTL_INT_OPEN_DRAIN	(2 << CS42XX8_STATUSCTL_INI_SHIFT)
+
+/* Status (Address 19h)*/
+#define CS42XX8_STATUS_DAC_CLK_ERR_SHIFT	4
+#define CS42XX8_STATUS_DAC_CLK_ERR_MASK		(1 << CS42XX8_STATUS_DAC_CLK_ERR_SHIFT)
+#define CS42XX8_STATUS_ADC_CLK_ERR_SHIFT	3
+#define CS42XX8_STATUS_ADC_CLK_ERR_MASK		(1 << CS42XX8_STATUS_ADC_CLK_ERR_SHIFT)
+#define CS42XX8_STATUS_ADC3_OVFL_SHIFT		2
+#define CS42XX8_STATUS_ADC3_OVFL_MASK		(1 << CS42XX8_STATUS_ADC3_OVFL_SHIFT)
+#define CS42XX8_STATUS_ADC2_OVFL_SHIFT		1
+#define CS42XX8_STATUS_ADC2_OVFL_MASK		(1 << CS42XX8_STATUS_ADC2_OVFL_SHIFT)
+#define CS42XX8_STATUS_ADC1_OVFL_SHIFT		0
+#define CS42XX8_STATUS_ADC1_OVFL_MASK		(1 << CS42XX8_STATUS_ADC1_OVFL_SHIFT)
+
+/* Status Mask (Address 1Ah) */
+#define CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT	4
+#define CS42XX8_STATUS_DAC_CLK_ERR_M_MASK	(1 << CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT)
+#define CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT	3
+#define CS42XX8_STATUS_ADC_CLK_ERR_M_MASK	(1 << CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT)
+#define CS42XX8_STATUS_ADC3_OVFL_M_SHIFT	2
+#define CS42XX8_STATUS_ADC3_OVFL_M_MASK		(1 << CS42XX8_STATUS_ADC3_OVFL_M_SHIFT)
+#define CS42XX8_STATUS_ADC2_OVFL_M_SHIFT	1
+#define CS42XX8_STATUS_ADC2_OVFL_M_MASK		(1 << CS42XX8_STATUS_ADC2_OVFL_M_SHIFT)
+#define CS42XX8_STATUS_ADC1_OVFL_M_SHIFT	0
+#define CS42XX8_STATUS_ADC1_OVFL_M_MASK		(1 << CS42XX8_STATUS_ADC1_OVFL_M_SHIFT)
+
+/* MUTEC Pin Control (Address 1Bh) */
+#define CS42XX8_MUTEC_MCPOLARITY_SHIFT		1
+#define CS42XX8_MUTEC_MCPOLARITY_MASK		(1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
+#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_LOW	(0 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
+#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_HIGH	(1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
+#define CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT	0
+#define CS42XX8_MUTEC_MUTEC_ACTIVE_MASK		(1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT)
+#define CS42XX8_MUTEC_MUTEC_ACTIVE		(1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT)
+#endif /* _CS42XX8_H */
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index 3e264a7..3a89ce6 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -918,8 +918,7 @@
 			      struct snd_pcm_hw_params *params,
 			      struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	u16 aif = 0;
 	unsigned int fs_val = 0;
 
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 96a4745..98c6e10 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2343,7 +2343,6 @@
 
 	max98090->devtype = id->driver_data;
 	i2c_set_clientdata(i2c, max98090);
-	max98090->control_data = i2c;
 	max98090->pdata = i2c->dev.platform_data;
 	max98090->irq = i2c->irq;
 
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
index 7e103f2..1a4e233 100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
@@ -1523,7 +1523,6 @@
 	struct regmap *regmap;
 	struct snd_soc_codec *codec;
 	enum max98090_type devtype;
-	void *control_data;
 	struct max98090_pdata *pdata;
 	unsigned int sysclk;
 	unsigned int bclk;
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 37d737e..2c59b1f 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -106,8 +106,7 @@
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	unsigned int rate = params_rate(params);
 	int i;
 
@@ -126,8 +125,7 @@
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	unsigned int rate = params_rate(params);
 	unsigned int val;
 
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 13ccee4..0061ae6 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -1594,8 +1594,7 @@
 static int rt5640_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 	unsigned int val_len = 0, val_clk, mask_clk;
 	int dai_sel, pre_div, bclk_ms, frame_size;
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
index 90e3a22..58e7c1f 100644
--- a/sound/soc/codecs/sirf-audio-codec.c
+++ b/sound/soc/codecs/sirf-audio-codec.c
@@ -337,18 +337,9 @@
 
 static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
 {
-	int ret;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
-	struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
 
 	pm_runtime_enable(codec->dev);
-	codec->control_data = sirf_audio_codec->regmap;
-
-	ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
-	if (ret != 0) {
-		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-		return ret;
-	}
 
 	if (of_device_is_compatible(codec->dev->of_node, "sirf,prima2-audio-codec")) {
 		snd_soc_dapm_new_controls(dapm,
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index a3c61d3..a40c4b0 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -193,8 +193,7 @@
 		struct snd_pcm_hw_params *params,
 		struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	int pdata, play_freq_val, record_freq_val;
 	int bclk_to_fs_ratio;
 
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index e60e37b..fa158cf 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -129,7 +129,7 @@
 	},
 };
 
-struct regmap_config aic31xx_i2c_regmap = {
+static const struct regmap_config aic31xx_i2c_regmap = {
 	.reg_bits = 8,
 	.val_bits = 8,
 	.writeable_reg = aic31xx_writeable,
@@ -321,9 +321,9 @@
 static const struct snd_kcontrol_new rdac_in_control =
 	SOC_DAPM_ENUM("DAC Right Input", rdac_in_enum);
 
-int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
-		      unsigned int mask, unsigned int wbits, int sleep,
-		      int count)
+static int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
+			     unsigned int mask, unsigned int wbits, int sleep,
+			     int count)
 {
 	unsigned int bits;
 	int counter = count;
@@ -753,10 +753,9 @@
 
 static int aic31xx_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
-			     struct snd_soc_dai *tmp)
+			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	u8 data = 0;
 
 	dev_dbg(codec->dev, "## %s: format %d width %d rate %d\n",
@@ -943,7 +942,6 @@
 
 static void aic31xx_clk_off(struct snd_soc_codec *codec)
 {
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
 	u8 mask = AIC31XX_PM_MASK;
 	u8 off = 0;
 
@@ -1021,7 +1019,8 @@
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
-		aic31xx_power_off(codec);
+		if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+			aic31xx_power_off(codec);
 		break;
 	}
 	codec->dapm.bias_level = level;
@@ -1050,18 +1049,9 @@
 	dev_dbg(aic31xx->dev, "## %s\n", __func__);
 
 	aic31xx = snd_soc_codec_get_drvdata(codec);
-	codec->control_data = aic31xx->regmap;
 
 	aic31xx->codec = codec;
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-
-	if (ret != 0) {
-		dev_err(codec->dev, "snd_soc_codec_set_cache_io failed %d\n",
-			ret);
-		return ret;
-	}
-
 	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
 		aic31xx->disable_nb[i].nb.notifier_call =
 			aic31xx_regulator_event;
@@ -1187,7 +1177,7 @@
 }
 #endif /* CONFIG_OF */
 
-void aic31xx_device_init(struct aic31xx_priv *aic31xx)
+static void aic31xx_device_init(struct aic31xx_priv *aic31xx)
 {
 	int ret, i;
 
@@ -1238,7 +1228,6 @@
 		return -ENOMEM;
 
 	aic31xx->regmap = devm_regmap_init_i2c(i2c, regmap_config);
-
 	if (IS_ERR(aic31xx->regmap)) {
 		ret = PTR_ERR(aic31xx->regmap);
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -1251,18 +1240,14 @@
 
 	aic31xx_device_init(aic31xx);
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx,
+	return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx,
 				     aic31xx_dai_driver,
 				     ARRAY_SIZE(aic31xx_dai_driver));
-
-	return ret;
 }
 
 static int aic31xx_i2c_remove(struct i2c_client *i2c)
 {
-	struct aic31xx_priv *aic31xx = dev_get_drvdata(&i2c->dev);
-
-	kfree(aic31xx);
+	snd_soc_unregister_codec(&i2c->dev);
 	return 0;
 }
 
@@ -1284,7 +1269,7 @@
 		.of_match_table = of_match_ptr(tlv320aic31xx_of_match),
 	},
 	.probe		= aic31xx_i2c_probe,
-	.remove		= (aic31xx_i2c_remove),
+	.remove		= aic31xx_i2c_remove,
 	.id_table	= aic31xx_i2c_id,
 };
 
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index c94d4c1..edf27ac 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -203,8 +203,7 @@
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
 	u8 hw_params;
 
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 4dadaa8..e62e707 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -566,8 +566,7 @@
 static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
 
 	/* shut down WSPLL power if running from this clock */
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 7558c83..af7ed8b 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -504,8 +504,7 @@
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
 	u16 paifa = 0;
 	u16 paifb = 0;
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 621e9a9..cab98a5 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -123,35 +123,29 @@
 /* Logic for a aic3x as connected on a davinci-evm */
 static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
+	struct snd_soc_card *card = rtd->card;
 	struct snd_soc_codec *codec = rtd->codec;
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	struct device_node *np = codec->card->dev->of_node;
 	int ret;
 
 	/* Add davinci-evm specific widgets */
-	snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
+	snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets,
 				  ARRAY_SIZE(aic3x_dapm_widgets));
 
 	if (np) {
-		ret = snd_soc_of_parse_audio_routing(codec->card,
-							"ti,audio-routing");
+		ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
 		if (ret)
 			return ret;
 	} else {
 		/* Set up davinci-evm specific audio path audio_map */
-		snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+		snd_soc_dapm_add_routes(&card->dapm, audio_map,
+					ARRAY_SIZE(audio_map));
 	}
 
 	/* not connected */
-	snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
-	snd_soc_dapm_disable_pin(dapm, "HPLCOM");
-	snd_soc_dapm_disable_pin(dapm, "HPRCOM");
-
-	/* always connected */
-	snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
-	snd_soc_dapm_enable_pin(dapm, "Line Out");
-	snd_soc_dapm_enable_pin(dapm, "Mic Jack");
-	snd_soc_dapm_enable_pin(dapm, "Line In");
+	snd_soc_dapm_nc_pin(&codec->dapm, "MONO_LOUT");
+	snd_soc_dapm_nc_pin(&codec->dapm, "HPLCOM");
+	snd_soc_dapm_nc_pin(&codec->dapm, "HPRCOM");
 
 	return 0;
 }
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index b0ae067..a01ae97 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -1026,6 +1026,7 @@
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
 	struct davinci_pcm_dma_params *dma_params;
+	struct snd_dmaengine_dai_dma_data *dma_data;
 	struct resource *mem, *ioarea, *res, *dat;
 	struct davinci_mcasp_pdata *pdata;
 	struct davinci_mcasp *mcasp;
@@ -1095,6 +1096,7 @@
 		mcasp->dat_port = true;
 
 	dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
+	dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
 	dma_params->asp_chan_q = pdata->asp_chan_q;
 	dma_params->ram_chan_q = pdata->ram_chan_q;
 	dma_params->sram_pool = pdata->sram_pool;
@@ -1105,7 +1107,7 @@
 		dma_params->dma_addr = mem->start + pdata->tx_dma_offset;
 
 	/* Unconditional dmaengine stuff */
-	mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_params->dma_addr;
+	dma_data->addr = dma_params->dma_addr;
 
 	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
 	if (res)
@@ -1113,7 +1115,14 @@
 	else
 		dma_params->channel = pdata->tx_dma_channel;
 
+	/* dmaengine filter data for DT and non-DT boot */
+	if (pdev->dev.of_node)
+		dma_data->filter_data = "tx";
+	else
+		dma_data->filter_data = &dma_params->channel;
+
 	dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
+	dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
 	dma_params->asp_chan_q = pdata->asp_chan_q;
 	dma_params->ram_chan_q = pdata->ram_chan_q;
 	dma_params->sram_pool = pdata->sram_pool;
@@ -1124,7 +1133,7 @@
 		dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
 
 	/* Unconditional dmaengine stuff */
-	mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_params->dma_addr;
+	dma_data->addr = dma_params->dma_addr;
 
 	if (mcasp->version < MCASP_VERSION_3) {
 		mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
@@ -1140,9 +1149,11 @@
 	else
 		dma_params->channel = pdata->rx_dma_channel;
 
-	/* Unconditional dmaengine stuff */
-	mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx";
-	mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx";
+	/* dmaengine filter data for DT and non-DT boot */
+	if (pdev->dev.of_node)
+		dma_data->filter_data = "rx";
+	else
+		dma_data->filter_data = &dma_params->channel;
 
 	dev_set_drvdata(&pdev->dev, mcasp);
 
diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/davinci/edma-pcm.c
new file mode 100644
index 0000000..d38afb1
--- /dev/null
+++ b/sound/soc/davinci/edma-pcm.c
@@ -0,0 +1,57 @@
+/*
+ * edma-pcm.c - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Based on: sound/soc/tegra/tegra_pcm.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+#include <linux/edma.h>
+
+static const struct snd_pcm_hardware edma_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_BATCH |
+				  SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
+				  SNDRV_PCM_INFO_INTERLEAVED,
+	.buffer_bytes_max	= 128 * 1024,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 64 * 1024,
+	.periods_min		= 2,
+	.periods_max		= 19, /* Limit by edma dmaengine driver */
+};
+
+static const struct snd_dmaengine_pcm_config edma_dmaengine_pcm_config = {
+	.pcm_hardware = &edma_pcm_hardware,
+	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+	.compat_filter_fn = edma_filter_fn,
+	.prealloc_buffer_size = 128 * 1024,
+};
+
+int edma_pcm_platform_register(struct device *dev)
+{
+	return devm_snd_dmaengine_pcm_register(dev, &edma_dmaengine_pcm_config,
+					SND_DMAENGINE_PCM_FLAG_COMPAT);
+}
+EXPORT_SYMBOL_GPL(edma_pcm_platform_register);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("eDMA PCM ASoC platform driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/edma-pcm.h b/sound/soc/davinci/edma-pcm.h
new file mode 100644
index 0000000..894c378
--- /dev/null
+++ b/sound/soc/davinci/edma-pcm.h
@@ -0,0 +1,25 @@
+/*
+ * edma-pcm.h - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Based on: sound/soc/tegra/tegra_pcm.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __EDMA_PCM_H__
+#define __EDMA_PCM_H__
+
+int edma_pcm_platform_register(struct device *dev);
+
+#endif /* __EDMA_PCM_H__ */
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 5dd4769..2ee8ed5 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -20,7 +20,6 @@
 
 struct simple_card_data {
 	struct snd_soc_card snd_card;
-	unsigned int daifmt;
 	struct asoc_simple_dai cpu_dai;
 	struct asoc_simple_dai codec_dai;
 	struct snd_soc_dai_link snd_link;
@@ -105,12 +104,12 @@
 	/* get dai->name */
 	ret = snd_soc_of_get_dai_name(np, name);
 	if (ret < 0)
-		goto parse_error;
+		return ret;
 
 	/* parse TDM slot */
 	ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
 	if (ret)
-		goto parse_error;
+		return ret;
 
 	/*
 	 * bitclock-inversion, frame-inversion
@@ -130,7 +129,7 @@
 		clk = of_clk_get(np, 0);
 		if (IS_ERR(clk)) {
 			ret = PTR_ERR(clk);
-			goto parse_error;
+			return ret;
 		}
 
 		dai->sysclk = clk_get_rate(clk);
@@ -144,12 +143,7 @@
 			dai->sysclk = clk_get_rate(clk);
 	}
 
-	ret = 0;
-
-parse_error:
-	of_node_put(node);
-
-	return ret;
+	return 0;
 }
 
 static int asoc_simple_card_parse_of(struct device_node *node,
@@ -157,15 +151,18 @@
 				     struct device *dev)
 {
 	struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
+	struct asoc_simple_dai *codec_dai = &priv->codec_dai;
+	struct asoc_simple_dai *cpu_dai = &priv->cpu_dai;
 	struct device_node *np;
 	char *name;
+	unsigned int daifmt;
 	int ret;
 
 	/* parsing the card name from DT */
 	snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
 
 	/* get CPU/CODEC common format via simple-audio-card,format */
-	priv->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
+	daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
 		(SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
 
 	/* off-codec widgets */
@@ -187,25 +184,35 @@
 	/* CPU sub-node */
 	ret = -EINVAL;
 	np = of_get_child_by_name(node, "simple-audio-card,cpu");
-	if (np)
-		ret = asoc_simple_card_sub_parse_of(np, priv->daifmt,
-						  &priv->cpu_dai,
+	if (np) {
+		ret = asoc_simple_card_sub_parse_of(np, daifmt,
+						  cpu_dai,
 						  &dai_link->cpu_of_node,
 						  &dai_link->cpu_dai_name);
+		of_node_put(np);
+	}
 	if (ret < 0)
 		return ret;
 
 	/* CODEC sub-node */
 	ret = -EINVAL;
 	np = of_get_child_by_name(node, "simple-audio-card,codec");
-	if (np)
-		ret = asoc_simple_card_sub_parse_of(np, priv->daifmt,
-						  &priv->codec_dai,
+	if (np) {
+		ret = asoc_simple_card_sub_parse_of(np, daifmt,
+						  codec_dai,
 						  &dai_link->codec_of_node,
 						  &dai_link->codec_dai_name);
+		of_node_put(np);
+	}
 	if (ret < 0)
 		return ret;
 
+	/*
+	 * overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC
+	 * while the other bits should be identical unless buggy SW/HW design.
+	 */
+	cpu_dai->fmt = codec_dai->fmt;
+
 	if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name)
 		return -EINVAL;
 
@@ -224,15 +231,15 @@
 	dai_link->platform_of_node = dai_link->cpu_of_node;
 
 	dev_dbg(dev, "card-name : %s\n", name);
-	dev_dbg(dev, "platform : %04x\n", priv->daifmt);
+	dev_dbg(dev, "platform : %04x\n", daifmt);
 	dev_dbg(dev, "cpu : %s / %04x / %d\n",
 		dai_link->cpu_dai_name,
-		priv->cpu_dai.fmt,
-		priv->cpu_dai.sysclk);
+		cpu_dai->fmt,
+		cpu_dai->sysclk);
 	dev_dbg(dev, "codec : %s / %04x / %d\n",
 		dai_link->codec_dai_name,
-		priv->codec_dai.fmt,
-		priv->codec_dai.sysclk);
+		codec_dai->fmt,
+		codec_dai->sysclk);
 
 	/*
 	 * soc_bind_dai_link() will check cpu name
@@ -248,6 +255,27 @@
 	return 0;
 }
 
+/* update the reference count of the devices nodes at end of probe */
+static int asoc_simple_card_unref(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct snd_soc_dai_link *dai_link;
+	struct device_node *np;
+	int num_links;
+
+	for (num_links = 0, dai_link = card->dai_link;
+	     num_links < card->num_links;
+	     num_links++, dai_link++) {
+		np = (struct device_node *) dai_link->cpu_of_node;
+		if (np)
+			of_node_put(np);
+		np = (struct device_node *) dai_link->codec_of_node;
+		if (np)
+			of_node_put(np);
+	}
+	return 0;
+}
+
 static int asoc_simple_card_probe(struct platform_device *pdev)
 {
 	struct simple_card_data *priv;
@@ -275,7 +303,7 @@
 		if (ret < 0) {
 			if (ret != -EPROBE_DEFER)
 				dev_err(dev, "parse error %d\n", ret);
-			return ret;
+			goto err;
 		}
 	} else {
 		struct asoc_simple_card_info *cinfo;
@@ -318,7 +346,11 @@
 
 	snd_soc_card_set_drvdata(&priv->snd_card, priv);
 
-	return devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
+	ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
+
+err:
+	asoc_simple_card_unref(pdev);
+	return ret;
 }
 
 static const struct of_device_id asoc_simple_of_match[] = {
diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/mfld_machine.c
index 0cef32e..031d787 100644
--- a/sound/soc/intel/mfld_machine.c
+++ b/sound/soc/intel/mfld_machine.c
@@ -53,6 +53,7 @@
 
 static unsigned int	hs_switch;
 static unsigned int	lo_dac;
+static struct snd_soc_codec *mfld_codec;
 
 struct mfld_mc_private {
 	void __iomem *int_base;
@@ -100,8 +101,8 @@
 static int headset_set_switch(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_context *dapm = &card->dapm;
 
 	if (ucontrol->value.integer.value[0] == hs_switch)
 		return 0;
@@ -127,10 +128,8 @@
 	return 0;
 }
 
-static void lo_enable_out_pins(struct snd_soc_codec *codec)
+static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm)
 {
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
 	snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL");
 	snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR");
 	snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL");
@@ -156,8 +155,8 @@
 static int lo_set_switch(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_context *dapm = &card->dapm;
 
 	if (ucontrol->value.integer.value[0] == lo_dac)
 		return 0;
@@ -167,35 +166,35 @@
 	/* we dont want to work with last state of lineout so just enable all
 	 * pins and then disable pins not required
 	 */
-	lo_enable_out_pins(codec);
+	lo_enable_out_pins(dapm);
 
 	switch (ucontrol->value.integer.value[0]) {
 	case 0:
 		pr_debug("set vibra path\n");
 		snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
 		snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT");
-		snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0);
+		snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0);
 		break;
 
 	case 1:
 		pr_debug("set hs  path\n");
 		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
 		snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
-		snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22);
+		snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x22);
 		break;
 
 	case 2:
 		pr_debug("set spkr path\n");
 		snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL");
 		snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR");
-		snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44);
+		snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x44);
 		break;
 
 	case 3:
 		pr_debug("set null path\n");
 		snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL");
 		snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR");
-		snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66);
+		snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x66);
 		break;
 	}
 
@@ -238,26 +237,11 @@
 
 static int mfld_init(struct snd_soc_pcm_runtime *runtime)
 {
-	struct snd_soc_codec *codec = runtime->codec;
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
 	int ret_val;
 
-	/* Add jack sense widgets */
-	snd_soc_dapm_new_controls(dapm, mfld_widgets, ARRAY_SIZE(mfld_widgets));
+	mfld_codec = runtime->codec;
 
-	/* Set up the map */
-	snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map));
-
-	/* always connected */
-	snd_soc_dapm_enable_pin(dapm, "Headphones");
-	snd_soc_dapm_enable_pin(dapm, "Mic");
-
-	ret_val = snd_soc_add_codec_controls(codec, mfld_snd_controls,
-				ARRAY_SIZE(mfld_snd_controls));
-	if (ret_val) {
-		pr_err("soc_add_controls failed %d", ret_val);
-		return ret_val;
-	}
 	/* default is earpiece pin, userspace sets it explcitly */
 	snd_soc_dapm_disable_pin(dapm, "Headphones");
 	/* default is lineout NC, userspace sets it explcitly */
@@ -270,7 +254,7 @@
 	snd_soc_dapm_disable_pin(dapm, "LINEINR");
 
 	/* Headset and button jack detection */
-	ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack",
+	ret_val = snd_soc_jack_new(mfld_codec, "Intel(R) MID Audio Jack",
 			SND_JACK_HEADSET | SND_JACK_BTN_0 |
 			SND_JACK_BTN_1, &mfld_jack);
 	if (ret_val) {
@@ -352,6 +336,13 @@
 	.owner = THIS_MODULE,
 	.dai_link = mfld_msic_dailink,
 	.num_links = ARRAY_SIZE(mfld_msic_dailink),
+
+	.controls = mfld_snd_controls,
+	.num_controls = ARRAY_SIZE(mfld_snd_controls),
+	.dapm_widgets = mfld_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mfld_widgets),
+	.dapm_routes = mfld_map,
+	.num_dapm_routes = ARRAY_SIZE(mfld_map),
 };
 
 static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig
index 2dc3ecf..49f8437 100644
--- a/sound/soc/kirkwood/Kconfig
+++ b/sound/soc/kirkwood/Kconfig
@@ -10,6 +10,7 @@
 	tristate "SoC Audio support for Armada 370 DB"
 	depends on SND_KIRKWOOD_SOC && (ARCH_MVEBU || COMPILE_TEST) && I2C
 	select SND_SOC_CS42L51
+	select SND_SOC_SPDIF
 	help
 	  Say Y if you want to add support for SoC audio on
 	  the Armada 370 Development Board.
diff --git a/sound/soc/kirkwood/armada-370-db.c b/sound/soc/kirkwood/armada-370-db.c
index 977639b..c443338 100644
--- a/sound/soc/kirkwood/armada-370-db.c
+++ b/sound/soc/kirkwood/armada-370-db.c
@@ -67,6 +67,20 @@
 	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
 	.ops = &a370db_ops,
 },
+{
+	.name = "S/PDIF out",
+	.stream_name = "spdif-out",
+	.cpu_dai_name = "spdif",
+	.codec_dai_name = "dit-hifi",
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+},
+{
+	.name = "S/PDIF in",
+	.stream_name = "spdif-in",
+	.cpu_dai_name = "spdif",
+	.codec_dai_name = "dir-hifi",
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+},
 };
 
 static struct snd_soc_card a370db = {
@@ -95,6 +109,20 @@
 		of_parse_phandle(pdev->dev.of_node,
 				 "marvell,audio-codec", 0);
 
+	a370db_dai[1].cpu_of_node = a370db_dai[0].cpu_of_node;
+	a370db_dai[1].platform_of_node = a370db_dai[0].cpu_of_node;
+
+	a370db_dai[1].codec_of_node =
+		of_parse_phandle(pdev->dev.of_node,
+				 "marvell,audio-codec", 1);
+
+	a370db_dai[2].cpu_of_node = a370db_dai[0].cpu_of_node;
+	a370db_dai[2].platform_of_node = a370db_dai[0].cpu_of_node;
+
+	a370db_dai[2].codec_of_node =
+		of_parse_phandle(pdev->dev.of_node,
+				 "marvell,audio-codec", 2);
+
 	return devm_snd_soc_register_card(card->dev, card);
 }
 
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index ebb1390..024dafc 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -203,8 +203,7 @@
 
 static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
 
 	return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
 				ARRAY_SIZE(dmic_audio_map));
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 1967f44..710a079 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1711,9 +1711,9 @@
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
-		fsi->clk_master = 1;
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
+		fsi->clk_master = 1; /* codec is slave, cpu is master */
 		break;
 	default:
 		return -EINVAL;
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 953f1cc..69c4426 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -392,6 +392,7 @@
 }
 
 int rsnd_adg_probe(struct platform_device *pdev,
+		   const struct rsnd_of_data *of_data,
 		   struct rsnd_priv *priv)
 {
 	struct rsnd_adg *adg;
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 6a1b45d..215b668 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -100,6 +100,21 @@
 #define RSND_RATES SNDRV_PCM_RATE_8000_96000
 #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
 
+static struct rsnd_of_data rsnd_of_data_gen1 = {
+	.flags = RSND_GEN1,
+};
+
+static struct rsnd_of_data rsnd_of_data_gen2 = {
+	.flags = RSND_GEN2,
+};
+
+static 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 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rsnd_of_match);
+
 /*
  *	rsnd_platform functions
  */
@@ -510,10 +525,10 @@
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
-		rdai->clk_master = 1;
+		rdai->clk_master = 0;
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
-		rdai->clk_master = 0;
+		rdai->clk_master = 1; /* codec is slave, cpu is master */
 		break;
 	default:
 		return -EINVAL;
@@ -620,7 +635,92 @@
 	return ret;
 }
 
+static void rsnd_of_parse_dai(struct platform_device *pdev,
+			      const struct rsnd_of_data *of_data,
+			      struct rsnd_priv *priv)
+{
+	struct device_node *dai_node,	*dai_np;
+	struct device_node *ssi_node,	*ssi_np;
+	struct device_node *src_node,	*src_np;
+	struct device_node *playback, *capture;
+	struct rsnd_dai_platform_info *dai_info;
+	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+	struct device *dev = &pdev->dev;
+	int nr, i;
+	int dai_i, ssi_i, src_i;
+
+	if (!of_data)
+		return;
+
+	dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai");
+	if (!dai_node)
+		return;
+
+	nr = of_get_child_count(dai_node);
+	if (!nr)
+		return;
+
+	dai_info = devm_kzalloc(dev,
+				sizeof(struct rsnd_dai_platform_info) * nr,
+				GFP_KERNEL);
+	if (!dai_info) {
+		dev_err(dev, "dai info allocation error\n");
+		return;
+	}
+
+	info->dai_info_nr	= nr;
+	info->dai_info		= dai_info;
+
+	ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
+	src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
+
+#define mod_parse(name)							\
+if (name##_node) {							\
+	struct rsnd_##name##_platform_info *name##_info;		\
+									\
+	name##_i = 0;							\
+	for_each_child_of_node(name##_node, name##_np) {		\
+		name##_info = info->name##_info + name##_i;		\
+									\
+		if (name##_np == playback)				\
+			dai_info->playback.name = name##_info;		\
+		if (name##_np == capture)				\
+			dai_info->capture.name = name##_info;		\
+									\
+		name##_i++;						\
+	}								\
+}
+
+	/*
+	 * parse all dai
+	 */
+	dai_i = 0;
+	for_each_child_of_node(dai_node, dai_np) {
+		dai_info = info->dai_info + dai_i;
+
+		for (i = 0;; i++) {
+
+			playback = of_parse_phandle(dai_np, "playback", i);
+			capture  = of_parse_phandle(dai_np, "capture", i);
+
+			if (!playback && !capture)
+				break;
+
+			mod_parse(ssi);
+			mod_parse(src);
+
+			if (playback)
+				of_node_put(playback);
+			if (capture)
+				of_node_put(capture);
+		}
+
+		dai_i++;
+	}
+}
+
 static int rsnd_dai_probe(struct platform_device *pdev,
+			  const struct rsnd_of_data *of_data,
 			  struct rsnd_priv *priv)
 {
 	struct snd_soc_dai_driver *drv;
@@ -628,13 +728,16 @@
 	struct rsnd_dai *rdai;
 	struct rsnd_mod *pmod, *cmod;
 	struct device *dev = rsnd_priv_to_dev(priv);
-	int dai_nr = info->dai_info_nr;
+	int dai_nr;
 	int i;
 
+	rsnd_of_parse_dai(pdev, of_data, priv);
+
 	/*
 	 * dai_nr should be set via dai_info_nr,
 	 * but allow it to keeping compatible
 	 */
+	dai_nr = info->dai_info_nr;
 	if (!dai_nr) {
 		/* get max dai nr */
 		for (dai_nr = 0; dai_nr < 32; dai_nr++) {
@@ -802,7 +905,10 @@
 	struct rsnd_priv *priv;
 	struct device *dev = &pdev->dev;
 	struct rsnd_dai *rdai;
+	const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev);
+	const struct rsnd_of_data *of_data;
 	int (*probe_func[])(struct platform_device *pdev,
+			    const struct rsnd_of_data *of_data,
 			    struct rsnd_priv *priv) = {
 		rsnd_gen_probe,
 		rsnd_ssi_probe,
@@ -812,7 +918,16 @@
 	};
 	int ret, i;
 
-	info = pdev->dev.platform_data;
+	info = NULL;
+	of_data = NULL;
+	if (of_id) {
+		info = devm_kzalloc(&pdev->dev,
+				    sizeof(struct rcar_snd_info), GFP_KERNEL);
+		of_data = of_id->data;
+	} else {
+		info = pdev->dev.platform_data;
+	}
+
 	if (!info) {
 		dev_err(dev, "driver needs R-Car sound information\n");
 		return -ENODEV;
@@ -835,7 +950,7 @@
 	 *	init each module
 	 */
 	for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
-		ret = probe_func[i](pdev, priv);
+		ret = probe_func[i](pdev, of_data, priv);
 		if (ret)
 			return ret;
 	}
@@ -903,6 +1018,7 @@
 static struct platform_driver rsnd_driver = {
 	.driver	= {
 		.name	= "rcar_sound",
+		.of_match_table = rsnd_of_match,
 	},
 	.probe		= rsnd_probe,
 	.remove		= rsnd_remove,
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 9094970..50a1ef3 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -359,13 +359,28 @@
 /*
  *		Gen
  */
+static void rsnd_of_parse_gen(struct platform_device *pdev,
+			      const struct rsnd_of_data *of_data,
+			      struct rsnd_priv *priv)
+{
+	struct rcar_snd_info *info = priv->info;
+
+	if (!of_data)
+		return;
+
+	info->flags = of_data->flags;
+}
+
 int rsnd_gen_probe(struct platform_device *pdev,
+		   const struct rsnd_of_data *of_data,
 		   struct rsnd_priv *priv)
 {
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_gen *gen;
 	int ret;
 
+	rsnd_of_parse_gen(pdev, of_data, priv);
+
 	gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
 	if (!gen) {
 		dev_err(dev, "GEN allocate failed\n");
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index c46e0af..619d198 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -17,6 +17,8 @@
 #include <linux/io.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
 #include <linux/sh_dma.h>
 #include <linux/workqueue.h>
 #include <sound/rcar_snd.h>
@@ -113,6 +115,7 @@
 #define RSND_REG_SRCOUT_TIMSEL4		RSND_REG_SHARE18
 #define RSND_REG_AUDIO_CLK_SEL2		RSND_REG_SHARE19
 
+struct rsnd_of_data;
 struct rsnd_priv;
 struct rsnd_mod;
 struct rsnd_dai;
@@ -260,6 +263,7 @@
  *	R-Car Gen1/Gen2
  */
 int rsnd_gen_probe(struct platform_device *pdev,
+		   const struct rsnd_of_data *of_data,
 		   struct rsnd_priv *priv);
 void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
 			       struct rsnd_mod *mod,
@@ -273,6 +277,7 @@
 int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
 int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
 int rsnd_adg_probe(struct platform_device *pdev,
+		   const struct rsnd_of_data *of_data,
 		   struct rsnd_priv *priv);
 int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
 				  struct rsnd_mod *mod,
@@ -290,6 +295,10 @@
 /*
  *	R-Car sound priv
  */
+struct rsnd_of_data {
+	u32 flags;
+};
+
 struct rsnd_priv {
 
 	struct device *dev;
@@ -348,6 +357,7 @@
  *	R-Car SRC
  */
 int rsnd_src_probe(struct platform_device *pdev,
+		   const struct rsnd_of_data *of_data,
 		   struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
 unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
@@ -366,6 +376,7 @@
  *	R-Car SSI
  */
 int rsnd_ssi_probe(struct platform_device *pdev,
+		   const struct rsnd_of_data *of_data,
 		   struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
 struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index ea6a214..eee75eb 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -628,7 +628,41 @@
 	return &((struct rsnd_src *)(priv->src) + id)->mod;
 }
 
+static void rsnd_of_parse_src(struct platform_device *pdev,
+			      const struct rsnd_of_data *of_data,
+			      struct rsnd_priv *priv)
+{
+	struct device_node *src_node;
+	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+	struct rsnd_src_platform_info *src_info;
+	struct device *dev = &pdev->dev;
+	int nr;
+
+	if (!of_data)
+		return;
+
+	src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
+	if (!src_node)
+		return;
+
+	nr = of_get_child_count(src_node);
+	if (!nr)
+		return;
+
+	src_info = devm_kzalloc(dev,
+				sizeof(struct rsnd_src_platform_info) * nr,
+				GFP_KERNEL);
+	if (!src_info) {
+		dev_err(dev, "src info allocation error\n");
+		return;
+	}
+
+	info->src_info		= src_info;
+	info->src_info_nr	= nr;
+}
+
 int rsnd_src_probe(struct platform_device *pdev,
+		   const struct rsnd_of_data *of_data,
 		   struct rsnd_priv *priv)
 {
 	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
@@ -639,6 +673,8 @@
 	char name[RSND_SRC_NAME_SIZE];
 	int i, nr;
 
+	rsnd_of_parse_src(pdev, of_data, priv);
+
 	/*
 	 * init SRC
 	 */
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 633b23d..4b7e206 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -588,7 +588,61 @@
 	}
 }
 
+
+static void rsnd_of_parse_ssi(struct platform_device *pdev,
+			      const struct rsnd_of_data *of_data,
+			      struct rsnd_priv *priv)
+{
+	struct device_node *node;
+	struct device_node *np;
+	struct rsnd_ssi_platform_info *ssi_info;
+	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+	struct device *dev = &pdev->dev;
+	int nr, i;
+
+	if (!of_data)
+		return;
+
+	node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
+	if (!node)
+		return;
+
+	nr = of_get_child_count(node);
+	if (!nr)
+		return;
+
+	ssi_info = devm_kzalloc(dev,
+				sizeof(struct rsnd_ssi_platform_info) * nr,
+				GFP_KERNEL);
+	if (!ssi_info) {
+		dev_err(dev, "ssi info allocation error\n");
+		return;
+	}
+
+	info->ssi_info		= ssi_info;
+	info->ssi_info_nr	= nr;
+
+	i = -1;
+	for_each_child_of_node(node, np) {
+		i++;
+
+		ssi_info = info->ssi_info + i;
+
+		/*
+		 * pin settings
+		 */
+		if (of_get_property(np, "shared-pin", NULL))
+			ssi_info->flags |= RSND_SSI_CLK_PIN_SHARE;
+
+		/*
+		 * irq
+		 */
+		ssi_info->pio_irq = irq_of_parse_and_map(np, 0);
+	}
+}
+
 int rsnd_ssi_probe(struct platform_device *pdev,
+		   const struct rsnd_of_data *of_data,
 		   struct rsnd_priv *priv)
 {
 	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
@@ -600,6 +654,8 @@
 	char name[RSND_SSI_NAME_SIZE];
 	int i, nr;
 
+	rsnd_of_parse_ssi(pdev, of_data, priv);
+
 	/*
 	 *	init SSI
 	 */
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index 8aa0869..260efc8 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -23,21 +23,6 @@
 static int hw_write(struct snd_soc_codec *codec, unsigned int reg,
 		    unsigned int value)
 {
-	int ret;
-
-	if (!snd_soc_codec_volatile_register(codec, reg) &&
-	    reg < codec->driver->reg_cache_size &&
-	    !codec->cache_bypass) {
-		ret = snd_soc_cache_write(codec, reg, value);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (codec->cache_only) {
-		codec->cache_sync = 1;
-		return 0;
-	}
-
 	return regmap_write(codec->control_data, reg, value);
 }
 
@@ -46,23 +31,11 @@
 	int ret;
 	unsigned int val;
 
-	if (reg >= codec->driver->reg_cache_size ||
-	    snd_soc_codec_volatile_register(codec, reg) ||
-	    codec->cache_bypass) {
-		if (codec->cache_only)
-			return -1;
-
-		ret = regmap_read(codec->control_data, reg, &val);
-		if (ret == 0)
-			return val;
-		else
-			return -1;
-	}
-
-	ret = snd_soc_cache_read(codec, reg, &val);
-	if (ret < 0)
+	ret = regmap_read(codec->control_data, reg, &val);
+	if (ret == 0)
+		return val;
+	else
 		return -1;
-	return val;
 }
 
 /**
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 330eaf0..2cedf09 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -2050,7 +2050,6 @@
 
 		paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
 		if (paths < 0) {
-			dpcm_path_put(&list);
 			dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
 					fe->dai_link->name,  "playback");
 			mutex_unlock(&card->mutex);
@@ -2080,7 +2079,6 @@
 
 		paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
 		if (paths < 0) {
-			dpcm_path_put(&list);
 			dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
 					fe->dai_link->name,  "capture");
 			mutex_unlock(&card->mutex);
@@ -2145,7 +2143,6 @@
 	fe->dpcm[stream].runtime = fe_substream->runtime;
 
 	if (dpcm_path_get(fe, stream, &list) <= 0) {
-		dpcm_path_put(&list);
 		dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
 			fe->dai_link->name, stream ? "capture" : "playback");
 	}
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
index cf5e1cf..0a59e23 100644
--- a/sound/soc/tegra/tegra20_ac97.c
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -306,7 +306,7 @@
 	.readable_reg = tegra20_ac97_wr_rd_reg,
 	.volatile_reg = tegra20_ac97_volatile_reg,
 	.precious_reg = tegra20_ac97_precious_reg,
-	.cache_type = REGCACHE_RBTREE,
+	.cache_type = REGCACHE_FLAT,
 };
 
 static int tegra20_ac97_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c
index e723929..a634f13 100644
--- a/sound/soc/tegra/tegra20_das.c
+++ b/sound/soc/tegra/tegra20_das.c
@@ -128,7 +128,7 @@
 	.max_register = LAST_REG(DAC_INPUT_DATA_CLK_SEL),
 	.writeable_reg = tegra20_das_wr_rd_reg,
 	.readable_reg = tegra20_das_wr_rd_reg,
-	.cache_type = REGCACHE_RBTREE,
+	.cache_type = REGCACHE_FLAT,
 };
 
 static int tegra20_das_probe(struct platform_device *pdev)
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 42c1f6b..79a9932 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -333,7 +333,7 @@
 	.readable_reg = tegra20_i2s_wr_rd_reg,
 	.volatile_reg = tegra20_i2s_volatile_reg,
 	.precious_reg = tegra20_i2s_precious_reg,
-	.cache_type = REGCACHE_RBTREE,
+	.cache_type = REGCACHE_FLAT,
 };
 
 static int tegra20_i2s_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index 8c7c102..a0ce924 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -259,7 +259,7 @@
 	.readable_reg = tegra20_spdif_wr_rd_reg,
 	.volatile_reg = tegra20_spdif_volatile_reg,
 	.precious_reg = tegra20_spdif_precious_reg,
-	.cache_type = REGCACHE_RBTREE,
+	.cache_type = REGCACHE_FLAT,
 };
 
 static int tegra20_spdif_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index d6f4c99..0db68f4 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -471,7 +471,7 @@
 	.readable_reg = tegra30_ahub_apbif_wr_rd_reg,
 	.volatile_reg = tegra30_ahub_apbif_volatile_reg,
 	.precious_reg = tegra30_ahub_apbif_precious_reg,
-	.cache_type = REGCACHE_RBTREE,
+	.cache_type = REGCACHE_FLAT,
 };
 
 static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg)
@@ -490,7 +490,7 @@
 	.max_register = LAST_REG(AUDIO_RX),
 	.writeable_reg = tegra30_ahub_ahub_wr_rd_reg,
 	.readable_reg = tegra30_ahub_ahub_wr_rd_reg,
-	.cache_type = REGCACHE_RBTREE,
+	.cache_type = REGCACHE_FLAT,
 };
 
 static struct tegra30_ahub_soc_data soc_data_tegra30 = {
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 49ad936..f146c41 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -357,7 +357,7 @@
 	.writeable_reg = tegra30_i2s_wr_rd_reg,
 	.readable_reg = tegra30_i2s_wr_rd_reg,
 	.volatile_reg = tegra30_i2s_volatile_reg,
-	.cache_type = REGCACHE_RBTREE,
+	.cache_type = REGCACHE_FLAT,
 };
 
 static const struct tegra30_i2s_soc_data tegra30_i2s_config = {