Merge branch 'asoc-omap' into for-3.7
diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt
new file mode 100644
index 0000000..6b222f9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cs4270.txt
@@ -0,0 +1,21 @@
+CS4270 audio CODEC
+
+The driver for this device currently only supports I2C.
+
+Required properties:
+
+  - compatible : "cirrus,cs4270"
+
+  - reg : the I2C address of the device for I2C
+
+Optional properties:
+
+  - reset-gpio : a GPIO spec for the reset pin. If specified, it will be
+		 deasserted before communication to the codec starts.
+
+Example:
+
+codec: cs4270@48 {
+	compatible = "cirrus,cs4270";
+	reg = <0x48>;
+};
diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
new file mode 100644
index 0000000..e6148ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
@@ -0,0 +1,44 @@
+Texas Instruments McASP controller
+
+Required properties:
+- compatible :
+	"ti,dm646x-mcasp-audio"	: for DM646x platforms
+	"ti,da830-mcasp-audio"	: for both DA830 & DA850 platforms
+
+- reg : Should contain McASP registers offset and length
+- interrupts : Interrupt number for McASP
+- op-mode : I2S/DIT ops mode.
+- tdm-slots : Slots for TDM operation.
+- num-serializer : Serializers used by McASP.
+- serial-dir : A list of serializer pin mode. The list number should be equal
+		to "num-serializer" parameter. Each entry is a number indication
+		serializer pin direction. (0 - INACTIVE, 1 - TX, 2 - RX)
+
+
+Optional properties:
+
+- ti,hwmods : Must be "mcasp<n>", n is controller instance starting 0
+- tx-num-evt : FIFO levels.
+- rx-num-evt : FIFO levels.
+- sram-size-playback : size of sram to be allocated during playback
+- sram-size-capture  : size of sram to be allocated during capture
+
+Example:
+
+mcasp0: mcasp0@1d00000 {
+	compatible = "ti,da830-mcasp-audio";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	reg = <0x100000 0x3000>;
+	interrupts = <82 83>;
+	op-mode = <0>;		/* MCASP_IIS_MODE */
+	tdm-slots = <2>;
+	num-serializer = <16>;
+	serial-dir = <
+			0 0 0 0	/* 0: INACTIVE, 1: TX, 2: RX */
+			0 0 0 0
+			0 0 0 1
+			2 0 0 0 >;
+	tx-num-evt = <1>;
+	rx-num-evt = <1>;
+};
diff --git a/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt
new file mode 100644
index 0000000..65dec87
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt
@@ -0,0 +1,91 @@
+* Texas Instruments OMAP4+ and twl6040 based audio setups
+
+Required properties:
+- compatible: "ti,abe-twl6040"
+- ti,model: Name of the sound card ( for example "SDP4430")
+- ti,mclk-freq: MCLK frequency for HPPLL operation
+- ti,mcpdm: phandle for the McPDM node
+- ti,twl6040: phandle for the twl6040 core node
+- ti,audio-routing: List of 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.
+
+Optional properties:
+- ti,dmic: phandle for the OMAP dmic node if the machine have it connected
+- ti,jack_detection: Need to be set to <1> if the board capable to detect jack
+  insertion, removal.
+
+Available audio endpoints for the audio-routing table:
+
+Board connectors:
+ * Headset Stereophone
+ * Earphone Spk
+ * Ext Spk
+ * Line Out
+ * Vibrator
+ * Headset Mic
+ * Main Handset Mic
+ * Sub Handset Mic
+ * Line In
+ * Digital Mic
+
+twl6040 pins:
+ * HSOL
+ * HSOR
+ * EP
+ * HFL
+ * HFR
+ * AUXL
+ * AUXR
+ * VIBRAL
+ * VIBRAR
+ * HSMIC
+ * MAINMIC
+ * SUBMIC
+ * AFML
+ * AFMR
+
+ * Headset Mic Bias
+ * Main Mic Bias
+ * Digital Mic1 Bias
+ * Digital Mic2 Bias
+
+Digital mic pins:
+ * DMic
+
+Example:
+
+sound {
+	compatible = "ti,abe-twl6040";
+	ti,model = "SDP4430";
+
+	ti,jack-detection = <1>;
+	ti,mclk-freq = <38400000>;
+
+	ti,mcpdm = <&mcpdm>;
+	ti,dmic = <&dmic>;
+
+	ti,twl6040 = <&twl6040>;
+
+	/* Audio routing */
+	ti,audio-routing =
+		"Headset Stereophone", "HSOL",
+		"Headset Stereophone", "HSOR",
+		"Earphone Spk", "EP",
+		"Ext Spk", "HFL",
+		"Ext Spk", "HFR",
+		"Line Out", "AUXL",
+		"Line Out", "AUXR",
+		"Vibrator", "VIBRAL",
+		"Vibrator", "VIBRAR",
+		"HSMIC", "Headset Mic",
+		"Headset Mic", "Headset Mic Bias",
+		"MAINMIC", "Main Handset Mic",
+		"Main Handset Mic", "Main Mic Bias",
+		"SUBMIC", "Sub Handset Mic",
+		"Sub Handset Mic", "Main Mic Bias",
+		"AFML", "Line In",
+		"AFMR", "Line In",
+		"DMic", "Digital Mic",
+		"Digital Mic", "Digital Mic1 Bias";
+};
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
new file mode 100644
index 0000000..e7b98f4
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
@@ -0,0 +1,20 @@
+Texas Instruments - tlv320aic3x Codec module
+
+The tlv320aic3x serial control bus communicates through I2C protocols
+
+Required properties:
+- compatible - "string" -  "ti,tlv320aic3x"
+- reg - <int> -  I2C slave address
+
+
+Optional properties:
+
+- gpio-reset - gpio pin number used for codec reset
+- ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
+
+Example:
+
+tlv320aic3x: tlv320aic3x@1b {
+	compatible = "ti,tlv320aic3x";
+	reg = <0x1b>;
+};
diff --git a/arch/arm/mach-davinci/asp.h b/arch/arm/mach-davinci/asp.h
new file mode 100644
index 0000000..d9b2acd
--- /dev/null
+++ b/arch/arm/mach-davinci/asp.h
@@ -0,0 +1,49 @@
+/*
+ * TI DaVinci Audio definitions
+ */
+#ifndef __ASM_ARCH_DAVINCI_ASP_H
+#define __ASM_ARCH_DAVINCI_ASP_H
+
+/* Bases of dm644x and dm355 register banks */
+#define DAVINCI_ASP0_BASE	0x01E02000
+#define DAVINCI_ASP1_BASE	0x01E04000
+
+/* Bases of dm365 register banks */
+#define DAVINCI_DM365_ASP0_BASE	0x01D02000
+
+/* Bases of dm646x register banks */
+#define DAVINCI_DM646X_MCASP0_REG_BASE		0x01D01000
+#define DAVINCI_DM646X_MCASP1_REG_BASE		0x01D01800
+
+/* Bases of da850/da830 McASP0  register banks */
+#define DAVINCI_DA8XX_MCASP0_REG_BASE	0x01D00000
+
+/* Bases of da830 McASP1 register banks */
+#define DAVINCI_DA830_MCASP1_REG_BASE	0x01D04000
+
+/* EDMA channels of dm644x and dm355 */
+#define DAVINCI_DMA_ASP0_TX	2
+#define DAVINCI_DMA_ASP0_RX	3
+#define DAVINCI_DMA_ASP1_TX	8
+#define DAVINCI_DMA_ASP1_RX	9
+
+/* EDMA channels of dm646x */
+#define DAVINCI_DM646X_DMA_MCASP0_AXEVT0	6
+#define DAVINCI_DM646X_DMA_MCASP0_AREVT0	9
+#define DAVINCI_DM646X_DMA_MCASP1_AXEVT1	12
+
+/* EDMA channels of da850/da830 McASP0 */
+#define DAVINCI_DA8XX_DMA_MCASP0_AREVT	0
+#define DAVINCI_DA8XX_DMA_MCASP0_AXEVT	1
+
+/* EDMA channels of da830 McASP1 */
+#define DAVINCI_DA830_DMA_MCASP1_AREVT	2
+#define DAVINCI_DA830_DMA_MCASP1_AXEVT	3
+
+/* Interrupts */
+#define DAVINCI_ASP0_RX_INT	IRQ_MBRINT
+#define DAVINCI_ASP0_TX_INT	IRQ_MBXINT
+#define DAVINCI_ASP1_RX_INT	IRQ_MBRINT
+#define DAVINCI_ASP1_TX_INT	IRQ_MBXINT
+
+#endif /* __ASM_ARCH_DAVINCI_ASP_H */
diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h
index 8db0fc6..8661b20 100644
--- a/arch/arm/mach-davinci/davinci.h
+++ b/arch/arm/mach-davinci/davinci.h
@@ -22,10 +22,11 @@
 #include <linux/davinci_emac.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
+#include <linux/platform_data/davinci_asp.h>
 
-#include <mach/asp.h>
 #include <mach/keyscan.h>
 #include <mach/hardware.h>
+#include <mach/edma.h>
 
 #include <media/davinci/vpfe_capture.h>
 #include <media/davinci/vpif_types.h>
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 783eab6..bd2f72b 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -24,6 +24,7 @@
 #include <mach/cpuidle.h>
 
 #include "clock.h"
+#include "asp.h"
 
 #define DA8XX_TPCC_BASE			0x01c00000
 #define DA8XX_TPTC0_BASE		0x01c08000
@@ -505,15 +506,8 @@
 	.resource	= da850_mcasp_resources,
 };
 
-static struct platform_device davinci_pcm_device = {
-	.name	= "davinci-pcm-audio",
-	.id	= -1,
-};
-
 void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata)
 {
-	platform_device_register(&davinci_pcm_device);
-
 	/* DA830/OMAP-L137 has 3 instances of McASP */
 	if (cpu_is_davinci_da830() && id == 1) {
 		da830_mcasp1_device.dev.platform_data = pdata;
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
index d2f96662..70056fb 100644
--- a/arch/arm/mach-davinci/devices.c
+++ b/arch/arm/mach-davinci/devices.c
@@ -313,16 +313,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-static struct platform_device davinci_pcm_device = {
-	.name		= "davinci-pcm-audio",
-	.id		= -1,
-};
-
-static void davinci_init_pcm(void)
-{
-	platform_device_register(&davinci_pcm_device);
-}
-
 /*-------------------------------------------------------------------------*/
 
 struct davinci_timer_instance davinci_timer_instance[2] = {
@@ -345,7 +335,6 @@
 	/* please keep these calls, and their implementations above,
 	 * in alphabetical order so they're easier to sort through.
 	 */
-	davinci_init_pcm();
 	davinci_init_wdt();
 
 	return 0;
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index 678cd99..e47a3f0 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -26,13 +26,13 @@
 #include <mach/time.h>
 #include <mach/serial.h>
 #include <mach/common.h>
-#include <mach/asp.h>
 #include <mach/spi.h>
 #include <mach/gpio-davinci.h>
 
 #include "davinci.h"
 #include "clock.h"
 #include "mux.h"
+#include "asp.h"
 
 #define DM355_UART2_BASE	(IO_PHYS + 0x206000)
 
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index a50d49de..f473745 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -29,7 +29,6 @@
 #include <mach/time.h>
 #include <mach/serial.h>
 #include <mach/common.h>
-#include <mach/asp.h>
 #include <mach/keyscan.h>
 #include <mach/spi.h>
 #include <mach/gpio-davinci.h>
@@ -37,6 +36,7 @@
 #include "davinci.h"
 #include "clock.h"
 #include "mux.h"
+#include "asp.h"
 
 #define DM365_REF_FREQ		24000000	/* 24 MHz on the DM365 EVM */
 
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index c8b8666..0755d46 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -23,12 +23,12 @@
 #include <mach/time.h>
 #include <mach/serial.h>
 #include <mach/common.h>
-#include <mach/asp.h>
 #include <mach/gpio-davinci.h>
 
 #include "davinci.h"
 #include "clock.h"
 #include "mux.h"
+#include "asp.h"
 
 /*
  * Device specific clocks
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
index 9eb87c1..97c0f8e 100644
--- a/arch/arm/mach-davinci/dm646x.c
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -24,12 +24,12 @@
 #include <mach/time.h>
 #include <mach/serial.h>
 #include <mach/common.h>
-#include <mach/asp.h>
 #include <mach/gpio-davinci.h>
 
 #include "davinci.h"
 #include "clock.h"
 #include "mux.h"
+#include "asp.h"
 
 #define DAVINCI_VPIF_BASE       (0x01C12000)
 
diff --git a/arch/arm/mach-davinci/include/mach/asp.h b/arch/arm/mach-davinci/include/mach/asp.h
deleted file mode 100644
index 9aa2409..0000000
--- a/arch/arm/mach-davinci/include/mach/asp.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * <mach/asp.h> - DaVinci Audio Serial Port support
- */
-#ifndef __ASM_ARCH_DAVINCI_ASP_H
-#define __ASM_ARCH_DAVINCI_ASP_H
-
-#include <mach/irqs.h>
-#include <mach/edma.h>
-
-/* Bases of dm644x and dm355 register banks */
-#define DAVINCI_ASP0_BASE	0x01E02000
-#define DAVINCI_ASP1_BASE	0x01E04000
-
-/* Bases of dm365 register banks */
-#define DAVINCI_DM365_ASP0_BASE	0x01D02000
-
-/* Bases of dm646x register banks */
-#define	DAVINCI_DM646X_MCASP0_REG_BASE		0x01D01000
-#define DAVINCI_DM646X_MCASP1_REG_BASE		0x01D01800
-
-/* Bases of da850/da830 McASP0  register banks */
-#define DAVINCI_DA8XX_MCASP0_REG_BASE	0x01D00000
-
-/* Bases of da830 McASP1 register banks */
-#define DAVINCI_DA830_MCASP1_REG_BASE	0x01D04000
-
-/* EDMA channels of dm644x and dm355 */
-#define DAVINCI_DMA_ASP0_TX	2
-#define DAVINCI_DMA_ASP0_RX	3
-#define DAVINCI_DMA_ASP1_TX	8
-#define DAVINCI_DMA_ASP1_RX	9
-
-/* EDMA channels of dm646x */
-#define	DAVINCI_DM646X_DMA_MCASP0_AXEVT0	6
-#define	DAVINCI_DM646X_DMA_MCASP0_AREVT0	9
-#define	DAVINCI_DM646X_DMA_MCASP1_AXEVT1	12
-
-/* EDMA channels of da850/da830 McASP0 */
-#define	DAVINCI_DA8XX_DMA_MCASP0_AREVT	0
-#define	DAVINCI_DA8XX_DMA_MCASP0_AXEVT	1
-
-/* EDMA channels of da830 McASP1 */
-#define	DAVINCI_DA830_DMA_MCASP1_AREVT	2
-#define	DAVINCI_DA830_DMA_MCASP1_AXEVT	3
-
-/* Interrupts */
-#define DAVINCI_ASP0_RX_INT	IRQ_MBRINT
-#define DAVINCI_ASP0_TX_INT	IRQ_MBXINT
-#define DAVINCI_ASP1_RX_INT	IRQ_MBRINT
-#define DAVINCI_ASP1_TX_INT	IRQ_MBXINT
-
-struct snd_platform_data {
-	u32 tx_dma_offset;
-	u32 rx_dma_offset;
-	enum dma_event_q asp_chan_q;	/* event queue number for ASP channel */
-	enum dma_event_q ram_chan_q;	/* event queue number for RAM channel */
-	unsigned int codec_fmt;
-	/*
-	 * Allowing this is more efficient and eliminates left and right swaps
-	 * caused by underruns, but will swap the left and right channels
-	 * when compared to previous behavior.
-	 */
-	unsigned enable_channel_combine:1;
-	unsigned sram_size_playback;
-	unsigned sram_size_capture;
-
-	/*
-	 * If McBSP peripheral gets the clock from an external pin,
-	 * there are three chooses, that are MCBSP_CLKX, MCBSP_CLKR
-	 * and MCBSP_CLKS.
-	 * Depending on different hardware connections it is possible
-	 * to use this setting to change the behaviour of McBSP
-	 * driver. The dm365_clk_input_pin enum is available for dm365
-	 */
-	int clk_input_pin;
-
-	/*
-	 * This flag works when both clock and FS are outputs for the cpu
-	 * and makes clock more accurate (FS is not symmetrical and the
-	 * clock is very fast.
-	 * The clock becoming faster is named
-	 * i2s continuous serial clock (I2S_SCK) and it is an externally
-	 * visible bit clock.
-	 *
-	 * first line : WordSelect
-	 * second line : ContinuousSerialClock
-	 * third line: SerialData
-	 *
-	 * SYMMETRICAL APPROACH:
-	 *   _______________________          LEFT
-	 * _|         RIGHT         |______________________|
-	 *     _   _         _   _   _   _         _   _
-	 *   _| |_| |_ x16 _| |_| |_| |_| |_ x16 _| |_| |_
-	 *     _   _         _   _   _   _         _   _
-	 *   _/ \_/ \_ ... _/ \_/ \_/ \_/ \_ ... _/ \_/ \_
-	 *    \_/ \_/       \_/ \_/ \_/ \_/       \_/ \_/
-	 *
-	 * ACCURATE CLOCK APPROACH:
-	 *   ______________          LEFT
-	 * _|     RIGHT    |_______________________________|
-	 *     _         _   _         _   _   _   _   _   _
-	 *   _| |_ x16 _| |_| |_ x16 _| |_| |_| |_| |_| |_| |
-	 *     _         _   _          _      dummy cycles
-	 *   _/ \_ ... _/ \_/ \_  ... _/ \__________________
-	 *    \_/       \_/ \_/        \_/
-	 *
-	 */
-	bool i2s_accurate_sck;
-
-	/* McASP specific fields */
-	int tdm_slots;
-	u8 op_mode;
-	u8 num_serializer;
-	u8 *serial_dir;
-	u8 version;
-	u8 txnumevt;
-	u8 rxnumevt;
-};
-
-enum {
-	MCASP_VERSION_1 = 0,	/* DM646x */
-	MCASP_VERSION_2,	/* DA8xx/OMAPL1x */
-};
-
-enum dm365_clk_input_pin {
-	MCBSP_CLKR = 0,		/* DM365 */
-	MCBSP_CLKS,
-};
-
-#define INACTIVE_MODE	0
-#define TX_MODE		1
-#define RX_MODE		2
-
-#define DAVINCI_MCASP_IIS_MODE	0
-#define DAVINCI_MCASP_DIT_MODE	1
-
-#endif /* __ASM_ARCH_DAVINCI_ASP_H */
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index a2f1f27..c74a6ab 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -16,11 +16,11 @@
 #include <linux/platform_device.h>
 #include <linux/davinci_emac.h>
 #include <linux/spi/spi.h>
+#include <linux/platform_data/davinci_asp.h>
 
 #include <mach/serial.h>
 #include <mach/edma.h>
 #include <mach/i2c.h>
-#include <mach/asp.h>
 #include <mach/mmc.h>
 #include <mach/usb.h>
 #include <mach/pm.h>
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
index fc179ca..29f16e5 100644
--- a/arch/blackfin/mach-bf527/boards/ezkit.c
+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
@@ -587,6 +587,21 @@
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
+	        || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+static const char * const ad1836_link[] = {
+	"bfin-tdm.0",
+	"spi0.4",
+};
+static struct platform_device bfin_ad1836_machine = {
+	.name = "bfin-snd-ad1836",
+	.id = -1,
+	.dev = {
+		.platform_data = (void *)ad1836_link,
+	},
+};
+#endif
+
 static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #if defined(CONFIG_MTD_M25P80) \
 	|| defined(CONFIG_MTD_M25P80_MODULE)
@@ -1269,6 +1284,11 @@
 #if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
 	&bfin_tdm,
 #endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
+	defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+	&bfin_ad1836_machine,
+#endif
 };
 
 static int __init ezkit_init(void)
diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
index ce88a71..6fca869 100644
--- a/arch/blackfin/mach-bf533/boards/stamp.c
+++ b/arch/blackfin/mach-bf533/boards/stamp.c
@@ -617,6 +617,21 @@
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
+	        || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+static const char * const ad1836_link[] = {
+	"bfin-tdm.0",
+	"spi0.4",
+};
+static struct platform_device bfin_ad1836_machine = {
+	.name = "bfin-snd-ad1836",
+	.id = -1,
+	.dev = {
+		.platform_data = (void *)ad1836_link,
+	},
+};
+#endif
+
 #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \
 	defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
 static const unsigned ad73311_gpio[] = {
@@ -754,6 +769,11 @@
 	&bfin_ac97_pcm,
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
+	defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+	&bfin_ad1836_machine,
+#endif
+
 #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \
 	defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
 	&bfin_ad73311_machine,
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 5ed654a..307bd7e 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -2641,6 +2641,21 @@
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
+	        || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+static const char * const ad1836_link[] = {
+	"bfin-tdm.0",
+	"spi0.4",
+};
+static struct platform_device bfin_ad1836_machine = {
+	.name = "bfin-snd-ad1836",
+	.id = -1,
+	.dev = {
+		.platform_data = (void *)ad1836_link,
+	},
+};
+#endif
+
 #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \
 				defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
 static const unsigned ad73311_gpio[] = {
@@ -2927,6 +2942,11 @@
 	&bfin_ac97_pcm,
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
+	defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+	&bfin_ad1836_machine,
+#endif
+
 #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \
 		defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
 	&bfin_ad73311_machine,
diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
index 7c36777..551f866 100644
--- a/arch/blackfin/mach-bf561/boards/ezkit.c
+++ b/arch/blackfin/mach-bf561/boards/ezkit.c
@@ -539,6 +539,21 @@
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
+	        || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+static const char * const ad1836_link[] = {
+	"bfin-tdm.0",
+	"spi0.4",
+};
+static struct platform_device bfin_ad1836_machine = {
+	.name = "bfin-snd-ad1836",
+	.id = -1,
+	.dev = {
+		.platform_data = (void *)ad1836_link,
+	},
+};
+#endif
+
 static struct platform_device *ezkit_devices[] __initdata = {
 
 	&bfin_dpmc,
@@ -603,6 +618,11 @@
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 	&bfin_ac97,
 #endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
+	defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+	&bfin_ad1836_machine,
+#endif
 };
 
 static int __init net2272_init(void)
diff --git a/arch/blackfin/mach-bf609/boards/ezkit.c b/arch/blackfin/mach-bf609/boards/ezkit.c
index c2cf1ae..61c1f47 100644
--- a/arch/blackfin/mach-bf609/boards/ezkit.c
+++ b/arch/blackfin/mach-bf609/boards/ezkit.c
@@ -818,6 +818,21 @@
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
+	        || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+static const char * const ad1836_link[] = {
+	"bfin-tdm.0",
+	"spi0.76",
+};
+static struct platform_device bfin_ad1836_machine = {
+	.name = "bfin-snd-ad1836",
+	.id = -1,
+	.dev = {
+		.platform_data = (void *)ad1836_link,
+	},
+};
+#endif
+
 #if defined(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61) || \
 	defined(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61_MODULE)
 static struct platform_device adau1761_device = {
@@ -1557,6 +1572,10 @@
 	defined(CONFIG_SND_BF6XX_SOC_I2S_MODULE)
 	&bfin_i2s,
 #endif
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
+	defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+	&bfin_ad1836_machine,
+#endif
 #if defined(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61) || \
 	defined(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61_MODULE)
 	&adau1761_device,
diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h
index f0361c0..fc87be4 100644
--- a/include/linux/mfd/wm8994/pdata.h
+++ b/include/linux/mfd/wm8994/pdata.h
@@ -164,6 +164,10 @@
 	int num_micd_rates;
 	struct wm8958_micd_rate *micd_rates;
 
+	/* Power up delays to add after microphone bias power up (ms) */
+	int micb1_delay;
+	int micb2_delay;
+
         /* LINEOUT can be differential or single ended */
         unsigned int lineout1_diff:1;
         unsigned int lineout2_diff:1;
diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h
new file mode 100644
index 0000000..79c26aa
--- /dev/null
+++ b/include/linux/platform_data/davinci_asp.h
@@ -0,0 +1,104 @@
+/*
+ * TI DaVinci Audio Serial Port support
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DAVINCI_ASP_H
+#define __DAVINCI_ASP_H
+
+struct snd_platform_data {
+	u32 tx_dma_offset;
+	u32 rx_dma_offset;
+	int asp_chan_q;	/* event queue number for ASP channel */
+	int ram_chan_q;	/* event queue number for RAM channel */
+	unsigned int codec_fmt;
+	/*
+	 * Allowing this is more efficient and eliminates left and right swaps
+	 * caused by underruns, but will swap the left and right channels
+	 * when compared to previous behavior.
+	 */
+	unsigned enable_channel_combine:1;
+	unsigned sram_size_playback;
+	unsigned sram_size_capture;
+
+	/*
+	 * If McBSP peripheral gets the clock from an external pin,
+	 * there are three chooses, that are MCBSP_CLKX, MCBSP_CLKR
+	 * and MCBSP_CLKS.
+	 * Depending on different hardware connections it is possible
+	 * to use this setting to change the behaviour of McBSP
+	 * driver.
+	 */
+	int clk_input_pin;
+
+	/*
+	 * This flag works when both clock and FS are outputs for the cpu
+	 * and makes clock more accurate (FS is not symmetrical and the
+	 * clock is very fast.
+	 * The clock becoming faster is named
+	 * i2s continuous serial clock (I2S_SCK) and it is an externally
+	 * visible bit clock.
+	 *
+	 * first line : WordSelect
+	 * second line : ContinuousSerialClock
+	 * third line: SerialData
+	 *
+	 * SYMMETRICAL APPROACH:
+	 *   _______________________          LEFT
+	 * _|         RIGHT         |______________________|
+	 *     _   _         _   _   _   _         _   _
+	 *   _| |_| |_ x16 _| |_| |_| |_| |_ x16 _| |_| |_
+	 *     _   _         _   _   _   _         _   _
+	 *   _/ \_/ \_ ... _/ \_/ \_/ \_/ \_ ... _/ \_/ \_
+	 *    \_/ \_/       \_/ \_/ \_/ \_/       \_/ \_/
+	 *
+	 * ACCURATE CLOCK APPROACH:
+	 *   ______________          LEFT
+	 * _|     RIGHT    |_______________________________|
+	 *     _         _   _         _   _   _   _   _   _
+	 *   _| |_ x16 _| |_| |_ x16 _| |_| |_| |_| |_| |_| |
+	 *     _         _   _          _      dummy cycles
+	 *   _/ \_ ... _/ \_/ \_  ... _/ \__________________
+	 *    \_/       \_/ \_/        \_/
+	 *
+	 */
+	bool i2s_accurate_sck;
+
+	/* McASP specific fields */
+	int tdm_slots;
+	u8 op_mode;
+	u8 num_serializer;
+	u8 *serial_dir;
+	u8 version;
+	u8 txnumevt;
+	u8 rxnumevt;
+};
+
+enum {
+	MCASP_VERSION_1 = 0,	/* DM646x */
+	MCASP_VERSION_2,	/* DA8xx/OMAPL1x */
+};
+
+enum mcbsp_clk_input_pin {
+	MCBSP_CLKR = 0,		/* as in DM365 */
+	MCBSP_CLKS,
+};
+
+#define INACTIVE_MODE	0
+#define TX_MODE		1
+#define RX_MODE		2
+
+#define DAVINCI_MCASP_IIS_MODE	0
+#define DAVINCI_MCASP_DIT_MODE	1
+
+#endif
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
index 48f2a1f..f2912ab 100644
--- a/include/sound/compress_driver.h
+++ b/include/sound/compress_driver.h
@@ -61,6 +61,7 @@
 	u64 total_bytes_available;
 	u64 total_bytes_transferred;
 	wait_queue_head_t sleep;
+	void *private_data;
 };
 
 /**
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 1f69e0a..628db7b 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -18,6 +18,7 @@
 
 struct snd_pcm_substream;
 struct snd_soc_dapm_widget;
+struct snd_compr_stream;
 
 /*
  * DAI hardware audio formats.
@@ -205,6 +206,8 @@
 	int (*remove)(struct snd_soc_dai *dai);
 	int (*suspend)(struct snd_soc_dai *dai);
 	int (*resume)(struct snd_soc_dai *dai);
+	/* compress dai */
+	bool compress_dai;
 
 	/* ops */
 	const struct snd_soc_dai_ops *ops;
diff --git a/include/sound/soc.h b/include/sound/soc.h
index e063380..313b766 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -22,6 +22,7 @@
 #include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
+#include <sound/compress_driver.h>
 #include <sound/control.h>
 #include <sound/ac97_codec.h>
 
@@ -399,6 +400,7 @@
 int snd_soc_platform_write(struct snd_soc_platform *platform,
 					unsigned int reg, unsigned int val);
 int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
+int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);
 
 struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
 		const char *dai_link, int stream);
@@ -632,6 +634,13 @@
 	int (*trigger)(struct snd_pcm_substream *, int);
 };
 
+struct snd_soc_compr_ops {
+	int (*startup)(struct snd_compr_stream *);
+	void (*shutdown)(struct snd_compr_stream *);
+	int (*set_params)(struct snd_compr_stream *);
+	int (*trigger)(struct snd_compr_stream *);
+};
+
 /* SoC cache ops */
 struct snd_soc_cache_ops {
 	const char *name;
@@ -787,9 +796,12 @@
 	snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
 		struct snd_soc_dai *);
 
-	/* platform stream ops */
+	/* platform stream pcm ops */
 	struct snd_pcm_ops *ops;
 
+	/* platform stream compress ops */
+	struct snd_compr_ops *compr_ops;
+
 	/* platform stream completion event */
 	int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
 
@@ -891,6 +903,7 @@
 
 	/* machine stream operations */
 	struct snd_soc_ops *ops;
+	struct snd_soc_compr_ops *compr_ops;
 };
 
 struct snd_soc_codec_conf {
@@ -1027,6 +1040,7 @@
 
 	/* runtime devices */
 	struct snd_pcm *pcm;
+	struct snd_compr *compr;
 	struct snd_soc_codec *codec;
 	struct snd_soc_platform *platform;
 	struct snd_soc_dai *codec_dai;
diff --git a/include/sound/wm0010.h b/include/sound/wm0010.h
new file mode 100644
index 0000000..3261e90
--- /dev/null
+++ b/include/sound/wm0010.h
@@ -0,0 +1,27 @@
+/*
+ * wm0010.h -- Platform data for WM0010 DSP Driver
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef WM0010_PDATA_H
+#define WM0010_PDATA_H
+
+struct wm0010_pdata {
+	int gpio_reset;
+
+	/* Set if there is an inverter between the GPIO controlling
+	 * the reset signal and the device.
+	 */
+	int reset_active_high;
+	int irq_flags;
+};
+
+#endif
diff --git a/include/sound/wm8993.h b/include/sound/wm8993.h
index eee19f6..8016fd8 100644
--- a/include/sound/wm8993.h
+++ b/include/sound/wm8993.h
@@ -32,6 +32,10 @@
 	unsigned int lineout1fb:1;
 	unsigned int lineout2fb:1;
 
+	/* Delay to add for microphones to stabalise after power up */
+	int micbias1_delay;
+	int micbias2_delay;
+
 	/* Microphone biases: 0=0.9*AVDD1 1=0.65*AVVD1 */
 	unsigned int micbias1_lvl:1;
 	unsigned int micbias2_lvl:1;
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index c5de0a8..5da8ca7 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -9,6 +9,7 @@
 	select SND_JACK if INPUT=y || INPUT=SND
 	select REGMAP_I2C if I2C
 	select REGMAP_SPI if SPI_MASTER
+	select SND_COMPRESS_OFFLOAD
 	---help---
 
 	  If you want ASoC support, you should say Y here and also to the
@@ -32,9 +33,9 @@
 source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
 source "sound/soc/blackfin/Kconfig"
+source "sound/soc/cirrus/Kconfig"
 source "sound/soc/davinci/Kconfig"
 source "sound/soc/dwc/Kconfig"
-source "sound/soc/ep93xx/Kconfig"
 source "sound/soc/fsl/Kconfig"
 source "sound/soc/jz4740/Kconfig"
 source "sound/soc/nuc900/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 00a555a..bcbf1d0 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,5 +1,5 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
-snd-soc-core-objs += soc-pcm.o soc-io.o
+snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o
 
 snd-soc-dmaengine-pcm-objs := soc-dmaengine-pcm.o
 obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o
@@ -10,9 +10,9 @@
 obj-$(CONFIG_SND_SOC)	+= atmel/
 obj-$(CONFIG_SND_SOC)	+= au1x/
 obj-$(CONFIG_SND_SOC)	+= blackfin/
+obj-$(CONFIG_SND_SOC)	+= cirrus/
 obj-$(CONFIG_SND_SOC)	+= davinci/
 obj-$(CONFIG_SND_SOC)	+= dwc/
-obj-$(CONFIG_SND_SOC)	+= ep93xx/
 obj-$(CONFIG_SND_SOC)	+= fsl/
 obj-$(CONFIG_SND_SOC)	+= jz4740/
 obj-$(CONFIG_SND_SOC)	+= mid-x86/
diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c
index d542d40..16b9c9e 100644
--- a/sound/soc/blackfin/bf5xx-ad1836.c
+++ b/sound/soc/blackfin/bf5xx-ad1836.c
@@ -59,62 +59,63 @@
 #define BF5XX_AD1836_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
 				SND_SOC_DAIFMT_CBM_CFM)
 
-static struct snd_soc_dai_link bf5xx_ad1836_dai[] = {
-	{
-		.name = "ad1836",
-		.stream_name = "AD1836",
-		.cpu_dai_name = "bfin-tdm.0",
-		.codec_dai_name = "ad1836-hifi",
-		.platform_name = "bfin-tdm-pcm-audio",
-		.codec_name = "spi0.4",
-		.ops = &bf5xx_ad1836_ops,
-		.dai_fmt = BF5XX_AD1836_DAIFMT,
-	},
-	{
-		.name = "ad1836",
-		.stream_name = "AD1836",
-		.cpu_dai_name = "bfin-tdm.1",
-		.codec_dai_name = "ad1836-hifi",
-		.platform_name = "bfin-tdm-pcm-audio",
-		.codec_name = "spi0.4",
-		.ops = &bf5xx_ad1836_ops,
-		.dai_fmt = BF5XX_AD1836_DAIFMT,
-	},
+static struct snd_soc_dai_link bf5xx_ad1836_dai = {
+	.name = "ad1836",
+	.stream_name = "AD1836",
+	.codec_dai_name = "ad1836-hifi",
+	.platform_name = "bfin-tdm-pcm-audio",
+	.ops = &bf5xx_ad1836_ops,
+	.dai_fmt = BF5XX_AD1836_DAIFMT,
 };
 
 static struct snd_soc_card bf5xx_ad1836 = {
 	.name = "bfin-ad1836",
 	.owner = THIS_MODULE,
-	.dai_link = &bf5xx_ad1836_dai[CONFIG_SND_BF5XX_SPORT_NUM],
+	.dai_link = &bf5xx_ad1836_dai,
 	.num_links = 1,
 };
 
-static struct platform_device *bfxx_ad1836_snd_device;
-
-static int __init bf5xx_ad1836_init(void)
+static __devinit int bf5xx_ad1836_driver_probe(struct platform_device *pdev)
 {
+	struct snd_soc_card *card = &bf5xx_ad1836;
+	const char **link_name;
 	int ret;
 
-	bfxx_ad1836_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!bfxx_ad1836_snd_device)
-		return -ENOMEM;
+	link_name = pdev->dev.platform_data;
+	if (!link_name) {
+		dev_err(&pdev->dev, "No platform data supplied\n");
+		return -EINVAL;
+	}
+	bf5xx_ad1836_dai.cpu_dai_name = link_name[0];
+	bf5xx_ad1836_dai.codec_name = link_name[1];
 
-	platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836);
-	ret = platform_device_add(bfxx_ad1836_snd_device);
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
 
+	ret = snd_soc_register_card(card);
 	if (ret)
-		platform_device_put(bfxx_ad1836_snd_device);
-
+		dev_err(&pdev->dev, "Failed to register card\n");
 	return ret;
 }
 
-static void __exit bf5xx_ad1836_exit(void)
+static int __devexit bf5xx_ad1836_driver_remove(struct platform_device *pdev)
 {
-	platform_device_unregister(bfxx_ad1836_snd_device);
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(card);
+	return 0;
 }
 
-module_init(bf5xx_ad1836_init);
-module_exit(bf5xx_ad1836_exit);
+static struct platform_driver bf5xx_ad1836_driver = {
+	.driver = {
+		.name = "bfin-snd-ad1836",
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = bf5xx_ad1836_driver_probe,
+	.remove = __devexit_p(bf5xx_ad1836_driver_remove),
+};
+module_platform_driver(bf5xx_ad1836_driver);
 
 /* Module information */
 MODULE_AUTHOR("Barry Song");
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/cirrus/Kconfig
similarity index 100%
rename from sound/soc/ep93xx/Kconfig
rename to sound/soc/cirrus/Kconfig
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/cirrus/Makefile
similarity index 100%
rename from sound/soc/ep93xx/Makefile
rename to sound/soc/cirrus/Makefile
diff --git a/sound/soc/ep93xx/edb93xx.c b/sound/soc/cirrus/edb93xx.c
similarity index 100%
rename from sound/soc/ep93xx/edb93xx.c
rename to sound/soc/cirrus/edb93xx.c
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c
similarity index 100%
rename from sound/soc/ep93xx/ep93xx-ac97.c
rename to sound/soc/cirrus/ep93xx-ac97.c
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
similarity index 100%
rename from sound/soc/ep93xx/ep93xx-i2s.c
rename to sound/soc/cirrus/ep93xx-i2s.c
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c
similarity index 100%
rename from sound/soc/ep93xx/ep93xx-pcm.c
rename to sound/soc/cirrus/ep93xx-pcm.c
diff --git a/sound/soc/ep93xx/ep93xx-pcm.h b/sound/soc/cirrus/ep93xx-pcm.h
similarity index 100%
rename from sound/soc/ep93xx/ep93xx-pcm.h
rename to sound/soc/cirrus/ep93xx-pcm.h
diff --git a/sound/soc/ep93xx/simone.c b/sound/soc/cirrus/simone.c
similarity index 100%
rename from sound/soc/ep93xx/simone.c
rename to sound/soc/cirrus/simone.c
diff --git a/sound/soc/ep93xx/snappercl15.c b/sound/soc/cirrus/snappercl15.c
similarity index 100%
rename from sound/soc/ep93xx/snappercl15.c
rename to sound/soc/cirrus/snappercl15.c
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9f8e859..3684255 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -70,6 +70,7 @@
 	select SND_SOC_UDA134X
 	select SND_SOC_UDA1380 if I2C
 	select SND_SOC_WL1273 if MFD_WL1273_CORE
+	select SND_SOC_WM0010 if SPI_MASTER
 	select SND_SOC_WM1250_EV1 if I2C
 	select SND_SOC_WM2000 if I2C
 	select SND_SOC_WM2200 if I2C
@@ -326,6 +327,9 @@
 config SND_SOC_WL1273
 	tristate
 
+config SND_SOC_WM0010
+	tristate
+
 config SND_SOC_WM1250_EV1
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 34148bb..ca508b2 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -61,6 +61,7 @@
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wl1273-objs := wl1273.o
+snd-soc-wm0010-objs := wm0010.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm2000-objs := wm2000.o
 snd-soc-wm2200-objs := wm2200.o
@@ -177,6 +178,7 @@
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
+obj-$(CONFIG_SND_SOC_WM0010)	+= snd-soc-wm0010.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
 obj-$(CONFIG_SND_SOC_WM2000)	+= snd-soc-wm2000.o
 obj-$(CONFIG_SND_SOC_WM2200)	+= snd-soc-wm2200.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 23b4018..b783650 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -2404,12 +2404,12 @@
 
 	dev_dbg(dev, "%s: Enter.\n", __func__);
 
-	/* Setup AB8500 according to board-settings */
-	pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent);
-
 	/* Inform SoC Core that we have our own I/O arrangements. */
 	codec->control_data = (void *)true;
 
+	/* Setup AB8500 according to board-settings */
+	pdata = dev_get_platdata(dev->parent);
+
 	status = ab8500_audio_setup_mics(codec, &pdata->codec->amics);
 	if (status < 0) {
 		pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index c67b50d..ae1eb51 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -379,17 +379,7 @@
 	.id_table	= ad1836_ids,
 };
 
-static int __init ad1836_init(void)
-{
-	return spi_register_driver(&ad1836_spi_driver);
-}
-module_init(ad1836_init);
-
-static void __exit ad1836_exit(void)
-{
-	spi_unregister_driver(&ad1836_spi_driver);
-}
-module_exit(ad1836_exit);
+module_spi_driver(ad1836_spi_driver);
 
 MODULE_DESCRIPTION("ASoC ad1836 driver");
 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 44f5906..704544b 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -1392,17 +1392,7 @@
 	.id_table = adau1373_i2c_id,
 };
 
-static int __init adau1373_init(void)
-{
-	return i2c_add_driver(&adau1373_i2c_driver);
-}
-module_init(adau1373_init);
-
-static void __exit adau1373_exit(void)
-{
-	i2c_del_driver(&adau1373_i2c_driver);
-}
-module_exit(adau1373_exit);
+module_i2c_driver(adau1373_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC ADAU1373 driver");
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 3d50fc8..51f2f3c 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -527,17 +527,7 @@
 	.id_table	= adau1701_i2c_id,
 };
 
-static int __init adau1701_init(void)
-{
-	return i2c_add_driver(&adau1701_i2c_driver);
-}
-module_init(adau1701_init);
-
-static void __exit adau1701_exit(void)
-{
-	i2c_del_driver(&adau1701_i2c_driver);
-}
-module_exit(adau1701_exit);
+module_i2c_driver(adau1701_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver");
 MODULE_AUTHOR("Cliff Cai <cliff.cai@analog.com>");
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index 5fb7c2a..2b45797 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -696,17 +696,7 @@
 	.id_table = ak4671_i2c_id,
 };
 
-static int __init ak4671_modinit(void)
-{
-	return i2c_add_driver(&ak4671_i2c_driver);
-}
-module_init(ak4671_modinit);
-
-static void __exit ak4671_exit(void)
-{
-	i2c_del_driver(&ak4671_i2c_driver);
-}
-module_exit(ak4671_exit);
+module_i2c_driver(ak4671_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC AK4671 codec driver");
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 5c9caca..5e96a0a 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -229,6 +229,69 @@
 }
 EXPORT_SYMBOL_GPL(arizona_out_ev);
 
+static unsigned int arizona_sysclk_48k_rates[] = {
+	6144000,
+	12288000,
+	22579200,
+	49152000,
+};
+
+static unsigned int arizona_sysclk_44k1_rates[] = {
+	5644800,
+	11289600,
+	24576000,
+	45158400,
+};
+
+static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
+			     unsigned int freq)
+{
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	unsigned int reg;
+	unsigned int *rates;
+	int ref, div, refclk;
+
+	switch (clk) {
+	case ARIZONA_CLK_OPCLK:
+		reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
+		refclk = priv->sysclk;
+		break;
+	case ARIZONA_CLK_ASYNC_OPCLK:
+		reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
+		refclk = priv->asyncclk;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (refclk % 8000)
+		rates = arizona_sysclk_44k1_rates;
+	else
+		rates = arizona_sysclk_48k_rates;
+
+	for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
+		     rates[ref] <= refclk; ref++) {
+		div = 1;
+		while (rates[ref] / div >= freq && div < 32) {
+			if (rates[ref] / div == freq) {
+				dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
+					freq);
+				snd_soc_update_bits(codec, reg,
+						    ARIZONA_OPCLK_DIV_MASK |
+						    ARIZONA_OPCLK_SEL_MASK,
+						    (div <<
+						     ARIZONA_OPCLK_DIV_SHIFT) |
+						    ref);
+				return 0;
+			}
+			div++;
+		}
+	}
+
+	dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
+	return -EINVAL;
+}
+
 int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 		       int source, unsigned int freq, int dir)
 {
@@ -252,6 +315,9 @@
 		reg = ARIZONA_ASYNC_CLOCK_1;
 		clk = &priv->asyncclk;
 		break;
+	case ARIZONA_CLK_OPCLK:
+	case ARIZONA_CLK_ASYNC_OPCLK:
+		return arizona_set_opclk(codec, clk_id, freq);
 	default:
 		return -EINVAL;
 	}
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 59caca8..eb66b52 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -17,8 +17,10 @@
 
 #include <sound/soc.h>
 
-#define ARIZONA_CLK_SYSCLK   1
-#define ARIZONA_CLK_ASYNCCLK 2
+#define ARIZONA_CLK_SYSCLK         1
+#define ARIZONA_CLK_ASYNCCLK       2
+#define ARIZONA_CLK_OPCLK          3
+#define ARIZONA_CLK_ASYNC_OPCLK    4
 
 #define ARIZONA_CLK_SRC_MCLK1    0x0
 #define ARIZONA_CLK_SRC_MCLK2    0x1
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 047917f..44a176f 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -29,6 +29,8 @@
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 
 /*
  * The codec isn't really big-endian or little-endian, since the I2S
@@ -639,6 +641,15 @@
 	.reg_cache_default =	cs4270_default_reg_cache,
 };
 
+/*
+ * cs4270_of_match - the device tree bindings
+ */
+static const struct of_device_id cs4270_of_match[] = {
+	{ .compatible = "cirrus,cs4270", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cs4270_of_match);
+
 /**
  * cs4270_i2c_probe - initialize the I2C interface of the CS4270
  * @i2c_client: the I2C client object
@@ -650,9 +661,25 @@
 static int cs4270_i2c_probe(struct i2c_client *i2c_client,
 	const struct i2c_device_id *id)
 {
+	struct device_node *np = i2c_client->dev.of_node;
 	struct cs4270_private *cs4270;
 	int ret;
 
+	/* See if we have a way to bring the codec out of reset */
+	if (np) {
+		enum of_gpio_flags flags;
+		int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
+
+		if (gpio_is_valid(gpio)) {
+			ret = devm_gpio_request_one(&i2c_client->dev, gpio,
+				     flags & OF_GPIO_ACTIVE_LOW ?
+					GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
+				     "cs4270 reset");
+			if (ret < 0)
+				return ret;
+		}
+	}
+
 	/* Verify that we have a CS4270 */
 
 	ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
@@ -718,23 +745,14 @@
 	.driver = {
 		.name = "cs4270",
 		.owner = THIS_MODULE,
+		.of_match_table = cs4270_of_match,
 	},
 	.id_table = cs4270_id,
 	.probe = cs4270_i2c_probe,
 	.remove = cs4270_i2c_remove,
 };
 
-static int __init cs4270_init(void)
-{
-	return i2c_add_driver(&cs4270_i2c_driver);
-}
-module_init(cs4270_init);
-
-static void __exit cs4270_exit(void)
-{
-	i2c_del_driver(&cs4270_i2c_driver);
-}
-module_exit(cs4270_exit);
+module_i2c_driver(cs4270_i2c_driver);
 
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver");
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 091d019..1e0fa3b 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -614,24 +614,7 @@
 	.remove = cs42l51_i2c_remove,
 };
 
-static int __init cs42l51_init(void)
-{
-	int ret;
-
-	ret = i2c_add_driver(&cs42l51_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "%s: can't add i2c driver\n", __func__);
-		return ret;
-	}
-	return 0;
-}
-module_init(cs42l51_init);
-
-static void __exit cs42l51_exit(void)
-{
-	i2c_del_driver(&cs42l51_i2c_driver);
-}
-module_exit(cs42l51_exit);
+module_i2c_driver(cs42l51_i2c_driver);
 
 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 628daf6..6159929 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -24,7 +24,6 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index 5d8f39e..1bf5560 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -13,7 +13,6 @@
  */
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
index ba4fafb..81a328c 100644
--- a/sound/soc/codecs/lm4857.c
+++ b/sound/soc/codecs/lm4857.c
@@ -250,17 +250,7 @@
 	.id_table = lm4857_i2c_id,
 };
 
-static int __init lm4857_init(void)
-{
-	return i2c_add_driver(&lm4857_i2c_driver);
-}
-module_init(lm4857_init);
-
-static void __exit lm4857_exit(void)
-{
-	i2c_del_driver(&lm4857_i2c_driver);
-}
-module_exit(lm4857_exit);
+module_i2c_driver(lm4857_i2c_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("LM4857 amplifier driver");
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index af7324b..3264a51 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -2107,23 +2107,7 @@
        .id_table = max98088_i2c_id,
 };
 
-static int __init max98088_init(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&max98088_i2c_driver);
-       if (ret)
-               pr_err("Failed to register max98088 I2C driver: %d\n", ret);
-
-       return ret;
-}
-module_init(max98088_init);
-
-static void __exit max98088_exit(void)
-{
-       i2c_del_driver(&max98088_i2c_driver);
-}
-module_exit(max98088_exit);
+module_i2c_driver(max98088_i2c_driver);
 
 MODULE_DESCRIPTION("ALSA SoC MAX98088 driver");
 MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin");
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 7cd508e..38d43c5 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -2533,23 +2533,7 @@
 	.id_table = max98095_i2c_id,
 };
 
-static int __init max98095_init(void)
-{
-	int ret;
-
-	ret = i2c_add_driver(&max98095_i2c_driver);
-	if (ret)
-		pr_err("Failed to register max98095 I2C driver: %d\n", ret);
-
-	return ret;
-}
-module_init(max98095_init);
-
-static void __exit max98095_exit(void)
-{
-	i2c_del_driver(&max98095_i2c_driver);
-}
-module_exit(max98095_exit);
+module_i2c_driver(max98095_i2c_driver);
 
 MODULE_DESCRIPTION("ALSA SoC MAX98095 driver");
 MODULE_AUTHOR("Peter Hsiang");
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index a191309..efe535c 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -369,17 +369,7 @@
 	.id_table = max9850_i2c_id,
 };
 
-static int __init max9850_init(void)
-{
-	return i2c_add_driver(&max9850_i2c_driver);
-}
-module_init(max9850_init);
-
-static void __exit max9850_exit(void)
-{
-	i2c_del_driver(&max9850_i2c_driver);
-}
-module_exit(max9850_exit);
+module_i2c_driver(max9850_i2c_driver);
 
 MODULE_AUTHOR("Christian Glindkamp <christian.glindkamp@taskit.de>");
 MODULE_DESCRIPTION("ASoC MAX9850 codec driver");
diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c
index 3a2ba3d..d15e594 100644
--- a/sound/soc/codecs/max9877.c
+++ b/sound/soc/codecs/max9877.c
@@ -291,17 +291,7 @@
 	.id_table = max9877_i2c_id,
 };
 
-static int __init max9877_init(void)
-{
-	return i2c_add_driver(&max9877_i2c_driver);
-}
-module_init(max9877_init);
-
-static void __exit max9877_exit(void)
-{
-	i2c_del_driver(&max9877_i2c_driver);
-}
-module_exit(max9877_exit);
+module_i2c_driver(max9877_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC MAX9877 amp driver");
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 8d717f4..51b7313 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -1006,17 +1006,7 @@
 	.id_table = sta32x_i2c_id,
 };
 
-static int __init sta32x_init(void)
-{
-	return i2c_add_driver(&sta32x_i2c_driver);
-}
-module_init(sta32x_init);
-
-static void __exit sta32x_exit(void)
-{
-	i2c_del_driver(&sta32x_i2c_driver);
-}
-module_exit(sta32x_exit);
+module_i2c_driver(sta32x_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC STA32X driver");
 MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 0c225cd..9e31448 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -358,7 +358,7 @@
 	return 0;
 }
 
-struct snd_soc_codec_driver sta529_codec_driver = {
+static const struct snd_soc_codec_driver sta529_codec_driver = {
 	.probe = sta529_probe,
 	.remove = sta529_remove,
 	.set_bias_level = sta529_set_bias_level,
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 85944e9..b1f6982 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -444,14 +444,4 @@
 	.remove = aic26_spi_remove,
 };
 
-static int __init aic26_init(void)
-{
-	return spi_register_driver(&aic26_spi);
-}
-module_init(aic26_init);
-
-static void __exit aic26_exit(void)
-{
-	spi_unregister_driver(&aic26_spi);
-}
-module_exit(aic26_exit);
+module_spi_driver(aic26_spi);
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index b0a73d3..f230292 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -746,24 +746,7 @@
 	.id_table = aic32x4_i2c_id,
 };
 
-static int __init aic32x4_modinit(void)
-{
-	int ret = 0;
-
-	ret = i2c_add_driver(&aic32x4_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register aic32x4 I2C driver: %d\n",
-		       ret);
-	}
-	return ret;
-}
-module_init(aic32x4_modinit);
-
-static void __exit aic32x4_exit(void)
-{
-	i2c_del_driver(&aic32x4_i2c_driver);
-}
-module_exit(aic32x4_exit);
+module_i2c_driver(aic32x4_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver");
 MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index dc78f5a..5708a97 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -40,6 +40,7 @@
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -1457,6 +1458,8 @@
 {
 	struct aic3x_pdata *pdata = i2c->dev.platform_data;
 	struct aic3x_priv *aic3x;
+	struct aic3x_setup_data *ai3x_setup;
+	struct device_node *np = i2c->dev.of_node;
 	int ret;
 
 	aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
@@ -1471,6 +1474,25 @@
 	if (pdata) {
 		aic3x->gpio_reset = pdata->gpio_reset;
 		aic3x->setup = pdata->setup;
+	} else if (np) {
+		ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup),
+								GFP_KERNEL);
+		if (ai3x_setup == NULL) {
+			dev_err(&i2c->dev, "failed to create private data\n");
+			return -ENOMEM;
+		}
+
+		ret = of_get_named_gpio(np, "gpio-reset", 0);
+		if (ret >= 0)
+			aic3x->gpio_reset = ret;
+		else
+			aic3x->gpio_reset = -1;
+
+		if (of_property_read_u32_array(np, "ai3x-gpio-func",
+					ai3x_setup->gpio_func, 2) >= 0) {
+			aic3x->setup = ai3x_setup;
+		}
+
 	} else {
 		aic3x->gpio_reset = -1;
 	}
@@ -1488,34 +1510,27 @@
 	return 0;
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id tlv320aic3x_of_match[] = {
+	{ .compatible = "ti,tlv320aic3x", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match);
+#endif
+
 /* machine i2c codec control layer */
 static struct i2c_driver aic3x_i2c_driver = {
 	.driver = {
 		.name = "tlv320aic3x-codec",
 		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(tlv320aic3x_of_match),
 	},
 	.probe	= aic3x_i2c_probe,
 	.remove = aic3x_i2c_remove,
 	.id_table = aic3x_i2c_id,
 };
 
-static int __init aic3x_modinit(void)
-{
-	int ret = 0;
-	ret = i2c_add_driver(&aic3x_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n",
-		       ret);
-	}
-	return ret;
-}
-module_init(aic3x_modinit);
-
-static void __exit aic3x_exit(void)
-{
-	i2c_del_driver(&aic3x_i2c_driver);
-}
-module_exit(aic3x_exit);
+module_i2c_driver(aic3x_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver");
 MODULE_AUTHOR("Vladimir Barinov");
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 0dd4107..d2e16c5 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -1621,24 +1621,7 @@
 	.id_table	= tlv320dac33_i2c_id,
 };
 
-static int __init dac33_module_init(void)
-{
-	int r;
-	r = i2c_add_driver(&tlv320dac33_i2c_driver);
-	if (r < 0) {
-		printk(KERN_ERR "DAC33: driver registration failed\n");
-		return r;
-	}
-	return 0;
-}
-module_init(dac33_module_init);
-
-static void __exit dac33_module_exit(void)
-{
-	i2c_del_driver(&tlv320dac33_i2c_driver);
-}
-module_exit(dac33_module_exit);
-
+module_i2c_driver(tlv320dac33_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver");
 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 6fe4aa3..565ff39 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -487,19 +487,8 @@
 	.id_table = tpa6130a2_id,
 };
 
-static int __init tpa6130a2_init(void)
-{
-	return i2c_add_driver(&tpa6130a2_i2c_driver);
-}
-
-static void __exit tpa6130a2_exit(void)
-{
-	i2c_del_driver(&tpa6130a2_i2c_driver);
-}
+module_i2c_driver(tpa6130a2_i2c_driver);
 
 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver");
 MODULE_LICENSE("GPL");
-
-module_init(tpa6130a2_init);
-module_exit(tpa6130a2_exit);
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
new file mode 100644
index 0000000..5f99148
--- /dev/null
+++ b/sound/soc/codecs/wm0010.c
@@ -0,0 +1,942 @@
+/*
+ * wm0010.c  --  WM0010 DSP Driver
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Authors: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *          Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *          Scott Ling <sl@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/irqreturn.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include <sound/soc.h>
+#include <sound/wm0010.h>
+
+#define DEVICE_ID_WM0010	10
+
+enum dfw_cmd {
+	DFW_CMD_FUSE = 0x01,
+	DFW_CMD_CODE_HDR,
+	DFW_CMD_CODE_DATA,
+	DFW_CMD_PLL,
+	DFW_CMD_INFO = 0xff
+};
+
+struct dfw_binrec {
+	u8 command;
+	u32 length:24;
+	u32 address;
+	uint8_t data[0];
+} __packed;
+
+struct dfw_pllrec {
+	u8 command;
+	u32 length:24;
+	u32 address;
+	u32 clkctrl1;
+	u32 clkctrl2;
+	u32 clkctrl3;
+	u32 ldetctrl;
+	u32 uart_div;
+	u32 spi_div;
+} __packed;
+
+static struct pll_clock_map {
+	int max_sysclk;
+	int max_pll_spi_speed;
+	u32 pll_clkctrl1;
+} pll_clock_map[] = {			   /* Dividers */
+	{ 22000000, 26000000, 0x00201f11 }, /* 2,32,2  */
+	{ 18000000, 26000000, 0x00203f21 }, /* 2,64,4  */
+	{ 14000000, 26000000, 0x00202620 }, /* 1,39,4  */
+	{ 10000000, 22000000, 0x00203120 }, /* 1,50,4  */
+	{  6500000, 22000000, 0x00204520 }, /* 1,70,4  */
+	{  5500000, 22000000, 0x00103f10 }, /* 1,64,2  */
+};
+
+enum wm0010_state {
+	WM0010_POWER_OFF,
+	WM0010_OUT_OF_RESET,
+	WM0010_BOOTROM,
+	WM0010_STAGE2,
+	WM0010_FIRMWARE,
+};
+
+struct wm0010_priv {
+	struct snd_soc_codec *codec;
+
+	struct mutex lock;
+	struct device *dev;
+
+	struct wm0010_pdata pdata;
+
+	int gpio_reset;
+	int gpio_reset_value;
+
+	struct regulator_bulk_data core_supplies[2];
+	struct regulator *dbvdd;
+
+	int sysclk;
+
+	enum wm0010_state state;
+	bool boot_failed;
+	int boot_done;
+	bool ready;
+	bool pll_running;
+	int max_spi_freq;
+	int board_max_spi_speed;
+	u32 pll_clkctrl1;
+
+	spinlock_t irq_lock;
+	int irq;
+
+	struct completion boot_completion;
+};
+
+struct wm0010_spi_msg {
+	struct spi_message m;
+	struct spi_transfer t;
+	u8 *tx_buf;
+	u8 *rx_buf;
+	size_t len;
+};
+
+static const struct snd_soc_dapm_widget wm0010_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("CLKIN",  SND_SOC_NOPM, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route wm0010_dapm_routes[] = {
+	{ "SDI2 Capture", NULL, "SDI1 Playback" },
+	{ "SDI1 Capture", NULL, "SDI2 Playback" },
+
+	{ "SDI1 Capture", NULL, "CLKIN" },
+	{ "SDI2 Capture", NULL, "CLKIN" },
+	{ "SDI1 Playback", NULL, "CLKIN" },
+	{ "SDI2 Playback", NULL, "CLKIN" },
+};
+
+static const char *wm0010_state_to_str(enum wm0010_state state)
+{
+	const char *state_to_str[] = {
+		"Power off",
+		"Out of reset",
+		"Boot ROM",
+		"Stage2",
+		"Firmware"
+	};
+
+	if (state < 0 || state >= ARRAY_SIZE(state_to_str))
+		return "null";
+	return state_to_str[state];
+}
+
+/* Called with wm0010->lock held */
+static void wm0010_halt(struct snd_soc_codec *codec)
+{
+	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+	unsigned long flags;
+	enum wm0010_state state;
+
+	/* Fetch the wm0010 state */
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	state = wm0010->state;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	switch (state) {
+	case WM0010_POWER_OFF:
+		/* If there's nothing to do, bail out */
+		return;
+	case WM0010_OUT_OF_RESET:
+	case WM0010_BOOTROM:
+	case WM0010_STAGE2:
+	case WM0010_FIRMWARE:
+		/* Remember to put chip back into reset */
+		gpio_set_value(wm0010->gpio_reset, wm0010->gpio_reset_value);
+		/* Disable the regulators */
+		regulator_disable(wm0010->dbvdd);
+		regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies),
+				       wm0010->core_supplies);
+		break;
+	}
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	wm0010->state = WM0010_POWER_OFF;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+}
+
+struct wm0010_boot_xfer {
+	struct list_head list;
+	struct snd_soc_codec *codec;
+	struct completion *done;
+	struct spi_message m;
+	struct spi_transfer t;
+};
+
+/* Called with wm0010->lock held */
+static void wm0010_mark_boot_failure(struct wm0010_priv *wm0010)
+{
+	enum wm0010_state state;
+	unsigned long flags;
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	state = wm0010->state;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	dev_err(wm0010->dev, "Failed to transition from `%s' state to `%s' state\n",
+		wm0010_state_to_str(state), wm0010_state_to_str(state + 1));
+
+	wm0010->boot_failed = true;
+}
+
+static void wm0010_boot_xfer_complete(void *data)
+{
+	struct wm0010_boot_xfer *xfer = data;
+	struct snd_soc_codec *codec = xfer->codec;
+	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+	u32 *out32 = xfer->t.rx_buf;
+	int i;
+
+	if (xfer->m.status != 0) {
+		dev_err(codec->dev, "SPI transfer failed: %d\n",
+			xfer->m.status);
+		wm0010_mark_boot_failure(wm0010);
+		if (xfer->done)
+			complete(xfer->done);
+		return;
+	}
+
+	for (i = 0; i < xfer->t.len / 4; i++) {
+		dev_dbg(codec->dev, "%d: %04x\n", i, out32[i]);
+
+		switch (be32_to_cpu(out32[i])) {
+		case 0xe0e0e0e0:
+			dev_err(codec->dev,
+				"%d: ROM error reported in stage 2\n", i);
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x55555555:
+			if (wm0010->boot_done == 0)
+				break;
+			dev_err(codec->dev,
+				"%d: ROM bootloader running in stage 2\n", i);
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0000:
+			dev_dbg(codec->dev, "Stage2 loader running\n");
+			break;
+
+		case 0x0fed0007:
+			dev_dbg(codec->dev, "CODE_HDR packet received\n");
+			break;
+
+		case 0x0fed0008:
+			dev_dbg(codec->dev, "CODE_DATA packet received\n");
+			break;
+
+		case 0x0fed0009:
+			dev_dbg(codec->dev, "Download complete\n");
+			break;
+
+		case 0x0fed000c:
+			dev_dbg(codec->dev, "Application start\n");
+			break;
+
+		case 0x0fed000e:
+			dev_dbg(codec->dev, "PLL packet received\n");
+			wm0010->pll_running = true;
+			break;
+
+		case 0x0fed0025:
+			dev_err(codec->dev, "Device reports image too long\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed002c:
+			dev_err(codec->dev, "Device reports bad SPI packet\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0031:
+			dev_err(codec->dev, "Device reports SPI read overflow\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0032:
+			dev_err(codec->dev, "Device reports SPI underclock\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0033:
+			dev_err(codec->dev, "Device reports bad header packet\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0034:
+			dev_err(codec->dev, "Device reports invalid packet type\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0035:
+			dev_err(codec->dev, "Device reports data before header error\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0038:
+			dev_err(codec->dev, "Device reports invalid PLL packet\n");
+			break;
+
+		case 0x0fed003a:
+			dev_err(codec->dev, "Device reports packet alignment error\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		default:
+			dev_err(codec->dev, "Unrecognised return 0x%x\n",
+			    be32_to_cpu(out32[i]));
+			wm0010_mark_boot_failure(wm0010);
+			break;
+		}
+
+		if (wm0010->boot_failed)
+			break;
+	}
+
+	wm0010->boot_done++;
+	if (xfer->done)
+		complete(xfer->done);
+}
+
+static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
+{
+	int i;
+
+	for (i = 0; i < len / 8; i++)
+		data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i]));
+}
+
+static int wm0010_boot(struct snd_soc_codec *codec)
+{
+	struct spi_device *spi = to_spi_device(codec->dev);
+	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+	unsigned long flags;
+	struct list_head xfer_list;
+	struct wm0010_boot_xfer *xfer;
+	int ret;
+	struct completion done;
+	const struct firmware *fw;
+	const struct dfw_binrec *rec;
+	struct spi_message m;
+	struct spi_transfer t;
+	struct dfw_pllrec pll_rec;
+	u32 *img, *p;
+	u64 *img_swap;
+	u8 *out;
+	u32 len, offset;
+	int i;
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	if (wm0010->state != WM0010_POWER_OFF)
+		dev_warn(wm0010->dev, "DSP already powered up!\n");
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	if (wm0010->sysclk > 26000000) {
+		dev_err(codec->dev, "Max DSP clock frequency is 26MHz\n");
+		ret = -ECANCELED;
+		goto err;
+	}
+
+	INIT_LIST_HEAD(&xfer_list);
+
+	mutex_lock(&wm0010->lock);
+	wm0010->pll_running = false;
+
+	dev_dbg(codec->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq);
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm0010->core_supplies),
+				    wm0010->core_supplies);
+	if (ret != 0) {
+		dev_err(&spi->dev, "Failed to enable core supplies: %d\n",
+			ret);
+		mutex_unlock(&wm0010->lock);
+		goto err;
+	}
+
+	ret = regulator_enable(wm0010->dbvdd);
+	if (ret != 0) {
+		dev_err(&spi->dev, "Failed to enable DBVDD: %d\n", ret);
+		goto err_core;
+	}
+
+	/* Release reset */
+	gpio_set_value(wm0010->gpio_reset, !wm0010->gpio_reset_value);
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	wm0010->state = WM0010_OUT_OF_RESET;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	/* First the bootloader */
+	ret = request_firmware(&fw, "wm0010_stage2.bin", codec->dev);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to request stage2 loader: %d\n",
+			ret);
+		goto abort;
+	}
+
+	if (!wait_for_completion_timeout(&wm0010->boot_completion,
+					 msecs_to_jiffies(10)))
+		dev_err(codec->dev, "Failed to get interrupt from DSP\n");
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	wm0010->state = WM0010_BOOTROM;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	dev_dbg(codec->dev, "Downloading %d byte stage 2 loader\n", fw->size);
+
+	/* Copy to local buffer first as vmalloc causes problems for dma */
+	img = kzalloc(fw->size, GFP_KERNEL);
+	if (!img) {
+		dev_err(codec->dev, "Failed to allocate image buffer\n");
+		goto abort;
+	}
+
+	out = kzalloc(fw->size, GFP_KERNEL);
+	if (!out) {
+		dev_err(codec->dev, "Failed to allocate output buffer\n");
+		goto abort;
+	}
+
+	memcpy(img, &fw->data[0], fw->size);
+
+	spi_message_init(&m);
+	memset(&t, 0, sizeof(t));
+	t.rx_buf = out;
+	t.tx_buf = img;
+	t.len = fw->size;
+	t.bits_per_word = 8;
+	t.speed_hz = wm0010->sysclk / 10;
+	spi_message_add_tail(&t, &m);
+
+	dev_dbg(codec->dev, "Starting initial download at %dHz\n",
+		t.speed_hz);
+
+	ret = spi_sync(spi, &m);
+	if (ret != 0) {
+		dev_err(codec->dev, "Initial download failed: %d\n", ret);
+		goto abort;
+	}
+
+	/* Look for errors from the boot ROM */
+	for (i = 0; i < fw->size; i++) {
+		if (out[i] != 0x55) {
+			ret = -EBUSY;
+			dev_err(codec->dev, "Boot ROM error: %x in %d\n",
+				out[i], i);
+			wm0010_mark_boot_failure(wm0010);
+			goto abort;
+		}
+	}
+
+	release_firmware(fw);
+	kfree(img);
+	kfree(out);
+
+	if (!wait_for_completion_timeout(&wm0010->boot_completion,
+					 msecs_to_jiffies(10)))
+		dev_err(codec->dev, "Failed to get interrupt from DSP loader.\n");
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	wm0010->state = WM0010_STAGE2;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	/* Only initialise PLL if max_spi_freq initialised */
+	if (wm0010->max_spi_freq) {
+
+		/* Initialise a PLL record */
+		memset(&pll_rec, 0, sizeof(pll_rec));
+		pll_rec.command = DFW_CMD_PLL;
+		pll_rec.length = (sizeof(pll_rec) - 8);
+
+		/* On wm0010 only the CLKCTRL1 value is used */
+		pll_rec.clkctrl1 = wm0010->pll_clkctrl1;
+
+		len = pll_rec.length + 8;
+		out = kzalloc(len, GFP_KERNEL);
+		if (!out) {
+			dev_err(codec->dev,
+				"Failed to allocate RX buffer\n");
+			goto abort;
+		}
+
+		img_swap = kzalloc(len, GFP_KERNEL);
+		if (!img_swap) {
+			dev_err(codec->dev,
+				"Failed to allocate image buffer\n");
+			goto abort;
+		}
+
+		/* We need to re-order for 0010 */
+		byte_swap_64((u64 *)&pll_rec, img_swap, len);
+
+		spi_message_init(&m);
+		memset(&t, 0, sizeof(t));
+		t.rx_buf = out;
+		t.tx_buf = img_swap;
+		t.len = len;
+		t.bits_per_word = 8;
+		t.speed_hz = wm0010->sysclk / 6;
+		spi_message_add_tail(&t, &m);
+
+		ret = spi_sync(spi, &m);
+		if (ret != 0) {
+			dev_err(codec->dev, "First PLL write failed: %d\n", ret);
+			goto abort;
+		}
+
+		/* Use a second send of the message to get the return status */
+		ret = spi_sync(spi, &m);
+		if (ret != 0) {
+			dev_err(codec->dev, "Second PLL write failed: %d\n", ret);
+			goto abort;
+		}
+
+		p = (u32 *)out;
+
+		/* Look for PLL active code from the DSP */
+		for (i = 0; i < len / 4; i++) {
+			if (*p == 0x0e00ed0f) {
+				dev_dbg(codec->dev, "PLL packet received\n");
+				wm0010->pll_running = true;
+				break;
+			}
+			p++;
+		}
+
+		kfree(img_swap);
+		kfree(out);
+	} else
+		dev_dbg(codec->dev, "Not enabling DSP PLL.");
+
+	ret = request_firmware(&fw, "wm0010.dfw", codec->dev);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to request application: %d\n",
+			ret);
+		goto abort;
+	}
+
+	rec = (const struct dfw_binrec *)fw->data;
+	offset = 0;
+	wm0010->boot_done = 0;
+	wm0010->boot_failed = false;
+	BUG_ON(!list_empty(&xfer_list));
+	init_completion(&done);
+
+	/* First record should be INFO */
+	if (rec->command != DFW_CMD_INFO) {
+		dev_err(codec->dev, "First record not INFO\r\n");
+		goto abort;
+	}
+
+	/* Check it's a 0010 file */
+	if (rec->data[0] != DEVICE_ID_WM0010) {
+		dev_err(codec->dev, "Not a WM0010 firmware file.\r\n");
+		goto abort;
+	}
+
+	/* Skip the info record as we don't need to send it */
+	offset += ((rec->length) + 8);
+	rec = (void *)&rec->data[rec->length];
+
+	while (offset < fw->size) {
+		dev_dbg(codec->dev,
+			"Packet: command %d, data length = 0x%x\r\n",
+			rec->command, rec->length);
+		len = rec->length + 8;
+
+		out = kzalloc(len, GFP_KERNEL);
+		if (!out) {
+			dev_err(codec->dev,
+				"Failed to allocate RX buffer\n");
+			goto abort;
+		}
+
+		img_swap = kzalloc(len, GFP_KERNEL);
+		if (!img_swap) {
+			dev_err(codec->dev,
+				"Failed to allocate image buffer\n");
+			goto abort;
+		}
+
+		/* We need to re-order for 0010 */
+		byte_swap_64((u64 *)&rec->command, img_swap, len);
+
+		xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
+		if (!xfer) {
+			dev_err(codec->dev, "Failed to allocate xfer\n");
+			goto abort;
+		}
+
+		xfer->codec = codec;
+		list_add_tail(&xfer->list, &xfer_list);
+
+		spi_message_init(&xfer->m);
+		xfer->m.complete = wm0010_boot_xfer_complete;
+		xfer->m.context = xfer;
+		xfer->t.tx_buf = img_swap;
+		xfer->t.rx_buf = out;
+		xfer->t.len = len;
+		xfer->t.bits_per_word = 8;
+
+		if (!wm0010->pll_running) {
+			xfer->t.speed_hz = wm0010->sysclk / 6;
+		} else {
+			xfer->t.speed_hz = wm0010->max_spi_freq;
+
+			if (wm0010->board_max_spi_speed &&
+			   (wm0010->board_max_spi_speed < wm0010->max_spi_freq))
+					xfer->t.speed_hz = wm0010->board_max_spi_speed;
+		}
+
+		/* Store max usable spi frequency for later use */
+		wm0010->max_spi_freq = xfer->t.speed_hz;
+
+		spi_message_add_tail(&xfer->t, &xfer->m);
+
+		offset += ((rec->length) + 8);
+		rec = (void *)&rec->data[rec->length];
+
+		if (offset >= fw->size) {
+			dev_dbg(codec->dev, "All transfers scheduled\n");
+			xfer->done = &done;
+		}
+
+		ret = spi_async(spi, &xfer->m);
+		if (ret != 0) {
+			dev_err(codec->dev, "Write failed: %d\n", ret);
+			goto abort;
+		}
+
+		if (wm0010->boot_failed)
+			goto abort;
+	}
+
+	wait_for_completion(&done);
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	wm0010->state = WM0010_FIRMWARE;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	mutex_unlock(&wm0010->lock);
+
+	release_firmware(fw);
+
+	while (!list_empty(&xfer_list)) {
+		xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer,
+					list);
+		kfree(xfer->t.rx_buf);
+		kfree(xfer->t.tx_buf);
+		list_del(&xfer->list);
+		kfree(xfer);
+	}
+
+	return 0;
+
+abort:
+	/* Put the chip back into reset */
+	wm0010_halt(codec);
+	mutex_unlock(&wm0010->lock);
+	return ret;
+err_core:
+	regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies),
+			       wm0010->core_supplies);
+err:
+	return ret;
+}
+
+static int wm0010_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE)
+			wm0010_boot(codec);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) {
+			mutex_lock(&wm0010->lock);
+			wm0010_halt(codec);
+			mutex_unlock(&wm0010->lock);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		break;
+	}
+
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+static int wm0010_set_sysclk(struct snd_soc_codec *codec, int source,
+			     int clk_id, unsigned int freq, int dir)
+{
+	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+	unsigned int i;
+
+	wm0010->sysclk = freq;
+
+	if (freq < pll_clock_map[ARRAY_SIZE(pll_clock_map)-1].max_sysclk) {
+		wm0010->max_spi_freq = 0;
+	} else {
+		for (i = 0; i < ARRAY_SIZE(pll_clock_map); i++)
+			if (freq >= pll_clock_map[i].max_sysclk)
+				break;
+
+		wm0010->max_spi_freq = pll_clock_map[i].max_pll_spi_speed;
+		wm0010->pll_clkctrl1 = pll_clock_map[i].pll_clkctrl1;
+	}
+
+	return 0;
+}
+
+static int wm0010_probe(struct snd_soc_codec *codec);
+
+static struct snd_soc_codec_driver soc_codec_dev_wm0010 = {
+	.probe = wm0010_probe,
+	.set_bias_level = wm0010_set_bias_level,
+	.set_sysclk = wm0010_set_sysclk,
+	.idle_bias_off = true,
+
+	.dapm_widgets = wm0010_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm0010_dapm_widgets),
+	.dapm_routes = wm0010_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm0010_dapm_routes),
+};
+
+#define WM0010_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define WM0010_FORMATS (SNDRV_PCM_FMTBIT_S8 | 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_driver wm0010_dai[] = {
+	{
+		.name = "wm0010-sdi1",
+		.playback = {
+			.stream_name = "SDI1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM0010_RATES,
+			.formats = WM0010_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "SDI1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM0010_RATES,
+			 .formats = WM0010_FORMATS,
+		 },
+	},
+	{
+		.name = "wm0010-sdi2",
+		.playback = {
+			.stream_name = "SDI2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM0010_RATES,
+			.formats = WM0010_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "SDI2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM0010_RATES,
+			 .formats = WM0010_FORMATS,
+		 },
+	},
+};
+
+static irqreturn_t wm0010_irq(int irq, void *data)
+{
+	struct wm0010_priv *wm0010 = data;
+
+	switch (wm0010->state) {
+	case WM0010_POWER_OFF:
+	case WM0010_OUT_OF_RESET:
+	case WM0010_BOOTROM:
+	case WM0010_STAGE2:
+		spin_lock(&wm0010->irq_lock);
+		complete(&wm0010->boot_completion);
+		spin_unlock(&wm0010->irq_lock);
+		return IRQ_HANDLED;
+	default:
+		return IRQ_NONE;
+	}
+
+	return IRQ_NONE;
+}
+
+static int wm0010_probe(struct snd_soc_codec *codec)
+{
+	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+
+	wm0010->codec = codec;
+
+	return 0;
+}
+
+static int __devinit wm0010_spi_probe(struct spi_device *spi)
+{
+	unsigned long flags;
+	unsigned long gpio_flags;
+	int ret;
+	int trigger;
+	int irq;
+	struct wm0010_priv *wm0010;
+
+	wm0010 = devm_kzalloc(&spi->dev, sizeof(*wm0010),
+			      GFP_KERNEL);
+	if (!wm0010)
+		return -ENOMEM;
+
+	mutex_init(&wm0010->lock);
+	spin_lock_init(&wm0010->irq_lock);
+
+	spi_set_drvdata(spi, wm0010);
+	wm0010->dev = &spi->dev;
+
+	if (dev_get_platdata(&spi->dev))
+		memcpy(&wm0010->pdata, dev_get_platdata(&spi->dev),
+		       sizeof(wm0010->pdata));
+
+	init_completion(&wm0010->boot_completion);
+
+	wm0010->core_supplies[0].supply = "AVDD";
+	wm0010->core_supplies[1].supply = "DCVDD";
+	ret = devm_regulator_bulk_get(wm0010->dev, ARRAY_SIZE(wm0010->core_supplies),
+				      wm0010->core_supplies);
+	if (ret != 0) {
+		dev_err(wm0010->dev, "Failed to obtain core supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	wm0010->dbvdd = devm_regulator_get(wm0010->dev, "DBVDD");
+	if (IS_ERR(wm0010->dbvdd)) {
+		ret = PTR_ERR(wm0010->dbvdd);
+		dev_err(wm0010->dev, "Failed to obtain DBVDD: %d\n", ret);
+		return ret;
+	}
+
+	if (wm0010->pdata.gpio_reset) {
+		wm0010->gpio_reset = wm0010->pdata.gpio_reset;
+
+		if (wm0010->pdata.reset_active_high)
+			wm0010->gpio_reset_value = 1;
+		else
+			wm0010->gpio_reset_value = 0;
+
+		if (wm0010->gpio_reset_value)
+			gpio_flags = GPIOF_OUT_INIT_HIGH;
+		else
+			gpio_flags = GPIOF_OUT_INIT_LOW;
+
+		ret = devm_gpio_request_one(wm0010->dev, wm0010->gpio_reset,
+					    gpio_flags, "wm0010 reset");
+		if (ret < 0) {
+			dev_err(wm0010->dev,
+				"Failed to request GPIO for DSP reset: %d\n",
+				ret);
+			return ret;
+		}
+	} else {
+		dev_err(wm0010->dev, "No reset GPIO configured\n");
+		return -EINVAL;
+	}
+
+	irq = spi->irq;
+	if (wm0010->pdata.irq_flags)
+		trigger = wm0010->pdata.irq_flags;
+	else
+		trigger = IRQF_TRIGGER_FALLING;
+	trigger |= IRQF_ONESHOT;
+
+	ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger,
+				   "wm0010", wm0010);
+	if (ret) {
+		dev_err(wm0010->dev, "Failed to request IRQ %d: %d\n",
+			irq, ret);
+		return ret;
+	}
+	wm0010->irq = irq;
+
+	if (spi->max_speed_hz)
+		wm0010->board_max_spi_speed = spi->max_speed_hz;
+	else
+		wm0010->board_max_spi_speed = 0;
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	wm0010->state = WM0010_POWER_OFF;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	ret = snd_soc_register_codec(&spi->dev,
+				     &soc_codec_dev_wm0010, wm0010_dai,
+				     ARRAY_SIZE(wm0010_dai));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int __devexit wm0010_spi_remove(struct spi_device *spi)
+{
+	struct wm0010_priv *wm0010 = spi_get_drvdata(spi);
+
+	snd_soc_unregister_codec(&spi->dev);
+
+	if (wm0010->gpio_reset) {
+		/* Remember to put chip back into reset */
+		gpio_set_value(wm0010->gpio_reset, wm0010->gpio_reset_value);
+	}
+
+	if (wm0010->irq)
+		free_irq(wm0010->irq, wm0010);
+
+	return 0;
+}
+
+static struct spi_driver wm0010_spi_driver = {
+	.driver = {
+		.name	= "wm0010",
+		.bus 	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm0010_spi_probe,
+	.remove		= __devexit_p(wm0010_spi_remove),
+};
+
+module_spi_driver(wm0010_spi_driver);
+
+MODULE_DESCRIPTION("ASoC WM0010 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 3fd5b29..89cd6fc 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -858,17 +858,7 @@
 	.id_table = wm2000_i2c_id,
 };
 
-static int __init wm2000_init(void)
-{
-	return i2c_add_driver(&wm2000_i2c_driver);
-}
-module_init(wm2000_init);
-
-static void __exit wm2000_exit(void)
-{
-	i2c_del_driver(&wm2000_i2c_driver);
-}
-module_exit(wm2000_exit);
+module_i2c_driver(wm2000_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM2000 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>");
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 32682c1..71debd0 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -2270,17 +2270,7 @@
 	.id_table = wm2200_i2c_id,
 };
 
-static int __init wm2200_modinit(void)
-{
-	return i2c_add_driver(&wm2200_i2c_driver);
-}
-module_init(wm2200_modinit);
-
-static void __exit wm2200_exit(void)
-{
-	i2c_del_driver(&wm2200_i2c_driver);
-}
-module_exit(wm2200_exit);
+module_i2c_driver(wm2200_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM2200 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index e33d327..e2fb07e 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -274,11 +274,36 @@
 ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
 
+
+static const char *wm5102_aec_loopback_texts[] = {
+	"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "EPOUT",
+	"SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R",
+};
+
+static const unsigned int wm5102_aec_loopback_values[] = {
+	0, 1, 2, 3, 4, 6, 7, 8, 9,
+};
+
+static const struct soc_enum wm5102_aec_loopback =
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+			      ARIZONA_AEC_LOOPBACK_SRC_SHIFT,
+			      ARIZONA_AEC_LOOPBACK_SRC_MASK,
+			      ARRAY_SIZE(wm5102_aec_loopback_texts),
+			      wm5102_aec_loopback_texts,
+			      wm5102_aec_loopback_values);
+
+static const struct snd_kcontrol_new wm5102_aec_loopback_mux =
+	SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5102_aec_loopback);
+
 static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
 		    0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
 		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+		    ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
 
 SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0),
 SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0),
@@ -421,6 +446,9 @@
 SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
 		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
 
+SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+		       ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux),
+
 SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
@@ -516,6 +544,7 @@
 	{ name, "Noise Generator", "Noise Generator" }, \
 	{ name, "Tone Generator 1", "Tone Generator 1" }, \
 	{ name, "Tone Generator 2", "Tone Generator 2" }, \
+	{ name, "AEC", "AEC Loopback" }, \
 	{ name, "IN1L", "IN1L PGA" }, \
 	{ name, "IN1R", "IN1R PGA" }, \
 	{ name, "IN2L", "IN2L PGA" }, \
@@ -681,21 +710,30 @@
 	ARIZONA_MIXER_ROUTES("ASRC2L", "ASRC2L"),
 	ARIZONA_MIXER_ROUTES("ASRC2R", "ASRC2R"),
 
+	{ "AEC Loopback", "HPOUT1L", "OUT1L" },
+	{ "AEC Loopback", "HPOUT1R", "OUT1R" },
 	{ "HPOUT1L", NULL, "OUT1L" },
 	{ "HPOUT1R", NULL, "OUT1R" },
 
+	{ "AEC Loopback", "HPOUT2L", "OUT2L" },
+	{ "AEC Loopback", "HPOUT2R", "OUT2R" },
 	{ "HPOUT2L", NULL, "OUT2L" },
 	{ "HPOUT2R", NULL, "OUT2R" },
 
+	{ "AEC Loopback", "EPOUT", "OUT3L" },
 	{ "EPOUTN", NULL, "OUT3L" },
 	{ "EPOUTP", NULL, "OUT3L" },
 
+	{ "AEC Loopback", "SPKOUTL", "OUT4L" },
 	{ "SPKOUTLN", NULL, "OUT4L" },
 	{ "SPKOUTLP", NULL, "OUT4L" },
 
+	{ "AEC Loopback", "SPKOUTR", "OUT4R" },
 	{ "SPKOUTRN", NULL, "OUT4R" },
 	{ "SPKOUTRP", NULL, "OUT4R" },
 
+	{ "AEC Loopback", "SPKDAT1L", "OUT5L" },
+	{ "AEC Loopback", "SPKDAT1R", "OUT5R" },
 	{ "SPKDAT1L", NULL, "OUT5L" },
 	{ "SPKDAT1R", NULL, "OUT5R" },
 };
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 01ebbcc..57c7d9c 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -305,6 +305,10 @@
 		    0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
 		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+		    ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
 
 SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0),
 SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0),
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
index a5127b4..c7c0034 100644
--- a/sound/soc/codecs/wm8770.c
+++ b/sound/soc/codecs/wm8770.c
@@ -724,24 +724,7 @@
 	.remove = __devexit_p(wm8770_spi_remove)
 };
 
-static int __init wm8770_modinit(void)
-{
-	int ret = 0;
-
-	ret = spi_register_driver(&wm8770_spi_driver);
-	if (ret) {
-		printk(KERN_ERR "Failed to register wm8770 SPI driver: %d\n",
-		       ret);
-	}
-	return ret;
-}
-module_init(wm8770_modinit);
-
-static void __exit wm8770_exit(void)
-{
-	spi_unregister_driver(&wm8770_spi_driver);
-}
-module_exit(wm8770_exit);
+module_spi_driver(wm8770_spi_driver);
 
 MODULE_DESCRIPTION("ASoC WM8770 driver");
 MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 73f1c8d..839414f 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -2241,23 +2241,7 @@
 	.id_table = wm8903_i2c_id,
 };
 
-static int __init wm8903_modinit(void)
-{
-	int ret = 0;
-	ret = i2c_add_driver(&wm8903_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register wm8903 I2C driver: %d\n",
-		       ret);
-	}
-	return ret;
-}
-module_init(wm8903_modinit);
-
-static void __exit wm8903_exit(void)
-{
-	i2c_del_driver(&wm8903_i2c_driver);
-}
-module_exit(wm8903_exit);
+module_i2c_driver(wm8903_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8903 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>");
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 481a3d9..b20aa4e 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -785,23 +785,7 @@
 	.id_table = wm8940_i2c_id,
 };
 
-static int __init wm8940_modinit(void)
-{
-	int ret = 0;
-	ret = i2c_add_driver(&wm8940_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n",
-		       ret);
-	}
-	return ret;
-}
-module_init(wm8940_modinit);
-
-static void __exit wm8940_exit(void)
-{
-	i2c_del_driver(&wm8940_i2c_driver);
-}
-module_exit(wm8940_exit);
+module_i2c_driver(wm8940_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8940 driver");
 MODULE_AUTHOR("Jonathan Cameron");
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 61fe974..2f1c075 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -1071,23 +1071,7 @@
 	.id_table = wm8955_i2c_id,
 };
 
-static int __init wm8955_modinit(void)
-{
-	int ret = 0;
-	ret = i2c_add_driver(&wm8955_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n",
-		       ret);
-	}
-	return ret;
-}
-module_init(wm8955_modinit);
-
-static void __exit wm8955_exit(void)
-{
-	i2c_del_driver(&wm8955_i2c_driver);
-}
-module_exit(wm8955_exit);
+module_i2c_driver(wm8955_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8955 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
index 1332692..00121ba 100644
--- a/sound/soc/codecs/wm8958-dsp2.c
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -946,7 +946,7 @@
 		wm8994->mbc_texts = kmalloc(sizeof(char *)
 					    * pdata->num_mbc_cfgs, GFP_KERNEL);
 		if (!wm8994->mbc_texts) {
-			dev_err(wm8994->codec->dev,
+			dev_err(wm8994->hubs.codec->dev,
 				"Failed to allocate %d MBC config texts\n",
 				pdata->num_mbc_cfgs);
 			return;
@@ -958,9 +958,10 @@
 		wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
 		wm8994->mbc_enum.texts = wm8994->mbc_texts;
 
-		ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
+		ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+						 control, 1);
 		if (ret != 0)
-			dev_err(wm8994->codec->dev,
+			dev_err(wm8994->hubs.codec->dev,
 				"Failed to add MBC mode controls: %d\n", ret);
 	}
 
@@ -974,7 +975,7 @@
 		wm8994->vss_texts = kmalloc(sizeof(char *)
 					    * pdata->num_vss_cfgs, GFP_KERNEL);
 		if (!wm8994->vss_texts) {
-			dev_err(wm8994->codec->dev,
+			dev_err(wm8994->hubs.codec->dev,
 				"Failed to allocate %d VSS config texts\n",
 				pdata->num_vss_cfgs);
 			return;
@@ -986,9 +987,10 @@
 		wm8994->vss_enum.max = pdata->num_vss_cfgs;
 		wm8994->vss_enum.texts = wm8994->vss_texts;
 
-		ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
+		ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+						 control, 1);
 		if (ret != 0)
-			dev_err(wm8994->codec->dev,
+			dev_err(wm8994->hubs.codec->dev,
 				"Failed to add VSS mode controls: %d\n", ret);
 	}
 
@@ -1003,7 +1005,7 @@
 		wm8994->vss_hpf_texts = kmalloc(sizeof(char *)
 						* pdata->num_vss_hpf_cfgs, GFP_KERNEL);
 		if (!wm8994->vss_hpf_texts) {
-			dev_err(wm8994->codec->dev,
+			dev_err(wm8994->hubs.codec->dev,
 				"Failed to allocate %d VSS HPF config texts\n",
 				pdata->num_vss_hpf_cfgs);
 			return;
@@ -1015,9 +1017,10 @@
 		wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;
 		wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
 
-		ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
+		ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+						 control, 1);
 		if (ret != 0)
-			dev_err(wm8994->codec->dev,
+			dev_err(wm8994->hubs.codec->dev,
 				"Failed to add VSS HPFmode controls: %d\n",
 				ret);
 	}
@@ -1033,7 +1036,7 @@
 		wm8994->enh_eq_texts = kmalloc(sizeof(char *)
 						* pdata->num_enh_eq_cfgs, GFP_KERNEL);
 		if (!wm8994->enh_eq_texts) {
-			dev_err(wm8994->codec->dev,
+			dev_err(wm8994->hubs.codec->dev,
 				"Failed to allocate %d enhanced EQ config texts\n",
 				pdata->num_enh_eq_cfgs);
 			return;
@@ -1045,9 +1048,10 @@
 		wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;
 		wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
 
-		ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
+		ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+						 control, 1);
 		if (ret != 0)
-			dev_err(wm8994->codec->dev,
+			dev_err(wm8994->hubs.codec->dev,
 				"Failed to add enhanced EQ controls: %d\n",
 				ret);
 	}
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 96518ac..804f411 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -1010,23 +1010,7 @@
 	.id_table = wm8960_i2c_id,
 };
 
-static int __init wm8960_modinit(void)
-{
-	int ret = 0;
-	ret = i2c_add_driver(&wm8960_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n",
-		       ret);
-	}
-	return ret;
-}
-module_init(wm8960_modinit);
-
-static void __exit wm8960_exit(void)
-{
-	i2c_del_driver(&wm8960_i2c_driver);
-}
-module_exit(wm8960_exit);
+module_i2c_driver(wm8960_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8960 driver");
 MODULE_AUTHOR("Liam Girdwood");
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 01edbcc..719fb69 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -1114,23 +1114,7 @@
 	.id_table = wm8961_i2c_id,
 };
 
-static int __init wm8961_modinit(void)
-{
-	int ret = 0;
-	ret = i2c_add_driver(&wm8961_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register wm8961 I2C driver: %d\n",
-		       ret);
-	}
-	return ret;
-}
-module_init(wm8961_modinit);
-
-static void __exit wm8961_exit(void)
-{
-	i2c_del_driver(&wm8961_i2c_driver);
-}
-module_exit(wm8961_exit);
+module_i2c_driver(wm8961_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8961 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index eef783f..5ce6477 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -721,23 +721,7 @@
 	.id_table = wm8971_i2c_id,
 };
 
-static int __init wm8971_modinit(void)
-{
-	int ret = 0;
-	ret = i2c_add_driver(&wm8971_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n",
-		       ret);
-	}
-	return ret;
-}
-module_init(wm8971_modinit);
-
-static void __exit wm8971_exit(void)
-{
-	i2c_del_driver(&wm8971_i2c_driver);
-}
-module_exit(wm8971_exit);
+module_i2c_driver(wm8971_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8971 driver");
 MODULE_AUTHOR("Lab126");
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index d93c03f..9a39511 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -659,23 +659,7 @@
 	.id_table = wm8974_i2c_id,
 };
 
-static int __init wm8974_modinit(void)
-{
-	int ret = 0;
-	ret = i2c_add_driver(&wm8974_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n",
-		       ret);
-	}
-	return ret;
-}
-module_init(wm8974_modinit);
-
-static void __exit wm8974_exit(void)
-{
-	i2c_del_driver(&wm8974_i2c_driver);
-}
-module_exit(wm8974_exit);
+module_i2c_driver(wm8974_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8974 driver");
 MODULE_AUTHOR("Liam Girdwood");
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index a5be3ad..5421fd9 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -1105,23 +1105,7 @@
 	.id_table = wm8978_i2c_id,
 };
 
-static int __init wm8978_modinit(void)
-{
-	int ret = 0;
-	ret = i2c_add_driver(&wm8978_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n",
-		       ret);
-	}
-	return ret;
-}
-module_init(wm8978_modinit);
-
-static void __exit wm8978_exit(void)
-{
-	i2c_del_driver(&wm8978_i2c_driver);
-}
-module_exit(wm8978_exit);
+module_i2c_driver(wm8978_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8978 codec driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 9ac31ba..b9dbfeb 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -1400,23 +1400,7 @@
 	.id_table = wm8991_i2c_id,
 };
 
-static int __init wm8991_modinit(void)
-{
-	int ret;
-	ret = i2c_add_driver(&wm8991_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register WM8991 I2C driver: %d\n",
-		       ret);
-	}
-	return 0;
-}
-module_init(wm8991_modinit);
-
-static void __exit wm8991_exit(void)
-{
-	i2c_del_driver(&wm8991_i2c_driver);
-}
-module_exit(wm8991_exit);
+module_i2c_driver(wm8991_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8991 driver");
 MODULE_AUTHOR("Graeme Gregory");
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 9fd80d6..94737a3 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -1520,6 +1520,8 @@
 				      wm8993->pdata.lineout2fb,
 				      wm8993->pdata.jd_scthr,
 				      wm8993->pdata.jd_thr,
+				      wm8993->pdata.micbias1_delay,
+				      wm8993->pdata.micbias2_delay,
 				      wm8993->pdata.micbias1_lvl,
 				      wm8993->pdata.micbias2_lvl);
 
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 6c9eeca..2b2dadc 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -671,6 +671,18 @@
 	       eq_tlv),
 };
 
+static const struct snd_kcontrol_new wm8994_drc_controls[] = {
+SND_SOC_BYTES_MASK("AIF1.1 DRC", WM8994_AIF1_DRC1_1, 5,
+		   WM8994_AIF1DAC1_DRC_ENA | WM8994_AIF1ADC1L_DRC_ENA |
+		   WM8994_AIF1ADC1R_DRC_ENA),
+SND_SOC_BYTES_MASK("AIF1.2 DRC", WM8994_AIF1_DRC2_1, 5,
+		   WM8994_AIF1DAC2_DRC_ENA | WM8994_AIF1ADC2L_DRC_ENA |
+		   WM8994_AIF1ADC2R_DRC_ENA),
+SND_SOC_BYTES_MASK("AIF2 DRC", WM8994_AIF2_DRC_1, 5,
+		   WM8994_AIF2DAC_DRC_ENA | WM8994_AIF2ADCL_DRC_ENA |
+		   WM8994_AIF2ADCR_DRC_ENA),
+};
+
 static const char *wm8958_ng_text[] = {
 	"30ms", "125ms", "250ms", "500ms",
 };
@@ -789,11 +801,27 @@
 			 struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		return configure_clock(codec);
 
+	case SND_SOC_DAPM_POST_PMU:
+		/*
+		 * JACKDET won't run until we start the clock and it
+		 * only reports deltas, make sure we notify the state
+		 * up the stack on startup.  Use a *very* generous
+		 * timeout for paranoia, there's no urgency and we
+		 * don't want false reports.
+		 */
+		if (wm8994->jackdet && !wm8994->clk_has_run) {
+			schedule_delayed_work(&wm8994->jackdet_bootstrap,
+					      msecs_to_jiffies(1000));
+			wm8994->clk_has_run = true;
+		}
+		break;
+
 	case SND_SOC_DAPM_POST_PMD:
 		configure_clock(codec);
 		break;
@@ -1632,7 +1660,8 @@
 		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
 SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
-		    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		    SND_SOC_DAPM_PRE_PMD),
 
 SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, 3, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("DSP2CLK", SND_SOC_NOPM, 2, 0, NULL, 0),
@@ -2102,6 +2131,10 @@
 	case WM8994_FLL_SRC_LRCLK:
 	case WM8994_FLL_SRC_BCLK:
 		break;
+	case WM8994_FLL_SRC_INTERNAL:
+		freq_in = 12000000;
+		freq_out = 12000000;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -2161,12 +2194,14 @@
 
 	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_4 + reg_offset,
 			    WM8994_FLL1_N_MASK,
-				    fll.n << WM8994_FLL1_N_SHIFT);
+			    fll.n << WM8994_FLL1_N_SHIFT);
 
 	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
-			    WM8958_FLL1_BYP |
+			    WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP |
 			    WM8994_FLL1_REFCLK_DIV_MASK |
 			    WM8994_FLL1_REFCLK_SRC_MASK,
+			    ((src == WM8994_FLL_SRC_INTERNAL)
+			     << WM8994_FLL1_FRC_NCO_SHIFT) |
 			    (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
 			    (src - 1));
 
@@ -2192,13 +2227,16 @@
 			}
 		}
 
+		reg = WM8994_FLL1_ENA;
+
 		if (fll.k)
-			reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC;
-		else
-			reg = WM8994_FLL1_ENA;
+			reg |= WM8994_FLL1_FRAC;
+		if (src == WM8994_FLL_SRC_INTERNAL)
+			reg |= WM8994_FLL1_OSC_ENA;
+
 		snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
-				    WM8994_FLL1_ENA | WM8994_FLL1_FRAC,
-				    reg);
+				    WM8994_FLL1_ENA | WM8994_FLL1_OSC_ENA |
+				    WM8994_FLL1_FRAC, reg);
 
 		if (wm8994->fll_locked_irq) {
 			timeout = wait_for_completion_timeout(&wm8994->fll_locked[id],
@@ -3027,7 +3065,7 @@
 
 static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
 {
-	struct snd_soc_codec *codec = wm8994->codec;
+	struct snd_soc_codec *codec = wm8994->hubs.codec;
 	struct wm8994_pdata *pdata = wm8994->pdata;
 	struct snd_kcontrol_new controls[] = {
 		SOC_ENUM_EXT("AIF1.1 EQ Mode",
@@ -3085,16 +3123,16 @@
 	wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts;
 	wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
 
-	ret = snd_soc_add_codec_controls(wm8994->codec, controls,
+	ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,
 				   ARRAY_SIZE(controls));
 	if (ret != 0)
-		dev_err(wm8994->codec->dev,
+		dev_err(wm8994->hubs.codec->dev,
 			"Failed to add ReTune Mobile controls: %d\n", ret);
 }
 
 static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 {
-	struct snd_soc_codec *codec = wm8994->codec;
+	struct snd_soc_codec *codec = wm8994->hubs.codec;
 	struct wm8994_pdata *pdata = wm8994->pdata;
 	int ret, i;
 
@@ -3107,6 +3145,8 @@
 				      pdata->lineout2fb,
 				      pdata->jd_scthr,
 				      pdata->jd_thr,
+				      pdata->micb1_delay,
+				      pdata->micb2_delay,
 				      pdata->micbias1_lvl,
 				      pdata->micbias2_lvl);
 
@@ -3123,10 +3163,10 @@
 		};
 
 		/* We need an array of texts for the enum API */
-		wm8994->drc_texts = devm_kzalloc(wm8994->codec->dev,
+		wm8994->drc_texts = devm_kzalloc(wm8994->hubs.codec->dev,
 			    sizeof(char *) * pdata->num_drc_cfgs, GFP_KERNEL);
 		if (!wm8994->drc_texts) {
-			dev_err(wm8994->codec->dev,
+			dev_err(wm8994->hubs.codec->dev,
 				"Failed to allocate %d DRC config texts\n",
 				pdata->num_drc_cfgs);
 			return;
@@ -3138,23 +3178,28 @@
 		wm8994->drc_enum.max = pdata->num_drc_cfgs;
 		wm8994->drc_enum.texts = wm8994->drc_texts;
 
-		ret = snd_soc_add_codec_controls(wm8994->codec, controls,
+		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,
 					   ARRAY_SIZE(controls));
-		if (ret != 0)
-			dev_err(wm8994->codec->dev,
-				"Failed to add DRC mode controls: %d\n", ret);
-
 		for (i = 0; i < WM8994_NUM_DRC; i++)
 			wm8994_set_drc(codec, i);
+	} else {
+		ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+						 wm8994_drc_controls,
+						 ARRAY_SIZE(wm8994_drc_controls));
 	}
 
+	if (ret != 0)
+		dev_err(wm8994->hubs.codec->dev,
+			"Failed to add DRC mode controls: %d\n", ret);
+
+
 	dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
 		pdata->num_retune_mobile_cfgs);
 
 	if (pdata->num_retune_mobile_cfgs)
 		wm8994_handle_retune_mobile_pdata(wm8994);
 	else
-		snd_soc_add_codec_controls(wm8994->codec, wm8994_eq_controls,
+		snd_soc_add_codec_controls(wm8994->hubs.codec, wm8994_eq_controls,
 				     ARRAY_SIZE(wm8994_eq_controls));
 
 	for (i = 0; i < ARRAY_SIZE(pdata->micbias); i++) {
@@ -3236,6 +3281,12 @@
 
 	snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg);
 
+	/* enable MICDET and MICSHRT deboune */
+	snd_soc_update_bits(codec, WM8994_IRQ_DEBOUNCE,
+			    WM8994_MIC1_DET_DB_MASK | WM8994_MIC1_SHRT_DB_MASK |
+			    WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK,
+			    WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB);
+
 	snd_soc_dapm_sync(&codec->dapm);
 
 	return 0;
@@ -3309,7 +3360,7 @@
 static irqreturn_t wm8994_mic_irq(int irq, void *data)
 {
 	struct wm8994_priv *priv = data;
-	struct snd_soc_codec *codec = priv->codec;
+	struct snd_soc_codec *codec = priv->hubs.codec;
 
 #ifndef CONFIG_SND_SOC_WM8994_MODULE
 	trace_snd_soc_jack_irq(dev_name(codec->dev));
@@ -3345,7 +3396,7 @@
 
 			snd_soc_jack_report(wm8994->micdet[0].jack, 0,
 					    wm8994->btn_mask |
-					     SND_JACK_HEADSET);
+					    SND_JACK_HEADSET);
 		}
 		return;
 	}
@@ -3422,7 +3473,7 @@
 static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
 {
 	struct wm8994_priv *wm8994 = data;
-	struct snd_soc_codec *codec = wm8994->codec;
+	struct snd_soc_codec *codec = wm8994->hubs.codec;
 	int reg;
 	bool present;
 
@@ -3499,10 +3550,22 @@
 				    SND_JACK_MECHANICAL | SND_JACK_HEADSET |
 				    wm8994->btn_mask);
 
+	/* Since we only report deltas force an update, ensures we
+	 * avoid bootstrapping issues with the core. */
+	snd_soc_jack_report(wm8994->micdet[0].jack, 0, 0);
+
 	pm_runtime_put(codec->dev);
 	return IRQ_HANDLED;
 }
 
+static void wm1811_jackdet_bootstrap(struct work_struct *work)
+{
+	struct wm8994_priv *wm8994 = container_of(work,
+						struct wm8994_priv,
+						jackdet_bootstrap.work);
+	wm1811_jackdet_irq(0, wm8994);
+}
+
 /**
  * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ
  *
@@ -3573,6 +3636,10 @@
 		 * otherwise jump straight to microphone detection.
 		 */
 		if (wm8994->jackdet) {
+			/* Disable debounce for the initial detect */
+			snd_soc_update_bits(codec, WM1811_JACKDET_CTRL,
+					    WM1811_JACKDET_DB, 0);
+
 			snd_soc_update_bits(codec, WM8958_MICBIAS2,
 					    WM8958_MICB2_DISCH,
 					    WM8958_MICB2_DISCH);
@@ -3600,7 +3667,7 @@
 static irqreturn_t wm8958_mic_irq(int irq, void *data)
 {
 	struct wm8994_priv *wm8994 = data;
-	struct snd_soc_codec *codec = wm8994->codec;
+	struct snd_soc_codec *codec = wm8994->hubs.codec;
 	int reg, count;
 
 	/*
@@ -3690,15 +3757,15 @@
 	unsigned int reg;
 	int ret, i;
 
-	wm8994->codec = codec;
+	wm8994->hubs.codec = codec;
 	codec->control_data = control->regmap;
 
 	snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
 
-	wm8994->codec = codec;
-
 	mutex_init(&wm8994->accdet_lock);
 	INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work);
+	INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
+			  wm1811_jackdet_bootstrap);
 
 	for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
 		init_completion(&wm8994->fll_locked[i]);
@@ -3756,14 +3823,17 @@
 		wm8994->hubs.no_cache_dac_hp_direct = true;
 		wm8994->fll_byp = true;
 
-		switch (wm8994->revision) {
+		switch (control->cust_id) {
 		case 0:
-		case 1:
 		case 2:
-		case 3:
 			wm8994->hubs.dcs_codes_l = -9;
 			wm8994->hubs.dcs_codes_r = -7;
 			break;
+		case 1:
+		case 3:
+			wm8994->hubs.dcs_codes_l = -8;
+			wm8994->hubs.dcs_codes_r = -7;
+			break;
 		default:
 			break;
 		}
@@ -3852,7 +3922,7 @@
 
 	switch (control->type) {
 	case WM1811:
-		if (wm8994->revision > 1) {
+		if (control->cust_id > 1 || wm8994->revision > 1) {
 			ret = wm8994_request_irq(wm8994->wm8994,
 						 WM8994_IRQ_GPIO(6),
 						 wm1811_jackdet_irq, "JACKDET",
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index d77e06f..f142ec1 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -28,10 +28,11 @@
 #define WM8994_FLL1 1
 #define WM8994_FLL2 2
 
-#define WM8994_FLL_SRC_MCLK1  1
-#define WM8994_FLL_SRC_MCLK2  2
-#define WM8994_FLL_SRC_LRCLK  3
-#define WM8994_FLL_SRC_BCLK   4
+#define WM8994_FLL_SRC_MCLK1    1
+#define WM8994_FLL_SRC_MCLK2    2
+#define WM8994_FLL_SRC_LRCLK    3
+#define WM8994_FLL_SRC_BCLK     4
+#define WM8994_FLL_SRC_INTERNAL 5
 
 enum wm8994_vmid_mode {
 	WM8994_VMID_NORMAL,
@@ -72,7 +73,6 @@
 struct wm8994_priv {
 	struct wm_hubs_data hubs;
 	struct wm8994 *wm8994;
-	struct snd_soc_codec *codec;
 	int sysclk[2];
 	int sysclk_rate[2];
 	int mclk[2];
@@ -81,6 +81,7 @@
 	struct completion fll_locked[2];
 	bool fll_locked_irq;
 	bool fll_byp;
+	bool clk_has_run;
 
 	int vmid_refcount;
 	int active_refcount;
@@ -134,6 +135,7 @@
 	int btn_mask;
 	bool jackdet;
 	int jackdet_mode;
+	struct delayed_work jackdet_bootstrap;
 
 	wm8958_micdet_cb jack_cb;
 	void *jack_cb_data;
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index 2c2346f..c7ddc56 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -695,17 +695,7 @@
 	.id_table = wm9090_id,
 };
 
-static int __init wm9090_init(void)
-{
-	return i2c_add_driver(&wm9090_i2c_driver);
-}
-module_init(wm9090_init);
-
-static void __exit wm9090_exit(void)
-{
-	i2c_del_driver(&wm9090_i2c_driver);
-}
-module_exit(wm9090_exit);
+module_i2c_driver(wm9090_i2c_driver);
 
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_DESCRIPTION("WM9090 ASoC driver");
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index c6d2076..1992a62 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -132,8 +132,9 @@
 SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 1),
 SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1),
 
-SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0),
-SOC_SINGLE("Capture to Phone 20dB Boost Switch", AC97_REC_SEL, 11, 1, 1),
+SOC_SINGLE_TLV("Capture Boost Switch", AC97_REC_SEL, 14, 1, 0, boost_tlv),
+SOC_SINGLE_TLV("Capture to Phone Boost Switch", AC97_REC_SEL, 11, 1, 1,
+	       boost_tlv),
 
 SOC_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),
 SOC_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1),
@@ -146,7 +147,7 @@
 SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1),
 SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1),
 
-SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1),
+SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1),
 SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),
 SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 0),
 SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
@@ -699,8 +700,8 @@
 
 static struct platform_driver wm9712_codec_driver = {
 	.driver = {
-			.name = "wm9712-codec",
-			.owner = THIS_MODULE,
+		.name = "wm9712-codec",
+		.owner = THIS_MODULE,
 	},
 
 	.probe = wm9712_probe,
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 61baa48..7a773a8 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -199,15 +199,56 @@
 	list_add_tail(&cache->list, &hubs->dcs_cache);
 }
 
+static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
+				  u16 *reg_l, u16 *reg_r)
+{
+	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	u16 dcs_reg, reg;
+
+	switch (hubs->dcs_readback_mode) {
+	case 2:
+		dcs_reg = WM8994_DC_SERVO_4E;
+		break;
+	case 1:
+		dcs_reg = WM8994_DC_SERVO_READBACK;
+		break;
+	default:
+		dcs_reg = WM8993_DC_SERVO_3;
+		break;
+	}
+
+	/* Different chips in the family support different readback
+	 * methods.
+	 */
+	switch (hubs->dcs_readback_mode) {
+	case 0:
+		*reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
+			& WM8993_DCS_INTEG_CHAN_0_MASK;
+		*reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
+			& WM8993_DCS_INTEG_CHAN_1_MASK;
+		break;
+	case 2:
+	case 1:
+		reg = snd_soc_read(codec, dcs_reg);
+		*reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
+			>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+		*reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
+		break;
+	default:
+		WARN(1, "Unknown DCS readback method\n");
+		return;
+	}
+}
+
 /*
  * Startup calibration of the DC servo
  */
-static void calibrate_dc_servo(struct snd_soc_codec *codec)
+static void enable_dc_servo(struct snd_soc_codec *codec)
 {
 	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 	struct wm_hubs_dcs_cache *cache;
 	s8 offset;
-	u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg;
+	u16 reg_l, reg_r, dcs_cfg, dcs_reg;
 
 	switch (hubs->dcs_readback_mode) {
 	case 2:
@@ -245,27 +286,7 @@
 				  WM8993_DCS_TRIG_STARTUP_1);
 	}
 
-	/* Different chips in the family support different readback
-	 * methods.
-	 */
-	switch (hubs->dcs_readback_mode) {
-	case 0:
-		reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
-			& WM8993_DCS_INTEG_CHAN_0_MASK;
-		reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
-			& WM8993_DCS_INTEG_CHAN_1_MASK;
-		break;
-	case 2:
-	case 1:
-		reg = snd_soc_read(codec, dcs_reg);
-		reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
-			>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
-		reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
-		break;
-	default:
-		WARN(1, "Unknown DCS readback method\n");
-		return;
-	}
+	wm_hubs_read_dc_servo(codec, &reg_l, &reg_r);
 
 	dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
 
@@ -276,12 +297,16 @@
 			hubs->dcs_codes_l, hubs->dcs_codes_r);
 
 		/* HPOUT1R */
-		offset = reg_r;
+		offset = (s8)reg_r;
+		dev_dbg(codec->dev, "DCS right %d->%d\n", offset,
+			offset + hubs->dcs_codes_r);
 		offset += hubs->dcs_codes_r;
 		dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
 
 		/* HPOUT1L */
-		offset = reg_l;
+		offset = (s8)reg_l;
+		dev_dbg(codec->dev, "DCS left %d->%d\n", offset,
+			offset + hubs->dcs_codes_l);
 		offset += hubs->dcs_codes_l;
 		dcs_cfg |= (u8)offset;
 
@@ -535,7 +560,7 @@
 		snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
 				    WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
 
-		calibrate_dc_servo(codec);
+		enable_dc_servo(codec);
 
 		reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
 			WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
@@ -619,6 +644,28 @@
 	return 0;
 }
 
+static int micbias_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+
+	switch (w->shift) {
+	case WM8993_MICB1_ENA_SHIFT:
+		if (hubs->micb1_delay)
+			msleep(hubs->micb1_delay);
+		break;
+	case WM8993_MICB2_ENA_SHIFT:
+		if (hubs->micb2_delay)
+			msleep(hubs->micb2_delay);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 void wm_hubs_update_class_w(struct snd_soc_codec *codec)
 {
 	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
@@ -809,8 +856,10 @@
 SND_SOC_DAPM_INPUT("IN2RN"),
 SND_SOC_DAPM_INPUT("IN2RP:VXRP"),
 
-SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0,
+		    micbias_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0,
+		    micbias_event, SND_SOC_DAPM_POST_PMU),
 
 SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
 		   in1l_pga, ARRAY_SIZE(in1l_pga)),
@@ -1112,6 +1161,8 @@
 	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 
+	hubs->codec = codec;
+
 	INIT_LIST_HEAD(&hubs->dcs_cache);
 	init_completion(&hubs->dcs_done);
 
@@ -1143,13 +1194,16 @@
 int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
 				  int lineout1_diff, int lineout2_diff,
 				  int lineout1fb, int lineout2fb,
-				  int jd_scthr, int jd_thr, int micbias1_lvl,
-				  int micbias2_lvl)
+				  int jd_scthr, int jd_thr,
+				  int micbias1_delay, int micbias2_delay,
+				  int micbias1_lvl, int micbias2_lvl)
 {
 	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 
 	hubs->lineout1_se = !lineout1_diff;
 	hubs->lineout2_se = !lineout2_diff;
+	hubs->micb1_delay = micbias1_delay;
+	hubs->micb2_delay = micbias2_delay;
 
 	if (!lineout1_diff)
 		snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h
index da2dc89..24c763d 100644
--- a/sound/soc/codecs/wm_hubs.h
+++ b/sound/soc/codecs/wm_hubs.h
@@ -36,6 +36,9 @@
 	struct list_head dcs_cache;
 	bool (*check_class_w_digital)(struct snd_soc_codec *);
 
+	int micb1_delay;
+	int micb2_delay;
+
 	bool lineout1_se;
 	bool lineout1n_ena;
 	bool lineout1p_ena;
@@ -46,6 +49,8 @@
 
 	bool dcs_done_irq;
 	struct completion dcs_done;
+
+	struct snd_soc_codec *codec;
 };
 
 extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *);
@@ -54,6 +59,7 @@
 					 int lineout1_diff, int lineout2_diff,
 					 int lineout1fb, int lineout2fb,
 					 int jd_scthr, int jd_thr,
+					 int micbias1_dly, int micbias2_dly,
 					 int micbias1_lvl, int micbias2_lvl);
 
 extern irqreturn_t wm_hubs_dcs_done(int irq, void *data);
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 10a2d8c..6fac5af 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -22,10 +22,6 @@
 #include <asm/dma.h>
 #include <asm/mach-types.h>
 
-#include <mach/asp.h>
-#include <mach/edma.h>
-#include <mach/mux.h>
-
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
 #include "davinci-mcasp.h"
@@ -160,7 +156,7 @@
 	.cpu_dai_name = "davinci-mcbsp",
 	.codec_dai_name = "tlv320aic3x-hifi",
 	.codec_name = "tlv320aic3x-codec.1-001b",
-	.platform_name = "davinci-pcm-audio",
+	.platform_name = "davinci-mcbsp",
 	.init = evm_aic3x_init,
 	.ops = &evm_ops,
 };
@@ -171,7 +167,7 @@
 	.cpu_dai_name = "davinci-mcbsp.1",
 	.codec_dai_name = "tlv320aic3x-hifi",
 	.codec_name = "tlv320aic3x-codec.1-001b",
-	.platform_name = "davinci-pcm-audio",
+	.platform_name = "davinci-mcbsp.1",
 	.init = evm_aic3x_init,
 	.ops = &evm_ops,
 };
@@ -185,14 +181,15 @@
 	.init = evm_aic3x_init,
 	.codec_name = "tlv320aic3x-codec.1-0018",
 	.ops = &evm_ops,
+	.platform_name = "davinci-mcbsp",
 #elif defined(CONFIG_SND_DM365_VOICE_CODEC)
 	.name = "Voice Codec - CQ93VC",
 	.stream_name = "CQ93",
 	.cpu_dai_name = "davinci-vcif",
 	.codec_dai_name = "cq93vc-hifi",
 	.codec_name = "cq93vc-codec",
+	.platform_name = "davinci-vcif",
 #endif
-	.platform_name = "davinci-pcm-audio",
 };
 
 static struct snd_soc_dai_link dm6467_evm_dai[] = {
@@ -201,7 +198,7 @@
 		.stream_name = "AIC3X",
 		.cpu_dai_name= "davinci-mcasp.0",
 		.codec_dai_name = "tlv320aic3x-hifi",
-		.platform_name ="davinci-pcm-audio",
+		.platform_name = "davinci-mcasp.0",
 		.codec_name = "tlv320aic3x-codec.0-001a",
 		.init = evm_aic3x_init,
 		.ops = &evm_ops,
@@ -212,7 +209,7 @@
 		.cpu_dai_name= "davinci-mcasp.1",
 		.codec_dai_name = "dit-hifi",
 		.codec_name = "spdif_dit",
-		.platform_name = "davinci-pcm-audio",
+		.platform_name = "davinci-mcasp.1",
 		.ops = &evm_spdif_ops,
 	},
 };
@@ -223,7 +220,7 @@
 	.cpu_dai_name = "davinci-mcasp.1",
 	.codec_dai_name = "tlv320aic3x-hifi",
 	.codec_name = "tlv320aic3x-codec.1-0018",
-	.platform_name = "davinci-pcm-audio",
+	.platform_name = "davinci-mcasp.1",
 	.init = evm_aic3x_init,
 	.ops = &evm_ops,
 };
@@ -234,7 +231,7 @@
 	.cpu_dai_name= "davinci-mcasp.0",
 	.codec_dai_name = "tlv320aic3x-hifi",
 	.codec_name = "tlv320aic3x-codec.1-0018",
-	.platform_name = "davinci-pcm-audio",
+	.platform_name = "davinci-mcasp.0",
 	.init = evm_aic3x_init,
 	.ops = &evm_ops,
 };
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 0a74b95..8218312 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/platform_data/davinci_asp.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -23,8 +24,6 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include <mach/asp.h>
-
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
 
@@ -732,8 +731,16 @@
 	if (ret != 0)
 		goto err_release_clk;
 
+	ret = davinci_soc_platform_register(&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+		goto err_unregister_dai;
+	}
+
 	return 0;
 
+err_unregister_dai:
+	snd_soc_unregister_dai(&pdev->dev);
 err_release_clk:
 	clk_disable(dev->clk);
 	clk_put(dev->clk);
@@ -745,6 +752,8 @@
 	struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
 
 	snd_soc_unregister_dai(&pdev->dev);
+	davinci_soc_platform_unregister(&pdev->dev);
+
 	clk_disable(dev->clk);
 	clk_put(dev->clk);
 	dev->clk = NULL;
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index ce5e5cd..c3eae1d 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -21,7 +21,10 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/io.h>
-#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -782,20 +785,17 @@
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (!dev->clk_active) {
-			clk_enable(dev->clk);
-			dev->clk_active = 1;
-		}
+		ret = pm_runtime_get_sync(dev->dev);
+		if (IS_ERR_VALUE(ret))
+			dev_err(dev->dev, "pm_runtime_get_sync() failed\n");
 		davinci_mcasp_start(dev, substream->stream);
 		break;
 
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 		davinci_mcasp_stop(dev, substream->stream);
-		if (dev->clk_active) {
-			clk_disable(dev->clk);
-			dev->clk_active = 0;
-		}
-
+		ret = pm_runtime_put_sync(dev->dev);
+		if (IS_ERR_VALUE(ret))
+			dev_err(dev->dev, "pm_runtime_put_sync() failed\n");
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
@@ -865,6 +865,114 @@
 
 };
 
+static const struct of_device_id mcasp_dt_ids[] = {
+	{
+		.compatible = "ti,dm646x-mcasp-audio",
+		.data = (void *)MCASP_VERSION_1,
+	},
+	{
+		.compatible = "ti,da830-mcasp-audio",
+		.data = (void *)MCASP_VERSION_2,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mcasp_dt_ids);
+
+static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
+						struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct snd_platform_data *pdata = NULL;
+	const struct of_device_id *match =
+			of_match_device(of_match_ptr(mcasp_dt_ids), &pdev->dev);
+
+	const u32 *of_serial_dir32;
+	u8 *of_serial_dir;
+	u32 val;
+	int i, ret = 0;
+
+	if (pdev->dev.platform_data) {
+		pdata = pdev->dev.platform_data;
+		return pdata;
+	} else if (match) {
+		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+		if (!pdata) {
+			ret = -ENOMEM;
+			goto nodata;
+		}
+	} else {
+		/* control shouldn't reach here. something is wrong */
+		ret = -EINVAL;
+		goto nodata;
+	}
+
+	if (match->data)
+		pdata->version = (u8)((int)match->data);
+
+	ret = of_property_read_u32(np, "op-mode", &val);
+	if (ret >= 0)
+		pdata->op_mode = val;
+
+	ret = of_property_read_u32(np, "tdm-slots", &val);
+	if (ret >= 0)
+		pdata->tdm_slots = val;
+
+	ret = of_property_read_u32(np, "num-serializer", &val);
+	if (ret >= 0)
+		pdata->num_serializer = val;
+
+	of_serial_dir32 = of_get_property(np, "serial-dir", &val);
+	val /= sizeof(u32);
+	if (val != pdata->num_serializer) {
+		dev_err(&pdev->dev,
+				"num-serializer(%d) != serial-dir size(%d)\n",
+				pdata->num_serializer, val);
+		ret = -EINVAL;
+		goto nodata;
+	}
+
+	if (of_serial_dir32) {
+		of_serial_dir = devm_kzalloc(&pdev->dev,
+						(sizeof(*of_serial_dir) * val),
+						GFP_KERNEL);
+		if (!of_serial_dir) {
+			ret = -ENOMEM;
+			goto nodata;
+		}
+
+		for (i = 0; i < pdata->num_serializer; i++)
+			of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
+
+		pdata->serial_dir = of_serial_dir;
+	}
+
+	ret = of_property_read_u32(np, "tx-num-evt", &val);
+	if (ret >= 0)
+		pdata->txnumevt = val;
+
+	ret = of_property_read_u32(np, "rx-num-evt", &val);
+	if (ret >= 0)
+		pdata->rxnumevt = val;
+
+	ret = of_property_read_u32(np, "sram-size-playback", &val);
+	if (ret >= 0)
+		pdata->sram_size_playback = val;
+
+	ret = of_property_read_u32(np, "sram-size-capture", &val);
+	if (ret >= 0)
+		pdata->sram_size_capture = val;
+
+	return  pdata;
+
+nodata:
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Error populating platform data, err %d\n",
+			ret);
+		pdata = NULL;
+	}
+	return  pdata;
+}
+
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
 	struct davinci_pcm_dma_params *dma_data;
@@ -873,11 +981,22 @@
 	struct davinci_audio_dev *dev;
 	int ret;
 
+	if (!pdev->dev.platform_data && !pdev->dev.of_node) {
+		dev_err(&pdev->dev, "No platform data supplied\n");
+		return -EINVAL;
+	}
+
 	dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_audio_dev),
 			   GFP_KERNEL);
 	if (!dev)
 		return	-ENOMEM;
 
+	pdata = davinci_mcasp_set_pdata_from_of(pdev);
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data\n");
+		return -EINVAL;
+	}
+
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!mem) {
 		dev_err(&pdev->dev, "no mem resource?\n");
@@ -891,13 +1010,13 @@
 		return -EBUSY;
 	}
 
-	pdata = pdev->dev.platform_data;
-	dev->clk = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(dev->clk))
-		return -ENODEV;
+	pm_runtime_enable(&pdev->dev);
 
-	clk_enable(dev->clk);
-	dev->clk_active = 1;
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (IS_ERR_VALUE(ret)) {
+		dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
+		return ret;
+	}
 
 	dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
 	if (!dev->base) {
@@ -914,6 +1033,7 @@
 	dev->version = pdata->version;
 	dev->txnumevt = pdata->txnumevt;
 	dev->rxnumevt = pdata->rxnumevt;
+	dev->dev = &pdev->dev;
 
 	dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
 	dma_data->asp_chan_q = pdata->asp_chan_q;
@@ -952,22 +1072,31 @@
 
 	if (ret != 0)
 		goto err_release_clk;
+
+	ret = davinci_soc_platform_register(&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+		goto err_unregister_dai;
+	}
+
 	return 0;
 
+err_unregister_dai:
+	snd_soc_unregister_dai(&pdev->dev);
 err_release_clk:
-	clk_disable(dev->clk);
-	clk_put(dev->clk);
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
 	return ret;
 }
 
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
-	struct davinci_audio_dev *dev = dev_get_drvdata(&pdev->dev);
 
 	snd_soc_unregister_dai(&pdev->dev);
-	clk_disable(dev->clk);
-	clk_put(dev->clk);
-	dev->clk = NULL;
+	davinci_soc_platform_unregister(&pdev->dev);
+
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
 
 	return 0;
 }
@@ -978,6 +1107,7 @@
 	.driver		= {
 		.name	= "davinci-mcasp",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(mcasp_dt_ids),
 	},
 };
 
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
index 4681acc..0de9ed6 100644
--- a/sound/soc/davinci/davinci-mcasp.h
+++ b/sound/soc/davinci/davinci-mcasp.h
@@ -19,7 +19,8 @@
 #define DAVINCI_MCASP_H
 
 #include <linux/io.h>
-#include <mach/asp.h>
+#include <linux/platform_data/davinci_asp.h>
+
 #include "davinci-pcm.h"
 
 #define DAVINCI_MCASP_RATES	SNDRV_PCM_RATE_8000_96000
@@ -40,9 +41,8 @@
 	struct davinci_pcm_dma_params dma_params[2];
 	void __iomem *base;
 	int sample_rate;
-	struct clk *clk;
+	struct device *dev;
 	unsigned int codec_fmt;
-	u8 clk_active;
 
 	/* McASP specific data */
 	int	tdm_slots;
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 97d77b2..93ea3bf 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -23,7 +23,6 @@
 #include <sound/soc.h>
 
 #include <asm/dma.h>
-#include <mach/edma.h>
 #include <mach/sram.h>
 
 #include "davinci-pcm.h"
@@ -864,28 +863,17 @@
 	.pcm_free = 	davinci_pcm_free,
 };
 
-static int __devinit davinci_soc_platform_probe(struct platform_device *pdev)
+int davinci_soc_platform_register(struct device *dev)
 {
-	return snd_soc_register_platform(&pdev->dev, &davinci_soc_platform);
+	return snd_soc_register_platform(dev, &davinci_soc_platform);
 }
+EXPORT_SYMBOL_GPL(davinci_soc_platform_register);
 
-static int __devexit davinci_soc_platform_remove(struct platform_device *pdev)
+void davinci_soc_platform_unregister(struct device *dev)
 {
-	snd_soc_unregister_platform(&pdev->dev);
-	return 0;
+	snd_soc_unregister_platform(dev);
 }
-
-static struct platform_driver davinci_pcm_driver = {
-	.driver = {
-			.name = "davinci-pcm-audio",
-			.owner = THIS_MODULE,
-	},
-
-	.probe = davinci_soc_platform_probe,
-	.remove = __devexit_p(davinci_soc_platform_remove),
-};
-
-module_platform_driver(davinci_pcm_driver);
+EXPORT_SYMBOL_GPL(davinci_soc_platform_unregister);
 
 MODULE_AUTHOR("Vladimir Barinov");
 MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index c0d6c9b..fc4d01c 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -12,9 +12,8 @@
 #ifndef _DAVINCI_PCM_H
 #define _DAVINCI_PCM_H
 
+#include <linux/platform_data/davinci_asp.h>
 #include <mach/edma.h>
-#include <mach/asp.h>
-
 
 struct davinci_pcm_dma_params {
 	int channel;			/* sync dma channel ID */
@@ -28,4 +27,7 @@
 	unsigned int fifo_level;
 };
 
+int davinci_soc_platform_register(struct device *dev);
+void davinci_soc_platform_unregister(struct device *dev);
+
 #endif
diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c
index f71175b..5be65aa 100644
--- a/sound/soc/davinci/davinci-sffsdr.c
+++ b/sound/soc/davinci/davinci-sffsdr.c
@@ -86,7 +86,7 @@
 	.cpu_dai_name = "davinci-mcbsp",
 	.codec_dai_name = "pcm3008-hifi",
 	.codec_name = "pcm3008-codec",
-	.platform_name = "davinci-pcm-audio",
+	.platform_name = "davinci-mcbsp",
 	.ops = &sffsdr_ops,
 };
 
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
index da030ff..07bde2e 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/davinci/davinci-vcif.c
@@ -240,12 +240,20 @@
 		return ret;
 	}
 
+	ret = davinci_soc_platform_register(&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+		snd_soc_unregister_dai(&pdev->dev);
+		return ret;
+	}
+
 	return 0;
 }
 
 static int davinci_vcif_remove(struct platform_device *pdev)
 {
 	snd_soc_unregister_dai(&pdev->dev);
+	davinci_soc_platform_unregister(&pdev->dev);
 
 	return 0;
 }
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index 81d7728..7074ae6 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -524,7 +524,7 @@
 	int ret = 0;
 	struct snd_soc_dai_driver *dai;
 
-	ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
+	ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL);
 	if (!ssi)
 		return -ENOMEM;
 	dev_set_drvdata(&pdev->dev, ssi);
@@ -537,7 +537,7 @@
 
 	ssi->irq = platform_get_irq(pdev, 0);
 
-	ssi->clk = clk_get(&pdev->dev, NULL);
+	ssi->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(ssi->clk)) {
 		ret = PTR_ERR(ssi->clk);
 		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
@@ -552,23 +552,18 @@
 		goto failed_get_resource;
 	}
 
-	if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) {
-		dev_err(&pdev->dev, "request_mem_region failed\n");
-		ret = -EBUSY;
-		goto failed_get_resource;
-	}
-
-	ssi->base = ioremap(res->start, resource_size(res));
+	ssi->base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!ssi->base) {
 		dev_err(&pdev->dev, "ioremap failed\n");
 		ret = -ENODEV;
-		goto failed_ioremap;
+		goto failed_register;
 	}
 
 	if (ssi->flags & IMX_SSI_USE_AC97) {
 		if (ac97_ssi) {
+			dev_err(&pdev->dev, "AC'97 SSI already registered\n");
 			ret = -EBUSY;
-			goto failed_ac97;
+			goto failed_register;
 		}
 		ac97_ssi = ssi;
 		setup_channel_to_ac97(ssi);
@@ -637,15 +632,10 @@
 failed_pdev_fiq_alloc:
 	snd_soc_unregister_dai(&pdev->dev);
 failed_register:
-failed_ac97:
-	iounmap(ssi->base);
-failed_ioremap:
 	release_mem_region(res->start, resource_size(res));
 failed_get_resource:
 	clk_disable_unprepare(ssi->clk);
-	clk_put(ssi->clk);
 failed_clk:
-	kfree(ssi);
 
 	return ret;
 }
@@ -663,11 +653,8 @@
 	if (ssi->flags & IMX_SSI_USE_AC97)
 		ac97_ssi = NULL;
 
-	iounmap(ssi->base);
 	release_mem_region(res->start, resource_size(res));
 	clk_disable_unprepare(ssi->clk);
-	clk_put(ssi->clk);
-	kfree(ssi);
 
 	return 0;
 }
diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c
index 2937e54..2cc7782 100644
--- a/sound/soc/mid-x86/mfld_machine.c
+++ b/sound/soc/mid-x86/mfld_machine.c
@@ -318,6 +318,15 @@
 		.platform_name = "sst-platform",
 		.init = NULL,
 	},
+	{
+		.name = "Medfield Compress",
+		.stream_name = "Speaker",
+		.cpu_dai_name = "Compress-cpu-dai",
+		.codec_dai_name = "SN95031 Speaker",
+		.codec_name = "sn95031",
+		.platform_name = "sst-platform",
+		.init = NULL,
+	},
 };
 
 /* SoC card */
diff --git a/sound/soc/mid-x86/sst_dsp.h b/sound/soc/mid-x86/sst_dsp.h
new file mode 100644
index 0000000..0fce1de
--- /dev/null
+++ b/sound/soc/mid-x86/sst_dsp.h
@@ -0,0 +1,134 @@
+#ifndef __SST_DSP_H__
+#define __SST_DSP_H__
+/*
+ *  sst_dsp.h - Intel SST Driver for audio engine
+ *
+ *  Copyright (C) 2008-12 Intel Corporation
+ *  Authors:	Vinod Koul <vinod.koul@linux.intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+enum sst_codec_types {
+	/*  AUDIO/MUSIC	CODEC Type Definitions */
+	SST_CODEC_TYPE_UNKNOWN = 0,
+	SST_CODEC_TYPE_PCM,	/* Pass through Audio codec */
+	SST_CODEC_TYPE_MP3,
+	SST_CODEC_TYPE_MP24,
+	SST_CODEC_TYPE_AAC,
+	SST_CODEC_TYPE_AACP,
+	SST_CODEC_TYPE_eAACP,
+};
+
+enum stream_type {
+	SST_STREAM_TYPE_NONE = 0,
+	SST_STREAM_TYPE_MUSIC = 1,
+};
+
+struct snd_pcm_params {
+	u16 codec;	/* codec type */
+	u8 num_chan;	/* 1=Mono, 2=Stereo */
+	u8 pcm_wd_sz;	/* 16/24 - bit*/
+	u32 reserved;	/* Bitrate in bits per second */
+	u32 sfreq;	/* Sampling rate in Hz */
+	u8 use_offload_path;
+	u8 reserved2;
+	u16 reserved3;
+	u8 channel_map[8];
+} __packed;
+
+/* MP3 Music Parameters Message */
+struct snd_mp3_params {
+	u16 codec;
+	u8  num_chan;	/* 1=Mono, 2=Stereo	*/
+	u8  pcm_wd_sz; /* 16/24 - bit*/
+	u8  crc_check; /* crc_check - disable (0) or enable (1) */
+	u8  reserved1; /* unused*/
+	u16 reserved2;	/* Unused */
+} __packed;
+
+#define AAC_BIT_STREAM_ADTS		0
+#define AAC_BIT_STREAM_ADIF		1
+#define AAC_BIT_STREAM_RAW		2
+
+/* AAC Music Parameters Message */
+struct snd_aac_params {
+	u16 codec;
+	u8 num_chan; /* 1=Mono, 2=Stereo*/
+	u8 pcm_wd_sz; /* 16/24 - bit*/
+	u8 bdownsample; /*SBR downsampling 0 - disable 1 -enabled AAC+ only */
+	u8 bs_format; /* input bit stream format adts=0, adif=1, raw=2 */
+	u16  reser2;
+	u32 externalsr; /*sampling rate of basic AAC raw bit stream*/
+	u8 sbr_signalling;/*disable/enable/set automode the SBR tool.AAC+*/
+	u8 reser1;
+	u16  reser3;
+} __packed;
+
+/* WMA Music Parameters Message */
+struct snd_wma_params {
+	u16 codec;
+	u8  num_chan;	/* 1=Mono, 2=Stereo */
+	u8  pcm_wd_sz;	/* 16/24 - bit*/
+	u32 brate;	/* Use the hard coded value. */
+	u32 sfreq;	/* Sampling freq eg. 8000, 441000, 48000 */
+	u32 channel_mask;  /* Channel Mask */
+	u16 format_tag;	/* Format Tag */
+	u16 block_align;	/* packet size */
+	u16 wma_encode_opt;/* Encoder option */
+	u8 op_align;	/* op align 0- 16 bit, 1- MSB, 2 LSB */
+	u8 reserved;	/* reserved */
+} __packed;
+
+/* Codec params struture */
+union  snd_sst_codec_params {
+	struct snd_pcm_params pcm_params;
+	struct snd_mp3_params mp3_params;
+	struct snd_aac_params aac_params;
+	struct snd_wma_params wma_params;
+} __packed;
+
+/* Address and size info of a frame buffer */
+struct sst_address_info {
+	u32 addr; /* Address at IA */
+	u32 size; /* Size of the buffer */
+};
+
+struct snd_sst_alloc_params_ext {
+	struct sst_address_info  ring_buf_info[8];
+	u8 sg_count;
+	u8 reserved;
+	u16 reserved2;
+	u32 frag_size;	/*Number of samples after which period elapsed
+				  message is sent valid only if path  = 0*/
+} __packed;
+
+struct snd_sst_stream_params {
+	union snd_sst_codec_params uc;
+} __packed;
+
+struct snd_sst_params {
+	u32 stream_id;
+	u8 codec;
+	u8 ops;
+	u8 stream_type;
+	u8 device_type;
+	struct snd_sst_stream_params sparams;
+	struct snd_sst_alloc_params_ext aparams;
+};
+
+#endif /* __SST_DSP_H__ */
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c
index d34563b..a263cbe 100644
--- a/sound/soc/mid-x86/sst_platform.c
+++ b/sound/soc/mid-x86/sst_platform.c
@@ -1,7 +1,7 @@
 /*
  *  sst_platform.c - Intel MID Platform driver
  *
- *  Copyright (C) 2010 Intel Corp
+ *  Copyright (C) 2010-2012 Intel Corp
  *  Author: Vinod Koul <vinod.koul@intel.com>
  *  Author: Harsha Priya <priya.harsha@intel.com>
  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -32,6 +32,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/compress_driver.h>
 #include "sst_platform.h"
 
 static struct sst_device *sst;
@@ -152,6 +153,16 @@
 		.formats = SNDRV_PCM_FMTBIT_S24_LE,
 	},
 },
+{
+	.name = "Compress-cpu-dai",
+	.compress_dai = 1,
+	.playback = {
+		.channels_min = SST_STEREO,
+		.channels_max = SST_STEREO,
+		.rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+},
 };
 
 /* helper functions */
@@ -463,8 +474,199 @@
 	}
 	return retval;
 }
+
+/* compress stream operations */
+static void sst_compr_fragment_elapsed(void *arg)
+{
+	struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
+
+	pr_debug("fragment elapsed by driver\n");
+	if (cstream)
+		snd_compr_fragment_elapsed(cstream);
+}
+
+static int sst_platform_compr_open(struct snd_compr_stream *cstream)
+{
+
+	int ret_val = 0;
+	struct snd_compr_runtime *runtime = cstream->runtime;
+	struct sst_runtime_stream *stream;
+
+	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+	if (!stream)
+		return -ENOMEM;
+
+	spin_lock_init(&stream->status_lock);
+
+	/* get the sst ops */
+	if (!sst || !try_module_get(sst->dev->driver->owner)) {
+		pr_err("no device available to run\n");
+		ret_val = -ENODEV;
+		goto out_ops;
+	}
+	stream->compr_ops = sst->compr_ops;
+
+	stream->id = 0;
+	sst_set_stream_status(stream, SST_PLATFORM_INIT);
+	runtime->private_data = stream;
+	return 0;
+out_ops:
+	kfree(stream);
+	return ret_val;
+}
+
+static int sst_platform_compr_free(struct snd_compr_stream *cstream)
+{
+	struct sst_runtime_stream *stream;
+	int ret_val = 0, str_id;
+
+	stream = cstream->runtime->private_data;
+	/*need to check*/
+	str_id = stream->id;
+	if (str_id)
+		ret_val = stream->compr_ops->close(str_id);
+	module_put(sst->dev->driver->owner);
+	kfree(stream);
+	pr_debug("%s: %d\n", __func__, ret_val);
+	return 0;
+}
+
+static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
+					struct snd_compr_params *params)
+{
+	struct sst_runtime_stream *stream;
+	int retval;
+	struct snd_sst_params str_params;
+	struct sst_compress_cb cb;
+
+	stream = cstream->runtime->private_data;
+	/* construct fw structure for this*/
+	memset(&str_params, 0, sizeof(str_params));
+
+	str_params.ops = STREAM_OPS_PLAYBACK;
+	str_params.stream_type = SST_STREAM_TYPE_MUSIC;
+	str_params.device_type = SND_SST_DEVICE_COMPRESS;
+
+	switch (params->codec.id) {
+	case SND_AUDIOCODEC_MP3: {
+		str_params.codec = SST_CODEC_TYPE_MP3;
+		str_params.sparams.uc.mp3_params.codec = SST_CODEC_TYPE_MP3;
+		str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
+		str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
+		break;
+	}
+
+	case SND_AUDIOCODEC_AAC: {
+		str_params.codec = SST_CODEC_TYPE_AAC;
+		str_params.sparams.uc.aac_params.codec = SST_CODEC_TYPE_AAC;
+		str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
+		str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
+		if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
+			str_params.sparams.uc.aac_params.bs_format =
+							AAC_BIT_STREAM_ADTS;
+		else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
+			str_params.sparams.uc.aac_params.bs_format =
+							AAC_BIT_STREAM_RAW;
+		else {
+			pr_err("Undefined format%d\n", params->codec.format);
+			return -EINVAL;
+		}
+		str_params.sparams.uc.aac_params.externalsr =
+						params->codec.sample_rate;
+		break;
+	}
+
+	default:
+		pr_err("codec not supported, id =%d\n", params->codec.id);
+		return -EINVAL;
+	}
+
+	str_params.aparams.ring_buf_info[0].addr  =
+					virt_to_phys(cstream->runtime->buffer);
+	str_params.aparams.ring_buf_info[0].size =
+					cstream->runtime->buffer_size;
+	str_params.aparams.sg_count = 1;
+	str_params.aparams.frag_size = cstream->runtime->fragment_size;
+
+	cb.param = cstream;
+	cb.compr_cb = sst_compr_fragment_elapsed;
+
+	retval = stream->compr_ops->open(&str_params, &cb);
+	if (retval < 0) {
+		pr_err("stream allocation failed %d\n", retval);
+		return retval;
+	}
+
+	stream->id = retval;
+	return 0;
+}
+
+static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
+{
+	struct sst_runtime_stream *stream =
+		cstream->runtime->private_data;
+
+	return stream->compr_ops->control(cmd, stream->id);
+}
+
+static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
+					struct snd_compr_tstamp *tstamp)
+{
+	struct sst_runtime_stream *stream;
+
+	stream  = cstream->runtime->private_data;
+	stream->compr_ops->tstamp(stream->id, tstamp);
+	tstamp->byte_offset = tstamp->copied_total %
+				 (u32)cstream->runtime->buffer_size;
+	pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
+	return 0;
+}
+
+static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
+					size_t bytes)
+{
+	struct sst_runtime_stream *stream;
+
+	stream  = cstream->runtime->private_data;
+	stream->compr_ops->ack(stream->id, (unsigned long)bytes);
+	stream->bytes_written += bytes;
+
+	return 0;
+}
+
+static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
+					struct snd_compr_caps *caps)
+{
+	struct sst_runtime_stream *stream =
+		cstream->runtime->private_data;
+
+	return stream->compr_ops->get_caps(caps);
+}
+
+static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
+					struct snd_compr_codec_caps *codec)
+{
+	struct sst_runtime_stream *stream =
+		cstream->runtime->private_data;
+
+	return stream->compr_ops->get_codec_caps(codec);
+}
+
+static struct snd_compr_ops sst_platform_compr_ops = {
+
+	.open = sst_platform_compr_open,
+	.free = sst_platform_compr_free,
+	.set_params = sst_platform_compr_set_params,
+	.trigger = sst_platform_compr_trigger,
+	.pointer = sst_platform_compr_pointer,
+	.ack = sst_platform_compr_ack,
+	.get_caps = sst_platform_compr_get_caps,
+	.get_codec_caps = sst_platform_compr_get_codec_caps,
+};
+
 static struct snd_soc_platform_driver sst_soc_platform_drv = {
 	.ops		= &sst_platform_ops,
+	.compr_ops	= &sst_platform_compr_ops,
 	.pcm_new	= sst_pcm_new,
 	.pcm_free	= sst_pcm_free,
 };
diff --git a/sound/soc/mid-x86/sst_platform.h b/sound/soc/mid-x86/sst_platform.h
index f04f4f7..d61c5d5 100644
--- a/sound/soc/mid-x86/sst_platform.h
+++ b/sound/soc/mid-x86/sst_platform.h
@@ -27,6 +27,8 @@
 #ifndef __SST_PLATFORMDRV_H__
 #define __SST_PLATFORMDRV_H__
 
+#include "sst_dsp.h"
+
 #define SST_MONO		1
 #define SST_STEREO		2
 #define SST_MAX_CAP		5
@@ -42,7 +44,6 @@
 #define SST_MIN_PERIODS		2
 #define SST_MAX_PERIODS		(1024*2)
 #define SST_FIFO_SIZE		0
-#define SST_CODEC_TYPE_PCM	1
 
 struct pcm_stream_info {
 	int str_id;
@@ -83,6 +84,7 @@
 	SND_SST_DEVICE_VIBRA,
 	SND_SST_DEVICE_HAPTIC,
 	SND_SST_DEVICE_CAPTURE,
+	SND_SST_DEVICE_COMPRESS,
 };
 
 /* PCM Parameters */
@@ -107,6 +109,24 @@
 	struct sst_pcm_params sparams;
 };
 
+struct sst_compress_cb {
+	void *param;
+	void (*compr_cb)(void *param);
+};
+
+struct compress_sst_ops {
+	const char *name;
+	int (*open) (struct snd_sst_params *str_params,
+			struct sst_compress_cb *cb);
+	int (*control) (unsigned int cmd, unsigned int str_id);
+	int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp);
+	int (*ack) (unsigned int str_id, unsigned long bytes);
+	int (*close) (unsigned int str_id);
+	int (*get_caps) (struct snd_compr_caps *caps);
+	int (*get_codec_caps) (struct snd_compr_codec_caps *codec);
+
+};
+
 struct sst_ops {
 	int (*open) (struct sst_stream_params *str_param);
 	int (*device_control) (int cmd, void *arg);
@@ -115,8 +135,11 @@
 
 struct sst_runtime_stream {
 	int     stream_status;
+	unsigned int id;
+	size_t bytes_written;
 	struct pcm_stream_info stream_info;
 	struct sst_ops *ops;
+	struct compress_sst_ops *compr_ops;
 	spinlock_t	status_lock;
 };
 
@@ -124,6 +147,7 @@
 	char *name;
 	struct device *dev;
 	struct sst_ops *ops;
+	struct compress_sst_ops *compr_ops;
 };
 
 int sst_register_dsp(struct sst_device *sst);
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index b303071..aa037b2 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -704,7 +704,7 @@
 		return ret;
 	}
 
-	saif->clk = clk_get(&pdev->dev, NULL);
+	saif->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(saif->clk)) {
 		ret = PTR_ERR(saif->clk);
 		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
@@ -717,8 +717,7 @@
 	saif->base = devm_request_and_ioremap(&pdev->dev, iores);
 	if (!saif->base) {
 		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -ENODEV;
-		goto failed_get_resource;
+		return -ENODEV;
 	}
 
 	dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -731,7 +730,7 @@
 					   &saif->dma_param.chan_num);
 		if (ret) {
 			dev_err(&pdev->dev, "failed to get dma channel\n");
-			goto failed_get_resource;
+			return ret;
 		}
 	} else {
 		saif->dma_param.chan_num = dmares->start;
@@ -742,7 +741,7 @@
 		ret = saif->irq;
 		dev_err(&pdev->dev, "failed to get irq resource: %d\n",
 			ret);
-		goto failed_get_resource;
+		return ret;
 	}
 
 	saif->dev = &pdev->dev;
@@ -750,7 +749,7 @@
 			       "mxs-saif", saif);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to request irq\n");
-		goto failed_get_resource;
+		return ret;
 	}
 
 	saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
@@ -758,7 +757,7 @@
 		ret = saif->dma_param.chan_irq;
 		dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
 			ret);
-		goto failed_get_resource;
+		return ret;
 	}
 
 	platform_set_drvdata(pdev, saif);
@@ -766,7 +765,7 @@
 	ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
 	if (ret) {
 		dev_err(&pdev->dev, "register DAI failed\n");
-		goto failed_get_resource;
+		return ret;
 	}
 
 	ret = mxs_pcm_platform_register(&pdev->dev);
@@ -779,19 +778,14 @@
 
 failed_pdev_alloc:
 	snd_soc_unregister_dai(&pdev->dev);
-failed_get_resource:
-	clk_put(saif->clk);
 
 	return ret;
 }
 
 static int __devexit mxs_saif_remove(struct platform_device *pdev)
 {
-	struct mxs_saif *saif = platform_get_drvdata(pdev);
-
 	mxs_pcm_platform_unregister(&pdev->dev);
 	snd_soc_unregister_dai(&pdev->dev);
-	clk_put(saif->clk);
 
 	return 0;
 }
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index 9d93793..be525df 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -25,6 +25,7 @@
 #include <linux/mfd/twl6040.h>
 #include <linux/platform_data/omap-abe-twl6040.h>
 #include <linux/module.h>
+#include <linux/of.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -43,6 +44,8 @@
 struct abe_twl6040 {
 	int	jack_detection;	/* board can detect jack events */
 	int	mclk_freq;	/* MCLK frequency speed for twl6040 */
+
+	struct platform_device *dmic_codec_dev;
 };
 
 static int omap_abe_hw_params(struct snd_pcm_substream *substream,
@@ -185,17 +188,6 @@
 	int hs_trim;
 	int ret = 0;
 
-	/* Disable not connected paths if not used */
-	twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
-	twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk");
-	twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk");
-	twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out");
-	twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator");
-	twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
-	twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic");
-	twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic");
-	twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In");
-
 	/*
 	 * Configure McPDM offset cancellation based on the HSOTRIM value from
 	 * twl6040.
@@ -216,6 +208,24 @@
 		twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
 	}
 
+	/*
+	 * NULL pdata means we booted with DT. In this case the routing is
+	 * provided and the card is fully routed, no need to mark pins.
+	 */
+	if (!pdata)
+		return ret;
+
+	/* Disable not connected paths if not used */
+	twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
+	twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk");
+	twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk");
+	twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out");
+	twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator");
+	twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
+	twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic");
+	twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic");
+	twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In");
+
 	return ret;
 }
 
@@ -270,52 +280,116 @@
 static __devinit int omap_abe_probe(struct platform_device *pdev)
 {
 	struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev);
+	struct device_node *node = pdev->dev.of_node;
 	struct snd_soc_card *card = &omap_abe_card;
 	struct abe_twl6040 *priv;
 	int num_links = 0;
-	int ret;
+	int ret = 0;
 
 	card->dev = &pdev->dev;
 
-	if (!pdata) {
-		dev_err(&pdev->dev, "Missing pdata\n");
-		return -ENODEV;
-	}
-
 	priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
 	if (priv == NULL)
 		return -ENOMEM;
 
-	if (pdata->card_name) {
-		card->name = pdata->card_name;
+	priv->dmic_codec_dev = ERR_PTR(-EINVAL);
+
+	if (node) {
+		struct device_node *dai_node;
+
+		if (snd_soc_of_parse_card_name(card, "ti,model")) {
+			dev_err(&pdev->dev, "Card name is not provided\n");
+			return -ENODEV;
+		}
+
+		ret = snd_soc_of_parse_audio_routing(card,
+						"ti,audio-routing");
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Error while parsing DAPM routing\n");
+			return ret;
+		}
+
+		dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
+		if (!dai_node) {
+			dev_err(&pdev->dev, "McPDM node is not provided\n");
+			return -EINVAL;
+		}
+		abe_twl6040_dai_links[0].cpu_dai_name  = NULL;
+		abe_twl6040_dai_links[0].cpu_of_node = dai_node;
+
+		dai_node = of_parse_phandle(node, "ti,dmic", 0);
+		if (dai_node) {
+			num_links = 2;
+			abe_twl6040_dai_links[1].cpu_dai_name  = NULL;
+			abe_twl6040_dai_links[1].cpu_of_node = dai_node;
+
+			priv->dmic_codec_dev = platform_device_register_simple(
+						"dmic-codec", -1, NULL, 0);
+			if (IS_ERR(priv->dmic_codec_dev)) {
+				dev_err(&pdev->dev,
+					"Can't instantiate dmic-codec\n");
+				return PTR_ERR(priv->dmic_codec_dev);
+			}
+		} else {
+			num_links = 1;
+		}
+
+		of_property_read_u32(node, "ti,jack-detection",
+				     &priv->jack_detection);
+		of_property_read_u32(node, "ti,mclk-freq",
+				     &priv->mclk_freq);
+		if (!priv->mclk_freq) {
+			dev_err(&pdev->dev, "MCLK frequency not provided\n");
+			ret = -EINVAL;
+			goto err_unregister;
+		}
+
+		omap_abe_card.fully_routed = 1;
+	} else if (pdata) {
+		if (pdata->card_name) {
+			card->name = pdata->card_name;
+		} else {
+			dev_err(&pdev->dev, "Card name is not provided\n");
+			return -ENODEV;
+		}
+
+		if (pdata->has_dmic)
+			num_links = 2;
+		else
+			num_links = 1;
+
+		priv->jack_detection = pdata->jack_detection;
+		priv->mclk_freq = pdata->mclk_freq;
 	} else {
-		dev_err(&pdev->dev, "Card name is not provided\n");
+		dev_err(&pdev->dev, "Missing pdata\n");
 		return -ENODEV;
 	}
 
-	priv->jack_detection = pdata->jack_detection;
-	priv->mclk_freq = pdata->mclk_freq;
-
 
 	if (!priv->mclk_freq) {
 		dev_err(&pdev->dev, "MCLK frequency missing\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_unregister;
 	}
 
-	if (pdata->has_dmic)
-		num_links = 2;
-	else
-		num_links = 1;
-
 	card->dai_link = abe_twl6040_dai_links;
 	card->num_links = num_links;
 
 	snd_soc_card_set_drvdata(card, priv);
 
 	ret = snd_soc_register_card(card);
-	if (ret)
+	if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 			ret);
+		goto err_unregister;
+	}
+
+	return 0;
+
+err_unregister:
+	if (!IS_ERR(priv->dmic_codec_dev))
+		platform_device_unregister(priv->dmic_codec_dev);
 
 	return ret;
 }
@@ -323,17 +397,28 @@
 static int __devexit omap_abe_remove(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
 
 	snd_soc_unregister_card(card);
 
+	if (!IS_ERR(priv->dmic_codec_dev))
+		platform_device_unregister(priv->dmic_codec_dev);
+
 	return 0;
 }
 
+static const struct of_device_id omap_abe_of_match[] = {
+	{.compatible = "ti,abe-twl6040", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, omap_abe_of_match);
+
 static struct platform_driver omap_abe_driver = {
 	.driver = {
 		.name = "omap-abe-twl6040",
 		.owner = THIS_MODULE,
 		.pm = &snd_soc_pm_ops,
+		.of_match_table = omap_abe_of_match,
 	},
 	.probe = omap_abe_probe,
 	.remove = __devexit_p(omap_abe_remove),
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 2c66e249..f7babb3 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -445,9 +445,8 @@
 {
 	struct omap_mcpdm *mcpdm;
 	struct resource *res;
-	int ret = 0;
 
-	mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
+	mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL);
 	if (!mcpdm)
 		return -ENOMEM;
 
@@ -456,55 +455,30 @@
 	mutex_init(&mcpdm->mutex);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
-		dev_err(&pdev->dev, "no resource\n");
-		goto err_res;
-	}
+	if (res == NULL)
+		return -ENOMEM;
 
-	if (!request_mem_region(res->start, resource_size(res), "McPDM")) {
-		ret = -EBUSY;
-		goto err_res;
-	}
+	if (!devm_request_mem_region(&pdev->dev, res->start,
+				     resource_size(res), "McPDM"))
+		return -EBUSY;
 
-	mcpdm->io_base = ioremap(res->start, resource_size(res));
-	if (!mcpdm->io_base) {
-		ret = -ENOMEM;
-		goto err_iomap;
-	}
+	mcpdm->io_base = devm_ioremap(&pdev->dev, res->start,
+				      resource_size(res));
+	if (!mcpdm->io_base)
+		return -ENOMEM;
 
 	mcpdm->irq = platform_get_irq(pdev, 0);
-	if (mcpdm->irq < 0) {
-		ret = mcpdm->irq;
-		goto err_irq;
-	}
+	if (mcpdm->irq < 0)
+		return mcpdm->irq;
 
 	mcpdm->dev = &pdev->dev;
 
-	ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
-	if (!ret)
-		return 0;
-
-err_irq:
-	iounmap(mcpdm->io_base);
-err_iomap:
-	release_mem_region(res->start, resource_size(res));
-err_res:
-	kfree(mcpdm);
-	return ret;
+	return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
 }
 
 static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
 {
-	struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev);
-	struct resource *res;
-
 	snd_soc_unregister_dai(&pdev->dev);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	iounmap(mcpdm->io_base);
-	release_mem_region(res->start, resource_size(res));
-
-	kfree(mcpdm);
 	return 0;
 }
 
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index fe3995c..e7b8317 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,6 +1,6 @@
 config SND_SOC_SAMSUNG
 	tristate "ASoC support for Samsung"
-	depends on ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_EXYNOS4
+	depends on PLAT_SAMSUNG
 	select S3C64XX_DMA if ARCH_S3C64XX
 	select S3C2410_DMA if ARCH_S3C24XX
 	help
@@ -191,6 +191,7 @@
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM8996
 	select SND_SOC_WM9081
+	select SND_SOC_WM0010
 	select SND_SOC_WM1250_EV1
 
 config SND_SOC_TOBERMORY
@@ -199,6 +200,14 @@
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM8962
 
+config SND_SOC_BELLS
+	tristate "Audio support for Wolfson Bells"
+	depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+	select SND_SAMSUNG_I2S
+	select SND_SOC_WM5102
+	select SND_SOC_WM5110
+	select SND_SOC_WM9081
+
 config SND_SOC_LOWLAND
 	tristate "Audio support for Wolfson Lowland"
 	depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 9d03beb..709f605 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -42,6 +42,7 @@
 snd-soc-tobermory-objs := tobermory.o
 snd-soc-lowland-objs := lowland.o
 snd-soc-littlemill-objs := littlemill.o
+snd-soc-bells-objs := bells.o
 
 obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -65,3 +66,4 @@
 obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o
 obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o
 obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o
+obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
new file mode 100644
index 0000000..5dc10df
--- /dev/null
+++ b/sound/soc/samsung/bells.c
@@ -0,0 +1,346 @@
+/*
+ * Bells audio support
+ *
+ * Copyright 2012 Wolfson Microelectronics
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+
+#include "../codecs/wm5102.h"
+#include "../codecs/wm9081.h"
+
+/*
+ * 44.1kHz based clocks for the SYSCLK domain, use a very high clock
+ * to allow all the DSP functionality to be enabled if desired.
+ */
+#define SYSCLK_RATE (44100 * 1024)
+
+/* 48kHz based clocks for the ASYNC domain */
+#define ASYNCCLK_RATE (48000 * 512)
+
+/* BCLK2 is fixed at this currently */
+#define BCLK2_RATE (64 * 8000)
+
+/*
+ * Expect a 24.576MHz crystal if one is fitted (the driver will function
+ * if this is not fitted).
+ */
+#define MCLK_RATE 24576000
+
+#define WM9081_AUDIO_RATE 44100
+#define WM9081_MCLK_RATE  (WM9081_AUDIO_RATE * 256)
+
+static int bells_set_bias_level(struct snd_soc_card *card,
+				struct snd_soc_dapm_context *dapm,
+				enum snd_soc_bias_level level)
+{
+	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_codec *codec = codec_dai->codec;
+	int ret;
+
+	if (dapm->dev != codec_dai->dev)
+		return 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+			ret = snd_soc_codec_set_pll(codec, WM5102_FLL1,
+						    ARIZONA_FLL_SRC_MCLK1,
+						    MCLK_RATE,
+						    SYSCLK_RATE);
+			if (ret < 0)
+				pr_err("Failed to start FLL: %d\n", ret);
+
+			ret = snd_soc_codec_set_pll(codec, WM5102_FLL2,
+						    ARIZONA_FLL_SRC_AIF2BCLK,
+						    BCLK2_RATE,
+						    ASYNCCLK_RATE);
+			if (ret < 0)
+				pr_err("Failed to start FLL: %d\n", ret);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int bells_set_bias_level_post(struct snd_soc_card *card,
+				     struct snd_soc_dapm_context *dapm,
+				     enum snd_soc_bias_level level)
+{
+	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_codec *codec = codec_dai->codec;
+	int ret;
+
+	if (dapm->dev != codec_dai->dev)
+		return 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_STANDBY:
+		ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, 0, 0, 0);
+		if (ret < 0) {
+			pr_err("Failed to stop FLL: %d\n", ret);
+			return ret;
+		}
+
+		ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, 0, 0, 0);
+		if (ret < 0) {
+			pr_err("Failed to stop FLL: %d\n", ret);
+			return ret;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	dapm->bias_level = level;
+
+	return 0;
+}
+
+static int bells_late_probe(struct snd_soc_card *card)
+{
+	struct snd_soc_codec *codec = card->rtd[0].codec;
+	struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
+	struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
+	struct snd_soc_dai *aif3_dai = card->rtd[2].cpu_dai;
+	struct snd_soc_dai *wm9081_dai = card->rtd[2].codec_dai;
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
+	if (ret != 0) {
+		dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
+	if (ret != 0) {
+		dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0);
+	if (ret != 0) {
+		dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
+				       ARIZONA_CLK_SRC_FLL1, SYSCLK_RATE,
+				       SND_SOC_CLOCK_IN);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0,
+				       WM9081_MCLK_RATE, SND_SOC_CLOCK_OUT);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK,
+				       ARIZONA_CLK_SRC_FLL2, ASYNCCLK_RATE,
+				       SND_SOC_CLOCK_IN);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK,
+				       0, WM9081_MCLK_RATE, 0);
+	if (ret != 0) {
+		dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_pcm_stream baseband_params = {
+	.formats = SNDRV_PCM_FMTBIT_S32_LE,
+	.rate_min = 8000,
+	.rate_max = 8000,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
+static const struct snd_soc_pcm_stream sub_params = {
+	.formats = SNDRV_PCM_FMTBIT_S32_LE,
+	.rate_min = WM9081_AUDIO_RATE,
+	.rate_max = WM9081_AUDIO_RATE,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
+static struct snd_soc_dai_link bells_dai_wm5102[] = {
+	{
+		.name = "CPU",
+		.stream_name = "CPU",
+		.cpu_dai_name = "samsung-i2s.0",
+		.codec_dai_name = "wm5102-aif1",
+		.platform_name = "samsung-audio",
+		.codec_name = "wm5102-codec",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBM_CFM,
+	},
+	{
+		.name = "Baseband",
+		.stream_name = "Baseband",
+		.cpu_dai_name = "wm5102-aif2",
+		.codec_dai_name = "wm1250-ev1",
+		.codec_name = "wm1250-ev1.1-0027",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBM_CFM,
+		.ignore_suspend = 1,
+		.params = &baseband_params,
+	},
+	{
+		.name = "Sub",
+		.stream_name = "Sub",
+		.cpu_dai_name = "wm5102-aif3",
+		.codec_dai_name = "wm9081-hifi",
+		.codec_name = "wm9081.1-006c",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBS_CFS,
+		.ignore_suspend = 1,
+		.params = &sub_params,
+	},
+};
+
+static struct snd_soc_dai_link bells_dai_wm5110[] = {
+	{
+		.name = "CPU",
+		.stream_name = "CPU",
+		.cpu_dai_name = "samsung-i2s.0",
+		.codec_dai_name = "wm5110-aif1",
+		.platform_name = "samsung-audio",
+		.codec_name = "wm5110-codec",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBM_CFM,
+	},
+	{
+		.name = "Baseband",
+		.stream_name = "Baseband",
+		.cpu_dai_name = "wm5110-aif2",
+		.codec_dai_name = "wm1250-ev1",
+		.codec_name = "wm1250-ev1.1-0027",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBM_CFM,
+		.ignore_suspend = 1,
+		.params = &baseband_params,
+	},
+	{
+		.name = "Sub",
+		.stream_name = "Sub",
+		.cpu_dai_name = "wm5102-aif3",
+		.codec_dai_name = "wm9081-hifi",
+		.codec_name = "wm9081.1-006c",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBS_CFS,
+		.ignore_suspend = 1,
+		.params = &sub_params,
+	},
+};
+
+static struct snd_soc_codec_conf bells_codec_conf[] = {
+	{
+		.dev_name = "wm9081.1-006c",
+		.name_prefix = "Sub",
+	},
+};
+
+static struct snd_soc_dapm_route bells_routes[] = {
+	{ "Sub CLK_SYS", NULL, "OPCLK" },
+};
+
+static struct snd_soc_card bells_cards[] = {
+	{
+		.name = "Bells WM5102",
+		.owner = THIS_MODULE,
+		.dai_link = bells_dai_wm5102,
+		.num_links = ARRAY_SIZE(bells_dai_wm5102),
+		.codec_conf = bells_codec_conf,
+		.num_configs = ARRAY_SIZE(bells_codec_conf),
+
+		.late_probe = bells_late_probe,
+
+		.dapm_routes = bells_routes,
+		.num_dapm_routes = ARRAY_SIZE(bells_routes),
+
+		.set_bias_level = bells_set_bias_level,
+		.set_bias_level_post = bells_set_bias_level_post,
+	},
+	{
+		.name = "Bells WM5110",
+		.owner = THIS_MODULE,
+		.dai_link = bells_dai_wm5110,
+		.num_links = ARRAY_SIZE(bells_dai_wm5110),
+		.codec_conf = bells_codec_conf,
+		.num_configs = ARRAY_SIZE(bells_codec_conf),
+
+		.late_probe = bells_late_probe,
+
+		.dapm_routes = bells_routes,
+		.num_dapm_routes = ARRAY_SIZE(bells_routes),
+
+		.set_bias_level = bells_set_bias_level,
+		.set_bias_level_post = bells_set_bias_level_post,
+	},
+};
+
+
+static __devinit int bells_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	bells_cards[pdev->id].dev = &pdev->dev;
+
+	ret = snd_soc_register_card(&bells_cards[pdev->id]);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"snd_soc_register_card(%s) failed: %d\n",
+			bells_cards[pdev->id].name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devexit bells_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_card(&bells_cards[pdev->id]);
+
+	return 0;
+}
+
+static struct platform_driver bells_driver = {
+	.driver = {
+		.name = "bells",
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = bells_probe,
+	.remove = __devexit_p(bells_remove),
+};
+
+module_platform_driver(bells_driver);
+
+MODULE_DESCRIPTION("Bells audio support");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bells");
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index a4a9fc7..c7e1c28 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -25,7 +25,7 @@
 				   struct snd_soc_dapm_context *dapm,
 				   enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai;
 	int ret;
 
 	if (dapm->dev != codec_dai->dev)
@@ -57,7 +57,7 @@
 					struct snd_soc_dapm_context *dapm,
 					enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai;
 	int ret;
 
 	if (dapm->dev != codec_dai->dev)
@@ -126,6 +126,18 @@
 	snd_soc_dapm_sync(&codec->dapm);
 }
 
+static int speyside_wm0010_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dai *dai = rtd->codec_dai;
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(dai, 0, MCLK_AUDIO_RATE, 0);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_dai *dai = rtd->codec_dai;
@@ -172,17 +184,37 @@
 	return 0;
 }
 
+static const struct snd_soc_pcm_stream dsp_codec_params = {
+	.formats = SNDRV_PCM_FMTBIT_S32_LE,
+	.rate_min = 48000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
 static struct snd_soc_dai_link speyside_dai[] = {
 	{
-		.name = "CPU",
-		.stream_name = "CPU",
+		.name = "CPU-DSP",
+		.stream_name = "CPU-DSP",
 		.cpu_dai_name = "samsung-i2s.0",
-		.codec_dai_name = "wm8996-aif1",
+		.codec_dai_name = "wm0010-sdi1",
 		.platform_name = "samsung-audio",
+		.codec_name = "spi0.0",
+		.init = speyside_wm0010_init,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBM_CFM,
+	},
+	{
+		.name = "DSP-CODEC",
+		.stream_name = "DSP-CODEC",
+		.cpu_dai_name = "wm0010-sdi2",
+		.codec_dai_name = "wm8996-aif1",
 		.codec_name = "wm8996.1-001a",
 		.init = speyside_wm8996_init,
 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 				| SND_SOC_DAIFMT_CBM_CFM,
+		.params = &dsp_codec_params,
+		.ignore_suspend = 1,
 	},
 	{
 		.name = "Baseband",
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
new file mode 100644
index 0000000..967d0e1
--- /dev/null
+++ b/sound/soc/soc-compress.c
@@ -0,0 +1,294 @@
+/*
+ * soc-compress.c  --  ALSA SoC Compress
+ *
+ * Copyright (C) 2012 Intel Corp.
+ *
+ * Authors: Namarta Kohli <namartax.kohli@intel.com>
+ *          Ramesh Babu K V <ramesh.babu@linux.intel.com>
+ *          Vinod Koul <vinod.koul@linux.intel.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/compress_params.h>
+#include <sound/compress_driver.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+static int soc_compr_open(struct snd_compr_stream *cstream)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret = 0;
+
+	if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
+		ret = platform->driver->compr_ops->open(cstream);
+		if (ret < 0) {
+			pr_err("compress asoc: can't open platform %s\n", platform->name);
+			goto out;
+		}
+	}
+
+	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
+		ret = rtd->dai_link->compr_ops->startup(cstream);
+		if (ret < 0) {
+			pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name);
+			goto machine_err;
+		}
+	}
+
+	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+		cpu_dai->playback_active++;
+		codec_dai->playback_active++;
+	} else {
+		cpu_dai->capture_active++;
+		codec_dai->capture_active++;
+	}
+
+	cpu_dai->active++;
+	codec_dai->active++;
+	rtd->codec->active++;
+
+	return 0;
+
+machine_err:
+	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
+		platform->driver->compr_ops->free(cstream);
+out:
+	return ret;
+}
+
+static int soc_compr_free(struct snd_compr_stream *cstream)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_codec *codec = rtd->codec;
+
+	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+		cpu_dai->playback_active--;
+		codec_dai->playback_active--;
+	} else {
+		cpu_dai->capture_active--;
+		codec_dai->capture_active--;
+	}
+
+	snd_soc_dai_digital_mute(codec_dai, 1);
+
+	cpu_dai->active--;
+	codec_dai->active--;
+	codec->active--;
+
+	if (!cpu_dai->active)
+		cpu_dai->rate = 0;
+
+	if (!codec_dai->active)
+		codec_dai->rate = 0;
+
+
+	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
+		rtd->dai_link->compr_ops->shutdown(cstream);
+
+	if (platform->driver->compr_ops && platform->driver->compr_ops->free)
+		platform->driver->compr_ops->free(cstream);
+	cpu_dai->runtime = NULL;
+
+	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+		if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
+		    rtd->dai_link->ignore_pmdown_time) {
+			snd_soc_dapm_stream_event(rtd,
+					SNDRV_PCM_STREAM_PLAYBACK,
+					SND_SOC_DAPM_STREAM_STOP);
+		} else
+			codec_dai->pop_wait = 1;
+			schedule_delayed_work(&rtd->delayed_work,
+				msecs_to_jiffies(rtd->pmdown_time));
+	} else {
+		/* capture streams can be powered down now */
+		snd_soc_dapm_stream_event(rtd,
+			SNDRV_PCM_STREAM_CAPTURE,
+			SND_SOC_DAPM_STREAM_STOP);
+	}
+
+	return 0;
+}
+
+static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
+{
+
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret = 0;
+
+	if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
+		ret = platform->driver->compr_ops->trigger(cstream, cmd);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (cmd == SNDRV_PCM_TRIGGER_START)
+		snd_soc_dai_digital_mute(codec_dai, 0);
+	else if (cmd == SNDRV_PCM_TRIGGER_STOP)
+		snd_soc_dai_digital_mute(codec_dai, 1);
+
+	return ret;
+}
+
+static int soc_compr_set_params(struct snd_compr_stream *cstream,
+					struct snd_compr_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+	int ret = 0;
+
+	/* first we call set_params for the platform driver
+	 * this should configure the soc side
+	 * if the machine has compressed ops then we call that as well
+	 * expectation is that platform and machine will configure everything
+	 * for this compress path, like configuring pcm port for codec
+	 */
+	if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
+		ret = platform->driver->compr_ops->set_params(cstream, params);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
+		ret = rtd->dai_link->compr_ops->set_params(cstream);
+		if (ret < 0)
+			return ret;
+	}
+
+	snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
+				SND_SOC_DAPM_STREAM_START);
+
+	return ret;
+}
+
+static int soc_compr_get_params(struct snd_compr_stream *cstream,
+					struct snd_codec *params)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+	int ret = 0;
+
+	if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
+		ret = platform->driver->compr_ops->get_params(cstream, params);
+
+	return ret;
+}
+
+static int soc_compr_get_caps(struct snd_compr_stream *cstream,
+				struct snd_compr_caps *caps)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+	int ret = 0;
+
+	if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
+		ret = platform->driver->compr_ops->get_caps(cstream, caps);
+
+	return ret;
+}
+
+static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
+				struct snd_compr_codec_caps *codec)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+	int ret = 0;
+
+	if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
+		ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
+
+	return ret;
+}
+
+static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+	int ret = 0;
+
+	if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
+		ret = platform->driver->compr_ops->ack(cstream, bytes);
+
+	return ret;
+}
+
+static int soc_compr_pointer(struct snd_compr_stream *cstream,
+			struct snd_compr_tstamp *tstamp)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+
+	if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
+		 platform->driver->compr_ops->pointer(cstream, tstamp);
+
+	return 0;
+}
+
+/* ASoC Compress operations */
+static struct snd_compr_ops soc_compr_ops = {
+	.open		= soc_compr_open,
+	.free		= soc_compr_free,
+	.set_params	= soc_compr_set_params,
+	.get_params	= soc_compr_get_params,
+	.trigger	= soc_compr_trigger,
+	.pointer	= soc_compr_pointer,
+	.ack		= soc_compr_ack,
+	.get_caps	= soc_compr_get_caps,
+	.get_codec_caps = soc_compr_get_codec_caps
+};
+
+/* create a new compress */
+int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_compr *compr;
+	char new_name[64];
+	int ret = 0, direction = 0;
+
+	/* check client and interface hw capabilities */
+	snprintf(new_name, sizeof(new_name), "%s %s-%d",
+			rtd->dai_link->stream_name, codec_dai->name, num);
+	direction = SND_COMPRESS_PLAYBACK;
+	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
+	if (compr == NULL) {
+		snd_printk(KERN_ERR "Cannot allocate compr\n");
+		return -ENOMEM;
+	}
+
+	compr->ops = &soc_compr_ops;
+	mutex_init(&compr->lock);
+	ret = snd_compress_new(rtd->card->snd_card, num, direction, compr);
+	if (ret < 0) {
+		pr_err("compress asoc: can't create compress for codec %s\n",
+			codec->name);
+		kfree(compr);
+		return ret;
+	}
+
+	rtd->compr = compr;
+	compr->private_data = rtd;
+
+	printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
+		cpu_dai->name);
+	return ret;
+}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c501af6..b95d1fb 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1388,37 +1388,48 @@
 	if (ret < 0)
 		pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret);
 
-	if (!dai_link->params) {
-		/* create the pcm */
-		ret = soc_new_pcm(rtd, num);
+	if (cpu_dai->driver->compress_dai) {
+		/*create compress_device"*/
+		ret = soc_new_compress(rtd, num);
 		if (ret < 0) {
-			pr_err("asoc: can't create pcm %s :%d\n",
-			       dai_link->stream_name, ret);
+			pr_err("asoc: can't create compress %s\n",
+					 dai_link->stream_name);
 			return ret;
 		}
 	} else {
-		/* link the DAI widgets */
-		play_w = codec_dai->playback_widget;
-		capture_w = cpu_dai->capture_widget;
-		if (play_w && capture_w) {
-			ret = snd_soc_dapm_new_pcm(card, dai_link->params,
-						   capture_w, play_w);
-			if (ret != 0) {
-				dev_err(card->dev, "Can't link %s to %s: %d\n",
-					play_w->name, capture_w->name, ret);
+
+		if (!dai_link->params) {
+			/* create the pcm */
+			ret = soc_new_pcm(rtd, num);
+			if (ret < 0) {
+				pr_err("asoc: can't create pcm %s :%d\n",
+				       dai_link->stream_name, ret);
 				return ret;
 			}
-		}
-
-		play_w = cpu_dai->playback_widget;
-		capture_w = codec_dai->capture_widget;
-		if (play_w && capture_w) {
-			ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+		} else {
+			/* link the DAI widgets */
+			play_w = codec_dai->playback_widget;
+			capture_w = cpu_dai->capture_widget;
+			if (play_w && capture_w) {
+				ret = snd_soc_dapm_new_pcm(card, dai_link->params,
 						   capture_w, play_w);
-			if (ret != 0) {
-				dev_err(card->dev, "Can't link %s to %s: %d\n",
-					play_w->name, capture_w->name, ret);
-				return ret;
+				if (ret != 0) {
+					dev_err(card->dev, "Can't link %s to %s: %d\n",
+						play_w->name, capture_w->name, ret);
+					return ret;
+				}
+			}
+
+			play_w = cpu_dai->playback_widget;
+			capture_w = codec_dai->capture_widget;
+			if (play_w && capture_w) {
+				ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+						   capture_w, play_w);
+				if (ret != 0) {
+					dev_err(card->dev, "Can't link %s to %s: %d\n",
+						play_w->name, capture_w->name, ret);
+					return ret;
+				}
 			}
 		}
 	}
@@ -1816,7 +1827,6 @@
 static int soc_probe(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	int ret = 0;
 
 	/*
 	 * no card, so machine driver should be registering card
@@ -1832,13 +1842,7 @@
 	/* Bodge while we unpick instantiation */
 	card->dev = &pdev->dev;
 
-	ret = snd_soc_register_card(card);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "Failed to register card\n");
-		return ret;
-	}
-
-	return 0;
+	return snd_soc_register_card(card);
 }
 
 static int soc_cleanup_card_resources(struct snd_soc_card *card)
@@ -3717,6 +3721,9 @@
 		}
 	}
 
+	if (!dai->codec)
+		dai->dapm.idle_bias_off = 1;
+
 	list_add(&dai->list, &dai_list);
 
 	mutex_unlock(&client_mutex);
@@ -3805,6 +3812,9 @@
 			}
 		}
 
+		if (!dai->codec)
+			dai->dapm.idle_bias_off = 1;
+
 		list_add(&dai->list, &dai_list);
 
 		mutex_unlock(&client_mutex);
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 0c17293..fa0fd8d 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -83,11 +83,6 @@
 	jack->status &= ~mask;
 	jack->status |= status & mask;
 
-	/* The DAPM sync is expensive enough to be worth skipping.
-	 * However, empty mask means pin synchronization is desired. */
-	if (mask && (jack->status == oldstatus))
-		goto out;
-
 	trace_snd_soc_jack_notify(jack, status);
 
 	list_for_each_entry(pin, &jack->pins, list) {
@@ -109,7 +104,6 @@
 
 	snd_jack_report(jack->jack, jack->status);
 
-out:
 	mutex_unlock(&jack->mutex);
 }
 EXPORT_SYMBOL_GPL(snd_soc_jack_report);
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index 057e28e..772cb19 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -760,6 +760,9 @@
 	drvdata = devm_kzalloc(&pdev->dev,
 				sizeof(struct ux500_msp_i2s_drvdata),
 				GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
 	drvdata->fmt = 0;
 	drvdata->slots = 1;
 	drvdata->tx_mask = 0x01;
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c
index 5c472f3..36be11e 100644
--- a/sound/soc/ux500/ux500_msp_i2s.c
+++ b/sound/soc/ux500/ux500_msp_i2s.c
@@ -673,6 +673,8 @@
 
 	*msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
 	msp = *msp_p;
+	if (!msp)
+		return -ENOMEM;
 
 	msp->id = platform_data->id;
 	msp->dev = &pdev->dev;