diff --git a/Documentation/sound/soc/codec.txt b/Documentation/sound/soc/codec.txt
new file mode 100644
index 0000000..b8bfeaf
--- /dev/null
+++ b/Documentation/sound/soc/codec.txt
@@ -0,0 +1,91 @@
+ASoC Codec driver
+=================
+
+** Still in progress **
+
+Writting an ASoC codec driver is relatively straight forward and can be broken down into the following sections.
+
+1. Audio Interface Capabilities
+
+   The codec audio interface(s) capabilities have to be defined and registered with the core. The definition describes the physical audio interface capabilities and includes format, speed, signal master/slave, signal inversion, etc. The physical codec interface is usually well described in the codec data sheet. 
+
+Codec digital audio link capabilities is described using the following struct :-
+
+/* SoC hardware mode */
+struct snd_soc_hw_mode {
+	u32 hformat;	/* SND_SOC_HWFMT_* */
+	u32 hbits;		/* SND_SOC_HWBITS() */
+	u32 rate;		/* sample rate */
+	u32 fs;			/* ratio of rate:bclk */ 
+	long priv1;		/* private mode data 1 */
+	long priv2;		/* private mode data 2 */
+	long priv3;		/* private mode data 3 */
+};
+
+This example is from the WM8750 and shows the supported options for 16bit pcm data at a 8k sample rate. Note that priv data can be used within the struct for codec setup.
+
+#define WM8750_HWFMT \
+	(SND_SOC_HWFMT_I2S | SND_SOC_HWFMT_LEFT_J | SND_SOC_HWFMT_RIGHT_J | \
+	SND_SOC_HWFMT_CBS_CFS | SND_SOC_HWFMT_CBM_CFM |\
+	SND_SOC_HWFMT_NB_NF | SND_SOC_HWFMT_NB_IF | SND_SOC_HWFMT_IB_NF | \
+	SND_SOC_HWFMT_IB_IF)
+
+/* priv1 is srate register setting */
+static struct snd_soc_hw_mode wm8750_hwfmt[] = {
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 8000,   64, 0x000c},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 8000,   96, 0x000e},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 8000,  128, 0x004c},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 8000,  192, 0x004e},
+}
+
+2. Audio controls
+
+   Audio controls are added in the usual ALSA way. There are convenience macros to help with this. i.e.
+
+#define SOC_SINGLE(xname, reg, shift, mask, invert)
+#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert, power)
+#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts)
+#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts)
+#define SOC_ENUM(xname, xenum)
+
+
+3. Dynamic Power Managment
+
+   Most portable audio codecs have fine grained power control. This enables the codec to use the minimum power possible per function. DPM automatically sets the lowest power state based upon internal audio routing and stream usage. 
+
+ We can have upto 4 codec power domains
+  i. Codec domain - VREF, VMID
+     Usually controlled at codec probe/remove, although can be set
+     at stream time if power is not needed for sidetone, etc.
+ ii. Platform/Machine domain - physically connected inputs and outputs
+     Is platform/machine and user action specific, is set in the .asoundrc file and
+     by userspace e.g when HP are inserted
+iii. Path domain - Internal codec path mixers
+     Are automatically set when mixer and mux settings are
+     changed by the user.
+ iv. Stream domain - DAC's and ADC's.
+     Enabled when stream playback/capture is started.  
+
+The machine domain (ii) is set outwith the codec driver.
+
+3.1 DPM Widgets
+
+   Each codec power block is controlled by a DPM widget. There are many different types of widget, each represents a different internal function within the codec. A dpm widget must be defined for every power block within the codec. i.e.
+
+	SND_SOC_DPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0, NULL, 0),
+	SND_SOC_DPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0, NULL, 0),
+
+3.2 Widget Interconnects
+
+   Widgets are connected to match the internal codec audio paths. 
+
+3.3 Codec dpm events
+
+
+4. Codec control interface
+
+
+5. Initialisation
+
+
+6. hw params
diff --git a/include/sound/soc-dpm.h b/include/sound/soc-dpm.h
index 5d4ebab..1a3a588 100644
--- a/include/sound/soc-dpm.h
+++ b/include/sound/soc-dpm.h
@@ -39,6 +39,10 @@
 #define SND_SOC_DPM_CLOCK(wname, preg, pshift, pinvert) \
 {.id = snd_soc_dpm_clock, .name = wname, .reg = preg, .shift = pshift, \
  .invert = pinvert, .kcontrols = NULL, .num_kcontrols = 0}
+/* not a true power register, but is used by dpm to minimise pops */ 
+#define SND_SOC_DPM_MUTE(wname, preg, pshift, pinvert) \
+{.id = snd_soc_dpm_mute, .name = wname, .reg = preg, .shift = pshift, \
+ .invert = pinvert, .kcontrols = NULL, .num_kcontrols = 0}
  
 /* platform domain */
 #define SND_SOC_DPM_INPUT(wname) \
@@ -47,6 +51,15 @@
 #define SND_SOC_DPM_OUTPUT(wname) \
 {.id = snd_soc_dpm_output, .name = wname, .kcontrols = NULL, \
  .num_kcontrols = 0}
+#define SND_SOC_DPM_MIC(wname) \
+{.id = snd_soc_dpm_mic, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0}
+#define SND_SOC_DPM_HP(wname) \
+{.id = snd_soc_dpm_hp, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0}
+#define SND_SOC_DPM_AMP(wname, wext_event) \
+{.id = snd_soc_dpm_amp, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0, .ext_event = wext_event}
  
 /* path domain */
 #define SND_SOC_DPM_VOLUME(wname, preg, pshift, pinvert, wcontrols, wncontrols) \
@@ -58,9 +71,9 @@
 #define SND_SOC_DPM_MIXER(wname, preg, pshift, pinvert, wcontrols, wncontrols) \
 {.id = snd_soc_dpm_mixer, .name = wname, .reg = preg, .shift = pshift, \
  .invert = pinvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols} 
-#define SND_SOC_DPM_MIC(wname, preg, pshift, pinvert, wcontrols, wncontrols) \
-{.id = snd_soc_dpm_mic, .name = wname, .reg = preg, .shift = pshift, \
- .invert = pinvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols} 
+#define SND_SOC_DPM_MICBIAS(wname, preg, pshift, pinvert) \
+{.id = snd_soc_dpm_micbias, .name = wname, .reg = preg, .shift = pshift, \
+ .invert = pinvert, .kcontrols = NULL, .num_kcontrols = 0} 
 
 /* stream domain */
 #define SND_SOC_DPM_DAC(wname, stname, preg, pshift, pinvert, wcontrols, wncontrols) \
@@ -92,19 +105,22 @@
 struct snd_soc_dpm_widget;
 enum snd_soc_dpm_type;
 struct snd_soc_dpm_path;
+struct snd_soc_dpm_pin;
 	
 int snd_soc_dpm_put_volsw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 int snd_soc_dpm_get_volsw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 int snd_soc_dpm_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 int snd_soc_dpm_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 int snd_soc_dpm_new_control(struct snd_soc_codec *codec, const struct snd_soc_dpm_widget *widget);
-int snd_soc_dpm_connect_input(struct snd_soc_codec *codec, char *target_name, 
-	char *control_name, char *src_name);
+int snd_soc_dpm_connect_input(struct snd_soc_codec *codec, const char *target_name, 
+	const char *control_name, const char *src_name);
 int snd_soc_dpm_sync(struct snd_soc_codec *codec);
-int snd_soc_dpm_stream_event(struct snd_soc_codec *codec, char * stream, int event);
+int snd_soc_dpm_stream_event(struct snd_soc_codec *codec, const char * stream, int event);
 int snd_soc_dpm_codec_event(struct snd_soc_codec *codec, int event);
 void snd_soc_dpm_sys_remove(struct device *dev);
 int snd_soc_dpm_sys_add(struct device *dev);
+int snd_soc_dpm_codec_mute(struct snd_soc_codec *codec, int mute);
+int snd_soc_dpm_set_connection(struct snd_soc_codec *codec, const struct snd_soc_dpm_pin *pin);
 
 enum snd_soc_dpm_type {
 	snd_soc_dpm_input = 0,
@@ -116,7 +132,11 @@ enum snd_soc_dpm_type {
 	snd_soc_dpm_dac,
 	snd_soc_dpm_clock,
 	snd_soc_dpm_vref,
+	snd_soc_dpm_micbias,
+	snd_soc_dpm_mute,
 	snd_soc_dpm_mic,
+	snd_soc_dpm_hp,
+	snd_soc_dpm_amp,
 };
 
 struct snd_soc_dpm_path {
@@ -144,11 +164,15 @@ struct snd_soc_dpm_widget {
 	/* dpm control */
 	short reg;						/* negative reg = no direct dpm */
 	unsigned char shift;
-	unsigned char status;			/* block rules status */ 
+	unsigned int value;				/* widget saved value */ 
 	unsigned char power:1;			/* block power status */
 	unsigned char invert:1;
 	unsigned char active:1;			/* active stream on DAC, ADC's */
-	unsigned char connected:1;	
+	unsigned char connected:1;		/* connected codec pin */
+	unsigned char sync:1;			/* sync complete */
+	unsigned char ext:1;			/* has external widgets */
+	unsigned char muted;			/* muted for pop reduction */
+	int (*ext_event)(struct snd_soc_codec*, int);
 	
 	/* kcontrols that relate to this widget */
 	int num_kcontrols;
@@ -159,4 +183,10 @@ struct snd_soc_dpm_widget {
 	struct list_head outputs;
 };
 
+/* codec pin connections */
+struct snd_soc_dpm_pin {
+	char *name;
+	int connected; /* this is dynamic for insertion/removal events e.g. hp, mic */
+};
+
 #endif
diff --git a/include/sound/soc.h b/include/sound/soc.h
index e4b274c..7163558 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -15,7 +15,6 @@
 
 #include <linux/device.h>
 #include <linux/types.h>
-#include <linux/i2c.h>
 #include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -266,12 +265,14 @@ struct snd_soc_codec {
 	snd_card_t *card;
 	struct platform_device pdev;
 	void *private_data;
+	void *machine_data;
 	int active_streams;
 	int pcm_devs;
 	int probed;
-	struct i2c_client i2c;
+	int dpm_state;
 	
 	/* codec IO */
+	void *control_data; /* codec control (i2c/3wire) data */
 	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
 	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
 	void *reg_cache;
@@ -293,6 +294,7 @@ struct snd_soc_platform {
 	int	(*remove)(struct device * dev);
 	struct bus_type	* bus;
 	int (*pcm_new)(snd_card_t *, struct snd_soc_pcm_codec *, snd_pcm_t *);
+	void (*pcm_free)(snd_pcm_t *);
 	snd_pcm_ops_t *pcm_ops;
 };
 
@@ -305,6 +307,9 @@ struct snd_soc_machine_config {
 	u32 connect:1;		/* interface and codec have been connected */
 	u32 card_reg:1;		/* codec card registered */
 	u32 flags;			/* preference flags */
+	
+	/* codec/machine specific init - e.g. add machine controls */
+	int (*init)(struct snd_soc_codec *codec); 
 };
 
 /* SoC machine interface */
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index a0ab318..c88dacc 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -27,13 +27,11 @@
 #include <sound/soc.h>
 #include <sound/soc-dpm.h>
 #include <sound/initval.h>
-#include <asm/hardware/scoop.h>
-#include <asm/arch/corgi.h>
 
 #include "wm8731.h"
 
 #define AUDIO_NAME "wm8731"
-#define WM8731_VERSION "0.3"
+#define WM8731_VERSION "0.4"
 
 
 /*
@@ -70,8 +68,8 @@ static struct i2c_client client_template
  * There is no point in caching the reset register
  */
 static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
-    0x0023, 0x0023, 0x0121, 0x0121, 
-    0x0012, 0x0000, 0x0000, 0x0000, 
+    0x0097, 0x0097, 0x0079, 0x0079, 
+    0x000a, 0x0008, 0x009f, 0x000a, 
     0x0000, 0x0000
 };
 
@@ -151,7 +149,7 @@ static int wm8731_write(struct snd_soc_c
 	unsigned int value)
 {
 	u8 data[2];
-
+	struct i2c_client* i2c = (struct i2c_client*)codec->control_data;
 	/* data is 
 	 *   D15..D9 WM8731 register offset
 	 *   D8...D0 register data
@@ -161,7 +159,7 @@ static int wm8731_write(struct snd_soc_c
 
 	wm8731_write_reg_cache (codec, reg, value);
 
-	if (i2c_master_send(&codec->i2c, data, 2) == 2)
+	if (i2c_master_send(i2c, data, 2) == 2)
 		return 0;
 	else
 		return -1;
@@ -170,9 +168,11 @@ static int wm8731_write(struct snd_soc_c
 #define wm8731_reset(c)	wm8731_write(c, WM8731_RESET, 0)
 
 static const char* wm8731_input_select[] = {"Line In", "Mic"};
+static const char* wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
 
 static const struct soc_enum wm8731_enum[] = {
 	SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select),
+	SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph),
 };
 
 static const snd_kcontrol_new_t wm8731_snd_controls[] = {
@@ -194,7 +194,8 @@ SOC_SINGLE("Sidetone Playback Volume", W
 
 SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
 SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
-
+	
+SOC_ENUM("Playback De-emphasis", wm8731_enum[1]),
 };
 
 /* add non dpm controls */
@@ -213,9 +214,9 @@ static int wm8731_add_controls(struct sn
 
 /* Output Mixer */
 static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = {
-SOC_DPM_SINGLE("Bypass Switch", WM8731_APANA, 3, 1, 0),
-SOC_DPM_SINGLE("Sidetone Switch", WM8731_APANA, 5, 1, 0),
-SOC_DPM_SINGLE("Playback Switch", WM8731_APANA, 4, 1, 0),
+SOC_DPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
+SOC_DPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0),
+SOC_DPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
 };
 
 /* Input mux */
@@ -226,6 +227,7 @@ SOC_DPM_ENUM("Input Select", wm8731_enum
 static const struct snd_soc_dpm_widget wm8731_dpm_widgets[] = {
 SND_SOC_DPM_CLOCK("WM8731 Clock", WM8731_PWR, 6, 1),
 SND_SOC_DPM_CLOCK("WM8731 Osc", WM8731_PWR, 5, 1),
+SND_SOC_DPM_MUTE("DAC Mute", WM8731_APDIGI, 3, 0),
 SND_SOC_DPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, &wm8731_output_mixer_controls[0], 
 	ARRAY_SIZE(wm8731_output_mixer_controls)),
 SND_SOC_DPM_DAC("DAC", "HiFi Playback", WM8731_PWR, 3, 1, NULL, 0),
@@ -236,12 +238,37 @@ SND_SOC_DPM_OUTPUT("LRHPOUT"),
 SND_SOC_DPM_ADC("ADC", "HiFi Capture", WM8731_PWR, 2, 1, NULL, 0),
 SND_SOC_DPM_MUX("Input Mux", -1, 0, 0, &wm8753_input_mux_controls),
 SND_SOC_DPM_VOLUME("Line Input", WM8731_PWR, 0, 1, NULL, 0),
-SND_SOC_DPM_MIC("Mic", WM8731_PWR, 1, 1, NULL, 0),
+SND_SOC_DPM_MICBIAS("Mic", WM8731_PWR, 1, 1),
 SND_SOC_DPM_INPUT("MICIN"),
 SND_SOC_DPM_INPUT("RLINEIN"),
 SND_SOC_DPM_INPUT("LLINEIN"),
 };
 
+static const char* intercon[][3] = {
+	/* output mixer */
+	{"Output Mixer", "Line Bypass Switch", "Line Input"},
+	{"Output Mixer", "HiFi Playback Switch", "DAC"},
+	{"Output Mixer", "Mic Sidetone Switch", "Mic"},
+	
+	/* outputs */
+	{"RHPOUT", NULL, "Output Mixer"},
+	{"ROUT", NULL, "Output Mixer"},
+	{"LHPOUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+	
+	/* input mux */
+	{"Input Mux", "Line In", "Line Input"},
+	{"Input Mux", "Mic", "Mic"},
+	
+	/* outputs */
+	{"Line Input", NULL, "LLINEIN"},
+	{"Line Input", NULL, "RLINEIN"},
+	{"Mic", NULL, "MICIN"},
+	
+	/* terminator */
+	{NULL, NULL, NULL},
+};
+
 static int wm8731_add_widgets(struct snd_soc_codec *codec)
 {
 	int i;
@@ -251,26 +278,9 @@ static int wm8731_add_widgets(struct snd
 	}
 	
 	/* set up audio path interconnects */
-	
-	/* output mixer */
-	snd_soc_dpm_connect_input(codec, "Output Mixer", "Bypass Switch", "Line Input");
-	snd_soc_dpm_connect_input(codec, "Output Mixer", "Playback Switch", "DAC");
-	snd_soc_dpm_connect_input(codec, "Output Mixer", "Sidetone Switch", "Mic");
-	
-	/* outputs */
-	snd_soc_dpm_connect_input(codec, "RHPOUT", NULL, "Output Mixer");
-	snd_soc_dpm_connect_input(codec, "ROUT", NULL, "Output Mixer");
-	snd_soc_dpm_connect_input(codec, "LHPOUT", NULL, "Output Mixer");
-	snd_soc_dpm_connect_input(codec, "LOUT", NULL, "Output Mixer");
-	
-	/* input mux */
-	snd_soc_dpm_connect_input(codec, "Input Mux", "Line In", "Line Input");
-	snd_soc_dpm_connect_input(codec, "Input Mux", "Mic", "Mic");
-	
-	/* outputs */
-	snd_soc_dpm_connect_input(codec, "Line Input", NULL, "LLINEIN");
-	snd_soc_dpm_connect_input(codec, "Line Input", NULL, "RLINEIN");
-	snd_soc_dpm_connect_input(codec, "Mic", NULL, "MICIN");
+	for(i = 0; intercon[i][0] != NULL; i++) {
+		snd_soc_dpm_connect_input(codec, intercon[i][0], intercon[i][1], intercon[i][2]);
+	}
 	
 	snd_soc_dpm_sync(codec);
 	return 0;
@@ -345,14 +355,8 @@ static int wm8731_pcm_prepare(snd_pcm_su
 
 	/* set rate */
 	wm8731_write(codec, WM8731_SRATE, pcm_c->hw_runtime.priv1);
-
 	wm8731_write(codec, WM8731_IFACE, iface);
 
-	wm8731_write(codec, WM8731_APANA, 0x12);
-
-	if (wm8731_write(codec, WM8731_ACTIVE, 0x01) != 0)
-		return -EIO;
-
 	return 0;
 }
 
@@ -362,31 +366,22 @@ static void wm8731_device_release(struct
 
 static int wm8731_dpm_event(struct snd_soc_codec *codec, int event)
 {
-	u16 pwr_reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff1f;
-	u16 act_reg = wm8731_read_reg_cache(codec, WM8731_ACTIVE) & 0xfffe;
-	u16 dac_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7;
-
 	switch (event) {
 		case SNDRV_CTL_POWER_D0: /* full On */
 			/* vref/mid, clk and osc on, dac unmute, active */
-			wm8731_write(codec, WM8731_ACTIVE, act_reg | 0x0001);
-			wm8731_write(codec, WM8731_APDIGI, dac_reg & 0xfff7);
+			wm8731_write(codec, WM8731_ACTIVE, 0x0001);
 			break;
 		case SNDRV_CTL_POWER_D1: /* partial On */
 		case SNDRV_CTL_POWER_D2: /* partial On */
 			break;
 		case SNDRV_CTL_POWER_D3hot: /* Off, with power */
 			/* everything off except vref/vmid, dac mute, inactive */
-			wm8731_write(codec, WM8731_APDIGI, dac_reg | 0x0008);
-			wm8731_write(codec, WM8731_PWR, pwr_reg | 0x0010);
-			wm8731_write(codec, WM8731_ACTIVE, act_reg);
+			wm8731_write(codec, WM8731_ACTIVE, 0x0);
 			wm8731_write(codec, WM8731_PWR, 0xff7f);
 			break;
 		case SNDRV_CTL_POWER_D3cold: /* Off, without power */
 			/* everything off, dac mute, inactive */
-			wm8731_write(codec, WM8731_APDIGI, dac_reg | 0x0008);
-			wm8731_write(codec, WM8731_PWR, pwr_reg | 0x0010);
-			wm8731_write(codec, WM8731_ACTIVE, act_reg);
+			wm8731_write(codec, WM8731_ACTIVE, 0x0);
 			wm8731_write(codec, WM8731_PWR, 0xffff);
 			break;
 	}
@@ -434,14 +429,6 @@ static int wm8731_probe(struct snd_soc_c
 	int reg;
 	
 	wm8731_reset(codec);
-	
-	reg = wm8731_read_reg_cache(codec, WM8731_PWR);
-	wm8731_write(codec, WM8731_PWR, reg);
-
-	reg = wm8731_read_reg_cache(codec, WM8731_APANA);
-	wm8731_write(codec, WM8731_APANA, reg);
-	reg = wm8731_read_reg_cache(codec, WM8731_APDIGI);
-	wm8731_write(codec, WM8731_APDIGI, reg);
 
 	wm8731_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
 	
@@ -476,6 +463,7 @@ static int wm8731_i2c_probe(struct i2c_a
 {		
 	int ret = 0;
 	struct snd_soc_codec *codec;
+	struct i2c_client *i2c;
 
 	client_template.adapter = adap;
 	client_template.addr = addr;
@@ -483,11 +471,19 @@ static int wm8731_i2c_probe(struct i2c_a
 	if ((codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
  
-	memcpy(&codec->i2c, &client_template, sizeof(struct i2c_client));
+	if ((i2c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL)) == NULL){
+		kfree(codec);
+		return -ENOMEM;
+	}
+	memcpy(i2c, &client_template, sizeof(struct i2c_client));
+	codec->control_data = i2c;
+	i2c->dev.platform_data = codec;
 
-	if((ret = i2c_attach_client(&codec->i2c)) < 0) {
+	if((ret = i2c_attach_client(i2c)) < 0) {
 		err("failed to attach codec at addr %x\n", addr);
+		kfree(i2c);
 		kfree(codec);
+		return ret;
 	}
 
 	codec->name = "WM8731";
@@ -511,6 +507,7 @@ static int wm8731_i2c_probe(struct i2c_a
 	if((ret = snd_soc_register_codec(codec)) < 0) {
 		err("can't register codec");
 		i2c_del_driver(&wm8731_i2c_driver);
+		kfree(i2c);
 		kfree(codec->reg_cache);
 		kfree(codec);
 	}
@@ -520,11 +517,13 @@ static int wm8731_i2c_probe(struct i2c_a
 
 static int wm8731_i2c_detach(struct i2c_client *client)
 {
-	struct snd_soc_codec *codec = container_of(client, struct snd_soc_codec, i2c);
+	struct snd_soc_codec *codec = 
+		(struct snd_soc_codec*)client->dev.platform_data;
 
 	i2c_detach_client(client);
 	snd_soc_unregister_codec(codec);
 	kfree(codec->reg_cache);
+	kfree(codec->control_data);
 	kfree(codec);
 	return 0;
 }
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index d47eb33..7647fdb 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/i2c.h>
 
 #include <sound/driver.h>
 #include <sound/core.h>
@@ -25,8 +26,6 @@
 #include <sound/soc.h>
 #include <sound/soc-dpm.h>
 #include <sound/initval.h>
-#include <asm/hardware/scoop.h>
-#include <asm/arch/spitz.h>
 
 #include "wm8750.h"
 
@@ -174,6 +173,7 @@ static int wm8750_write(struct snd_soc_c
 	unsigned int value)
 {
 	u8 data[2];
+	struct i2c_client *i2c = (struct i2c_client*)codec->control_data;
 
 	/* data is 
 	 *   D15..D9 WM8750 register offset
@@ -183,7 +183,7 @@ static int wm8750_write(struct snd_soc_c
 	data[1] = value & 0x00ff;
 
 	wm8750_write_reg_cache (codec, reg, value);
-	if (i2c_master_send(&codec->i2c, data, 2) == 2)
+	if (i2c_master_send(i2c, data, 2) == 2)
 		return 0;
 	else
 		return -1;
@@ -240,14 +240,10 @@ SOC_SINGLE("Right Capture Volume", WM875
 SOC_SINGLE("Right Capture ZC Switch", WM8750_RINVOL, 6, 1, 0),
 SOC_SINGLE("Right Capture Switch", WM8750_RINVOL, 7, 1, 1),
 
-SOC_SINGLE("Left Out1 Playback Volume", WM8750_LOUT1V, 0, 127, 0),
 SOC_SINGLE("Left Out1 Playback ZC Switch", WM8750_LOUT1V, 7, 1, 0),
-SOC_SINGLE("Right Out1 Playback Volume", WM8750_ROUT1V, 0, 127, 0),
 SOC_SINGLE("Right Out1 Playback ZC Switch", WM8750_ROUT1V, 7, 1, 0),
 
-SOC_SINGLE("Left Out2 Playback Volume", WM8750_LOUT2V, 0, 127, 0),
 SOC_SINGLE("Left Out2 Playback ZC Switch", WM8750_LOUT2V, 7, 1, 0),
-SOC_SINGLE("Right Out2 Playback Volume", WM8750_ROUT2V, 0, 127, 0),
 SOC_SINGLE("Right Out2 Playback ZC Switch", WM8750_ROUT2V, 7, 1, 0),
 
 SOC_ENUM("Playback De-emphasis", wm8750_enum[15]),
@@ -318,7 +314,6 @@ SOC_SINGLE("Right Bypass Right Playback 
 SOC_SINGLE("Left Bypass Mono Playback Volume", WM8750_MOUTM1, 4, 7, 1),
 SOC_SINGLE("Right Bypass Mono Playback Volume", WM8750_MOUTM2, 4, 7, 1), 
 
-SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0),
 SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0),
 
 };
@@ -391,21 +386,41 @@ SOC_DPM_ENUM("Route", wm8750_enum[13]);
 static const snd_kcontrol_new_t wm8750_monomux_controls =
 SOC_DPM_ENUM("Route", wm8750_enum[16]);
 
+/* LOUT 1 Volume */
+static const snd_kcontrol_new_t wm8750_lout1_vol_controls =
+SOC_DPM_SINGLE("Left Out1 Playback Volume", WM8750_LOUT1V, 0, 127, 0);
+
+/* ROUT 1 Volume */
+static const snd_kcontrol_new_t wm8750_rout1_vol_controls =
+SOC_DPM_SINGLE("Right Out1 Playback Volume", WM8750_ROUT1V, 0, 127, 0);
+
+/* LOUT 2 Volume */
+static const snd_kcontrol_new_t wm8750_lout2_vol_controls =
+SOC_DPM_SINGLE("Left Out2 Playback Volume", WM8750_LOUT2V, 0, 127, 0);
+
+/* ROUT 2 Volume */
+static const snd_kcontrol_new_t wm8750_rout2_vol_controls =
+SOC_DPM_SINGLE("Right Out2 Playback Volume", WM8750_ROUT2V, 0, 127, 0);
+
+/* Mono Volume */
+static const snd_kcontrol_new_t wm8750_mout_vol_controls =
+SOC_DPM_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0);
 
 static const struct snd_soc_dpm_widget wm8750_dpm_widgets[] = {
 	SND_SOC_DPM_CLOCK("WM8750 Clock", WM8750_PWR1, 0, 1),
+	SND_SOC_DPM_MUTE("DAC Mute", WM8750_ADCDAC, 3, 0),
 	SND_SOC_DPM_MIXER("Left Mixer", -1, 0, 0, &wm8750_left_mixer_controls[0], ARRAY_SIZE(wm8750_left_mixer_controls)),
 	SND_SOC_DPM_MIXER("Right Mixer", -1, 0, 0, &wm8750_right_mixer_controls[0], ARRAY_SIZE(wm8750_right_mixer_controls)),
 	SND_SOC_DPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0, &wm8750_mono_mixer_controls[0], ARRAY_SIZE(wm8750_mono_mixer_controls)),
 
-	SND_SOC_DPM_VOLUME("Right Out 2", WM8750_PWR2, 3, 0, NULL, 0),
-	SND_SOC_DPM_VOLUME("Left Out 2", WM8750_PWR2, 4, 0, NULL, 0),
-	SND_SOC_DPM_VOLUME("Right Out 1", WM8750_PWR2, 5, 0, NULL, 0),
-	SND_SOC_DPM_VOLUME("Left Out 1", WM8750_PWR2, 6, 0, NULL, 0),
+	SND_SOC_DPM_VOLUME("Right Out 2", WM8750_PWR2, 3, 0, &wm8750_rout2_vol_controls, 1),
+	SND_SOC_DPM_VOLUME("Left Out 2", WM8750_PWR2, 4, 0, &wm8750_lout2_vol_controls, 1),
+	SND_SOC_DPM_VOLUME("Right Out 1", WM8750_PWR2, 5, 0, &wm8750_rout1_vol_controls, 1),
+	SND_SOC_DPM_VOLUME("Left Out 1", WM8750_PWR2, 6, 0, &wm8750_lout1_vol_controls, 1),
 	SND_SOC_DPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0, NULL, 0),
 	SND_SOC_DPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0, NULL, 0),
 
-	//"Mic Bias", WM8750_PWR1, 1, 0
+	SND_SOC_DPM_MICBIAS("Mic Bias", WM8750_PWR1, 1, 0),
 	SND_SOC_DPM_ADC("Right ADC", "Right Capture", WM8750_PWR1, 2, 0, NULL, 0),
 	SND_SOC_DPM_ADC("Left ADC", "Left Capture", WM8750_PWR1, 3, 0, NULL, 0),
 
@@ -416,7 +431,8 @@ static const struct snd_soc_dpm_widget w
 
 	SND_SOC_DPM_MUX("Out3 Mux", -1, 0, 0, &wm8750_out3_controls),
 	SND_SOC_DPM_VOLUME("Out 3", WM8750_PWR2, 1, 0, NULL, 0),
-
+	SND_SOC_DPM_VOLUME("Mono Out 1", WM8750_PWR2, 2, 0, &wm8750_mout_vol_controls, 1),
+	
 	SND_SOC_DPM_MUX("Differential Mux", -1, 0, 0, &wm8750_diffmux_controls),
 	SND_SOC_DPM_MUX("Left ADC Mux", -1, 0, 0, &wm8750_monomux_controls),
 	SND_SOC_DPM_MUX("Right ADC Mux", -1, 0, 0, &wm8750_monomux_controls),
@@ -436,106 +452,115 @@ static const struct snd_soc_dpm_widget w
 	SND_SOC_DPM_INPUT("RINPUT3"),
 };
 
-static int wm8750_add_widgets(struct snd_soc_codec *codec)
-{
-	int i;
-	
-	for(i = 0; i < ARRAY_SIZE(wm8750_dpm_widgets); i++) {
-		snd_soc_dpm_new_control(codec, &wm8750_dpm_widgets[i]);
-	}
-	
+static const char* intercon[][3] = {
 	/* left mixer */
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Playback Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Left Bypass Switch", "Left Line Mux");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Right Playback Switch", "Right DAC");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Right Bypass Switch", "Right Line Mux");
+	{"Left Mixer", "Playback Switch", "Left DAC"},
+	{"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Left Mixer", "Right Playback Switch", "Right DAC"},
+	{"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
 
 	/* right mixer */
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Left Playback Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Left Bypass Switch", "Left Line Mux");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Playback Switch", "Right DAC");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Right Bypass Switch", "Right Line Mux");
+	{"Right Mixer", "Left Playback Switch", "Left DAC"},
+	{"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Right Mixer", "Playback Switch", "Right DAC"},
+	{"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
 
 	/* left out 1 */
-	snd_soc_dpm_connect_input(codec, "Left Out 1", NULL, "Left Mixer");
-	snd_soc_dpm_connect_input(codec, "LOUT1", NULL, "Left Out 1");
+	{"Left Out 1", NULL, "Left Mixer"},
+	{"LOUT1", NULL, "Left Out 1"},
 
 	/* left out 2 */
-	snd_soc_dpm_connect_input(codec, "Left Out 2", NULL, "Left Mixer");
-	snd_soc_dpm_connect_input(codec, "LOUT2", NULL, "Left Out 2");
+	{"Left Out 2", NULL, "Left Mixer"},
+	{"LOUT2", NULL, "Left Out 2"},
 	
 	/* right out 1 */
-	snd_soc_dpm_connect_input(codec, "Right Out 1", NULL, "Right Mixer");
-	snd_soc_dpm_connect_input(codec, "ROUT1", NULL, "Right Out 1");
+	{"Right Out 1", NULL, "Right Mixer"},
+	{"ROUT1", NULL, "Right Out 1"},
 
 	/* right out 2 */
-	snd_soc_dpm_connect_input(codec, "Right Out 2", NULL, "Right Mixer");
-	snd_soc_dpm_connect_input(codec, "ROUT2", NULL, "Right Out 2");
+	{"Right Out 2", NULL, "Right Mixer"},
+	{"ROUT2", NULL, "Right Out 2"},
 
 	/* mono mixer */
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Left Playback Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Left Bypass Switch", "Left Line Mux");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Right Playback Switch", "Right DAC");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Right Bypass Switch", "Right Line Mux");
+	{"Mono Mixer", "Left Playback Switch", "Left DAC"},
+	{"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Mono Mixer", "Right Playback Switch", "Right DAC"},
+	{"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
 	
 	/* mono out */
-	snd_soc_dpm_connect_input(codec, "Mono Out 1", NULL, "Mono Mixer");
-	snd_soc_dpm_connect_input(codec, "MONO1", NULL, "Mono Out 1");
+	{"Mono Out 1", NULL, "Mono Mixer"},
+	{"MONO1", NULL, "Mono Out 1"},
 
 	/* out 3 */
-	snd_soc_dpm_connect_input(codec, "Out3 Mux", "VREF", "VREF");
-	snd_soc_dpm_connect_input(codec, "Out3 Mux", "ROUT1 + Vol", "ROUT1");
-	snd_soc_dpm_connect_input(codec, "Out3 Mux", "ROUT1", "Right Mixer");
-	snd_soc_dpm_connect_input(codec, "Out3 Mux", "MonoOut", "MONO1");
-
-	snd_soc_dpm_connect_input(codec, "Out 3", NULL, "Out3 Mux");
-	snd_soc_dpm_connect_input(codec, "OUT3", NULL, "Out 3");
+	{"Out3 Mux", "VREF", "VREF"},
+	{"Out3 Mux", "ROUT1 + Vol", "ROUT1"},
+	{"Out3 Mux", "ROUT1", "Right Mixer"},
+	{"Out3 Mux", "MonoOut", "MONO1"},
+	{"Out 3", NULL, "Out3 Mux"},
+	{"OUT3", NULL, "Out 3"},
 
 	/* Left Line Mux */
-	snd_soc_dpm_connect_input(codec, "Left Line Mux", "Line 1", "LINPUT1");
-	snd_soc_dpm_connect_input(codec, "Left Line Mux", "Line 2", "LINPUT2");
-	snd_soc_dpm_connect_input(codec, "Left Line Mux", "Line 3", "LINPUT3");
-	snd_soc_dpm_connect_input(codec, "Left Line Mux", "PGA", "Left PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Left Line Mux", "Differential", "Differential Mux");
+	{"Left Line Mux", "Line 1", "LINPUT1"},
+	{"Left Line Mux", "Line 2", "LINPUT2"},
+	{"Left Line Mux", "Line 3", "LINPUT3"},
+	{"Left Line Mux", "PGA", "Left PGA Mux"},
+	{"Left Line Mux", "Differential", "Differential Mux"},
 
 	/* Right Line Mux */
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Line 1", "RINPUT1");
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Line 2", "RINPUT2");
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Line 3", "RINPUT3");
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "PGA", "Right PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Differential", "Differential Mux");
+	{"Right Line Mux", "Line 1", "RINPUT1"},
+	{"Right Line Mux", "Line 2", "RINPUT2"},
+	{"Right Line Mux", "Line 3", "RINPUT3"},
+	{"Right Line Mux", "PGA", "Right PGA Mux"},
+	{"Right Line Mux", "Differential", "Differential Mux"},
 
 	/* Left PGA Mux */
-	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Line 1", "LINPUT1");
-	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Line 2", "LINPUT2");
-	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Line 3", "LINPUT3");
-	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Differential", "Differential Mux");
+	{"Left PGA Mux", "Line 1", "LINPUT1"},
+	{"Left PGA Mux", "Line 2", "LINPUT2"},
+	{"Left PGA Mux", "Line 3", "LINPUT3"},
+	{"Left PGA Mux", "Differential", "Differential Mux"},
 
 	/* Right PGA Mux */
-	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Line 1", "RINPUT1");
-	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Line 2", "RINPUT2");
-	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Line 3", "RINPUT3");
-	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Differential", "Differential Mux");
+	{"Right PGA Mux", "Line 1", "RINPUT1"},
+	{"Right PGA Mux", "Line 2", "RINPUT2"},
+	{"Right PGA Mux", "Line 3", "RINPUT3"},
+	{"Right PGA Mux", "Differential", "Differential Mux"},
 
 	/* Differential Mux */
-	snd_soc_dpm_connect_input(codec, "Differential Mux", "Line 1", "LINPUT1");
-	snd_soc_dpm_connect_input(codec, "Differential Mux", "Line 1", "RINPUT1");
-	snd_soc_dpm_connect_input(codec, "Differential Mux", "Line 2", "LINPUT2");
-	snd_soc_dpm_connect_input(codec, "Differential Mux", "Line 2", "RINPUT2");
+	{"Differential Mux", "Line 1", "LINPUT1"},
+	{"Differential Mux", "Line 1", "RINPUT1"},
+	{"Differential Mux", "Line 2", "LINPUT2"},
+	{"Differential Mux", "Line 2", "RINPUT2"},
 
 	/* Left ADC Mux */
-	snd_soc_dpm_connect_input(codec, "Left ADC Mux", "Stereo", "Left PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Left ADC Mux", "Mono (Left)", "Left PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Left ADC Mux", "Digital Mono", "Left PGA Mux");
+	{"Left ADC Mux", "Stereo", "Left PGA Mux"},
+	{"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
+	{"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
 
 	/* Right ADC Mux */
-	snd_soc_dpm_connect_input(codec, "Right ADC Mux", "Stereo", "Right PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Right ADC Mux", "Mono (Right)", "Right PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Right ADC Mux", "Digital Mono", "Right PGA Mux");
+	{"Right ADC Mux", "Stereo", "Right PGA Mux"},
+	{"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
+	{"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
 
 	/* ADC */
-	snd_soc_dpm_connect_input(codec, "Left ADC", NULL, "Left ADC Mux");
-	snd_soc_dpm_connect_input(codec, "Right ADC", NULL, "Right ADC Mux");
+	{"Left ADC", NULL, "Left ADC Mux"},
+	{"Right ADC", NULL, "Right ADC Mux"},
+	
+	/* terminator */
+	{NULL, NULL, NULL},
+};
+
+static int wm8750_add_widgets(struct snd_soc_codec *codec)
+{
+	int i;
+	
+	for(i = 0; i < ARRAY_SIZE(wm8750_dpm_widgets); i++) {
+		snd_soc_dpm_new_control(codec, &wm8750_dpm_widgets[i]);
+	}
+	
+	/* set up audio path interconnects */
+	for(i = 0; intercon[i][0] != NULL; i++) {
+		snd_soc_dpm_connect_input(codec, intercon[i][0], intercon[i][1], intercon[i][2]);
+	}
 
 	snd_soc_dpm_sync(codec);
 	return 0;
@@ -551,7 +576,7 @@ static int wm8750_pcm_prepare(snd_pcm_su
 	/* set master/slave audio interface */
 	switch(pcm_c->hw_runtime.hformat & SND_SOC_CLOCK_MASK) {
 		case SND_SOC_HWFMT_CBM_CFM:
-			iface |= 0x0020;
+			iface |= 0x0040;
 			break;
 		case SND_SOC_HWFMT_CBS_CFS:
 			break;
@@ -619,13 +644,11 @@ static void wm8750_device_release(struct
 static int wm8750_dpm_event(struct snd_soc_codec *codec, int event)
 {
 	u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3f;
-	u16 dac_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7;
-
+	
 	switch (event) {
 		case SNDRV_CTL_POWER_D0: /* full On */
 			/* set vmid to 50k and unmute dac */
 			wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0);
-			wm8750_write(codec, WM8750_ADCDAC, dac_reg);
 			break;
 		case SNDRV_CTL_POWER_D1: /* partial On */
 		case SNDRV_CTL_POWER_D2: /* partial On */
@@ -634,11 +657,9 @@ static int wm8750_dpm_event(struct snd_s
 			break;
 		case SNDRV_CTL_POWER_D3hot: /* Off, with power */
 			/* mute dac and set vmid to 500k, enable VREF */
-			wm8750_write(codec, WM8750_ADCDAC, dac_reg | 0x0008);
 			wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0140);
 			break;
 		case SNDRV_CTL_POWER_D3cold: /* Off, without power */
-			wm8750_write(codec, WM8750_ADCDAC, dac_reg | 0x0008);
 			wm8750_write(codec, WM8750_PWR1, 0x0000);
 			break;
 	}
@@ -688,7 +709,9 @@ static int wm8750_probe(struct snd_soc_c
 	info("WM8750 Audio Codec %s", WM8750_VERSION);
 	
 	wm8750_reset(codec);
-	wm8750_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
+	
+	/* charge output caps */
+	wm8750_dpm_event(codec, SNDRV_CTL_POWER_D2);
 
 	/* set the update bits */
 	reg = wm8750_read_reg_cache(codec, WM8750_LDAC);
@@ -710,6 +733,10 @@ static int wm8750_probe(struct snd_soc_c
 
 	wm8750_add_controls(codec);
 	wm8750_add_widgets(codec);
+	
+	/* wait for caps to finish charging - liam make this thread */
+	ssleep(1);
+	wm8750_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
 
 	return 0;
 }
@@ -729,6 +756,7 @@ static int wm8750_i2c_probe(struct i2c_a
 {		
 	int ret = 0;
 	struct snd_soc_codec *codec;
+	struct i2c_client *i2c;
 
 	client_template.adapter = adap;
 	client_template.addr = addr;
@@ -736,11 +764,19 @@ static int wm8750_i2c_probe(struct i2c_a
 	if ((codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
  
-	memcpy(&codec->i2c, &client_template, sizeof(struct i2c_client));
+	if ((i2c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL)) == NULL){
+		kfree(codec);
+		return -ENOMEM;
+	}
+	memcpy(i2c, &client_template, sizeof(struct i2c_client));
+	codec->control_data = i2c;
+	i2c->dev.platform_data = codec;
 
-	if((ret = i2c_attach_client(&codec->i2c)) < 0) {
+	if((ret = i2c_attach_client(i2c)) < 0) {
 		err("failed to attach codec at addr %x\n", addr);
+		kfree(i2c);
 		kfree(codec);
+		return ret;
 	}
 
 	codec->name = "WM8750";
@@ -764,6 +800,7 @@ static int wm8750_i2c_probe(struct i2c_a
 	if((ret = snd_soc_register_codec(codec)) < 0) {
 		err("can't register codec");
 		i2c_del_driver(&wm8750_i2c_driver);
+		kfree(i2c);
 		kfree(codec->reg_cache);
 		kfree(codec);
 	}
@@ -773,10 +810,12 @@ static int wm8750_i2c_probe(struct i2c_a
 
 static int wm8750_i2c_detach(struct i2c_client *client)
 {
-	struct snd_soc_codec *codec = container_of(client, struct snd_soc_codec, i2c);
-
+	struct snd_soc_codec *codec = 
+		(struct snd_soc_codec*)client->dev.platform_data;
+			
 	i2c_detach_client(client);
 	snd_soc_unregister_codec(codec);
+	kfree(codec->control_data);
 	kfree(codec->reg_cache);
 	kfree(codec);
 	return 0;
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 507d58e..5c5316a 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -247,7 +247,7 @@ static int wm8753_write(struct snd_soc_c
 	unsigned int value)
 {
 	u8 data[2];
-
+	struct i2c_client *i2c = (struct i2c_client*)codec->control_data;
 	/* data is 
 	 *   D15..D9 WM8753 register offset
 	 *   D8...D0 register data
@@ -256,7 +256,7 @@ static int wm8753_write(struct snd_soc_c
 	data[1] = value & 0x00ff;
 
 	wm8753_write_reg_cache (codec, reg, value);
-	if (i2c_master_send(&codec->i2c, data, 2) == 2)
+	if (i2c_master_send(i2c, data, 2) == 2)
 		return 0;
 	else
 		return -1;
@@ -339,19 +339,15 @@ SOC_SINGLE("Right ADC Capture Volume", W
 SOC_SINGLE("Right ADC Capture Switch", WM8753_RADC, 7, 1, 0),
 SOC_SINGLE("Right ADC Capture ZC Switch", WM8753_RADC, 6, 1, 0),
 
-SOC_SINGLE("Left Out 1 Volume", WM8753_LOUT1V, 0, 127, 0),
-SOC_SINGLE("Left Out 1 ZC Switch", WM8753_LOUT1V, 7, 1, 0),
-SOC_SINGLE("Left Out 2 Volume", WM8753_LOUT2V, 0, 127, 0),
-SOC_SINGLE("Left Out 2 ZC Switch", WM8753_LOUT2V, 7, 1, 0),
+SOC_SINGLE("Left Out1 Playback ZC Switch", WM8753_LOUT1V, 7, 1, 0),
+SOC_SINGLE("Left Out2 Playback ZC Switch", WM8753_LOUT2V, 7, 1, 0),
 	
 SOC_SINGLE("Left Bypass Playback Volume", WM8753_LOUTM1, 4, 7, 1),
 SOC_SINGLE("Left Sidetone Playback Volume", WM8753_LOUTM2, 4, 7, 1),
 SOC_SINGLE("Left Voice Playback Volume", WM8753_LOUTM2, 0, 7, 1),
 
-SOC_SINGLE("Right Out 1 Volume", WM8753_ROUT1V, 0, 127, 0),
-SOC_SINGLE("Right Out 1 ZC Switch", WM8753_ROUT1V, 7, 1, 0),
-SOC_SINGLE("Right Out 2 Volume", WM8753_ROUT2V, 0, 127, 0),
-SOC_SINGLE("Right Out 2 ZC Switch", WM8753_ROUT2V, 7, 1, 0),
+SOC_SINGLE("Right Out1 Playback ZC Switch", WM8753_ROUT1V, 7, 1, 0),
+SOC_SINGLE("Right Out2 Playback ZC Switch", WM8753_ROUT2V, 7, 1, 0),
 
 SOC_SINGLE("Right Bypass Playback Volume", WM8753_ROUTM1, 4, 7, 1),
 SOC_SINGLE("Right Sidetone Playback Volume", WM8753_ROUTM2, 4, 7, 1),
@@ -361,8 +357,7 @@ SOC_SINGLE("Mono Bypass Playback Volume"
 SOC_SINGLE("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1),
 SOC_SINGLE("Mono Voice Playback Volume", WM8753_MOUTM2, 4, 7, 1),
 
-SOC_SINGLE("Mono Volume", WM8753_MOUTV, 0, 127, 0),
-SOC_SINGLE("Mono ZC Switch", WM8753_MOUTV, 7, 1, 0),
+SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0),
 
 SOC_ENUM("Bass Boost", wm8753_enum[0]),
 SOC_ENUM("Bass Filter", wm8753_enum[1]),
@@ -522,25 +517,47 @@ SOC_DPM_ENUM("Route", wm8753_enum[15]);
 static const snd_kcontrol_new_t wm8753_mic_sel_mux_controls =
 SOC_DPM_ENUM("Route", wm8753_enum[25]);
 
+/* LOUT 1 Volume */
+static const snd_kcontrol_new_t wm8753_lout1_vol_controls =
+SOC_DPM_SINGLE("Left Out1 Playback Volume", WM8753_LOUT1V, 0, 127, 0);
+
+/* LOUT 2 Volume */
+static const snd_kcontrol_new_t wm8753_lout2_vol_controls =
+SOC_DPM_SINGLE("Left Out2 Playback Volume", WM8753_LOUT2V, 0, 127, 0);
+
+/* ROUT 1 Volume */
+static const snd_kcontrol_new_t wm8753_rout1_vol_controls =
+SOC_DPM_SINGLE("Right Out1 Playback Volume", WM8753_ROUT1V, 0, 127, 0);
+
+/* ROUT 2 Volume */
+static const snd_kcontrol_new_t wm8753_rout2_vol_controls =
+SOC_DPM_SINGLE("Right Out2 Playback Volume", WM8753_ROUT2V, 0, 127, 0);
+
+/* Mono 1 Volume */
+static const snd_kcontrol_new_t wm8753_mout1_vol_controls =
+SOC_DPM_SINGLE("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0);
+
 static const struct snd_soc_dpm_widget wm8753_dpm_widgets[] = {
 SND_SOC_DPM_CLOCK("WM8753 Clock", WM8753_PWR1, 0, 1),
+SND_SOC_DPM_MUTE("DAC Mute", WM8753_DAC, 3, 0),
+SND_SOC_DPM_MICBIAS("Mic Bias", WM8753_PWR1, 5, 0),
 SND_SOC_DPM_MIXER("Left Mixer", WM8753_PWR4, 0, 0, &wm8753_left_mixer_controls[0], 
 	ARRAY_SIZE(wm8753_left_mixer_controls)),
-SND_SOC_DPM_VOLUME("Left Out 1", WM8753_PWR3, 8, 0, NULL, 0),
-SND_SOC_DPM_VOLUME("Left Out 2", WM8753_PWR3, 6, 0, NULL, 0),
+SND_SOC_DPM_VOLUME("Left Out 1", WM8753_PWR3, 8, 0, &wm8753_lout1_vol_controls, 1),
+SND_SOC_DPM_VOLUME("Left Out 2", WM8753_PWR3, 6, 0, &wm8753_lout2_vol_controls, 1),
 SND_SOC_DPM_DAC("Left DAC", "Left HiFi Playback", WM8753_PWR1, 3, 0, NULL, 0),
 SND_SOC_DPM_OUTPUT("LOUT1"),
 SND_SOC_DPM_OUTPUT("LOUT2"),
 SND_SOC_DPM_MIXER("Right Mixer", WM8753_PWR4, 1, 0, &wm8753_right_mixer_controls[0], 
 	ARRAY_SIZE(wm8753_right_mixer_controls)),
-SND_SOC_DPM_VOLUME("Right Out 1", WM8753_PWR3, 7, 0, NULL, 0),
-SND_SOC_DPM_VOLUME("Right Out 2", WM8753_PWR3, 5, 0, NULL, 0),
+SND_SOC_DPM_VOLUME("Right Out 1", WM8753_PWR3, 7, 0, &wm8753_rout1_vol_controls, 1),
+SND_SOC_DPM_VOLUME("Right Out 2", WM8753_PWR3, 5, 0, &wm8753_rout2_vol_controls, 1),
 SND_SOC_DPM_DAC("Right DAC", "Right HiFi Playback", WM8753_PWR1, 2, 0, NULL, 0),
 SND_SOC_DPM_OUTPUT("ROUT1"),
 SND_SOC_DPM_OUTPUT("ROUT2"),
 SND_SOC_DPM_MIXER("Mono Mixer", WM8753_PWR4, 2, 0, &wm8753_mono_mixer_controls[0], 
 	ARRAY_SIZE(wm8753_mono_mixer_controls)),
-SND_SOC_DPM_VOLUME("Mono Out 1", WM8753_PWR3, 2, 0, NULL, 0),
+SND_SOC_DPM_VOLUME("Mono Out 1", WM8753_PWR3, 2, 0, &wm8753_mout1_vol_controls, 1),
 SND_SOC_DPM_VOLUME("Mono Out 2", WM8753_PWR3, 1, 0, NULL, 0),
 SND_SOC_DPM_DAC("Voice DAC", "Voice Playback", WM8753_PWR1, 4, 0, NULL, 0),
 SND_SOC_DPM_OUTPUT("MONO1"),
@@ -561,7 +578,7 @@ SND_SOC_DPM_MUX("Capture Left Mixer", -1
 SND_SOC_DPM_MUX("Capture Right Mixer", -1, 0, 0, &wm8753_adc_mono_controls),
 SND_SOC_DPM_MUX("Capture Left Mux", -1, 0, 0, &wm8753_adc_left_controls),
 SND_SOC_DPM_MUX("Capture Right Mux", -1, 0, 0, &wm8753_adc_right_controls),
-SND_SOC_DPM_MUX("MIC ST Mux", -1, 0, 0, &wm8753_mic_mux_controls),
+SND_SOC_DPM_MUX("Mic Sidetone Mux", -1, 0, 0, &wm8753_mic_mux_controls),
 SND_SOC_DPM_VOLUME("Left Capture Volume", WM8753_PWR2, 5, 0, NULL, 0),
 SND_SOC_DPM_VOLUME("Right Capture Volume", WM8753_PWR2, 4, 0, NULL, 0),
 SND_SOC_DPM_MIXER("ALC Mixer", WM8753_PWR2, 6, 0, &wm8753_alc_mixer_controls[0], 
@@ -586,170 +603,174 @@ SND_SOC_DPM_INPUT("MIC2N"),
 SND_SOC_DPM_INPUT("MIC2"),
 };
 
-static int wm8753_add_widgets(struct snd_soc_codec *codec)
-{
-	int i;
-	
-	for(i = 0; i < ARRAY_SIZE(wm8753_dpm_widgets); i++) {
-		snd_soc_dpm_new_control(codec, &wm8753_dpm_widgets[i]);
-	}
-	
-	/* set up audio path interconnects */
-	
+static const char* intercon[][3] = {
 	/* left mixer */
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Left Playback Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Voice Playback Switch", "Voice DAC");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Sidetone Playback Switch", "MIC ST Mux");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Bypass Playback Switch", "Line Left Mux");
+	{"Left Mixer", "Left Playback Switch", "Left DAC"},
+	{"Left Mixer", "Voice Playback Switch", "Voice DAC"},
+	{"Left Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},
+	{"Left Mixer", "Bypass Playback Switch", "Line Left Mux"},
 	
 	/* right mixer */
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Right Playback Switch", "Right DAC");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Voice Playback Switch", "Voice DAC");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Sidetone Playback Switch", "MIC ST Mux");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Bypass Playback Switch", "Line Right Mux");
+	{"Right Mixer", "Right Playback Switch", "Right DAC"},
+	{"Right Mixer", "Voice Playback Switch", "Voice DAC"},
+	{"Right Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},
+	{"Right Mixer", "Bypass Playback Switch", "Line Right Mux"},
 	
 	/* mono mixer */
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Voice Playback Switch", "Voice DAC");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Left Playback Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Right Playback Switch", "Right DAC");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Sidetone Playback Switch", "MIC ST Mux");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Bypass Playback Switch", "Line Mono Mux");
+	{"Mono Mixer", "Voice Playback Switch", "Voice DAC"},
+	{"Mono Mixer", "Left Playback Switch", "Left DAC"},
+	{"Mono Mixer", "Right Playback Switch", "Right DAC"},
+	{"Mono Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},
+	{"Mono Mixer", "Bypass Playback Switch", "Line Mono Mux"},
 	
 	/* left out */
-	snd_soc_dpm_connect_input(codec, "Left Out 1", NULL, "Left Mixer");
-	snd_soc_dpm_connect_input(codec, "Left Out 2", NULL, "Left Mixer");
-	snd_soc_dpm_connect_input(codec, "LOUT1", NULL, "Left Out 1");
-	snd_soc_dpm_connect_input(codec, "LOUT2", NULL, "Left Out 2");
+	{"Left Out 1", NULL, "Left Mixer"},
+	{"Left Out 2", NULL, "Left Mixer"},
+	{"LOUT1", NULL, "Left Out 1"},
+	{"LOUT2", NULL, "Left Out 2"},
 
 	/* right out */
-	snd_soc_dpm_connect_input(codec, "Right Out 1", NULL, "Right Mixer");
-	snd_soc_dpm_connect_input(codec, "Right Out 2", NULL, "Right Mixer");
-	snd_soc_dpm_connect_input(codec, "ROUT1", NULL, "Right Out 1");
-	snd_soc_dpm_connect_input(codec, "ROUT2", NULL, "Right Out 2");
+	{"Right Out 1", NULL, "Right Mixer"},
+	{"Right Out 2", NULL, "Right Mixer"},
+	{"ROUT1", NULL, "Right Out 1"},
+	{"ROUT2", NULL, "Right Out 2"},
 	
 	/* mono 1 out */
-	snd_soc_dpm_connect_input(codec, "Mono Out 1", NULL, "Mono Mixer");
-	snd_soc_dpm_connect_input(codec, "MONO1", NULL, "Mono Out 1");
+	{"Mono Out 1", NULL, "Mono Mixer"},
+	{"MONO1", NULL, "Mono Out 1"},
 	
 	/* mono 2 out */
-	snd_soc_dpm_connect_input(codec, "Mono 2 Mux", "Left + Right", "Out3 Left + Right");
-	snd_soc_dpm_connect_input(codec, "Mono 2 Mux", "Inverted Mono 1", "MONO1");
-	snd_soc_dpm_connect_input(codec, "Mono 2 Mux", "Left", "Left Mixer");
-	snd_soc_dpm_connect_input(codec, "Mono 2 Mux", "Right", "Right Mixer");
-	snd_soc_dpm_connect_input(codec, "Mono Out 2", NULL, "Mono 2 Mux");
-	snd_soc_dpm_connect_input(codec, "MONO2", NULL, "Mono Out 2");
+	{"Mono 2 Mux", "Left + Right", "Out3 Left + Right"},
+	{"Mono 2 Mux", "Inverted Mono 1", "MONO1"},
+	{"Mono 2 Mux", "Left", "Left Mixer"},
+	{"Mono 2 Mux", "Right", "Right Mixer"},
+	{"Mono Out 2", NULL, "Mono 2 Mux"},
+	{"MONO2", NULL, "Mono Out 2"},
 	
 	/* out 3 */
-	snd_soc_dpm_connect_input(codec, "Out3 Left + Right", NULL, "Left Mixer");
-	snd_soc_dpm_connect_input(codec, "Out3 Left + Right", NULL, "Right Mixer");
-	snd_soc_dpm_connect_input(codec, "Out3 Mux", "VREF", "VREF");
-	snd_soc_dpm_connect_input(codec, "Out3 Mux", "Left + Right", "Out3 Left + Right");
-	snd_soc_dpm_connect_input(codec, "Out3 Mux", "ROUT2", "ROUT2");
-	snd_soc_dpm_connect_input(codec, "Out 3", NULL, "Out3 Mux");
-	snd_soc_dpm_connect_input(codec, "OUT3", NULL, "Out 3");
+	{"Out3 Left + Right", NULL, "Left Mixer"},
+	{"Out3 Left + Right", NULL, "Right Mixer"},
+	{"Out3 Mux", "VREF", "VREF"},
+	{"Out3 Mux", "Left + Right", "Out3 Left + Right"},
+	{"Out3 Mux", "ROUT2", "ROUT2"},
+	{"Out 3", NULL, "Out3 Mux"},
+	{"OUT3", NULL, "Out 3"},
 	
 	/* out 4 */
-	snd_soc_dpm_connect_input(codec, "Out4 Mux", "VREF", "VREF");
-	snd_soc_dpm_connect_input(codec, "Out4 Mux", "Capture ST", "Capture ST Mixer");
-	snd_soc_dpm_connect_input(codec, "Out4 Mux", "LOUT2", "LOUT2");
-	snd_soc_dpm_connect_input(codec, "Out 4", NULL, "Out4 Mux");
-	snd_soc_dpm_connect_input(codec, "OUT4", NULL, "Out 4");
+	{"Out4 Mux", "VREF", "VREF"},
+	{"Out4 Mux", "Capture ST", "Capture ST Mixer"},
+	{"Out4 Mux", "LOUT2", "LOUT2"},
+	{"Out 4", NULL, "Out4 Mux"},
+	{"OUT4", NULL, "Out 4"},
 	
 	/* record mixer  */
-	snd_soc_dpm_connect_input(codec, "Playback Mixer", "Left Capture Switch", "Left Mixer");
-	snd_soc_dpm_connect_input(codec, "Playback Mixer", "Voice Capture Switch", "Mono Mixer");
-	snd_soc_dpm_connect_input(codec, "Playback Mixer", "Right Capture Switch", "Right Mixer");
+	{"Playback Mixer", "Left Capture Switch", "Left Mixer"},
+	{"Playback Mixer", "Voice Capture Switch", "Mono Mixer"},
+	{"Playback Mixer", "Right Capture Switch", "Right Mixer"},
 	
 	/* Mic/SideTone Mux */
-	snd_soc_dpm_connect_input(codec, "Mic Mux", "Left PGA", "Left Capture Volume");
-	snd_soc_dpm_connect_input(codec, "Mic Mux", "Right PGA", "Right Capture Volume");
-	snd_soc_dpm_connect_input(codec, "Mic Mux", "Mic 1", "Mic 1 Volume");
-	snd_soc_dpm_connect_input(codec, "Mic Mux", "Mic 2", "Mic 2 Volume");
+	{"Mic Sidetone Mux", "Left PGA", "Left Capture Volume"},
+	{"Mic Sidetone Mux", "Right PGA", "Right Capture Volume"},
+	{"Mic Sidetone Mux", "Mic 1", "Mic 1 Volume"},
+	{"Mic Sidetone Mux", "Mic 2", "Mic 2 Volume"},
 	
 	/* Capture Left Mux */
-	snd_soc_dpm_connect_input(codec, "Capture Left Mux", "PGA", "Left Capture Volume");
-	snd_soc_dpm_connect_input(codec, "Capture Left Mux", "Line or RXP-RXN", "Line Left Mux");
-	snd_soc_dpm_connect_input(codec, "Capture Left Mux", "Line", "LINE1");
+	{"Capture Left Mux", "PGA", "Left Capture Volume"},
+	{"Capture Left Mux", "Line or RXP-RXN", "Line Left Mux"},
+	{"Capture Left Mux", "Line", "LINE1"},
 	
 	/* Capture Right Mux */
-	snd_soc_dpm_connect_input(codec, "Capture Right Mux", "PGA", "Right Capture Volume");
-	snd_soc_dpm_connect_input(codec, "Capture Right Mux", "Line or RXP-RXN", "Line Right Mux");
-	snd_soc_dpm_connect_input(codec, "Capture Right Mux", "Sidetone", "Capture ST Mixer");
+	{"Capture Right Mux", "PGA", "Right Capture Volume"},
+	{"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"},
+	{"Capture Right Mux", "Sidetone", "Capture ST Mixer"},
 	
 	/* Mono Capture mixer-mux */
-	snd_soc_dpm_connect_input(codec, "Capture Right Mixer", "Stereo", "Capture Right Mux");
-	snd_soc_dpm_connect_input(codec, "Capture Left Mixer", "Analogue Mix Left", "Capture Left Mux");
-	snd_soc_dpm_connect_input(codec, "Capture Left Mixer", "Analogue Mix Left", "Capture Right Mux");
-	snd_soc_dpm_connect_input(codec, "Capture Right Mixer", "Analogue Mix Right", "Capture Left Mux");
-	snd_soc_dpm_connect_input(codec, "Capture Right Mixer", "Analogue Mix Right", "Capture Right Mux");
-	snd_soc_dpm_connect_input(codec, "Capture Left Mixer", "Digital Mono Mix", "Capture Left Mux");
-	snd_soc_dpm_connect_input(codec, "Capture Left Mixer", "Digital Mono Mix", "Capture Right Mux");
-	snd_soc_dpm_connect_input(codec, "Capture Right Mixer", "Digital Mono Mix", "Capture Left Mux");
-	snd_soc_dpm_connect_input(codec, "Capture Right Mixer", "Digital Mono Mix", "Capture Right Mux");
+	{"Capture Right Mixer", "Stereo", "Capture Right Mux"},
+	{"Capture Left Mixer", "Analogue Mix Left", "Capture Left Mux"},
+	{"Capture Left Mixer", "Analogue Mix Left", "Capture Right Mux"},
+	{"Capture Right Mixer", "Analogue Mix Right", "Capture Left Mux"},
+	{"Capture Right Mixer", "Analogue Mix Right", "Capture Right Mux"},
+	{"Capture Left Mixer", "Digital Mono Mix", "Capture Left Mux"},
+	{"Capture Left Mixer", "Digital Mono Mix", "Capture Right Mux"},
+	{"Capture Right Mixer", "Digital Mono Mix", "Capture Left Mux"},
+	{"Capture Right Mixer", "Digital Mono Mix", "Capture Right Mux"},
 	
 	/* ADC */
-	snd_soc_dpm_connect_input(codec, "Left ADC", NULL, "Capture Left Mixer");
-	snd_soc_dpm_connect_input(codec, "Right ADC", NULL, "Capture Right Mixer");
+	{"Left ADC", NULL, "Capture Left Mixer"},
+	{"Right ADC", NULL, "Capture Right Mixer"},
 
 	/* Left Capture Volume */
-	snd_soc_dpm_connect_input(codec, "Left Capture Volume", NULL, "ACIN");
+	{"Left Capture Volume", NULL, "ACIN"},
 	
 	/* Right Capture Volume */
-	snd_soc_dpm_connect_input(codec, "Right Capture Volume", NULL, "Mic 2 Volume");
+	{"Right Capture Volume", NULL, "Mic 2 Volume"},
 
 	/* ALC Mixer */
-	snd_soc_dpm_connect_input(codec, "ALC Mixer", "Line Capture Switch", "Line Mixer");
-	snd_soc_dpm_connect_input(codec, "ALC Mixer", "Mic2 Capture Switch", "Mic 2 Volume");
-	snd_soc_dpm_connect_input(codec, "ALC Mixer", "Mic1 Capture Switch", "Mic 1 Volume");
-	snd_soc_dpm_connect_input(codec, "ALC Mixer", "Rx Capture Switch", "Rx Mixer");
+	{"ALC Mixer", "Line Capture Switch", "Line Mixer"},
+	{"ALC Mixer", "Mic2 Capture Switch", "Mic 2 Volume"},
+	{"ALC Mixer", "Mic1 Capture Switch", "Mic 1 Volume"},
+	{"ALC Mixer", "Rx Capture Switch", "Rx Mixer"},
 	
 	/* Line Left Mux */
-	snd_soc_dpm_connect_input(codec, "Line Left Mux", "Line 1", "LINE1");
-	snd_soc_dpm_connect_input(codec, "Line Left Mux", "Rx Mix", "Rx Mixer");
+	{"Line Left Mux", "Line 1", "LINE1"},
+	{"Line Left Mux", "Rx Mix", "Rx Mixer"},
 	
 	/* Line Right Mux */
-	snd_soc_dpm_connect_input(codec, "Line Right Mux", "Line 2", "LINE2");
-	snd_soc_dpm_connect_input(codec, "Line Right Mux", "Rx Mix", "Rx Mixer");
+	{"Line Right Mux", "Line 2", "LINE2"},
+	{"Line Right Mux", "Rx Mix", "Rx Mixer"},
 	
 	/* Line Mono Mux */
-	snd_soc_dpm_connect_input(codec, "Line Mono Mux", "Line Mix", "Line Mixer");
-	snd_soc_dpm_connect_input(codec, "Line Mono Mux", "Rx Mix", "Rx Mixer");
+	{"Line Mono Mux", "Line Mix", "Line Mixer"},
+	{"Line Mono Mux", "Rx Mix", "Rx Mixer"},
 	
 	/* Line Mixer/Mux */
-	snd_soc_dpm_connect_input(codec, "Line Mixer", "Line 1 + 2", "LINE1");
-	snd_soc_dpm_connect_input(codec, "Line Mixer", "Line 1 - 2", "LINE1");
-	snd_soc_dpm_connect_input(codec, "Line Mixer", "Line 1 + 2", "LINE2");
-	snd_soc_dpm_connect_input(codec, "Line Mixer", "Line 1 - 2", "LINE2");
-	snd_soc_dpm_connect_input(codec, "Line Mixer", "Line 1", "LINE1");
-	snd_soc_dpm_connect_input(codec, "Line Mixer", "Line 2", "LINE2");
+	{"Line Mixer", "Line 1 + 2", "LINE1"},
+	{"Line Mixer", "Line 1 - 2", "LINE1"},
+	{"Line Mixer", "Line 1 + 2", "LINE2"},
+	{"Line Mixer", "Line 1 - 2", "LINE2"},
+	{"Line Mixer", "Line 1", "LINE1"},
+	{"Line Mixer", "Line 2", "LINE2"},
 	
 	/* Rx Mixer/Mux */
-	snd_soc_dpm_connect_input(codec, "Rx Mixer", "RXP - RXN", "RXP");
-	snd_soc_dpm_connect_input(codec, "Rx Mixer", "RXP + RXN", "RXP");
-	snd_soc_dpm_connect_input(codec, "Rx Mixer", "RXP - RXN", "RXN");
-	snd_soc_dpm_connect_input(codec, "Rx Mixer", "RXP + RXN", "RXN");
-	snd_soc_dpm_connect_input(codec, "Rx Mixer", "RXP", "RXP");
-	snd_soc_dpm_connect_input(codec, "Rx Mixer", "RXN", "RXN");
+	{"Rx Mixer", "RXP - RXN", "RXP"},
+	{"Rx Mixer", "RXP + RXN", "RXP"},
+	{"Rx Mixer", "RXP - RXN", "RXN"},
+	{"Rx Mixer", "RXP + RXN", "RXN"},
+	{"Rx Mixer", "RXP", "RXP"},
+	{"Rx Mixer", "RXN", "RXN"},
 	
 	/* Mic 1 Volume */
-	snd_soc_dpm_connect_input(codec, "Mic 1 Volume", NULL, "MIC1N");
-	snd_soc_dpm_connect_input(codec, "Mic 1 Volume", NULL, "Mic Selection Mux");
+	{"Mic 1 Volume", NULL, "MIC1N"},
+	{"Mic 1 Volume", NULL, "Mic Selection Mux"},
 	
 	/* Mic 2 Volume */
-	snd_soc_dpm_connect_input(codec, "Mic 2 Volume", NULL, "MIC2N");
-	snd_soc_dpm_connect_input(codec, "Mic 2 Volume", NULL, "MIC2");
+	{"Mic 2 Volume", NULL, "MIC2N"},
+	{"Mic 2 Volume", NULL, "MIC2"},
 	
 	/* Mic Selector Mux */
-	snd_soc_dpm_connect_input(codec, "Mic Selection Mux", "Mic 1", "MIC1");
-	snd_soc_dpm_connect_input(codec, "Mic Selection Mux", "Mic 2", "MIC2N");
-	snd_soc_dpm_connect_input(codec, "Mic Selection Mux", "Mic 3", "MIC2");
+	{"Mic Selection Mux", "Mic 1", "MIC1"},
+	{"Mic Selection Mux", "Mic 2", "MIC2N"},
+	{"Mic Selection Mux", "Mic 3", "MIC2"},
 	
 	/* ACOP */
-	snd_soc_dpm_connect_input(codec, "ACOP", NULL, "ALC Mixer");
+	{"ACOP", NULL, "ALC Mixer"},
+	
+	/* terminator */
+	{NULL, NULL, NULL},
+};
+
+static int wm8753_add_widgets(struct snd_soc_codec *codec)
+{
+	int i;
+	
+	for(i = 0; i < ARRAY_SIZE(wm8753_dpm_widgets); i++) {
+		snd_soc_dpm_new_control(codec, &wm8753_dpm_widgets[i]);
+	}
 	
-	/* ACIN --> ACOP */
-	// liam - make this a mod param OR better still machine layer
-	snd_soc_dpm_connect_input(codec, "ACIN", NULL, "ACOP");
+	/* set up audio path interconnects */
+	for(i = 0; intercon[i][0] != NULL; i++) {
+		snd_soc_dpm_connect_input(codec, intercon[i][0], intercon[i][1], intercon[i][2]);
+	}
 	
 	snd_soc_dpm_sync(codec);
 	return 0;
@@ -1025,13 +1046,11 @@ static void wm8753_device_release(struct
 static int wm8753_dpm_event(struct snd_soc_codec *codec, int event)
 {
 	u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3f;
-	u16 dac_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7;
 
 	switch (event) {
 		case SNDRV_CTL_POWER_D0: /* full On */
 			/* set vmid to 50k and unmute dac */
 			wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);
-			wm8753_write(codec, WM8753_DAC, dac_reg);
 			break;
 		case SNDRV_CTL_POWER_D1: /* partial On */
 		case SNDRV_CTL_POWER_D2: /* partial On */
@@ -1040,11 +1059,9 @@ static int wm8753_dpm_event(struct snd_s
 			break;
 		case SNDRV_CTL_POWER_D3hot: /* Off, with power */
 			/* mute dac and set vmid to 500k, enable VREF */
-			wm8753_write(codec, WM8753_DAC, dac_reg | 0x0008);
 			wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0140);
 			break;
 		case SNDRV_CTL_POWER_D3cold: /* Off, without power */
-			wm8753_write(codec, WM8753_DAC, dac_reg | 0x0008);
 			wm8753_write(codec, WM8753_PWR1, 0x0001);
 			break;
 	}
@@ -1105,9 +1122,9 @@ static int wm8753_probe(struct snd_soc_c
 
 	wm8753_reset(codec);
 	
-	/* set vmid to 500k - low power standy */
-	wm8753_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
-
+	/* charge output caps */
+	wm8753_dpm_event(codec, SNDRV_CTL_POWER_D2);
+	
 	/* set the update bits */
 	reg = wm8753_read_reg_cache(codec, WM8753_LDAC);
 	wm8753_write(codec, WM8753_LDAC, reg | 0x0100);
@@ -1128,6 +1145,10 @@ static int wm8753_probe(struct snd_soc_c
 
 	wm8753_add_controls(codec);
 	wm8753_add_widgets(codec);
+	
+	/* wait for caps to finish charging - liam make this thread */
+	ssleep(1);
+	wm8753_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
 
 	return 0;
 }
@@ -1148,6 +1169,7 @@ static int wm8753_i2c_probe(struct i2c_a
 {		
 	int ret = 0;
 	struct snd_soc_codec *codec;
+	struct i2c_client *i2c;
 
 	client_template.adapter = adap;
 	client_template.addr = addr;
@@ -1155,11 +1177,19 @@ static int wm8753_i2c_probe(struct i2c_a
 	if ((codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
  
-	memcpy(&codec->i2c, &client_template, sizeof(struct i2c_client));
+	if ((i2c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL)) == NULL){
+		kfree(codec);
+		return -ENOMEM;
+	}
+	memcpy(i2c, &client_template, sizeof(struct i2c_client));
+	codec->control_data = i2c;
+	i2c->dev.platform_data = codec;
 
-	if((ret = i2c_attach_client(&codec->i2c)) < 0) {
+	if((ret = i2c_attach_client(i2c)) < 0) {
 		err("failed to attach codec at addr %x\n", addr);
+		kfree(i2c);
 		kfree(codec);
+		return ret;
 	}
 
 	codec->name = "WM8753";
@@ -1183,6 +1213,7 @@ static int wm8753_i2c_probe(struct i2c_a
 	if((ret = snd_soc_register_codec(codec)) < 0) {
 		err("can't register codec");
 		i2c_del_driver(&wm8753_i2c_driver);
+		kfree(i2c);
 		kfree(codec->reg_cache);
 		kfree(codec);
 	}
@@ -1192,7 +1223,8 @@ static int wm8753_i2c_probe(struct i2c_a
 
 static int wm8753_i2c_detach(struct i2c_client *client)
 {
-	struct snd_soc_codec *codec = container_of(client, struct snd_soc_codec, i2c);
+	struct snd_soc_codec *codec = 
+		(struct snd_soc_codec*)client->dev.platform_data;
 
 	i2c_detach_client(client);
 	snd_soc_unregister_codec(codec);
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index f5c6fcb..44ab8c2 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -174,6 +174,7 @@ static int wm8971_write(struct snd_soc_c
 	unsigned int value)
 {
 	u8 data[2];
+	struct i2c_client *i2c = (struct i2c_client*)codec->control_data;
 
 	/* D15..D9 is WM8971 register offset, D8..D0 is register data */
 	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
@@ -181,7 +182,7 @@ static int wm8971_write(struct snd_soc_c
 
 	wm8971_write_reg_cache (codec, reg, value);
 
-	return (i2c_master_send(&codec->i2c, data, 2) == 2) ? 0 : -1;
+	return (i2c_master_send(i2c, data, 2) == 2) ? 0 : -1;
 }
 
 #define wm8971_reset(c)	wm8971_write(c, WM8971_RESET, 0)
@@ -226,15 +227,11 @@ static const snd_kcontrol_new_t wm8971_s
 	SOC_SINGLE("Left ADC Capture Volume", WM8971_LADC, 0, 255, 0),
 	SOC_SINGLE("Right ADC Capture Volume", WM8971_RADC, 0, 255, 0),
 
-	SOC_SINGLE("Left Out1 Playback Volume", WM8971_LOUT1V, 0, 127, 0),
 	SOC_SINGLE("Left Out1 Playback ZC Switch", WM8971_LOUT1V, 7, 1, 0),
-	SOC_SINGLE("Left Out2 Playback Volume", WM8971_LOUT2V, 0, 127, 0),
 	SOC_SINGLE("Left Out2 Playback ZC Switch", WM8971_LOUT2V, 7, 1, 0),
-
-	SOC_SINGLE("Right Out 1 Volume", WM8971_ROUT1V, 0, 127, 0),
-	SOC_SINGLE("Right Out 1 ZC Switch", WM8971_ROUT1V, 7, 1, 0),
-	SOC_SINGLE("Right Out 2 Volume", WM8971_ROUT2V, 0, 127, 0),
-	SOC_SINGLE("Right Out 2 ZC Switch", WM8971_ROUT2V, 7, 1, 0),
+	
+	SOC_SINGLE("Right Out1 Playback ZC Switch", WM8971_ROUT1V, 7, 1, 0),
+	SOC_SINGLE("Right Out2 Playback ZC Switch", WM8971_ROUT2V, 7, 1, 0),
 
 	SOC_SINGLE("Left Bypass Left Playback Volume", WM8971_LOUTM1, 4, 7, 1),
 	SOC_SINGLE("Right Bypass Left Playback Volume", WM8971_LOUTM2, 4, 7, 1),
@@ -245,7 +242,6 @@ static const snd_kcontrol_new_t wm8971_s
 	SOC_SINGLE("Left Bypass Mono Playback Volume", WM8971_MOUTM1, 4, 7, 1),
 	SOC_SINGLE("Right Bypass Mono Playback Volume", WM8971_MOUTM2, 4, 7, 1), 
 
-	SOC_SINGLE("Mono Playback Volume", WM8971_MOUTV, 0, 127, 0),
 	SOC_SINGLE("Mono Playback ZC Switch", WM8971_MOUTV, 7, 1, 0),
 
 	SOC_ENUM("Bass Boost", wm8971_enum[0]),
@@ -352,21 +348,42 @@ SOC_DPM_ENUM("Route", wm8971_enum[11]);
 static const snd_kcontrol_new_t wm8971_monomux_controls =
 SOC_DPM_ENUM("Route", wm8971_enum[13]);
 
+/* LOUT 1 Volume */
+static const snd_kcontrol_new_t wm8971_lout1_vol_controls =
+SOC_DPM_SINGLE("Left Out1 Playback Volume", WM8971_LOUT1V, 0, 127, 0);
+
+/* ROUT 1 Volume */
+static const snd_kcontrol_new_t wm8971_rout1_vol_controls =
+SOC_DPM_SINGLE("Right Out1 Playback Volume", WM8971_ROUT1V, 0, 127, 0);
+
+/* LOUT 2 Volume */
+static const snd_kcontrol_new_t wm8971_lout2_vol_controls =
+SOC_DPM_SINGLE("Left Out2 Playback Volume", WM8971_LOUT2V, 0, 127, 0);
+
+/* ROUT 2 Volume */
+static const snd_kcontrol_new_t wm8971_rout2_vol_controls =
+SOC_DPM_SINGLE("Right Out2 Playback Volume", WM8971_ROUT2V, 0, 127, 0);
+
+/* Mono Volume */
+static const snd_kcontrol_new_t wm8971_mout_vol_controls =
+SOC_DPM_SINGLE("Mono Playback Volume", WM8971_MOUTV, 0, 127, 0);
 
 static const struct snd_soc_dpm_widget wm8971_dpm_widgets[] = {
 	SND_SOC_DPM_CLOCK("WM8971 Clock", WM8971_PWR1, 0, 1),
+	SND_SOC_DPM_MUTE("DAC Mute", WM8971_ADCDAC, 3, 0),
 	SND_SOC_DPM_MIXER("Left Mixer", -1, 0, 0, &wm8971_left_mixer_controls[0], ARRAY_SIZE(wm8971_left_mixer_controls)),
 	SND_SOC_DPM_MIXER("Right Mixer", -1, 0, 0, &wm8971_right_mixer_controls[0], ARRAY_SIZE(wm8971_right_mixer_controls)),
 	SND_SOC_DPM_MIXER("Mono Mixer", WM8971_PWR2, 2, 0, &wm8971_mono_mixer_controls[0], ARRAY_SIZE(wm8971_mono_mixer_controls)),
 
-	SND_SOC_DPM_VOLUME("Right Out 2", WM8971_PWR2, 3, 0, NULL, 0),
-	SND_SOC_DPM_VOLUME("Left Out 2", WM8971_PWR2, 4, 0, NULL, 0),
-	SND_SOC_DPM_VOLUME("Right Out 1", WM8971_PWR2, 5, 0, NULL, 0),
-	SND_SOC_DPM_VOLUME("Left Out 1", WM8971_PWR2, 6, 0, NULL, 0),
+	SND_SOC_DPM_VOLUME("Right Out 2", WM8971_PWR2, 3, 0, &wm8971_rout2_vol_controls, 1),
+	SND_SOC_DPM_VOLUME("Left Out 2", WM8971_PWR2, 4, 0, &wm8971_lout2_vol_controls, 1),
+	SND_SOC_DPM_VOLUME("Right Out 1", WM8971_PWR2, 5, 0, &wm8971_rout1_vol_controls, 1),
+	SND_SOC_DPM_VOLUME("Left Out 1", WM8971_PWR2, 6, 0, &wm8971_lout1_vol_controls, 1),
 	SND_SOC_DPM_DAC("Right DAC", "Right Playback", WM8971_PWR2, 7, 0, NULL, 0),
 	SND_SOC_DPM_DAC("Left DAC", "Left Playback", WM8971_PWR2, 8, 0, NULL, 0),
-
-	//"Mic Bias", WM8971_PWR1, 1, 0
+	SND_SOC_DPM_VOLUME("Mono Out 1", WM8971_PWR2, 2, 0, &wm8971_mout_vol_controls, 1),
+	
+	SND_SOC_DPM_MICBIAS("Mic Bias", WM8971_PWR1, 1, 0),
 	SND_SOC_DPM_ADC("Right ADC", "Right Capture", WM8971_PWR1, 2, 0, NULL, 0),
 	SND_SOC_DPM_ADC("Left ADC", "Left Capture", WM8971_PWR1, 3, 0, NULL, 0),
 
@@ -389,89 +406,99 @@ static const struct snd_soc_dpm_widget w
 	SND_SOC_DPM_INPUT("MIC"),
 };
 
-static int wm8971_add_widgets(struct snd_soc_codec *codec)
-{
-	int i;
-	
-	for(i = 0; i < ARRAY_SIZE(wm8971_dpm_widgets); i++) {
-		snd_soc_dpm_new_control(codec, &wm8971_dpm_widgets[i]);
-	}
-	
+static const char* intercon[][3] = {
 	/* left mixer */
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Playback Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Left Bypass Switch", "Left Line Mux");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Right Playback Switch", "Right DAC");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Right Bypass Switch", "Right Line Mux");
+	{"Left Mixer", "Playback Switch", "Left DAC"},
+	{"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Left Mixer", "Right Playback Switch", "Right DAC"},
+	{"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
 
 	/* right mixer */
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Left Playback Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Left Bypass Switch", "Left Line Mux");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Playback Switch", "Right DAC");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Right Bypass Switch", "Right Line Mux");
+	{"Right Mixer", "Left Playback Switch", "Left DAC"},
+	{"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Right Mixer", "Playback Switch", "Right DAC"},
+	{"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
 
 	/* left out 1 */
-	snd_soc_dpm_connect_input(codec, "Left Out 1", NULL, "Left Mixer");
-	snd_soc_dpm_connect_input(codec, "LOUT1", NULL, "Left Out 1");
+	{"Left Out 1", NULL, "Left Mixer"},
+	{"LOUT1", NULL, "Left Out 1"},
 
 	/* left out 2 */
-	snd_soc_dpm_connect_input(codec, "Left Out 2", NULL, "Left Mixer");
-	snd_soc_dpm_connect_input(codec, "LOUT2", NULL, "Left Out 2");
+	{"Left Out 2", NULL, "Left Mixer"},
+	{"LOUT2", NULL, "Left Out 2"},
 	
 	/* right out 1 */
-	snd_soc_dpm_connect_input(codec, "Right Out 1", NULL, "Right Mixer");
-	snd_soc_dpm_connect_input(codec, "ROUT1", NULL, "Right Out 1");
+	{"Right Out 1", NULL, "Right Mixer"},
+	{"ROUT1", NULL, "Right Out 1"},
 
 	/* right out 2 */
-	snd_soc_dpm_connect_input(codec, "Right Out 2", NULL, "Right Mixer");
-	snd_soc_dpm_connect_input(codec, "ROUT2", NULL, "Right Out 2");
+	{"Right Out 2", NULL, "Right Mixer"},
+	{"ROUT2", NULL, "Right Out 2"},
 
 	/* mono mixer */
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Left Playback Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Left Bypass Switch", "Left Line Mux");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Right Playback Switch", "Right DAC");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Right Bypass Switch", "Right Line Mux");
+	{"Mono Mixer", "Left Playback Switch", "Left DAC"},
+	{"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Mono Mixer", "Right Playback Switch", "Right DAC"},
+	{"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
 	
 	/* mono out */
-	snd_soc_dpm_connect_input(codec, "Mono Out", NULL, "Mono Mixer");
-	snd_soc_dpm_connect_input(codec, "MONO1", NULL, "Mono Out");
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONO1", NULL, "Mono Out"},
 
 	/* Left Line Mux */
-	snd_soc_dpm_connect_input(codec, "Left Line Mux", "Line", "LINPUT1");
-	snd_soc_dpm_connect_input(codec, "Left Line Mux", "PGA", "Left PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Left Line Mux", "Differential", "Differential Mux");
+	{"Left Line Mux", "Line", "LINPUT1"},
+	{"Left Line Mux", "PGA", "Left PGA Mux"},
+	{"Left Line Mux", "Differential", "Differential Mux"},
 
 	/* Right Line Mux */
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Line", "RINPUT1");
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Mic", "MIC");
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "PGA", "Right PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Differential", "Differential Mux");
+	{"Right Line Mux", "Line", "RINPUT1"},
+	{"Right Line Mux", "Mic", "MIC"},
+	{"Right Line Mux", "PGA", "Right PGA Mux"},
+	{"Right Line Mux", "Differential", "Differential Mux"},
 
 	/* Left PGA Mux */
-	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Line", "LINPUT1");
-	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Differential", "Differential Mux");
+	{"Left PGA Mux", "Line", "LINPUT1"},
+	{"Left PGA Mux", "Differential", "Differential Mux"},
 
 	/* Right PGA Mux */
-	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Line", "RINPUT1");
-	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Differential", "Differential Mux");
+	{"Right PGA Mux", "Line", "RINPUT1"},
+	{"Right PGA Mux", "Differential", "Differential Mux"},
 
 	/* Differential Mux */
-	snd_soc_dpm_connect_input(codec, "Differential Mux", "Line", "LINPUT1");
-	snd_soc_dpm_connect_input(codec, "Differential Mux", "Line", "RINPUT1");
+	{"Differential Mux", "Line", "LINPUT1"},
+	{"Differential Mux", "Line", "RINPUT1"},
 
 	/* Left ADC Mux */
-	snd_soc_dpm_connect_input(codec, "Left ADC Mux", "Stereo", "Left PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Left ADC Mux", "Mono (Left)", "Left PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Left ADC Mux", "Digital Mono", "Left PGA Mux");
+	{"Left ADC Mux", "Stereo", "Left PGA Mux"},
+	{"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
+	{"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
 
 	/* Right ADC Mux */
-	snd_soc_dpm_connect_input(codec, "Right ADC Mux", "Stereo", "Right PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Right ADC Mux", "Mono (Right)", "Right PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Right ADC Mux", "Digital Mono", "Right PGA Mux");
+	{"Right ADC Mux", "Stereo", "Right PGA Mux"},
+	{"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
+	{"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
 
 	/* ADC */
-	snd_soc_dpm_connect_input(codec, "Left ADC", NULL, "Left ADC Mux");
-	snd_soc_dpm_connect_input(codec, "Right ADC", NULL, "Right ADC Mux");
+	{"Left ADC", NULL, "Left ADC Mux"},
+	{"Right ADC", NULL, "Right ADC Mux"},
+
+	/* terminator */
+	{NULL, NULL, NULL},
+};
 
+static int wm8971_add_widgets(struct snd_soc_codec *codec)
+{
+	int i;
+	
+	for(i = 0; i < ARRAY_SIZE(wm8971_dpm_widgets); i++) {
+		snd_soc_dpm_new_control(codec, &wm8971_dpm_widgets[i]);
+	}
+	
+	/* set up audio path interconnects */
+	for(i = 0; intercon[i][0] != NULL; i++) {
+		snd_soc_dpm_connect_input(codec, intercon[i][0], intercon[i][1], intercon[i][2]);
+	}
+	
 	snd_soc_dpm_sync(codec);
 	return 0;
 }
@@ -485,7 +512,7 @@ static int wm8971_pcm_prepare(snd_pcm_su
 	/* set master/slave audio interface */
 	switch(pcm_c->hw_runtime.hformat & SND_SOC_CLOCK_MASK) {
 		case SND_SOC_HWFMT_CBM_CFM:
-			iface |= 0x0020;
+			iface |= 0x0040;
 			break;
 		case SND_SOC_HWFMT_CBS_CFS:
 			break;
@@ -554,13 +581,11 @@ static void wm8971_device_release(struct
 static int wm8971_dpm_event(struct snd_soc_codec *codec, int event)
 {
 	u16 pwr_reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3f;
-	u16 dac_reg = wm8971_read_reg_cache(codec, WM8971_ADCDAC) & 0xfff7;
 
 	switch (event) {
 		case SNDRV_CTL_POWER_D0: /* full On */
 			/* set vmid to 50k and unmute dac */
 			wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x00c0);
-			wm8971_write(codec, WM8971_ADCDAC, dac_reg);
 			break;
 		case SNDRV_CTL_POWER_D1: /* partial On */
 		case SNDRV_CTL_POWER_D2: /* partial On */
@@ -569,11 +594,9 @@ static int wm8971_dpm_event(struct snd_s
 			break;
 		case SNDRV_CTL_POWER_D3hot: /* Off, with power */
 			/* mute dac and set vmid to 500k, enable VREF */
-			wm8971_write(codec, WM8971_ADCDAC, dac_reg | 0x0008);
 			wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
 			break;
 		case SNDRV_CTL_POWER_D3cold: /* Off, without power */
-			wm8971_write(codec, WM8971_ADCDAC, dac_reg | 0x0008);
 			wm8971_write(codec, WM8971_PWR1, 0x0000);
 			break;
 	}
@@ -621,8 +644,8 @@ static int wm8971_probe(struct snd_soc_c
 	/* reset the WM8971 */
 	wm8971_reset(codec);
 
-	/* power up */
-	wm8971_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
+	/* charge output caps */
+	wm8971_dpm_event(codec, SNDRV_CTL_POWER_D2);
 
 	/* set the update bits */
 	reg = wm8971_read_reg_cache(codec, WM8971_LDAC);
@@ -647,6 +670,10 @@ static int wm8971_probe(struct snd_soc_c
 
 	wm8971_add_controls(codec);
 	wm8971_add_widgets(codec);
+	
+	/* wait for caps to finish charging - liam make this thread */
+	ssleep(1);
+	wm8971_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
 
 	return 0;
 }
@@ -665,18 +692,27 @@ static int wm8971_i2c_probe(struct i2c_a
 {		
 	int ret = 0;
 	struct snd_soc_codec *codec;
-
+	struct i2c_client *i2c;
+		
 	client_template.adapter = adap;
 	client_template.addr = addr;
 	
 	if ((codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
  
-	memcpy(&codec->i2c, &client_template, sizeof(struct i2c_client));
+	if ((i2c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL)) == NULL){
+		kfree(codec);
+		return -ENOMEM;
+	}
+	memcpy(i2c, &client_template, sizeof(struct i2c_client));
+	codec->control_data = i2c;
+	i2c->dev.platform_data = codec;
 
-	if((ret = i2c_attach_client(&codec->i2c)) < 0) {
+	if((ret = i2c_attach_client(i2c)) < 0) {
 		err("failed to attach codec at addr %x\n", addr);
+		kfree(i2c);
 		kfree(codec);
+		return ret;
 	}
 
 	codec->name = "WM8971";
@@ -700,6 +736,7 @@ static int wm8971_i2c_probe(struct i2c_a
 	if((ret = snd_soc_register_codec(codec)) < 0) {
 		err("can't register codec");
 		i2c_del_driver(&wm8971_i2c_driver);
+		kfree(i2c);
 		kfree(codec->reg_cache);
 		kfree(codec);
 	}
@@ -709,10 +746,12 @@ static int wm8971_i2c_probe(struct i2c_a
 
 static int wm8971_i2c_detach(struct i2c_client *client)
 {
-	struct snd_soc_codec *codec = container_of(client, struct snd_soc_codec, i2c);
-
+	struct snd_soc_codec *codec = 
+		(struct snd_soc_codec*)client->dev.platform_data;
+	
 	i2c_detach_client(client);
 	snd_soc_unregister_codec(codec);
+	kfree(codec->control_data);
 	kfree(codec->reg_cache);
 	kfree(codec);
 	return 0;
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 38a5d4d..aec10ec 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -1,7 +1,6 @@
 config SND_PXA2xx_SOC
 	tristate "SoC Audio for the Intel PXA2xx chip"
 	depends on ARCH_PXA && SND
-	select SND_AC97_CODEC
 	select SND_PCM
 	help
 	  Say Y or M if you want to add support for codecs attached to
diff --git a/sound/soc/pxa/mainstone.c b/sound/soc/pxa/mainstone.c
index 67f9a20..03bfced 100644
--- a/sound/soc/pxa/mainstone.c
+++ b/sound/soc/pxa/mainstone.c
@@ -5,7 +5,7 @@
  * Author: Liam Girdwood
  *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
  *
- *  Mainstone audio amplifier code taken from arch/arm/mainstone.c
+ *  Mainstone audio amplifier code taken from arch/arm/mach-pxa/mainstone.c
  *  Copyright:	MontaVista Software Inc.
  * 
  *  This program is free software; you can redistribute  it and/or modify it
@@ -16,8 +16,6 @@
  *  Revision history
  *    30th Oct 2005   Initial version.
  * 
- * Todo:
- *  o Try and reduce amplifier pop....
  */
  
 #include <linux/module.h>
@@ -28,19 +26,19 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
+#include <sound/soc-dpm.h>
 
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/mainstone.h>
 #include <asm/arch/audio.h>
 
+#include "../codecs/wm8753.h"
+
 static int mainstone_startup(snd_pcm_substream_t *substream)
 {
 	struct snd_soc_pcm_codec *pcm_c = substream->private_data;
 	struct snd_soc_pcm_interface *pcm_i = pcm_c->pcm_i;
 	
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF;
-		
 	if(pcm_i->type == SND_SOC_SSP && pcm_i->id == 1) {
 		/* enable USB on the go MUX so we can use SSPFRM2 */
 		MST_MSCWR2 |= MST_MSCWR2_USB_OTG_SEL;
@@ -53,10 +51,7 @@ static void mainstone_shutdown(snd_pcm_s
 {
 	struct snd_soc_pcm_codec *pcm_c = substream->private_data;
 	struct snd_soc_pcm_interface *pcm_i = pcm_c->pcm_i;
-	
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
-		
+			
 	if(pcm_i->type == SND_SOC_SSP && pcm_i->id == 1) {
 		/* disable USB on the go MUX so we can use ttyS0 */
 		MST_MSCWR2 &= ~MST_MSCWR2_USB_OTG_SEL;
@@ -86,21 +81,117 @@ static int mainstone_resume(struct snd_s
 
 static int mainstone_probe(struct snd_soc_machine *machine)
 {
+	MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF;
 	return 0;
 }
 
 static int mainstone_remove(struct snd_soc_machine *machine)
 {
+	MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+/* example external dpm event callback */
+int external_amp_event(struct snd_soc_codec *codec, int event)
+{
+	return 0;
+}
+
+/* example machine dpm widgets */
+static const struct snd_soc_dpm_widget wm8753_dpm_widgets[] = {
+SND_SOC_DPM_HP("Headphone Jack"),
+SND_SOC_DPM_MIC("Mic1 Jack"),
+SND_SOC_DPM_AMP("Ext Amp", external_amp_event),
+};
+
+/* example machine interconnections */
+static const char* intercon[][3] = {
+	
+	/* headphone connected to LOUT1, ROUT1 */
+	{"Headphone Jack", NULL, "LOUT1"},
+	{"Headphone Jack", NULL, "ROUT1"},
+	
+	/* ext speaker connected to LOUT2, ROUT2 via amp */
+	{"Ext Amp", NULL, "LOUT2"},
+	{"Ext Amp", NULL, "ROUT2"},
+	
+	/* mic is connected to mic1 - with bias */
+	{"MIC1", NULL, "Mic Bias"},
+	{"MIC1N", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic1 Jack"},
+	{"Mic Bias", NULL, "Mic1 Jack"},
+	
+	{"ACIN", NULL, "ACOP"},
+	{NULL, NULL, NULL},
+};
+
+/* example unconnected codec pins */
+static const struct snd_soc_dpm_pin wm8753_mainstone_pins[] = {
+	{"RXP", 0},
+	{"RXN", 0},
+	{"MIC2", 0},
+};
+
+/* headphone detect support on my board */
+static const char * hp_pol[] = {"Headphone", "Speaker"};
+static const struct soc_enum wm8753_enum =
+	SOC_ENUM_SINGLE(WM8753_OUTCTL, 1, 2, hp_pol);
+
+static const snd_kcontrol_new_t wm8753_mainstone_controls[] = {
+	SOC_SINGLE("Headphone Detect Switch", WM8753_OUTCTL, 6, 1, 0),
+	SOC_ENUM("Headphone Detect Polarity", wm8753_enum),
+};
+
+/*
+ * This is an example machine initialisation for a wm8753 connected to a 
+ * Mainstone II. It is missing logic to detect hp/mic insertions and logic
+ * to re-route the audio in such an event.
+ */
+
+static int mainstone_wm8753_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+	
+	/* set up mainstone codec pins */
+	for (i = 0; i < ARRAY_SIZE(wm8753_mainstone_pins); i++)
+		snd_soc_dpm_set_connection(codec, &wm8753_mainstone_pins[i]);
+	
+	/* add mainstone specific controls */
+	for (i = 0; i < ARRAY_SIZE(wm8753_mainstone_controls); i++) {
+		if ((err = snd_ctl_add(codec->card, snd_soc_cnew(&wm8753_mainstone_controls[i],codec, NULL))) < 0)
+			return err;
+	}
+	
+	/* add mainstone specific widgets */
+	for(i = 0; i < ARRAY_SIZE(wm8753_dpm_widgets); i++) {
+		snd_soc_dpm_new_control(codec, &wm8753_dpm_widgets[i]);
+	}
+	
+	/* set up mainstone specific audio path interconnects */
+	for(i = 0; intercon[i][0] != NULL; i++) {
+		snd_soc_dpm_connect_input(codec, intercon[i][0], intercon[i][1], intercon[i][2]);
+	}
+	snd_soc_dpm_sync(codec);
+	
 	return 0;
 }
 
-/* I've added all my different configs here atm */
+/* I've added all my different configs here atm for easier testing on ms II */
 static struct snd_soc_machine_config codecs[] = {
-	{.name = "WM8753", .sname = "WM8753 HiFi", SND_SOC_I2S, 0},
+{
+	.name = "WM8753", 
+	.sname = "WM8753 HiFi", 
+	.interface = SND_SOC_I2S, 
+	.int_num = 0,
+	.init = mainstone_wm8753_init,
+},
+#if 0
 	{.name = "WM8971", .sname = "WM8971", SND_SOC_I2S, 0},
 	{.name = "WM8750", .sname = "WM8750", SND_SOC_I2S, 0},
+	{.name = "WM8731", .sname = "WM8731", SND_SOC_I2S, 0},
 	{.name = "WM8753", .sname = "WM8753 Voice", SND_SOC_SSP, 1},
 	{.name = "AC97", .sname = "AC97 Audio", SND_SOC_AC97, 0},
+#endif
 };
 
 static struct snd_soc_machine mainstone = {
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index d6e097b..21f27c3 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -45,7 +45,6 @@ static int i2s_open = 0;
 
 /*
  * priv1 is sadiv
- * priv2 is bits[15..8] = MCLK divisor, bits[7..0] = sr
  */
 static struct snd_soc_hw_mode pxa2xx_i2s[] = {
 	{PXA_I2S_HWFMT, 	SND_SOC_HWBITS(16),		8000,	64,		0x00000048},
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index c61d0e9..2b8f7fa 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -15,7 +15,6 @@
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
-#include <linux/delay.h> //
 
 #include <sound/driver.h>
 #include <sound/core.h>
@@ -334,8 +333,6 @@ int pxa2xx_pcm_new(snd_card_t *card, str
 {
 	int ret = 0;
 
-	pcm->private_free = pxa2xx_pcm_free_dma_buffers;
-	
 	if (!card->dev->dma_mask)
 		card->dev->dma_mask = &pxa2xx_pcm_dmamask;
 	if (!card->dev->coherent_dma_mask)
@@ -385,6 +382,7 @@ static struct snd_soc_platform pxa2xx_so
 	.remove		= pxa2xx_soc_remove,
 	.pcm_ops 	= &pxa2xx_pcm_ops,
 	.pcm_new	= pxa2xx_pcm_new,
+	.pcm_free	= pxa2xx_pcm_free_dma_buffers,
 };
 
 module_init(pxa2xx_soc_init);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c885891..5f3bf78 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -41,7 +41,7 @@
 #include <sound/soc-dpm.h>
 #include <sound/initval.h>
 
-#define SND_SOC_VERSION "0.6"
+#define SND_SOC_VERSION "0.7"
 
 #define iface_name(x) \
 	(((x) == SND_SOC_AC97) ? "ac97" : \
@@ -111,7 +111,8 @@ static int soc_match_hw(struct snd_soc_h
 
 /* Check that common hw capabilities exist between the codec and interface for
  * the given hw params */
-static int soc_check_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params)
+static int soc_check_hw_params(snd_pcm_substream_t *substream, 
+	snd_pcm_hw_params_t *params)
 {
 	struct snd_soc_pcm_codec *pcm_c = substream->private_data;
 	struct snd_soc_pcm_interface *pcm_i = pcm_c->pcm_i;
@@ -355,6 +356,9 @@ static int soc_pcm_hw_params(snd_pcm_sub
 		}
 	}
 	
+	if(codec->dpm_state == SNDRV_CTL_POWER_D0)
+		return 0;
+	
 	if(codec->dpm_event)
 		codec->dpm_event(codec, SNDRV_CTL_POWER_D1);
 	
@@ -366,7 +370,8 @@ static int soc_pcm_hw_params(snd_pcm_sub
 		
 	if(codec->dpm_event)
 		codec->dpm_event(codec, SNDRV_CTL_POWER_D0);
-		
+	snd_soc_dpm_codec_mute(codec, 0);
+	codec->dpm_state = SNDRV_CTL_POWER_D0;
 	return ret;
 	
 platform_err:
@@ -400,15 +405,21 @@ static int soc_pcm_hw_free(snd_pcm_subst
 	if(platform->pcm_ops->hw_free)
 		platform->pcm_ops->hw_free(substream);
 	
-	if(codec->dpm_event)
-		codec->dpm_event(codec, SNDRV_CTL_POWER_D3hot);
-		
+	if(codec->dpm_state == SNDRV_CTL_POWER_D3hot)
+		return 0;
+	
+	snd_soc_dpm_codec_mute(codec, 1);
 	snd_soc_dpm_codec_event(codec, SNDRV_CTL_POWER_D3hot);
+		
 	if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		snd_soc_dpm_stream_event(codec, pcm_c->playback.sname, SND_SOC_DPM_STREAM_STOP);
 	else
 		snd_soc_dpm_stream_event(codec, pcm_c->capture.sname, SND_SOC_DPM_STREAM_STOP);
 	
+	if(codec->dpm_event)
+		codec->dpm_event(codec, SNDRV_CTL_POWER_D3hot);
+	
+	codec->dpm_state = SNDRV_CTL_POWER_D3hot;
 	return 0;
 }
 
@@ -526,6 +537,7 @@ static int soc_probe_codec(struct snd_so
 	if(codec->probe && (ret = codec->probe(codec)) < 0)
 		goto err;
 	codec->probed = 1;
+	codec->dpm_state = SNDRV_CTL_POWER_D3hot;
 	soc_sync_objects();
 	return 0;
 	
@@ -601,7 +613,6 @@ int snd_soc_register_codec(struct snd_so
 		return ret;
 	}
 
-		
 	up(&soc_sem);
 	return ret;
 }
@@ -818,6 +829,9 @@ int snd_soc_pcm_connect(struct snd_soc_m
 		printk(KERN_ERR "soc: platform pcm constructor failed\n");
 		goto err;
 	}
+	pcm->private_free = platform->pcm_free;
+	if(machine->config[nconfig].init)
+		machine->config[nconfig].init(codec);
 	
 	printk(KERN_INFO "soc: %s <-> %s mapping ok\n", pcm_c->name, iface->name);
 	return ret;
diff --git a/sound/soc/soc-dpm.c b/sound/soc/soc-dpm.c
index d4bb378..4a8f3f6 100644
--- a/sound/soc/soc-dpm.c
+++ b/sound/soc/soc-dpm.c
@@ -21,9 +21,7 @@
  * 
  *  Todo:
  *    o Platform power domain - could this be tied into machine layer ???
- *    o DPM power change sequencing - order dpm "ons" to minimise pops.
- *    o DPM power change volume stepping - mute or have volume at minimum
- *      then gradually increase to preset level to minimise pops.
+ *    o DPM power change sequencing - allow for configurable sequences
  *    o Support for analogue bias optimisation.
  *    o Support for reduced codec oversampling rates.
  *    o Support for reduced codec bias currents.
@@ -61,63 +59,66 @@ static struct snd_soc_dpm_widget *dpm_cn
 	return widget;
 }
 
+/* set up initial codec paths */  
 static void dpm_set_path_status(struct snd_soc_dpm_widget *w, 
 	struct snd_soc_dpm_path *p, int i)
 {	
-	switch (w->id)
-	{
-		case snd_soc_dpm_mixer: 
-		{
-			int val;
-			int reg = w->kcontrols[i].private_value & 0xff;
-			int shift = (w->kcontrols[i].private_value >> 8) & 0x0f;
-			int mask = (w->kcontrols[i].private_value >> 16) & 0xff;
-			int invert = (w->kcontrols[i].private_value >> 24) & 0x01;
-			
-			val = snd_soc_read(w->codec, reg);
-			val = (reg >> shift) & mask;
+	switch (w->id){
+	case snd_soc_dpm_mixer: {
+		int val;
+		int reg = w->kcontrols[i].private_value & 0xff;
+		int shift = (w->kcontrols[i].private_value >> 8) & 0x0f;
+		int mask = (w->kcontrols[i].private_value >> 16) & 0xff;
+		int invert = (w->kcontrols[i].private_value >> 24) & 0x01;
 		
-			if((invert && !val) || (!invert && val))
-				p->connect = 1;
-			else
-				p->connect = 0;
-		}
-		break;
-		case snd_soc_dpm_mux: 
-		{			
-			struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
-			int val, item, bitmask;
-			
-			for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
-			;
-			val = snd_soc_read(w->codec, e->reg);
-			item = (val >> e->shift_l) & (bitmask - 1);
-			
+		val = snd_soc_read(w->codec, reg);
+		val = (reg >> shift) & mask;
+	
+		if((invert && !val) || (!invert && val))
+			p->connect = 1;
+		else
 			p->connect = 0;
-			for (i = 0; i < e->mask; i++) {
-				if (!(strcmp(p->name, e->texts[i])) && item == i)
-					p->connect = 1;
-			}
+	}
+	break;
+	case snd_soc_dpm_mux: {
+		struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
+		int val, item, bitmask;
+		
+		for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+		;
+		val = snd_soc_read(w->codec, e->reg);
+		item = (val >> e->shift_l) & (bitmask - 1);
+		
+		p->connect = 0;
+		for (i = 0; i < e->mask; i++) {
+			if (!(strcmp(p->name, e->texts[i])) && item == i)
+				p->connect = 1;
 		}
-		break;
-		/* dont affect routing - always connected */
-		case snd_soc_dpm_volume:
-		case snd_soc_dpm_output:
-		case snd_soc_dpm_adc:
-		case snd_soc_dpm_input:
-		case snd_soc_dpm_dac:
-		case snd_soc_dpm_clock:
-		case snd_soc_dpm_vref:	
-		case snd_soc_dpm_mic:
-			p->connect = 1;
-		break;
 	}
-	//printk("* %s --> %s %s\n", w->name, p->name, p->connect ? "connect" : "disconnect");
+	break;
+	/* does not effect routing - always connected */
+	case snd_soc_dpm_volume:
+	case snd_soc_dpm_output:
+	case snd_soc_dpm_adc:
+	case snd_soc_dpm_input:
+	case snd_soc_dpm_dac:
+	case snd_soc_dpm_clock:
+	case snd_soc_dpm_vref:	
+	case snd_soc_dpm_amp:
+	case snd_soc_dpm_micbias:
+		p->connect = 1;
+	case snd_soc_dpm_mute:
+	/* does effect routing - dynamically connected */
+	case snd_soc_dpm_hp:
+	case snd_soc_dpm_mic:			
+		p->connect = 0;
+	break;
+	}
 }	
 
 static int dpm_connect_mux(struct snd_soc_codec *codec, struct snd_soc_dpm_widget *src, 
 	struct snd_soc_dpm_widget *dest, struct snd_soc_dpm_path *path, 
-	char *control_name, const snd_kcontrol_new_t *kcontrol)
+	const char *control_name, const snd_kcontrol_new_t *kcontrol)
 {
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	int i;
@@ -137,7 +138,7 @@ static int dpm_connect_mux(struct snd_so
 }
 
 static int dpm_connect_mixer(struct snd_soc_codec *codec, struct snd_soc_dpm_widget *src, 
-	struct snd_soc_dpm_widget *dest, struct snd_soc_dpm_path *path, char *control_name)
+	struct snd_soc_dpm_widget *dest, struct snd_soc_dpm_path *path, const char *control_name)
 {
 	int i;
 	
@@ -155,8 +156,8 @@ static int dpm_connect_mixer(struct snd_
 	return -ENODEV;
 }
 
-int snd_soc_dpm_connect_input(struct snd_soc_codec *codec, char *dest_name, 
-	char * control_name, char *src_name)
+int snd_soc_dpm_connect_input(struct snd_soc_codec *codec, const char *dest_name, 
+	const char * control_name, const char *src_name)
 {
 	struct snd_soc_dpm_path *path;
 	struct snd_soc_dpm_widget *src = NULL, *dest = NULL, *w;
@@ -182,14 +183,24 @@ int snd_soc_dpm_connect_input(struct snd
 	
 	path = kzalloc(sizeof(struct snd_soc_dpm_path), GFP_KERNEL);
 	if (!path)
-		return -ENOMEM;
-	
+		return -ENOMEM;	
+
 	path->in = src;
 	path->out = dest;
 	INIT_LIST_HEAD(&path->list);
 	INIT_LIST_HEAD(&path->list_in);
 	INIT_LIST_HEAD(&path->list_out);
 
+	/* check for external widgets */
+	if(dest->id == snd_soc_dpm_input) {	
+		if (src->id == snd_soc_dpm_micbias || src->id == snd_soc_dpm_mic)
+			dest->ext = 1;
+	}
+	if(src->id == snd_soc_dpm_output) {	
+		if (dest->id == snd_soc_dpm_amp || dest->id == snd_soc_dpm_hp)
+			src->ext = 1;
+	}
+	
 	if(control_name == NULL) {
 		list_add(&path->list, &codec->dpm_paths);
 		list_add(&path->list_out, &dest->inputs);
@@ -199,27 +210,36 @@ int snd_soc_dpm_connect_input(struct snd
 	}
 
 	switch(dest->id) {
-		case snd_soc_dpm_adc:
-		case snd_soc_dpm_dac:
-		case snd_soc_dpm_volume:
-		case snd_soc_dpm_input:
-		case snd_soc_dpm_output:
-		case snd_soc_dpm_clock:
-		case snd_soc_dpm_vref:
-		case snd_soc_dpm_mic:
-			list_add(&path->list, &codec->dpm_paths);
-			list_add(&path->list_out, &dest->inputs);
-			list_add(&path->list_in, &src->outputs);
-			path->connect = 1;
-			return 0;
-		case snd_soc_dpm_mux:
-			if((ret = dpm_connect_mux(codec, src, dest, path, control_name, &dest->kcontrols[0])) != 0)
-				goto err;
-			break;
-		case snd_soc_dpm_mixer:
-			if((ret = dpm_connect_mixer(codec, src, dest, path, control_name)) != 0)
-				goto err;
-			break;
+	case snd_soc_dpm_adc:
+	case snd_soc_dpm_dac:
+	case snd_soc_dpm_volume:
+	case snd_soc_dpm_input:
+	case snd_soc_dpm_output:
+	case snd_soc_dpm_clock:
+	case snd_soc_dpm_vref:
+	case snd_soc_dpm_micbias:
+	case snd_soc_dpm_mute:
+	case snd_soc_dpm_amp:
+		list_add(&path->list, &codec->dpm_paths);
+		list_add(&path->list_out, &dest->inputs);
+		list_add(&path->list_in, &src->outputs);
+		path->connect = 1;
+		return 0;
+	case snd_soc_dpm_mux:
+		if((ret = dpm_connect_mux(codec, src, dest, path, control_name, &dest->kcontrols[0])) != 0)
+			goto err;
+		break;
+	case snd_soc_dpm_mixer:
+		if((ret = dpm_connect_mixer(codec, src, dest, path, control_name)) != 0)
+			goto err;
+		break;
+	case snd_soc_dpm_hp:
+	case snd_soc_dpm_mic:
+		list_add(&path->list, &codec->dpm_paths);
+		list_add(&path->list_out, &dest->inputs);
+		list_add(&path->list_in, &src->outputs);
+		path->connect = 0;
+		return 0;
 	}
 	return 0;
 
@@ -258,6 +278,50 @@ static int dpm_update_bits(struct snd_so
 	return change;
 }
 
+/* ramps the volume up or down to minimise pops before or after a power event */
+static int dpm_set_volume(struct snd_soc_dpm_widget *widget, int power)
+{
+	const snd_kcontrol_new_t *k = widget->kcontrols;
+	
+	if(widget->muted && !power)
+		return 0;
+	if(!widget->muted && power)
+		return 0;
+	
+	if(widget->num_kcontrols && k) {
+		int reg = k->private_value & 0xff;
+		int shift = (k->private_value >> 8) & 0x0f;
+		int mask = (k->private_value >> 16) & 0xff;
+		int invert = (k->private_value >> 24) & 0x01;
+		
+		if (power) {
+			int i;
+			/* power up has happended, increase volume to last level */
+			if(invert) {
+				for (i = mask; i > widget->value; i--)
+					snd_soc_update_bits(widget->codec, reg, mask, i);
+			} else {
+				for (i = 0; i < widget->value; i++)
+					snd_soc_update_bits(widget->codec, reg, mask, i);
+			}
+			widget->muted = 0;
+		} else {
+			/* power down is about to occur, decrease volume to mute */
+			int val = snd_soc_read(widget->codec, reg);
+			int i = widget->value = (val >> shift) & mask;
+			if(invert) {
+				for (; i < mask; i++)
+					snd_soc_update_bits(widget->codec, reg, mask, i);
+			} else {
+				for (; i > 0; i--)
+					snd_soc_update_bits(widget->codec, reg, mask, i);
+			}
+			widget->muted = 1;
+		}
+	}
+	return 0;
+}
+
 static int dpm_sync_mixer(struct snd_soc_codec *codec, struct snd_soc_dpm_widget *w)
 {
 	int i, ret = 0;
@@ -273,6 +337,7 @@ static int dpm_sync_mixer(struct snd_soc
 		{
 			path = list_entry(lp, struct snd_soc_dpm_path, list_out);
 			
+			/* mixer/mux paths name must match control name */
 			if (path->name != (char*)w->kcontrols[i].name) 
 				continue;
 				
@@ -321,6 +386,23 @@ static int dpm_sync_mux(struct snd_soc_c
 	return ret;
 }
 
+static int dpm_sync_volume(struct snd_soc_codec *codec, struct snd_soc_dpm_widget *w)
+{
+	snd_kcontrol_t *kcontrol;
+	int ret = 0;
+	
+	if(!w->num_kcontrols)
+		return -EINVAL;
+	
+	kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
+	if ((ret = snd_ctl_add(codec->card, kcontrol)) < 0) {
+		printk(KERN_ERR "soc: failed to add kcontrol %s\n", w->name);
+		return ret;
+	}
+	
+	return ret;
+}
+
 /*
  * Reset 'walked' bit for each path
  */
@@ -347,7 +429,11 @@ static int is_connected_output_ep(struct
 
 	if(widget->id == snd_soc_dpm_adc && widget->active)
 		return 1;
-	if(widget->id == snd_soc_dpm_output && widget->connected)
+	if(widget->id == snd_soc_dpm_output && widget->connected && !widget->ext)
+		return 1;
+	if(widget->id == snd_soc_dpm_hp && widget->connected)
+		return 1;
+	if(widget->id == snd_soc_dpm_amp && widget->connected)
 		return 1;
 	
 	list_for_each(lp, &widget->outputs)
@@ -376,7 +462,9 @@ static int is_connected_input_ep(struct 
 	
 	if(widget->id == snd_soc_dpm_dac && widget->active)
 		return 1;
-	if(widget->id == snd_soc_dpm_input && widget->connected)
+	if(widget->id == snd_soc_dpm_input && widget->connected && !widget->ext)
+		return 1;
+	if(widget->id == snd_soc_dpm_mic && widget->connected)
 		return 1;
 	
 	list_for_each(lp, &widget->inputs)
@@ -394,43 +482,89 @@ static int is_connected_input_ep(struct 
 	return con;
 }
 
-static int dpm_power_widgets(struct snd_soc_codec *codec)
+static int dpm_power_widgets(struct snd_soc_codec *codec, int event)
 {
 	struct snd_soc_dpm_widget *w;
 	struct list_head *l;
-	int in, out, pm;
+	int in, out, pm = 0, i, c = 1, *seq = NULL;
+	int up_seq[] = {snd_soc_dpm_dac, snd_soc_dpm_mixer, snd_soc_dpm_volume, snd_soc_dpm_mute};
+	int down_seq[] = {snd_soc_dpm_volume, snd_soc_dpm_mixer, snd_soc_dpm_dac, snd_soc_dpm_mute};
+
+	if(event == SND_SOC_DPM_STREAM_START) {
+		c = ARRAY_SIZE(up_seq);
+		seq = up_seq;
+	} else if (event == SND_SOC_DPM_STREAM_STOP) {
+		c = ARRAY_SIZE(down_seq);
+		seq = down_seq;
+	}
 	
-	list_for_each(l, &codec->dpm_widgets)
-	{
-		w = list_entry(l, struct snd_soc_dpm_widget, list);
-		
-		if(w->id == snd_soc_dpm_vref || w->id == snd_soc_dpm_clock)
-			continue;
-		
-		if(w->id == snd_soc_dpm_adc && w->active) {
+	for(i = 0; i < c; i++){
+		list_for_each(l, &codec->dpm_widgets)
+		{
+			w = list_entry(l, struct snd_soc_dpm_widget, list);
+			
+			if(seq && seq[i] && w->id != seq[i])
+				continue;
+			
+			if(w->id == snd_soc_dpm_vref || w->id == snd_soc_dpm_clock ||
+				w->id == snd_soc_dpm_mute)
+				continue;
+			
+			if(w->id == snd_soc_dpm_adc && w->active) {
+				in = is_connected_input_ep(w);
+				dpm_clear_walk(w->codec);
+				pm = (in != 0) ? 1 : 0;
+				if(w->invert)
+					pm = (pm ? 0:1);
+				dpm_update_bits(w, pm);
+				continue;
+			}
+			
+			if(w->id == snd_soc_dpm_dac && w->active) {
+				out = is_connected_output_ep(w);
+				dpm_clear_walk(w->codec);
+				pm = (out != 0) ? 1 : 0;
+				if(w->invert)
+					pm = (pm ? 0:1);
+				dpm_update_bits(w, pm);
+				continue;
+			}
+			
+			if(w->id == snd_soc_dpm_volume) {
+				int on;
+				in = is_connected_input_ep(w);
+				dpm_clear_walk(w->codec);
+				out = is_connected_output_ep(w);
+				dpm_clear_walk(w->codec);
+				pm = on = (out != 0 && in != 0) ? 1 : 0;
+				
+				if(!on)
+					dpm_set_volume(w, on); /* lower volume to reduce pops */
+				
+				if(w->invert)
+					pm = (on ? 0:1);
+				dpm_update_bits(w, pm);
+				
+				if(on) 
+					dpm_set_volume(w, on); /* restore volume from zero */
+				
+				continue;
+			}
 			in = is_connected_input_ep(w);
 			dpm_clear_walk(w->codec);
-			pm = (in != 0) ? 1 : 0;
-			dpm_update_bits(w, pm);
-			continue;
-		}
-		
-		if(w->id == snd_soc_dpm_dac && w->active) {
 			out = is_connected_output_ep(w);
 			dpm_clear_walk(w->codec);
-			pm = (out != 0) ? 1 : 0;
+			pm = (out != 0 && in != 0) ? 1 : 0;
+			if(w->invert)
+					pm = (pm ? 0:1);
 			dpm_update_bits(w, pm);
-			continue;
+			if(w->ext_event)
+				w->ext_event(w->codec, pm);
+			/*printk("widget %s\n in %d out %d pm %s ext %d con %d\n", 
+				w->name, in, out, pm ? "On":"Off", w->ext, w->connected);*/	
 		}
-		
-		in = is_connected_input_ep(w);
-		dpm_clear_walk(w->codec);
-		out = is_connected_output_ep(w);
-		dpm_clear_walk(w->codec);
-		pm = (out != 0 && in != 0) ? 1 : 0;
-		dpm_update_bits(w, pm);
-		//printk("widget %s\n in %d out %d pm %s\n", w->name, in, out, pm ? "On":"Off");	
 	}
+	
 	return 0;
 }
 
@@ -463,7 +597,7 @@ static int dpm_mux_update_power(struct s
 			path->connect = 0; /* old connection must be powered down */	
 	}
 	
-	dpm_power_widgets(widget->codec);			
+	dpm_power_widgets(widget->codec, 0);			
 	return 0;
 }
 
@@ -494,7 +628,7 @@ static int dpm_mixer_update_power(struct
 		break;
 	}
 	
-	dpm_power_widgets(widget->codec);
+	dpm_power_widgets(widget->codec, 0);
 	return 0;
 }
 
@@ -541,27 +675,37 @@ int snd_soc_dpm_sync(struct snd_soc_code
 	list_for_each(lw, &codec->dpm_widgets)
 	{
 		w = list_entry(lw, struct snd_soc_dpm_widget, list);
-
+		
+		if(w->sync)
+			continue;
+		
 		switch(w->id) {
-			case snd_soc_dpm_mixer:
-				dpm_sync_mixer(codec, w);
-				break;
-			case snd_soc_dpm_mux:
-				dpm_sync_mux(codec, w);
-				break;
-			case snd_soc_dpm_adc:
-			case snd_soc_dpm_dac:
-			case snd_soc_dpm_volume:
-			case snd_soc_dpm_input:
-			case snd_soc_dpm_output:
-			case snd_soc_dpm_clock:
-			case snd_soc_dpm_vref:
-			case snd_soc_dpm_mic:				
-				break;
+		case snd_soc_dpm_mixer:
+			dpm_sync_mixer(codec, w);
+			break;
+		case snd_soc_dpm_mux:
+			dpm_sync_mux(codec, w);
+			break;
+		case snd_soc_dpm_adc:
+		case snd_soc_dpm_dac:
+		case snd_soc_dpm_volume:
+			dpm_sync_volume(codec, w);
+			break;
+		case snd_soc_dpm_input:
+		case snd_soc_dpm_output:
+		case snd_soc_dpm_clock:
+		case snd_soc_dpm_vref:
+		case snd_soc_dpm_micbias:
+		case snd_soc_dpm_mute:
+		case snd_soc_dpm_amp:
+		case snd_soc_dpm_hp:
+		case snd_soc_dpm_mic:  				
+			break;
 		}
+		w->sync = 1;
 	}
 	
-	dpm_power_widgets(codec);
+	dpm_power_widgets(codec, 0);
 	return 0;
 }
 
@@ -574,6 +718,11 @@ int snd_soc_dpm_get_volsw(snd_kcontrol_t
 	int mask = (kcontrol->private_value >> 16) & 0xff;
 	int invert = (kcontrol->private_value >> 24) & 0x01;
 
+	if(widget->id == snd_soc_dpm_volume && !widget->power) {
+		ucontrol->value.integer.value[0] = widget->value;
+		return 0;
+	}
+	
 	ucontrol->value.integer.value[0] = (snd_soc_read(widget->codec, reg) >> shift) & mask;
 	if (shift != rshift)
 		ucontrol->value.integer.value[1] = (snd_soc_read(widget->codec, reg) >> rshift) & mask;
@@ -609,6 +758,11 @@ int snd_soc_dpm_put_volsw(snd_kcontrol_t
 		val |= val2 << rshift;
 	}
 	
+	if(widget->id == snd_soc_dpm_volume && !widget->power) {
+		widget->value = val;
+		return 1;
+	}
+	
 	dpm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert);
 	return snd_soc_update_bits(widget->codec, reg, val_mask, val);
 }
@@ -666,13 +820,15 @@ int snd_soc_dpm_new_control(struct snd_s
 	INIT_LIST_HEAD(&w->outputs);
 	INIT_LIST_HEAD(&w->list);
 	list_add(&w->list, &codec->dpm_widgets);
-	// liam - remove when implemented
-	w->connected = 1; // liam - set by .asoundrc extension or machine layer
 	
+	/* machine layer set ups unconnected pins and insertions */
+	w->connected = 1;
 	return 0;
 }
 
-int snd_soc_dpm_stream_event(struct snd_soc_codec *codec, char * stream, int event)
+/* stream event notification */
+int snd_soc_dpm_stream_event(struct snd_soc_codec *codec, 
+	const char * stream, int event)
 {
 	struct snd_soc_dpm_widget *w;
 	struct list_head *l = NULL;	
@@ -686,25 +842,43 @@ int snd_soc_dpm_stream_event(struct snd_
 		
 		if (strstr(w->sname, stream)) {
 			switch(event) {
-				case SND_SOC_DPM_STREAM_START:
-					w->active = 1;
-					break;
-				case SND_SOC_DPM_STREAM_STOP:
-				case SND_SOC_DPM_STREAM_SUSPEND:	
-					w->active = 0;
-					break;
-				case SND_SOC_DPM_STREAM_PAUSE_PUSH:
-					break;
-				case SND_SOC_DPM_STREAM_PAUSE_RELEASE:
-					break;
+			case SND_SOC_DPM_STREAM_START:
+				w->active = 1;
+				break;
+			case SND_SOC_DPM_STREAM_STOP:
+			case SND_SOC_DPM_STREAM_SUSPEND:	
+				w->active = 0;
+				break;
+			case SND_SOC_DPM_STREAM_PAUSE_PUSH:
+				break;
+			case SND_SOC_DPM_STREAM_PAUSE_RELEASE:
+				break;
 			}
 		}					
 	}
 	
-	dpm_power_widgets(codec);
+	dpm_power_widgets(codec, event);
+	return 0;
+}
+
+/* mute/unmute codec DAC mute bits - used to reduce pops */
+int snd_soc_dpm_codec_mute(struct snd_soc_codec *codec, int mute)
+{
+	struct snd_soc_dpm_widget *w;
+	struct list_head *l = NULL;	
+
+	list_for_each(l, &codec->dpm_widgets)
+	{
+		w = list_entry(l, struct snd_soc_dpm_widget, list);
+
+		if(w->id == snd_soc_dpm_mute)
+			dpm_update_bits(w, mute);
+	}
+	
 	return 0;
 }
 
+/* handle codec level dpm events - i.e. clocks */ 
 int snd_soc_dpm_codec_event(struct snd_soc_codec *codec, int event)
 {
 	struct snd_soc_dpm_widget *w;
@@ -742,6 +916,25 @@ int snd_soc_dpm_codec_event(struct snd_s
 	return 0;
 }
 
+/* update codec dpm status with connected pins/inputs */
+int snd_soc_dpm_set_connection(struct snd_soc_codec *codec, 
+	const struct snd_soc_dpm_pin *pin)
+{
+	struct snd_soc_dpm_widget *w;
+	struct list_head *l = NULL;	
+
+	list_for_each(l, &codec->dpm_widgets)
+	{
+		w = list_entry(l, struct snd_soc_dpm_widget, list);
+			
+		if(!strcmp(w->name, pin->name)) {
+			w->connected = pin->connected;
+		}
+	}
+	
+	return 0;	
+}
+
 EXPORT_SYMBOL_GPL(snd_soc_dpm_put_volsw);
 EXPORT_SYMBOL_GPL(snd_soc_dpm_get_volsw);
 EXPORT_SYMBOL_GPL(snd_soc_dpm_connect_input);
@@ -751,6 +944,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dpm_put_enum_d
 EXPORT_SYMBOL_GPL(snd_soc_dpm_get_enum_double);
 EXPORT_SYMBOL_GPL(snd_soc_dpm_stream_event);
 EXPORT_SYMBOL_GPL(snd_soc_dpm_codec_event);
+EXPORT_SYMBOL_GPL(snd_soc_dpm_codec_mute);
+EXPORT_SYMBOL_GPL(snd_soc_dpm_set_connection);
 
 /* Module information */ 
 MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
