diff --git a/include/sound/soc-dpm.h b/include/sound/soc-dpm.h
index 49cd2c5..dfbff2a 100644
--- a/include/sound/soc-dpm.h
+++ b/include/sound/soc-dpm.h
@@ -35,10 +35,7 @@
  *     Enabled when stream playback/capture is started.  
  */
 
-/* codec domain - vmid handled by the codec driver atm */  
-#define SND_SOC_DPM_VREF(wname, preg, pshift, pinvert) \
-{.id = snd_soc_dpm_vref, .name = wname, .reg = preg, .shift = pshift, \
- .invert = pinvert, .kcontrols = NULL, .num_kcontrols = 0}
+/* codec domain - vmid, vref handled by the codec driver */  
 #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}
@@ -55,9 +52,9 @@
 #define SND_SOC_DPM_VOLUME(wname, preg, pshift, pinvert, wcontrols, wncontrols) \
 {.id = snd_soc_dpm_volume, .name = wname, .reg = preg, .shift = pshift, \
  .invert = pinvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
-#define SND_SOC_DPM_MUX(wname, preg, pshift, pinvert, wcontrols, wncontrols) \
+#define SND_SOC_DPM_MUX(wname, preg, pshift, pinvert, wcontrols) \
 {.id = snd_soc_dpm_mux, .name = wname, .reg = preg, .shift = pshift, \
- .invert = pinvert,	.kcontrols = wcontrols, .num_kcontrols = wncontrols} 
+ .invert = pinvert,	.kcontrols = wcontrols, .num_kcontrols = 1} 
 #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} 
@@ -91,9 +88,6 @@
 #define SND_SOC_DPM_STREAM_SUSPEND		0x4
 #define SND_SOC_DPM_STREAM_PAUSE_PUSH	0x8
 #define SND_SOC_DPM_STREAM_PAUSE_RELEASE	0x10  
-  
-#define SND_SOC_DPM_CODEC_ON	0x1
-#define SND_SOC_DPM_CODEC_OFF	0x2
 
 typedef struct snd_soc_dpm_widget snd_soc_dpm_widget_t;
 typedef enum snd_soc_dpm_type snd_soc_dpm_type_t;
@@ -122,6 +116,7 @@ enum snd_soc_dpm_type {
 	snd_soc_dpm_dac,
 	snd_soc_dpm_clock,
 	snd_soc_dpm_vref,
+	snd_soc_dpm_mic,
 };
 
 struct snd_soc_dpm_path {
diff --git a/include/sound/soc.h b/include/sound/soc.h
index f244a67..7f017e1 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -50,7 +50,7 @@
  */
 #define SND_SOC_AC97		0x1
 #define SND_SOC_I2S			0x2
-#define SND_SOC_SSP			0x3
+#define SND_SOC_SSP			0x4
 
 /*
  * hw interface formats
@@ -104,11 +104,6 @@ typedef struct snd_soc_hw_mode snd_soc_h
 typedef struct snd_soc_machine snd_soc_machine_t;
 
 /*
- * Queries SoC layer for available interface
- */
-int snd_soc_iface_query(int iface_type, int num);
-
-/*
  * SoC registration objects:-
  * 
  *  o Codec (n)
@@ -131,14 +126,14 @@ void snd_soc_unregister_interface(snd_so
 int snd_soc_register_machine(snd_soc_machine_t *machine);
 void snd_soc_unregister_machine(snd_soc_machine_t *machine);
 
-/* pcm constructor */
-int snd_soc_pcm_new(snd_soc_codec_t *codec, int dev_no, snd_soc_pcm_codec_t *pcm_c, 
-		snd_pcm_t **rpcm, int play, int capt, int iface_type, int num);
+/* pcm <-> interface connect */
+int snd_soc_pcm_connect(snd_soc_machine_t *machine, char *name, int iface_type, int num);
+int snd_soc_pcm_register(snd_soc_machine_t *machine, char *name);
 
+/* set runtime hw params */
 int snd_soc_set_runtime_hw(snd_pcm_substream_t *substream, 
 	const snd_pcm_hardware_t *hw);
 
-
 /* codec register bit access */
 int snd_soc_update_bits(snd_soc_codec_t *codec, unsigned short reg,
 				unsigned short mask, unsigned short value);
@@ -205,12 +200,14 @@ struct snd_soc_pcm_codec {
 	snd_soc_pcm_stream_t playback;
 	snd_soc_pcm_stream_t capture;
 	snd_soc_hw_bus_t hw;
+	int nplayback;
+	int ncapture;
 	
 	/* runtime info */
 	snd_soc_hw_mode_t hw_runtime;
 	snd_soc_ops_t ops;
 	snd_soc_pcm_interface_t *pcm_i;
-	snd_soc_codec_t *codec; // liam - check
+	snd_soc_codec_t *codec;
 	
 	/* private data */
 	void *priv;
@@ -254,20 +251,21 @@ struct snd_soc_codec {
 	char *name;
 	char *longname;
 	struct module *owner;
-		
-	int probed;
+	
+	/* callbacks */
 	int (*probe)(snd_soc_codec_t *codec);
 	void (*remove)(snd_soc_codec_t *codec);
 	int (*suspend)(snd_soc_codec_t *codec, pm_message_t state);
 	int (*resume)(snd_soc_codec_t *codec);
+	int (*dpm_event)(snd_soc_codec_t *codec, int event);
 	
 	/* runtime */
 	snd_card_t *card;
-	snd_pcm_t *pcm;
 	struct platform_device pdev;
-	snd_soc_pcm_interface_t *interface; // liam - this needs to be 1:n
 	void *private_data;
 	int active_streams;
+	int pcm_devs;
+	int probed;
 	
 	/* codec IO */
 	unsigned int (*read)(u16);
@@ -276,6 +274,10 @@ struct snd_soc_codec {
 	struct list_head list;
 	struct list_head dpm_widgets;
 	struct list_head dpm_paths;
+	
+	/* codec pcms */
+	snd_soc_pcm_codec_t *pcms;
+	int	npcms;
 };
 
 /* SoC platform interface */
@@ -285,7 +287,7 @@ struct snd_soc_platform {
 	int	(*probe)(struct device * dev);
 	int	(*remove)(struct device * dev);
 	struct bus_type	* bus;
-	int (*pcm_new)(snd_card_t *, snd_soc_pcm_codec_t *, int, int, snd_pcm_t *);
+	int (*pcm_new)(snd_card_t *, snd_soc_pcm_codec_t *, snd_pcm_t *);
 	snd_pcm_ops_t *pcm_ops;
 };
 
@@ -293,10 +295,12 @@ struct snd_soc_platform {
 struct snd_soc_machine {
 	char *name;
 	
-	int	(*probe)(struct device * dev);
-	int	(*remove)(struct device * dev);
-	struct bus_type	* bus;
-	snd_pcm_ops_t *pcm_ops;
+	int	(*probe)(snd_soc_machine_t *machine);
+	int	(*remove)(snd_soc_machine_t *machine);
+	int (*suspend)(snd_soc_machine_t *machine, pm_message_t state);
+	int (*resume)(snd_soc_machine_t *machine);
+	
+	struct snd_soc_ops *ops;
 };
 
 /* enamerated kcontrol */
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index c4e1885..44ebee1 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -37,15 +37,15 @@ static void ac97_soc_device_release(stru
 
 static int ac97_soc_suspend(snd_soc_codec_t *codec, pm_message_t state)
 {
-	snd_soc_pcm_interface_t *i = codec->interface;
-	snd_ac97_suspend(i->ac97);
+	//snd_soc_pcm_interface_t *i = codec->interface;
+	//snd_ac97_suspend(i->ac97);
 	return 0;
 }	
 
 static int ac97_soc_resume(snd_soc_codec_t *codec)
 {
-	snd_soc_pcm_interface_t *i = codec->interface;
-	snd_ac97_resume(i->ac97);
+	//snd_soc_pcm_interface_t *i = codec->interface;
+	//snd_ac97_resume(i->ac97);
 	return 0;
 }
 
@@ -73,13 +73,10 @@ static snd_pcm_t *pcm_ac97;
 static int ac97_soc_probe(snd_soc_codec_t *codec)
 {
 	int ret;
-
-	if(snd_soc_iface_query(SND_SOC_AC97, 0))
-		return -ENODEV;
 	
-	if((ret = snd_soc_pcm_new(codec, 0, &ac97_soc_client, 
-		&pcm_ac97, 1, 1, SND_SOC_AC97, 0)) < 0)
-		return ret;
+//	if((ret = snd_soc_pcm_new(codec, 0, &ac97_soc_client, 
+//		&pcm_ac97, 1, 1, SND_SOC_AC97, 0)) < 0)
+//		return ret;
 	
 	ac97_soc_add_widgets(&ac97_soc_codec);
 
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 0bff291..fc6b085 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -34,8 +34,7 @@
 #include "wm8753.h"
 
 #define AUDIO_NAME "wm8753"
-#define WM8753_VERSION "0.2"
-
+#define WM8753_VERSION "0.4"
 
 /*
  * Debug
@@ -54,15 +53,7 @@
 #define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
 
 
-static int hifi = 1;
-module_param(hifi, int, 0);
-MODULE_PARM_DESC(hifi, "enable AUX ADC sysfs entries");
-
-static int voice = 1;
-module_param(voice, int, 0);
-MODULE_PARM_DESC(voice, "enable codec status sysfs entries");
 
-	
 /* 
  * WM8753 2 wire address is determined by GPIO5
  * state during powerup.
@@ -71,21 +62,14 @@ MODULE_PARM_DESC(voice, "enable codec st
  */
 #define WM8753_2W_ADDR1	0x1a
 #define WM8753_2W_ADDR2	0x1b
-#define I2C_DRIVERID_WM8753 0xfefe
-
+#define I2C_DRIVERID_WM8753 0xfefe /* liam -  need a proper id */
 
 static unsigned short normal_i2c[] = { WM8753_2W_ADDR1, WM8753_2W_ADDR2,
                                        I2C_CLIENT_END };
 
 /* Magic definition of all other variables and things */
 I2C_CLIENT_INSMOD;
-
-struct wm8753_ {
-	struct i2c_client *i2c;
-	snd_pcm_t *pcm_voice;
-	snd_pcm_t *pcm_hifi;
-};
-static struct wm8753_ wm8753;
+struct i2c_client* wm8753_i2c = NULL;
 
 /*
  * wm8753 register cache
@@ -255,23 +239,15 @@ static int wm8753_reset(struct i2c_clien
  * Attach WM8753 2 wire client 
  */
 static int wm8753_i2c_probe(struct i2c_adapter *adap, int addr, int kind)
-{		 
+{
     client_template.adapter = adap;
     client_template.addr = addr;
 	
-    if ((wm8753.i2c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)) == NULL)
+    if ((wm8753_i2c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)) == NULL)
         return -ENOMEM;
 
-    memcpy(wm8753.i2c, &client_template, sizeof(struct i2c_client));
-	//wm8753_2w_client->data = (void*)&wm8753;
-	
-	if (wm8753_reset(wm8753.i2c) != 0) {
-		kfree (wm8753.i2c);  //liam - looks like somebody is still using this.....
-		err("cannot reset the WM8753");
-		return -EIO;
-	}
-
-    return i2c_attach_client(wm8753.i2c);
+    memcpy(wm8753_i2c, &client_template, sizeof(struct i2c_client));
+	return i2c_attach_client(wm8753_i2c);
 }
 
 static int wm8753_i2c_detach(struct i2c_client *client)
@@ -325,7 +301,7 @@ static int wm8753_2w_write(struct i2c_cl
 
 static int wm8753_write (u16 reg, unsigned int value)
 {
-	return wm8753_2w_write(wm8753.i2c, reg, value);	
+	return wm8753_2w_write(wm8753_i2c, reg, value);	
 }
 
 /* 
@@ -480,8 +456,6 @@ SOC_SINGLE("ADC 6dB Attenuate", WM8753_A
 SOC_SINGLE("DAC 6dB Attenuate", WM8753_ADCTL1, 1, 1, 0),
 
 SOC_ENUM("De-emphasis", wm8753_enum[8]),
-SOC_SINGLE("DAC Switch", WM8753_DAC, 3, 1, 1),
-
 SOC_ENUM("DAC Mono Mix", wm8753_enum[9]),
 SOC_ENUM("DAC Phase", wm8753_enum[10]),
 
@@ -507,48 +481,44 @@ static int wm8753_add_controls(snd_soc_c
 
 /* Left Mixer */
 static const snd_kcontrol_new_t wm8753_left_mixer_controls[] = {
-SOC_DPM_SINGLE("Voice Switch", WM8753_LOUTM2, 8, 1, 0),
+SOC_DPM_SINGLE("Playback Voice Switch", WM8753_LOUTM2, 8, 1, 0),
 SOC_DPM_SINGLE("Sidetone Switch", WM8753_LOUTM2, 7, 1, 0),
-SOC_DPM_SINGLE("DAC Switch", WM8753_LOUTM1, 8, 1, 0),
+SOC_DPM_SINGLE("Playback Left Switch", WM8753_LOUTM1, 8, 1, 0),
 SOC_DPM_SINGLE("Capture Mux Switch", WM8753_LOUTM1, 7, 1, 0),
 };
 
 /* Right mixer */
 static const snd_kcontrol_new_t wm8753_right_mixer_controls[] = {
-SOC_DPM_SINGLE("Voice Switch", WM8753_ROUTM2, 8, 1, 0),
+SOC_DPM_SINGLE("Playback Voice Switch", WM8753_ROUTM2, 8, 1, 0),
 SOC_DPM_SINGLE("Sidetone Switch", WM8753_ROUTM2, 7, 1, 0),
-SOC_DPM_SINGLE("DAC Switch", WM8753_ROUTM1, 8, 1, 0),
+SOC_DPM_SINGLE("Playback Right Switch", WM8753_ROUTM1, 8, 1, 0),
 SOC_DPM_SINGLE("Capture Mux Switch", WM8753_ROUTM1, 7, 1, 0),
 };
 
 /* Mono mixer */
 static const snd_kcontrol_new_t wm8753_mono_mixer_controls[] = {
-SOC_DPM_SINGLE("Left Switch", WM8753_MOUTM1, 8, 1, 0),
-SOC_DPM_SINGLE("Right Switch", WM8753_MOUTM2, 8, 1, 0),
-SOC_DPM_SINGLE("DAC Switch", WM8753_MOUTM2, 4, 1, 0),
+SOC_DPM_SINGLE("Playback Left Switch", WM8753_MOUTM1, 8, 1, 0),
+SOC_DPM_SINGLE("Playback Right Switch", WM8753_MOUTM2, 8, 1, 0),
+SOC_DPM_SINGLE("Playback Voice Switch", WM8753_MOUTM2, 4, 1, 0),
 SOC_DPM_SINGLE("Sidetone Switch", WM8753_MOUTM2, 7, 1, 0),
 SOC_DPM_SINGLE("Capture Mux Switch", WM8753_ROUTM1, 7, 1, 0),
 };
 
 /* Mono 2 Mux */
-static const snd_kcontrol_new_t wm8753_mono2_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[17]),
-};
+static const snd_kcontrol_new_t wm8753_mono2_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[17]);
 
 /* Out 3 Mux */
-static const snd_kcontrol_new_t wm8753_out3_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[18]),
-};
+static const snd_kcontrol_new_t wm8753_out3_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[18]);
 
 /* Out 4 Mux */
-static const snd_kcontrol_new_t wm8753_out4_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[19]),
-};
+static const snd_kcontrol_new_t wm8753_out4_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[19]);
 
 /* ADC Mono Mix */
-static const snd_kcontrol_new_t wm8753_adc_mono_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[22]),
-};
+static const snd_kcontrol_new_t wm8753_adc_mono_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[22]);
 
 /* ST Record mixer */
 static const snd_kcontrol_new_t wm8753_record_mixer_controls[] = {
@@ -558,19 +528,16 @@ SOC_DPM_SINGLE("Right Switch", WM8753_RE
 };
 
 /* Left ADC mux */
-static const snd_kcontrol_new_t wm8753_adc_left_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[21]),
-};
+static const snd_kcontrol_new_t wm8753_adc_left_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[21]);
 
 /* Right ADC mux */
-static const snd_kcontrol_new_t wm8753_adc_right_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[20]),
-};
+static const snd_kcontrol_new_t wm8753_adc_right_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[20]);
 
 /* MIC mux */
-static const snd_kcontrol_new_t wm8753_mic_mux_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[16]),
-};
+static const snd_kcontrol_new_t wm8753_mic_mux_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[16]);
 
 /* ALC mixer */
 static const snd_kcontrol_new_t wm8753_alc_mixer_controls[] = {
@@ -581,37 +548,30 @@ SOC_DPM_SINGLE("Rx Switch", WM8753_INCTL
 };
 
 /* Left Line mux */
-static const snd_kcontrol_new_t wm8753_line_left_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[14]),
-};
+static const snd_kcontrol_new_t wm8753_line_left_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[14]);
 
 /* Right Line mux */
-static const snd_kcontrol_new_t wm8753_line_right_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[13]),
-};
+static const snd_kcontrol_new_t wm8753_line_right_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[13]);
 
 /* Mono Line mux */
-static const snd_kcontrol_new_t wm8753_line_mono_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[12]),
-};
+static const snd_kcontrol_new_t wm8753_line_mono_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[12]);
 
 /* Line mux and mixer */
-static const snd_kcontrol_new_t wm8753_line_mux_mix_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[11]),
-};
+static const snd_kcontrol_new_t wm8753_line_mux_mix_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[11]);
 
 /* Rx mux and mixer */
-static const snd_kcontrol_new_t wm8753_rx_mux_mix_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[15]),
-};
+static const snd_kcontrol_new_t wm8753_rx_mux_mix_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[15]);
 
 /* Mic Selector Mux */
-static const snd_kcontrol_new_t wm8753_mic_sel_mux_controls[] = {
-SOC_DPM_ENUM("Source", wm8753_enum[25]),
-};
+static const snd_kcontrol_new_t wm8753_mic_sel_mux_controls =
+SOC_DPM_ENUM("Source", wm8753_enum[25]);
 
 static const snd_soc_dpm_widget_t wm8753_dpm_widgets[] = {
-SND_SOC_DPM_VREF("WM8753 VRef", WM8753_PWR1, 6, 0),
 SND_SOC_DPM_CLOCK("WM8753 Clock", WM8753_PWR1, 0, 1),
 SND_SOC_DPM_MIXER("Left Mixer", WM8753_PWR4, 0, 0, &wm8753_left_mixer_controls[0], 
 	ARRAY_SIZE(wm8753_left_mixer_controls)),
@@ -633,50 +593,36 @@ SND_SOC_DPM_VOLUME("Mono Out 1", WM8753_
 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"),
-SND_SOC_DPM_MUX("Mono 2 Mux", -1, 0, 0, &wm8753_mono2_controls[0], 
-	ARRAY_SIZE(wm8753_mono2_controls)),
+SND_SOC_DPM_MUX("Mono 2 Mux", -1, 0, 0, &wm8753_mono2_controls),
 SND_SOC_DPM_OUTPUT("MONO2"),
 SND_SOC_DPM_MIXER("Out3 Left + Right", -1, 0, 0, NULL, 0),
-SND_SOC_DPM_MUX("Out3 Mux", -1, 0, 0, &wm8753_out3_controls[0], 
-	ARRAY_SIZE(wm8753_out3_controls)),
+SND_SOC_DPM_MUX("Out3 Mux", -1, 0, 0, &wm8753_out3_controls),
 SND_SOC_DPM_VOLUME("Out 3", WM8753_PWR3, 4, 0, NULL, 0),
 SND_SOC_DPM_OUTPUT("OUT3"),
-SND_SOC_DPM_MUX("Out4 Mux", -1, 0, 0, &wm8753_out4_controls[0], 
-	ARRAY_SIZE(wm8753_out4_controls)),
+SND_SOC_DPM_MUX("Out4 Mux", -1, 0, 0, &wm8753_out4_controls),
 SND_SOC_DPM_VOLUME("Out 4", WM8753_PWR3, 3, 0, NULL, 0),
 SND_SOC_DPM_OUTPUT("OUT4"),
 SND_SOC_DPM_MIXER("Capture ST Mixer", WM8753_PWR4, 3, 0, &wm8753_record_mixer_controls[0], 
 	ARRAY_SIZE(wm8753_record_mixer_controls)),
 SND_SOC_DPM_ADC("Left ADC", "Left Voice Capture", WM8753_PWR2, 3, 0, NULL, 0),
 SND_SOC_DPM_ADC("Right ADC", "Right Voice Capture", WM8753_PWR2, 2, 0, NULL, 0),
-SND_SOC_DPM_MUX("Capture Left Mixer", -1, 0, 0, &wm8753_adc_mono_controls[0], 
-	ARRAY_SIZE(wm8753_adc_mono_controls)),
-SND_SOC_DPM_MUX("Capture Right Mixer", -1, 0, 0, &wm8753_adc_mono_controls[0], 
-	ARRAY_SIZE(wm8753_adc_mono_controls)),
-SND_SOC_DPM_MUX("Capture Left Mux", -1, 0, 0, &wm8753_adc_left_controls[0], 
-	ARRAY_SIZE(wm8753_adc_left_controls)),
-SND_SOC_DPM_MUX("Capture Right Mux", -1, 0, 0, &wm8753_adc_right_controls[0], 
-	ARRAY_SIZE(wm8753_adc_right_controls)),
-SND_SOC_DPM_MUX("MIC ST Mux", -1, 0, 0, &wm8753_mic_mux_controls[0], 
-	ARRAY_SIZE(wm8753_mic_mux_controls)),
+SND_SOC_DPM_MUX("Capture Left Mixer", -1, 0, 0, &wm8753_adc_mono_controls),
+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_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], 
 	ARRAY_SIZE(wm8753_alc_mixer_controls)),
-SND_SOC_DPM_MUX("Line Left Mux", -1, 0, 0, &wm8753_line_left_controls[0], 
-	ARRAY_SIZE(wm8753_line_left_controls)),
-SND_SOC_DPM_MUX("Line Right Mux", -1, 0, 0, &wm8753_line_right_controls[0], 
-	ARRAY_SIZE(wm8753_line_right_controls)),
-SND_SOC_DPM_MUX("Line Mono Mux", -1, 0, 0, &wm8753_line_mono_controls[0], 
-	ARRAY_SIZE(wm8753_line_mono_controls)),
-SND_SOC_DPM_MUX("Line Mixer", -1, 0, 0, &wm8753_line_mux_mix_controls[0], 
-	ARRAY_SIZE(wm8753_line_mux_mix_controls)),
-SND_SOC_DPM_MUX("Rx Mixer", -1, 0, 0, &wm8753_rx_mux_mix_controls[0], 
-	ARRAY_SIZE(wm8753_rx_mux_mix_controls)),
+SND_SOC_DPM_MUX("Line Left Mux", -1, 0, 0, &wm8753_line_left_controls),
+SND_SOC_DPM_MUX("Line Right Mux", -1, 0, 0, &wm8753_line_right_controls),
+SND_SOC_DPM_MUX("Line Mono Mux", -1, 0, 0, &wm8753_line_mono_controls),
+SND_SOC_DPM_MUX("Line Mixer", -1, 0, 0, &wm8753_line_mux_mix_controls),
+SND_SOC_DPM_MUX("Rx Mixer", -1, 0, 0, &wm8753_rx_mux_mix_controls),
 SND_SOC_DPM_VOLUME("Mic 1 Volume", WM8753_PWR2, 8, 0, NULL, 0),
 SND_SOC_DPM_VOLUME("Mic 2 Volume", WM8753_PWR2, 7, 0, NULL, 0),
-SND_SOC_DPM_MUX("Mic Selection Mux", -1, 0, 0, &wm8753_mic_sel_mux_controls[0], 
-	ARRAY_SIZE(wm8753_mic_sel_mux_controls)),
+SND_SOC_DPM_MUX("Mic Selection Mux", -1, 0, 0, &wm8753_mic_sel_mux_controls),
 SND_SOC_DPM_INPUT("LINE1"),
 SND_SOC_DPM_INPUT("LINE2"),
 SND_SOC_DPM_INPUT("RXP"),
@@ -700,21 +646,21 @@ static int wm8753_add_widgets(snd_soc_co
 	/* set up audio path interconnects */
 	
 	/* left mixer */
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "DAC Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Voice Switch", "Voice DAC");
+	snd_soc_dpm_connect_input(codec, "Left Mixer", "Playback Left Switch", "Left DAC");
+	snd_soc_dpm_connect_input(codec, "Left Mixer", "Playback Voice Switch", "Voice DAC");
 	snd_soc_dpm_connect_input(codec, "Left Mixer", "Sidetone Switch", "MIC ST Mux");
 	snd_soc_dpm_connect_input(codec, "Left Mixer", "Capture Mux Switch", "Line Left Mux");
 	
 	/* right mixer */
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "DAC Switch", "Right DAC");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Voice Switch", "Voice DAC");
+	snd_soc_dpm_connect_input(codec, "Right Mixer", "Playback Right Switch", "Right DAC");
+	snd_soc_dpm_connect_input(codec, "Right Mixer", "Playback Voice Switch", "Voice DAC");
 	snd_soc_dpm_connect_input(codec, "Right Mixer", "Sidetone Switch", "MIC ST Mux");
 	snd_soc_dpm_connect_input(codec, "Right Mixer", "Capture Mux Switch", "Line Right Mux");
 	
 	/* mono mixer */
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "DAC Switch", "Voice DAC");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Left Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Right Switch", "Right DAC");
+	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Playback Voice Switch", "Voice DAC");
+	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Playback Left Switch", "Left DAC");
+	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Playback Right Switch", "Right DAC");
 	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Sidetone Switch", "MIC ST Mux");
 	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Capture Mux Switch", "Line Mono Mux");
 	
@@ -724,7 +670,6 @@ static int wm8753_add_widgets(snd_soc_co
 	snd_soc_dpm_connect_input(codec, "LOUT1", NULL, "Left Out 1");
 	snd_soc_dpm_connect_input(codec, "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");
@@ -871,8 +816,8 @@ static u32 wm8753_config_pll(int pll, u3
 		clk = wm8753_read_reg_cache(WM8753_CLOCK) & 0x0010;
         if (!speed) {
             /* disable PLL1  */
-            wm8753_2w_write(wm8753.i2c, WM8753_PLL1CTL1, 0x0026);
-			wm8753_2w_write(wm8753.i2c, WM8753_CLOCK, clk);
+            wm8753_2w_write(wm8753_i2c, WM8753_PLL1CTL1, 0x0026);
+			wm8753_2w_write(wm8753_i2c, WM8753_CLOCK, clk);
         } else {
             u16 value = 0;
             int i = 0;   
@@ -885,33 +830,33 @@ static u32 wm8753_config_pll(int pll, u3
 			
 			/* do we need to enable the PLL ? */
 			if (!pll_div[i].n) {
-				wm8753_2w_write(wm8753.i2c, WM8753_CLOCK, 0x0);
+				wm8753_2w_write(wm8753_i2c, WM8753_CLOCK, 0x0);
 				return 0;
 			}
     
             /* set up N and K PLL divisor ratios */
             /* bits 8:5 = PLL_N, bits 3:0 = PLL_K[21:18] */
             value = (pll_div[i].n << 5) + ((pll_div[i].k & 0x3c0000) >> 18);  
-            wm8753_2w_write(wm8753.i2c, WM8753_PLL1CTL2, value);
+            wm8753_2w_write(wm8753_i2c, WM8753_PLL1CTL2, value);
      
             /* bits 8:0 = PLL_K[17:9] */
             value = (pll_div[i].k & 0x03fe00) >> 9;
-            wm8753_2w_write(wm8753.i2c, WM8753_PLL1CTL3, value);
+            wm8753_2w_write(wm8753_i2c, WM8753_PLL1CTL3, value);
     
             /* bits 8:0 = PLL_K[8:0] */
             value = pll_div[i].k & 0x0001ff;
-            wm8753_2w_write(wm8753.i2c, WM8753_PLL1CTL4, value);
+            wm8753_2w_write(wm8753_i2c, WM8753_PLL1CTL4, value);
      
             /* set PLL1 as input and enable */
-            wm8753_2w_write(wm8753.i2c, WM8753_PLL1CTL1, 0x0027);
-			wm8753_2w_write(wm8753.i2c, WM8753_CLOCK, clk | 0x0010);
+            wm8753_2w_write(wm8753_i2c, WM8753_PLL1CTL1, 0x0027);
+			wm8753_2w_write(wm8753_i2c, WM8753_CLOCK, clk | 0x0010);
         }
     } else {
 		clk = wm8753_read_reg_cache(WM8753_CLOCK) & 0x0008;
         if (!speed) {
             /* disable PLL2  */
-            wm8753_2w_write(wm8753.i2c, WM8753_PLL2CTL1, 0x0026);
-			wm8753_2w_write(wm8753.i2c, WM8753_CLOCK, clk);
+            wm8753_2w_write(wm8753_i2c, WM8753_PLL2CTL1, 0x0026);
+			wm8753_2w_write(wm8753_i2c, WM8753_CLOCK, clk);
         } else {
             u16 value = 0;
             int i = 0;   
@@ -924,43 +869,31 @@ static u32 wm8753_config_pll(int pll, u3
 			
     		/* do we need to enable the PLL ? */
 			if (!pll_div[i].n) {
-				wm8753_2w_write(wm8753.i2c, WM8753_CLOCK, 0x0);
+				wm8753_2w_write(wm8753_i2c, WM8753_CLOCK, 0x0);
 				return 0;
 			}
 			
             /* set up N and K PLL divisor ratios */
             /* bits 8:5 = PLL_N, bits 3:0 = PLL_K[21:18] */
             value = (pll_div[i].n << 5) + ((pll_div[i].k & 0x3c0000) >> 18);  
-            wm8753_2w_write(wm8753.i2c, WM8753_PLL2CTL2, value);
+            wm8753_2w_write(wm8753_i2c, WM8753_PLL2CTL2, value);
      
             /* bits 8:0 = PLL_K[17:9] */
             value = (pll_div[i].k & 0x03fe00) >> 9;
-            wm8753_2w_write(wm8753.i2c, WM8753_PLL2CTL3, value);
+            wm8753_2w_write(wm8753_i2c, WM8753_PLL2CTL3, value);
     
             /* bits 8:0 = PLL_K[8:0] */
             value = pll_div[i].k & 0x0001ff;
-            wm8753_2w_write(wm8753.i2c, WM8753_PLL2CTL4, value);
+            wm8753_2w_write(wm8753_i2c, WM8753_PLL2CTL4, value);
      
             /* set PLL1 as input and enable */
-            wm8753_2w_write(wm8753.i2c, WM8753_PLL2CTL1, 0x0027);
-			wm8753_2w_write(wm8753.i2c, WM8753_CLOCK, clk | 0x0008);
+            wm8753_2w_write(wm8753_i2c, WM8753_PLL2CTL1, 0x0027);
+			wm8753_2w_write(wm8753_i2c, WM8753_CLOCK, clk | 0x0008);
         }
     }
 	return speed;
 }
 
-static int wm8753_pcm_voice_startup(snd_pcm_substream_t *substream)
-{
-	//snd_pcm_runtime_t *runtime = substream->runtime;
-
-	return 0;
-}
-
-static void wm8753_pcm_voice_shutdown(snd_pcm_substream_t *substream)
-{
-
-}
-
 static int wm8753_pcm_voice_prepare(snd_pcm_substream_t *substream)
 {
 	snd_soc_pcm_codec_t *pcm_c = substream->private_data;
@@ -1017,11 +950,11 @@ static int wm8753_pcm_voice_prepare(snd_
 	/* set rate */
 	clock = wm8753_read_reg_cache(WM8753_CLOCK) & 0x003f;
 	clock |= (pcm_c->hw_runtime.priv2 & 0xff00) >> 2;
-	wm8753_2w_write(wm8753.i2c, WM8753_CLOCK, clock);
+	wm8753_2w_write(wm8753_i2c, WM8753_CLOCK, clock);
 
 	srate = wm8753_read_reg_cache(WM8753_SRATE1) & 0x017f;
 	srate |= (pcm_c->hw_runtime. priv2 & 0xff) << 7;
-	wm8753_2w_write(wm8753.i2c, WM8753_SRATE1, srate);
+	wm8753_2w_write(wm8753_i2c, WM8753_SRATE1, srate);
 	
 	/* clock inversion */
 	switch(pcm_c->hw_runtime.hformat & SND_SOC_INV_MASK) {
@@ -1035,22 +968,11 @@ static int wm8753_pcm_voice_prepare(snd_
 			voice |= 0x0010;
 			break;
 	}
-	wm8753_2w_write(wm8753.i2c, WM8753_IOCTL, ioctl);
-	wm8753_2w_write(wm8753.i2c, WM8753_PCM, voice);
+	wm8753_2w_write(wm8753_i2c, WM8753_IOCTL, ioctl);
+	wm8753_2w_write(wm8753_i2c, WM8753_PCM, voice);
 	return 0;
 }
 
-static int wm8753_pcm_hifi_startup(snd_pcm_substream_t *substream)
-{
-
-	return 0;
-}
-
-static void wm8753_pcm_hifi_shutdown(snd_pcm_substream_t *substream)
-{	
-
-}
-
 static int wm8753_pcm_hifi_prepare(snd_pcm_substream_t *substream)
 {
 	snd_soc_pcm_codec_t *pcm_c = substream->private_data;
@@ -1122,9 +1044,9 @@ static int wm8753_pcm_hifi_prepare(snd_p
 			srate |= (0x4 << 3);
 			break;
 	}		
-	wm8753_2w_write(wm8753.i2c, WM8753_SRATE2, srate);
+	wm8753_2w_write(wm8753_i2c, WM8753_SRATE2, srate);
 	srate = (pcm_c->hw_runtime. priv2 & 0xff) << 1;
-	wm8753_2w_write(wm8753.i2c, WM8753_SRATE1, srate);
+	wm8753_2w_write(wm8753_i2c, WM8753_SRATE1, srate);
 	
 	/* clock inversion */
 	switch(pcm_c->hw_runtime.hformat & SND_SOC_INV_MASK) {
@@ -1138,8 +1060,8 @@ static int wm8753_pcm_hifi_prepare(snd_p
 			hifi |= 0x0010;
 			break;
 	}
-	wm8753_2w_write(wm8753.i2c, WM8753_IOCTL, ioctl | 0x0008);
-	wm8753_2w_write(wm8753.i2c, WM8753_HIFI, hifi);
+	wm8753_2w_write(wm8753_i2c, WM8753_IOCTL, ioctl | 0x0008);
+	wm8753_2w_write(wm8753_i2c, WM8753_HIFI, hifi);
 	return 0;
 }
 
@@ -1147,8 +1069,38 @@ static void wm8753_device_release(struct
 {
 }
 
-static snd_soc_pcm_codec_t wm8753_pcm_voice_client = {
-	.name = "WM8753 Voice",
+static int wm8753_dpm_event(snd_soc_codec_t *codec, int event)
+{
+	u16 pwr_reg = wm8753_read_reg_cache(WM8753_PWR1) & 0xfe3f;
+	u16 dac_reg = wm8753_read_reg_cache(WM8753_DAC) & 0xfff7;
+
+	switch (event) {
+		case SNDRV_CTL_POWER_D0: /* full On */
+			/* set vmid to 50k and unmute dac */
+			wm8753_2w_write(wm8753_i2c, WM8753_PWR1, pwr_reg | 0x00c0);
+			wm8753_2w_write(wm8753_i2c, WM8753_DAC, dac_reg);
+			break;
+		case SNDRV_CTL_POWER_D1: /* partial On */
+		case SNDRV_CTL_POWER_D2: /* partial On */
+			/* set vmid to 5k for quick power up */
+			wm8753_2w_write(wm8753_i2c, WM8753_PWR1, pwr_reg | 0x01c0);
+			break;
+		case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+			/* mute dac and set vmid to 500k, enable VREF */
+			wm8753_2w_write(wm8753_i2c, WM8753_DAC, dac_reg | 0x0008);
+			wm8753_2w_write(wm8753_i2c, WM8753_PWR1, pwr_reg | 0x0140);
+			break;
+		case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+			wm8753_2w_write(wm8753_i2c, WM8753_DAC, dac_reg | 0x0008);
+			wm8753_2w_write(wm8753_i2c, WM8753_PWR1, 0x0001);
+			break;
+	}
+	
+	return 0;
+}
+
+static snd_soc_pcm_codec_t wm8753_pcm_clients[] = {
+{	.name = "WM8753 Voice",
 	.playback = {
 		.sname = "Voice Playback",
 		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
@@ -1164,18 +1116,15 @@ static snd_soc_pcm_codec_t wm8753_pcm_vo
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
 		.channels_max = 2,},
+	.nplayback = 1,
+	.ncapture = 1,
 	.ops = {
-		.startup = wm8753_pcm_voice_startup,
-		.shutdown = wm8753_pcm_voice_shutdown,
 		.prepare = wm8753_pcm_voice_prepare,},
 	.hw = {
 		.num_hmodes = ARRAY_SIZE(wm8753_voice),
 		.hmodes = &wm8753_voice[0],
-		},
-};
-
-static snd_soc_pcm_codec_t wm8753_pcm_hifi_client = {
-	.name = "WM8753 Hifi",
+		},},
+{	.name = "WM8753 HiFi",
 	.playback = {
 		.sname = "HiFi Playback",
 		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
@@ -1184,13 +1133,13 @@ static snd_soc_pcm_codec_t wm8753_pcm_hi
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
 		.channels_max = 2,},
+	.nplayback = 1,
+	.ncapture = 1,
 	.ops = {
-		.startup = wm8753_pcm_hifi_startup,
-		.shutdown = wm8753_pcm_hifi_shutdown,
 		.prepare = wm8753_pcm_hifi_prepare,},
 	.hw = {
 		.num_hmodes = ARRAY_SIZE(wm8753_hifi),
-		.hmodes = &wm8753_hifi[0],},
+		.hmodes = &wm8753_hifi[0],},},
 };
 
 static snd_soc_codec_t wm8753_soc_codec;
@@ -1201,72 +1150,35 @@ static snd_soc_codec_t wm8753_soc_codec;
  */
 static int wm8753_probe(snd_soc_codec_t *codec)
 {
-	int ret;
-	int dev_no = 0;
 	int reg;
-	
-	info("WM8753 Audio Codec %s", WM8753_VERSION);
-	if(!hifi && !voice) {
-		err("no interfaces selected");
-		return -ENODEV;
-	}
-
-	/* check platform for interfaces */
-	if(voice && snd_soc_iface_query(SND_SOC_SSP, 1)) {
-		err("voice interface not available");
-		voice = 0;
-	}
-	if(hifi && snd_soc_iface_query(SND_SOC_I2S, 0)) {
-		err("HiFi interface not available");
-		hifi = 0;
-	}
-	if(!hifi && !voice) {
-		err("no interfaces available");
-		return -ENODEV;
-	}
 
-	if (voice) {
-		if((ret = snd_soc_pcm_new(codec, dev_no++, &wm8753_pcm_voice_client, 
-				&wm8753.pcm_voice, 1, 1, SND_SOC_SSP, 1)) < 0)
-			return ret;
-	}
-		
-	if (hifi) {
-		if((ret = snd_soc_pcm_new(codec, dev_no++, &wm8753_pcm_hifi_client, 
-				&wm8753.pcm_hifi, 1, 0, SND_SOC_I2S, 0)) < 0)
-			return ret;
-	}
-
-	if ((ret = i2c_add_driver(&wm8753_i2c_driver)) != 0) {
-		err("can't add i2c driver");
-		return ret;
-	}
-	
-	/* set vmid to 50k - liam move to dpm */
-	wm8753_2w_write(wm8753.i2c, WM8753_PWR1, 0x0080);
+	wm8753_reset(wm8753_i2c);
 	
+	/* set vmid to 500k - low power standy */
+	wm8753_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
+
 	/* set the update bits */
 	reg = wm8753_read_reg_cache(WM8753_LDAC);
-	wm8753_2w_write(wm8753.i2c, WM8753_LDAC, reg | 0x0100);
+	wm8753_2w_write(wm8753_i2c, WM8753_LDAC, reg | 0x0100);
 	reg = wm8753_read_reg_cache(WM8753_RDAC);
-	wm8753_2w_write(wm8753.i2c, WM8753_RDAC, reg | 0x0100);
+	wm8753_2w_write(wm8753_i2c, WM8753_RDAC, reg | 0x0100);
 	reg = wm8753_read_reg_cache(WM8753_LOUT1V);
-	wm8753_2w_write(wm8753.i2c, WM8753_LOUT1V, reg | 0x0100);
+	wm8753_2w_write(wm8753_i2c, WM8753_LOUT1V, reg | 0x0100);
 	reg = wm8753_read_reg_cache(WM8753_ROUT1V);
-	wm8753_2w_write(wm8753.i2c, WM8753_ROUT1V, reg | 0x0100);
+	wm8753_2w_write(wm8753_i2c, WM8753_ROUT1V, reg | 0x0100);
 	reg = wm8753_read_reg_cache(WM8753_LOUT2V);
-	wm8753_2w_write(wm8753.i2c, WM8753_LOUT2V, reg | 0x0100);
+	wm8753_2w_write(wm8753_i2c, WM8753_LOUT2V, reg | 0x0100);
 	reg = wm8753_read_reg_cache(WM8753_ROUT2V);
-	wm8753_2w_write(wm8753.i2c, WM8753_ROUT2V, reg | 0x0100);
+	wm8753_2w_write(wm8753_i2c, WM8753_ROUT2V, reg | 0x0100);
 	reg = wm8753_read_reg_cache(WM8753_LINVOL);
-	wm8753_2w_write(wm8753.i2c, WM8753_LINVOL, reg | 0x0100);
+	wm8753_2w_write(wm8753_i2c, WM8753_LINVOL, reg | 0x0100);
 	reg = wm8753_read_reg_cache(WM8753_RINVOL);
-	wm8753_2w_write(wm8753.i2c, WM8753_RINVOL, reg | 0x0100);
+	wm8753_2w_write(wm8753_i2c, WM8753_RINVOL, reg | 0x0100);
 
 	wm8753_add_controls(&wm8753_soc_codec);
 	wm8753_add_widgets(&wm8753_soc_codec);
 
-	return ret;
+	return 0;
 }
 
 /* 
@@ -1274,17 +1186,16 @@ static int wm8753_probe(snd_soc_codec_t 
  */
 static void wm8753_remove(snd_soc_codec_t *codec)
 {
-	/* power down vmid - liam move to dpm */
-	wm8753_2w_write(wm8753.i2c, WM8753_PWR1, 0x0000);
-	i2c_del_driver(&wm8753_i2c_driver);
+	/* power down chip */
+	wm8753_dpm_event(codec, SNDRV_CTL_POWER_D3cold);
 }
 
 static snd_soc_codec_t wm8753_soc_codec = {
 	.name = "WM8753",
-	.longname = "wm8753 long name",
+	.longname = "WM8753 Portable Codec",
 	.owner = THIS_MODULE,
 	.pdev = {
-		.name		= "wm8753 pdev",
+		.name		= "soc-wm8753",
 		.id		= -1,
 		.dev		= {.release = wm8753_device_release},
 	},
@@ -1292,16 +1203,40 @@ static snd_soc_codec_t wm8753_soc_codec 
 	.remove = wm8753_remove,
 	.read = wm8753_read_reg_cache,
 	.write = wm8753_write,
+	.dpm_event = wm8753_dpm_event,
+	.pcms = wm8753_pcm_clients,
+	.npcms = ARRAY_SIZE(wm8753_pcm_clients),
 };	
 
 static int __init wm8753_init(void)
 {	
-	return snd_soc_register_codec(&wm8753_soc_codec);
+	int ret = 0;
+	
+	info("WM8753 Audio Codec %s", WM8753_VERSION);
+
+	if ((ret = i2c_add_driver(&wm8753_i2c_driver)) != 0) {
+		err("can't add i2c driver");
+		return ret;
+	}
+	
+	if(!wm8753_i2c) {
+		err("can't find chip on i2c bus");
+		i2c_del_driver(&wm8753_i2c_driver);
+		return -ENODEV;
+	}
+	
+	if((ret = snd_soc_register_codec(&wm8753_soc_codec)) < 0) {
+		err("can't register driver");
+		i2c_del_driver(&wm8753_i2c_driver);
+		return ret;
+	}
+	return ret;
 }
 
 static void __exit wm8753_exit(void)
 {
 	snd_soc_unregister_codec(&wm8753_soc_codec);
+	i2c_del_driver(&wm8753_i2c_driver);
 }
 
 module_init(wm8753_init);
diff --git a/sound/soc/codecs/wm9713-voice.c b/sound/soc/codecs/wm9713-voice.c
index 1b1445f..0792288 100644
--- a/sound/soc/codecs/wm9713-voice.c
+++ b/sound/soc/codecs/wm9713-voice.c
@@ -213,8 +213,8 @@ static int wm9713_soc_probe(snd_soc_code
 {
 	int ret;
 
-	ret = snd_soc_pcm_new(codec, 0, &wm9713_voice_client, 
-			&wm9713.pcm_voice, 1, 1, SND_SOC_SSP, 1);
+	//ret = snd_soc_pcm_new(codec, 0, &wm9713_voice_client, 
+	//		&wm9713.pcm_voice, 1, 1, SND_SOC_SSP, 1);
 	return ret;
 }
 
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 7b4eb22..38a5d4d 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -33,3 +33,15 @@ config SND_PXA2xx_SOC_SSP
 	help
 	  Say Y or M if you want to add support for PCM codecs attached to
 	  the PXA2xx SSP interface.
+
+# Supported machines
+menu "PXA2xx machine support"
+depends on SND_PXA2xx_SOC
+
+config SND_PXA2xx_SOC_MAINSTONE
+	tristate "SoC Audio support for Intel Mainstone"
+	depends on SND_PXA2xx_SOC
+	help
+	  Say Y or M if you want to add support for SoC audio on Mainstone.
+	  
+endmenu
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index d6f1fe5..f68febe 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -3,8 +3,11 @@ snd-pxa2xx-soc-objs := pxa2xx-pcm.o 
 snd-pxa2xx-soc-ac97-objs := pxa2xx-ac97.o 
 snd-pxa2xx-soc-i2s-objs := pxa2xx-i2s.o 
 snd-pxa2xx-soc-ssp-objs := pxa2xx-ssp.o
+snd-pxa2xx-soc-mainstone-objs := mainstone.o
 
 obj-$(CONFIG_SND_PXA2xx_SOC) += snd-pxa2xx-soc.o
 obj-$(CONFIG_SND_PXA2xx_SOC_AC97) += snd-pxa2xx-soc-ac97.o
 obj-$(CONFIG_SND_PXA2xx_SOC_I2S) += snd-pxa2xx-soc-i2s.o
 obj-$(CONFIG_SND_PXA2xx_SOC_SSP) += snd-pxa2xx-soc-ssp.o
+
+obj-$(CONFIG_SND_PXA2xx_SOC_MAINSTONE) += snd-pxa2xx-soc-mainstone.o
\ No newline at end of file
diff --git a/sound/soc/pxa/mainstone.c b/sound/soc/pxa/mainstone.c
new file mode 100644
index 0000000..2fe67a2
--- /dev/null
+++ b/sound/soc/pxa/mainstone.c
@@ -0,0 +1,144 @@
+/*
+ * mainstone.c  --  SoC audio for Mainstone
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  Mainstone audio amplifier code taken from arch/arm/mainstone.c
+ *  Copyright:	MontaVista Software Inc.
+ * 
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    30th Oct 2005   Initial version.
+ * 
+ * Todo:
+ *  o Try and reduce amplifier pop....
+ */
+ 
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mainstone.h>
+#include <asm/arch/audio.h>
+
+struct audio_codecs_ {
+	char *name;
+	int interface;
+	int int_num;
+};
+
+/* I've added all my different configs here atm */
+static struct audio_codecs_ codecs[] = {
+	{.name = "WM8753 HiFi", SND_SOC_I2S, 0},
+	{.name = "WM8753 Voice", SND_SOC_SSP, 1},
+	{.name = "AC97 Audio", SND_SOC_AC97, 0},
+};
+
+static int mainstone_startup(snd_pcm_substream_t *substream)
+{
+	snd_soc_pcm_codec_t *pcm_c = substream->private_data;
+	snd_soc_pcm_interface_t *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;
+		MST_MSCWR2 &= ~MST_MSCWR2_USB_OTG_RST;
+	}
+	return 0;
+}
+
+static void mainstone_shutdown(snd_pcm_substream_t *substream)
+{
+	snd_soc_pcm_codec_t *pcm_c = substream->private_data;
+	snd_soc_pcm_interface_t *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;
+		MST_MSCWR2 |= MST_MSCWR2_USB_OTG_RST;
+	}
+}
+
+static struct snd_soc_ops mainstone_ops = {
+	.startup = mainstone_startup,
+	.shutdown = mainstone_shutdown,
+};
+
+static long mst_audio_suspend_mask;
+
+static int mainstone_suspend(snd_soc_machine_t *machine, pm_message_t state)
+{
+	mst_audio_suspend_mask = MST_MSCWR2;
+	MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_resume(snd_soc_machine_t *machine)
+{
+	MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_probe(snd_soc_machine_t *machine)
+{
+	int i, ret = 0;
+
+	for(i = 0; i < ARRAY_SIZE(codecs); i++) {
+		if((ret = snd_soc_pcm_connect(machine, codecs[i].name, 
+			codecs[i].interface, codecs[i].int_num)) < 0) {
+			printk(KERN_ERR "soc: failed to create new pcm for %s\n", codecs[i].name);
+		}
+	}
+	
+	return snd_soc_pcm_register(machine, "WM8753");
+}
+
+static int mainstone_remove(snd_soc_machine_t *machine)
+{
+	return 0;
+}
+
+static struct snd_soc_machine mainstone = {
+	.name = "Mainstone",
+	.probe = mainstone_probe,
+	.remove = mainstone_remove,
+	.suspend = mainstone_suspend,
+	.resume = mainstone_resume,
+	.ops = &mainstone_ops,
+};
+
+static int __init snd_soc_init(void) 
+{
+	return snd_soc_register_machine(&mainstone);
+}
+
+static void __exit snd_soc_exit(void) 
+{
+	snd_soc_unregister_machine(&mainstone);
+}
+
+module_init(snd_soc_init); 
+module_exit(snd_soc_exit);
+
+/* Module information */ 
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC Mainstone");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 15c156d..24a64a0 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -181,11 +181,11 @@ static int pxa2xx_i2s_hw_params(snd_pcm_
 			SACR1 &= ~SACR1_DREC;
 			SAIMR |= SAIMR_RFS;
 		}
-		
-		SADIV = get_sadiv(pcm_i->hw_runtime.rate);
-		SACR0 |= SACR0_ENB;
 	}
 	
+	SADIV = get_sadiv(pcm_i->hw_runtime.rate);
+	SACR0 |= SACR0_ENB;
+	
 	return 0;
 }
 
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index ff691c3..a8a3e64 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -50,9 +50,6 @@ struct pxa2xx_runtime_data {
 	dma_addr_t dma_desc_array_phys;
 };
 
-static struct device* pxa2xx_dev = NULL;
-static pxa2xx_audio_ops_t *platform_ops = NULL;
-
 static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id, struct pt_regs *regs)
 {
 	snd_pcm_substream_t *substream = dev_id;
@@ -83,7 +80,7 @@ static int pxa2xx_pcm_hw_params(snd_pcm_
 	pxa_dma_desc *dma_desc;
 	dma_addr_t dma_buff_phys, next_desc_phys;
 	int ret;
-	
+
 	rtd->params = dma;
 	ret = pxa_request_dma(rtd->params->name, DMA_PRIO_LOW,
 			      pxa2xx_pcm_dma_irq, substream);
@@ -179,6 +176,7 @@ static snd_pcm_uframes_t pxa2xx_pcm_poin
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	struct pxa2xx_runtime_data *rtd = runtime->private_data;
+
 	dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
 			 DSADR(rtd->dma_ch) : DTADR(rtd->dma_ch);
 	snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
@@ -213,7 +211,7 @@ static int pxa2xx_pcm_open(snd_pcm_subst
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	struct pxa2xx_runtime_data *rtd;
 	int ret;
-	
+
 	snd_soc_set_runtime_hw(substream, &pxa2xx_pcm_hardware);
 
 	/*
@@ -245,9 +243,6 @@ static int pxa2xx_pcm_open(snd_pcm_subst
 		goto err1;
 
 	runtime->private_data = rtd;
-
-	if (platform_ops && platform_ops->startup)
-		platform_ops->startup(substream, platform_ops->priv);
 	return 0;
 
  err1:
@@ -259,10 +254,6 @@ static int pxa2xx_pcm_open(snd_pcm_subst
 static int pxa2xx_pcm_close(snd_pcm_substream_t *substream)
 {
 	struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
-	
-	if (platform_ops && platform_ops->shutdown)
-		platform_ops->shutdown(substream, platform_ops->priv);
-		
 	dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
 			      rtd->dma_desc_array, rtd->dma_desc_array_phys);
 	kfree(rtd);
@@ -317,35 +308,37 @@ static void pxa2xx_pcm_free_dma_buffers(
 		substream = pcm->streams[stream].substream;
 		if (!substream)
 			continue;
+			
 		buf = &substream->dma_buffer;
 		if (!buf->area)
 			continue;
+		
 		dma_free_writecombine(pcm->card->dev, buf->bytes,
 				      buf->area, buf->addr);
-		buf->area = NULL;
+		buf->area = NULL;	
 	}
 }
 
 static u64 pxa2xx_pcm_dmamask = 0xffffffff;
 
-int pxa2xx_pcm_new(snd_card_t *card, snd_soc_pcm_codec_t *pcm_c,
-	int play, int capt, snd_pcm_t *pcm)
+int pxa2xx_pcm_new(snd_card_t *card, snd_soc_pcm_codec_t *pcm_c, snd_pcm_t *pcm)
 {
 	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)
 		card->dev->coherent_dma_mask = 0xffffffff;
 
-	if (play) {
+	if (pcm_c->nplayback) {
 		ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
 		if (ret)
 			goto out;
 	}
 
-	if (capt) {
+	if (pcm_c->ncapture) {
 		ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
 		if (ret)
 			goto out;
@@ -358,15 +351,11 @@ snd_soc_platform_t pxa2xx_soc_platform;
 
 static int pxa2xx_soc_probe(struct device *dev)
 {
-	pxa2xx_dev = dev;
-	platform_ops = pxa2xx_dev->platform_data;
 	return 0;
 }
 
 static int pxa2xx_soc_remove(struct device *dev)
 {
-	pxa2xx_dev = NULL;
-	platform_ops = NULL;
 	return 0;
 }
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 8dd5a83..1da29ac 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -15,9 +15,11 @@
  *    25th Oct 2005   Working Codec, Interface and Platform registration.
  *
  *  TODO:
- *   o Add machine layer.
- *   o Should probably add hw rules to enforce rates, etc.
- *   o Testing.....
+ *   o Finish machine layer - move machine stuff out pxa2xx-pcm.c
+ *   o Make codec info const and copy on registration (e.g. kcontrols)
+ *   o Change away from ALSA pm callbacks and types for 2.6.15
+ *   o Add hw rules to enforce rates, etc.
+ *   o More testing with other codecs/machines.
  *   o Add more codecs and platforms to ensure good API coverage.
  *   o Support TDM on PCM and I2S
  */
@@ -39,7 +41,7 @@
 #include <sound/soc-dpm.h>
 #include <sound/initval.h>
 
-#define SND_SOC_VERSION "0.3"
+#define SND_SOC_VERSION "0.4"
 
 #define iface_name(x) \
 	(((x) == SND_SOC_AC97) ? "ac97" : \
@@ -50,6 +52,7 @@ static DECLARE_MUTEX(soc_sem);
 static LIST_HEAD(codecs);
 static LIST_HEAD(interfaces);
 static struct snd_soc_platform *platform = NULL;
+static struct snd_soc_machine *machine = NULL;
 
 
 int snd_soc_update_bits(snd_soc_codec_t *codec, unsigned short reg,
@@ -160,6 +163,9 @@ static int soc_pcm_open(snd_pcm_substrea
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	int ret = 0;
 
+	if(!machine || !platform)
+		return -ENODEV;
+	
 	/* Check that the codec and SoC audio interface's are compatible */
 	if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		runtime->hw.rates = pcm_c->playback.rates & pcm_i->playback.rates;
@@ -209,6 +215,13 @@ static int soc_pcm_open(snd_pcm_substrea
 			goto platform_err;
 		}
 	}
+	
+	if(machine->ops->startup) {
+		if((ret = machine->ops->startup(substream)) < 0) {
+			printk(KERN_ERR "soc: %s startup failed\n", machine->name);
+			goto machine_err;
+		}
+	}
 
 	if(pcm_c->ops.startup) {
 		if((ret = pcm_c->ops.startup(substream)) < 0) {
@@ -223,6 +236,10 @@ pcm_err:
 	if(pcm_c->ops.shutdown)
 		pcm_c->ops.shutdown(substream);
 	
+machine_err:
+	if(machine->ops->shutdown)
+		machine->ops->shutdown(substream);
+	
 platform_err:
 	if(platform->pcm_ops->close)
 		platform->pcm_ops->close(substream);
@@ -246,6 +263,9 @@ static int soc_pcm_close(snd_pcm_substre
 	if(pcm_c->ops.shutdown)
 		pcm_c->ops.shutdown(substream);
 	
+	if(machine->ops->shutdown)
+		machine->ops->shutdown(substream);
+	
 	if(platform->pcm_ops->close)
 		platform->pcm_ops->close(substream);
 
@@ -334,11 +354,18 @@ static int soc_pcm_hw_params(snd_pcm_sub
 		}
 	}
 	
-	snd_soc_dpm_codec_event(codec, SND_SOC_DPM_CODEC_ON);
+	if(codec->dpm_event)
+		codec->dpm_event(codec, SNDRV_CTL_POWER_D1);
+	
+	snd_soc_dpm_codec_event(codec, SNDRV_CTL_POWER_D1);
 	if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		snd_soc_dpm_stream_event(codec, pcm_c->playback.sname, SND_SOC_DPM_STREAM_START);
 	else
 		snd_soc_dpm_stream_event(codec, pcm_c->capture.sname, SND_SOC_DPM_STREAM_START);
+		
+	if(codec->dpm_event)
+		codec->dpm_event(codec, SNDRV_CTL_POWER_D0);
+		
 	return ret;
 	
 platform_err:
@@ -352,13 +379,7 @@ interface_err:
 codec_err:
 	if(pcm_c->ops.hw_free)
 		pcm_c->ops.hw_free(substream);
-	snd_soc_dpm_codec_event(codec, SND_SOC_DPM_CODEC_OFF);
-	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);
-	
-	
+
 	return ret;
 }
 
@@ -378,7 +399,10 @@ static int soc_pcm_hw_free(snd_pcm_subst
 	if(platform->pcm_ops->hw_free)
 		platform->pcm_ops->hw_free(substream);
 	
-	snd_soc_dpm_codec_event(codec, SND_SOC_DPM_CODEC_OFF);
+	if(codec->dpm_event)
+		codec->dpm_event(codec, SNDRV_CTL_POWER_D3hot);
+		
+	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
@@ -404,13 +428,13 @@ static snd_pcm_ops_t soc_pcm_ops = {
 static int soc_suspend(snd_card_t *card, pm_message_t state)
 {
 	snd_soc_codec_t *c = card->pm_private_data;
-	snd_soc_pcm_interface_t *i = c->interface;
+	//snd_soc_pcm_interface_t *i = c->interface;
 	
-	snd_pcm_suspend_all(c->pcm);
+	//snd_pcm_suspend_all(c->pcm);
 	if(c->suspend)
 		c->suspend(c, state);
-	if(i->suspend)
-		i->suspend(i, state);
+	//if(i->suspend)
+	//	i->suspend(i, state);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
 	
 	return 0;
@@ -419,12 +443,12 @@ static int soc_suspend(snd_card_t *card,
 static int soc_resume(snd_card_t * card)
 {
 	snd_soc_codec_t *c = card->pm_private_data;
-	snd_soc_pcm_interface_t *i = c->interface;
+	//snd_soc_pcm_interface_t *i = c->interface;
 	
 	if(c->resume)
 		c->resume(c);
-	if(i->resume)
-		i->resume(i);
+	//if(i->resume)
+	//	i->resume(i);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 
 	return 0;
@@ -439,9 +463,6 @@ static int soc_probe_codec(snd_soc_codec
 {
 	int ret = 0;
 	
-	if(codec->probed)
-		return 0;
-	
 	/* register a sound card */
 	codec->card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, codec->owner, 0);
 	if (!codec->card) {
@@ -453,28 +474,9 @@ static int soc_probe_codec(snd_soc_codec
 	codec->card->dev = &codec->pdev.dev;
 	codec->card->private_data = codec;
 	strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
-		
-	if((ret = codec->probe(codec)) < 0)
-		goto err;
-	if(!codec->interface)
-		goto err;
-		
-	snprintf(codec->card->shortname, sizeof(codec->card->shortname),
-		 "%s", codec->name);
-	snprintf(codec->card->longname, sizeof(codec->card->longname),
-		 "%s (%s)", codec->longname, "SoC");
-	
-	if((ret = snd_card_register(codec->card)) < 0) {
-		printk(KERN_ERR "soc: failed to register soundcard for codec %s\n", codec->name);
+
+	if(codec->probe && (ret = codec->probe(codec)) < 0)
 		goto err;
-	}
-		
-	if(codec->interface->probe)
-		if((ret = codec->interface->probe(codec->interface)) < 0)
-			goto err;
-			
-	snd_soc_dpm_sys_add(&codec->pdev.dev);
-	snd_card_set_pm_callback(codec->card, soc_suspend, soc_resume, codec);		     
 	codec->probed = 1;
 	return 0;
 	
@@ -514,23 +516,22 @@ static void soc_free_dpm_widgets(snd_soc
 
 static int soc_remove_codec(snd_soc_codec_t *codec)
 {	
-	if (!codec->probed)
+	if(!codec->probed)
 		return 0;
 	
 	if (codec->card) {
+		snd_soc_dpm_sys_remove(&codec->pdev.dev);
 		snd_card_free(codec->card);
 		platform_device_unregister(&codec->pdev);
 		codec->card = NULL;
 	}
+	if(codec->remove)
+		codec->remove(codec);
 
-	if(codec->interface->remove)
-		codec->interface->remove(codec->interface);
-	codec->remove(codec);
-	snd_soc_dpm_sys_remove(&codec->pdev.dev);
-	
 	/* free any DPM objects */
 	soc_free_dpm_widgets(codec);
 	codec->probed = 0;
+
 	return 0;
 }
 
@@ -542,13 +543,16 @@ int snd_soc_register_codec(snd_soc_codec
 	INIT_LIST_HEAD(&codec->list);
 	INIT_LIST_HEAD(&codec->dpm_widgets);
 	INIT_LIST_HEAD(&codec->dpm_paths);
-	list_add(&codec->list, &codecs);
-
-	if (platform)
-		ret = soc_probe_codec(codec);
 	
+	if((ret = soc_probe_codec(codec)) < 0) {
+		printk(KERN_ERR "soc: probe of codec %s failed\n", codec->name);
+		up(&soc_sem);
+		return ret;
+	}
+
+	list_add(&codec->list, &codecs);	
 	up(&soc_sem);
-	return 0;
+	return ret;
 }
 
 void snd_soc_unregister_codec(snd_soc_codec_t *codec)
@@ -561,7 +565,16 @@ void snd_soc_unregister_codec(snd_soc_co
 
 int snd_soc_register_interface(snd_soc_pcm_interface_t *iface)
 {	
-	down (&soc_sem);
+	int ret = 0;
+	
+	down(&soc_sem);
+	
+	if(iface->probe && (ret = iface->probe(iface)) < 0) {
+		printk(KERN_ERR "soc: probe of interface %s failed\n", iface->name);
+		up(&soc_sem);
+		return ret;
+	}		
+
 	INIT_LIST_HEAD(&iface->list);
 	list_add(&iface->list, &interfaces);
 	up(&soc_sem);
@@ -572,7 +585,7 @@ void snd_soc_unregister_interface(snd_so
 {
 	down(&soc_sem);
 	list_del_init(&iface->list);
-	if (platform && iface->remove) 
+	if (iface->remove) 
 		iface->remove(iface);
 	up(&soc_sem);	
 }
@@ -581,15 +594,14 @@ static struct device_driver soc_pdrv;
 
 int snd_soc_register_platform(snd_soc_platform_t *p)
 {
-	struct list_head *l;
-	snd_soc_codec_t *c;
-	int ret;
+	int ret = 0;
 	
 	down(&soc_sem);
 	if(platform) {
 		up(&soc_sem);
 		return -EBUSY;
 	}
+
 	platform = p;
 	soc_pcm_ops.mmap = p->pcm_ops->mmap;
 	soc_pcm_ops.pointer = p->pcm_ops->pointer;
@@ -598,116 +610,191 @@ int snd_soc_register_platform(snd_soc_pl
 	soc_pdrv.name = p->name;
 	soc_pdrv.probe = p->probe;
 	soc_pdrv.remove = p->remove;
-		
+
 	if((ret = driver_register(&soc_pdrv)) < 0) {
 		printk(KERN_ERR "soc: failed to register platform %s\n", p->name);
 		up(&soc_sem);
 		return ret;
 	}
+
+	up(&soc_sem);
+	return ret;
+}
+
+void snd_soc_unregister_platform(snd_soc_platform_t *p)
+{
+	struct list_head *l;
+	snd_soc_codec_t *c = NULL;
+		
+	down(&soc_sem);
+	driver_unregister(&soc_pdrv);
 	
 	list_for_each(l, &codecs) {
 		c = list_entry(l, snd_soc_codec_t, list);
-		ret = soc_probe_codec(c);
-		if (ret < 0)
-			printk(KERN_ERR "soc: probe of codec %s failed\n", c->name);
+		soc_remove_codec(c);
 	}
-	up(&soc_sem);
 	
+	platform = NULL;
+	up(&soc_sem);	
+}
+
+int snd_soc_register_machine(snd_soc_machine_t *m)
+{
+	int ret = 0;
+
+	down(&soc_sem);
+	if(m->probe) {
+		if((ret = m->probe(m)) < 0) {
+			up(&soc_sem);
+			return ret;
+		}
+	}
+	machine = m;
+	up(&soc_sem);
 	return 0;
 }
 
-void snd_soc_unregister_platform(snd_soc_platform_t *platform)
+void snd_soc_unregister_machine(snd_soc_machine_t *m)
+{
+	down(&soc_sem);
+	if(machine->remove)
+		machine->remove(m);
+	machine = NULL;
+	up(&soc_sem);
+}
+
+/* find codec from pcm name */
+static snd_soc_codec_t * soc_get_codec_from_pcm(char *pcm_name, snd_soc_pcm_codec_t **pcm_c)
 {
 	struct list_head *l;
-	snd_soc_codec_t *c;
+	snd_soc_codec_t *c = NULL;
 
-	down(&soc_sem);
 	list_for_each(l, &codecs) {
+		int i = 0;
 		c = list_entry(l, snd_soc_codec_t, list);
-		soc_remove_codec(c);
+
+		if(c->npcms == 0)
+			continue;
+			
+		for(;i < c->npcms; i++) {
+			if(!strcmp(pcm_name, c->pcms[i].name)) {
+				if(pcm_c)
+					*pcm_c = &c->pcms[i];
+				return c;
+			}
+		}
 	}
 	
-	driver_unregister(&soc_pdrv);
-	platform = NULL;
-	up(&soc_sem);	
+	return NULL;
 }
 
-int snd_soc_pcm_new(snd_soc_codec_t *codec, int dev_no, snd_soc_pcm_codec_t *pcm_c, 
-		snd_pcm_t **rpcm, int play, int capt, int iface_type, int num)
+static snd_soc_codec_t * soc_get_codec(char *name)
+{
+	struct list_head *l;
+	snd_soc_codec_t *c = NULL;
+
+	list_for_each(l, &codecs) {
+		c = list_entry(l, snd_soc_codec_t, list);
+			
+		if(!strcmp(name, c->name))
+			return c;
+	}
+	
+	return NULL;
+}
+
+static snd_soc_pcm_interface_t* soc_get_interface(int iface_type, int num)
 {
-	snd_pcm_t *pcm;
-	snd_card_t *card = codec->card;
-	int ret;
 	struct list_head *l;
 	snd_soc_pcm_interface_t *i = NULL;
-	char name[32];
 	
-	down(&soc_sem);
 	list_for_each(l, &interfaces) {
 		i = list_entry(l, snd_soc_pcm_interface_t, list);
 		if (i->type == iface_type && i->id == num){
-			if (i->pcm_c){
-				up(&soc_sem);
-				return -EBUSY;
-			} else
-				break;	
+			if (i->pcm_c)
+				return NULL;
+			else
+				return i;
 		}
 	}
+	return NULL;
+}
+
+int snd_soc_pcm_connect(snd_soc_machine_t *machine, char *name, int iface_type, int num)
+{
+	snd_pcm_t *pcm;
+	snd_soc_pcm_codec_t *pcm_c;
+	int ret = 0;
+	snd_soc_pcm_interface_t *iface;
+	snd_soc_codec_t *codec;
+	char new_name[32];
+	
+	if((codec = soc_get_codec_from_pcm(name, &pcm_c)) == NULL) {
+		printk(KERN_ERR "soc: can't find codec pcm %s\n", name);
+		return -ENODEV;
+	}
+	
+	if((iface = soc_get_interface(iface_type, num)) == NULL) {
+		printk(KERN_ERR "soc: can't find %s interface %d\n", iface_name(iface_type), num);
+		return -ENODEV;
+	}
 	
 	/* check client and interface hw capabilities */
-	pcm_c->pcm_i = i;
-	i->card = card;
-	i->pcm_c = pcm_c;
-	codec->interface = i;
-	sprintf(name, "%s-%s-%d", pcm_c->name, iface_name(iface_type), num);
-	if((ret = snd_pcm_new(card, name, dev_no, play, capt, &pcm)) < 0) {
+	sprintf(new_name, "%s-%s-%d", pcm_c->name, iface_name(iface_type), num);
+	if((ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, pcm_c->nplayback, pcm_c->ncapture, &pcm)) < 0) {
 		printk(KERN_ERR "soc: can't create pcm for codec %s\n", codec->name);
 		goto err;
 	}
-
+	pcm_c->pcm_i = iface;
+	iface->card = codec->card;
+	iface->pcm_c = pcm_c;
 	pcm->private_data = pcm_c;
-	if (play)
+		
+	if (pcm_c->nplayback)
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
 
-	if (capt)
+	if (pcm_c->ncapture)
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
 
-	if((ret = platform->pcm_new(card, pcm_c, play, capt, pcm)) < 0) {
+	if((ret = platform->pcm_new(codec->card, pcm_c, pcm)) < 0) {
 		printk(KERN_ERR "soc: platform pcm constructor failed\n");
 		goto err;
 	}
 	
-	codec->pcm = pcm;
-	if (rpcm)
-		*rpcm = pcm;
-
-	printk(KERN_INFO "soc: %s <-> %s mapping ok\n", pcm_c->name, i->name);
-	up(&soc_sem);
-	return 0;
+	printk(KERN_INFO "soc: %s <-> %s mapping ok\n", pcm_c->name, iface->name);
+	return ret;
 	
 err:
 	pcm_c->pcm_i = NULL;
-	i->card = NULL;
-	i->pcm_c = NULL;
-	codec->interface = NULL;
-	up(&soc_sem);
+	iface->card = NULL;
+	iface->pcm_c = NULL;
 	return ret;
 }
 
-int snd_soc_iface_query(int iface_type, int num)
+int snd_soc_pcm_register(snd_soc_machine_t *machine, char *name)
 {
-	struct list_head *l;
-	snd_soc_pcm_interface_t *i;
+	snd_soc_codec_t * codec;
+	int ret = 0;
 
-	list_for_each(l, &interfaces) {
-		i = list_entry(l, snd_soc_pcm_interface_t, list);
-		if (i->type == iface_type && i->id == num){
-			up(&soc_sem);
-			return 0;
-		}
+	if((codec = soc_get_codec(name)) == NULL)
+		return -ENODEV;
+	
+	snprintf(codec->card->shortname, sizeof(codec->card->shortname),
+		 "%s", codec->name);
+	snprintf(codec->card->longname, sizeof(codec->card->longname),
+		 "%s (%s)", codec->longname, "SoC");
+	
+	snd_card_set_pm_callback(codec->card, soc_suspend, soc_resume, codec);
+	
+	if((ret = snd_card_register(codec->card)) < 0) {
+		printk(KERN_ERR "soc: failed to register soundcard for codec %s\n", codec->name);
+		return ret;
 	}
+	
+	codec->pdev.dev.driver_data = codec;
+	snd_soc_dpm_sys_add(&codec->pdev.dev);
 
-	return -ENODEV;
+	return ret;	
 }
 
 int snd_soc_set_runtime_hw(snd_pcm_substream_t *substream, const snd_pcm_hardware_t *hw)
@@ -873,8 +960,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec
 EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
 EXPORT_SYMBOL_GPL(snd_soc_register_platform);
 EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
-EXPORT_SYMBOL_GPL(snd_soc_pcm_new);
-EXPORT_SYMBOL_GPL(snd_soc_iface_query);
+EXPORT_SYMBOL_GPL(snd_soc_pcm_connect);
 EXPORT_SYMBOL_GPL(snd_soc_register_interface);
 EXPORT_SYMBOL_GPL(snd_soc_unregister_interface);
 EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hw);
@@ -887,7 +973,9 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
 EXPORT_SYMBOL_GPL(snd_soc_update_bits);
 EXPORT_SYMBOL_GPL(snd_soc_test_bits);
-
+EXPORT_SYMBOL_GPL(snd_soc_register_machine);
+EXPORT_SYMBOL_GPL(snd_soc_unregister_machine);
+EXPORT_SYMBOL_GPL(snd_soc_pcm_register);
 
 /* Module information */ 
 MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
diff --git a/sound/soc/soc-dpm.c b/sound/soc/soc-dpm.c
index 91ab5af..9c304f7 100644
--- a/sound/soc/soc-dpm.c
+++ b/sound/soc/soc-dpm.c
@@ -20,9 +20,6 @@
  *      DAC's/ADC's.
  * 
  *  Todo:
- *    o Codec dpm event notification. e.g. mute DAC's to stop pops
- *    o sysfs dpm status.
- *    o VMID selection.
  *    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
@@ -49,7 +46,7 @@
 #include <sound/initval.h>
 
 
-static int dpm_status = 0;
+static int dpm_status = 1;
 module_param(dpm_status, int, 0);
 MODULE_PARM_DESC(dpm_status, "enable DPM sysfs entries");
 
@@ -111,6 +108,7 @@ static void dpm_set_path_status(snd_soc_
 		case snd_soc_dpm_dac:
 		case snd_soc_dpm_clock:
 		case snd_soc_dpm_vref:	
+		case snd_soc_dpm_mic:
 			p->connect = 1;
 		break;
 	}
@@ -206,7 +204,8 @@ int snd_soc_dpm_connect_input(snd_soc_co
 		case snd_soc_dpm_input:
 		case snd_soc_dpm_output:
 		case snd_soc_dpm_clock:
-		case snd_soc_dpm_vref:	
+		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);
@@ -230,7 +229,6 @@ err:
 	return ret;
 }
 
-
 static int dpm_update_bits(snd_soc_dpm_widget_t *widget, int power)
 {
 	int change;
@@ -248,8 +246,13 @@ static int dpm_update_bits(snd_soc_dpm_w
 	new = (old & ~(0x1 << widget->shift)) | (power << widget->shift);
 	
 	change = old != new;
-	if (change)
+	if (change) {
 		snd_soc_write(codec, widget->reg, new);
+		if (!widget->invert)
+			widget->power = power;
+		else
+			widget->power = power ? 0:1;
+	}
 
 	return change;
 }
@@ -491,40 +494,39 @@ static int dpm_mixer_update_power(snd_so
 	return 0;
 }
 
-#if 0
-#define DPM_STATUS_ATTR(name) \
-static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf)   \
-{ \
-	snd_soc_codec_t *codec = (snd_soc_codec_t*)dev->driver_data; \
-	snd_soc_dpm_widget_t *w = NULL; 	\
-	struct list_head *l = NULL; 	\
-	int count = 0; 	\
-					\
-	list_for_each(l, &codec->dpm_widgets) \
-	{ \
-		w = list_entry(l, snd_soc_dpm_widget_t, list); \
-		count += sprintf(buf, "%s: %s\n", w->name, w->power ? "On":"Off");	\
-	} \
-	return count;\
-} \
-static DEVICE_ATTR(name, 0444, name##_show, NULL)
-		     
-DPM_STATUS_ATTR(dpm_status);
-#endif
+static ssize_t dpm_status_show(struct device *dev, struct device_attribute *attr, char *buf)   \
+{
+	snd_soc_codec_t *codec = (snd_soc_codec_t*)dev->driver_data;
+	snd_soc_dpm_widget_t *w = NULL;
+	struct list_head *l = NULL;
+	int count = 0; 
 
+	list_for_each(l, &codec->dpm_widgets)
+	{
+		w = list_entry(l, snd_soc_dpm_widget_t, list);
+		if (w->name && w->reg > 0 && 
+			w->id != snd_soc_dpm_input && w->id != snd_soc_dpm_output)
+			count += sprintf(buf + count, "%s: %s\n", w->name, w->power ? "On":"Off");
+	}
+	
+	return count;
+}
+
+static DEVICE_ATTR(dpm, 0444, dpm_status_show, NULL);
+		     
 int snd_soc_dpm_sys_add(struct device *dev) 
 {
 	int ret = 0;
-	
-//	if (dpm_status)
-//		ret = device_create_file(dev, &dev_attr_dpm_status);
+
+	if (dpm_status)
+		ret = device_create_file(dev, &dev_attr_dpm);
 	return ret;
 }	     
 
 void snd_soc_dpm_sys_remove(struct device *dev) 
 {
-	//if (dpm_status)
-	//	device_remove_file(dev, &dev_attr_dpm_status);
+	if (dpm_status)
+		device_remove_file(dev, &dev_attr_dpm);
 } 
 
 int snd_soc_dpm_sync(snd_soc_codec_t *codec)
@@ -549,7 +551,8 @@ int snd_soc_dpm_sync(snd_soc_codec_t *co
 			case snd_soc_dpm_input:
 			case snd_soc_dpm_output:
 			case snd_soc_dpm_clock:
-			case snd_soc_dpm_vref:				
+			case snd_soc_dpm_vref:
+			case snd_soc_dpm_mic:				
 				break;
 		}
 	}
@@ -649,7 +652,7 @@ int snd_soc_dpm_put_enum_double(snd_kcon
 int snd_soc_dpm_new_control(snd_soc_codec_t *codec, const snd_soc_dpm_widget_t *widget)
 {
 	snd_soc_dpm_widget_t *w;
-	
+
 	if ((w = dpm_cnew_widget(widget)) == NULL)
 		return -ENOMEM;
 
@@ -658,7 +661,6 @@ int snd_soc_dpm_new_control(snd_soc_code
 	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
 	
@@ -704,19 +706,19 @@ int snd_soc_dpm_codec_event(snd_soc_code
 	struct list_head *l = NULL;	
 	int pm = 0, active = 0;
 
-	if(event == SND_SOC_DPM_CODEC_ON) {
+	if(event == SNDRV_CTL_POWER_D1) {
 		if(codec->active_streams)
 			return 0;
 		pm = 1;
 		active = 1;
 	
-	} else if(event == SND_SOC_DPM_CODEC_OFF){
+	} else if(event == SNDRV_CTL_POWER_D3hot){
 		if(!codec->active_streams)
 			return 0;
 		pm = 0;
 		active = -1;
 	}
-
+		
 	list_for_each(l, &codec->dpm_widgets)
 	{
 		int tpm = pm;

