Merge tag 'v3.4-rc2' into for-3.5

Linux 3.4-rc2 contains some bug fixes we need, including the addition of
an export for regcache_sync_region().
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt
new file mode 100644
index 0000000..d09b4e3
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt
@@ -0,0 +1,49 @@
+Freescale i.MX audio complex with SGTL5000 codec
+
+Required properties:
+- compatible : "fsl,imx-audio-sgtl5000"
+- model : The user-visible name of this sound complex
+- ssi-controller : The phandle of the i.MX SSI controller
+- audio-codec : The phandle of the SGTL5000 audio codec
+- audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names could be power
+  supplies, SGTL5000 pins, and the jacks on the board:
+
+  Power supplies:
+   * Mic Bias
+
+  SGTL5000 pins:
+   * MIC_IN
+   * LINE_IN
+   * HP_OUT
+   * LINE_OUT
+
+  Board connectors:
+   * Mic Jack
+   * Line In Jack
+   * Headphone Jack
+   * Line Out Jack
+   * Ext Spk
+
+- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
+- mux-ext-port : The external port of the i.MX audio muxer
+
+Note: The AUDMUX port numbering should start at 1, which is consistent with
+hardware manual.
+
+Example:
+
+sound {
+	compatible = "fsl,imx51-babbage-sgtl5000",
+		     "fsl,imx-audio-sgtl5000";
+	model = "imx51-babbage-sgtl5000";
+	ssi-controller = <&ssi1>;
+	audio-codec = <&sgtl5000>;
+	audio-routing =
+		"Mic Jack", "Mic Bias",
+		"MIC_IN", "Mic Bias",
+		"Headphone Jack", "HP_OUT";
+	mux-int-port = <1>;
+	mux-ext-port = <3>;
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index 2dcfca8..61ac041 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6663,6 +6663,12 @@
 F:	drivers/mmc/host/tifm_sd.c
 F:	include/linux/tifm.h
 
+TI LM49xxx FAMILY ASoC CODEC DRIVERS
+M:	M R Swami Reddy <mr.swami.reddy@ti.com>
+L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:	Maintained
+F:	sound/soc/codecs/lm49453*
+
 TI TWL4030 SERIES SOC CODEC DRIVER
 M:	Peter Ujfalusi <peter.ujfalusi@ti.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c
index 0952494..86abcf0 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -64,9 +64,9 @@
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C2_BASE, "tegra-i2c.1", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C3_BASE, "tegra-i2c.2", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c-dvc", TEGRA_DVC_BASE, "tegra-i2c.3", NULL),
-	OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.0", NULL),
-	OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra-i2s.1", NULL),
-	OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra-das", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra20-i2s.0", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra20-i2s.1", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra20-das", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0",
 		       &tegra_ehci1_pdata),
 	OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1",
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
index c00aadb..5eb74ea 100644
--- a/arch/arm/mach-tegra/board-harmony.c
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -122,7 +122,6 @@
 	&tegra_ehci3_device,
 	&tegra_i2s_device1,
 	&tegra_das_device,
-	&tegra_pcm_device,
 	&harmony_audio_device,
 };
 
diff --git a/arch/arm/mach-tegra/board-seaboard.c b/arch/arm/mach-tegra/board-seaboard.c
index d669847..0e2957f 100644
--- a/arch/arm/mach-tegra/board-seaboard.c
+++ b/arch/arm/mach-tegra/board-seaboard.c
@@ -153,7 +153,6 @@
 	&seaboard_gpio_keys_device,
 	&tegra_i2s_device1,
 	&tegra_das_device,
-	&tegra_pcm_device,
 	&seaboard_audio_device,
 };
 
diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c
index cd52820a..ba2e047 100644
--- a/arch/arm/mach-tegra/board-trimslice.c
+++ b/arch/arm/mach-tegra/board-trimslice.c
@@ -86,7 +86,6 @@
 	&tegra_sdhci_device4,
 	&tegra_i2s_device1,
 	&tegra_das_device,
-	&tegra_pcm_device,
 	&trimslice_audio_device,
 };
 
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index 5f6b867..d6c9b26 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -671,14 +671,14 @@
 };
 
 struct platform_device tegra_i2s_device1 = {
-	.name		= "tegra-i2s",
+	.name		= "tegra20-i2s",
 	.id		= 0,
 	.resource	= i2s_resource1,
 	.num_resources	= ARRAY_SIZE(i2s_resource1),
 };
 
 struct platform_device tegra_i2s_device2 = {
-	.name		= "tegra-i2s",
+	.name		= "tegra20-i2s",
 	.id		= 1,
 	.resource	= i2s_resource2,
 	.num_resources	= ARRAY_SIZE(i2s_resource2),
@@ -693,13 +693,8 @@
 };
 
 struct platform_device tegra_das_device = {
-	.name		= "tegra-das",
+	.name		= "tegra20-das",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(tegra_das_resources),
 	.resource	= tegra_das_resources,
 };
-
-struct platform_device tegra_pcm_device = {
-	.name = "tegra-pcm-audio",
-	.id = -1,
-};
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
index ec45567..138c642 100644
--- a/arch/arm/mach-tegra/devices.h
+++ b/arch/arm/mach-tegra/devices.h
@@ -52,6 +52,5 @@
 extern struct platform_device tegra_i2s_device1;
 extern struct platform_device tegra_i2s_device2;
 extern struct platform_device tegra_das_device;
-extern struct platform_device tegra_pcm_device;
 
 #endif
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 592a4ee..cf4999b 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -2142,8 +2142,8 @@
 	PERIPH_CLK("apbdma",	"tegra-dma",		NULL,	34,	0,	108000000, mux_pclk,			0),
 	PERIPH_CLK("rtc",	"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET),
 	PERIPH_CLK("timer",	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0),
-	PERIPH_CLK("i2s1",	"tegra-i2s.0",		NULL,	11,	0x100,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("i2s2",	"tegra-i2s.1",		NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("i2s1",	"tegra20-i2s.0",	NULL,	11,	0x100,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("i2s2",	"tegra20-i2s.1",	NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
 	PERIPH_CLK("spdif_out",	"spdif_out",		NULL,	10,	0x108,	100000000, mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
 	PERIPH_CLK("spdif_in",	"spdif_in",		NULL,	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71),
 	PERIPH_CLK("pwm",	"pwm",			NULL,	17,	0x110,	432000000, mux_pllp_pllc_audio_clkm_clk32,	MUX | DIV_U71),
diff --git a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
index 0db9ba0..c09598b 100644
--- a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
+++ b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
@@ -100,6 +100,7 @@
 CONFIG_SND_PCM_OSS=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
 CONFIG_SND_SOC=y
+CONFIG_SND_POWERPC_SOC=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_CMOS=y
 CONFIG_EXT2_FS=y
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index d6b6df5..62bb723 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -141,6 +141,7 @@
 # CONFIG_SND_PPC is not set
 # CONFIG_SND_USB is not set
 CONFIG_SND_SOC=y
+CONFIG_SND_POWERPC_SOC=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index 5b0e292..d182842 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -143,6 +143,7 @@
 # CONFIG_SND_PPC is not set
 # CONFIG_SND_USB is not set
 CONFIG_SND_SOC=y
+CONFIG_SND_POWERPC_SOC=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
diff --git a/include/sound/max98095.h b/include/sound/max98095.h
index 7513a42..65b1c90 100644
--- a/include/sound/max98095.h
+++ b/include/sound/max98095.h
@@ -49,6 +49,18 @@
 	 */
 	unsigned int digmic_left_mode:1;
 	unsigned int digmic_right_mode:1;
+
+	/* Pin5 is the mechanical method of sensing jack insertion
+	 * but it is something that might not be supported.
+	 * 0 = PIN5 not supported
+	 * 1 = PIN5 supported
+	 */
+	int jack_detect_pin5en:1;
+
+	/* Slew amount for jack detection. Calculated as 4 * (delay + 1).
+	 * Default delay is 24 to get a time of 100ms.
+	 */
+	unsigned int jack_detect_delay;
 };
 
 #endif
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index c429f24..3248fbc 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -241,6 +241,7 @@
 
 	struct snd_soc_dapm_widget *playback_widget;
 	struct snd_soc_dapm_widget *capture_widget;
+	struct snd_soc_dapm_context dapm;
 
 	/* DAI DMA data */
 	void *playback_dma_data;
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 8da3c24..01e7ad1 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -141,10 +141,6 @@
 {       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 	.invert = winvert, .kcontrol_news = wcontrols, \
 	.num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
-#define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
-{	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0, \
-	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
 {	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
@@ -324,6 +320,7 @@
 struct snd_soc_dapm_pin;
 struct snd_soc_dapm_route;
 struct snd_soc_dapm_context;
+struct regulator;
 
 int dapm_reg_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event);
@@ -369,8 +366,8 @@
 			     const struct snd_soc_dapm_route *route, int num);
 
 /* dapm events */
-int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
-			      struct snd_soc_dai *dai, int event);
+void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+	int event);
 void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 /* external DAPM widget events */
@@ -432,6 +429,11 @@
 	snd_soc_dapm_dai,		/* link to DAI structure */
 };
 
+enum snd_soc_dapm_subclass {
+	SND_SOC_DAPM_CLASS_INIT		= 0,
+	SND_SOC_DAPM_CLASS_RUNTIME	= 1,
+};
+
 /*
  * DAPM audio route definition.
  *
@@ -482,9 +484,10 @@
 	struct snd_soc_dapm_context *dapm;
 
 	void *priv;				/* widget specific data */
+	struct regulator *regulator;		/* attached regulator */
 
 	/* dapm control */
-	short reg;						/* negative reg = no direct dapm */
+	int reg;				/* negative reg = no direct dapm */
 	unsigned char shift;			/* bits to shift */
 	unsigned int saved_value;		/* widget saved value */
 	unsigned int value;				/* widget current value */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 2ebf787..acb57b8 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -55,6 +55,18 @@
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
 	.put = snd_soc_put_volsw, \
 	.private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+#define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \
+{       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+	SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.tlv.p  = (tlv_array),\
+	.info = snd_soc_info_volsw, \
+	.get = snd_soc_get_volsw_sx,\
+	.put = snd_soc_put_volsw_sx, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = xreg, .rreg = xreg, \
+		.shift = xshift, .rshift = xshift, \
+		.max = xmax, .min = xmin} }
 #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
@@ -85,6 +97,18 @@
 	.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
 	.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
 					    xmax, xinvert) }
+#define SOC_DOUBLE_R_SX_TLV(xname, xreg, xrreg, xshift, xmin, xmax, tlv_array) \
+{       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+	SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.tlv.p  = (tlv_array), \
+	.info = snd_soc_info_volsw, \
+	.get = snd_soc_get_volsw_sx, \
+	.put = snd_soc_put_volsw_sx, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = xreg, .rreg = xrreg, \
+		.shift = xshift, .rshift = xshift, \
+		.max = xmax, .min = xmin} }
 #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
 {	.iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
@@ -171,20 +195,6 @@
 	.get = xhandler_get, .put = xhandler_put, \
 	.private_value = (unsigned long)&xenum }
 
-#define SOC_DOUBLE_R_SX_TLV(xname, xreg_left, xreg_right, xshift,\
-		xmin, xmax, tlv_array) \
-{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
-		  SNDRV_CTL_ELEM_ACCESS_READWRITE, \
-	.tlv.p = (tlv_array), \
-	.info = snd_soc_info_volsw_2r_sx, \
-	.get = snd_soc_get_volsw_2r_sx, \
-	.put = snd_soc_put_volsw_2r_sx, \
-	.private_value = (unsigned long)&(struct soc_mixer_control) \
-		{.reg = xreg_left, \
-		 .rreg = xreg_right, .shift = xshift, \
-		 .min = xmin, .max = xmax} }
-
 #define SND_SOC_BYTES(xname, xbase, xregs)		      \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,   \
 	.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
@@ -288,6 +298,11 @@
 	SND_SOC_PCM_CLASS_BE	= 1,
 };
 
+enum snd_soc_card_subclass {
+	SND_SOC_CARD_CLASS_INIT		= 0,
+	SND_SOC_CARD_CLASS_RUNTIME	= 1,
+};
+
 int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 			     int source, unsigned int freq, int dir);
 int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
@@ -413,6 +428,10 @@
 	struct snd_ctl_elem_value *ucontrol);
 #define snd_soc_get_volsw_2r snd_soc_get_volsw
 #define snd_soc_put_volsw_2r snd_soc_put_volsw
+int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_info *uinfo);
 int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
@@ -421,12 +440,6 @@
 	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_limit_volume(struct snd_soc_codec *codec,
 	const char *name, int max);
-int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_info *uinfo);
-int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol);
-int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_info *uinfo);
 int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
@@ -513,6 +526,7 @@
 #endif
 
 struct snd_soc_jack {
+	struct mutex mutex;
 	struct snd_jack *jack;
 	struct snd_soc_codec *codec;
 	struct list_head pins;
@@ -800,6 +814,7 @@
 
 	struct list_head list;
 	struct mutex mutex;
+	struct mutex dapm_mutex;
 
 	bool instantiated;
 
@@ -889,7 +904,6 @@
 	enum snd_soc_pcm_subclass pcm_subclass;
 	struct snd_pcm_ops ops;
 
-	unsigned int complete:1;
 	unsigned int dev_registered:1;
 
 	long pmdown_time;
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 91c9855..0f85f6d 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -35,7 +35,6 @@
 source "sound/soc/davinci/Kconfig"
 source "sound/soc/ep93xx/Kconfig"
 source "sound/soc/fsl/Kconfig"
-source "sound/soc/imx/Kconfig"
 source "sound/soc/jz4740/Kconfig"
 source "sound/soc/nuc900/Kconfig"
 source "sound/soc/omap/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 2feaf37..363dfd6 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -12,7 +12,6 @@
 obj-$(CONFIG_SND_SOC)	+= davinci/
 obj-$(CONFIG_SND_SOC)	+= ep93xx/
 obj-$(CONFIG_SND_SOC)	+= fsl/
-obj-$(CONFIG_SND_SOC)   += imx/
 obj-$(CONFIG_SND_SOC)	+= jz4740/
 obj-$(CONFIG_SND_SOC)	+= mid-x86/
 obj-$(CONFIG_SND_SOC)	+= mxs/
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 6508e8b..2e51eb0 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -37,11 +37,13 @@
 	select SND_SOC_DFBMCS320
 	select SND_SOC_JZ4740_CODEC
 	select SND_SOC_LM4857 if I2C
+	select SND_SOC_LM49453 if I2C
 	select SND_SOC_MAX98088 if I2C
 	select SND_SOC_MAX98095 if I2C
 	select SND_SOC_MAX9850 if I2C
 	select SND_SOC_MAX9768 if I2C
 	select SND_SOC_MAX9877 if I2C
+	select SND_SOC_ML26124 if I2C
 	select SND_SOC_PCM3008
 	select SND_SOC_RT5631 if I2C
 	select SND_SOC_SGTL5000 if I2C
@@ -217,6 +219,9 @@
 config SND_SOC_DMIC
 	tristate
 
+config SND_SOC_LM49453
+	tristate
+
 config SND_SOC_MAX98088
        tristate
 
@@ -436,5 +441,8 @@
 config SND_SOC_MAX9877
 	tristate
 
+config SND_SOC_ML26124
+	tristate
+
 config SND_SOC_TPA6130A2
 	tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 6662eb0..db61c44 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -25,10 +25,12 @@
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
 snd-soc-lm4857-objs := lm4857.o
+snd-soc-lm49453-objs := lm49453.o
 snd-soc-max9768-objs := max9768.o
 snd-soc-max98088-objs := max98088.o
 snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
+snd-soc-ml26124-objs := ml26124.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-sgtl5000-objs := sgtl5000.o
@@ -128,13 +130,15 @@
 obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DFBMCS320)	+= snd-soc-dfbmcs320.o
 obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_LM4857)	+= snd-soc-lm4857.o
-obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
+obj-$(CONFIG_SND_SOC_LM49453)   += snd-soc-lm49453.o
 obj-$(CONFIG_SND_SOC_MAX9768)	+= snd-soc-max9768.o
 obj-$(CONFIG_SND_SOC_MAX98088)	+= snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_MAX98095)	+= snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
+obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_RT5631)	+= snd-soc-rt5631.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 1bbad4c..a99a1b3 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -26,9 +26,7 @@
 static int ac97_prepare(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 
 	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
 		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 12e3b41..c67b50d 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -162,9 +162,7 @@
 		struct snd_soc_dai *dai)
 {
 	int word_len = 0;
-
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 
 	/* bit size */
 	switch (params_format(params)) {
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index a4a6bef..13e62be 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -245,9 +245,7 @@
 		struct snd_soc_dai *dai)
 {
 	int word_len = 0, master_rate = 0;
-
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
 
 	/* bit size */
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 78e9ce4..3d50fc8 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -258,8 +258,7 @@
 static int adau1701_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;
 	snd_pcm_format_t format;
 	unsigned int val;
 
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index ceb96ec..31d4483 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -88,8 +88,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 val = 0;
 
 	/* set the IEC958 bits: consumer mode, no copyright bit */
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 838ae8b..618fdc3 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -262,8 +262,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 ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
 	u8 mode2 = snd_soc_read(codec, AK4535_MODE2) & ~(0x3 << 5);
 	int rate = params_rate(params), fs = 256;
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index c4d165a..543a12f 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -296,8 +296,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 ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
 	int rate = params_rate(params), fs = 256;
 	u8 mode2;
@@ -517,67 +516,24 @@
 
 static int ak4641_probe(struct snd_soc_codec *codec)
 {
-	struct ak4641_platform_data *pdata = codec->dev->platform_data;
 	int ret;
 
-
-	if (pdata) {
-		if (gpio_is_valid(pdata->gpio_power)) {
-			ret = gpio_request_one(pdata->gpio_power,
-					GPIOF_OUT_INIT_LOW, "ak4641 power");
-			if (ret)
-				goto err_out;
-		}
-		if (gpio_is_valid(pdata->gpio_npdn)) {
-			ret = gpio_request_one(pdata->gpio_npdn,
-					GPIOF_OUT_INIT_LOW, "ak4641 npdn");
-			if (ret)
-				goto err_gpio;
-
-			udelay(1); /* > 150 ns */
-			gpio_set_value(pdata->gpio_npdn, 1);
-		}
-	}
-
 	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
 	if (ret != 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-		goto err_register;
+		return ret;
 	}
 
 	/* power on device */
 	ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	return 0;
-
-err_register:
-	if (pdata) {
-		if (gpio_is_valid(pdata->gpio_power))
-			gpio_set_value(pdata->gpio_power, 0);
-		if (gpio_is_valid(pdata->gpio_npdn))
-			gpio_free(pdata->gpio_npdn);
-	}
-err_gpio:
-	if (pdata && gpio_is_valid(pdata->gpio_power))
-		gpio_free(pdata->gpio_power);
-err_out:
-	return ret;
 }
 
 static int ak4641_remove(struct snd_soc_codec *codec)
 {
-	struct ak4641_platform_data *pdata = codec->dev->platform_data;
-
 	ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-	if (pdata) {
-		if (gpio_is_valid(pdata->gpio_power)) {
-			gpio_set_value(pdata->gpio_power, 0);
-			gpio_free(pdata->gpio_power);
-		}
-		if (gpio_is_valid(pdata->gpio_npdn))
-			gpio_free(pdata->gpio_npdn);
-	}
 	return 0;
 }
 
@@ -604,6 +560,7 @@
 static int __devinit ak4641_i2c_probe(struct i2c_client *i2c,
 				      const struct i2c_device_id *id)
 {
+	struct ak4641_platform_data *pdata = i2c->dev.platform_data;
 	struct ak4641_priv *ak4641;
 	int ret;
 
@@ -612,16 +569,62 @@
 	if (!ak4641)
 		return -ENOMEM;
 
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power)) {
+			ret = gpio_request_one(pdata->gpio_power,
+					GPIOF_OUT_INIT_LOW, "ak4641 power");
+			if (ret)
+				goto err_out;
+		}
+		if (gpio_is_valid(pdata->gpio_npdn)) {
+			ret = gpio_request_one(pdata->gpio_npdn,
+					GPIOF_OUT_INIT_LOW, "ak4641 npdn");
+			if (ret)
+				goto err_gpio;
+
+			udelay(1); /* > 150 ns */
+			gpio_set_value(pdata->gpio_npdn, 1);
+		}
+	}
+
 	i2c_set_clientdata(i2c, ak4641);
 
 	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4641,
 				ak4641_dai, ARRAY_SIZE(ak4641_dai));
+	if (ret != 0)
+		goto err_gpio2;
+
+	return 0;
+
+err_gpio2:
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power))
+			gpio_set_value(pdata->gpio_power, 0);
+		if (gpio_is_valid(pdata->gpio_npdn))
+			gpio_free(pdata->gpio_npdn);
+	}
+err_gpio:
+	if (pdata && gpio_is_valid(pdata->gpio_power))
+		gpio_free(pdata->gpio_power);
+err_out:
 	return ret;
 }
 
 static int __devexit ak4641_i2c_remove(struct i2c_client *i2c)
 {
+	struct ak4641_platform_data *pdata = i2c->dev.platform_data;
+
 	snd_soc_unregister_codec(&i2c->dev);
+
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power)) {
+			gpio_set_value(pdata->gpio_power, 0);
+			gpio_free(pdata->gpio_power);
+		}
+		if (gpio_is_valid(pdata->gpio_npdn))
+			gpio_free(pdata->gpio_npdn);
+	}
+
 	return 0;
 }
 
@@ -641,23 +644,7 @@
 	.id_table = ak4641_i2c_id,
 };
 
-static int __init ak4641_modinit(void)
-{
-	int ret;
-
-	ret = i2c_add_driver(&ak4641_i2c_driver);
-	if (ret != 0)
-		pr_err("Failed to register AK4641 I2C driver: %d\n", ret);
-
-	return ret;
-}
-module_init(ak4641_modinit);
-
-static void __exit ak4641_exit(void)
-{
-	i2c_del_driver(&ak4641_i2c_driver);
-}
-module_exit(ak4641_exit);
+module_i2c_driver(ak4641_i2c_driver);
 
 MODULE_DESCRIPTION("SoC AK4641 driver");
 MODULE_AUTHOR("Harald Welte <laforge@gnufiish.org>");
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index d47b62d..3061d35 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -705,8 +705,7 @@
 static int alc5623_pcm_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 alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
 	int coeff, rate;
 	u16 iface;
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index e2111e0..93a5909 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -861,8 +861,7 @@
 static int alc5632_pcm_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;
 	int coeff, rate;
 	u16 iface;
 
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 1d672f5..047917f 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -307,8 +307,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 cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	unsigned int i;
@@ -600,10 +599,12 @@
 static int cs4270_soc_resume(struct snd_soc_codec *codec)
 {
 	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
-	int reg;
+	int reg, ret;
 
-	regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
-			      cs4270->supplies);
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
+				    cs4270->supplies);
+	if (ret != 0)
+		return ret;
 
 	/* In case the device was put to hard reset during sleep, we need to
 	 * wait 500ns here before any I2C communication. */
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index bf71412..9eb01d7 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -318,8 +318,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 cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 	int i, ret;
 	unsigned int ratio, val;
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index a8bf588..091d019 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -141,15 +141,15 @@
 static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
 	SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
 			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
-			7, 0xffffff99, 0x18, adc_pcm_tlv),
+			6, 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",
 			CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
-			8, 0xffffff19, 0x18, aout_tlv),
+			0, 0x34, 0xE4, aout_tlv),
 	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
 			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
-			7, 0xffffff99, 0x18, adc_pcm_tlv),
+			6, 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),
@@ -356,8 +356,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 cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	unsigned int i;
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 78979b3..2cc50b3 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -402,37 +402,37 @@
 
 static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
 	SOC_DOUBLE_R_SX_TLV("Headphone Analog Playback Volume",
-			CS42L73_HPAAVOL, CS42L73_HPBAVOL, 7,
-			0xffffffC1, 0x0C, hpaloa_tlv),
+			CS42L73_HPAAVOL, CS42L73_HPBAVOL, 0,
+			0x41, 0x4B, hpaloa_tlv),
 
 	SOC_DOUBLE_R_SX_TLV("LineOut Analog Playback Volume", CS42L73_LOAAVOL,
-			CS42L73_LOBAVOL, 7, 0xffffffC1, 0x0C, hpaloa_tlv),
+			CS42L73_LOBAVOL, 0, 0x41, 0x4B, hpaloa_tlv),
 
 	SOC_DOUBLE_R_SX_TLV("Input PGA Analog Volume", CS42L73_MICAPREPGAAVOL,
-			CS42L73_MICBPREPGABVOL, 5, 0xffffff35,
-			0x34, micpga_tlv),
+			CS42L73_MICBPREPGABVOL, 5, 0x34,
+			0x24, micpga_tlv),
 
 	SOC_DOUBLE_R("MIC Preamp Switch", CS42L73_MICAPREPGAAVOL,
 			CS42L73_MICBPREPGABVOL, 6, 1, 1),
 
 	SOC_DOUBLE_R_SX_TLV("Input Path Digital Volume", CS42L73_IPADVOL,
-			CS42L73_IPBDVOL, 7, 0xffffffA0, 0xA0, ipd_tlv),
+			CS42L73_IPBDVOL, 0, 0xA0, 0x6C, ipd_tlv),
 
 	SOC_DOUBLE_R_SX_TLV("HL Digital Playback Volume",
-			CS42L73_HLADVOL, CS42L73_HLBDVOL, 7, 0xffffffE5,
-			0xE4, hl_tlv),
+			CS42L73_HLADVOL, CS42L73_HLBDVOL,
+			0, 0x34, 0xE4, hl_tlv),
 
 	SOC_SINGLE_TLV("ADC A Boost Volume",
 			CS42L73_ADCIPC, 2, 0x01, 1, adc_boost_tlv),
 
 	SOC_SINGLE_TLV("ADC B Boost Volume",
-			CS42L73_ADCIPC, 6, 0x01, 1, adc_boost_tlv),
+		       CS42L73_ADCIPC, 6, 0x01, 1, adc_boost_tlv),
 
-	SOC_SINGLE_TLV("Speakerphone Digital Playback Volume",
-			CS42L73_SPKDVOL, 0, 0xE4, 1, hl_tlv),
+	SOC_SINGLE_SX_TLV("Speakerphone Digital Volume",
+			    CS42L73_SPKDVOL, 0, 0x34, 0xE4, hl_tlv),
 
-	SOC_SINGLE_TLV("Ear Speaker Digital Playback Volume",
-			CS42L73_ESLDVOL, 0, 0xE4, 1, hl_tlv),
+	SOC_SINGLE_SX_TLV("Ear Speaker Digital Volume",
+			    CS42L73_ESLDVOL, 0, 0x34, 0xE4, hl_tlv),
 
 	SOC_DOUBLE_R("Headphone Analog Playback Switch", CS42L73_HPAAVOL,
 			CS42L73_HPBAVOL, 7, 1, 1),
@@ -1089,8 +1089,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 cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
 	int id = dai->id;
 	int mclk_coeff;
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 7843711..5dfdf6e 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -17,6 +17,7 @@
 
 #include <linux/delay.h>
 #include <linux/i2c.h>
+#include <linux/spi/spi.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -27,6 +28,7 @@
 #include <sound/tlv.h>
 
 /* DA7210 register space */
+#define DA7210_PAGE_CONTROL		0x00
 #define DA7210_CONTROL			0x01
 #define DA7210_STATUS			0x02
 #define DA7210_STARTUP1			0x03
@@ -631,6 +633,7 @@
 };
 
 static struct reg_default da7210_reg_defaults[] = {
+	{ 0x00, 0x00 },
 	{ 0x01, 0x11 },
 	{ 0x03, 0x00 },
 	{ 0x04, 0x00 },
@@ -713,8 +716,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;
 	u32 dai_cfg1;
 	u32 fs, bypass;
 
@@ -928,13 +930,6 @@
 	 */
 
 	/*
-	 * make sure that DA7210 use bypass mode before start up
-	 */
-	snd_soc_write(codec, DA7210_STARTUP1, 0);
-	snd_soc_write(codec, DA7210_PLL_DIV3,
-		     DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
-
-	/*
 	 * ADC settings
 	 */
 
@@ -1025,16 +1020,6 @@
 		     DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
 	snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
 
-	/* As suggested by Dialog */
-	/* unlock */
-	regmap_write(da7210->regmap, DA7210_A_HID_UNLOCK,	0x8B);
-	regmap_write(da7210->regmap, DA7210_A_TEST_UNLOCK,	0xB4);
-	regmap_write(da7210->regmap, DA7210_A_PLL1,		0x01);
-	regmap_write(da7210->regmap, DA7210_A_CP_MODE,		0x7C);
-	/* re-lock */
-	regmap_write(da7210->regmap, DA7210_A_HID_UNLOCK,	0x00);
-	regmap_write(da7210->regmap, DA7210_A_TEST_UNLOCK,	0x00);
-
 	/* Activate all enabled subsystem */
 	snd_soc_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
 
@@ -1055,7 +1040,26 @@
 	.num_dapm_routes	= ARRAY_SIZE(da7210_audio_map),
 };
 
-static struct regmap_config da7210_regmap = {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+static struct reg_default da7210_regmap_i2c_patch[] = {
+
+	/* System controller master disable */
+	{ DA7210_STARTUP1, 0x00 },
+	/* make sure that DA7210 use bypass mode before start up */
+	{ DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP },
+
+	/* to unlock */
+	{ DA7210_A_HID_UNLOCK, 0x8B},
+	{ DA7210_A_TEST_UNLOCK, 0xB4},
+	{ DA7210_A_PLL1, 0x01},
+	{ DA7210_A_CP_MODE, 0x7C},
+	/* to re-lock */
+	{ DA7210_A_HID_UNLOCK, 0x00},
+	{ DA7210_A_TEST_UNLOCK, 0x00},
+};
+
+static const struct regmap_config da7210_regmap_config_i2c = {
 	.reg_bits = 8,
 	.val_bits = 8,
 
@@ -1066,7 +1070,6 @@
 	.cache_type = REGCACHE_RBTREE,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
 			   	      const struct i2c_device_id *id)
 {
@@ -1080,13 +1083,18 @@
 
 	i2c_set_clientdata(i2c, da7210);
 
-	da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap);
+	da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap_config_i2c);
 	if (IS_ERR(da7210->regmap)) {
 		ret = PTR_ERR(da7210->regmap);
 		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
 		return ret;
 	}
 
+	ret = regmap_register_patch(da7210->regmap, da7210_regmap_i2c_patch,
+				    ARRAY_SIZE(da7210_regmap_i2c_patch));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
 	ret =  snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_da7210, &da7210_dai, 1);
 	if (ret < 0) {
@@ -1119,7 +1127,7 @@
 /* I2C codec control layer */
 static struct i2c_driver da7210_i2c_driver = {
 	.driver = {
-		.name = "da7210-codec",
+		.name = "da7210",
 		.owner = THIS_MODULE,
 	},
 	.probe		= da7210_i2c_probe,
@@ -1128,12 +1136,112 @@
 };
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+
+static struct reg_default da7210_regmap_spi_patch[] = {
+	/* Dummy read to give two pulses over nCS for SPI */
+	{ DA7210_AUX2, 0x00 },
+	{ DA7210_AUX2, 0x00 },
+
+	/* System controller master disable */
+	{ DA7210_STARTUP1, 0x00 },
+	/* make sure that DA7210 use bypass mode before start up */
+	{ DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP },
+
+	/* to set PAGE1 of SPI register space */
+	{ DA7210_PAGE_CONTROL, 0x80 },
+	/* to unlock */
+	{ DA7210_A_HID_UNLOCK, 0x8B},
+	{ DA7210_A_TEST_UNLOCK, 0xB4},
+	{ DA7210_A_PLL1, 0x01},
+	{ DA7210_A_CP_MODE, 0x7C},
+	/* to re-lock */
+	{ DA7210_A_HID_UNLOCK, 0x00},
+	{ DA7210_A_TEST_UNLOCK, 0x00},
+	/* to set back PAGE0 of SPI register space */
+	{ DA7210_PAGE_CONTROL, 0x00 },
+};
+
+static const struct regmap_config da7210_regmap_config_spi = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.read_flag_mask = 0x01,
+	.write_flag_mask = 0x00,
+
+	.reg_defaults = da7210_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(da7210_reg_defaults),
+	.volatile_reg = da7210_volatile_register,
+	.readable_reg = da7210_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit da7210_spi_probe(struct spi_device *spi)
+{
+	struct da7210_priv *da7210;
+	int ret;
+
+	da7210 = devm_kzalloc(&spi->dev, sizeof(struct da7210_priv),
+			      GFP_KERNEL);
+	if (!da7210)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, da7210);
+	da7210->regmap = devm_regmap_init_spi(spi, &da7210_regmap_config_spi);
+	if (IS_ERR(da7210->regmap)) {
+		ret = PTR_ERR(da7210->regmap);
+		dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_register_patch(da7210->regmap, da7210_regmap_spi_patch,
+				    ARRAY_SIZE(da7210_regmap_spi_patch));
+	if (ret != 0)
+		dev_warn(&spi->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	ret =  snd_soc_register_codec(&spi->dev,
+			&soc_codec_dev_da7210, &da7210_dai, 1);
+	if (ret < 0)
+		goto err_regmap;
+
+	return ret;
+
+err_regmap:
+	regmap_exit(da7210->regmap);
+
+	return ret;
+}
+
+static int __devexit da7210_spi_remove(struct spi_device *spi)
+{
+	struct da7210_priv *da7210 = spi_get_drvdata(spi);
+	snd_soc_unregister_codec(&spi->dev);
+	regmap_exit(da7210->regmap);
+	return 0;
+}
+
+static struct spi_driver da7210_spi_driver = {
+	.driver = {
+		.name = "da7210",
+		.owner = THIS_MODULE,
+	},
+	.probe = da7210_spi_probe,
+	.remove = __devexit_p(da7210_spi_remove)
+};
+#endif
+
 static int __init da7210_modinit(void)
 {
 	int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	ret = i2c_add_driver(&da7210_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&da7210_spi_driver);
+	if (ret) {
+		printk(KERN_ERR "Failed to register da7210 SPI driver: %d\n",
+		       ret);
+	}
+#endif
 	return ret;
 }
 module_init(da7210_modinit);
@@ -1143,6 +1251,9 @@
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&da7210_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&da7210_spi_driver);
+#endif
 }
 module_exit(da7210_exit);
 
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 4624e75..85d9cab 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -164,8 +164,7 @@
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
 	uint32_t val;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec =rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 
 	switch (params_rate(params)) {
 	case 8000:
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
new file mode 100644
index 0000000..5eb726b
--- /dev/null
+++ b/sound/soc/codecs/lm49453.c
@@ -0,0 +1,1550 @@
+/*
+ * lm49453.c  -  LM49453 ALSA Soc Audio driver
+ *
+ * Copyright (c) 2012 Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * Initially based on sound/soc/codecs/wm8350.c
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <asm/div64.h>
+#include "lm49453.h"
+
+static struct reg_default lm49453_reg_defs[] = {
+	{ 0, 0x00 },
+	{ 1, 0x00 },
+	{ 2, 0x00 },
+	{ 3, 0x00 },
+	{ 4, 0x00 },
+	{ 5, 0x00 },
+	{ 6, 0x00 },
+	{ 7, 0x00 },
+	{ 8, 0x00 },
+	{ 9, 0x00 },
+	{ 10, 0x00 },
+	{ 11, 0x00 },
+	{ 12, 0x00 },
+	{ 13, 0x00 },
+	{ 14, 0x00 },
+	{ 15, 0x00 },
+	{ 16, 0x00 },
+	{ 17, 0x00 },
+	{ 18, 0x00 },
+	{ 19, 0x00 },
+	{ 20, 0x00 },
+	{ 21, 0x00 },
+	{ 22, 0x00 },
+	{ 23, 0x00 },
+	{ 32, 0x00 },
+	{ 33, 0x00 },
+	{ 35, 0x00 },
+	{ 36, 0x00 },
+	{ 37, 0x00 },
+	{ 46, 0x00 },
+	{ 48, 0x00 },
+	{ 49, 0x00 },
+	{ 51, 0x00 },
+	{ 56, 0x00 },
+	{ 58, 0x00 },
+	{ 59, 0x00 },
+	{ 60, 0x00 },
+	{ 61, 0x00 },
+	{ 62, 0x00 },
+	{ 63, 0x00 },
+	{ 64, 0x00 },
+	{ 65, 0x00 },
+	{ 66, 0x00 },
+	{ 67, 0x00 },
+	{ 68, 0x00 },
+	{ 69, 0x00 },
+	{ 70, 0x00 },
+	{ 71, 0x00 },
+	{ 72, 0x00 },
+	{ 73, 0x00 },
+	{ 74, 0x00 },
+	{ 75, 0x00 },
+	{ 76, 0x00 },
+	{ 77, 0x00 },
+	{ 78, 0x00 },
+	{ 79, 0x00 },
+	{ 80, 0x00 },
+	{ 81, 0x00 },
+	{ 82, 0x00 },
+	{ 83, 0x00 },
+	{ 85, 0x00 },
+	{ 85, 0x00 },
+	{ 86, 0x00 },
+	{ 87, 0x00 },
+	{ 88, 0x00 },
+	{ 89, 0x00 },
+	{ 90, 0x00 },
+	{ 91, 0x00 },
+	{ 92, 0x00 },
+	{ 93, 0x00 },
+	{ 94, 0x00 },
+	{ 95, 0x00 },
+	{ 96, 0x01 },
+	{ 97, 0x00 },
+	{ 98, 0x00 },
+	{ 99, 0x00 },
+	{ 100, 0x00 },
+	{ 101, 0x00 },
+	{ 102, 0x00 },
+	{ 103, 0x01 },
+	{ 105, 0x01 },
+	{ 106, 0x00 },
+	{ 107, 0x01 },
+	{ 107, 0x00 },
+	{ 108, 0x00 },
+	{ 109, 0x00 },
+	{ 110, 0x00 },
+	{ 111, 0x02 },
+	{ 112, 0x02 },
+	{ 113, 0x00 },
+	{ 121, 0x80 },
+	{ 122, 0xBB },
+	{ 123, 0x80 },
+	{ 124, 0xBB },
+	{ 128, 0x00 },
+	{ 130, 0x00 },
+	{ 131, 0x00 },
+	{ 132, 0x00 },
+	{ 133, 0x0A },
+	{ 134, 0x0A },
+	{ 135, 0x0A },
+	{ 136, 0x0F },
+	{ 137, 0x00 },
+	{ 138, 0x73 },
+	{ 139, 0x33 },
+	{ 140, 0x73 },
+	{ 141, 0x33 },
+	{ 142, 0x73 },
+	{ 143, 0x33 },
+	{ 144, 0x73 },
+	{ 145, 0x33 },
+	{ 146, 0x73 },
+	{ 147, 0x33 },
+	{ 148, 0x73 },
+	{ 149, 0x33 },
+	{ 150, 0x73 },
+	{ 151, 0x33 },
+	{ 152, 0x00 },
+	{ 153, 0x00 },
+	{ 154, 0x00 },
+	{ 155, 0x00 },
+	{ 176, 0x00 },
+	{ 177, 0x00 },
+	{ 178, 0x00 },
+	{ 179, 0x00 },
+	{ 180, 0x00 },
+	{ 181, 0x00 },
+	{ 182, 0x00 },
+	{ 183, 0x00 },
+	{ 184, 0x00 },
+	{ 185, 0x00 },
+	{ 186, 0x00 },
+	{ 189, 0x00 },
+	{ 188, 0x00 },
+	{ 194, 0x00 },
+	{ 195, 0x00 },
+	{ 196, 0x00 },
+	{ 197, 0x00 },
+	{ 200, 0x00 },
+	{ 201, 0x00 },
+	{ 202, 0x00 },
+	{ 203, 0x00 },
+	{ 204, 0x00 },
+	{ 205, 0x00 },
+	{ 208, 0x00 },
+	{ 209, 0x00 },
+	{ 210, 0x00 },
+	{ 211, 0x00 },
+	{ 213, 0x00 },
+	{ 214, 0x00 },
+	{ 215, 0x00 },
+	{ 216, 0x00 },
+	{ 217, 0x00 },
+	{ 218, 0x00 },
+	{ 219, 0x00 },
+	{ 221, 0x00 },
+	{ 222, 0x00 },
+	{ 224, 0x00 },
+	{ 225, 0x00 },
+	{ 226, 0x00 },
+	{ 227, 0x00 },
+	{ 228, 0x00 },
+	{ 229, 0x00 },
+	{ 230, 0x13 },
+	{ 231, 0x00 },
+	{ 232, 0x80 },
+	{ 233, 0x0C },
+	{ 234, 0xDD },
+	{ 235, 0x00 },
+	{ 236, 0x04 },
+	{ 237, 0x00 },
+	{ 238, 0x00 },
+	{ 239, 0x00 },
+	{ 240, 0x00 },
+	{ 241, 0x00 },
+	{ 242, 0x00 },
+	{ 243, 0x00 },
+	{ 244, 0x00 },
+	{ 245, 0x00 },
+	{ 248, 0x00 },
+	{ 249, 0x00 },
+	{ 254, 0x00 },
+	{ 255, 0x00 },
+};
+
+/* codec private data */
+struct lm49453_priv {
+	struct regmap *regmap;
+	int fs_rate;
+};
+
+/* capture path controls */
+
+static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"};
+
+static const SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5,
+				  lm49453_mic2mode_text);
+
+static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"};
+
+static const SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum,
+				  LM49453_P0_DIGITAL_MIC1_CONFIG_REG,
+				  7, lm49453_dmic_cfg_text);
+
+static const SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum,
+				  LM49453_P0_DIGITAL_MIC2_CONFIG_REG,
+				  7, lm49453_dmic_cfg_text);
+
+/* MUX Controls */
+static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" };
+
+static const char *lm49453_adcr_mux_text[] = { "MIC2", "Aux_R" };
+
+static const struct soc_enum lm49453_adcl_enum =
+	SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 0,
+			ARRAY_SIZE(lm49453_adcl_mux_text),
+			lm49453_adcl_mux_text);
+
+static const struct soc_enum lm49453_adcr_enum =
+	SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 1,
+			ARRAY_SIZE(lm49453_adcr_mux_text),
+			lm49453_adcr_mux_text);
+
+static const struct snd_kcontrol_new lm49453_adcl_mux_control =
+	SOC_DAPM_ENUM("ADC Left Mux", lm49453_adcl_enum);
+
+static const struct snd_kcontrol_new lm49453_adcr_mux_control =
+	SOC_DAPM_ENUM("ADC Right Mux", lm49453_adcr_enum);
+
+static const struct snd_kcontrol_new lm49453_headset_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHPL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHPL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHPL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHPL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHPL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHPL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHPL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHPL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHPL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHPL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHPL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHPL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHPL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHPL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHPL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHPL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 0, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_headset_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHPR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHPR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHPR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHPR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHPR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHPR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHPR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHPR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHPR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHPR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHPR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHPR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHPR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHPR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHPR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHPR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 1, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_speaker_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLSL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLSL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLSL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLSL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLSL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLSL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLSL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLSL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLSL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLSL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLSL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLSL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLSL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLSL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLSL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLSL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 2, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_speaker_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLSR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLSR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLSR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLSR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLSR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLSR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLSR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLSR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLSR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLSR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLSR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLSR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLSR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLSR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLSR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLSR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 3, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_haptic_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHAL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHAL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHAL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHAL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHAL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHAL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHAL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHAL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHAL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHAL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHAL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHAL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHAL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHAL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHAL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHAL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 4, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_haptic_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHAR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHAR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHAR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHAR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHAR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHAR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHAR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHAR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHAR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHAR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHAR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHAR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHAR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHAR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHAR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHAR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 5, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_lineout_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLOL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLOL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLOL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLOL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLOL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLOL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLOL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLOL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLOL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLOL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLOL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLOL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLOL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLOL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLOL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLOL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 6, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_lineout_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLOR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLOR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLOR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLOR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLOR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLOR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLOR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLOR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLOR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLOR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLOR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLOR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLOR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLOR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLOR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLOR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 7, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx1_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_PORT1_TX1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_PORT1_TX1_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx2_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_PORT1_TX2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT1_TX2_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx3_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX3_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX3_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX3_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX3_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX3_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX3_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_PORT1_TX3_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx4_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX4_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX4_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX4_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX4_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX4_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX4_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_PORT1_TX4_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx5_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX5_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX5_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX5_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX5_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX5_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX5_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_PORT1_TX5_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx6_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX6_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX6_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX6_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX6_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX6_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX6_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_PORT1_TX6_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx7_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX7_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX7_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX7_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX7_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX7_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX7_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_PORT1_TX7_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx8_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX8_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX8_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX8_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX8_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX8_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX8_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_PORT1_TX8_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port2_tx1_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT2_TX1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT2_TX1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT2_TX1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT2_TX1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT2_TX1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT2_TX1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_PORT2_TX1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_PORT2_TX1_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port2_tx2_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT2_TX2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT2_TX2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT2_TX2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT2_TX2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT2_TX2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT2_TX2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_PORT2_TX2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT2_TX2_REG, 7, 1, 0),
+};
+
+/* TLV Declarations */
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7650, 150, 1);
+static const DECLARE_TLV_DB_SCALE(port_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new lm49453_sidetone_mixer_controls[] = {
+/* Sidetone supports mono only */
+SOC_DAPM_SINGLE_TLV("Sidetone ADCL Volume", LM49453_P0_STN_VOL_ADCL_REG,
+		     0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone ADCR Volume", LM49453_P0_STN_VOL_ADCR_REG,
+		     0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC1L Volume", LM49453_P0_STN_VOL_DMIC1L_REG,
+		     0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC1R Volume", LM49453_P0_STN_VOL_DMIC1R_REG,
+		     0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC2L Volume", LM49453_P0_STN_VOL_DMIC2L_REG,
+		     0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC2R Volume", LM49453_P0_STN_VOL_DMIC2R_REG,
+		     0, 0x3F, 0, digital_tlv),
+};
+
+static const struct snd_kcontrol_new lm49453_snd_controls[] = {
+	/* mic1 and mic2 supports mono only */
+	SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_ADC_LEVELL_REG, 0, 6,
+			0, digital_tlv),
+	SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_ADC_LEVELR_REG, 0, 6,
+			0, digital_tlv),
+
+	SOC_DOUBLE_R_TLV("DMIC1 Volume", LM49453_P0_DMIC1_LEVELL_REG,
+			  LM49453_P0_DMIC1_LEVELR_REG, 0, 6, 0, digital_tlv),
+	SOC_DOUBLE_R_TLV("DMIC2 Volume", LM49453_P0_DMIC2_LEVELL_REG,
+			  LM49453_P0_DMIC2_LEVELR_REG, 0, 6, 0, digital_tlv),
+
+	SOC_DAPM_ENUM("Mic2Mode", lm49453_mic2mode_enum),
+	SOC_DAPM_ENUM("DMIC12 SRC", lm49453_dmic12_cfg_enum),
+	SOC_DAPM_ENUM("DMIC34 SRC", lm49453_dmic34_cfg_enum),
+
+	/* Capture path filter enable */
+	SOC_SINGLE("DMIC1 HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+					    0, 1, 0),
+	SOC_SINGLE("DMIC2 HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+					    1, 1, 0),
+	SOC_SINGLE("ADC HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+					  2, 1, 0),
+
+	SOC_DOUBLE_R_TLV("DAC HP Volume", LM49453_P0_DAC_HP_LEVELL_REG,
+			  LM49453_P0_DAC_HP_LEVELR_REG, 0, 6, 0, digital_tlv),
+	SOC_DOUBLE_R_TLV("DAC LO Volume", LM49453_P0_DAC_LO_LEVELL_REG,
+			  LM49453_P0_DAC_LO_LEVELR_REG, 0, 6, 0, digital_tlv),
+	SOC_DOUBLE_R_TLV("DAC LS Volume", LM49453_P0_DAC_LS_LEVELL_REG,
+			  LM49453_P0_DAC_LS_LEVELR_REG, 0, 6, 0, digital_tlv),
+	SOC_DOUBLE_R_TLV("DAC HA Volume", LM49453_P0_DAC_HA_LEVELL_REG,
+			  LM49453_P0_DAC_HA_LEVELR_REG, 0, 6, 0, digital_tlv),
+
+	SOC_SINGLE_TLV("EP Volume", LM49453_P0_DAC_LS_LEVELL_REG,
+			0, 6, 0, digital_tlv),
+
+	SOC_SINGLE_TLV("PORT1_1_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+			0, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_2_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+			2, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_3_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+			4, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_4_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+			6, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_5_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+			0, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_6_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+			2, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_7_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+			4, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_8_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+			6, 3, 0, port_tlv),
+
+	SOC_SINGLE_TLV("PORT2_1_RX_LVL Volume", LM49453_P0_PORT2_RX_LVL_REG,
+			0, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT2_2_RX_LVL Volume", LM49453_P0_PORT2_RX_LVL_REG,
+			2, 3, 0, port_tlv),
+
+	SOC_SINGLE("Port1 Playback Switch", LM49453_P0_AUDIO_PORT1_BASIC_REG,
+		    1, 1, 0),
+	SOC_SINGLE("Port2 Playback Switch", LM49453_P0_AUDIO_PORT2_BASIC_REG,
+		    1, 1, 0),
+	SOC_SINGLE("Port1 Capture Switch", LM49453_P0_AUDIO_PORT1_BASIC_REG,
+		    2, 1, 0),
+	SOC_SINGLE("Port2 Capture Switch", LM49453_P0_AUDIO_PORT2_BASIC_REG,
+		    2, 1, 0)
+
+};
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget lm49453_dapm_widgets[] = {
+
+	/* All end points HP,EP, LS, Lineout and Haptic */
+	SND_SOC_DAPM_OUTPUT("HPOUTL"),
+	SND_SOC_DAPM_OUTPUT("HPOUTR"),
+	SND_SOC_DAPM_OUTPUT("EPOUT"),
+	SND_SOC_DAPM_OUTPUT("LSOUTL"),
+	SND_SOC_DAPM_OUTPUT("LSOUTR"),
+	SND_SOC_DAPM_OUTPUT("LOOUTR"),
+	SND_SOC_DAPM_OUTPUT("LOOUTL"),
+	SND_SOC_DAPM_OUTPUT("HAOUTL"),
+	SND_SOC_DAPM_OUTPUT("HAOUTR"),
+
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_INPUT("DMIC1DAT"),
+	SND_SOC_DAPM_INPUT("DMIC2DAT"),
+	SND_SOC_DAPM_INPUT("AUXL"),
+	SND_SOC_DAPM_INPUT("AUXR"),
+
+	SND_SOC_DAPM_PGA("PORT1_1_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_2_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_3_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_4_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_5_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_6_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_7_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_8_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT2_1_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT2_2_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("AMIC1Bias", LM49453_P0_MICL_REG, 6, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AMIC2Bias", LM49453_P0_MICR_REG, 6, 0, NULL, 0),
+
+	/* playback path driver enables */
+	SND_SOC_DAPM_OUT_DRV("Headset Switch",
+			LM49453_P0_PMC_SETUP_REG, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Earpiece Switch",
+			LM49453_P0_EP_REG, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Speaker Left Switch",
+			LM49453_P0_DIS_PKVL_FB_REG, 0, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Speaker Right Switch",
+			LM49453_P0_DIS_PKVL_FB_REG, 1, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Haptic Left Switch",
+			LM49453_P0_DIS_PKVL_FB_REG, 2, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Haptic Right Switch",
+			LM49453_P0_DIS_PKVL_FB_REG, 3, 1, NULL, 0),
+
+	/* DAC */
+	SND_SOC_DAPM_DAC("HPL DAC", "Headset", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("HPR DAC", "Headset", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("LSL DAC", "Speaker", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("LSR DAC", "Speaker", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("HAL DAC", "Haptic", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("HAR DAC", "Haptic", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("LOL DAC", "Lineout", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("LOR DAC", "Lineout", SND_SOC_NOPM, 0, 0),
+
+
+	SND_SOC_DAPM_PGA("AUXL Input",
+			LM49453_P0_ANALOG_MIXER_ADC_REG, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUXR Input",
+			LM49453_P0_ANALOG_MIXER_ADC_REG, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Sidetone", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("DMIC1 Left", "Capture", SND_SOC_NOPM, 1, 0),
+	SND_SOC_DAPM_ADC("DMIC1 Right", "Capture", SND_SOC_NOPM, 1, 0),
+	SND_SOC_DAPM_ADC("DMIC2 Left", "Capture", SND_SOC_NOPM, 1, 0),
+	SND_SOC_DAPM_ADC("DMIC2 Right", "Capture", SND_SOC_NOPM, 1, 0),
+
+	SND_SOC_DAPM_ADC("ADC Left", "Capture", SND_SOC_NOPM, 1, 0),
+	SND_SOC_DAPM_ADC("ADC Right", "Capture", SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("ADCL Mux", SND_SOC_NOPM, 0, 0,
+			  &lm49453_adcl_mux_control),
+	SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0,
+			  &lm49453_adcr_mux_control),
+
+	SND_SOC_DAPM_MUX("Mic1 Input",
+			SND_SOC_NOPM, 0, 0, &lm49453_adcl_mux_control),
+
+	SND_SOC_DAPM_MUX("Mic2 Input",
+			SND_SOC_NOPM, 0, 0, &lm49453_adcr_mux_control),
+
+	/* AIF */
+	SND_SOC_DAPM_AIF_IN("PORT1_SDI", NULL, 0,
+			    LM49453_P0_PULL_CONFIG1_REG, 2, 0),
+	SND_SOC_DAPM_AIF_IN("PORT2_SDI", NULL, 0,
+			    LM49453_P0_PULL_CONFIG1_REG, 6, 0),
+
+	SND_SOC_DAPM_AIF_OUT("PORT1_SDO", NULL, 0,
+			     LM49453_P0_PULL_CONFIG1_REG, 3, 0),
+	SND_SOC_DAPM_AIF_OUT("PORT2_SDO", NULL, 0,
+			      LM49453_P0_PULL_CONFIG1_REG, 7, 0),
+
+	/* Port1 TX controls */
+	SND_SOC_DAPM_OUT_DRV("P1_1_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_2_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_3_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_4_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_5_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_6_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_7_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_8_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Port2 TX controls */
+	SND_SOC_DAPM_OUT_DRV("P2_1_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P2_2_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Sidetone Mixer */
+	SND_SOC_DAPM_MIXER("Sidetone Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_sidetone_mixer_controls,
+			    ARRAY_SIZE(lm49453_sidetone_mixer_controls)),
+
+	/* DAC MIXERS */
+	SND_SOC_DAPM_MIXER("HPL Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_headset_left_mixer,
+			    ARRAY_SIZE(lm49453_headset_left_mixer)),
+	SND_SOC_DAPM_MIXER("HPR Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_headset_right_mixer,
+			    ARRAY_SIZE(lm49453_headset_right_mixer)),
+	SND_SOC_DAPM_MIXER("LOL Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_lineout_left_mixer,
+			    ARRAY_SIZE(lm49453_lineout_left_mixer)),
+	SND_SOC_DAPM_MIXER("LOR Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_lineout_right_mixer,
+			    ARRAY_SIZE(lm49453_lineout_right_mixer)),
+	SND_SOC_DAPM_MIXER("LSL Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_speaker_left_mixer,
+			    ARRAY_SIZE(lm49453_speaker_left_mixer)),
+	SND_SOC_DAPM_MIXER("LSR Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_speaker_right_mixer,
+			    ARRAY_SIZE(lm49453_speaker_right_mixer)),
+	SND_SOC_DAPM_MIXER("HAL Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_haptic_left_mixer,
+			    ARRAY_SIZE(lm49453_haptic_left_mixer)),
+	SND_SOC_DAPM_MIXER("HAR Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_haptic_right_mixer,
+			    ARRAY_SIZE(lm49453_haptic_right_mixer)),
+
+	/* Capture Mixer */
+	SND_SOC_DAPM_MIXER("Port1_1 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx1_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx1_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_2 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx2_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx2_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_3 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx3_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx3_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_4 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx4_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx4_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_5 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx5_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx5_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_6 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx6_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx6_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_7 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx7_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx7_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_8 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx8_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx8_mixer)),
+
+	SND_SOC_DAPM_MIXER("Port2_1 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port2_tx1_mixer,
+			    ARRAY_SIZE(lm49453_port2_tx1_mixer)),
+	SND_SOC_DAPM_MIXER("Port2_2 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port2_tx2_mixer,
+			    ARRAY_SIZE(lm49453_port2_tx2_mixer)),
+};
+
+static const struct snd_soc_dapm_route lm49453_audio_map[] = {
+	/* Port SDI mapping */
+	{ "PORT1_1_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_2_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_3_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_4_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_5_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_6_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_7_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_8_RX", "Port1 Playback Switch", "PORT1_SDI" },
+
+	{ "PORT2_1_RX", "Port2 Playback Switch", "PORT2_SDI" },
+	{ "PORT2_2_RX", "Port2 Playback Switch", "PORT2_SDI" },
+
+	/* HP mapping */
+	{ "HPL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "HPL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "HPL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "HPL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "HPL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "HPL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "HPL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "HPL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	{ "HPL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "HPL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "HPL Mixer", "ADCL Switch", "ADC Left" },
+	{ "HPL Mixer", "ADCR Switch", "ADC Right" },
+	{ "HPL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "HPL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "HPL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "HPL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "HPL Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "HPL DAC", NULL, "HPL Mixer" },
+
+	{ "HPR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "HPR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "HPR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "HPR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "HPR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "HPR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "HPR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "HPR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "HPR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "HPR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "HPR Mixer", "ADCL Switch", "ADC Left" },
+	{ "HPR Mixer", "ADCR Switch", "ADC Right" },
+	{ "HPR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "HPR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "HPR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "HPR Mixer", "DMIC2L Switch", "DMIC2 Right" },
+	{ "HPR Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "HPR DAC", NULL, "HPR Mixer" },
+
+	{ "HPOUTL", "Headset Switch", "HPL DAC"},
+	{ "HPOUTR", "Headset Switch", "HPR DAC"},
+
+	/* EP map */
+	{ "EPOUT", "Earpiece Switch", "HPL DAC" },
+
+	/* Speaker map */
+	{ "LSL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "LSL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "LSL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "LSL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "LSL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "LSL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "LSL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "LSL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "LSL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "LSL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "LSL Mixer", "ADCL Switch", "ADC Left" },
+	{ "LSL Mixer", "ADCR Switch", "ADC Right" },
+	{ "LSL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "LSL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "LSL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "LSL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "LSL Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "LSL DAC", NULL, "LSL Mixer" },
+
+	{ "LSR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "LSR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "LSR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "LSR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "LSR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "LSR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "LSR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "LSR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "LSR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "LSR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "LSR Mixer", "ADCL Switch", "ADC Left" },
+	{ "LSR Mixer", "ADCR Switch", "ADC Right" },
+	{ "LSR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "LSR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "LSR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "LSR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "LSR Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "LSR DAC", NULL, "LSR Mixer" },
+
+	{ "LSOUTL", "Speaker Left Switch", "LSL DAC"},
+	{ "LSOUTR", "Speaker Left Switch", "LSR DAC"},
+
+	/* Haptic map */
+	{ "HAL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "HAL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "HAL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "HAL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "HAL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "HAL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "HAL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "HAL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "HAL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "HAL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "HAL Mixer", "ADCL Switch", "ADC Left" },
+	{ "HAL Mixer", "ADCR Switch", "ADC Right" },
+	{ "HAL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "HAL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "HAL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "HAL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "HAL Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "HAL DAC", NULL, "HAL Mixer" },
+
+	{ "HAR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "HAR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "HAR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "HAR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "HAR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "HAR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "HAR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "HAR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "HAR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "HAR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "HAR Mixer", "ADCL Switch", "ADC Left" },
+	{ "HAR Mixer", "ADCR Switch", "ADC Right" },
+	{ "HAR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "HAR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "HAR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "HAR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "HAR Mixer", "Sideton Switch", "Sidetone" },
+
+	{ "HAR DAC", NULL, "HAR Mixer" },
+
+	{ "HAOUTL", "Haptic Left Switch", "HAL DAC" },
+	{ "HAOUTR", "Haptic Right Switch", "HAR DAC" },
+
+	/* Lineout map */
+	{ "LOL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "LOL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "LOL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "LOL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "LOL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "LOL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "LOL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "LOL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "LOL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "LOL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "LOL Mixer", "ADCL Switch", "ADC Left" },
+	{ "LOL Mixer", "ADCR Switch", "ADC Right" },
+	{ "LOL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "LOL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "LOL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "LOL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "LOL Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "LOL DAC", NULL, "LOL Mixer" },
+
+	{ "LOR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "LOR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "LOR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "LOR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "LOR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "LOR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "LOR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "LOR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "LOR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "LOR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "LOR Mixer", "ADCL Switch", "ADC Left" },
+	{ "LOR Mixer", "ADCR Switch", "ADC Right" },
+	{ "LOR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "LOR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "LOR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "LOR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "LOR Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "LOR DAC", NULL, "LOR Mixer" },
+
+	{ "LOOUTL", NULL, "LOL DAC" },
+	{ "LOOUTR", NULL, "LOR DAC" },
+
+	/* TX map */
+	/* Port1 mappings */
+	{ "Port1_1 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_1 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_1 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_1 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_1 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_1 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_2 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_2 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_2 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_2 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_2 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_2 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_3 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_3 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_3 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_3 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_3 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_3 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_4 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_4 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_4 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_4 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_4 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_4 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_5 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_5 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_5 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_5 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_5 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_5 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_6 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_6 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_6 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_6 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_6 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_6 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_7 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_7 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_7 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_7 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_7 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_7 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_8 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_8 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_8 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_8 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_8 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_8 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port2_1 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port2_1 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port2_1 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port2_1 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port2_1 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port2_1 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port2_2 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port2_2 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port2_2 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port2_2 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port2_2 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port2_2 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "P1_1_TX", NULL, "Port1_1 Mixer" },
+	{ "P1_2_TX", NULL, "Port1_2 Mixer" },
+	{ "P1_3_TX", NULL, "Port1_3 Mixer" },
+	{ "P1_4_TX", NULL, "Port1_4 Mixer" },
+	{ "P1_5_TX", NULL, "Port1_5 Mixer" },
+	{ "P1_6_TX", NULL, "Port1_6 Mixer" },
+	{ "P1_7_TX", NULL, "Port1_7 Mixer" },
+	{ "P1_8_TX", NULL, "Port1_8 Mixer" },
+
+	{ "P2_1_TX", NULL, "Port2_1 Mixer" },
+	{ "P2_2_TX", NULL, "Port2_2 Mixer" },
+
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_1_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_2_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_3_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_4_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_5_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_6_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_7_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_8_TX"},
+
+	{ "PORT2_SDO", "Port2 Capture Switch", "P2_1_TX"},
+	{ "PORT2_SDO", "Port2 Capture Switch", "P2_2_TX"},
+
+	{ "Mic1 Input", NULL, "AMIC1" },
+	{ "Mic2 Input", NULL, "AMIC2" },
+
+	{ "AUXL Input", NULL, "AUXL" },
+	{ "AUXR Input", NULL, "AUXR" },
+
+	/* AUX connections */
+	{ "ADCL Mux", "Aux_L", "AUXL Input" },
+	{ "ADCL Mux", "MIC1", "Mic1 Input" },
+
+	{ "ADCR Mux", "Aux_R", "AUXR Input" },
+	{ "ADCR Mux", "MIC2", "Mic2 Input" },
+
+	/* ADC connection */
+	{ "ADC Left", NULL, "ADCL Mux"},
+	{ "ADC Right", NULL, "ADCR Mux"},
+
+	{ "DMIC1 Left", NULL, "DMIC1DAT"},
+	{ "DMIC1 Right", NULL, "DMIC1DAT"},
+	{ "DMIC2 Left", NULL, "DMIC2DAT"},
+	{ "DMIC2 Right", NULL, "DMIC2DAT"},
+
+	/* Sidetone map */
+	{ "Sidetone Mixer", NULL, "ADC Left" },
+	{ "Sidetone Mixer", NULL, "ADC Right" },
+	{ "Sidetone Mixer", NULL, "DMIC1 Left" },
+	{ "Sidetone Mixer", NULL, "DMIC1 Right" },
+	{ "Sidetone Mixer", NULL, "DMIC2 Left" },
+	{ "Sidetone Mixer", NULL, "DMIC2 Right" },
+
+	{ "Sidetone", "Sidetone Switch", "Sidetone Mixer" },
+};
+
+static int lm49453_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+	u16 clk_div = 0;
+
+	lm49453->fs_rate = params_rate(params);
+
+	/* Setting DAC clock dividers based on substream sample rate. */
+	switch (lm49453->fs_rate) {
+	case 8000:
+	case 16000:
+	case 32000:
+	case 24000:
+	case 48000:
+		clk_div = 256;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk_div = 216;
+		break;
+	case 96000:
+		clk_div = 127;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_write(codec, LM49453_P0_ADC_CLK_DIV_REG, clk_div);
+	snd_soc_write(codec, LM49453_P0_DAC_HP_CLK_DIV_REG, clk_div);
+
+	return 0;
+}
+
+static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	u16 aif_val;
+	int mode = 0;
+	int clk_phase = 0;
+	int clk_shift = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aif_val = 0;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		aif_val = LM49453_AUDIO_PORT1_BASIC_SYNC_MS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		aif_val = LM49453_AUDIO_PORT1_BASIC_CLK_MS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif_val = LM49453_AUDIO_PORT1_BASIC_CLK_MS |
+			  LM49453_AUDIO_PORT1_BASIC_SYNC_MS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		mode = 1;
+		clk_phase = (1 << 5);
+		clk_shift = 1;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		mode = 1;
+		clk_phase = (1 << 5);
+		clk_shift = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, LM49453_P0_AUDIO_PORT1_BASIC_REG,
+			    LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(1)|BIT(5),
+			    (aif_val | mode | clk_phase));
+
+	snd_soc_write(codec, LM49453_P0_AUDIO_PORT1_RX_MSB_REG, clk_shift);
+
+	return 0;
+}
+
+static int lm49453_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				  unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 pll_clk = 0;
+
+	switch (freq) {
+	case 12288000:
+	case 26000000:
+	case 19200000:
+		/* pll clk slection */
+		pll_clk = 0;
+		break;
+	case 48000:
+	case 32576:
+		/* fll clk slection */
+		pll_clk = BIT(4);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG, BIT(4), pll_clk);
+
+	return 0;
+}
+
+static int lm49453_hp_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(1)|BIT(0),
+			    (mute ? (BIT(1)|BIT(0)) : 0));
+	return 0;
+}
+
+static int lm49453_lo_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(3)|BIT(2),
+			    (mute ? (BIT(3)|BIT(2)) : 0));
+	return 0;
+}
+
+static int lm49453_ls_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(5)|BIT(4),
+			    (mute ? (BIT(5)|BIT(4)) : 0));
+	return 0;
+}
+
+static int lm49453_ep_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(4),
+			    (mute ? BIT(4) : 0));
+	return 0;
+}
+
+static int lm49453_ha_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(7)|BIT(6),
+			    (mute ? (BIT(7)|BIT(6)) : 0));
+	return 0;
+}
+
+static int lm49453_set_bias_level(struct snd_soc_codec *codec,
+				  enum snd_soc_bias_level level)
+{
+	struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+			regcache_sync(lm49453->regmap);
+
+		snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
+				    LM49453_PMC_SETUP_CHIP_EN, LM49453_CHIP_EN);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
+				    LM49453_PMC_SETUP_CHIP_EN, 0);
+		break;
+	}
+
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+/* Formates supported by LM49453 driver. */
+#define LM49453_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops lm49453_headset_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_hp_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_speaker_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_ls_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_haptic_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_ha_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_ep_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_ep_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_lineout_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_lo_mute,
+};
+
+/* LM49453 dai structure. */
+struct snd_soc_dai_driver lm49453_dai[] = {
+	{
+		.name = "LM49453 Headset",
+		.playback = {
+			.stream_name = "Headset",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 5,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_headset_dai_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "LM49453 Speaker",
+		.playback = {
+			.stream_name = "Speaker",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_speaker_dai_ops,
+	},
+	{
+		.name = "LM49453 Haptic",
+		.playback = {
+			.stream_name = "Haptic",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_haptic_dai_ops,
+	},
+	{
+		.name = "LM49453 Earpiece",
+		.playback = {
+			.stream_name = "Earpiece",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_ep_dai_ops,
+	},
+	{
+		.name = "LM49453 line out",
+		.playback = {
+			.stream_name = "Lineout",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_lineout_dai_ops,
+	},
+};
+
+static int lm49453_suspend(struct snd_soc_codec *codec)
+{
+	lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int lm49453_resume(struct snd_soc_codec *codec)
+{
+	lm49453_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	return 0;
+}
+
+static int lm49453_probe(struct snd_soc_codec *codec)
+{
+	struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	codec->control_data = lm49453->regmap;
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/* power down chip */
+static int lm49453_remove(struct snd_soc_codec *codec)
+{
+	lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
+	.probe = lm49453_probe,
+	.remove = lm49453_remove,
+	.suspend = lm49453_suspend,
+	.resume = lm49453_resume,
+	.set_bias_level = lm49453_set_bias_level,
+	.controls = lm49453_snd_controls,
+	.num_controls = ARRAY_SIZE(lm49453_snd_controls),
+	.dapm_widgets = lm49453_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(lm49453_dapm_widgets),
+	.dapm_routes = lm49453_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(lm49453_audio_map),
+	.idle_bias_off = true,
+};
+
+static const struct regmap_config lm49453_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = LM49453_MAX_REGISTER,
+	.reg_defaults = lm49453_reg_defs,
+	.num_reg_defaults = ARRAY_SIZE(lm49453_reg_defs),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int lm49453_i2c_probe(struct i2c_client *i2c,
+				       const struct i2c_device_id *id)
+{
+	struct lm49453_priv *lm49453;
+	int ret = 0;
+
+	lm49453 = devm_kzalloc(&i2c->dev, sizeof(struct lm49453_priv),
+				GFP_KERNEL);
+
+	if (lm49453 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, lm49453);
+
+	lm49453->regmap = regmap_init_i2c(i2c, &lm49453_regmap_config);
+	if (IS_ERR(lm49453->regmap)) {
+		ret = PTR_ERR(lm49453->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret =  snd_soc_register_codec(&i2c->dev,
+				      &soc_codec_dev_lm49453,
+				      lm49453_dai, ARRAY_SIZE(lm49453_dai));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		regmap_exit(lm49453->regmap);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int __devexit lm49453_i2c_remove(struct i2c_client *client)
+{
+	struct lm49453_priv *lm49453 = i2c_get_clientdata(client);
+
+	snd_soc_unregister_codec(&client->dev);
+	regmap_exit(lm49453->regmap);
+	return 0;
+}
+
+static const struct i2c_device_id lm49453_i2c_id[] = {
+	{ "lm49453", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm49453_i2c_id);
+
+static struct i2c_driver lm49453_i2c_driver = {
+	.driver = {
+		.name = "lm49453",
+		.owner = THIS_MODULE,
+	},
+	.probe = lm49453_i2c_probe,
+	.remove = __devexit_p(lm49453_i2c_remove),
+	.id_table = lm49453_i2c_id,
+};
+
+module_i2c_driver(lm49453_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC LM49453 driver");
+MODULE_AUTHOR("M R Swami Reddy <MR.Swami.Reddy@ti.com");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/lm49453.h b/sound/soc/codecs/lm49453.h
new file mode 100644
index 0000000..a63cfa5
--- /dev/null
+++ b/sound/soc/codecs/lm49453.h
@@ -0,0 +1,380 @@
+/*
+ * lm49453.h  -  LM49453 ALSA Soc Audio drive
+ *
+ * Copyright (c) 2012  Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ */
+
+#ifndef _LM49453_H
+#define _LM49453_H
+
+#include <linux/bitops.h>
+
+/* LM49453_P0 register space for page0 */
+#define LM49453_P0_PMC_SETUP_REG			0x00
+#define LM49453_P0_PLL_CLK_SEL1_REG			0x01
+#define LM49453_P0_PLL_CLK_SEL2_REG			0x02
+#define LM49453_P0_PMC_CLK_DIV_REG			0x03
+#define LM49453_P0_HSDET_CLK_DIV_REG			0x04
+#define LM49453_P0_DMIC_CLK_DIV_REG			0x05
+#define LM49453_P0_ADC_CLK_DIV_REG			0x06
+#define LM49453_P0_DAC_OT_CLK_DIV_REG			0x07
+#define LM49453_P0_PLL_HF_M_REG				0x08
+#define LM49453_P0_PLL_LF_M_REG				0x09
+#define LM49453_P0_PLL_NL_REG				0x0A
+#define LM49453_P0_PLL_N_MODL_REG			0x0B
+#define LM49453_P0_PLL_N_MODH_REG			0x0C
+#define LM49453_P0_PLL_P1_REG				0x0D
+#define LM49453_P0_PLL_P2_REG				0x0E
+#define LM49453_P0_FLL_REF_FREQL_REG			0x0F
+#define LM49453_P0_FLL_REF_FREQH_REG			0x10
+#define LM49453_P0_VCO_TARGETLL_REG			0x11
+#define LM49453_P0_VCO_TARGETLH_REG			0x12
+#define LM49453_P0_VCO_TARGETHL_REG			0x13
+#define LM49453_P0_VCO_TARGETHH_REG			0x14
+#define LM49453_P0_PLL_CONFIG_REG			0x15
+#define LM49453_P0_DAC_CLK_SEL_REG			0x16
+#define LM49453_P0_DAC_HP_CLK_DIV_REG			0x17
+
+/* Analog Mixer Input Stages */
+#define LM49453_P0_MICL_REG				0x20
+#define LM49453_P0_MICR_REG				0x21
+#define LM49453_P0_EP_REG				0x24
+#define LM49453_P0_DIS_PKVL_FB_REG			0x25
+
+/* Analog Mixer Output Stages */
+#define LM49453_P0_ANALOG_MIXER_ADC_REG			0x2E
+
+/*ADC or DAC */
+#define LM49453_P0_ADC_DSP_REG				0x30
+#define LM49453_P0_DAC_DSP_REG				0x31
+
+/* EFFECTS ENABLES */
+#define LM49453_P0_ADC_FX_ENABLES_REG			0x33
+
+/* GPIO */
+#define LM49453_P0_GPIO1_REG				0x38
+#define LM49453_P0_GPIO2_REG				0x39
+#define LM49453_P0_GPIO3_REG				0x3A
+#define LM49453_P0_HAP_CTL_REG				0x3B
+#define LM49453_P0_HAP_FREQ_PROG_LEFTL_REG		0x3C
+#define LM49453_P0_HAP_FREQ_PROG_LEFTH_REG		0x3D
+#define LM49453_P0_HAP_FREQ_PROG_RIGHTL_REG		0x3E
+#define LM49453_P0_HAP_FREQ_PROG_RIGHTH_REG		0x3F
+
+/* DIGITAL MIXER */
+#define LM49453_P0_DMIX_CLK_SEL_REG			0x40
+#define LM49453_P0_PORT1_RX_LVL1_REG			0x41
+#define LM49453_P0_PORT1_RX_LVL2_REG			0x42
+#define LM49453_P0_PORT2_RX_LVL_REG			0x43
+#define LM49453_P0_PORT1_TX1_REG			0x44
+#define LM49453_P0_PORT1_TX2_REG			0x45
+#define LM49453_P0_PORT1_TX3_REG			0x46
+#define LM49453_P0_PORT1_TX4_REG			0x47
+#define LM49453_P0_PORT1_TX5_REG			0x48
+#define LM49453_P0_PORT1_TX6_REG			0x49
+#define LM49453_P0_PORT1_TX7_REG			0x4A
+#define LM49453_P0_PORT1_TX8_REG			0x4B
+#define LM49453_P0_PORT2_TX1_REG			0x4C
+#define LM49453_P0_PORT2_TX2_REG			0x4D
+#define LM49453_P0_STN_SEL_REG				0x4F
+#define LM49453_P0_DACHPL1_REG				0x50
+#define LM49453_P0_DACHPL2_REG				0x51
+#define LM49453_P0_DACHPR1_REG				0x52
+#define LM49453_P0_DACHPR2_REG				0x53
+#define LM49453_P0_DACLOL1_REG				0x54
+#define LM49453_P0_DACLOL2_REG				0x55
+#define LM49453_P0_DACLOR1_REG				0x56
+#define LM49453_P0_DACLOR2_REG				0x57
+#define LM49453_P0_DACLSL1_REG				0x58
+#define LM49453_P0_DACLSL2_REG				0x59
+#define LM49453_P0_DACLSR1_REG				0x5A
+#define LM49453_P0_DACLSR2_REG				0x5B
+#define LM49453_P0_DACHAL1_REG				0x5C
+#define LM49453_P0_DACHAL2_REG				0x5D
+#define LM49453_P0_DACHAR1_REG				0x5E
+#define LM49453_P0_DACHAR2_REG				0x5F
+
+/* AUDIO PORT 1 (TDM) */
+#define LM49453_P0_AUDIO_PORT1_BASIC_REG		0x60
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN1_REG		0x61
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN2_REG		0x62
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN3_REG		0x63
+#define LM49453_P0_AUDIO_PORT1_SYNC_RATE_REG		0x64
+#define LM49453_P0_AUDIO_PORT1_SYNC_SDO_SETUP_REG	0x65
+#define LM49453_P0_AUDIO_PORT1_DATA_WIDTH_REG		0x66
+#define LM49453_P0_AUDIO_PORT1_RX_MSB_REG		0x67
+#define LM49453_P0_AUDIO_PORT1_TX_MSB_REG		0x68
+#define LM49453_P0_AUDIO_PORT1_TDM_CHANNELS_REG		0x69
+
+/* AUDIO PORT 2 */
+#define LM49453_P0_AUDIO_PORT2_BASIC_REG		0x6A
+#define LM49453_P0_AUDIO_PORT2_CLK_GEN1_REG		0x6B
+#define LM49453_P0_AUDIO_PORT2_CLK_GEN2_REG		0x6C
+#define LM49453_P0_AUDIO_PORT2_SYNC_GEN_REG		0x6D
+#define LM49453_P0_AUDIO_PORT2_DATA_WIDTH_REG		0x6E
+#define LM49453_P0_AUDIO_PORT2_RX_MODE_REG		0x6F
+#define LM49453_P0_AUDIO_PORT2_TX_MODE_REG		0x70
+
+/* SAMPLE RATE */
+#define LM49453_P0_PORT1_SR_LSB_REG			0x79
+#define LM49453_P0_PORT1_SR_MSB_REG			0x7A
+#define LM49453_P0_PORT2_SR_LSB_REG			0x7B
+#define LM49453_P0_PORT2_SR_MSB_REG			0x7C
+
+/* EFFECTS - HPFs */
+#define LM49453_P0_HPF_REG				0x80
+
+/* EFFECTS ADC ALC */
+#define LM49453_P0_ADC_ALC1_REG				0x82
+#define LM49453_P0_ADC_ALC2_REG				0x83
+#define LM49453_P0_ADC_ALC3_REG				0x84
+#define LM49453_P0_ADC_ALC4_REG				0x85
+#define LM49453_P0_ADC_ALC5_REG				0x86
+#define LM49453_P0_ADC_ALC6_REG				0x87
+#define LM49453_P0_ADC_ALC7_REG				0x88
+#define LM49453_P0_ADC_ALC8_REG				0x89
+#define LM49453_P0_DMIC1_LEVELL_REG			0x8A
+#define LM49453_P0_DMIC1_LEVELR_REG			0x8B
+#define LM49453_P0_DMIC2_LEVELL_REG			0x8C
+#define LM49453_P0_DMIC2_LEVELR_REG			0x8D
+#define LM49453_P0_ADC_LEVELL_REG			0x8E
+#define LM49453_P0_ADC_LEVELR_REG			0x8F
+#define LM49453_P0_DAC_HP_LEVELL_REG			0x90
+#define LM49453_P0_DAC_HP_LEVELR_REG			0x91
+#define LM49453_P0_DAC_LO_LEVELL_REG			0x92
+#define LM49453_P0_DAC_LO_LEVELR_REG			0x93
+#define LM49453_P0_DAC_LS_LEVELL_REG			0x94
+#define LM49453_P0_DAC_LS_LEVELR_REG			0x95
+#define LM49453_P0_DAC_HA_LEVELL_REG			0x96
+#define LM49453_P0_DAC_HA_LEVELR_REG			0x97
+#define LM49453_P0_SOFT_MUTE_REG			0x98
+#define LM49453_P0_DMIC_MUTE_CFG_REG			0x99
+#define LM49453_P0_ADC_MUTE_CFG_REG			0x9A
+#define LM49453_P0_DAC_MUTE_CFG_REG			0x9B
+
+/*DIGITAL MIC1 */
+#define LM49453_P0_DIGITAL_MIC1_CONFIG_REG		0xB0
+#define LM49453_P0_DIGITAL_MIC1_DATA_DELAYL_REG		0xB1
+#define LM49453_P0_DIGITAL_MIC1_DATA_DELAYR_REG		0xB2
+
+/*DIGITAL MIC2 */
+#define LM49453_P0_DIGITAL_MIC2_CONFIG_REG		0xB3
+#define LM49453_P0_DIGITAL_MIC2_DATA_DELAYL_REG		0xB4
+#define LM49453_P0_DIGITAL_MIC2_DATA_DELAYR_REG		0xB5
+
+/* ADC DECIMATOR */
+#define LM49453_P0_ADC_DECIMATOR_REG			0xB6
+
+/* DAC CONFIGURE */
+#define LM49453_P0_DAC_CONFIG_REG			0xB7
+
+/* SIDETONE */
+#define LM49453_P0_STN_VOL_ADCL_REG			0xB8
+#define LM49453_P0_STN_VOL_ADCR_REG			0xB9
+#define LM49453_P0_STN_VOL_DMIC1L_REG			0xBA
+#define LM49453_P0_STN_VOL_DMIC1R_REG			0xBB
+#define LM49453_P0_STN_VOL_DMIC2L_REG			0xBC
+#define LM49453_P0_STN_VOL_DMIC2R_REG			0xBD
+
+/* ADC/DAC CLIPPING MONITORS (Read Only/Write to Clear) */
+#define LM49453_P0_ADC_DEC_CLIP_REG			0xC2
+#define LM49453_P0_ADC_HPF_CLIP_REG			0xC3
+#define LM49453_P0_ADC_LVL_CLIP_REG			0xC4
+#define LM49453_P0_DAC_LVL_CLIP_REG			0xC5
+
+/* ADC ALC EFFECT MONITORS (Read Only) */
+#define LM49453_P0_ADC_LVLMONL_REG			0xC8
+#define LM49453_P0_ADC_LVLMONR_REG			0xC9
+#define LM49453_P0_ADC_ALCMONL_REG			0xCA
+#define LM49453_P0_ADC_ALCMONR_REG			0xCB
+#define LM49453_P0_ADC_MUTED_REG			0xCC
+#define LM49453_P0_DAC_MUTED_REG			0xCD
+
+/* HEADSET DETECT */
+#define LM49453_P0_HSD_PPB_LONG_CNT_LIMITL_REG		0xD0
+#define LM49453_P0_HSD_PPB_LONG_CNT_LIMITR_REG		0xD1
+#define LM49453_P0_HSD_PIN3_4_EX_LOOP_CNT_LIMITL_REG	0xD2
+#define LM49453_P0_HSD_PIN3_4_EX_LOOP_CNT_LIMITH_REG	0xD3
+#define LM49453_P0_HSD_TIMEOUT1_REG			0xD4
+#define LM49453_P0_HSD_TIMEOUT2_REG			0xD5
+#define LM49453_P0_HSD_TIMEOUT3_REG			0xD6
+#define LM49453_P0_HSD_PIN3_4_CFG_REG			0xD7
+#define LM49453_P0_HSD_IRQ1_REG				0xD8
+#define LM49453_P0_HSD_IRQ2_REG				0xD9
+#define LM49453_P0_HSD_IRQ3_REG				0xDA
+#define LM49453_P0_HSD_IRQ4_REG				0xDB
+#define LM49453_P0_HSD_IRQ_MASK1_REG			0xDC
+#define LM49453_P0_HSD_IRQ_MASK2_REG			0xDD
+#define LM49453_P0_HSD_IRQ_MASK3_REG			0xDE
+#define LM49453_P0_HSD_R_HPLL_REG			0xE0
+#define LM49453_P0_HSD_R_HPLH_REG			0xE1
+#define LM49453_P0_HSD_R_HPLU_REG			0xE2
+#define LM49453_P0_HSD_R_HPRL_REG			0xE3
+#define LM49453_P0_HSD_R_HPRH_REG			0xE4
+#define LM49453_P0_HSD_R_HPRU_REG			0xE5
+#define LM49453_P0_HSD_VEL_L_FINALL_REG			0xE6
+#define LM49453_P0_HSD_VEL_L_FINALH_REG			0xE7
+#define LM49453_P0_HSD_VEL_L_FINALU_REG			0xE8
+#define LM49453_P0_HSD_RO_FINALL_REG			0xE9
+#define LM49453_P0_HSD_RO_FINALH_REG			0xEA
+#define LM49453_P0_HSD_RO_FINALU_REG			0xEB
+#define LM49453_P0_HSD_VMIC_BIAS_FINALL_REG		0xEC
+#define LM49453_P0_HSD_VMIC_BIAS_FINALH_REG		0xED
+#define LM49453_P0_HSD_VMIC_BIAS_FINALU_REG		0xEE
+#define LM49453_P0_HSD_PIN_CONFIG_REG			0xEF
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS1_REG	0xF1
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS2_REG	0xF2
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS3_REG	0xF3
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATEL_REG	0xF4
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATEH_REG	0xF5
+
+/* I/O PULLDOWN CONFIG */
+#define LM49453_P0_PULL_CONFIG1_REG			0xF8
+#define LM49453_P0_PULL_CONFIG2_REG			0xF9
+#define LM49453_P0_PULL_CONFIG3_REG			0xFA
+
+/* RESET */
+#define LM49453_P0_RESET_REG				0xFE
+
+/* PAGE */
+#define LM49453_PAGE_REG				0xFF
+
+#define LM49453_MAX_REGISTER				(0xFF+1)
+
+/* LM49453_P0_PMC_SETUP_REG (0x00h) */
+#define LM49453_PMC_SETUP_CHIP_EN			(BIT(1)|BIT(0))
+#define LM49453_PMC_SETUP_PLL_EN			BIT(2)
+#define LM49453_PMC_SETUP_PLL_P2_EN			BIT(3)
+#define LM49453_PMC_SETUP_PLL_FLL			BIT(4)
+#define LM49453_PMC_SETUP_MCLK_OVER			BIT(5)
+#define LM49453_PMC_SETUP_RTC_CLK_OVER			BIT(6)
+#define LM49453_PMC_SETUP_CHIP_ACTIVE			BIT(7)
+
+/* Chip Enable bits */
+#define LM49453_CHIP_EN_SHUTDOWN			0x00
+#define LM49453_CHIP_EN					0x01
+#define LM49453_CHIP_EN_HSD_DETECT			0x02
+#define LM49453_CHIP_EN_INVALID_HSD			0x03
+
+/* LM49453_P0_PLL_CLK_SEL1_REG (0x01h) */
+#define LM49453_CLK_SEL1_MCLK_SEL			0x11
+#define LM49453_CLK_SEL1_RTC_SEL			0x11
+#define LM49453_CLK_SEL1_PORT1_SEL			0x10
+#define LM49453_CLK_SEL1_PORT2_SEL			0x11
+
+/* LM49453_P0_PLL_CLK_SEL2_REG (0x02h) */
+#define LM49453_CLK_SEL2_ADC_CLK_SEL			0x38
+
+/* LM49453_P0_FLL_REF_FREQL_REG (0x0F) */
+#define LM49453_FLL_REF_FREQ_VAL			0x8ca0001
+
+/* LM49453_P0_VCO_TARGETLL_REG (0x11) */
+#define LM49453_VCO_TARGET_VAL				0x8ca0001
+
+/* LM49453_P0_ADC_DSP_REG (0x30h) */
+#define LM49453_ADC_DSP_ADC_MUTEL			BIT(0)
+#define LM49453_ADC_DSP_ADC_MUTER			BIT(1)
+#define LM49453_ADC_DSP_DMIC1_MUTEL			BIT(2)
+#define LM49453_ADC_DSP_DMIC1_MUTER			BIT(3)
+#define LM49453_ADC_DSP_DMIC2_MUTEL			BIT(4)
+#define LM49453_ADC_DSP_DMIC2_MUTER			BIT(5)
+#define LM49453_ADC_DSP_MUTE_ALL			0x3F
+
+/* LM49453_P0_DAC_DSP_REG (0x31h) */
+#define LM49453_DAC_DSP_MUTE_ALL			0xFF
+
+/* LM49453_P0_AUDIO_PORT1_BASIC_REG (0x60h) */
+#define LM49453_AUDIO_PORT1_BASIC_FMT_MASK		(BIT(4)|BIT(3))
+#define LM49453_AUDIO_PORT1_BASIC_CLK_MS		BIT(3)
+#define LM49453_AUDIO_PORT1_BASIC_SYNC_MS		BIT(4)
+
+/* LM49453_P0_RESET_REG (0xFEh) */
+#define LM49453_RESET_REG_RST				BIT(0)
+
+/* Page select register bits (0xFF) */
+#define LM49453_PAGE0_SELECT				0x0
+#define LM49453_PAGE1_SELECT				0x1
+
+/* LM49453_P0_HSD_PIN3_4_CFG_REG (Jack Pin config - 0xD7) */
+#define LM49453_JACK_DISABLE				0x00
+#define LM49453_JACK_CONFIG1				0x01
+#define LM49453_JACK_CONFIG2				0x02
+#define LM49453_JACK_CONFIG3				0x03
+#define LM49453_JACK_CONFIG4				0x04
+#define LM49453_JACK_CONFIG5				0x05
+
+/* Page 1 REGISTERS */
+
+/* SIDETONE */
+#define LM49453_P1_SIDETONE_SA0L_REG			0x80
+#define LM49453_P1_SIDETONE_SA0H_REG			0x81
+#define LM49453_P1_SIDETONE_SAB0U_REG			0x82
+#define LM49453_P1_SIDETONE_SB0L_REG			0x83
+#define LM49453_P1_SIDETONE_SB0H_REG			0x84
+#define LM49453_P1_SIDETONE_SH0L_REG			0x85
+#define LM49453_P1_SIDETONE_SH0H_REG			0x86
+#define LM49453_P1_SIDETONE_SH0U_REG			0x87
+#define LM49453_P1_SIDETONE_SA1L_REG			0x88
+#define LM49453_P1_SIDETONE_SA1H_REG			0x89
+#define LM49453_P1_SIDETONE_SAB1U_REG			0x8A
+#define LM49453_P1_SIDETONE_SB1L_REG			0x8B
+#define LM49453_P1_SIDETONE_SB1H_REG			0x8C
+#define LM49453_P1_SIDETONE_SH1L_REG			0x8D
+#define LM49453_P1_SIDETONE_SH1H_REG			0x8E
+#define LM49453_P1_SIDETONE_SH1U_REG			0x8F
+#define LM49453_P1_SIDETONE_SA2L_REG			0x90
+#define LM49453_P1_SIDETONE_SA2H_REG			0x91
+#define LM49453_P1_SIDETONE_SAB2U_REG			0x92
+#define LM49453_P1_SIDETONE_SB2L_REG			0x93
+#define LM49453_P1_SIDETONE_SB2H_REG			0x94
+#define LM49453_P1_SIDETONE_SH2L_REG			0x95
+#define LM49453_P1_SIDETONE_SH2H_REG			0x96
+#define LM49453_P1_SIDETONE_SH2U_REG			0x97
+#define LM49453_P1_SIDETONE_SA3L_REG			0x98
+#define LM49453_P1_SIDETONE_SA3H_REG			0x99
+#define LM49453_P1_SIDETONE_SAB3U_REG			0x9A
+#define LM49453_P1_SIDETONE_SB3L_REG			0x9B
+#define LM49453_P1_SIDETONE_SB3H_REG			0x9C
+#define LM49453_P1_SIDETONE_SH3L_REG			0x9D
+#define LM49453_P1_SIDETONE_SH3H_REG			0x9E
+#define LM49453_P1_SIDETONE_SH3U_REG			0x9F
+#define LM49453_P1_SIDETONE_SA4L_REG			0xA0
+#define LM49453_P1_SIDETONE_SA4H_REG			0xA1
+#define LM49453_P1_SIDETONE_SAB4U_REG			0xA2
+#define LM49453_P1_SIDETONE_SB4L_REG			0xA3
+#define LM49453_P1_SIDETONE_SB4H_REG			0xA4
+#define LM49453_P1_SIDETONE_SH4L_REG			0xA5
+#define LM49453_P1_SIDETONE_SH4H_REG			0xA6
+#define LM49453_P1_SIDETONE_SH4U_REG			0xA7
+#define LM49453_P1_SIDETONE_SA5L_REG			0xA8
+#define LM49453_P1_SIDETONE_SA5H_REG			0xA9
+#define LM49453_P1_SIDETONE_SAB5U_REG			0xAA
+#define LM49453_P1_SIDETONE_SB5L_REG			0xAB
+#define LM49453_P1_SIDETONE_SB5H_REG			0xAC
+#define LM49453_P1_SIDETONE_SH5L_REG			0xAD
+#define LM49453_P1_SIDETONE_SH5H_REG			0xAE
+#define LM49453_P1_SIDETONE_SH5U_REG			0xAF
+
+/* CHARGE PUMP CONFIG */
+#define LM49453_P1_CP_CONFIG1_REG			0xB0
+#define LM49453_P1_CP_CONFIG2_REG			0xB1
+#define LM49453_P1_CP_CONFIG3_REG			0xB2
+#define LM49453_P1_CP_CONFIG4_REG			0xB3
+#define LM49453_P1_CP_LA_VTH1L_REG			0xB4
+#define LM49453_P1_CP_LA_VTH1M_REG			0xB5
+#define LM49453_P1_CP_LA_VTH2L_REG			0xB6
+#define LM49453_P1_CP_LA_VTH2M_REG			0xB7
+#define LM49453_P1_CP_LA_VTH3L_REG			0xB8
+#define LM49453_P1_CP_LA_VTH3H_REG			0xB9
+#define LM49453_P1_CP_CLK_DIV_REG			0xBA
+
+/* DAC */
+#define LM49453_P1_DAC_CHOP_REG				0xC0
+
+#define	LM49453_CLK_SRC_MCLK				1
+#endif
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 0bb511a..35179e2 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <asm/div64.h>
 #include <sound/max98095.h>
+#include <sound/jack.h>
 #include "max98095.h"
 
 enum max98095_type {
@@ -51,6 +52,8 @@
 	u8 lin_state;
 	unsigned int mic1pre;
 	unsigned int mic2pre;
+	struct snd_soc_jack *headphone_jack;
+	struct snd_soc_jack *mic_jack;
 };
 
 static const u8 max98095_reg_def[M98095_REG_CNT] = {
@@ -2173,9 +2176,125 @@
 		max98095_handle_bq_pdata(codec);
 }
 
+static irqreturn_t max98095_report_jack(int irq, void *data)
+{
+	struct snd_soc_codec *codec = data;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	unsigned int value;
+	int hp_report = 0;
+	int mic_report = 0;
+
+	/* Read the Jack Status Register */
+	value = snd_soc_read(codec, M98095_007_JACK_AUTO_STS);
+
+	/* If ddone is not set, then detection isn't finished yet */
+	if ((value & M98095_DDONE) == 0)
+		return IRQ_NONE;
+
+	/* if hp, check its bit, and if set, clear it */
+	if ((value & M98095_HP_IN || value & M98095_LO_IN) &&
+		max98095->headphone_jack)
+		hp_report |= SND_JACK_HEADPHONE;
+
+	/* if mic, check its bit, and if set, clear it */
+	if ((value & M98095_MIC_IN) && max98095->mic_jack)
+		mic_report |= SND_JACK_MICROPHONE;
+
+	if (max98095->headphone_jack == max98095->mic_jack) {
+		snd_soc_jack_report(max98095->headphone_jack,
+					hp_report | mic_report,
+					SND_JACK_HEADSET);
+	} else {
+		if (max98095->headphone_jack)
+			snd_soc_jack_report(max98095->headphone_jack,
+					hp_report, SND_JACK_HEADPHONE);
+		if (max98095->mic_jack)
+			snd_soc_jack_report(max98095->mic_jack,
+					mic_report, SND_JACK_MICROPHONE);
+	}
+
+	return IRQ_HANDLED;
+}
+
+int max98095_jack_detect_enable(struct snd_soc_codec *codec)
+{
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+	int detect_enable = M98095_JDEN;
+	unsigned int slew = M98095_DEFAULT_SLEW_DELAY;
+
+	if (max98095->pdata->jack_detect_pin5en)
+		detect_enable |= M98095_PIN5EN;
+
+	if (max98095->pdata->jack_detect_delay)
+		slew = max98095->pdata->jack_detect_delay;
+
+	ret = snd_soc_write(codec, M98095_08E_JACK_DC_SLEW, slew);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+		return ret;
+	}
+
+	/* configure auto detection to be enabled */
+	ret = snd_soc_write(codec, M98095_089_JACK_DET_AUTO, detect_enable);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+int max98095_jack_detect_disable(struct snd_soc_codec *codec)
+{
+	int ret = 0;
+
+	/* configure auto detection to be disabled */
+	ret = snd_soc_write(codec, M98095_089_JACK_DET_AUTO, 0x0);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+int max98095_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
+{
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *client = to_i2c_client(codec->dev);
+	int ret = 0;
+
+	max98095->headphone_jack = hp_jack;
+	max98095->mic_jack = mic_jack;
+
+	/* only progress if we have at least 1 jack pointer */
+	if (!hp_jack && !mic_jack)
+		return -EINVAL;
+
+	max98095_jack_detect_enable(codec);
+
+	/* enable interrupts for headphone jack detection */
+	ret = snd_soc_update_bits(codec, M98095_013_JACK_INT_EN,
+		M98095_IDDONE, M98095_IDDONE);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to cfg jack irqs %d\n", ret);
+		return ret;
+	}
+
+	max98095_report_jack(client->irq, codec);
+	return 0;
+}
+
 #ifdef CONFIG_PM
 static int max98095_suspend(struct snd_soc_codec *codec)
 {
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+	if (max98095->headphone_jack || max98095->mic_jack)
+		max98095_jack_detect_disable(codec);
+
 	max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
 	return 0;
@@ -2183,8 +2302,16 @@
 
 static int max98095_resume(struct snd_soc_codec *codec)
 {
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *client = to_i2c_client(codec->dev);
+
 	max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
+	if (max98095->headphone_jack || max98095->mic_jack) {
+		max98095_jack_detect_enable(codec);
+		max98095_report_jack(client->irq, codec);
+	}
+
 	return 0;
 }
 #else
@@ -2227,6 +2354,7 @@
 {
 	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 	struct max98095_cdata *cdata;
+	struct i2c_client *client;
 	int ret = 0;
 
 	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
@@ -2238,6 +2366,8 @@
 	/* reset the codec, the DSP core, and disable all interrupts */
 	max98095_reset(codec);
 
+	client = to_i2c_client(codec->dev);
+
 	/* initialize private data */
 
 	max98095->sysclk = (unsigned)-1;
@@ -2266,11 +2396,23 @@
 	max98095->mic1pre = 0;
 	max98095->mic2pre = 0;
 
+	if (client->irq) {
+		/* register an audio interrupt */
+		ret = request_threaded_irq(client->irq, NULL,
+			max98095_report_jack,
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+			"max98095", codec);
+		if (ret) {
+			dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
+			goto err_access;
+		}
+	}
+
 	ret = snd_soc_read(codec, M98095_0FF_REV_ID);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failure reading hardware revision: %d\n",
 			ret);
-		goto err_access;
+		goto err_irq;
 	}
 	dev_info(codec->dev, "Hardware revision: %c\n", ret - 0x40 + 'A');
 
@@ -2306,14 +2448,28 @@
 
 	max98095_add_widgets(codec);
 
+	return 0;
+
+err_irq:
+	if (client->irq)
+		free_irq(client->irq, codec);
 err_access:
 	return ret;
 }
 
 static int max98095_remove(struct snd_soc_codec *codec)
 {
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *client = to_i2c_client(codec->dev);
+
 	max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
+	if (max98095->headphone_jack || max98095->mic_jack)
+		max98095_jack_detect_disable(codec);
+
+	if (client->irq)
+		free_irq(client->irq, codec);
+
 	return 0;
 }
 
diff --git a/sound/soc/codecs/max98095.h b/sound/soc/codecs/max98095.h
index 891584a..2ebbe4e 100644
--- a/sound/soc/codecs/max98095.h
+++ b/sound/soc/codecs/max98095.h
@@ -175,11 +175,23 @@
 
 /* MAX98095 Registers Bit Fields */
 
+/* M98095_007_JACK_AUTO_STS */
+	#define M98095_MIC_IN			(1<<3)
+	#define M98095_LO_IN			(1<<5)
+	#define M98095_HP_IN			(1<<6)
+	#define M98095_DDONE			(1<<7)
+
 /* M98095_00F_HOST_CFG */
 	#define M98095_SEG                      (1<<0)
 	#define M98095_XTEN                     (1<<1)
 	#define M98095_MDLLEN                   (1<<2)
 
+/* M98095_013_JACK_INT_EN */
+	#define M98095_IMIC_IN			(1<<3)
+	#define M98095_ILO_IN			(1<<5)
+	#define M98095_IHP_IN			(1<<6)
+	#define M98095_IDDONE			(1<<7)
+
 /* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */
 	#define M98095_CLKMODE_MASK             0xFF
 
@@ -255,6 +267,10 @@
 	#define M98095_EQ2EN                    (1<<1)
 	#define M98095_EQ1EN                    (1<<0)
 
+/* M98095_089_JACK_DET_AUTO */
+	#define M98095_PIN5EN			(1<<2)
+	#define M98095_JDEN			(1<<7)
+
 /* M98095_090_PWR_EN_IN */
 	#define M98095_INEN                     (1<<7)
 	#define M98095_MB2EN                    (1<<3)
@@ -296,4 +312,10 @@
 #define M98095_174_DAI1_BQ_BASE             0x74
 #define M98095_17E_DAI2_BQ_BASE             0x7E
 
+/* Default Delay used in Slew Rate Calculation for Jack detection */
+#define M98095_DEFAULT_SLEW_DELAY		0x18
+
+extern int max98095_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
+
 #endif
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
new file mode 100644
index 0000000..22cb5bf
--- /dev/null
+++ b/sound/soc/codecs/ml26124.c
@@ -0,0 +1,681 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "ml26124.h"
+
+#define DVOL_CTL_DVMUTE_ON		BIT(4)	/* Digital volume MUTE On */
+#define DVOL_CTL_DVMUTE_OFF		0	/* Digital volume MUTE Off */
+#define ML26124_SAI_NO_DELAY	BIT(1)
+#define ML26124_SAI_FRAME_SYNC	(BIT(5) | BIT(0)) /* For mono (Telecodec) */
+#define ML26134_CACHESIZE 212
+#define ML26124_VMID	BIT(1)
+#define ML26124_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 |\
+		       SNDRV_PCM_RATE_48000)
+#define ML26124_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+#define ML26124_NUM_REGISTER ML26134_CACHESIZE
+
+struct ml26124_priv {
+	u32 mclk;
+	u32 rate;
+	struct regmap *regmap;
+	int clk_in;
+	struct snd_pcm_substream *substream;
+};
+
+struct clk_coeff {
+	u32 mclk;
+	u32 rate;
+	u8 pllnl;
+	u8 pllnh;
+	u8 pllml;
+	u8 pllmh;
+	u8 plldiv;
+};
+
+/* ML26124 configuration */
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7150, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(alclvl, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mingain, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(maxgain, -675, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_vol, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0);
+
+static const char * const ml26124_companding[] = {"16bit PCM", "u-law",
+						  "A-law"};
+
+static const struct soc_enum ml26124_adc_companding_enum
+	= SOC_ENUM_SINGLE(ML26124_SAI_TRANS_CTL, 6, 3, ml26124_companding);
+
+static const struct soc_enum ml26124_dac_companding_enum
+	= SOC_ENUM_SINGLE(ML26124_SAI_RCV_CTL, 6, 3, ml26124_companding);
+
+static const struct snd_kcontrol_new ml26124_snd_controls[] = {
+	SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("Playback Digital Volume", ML26124_PLBAK_DIG_VOL, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("Digital Boost Volume", ML26124_DIGI_BOOST_VOL, 0,
+			0x3f, 0, boost_vol),
+	SOC_SINGLE_TLV("EQ Band0 Volume", ML26124_EQ_GAIN_BRAND0, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("EQ Band1 Volume", ML26124_EQ_GAIN_BRAND1, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("EQ Band2 Volume", ML26124_EQ_GAIN_BRAND2, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("EQ Band3 Volume", ML26124_EQ_GAIN_BRAND3, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("EQ Band4 Volume", ML26124_EQ_GAIN_BRAND4, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("ALC Target Level", ML26124_ALC_TARGET_LEV, 0,
+			0xf, 1, alclvl),
+	SOC_SINGLE_TLV("ALC Min Input Volume", ML26124_ALC_MAXMIN_GAIN, 0,
+			7, 0, mingain),
+	SOC_SINGLE_TLV("ALC Max Input Volume", ML26124_ALC_MAXMIN_GAIN, 4,
+			7, 1, maxgain),
+	SOC_SINGLE_TLV("Playback Limiter Min Input Volume",
+			ML26124_PL_MAXMIN_GAIN, 0, 7, 0, mingain),
+	SOC_SINGLE_TLV("Playback Limiter Max Input Volume",
+			ML26124_PL_MAXMIN_GAIN, 4, 7, 1, maxgain),
+	SOC_SINGLE_TLV("Playback Boost Volume", ML26124_PLYBAK_BOST_VOL, 0,
+			0x3f, 0, boost_vol),
+	SOC_SINGLE("DC High Pass Filter Switch", ML26124_FILTER_EN, 0, 1, 0),
+	SOC_SINGLE("Noise High Pass Filter Switch", ML26124_FILTER_EN, 1, 1, 0),
+	SOC_SINGLE("ZC Switch", ML26124_PW_ZCCMP_PW_MNG, 1,
+		    1, 0),
+	SOC_SINGLE("EQ Band0 Switch", ML26124_FILTER_EN, 2, 1, 0),
+	SOC_SINGLE("EQ Band1 Switch", ML26124_FILTER_EN, 3, 1, 0),
+	SOC_SINGLE("EQ Band2 Switch", ML26124_FILTER_EN, 4, 1, 0),
+	SOC_SINGLE("EQ Band3 Switch", ML26124_FILTER_EN, 5, 1, 0),
+	SOC_SINGLE("EQ Band4 Switch", ML26124_FILTER_EN, 6, 1, 0),
+	SOC_SINGLE("Play Limiter", ML26124_DVOL_CTL, 0, 1, 0),
+	SOC_SINGLE("Capture Limiter", ML26124_DVOL_CTL, 1, 1, 0),
+	SOC_SINGLE("Digital Volume Fade Switch", ML26124_DVOL_CTL, 3, 1, 0),
+	SOC_SINGLE("Digital Switch", ML26124_DVOL_CTL, 4, 1, 0),
+	SOC_ENUM("DAC Companding", ml26124_dac_companding_enum),
+	SOC_ENUM("ADC Companding", ml26124_adc_companding_enum),
+};
+
+static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Switch", ML26124_SPK_AMP_OUT, 1, 1, 0),
+	SOC_DAPM_SINGLE("Line in loopback Switch", ML26124_SPK_AMP_OUT, 3, 1,
+			 0),
+	SOC_DAPM_SINGLE("PGA Switch", ML26124_SPK_AMP_OUT, 5, 1, 0),
+};
+
+/* Input mux */
+static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in",
+				"Digital MIC in", "Analog MIC Differential in"};
+
+static const struct soc_enum ml26124_insel_enum =
+	SOC_ENUM_SINGLE(ML26124_MIC_IF_CTL, 0, 3, ml26124_input_select);
+
+static const struct snd_kcontrol_new ml26124_input_mux_controls =
+	SOC_DAPM_ENUM("Input Select", ml26124_insel_enum);
+
+static const struct snd_kcontrol_new ml26124_line_control =
+	SOC_DAPM_SINGLE("Switch", ML26124_PW_LOUT_PW_MNG, 1, 1, 0);
+
+static const struct snd_soc_dapm_widget ml26124_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("MCLKEN", ML26124_CLK_EN, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLLEN", ML26124_CLK_EN, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLLOE", ML26124_CLK_EN, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS", ML26124_PW_REF_PW_MNG, 2, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
+			   &ml26124_output_mixer_controls[0],
+			   ARRAY_SIZE(ml26124_output_mixer_controls)),
+	SND_SOC_DAPM_DAC("DAC", "Playback", ML26124_PW_DAC_PW_MNG, 1, 0),
+	SND_SOC_DAPM_ADC("ADC", "Capture", ML26124_PW_IN_PW_MNG, 1, 0),
+	SND_SOC_DAPM_PGA("PGA", ML26124_PW_IN_PW_MNG, 3, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+			  &ml26124_input_mux_controls),
+	SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0,
+			     &ml26124_line_control),
+	SND_SOC_DAPM_INPUT("MDIN"),
+	SND_SOC_DAPM_INPUT("MIN"),
+	SND_SOC_DAPM_INPUT("LIN"),
+	SND_SOC_DAPM_OUTPUT("SPOUT"),
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+};
+
+static const struct snd_soc_dapm_route ml26124_intercon[] = {
+	/* Supply */
+	{"DAC", NULL, "MCLKEN"},
+	{"ADC", NULL, "MCLKEN"},
+	{"DAC", NULL, "PLLEN"},
+	{"ADC", NULL, "PLLEN"},
+	{"DAC", NULL, "PLLOE"},
+	{"ADC", NULL, "PLLOE"},
+
+	/* output mixer */
+	{"Output Mixer", "DAC Switch", "DAC"},
+	{"Output Mixer", "Line in loopback Switch", "LIN"},
+
+	/* outputs */
+	{"LOUT", NULL, "Output Mixer"},
+	{"SPOUT", NULL, "Output Mixer"},
+	{"Line Out Enable", NULL, "LOUT"},
+
+	/* input */
+	{"ADC", NULL, "Input Mux"},
+	{"Input Mux", "Analog MIC SingleEnded in", "PGA"},
+	{"Input Mux", "Analog MIC Differential in", "PGA"},
+	{"PGA", NULL, "MIN"},
+};
+
+/* PLLOutputFreq(Hz) = InputMclkFreq(Hz) * PLLM / (PLLN * PLLDIV) */
+static const struct clk_coeff coeff_div[] = {
+	{12288000, 16000, 0xc, 0x0, 0x20, 0x0, 0x4},
+	{12288000, 32000, 0xc, 0x0, 0x20, 0x0, 0x4},
+	{12288000, 48000, 0xc, 0x0, 0x30, 0x0, 0x4},
+};
+
+static struct reg_default ml26124_reg[] = {
+	/* CLOCK control Register */
+	{0x00, 0x00 },	/* Sampling Rate */
+	{0x02, 0x00},	/* PLL NL */
+	{0x04, 0x00},	/* PLLNH */
+	{0x06, 0x00},	/* PLLML */
+	{0x08, 0x00},	/* MLLMH */
+	{0x0a, 0x00},	/* PLLDIV */
+	{0x0c, 0x00},	/* Clock Enable */
+	{0x0e, 0x00},	/* CLK Input/Output Control */
+
+	/* System Control Register */
+	{0x10, 0x00},	/* Software RESET */
+	{0x12, 0x00},	/* Record/Playback Run */
+	{0x14, 0x00},	/* Mic Input/Output control */
+
+	/* Power Management Register */
+	{0x20, 0x00},	/* Reference Power Management */
+	{0x22, 0x00},	/* Input Power Management */
+	{0x24, 0x00},	/* DAC Power Management */
+	{0x26, 0x00},	/* SP-AMP Power Management */
+	{0x28, 0x00},	/* LINEOUT Power Management */
+	{0x2a, 0x00},	/* VIDEO Power Management */
+	{0x2e, 0x00},	/* AC-CMP Power Management */
+
+	/* Analog reference Control Register */
+	{0x30, 0x04},	/* MICBIAS Voltage Control */
+
+	/* Input/Output Amplifier Control Register */
+	{0x32, 0x10},	/* MIC Input Volume */
+	{0x38, 0x00},	/* Mic Boost Volume */
+	{0x3a, 0x33},	/* Speaker AMP Volume */
+	{0x48, 0x00},	/* AMP Volume Control Function Enable */
+	{0x4a, 0x00},	/* Amplifier Volume Fader Control */
+
+	/* Analog Path Control Register */
+	{0x54, 0x00},	/* Speaker AMP Output Control */
+	{0x5a, 0x00},	/* Mic IF Control */
+	{0xe8, 0x01},	/* Mic Select Control */
+
+	/* Audio Interface Control Register */
+	{0x60, 0x00},	/* SAI-Trans Control */
+	{0x62, 0x00},	/* SAI-Receive Control */
+	{0x64, 0x00},	/* SAI Mode select */
+
+	/* DSP Control Register */
+	{0x66, 0x01},	/* Filter Func Enable */
+	{0x68, 0x00},	/* Volume Control Func Enable */
+	{0x6A, 0x00},	/* Mixer & Volume Control*/
+	{0x6C, 0xff},	/* Record Digital Volume */
+	{0x70, 0xff},	/* Playback Digital Volume */
+	{0x72, 0x10},	/* Digital Boost Volume */
+	{0x74, 0xe7},	/* EQ gain Band0 */
+	{0x76, 0xe7},	/* EQ gain Band1 */
+	{0x78, 0xe7},	/* EQ gain Band2 */
+	{0x7A, 0xe7},	/* EQ gain Band3 */
+	{0x7C, 0xe7},	/* EQ gain Band4 */
+	{0x7E, 0x00},	/* HPF2 CutOff*/
+	{0x80, 0x00},	/* EQ Band0 Coef0L */
+	{0x82, 0x00},	/* EQ Band0 Coef0H */
+	{0x84, 0x00},	/* EQ Band0 Coef0L */
+	{0x86, 0x00},	/* EQ Band0 Coef0H */
+	{0x88, 0x00},	/* EQ Band1 Coef0L */
+	{0x8A, 0x00},	/* EQ Band1 Coef0H */
+	{0x8C, 0x00},	/* EQ Band1 Coef0L */
+	{0x8E, 0x00},	/* EQ Band1 Coef0H */
+	{0x90, 0x00},	/* EQ Band2 Coef0L */
+	{0x92, 0x00},	/* EQ Band2 Coef0H */
+	{0x94, 0x00},	/* EQ Band2 Coef0L */
+	{0x96, 0x00},	/* EQ Band2 Coef0H */
+	{0x98, 0x00},	/* EQ Band3 Coef0L */
+	{0x9A, 0x00},	/* EQ Band3 Coef0H */
+	{0x9C, 0x00},	/* EQ Band3 Coef0L */
+	{0x9E, 0x00},	/* EQ Band3 Coef0H */
+	{0xA0, 0x00},	/* EQ Band4 Coef0L */
+	{0xA2, 0x00},	/* EQ Band4 Coef0H */
+	{0xA4, 0x00},	/* EQ Band4 Coef0L */
+	{0xA6, 0x00},	/* EQ Band4 Coef0H */
+
+	/* ALC Control Register */
+	{0xb0, 0x00},	/* ALC Mode */
+	{0xb2, 0x02},	/* ALC Attack Time */
+	{0xb4, 0x03},	/* ALC Decay Time */
+	{0xb6, 0x00},	/* ALC Hold Time */
+	{0xb8, 0x0b},	/* ALC Target Level */
+	{0xba, 0x70},	/* ALC Max/Min Gain */
+	{0xbc, 0x00},	/* Noise Gate Threshold */
+	{0xbe, 0x00},	/* ALC ZeroCross TimeOut */
+
+	/* Playback Limiter Control Register */
+	{0xc0, 0x04},	/* PL Attack Time */
+	{0xc2, 0x05},	/* PL Decay Time */
+	{0xc4, 0x0d},	/* PL Target Level */
+	{0xc6, 0x70},	/* PL Max/Min Gain */
+	{0xc8, 0x10},	/* Playback Boost Volume */
+	{0xca, 0x00},	/* PL ZeroCross TimeOut */
+
+	/* Video Amplifier Control Register */
+	{0xd0, 0x01},	/* VIDEO AMP Gain Control */
+	{0xd2, 0x01},	/* VIDEO AMP Setup 1 */
+	{0xd4, 0x01},	/* VIDEO AMP Control2 */
+};
+
+/* Get sampling rate value of sampling rate setting register (0x0) */
+static inline int get_srate(int rate)
+{
+	int srate;
+
+	switch (rate) {
+	case 16000:
+		srate = 3;
+		break;
+	case 32000:
+		srate = 6;
+		break;
+	case 48000:
+		srate = 8;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return srate;
+}
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int ml26124_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *hw_params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+	int i = get_coeff(priv->mclk, params_rate(hw_params));
+
+	priv->substream = substream;
+	priv->rate = params_rate(hw_params);
+
+	if (priv->clk_in) {
+		switch (priv->mclk / params_rate(hw_params)) {
+		case 256:
+			snd_soc_update_bits(codec, ML26124_CLK_CTL,
+					    BIT(0) | BIT(1), 1);
+			break;
+		case 512:
+			snd_soc_update_bits(codec, ML26124_CLK_CTL,
+					    BIT(0) | BIT(1), 2);
+			break;
+		case 1024:
+			snd_soc_update_bits(codec, ML26124_CLK_CTL,
+					    BIT(0) | BIT(1), 3);
+			break;
+		default:
+			dev_err(codec->dev, "Unsupported MCLKI\n");
+			break;
+		}
+	} else {
+		snd_soc_update_bits(codec, ML26124_CLK_CTL,
+				    BIT(0) | BIT(1), 0);
+	}
+
+	switch (params_rate(hw_params)) {
+	case 16000:
+		snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
+				    get_srate(params_rate(hw_params)));
+		snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
+				    coeff_div[i].pllnl);
+		snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
+				    coeff_div[i].pllnh);
+		snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
+				    coeff_div[i].pllml);
+		snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
+				    coeff_div[i].pllmh);
+		snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
+				    coeff_div[i].plldiv);
+		break;
+	case 32000:
+		snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
+				    get_srate(params_rate(hw_params)));
+		snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
+				    coeff_div[i].pllnl);
+		snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
+				    coeff_div[i].pllnh);
+		snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
+				    coeff_div[i].pllml);
+		snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
+				    coeff_div[i].pllmh);
+		snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
+				    coeff_div[i].plldiv);
+		break;
+	case 48000:
+		snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
+				    get_srate(params_rate(hw_params)));
+		snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
+				    coeff_div[i].pllnl);
+		snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
+				    coeff_div[i].pllnh);
+		snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
+				    coeff_div[i].pllml);
+		snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
+				    coeff_div[i].pllmh);
+		snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
+				    coeff_div[i].plldiv);
+		break;
+	default:
+		pr_err("%s:this rate is no support for ml26124\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ml26124_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (priv->substream->stream) {
+	case SNDRV_PCM_STREAM_CAPTURE:
+		snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, BIT(0), 1);
+		break;
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, BIT(1), 2);
+		break;
+	}
+
+	if (mute)
+		snd_soc_update_bits(codec, ML26124_DVOL_CTL, BIT(4),
+				    DVOL_CTL_DVMUTE_ON);
+	else
+		snd_soc_update_bits(codec, ML26124_DVOL_CTL, BIT(4),
+				    DVOL_CTL_DVMUTE_OFF);
+
+	return 0;
+}
+
+static int ml26124_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	unsigned char mode;
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		mode = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		mode = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_update_bits(codec, ML26124_SAI_MODE_SEL, BIT(0), mode);
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ml26124_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 ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (clk_id) {
+	case ML26124_USE_PLLOUT:
+		priv->clk_in = ML26124_USE_PLLOUT;
+		break;
+	case ML26124_USE_MCLKI:
+		priv->clk_in = ML26124_USE_MCLKI;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	priv->mclk = freq;
+
+	return 0;
+}
+
+static int ml26124_set_bias_level(struct snd_soc_codec *codec,
+		enum snd_soc_bias_level level)
+{
+	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_update_bits(codec, ML26124_PW_SPAMP_PW_MNG,
+				    ML26124_R26_MASK, ML26124_BLT_PREAMP_ON);
+		msleep(100);
+		snd_soc_update_bits(codec, ML26124_PW_SPAMP_PW_MNG,
+				    ML26124_R26_MASK,
+				    ML26124_MICBEN_ON | ML26124_BLT_ALL_ON);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* VMID ON */
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
+					    ML26124_VMID, ML26124_VMID);
+			msleep(500);
+			regcache_sync(priv->regmap);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* VMID OFF */
+		snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
+				    ML26124_VMID, 0);
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ml26124_dai_ops = {
+	.hw_params	= ml26124_hw_params,
+	.digital_mute	= ml26124_mute,
+	.set_fmt	= ml26124_set_dai_fmt,
+	.set_sysclk	= ml26124_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver ml26124_dai = {
+	.name = "ml26124-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ML26124_RATES,
+		.formats = ML26124_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ML26124_RATES,
+		.formats = ML26124_FORMATS,},
+	.ops = &ml26124_dai_ops,
+	.symmetric_rates = 1,
+};
+
+#ifdef CONFIG_PM
+static int ml26124_suspend(struct snd_soc_codec *codec)
+{
+	ml26124_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int ml26124_resume(struct snd_soc_codec *codec)
+{
+	ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+#else
+#define ml26124_suspend NULL
+#define ml26124_resume NULL
+#endif
+
+static int ml26124_probe(struct snd_soc_codec *codec)
+{
+	int ret;
+	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+	codec->control_data = priv->regmap;
+
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	/* Software Reset */
+	snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1);
+	snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0);
+
+	ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
+	.probe =	ml26124_probe,
+	.suspend =	ml26124_suspend,
+	.resume =	ml26124_resume,
+	.set_bias_level = ml26124_set_bias_level,
+	.dapm_widgets = ml26124_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets),
+	.dapm_routes = ml26124_intercon,
+	.num_dapm_routes = ARRAY_SIZE(ml26124_intercon),
+	.controls = ml26124_snd_controls,
+	.num_controls = ARRAY_SIZE(ml26124_snd_controls),
+};
+
+static const struct regmap_config ml26124_i2c_regmap = {
+	.val_bits = 8,
+	.reg_bits = 8,
+	.max_register = ML26124_NUM_REGISTER,
+	.reg_defaults = ml26124_reg,
+	.num_reg_defaults = ARRAY_SIZE(ml26124_reg),
+	.cache_type = REGCACHE_RBTREE,
+	.write_flag_mask = 0x01,
+};
+
+static __devinit int ml26124_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct ml26124_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, priv);
+
+	priv->regmap = regmap_init_i2c(i2c, &ml26124_i2c_regmap);
+	if (IS_ERR(priv->regmap)) {
+		ret = PTR_ERR(priv->regmap);
+		dev_err(&i2c->dev, "regmap_init_i2c() failed: %d\n", ret);
+		return ret;
+	}
+
+	return snd_soc_register_codec(&i2c->dev,
+			&soc_codec_dev_ml26124, &ml26124_dai, 1);
+}
+
+static __devexit int ml26124_i2c_remove(struct i2c_client *client)
+{
+	struct ml26124_priv *priv = i2c_get_clientdata(client);
+
+	snd_soc_unregister_codec(&client->dev);
+	regmap_exit(priv->regmap);
+	return 0;
+}
+
+static const struct i2c_device_id ml26124_i2c_id[] = {
+	{ "ml26124", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ml26124_i2c_id);
+
+static struct i2c_driver ml26124_i2c_driver = {
+	.driver = {
+		.name = "ml26124",
+		.owner = THIS_MODULE,
+	},
+	.probe = ml26124_i2c_probe,
+	.remove = __devexit_p(ml26124_i2c_remove),
+	.id_table = ml26124_i2c_id,
+};
+
+module_i2c_driver(ml26124_i2c_driver);
+
+MODULE_AUTHOR("Tomoya MORINAGA <tomoya.rohm@gmail.com>");
+MODULE_DESCRIPTION("LAPIS Semiconductor ML26124 ALSA SoC codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ml26124.h b/sound/soc/codecs/ml26124.h
new file mode 100644
index 0000000..5ea0cbb
--- /dev/null
+++ b/sound/soc/codecs/ml26124.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef ML26124_H
+#define ML26124_H
+
+/* Clock Control Register */
+#define ML26124_SMPLING_RATE		0x00
+#define ML26124_PLLNL			0x02
+#define ML26124_PLLNH			0x04
+#define ML26124_PLLML			0x06
+#define ML26124_PLLMH			0x08
+#define ML26124_PLLDIV			0x0a
+#define ML26124_CLK_EN			0x0c
+#define ML26124_CLK_CTL			0x0e
+
+/* System Control Register */
+#define ML26124_SW_RST			0x10
+#define ML26124_REC_PLYBAK_RUN		0x12
+#define ML26124_MIC_TIM			0x14
+
+/* Power Mnagement Register */
+#define ML26124_PW_REF_PW_MNG		0x20
+#define ML26124_PW_IN_PW_MNG		0x22
+#define ML26124_PW_DAC_PW_MNG		0x24
+#define ML26124_PW_SPAMP_PW_MNG		0x26
+#define ML26124_PW_LOUT_PW_MNG		0x28
+#define ML26124_PW_VOUT_PW_MNG		0x2a
+#define ML26124_PW_ZCCMP_PW_MNG		0x2e
+
+/* Analog Reference Control Register */
+#define ML26124_PW_MICBIAS_VOL		0x30
+
+/* Input/Output Amplifier Control Register */
+#define ML26124_PW_MIC_IN_VOL		0x32
+#define ML26124_PW_MIC_BOST_VOL		0x38
+#define ML26124_PW_SPK_AMP_VOL		0x3a
+#define ML26124_PW_AMP_VOL_FUNC		0x48
+#define ML26124_PW_AMP_VOL_FADE		0x4a
+
+/* Analog Path Control Register */
+#define ML26124_SPK_AMP_OUT		0x54
+#define ML26124_MIC_IF_CTL		0x5a
+#define ML26124_MIC_SELECT		0xe8
+
+/* Audio Interface Control Register */
+#define ML26124_SAI_TRANS_CTL		0x60
+#define ML26124_SAI_RCV_CTL		0x62
+#define ML26124_SAI_MODE_SEL		0x64
+
+/* DSP Control Register */
+#define ML26124_FILTER_EN		0x66
+#define ML26124_DVOL_CTL		0x68
+#define ML26124_MIXER_VOL_CTL		0x6a
+#define ML26124_RECORD_DIG_VOL		0x6c
+#define ML26124_PLBAK_DIG_VOL		0x70
+#define ML26124_DIGI_BOOST_VOL		0x72
+#define ML26124_EQ_GAIN_BRAND0		0x74
+#define ML26124_EQ_GAIN_BRAND1		0x76
+#define ML26124_EQ_GAIN_BRAND2		0x78
+#define ML26124_EQ_GAIN_BRAND3		0x7a
+#define ML26124_EQ_GAIN_BRAND4		0x7c
+#define ML26124_HPF2_CUTOFF		0x7e
+#define ML26124_EQBRAND0_F0L		0x80
+#define ML26124_EQBRAND0_F0H		0x82
+#define ML26124_EQBRAND0_F1L		0x84
+#define ML26124_EQBRAND0_F1H		0x86
+#define ML26124_EQBRAND1_F0L		0x88
+#define ML26124_EQBRAND1_F0H		0x8a
+#define ML26124_EQBRAND1_F1L		0x8c
+#define ML26124_EQBRAND1_F1H		0x8e
+#define ML26124_EQBRAND2_F0L		0x90
+#define ML26124_EQBRAND2_F0H		0x92
+#define ML26124_EQBRAND2_F1L		0x94
+#define ML26124_EQBRAND2_F1H		0x96
+#define ML26124_EQBRAND3_F0L		0x98
+#define ML26124_EQBRAND3_F0H		0x9a
+#define ML26124_EQBRAND3_F1L		0x9c
+#define ML26124_EQBRAND3_F1H		0x9e
+#define ML26124_EQBRAND4_F0L		0xa0
+#define ML26124_EQBRAND4_F0H		0xa2
+#define ML26124_EQBRAND4_F1L		0xa4
+#define ML26124_EQBRAND4_F1H		0xa6
+
+/* ALC Control Register */
+#define ML26124_ALC_MODE		0xb0
+#define ML26124_ALC_ATTACK_TIM		0xb2
+#define ML26124_ALC_DECAY_TIM		0xb4
+#define ML26124_ALC_HOLD_TIM		0xb6
+#define ML26124_ALC_TARGET_LEV		0xb8
+#define ML26124_ALC_MAXMIN_GAIN		0xba
+#define ML26124_NOIS_GATE_THRSH		0xbc
+#define ML26124_ALC_ZERO_TIMOUT		0xbe
+
+/* Playback Limiter Control Register */
+#define ML26124_PL_ATTACKTIME		0xc0
+#define ML26124_PL_DECAYTIME		0xc2
+#define ML26124_PL_TARGETTIME		0xc4
+#define ML26124_PL_MAXMIN_GAIN		0xc6
+#define ML26124_PLYBAK_BOST_VOL		0xc8
+#define ML26124_PL_0CROSS_TIMOUT	0xca
+
+/* Video Amplifer Control Register */
+#define ML26124_VIDEO_AMP_GAIN_CTL	0xd0
+#define ML26124_VIDEO_AMP_SETUP1	0xd2
+#define ML26124_VIDEO_AMP_CTL2		0xd4
+
+/* Clock select for machine driver */
+#define ML26124_USE_PLL			0
+#define ML26124_USE_MCLKI_256FS		1
+#define ML26124_USE_MCLKI_512FS		2
+#define ML26124_USE_MCLKI_1024FS	3
+
+/* Register Mask */
+#define ML26124_R0_MASK	0xf
+#define ML26124_R2_MASK	0xff
+#define ML26124_R4_MASK	0x1
+#define ML26124_R6_MASK	0xf
+#define ML26124_R8_MASK	0x3f
+#define ML26124_Ra_MASK	0x1f
+#define ML26124_Rc_MASK	0x1f
+#define ML26124_Re_MASK	0x7
+#define ML26124_R10_MASK	0x1
+#define ML26124_R12_MASK	0x17
+#define ML26124_R14_MASK	0x3f
+#define ML26124_R20_MASK	0x47
+#define ML26124_R22_MASK	0xa
+#define ML26124_R24_MASK	0x2
+#define ML26124_R26_MASK	0x1f
+#define ML26124_R28_MASK	0x2
+#define ML26124_R2a_MASK	0x2
+#define ML26124_R2e_MASK	0x2
+#define ML26124_R30_MASK	0x7
+#define ML26124_R32_MASK	0x3f
+#define ML26124_R38_MASK	0x38
+#define ML26124_R3a_MASK	0x3f
+#define ML26124_R48_MASK	0x3
+#define ML26124_R4a_MASK	0x7
+#define ML26124_R54_MASK	0x2a
+#define ML26124_R5a_MASK	0x3
+#define ML26124_Re8_MASK	0x3
+#define ML26124_R60_MASK	0xff
+#define ML26124_R62_MASK	0xff
+#define ML26124_R64_MASK	0x1
+#define ML26124_R66_MASK	0xff
+#define ML26124_R68_MASK	0x3b
+#define ML26124_R6a_MASK	0xf3
+#define ML26124_R6c_MASK	0xff
+#define ML26124_R70_MASK	0xff
+
+#define ML26124_MCLKEN		BIT(0)
+#define ML26124_PLLEN		BIT(1)
+#define ML26124_PLLOE		BIT(2)
+#define ML26124_MCLKOE		BIT(3)
+
+#define ML26124_BLT_ALL_ON	0x1f
+#define ML26124_BLT_PREAMP_ON	0x13
+
+#define ML26124_MICBEN_ON	BIT(2)
+
+enum ml26124_regs {
+	ML26124_MCLK = 0,
+};
+
+enum ml26124_clk_in {
+	ML26124_USE_PLLOUT = 0,
+	ML26124_USE_MCLKI,
+};
+
+#endif
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 20c324c..95147e4 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -1361,8 +1361,7 @@
 static int rt5631_hifi_pcm_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 rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
 	int timesofbclk = 32, coeff;
 	unsigned int iface = 0;
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index d192626..9538d41 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -84,8 +84,8 @@
 
 static struct regulator_init_data ldo_init_data = {
 	.constraints = {
-		.min_uV                 = 850000,
-		.max_uV                 = 1600000,
+		.min_uV                 = 1200000,
+		.max_uV                 = 1200000,
 		.valid_modes_mask       = REGULATOR_MODE_NORMAL,
 		.valid_ops_mask         = REGULATOR_CHANGE_STATUS,
 	},
@@ -197,9 +197,9 @@
 	SND_SOC_DAPM_OUTPUT("HP_OUT"),
 	SND_SOC_DAPM_OUTPUT("LINE_OUT"),
 
-	SND_SOC_DAPM_MICBIAS_E("Mic Bias", SGTL5000_CHIP_MIC_CTRL, 8, 0,
-				mic_bias_event,
-				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("Mic Bias", SGTL5000_CHIP_MIC_CTRL, 8, 0,
+			    mic_bias_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
 	SND_SOC_DAPM_PGA_E("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0,
 			small_pop_event,
@@ -664,8 +664,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 sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 	int channels = params_channels(params);
 	int i2s_ctl = 0;
@@ -1450,17 +1449,7 @@
 	.id_table = sgtl5000_id,
 };
 
-static int __init sgtl5000_modinit(void)
-{
-	return i2c_add_driver(&sgtl5000_i2c_driver);
-}
-module_init(sgtl5000_modinit);
-
-static void __exit sgtl5000_exit(void)
-{
-	i2c_del_driver(&sgtl5000_i2c_driver);
-}
-module_exit(sgtl5000_exit);
+module_i2c_driver(sgtl5000_i2c_driver);
 
 MODULE_DESCRIPTION("Freescale SGTL5000 ALSA SoC Codec Driver");
 MODULE_AUTHOR("Zeng Zhaoming <zengzm.kernel@gmail.com>");
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index de2b205..4c94fd2 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -254,8 +254,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 ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 	u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3;
 	int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
@@ -291,8 +290,7 @@
 static int ssm2602_startup(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;
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 	struct snd_pcm_runtime *master_runtime;
 
@@ -328,8 +326,7 @@
 static void ssm2602_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;
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
 	if (ssm2602->master_substream == substream)
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 7db6fa5..8d717f4 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -609,8 +609,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 sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
 	unsigned int rate;
 	int i, mcs = -1, ir = -1;
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 16d55f9..8c758b21 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -34,8 +34,6 @@
 
 #include "tlv320aic23.h"
 
-#define AIC23_VERSION "0.1"
-
 /*
  * AIC23 register cache
  */
@@ -325,8 +323,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 iface_reg;
 	int ret;
 	struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
@@ -371,8 +368,7 @@
 static int tlv320aic23_pcm_prepare(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;
 
 	/* set active */
 	snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0001);
@@ -383,8 +379,7 @@
 static void tlv320aic23_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;
 	struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
 
 	/* deactivate */
@@ -548,8 +543,6 @@
 	struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 
-	printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
-
 	ret = snd_soc_codec_set_cache_io(codec, 7, 9, aic23->control_type);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 802064b..85944e9 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -126,8 +126,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 aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
 	int fsref, divisor, wlen, pval, jval, dval, qval;
 	u16 reg;
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 8d20f6e..bde2d1a 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -802,8 +802,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 aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
 	int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
 	u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 4587ddd..0dd4107 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -62,8 +62,10 @@
 #define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \
 	(((samples)*5000) / (((burstrate)*5000) / ((burstrate) - (playrate))))
 
-static void dac33_calculate_times(struct snd_pcm_substream *substream);
-static int dac33_prepare_chip(struct snd_pcm_substream *substream);
+static void dac33_calculate_times(struct snd_pcm_substream *substream,
+				  struct snd_soc_codec *codec);
+static int dac33_prepare_chip(struct snd_pcm_substream *substream,
+			      struct snd_soc_codec *codec);
 
 enum dac33_state {
 	DAC33_IDLE = 0,
@@ -427,8 +429,8 @@
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		if (likely(dac33->substream)) {
-			dac33_calculate_times(dac33->substream);
-			dac33_prepare_chip(dac33->substream);
+			dac33_calculate_times(dac33->substream, w->codec);
+			dac33_prepare_chip(dac33->substream, w->codec);
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
@@ -799,8 +801,7 @@
 static int dac33_startup(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;
 	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
 	/* Stream started, save the substream pointer */
@@ -812,8 +813,7 @@
 static void dac33_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;
 	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
 	dac33->substream = NULL;
@@ -825,8 +825,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 tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
 	/* Check parameters for validity */
@@ -868,10 +867,9 @@
  * writes happens in different order, than dac33 might end up in unknown state.
  * Use the known, working sequence of register writes to initialize the dac33.
  */
-static int dac33_prepare_chip(struct snd_pcm_substream *substream)
+static int dac33_prepare_chip(struct snd_pcm_substream *substream,
+			      struct snd_soc_codec *codec)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
 	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
 	u8 aictrl_a, aictrl_b, fifoctrl_a;
@@ -1067,10 +1065,9 @@
 	return 0;
 }
 
-static void dac33_calculate_times(struct snd_pcm_substream *substream)
+static void dac33_calculate_times(struct snd_pcm_substream *substream,
+				  struct snd_soc_codec *codec)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
 	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	unsigned int period_size = substream->runtime->period_size;
 	unsigned int rate = substream->runtime->rate;
@@ -1128,8 +1125,7 @@
 static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	int ret = 0;
 
@@ -1161,8 +1157,7 @@
 			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;
 	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	unsigned long long t0, t1, t_now;
 	unsigned int time_delta, uthr;
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 170cf9a..391fcfc 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -1685,8 +1685,7 @@
 static int twl4030_startup(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;
 	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
 	if (twl4030->master_substream) {
@@ -1715,8 +1714,7 @@
 static void twl4030_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;
 	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
 	if (twl4030->master_substream == substream)
@@ -1740,8 +1738,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 twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 	u8 mode, old_mode, format, old_format;
 
@@ -1974,8 +1971,7 @@
 static int twl4030_voice_startup(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;
 	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 	u8 mode;
 
@@ -2007,8 +2003,7 @@
 static void twl4030_voice_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;
 
 	/* Enable voice digital filters */
 	twl4030_voice_enable(codec, substream->stream, 0);
@@ -2017,8 +2012,7 @@
 static int twl4030_voice_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 twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 	u8 old_mode, mode;
 
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 2d8c6b8..ccbc88a 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -1340,8 +1340,7 @@
 static int twl6040_startup(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;
 	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
 	snd_pcm_hw_constraint_list(substream->runtime, 0,
@@ -1355,8 +1354,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 twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 	int rate;
 
@@ -1392,8 +1390,7 @@
 static int twl6040_prepare(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;
 	struct twl6040 *twl6040 = codec->control_data;
 	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 	int ret;
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 797b0dd..6c3d43b 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -159,8 +159,7 @@
 static int uda134x_startup(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;
 	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
 	struct snd_pcm_runtime *master_runtime;
 
@@ -191,8 +190,7 @@
 static void uda134x_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;
 	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
 
 	if (uda134x->master_substream == substream)
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 4f1b23d..2502214 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -502,8 +502,7 @@
 static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
 		struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
 	int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
 
@@ -528,8 +527,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 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
 
 	/* set WSPLL power and divider if running from this clock */
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index 3d868dc..7b24d6d 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -293,8 +293,7 @@
 static int wl1273_startup(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;
 	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
 
 	switch (wl1273->mode) {
@@ -329,8 +328,7 @@
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(rtd->codec);
+	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(dai->codec);
 	struct wl1273_core *core = wl1273->core;
 	unsigned int rate, width, r;
 
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index b9c185c..0594636 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2454,7 +2454,7 @@
 
 	wm5100->dev = &i2c->dev;
 
-	wm5100->regmap = regmap_init_i2c(i2c, &wm5100_regmap);
+	wm5100->regmap = devm_regmap_init_i2c(i2c, &wm5100_regmap);
 	if (IS_ERR(wm5100->regmap)) {
 		ret = PTR_ERR(wm5100->regmap);
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -2479,7 +2479,7 @@
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
 			ret);
-		goto err_regmap;
+		goto err;
 	}
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
@@ -2487,7 +2487,7 @@
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
 			ret);
-		goto err_regmap;
+		goto err;
 	}
 
 	if (wm5100->pdata.ldo_ena) {
@@ -2660,8 +2660,6 @@
 err_enable:
 	regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
 			       wm5100->core_supplies);
-err_regmap:
-	regmap_exit(wm5100->regmap);
 err:
 	return ret;
 }
@@ -2682,7 +2680,6 @@
 		gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
 		gpio_free(wm5100->pdata.ldo_ena);
 	}
-	regmap_exit(wm5100->regmap);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 898979d..5dc31eb 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -138,8 +138,8 @@
                 return ret;
 
         /* now hit the volume update bits (always bit 8) */
-        val = wm8400_read(codec, reg);
-        return wm8400_write(codec, reg, val | 0x0100);
+        val = snd_soc_read(codec, reg);
+        return snd_soc_write(codec, reg, val | 0x0100);
 }
 
 #define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \
@@ -362,8 +362,8 @@
 {
 	u16 reg, fakepower;
 
-	reg = wm8400_read(w->codec, WM8400_POWER_MANAGEMENT_2);
-	fakepower = wm8400_read(w->codec, WM8400_INTDRIVBITS);
+	reg = snd_soc_read(w->codec, WM8400_POWER_MANAGEMENT_2);
+	fakepower = snd_soc_read(w->codec, WM8400_INTDRIVBITS);
 
 	if (fakepower & ((1 << WM8400_INMIXL_PWR) |
 		(1 << WM8400_AINLMUX_PWR))) {
@@ -378,7 +378,7 @@
 	} else {
 		reg &= ~WM8400_AINR_ENA;
 	}
-	wm8400_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
+	snd_soc_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
 
 	return 0;
 }
@@ -394,7 +394,7 @@
 
 	switch (reg_shift) {
 	case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
-		reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER1);
+		reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER1);
 		if (reg & WM8400_LDLO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 1 LDLO Set\n");
@@ -402,7 +402,7 @@
 		}
 		break;
 	case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
-		reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER2);
+		reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER2);
 		if (reg & WM8400_RDRO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 2 RDRO Set\n");
@@ -410,7 +410,7 @@
 		}
 		break;
 	case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
-		reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
+		reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
 		if (reg & WM8400_LDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer LDSPK Set\n");
@@ -418,7 +418,7 @@
 		}
 		break;
 	case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
-		reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
+		reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
 		if (reg & WM8400_RDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer RDSPK Set\n");
@@ -1021,13 +1021,13 @@
 	wm8400->fll_in = freq_in;
 
 	/* We *must* disable the FLL before any changes */
-	reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_2);
+	reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_2);
 	reg &= ~WM8400_FLL_ENA;
-	wm8400_write(codec, WM8400_POWER_MANAGEMENT_2, reg);
+	snd_soc_write(codec, WM8400_POWER_MANAGEMENT_2, reg);
 
-	reg = wm8400_read(codec, WM8400_FLL_CONTROL_1);
+	reg = snd_soc_read(codec, WM8400_FLL_CONTROL_1);
 	reg &= ~WM8400_FLL_OSC_ENA;
-	wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
+	snd_soc_write(codec, WM8400_FLL_CONTROL_1, reg);
 
 	if (!freq_out)
 		return 0;
@@ -1035,15 +1035,15 @@
 	reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK);
 	reg |= WM8400_FLL_FRAC | factors.fratio;
 	reg |= factors.freq_ref << WM8400_FLL_REF_FREQ_SHIFT;
-	wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
+	snd_soc_write(codec, WM8400_FLL_CONTROL_1, reg);
 
-	wm8400_write(codec, WM8400_FLL_CONTROL_2, factors.k);
-	wm8400_write(codec, WM8400_FLL_CONTROL_3, factors.n);
+	snd_soc_write(codec, WM8400_FLL_CONTROL_2, factors.k);
+	snd_soc_write(codec, WM8400_FLL_CONTROL_3, factors.n);
 
-	reg = wm8400_read(codec, WM8400_FLL_CONTROL_4);
+	reg = snd_soc_read(codec, WM8400_FLL_CONTROL_4);
 	reg &= ~WM8400_FLL_OUTDIV_MASK;
 	reg |= factors.outdiv;
-	wm8400_write(codec, WM8400_FLL_CONTROL_4, reg);
+	snd_soc_write(codec, WM8400_FLL_CONTROL_4, reg);
 
 	return 0;
 }
@@ -1057,8 +1057,8 @@
 	struct snd_soc_codec *codec = codec_dai->codec;
 	u16 audio1, audio3;
 
-	audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
-	audio3 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_3);
+	audio1 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_1);
+	audio3 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_3);
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1099,8 +1099,8 @@
 		return -EINVAL;
 	}
 
-	wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
-	wm8400_write(codec, WM8400_AUDIO_INTERFACE_3, audio3);
+	snd_soc_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+	snd_soc_write(codec, WM8400_AUDIO_INTERFACE_3, audio3);
 	return 0;
 }
 
@@ -1112,24 +1112,24 @@
 
 	switch (div_id) {
 	case WM8400_MCLK_DIV:
-		reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+		reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
 			~WM8400_MCLK_DIV_MASK;
-		wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+		snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
 		break;
 	case WM8400_DACCLK_DIV:
-		reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+		reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
 			~WM8400_DAC_CLKDIV_MASK;
-		wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+		snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
 		break;
 	case WM8400_ADCCLK_DIV:
-		reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+		reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
 			~WM8400_ADC_CLKDIV_MASK;
-		wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+		snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
 		break;
 	case WM8400_BCLK_DIV:
-		reg = wm8400_read(codec, WM8400_CLOCKING_1) &
+		reg = snd_soc_read(codec, WM8400_CLOCKING_1) &
 			~WM8400_BCLK_DIV_MASK;
-		wm8400_write(codec, WM8400_CLOCKING_1, reg | div);
+		snd_soc_write(codec, WM8400_CLOCKING_1, reg | div);
 		break;
 	default:
 		return -EINVAL;
@@ -1145,9 +1145,8 @@
 	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;
-	u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
+	struct snd_soc_codec *codec = dai->codec;
+	u16 audio1 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_1);
 
 	audio1 &= ~WM8400_AIF_WL_MASK;
 	/* bit size */
@@ -1165,19 +1164,19 @@
 		break;
 	}
 
-	wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+	snd_soc_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
 	return 0;
 }
 
 static int wm8400_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 val = wm8400_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
+	u16 val = snd_soc_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
 
 	if (mute)
-		wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+		snd_soc_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
 	else
-		wm8400_write(codec, WM8400_DAC_CTRL, val);
+		snd_soc_write(codec, WM8400_DAC_CTRL, val);
 
 	return 0;
 }
@@ -1196,9 +1195,9 @@
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID=2*50k */
-		val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
+		val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1) &
 			~WM8400_VMID_MODE_MASK;
-		wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2);
+		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
@@ -1212,74 +1211,74 @@
 				return ret;
 			}
 
-			wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
+			snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1,
 				     WM8400_CODEC_ENA | WM8400_SYSCLK_ENA);
 
 			/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
-			wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+			snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
 				     WM8400_BUFDCOPEN | WM8400_POBCTRL);
 
 			msleep(50);
 
 			/* Enable VREF & VMID at 2x50k */
-			val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+			val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
 			val |= 0x2 | WM8400_VREF_ENA;
-			wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+			snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
 
 			/* Enable BUFIOEN */
-			wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+			snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
 				     WM8400_BUFDCOPEN | WM8400_POBCTRL |
 				     WM8400_BUFIOEN);
 
 			/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-			wm8400_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN);
+			snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN);
 		}
 
 		/* VMID=2*300k */
-		val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
+		val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1) &
 			~WM8400_VMID_MODE_MASK;
-		wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4);
+		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Enable POBCTRL and SOFT_ST */
-		wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+		snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
 			WM8400_POBCTRL | WM8400_BUFIOEN);
 
 		/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
-		wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+		snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
 			WM8400_BUFDCOPEN | WM8400_POBCTRL |
 			WM8400_BUFIOEN);
 
 		/* mute DAC */
-		val = wm8400_read(codec, WM8400_DAC_CTRL);
-		wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+		val = snd_soc_read(codec, WM8400_DAC_CTRL);
+		snd_soc_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
 
 		/* Enable any disabled outputs */
-		val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+		val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
 		val |= WM8400_SPK_ENA | WM8400_OUT3_ENA |
 			WM8400_OUT4_ENA | WM8400_LOUT_ENA |
 			WM8400_ROUT_ENA;
-		wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
 
 		/* Disable VMID */
 		val &= ~WM8400_VMID_MODE_MASK;
-		wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
 
 		msleep(300);
 
 		/* Enable all output discharge bits */
-		wm8400_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
+		snd_soc_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
 			WM8400_DIS_RLINE | WM8400_DIS_OUT3 |
 			WM8400_DIS_OUT4 | WM8400_DIS_LOUT |
 			WM8400_DIS_ROUT);
 
 		/* Disable VREF */
 		val &= ~WM8400_VREF_ENA;
-		wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
 
 		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-		wm8400_write(codec, WM8400_ANTIPOP2, 0x0);
+		snd_soc_write(codec, WM8400_ANTIPOP2, 0x0);
 
 		ret = regulator_bulk_disable(ARRAY_SIZE(power),
 					     &power[0]);
@@ -1385,19 +1384,19 @@
 
 	wm8400_codec_reset(codec);
 
-	reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
-	wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
+	reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
+	snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
 
 	/* Latch volume update bits */
-	reg = wm8400_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
-	wm8400_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+	reg = snd_soc_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
+	snd_soc_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
 		     reg & WM8400_IPVU);
-	reg = wm8400_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
-	wm8400_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+	reg = snd_soc_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
+	snd_soc_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
 		     reg & WM8400_IPVU);
 
-	wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
-	wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+	snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+	snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
 
 	if (!schedule_work(&priv->work)) {
 		ret = -EINVAL;
@@ -1414,8 +1413,8 @@
 {
 	u16 reg;
 
-	reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
-	wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
+	reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
+	snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1,
 		     reg & (~WM8400_CODEC_ENA));
 
 	regulator_bulk_free(ARRAY_SIZE(power), power);
@@ -1428,7 +1427,7 @@
 	.remove =	wm8400_codec_remove,
 	.suspend =	wm8400_suspend,
 	.resume =	wm8400_resume,
-	.read = wm8400_read,
+	.read = snd_soc_read,
 	.write = wm8400_write,
 	.set_bias_level = wm8400_set_bias_level,
 
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 9166126..56a0495 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -392,8 +392,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 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
 	u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
 
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 7fea2c3..1c3ffb2 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -145,8 +145,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 wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
 	int i;
 	u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index fc3d59e..1467f97 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -88,8 +88,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 dac = snd_soc_read(codec, WM8728_DACCTL);
 
 	dac &= ~0x18;
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index 4fe9d19..d052012 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -329,8 +329,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 wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
 	int i;
 	u16 clocking = 0;
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index 3941f50..6e849cb 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.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 wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
 	u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
 	int i;
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index e4c50ce..89151ca 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -547,8 +547,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 wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
 	u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3;
 	u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0;
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index e27e7b6..a26482c 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -931,8 +931,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 wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
 	u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01f3;
 	u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x017f;
@@ -1161,8 +1160,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 wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
 	u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x01c0;
 	u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01f3;
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index f18c554..077c962 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -610,8 +610,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 reg;
 
 	reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60;
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index c91fb2f..86b8a29 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1432,8 +1432,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 wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 	int fs = params_rate(params);
 	int bclk;
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index d2883af..481a3d9 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -371,8 +371,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 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
 	u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
 	u16 companding =  snd_soc_read(codec,
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 840d720..8bc659d 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -505,8 +505,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 wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
 	u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
 	int i;
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 15d467f..0cfce99 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -1478,7 +1478,8 @@
 
 static int wm8962_dsp2_write_config(struct snd_soc_codec *codec)
 {
-	return 0;
+	return regcache_sync_region(codec->control_data,
+				    WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER);
 }
 
 static int wm8962_dsp2_set_enable(struct snd_soc_codec *codec, u16 val)
@@ -1755,10 +1756,22 @@
 SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23,
 		 WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv),
 
+SOC_SINGLE("3D Switch", WM8962_THREED1, 0, 1, 0),
+SND_SOC_BYTES_MASK("3D Coefficients", WM8962_THREED1, 4, WM8962_THREED_ENA),
+
+SOC_SINGLE("DF1 Switch", WM8962_DF1, 0, 1, 0),
+SND_SOC_BYTES_MASK("DF1 Coefficients", WM8962_DF1, 7, WM8962_DF1_ENA),
+
+SOC_SINGLE("DRC Switch", WM8962_DRC_1, 0, 1, 0),
+SND_SOC_BYTES_MASK("DRC Coefficients", WM8962_DRC_1, 5, WM8962_DRC_ENA),
+
 WM8962_DSP2_ENABLE("VSS Switch", WM8962_VSS_ENA_SHIFT),
+SND_SOC_BYTES("VSS Coefficients", WM8962_VSS_XHD2_1, 148),
 WM8962_DSP2_ENABLE("HPF1 Switch", WM8962_HPF1_ENA_SHIFT),
 WM8962_DSP2_ENABLE("HPF2 Switch", WM8962_HPF2_ENA_SHIFT),
+SND_SOC_BYTES("HPF Coefficients", WM8962_LHPF2, 1),
 WM8962_DSP2_ENABLE("HD Bass Switch", WM8962_HDBASS_ENA_SHIFT),
+SND_SOC_BYTES("HD Bass Coefficients", WM8962_HDBASS_AI_1, 30),
 };
 
 static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
@@ -2519,8 +2532,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 wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
 	int i;
 	int aif0 = 0;
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 28fe59e..eef783f 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -478,8 +478,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 wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
 	u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
 	u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 72d5fdc..a5be3ad 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -723,8 +723,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 wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
 	/* Word length mask = 0x60 */
 	u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60;
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 6cdf6a2..1d4c5cf 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -668,8 +668,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 wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
 	u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3;
 	u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180;
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 9d24235..db63c97 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -1112,8 +1112,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 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
 
 	audio1 &= ~WM8990_AIF_WL_MASK;
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 7c49642..44f72dc 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -689,6 +689,9 @@
 	if (!wm8994->jackdet || !wm8994->jack_cb)
 		return;
 
+	if (!wm8994->jackdet || !wm8994->jack_cb)
+		return;
+
 	if (wm8994->active_refcount)
 		mode = WM1811_JACKDET_MODE_AUDIO;
 
@@ -1900,24 +1903,20 @@
 	struct wm8994 *control = wm8994->wm8994;
 	int reg_offset, ret;
 	struct fll_div fll;
-	u16 reg, aif1, aif2;
+	u16 reg, clk1, aif_reg, aif_src;
 	unsigned long timeout;
 	bool was_enabled;
 
-	aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
-		& WM8994_AIF1CLK_ENA;
-
-	aif2 = snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
-		& WM8994_AIF2CLK_ENA;
-
 	switch (id) {
 	case WM8994_FLL1:
 		reg_offset = 0;
 		id = 0;
+		aif_src = 0x10;
 		break;
 	case WM8994_FLL2:
 		reg_offset = 0x20;
 		id = 1;
+		aif_src = 0x18;
 		break;
 	default:
 		return -EINVAL;
@@ -1959,11 +1958,20 @@
 	if (ret < 0)
 		return ret;
 
-	/* Gate the AIF clocks while we reclock */
-	snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
-			    WM8994_AIF1CLK_ENA, 0);
-	snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
-			    WM8994_AIF2CLK_ENA, 0);
+	/* Make sure that we're not providing SYSCLK right now */
+	clk1 = snd_soc_read(codec, WM8994_CLOCKING_1);
+	if (clk1 & WM8994_SYSCLK_SRC)
+		aif_reg = WM8994_AIF2_CLOCKING_1;
+	else
+		aif_reg = WM8994_AIF1_CLOCKING_1;
+	reg = snd_soc_read(codec, aif_reg);
+
+	if ((reg & WM8994_AIF1CLK_ENA) &&
+	    (reg & WM8994_AIF1CLK_SRC_MASK) == aif_src) {
+		dev_err(codec->dev, "FLL%d is currently providing SYSCLK\n",
+			id + 1);
+		return -EBUSY;
+	}
 
 	/* We always need to disable the FLL while reconfiguring */
 	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
@@ -2049,12 +2057,6 @@
 	wm8994->fll[id].out = freq_out;
 	wm8994->fll[id].src = src;
 
-	/* Enable any gated AIF clocks */
-	snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
-			    WM8994_AIF1CLK_ENA, aif1);
-	snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
-			    WM8994_AIF2CLK_ENA, aif2);
-
 	configure_clock(codec);
 
 	return 0;
@@ -2624,33 +2626,6 @@
 	return snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
 }
 
-static void wm8994_aif_shutdown(struct snd_pcm_substream *substream,
-				struct snd_soc_dai *dai)
-{
-	struct snd_soc_codec *codec = dai->codec;
-	int rate_reg = 0;
-
-	switch (dai->id) {
-	case 1:
-		rate_reg = WM8994_AIF1_RATE;
-		break;
-	case 2:
-		rate_reg = WM8994_AIF2_RATE;
-		break;
-	default:
-		break;
-	}
-
-	/* If the DAI is idle then configure the divider tree for the
-	 * lowest output rate to save a little power if the clock is
-	 * still active (eg, because it is system clock).
-	 */
-	if (rate_reg && !dai->playback_active && !dai->capture_active)
-		snd_soc_update_bits(codec, rate_reg,
-				    WM8994_AIF1_SR_MASK |
-				    WM8994_AIF1CLK_RATE_MASK, 0x9);
-}
-
 static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
@@ -2732,7 +2707,6 @@
 	.set_sysclk	= wm8994_set_dai_sysclk,
 	.set_fmt	= wm8994_set_dai_fmt,
 	.hw_params	= wm8994_hw_params,
-	.shutdown	= wm8994_aif_shutdown,
 	.digital_mute	= wm8994_aif_mute,
 	.set_pll	= wm8994_set_fll,
 	.set_tristate	= wm8994_set_tristate,
@@ -2742,7 +2716,6 @@
 	.set_sysclk	= wm8994_set_dai_sysclk,
 	.set_fmt	= wm8994_set_dai_fmt,
 	.hw_params	= wm8994_hw_params,
-	.shutdown	= wm8994_aif_shutdown,
 	.digital_mute   = wm8994_aif_mute,
 	.set_pll	= wm8994_set_fll,
 	.set_tristate	= wm8994_set_tristate,
@@ -3247,9 +3220,6 @@
 
 		wm8958_micd_set_rate(codec);
 
-		snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
-				    SND_JACK_HEADSET);
-
 		/* If we have jackdet that will detect removal */
 		if (wm8994->jackdet) {
 			mutex_lock(&wm8994->accdet_lock);
@@ -3262,14 +3232,13 @@
 
 			mutex_unlock(&wm8994->accdet_lock);
 
-			if (wm8994->pdata->jd_ext_cap) {
-				mutex_lock(&codec->mutex);
+			if (wm8994->pdata->jd_ext_cap)
 				snd_soc_dapm_disable_pin(&codec->dapm,
 							 "MICBIAS2");
-				snd_soc_dapm_sync(&codec->dapm);
-				mutex_unlock(&codec->mutex);
-			}
 		}
+
+		snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
+				    SND_JACK_HEADSET);
 	}
 
 	/* Report short circuit as a button */
@@ -3358,16 +3327,11 @@
 
 	/* If required for an external cap force MICBIAS on */
 	if (wm8994->pdata->jd_ext_cap) {
-		mutex_lock(&codec->mutex);
-
 		if (present)
 			snd_soc_dapm_force_enable_pin(&codec->dapm,
 						      "MICBIAS2");
 		else
 			snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
-
-		snd_soc_dapm_sync(&codec->dapm);
-		mutex_unlock(&codec->mutex);
 	}
 
 	if (present)
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index cacc6a8..7c09593 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -236,9 +236,7 @@
 static int ac97_prepare(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	int reg;
 	u16 vra;
 
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index b342ae5..2603863 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -467,9 +467,7 @@
 static int ac97_prepare(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec =rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	int reg;
 	u16 vra;
 
@@ -487,9 +485,7 @@
 static int ac97_aux_prepare(struct snd_pcm_substream *substream,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	u16 vra, xsle;
 
 	vra = ac97_read(codec, AC97_EXTENDED_STATUS);
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c
index 0678637..bdffab3 100644
--- a/sound/soc/ep93xx/ep93xx-ac97.c
+++ b/sound/soc/ep93xx/ep93xx-ac97.c
@@ -87,17 +87,13 @@
  * struct ep93xx_ac97_info - EP93xx AC97 controller info structure
  * @lock: mutex serializing access to the bus (slot 1 & 2 ops)
  * @dev: pointer to the platform device dev structure
- * @mem: physical memory resource for the registers
  * @regs: mapped AC97 controller registers
- * @irq: AC97 interrupt number
  * @done: bus ops wait here for an interrupt
  */
 struct ep93xx_ac97_info {
 	struct mutex		lock;
 	struct device		*dev;
-	struct resource		*mem;
 	void __iomem		*regs;
-	int			irq;
 	struct completion	done;
 };
 
@@ -359,66 +355,50 @@
 static int __devinit ep93xx_ac97_probe(struct platform_device *pdev)
 {
 	struct ep93xx_ac97_info *info;
+	struct resource *res;
+	unsigned int irq;
 	int ret;
 
-	info = kzalloc(sizeof(struct ep93xx_ac97_info), GFP_KERNEL);
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	info->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (!info->regs)
+		return -ENXIO;
+
+	irq = platform_get_irq(pdev, 0);
+	if (!irq)
+		return -ENODEV;
+
+	ret = devm_request_irq(&pdev->dev, irq, ep93xx_ac97_interrupt,
+			       IRQF_TRIGGER_HIGH, pdev->name, info);
+	if (ret)
+		goto fail;
+
 	dev_set_drvdata(&pdev->dev, info);
 
 	mutex_init(&info->lock);
 	init_completion(&info->done);
 	info->dev = &pdev->dev;
 
-	info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!info->mem) {
-		ret = -ENXIO;
-		goto fail_free_info;
-	}
-
-	info->irq = platform_get_irq(pdev, 0);
-	if (!info->irq) {
-		ret = -ENXIO;
-		goto fail_free_info;
-	}
-
-	if (!request_mem_region(info->mem->start, resource_size(info->mem),
-				pdev->name)) {
-		ret = -EBUSY;
-		goto fail_free_info;
-	}
-
-	info->regs = ioremap(info->mem->start, resource_size(info->mem));
-	if (!info->regs) {
-		ret = -ENOMEM;
-		goto fail_release_mem;
-	}
-
-	ret = request_irq(info->irq, ep93xx_ac97_interrupt, IRQF_TRIGGER_HIGH,
-			  pdev->name, info);
-	if (ret)
-		goto fail_unmap_mem;
-
 	ep93xx_ac97_info = info;
 	platform_set_drvdata(pdev, info);
 
 	ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
 	if (ret)
-		goto fail_free_irq;
+		goto fail;
 
 	return 0;
 
-fail_free_irq:
+fail:
 	platform_set_drvdata(pdev, NULL);
-	free_irq(info->irq, info);
-fail_unmap_mem:
-	iounmap(info->regs);
-fail_release_mem:
-	release_mem_region(info->mem->start, resource_size(info->mem));
-fail_free_info:
-	kfree(info);
-
+	ep93xx_ac97_info = NULL;
+	dev_set_drvdata(&pdev->dev, NULL);
 	return ret;
 }
 
@@ -431,11 +411,9 @@
 	/* disable the AC97 controller */
 	ep93xx_ac97_write_reg(info, AC97GCR, 0);
 
-	free_irq(info->irq, info);
-	iounmap(info->regs);
-	release_mem_region(info->mem->start, resource_size(info->mem));
 	platform_set_drvdata(pdev, NULL);
-	kfree(info);
+	ep93xx_ac97_info = NULL;
+	dev_set_drvdata(&pdev->dev, NULL);
 
 	return 0;
 }
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
index f7a6234..8df8f6d 100644
--- a/sound/soc/ep93xx/ep93xx-i2s.c
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -63,7 +63,6 @@
 	struct clk			*sclk;
 	struct clk			*lrclk;
 	struct ep93xx_pcm_dma_params	*dma_params;
-	struct resource			*mem;
 	void __iomem			*regs;
 };
 
@@ -373,38 +372,22 @@
 	struct resource *res;
 	int err;
 
-	info = kzalloc(sizeof(struct ep93xx_i2s_info), GFP_KERNEL);
-	if (!info) {
-		err = -ENOMEM;
-		goto fail;
-	}
-
-	dev_set_drvdata(&pdev->dev, info);
-	info->dma_params = ep93xx_i2s_dma_params;
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		err = -ENODEV;
-		goto fail_free_info;
-	}
+	if (!res)
+		return -ENODEV;
 
-	info->mem = request_mem_region(res->start, resource_size(res),
-				       pdev->name);
-	if (!info->mem) {
-		err = -EBUSY;
-		goto fail_free_info;
-	}
-
-	info->regs = ioremap(info->mem->start, resource_size(info->mem));
-	if (!info->regs) {
-		err = -ENXIO;
-		goto fail_release_mem;
-	}
+	info->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (!info->regs)
+		return -ENXIO;
 
 	info->mclk = clk_get(&pdev->dev, "mclk");
 	if (IS_ERR(info->mclk)) {
 		err = PTR_ERR(info->mclk);
-		goto fail_unmap_mem;
+		goto fail;
 	}
 
 	info->sclk = clk_get(&pdev->dev, "sclk");
@@ -419,6 +402,9 @@
 		goto fail_put_sclk;
 	}
 
+	dev_set_drvdata(&pdev->dev, info);
+	info->dma_params = ep93xx_i2s_dma_params;
+
 	err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
 	if (err)
 		goto fail_put_lrclk;
@@ -426,17 +412,12 @@
 	return 0;
 
 fail_put_lrclk:
+	dev_set_drvdata(&pdev->dev, NULL);
 	clk_put(info->lrclk);
 fail_put_sclk:
 	clk_put(info->sclk);
 fail_put_mclk:
 	clk_put(info->mclk);
-fail_unmap_mem:
-	iounmap(info->regs);
-fail_release_mem:
-	release_mem_region(info->mem->start, resource_size(info->mem));
-fail_free_info:
-	kfree(info);
 fail:
 	return err;
 }
@@ -446,12 +427,10 @@
 	struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
 
 	snd_soc_unregister_dai(&pdev->dev);
+	dev_set_drvdata(&pdev->dev, NULL);
 	clk_put(info->lrclk);
 	clk_put(info->sclk);
 	clk_put(info->mclk);
-	iounmap(info->regs);
-	release_mem_region(info->mem->start, resource_size(info->mem));
-	kfree(info);
 	return 0;
 }
 
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index d754d34..0094789 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,18 +1,31 @@
+config SND_SOC_FSL_SSI
+	tristate
+
+config SND_SOC_FSL_UTILS
+	tristate
+
+menuconfig SND_POWERPC_SOC
+	tristate "SoC Audio for Freescale PowerPC CPUs"
+	depends on FSL_SOC
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the PowerPC CPUs.
+
+if SND_POWERPC_SOC
+
 config SND_MPC52xx_DMA
 	tristate
 
-# ASoC platform support for the Freescale PowerPC SOCs that have an SSI and
-# an Elo DMA controller, such as the MPC8610 and P1022.  You will still need to
-# select a platform driver and a codec driver.
-config SND_SOC_POWERPC_SSI
+config SND_SOC_POWERPC_DMA
 	tristate
-	depends on FSL_SOC
 
 config SND_SOC_MPC8610_HPCD
 	tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
 	# I2C is necessary for the CS4270 driver
 	depends on MPC8610_HPCD && I2C
-	select SND_SOC_POWERPC_SSI
+	select SND_SOC_FSL_SSI
+	select SND_SOC_FSL_UTILS
+	select SND_SOC_POWERPC_DMA
 	select SND_SOC_CS4270
 	select SND_SOC_CS4270_VD33_ERRATA
 	default y if MPC8610_HPCD
@@ -23,7 +36,9 @@
 	tristate "ALSA SoC support for the Freescale P1022 DS board"
 	# I2C is necessary for the WM8776 driver
 	depends on P1022_DS && I2C
-	select SND_SOC_POWERPC_SSI
+	select SND_SOC_FSL_SSI
+	select SND_SOC_FSL_UTILS
+	select SND_SOC_POWERPC_DMA
 	select SND_SOC_WM8776
 	default y if P1022_DS
 	help
@@ -65,3 +80,95 @@
 	help
 	  Say Y if you want to add support for sound on the Efika.
 
+endif # SND_POWERPC_SOC
+
+menuconfig SND_IMX_SOC
+	tristate "SoC Audio for Freescale i.MX CPUs"
+	depends on ARCH_MXC
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the i.MX CPUs.
+
+if SND_IMX_SOC
+
+config SND_SOC_IMX_SSI
+	tristate
+
+config SND_SOC_IMX_PCM
+	tristate
+
+config SND_SOC_IMX_PCM_FIQ
+	tristate
+	select FIQ
+	select SND_SOC_IMX_PCM
+
+config SND_SOC_IMX_PCM_DMA
+	tristate
+	select SND_SOC_DMAENGINE_PCM
+	select SND_SOC_IMX_PCM
+
+config SND_SOC_IMX_AUDMUX
+	tristate
+
+config SND_MXC_SOC_WM1133_EV1
+	tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
+	depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
+	select SND_SOC_WM8350
+	select SND_SOC_IMX_PCM_FIQ
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_SSI
+	help
+	  Enable support for audio on the i.MX31ADS with the WM1133-EV1
+	  PMIC board with WM8835x fitted.
+
+config SND_SOC_MX27VIS_AIC32X4
+	tristate "SoC audio support for Visstrim M10 boards"
+	depends on MACH_IMX27_VISSTRIM_M10 && I2C
+	select SND_SOC_TLV320AIC32X4
+	select SND_SOC_IMX_PCM_DMA
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_SSI
+	help
+	  Say Y if you want to add support for SoC audio on Visstrim SM10
+	  board with TLV320AIC32X4 codec.
+
+config SND_SOC_PHYCORE_AC97
+	tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
+	depends on MACH_PCM043 || MACH_PCA100
+	select SND_SOC_AC97_BUS
+	select SND_SOC_WM9712
+	select SND_SOC_IMX_PCM_FIQ
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_SSI
+	help
+	  Say Y if you want to add support for SoC audio on Phytec phyCORE
+	  and phyCARD boards in AC97 mode
+
+config SND_SOC_EUKREA_TLV320
+	tristate "Eukrea TLV320"
+	depends on MACH_EUKREA_MBIMX27_BASEBOARD \
+		|| MACH_EUKREA_MBIMXSD25_BASEBOARD \
+		|| MACH_EUKREA_MBIMXSD35_BASEBOARD \
+		|| MACH_EUKREA_MBIMXSD51_BASEBOARD
+	depends on I2C
+	select SND_SOC_TLV320AIC23
+	select SND_SOC_IMX_PCM_FIQ
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_SSI
+	help
+	  Enable I2S based access to the TLV320AIC23B codec attached
+	  to the SSI interface
+
+config SND_SOC_IMX_SGTL5000
+	tristate "SoC Audio support for i.MX boards with sgtl5000"
+	depends on OF && I2C
+	select SND_SOC_SGTL5000
+	select SND_SOC_IMX_PCM_DMA
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_FSL_SSI
+	select SND_SOC_FSL_UTILS
+	help
+	  Say Y if you want to add support for SoC audio on an i.MX board with
+	  a sgtl5000 codec.
+
+endif # SND_IMX_SOC
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index b4a38c0..638d385 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -8,8 +8,11 @@
 
 # Freescale PowerPC SSI/DMA Platform Support
 snd-soc-fsl-ssi-objs := fsl_ssi.o
+snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
-obj-$(CONFIG_SND_SOC_POWERPC_SSI) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
+obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
+obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
+obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
@@ -20,3 +23,27 @@
 obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
 obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
 
+# i.MX Platform Support
+snd-soc-imx-ssi-objs := imx-ssi.o
+snd-soc-imx-audmux-objs := imx-audmux.o
+
+obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
+obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
+
+obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o
+snd-soc-imx-pcm-y := imx-pcm.o
+snd-soc-imx-pcm-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o
+snd-soc-imx-pcm-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o
+
+# i.MX Machine Support
+snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
+snd-soc-phycore-ac97-objs := phycore-ac97.o
+snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
+snd-soc-wm1133-ev1-objs := wm1133-ev1.o
+snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
+
+obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
+obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
+obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
+obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
+obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
similarity index 99%
rename from sound/soc/imx/eukrea-tlv320.c
rename to sound/soc/fsl/eukrea-tlv320.c
index 7d4475c..efb9ede 100644
--- a/sound/soc/imx/eukrea-tlv320.c
+++ b/sound/soc/fsl/eukrea-tlv320.c
@@ -7,7 +7,7 @@
  * which is Copyright 2009 Simtec Electronics
  * and on sound/soc/imx/phycore-ac97.c which is
  * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
- * 
+ *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
  *  Free Software Foundation;  either version 2 of the  License, or (at your
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 2eb407f..4ed2afd 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -11,11 +11,15 @@
  */
 
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 
 #include <sound/core.h>
@@ -25,6 +29,26 @@
 #include <sound/soc.h>
 
 #include "fsl_ssi.h"
+#include "imx-pcm.h"
+
+#ifdef PPC
+#define read_ssi(addr)			 in_be32(addr)
+#define write_ssi(val, addr)		 out_be32(addr, val)
+#define write_ssi_mask(addr, clear, set) clrsetbits_be32(addr, clear, set)
+#elif defined ARM
+#define read_ssi(addr)			 readl(addr)
+#define write_ssi(val, addr)		 writel(val, addr)
+/*
+ * FIXME: Proper locking should be added at write_ssi_mask caller level
+ * to ensure this register read/modify/write sequence is race free.
+ */
+static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
+{
+	u32 val = readl(addr);
+	val = (val & ~clear) | set;
+	writel(val, addr);
+}
+#endif
 
 /**
  * FSLSSI_I2S_RATES: sample rates supported by the I2S
@@ -94,6 +118,13 @@
 	struct device_attribute dev_attr;
 	struct platform_device *pdev;
 
+	bool new_binding;
+	bool ssi_on_imx;
+	struct clk *clk;
+	struct platform_device *imx_pcm_pdev;
+	struct imx_pcm_dma_params dma_params_tx;
+	struct imx_pcm_dma_params dma_params_rx;
+
 	struct {
 		unsigned int rfrc;
 		unsigned int tfrc;
@@ -145,7 +176,7 @@
 	   were interrupted for.  We mask it with the Interrupt Enable register
 	   so that we only check for events that we're interested in.
 	 */
-	sisr = in_be32(&ssi->sisr) & SIER_FLAGS;
+	sisr = read_ssi(&ssi->sisr) & SIER_FLAGS;
 
 	if (sisr & CCSR_SSI_SISR_RFRC) {
 		ssi_private->stats.rfrc++;
@@ -260,7 +291,7 @@
 
 	/* Clear the bits that we set */
 	if (sisr2)
-		out_be32(&ssi->sisr, sisr2);
+		write_ssi(sisr2, &ssi->sisr);
 
 	return ret;
 }
@@ -295,7 +326,7 @@
 		 * SSI needs to be disabled before updating the registers we set
 		 * here.
 		 */
-		clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+		write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
 
 		/*
 		 * Program the SSI into I2S Slave Non-Network Synchronous mode.
@@ -303,20 +334,18 @@
 		 *
 		 * FIXME: Little-endian samples require a different shift dir
 		 */
-		clrsetbits_be32(&ssi->scr,
+		write_ssi_mask(&ssi->scr,
 			CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
 			CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
 			| (synchronous ? CCSR_SSI_SCR_SYN : 0));
 
-		out_be32(&ssi->stcr,
-			 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
+		write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
 			 CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
-			 CCSR_SSI_STCR_TSCKP);
+			 CCSR_SSI_STCR_TSCKP, &ssi->stcr);
 
-		out_be32(&ssi->srcr,
-			 CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
+		write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
 			 CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
-			 CCSR_SSI_SRCR_RSCKP);
+			 CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
 
 		/*
 		 * The DC and PM bits are only used if the SSI is the clock
@@ -324,7 +353,7 @@
 		 */
 
 		/* Enable the interrupts and DMA requests */
-		out_be32(&ssi->sier, SIER_FLAGS);
+		write_ssi(SIER_FLAGS, &ssi->sier);
 
 		/*
 		 * Set the watermark for transmit FIFI 0 and receive FIFO 0. We
@@ -339,9 +368,9 @@
 		 * make this value larger (and maybe we should), but this way
 		 * data will be written to memory as soon as it's available.
 		 */
-		out_be32(&ssi->sfcsr,
-			CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
-			CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2));
+		write_ssi(CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
+			CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2),
+			&ssi->sfcsr);
 
 		/*
 		 * We keep the SSI disabled because if we enable it, then the
@@ -393,6 +422,12 @@
 		ssi_private->second_stream = substream;
 	}
 
+	if (ssi_private->ssi_on_imx)
+		snd_soc_dai_set_dma_data(dai, substream,
+			(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+				&ssi_private->dma_params_tx :
+				&ssi_private->dma_params_rx);
+
 	return 0;
 }
 
@@ -417,7 +452,7 @@
 	unsigned int sample_size =
 		snd_pcm_format_width(params_format(hw_params));
 	u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
-	int enabled = in_be32(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
+	int enabled = read_ssi(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
 
 	/*
 	 * If we're in synchronous mode, and the SSI is already enabled,
@@ -439,9 +474,9 @@
 	/* In synchronous mode, the SSI uses STCCR for capture */
 	if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
 	    ssi_private->cpu_dai_drv.symmetric_rates)
-		clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+		write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
 	else
-		clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+		write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
 
 	return 0;
 }
@@ -466,19 +501,19 @@
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			setbits32(&ssi->scr,
+			write_ssi_mask(&ssi->scr, 0,
 				CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
 		else
-			setbits32(&ssi->scr,
+			write_ssi_mask(&ssi->scr, 0,
 				CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
+			write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0);
 		else
-			clrbits32(&ssi->scr, CCSR_SSI_SCR_RE);
+			write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0);
 		break;
 
 	default:
@@ -510,7 +545,7 @@
 	if (!ssi_private->first_stream) {
 		struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
 
-		clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+		write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
 	}
 }
 
@@ -622,12 +657,6 @@
 	if (!of_device_is_available(np))
 		return -ENODEV;
 
-	/* Check for a codec-handle property. */
-	if (!of_get_property(np, "codec-handle", NULL)) {
-		dev_err(&pdev->dev, "missing codec-handle property\n");
-		return -ENODEV;
-	}
-
 	/* We only support the SSI in "I2S Slave" mode */
 	sprop = of_get_property(np, "fsl,mode", NULL);
 	if (!sprop || strcmp(sprop, "i2s-slave")) {
@@ -692,6 +721,50 @@
                 /* Older 8610 DTs didn't have the fifo-depth property */
 		ssi_private->fifo_depth = 8;
 
+	if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
+		u32 dma_events[2];
+		ssi_private->ssi_on_imx = true;
+
+		ssi_private->clk = clk_get(&pdev->dev, NULL);
+		if (IS_ERR(ssi_private->clk)) {
+			ret = PTR_ERR(ssi_private->clk);
+			dev_err(&pdev->dev, "could not get clock: %d\n", ret);
+			goto error_irq;
+		}
+		clk_prepare_enable(ssi_private->clk);
+
+		/*
+		 * We have burstsize be "fifo_depth - 2" to match the SSI
+		 * watermark setting in fsl_ssi_startup().
+		 */
+		ssi_private->dma_params_tx.burstsize =
+			ssi_private->fifo_depth - 2;
+		ssi_private->dma_params_rx.burstsize =
+			ssi_private->fifo_depth - 2;
+		ssi_private->dma_params_tx.dma_addr =
+			ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0);
+		ssi_private->dma_params_rx.dma_addr =
+			ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0);
+		/*
+		 * TODO: This is a temporary solution and should be changed
+		 * to use generic DMA binding later when the helplers get in.
+		 */
+		ret = of_property_read_u32_array(pdev->dev.of_node,
+					"fsl,ssi-dma-events", dma_events, 2);
+		if (ret) {
+			dev_err(&pdev->dev, "could not get dma events\n");
+			goto error_clk;
+		}
+		ssi_private->dma_params_tx.dma = dma_events[0];
+		ssi_private->dma_params_rx.dma = dma_events[1];
+
+		ssi_private->dma_params_tx.shared_peripheral =
+				of_device_is_compatible(of_get_parent(np),
+							"fsl,spba-bus");
+		ssi_private->dma_params_rx.shared_peripheral =
+				ssi_private->dma_params_tx.shared_peripheral;
+	}
+
 	/* Initialize the the device_attribute structure */
 	dev_attr = &ssi_private->dev_attr;
 	sysfs_attr_init(&dev_attr->attr);
@@ -715,6 +788,26 @@
 		goto error_dev;
 	}
 
+	if (ssi_private->ssi_on_imx) {
+		ssi_private->imx_pcm_pdev =
+			platform_device_register_simple("imx-pcm-audio",
+							-1, NULL, 0);
+		if (IS_ERR(ssi_private->imx_pcm_pdev)) {
+			ret = PTR_ERR(ssi_private->imx_pcm_pdev);
+			goto error_dev;
+		}
+	}
+
+	/*
+	 * If codec-handle property is missing from SSI node, we assume
+	 * that the machine driver uses new binding which does not require
+	 * SSI driver to trigger machine driver's probe.
+	 */
+	if (!of_get_property(np, "codec-handle", NULL)) {
+		ssi_private->new_binding = true;
+		goto done;
+	}
+
 	/* Trigger the machine driver's probe function.  The platform driver
 	 * name of the machine driver is taken from /compatible property of the
 	 * device tree.  We also pass the address of the CPU DAI driver
@@ -736,15 +829,24 @@
 		goto error_dai;
 	}
 
+done:
 	return 0;
 
 error_dai:
+	if (ssi_private->ssi_on_imx)
+		platform_device_unregister(ssi_private->imx_pcm_pdev);
 	snd_soc_unregister_dai(&pdev->dev);
 
 error_dev:
 	dev_set_drvdata(&pdev->dev, NULL);
 	device_remove_file(&pdev->dev, dev_attr);
 
+error_clk:
+	if (ssi_private->ssi_on_imx) {
+		clk_disable_unprepare(ssi_private->clk);
+		clk_put(ssi_private->clk);
+	}
+
 error_irq:
 	free_irq(ssi_private->irq, ssi_private);
 
@@ -764,7 +866,13 @@
 {
 	struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
 
-	platform_device_unregister(ssi_private->pdev);
+	if (!ssi_private->new_binding)
+		platform_device_unregister(ssi_private->pdev);
+	if (ssi_private->ssi_on_imx) {
+		platform_device_unregister(ssi_private->imx_pcm_pdev);
+		clk_disable_unprepare(ssi_private->clk);
+		clk_put(ssi_private->clk);
+	}
 	snd_soc_unregister_dai(&pdev->dev);
 	device_remove_file(&pdev->dev, &ssi_private->dev_attr);
 
@@ -779,6 +887,7 @@
 
 static const struct of_device_id fsl_ssi_ids[] = {
 	{ .compatible = "fsl,mpc8610-ssi", },
+	{ .compatible = "fsl,imx21-ssi", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c
new file mode 100644
index 0000000..b9e42b5
--- /dev/null
+++ b/sound/soc/fsl/fsl_utils.c
@@ -0,0 +1,91 @@
+/**
+ * Freescale ALSA SoC Machine driver utility
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <sound/soc.h>
+
+#include "fsl_utils.h"
+
+/**
+ * fsl_asoc_get_dma_channel - determine the dma channel for a SSI node
+ *
+ * @ssi_np: pointer to the SSI device tree node
+ * @name: name of the phandle pointing to the dma channel
+ * @dai: ASoC DAI link pointer to be filled with platform_name
+ * @dma_channel_id: dma channel id to be returned
+ * @dma_id: dma id to be returned
+ *
+ * This function determines the dma and channel id for given SSI node.  It
+ * also discovers the platform_name for the ASoC DAI link.
+ */
+int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
+			     const char *name,
+			     struct snd_soc_dai_link *dai,
+			     unsigned int *dma_channel_id,
+			     unsigned int *dma_id)
+{
+	struct resource res;
+	struct device_node *dma_channel_np, *dma_np;
+	const u32 *iprop;
+	int ret;
+
+	dma_channel_np = of_parse_phandle(ssi_np, name, 0);
+	if (!dma_channel_np)
+		return -EINVAL;
+
+	if (!of_device_is_compatible(dma_channel_np, "fsl,ssi-dma-channel")) {
+		of_node_put(dma_channel_np);
+		return -EINVAL;
+	}
+
+	/* Determine the dev_name for the device_node.  This code mimics the
+	 * behavior of of_device_make_bus_id(). We need this because ASoC uses
+	 * the dev_name() of the device to match the platform (DMA) device with
+	 * the CPU (SSI) device.  It's all ugly and hackish, but it works (for
+	 * now).
+	 *
+	 * dai->platform name should already point to an allocated buffer.
+	 */
+	ret = of_address_to_resource(dma_channel_np, 0, &res);
+	if (ret) {
+		of_node_put(dma_channel_np);
+		return ret;
+	}
+	snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
+		 (unsigned long long) res.start, dma_channel_np->name);
+
+	iprop = of_get_property(dma_channel_np, "cell-index", NULL);
+	if (!iprop) {
+		of_node_put(dma_channel_np);
+		return -EINVAL;
+	}
+	*dma_channel_id = be32_to_cpup(iprop);
+
+	dma_np = of_get_parent(dma_channel_np);
+	iprop = of_get_property(dma_np, "cell-index", NULL);
+	if (!iprop) {
+		of_node_put(dma_np);
+		return -EINVAL;
+	}
+	*dma_id = be32_to_cpup(iprop);
+
+	of_node_put(dma_np);
+	of_node_put(dma_channel_np);
+
+	return 0;
+}
+EXPORT_SYMBOL(fsl_asoc_get_dma_channel);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Freescale ASoC utility code");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_utils.h b/sound/soc/fsl/fsl_utils.h
new file mode 100644
index 0000000..b295112
--- /dev/null
+++ b/sound/soc/fsl/fsl_utils.h
@@ -0,0 +1,26 @@
+/**
+ * Freescale ALSA SoC Machine driver utility
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _FSL_UTILS_H
+#define _FSL_UTILS_H
+
+#define DAI_NAME_SIZE	32
+
+struct snd_soc_dai_link;
+struct device_node;
+
+int fsl_asoc_get_dma_channel(struct device_node *ssi_np, const char *name,
+			     struct snd_soc_dai_link *dai,
+			     unsigned int *dma_channel_id,
+			     unsigned int *dma_id);
+
+#endif /* _FSL_UTILS_H */
diff --git a/sound/soc/imx/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
similarity index 100%
rename from sound/soc/imx/imx-audmux.c
rename to sound/soc/fsl/imx-audmux.c
diff --git a/sound/soc/imx/imx-audmux.h b/sound/soc/fsl/imx-audmux.h
similarity index 100%
rename from sound/soc/imx/imx-audmux.h
rename to sound/soc/fsl/imx-audmux.h
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/fsl/imx-pcm-dma.c
similarity index 96%
rename from sound/soc/imx/imx-pcm-dma-mx2.c
rename to sound/soc/fsl/imx-pcm-dma.c
index 6b818de..f3c0a5e 100644
--- a/sound/soc/imx/imx-pcm-dma-mx2.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -109,7 +109,8 @@
 	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
 	dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
-	dma_data->peripheral_type = IMX_DMATYPE_SSI;
+	dma_data->peripheral_type = dma_params->shared_peripheral ?
+					IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI;
 	dma_data->priority = DMA_PRIO_HIGH;
 	dma_data->dma_request = dma_params->dma;
 
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
similarity index 100%
rename from sound/soc/imx/imx-pcm-fiq.c
rename to sound/soc/fsl/imx-pcm-fiq.c
diff --git a/sound/soc/imx/imx-pcm.c b/sound/soc/fsl/imx-pcm.c
similarity index 100%
rename from sound/soc/imx/imx-pcm.c
rename to sound/soc/fsl/imx-pcm.c
diff --git a/sound/soc/imx/imx-pcm.h b/sound/soc/fsl/imx-pcm.h
similarity index 93%
rename from sound/soc/imx/imx-pcm.h
rename to sound/soc/fsl/imx-pcm.h
index b5f5c3a..83c0ed7 100644
--- a/sound/soc/imx/imx-pcm.h
+++ b/sound/soc/fsl/imx-pcm.h
@@ -22,6 +22,7 @@
 	int dma;
 	unsigned long dma_addr;
 	int burstsize;
+	bool shared_peripheral;	/* The peripheral is on SPBA bus */
 };
 
 int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
new file mode 100644
index 0000000..e1a7441
--- /dev/null
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <sound/soc.h>
+
+#include "../codecs/sgtl5000.h"
+#include "imx-audmux.h"
+
+#define DAI_NAME_SIZE	32
+
+struct imx_sgtl5000_data {
+	struct snd_soc_dai_link dai;
+	struct snd_soc_card card;
+	char codec_dai_name[DAI_NAME_SIZE];
+	char platform_name[DAI_NAME_SIZE];
+	unsigned int clk_frequency;
+};
+
+static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct imx_sgtl5000_data *data = container_of(rtd->card,
+					struct imx_sgtl5000_data, card);
+	struct device *dev = rtd->card->dev;
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(rtd->codec_dai, SGTL5000_SYSCLK,
+				     data->clk_frequency, SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(dev, "could not set codec driver clock params\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget imx_sgtl5000_dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In Jack", NULL),
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_SPK("Line Out Jack", NULL),
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static int __devinit imx_sgtl5000_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *ssi_np, *codec_np;
+	struct platform_device *ssi_pdev;
+	struct imx_sgtl5000_data *data;
+	int int_port, ext_port;
+	int ret;
+
+	ret = of_property_read_u32(np, "mux-int-port", &int_port);
+	if (ret) {
+		dev_err(&pdev->dev, "mux-int-port missing or invalid\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
+	if (ret) {
+		dev_err(&pdev->dev, "mux-ext-port missing or invalid\n");
+		return ret;
+	}
+
+	/*
+	 * The port numbering in the hardware manual starts at 1, while
+	 * the audmux API expects it starts at 0.
+	 */
+	int_port--;
+	ext_port--;
+	ret = imx_audmux_v2_configure_port(int_port,
+			IMX_AUDMUX_V2_PTCR_SYN |
+			IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+			IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+			IMX_AUDMUX_V2_PTCR_TFSDIR |
+			IMX_AUDMUX_V2_PTCR_TCLKDIR,
+			IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
+	if (ret) {
+		dev_err(&pdev->dev, "audmux internal port setup failed\n");
+		return ret;
+	}
+	imx_audmux_v2_configure_port(ext_port,
+			IMX_AUDMUX_V2_PTCR_SYN |
+			IMX_AUDMUX_V2_PTCR_TCSEL(int_port),
+			IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
+	if (ret) {
+		dev_err(&pdev->dev, "audmux external port setup failed\n");
+		return ret;
+	}
+
+	ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
+	codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
+	if (!ssi_np || !codec_np) {
+		dev_err(&pdev->dev, "phandle missing or invalid\n");
+		return -EINVAL;
+	}
+
+	ssi_pdev = of_find_device_by_node(ssi_np);
+	if (!ssi_pdev) {
+		dev_err(&pdev->dev, "failed to find SSI platform device\n");
+		return -EINVAL;
+	}
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	ret = of_property_read_u32(codec_np, "clock-frequency",
+				   &data->clk_frequency);
+	if (ret) {
+		dev_err(&pdev->dev, "clock-frequency missing or invalid\n");
+		return ret;
+	}
+
+	data->dai.name = "HiFi";
+	data->dai.stream_name = "HiFi";
+	data->dai.codec_dai_name = "sgtl5000";
+	data->dai.codec_of_node = codec_np;
+	data->dai.cpu_dai_name = dev_name(&ssi_pdev->dev);
+	data->dai.platform_name = "imx-pcm-audio";
+	data->dai.init = &imx_sgtl5000_dai_init;
+	data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			    SND_SOC_DAIFMT_CBM_CFM;
+
+	data->card.dev = &pdev->dev;
+	ret = snd_soc_of_parse_card_name(&data->card, "model");
+	if (ret)
+		return ret;
+	ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
+	if (ret)
+		return ret;
+	data->card.num_links = 1;
+	data->card.dai_link = &data->dai;
+	data->card.dapm_widgets = imx_sgtl5000_dapm_widgets;
+	data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets);
+
+	ret = snd_soc_register_card(&data->card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, data);
+	of_node_put(ssi_np);
+	of_node_put(codec_np);
+
+	return 0;
+}
+
+static int __devexit imx_sgtl5000_remove(struct platform_device *pdev)
+{
+	struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(&data->card);
+
+	return 0;
+}
+
+static const struct of_device_id imx_sgtl5000_dt_ids[] = {
+	{ .compatible = "fsl,imx-audio-sgtl5000", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_sgtl5000_dt_ids);
+
+static struct platform_driver imx_sgtl5000_driver = {
+	.driver = {
+		.name = "imx-sgtl5000",
+		.owner = THIS_MODULE,
+		.of_match_table = imx_sgtl5000_dt_ids,
+	},
+	.probe = imx_sgtl5000_probe,
+	.remove = __devexit_p(imx_sgtl5000_remove),
+};
+module_platform_driver(imx_sgtl5000_driver);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("Freescale i.MX SGTL5000 ASoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-sgtl5000");
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
similarity index 99%
rename from sound/soc/imx/imx-ssi.c
rename to sound/soc/fsl/imx-ssi.c
index 4f81ed4..cf3ed03 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -28,7 +28,7 @@
  * value. When we read the same register two times (and the register still
  * contains the same value) these status bits are not set. We work
  * around this by not polling these bits but only wait a fixed delay.
- * 
+ *
  */
 
 #include <linux/clk.h>
diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/fsl/imx-ssi.h
similarity index 100%
rename from sound/soc/imx/imx-ssi.h
rename to sound/soc/fsl/imx-ssi.h
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 3fea5a1..60bcba1 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -14,18 +14,16 @@
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
-#include <linux/of_i2c.h>
 #include <sound/soc.h>
 #include <asm/fsl_guts.h>
 
 #include "fsl_dma.h"
 #include "fsl_ssi.h"
+#include "fsl_utils.h"
 
 /* There's only one global utilities register */
 static phys_addr_t guts_phys;
 
-#define DAI_NAME_SIZE	32
-
 /**
  * mpc8610_hpcd_data: machine-specific ASoC device data
  *
@@ -43,7 +41,6 @@
 	unsigned int dma_id[2];		/* 0 = DMA1, 1 = DMA2, etc */
 	unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
 	char codec_dai_name[DAI_NAME_SIZE];
-	char codec_name[DAI_NAME_SIZE];
 	char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
 };
 
@@ -181,141 +178,6 @@
 };
 
 /**
- * get_node_by_phandle_name - get a node by its phandle name
- *
- * This function takes a node, the name of a property in that node, and a
- * compatible string.  Assuming the property is a phandle to another node,
- * it returns that node, (optionally) if that node is compatible.
- *
- * If the property is not a phandle, or the node it points to is not compatible
- * with the specific string, then NULL is returned.
- */
-static struct device_node *get_node_by_phandle_name(struct device_node *np,
-					       const char *name,
-					       const char *compatible)
-{
-	const phandle *ph;
-	int len;
-
-	ph = of_get_property(np, name, &len);
-	if (!ph || (len != sizeof(phandle)))
-		return NULL;
-
-	np = of_find_node_by_phandle(*ph);
-	if (!np)
-		return NULL;
-
-	if (compatible && !of_device_is_compatible(np, compatible)) {
-		of_node_put(np);
-		return NULL;
-	}
-
-	return np;
-}
-
-/**
- * get_parent_cell_index -- return the cell-index of the parent of a node
- *
- * Return the value of the cell-index property of the parent of the given
- * node.  This is used for DMA channel nodes that need to know the DMA ID
- * of the controller they are on.
- */
-static int get_parent_cell_index(struct device_node *np)
-{
-	struct device_node *parent = of_get_parent(np);
-	const u32 *iprop;
-
-	if (!parent)
-		return -1;
-
-	iprop = of_get_property(parent, "cell-index", NULL);
-	of_node_put(parent);
-
-	if (!iprop)
-		return -1;
-
-	return be32_to_cpup(iprop);
-}
-
-/**
- * codec_node_dev_name - determine the dev_name for a codec node
- *
- * This function determines the dev_name for an I2C node.  This is the name
- * that would be returned by dev_name() if this device_node were part of a
- * 'struct device'  It's ugly and hackish, but it works.
- *
- * The dev_name for such devices include the bus number and I2C address. For
- * example, "cs4270.0-004f".
- */
-static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
-{
-	const u32 *iprop;
-	int addr;
-	char temp[DAI_NAME_SIZE];
-	struct i2c_client *i2c;
-
-	of_modalias_node(np, temp, DAI_NAME_SIZE);
-
-	iprop = of_get_property(np, "reg", NULL);
-	if (!iprop)
-		return -EINVAL;
-
-	addr = be32_to_cpup(iprop);
-
-	/* We need the adapter number */
-	i2c = of_find_i2c_device_by_node(np);
-	if (!i2c)
-		return -ENODEV;
-
-	snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr);
-
-	return 0;
-}
-
-static int get_dma_channel(struct device_node *ssi_np,
-			   const char *name,
-			   struct snd_soc_dai_link *dai,
-			   unsigned int *dma_channel_id,
-			   unsigned int *dma_id)
-{
-	struct resource res;
-	struct device_node *dma_channel_np;
-	const u32 *iprop;
-	int ret;
-
-	dma_channel_np = get_node_by_phandle_name(ssi_np, name,
-						  "fsl,ssi-dma-channel");
-	if (!dma_channel_np)
-		return -EINVAL;
-
-	/* Determine the dev_name for the device_node.  This code mimics the
-	 * behavior of of_device_make_bus_id(). We need this because ASoC uses
-	 * the dev_name() of the device to match the platform (DMA) device with
-	 * the CPU (SSI) device.  It's all ugly and hackish, but it works (for
-	 * now).
-	 *
-	 * dai->platform name should already point to an allocated buffer.
-	 */
-	ret = of_address_to_resource(dma_channel_np, 0, &res);
-	if (ret)
-		return ret;
-	snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
-		 (unsigned long long) res.start, dma_channel_np->name);
-
-	iprop = of_get_property(dma_channel_np, "cell-index", NULL);
-	if (!iprop) {
-		of_node_put(dma_channel_np);
-		return -EINVAL;
-	}
-
-	*dma_channel_id = be32_to_cpup(iprop);
-	*dma_id = get_parent_cell_index(dma_channel_np);
-	of_node_put(dma_channel_np);
-
-	return 0;
-}
-
-/**
  * mpc8610_hpcd_probe: platform probe function for the machine driver
  *
  * Although this is a machine driver, the SSI node is the "master" node with
@@ -352,16 +214,8 @@
 	machine_data->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
 	machine_data->dai[0].ops = &mpc8610_hpcd_ops;
 
-	/* Determine the codec name, it will be used as the codec DAI name */
-	ret = codec_node_dev_name(codec_np, machine_data->codec_name,
-				  DAI_NAME_SIZE);
-	if (ret) {
-		dev_err(&pdev->dev, "invalid codec node %s\n",
-			codec_np->full_name);
-		ret = -EINVAL;
-		goto error;
-	}
-	machine_data->dai[0].codec_name = machine_data->codec_name;
+	/* ASoC core can match codec with device node */
+	machine_data->dai[0].codec_of_node = codec_np;
 
 	/* The DAI name from the codec (snd_soc_dai_driver.name) */
 	machine_data->dai[0].codec_dai_name = "cs4270-hifi";
@@ -458,9 +312,10 @@
 
 	/* Find the playback DMA channel to use. */
 	machine_data->dai[0].platform_name = machine_data->platform_name[0];
-	ret = get_dma_channel(np, "fsl,playback-dma", &machine_data->dai[0],
-			      &machine_data->dma_channel_id[0],
-			      &machine_data->dma_id[0]);
+	ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma",
+				       &machine_data->dai[0],
+				       &machine_data->dma_channel_id[0],
+				       &machine_data->dma_id[0]);
 	if (ret) {
 		dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
 		goto error;
@@ -468,9 +323,10 @@
 
 	/* Find the capture DMA channel to use. */
 	machine_data->dai[1].platform_name = machine_data->platform_name[1];
-	ret = get_dma_channel(np, "fsl,capture-dma", &machine_data->dai[1],
-			      &machine_data->dma_channel_id[1],
-			      &machine_data->dma_id[1]);
+	ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma",
+				       &machine_data->dai[1],
+				       &machine_data->dma_channel_id[1],
+				       &machine_data->dma_id[1]);
 	if (ret) {
 		dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
 		goto error;
diff --git a/sound/soc/imx/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c
similarity index 100%
rename from sound/soc/imx/mx27vis-aic32x4.c
rename to sound/soc/fsl/mx27vis-aic32x4.c
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index 982a1c9..50adf40 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -14,12 +14,12 @@
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
-#include <linux/of_i2c.h>
 #include <sound/soc.h>
 #include <asm/fsl_guts.h>
 
 #include "fsl_dma.h"
 #include "fsl_ssi.h"
+#include "fsl_utils.h"
 
 /* P1022-specific PMUXCR and DMUXCR bit definitions */
 
@@ -57,8 +57,6 @@
 /* There's only one global utilities register */
 static phys_addr_t guts_phys;
 
-#define DAI_NAME_SIZE	32
-
 /**
  * machine_data: machine-specific ASoC device data
  *
@@ -75,7 +73,6 @@
 	unsigned int ssi_id;		/* 0 = SSI1, 1 = SSI2, etc */
 	unsigned int dma_id[2];		/* 0 = DMA1, 1 = DMA2, etc */
 	unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
-	char codec_name[DAI_NAME_SIZE];
 	char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
 };
 
@@ -191,136 +188,6 @@
 };
 
 /**
- * get_node_by_phandle_name - get a node by its phandle name
- *
- * This function takes a node, the name of a property in that node, and a
- * compatible string.  Assuming the property is a phandle to another node,
- * it returns that node, (optionally) if that node is compatible.
- *
- * If the property is not a phandle, or the node it points to is not compatible
- * with the specific string, then NULL is returned.
- */
-static struct device_node *get_node_by_phandle_name(struct device_node *np,
-	const char *name, const char *compatible)
-{
-	np = of_parse_phandle(np, name, 0);
-	if (!np)
-		return NULL;
-
-	if (!of_device_is_compatible(np, compatible)) {
-		of_node_put(np);
-		return NULL;
-	}
-
-	return np;
-}
-
-/**
- * get_parent_cell_index -- return the cell-index of the parent of a node
- *
- * Return the value of the cell-index property of the parent of the given
- * node.  This is used for DMA channel nodes that need to know the DMA ID
- * of the controller they are on.
- */
-static int get_parent_cell_index(struct device_node *np)
-{
-	struct device_node *parent = of_get_parent(np);
-	const u32 *iprop;
-	int ret = -1;
-
-	if (!parent)
-		return -1;
-
-	iprop = of_get_property(parent, "cell-index", NULL);
-	if (iprop)
-		ret = be32_to_cpup(iprop);
-
-	of_node_put(parent);
-
-	return ret;
-}
-
-/**
- * codec_node_dev_name - determine the dev_name for a codec node
- *
- * This function determines the dev_name for an I2C node.  This is the name
- * that would be returned by dev_name() if this device_node were part of a
- * 'struct device'  It's ugly and hackish, but it works.
- *
- * The dev_name for such devices include the bus number and I2C address. For
- * example, "cs4270-codec.0-004f".
- */
-static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
-{
-	const u32 *iprop;
-	int addr;
-	char temp[DAI_NAME_SIZE];
-	struct i2c_client *i2c;
-
-	of_modalias_node(np, temp, DAI_NAME_SIZE);
-
-	iprop = of_get_property(np, "reg", NULL);
-	if (!iprop)
-		return -EINVAL;
-
-	addr = be32_to_cpup(iprop);
-
-	/* We need the adapter number */
-	i2c = of_find_i2c_device_by_node(np);
-	if (!i2c)
-		return -ENODEV;
-
-	snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr);
-
-	return 0;
-}
-
-static int get_dma_channel(struct device_node *ssi_np,
-			   const char *name,
-			   struct snd_soc_dai_link *dai,
-			   unsigned int *dma_channel_id,
-			   unsigned int *dma_id)
-{
-	struct resource res;
-	struct device_node *dma_channel_np;
-	const u32 *iprop;
-	int ret;
-
-	dma_channel_np = get_node_by_phandle_name(ssi_np, name,
-						  "fsl,ssi-dma-channel");
-	if (!dma_channel_np)
-		return -EINVAL;
-
-	/* Determine the dev_name for the device_node.  This code mimics the
-	 * behavior of of_device_make_bus_id(). We need this because ASoC uses
-	 * the dev_name() of the device to match the platform (DMA) device with
-	 * the CPU (SSI) device.  It's all ugly and hackish, but it works (for
-	 * now).
-	 *
-	 * dai->platform name should already point to an allocated buffer.
-	 */
-	ret = of_address_to_resource(dma_channel_np, 0, &res);
-	if (ret) {
-		of_node_put(dma_channel_np);
-		return ret;
-	}
-	snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
-		 (unsigned long long) res.start, dma_channel_np->name);
-
-	iprop = of_get_property(dma_channel_np, "cell-index", NULL);
-	if (!iprop) {
-		of_node_put(dma_channel_np);
-		return -EINVAL;
-	}
-
-	*dma_channel_id = be32_to_cpup(iprop);
-	*dma_id = get_parent_cell_index(dma_channel_np);
-	of_node_put(dma_channel_np);
-
-	return 0;
-}
-
-/**
  * p1022_ds_probe: platform probe function for the machine driver
  *
  * Although this is a machine driver, the SSI node is the "master" node with
@@ -357,15 +224,8 @@
 	mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
 	mdata->dai[0].ops = &p1022_ds_ops;
 
-	/* Determine the codec name, it will be used as the codec DAI name */
-	ret = codec_node_dev_name(codec_np, mdata->codec_name, DAI_NAME_SIZE);
-	if (ret) {
-		dev_err(&pdev->dev, "invalid codec node %s\n",
-			codec_np->full_name);
-		ret = -EINVAL;
-		goto error;
-	}
-	mdata->dai[0].codec_name = mdata->codec_name;
+	/* ASoC core can match codec with device node */
+	mdata->dai[0].codec_of_node = codec_np;
 
 	/* We register two DAIs per SSI, one for playback and the other for
 	 * capture.  We support codecs that have separate DAIs for both playback
@@ -462,9 +322,9 @@
 
 	/* Find the playback DMA channel to use. */
 	mdata->dai[0].platform_name = mdata->platform_name[0];
-	ret = get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0],
-			      &mdata->dma_channel_id[0],
-			      &mdata->dma_id[0]);
+	ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0],
+				       &mdata->dma_channel_id[0],
+				       &mdata->dma_id[0]);
 	if (ret) {
 		dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
 		goto error;
@@ -472,9 +332,9 @@
 
 	/* Find the capture DMA channel to use. */
 	mdata->dai[1].platform_name = mdata->platform_name[1];
-	ret = get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1],
-			      &mdata->dma_channel_id[1],
-			      &mdata->dma_id[1]);
+	ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1],
+				       &mdata->dma_channel_id[1],
+				       &mdata->dma_id[1]);
 	if (ret) {
 		dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
 		goto error;
diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/fsl/phycore-ac97.c
similarity index 100%
rename from sound/soc/imx/phycore-ac97.c
rename to sound/soc/fsl/phycore-ac97.c
diff --git a/sound/soc/imx/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c
similarity index 100%
rename from sound/soc/imx/wm1133-ev1.c
rename to sound/soc/fsl/wm1133-ev1.c
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
deleted file mode 100644
index 810acaa..0000000
--- a/sound/soc/imx/Kconfig
+++ /dev/null
@@ -1,79 +0,0 @@
-menuconfig SND_IMX_SOC
-	tristate "SoC Audio for Freescale i.MX CPUs"
-	depends on ARCH_MXC
-	help
-	  Say Y or M if you want to add support for codecs attached to
-	  the i.MX SSI interface.
-
-
-if SND_IMX_SOC
-
-config SND_SOC_IMX_SSI
-	tristate
-
-config SND_SOC_IMX_PCM
-	tristate
-
-config SND_MXC_SOC_FIQ
-	tristate
-	select FIQ
-	select SND_SOC_IMX_PCM
-
-config SND_MXC_SOC_MX2
-	select SND_SOC_DMAENGINE_PCM
-	tristate
-	select SND_SOC_IMX_PCM
-
-config SND_SOC_IMX_AUDMUX
-	tristate
-
-config SND_MXC_SOC_WM1133_EV1
-	tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
-	depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
-	select SND_SOC_WM8350
-	select SND_MXC_SOC_FIQ
-	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_IMX_SSI
-	help
-	  Enable support for audio on the i.MX31ADS with the WM1133-EV1
-	  PMIC board with WM8835x fitted.
-
-config SND_SOC_MX27VIS_AIC32X4
-	tristate "SoC audio support for Visstrim M10 boards"
-	depends on MACH_IMX27_VISSTRIM_M10 && I2C
-	select SND_SOC_TLV320AIC32X4
-	select SND_MXC_SOC_MX2
-	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_IMX_SSI
-	help
-	  Say Y if you want to add support for SoC audio on Visstrim SM10
-	  board with TLV320AIC32X4 codec.
-
-config SND_SOC_PHYCORE_AC97
-	tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
-	depends on MACH_PCM043 || MACH_PCA100
-	select SND_SOC_AC97_BUS
-	select SND_SOC_WM9712
-	select SND_MXC_SOC_FIQ
-	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_IMX_SSI
-	help
-	  Say Y if you want to add support for SoC audio on Phytec phyCORE
-	  and phyCARD boards in AC97 mode
-
-config SND_SOC_EUKREA_TLV320
-	tristate "Eukrea TLV320"
-	depends on MACH_EUKREA_MBIMX27_BASEBOARD \
-		|| MACH_EUKREA_MBIMXSD25_BASEBOARD \
-		|| MACH_EUKREA_MBIMXSD35_BASEBOARD \
-		|| MACH_EUKREA_MBIMXSD51_BASEBOARD
-	depends on I2C
-	select SND_SOC_TLV320AIC23
-	select SND_MXC_SOC_FIQ
-	select SND_SOC_IMX_AUDMUX
-	select SND_SOC_IMX_SSI
-	help
-	  Enable I2S based access to the TLV320AIC23B codec attached
-	  to the SSI interface
-
-endif	# SND_IMX_SOC
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
deleted file mode 100644
index f5db3e9..0000000
--- a/sound/soc/imx/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-# i.MX Platform Support
-snd-soc-imx-ssi-objs := imx-ssi.o
-snd-soc-imx-audmux-objs := imx-audmux.o
-
-obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
-obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
-
-obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o
-snd-soc-imx-pcm-y := imx-pcm.o
-snd-soc-imx-pcm-$(CONFIG_SND_MXC_SOC_FIQ) += imx-pcm-fiq.o
-snd-soc-imx-pcm-$(CONFIG_SND_MXC_SOC_MX2) += imx-pcm-dma-mx2.o
-
-# i.MX Machine Support
-snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
-snd-soc-phycore-ac97-objs := phycore-ac97.o
-snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
-snd-soc-wm1133-ev1-objs := wm1133-ev1.o
-
-obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
-obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
-obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
-obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index a5af7c4..4134967 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -346,7 +346,7 @@
 
 	/* Playback */
 	dma_config = &i2s->pcm_config_playback.dma_config;
-	dma_config->src_width = JZ4740_DMA_WIDTH_32BIT,
+	dma_config->src_width = JZ4740_DMA_WIDTH_32BIT;
 	dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
 	dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
 	dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
@@ -355,7 +355,7 @@
 
 	/* Capture */
 	dma_config = &i2s->pcm_config_capture.dma_config;
-	dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT,
+	dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT;
 	dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
 	dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
 	dma_config->flags = JZ4740_DMA_DST_AUTOINC;
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 609abd5..453b092 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -165,7 +165,7 @@
 	struct pxa2xx_pcm_dma_params *dma_data;
 
 	BUG_ON(IS_ERR(clk_i2s));
-	clk_enable(clk_i2s);
+	clk_prepare_enable(clk_i2s);
 	clk_ena = 1;
 	pxa_i2s_wait();
 
@@ -258,7 +258,7 @@
 		SACR0 &= ~SACR0_ENB;
 		pxa_i2s_wait();
 		if (clk_ena) {
-			clk_disable(clk_i2s);
+			clk_disable_unprepare(clk_i2s);
 			clk_ena = 0;
 		}
 	}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index e19c24a..8a17048 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -54,7 +54,6 @@
 #endif
 
 static DEFINE_MUTEX(client_mutex);
-static LIST_HEAD(card_list);
 static LIST_HEAD(dai_list);
 static LIST_HEAD(platform_list);
 static LIST_HEAD(codec_list);
@@ -567,19 +566,16 @@
 	}
 
 	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
 
 		if (card->rtd[i].dai_link->ignore_suspend)
 			continue;
 
 		snd_soc_dapm_stream_event(&card->rtd[i],
 					  SNDRV_PCM_STREAM_PLAYBACK,
-					  codec_dai,
 					  SND_SOC_DAPM_STREAM_SUSPEND);
 
 		snd_soc_dapm_stream_event(&card->rtd[i],
 					  SNDRV_PCM_STREAM_CAPTURE,
-					  codec_dai,
 					  SND_SOC_DAPM_STREAM_SUSPEND);
 	}
 
@@ -683,17 +679,16 @@
 	}
 
 	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
 
 		if (card->rtd[i].dai_link->ignore_suspend)
 			continue;
 
 		snd_soc_dapm_stream_event(&card->rtd[i],
-					  SNDRV_PCM_STREAM_PLAYBACK, codec_dai,
+					  SNDRV_PCM_STREAM_PLAYBACK,
 					  SND_SOC_DAPM_STREAM_RESUME);
 
 		snd_soc_dapm_stream_event(&card->rtd[i],
-					  SNDRV_PCM_STREAM_CAPTURE, codec_dai,
+					  SNDRV_PCM_STREAM_CAPTURE,
 					  SND_SOC_DAPM_STREAM_RESUME);
 	}
 
@@ -783,15 +778,9 @@
 	struct snd_soc_dai *codec_dai, *cpu_dai;
 	const char *platform_name;
 
-	if (rtd->complete)
-		return 1;
 	dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num);
 
-	/* do we already have the CPU DAI for this link ? */
-	if (rtd->cpu_dai) {
-		goto find_codec;
-	}
-	/* no, then find CPU DAI from registered DAIs*/
+	/* Find CPU DAI from registered DAIs*/
 	list_for_each_entry(cpu_dai, &dai_list, list) {
 		if (dai_link->cpu_dai_of_node) {
 			if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
@@ -802,18 +791,15 @@
 		}
 
 		rtd->cpu_dai = cpu_dai;
-		goto find_codec;
 	}
-	dev_dbg(card->dev, "CPU DAI %s not registered\n",
+
+	if (!rtd->cpu_dai) {
+		dev_dbg(card->dev, "CPU DAI %s not registered\n",
 			dai_link->cpu_dai_name);
-
-find_codec:
-	/* do we already have the CODEC for this link ? */
-	if (rtd->codec) {
-		goto find_platform;
+		return -EPROBE_DEFER;
 	}
 
-	/* no, then find CODEC from registered CODECs*/
+	/* Find CODEC from registered CODECs */
 	list_for_each_entry(codec, &codec_list, list) {
 		if (dai_link->codec_of_node) {
 			if (codec->dev->of_node != dai_link->codec_of_node)
@@ -835,28 +821,28 @@
 					dai_link->codec_dai_name)) {
 
 				rtd->codec_dai = codec_dai;
-				goto find_platform;
 			}
 		}
-		dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+
+		if (!rtd->codec_dai) {
+			dev_dbg(card->dev, "CODEC DAI %s not registered\n",
 				dai_link->codec_dai_name);
-
-		goto find_platform;
+			return -EPROBE_DEFER;
+		}
 	}
-	dev_dbg(card->dev, "CODEC %s not registered\n",
-			dai_link->codec_name);
 
-find_platform:
-	/* do we need a platform? */
-	if (rtd->platform)
-		goto out;
+	if (!rtd->codec) {
+		dev_dbg(card->dev, "CODEC %s not registered\n",
+			dai_link->codec_name);
+		return -EPROBE_DEFER;
+	}
 
 	/* if there's no platform we match on the empty platform */
 	platform_name = dai_link->platform_name;
 	if (!platform_name && !dai_link->platform_of_node)
 		platform_name = "snd-soc-dummy";
 
-	/* no, then find one from the set of registered platforms */
+	/* find one from the set of registered platforms */
 	list_for_each_entry(platform, &platform_list, list) {
 		if (dai_link->platform_of_node) {
 			if (platform->dev->of_node !=
@@ -868,20 +854,16 @@
 		}
 
 		rtd->platform = platform;
-		goto out;
 	}
-
-	dev_dbg(card->dev, "platform %s not registered\n",
+	if (!rtd->platform) {
+		dev_dbg(card->dev, "platform %s not registered\n",
 			dai_link->platform_name);
-	return 0;
-
-out:
-	/* mark rtd as complete if we found all 4 of our client devices */
-	if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) {
-		rtd->complete = 1;
-		card->num_rtd++;
+		return -EPROBE_DEFER;
 	}
-	return 1;
+
+	card->num_rtd++;
+
+	return 0;
 }
 
 static void soc_remove_codec(struct snd_soc_codec *codec)
@@ -1068,6 +1050,7 @@
 {
 	int ret = 0;
 	const struct snd_soc_platform_driver *driver = platform->driver;
+	struct snd_soc_dai *dai;
 
 	platform->card = card;
 	platform->dapm.card = card;
@@ -1081,6 +1064,14 @@
 		snd_soc_dapm_new_controls(&platform->dapm,
 			driver->dapm_widgets, driver->num_dapm_widgets);
 
+	/* Create DAPM widgets for each DAI stream */
+	list_for_each_entry(dai, &dai_list, list) {
+		if (dai->dev != platform->dev)
+			continue;
+
+		snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);
+	}
+
 	if (driver->probe) {
 		ret = driver->probe(platform);
 		if (ret < 0) {
@@ -1216,9 +1207,12 @@
 	/* probe the cpu_dai */
 	if (!cpu_dai->probed &&
 			cpu_dai->driver->probe_order == order) {
+		cpu_dai->dapm.card = card;
 		if (!try_module_get(cpu_dai->dev->driver->owner))
 			return -ENODEV;
 
+		snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai);
+
 		if (cpu_dai->driver->probe) {
 			ret = cpu_dai->driver->probe(cpu_dai);
 			if (ret < 0) {
@@ -1332,6 +1326,20 @@
 }
 #endif
 
+static int soc_check_aux_dev(struct snd_soc_card *card, int num)
+{
+	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+	struct snd_soc_codec *codec;
+
+	/* find CODEC from registered CODECs*/
+	list_for_each_entry(codec, &codec_list, list) {
+		if (!strcmp(codec->name, aux_dev->codec_name))
+			return 0;
+	}
+
+	return -EPROBE_DEFER;
+}
+
 static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
 {
 	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
@@ -1352,7 +1360,7 @@
 	}
 	/* codec not found */
 	dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name);
-	goto out;
+	return -EPROBE_DEFER;
 
 found:
 	ret = soc_probe_codec(card, codec);
@@ -1402,7 +1410,7 @@
 	return 0;
 }
 
-static void snd_soc_instantiate_card(struct snd_soc_card *card)
+static int snd_soc_instantiate_card(struct snd_soc_card *card)
 {
 	struct snd_soc_codec *codec;
 	struct snd_soc_codec_conf *codec_conf;
@@ -1410,21 +1418,20 @@
 	struct snd_soc_dai_link *dai_link;
 	int ret, i, order;
 
-	mutex_lock(&card->mutex);
-
-	if (card->instantiated) {
-		mutex_unlock(&card->mutex);
-		return;
-	}
+	mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
 
 	/* bind DAIs */
-	for (i = 0; i < card->num_links; i++)
-		soc_bind_dai_link(card, i);
+	for (i = 0; i < card->num_links; i++) {
+		ret = soc_bind_dai_link(card, i);
+		if (ret != 0)
+			goto base_error;
+	}
 
-	/* bind completed ? */
-	if (card->num_rtd != card->num_links) {
-		mutex_unlock(&card->mutex);
-		return;
+	/* check aux_devs too */
+	for (i = 0; i < card->num_aux_devs; i++) {
+		ret = soc_check_aux_dev(card, i);
+		if (ret != 0)
+			goto base_error;
 	}
 
 	/* initialize the register cache for each available codec */
@@ -1444,10 +1451,8 @@
 			}
 		}
 		ret = snd_soc_init_codec_cache(codec, compress_type);
-		if (ret < 0) {
-			mutex_unlock(&card->mutex);
-			return;
-		}
+		if (ret < 0)
+			goto base_error;
 	}
 
 	/* card bind complete so register a sound card */
@@ -1456,8 +1461,7 @@
 	if (ret < 0) {
 		pr_err("asoc: can't create sound card for card %s: %d\n",
 			card->name, ret);
-		mutex_unlock(&card->mutex);
-		return;
+		goto base_error;
 	}
 	card->snd_card->dev = card->dev;
 
@@ -1597,7 +1601,8 @@
 	card->instantiated = 1;
 	snd_soc_dapm_sync(&card->dapm);
 	mutex_unlock(&card->mutex);
-	return;
+
+	return 0;
 
 probe_aux_dev_err:
 	for (i = 0; i < card->num_aux_devs; i++)
@@ -1612,18 +1617,10 @@
 
 	snd_card_free(card->snd_card);
 
+base_error:
 	mutex_unlock(&card->mutex);
-}
 
-/*
- * Attempt to initialise any uninitialised cards.  Must be called with
- * client_mutex.
- */
-static void snd_soc_instantiate_cards(void)
-{
-	struct snd_soc_card *card;
-	list_for_each_entry(card, &card_list, list)
-		snd_soc_instantiate_card(card);
+	return ret;
 }
 
 /* probes a new socdev */
@@ -2525,6 +2522,87 @@
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
 
 /**
+ * snd_soc_get_volsw_sx - single mixer get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a single mixer control, or a double mixer
+ * control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct soc_mixer_control *mc =
+	    (struct soc_mixer_control *)kcontrol->private_value;
+
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	int max = mc->max;
+	int min = mc->min;
+	int mask = (1 << (fls(min + max) - 1)) - 1;
+
+	ucontrol->value.integer.value[0] =
+	    ((snd_soc_read(codec, reg) >> shift) - min) & mask;
+
+	if (snd_soc_volsw_is_stereo(mc))
+		ucontrol->value.integer.value[1] =
+			((snd_soc_read(codec, reg2) >> rshift) - min) & mask;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
+
+/**
+ * snd_soc_put_volsw_sx - double mixer set callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a double mixer control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct soc_mixer_control *mc =
+	    (struct soc_mixer_control *)kcontrol->private_value;
+
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	int max = mc->max;
+	int min = mc->min;
+	int mask = (1 << (fls(min + max) - 1)) - 1;
+	int err = 0;
+	unsigned short val, val_mask, val2 = 0;
+
+	val_mask = mask << shift;
+	val = (ucontrol->value.integer.value[0] + min) & mask;
+	val = val << shift;
+
+	if (snd_soc_update_bits_locked(codec, reg, val_mask, val))
+			return err;
+
+	if (snd_soc_volsw_is_stereo(mc)) {
+		val_mask = mask << rshift;
+		val2 = (ucontrol->value.integer.value[1] + min) & mask;
+		val2 = val2 << rshift;
+
+		if (snd_soc_update_bits_locked(codec, reg2, val_mask, val2))
+			return err;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx);
+
+/**
  * snd_soc_info_volsw_s8 - signed mixer info callback
  * @kcontrol: mixer control
  * @uinfo: control element information
@@ -2645,99 +2723,6 @@
 }
 EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
 
-/**
- * snd_soc_info_volsw_2r_sx - double with tlv and variable data size
- *  mixer info callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-			struct snd_ctl_elem_info *uinfo)
-{
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
-	int max = mc->max;
-	int min = mc->min;
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 2;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = max-min;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx);
-
-/**
- * snd_soc_get_volsw_2r_sx - double with tlv and variable data size
- *  mixer get callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-			struct snd_ctl_elem_value *ucontrol)
-{
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	unsigned int mask = (1<<mc->shift)-1;
-	int min = mc->min;
-	int val = snd_soc_read(codec, mc->reg) & mask;
-	int valr = snd_soc_read(codec, mc->rreg) & mask;
-
-	ucontrol->value.integer.value[0] = ((val & 0xff)-min) & mask;
-	ucontrol->value.integer.value[1] = ((valr & 0xff)-min) & mask;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx);
-
-/**
- * snd_soc_put_volsw_2r_sx - double with tlv and variable data size
- *  mixer put callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-			struct snd_ctl_elem_value *ucontrol)
-{
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	unsigned int mask = (1<<mc->shift)-1;
-	int min = mc->min;
-	int ret;
-	unsigned int val, valr, oval, ovalr;
-
-	val = ((ucontrol->value.integer.value[0]+min) & 0xff);
-	val &= mask;
-	valr = ((ucontrol->value.integer.value[1]+min) & 0xff);
-	valr &= mask;
-
-	oval = snd_soc_read(codec, mc->reg) & mask;
-	ovalr = snd_soc_read(codec, mc->rreg) & mask;
-
-	ret = 0;
-	if (oval != val) {
-		ret = snd_soc_write(codec, mc->reg, val);
-		if (ret < 0)
-			return ret;
-	}
-	if (ovalr != valr) {
-		ret = snd_soc_write(codec, mc->rreg, valr);
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
-
 int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_info *uinfo)
 {
@@ -3058,7 +3043,7 @@
  */
 int snd_soc_register_card(struct snd_soc_card *card)
 {
-	int i;
+	int i, ret;
 
 	if (!card->name || !card->dev)
 		return -EINVAL;
@@ -3120,15 +3105,13 @@
 	INIT_LIST_HEAD(&card->dapm_dirty);
 	card->instantiated = 0;
 	mutex_init(&card->mutex);
+	mutex_init(&card->dapm_mutex);
 
-	mutex_lock(&client_mutex);
-	list_add(&card->list, &card_list);
-	snd_soc_instantiate_cards();
-	mutex_unlock(&client_mutex);
+	ret = snd_soc_instantiate_card(card);
+	if (ret != 0)
+		soc_cleanup_card_debugfs(card);
 
-	dev_dbg(card->dev, "Registered card '%s'\n", card->name);
-
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_register_card);
 
@@ -3142,9 +3125,6 @@
 {
 	if (card->instantiated)
 		soc_cleanup_card_resources(card);
-	mutex_lock(&client_mutex);
-	list_del(&card->list);
-	mutex_unlock(&client_mutex);
 	dev_dbg(card->dev, "Unregistered card '%s'\n", card->name);
 
 	return 0;
@@ -3235,12 +3215,12 @@
 
 	dai->dev = dev;
 	dai->driver = dai_drv;
+	dai->dapm.dev = dev;
 	if (!dai->driver->ops)
 		dai->driver->ops = &null_dai_ops;
 
 	mutex_lock(&client_mutex);
 	list_add(&dai->list, &dai_list);
-	snd_soc_instantiate_cards();
 	mutex_unlock(&client_mutex);
 
 	pr_debug("Registered DAI '%s'\n", dai->name);
@@ -3311,6 +3291,7 @@
 			dai->id = dai->driver->id;
 		else
 			dai->id = i;
+		dai->dapm.dev = dev;
 		if (!dai->driver->ops)
 			dai->driver->ops = &null_dai_ops;
 
@@ -3321,9 +3302,6 @@
 		pr_debug("Registered DAI '%s'\n", dai->name);
 	}
 
-	mutex_lock(&client_mutex);
-	snd_soc_instantiate_cards();
-	mutex_unlock(&client_mutex);
 	return 0;
 
 err:
@@ -3381,7 +3359,6 @@
 
 	mutex_lock(&client_mutex);
 	list_add(&platform->list, &platform_list);
-	snd_soc_instantiate_cards();
 	mutex_unlock(&client_mutex);
 
 	pr_debug("Registered platform '%s'\n", platform->name);
@@ -3540,7 +3517,6 @@
 
 	mutex_lock(&client_mutex);
 	list_add(&codec->list, &codec_list);
-	snd_soc_instantiate_cards();
 	mutex_unlock(&client_mutex);
 
 	pr_debug("Registered codec '%s'\n", codec->name);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 5cbd2d76..589e16b 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -206,7 +206,23 @@
 	return -1;
 }
 
-static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
+static inline void soc_widget_lock(struct snd_soc_dapm_widget *w)
+{
+	if (w->codec && !w->codec->using_regmap)
+		mutex_lock(&w->codec->mutex);
+	else if (w->platform)
+		mutex_lock(&w->platform->mutex);
+}
+
+static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w)
+{
+	if (w->codec && !w->codec->using_regmap)
+		mutex_unlock(&w->codec->mutex);
+	else if (w->platform)
+		mutex_unlock(&w->platform->mutex);
+}
+
+static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
 	unsigned short reg, unsigned int mask, unsigned int value)
 {
 	bool change;
@@ -219,18 +235,24 @@
 		if (ret != 0)
 			return ret;
 	} else {
+		soc_widget_lock(w);
 		ret = soc_widget_read(w, reg);
-		if (ret < 0)
+		if (ret < 0) {
+			soc_widget_unlock(w);
 			return ret;
+		}
 
 		old = ret;
 		new = (old & ~mask) | (value & mask);
 		change = old != new;
 		if (change) {
 			ret = soc_widget_write(w, reg, new);
-			if (ret < 0)
+			if (ret < 0) {
+				soc_widget_unlock(w);
 				return ret;
+			}
 		}
+		soc_widget_unlock(w);
 	}
 
 	return change;
@@ -847,7 +869,7 @@
 	else
 		val = w->off_val;
 
-	soc_widget_update_bits(w, -(w->reg + 1),
+	soc_widget_update_bits_locked(w, -(w->reg + 1),
 			    w->mask << w->shift, val << w->shift);
 
 	return 0;
@@ -861,9 +883,9 @@
 		   struct snd_kcontrol *kcontrol, int event)
 {
 	if (SND_SOC_DAPM_EVENT_ON(event))
-		return regulator_enable(w->priv);
+		return regulator_enable(w->regulator);
 	else
-		return regulator_disable_deferred(w->priv, w->shift);
+		return regulator_disable_deferred(w->regulator, w->shift);
 }
 EXPORT_SYMBOL_GPL(dapm_regulator_event);
 
@@ -1105,7 +1127,7 @@
 			"pop test : Applying 0x%x/0x%x to %x in %dms\n",
 			value, mask, reg, card->pop_time);
 		pop_wait(card->pop_time);
-		soc_widget_update_bits(w, reg, mask, value);
+		soc_widget_update_bits_locked(w, reg, mask, value);
 	}
 
 	list_for_each_entry(w, pending, power_list) {
@@ -1235,7 +1257,7 @@
 			       w->name, ret);
 	}
 
-	ret = snd_soc_update_bits(w->codec, update->reg, update->mask,
+	ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
 				  update->val);
 	if (ret < 0)
 		pr_err("%s DAPM update failed: %d\n", w->name, ret);
@@ -1419,12 +1441,10 @@
 	trace_snd_soc_dapm_start(card);
 
 	list_for_each_entry(d, &card->dapm_list, list) {
-		if (d->n_widgets || d->codec == NULL) {
-			if (d->idle_bias_off)
-				d->target_bias_level = SND_SOC_BIAS_OFF;
-			else
-				d->target_bias_level = SND_SOC_BIAS_STANDBY;
-		}
+		if (d->idle_bias_off)
+			d->target_bias_level = SND_SOC_BIAS_OFF;
+		else
+			d->target_bias_level = SND_SOC_BIAS_STANDBY;
 	}
 
 	dapm_reset(card);
@@ -1469,32 +1489,6 @@
 
 	}
 
-	/* If there are no DAPM widgets then try to figure out power from the
-	 * event type.
-	 */
-	if (!dapm->n_widgets) {
-		switch (event) {
-		case SND_SOC_DAPM_STREAM_START:
-		case SND_SOC_DAPM_STREAM_RESUME:
-			dapm->target_bias_level = SND_SOC_BIAS_ON;
-			break;
-		case SND_SOC_DAPM_STREAM_STOP:
-			if (dapm->codec && dapm->codec->active)
-				dapm->target_bias_level = SND_SOC_BIAS_ON;
-			else
-				dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
-			break;
-		case SND_SOC_DAPM_STREAM_SUSPEND:
-			dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
-			break;
-		case SND_SOC_DAPM_STREAM_NOP:
-			dapm->target_bias_level = dapm->bias_level;
-			break;
-		default:
-			break;
-		}
-	}
-
 	/* Force all contexts in the card to the same bias state if
 	 * they're not ground referenced.
 	 */
@@ -1707,7 +1701,7 @@
 #endif
 
 /* test and update the power status of a mux widget */
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
 				 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
 {
 	struct snd_soc_dapm_path *path;
@@ -1746,10 +1740,22 @@
 
 	return 0;
 }
+
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+		struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
+{
+	struct snd_soc_card *card = widget->dapm->card;
+	int ret;
+
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+	mutex_unlock(&card->dapm_mutex);
+	return ret;
+}
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
 
 /* test and update the power status of a mixer or switch widget */
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
 				   struct snd_kcontrol *kcontrol, int connect)
 {
 	struct snd_soc_dapm_path *path;
@@ -1778,6 +1784,18 @@
 
 	return 0;
 }
+
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+				struct snd_kcontrol *kcontrol, int connect)
+{
+	struct snd_soc_card *card = widget->dapm->card;
+	int ret;
+
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
+	mutex_unlock(&card->dapm_mutex);
+	return ret;
+}
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
 
 /* show dapm widget status in sys fs */
@@ -1937,6 +1955,8 @@
  */
 int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
 {
+	int ret;
+
 	/*
 	 * Suppress early reports (eg, jacks syncing their state) to avoid
 	 * silly DAPM runs during card startup.
@@ -1944,7 +1964,10 @@
 	if (!dapm->card || !dapm->card->instantiated)
 		return 0;
 
-	return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+	mutex_unlock(&dapm->card->dapm_mutex);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
 
@@ -2110,6 +2133,7 @@
 {
 	int i, ret;
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 	for (i = 0; i < num; i++) {
 		ret = snd_soc_dapm_add_route(dapm, route);
 		if (ret < 0) {
@@ -2119,6 +2143,7 @@
 		}
 		route++;
 	}
+	mutex_unlock(&dapm->card->dapm_mutex);
 
 	return 0;
 }
@@ -2191,12 +2216,14 @@
 	int i, err;
 	int ret = 0;
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 	for (i = 0; i < num; i++) {
 		err = snd_soc_dapm_weak_route(dapm, route);
 		if (err)
 			ret = err;
 		route++;
 	}
+	mutex_unlock(&dapm->card->dapm_mutex);
 
 	return ret;
 }
@@ -2215,6 +2242,8 @@
 	struct snd_soc_dapm_widget *w;
 	unsigned int val;
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+
 	list_for_each_entry(w, &dapm->card->widgets, list)
 	{
 		if (w->new)
@@ -2224,8 +2253,10 @@
 			w->kcontrols = kzalloc(w->num_kcontrols *
 						sizeof(struct snd_kcontrol *),
 						GFP_KERNEL);
-			if (!w->kcontrols)
+			if (!w->kcontrols) {
+				mutex_unlock(&dapm->card->dapm_mutex);
 				return -ENOMEM;
+			}
 		}
 
 		switch(w->id) {
@@ -2265,6 +2296,7 @@
 	}
 
 	dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+	mutex_unlock(&dapm->card->dapm_mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -2324,6 +2356,7 @@
 	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_card *card = codec->card;
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int reg = mc->reg;
@@ -2350,7 +2383,7 @@
 		/* old connection must be powered down */
 		connect = invert ? 1 : 0;
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	change = snd_soc_test_bits(widget->codec, reg, mask, val);
 	if (change) {
@@ -2366,13 +2399,13 @@
 			update.val = val;
 			widget->dapm->update = &update;
 
-			snd_soc_dapm_mixer_update_power(widget, kcontrol, connect);
+			soc_dapm_mixer_update_power(widget, kcontrol, connect);
 
 			widget->dapm->update = NULL;
 		}
 	}
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
@@ -2421,6 +2454,7 @@
 	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_card *card = codec->card;
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val, mux, change;
 	unsigned int mask, bitmask;
@@ -2441,7 +2475,7 @@
 		mask |= (bitmask - 1) << e->shift_r;
 	}
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
 	if (change) {
@@ -2457,13 +2491,13 @@
 			update.val = val;
 			widget->dapm->update = &update;
 
-			snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+			soc_dapm_mux_update_power(widget, kcontrol, mux, e);
 
 			widget->dapm->update = NULL;
 		}
 	}
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
@@ -2500,6 +2534,7 @@
 	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_card *card = codec->card;
 	struct soc_enum *e =
 		(struct soc_enum *)kcontrol->private_value;
 	int change;
@@ -2509,7 +2544,7 @@
 	if (ucontrol->value.enumerated.item[0] >= e->max)
 		return -EINVAL;
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	change = widget->value != ucontrol->value.enumerated.item[0];
 	if (change) {
@@ -2518,11 +2553,11 @@
 
 			widget->value = ucontrol->value.enumerated.item[0];
 
-			snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
+			soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
 		}
 	}
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
@@ -2587,6 +2622,7 @@
 	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
 	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_card *card = codec->card;
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val, mux, change;
 	unsigned int mask;
@@ -2605,7 +2641,7 @@
 		mask |= e->mask << e->shift_r;
 	}
 
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
 	if (change) {
@@ -2621,13 +2657,13 @@
 			update.val = val;
 			widget->dapm->update = &update;
 
-			snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+			soc_dapm_mux_update_power(widget, kcontrol, mux, e);
 
 			widget->dapm->update = NULL;
 		}
 	}
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
@@ -2664,12 +2700,12 @@
 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 	const char *pin = (const char *)kcontrol->private_value;
 
-	mutex_lock(&card->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	ucontrol->value.integer.value[0] =
 		snd_soc_dapm_get_pin_status(&card->dapm, pin);
 
-	mutex_unlock(&card->mutex);
+	mutex_unlock(&card->dapm_mutex);
 
 	return 0;
 }
@@ -2687,17 +2723,16 @@
 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 	const char *pin = (const char *)kcontrol->private_value;
 
-	mutex_lock(&card->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
 	if (ucontrol->value.integer.value[0])
 		snd_soc_dapm_enable_pin(&card->dapm, pin);
 	else
 		snd_soc_dapm_disable_pin(&card->dapm, pin);
 
+	mutex_unlock(&card->dapm_mutex);
+
 	snd_soc_dapm_sync(&card->dapm);
-
-	mutex_unlock(&card->mutex);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
@@ -2715,9 +2750,9 @@
 
 	switch (w->id) {
 	case snd_soc_dapm_regulator_supply:
-		w->priv = devm_regulator_get(dapm->dev, w->name);
-		if (IS_ERR(w->priv)) {
-			ret = PTR_ERR(w->priv);
+		w->regulator = devm_regulator_get(dapm->dev, w->name);
+		if (IS_ERR(w->regulator)) {
+			ret = PTR_ERR(w->regulator);
 			dev_err(dapm->dev, "Failed to request %s: %d\n",
 				w->name, ret);
 			return NULL;
@@ -2815,6 +2850,7 @@
 	struct snd_soc_dapm_widget *w;
 	int i;
 
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 	for (i = 0; i < num; i++) {
 		w = snd_soc_dapm_new_control(dapm, widget);
 		if (!w) {
@@ -2825,6 +2861,7 @@
 		}
 		widget++;
 	}
+	mutex_unlock(&dapm->card->dapm_mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
@@ -2932,37 +2969,61 @@
 	return 0;
 }
 
-static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
-				  int stream, struct snd_soc_dai *dai,
-				  int event)
+static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+	int event)
 {
-	struct snd_soc_dapm_widget *w;
 
-	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-		w = dai->playback_widget;
-	else
-		w = dai->capture_widget;
+	struct snd_soc_dapm_widget *w_cpu, *w_codec;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
-	if (!w)
-		return;
-
-	dapm_mark_dirty(w, "stream event");
-
-	switch (event) {
-	case SND_SOC_DAPM_STREAM_START:
-		w->active = 1;
-		break;
-	case SND_SOC_DAPM_STREAM_STOP:
-		w->active = 0;
-		break;
-	case SND_SOC_DAPM_STREAM_SUSPEND:
-	case SND_SOC_DAPM_STREAM_RESUME:
-	case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
-	case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
-		break;
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		w_cpu = cpu_dai->playback_widget;
+		w_codec = codec_dai->playback_widget;
+	} else {
+		w_cpu = cpu_dai->capture_widget;
+		w_codec = codec_dai->capture_widget;
 	}
 
-	dapm_power_widgets(dapm, event);
+	if (w_cpu) {
+
+		dapm_mark_dirty(w_cpu, "stream event");
+
+		switch (event) {
+		case SND_SOC_DAPM_STREAM_START:
+			w_cpu->active = 1;
+			break;
+		case SND_SOC_DAPM_STREAM_STOP:
+			w_cpu->active = 0;
+			break;
+		case SND_SOC_DAPM_STREAM_SUSPEND:
+		case SND_SOC_DAPM_STREAM_RESUME:
+		case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
+		case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
+			break;
+		}
+	}
+
+	if (w_codec) {
+
+		dapm_mark_dirty(w_codec, "stream event");
+
+		switch (event) {
+		case SND_SOC_DAPM_STREAM_START:
+			w_codec->active = 1;
+			break;
+		case SND_SOC_DAPM_STREAM_STOP:
+			w_codec->active = 0;
+			break;
+		case SND_SOC_DAPM_STREAM_SUSPEND:
+		case SND_SOC_DAPM_STREAM_RESUME:
+		case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
+		case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
+			break;
+		}
+	}
+
+	dapm_power_widgets(&rtd->card->dapm, event);
 }
 
 /**
@@ -2976,15 +3037,14 @@
  *
  * Returns 0 for success else error.
  */
-int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
-			      struct snd_soc_dai *dai, int event)
+void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+			      int event)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_card *card = rtd->card;
 
-	mutex_lock(&codec->mutex);
-	soc_dapm_stream_event(&codec->dapm, stream, dai, event);
-	mutex_unlock(&codec->mutex);
-	return 0;
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	soc_dapm_stream_event(rtd, stream, event);
+	mutex_unlock(&card->dapm_mutex);
 }
 
 /**
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index ee4353f..7f8b3b7 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -36,6 +36,7 @@
 int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
 		     struct snd_soc_jack *jack)
 {
+	mutex_init(&jack->mutex);
 	jack->codec = codec;
 	INIT_LIST_HEAD(&jack->pins);
 	INIT_LIST_HEAD(&jack->jack_zones);
@@ -75,7 +76,7 @@
 	codec = jack->codec;
 	dapm =  &codec->dapm;
 
-	mutex_lock(&codec->mutex);
+	mutex_lock(&jack->mutex);
 
 	oldstatus = jack->status;
 
@@ -109,7 +110,7 @@
 	snd_jack_report(jack->jack, jack->status);
 
 out:
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&jack->mutex);
 }
 EXPORT_SYMBOL_GPL(snd_soc_jack_report);
 
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 0ad8dca..26a60b4 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -308,7 +308,7 @@
 	if (codec_dai->pop_wait == 1) {
 		codec_dai->pop_wait = 0;
 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
-					  codec_dai, SND_SOC_DAPM_STREAM_STOP);
+					  SND_SOC_DAPM_STREAM_STOP);
 	}
 
 	mutex_unlock(&rtd->pcm_mutex);
@@ -373,7 +373,6 @@
 			/* powered down playback stream now */
 			snd_soc_dapm_stream_event(rtd,
 						  SNDRV_PCM_STREAM_PLAYBACK,
-						  codec_dai,
 						  SND_SOC_DAPM_STREAM_STOP);
 		} else {
 			/* start delayed pop wq here for playback streams */
@@ -384,7 +383,7 @@
 	} else {
 		/* capture streams can be powered down now */
 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
-					  codec_dai, SND_SOC_DAPM_STREAM_STOP);
+					  SND_SOC_DAPM_STREAM_STOP);
 	}
 
 	mutex_unlock(&rtd->pcm_mutex);
@@ -453,8 +452,8 @@
 		cancel_delayed_work(&rtd->delayed_work);
 	}
 
-	snd_soc_dapm_stream_event(rtd, substream->stream, codec_dai,
-				  SND_SOC_DAPM_STREAM_START);
+	snd_soc_dapm_stream_event(rtd, substream->stream,
+			SND_SOC_DAPM_STREAM_START);
 
 	snd_soc_dai_digital_mute(codec_dai, 0);
 
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index ce1b773..556cac2 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -4,20 +4,29 @@
 	help
 	  Say Y or M here if you want support for SoC audio on Tegra.
 
-config SND_SOC_TEGRA_I2S
+config SND_SOC_TEGRA20_DAS
 	tristate
-	depends on SND_SOC_TEGRA
+	depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+	help
+	  Say Y or M if you want to add support for the Tegra20 DAS module.
+	  You will also need to select the individual machine drivers to
+	  support below.
+
+config SND_SOC_TEGRA20_I2S
+	tristate
+	depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+	select SND_SOC_TEGRA20_DAS
 	help
 	  Say Y or M if you want to add support for codecs attached to the
-	  Tegra I2S interface. You will also need to select the individual
+	  Tegra20 I2S interface. You will also need to select the individual
 	  machine drivers to support below.
 
-config SND_SOC_TEGRA_SPDIF
+config SND_SOC_TEGRA20_SPDIF
 	tristate
-	depends on SND_SOC_TEGRA
+	depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
 	default m
 	help
-	  Say Y or M if you want to add support for the SPDIF interface.
+	  Say Y or M if you want to add support for the Tegra20 SPDIF interface.
 	  You will also need to select the individual machine drivers to support
 	  below.
 
@@ -32,7 +41,7 @@
 	tristate "SoC Audio support for Tegra boards using a WM8903 codec"
 	depends on SND_SOC_TEGRA && I2C
 	depends on MACH_HAS_SND_SOC_TEGRA_WM8903
-	select SND_SOC_TEGRA_I2S
+	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
 	select SND_SOC_WM8903
 	help
 	  Say Y or M here if you want to add support for SoC audio on Tegra
@@ -42,17 +51,17 @@
 config SND_SOC_TEGRA_TRIMSLICE
 	tristate "SoC Audio support for TrimSlice board"
 	depends on SND_SOC_TEGRA && MACH_TRIMSLICE && I2C
-	select SND_SOC_TEGRA_I2S
+	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
 	select SND_SOC_TLV320AIC23
 	help
 	  Say Y or M here if you want to add support for SoC audio on the
 	  TrimSlice platform.
 
 config SND_SOC_TEGRA_ALC5632
-       tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
-       depends on SND_SOC_TEGRA && I2C
-       select SND_SOC_TEGRA_I2S
-       select SND_SOC_ALC5632
-       help
-         Say Y or M here if you want to add support for SoC audio on the
-         Toshiba AC100 netbook.
+	tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
+	depends on SND_SOC_TEGRA && I2C
+	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+	select SND_SOC_ALC5632
+	help
+	  Say Y or M here if you want to add support for SoC audio on the
+	  Toshiba AC100 netbook.
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 8e584b8..4726b90 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -1,15 +1,15 @@
 # Tegra platform Support
-snd-soc-tegra-das-objs := tegra_das.o
 snd-soc-tegra-pcm-objs := tegra_pcm.o
-snd-soc-tegra-i2s-objs := tegra_i2s.o
-snd-soc-tegra-spdif-objs := tegra_spdif.o
 snd-soc-tegra-utils-objs += tegra_asoc_utils.o
+snd-soc-tegra20-das-objs := tegra20_das.o
+snd-soc-tegra20-i2s-objs := tegra20_i2s.o
+snd-soc-tegra20-spdif-objs := tegra20_spdif.o
 
-obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
-obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-das.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
-obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o
-obj-$(CONFIG_SND_SOC_TEGRA_SPDIF) += snd-soc-tegra-spdif.o
+obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
+obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o
+obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
 
 # Tegra machine Support
 snd-soc-tegra-wm8903-objs := tegra_wm8903.o
diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c
new file mode 100644
index 0000000..812696d
--- /dev/null
+++ b/sound/soc/tegra/tegra20_das.c
@@ -0,0 +1,260 @@
+/*
+ * tegra20_das.c - Tegra20 DAS driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include "tegra20_das.h"
+
+#define DRV_NAME "tegra20-das"
+
+static struct tegra20_das *das;
+
+static inline void tegra20_das_write(u32 reg, u32 val)
+{
+	__raw_writel(val, das->regs + reg);
+}
+
+static inline u32 tegra20_das_read(u32 reg)
+{
+	return __raw_readl(das->regs + reg);
+}
+
+int tegra20_das_connect_dap_to_dac(int dap, int dac)
+{
+	u32 addr;
+	u32 reg;
+
+	if (!das)
+		return -ENODEV;
+
+	addr = TEGRA20_DAS_DAP_CTRL_SEL +
+		(dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
+	reg = dac << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
+
+	tegra20_das_write(addr, reg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dac);
+
+int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master,
+				   int sdata1rx, int sdata2rx)
+{
+	u32 addr;
+	u32 reg;
+
+	if (!das)
+		return -ENODEV;
+
+	addr = TEGRA20_DAS_DAP_CTRL_SEL +
+		(dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
+	reg = otherdap << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P |
+		!!sdata2rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P |
+		!!sdata1rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P |
+		!!master << TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P;
+
+	tegra20_das_write(addr, reg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dap);
+
+int tegra20_das_connect_dac_to_dap(int dac, int dap)
+{
+	u32 addr;
+	u32 reg;
+
+	if (!das)
+		return -ENODEV;
+
+	addr = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL +
+		(dac * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
+	reg = dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
+		dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
+		dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
+
+	tegra20_das_write(addr, reg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra20_das_connect_dac_to_dap);
+
+#ifdef CONFIG_DEBUG_FS
+static int tegra20_das_show(struct seq_file *s, void *unused)
+{
+	int i;
+	u32 addr;
+	u32 reg;
+
+	for (i = 0; i < TEGRA20_DAS_DAP_CTRL_SEL_COUNT; i++) {
+		addr = TEGRA20_DAS_DAP_CTRL_SEL +
+			(i * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
+		reg = tegra20_das_read(addr);
+		seq_printf(s, "TEGRA20_DAS_DAP_CTRL_SEL[%d] = %08x\n", i, reg);
+	}
+
+	for (i = 0; i < TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT; i++) {
+		addr = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL +
+			(i * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
+		reg = tegra20_das_read(addr);
+		seq_printf(s, "TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL[%d] = %08x\n",
+			   i, reg);
+	}
+
+	return 0;
+}
+
+static int tegra20_das_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, tegra20_das_show, inode->i_private);
+}
+
+static const struct file_operations tegra20_das_debug_fops = {
+	.open    = tegra20_das_debug_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = single_release,
+};
+
+static void tegra20_das_debug_add(struct tegra20_das *das)
+{
+	das->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
+					 snd_soc_debugfs_root, das,
+					 &tegra20_das_debug_fops);
+}
+
+static void tegra20_das_debug_remove(struct tegra20_das *das)
+{
+	if (das->debug)
+		debugfs_remove(das->debug);
+}
+#else
+static inline void tegra20_das_debug_add(struct tegra20_das *das)
+{
+}
+
+static inline void tegra20_das_debug_remove(struct tegra20_das *das)
+{
+}
+#endif
+
+static int __devinit tegra20_das_probe(struct platform_device *pdev)
+{
+	struct resource *res, *region;
+	int ret = 0;
+
+	if (das)
+		return -ENODEV;
+
+	das = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_das), GFP_KERNEL);
+	if (!das) {
+		dev_err(&pdev->dev, "Can't allocate tegra20_das\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	das->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "No memory resource\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	region = devm_request_mem_region(&pdev->dev, res->start,
+					 resource_size(res), pdev->name);
+	if (!region) {
+		dev_err(&pdev->dev, "Memory region already claimed\n");
+		ret = -EBUSY;
+		goto err;
+	}
+
+	das->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!das->regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_1,
+					     TEGRA20_DAS_DAP_SEL_DAC1);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
+		goto err;
+	}
+	ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_1,
+					     TEGRA20_DAS_DAC_SEL_DAP1);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
+		goto err;
+	}
+
+	tegra20_das_debug_add(das);
+
+	platform_set_drvdata(pdev, das);
+
+	return 0;
+
+err:
+	das = NULL;
+	return ret;
+}
+
+static int __devexit tegra20_das_remove(struct platform_device *pdev)
+{
+	if (!das)
+		return -ENODEV;
+
+	tegra20_das_debug_remove(das);
+
+	das = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id tegra20_das_of_match[] __devinitconst = {
+	{ .compatible = "nvidia,tegra20-das", },
+	{},
+};
+
+static struct platform_driver tegra20_das_driver = {
+	.probe = tegra20_das_probe,
+	.remove = __devexit_p(tegra20_das_remove),
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = tegra20_das_of_match,
+	},
+};
+module_platform_driver(tegra20_das_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 DAS driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra20_das_of_match);
diff --git a/sound/soc/tegra/tegra20_das.h b/sound/soc/tegra/tegra20_das.h
new file mode 100644
index 0000000..ade4fe0
--- /dev/null
+++ b/sound/soc/tegra/tegra20_das.h
@@ -0,0 +1,135 @@
+/*
+ * tegra20_das.h - Definitions for Tegra20 DAS driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TEGRA20_DAS_H__
+#define __TEGRA20_DAS_H__
+
+/* Register TEGRA20_DAS_DAP_CTRL_SEL */
+#define TEGRA20_DAS_DAP_CTRL_SEL			0x00
+#define TEGRA20_DAS_DAP_CTRL_SEL_COUNT			5
+#define TEGRA20_DAS_DAP_CTRL_SEL_STRIDE			4
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P		31
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S		1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P	30
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S	1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P	29
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S	1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P		0
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S		5
+
+/* Values for field TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
+#define TEGRA20_DAS_DAP_SEL_DAC1	0
+#define TEGRA20_DAS_DAP_SEL_DAC2	1
+#define TEGRA20_DAS_DAP_SEL_DAC3	2
+#define TEGRA20_DAS_DAP_SEL_DAP1	16
+#define TEGRA20_DAS_DAP_SEL_DAP2	17
+#define TEGRA20_DAS_DAP_SEL_DAP3	18
+#define TEGRA20_DAS_DAP_SEL_DAP4	19
+#define TEGRA20_DAS_DAP_SEL_DAP5	20
+
+/* Register TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL */
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL			0x40
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT		3
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE		4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P	28
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S	4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P	24
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S	4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P	0
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S	4
+
+/*
+ * Values for:
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
+ */
+#define TEGRA20_DAS_DAC_SEL_DAP1	0
+#define TEGRA20_DAS_DAC_SEL_DAP2	1
+#define TEGRA20_DAS_DAC_SEL_DAP3	2
+#define TEGRA20_DAS_DAC_SEL_DAP4	3
+#define TEGRA20_DAS_DAC_SEL_DAP5	4
+
+/*
+ * Names/IDs of the DACs/DAPs.
+ */
+
+#define TEGRA20_DAS_DAP_ID_1 0
+#define TEGRA20_DAS_DAP_ID_2 1
+#define TEGRA20_DAS_DAP_ID_3 2
+#define TEGRA20_DAS_DAP_ID_4 3
+#define TEGRA20_DAS_DAP_ID_5 4
+
+#define TEGRA20_DAS_DAC_ID_1 0
+#define TEGRA20_DAS_DAC_ID_2 1
+#define TEGRA20_DAS_DAC_ID_3 2
+
+struct tegra20_das {
+	struct device *dev;
+	void __iomem *regs;
+	struct dentry *debug;
+};
+
+/*
+ * Terminology:
+ * DAS: Digital audio switch (HW module controlled by this driver)
+ * DAP: Digital audio port (port/pins on Tegra device)
+ * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
+ *
+ * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
+ * DAC, or another DAP. When DAPs are connected, one must be the master and
+ * one the slave. Each DAC allows selection of a specific DAP for input, to
+ * cater for the case where N DAPs are connected to 1 DAC for broadcast
+ * output.
+ *
+ * This driver is dumb; no attempt is made to ensure that a valid routing
+ * configuration is programmed.
+ */
+
+/*
+ * Connect a DAP to to a DAC
+ * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_*
+ * dac_sel: DAC to connect to: TEGRA20_DAS_DAP_SEL_DAC*
+ */
+extern int tegra20_das_connect_dap_to_dac(int dap_id, int dac_sel);
+
+/*
+ * Connect a DAP to to another DAP
+ * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_*
+ * other_dap_sel: DAP to connect to: TEGRA20_DAS_DAP_SEL_DAP*
+ * master: Is this DAP the master (1) or slave (0)
+ * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0)
+ * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0)
+ */
+extern int tegra20_das_connect_dap_to_dap(int dap_id, int other_dap_sel,
+					  int master, int sdata1rx,
+					  int sdata2rx);
+
+/*
+ * Connect a DAC's input to a DAP
+ * (DAC outputs are selected by the DAP)
+ * dac_id: DAC ID to connect: TEGRA20_DAS_DAC_ID_*
+ * dap_sel: DAP to receive input from: TEGRA20_DAS_DAC_SEL_DAP*
+ */
+extern int tegra20_das_connect_dac_to_dap(int dac_id, int dap_sel);
+
+#endif
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
new file mode 100644
index 0000000..9427f36
--- /dev/null
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -0,0 +1,457 @@
+/*
+ * tegra20_i2s.c - Tegra20 I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra20_i2s.h"
+
+#define DRV_NAME "tegra20-i2s"
+
+static inline void tegra20_i2s_write(struct tegra20_i2s *i2s, u32 reg, u32 val)
+{
+	__raw_writel(val, i2s->regs + reg);
+}
+
+static inline u32 tegra20_i2s_read(struct tegra20_i2s *i2s, u32 reg)
+{
+	return __raw_readl(i2s->regs + reg);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int tegra20_i2s_show(struct seq_file *s, void *unused)
+{
+#define REG(r) { r, #r }
+	static const struct {
+		int offset;
+		const char *name;
+	} regs[] = {
+		REG(TEGRA20_I2S_CTRL),
+		REG(TEGRA20_I2S_STATUS),
+		REG(TEGRA20_I2S_TIMING),
+		REG(TEGRA20_I2S_FIFO_SCR),
+		REG(TEGRA20_I2S_PCM_CTRL),
+		REG(TEGRA20_I2S_NW_CTRL),
+		REG(TEGRA20_I2S_TDM_CTRL),
+		REG(TEGRA20_I2S_TDM_TX_RX_CTRL),
+	};
+#undef REG
+
+	struct tegra20_i2s *i2s = s->private;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++) {
+		u32 val = tegra20_i2s_read(i2s, regs[i].offset);
+		seq_printf(s, "%s = %08x\n", regs[i].name, val);
+	}
+
+	return 0;
+}
+
+static int tegra20_i2s_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, tegra20_i2s_show, inode->i_private);
+}
+
+static const struct file_operations tegra20_i2s_debug_fops = {
+	.open    = tegra20_i2s_debug_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = single_release,
+};
+
+static void tegra20_i2s_debug_add(struct tegra20_i2s *i2s)
+{
+	i2s->debug = debugfs_create_file(i2s->dai.name, S_IRUGO,
+					 snd_soc_debugfs_root, i2s,
+					 &tegra20_i2s_debug_fops);
+}
+
+static void tegra20_i2s_debug_remove(struct tegra20_i2s *i2s)
+{
+	if (i2s->debug)
+		debugfs_remove(i2s->debug);
+}
+#else
+static inline void tegra20_i2s_debug_add(struct tegra20_i2s *i2s, int id)
+{
+}
+
+static inline void tegra20_i2s_debug_remove(struct tegra20_i2s *i2s)
+{
+}
+#endif
+
+static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
+				unsigned int fmt)
+{
+	struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_MASTER_ENABLE;
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	i2s->reg_ctrl &= ~(TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
+			   TEGRA20_I2S_CTRL_LRCK_MASK);
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct device *dev = substream->pcm->card->dev;
+	struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	u32 reg;
+	int ret, sample_size, srate, i2sclock, bitcnt;
+
+	i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_16;
+		sample_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_24;
+		sample_size = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_32;
+		sample_size = 32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	srate = params_rate(params);
+
+	/* Final "* 2" required by Tegra hardware */
+	i2sclock = srate * params_channels(params) * sample_size * 2;
+
+	ret = clk_set_rate(i2s->clk_i2s, i2sclock);
+	if (ret) {
+		dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
+		return ret;
+	}
+
+	bitcnt = (i2sclock / (2 * srate)) - 1;
+	if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
+		return -EINVAL;
+	reg = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
+
+	if (i2sclock % (2 * srate))
+		reg |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
+
+	clk_enable(i2s->clk_i2s);
+
+	tegra20_i2s_write(i2s, TEGRA20_I2S_TIMING, reg);
+
+	tegra20_i2s_write(i2s, TEGRA20_I2S_FIFO_SCR,
+		TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
+		TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
+
+	clk_disable(i2s->clk_i2s);
+
+	return 0;
+}
+
+static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s)
+{
+	i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO1_ENABLE;
+	tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s)
+{
+	i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO1_ENABLE;
+	tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s)
+{
+	i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO2_ENABLE;
+	tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s)
+{
+	i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO2_ENABLE;
+	tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
+{
+	struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		clk_enable(i2s->clk_i2s);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			tegra20_i2s_start_playback(i2s);
+		else
+			tegra20_i2s_start_capture(i2s);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			tegra20_i2s_stop_playback(i2s);
+		else
+			tegra20_i2s_stop_capture(i2s);
+		clk_disable(i2s->clk_i2s);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra20_i2s_probe(struct snd_soc_dai *dai)
+{
+	struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	dai->capture_dma_data = &i2s->capture_dma_data;
+	dai->playback_dma_data = &i2s->playback_dma_data;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
+	.set_fmt	= tegra20_i2s_set_fmt,
+	.hw_params	= tegra20_i2s_hw_params,
+	.trigger	= tegra20_i2s_trigger,
+};
+
+static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
+	.probe = tegra20_i2s_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &tegra20_i2s_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
+{
+	struct tegra20_i2s *i2s;
+	struct resource *mem, *memregion, *dmareq;
+	u32 of_dma[2];
+	u32 dma_ch;
+	int ret;
+
+	i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_i2s), GFP_KERNEL);
+	if (!i2s) {
+		dev_err(&pdev->dev, "Can't allocate tegra20_i2s\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	dev_set_drvdata(&pdev->dev, i2s);
+
+	i2s->dai = tegra20_i2s_dai_template;
+	i2s->dai.name = dev_name(&pdev->dev);
+
+	i2s->clk_i2s = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(i2s->clk_i2s)) {
+		dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
+		ret = PTR_ERR(i2s->clk_i2s);
+		goto err;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "No memory resource\n");
+		ret = -ENODEV;
+		goto err_clk_put;
+	}
+
+	dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!dmareq) {
+		if (of_property_read_u32_array(pdev->dev.of_node,
+					"nvidia,dma-request-selector",
+					of_dma, 2) < 0) {
+			dev_err(&pdev->dev, "No DMA resource\n");
+			ret = -ENODEV;
+			goto err_clk_put;
+		}
+		dma_ch = of_dma[1];
+	} else {
+		dma_ch = dmareq->start;
+	}
+
+	memregion = devm_request_mem_region(&pdev->dev, mem->start,
+					    resource_size(mem), DRV_NAME);
+	if (!memregion) {
+		dev_err(&pdev->dev, "Memory region already claimed\n");
+		ret = -EBUSY;
+		goto err_clk_put;
+	}
+
+	i2s->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+	if (!i2s->regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENOMEM;
+		goto err_clk_put;
+	}
+
+	i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
+	i2s->capture_dma_data.wrap = 4;
+	i2s->capture_dma_data.width = 32;
+	i2s->capture_dma_data.req_sel = dma_ch;
+
+	i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
+	i2s->playback_dma_data.wrap = 4;
+	i2s->playback_dma_data.width = 32;
+	i2s->playback_dma_data.req_sel = dma_ch;
+
+	i2s->reg_ctrl = TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
+
+	ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+		ret = -ENOMEM;
+		goto err_clk_put;
+	}
+
+	ret = tegra_pcm_platform_register(&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+		goto err_unregister_dai;
+	}
+
+	tegra20_i2s_debug_add(i2s);
+
+	return 0;
+
+err_unregister_dai:
+	snd_soc_unregister_dai(&pdev->dev);
+err_clk_put:
+	clk_put(i2s->clk_i2s);
+err:
+	return ret;
+}
+
+static int __devexit tegra20_i2s_platform_remove(struct platform_device *pdev)
+{
+	struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev);
+
+	tegra_pcm_platform_unregister(&pdev->dev);
+	snd_soc_unregister_dai(&pdev->dev);
+
+	tegra20_i2s_debug_remove(i2s);
+
+	clk_put(i2s->clk_i2s);
+
+	return 0;
+}
+
+static const struct of_device_id tegra20_i2s_of_match[] __devinitconst = {
+	{ .compatible = "nvidia,tegra20-i2s", },
+	{},
+};
+
+static struct platform_driver tegra20_i2s_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = tegra20_i2s_of_match,
+	},
+	.probe = tegra20_i2s_platform_probe,
+	.remove = __devexit_p(tegra20_i2s_platform_remove),
+};
+module_platform_driver(tegra20_i2s_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 I2S ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra20_i2s_of_match);
diff --git a/sound/soc/tegra/tegra20_i2s.h b/sound/soc/tegra/tegra20_i2s.h
new file mode 100644
index 0000000..86ab327
--- /dev/null
+++ b/sound/soc/tegra/tegra20_i2s.h
@@ -0,0 +1,165 @@
+/*
+ * tegra20_i2s.h - Definitions for Tegra20 I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TEGRA20_I2S_H__
+#define __TEGRA20_I2S_H__
+
+#include "tegra_pcm.h"
+
+/* Register offsets from TEGRA20_I2S1_BASE and TEGRA20_I2S2_BASE */
+
+#define TEGRA20_I2S_CTRL				0x00
+#define TEGRA20_I2S_STATUS				0x04
+#define TEGRA20_I2S_TIMING				0x08
+#define TEGRA20_I2S_FIFO_SCR				0x0c
+#define TEGRA20_I2S_PCM_CTRL				0x10
+#define TEGRA20_I2S_NW_CTRL				0x14
+#define TEGRA20_I2S_TDM_CTRL				0x20
+#define TEGRA20_I2S_TDM_TX_RX_CTRL			0x24
+#define TEGRA20_I2S_FIFO1				0x40
+#define TEGRA20_I2S_FIFO2				0x80
+
+/* Fields in TEGRA20_I2S_CTRL */
+
+#define TEGRA20_I2S_CTRL_FIFO2_TX_ENABLE		(1 << 30)
+#define TEGRA20_I2S_CTRL_FIFO1_ENABLE			(1 << 29)
+#define TEGRA20_I2S_CTRL_FIFO2_ENABLE			(1 << 28)
+#define TEGRA20_I2S_CTRL_FIFO1_RX_ENABLE		(1 << 27)
+#define TEGRA20_I2S_CTRL_FIFO_LPBK_ENABLE		(1 << 26)
+#define TEGRA20_I2S_CTRL_MASTER_ENABLE			(1 << 25)
+
+#define TEGRA20_I2S_LRCK_LEFT_LOW				0
+#define TEGRA20_I2S_LRCK_RIGHT_LOW			1
+
+#define TEGRA20_I2S_CTRL_LRCK_SHIFT			24
+#define TEGRA20_I2S_CTRL_LRCK_MASK			(1                          << TEGRA20_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA20_I2S_CTRL_LRCK_L_LOW			(TEGRA20_I2S_LRCK_LEFT_LOW  << TEGRA20_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA20_I2S_CTRL_LRCK_R_LOW			(TEGRA20_I2S_LRCK_RIGHT_LOW << TEGRA20_I2S_CTRL_LRCK_SHIFT)
+
+#define TEGRA20_I2S_BIT_FORMAT_I2S			0
+#define TEGRA20_I2S_BIT_FORMAT_RJM			1
+#define TEGRA20_I2S_BIT_FORMAT_LJM			2
+#define TEGRA20_I2S_BIT_FORMAT_DSP			3
+
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT		10
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_MASK		(3                          << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_I2S			(TEGRA20_I2S_BIT_FORMAT_I2S << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_RJM			(TEGRA20_I2S_BIT_FORMAT_RJM << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_LJM			(TEGRA20_I2S_BIT_FORMAT_LJM << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_DSP			(TEGRA20_I2S_BIT_FORMAT_DSP << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+
+#define TEGRA20_I2S_BIT_SIZE_16				0
+#define TEGRA20_I2S_BIT_SIZE_20				1
+#define TEGRA20_I2S_BIT_SIZE_24				2
+#define TEGRA20_I2S_BIT_SIZE_32				3
+
+#define TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT			8
+#define TEGRA20_I2S_CTRL_BIT_SIZE_MASK			(3                       << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_16			(TEGRA20_I2S_BIT_SIZE_16 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_20			(TEGRA20_I2S_BIT_SIZE_20 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_24			(TEGRA20_I2S_BIT_SIZE_24 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_32			(TEGRA20_I2S_BIT_SIZE_32 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+
+#define TEGRA20_I2S_FIFO_16_LSB				0
+#define TEGRA20_I2S_FIFO_20_LSB				1
+#define TEGRA20_I2S_FIFO_24_LSB				2
+#define TEGRA20_I2S_FIFO_32				3
+#define TEGRA20_I2S_FIFO_PACKED				7
+
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT		4
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK		(7                       << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_16_LSB		(TEGRA20_I2S_FIFO_16_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_20_LSB		(TEGRA20_I2S_FIFO_20_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_24_LSB		(TEGRA20_I2S_FIFO_24_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_32			(TEGRA20_I2S_FIFO_32     << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED		(TEGRA20_I2S_FIFO_PACKED << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+
+#define TEGRA20_I2S_CTRL_IE_FIFO1_ERR			(1 << 3)
+#define TEGRA20_I2S_CTRL_IE_FIFO2_ERR			(1 << 2)
+#define TEGRA20_I2S_CTRL_QE_FIFO1			(1 << 1)
+#define TEGRA20_I2S_CTRL_QE_FIFO2			(1 << 0)
+
+/* Fields in TEGRA20_I2S_STATUS */
+
+#define TEGRA20_I2S_STATUS_FIFO1_RDY			(1 << 31)
+#define TEGRA20_I2S_STATUS_FIFO2_RDY			(1 << 30)
+#define TEGRA20_I2S_STATUS_FIFO1_BSY			(1 << 29)
+#define TEGRA20_I2S_STATUS_FIFO2_BSY			(1 << 28)
+#define TEGRA20_I2S_STATUS_FIFO1_ERR			(1 << 3)
+#define TEGRA20_I2S_STATUS_FIFO2_ERR			(1 << 2)
+#define TEGRA20_I2S_STATUS_QS_FIFO1			(1 << 1)
+#define TEGRA20_I2S_STATUS_QS_FIFO2			(1 << 0)
+
+/* Fields in TEGRA20_I2S_TIMING */
+
+#define TEGRA20_I2S_TIMING_NON_SYM_ENABLE		(1 << 12)
+#define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT	0
+#define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US	0x7fff
+#define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK	(TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT)
+
+/* Fields in TEGRA20_I2S_FIFO_SCR */
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT	24
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT	16
+#define TEGRA20_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK		0x3f
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_CLR			(1 << 12)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_CLR			(1 << 8)
+
+#define TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT		0
+#define TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS		1
+#define TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS		2
+#define TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS		3
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT	4
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK		(3 << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT	(TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT     << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS	(TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS   << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS	(TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS  << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS	(TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT	0
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK		(3 << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT	(TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT     << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS	(TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS   << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS	(TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS  << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS	(TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+
+struct tegra20_i2s {
+	struct snd_soc_dai_driver dai;
+	struct clk *clk_i2s;
+	struct tegra_pcm_dma_params capture_dma_data;
+	struct tegra_pcm_dma_params playback_dma_data;
+	void __iomem *regs;
+	struct dentry *debug;
+	u32 reg_ctrl;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
new file mode 100644
index 0000000..ef5d49e
--- /dev/null
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -0,0 +1,351 @@
+/*
+ * tegra20_spdif.c - Tegra20 SPDIF driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2011-2012 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra20_spdif.h"
+
+#define DRV_NAME "tegra20-spdif"
+
+static inline void tegra20_spdif_write(struct tegra20_spdif *spdif, u32 reg,
+					u32 val)
+{
+	__raw_writel(val, spdif->regs + reg);
+}
+
+static inline u32 tegra20_spdif_read(struct tegra20_spdif *spdif, u32 reg)
+{
+	return __raw_readl(spdif->regs + reg);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int tegra20_spdif_show(struct seq_file *s, void *unused)
+{
+#define REG(r) { r, #r }
+	static const struct {
+		int offset;
+		const char *name;
+	} regs[] = {
+		REG(TEGRA20_SPDIF_CTRL),
+		REG(TEGRA20_SPDIF_STATUS),
+		REG(TEGRA20_SPDIF_STROBE_CTRL),
+		REG(TEGRA20_SPDIF_DATA_FIFO_CSR),
+		REG(TEGRA20_SPDIF_CH_STA_RX_A),
+		REG(TEGRA20_SPDIF_CH_STA_RX_B),
+		REG(TEGRA20_SPDIF_CH_STA_RX_C),
+		REG(TEGRA20_SPDIF_CH_STA_RX_D),
+		REG(TEGRA20_SPDIF_CH_STA_RX_E),
+		REG(TEGRA20_SPDIF_CH_STA_RX_F),
+		REG(TEGRA20_SPDIF_CH_STA_TX_A),
+		REG(TEGRA20_SPDIF_CH_STA_TX_B),
+		REG(TEGRA20_SPDIF_CH_STA_TX_C),
+		REG(TEGRA20_SPDIF_CH_STA_TX_D),
+		REG(TEGRA20_SPDIF_CH_STA_TX_E),
+		REG(TEGRA20_SPDIF_CH_STA_TX_F),
+	};
+#undef REG
+
+	struct tegra20_spdif *spdif = s->private;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++) {
+		u32 val = tegra20_spdif_read(spdif, regs[i].offset);
+		seq_printf(s, "%s = %08x\n", regs[i].name, val);
+	}
+
+	return 0;
+}
+
+static int tegra20_spdif_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, tegra20_spdif_show, inode->i_private);
+}
+
+static const struct file_operations tegra20_spdif_debug_fops = {
+	.open    = tegra20_spdif_debug_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = single_release,
+};
+
+static void tegra20_spdif_debug_add(struct tegra20_spdif *spdif)
+{
+	spdif->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
+						snd_soc_debugfs_root, spdif,
+						&tegra20_spdif_debug_fops);
+}
+
+static void tegra20_spdif_debug_remove(struct tegra20_spdif *spdif)
+{
+	if (spdif->debug)
+		debugfs_remove(spdif->debug);
+}
+#else
+static inline void tegra20_spdif_debug_add(struct tegra20_spdif *spdif)
+{
+}
+
+static inline void tegra20_spdif_debug_remove(struct tegra20_spdif *spdif)
+{
+}
+#endif
+
+static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct device *dev = substream->pcm->card->dev;
+	struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+	int ret, spdifclock;
+
+	spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_PACK;
+	spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_PACK;
+		spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_rate(params)) {
+	case 32000:
+		spdifclock = 4096000;
+		break;
+	case 44100:
+		spdifclock = 5644800;
+		break;
+	case 48000:
+		spdifclock = 6144000;
+		break;
+	case 88200:
+		spdifclock = 11289600;
+		break;
+	case 96000:
+		spdifclock = 12288000;
+		break;
+	case 176400:
+		spdifclock = 22579200;
+		break;
+	case 192000:
+		spdifclock = 24576000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);
+	if (ret) {
+		dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void tegra20_spdif_start_playback(struct tegra20_spdif *spdif)
+{
+	spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_TX_EN;
+	tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl);
+}
+
+static void tegra20_spdif_stop_playback(struct tegra20_spdif *spdif)
+{
+	spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_TX_EN;
+	tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl);
+}
+
+static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
+{
+	struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		clk_enable(spdif->clk_spdif_out);
+		tegra20_spdif_start_playback(spdif);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		tegra20_spdif_stop_playback(spdif);
+		clk_disable(spdif->clk_spdif_out);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra20_spdif_probe(struct snd_soc_dai *dai)
+{
+	struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+	dai->capture_dma_data = NULL;
+	dai->playback_dma_data = &spdif->playback_dma_data;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = {
+	.hw_params	= tegra20_spdif_hw_params,
+	.trigger	= tegra20_spdif_trigger,
+};
+
+static struct snd_soc_dai_driver tegra20_spdif_dai = {
+	.name = DRV_NAME,
+	.probe = tegra20_spdif_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+				SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &tegra20_spdif_dai_ops,
+};
+
+static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev)
+{
+	struct tegra20_spdif *spdif;
+	struct resource *mem, *memregion, *dmareq;
+	int ret;
+
+	spdif = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_spdif),
+			     GFP_KERNEL);
+	if (!spdif) {
+		dev_err(&pdev->dev, "Can't allocate tegra20_spdif\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	dev_set_drvdata(&pdev->dev, spdif);
+
+	spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out");
+	if (IS_ERR(spdif->clk_spdif_out)) {
+		pr_err("Can't retrieve spdif clock\n");
+		ret = PTR_ERR(spdif->clk_spdif_out);
+		goto err;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "No memory resource\n");
+		ret = -ENODEV;
+		goto err_clk_put;
+	}
+
+	dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!dmareq) {
+		dev_err(&pdev->dev, "No DMA resource\n");
+		ret = -ENODEV;
+		goto err_clk_put;
+	}
+
+	memregion = devm_request_mem_region(&pdev->dev, mem->start,
+					    resource_size(mem), DRV_NAME);
+	if (!memregion) {
+		dev_err(&pdev->dev, "Memory region already claimed\n");
+		ret = -EBUSY;
+		goto err_clk_put;
+	}
+
+	spdif->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+	if (!spdif->regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENOMEM;
+		goto err_clk_put;
+	}
+
+	spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT;
+	spdif->playback_dma_data.wrap = 4;
+	spdif->playback_dma_data.width = 32;
+	spdif->playback_dma_data.req_sel = dmareq->start;
+
+	ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+		ret = -ENOMEM;
+		goto err_clk_put;
+	}
+
+	ret = tegra_pcm_platform_register(&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+		goto err_unregister_dai;
+	}
+
+	tegra20_spdif_debug_add(spdif);
+
+	return 0;
+
+err_unregister_dai:
+	snd_soc_unregister_dai(&pdev->dev);
+err_clk_put:
+	clk_put(spdif->clk_spdif_out);
+err:
+	return ret;
+}
+
+static int __devexit tegra20_spdif_platform_remove(struct platform_device *pdev)
+{
+	struct tegra20_spdif *spdif = dev_get_drvdata(&pdev->dev);
+
+	tegra_pcm_platform_unregister(&pdev->dev);
+	snd_soc_unregister_dai(&pdev->dev);
+
+	tegra20_spdif_debug_remove(spdif);
+
+	clk_put(spdif->clk_spdif_out);
+
+	return 0;
+}
+
+static struct platform_driver tegra20_spdif_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = tegra20_spdif_platform_probe,
+	.remove = __devexit_p(tegra20_spdif_platform_remove),
+};
+
+module_platform_driver(tegra20_spdif_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 SPDIF ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h
new file mode 100644
index 0000000..823af4c
--- /dev/null
+++ b/sound/soc/tegra/tegra20_spdif.h
@@ -0,0 +1,472 @@
+/*
+ * tegra20_spdif.h - Definitions for Tegra20 SPDIF driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2011 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ * Copyright (c) 2008-2009, NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TEGRA20_SPDIF_H__
+#define __TEGRA20_SPDIF_H__
+
+#include "tegra_pcm.h"
+
+/* Offsets from TEGRA20_SPDIF_BASE */
+
+#define TEGRA20_SPDIF_CTRL					0x0
+#define TEGRA20_SPDIF_STATUS					0x4
+#define TEGRA20_SPDIF_STROBE_CTRL				0x8
+#define TEGRA20_SPDIF_DATA_FIFO_CSR				0x0C
+#define TEGRA20_SPDIF_DATA_OUT					0x40
+#define TEGRA20_SPDIF_DATA_IN					0x80
+#define TEGRA20_SPDIF_CH_STA_RX_A				0x100
+#define TEGRA20_SPDIF_CH_STA_RX_B				0x104
+#define TEGRA20_SPDIF_CH_STA_RX_C				0x108
+#define TEGRA20_SPDIF_CH_STA_RX_D				0x10C
+#define TEGRA20_SPDIF_CH_STA_RX_E				0x110
+#define TEGRA20_SPDIF_CH_STA_RX_F				0x114
+#define TEGRA20_SPDIF_CH_STA_TX_A				0x140
+#define TEGRA20_SPDIF_CH_STA_TX_B				0x144
+#define TEGRA20_SPDIF_CH_STA_TX_C				0x148
+#define TEGRA20_SPDIF_CH_STA_TX_D				0x14C
+#define TEGRA20_SPDIF_CH_STA_TX_E				0x150
+#define TEGRA20_SPDIF_CH_STA_TX_F				0x154
+#define TEGRA20_SPDIF_USR_STA_RX_A				0x180
+#define TEGRA20_SPDIF_USR_DAT_TX_A				0x1C0
+
+/* Fields in TEGRA20_SPDIF_CTRL */
+
+/* Start capturing from 0=right, 1=left channel */
+#define TEGRA20_SPDIF_CTRL_CAP_LC				(1 << 30)
+
+/* SPDIF receiver(RX) enable */
+#define TEGRA20_SPDIF_CTRL_RX_EN				(1 << 29)
+
+/* SPDIF Transmitter(TX) enable */
+#define TEGRA20_SPDIF_CTRL_TX_EN				(1 << 28)
+
+/* Transmit Channel status */
+#define TEGRA20_SPDIF_CTRL_TC_EN				(1 << 27)
+
+/* Transmit user Data */
+#define TEGRA20_SPDIF_CTRL_TU_EN				(1 << 26)
+
+/* Interrupt on transmit error */
+#define TEGRA20_SPDIF_CTRL_IE_TXE				(1 << 25)
+
+/* Interrupt on receive error */
+#define TEGRA20_SPDIF_CTRL_IE_RXE				(1 << 24)
+
+/* Interrupt on invalid preamble */
+#define TEGRA20_SPDIF_CTRL_IE_P					(1 << 23)
+
+/* Interrupt on "B" preamble */
+#define TEGRA20_SPDIF_CTRL_IE_B					(1 << 22)
+
+/* Interrupt when block of channel status received */
+#define TEGRA20_SPDIF_CTRL_IE_C					(1 << 21)
+
+/* Interrupt when a valid information unit (IU) is received */
+#define TEGRA20_SPDIF_CTRL_IE_U					(1 << 20)
+
+/* Interrupt when RX user FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_RU				(1 << 19)
+
+/* Interrupt when TX user FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_TU				(1 << 18)
+
+/* Interrupt when RX data FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_RX				(1 << 17)
+
+/* Interrupt when TX data FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_TX				(1 << 16)
+
+/* Loopback test mode enable */
+#define TEGRA20_SPDIF_CTRL_LBK_EN				(1 << 15)
+
+/*
+ * Pack data mode:
+ * 0 = Single data (16 bit needs to be  padded to match the
+ *     interface data bit size).
+ * 1 = Packeted left/right channel data into a single word.
+ */
+#define TEGRA20_SPDIF_CTRL_PACK					(1 << 14)
+
+/*
+ * 00 = 16bit data
+ * 01 = 20bit data
+ * 10 = 24bit data
+ * 11 = raw data
+ */
+#define TEGRA20_SPDIF_BIT_MODE_16BIT				0
+#define TEGRA20_SPDIF_BIT_MODE_20BIT				1
+#define TEGRA20_SPDIF_BIT_MODE_24BIT				2
+#define TEGRA20_SPDIF_BIT_MODE_RAW				3
+
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT			12
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_MASK			(3                            << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT			(TEGRA20_SPDIF_BIT_MODE_16BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_20BIT			(TEGRA20_SPDIF_BIT_MODE_20BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_24BIT			(TEGRA20_SPDIF_BIT_MODE_24BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_RAW				(TEGRA20_SPDIF_BIT_MODE_RAW   << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_STATUS */
+
+/*
+ * Note: IS_P, IS_B, IS_C, and IS_U are sticky bits. Software must
+ * write a 1 to the corresponding bit location to clear the status.
+ */
+
+/*
+ * Receiver(RX) shifter is busy receiving data.
+ * This bit is asserted when the receiver first locked onto the
+ * preamble of the data stream after RX_EN is asserted. This bit is
+ * deasserted when either,
+ * (a) the end of a frame is reached after RX_EN is deeasserted, or
+ * (b) the SPDIF data stream becomes inactive.
+ */
+#define TEGRA20_SPDIF_STATUS_RX_BSY				(1 << 29)
+
+/*
+ * Transmitter(TX) shifter is busy transmitting data.
+ * This bit is asserted when TX_EN is asserted.
+ * This bit is deasserted when the end of a frame is reached after
+ * TX_EN is deasserted.
+ */
+#define TEGRA20_SPDIF_STATUS_TX_BSY				(1 << 28)
+
+/*
+ * TX is busy shifting out channel status.
+ * This bit is asserted when both TX_EN and TC_EN are asserted and
+ * data from CH_STA_TX_A register is loaded into the internal shifter.
+ * This bit is deasserted when either,
+ * (a) the end of a frame is reached after TX_EN is deasserted, or
+ * (b) CH_STA_TX_F register is loaded into the internal shifter.
+ */
+#define TEGRA20_SPDIF_STATUS_TC_BSY				(1 << 27)
+
+/*
+ * TX User data FIFO busy.
+ * This bit is asserted when TX_EN and TXU_EN are asserted and
+ * there's data in the TX user FIFO.  This bit is deassert when either,
+ * (a) the end of a frame is reached after TX_EN is deasserted, or
+ * (b) there's no data left in the TX user FIFO.
+ */
+#define TEGRA20_SPDIF_STATUS_TU_BSY				(1 << 26)
+
+/* TX FIFO Underrun error status */
+#define TEGRA20_SPDIF_STATUS_TX_ERR				(1 << 25)
+
+/* RX FIFO Overrun error status */
+#define TEGRA20_SPDIF_STATUS_RX_ERR				(1 << 24)
+
+/* Preamble status: 0=Preamble OK, 1=bad/missing preamble */
+#define TEGRA20_SPDIF_STATUS_IS_P				(1 << 23)
+
+/* B-preamble detection status: 0=not detected, 1=B-preamble detected */
+#define TEGRA20_SPDIF_STATUS_IS_B				(1 << 22)
+
+/*
+ * RX channel block data receive status:
+ * 0=entire block not recieved yet.
+ * 1=received entire block of channel status,
+ */
+#define TEGRA20_SPDIF_STATUS_IS_C				(1 << 21)
+
+/* RX User Data Valid flag:  1=valid IU detected, 0 = no IU detected. */
+#define TEGRA20_SPDIF_STATUS_IS_U				(1 << 20)
+
+/*
+ * RX User FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_RU				(1 << 19)
+
+/*
+ * TX User FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_TU				(1 << 18)
+
+/*
+ * RX Data FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_RX				(1 << 17)
+
+/*
+ * TX Data FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_TX				(1 << 16)
+
+/* Fields in TEGRA20_SPDIF_STROBE_CTRL */
+
+/*
+ * Indicates the approximate number of detected SPDIFIN clocks within a
+ * bi-phase period.
+ */
+#define TEGRA20_SPDIF_STROBE_CTRL_PERIOD_SHIFT			16
+#define TEGRA20_SPDIF_STROBE_CTRL_PERIOD_MASK			(0xff << TEGRA20_SPDIF_STROBE_CTRL_PERIOD_SHIFT)
+
+/* Data strobe mode: 0=Auto-locked 1=Manual locked */
+#define TEGRA20_SPDIF_STROBE_CTRL_STROBE			(1 << 15)
+
+/*
+ * Manual data strobe time within the bi-phase clock period (in terms of
+ * the number of over-sampling clocks).
+ */
+#define TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT		8
+#define TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_MASK		(0x1f << TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT)
+
+/*
+ * Manual SPDIFIN bi-phase clock period (in terms of the number of
+ * over-sampling clocks).
+ */
+#define TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT		0
+#define TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK		(0x3f << TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT)
+
+/* Fields in SPDIF_DATA_FIFO_CSR */
+
+/* Clear Receiver User FIFO (RX USR.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_CLR			(1 << 31)
+
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT			0
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS			1
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS		2
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS			3
+
+/* RU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT		29
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_MASK		\
+		(0x3                                      << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU1_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU2_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU3_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU4_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+
+/* Number of RX USR.FIFO levels with valid data. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT		24
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_MASK		(0x1f << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT)
+
+/* Clear Transmitter User FIFO (TX USR.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_CLR			(1 << 23)
+
+/* TU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT		21
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_MASK		\
+		(0x3                                      << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU1_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU2_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU3_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU4_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+
+/* Number of TX USR.FIFO levels that could be filled. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT	16
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_MASK		(0x1f << SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT)
+
+/* Clear Receiver Data FIFO (RX DATA.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_CLR			(1 << 15)
+
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT			0
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS			1
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS		2
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS		3
+
+/* RU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT		13
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_MASK		\
+		(0x3                                       << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU1_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU4_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU8_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU12_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+
+/* Number of RX DATA.FIFO levels with valid data. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT		8
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_MASK		(0x1f << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT)
+
+/* Clear Transmitter Data FIFO (TX DATA.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_CLR			(1 << 7)
+
+/* TU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT		5
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK		\
+		(0x3                                       << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU1_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU8_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU12_WORD_FULL	\
+		(TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+
+/* Number of TX DATA.FIFO levels that could be filled. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT	0
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_MASK		(0x1f << SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_DATA_OUT */
+
+/*
+ * This register has 5 different formats:
+ * 16-bit        (BIT_MODE=00, PACK=0)
+ * 20-bit        (BIT_MODE=01, PACK=0)
+ * 24-bit        (BIT_MODE=10, PACK=0)
+ * raw           (BIT_MODE=11, PACK=0)
+ * 16-bit packed (BIT_MODE=00, PACK=1)
+ */
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_SHIFT			0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_MASK			(0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_20_SHIFT			0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_20_MASK			(0xfffff << TEGRA20_SPDIF_DATA_OUT_DATA_20_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_24_SHIFT			0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_24_MASK			(0xffffff << TEGRA20_SPDIF_DATA_OUT_DATA_24_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_P			(1 << 31)
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_C			(1 << 30)
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_U			(1 << 29)
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_V			(1 << 28)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT		8
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_MASK		(0xfffff << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT		4
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_MASK		(0xf << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT		0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_MASK		(0xf << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT	16
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_MASK	(0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT	0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_MASK		(0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_DATA_IN */
+
+/*
+ * This register has 5 different formats:
+ * 16-bit        (BIT_MODE=00, PACK=0)
+ * 20-bit        (BIT_MODE=01, PACK=0)
+ * 24-bit        (BIT_MODE=10, PACK=0)
+ * raw           (BIT_MODE=11, PACK=0)
+ * 16-bit packed (BIT_MODE=00, PACK=1)
+ *
+ * Bits 31:24 are common to all modes except 16-bit packed
+ */
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_P				(1 << 31)
+#define TEGRA20_SPDIF_DATA_IN_DATA_C				(1 << 30)
+#define TEGRA20_SPDIF_DATA_IN_DATA_U				(1 << 29)
+#define TEGRA20_SPDIF_DATA_IN_DATA_V				(1 << 28)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT		24
+#define TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_MASK		(0xf << TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_SHIFT			0
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_MASK			(0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_20_SHIFT			0
+#define TEGRA20_SPDIF_DATA_IN_DATA_20_MASK			(0xfffff << TEGRA20_SPDIF_DATA_IN_DATA_20_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_24_SHIFT			0
+#define TEGRA20_SPDIF_DATA_IN_DATA_24_MASK			(0xffffff << TEGRA20_SPDIF_DATA_IN_DATA_24_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT		8
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_MASK		(0xfffff << TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT		4
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_MASK			(0xf << TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT		0
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_MASK		(0xf << TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT	16
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_MASK		(0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT		0
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_MASK		(0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_A */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_B */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_C */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_D */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_E */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_F */
+
+/*
+ * The 6-word receive channel data page buffer holds a block (192 frames) of
+ * channel status information. The order of receive is from LSB to MSB
+ * bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A.
+ */
+
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_A */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_B */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_C */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_D */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_E */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_F */
+
+/*
+ * The 6-word transmit channel data page buffer holds a block (192 frames) of
+ * channel status information. The order of transmission is from LSB to MSB
+ * bit, and from CH_STA_TX_A to CH_STA_TX_F then back to CH_STA_TX_A.
+ */
+
+/* Fields in TEGRA20_SPDIF_USR_STA_RX_A */
+
+/*
+ * This 4-word deep FIFO receives user FIFO field information. The order of
+ * receive is from LSB to MSB bit.
+ */
+
+/* Fields in TEGRA20_SPDIF_USR_DAT_TX_A */
+
+/*
+ * This 4-word deep FIFO transmits user FIFO field information. The order of
+ * transmission is from LSB to MSB bit.
+ */
+
+struct tegra20_spdif {
+	struct clk *clk_spdif_out;
+	struct tegra_pcm_dma_params capture_dma_data;
+	struct tegra_pcm_dma_params playback_dma_data;
+	void __iomem *regs;
+	struct dentry *debug;
+	u32 reg_ctrl;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index e45ccd8..32de700 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -1,16 +1,17 @@
 /*
-* tegra_alc5632.c  --  Toshiba AC100(PAZ00) machine ASoC driver
-*
-* Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
-*
-* Authors:  Leon Romanovsky <leon@leon.nu>
-*           Andrey Danin <danindrey@mail.ru>
-*           Marc Dietrich <marvin24@gmx.de>
-*
-* 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.
-*/
+ * tegra_alc5632.c  --  Toshiba AC100(PAZ00) machine ASoC driver
+ *
+ * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+ * Copyright (C) 2012 - NVIDIA, Inc.
+ *
+ * Authors:  Leon Romanovsky <leon@leon.nu>
+ *           Andrey Danin <danindrey@mail.ru>
+ *           Marc Dietrich <marvin24@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
 
 #include <asm/mach-types.h>
 
@@ -28,9 +29,6 @@
 
 #include "../codecs/alc5632.h"
 
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
 #include "tegra_asoc_utils.h"
 
 #define DRV_NAME "tegra-alc5632"
@@ -39,7 +37,6 @@
 
 struct tegra_alc5632 {
 	struct tegra_asoc_utils_data util_data;
-	struct platform_device *pcm_dev;
 	int gpio_requested;
 	int gpio_hp_det;
 };
@@ -140,7 +137,6 @@
 static struct snd_soc_dai_link tegra_alc5632_dai = {
 	.name = "ALC5632",
 	.stream_name = "ALC5632 PCM",
-	.platform_name = "tegra-pcm-audio",
 	.codec_dai_name = "alc5632-hifi",
 	.init = tegra_alc5632_asoc_init,
 	.ops = &tegra_alc5632_asoc_ops,
@@ -179,8 +175,6 @@
 	platform_set_drvdata(pdev, card);
 	snd_soc_card_set_drvdata(card, alc5632);
 
-	alc5632->pcm_dev = ERR_PTR(-EINVAL);
-
 	if (!(pdev->dev.of_node)) {
 		dev_err(&pdev->dev, "Must be instantiated using device tree\n");
 		ret = -EINVAL;
@@ -214,18 +208,11 @@
 		goto err;
 	}
 
-	alc5632->pcm_dev = platform_device_register_simple(
-		"tegra-pcm-audio", -1, NULL, 0);
-	if (IS_ERR(alc5632->pcm_dev)) {
-		dev_err(&pdev->dev,
-			"Can't instantiate tegra-pcm-audio\n");
-		ret = PTR_ERR(alc5632->pcm_dev);
-		goto err;
-	}
+	tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_dai_of_node;
 
 	ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev);
 	if (ret)
-		goto err_unregister;
+		goto err;
 
 	ret = snd_soc_register_card(card);
 	if (ret) {
@@ -238,9 +225,6 @@
 
 err_fini_utils:
 	tegra_asoc_utils_fini(&alc5632->util_data);
-err_unregister:
-	if (!IS_ERR(alc5632->pcm_dev))
-		platform_device_unregister(alc5632->pcm_dev);
 err:
 	return ret;
 }
@@ -259,8 +243,6 @@
 	snd_soc_unregister_card(card);
 
 	tegra_asoc_utils_fini(&machine->util_data);
-	if (!IS_ERR(machine->pcm_dev))
-		platform_device_unregister(machine->pcm_dev);
 
 	return 0;
 }
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
index f8428e4..266189d 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -2,7 +2,7 @@
  * tegra_asoc_utils.c - Harmony machine ASoC driver
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -25,6 +25,7 @@
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
 
 #include "tegra_asoc_utils.h"
 
@@ -40,7 +41,10 @@
 	case 22050:
 	case 44100:
 	case 88200:
-		new_baseclock = 56448000;
+		if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+			new_baseclock = 56448000;
+		else
+			new_baseclock = 564480000;
 		break;
 	case 8000:
 	case 16000:
@@ -48,7 +52,10 @@
 	case 48000:
 	case 64000:
 	case 96000:
-		new_baseclock = 73728000;
+		if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+			new_baseclock = 73728000;
+		else
+			new_baseclock = 552960000;
 		break;
 	default:
 		return -EINVAL;
@@ -78,7 +85,7 @@
 		return err;
 	}
 
-	/* Don't set cdev1 rate; its locked to pll_a_out0 */
+	/* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
 
 	err = clk_enable(data->clk_pll_a);
 	if (err) {
@@ -112,6 +119,15 @@
 
 	data->dev = dev;
 
+	if (!of_have_populated_dt())
+		data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
+	else if (of_machine_is_compatible("nvidia,tegra20"))
+		data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
+	else if (of_machine_is_compatible("nvidia,tegra30"))
+		data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30;
+	else
+		return -EINVAL;
+
 	data->clk_pll_a = clk_get_sys(NULL, "pll_a");
 	if (IS_ERR(data->clk_pll_a)) {
 		dev_err(data->dev, "Can't retrieve clk pll_a\n");
@@ -126,15 +142,24 @@
 		goto err_put_pll_a;
 	}
 
-	data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
+	if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+		data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
+	else
+		data->clk_cdev1 = clk_get_sys("extern1", NULL);
 	if (IS_ERR(data->clk_cdev1)) {
 		dev_err(data->dev, "Can't retrieve clk cdev1\n");
 		ret = PTR_ERR(data->clk_cdev1);
 		goto err_put_pll_a_out0;
 	}
 
+	ret = tegra_asoc_utils_set_rate(data, 44100, 256 * 44100);
+	if (ret)
+		goto err_put_cdev1;
+
 	return 0;
 
+err_put_cdev1:
+	clk_put(data->clk_cdev1);
 err_put_pll_a_out0:
 	clk_put(data->clk_pll_a_out0);
 err_put_pll_a:
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h
index 4818195..44db1db 100644
--- a/sound/soc/tegra/tegra_asoc_utils.h
+++ b/sound/soc/tegra/tegra_asoc_utils.h
@@ -2,7 +2,7 @@
  * tegra_asoc_utils.h - Definitions for Tegra DAS driver
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -26,8 +26,14 @@
 struct clk;
 struct device;
 
+enum tegra_asoc_utils_soc {
+	TEGRA_ASOC_UTILS_SOC_TEGRA20,
+	TEGRA_ASOC_UTILS_SOC_TEGRA30,
+};
+
 struct tegra_asoc_utils_data {
 	struct device *dev;
+	enum tegra_asoc_utils_soc soc;
 	struct clk *clk_pll_a;
 	struct clk *clk_pll_a_out0;
 	struct clk *clk_cdev1;
@@ -42,4 +48,3 @@
 void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data);
 
 #endif
-
diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c
deleted file mode 100644
index 3b3c1ba..0000000
--- a/sound/soc/tegra/tegra_das.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * tegra_das.c - Tegra DAS driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <mach/iomap.h>
-#include <sound/soc.h>
-#include "tegra_das.h"
-
-#define DRV_NAME "tegra-das"
-
-static struct tegra_das *das;
-
-static inline void tegra_das_write(u32 reg, u32 val)
-{
-	__raw_writel(val, das->regs + reg);
-}
-
-static inline u32 tegra_das_read(u32 reg)
-{
-	return __raw_readl(das->regs + reg);
-}
-
-int tegra_das_connect_dap_to_dac(int dap, int dac)
-{
-	u32 addr;
-	u32 reg;
-
-	if (!das)
-		return -ENODEV;
-
-	addr = TEGRA_DAS_DAP_CTRL_SEL +
-		(dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
-	reg = dac << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
-
-	tegra_das_write(addr, reg);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dac);
-
-int tegra_das_connect_dap_to_dap(int dap, int otherdap, int master,
-					int sdata1rx, int sdata2rx)
-{
-	u32 addr;
-	u32 reg;
-
-	if (!das)
-		return -ENODEV;
-
-	addr = TEGRA_DAS_DAP_CTRL_SEL +
-		(dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
-	reg = otherdap << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P |
-		!!sdata2rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P |
-		!!sdata1rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P |
-		!!master << TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P;
-
-	tegra_das_write(addr, reg);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dap);
-
-int tegra_das_connect_dac_to_dap(int dac, int dap)
-{
-	u32 addr;
-	u32 reg;
-
-	if (!das)
-		return -ENODEV;
-
-	addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL +
-		(dac * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
-	reg = dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
-		dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
-		dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
-
-	tegra_das_write(addr, reg);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(tegra_das_connect_dac_to_dap);
-
-#ifdef CONFIG_DEBUG_FS
-static int tegra_das_show(struct seq_file *s, void *unused)
-{
-	int i;
-	u32 addr;
-	u32 reg;
-
-	for (i = 0; i < TEGRA_DAS_DAP_CTRL_SEL_COUNT; i++) {
-		addr = TEGRA_DAS_DAP_CTRL_SEL +
-			(i * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
-		reg = tegra_das_read(addr);
-		seq_printf(s, "TEGRA_DAS_DAP_CTRL_SEL[%d] = %08x\n", i, reg);
-	}
-
-	for (i = 0; i < TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT; i++) {
-		addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL +
-			(i * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
-		reg = tegra_das_read(addr);
-		seq_printf(s, "TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL[%d] = %08x\n",
-				 i, reg);
-	}
-
-	return 0;
-}
-
-static int tegra_das_debug_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, tegra_das_show, inode->i_private);
-}
-
-static const struct file_operations tegra_das_debug_fops = {
-	.open    = tegra_das_debug_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = single_release,
-};
-
-static void tegra_das_debug_add(struct tegra_das *das)
-{
-	das->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
-					 snd_soc_debugfs_root, das,
-					 &tegra_das_debug_fops);
-}
-
-static void tegra_das_debug_remove(struct tegra_das *das)
-{
-	if (das->debug)
-		debugfs_remove(das->debug);
-}
-#else
-static inline void tegra_das_debug_add(struct tegra_das *das)
-{
-}
-
-static inline void tegra_das_debug_remove(struct tegra_das *das)
-{
-}
-#endif
-
-static int __devinit tegra_das_probe(struct platform_device *pdev)
-{
-	struct resource *res, *region;
-	int ret = 0;
-
-	if (das)
-		return -ENODEV;
-
-	das = devm_kzalloc(&pdev->dev, sizeof(struct tegra_das), GFP_KERNEL);
-	if (!das) {
-		dev_err(&pdev->dev, "Can't allocate tegra_das\n");
-		ret = -ENOMEM;
-		goto err;
-	}
-	das->dev = &pdev->dev;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "No memory resource\n");
-		ret = -ENODEV;
-		goto err;
-	}
-
-	region = devm_request_mem_region(&pdev->dev, res->start,
-					 resource_size(res), pdev->name);
-	if (!region) {
-		dev_err(&pdev->dev, "Memory region already claimed\n");
-		ret = -EBUSY;
-		goto err;
-	}
-
-	das->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-	if (!das->regs) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1,
-					   TEGRA_DAS_DAP_SEL_DAC1);
-	if (ret) {
-		dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
-		goto err;
-	}
-	ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1,
-					   TEGRA_DAS_DAC_SEL_DAP1);
-	if (ret) {
-		dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
-		goto err;
-	}
-
-	tegra_das_debug_add(das);
-
-	platform_set_drvdata(pdev, das);
-
-	return 0;
-
-err:
-	das = NULL;
-	return ret;
-}
-
-static int __devexit tegra_das_remove(struct platform_device *pdev)
-{
-	if (!das)
-		return -ENODEV;
-
-	tegra_das_debug_remove(das);
-
-	das = NULL;
-
-	return 0;
-}
-
-static const struct of_device_id tegra_das_of_match[] __devinitconst = {
-	{ .compatible = "nvidia,tegra20-das", },
-	{},
-};
-
-static struct platform_driver tegra_das_driver = {
-	.probe = tegra_das_probe,
-	.remove = __devexit_p(tegra_das_remove),
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-		.of_match_table = tegra_das_of_match,
-	},
-};
-module_platform_driver(tegra_das_driver);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Tegra DAS driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, tegra_das_of_match);
diff --git a/sound/soc/tegra/tegra_das.h b/sound/soc/tegra/tegra_das.h
deleted file mode 100644
index 2c96c7b..0000000
--- a/sound/soc/tegra/tegra_das.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * tegra_das.h - Definitions for Tegra DAS driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __TEGRA_DAS_H__
-#define __TEGRA_DAS_H__
-
-/* Register TEGRA_DAS_DAP_CTRL_SEL */
-#define TEGRA_DAS_DAP_CTRL_SEL				0x00
-#define TEGRA_DAS_DAP_CTRL_SEL_COUNT			5
-#define TEGRA_DAS_DAP_CTRL_SEL_STRIDE			4
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P		31
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S		1
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P	30
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S	1
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P	29
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S	1
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P		0
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S		5
-
-/* Values for field TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
-#define TEGRA_DAS_DAP_SEL_DAC1	0
-#define TEGRA_DAS_DAP_SEL_DAC2	1
-#define TEGRA_DAS_DAP_SEL_DAC3	2
-#define TEGRA_DAS_DAP_SEL_DAP1	16
-#define TEGRA_DAS_DAP_SEL_DAP2	17
-#define TEGRA_DAS_DAP_SEL_DAP3	18
-#define TEGRA_DAS_DAP_SEL_DAP4	19
-#define TEGRA_DAS_DAP_SEL_DAP5	20
-
-/* Register TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL */
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL			0x40
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT			3
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE			4
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P	28
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S	4
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P	24
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S	4
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P		0
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S		4
-
-/*
- * Values for:
- * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
- * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
- * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
- */
-#define TEGRA_DAS_DAC_SEL_DAP1	0
-#define TEGRA_DAS_DAC_SEL_DAP2	1
-#define TEGRA_DAS_DAC_SEL_DAP3	2
-#define TEGRA_DAS_DAC_SEL_DAP4	3
-#define TEGRA_DAS_DAC_SEL_DAP5	4
-
-/*
- * Names/IDs of the DACs/DAPs.
- */
-
-#define TEGRA_DAS_DAP_ID_1 0
-#define TEGRA_DAS_DAP_ID_2 1
-#define TEGRA_DAS_DAP_ID_3 2
-#define TEGRA_DAS_DAP_ID_4 3
-#define TEGRA_DAS_DAP_ID_5 4
-
-#define TEGRA_DAS_DAC_ID_1 0
-#define TEGRA_DAS_DAC_ID_2 1
-#define TEGRA_DAS_DAC_ID_3 2
-
-struct tegra_das {
-	struct device *dev;
-	void __iomem *regs;
-	struct dentry *debug;
-};
-
-/*
- * Terminology:
- * DAS: Digital audio switch (HW module controlled by this driver)
- * DAP: Digital audio port (port/pins on Tegra device)
- * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
- * 
- * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
- * DAC, or another DAP. When DAPs are connected, one must be the master and
- * one the slave. Each DAC allows selection of a specific DAP for input, to
- * cater for the case where N DAPs are connected to 1 DAC for broadcast
- * output.
- *
- * This driver is dumb; no attempt is made to ensure that a valid routing
- * configuration is programmed.
- */
-
-/*
- * Connect a DAP to to a DAC
- * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_*
- * dac_sel: DAC to connect to: TEGRA_DAS_DAP_SEL_DAC*
- */
-extern int tegra_das_connect_dap_to_dac(int dap_id, int dac_sel);
-
-/*
- * Connect a DAP to to another DAP
- * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_*
- * other_dap_sel: DAP to connect to: TEGRA_DAS_DAP_SEL_DAP*
- * master: Is this DAP the master (1) or slave (0)
- * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0)
- * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0)
- */
-extern int tegra_das_connect_dap_to_dap(int dap_id, int other_dap_sel,
-					int master, int sdata1rx,
-					int sdata2rx);
-
-/*
- * Connect a DAC's input to a DAP
- * (DAC outputs are selected by the DAP)
- * dac_id: DAC ID to connect: TEGRA_DAS_DAC_ID_*
- * dap_sel: DAP to receive input from: TEGRA_DAS_DAC_SEL_DAP*
- */
-extern int tegra_das_connect_dac_to_dap(int dac_id, int dap_sel);
-
-#endif
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c
deleted file mode 100644
index 33509de..0000000
--- a/sound/soc/tegra/tegra_i2s.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * tegra_i2s.c - Tegra I2S driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- *
- * Copyright (c) 2009-2010, NVIDIA Corporation.
- * Scott Peterson <speterson@nvidia.com>
- *
- * Copyright (C) 2010 Google, Inc.
- * Iliyan Malchev <malchev@google.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <mach/iomap.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "tegra_i2s.h"
-
-#define DRV_NAME "tegra-i2s"
-
-static inline void tegra_i2s_write(struct tegra_i2s *i2s, u32 reg, u32 val)
-{
-	__raw_writel(val, i2s->regs + reg);
-}
-
-static inline u32 tegra_i2s_read(struct tegra_i2s *i2s, u32 reg)
-{
-	return __raw_readl(i2s->regs + reg);
-}
-
-#ifdef CONFIG_DEBUG_FS
-static int tegra_i2s_show(struct seq_file *s, void *unused)
-{
-#define REG(r) { r, #r }
-	static const struct {
-		int offset;
-		const char *name;
-	} regs[] = {
-		REG(TEGRA_I2S_CTRL),
-		REG(TEGRA_I2S_STATUS),
-		REG(TEGRA_I2S_TIMING),
-		REG(TEGRA_I2S_FIFO_SCR),
-		REG(TEGRA_I2S_PCM_CTRL),
-		REG(TEGRA_I2S_NW_CTRL),
-		REG(TEGRA_I2S_TDM_CTRL),
-		REG(TEGRA_I2S_TDM_TX_RX_CTRL),
-	};
-#undef REG
-
-	struct tegra_i2s *i2s = s->private;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(regs); i++) {
-		u32 val = tegra_i2s_read(i2s, regs[i].offset);
-		seq_printf(s, "%s = %08x\n", regs[i].name, val);
-	}
-
-	return 0;
-}
-
-static int tegra_i2s_debug_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, tegra_i2s_show, inode->i_private);
-}
-
-static const struct file_operations tegra_i2s_debug_fops = {
-	.open    = tegra_i2s_debug_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = single_release,
-};
-
-static void tegra_i2s_debug_add(struct tegra_i2s *i2s)
-{
-	i2s->debug = debugfs_create_file(i2s->dai.name, S_IRUGO,
-					 snd_soc_debugfs_root, i2s,
-					 &tegra_i2s_debug_fops);
-}
-
-static void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
-{
-	if (i2s->debug)
-		debugfs_remove(i2s->debug);
-}
-#else
-static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id)
-{
-}
-
-static inline void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
-{
-}
-#endif
-
-static int tegra_i2s_set_fmt(struct snd_soc_dai *dai,
-				unsigned int fmt)
-{
-	struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
-	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_NB_NF:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_MASTER_ENABLE;
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBS_CFS:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_MASTER_ENABLE;
-		break;
-	case SND_SOC_DAIFMT_CBM_CFM:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	i2s->reg_ctrl &= ~(TEGRA_I2S_CTRL_BIT_FORMAT_MASK | 
-				TEGRA_I2S_CTRL_LRCK_MASK);
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_DSP_A:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP;
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
-		break;
-	case SND_SOC_DAIFMT_DSP_B:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP;
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_R_LOW;
-		break;
-	case SND_SOC_DAIFMT_I2S:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_I2S;
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
-		break;
-	case SND_SOC_DAIFMT_RIGHT_J:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_RJM;
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
-		break;
-	case SND_SOC_DAIFMT_LEFT_J:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_LJM;
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int tegra_i2s_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params,
-				struct snd_soc_dai *dai)
-{
-        struct device *dev = substream->pcm->card->dev;
-	struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-	u32 reg;
-	int ret, sample_size, srate, i2sclock, bitcnt;
-
-	i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_BIT_SIZE_MASK;
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_16;
-		sample_size = 16;
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_24;
-		sample_size = 24;
-		break;
-	case SNDRV_PCM_FORMAT_S32_LE:
-		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_32;
-		sample_size = 32;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	srate = params_rate(params);
-
-	/* Final "* 2" required by Tegra hardware */
-	i2sclock = srate * params_channels(params) * sample_size * 2;
-
-	ret = clk_set_rate(i2s->clk_i2s, i2sclock);
-	if (ret) {
-		dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
-		return ret;
-	}
-
-	bitcnt = (i2sclock / (2 * srate)) - 1;
-	if (bitcnt < 0 || bitcnt > TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
-		return -EINVAL;
-	reg = bitcnt << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
-
-	if (i2sclock % (2 * srate))
-		reg |= TEGRA_I2S_TIMING_NON_SYM_ENABLE;
-
-	if (!i2s->clk_refs)
-		clk_enable(i2s->clk_i2s);
-
-	tegra_i2s_write(i2s, TEGRA_I2S_TIMING, reg);
-
-	tegra_i2s_write(i2s, TEGRA_I2S_FIFO_SCR,
-		TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
-		TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
-
-	if (!i2s->clk_refs)
-		clk_disable(i2s->clk_i2s);
-
-	return 0;
-}
-
-static void tegra_i2s_start_playback(struct tegra_i2s *i2s)
-{
-	i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO1_ENABLE;
-	tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static void tegra_i2s_stop_playback(struct tegra_i2s *i2s)
-{
-	i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO1_ENABLE;
-	tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static void tegra_i2s_start_capture(struct tegra_i2s *i2s)
-{
-	i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO2_ENABLE;
-	tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static void tegra_i2s_stop_capture(struct tegra_i2s *i2s)
-{
-	i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO2_ENABLE;
-	tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static int tegra_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-				struct snd_soc_dai *dai)
-{
-	struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-	case SNDRV_PCM_TRIGGER_RESUME:
-		if (!i2s->clk_refs)
-			clk_enable(i2s->clk_i2s);
-		i2s->clk_refs++;
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			tegra_i2s_start_playback(i2s);
-		else
-			tegra_i2s_start_capture(i2s);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			tegra_i2s_stop_playback(i2s);
-		else
-			tegra_i2s_stop_capture(i2s);
-		i2s->clk_refs--;
-		if (!i2s->clk_refs)
-			clk_disable(i2s->clk_i2s);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int tegra_i2s_probe(struct snd_soc_dai *dai)
-{
-	struct tegra_i2s * i2s = snd_soc_dai_get_drvdata(dai);
-
-	dai->capture_dma_data = &i2s->capture_dma_data;
-	dai->playback_dma_data = &i2s->playback_dma_data;
-
-	return 0;
-}
-
-static const struct snd_soc_dai_ops tegra_i2s_dai_ops = {
-	.set_fmt	= tegra_i2s_set_fmt,
-	.hw_params	= tegra_i2s_hw_params,
-	.trigger	= tegra_i2s_trigger,
-};
-
-static const struct snd_soc_dai_driver tegra_i2s_dai_template = {
-	.probe = tegra_i2s_probe,
-	.playback = {
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_96000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.capture = {
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_96000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.ops = &tegra_i2s_dai_ops,
-	.symmetric_rates = 1,
-};
-
-static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
-{
-	struct tegra_i2s * i2s;
-	struct resource *mem, *memregion, *dmareq;
-	u32 of_dma[2];
-	u32 dma_ch;
-	int ret;
-
-	i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2s), GFP_KERNEL);
-	if (!i2s) {
-		dev_err(&pdev->dev, "Can't allocate tegra_i2s\n");
-		ret = -ENOMEM;
-		goto err;
-	}
-	dev_set_drvdata(&pdev->dev, i2s);
-
-	i2s->dai = tegra_i2s_dai_template;
-	i2s->dai.name = dev_name(&pdev->dev);
-
-	i2s->clk_i2s = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(i2s->clk_i2s)) {
-		dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
-		ret = PTR_ERR(i2s->clk_i2s);
-		goto err;
-	}
-
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		dev_err(&pdev->dev, "No memory resource\n");
-		ret = -ENODEV;
-		goto err_clk_put;
-	}
-
-	dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (!dmareq) {
-		if (of_property_read_u32_array(pdev->dev.of_node,
-					"nvidia,dma-request-selector",
-					of_dma, 2) < 0) {
-			dev_err(&pdev->dev, "No DMA resource\n");
-			ret = -ENODEV;
-			goto err_clk_put;
-		}
-		dma_ch = of_dma[1];
-	} else {
-		dma_ch = dmareq->start;
-	}
-
-	memregion = devm_request_mem_region(&pdev->dev, mem->start,
-					    resource_size(mem), DRV_NAME);
-	if (!memregion) {
-		dev_err(&pdev->dev, "Memory region already claimed\n");
-		ret = -EBUSY;
-		goto err_clk_put;
-	}
-
-	i2s->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
-	if (!i2s->regs) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -ENOMEM;
-		goto err_clk_put;
-	}
-
-	i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2;
-	i2s->capture_dma_data.wrap = 4;
-	i2s->capture_dma_data.width = 32;
-	i2s->capture_dma_data.req_sel = dma_ch;
-
-	i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1;
-	i2s->playback_dma_data.wrap = 4;
-	i2s->playback_dma_data.width = 32;
-	i2s->playback_dma_data.req_sel = dma_ch;
-
-	i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED;
-
-	ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
-	if (ret) {
-		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
-		ret = -ENOMEM;
-		goto err_clk_put;
-	}
-
-	tegra_i2s_debug_add(i2s);
-
-	return 0;
-
-err_clk_put:
-	clk_put(i2s->clk_i2s);
-err:
-	return ret;
-}
-
-static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev)
-{
-	struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev);
-
-	snd_soc_unregister_dai(&pdev->dev);
-
-	tegra_i2s_debug_remove(i2s);
-
-	clk_put(i2s->clk_i2s);
-
-	return 0;
-}
-
-static const struct of_device_id tegra_i2s_of_match[] __devinitconst = {
-	{ .compatible = "nvidia,tegra20-i2s", },
-	{},
-};
-
-static struct platform_driver tegra_i2s_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-		.of_match_table = tegra_i2s_of_match,
-	},
-	.probe = tegra_i2s_platform_probe,
-	.remove = __devexit_p(tegra_i2s_platform_remove),
-};
-module_platform_driver(tegra_i2s_driver);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Tegra I2S ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, tegra_i2s_of_match);
diff --git a/sound/soc/tegra/tegra_i2s.h b/sound/soc/tegra/tegra_i2s.h
deleted file mode 100644
index 15ce1e2..0000000
--- a/sound/soc/tegra/tegra_i2s.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * tegra_i2s.h - Definitions for Tegra I2S driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- *
- * Copyright (c) 2009-2010, NVIDIA Corporation.
- * Scott Peterson <speterson@nvidia.com>
- *
- * Copyright (C) 2010 Google, Inc.
- * Iliyan Malchev <malchev@google.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __TEGRA_I2S_H__
-#define __TEGRA_I2S_H__
-
-#include "tegra_pcm.h"
-
-/* Register offsets from TEGRA_I2S1_BASE and TEGRA_I2S2_BASE */
-
-#define TEGRA_I2S_CTRL					0x00
-#define TEGRA_I2S_STATUS				0x04
-#define TEGRA_I2S_TIMING				0x08
-#define TEGRA_I2S_FIFO_SCR				0x0c
-#define TEGRA_I2S_PCM_CTRL				0x10
-#define TEGRA_I2S_NW_CTRL				0x14
-#define TEGRA_I2S_TDM_CTRL				0x20
-#define TEGRA_I2S_TDM_TX_RX_CTRL			0x24
-#define TEGRA_I2S_FIFO1					0x40
-#define TEGRA_I2S_FIFO2					0x80
-
-/* Fields in TEGRA_I2S_CTRL */
-
-#define TEGRA_I2S_CTRL_FIFO2_TX_ENABLE			(1 << 30)
-#define TEGRA_I2S_CTRL_FIFO1_ENABLE			(1 << 29)
-#define TEGRA_I2S_CTRL_FIFO2_ENABLE			(1 << 28)
-#define TEGRA_I2S_CTRL_FIFO1_RX_ENABLE			(1 << 27)
-#define TEGRA_I2S_CTRL_FIFO_LPBK_ENABLE			(1 << 26)
-#define TEGRA_I2S_CTRL_MASTER_ENABLE			(1 << 25)
-
-#define TEGRA_I2S_LRCK_LEFT_LOW				0
-#define TEGRA_I2S_LRCK_RIGHT_LOW			1
-
-#define TEGRA_I2S_CTRL_LRCK_SHIFT			24
-#define TEGRA_I2S_CTRL_LRCK_MASK			(1                        << TEGRA_I2S_CTRL_LRCK_SHIFT)
-#define TEGRA_I2S_CTRL_LRCK_L_LOW			(TEGRA_I2S_LRCK_LEFT_LOW  << TEGRA_I2S_CTRL_LRCK_SHIFT)
-#define TEGRA_I2S_CTRL_LRCK_R_LOW			(TEGRA_I2S_LRCK_RIGHT_LOW << TEGRA_I2S_CTRL_LRCK_SHIFT)
-
-#define TEGRA_I2S_BIT_FORMAT_I2S			0
-#define TEGRA_I2S_BIT_FORMAT_RJM			1
-#define TEGRA_I2S_BIT_FORMAT_LJM			2
-#define TEGRA_I2S_BIT_FORMAT_DSP			3
-
-#define TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT			10
-#define TEGRA_I2S_CTRL_BIT_FORMAT_MASK			(3                        << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_I2S			(TEGRA_I2S_BIT_FORMAT_I2S << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_RJM			(TEGRA_I2S_BIT_FORMAT_RJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_LJM			(TEGRA_I2S_BIT_FORMAT_LJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_DSP			(TEGRA_I2S_BIT_FORMAT_DSP << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-
-#define TEGRA_I2S_BIT_SIZE_16				0
-#define TEGRA_I2S_BIT_SIZE_20				1
-#define TEGRA_I2S_BIT_SIZE_24				2
-#define TEGRA_I2S_BIT_SIZE_32				3
-
-#define TEGRA_I2S_CTRL_BIT_SIZE_SHIFT			8
-#define TEGRA_I2S_CTRL_BIT_SIZE_MASK			(3                     << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_16			(TEGRA_I2S_BIT_SIZE_16 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_20			(TEGRA_I2S_BIT_SIZE_20 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_24			(TEGRA_I2S_BIT_SIZE_24 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_32			(TEGRA_I2S_BIT_SIZE_32 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-
-#define TEGRA_I2S_FIFO_16_LSB				0
-#define TEGRA_I2S_FIFO_20_LSB				1
-#define TEGRA_I2S_FIFO_24_LSB				2
-#define TEGRA_I2S_FIFO_32				3
-#define TEGRA_I2S_FIFO_PACKED				7
-
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT		4
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_MASK			(7                     << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_16_LSB		(TEGRA_I2S_FIFO_16_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_20_LSB		(TEGRA_I2S_FIFO_20_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_24_LSB		(TEGRA_I2S_FIFO_24_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_32			(TEGRA_I2S_FIFO_32     << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED		(TEGRA_I2S_FIFO_PACKED << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-
-#define TEGRA_I2S_CTRL_IE_FIFO1_ERR			(1 << 3)
-#define TEGRA_I2S_CTRL_IE_FIFO2_ERR			(1 << 2)
-#define TEGRA_I2S_CTRL_QE_FIFO1				(1 << 1)
-#define TEGRA_I2S_CTRL_QE_FIFO2				(1 << 0)
-
-/* Fields in TEGRA_I2S_STATUS */
-
-#define TEGRA_I2S_STATUS_FIFO1_RDY			(1 << 31)
-#define TEGRA_I2S_STATUS_FIFO2_RDY			(1 << 30)
-#define TEGRA_I2S_STATUS_FIFO1_BSY			(1 << 29)
-#define TEGRA_I2S_STATUS_FIFO2_BSY			(1 << 28)
-#define TEGRA_I2S_STATUS_FIFO1_ERR			(1 << 3)
-#define TEGRA_I2S_STATUS_FIFO2_ERR			(1 << 2)
-#define TEGRA_I2S_STATUS_QS_FIFO1			(1 << 1)
-#define TEGRA_I2S_STATUS_QS_FIFO2			(1 << 0)
-
-/* Fields in TEGRA_I2S_TIMING */
-
-#define TEGRA_I2S_TIMING_NON_SYM_ENABLE			(1 << 12)
-#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT	0
-#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US	0x7fff
-#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK		(TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT)
-
-/* Fields in TEGRA_I2S_FIFO_SCR */
-
-#define TEGRA_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT	24
-#define TEGRA_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT	16
-#define TEGRA_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK	0x3f
-
-#define TEGRA_I2S_FIFO_SCR_FIFO2_CLR			(1 << 12)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_CLR			(1 << 8)
-
-#define TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT			0
-#define TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS		1
-#define TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS		2
-#define TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS		3
-
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT		4
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK		(3 << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT	(TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT     << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS	(TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS   << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS	(TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS  << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS	(TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT		0
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK		(3 << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT	(TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT     << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS	(TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS   << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS	(TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS  << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS	(TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-
-struct tegra_i2s {
-	struct snd_soc_dai_driver dai;
-	struct clk *clk_i2s;
-	int clk_refs;
-	struct tegra_pcm_dma_params capture_dma_data;
-	struct tegra_pcm_dma_params playback_dma_data;
-	void __iomem *regs;
-	struct dentry *debug;
-	u32 reg_ctrl;
-};
-
-#endif
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 8b44571..127348d 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -2,7 +2,7 @@
  * tegra_pcm.c - Tegra PCM driver
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
  *
  * Based on code copyright/by:
  *
@@ -29,8 +29,8 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/dma-mapping.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -39,8 +39,6 @@
 
 #include "tegra_pcm.h"
 
-#define DRV_NAME "tegra-pcm-audio"
-
 static const struct snd_pcm_hardware tegra_pcm_hardware = {
 	.info			= SNDRV_PCM_INFO_MMAP |
 				  SNDRV_PCM_INFO_MMAP_VALID |
@@ -372,28 +370,18 @@
 	.pcm_free	= tegra_pcm_free,
 };
 
-static int __devinit tegra_pcm_platform_probe(struct platform_device *pdev)
+int __devinit tegra_pcm_platform_register(struct device *dev)
 {
-	return snd_soc_register_platform(&pdev->dev, &tegra_pcm_platform);
+	return snd_soc_register_platform(dev, &tegra_pcm_platform);
 }
+EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
 
-static int __devexit tegra_pcm_platform_remove(struct platform_device *pdev)
+void __devexit tegra_pcm_platform_unregister(struct device *dev)
 {
-	snd_soc_unregister_platform(&pdev->dev);
-	return 0;
+	snd_soc_unregister_platform(dev);
 }
-
-static struct platform_driver tegra_pcm_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-	},
-	.probe = tegra_pcm_platform_probe,
-	.remove = __devexit_p(tegra_pcm_platform_remove),
-};
-module_platform_driver(tegra_pcm_driver);
+EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
 
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("Tegra PCM ASoC driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index dbb9033..985d418 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -2,7 +2,7 @@
  * tegra_pcm.h - Definitions for Tegra PCM driver
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
  *
  * Based on code copyright/by:
  *
@@ -52,4 +52,7 @@
 	struct tegra_dma_channel *dma_chan;
 };
 
+int tegra_pcm_platform_register(struct device *dev);
+void tegra_pcm_platform_unregister(struct device *dev);
+
 #endif
diff --git a/sound/soc/tegra/tegra_spdif.c b/sound/soc/tegra/tegra_spdif.c
deleted file mode 100644
index 475428c..0000000
--- a/sound/soc/tegra/tegra_spdif.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * tegra_spdif.c - Tegra SPDIF driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2011 - NVIDIA, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <mach/iomap.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "tegra_spdif.h"
-
-#define DRV_NAME "tegra-spdif"
-
-static inline void tegra_spdif_write(struct tegra_spdif *spdif, u32 reg,
-					u32 val)
-{
-	__raw_writel(val, spdif->regs + reg);
-}
-
-static inline u32 tegra_spdif_read(struct tegra_spdif *spdif, u32 reg)
-{
-	return __raw_readl(spdif->regs + reg);
-}
-
-#ifdef CONFIG_DEBUG_FS
-static int tegra_spdif_show(struct seq_file *s, void *unused)
-{
-#define REG(r) { r, #r }
-	static const struct {
-		int offset;
-		const char *name;
-	} regs[] = {
-		REG(TEGRA_SPDIF_CTRL),
-		REG(TEGRA_SPDIF_STATUS),
-		REG(TEGRA_SPDIF_STROBE_CTRL),
-		REG(TEGRA_SPDIF_DATA_FIFO_CSR),
-		REG(TEGRA_SPDIF_CH_STA_RX_A),
-		REG(TEGRA_SPDIF_CH_STA_RX_B),
-		REG(TEGRA_SPDIF_CH_STA_RX_C),
-		REG(TEGRA_SPDIF_CH_STA_RX_D),
-		REG(TEGRA_SPDIF_CH_STA_RX_E),
-		REG(TEGRA_SPDIF_CH_STA_RX_F),
-		REG(TEGRA_SPDIF_CH_STA_TX_A),
-		REG(TEGRA_SPDIF_CH_STA_TX_B),
-		REG(TEGRA_SPDIF_CH_STA_TX_C),
-		REG(TEGRA_SPDIF_CH_STA_TX_D),
-		REG(TEGRA_SPDIF_CH_STA_TX_E),
-		REG(TEGRA_SPDIF_CH_STA_TX_F),
-	};
-#undef REG
-
-	struct tegra_spdif *spdif = s->private;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(regs); i++) {
-		u32 val = tegra_spdif_read(spdif, regs[i].offset);
-		seq_printf(s, "%s = %08x\n", regs[i].name, val);
-	}
-
-	return 0;
-}
-
-static int tegra_spdif_debug_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, tegra_spdif_show, inode->i_private);
-}
-
-static const struct file_operations tegra_spdif_debug_fops = {
-	.open    = tegra_spdif_debug_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = single_release,
-};
-
-static void tegra_spdif_debug_add(struct tegra_spdif *spdif)
-{
-	spdif->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
-						snd_soc_debugfs_root, spdif,
-						&tegra_spdif_debug_fops);
-}
-
-static void tegra_spdif_debug_remove(struct tegra_spdif *spdif)
-{
-	if (spdif->debug)
-		debugfs_remove(spdif->debug);
-}
-#else
-static inline void tegra_spdif_debug_add(struct tegra_spdif *spdif)
-{
-}
-
-static inline void tegra_spdif_debug_remove(struct tegra_spdif *spdif)
-{
-}
-#endif
-
-static int tegra_spdif_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params,
-				struct snd_soc_dai *dai)
-{
-	struct device *dev = substream->pcm->card->dev;
-	struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
-	int ret, spdifclock;
-
-	spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_PACK;
-	spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_BIT_MODE_MASK;
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_PACK;
-		spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_BIT_MODE_16BIT;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (params_rate(params)) {
-	case 32000:
-		spdifclock = 4096000;
-		break;
-	case 44100:
-		spdifclock = 5644800;
-		break;
-	case 48000:
-		spdifclock = 6144000;
-		break;
-	case 88200:
-		spdifclock = 11289600;
-		break;
-	case 96000:
-		spdifclock = 12288000;
-		break;
-	case 176400:
-		spdifclock = 22579200;
-		break;
-	case 192000:
-		spdifclock = 24576000;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);
-	if (ret) {
-		dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
-static void tegra_spdif_start_playback(struct tegra_spdif *spdif)
-{
-	spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_TX_EN;
-	tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl);
-}
-
-static void tegra_spdif_stop_playback(struct tegra_spdif *spdif)
-{
-	spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_TX_EN;
-	tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl);
-}
-
-static int tegra_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
-				struct snd_soc_dai *dai)
-{
-	struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-	case SNDRV_PCM_TRIGGER_RESUME:
-		if (!spdif->clk_refs)
-			clk_enable(spdif->clk_spdif_out);
-		spdif->clk_refs++;
-		tegra_spdif_start_playback(spdif);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-		tegra_spdif_stop_playback(spdif);
-		spdif->clk_refs--;
-		if (!spdif->clk_refs)
-			clk_disable(spdif->clk_spdif_out);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int tegra_spdif_probe(struct snd_soc_dai *dai)
-{
-	struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
-
-	dai->capture_dma_data = NULL;
-	dai->playback_dma_data = &spdif->playback_dma_data;
-
-	return 0;
-}
-
-static const struct snd_soc_dai_ops tegra_spdif_dai_ops = {
-	.hw_params	= tegra_spdif_hw_params,
-	.trigger	= tegra_spdif_trigger,
-};
-
-static struct snd_soc_dai_driver tegra_spdif_dai = {
-	.name = DRV_NAME,
-	.probe = tegra_spdif_probe,
-	.playback = {
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
-				SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-	},
-	.ops = &tegra_spdif_dai_ops,
-};
-
-static __devinit int tegra_spdif_platform_probe(struct platform_device *pdev)
-{
-	struct tegra_spdif *spdif;
-	struct resource *mem, *memregion, *dmareq;
-	int ret;
-
-	spdif = kzalloc(sizeof(struct tegra_spdif), GFP_KERNEL);
-	if (!spdif) {
-		dev_err(&pdev->dev, "Can't allocate tegra_spdif\n");
-		ret = -ENOMEM;
-		goto exit;
-	}
-	dev_set_drvdata(&pdev->dev, spdif);
-
-	spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out");
-	if (IS_ERR(spdif->clk_spdif_out)) {
-		pr_err("Can't retrieve spdif clock\n");
-		ret = PTR_ERR(spdif->clk_spdif_out);
-		goto err_free;
-	}
-
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		dev_err(&pdev->dev, "No memory resource\n");
-		ret = -ENODEV;
-		goto err_clk_put;
-	}
-
-	dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (!dmareq) {
-		dev_err(&pdev->dev, "No DMA resource\n");
-		ret = -ENODEV;
-		goto err_clk_put;
-	}
-
-	memregion = request_mem_region(mem->start, resource_size(mem),
-					DRV_NAME);
-	if (!memregion) {
-		dev_err(&pdev->dev, "Memory region already claimed\n");
-		ret = -EBUSY;
-		goto err_clk_put;
-	}
-
-	spdif->regs = ioremap(mem->start, resource_size(mem));
-	if (!spdif->regs) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -ENOMEM;
-		goto err_release;
-	}
-
-	spdif->playback_dma_data.addr = mem->start + TEGRA_SPDIF_DATA_OUT;
-	spdif->playback_dma_data.wrap = 4;
-	spdif->playback_dma_data.width = 32;
-	spdif->playback_dma_data.req_sel = dmareq->start;
-
-	ret = snd_soc_register_dai(&pdev->dev, &tegra_spdif_dai);
-	if (ret) {
-		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
-		ret = -ENOMEM;
-		goto err_unmap;
-	}
-
-	tegra_spdif_debug_add(spdif);
-
-	return 0;
-
-err_unmap:
-	iounmap(spdif->regs);
-err_release:
-	release_mem_region(mem->start, resource_size(mem));
-err_clk_put:
-	clk_put(spdif->clk_spdif_out);
-err_free:
-	kfree(spdif);
-exit:
-	return ret;
-}
-
-static int __devexit tegra_spdif_platform_remove(struct platform_device *pdev)
-{
-	struct tegra_spdif *spdif = dev_get_drvdata(&pdev->dev);
-	struct resource *res;
-
-	snd_soc_unregister_dai(&pdev->dev);
-
-	tegra_spdif_debug_remove(spdif);
-
-	iounmap(spdif->regs);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(res->start, resource_size(res));
-
-	clk_put(spdif->clk_spdif_out);
-
-	kfree(spdif);
-
-	return 0;
-}
-
-static struct platform_driver tegra_spdif_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-	},
-	.probe = tegra_spdif_platform_probe,
-	.remove = __devexit_p(tegra_spdif_platform_remove),
-};
-
-module_platform_driver(tegra_spdif_driver);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Tegra SPDIF ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_spdif.h b/sound/soc/tegra/tegra_spdif.h
deleted file mode 100644
index 2e03db4..0000000
--- a/sound/soc/tegra/tegra_spdif.h
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * tegra_spdif.h - Definitions for Tegra SPDIF driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2011 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- * Copyright (c) 2008-2009, NVIDIA Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __TEGRA_SPDIF_H__
-#define __TEGRA_SPDIF_H__
-
-#include "tegra_pcm.h"
-
-/* Offsets from TEGRA_SPDIF_BASE */
-
-#define TEGRA_SPDIF_CTRL					0x0
-#define TEGRA_SPDIF_STATUS					0x4
-#define TEGRA_SPDIF_STROBE_CTRL					0x8
-#define TEGRA_SPDIF_DATA_FIFO_CSR				0x0C
-#define TEGRA_SPDIF_DATA_OUT					0x40
-#define TEGRA_SPDIF_DATA_IN					0x80
-#define TEGRA_SPDIF_CH_STA_RX_A					0x100
-#define TEGRA_SPDIF_CH_STA_RX_B					0x104
-#define TEGRA_SPDIF_CH_STA_RX_C					0x108
-#define TEGRA_SPDIF_CH_STA_RX_D					0x10C
-#define TEGRA_SPDIF_CH_STA_RX_E					0x110
-#define TEGRA_SPDIF_CH_STA_RX_F					0x114
-#define TEGRA_SPDIF_CH_STA_TX_A					0x140
-#define TEGRA_SPDIF_CH_STA_TX_B					0x144
-#define TEGRA_SPDIF_CH_STA_TX_C					0x148
-#define TEGRA_SPDIF_CH_STA_TX_D					0x14C
-#define TEGRA_SPDIF_CH_STA_TX_E					0x150
-#define TEGRA_SPDIF_CH_STA_TX_F					0x154
-#define TEGRA_SPDIF_USR_STA_RX_A				0x180
-#define TEGRA_SPDIF_USR_DAT_TX_A				0x1C0
-
-/* Fields in TEGRA_SPDIF_CTRL */
-
-/* Start capturing from 0=right, 1=left channel */
-#define TEGRA_SPDIF_CTRL_CAP_LC					(1 << 30)
-
-/* SPDIF receiver(RX) enable */
-#define TEGRA_SPDIF_CTRL_RX_EN					(1 << 29)
-
-/* SPDIF Transmitter(TX) enable */
-#define TEGRA_SPDIF_CTRL_TX_EN					(1 << 28)
-
-/* Transmit Channel status */
-#define TEGRA_SPDIF_CTRL_TC_EN					(1 << 27)
-
-/* Transmit user Data */
-#define TEGRA_SPDIF_CTRL_TU_EN					(1 << 26)
-
-/* Interrupt on transmit error */
-#define TEGRA_SPDIF_CTRL_IE_TXE					(1 << 25)
-
-/* Interrupt on receive error */
-#define TEGRA_SPDIF_CTRL_IE_RXE					(1 << 24)
-
-/* Interrupt on invalid preamble */
-#define TEGRA_SPDIF_CTRL_IE_P					(1 << 23)
-
-/* Interrupt on "B" preamble */
-#define TEGRA_SPDIF_CTRL_IE_B					(1 << 22)
-
-/* Interrupt when block of channel status received */
-#define TEGRA_SPDIF_CTRL_IE_C					(1 << 21)
-
-/* Interrupt when a valid information unit (IU) is received */
-#define TEGRA_SPDIF_CTRL_IE_U					(1 << 20)
-
-/* Interrupt when RX user FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_RU					(1 << 19)
-
-/* Interrupt when TX user FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_TU					(1 << 18)
-
-/* Interrupt when RX data FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_RX					(1 << 17)
-
-/* Interrupt when TX data FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_TX					(1 << 16)
-
-/* Loopback test mode enable */
-#define TEGRA_SPDIF_CTRL_LBK_EN					(1 << 15)
-
-/*
- * Pack data mode:
- * 0 = Single data (16 bit needs to be  padded to match the
- *     interface data bit size).
- * 1 = Packeted left/right channel data into a single word.
- */
-#define TEGRA_SPDIF_CTRL_PACK					(1 << 14)
-
-/*
- * 00 = 16bit data
- * 01 = 20bit data
- * 10 = 24bit data
- * 11 = raw data
- */
-#define TEGRA_SPDIF_BIT_MODE_16BIT				0
-#define TEGRA_SPDIF_BIT_MODE_20BIT				1
-#define TEGRA_SPDIF_BIT_MODE_24BIT				2
-#define TEGRA_SPDIF_BIT_MODE_RAW				3
-
-#define TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT				12
-#define TEGRA_SPDIF_CTRL_BIT_MODE_MASK				(3                          << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_16BIT				(TEGRA_SPDIF_BIT_MODE_16BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_20BIT				(TEGRA_SPDIF_BIT_MODE_20BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_24BIT				(TEGRA_SPDIF_BIT_MODE_24BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_RAW				(TEGRA_SPDIF_BIT_MODE_RAW   << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-
-/* Fields in TEGRA_SPDIF_STATUS */
-
-/*
- * Note: IS_P, IS_B, IS_C, and IS_U are sticky bits. Software must
- * write a 1 to the corresponding bit location to clear the status.
- */
-
-/*
- * Receiver(RX) shifter is busy receiving data.
- * This bit is asserted when the receiver first locked onto the
- * preamble of the data stream after RX_EN is asserted. This bit is
- * deasserted when either,
- * (a) the end of a frame is reached after RX_EN is deeasserted, or
- * (b) the SPDIF data stream becomes inactive.
- */
-#define TEGRA_SPDIF_STATUS_RX_BSY				(1 << 29)
-
-/*
- * Transmitter(TX) shifter is busy transmitting data.
- * This bit is asserted when TX_EN is asserted.
- * This bit is deasserted when the end of a frame is reached after
- * TX_EN is deasserted.
- */
-#define TEGRA_SPDIF_STATUS_TX_BSY				(1 << 28)
-
-/*
- * TX is busy shifting out channel status.
- * This bit is asserted when both TX_EN and TC_EN are asserted and
- * data from CH_STA_TX_A register is loaded into the internal shifter.
- * This bit is deasserted when either,
- * (a) the end of a frame is reached after TX_EN is deasserted, or
- * (b) CH_STA_TX_F register is loaded into the internal shifter.
- */
-#define TEGRA_SPDIF_STATUS_TC_BSY				(1 << 27)
-
-/*
- * TX User data FIFO busy.
- * This bit is asserted when TX_EN and TXU_EN are asserted and
- * there's data in the TX user FIFO.  This bit is deassert when either,
- * (a) the end of a frame is reached after TX_EN is deasserted, or
- * (b) there's no data left in the TX user FIFO.
- */
-#define TEGRA_SPDIF_STATUS_TU_BSY				(1 << 26)
-
-/* TX FIFO Underrun error status */
-#define TEGRA_SPDIF_STATUS_TX_ERR				(1 << 25)
-
-/* RX FIFO Overrun error status */
-#define TEGRA_SPDIF_STATUS_RX_ERR				(1 << 24)
-
-/* Preamble status: 0=Preamble OK, 1=bad/missing preamble */
-#define TEGRA_SPDIF_STATUS_IS_P					(1 << 23)
-
-/* B-preamble detection status: 0=not detected, 1=B-preamble detected */
-#define TEGRA_SPDIF_STATUS_IS_B					(1 << 22)
-
-/*
- * RX channel block data receive status:
- * 0=entire block not recieved yet.
- * 1=received entire block of channel status,
- */
-#define TEGRA_SPDIF_STATUS_IS_C					(1 << 21)
-
-/* RX User Data Valid flag:  1=valid IU detected, 0 = no IU detected. */
-#define TEGRA_SPDIF_STATUS_IS_U					(1 << 20)
-
-/*
- * RX User FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_RU				(1 << 19)
-
-/*
- * TX User FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_TU				(1 << 18)
-
-/*
- * RX Data FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_RX				(1 << 17)
-
-/*
- * TX Data FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_TX				(1 << 16)
-
-/* Fields in TEGRA_SPDIF_STROBE_CTRL */
-
-/*
- * Indicates the approximate number of detected SPDIFIN clocks within a
- * bi-phase period.
- */
-#define TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT			16
-#define TEGRA_SPDIF_STROBE_CTRL_PERIOD_MASK			(0xff << TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT)
-
-/* Data strobe mode: 0=Auto-locked 1=Manual locked */
-#define TEGRA_SPDIF_STROBE_CTRL_STROBE				(1 << 15)
-
-/*
- * Manual data strobe time within the bi-phase clock period (in terms of
- * the number of over-sampling clocks).
- */
-#define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT		8
-#define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_MASK		(0x1f << TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT)
-
-/*
- * Manual SPDIFIN bi-phase clock period (in terms of the number of
- * over-sampling clocks).
- */
-#define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT		0
-#define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK		(0x3f << TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT)
-
-/* Fields in SPDIF_DATA_FIFO_CSR */
-
-/* Clear Receiver User FIFO (RX USR.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_CLR			(1 << 31)
-
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT			0
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS			1
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS			2
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS			3
-
-/* RU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT		29
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_MASK		\
-		(0x3                                    << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU1_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU2_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU3_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU4_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-
-/* Number of RX USR.FIFO levels with valid data. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT		24
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_MASK		(0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT)
-
-/* Clear Transmitter User FIFO (TX USR.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_CLR			(1 << 23)
-
-/* TU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT		21
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_MASK		\
-		(0x3                                   << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU1_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU2_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU3_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU4_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-
-/* Number of TX USR.FIFO levels that could be filled. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT		16
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_MASK		(0x1f << SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT)
-
-/* Clear Receiver Data FIFO (RX DATA.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_CLR			(1 << 15)
-
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT			0
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS			1
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS			2
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS			3
-
-/* RU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT		13
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_MASK		\
-		(0x3                                     << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU1_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU4_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU8_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU12_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-
-/* Number of RX DATA.FIFO levels with valid data. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT		8
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_MASK		(0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT)
-
-/* Clear Transmitter Data FIFO (TX DATA.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_CLR			(1 << 7)
-
-/* TU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT		5
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK		\
-		(0x3                                     << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU1_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU8_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU12_WORD_FULL	\
-		(TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-
-/* Number of TX DATA.FIFO levels that could be filled. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT		0
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_MASK		(0x1f << SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT)
-
-/* Fields in TEGRA_SPDIF_DATA_OUT */
-
-/*
- * This register has 5 different formats:
- * 16-bit        (BIT_MODE=00, PACK=0)
- * 20-bit        (BIT_MODE=01, PACK=0)
- * 24-bit        (BIT_MODE=10, PACK=0)
- * raw           (BIT_MODE=11, PACK=0)
- * 16-bit packed (BIT_MODE=00, PACK=1)
- */
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT			0
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_MASK			(0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT			0
-#define TEGRA_SPDIF_DATA_OUT_DATA_20_MASK			(0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT			0
-#define TEGRA_SPDIF_DATA_OUT_DATA_24_MASK			(0xffffff << TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_P				(1 << 31)
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_C				(1 << 30)
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_U				(1 << 29)
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_V				(1 << 28)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT		8
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_MASK			(0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT			4
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_MASK			(0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT		0
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_MASK		(0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT		16
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_MASK		(0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT		0
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_MASK		(0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT)
-
-/* Fields in TEGRA_SPDIF_DATA_IN */
-
-/*
- * This register has 5 different formats:
- * 16-bit        (BIT_MODE=00, PACK=0)
- * 20-bit        (BIT_MODE=01, PACK=0)
- * 24-bit        (BIT_MODE=10, PACK=0)
- * raw           (BIT_MODE=11, PACK=0)
- * 16-bit packed (BIT_MODE=00, PACK=1)
- *
- * Bits 31:24 are common to all modes except 16-bit packed
- */
-
-#define TEGRA_SPDIF_DATA_IN_DATA_P				(1 << 31)
-#define TEGRA_SPDIF_DATA_IN_DATA_C				(1 << 30)
-#define TEGRA_SPDIF_DATA_IN_DATA_U				(1 << 29)
-#define TEGRA_SPDIF_DATA_IN_DATA_V				(1 << 28)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT			24
-#define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_MASK			(0xf << TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT			0
-#define TEGRA_SPDIF_DATA_IN_DATA_16_MASK			(0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT			0
-#define TEGRA_SPDIF_DATA_IN_DATA_20_MASK			(0xfffff << TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT			0
-#define TEGRA_SPDIF_DATA_IN_DATA_24_MASK			(0xffffff << TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT			8
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_MASK			(0xfffff << TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT			4
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_MASK			(0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT		0
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_MASK		(0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT		16
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_MASK		(0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT		0
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_MASK		(0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT)
-
-/* Fields in TEGRA_SPDIF_CH_STA_RX_A */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_B */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_C */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_D */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_E */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_F */
-
-/*
- * The 6-word receive channel data page buffer holds a block (192 frames) of
- * channel status information. The order of receive is from LSB to MSB
- * bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A.
- */
-
-/* Fields in TEGRA_SPDIF_CH_STA_TX_A */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_B */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_C */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_D */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_E */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_F */
-
-/*
- * The 6-word transmit channel data page buffer holds a block (192 frames) of
- * channel status information. The order of transmission is from LSB to MSB
- * bit, and from CH_STA_TX_A to CH_STA_TX_F then back to CH_STA_TX_A.
- */
-
-/* Fields in TEGRA_SPDIF_USR_STA_RX_A */
-
-/*
- * This 4-word deep FIFO receives user FIFO field information. The order of
- * receive is from LSB to MSB bit.
- */
-
-/* Fields in TEGRA_SPDIF_USR_DAT_TX_A */
-
-/*
- * This 4-word deep FIFO transmits user FIFO field information. The order of
- * transmission is from LSB to MSB bit.
- */
-
-struct tegra_spdif {
-	struct clk *clk_spdif_out;
-	int clk_refs;
-	struct tegra_pcm_dma_params capture_dma_data;
-	struct tegra_pcm_dma_params playback_dma_data;
-	void __iomem *regs;
-	struct dentry *debug;
-	u32 reg_ctrl;
-};
-
-#endif
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 566655e..0b0df49 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -2,7 +2,7 @@
  * tegra_wm8903.c - Tegra machine ASoC driver for boards using WM8903 codec.
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010-2011 - NVIDIA, Inc.
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
  *
  * Based on code copyright/by:
  *
@@ -46,9 +46,6 @@
 
 #include "../codecs/wm8903.h"
 
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
 #include "tegra_asoc_utils.h"
 
 #define DRV_NAME "tegra-snd-wm8903"
@@ -61,7 +58,6 @@
 
 struct tegra_wm8903 {
 	struct tegra_wm8903_platform_data pdata;
-	struct platform_device *pcm_dev;
 	struct tegra_asoc_utils_data util_data;
 	int gpio_requested;
 };
@@ -354,8 +350,8 @@
 	.name = "WM8903",
 	.stream_name = "WM8903 PCM",
 	.codec_name = "wm8903.0-001a",
-	.platform_name = "tegra-pcm-audio",
-	.cpu_dai_name = "tegra-i2s.0",
+	.platform_name = "tegra20-i2s.0",
+	.cpu_dai_name = "tegra20-i2s.0",
 	.codec_dai_name = "wm8903-hifi",
 	.init = tegra_wm8903_init,
 	.ops = &tegra_wm8903_ops,
@@ -392,7 +388,6 @@
 		ret = -ENOMEM;
 		goto err;
 	}
-	machine->pcm_dev = ERR_PTR(-EINVAL);
 
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
@@ -428,14 +423,9 @@
 			goto err;
 		}
 
-		machine->pcm_dev = platform_device_register_simple(
-					"tegra-pcm-audio", -1, NULL, 0);
-		if (IS_ERR(machine->pcm_dev)) {
-			dev_err(&pdev->dev,
-				"Can't instantiate tegra-pcm-audio\n");
-			ret = PTR_ERR(machine->pcm_dev);
-			goto err;
-		}
+		tegra_wm8903_dai.platform_name = NULL;
+		tegra_wm8903_dai.platform_of_node =
+					tegra_wm8903_dai.cpu_dai_of_node;
 	} else {
 		if (machine_is_harmony()) {
 			card->dapm_routes = harmony_audio_map;
@@ -454,7 +444,7 @@
 
 	ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
 	if (ret)
-		goto err_unregister;
+		goto err;
 
 	ret = snd_soc_register_card(card);
 	if (ret) {
@@ -467,9 +457,6 @@
 
 err_fini_utils:
 	tegra_asoc_utils_fini(&machine->util_data);
-err_unregister:
-	if (!IS_ERR(machine->pcm_dev))
-		platform_device_unregister(machine->pcm_dev);
 err:
 	return ret;
 }
@@ -497,8 +484,6 @@
 	snd_soc_unregister_card(card);
 
 	tegra_asoc_utils_fini(&machine->util_data);
-	if (!IS_ERR(machine->pcm_dev))
-		platform_device_unregister(machine->pcm_dev);
 
 	return 0;
 }
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
index 2bdfc550..0fd115e 100644
--- a/sound/soc/tegra/trimslice.c
+++ b/sound/soc/tegra/trimslice.c
@@ -38,9 +38,6 @@
 
 #include "../codecs/tlv320aic23.h"
 
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
 #include "tegra_asoc_utils.h"
 
 #define DRV_NAME "tegra-snd-trimslice"
@@ -119,8 +116,8 @@
 	.name = "TLV320AIC23",
 	.stream_name = "AIC23",
 	.codec_name = "tlv320aic23-codec.2-001a",
-	.platform_name = "tegra-pcm-audio",
-	.cpu_dai_name = "tegra-i2s.0",
+	.platform_name = "tegra20-i2s.0",
+	.cpu_dai_name = "tegra20-i2s.0",
 	.codec_dai_name = "tlv320aic23-hifi",
 	.ops = &trimslice_asoc_ops,
 };