Index: linux-2.6.14/sound/soc/codecs/wm8731.c
===================================================================
--- linux-2.6.14.orig/sound/soc/codecs/wm8731.c	2005-11-02 09:59:20.000000000 +0000
+++ linux-2.6.14/sound/soc/codecs/wm8731.c	2005-11-02 15:05:26.000000000 +0000
@@ -33,7 +33,7 @@
 #include "wm8731.h"
 
 #define AUDIO_NAME "wm8731"
-#define WM8731_VERSION "0.1"
+#define WM8731_VERSION "0.2"
 
 
 /*
@@ -52,81 +52,68 @@
 #define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
 #define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
 
-
-
-/* 
- * WM8731 2 wire address is determined during powerup.
- *    low  = WM8731_2W_ADDR1
- *    high = WM8731_2W_ADDR2
- */
-#define WM8731_2W_ADDR1	0x1a
-#define WM8731_2W_ADDR2	0x1b
 #define I2C_DRIVERID_WM8731 0xf2fe
 
-
-static unsigned short normal_i2c[] = { WM8731_2W_ADDR1, WM8731_2W_ADDR2,
+static unsigned short normal_i2c[] = { 0x1a, 0x1b,
                                        I2C_CLIENT_END };
 
 /* Magic definition of all other variables and things */
 I2C_CLIENT_INSMOD;
 
-struct wm8731_ {
-	struct i2c_client *i2c;
-	snd_pcm_t *pcm_hifi;
-};
-static struct wm8731_ wm8731;
+struct i2c_client *wm8731_i2c;
 
 /*
  * wm8731 register cache
- * We can't read the WM8731 register space when we 
- * are using 2 wire for device control, so we cache them instead. 
+ * We can't read the WM8731 register space when we are
+ * using 2 wire for device control, so we cache them instead. 
+ * There is no point in caching the reset register
  */
-static u16 reg_cache[WM8731_RESET+1] = {
+static u16 reg_cache[WM8731_CACHEREGNUM] = {
     0x0023, 0x0023, 0x0121, 0x0121, 
     0x0012, 0x0000, 0x0000, 0x0000, 
-    0x0000, 0x0000, 0x0000, 0x0000, 
-    0x0000, 0x0000, 0x0000, 0x0000
+    0x0000, 0x0000, 0x0000
 };
 
-#define WM8731_HIFI_HWFMT \
+#define WM8731_HWFMT \
 	(SND_SOC_HWFMT_I2S | SND_SOC_HWFMT_LEFT_J | SND_SOC_HWFMT_RIGHT_J | \
-	SND_SOC_HWFMT_CBM_CFM | SND_SOC_HWFMT_CBS_CFS | \
+	SND_SOC_HWFMT_CBS_CFS | \
 	SND_SOC_HWFMT_NB_NF | SND_SOC_HWFMT_NB_IF | SND_SOC_HWFMT_IB_NF | \
 	SND_SOC_HWFMT_IB_IF)
+//	SND_SOC_HWFMT_CBS_CFM | 
 /*
  * priv1 is srate register setting
  */
-static snd_soc_hw_mode_t wm8731_hifi[] = {
+static snd_soc_hw_mode_t wm8731_hwfmt[] = {
 
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 8000 ,  64, 0x000c}, //256
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 8000,   96, 0x000e}, //384
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 8000 , 128, 0x004c}, //512
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 8000,  192, 0x004e}, //768
-
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 32000,  64, 0x0018}, //256
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 32000,  96, 0x001a}, //384
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 32000, 128, 0x0058}, //512
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 32000, 192, 0x005a}, //768
-
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 44100,  64, 0x0020}, //256
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 44100,  96, 0x0022}, //384
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 44100, 128, 0x0060}, //512
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 44100, 192, 0x0062}, //768
-
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 48000,  64, 0x0000}, //256
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 48000,  96, 0x0002}, //384
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 48000, 128, 0x0040}, //512
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 48000, 192, 0x0042}, //768
-
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 88200,  32, 0x003c}, //128
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 88200,  48, 0x003e}, //192
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 88200,  64, 0x007c}, //256
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 88200,  96, 0x007e}, //384
-
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 96000,  32, 0x001c}, //128
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 96000,  48, 0x001e}, //192
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 96000,  64, 0x005c}, //256
-	{WM8731_HIFI_HWFMT, SND_SOC_HWBITS(16), 96000,  96, 0x005e}, //384
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 8000 ,  64, 0x000c},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 8000,   96, 0x000e},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 8000 , 128, 0x004c},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 8000,  192, 0x004e},
+
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 32000,  64, 0x0018},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 32000,  96, 0x001a},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 32000, 128, 0x0058},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 32000, 192, 0x005a},
+
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 44100,  64, 0x0020},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 44100,  96, 0x0022},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 44100, 128, 0x0060},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 44100, 192, 0x0062},
+
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 48000,  64, 0x0000},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 48000,  96, 0x0002},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 48000, 128, 0x0040},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 48000, 192, 0x0042},
+
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 88200,  32, 0x003c},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 88200,  48, 0x003e},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 88200,  64, 0x007c},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 88200,  96, 0x007e},
+
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 96000,  32, 0x001c},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 96000,  48, 0x001e},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 96000,  64, 0x005c},
+	{WM8731_HWFMT, SND_SOC_HWBITS(16), 96000,  96, 0x005e},
 };
 
 
@@ -135,6 +122,10 @@
  */
 static inline unsigned int wm8731_read_reg_cache(u16 reg)
 {
+	if (reg == WM8731_RESET) 
+		return 0;
+	if (reg >= WM8731_CACHEREGNUM)
+		return -1;
 	return reg_cache[reg];
 }
 
@@ -144,7 +135,8 @@
 static inline void wm8731_write_reg_cache(u16 reg, unsigned int value)
 {
 	printk("wm8731: Writing %x to %x\n", value, reg);
-	reg_cache[reg] = value;
+	if (reg < WM8731_CACHEREGNUM)
+		reg_cache[reg] = value;
 }
 
 static struct i2c_client client_template;
@@ -155,22 +147,15 @@
  */
 static int wm8731_i2c_probe(struct i2c_adapter *adap, int addr, int kind)
 {		 
-    client_template.adapter = adap;
-    client_template.addr = addr;
+	client_template.adapter = adap;
+	client_template.addr = addr;
 	
-    if ((wm8731.i2c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)) == NULL)
-        return -ENOMEM;
+	if ((wm8731_i2c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)) == NULL)
+		return -ENOMEM;
 
-    memcpy(wm8731.i2c, &client_template, sizeof(struct i2c_client));
-	//wm8731_2w_client->data = (void*)&wm8731;
-	
-	if (wm8731_reset(wm8731.i2c) != 0) {
-		kfree (wm8731.i2c);
-		err("cannot reset the WM8731");
-		return -EIO;
-	}
+	memcpy(wm8731_i2c, &client_template, sizeof(struct i2c_client));
 
-    return i2c_attach_client(wm8731.i2c);
+	return i2c_attach_client(wm8731_i2c);
 }
 
 static int wm8731_i2c_detach(struct i2c_client *client)
@@ -216,6 +201,7 @@
 	data[1] = value & 0x00ff;
 
 	wm8731_write_reg_cache (reg, value);
+
 	if (i2c_master_send(client, data, 2) == 2)
 		return 0;
 	else
@@ -224,7 +210,7 @@
 
 static int wm8731_write (u16 reg, unsigned int value)
 {
-	return wm8731_2w_write(wm8731.i2c, reg, value);	
+	return wm8731_2w_write(wm8731_i2c, reg, value);	
 }
 
 /* 
@@ -236,173 +222,34 @@
 }
 
 static const char* wm8731_sidetone_att[] = {"-6dB", "-9dB", "-12dB", "-15dB"};
-
-/*
-static const char* wm8731_base[] = {"Linear Control", "Adaptive Boost"};
-static const char* wm8731_base_filter[] = 
-	{"130Hz @ 48kHz", "200Hz @ 48kHz", "100Hz @ 16kHz", "400Hz @ 48kHz", 
-	"100Hz @ 8kHz", "200Hz @ 8kHz"};
-static const char* wm8731_treble[] = {"8kHz", "4kHz"};
-static const char* wm8731_alc_func[] = {"Off", "Right", "Left", "Stereo"};
-static const char* wm8731_ng_type[] = {"Constant PGA Gain", "Mute ADC Output"};
-static const char* wm8731_3d_func[] = {"Capture", "Playback"};
-static const char* wm8731_3d_uc[] = {"2.2kHz", "1.5kHz"};
-static const char* wm8731_3d_lc[] = {"200Hz", "500Hz"};
-static const char* wm8731_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"};
-static const char* wm8731_mono_mix[] = {"Stereo", "Left", "Right", "Mono"};
-static const char* wm8731_dac_phase[] = {"Non Inverted", "Inverted"};
-static const char* wm8731_line_mix[] = {"Line 1 + 2", "Line 1 - 2", 
-	"Line 1", "Line 2"};
-static const char* wm8731_mono_mux[] = {"Line Mix", "Rx Mix"};
-static const char* wm8731_right_mux[] = {"Line 2", "Rx Mix"};
-static const char* wm8731_left_mux[] = {"Line 1", "Rx Mix"};
-static const char* wm8731_rxmsel[] = {"RXP - RXN", "RXP + RXN", "RXP", "RXN"};
-static const char* wm8731_sidetone_mux[] = {"Left PGA", "Mic 1", "Mic 2", "Right PGA"};
-static const char* wm8731_mono2_src[] = {"Inverted Mono 1", "Left", "Right", "Left + Right"};
-static const char* wm8731_out3[] = {"VREF", "ROUT2", "Left + Right"};
-static const char* wm8731_out4[] = {"VREF", "LOUT2", "Left + Right"};
-static const char* wm8731_radcsel[] = {"PGA", "Line 2 or RXP-RXN", "Left + Right + Mono Mix"};
-static const char* wm8731_ladcsel[] = {"PGA", "Line 1 or RXP-RXN", "Line 1 DC"};
-static const char* wm8731_mono_adc[] = {"Stereo", "Analogue Mix Left", "Analogue Mix Right",
-	"Digital Mono Mix"};
-static const char* wm8731_adc_hp[] = {"3.4Hz @ 48kHz", "82Hz @ 16k", "82Hz @ 8kHz", "170Hz @ 8kHz"};
-static const char* wm8731_adc_filter[] = {"HiFi", "Voice"};
-
-static const struct soc_enum wm8731_enum[] = {
-SOC_ENUM_SINGLE(WM8731_BASS, 7, 2, wm8731_base),
-SOC_ENUM_SINGLE(WM8731_BASS, 4, 6, wm8731_base_filter),
-SOC_ENUM_SINGLE(WM8731_TREBLE, 6, 2, wm8731_treble),
-SOC_ENUM_SINGLE(WM8731_ALC1, 7, 4, wm8731_alc_func),
-SOC_ENUM_SINGLE(WM8731_NGATE, 1, 2, wm8731_ng_type),
-SOC_ENUM_SINGLE(WM8731_3D, 7, 2, wm8731_3d_func),
-SOC_ENUM_SINGLE(WM8731_3D, 6, 2, wm8731_3d_uc),
-SOC_ENUM_SINGLE(WM8731_3D, 5, 2, wm8731_3d_lc),
-SOC_ENUM_SINGLE(WM8731_DAC, 1, 4, wm8731_deemp),
-SOC_ENUM_SINGLE(WM8731_DAC, 4, 4, wm8731_mono_mix),
-SOC_ENUM_SINGLE(WM8731_DAC, 6, 2, wm8731_dac_phase),
-SOC_ENUM_SINGLE(WM8731_INCTL1, 3, 4, wm8731_line_mix),
-SOC_ENUM_SINGLE(WM8731_INCTL1, 2, 2, wm8731_mono_mux),
-SOC_ENUM_SINGLE(WM8731_INCTL1, 1, 2, wm8731_right_mux),
-SOC_ENUM_SINGLE(WM8731_INCTL1, 0, 2, wm8731_left_mux),
-SOC_ENUM_SINGLE(WM8731_INCTL2, 6, 4, wm8731_rxmsel),
-SOC_ENUM_SINGLE(WM8731_INCTL2, 4, 4, wm8731_sidetone_mux),
-SOC_ENUM_SINGLE(WM8731_OUTCTL, 7, 4, wm8731_mono2_src),
-SOC_ENUM_SINGLE(WM8731_OUTCTL, 0, 3, wm8731_out3),
-SOC_ENUM_SINGLE(WM8731_OUTCTL, 0, 3, wm8731_out4),
-SOC_ENUM_SINGLE(WM8731_ADCIN, 2, 3, wm8731_radcsel),
-SOC_ENUM_SINGLE(WM8731_ADCIN, 0, 3, wm8731_ladcsel),
-SOC_ENUM_SINGLE(WM8731_ADCIN, 4, 4, wm8731_mono_adc),
-SOC_ENUM_SINGLE(WM8731_ADC, 2, 4, wm8731_adc_hp),
-SOC_ENUM_SINGLE(WM8731_ADC, 4, 2, wm8731_adc_filter),
-};*/
+static const char* wm8731_input_select[] = {"Line In", "Mic"};
 
 static const struct soc_enum wm8731_enum[] = {
-	SOC_ENUM_SINGLE(WM8731_APANA, 6, 2, wm8731_sidetone_att),
+	SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select),
+	SOC_ENUM_SINGLE(WM8731_APANA, 6, 4, wm8731_sidetone_att),
 };
 
 static const snd_kcontrol_new_t wm8731_snd_controls[] = {
-SOC_SINGLE("Left Out 1 Volume", WM8731_LOUT1V, 0, 127, 0),
-SOC_SINGLE("Left Out 1 ZC Switch", WM8731_LOUT1V, 7, 1, 0),
-SOC_SINGLE("Right Out 1 Volume", WM8731_ROUT1V, 0, 127, 0),
-SOC_SINGLE("Right Out 1 ZC Switch", WM8731_ROUT1V, 7, 1, 0),
-
-SOC_SINGLE("Capture Left Volume", WM8731_LINVOL, 0, 31, 0),
-SOC_SINGLE("Capture Left Switch", WM8731_LINVOL, 7, 1, 1),
-SOC_SINGLE("Capture Right Volume", WM8731_RINVOL, 0, 31, 0),
-SOC_SINGLE("Capture Right Switch", WM8731_RINVOL, 7, 1, 1),
-
-SOC_ENUM("Sidetone Attenuation", wm8731_enum[0]),
-SOC_SINGLE("Sidetone Switch", WM8731_APANA, 5, 1, 1),
-};
-
-/*
-Mic Boost Switch
-Mic Switch 
-*/
-
-
-
-	/*
-
-
-SOC_SINGLE("Right Out 2 Volume", WM8731_ROUT2V, 0, 127, 0),
-SOC_SINGLE("Right Out 2 ZC Switch", WM8731_ROUT2V, 7, 1, 0),
-
-SOC_SINGLE("Right Mux Right Mixer Volume", WM8731_ROUTM1, 4, 7, 1),
-
-SOC_SINGLE("Sidetone Right Mixer Volume", WM8731_ROUTM2, 4, 7, 1),
-SOC_SINGLE("Voice Right Mixer Volume", WM8731_ROUTM2, 0, 7, 1),
-
-SOC_SINGLE("Mono Mux Mono Mixer Volume", WM8731_MOUTM1, 4, 7, 1),
-SOC_SINGLE("Sidetone Mono Mixer Volume", WM8731_MOUTM2, 4, 7, 1),
-SOC_SINGLE("Voice Mono Mixer Volume", WM8731_MOUTM2, 4, 7, 1),
-
-SOC_SINGLE("Mono Volume", WM8731_MOUTV, 0, 127, 0),
-SOC_SINGLE("Mono ZC Switch", WM8731_MOUTV, 7, 1, 0),
-SOC_ENUM("Mono 2 Out", wm8731_enum[17]),
-
 
-SOC_SINGLE("Capture Right Mix Switch", WM8731_RECMIX1, 7, 1, 0),
-SOC_SINGLE("Capture Right Mix Volume", WM8731_RECMIX1, 4, 7, 1),
-SOC_SINGLE("Capture Left Mix Switch", WM8731_RECMIX1, 3, 1, 0),
-SOC_SINGLE("Capture Left Mix Volume", WM8731_RECMIX1, 0, 7, 1),
-SOC_SINGLE("Capture Mono Mix Switch", WM8731_RECMIX2, 3, 1, 0),
-SOC_SINGLE("Capture Mono Mix Volume", WM8731_RECMIX2, 0, 7, 1),
+SOC_SINGLE("Playback Left Volume", WM8731_LOUT1V, 0, 127, 0),
+SOC_SINGLE("Playback Left ZC Switch", WM8731_LOUT1V, 7, 1, 0),
+SOC_SINGLE("Playback Right Volume", WM8731_ROUT1V, 0, 127, 0),
+SOC_SINGLE("Playback Right ZC Switch", WM8731_ROUT1V, 7, 1, 0),
+
+SOC_SINGLE("Capture Line Left Volume", WM8731_LINVOL, 0, 31, 0),
+SOC_SINGLE("Capture Line Left Switch", WM8731_LINVOL, 7, 1, 1),
+SOC_SINGLE("Capture Line Right Volume", WM8731_RINVOL, 0, 31, 0),
+SOC_SINGLE("Capture Line Right Switch", WM8731_RINVOL, 7, 1, 1),
 
+SOC_SINGLE("Mic Boost Switch", WM8731_APANA, 0, 1, 0),
+SOC_SINGLE("Mic Switch", WM8731_APANA, 1, 1, 0),
 
+SOC_ENUM("Sidetone Attenuation", wm8731_enum[1]),
 
-SOC_ENUM("Capture Mono Mix", wm8731_enum[20]),
-SOC_ENUM("Capture Filter Select", wm8731_enum[22]),
-SOC_ENUM("Capture Filter Cut-off", wm8731_enum[21]),
-SOC_SINGLE("Capture Filter Switch", WM8731_ADC, 0, 1, 1),
+SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
+SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
 
-SOC_SINGLE("ALC Target Volume", WM8731_ALC1, 0, 7, 0),
-SOC_SINGLE("ALC Max Volume", WM8731_ALC1, 4, 7, 0),
-SOC_ENUM("ALC Function", wm8731_enum[3]),
-SOC_SINGLE("ALC ZC Switch", WM8731_ALC2, 8, 1, 0),
-SOC_SINGLE("ALC Hold Time", WM8731_ALC2, 0, 15, 1),
-SOC_SINGLE("ALC Decay Time", WM8731_ALC3, 4, 15, 1),
-SOC_SINGLE("ALC Attack Time", WM8731_ALC3, 0, 15, 0),
-SOC_SINGLE("ALC NG Threshold", WM8731_NGATE, 3, 31, 0),
-SOC_ENUM("ALC NG Type", wm8731_enum[4]),
-SOC_SINGLE("ALC NG Switch", WM8731_NGATE, 0, 1, 0),
-
-SOC_ENUM("3D Function", wm8731_enum[5]),
-SOC_ENUM("3D Upper Cut-off", wm8731_enum[6]),
-SOC_ENUM("3D Lower Cut-off", wm8731_enum[7]),
-SOC_SINGLE("3D Volume", WM8731_3D, 1, 15, 0),
-SOC_SINGLE("3D Switch", WM8731_3D, 0, 1, 0),
-
-SOC_SINGLE("ADC 6dB Attenuate", WM8731_ADCTL1, 2, 1, 0),
-SOC_SINGLE("DAC 6dB Attenuate", WM8731_ADCTL1, 1, 1, 0),
-
-SOC_ENUM("De-emphasis", wm8731_enum[8]),
-SOC_SINGLE("DAC Switch", WM8731_DAC, 3, 1, 1),
-
-SOC_ENUM("DAC Mono Mix", wm8731_enum[9]),
-SOC_ENUM("DAC Phase", wm8731_enum[10]),
-
-SOC_ENUM("Line Mix Select", wm8731_enum[11]),
-SOC_ENUM("Mono Mux Select", wm8731_enum[12]),
-SOC_ENUM("Right Mux Select", wm8731_enum[13]),
-SOC_ENUM("Left Mux Select", wm8731_enum[14]),
-
-SOC_ENUM("Differential Mix", wm8731_enum[15]),
-SOC_ENUM("Mic Sidetone Mux", wm8731_enum[16]),
-SOC_SINGLE("ALC Mix Line Switch", WM8731_INCTL2, 3, 1, 0),
-SOC_SINGLE("ALC Mix Mic 2 Switch", WM8731_INCTL2, 2, 1, 0),
-SOC_SINGLE("ALC Mix Mic 1 Switch", WM8731_INCTL2, 1, 1, 0),
-SOC_SINGLE("ALC Mix Rx Switch", WM8731_INCTL2, 0, 1, 0),
-
-SOC_ENUM("Out3 Output", wm8731_enum[18]),
-SOC_ENUM("Out4 Output", wm8731_enum[19]),
-
-SOC_SINGLE("Mic 1 Amp Switch", WM8731_PWR2, 8, 1, 0),
-SOC_SINGLE("Mic 2 Amp Switch", WM8731_PWR2, 7, 1, 0),
-SOC_SINGLE("Mic 2 Volume", WM8731_INCTL1, 7, 3, 0),
-SOC_SINGLE("Mic 1 Volume", WM8731_INCTL1, 5, 3, 0),
-
-};*/
+};
 
 /* add non dpm controls */
 static int wm8731_add_controls(snd_soc_codec_t *codec)
@@ -413,53 +260,85 @@
 		if ((err = snd_ctl_add(codec->card, snd_soc_cnew(&wm8731_snd_controls[i],codec, NULL))) < 0)
 			return err;
 	}
-}
-
-/*
- * Power up the codec -- WE ARE NOW ALMOST DOING THIS IN DPM
- */
-static int wm8731_power_up(snd_pcm_substream_t *substream)
-{	
-	mdelay(1);
-	if (wm8731_2w_write(wm8731.i2c, WM8731_PWR, 0x00) != 0)
-		return -EIO;
-
 	return 0;
 }
 
-/* WE CAN USE DPM IN NEAR FUTURE */
-static int wm8731_power_down(snd_pcm_substream_t *substream)
-{
-	if (wm8731_2w_write(wm8731.i2c, WM8731_PWR, 0x0f0) != 0) {
- 		err("could not powerdown WM8731");
-		return -EIO;
-	}
-	return 0;
-}
+/* Output Mixer */
+static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = {
+SOC_DPM_SINGLE("Line 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),
+};
 
+/* Input mux */
+static const snd_kcontrol_new_t wm8753_input_mux_controls = 
+SOC_DPM_ENUM("Input Select", wm8731_enum[0]);
+
+
+static const snd_soc_dpm_widget_t 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_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),
+SND_SOC_DPM_OUTPUT("LOUT"),
+SND_SOC_DPM_OUTPUT("LHPOUT"),
+SND_SOC_DPM_OUTPUT("ROUT"),
+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_INPUT("MICIN"),
+SND_SOC_DPM_INPUT("RLINEIN"),
+SND_SOC_DPM_INPUT("LLINEIN"),
+};
 
-static int wm8731_pcm_hifi_startup(snd_pcm_substream_t *substream)
+static int wm8731_add_widgets(snd_soc_codec_t *codec)
 {
-	wm8731_power_up(substream);
+	int i;
+	
+	for(i = 0; i < ARRAY_SIZE(wm8731_dpm_widgets); i++) {
+		snd_soc_dpm_new_control(codec, &wm8731_dpm_widgets[i]);
+	}
+	
+	/* set up audio path interconnects */
+	
+	/* output mixer */
+	snd_soc_dpm_connect_input(codec, "Output Mixer", "Line 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");
+	
+	snd_soc_dpm_sync(codec);
 	return 0;
 }
 
-static void wm8731_pcm_hifi_shutdown(snd_pcm_substream_t *substream)
-{	
-	wm8731_power_down(substream);
-}
-
-static int wm8731_pcm_hifi_prepare(snd_pcm_substream_t *substream)
+static int wm8731_pcm_prepare(snd_pcm_substream_t *substream)
 {
 	snd_soc_pcm_codec_t *pcm_c = substream->private_data;
 	u16 iface = 0;
 	
 	/* set master/slave audio interface */
 	switch(pcm_c->hw_runtime.hformat & SND_SOC_CLOCK_MASK) {
-		case SND_SOC_HWFMT_CBM_CFM:
-			iface |= 0x0020;
-			break;
-		case SND_SOC_HWFMT_CBM_CFS:
+		//case SND_SOC_HWFMT_CBS_CFM:
+		//	iface |= 0x0020;
+		//	break;
+		case SND_SOC_HWFMT_CBS_CFS:
 			break;
 	}
 	
@@ -511,15 +390,17 @@
 			break;
 	}
 	
-	if (wm8731_2w_write(wm8731.i2c, WM8731_ACTIVE, 0x00) != 0)
+	if (wm8731_2w_write(wm8731_i2c, WM8731_ACTIVE, 0x00) != 0)
 		return -EIO;
 
 	/* set rate */
-	wm8731_2w_write(wm8731.i2c, WM8731_SRATE, pcm_c->hw_runtime.priv1);
+	wm8731_2w_write(wm8731_i2c, WM8731_SRATE, pcm_c->hw_runtime.priv1);
+
+	wm8731_2w_write(wm8731_i2c, WM8731_IFACE, iface);
 
-	wm8731_2w_write(wm8731.i2c, WM8731_IFACE, iface);
+	wm8731_2w_write(wm8731_i2c, WM8731_APANA, 0x12);
 
-	if (wm8731_2w_write(wm8731.i2c, WM8731_ACTIVE, 0x01) != 0)
+	if (wm8731_2w_write(wm8731_i2c, WM8731_ACTIVE, 0x01) != 0)
 		return -EIO;
 
 	return 0;
@@ -529,87 +410,140 @@
 {
 }
 
-static snd_soc_pcm_codec_t wm8731_pcm_hifi_client = {
-	.name = "WM8731 PCM Codec",
+static int wm8731_dpm_event(snd_soc_codec_t *codec, int event)
+{
+	u16 pwr_reg = wm8731_read_reg_cache(WM8731_PWR) & 0xff1f;
+	u16 act_reg = wm8731_read_reg_cache(WM8731_ACTIVE) & 0xfffe;
+	u16 dac_reg = wm8731_read_reg_cache(WM8731_APDIGI) & 0xfff7;
+
+	switch (event) {
+		case SNDRV_CTL_POWER_D0: /* full On */
+			/* vref/mid, clk and osc on, dac unmute, active */
+			wm8731_2w_write(wm8731_i2c, WM8731_ACTIVE, act_reg | 0x0001);
+			wm8731_2w_write(wm8731_i2c, WM8731_APDIGI, dac_reg & 0xfff7);
+			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_2w_write(wm8731_i2c, WM8731_APDIGI, dac_reg | 0x0008);
+			wm8731_2w_write(wm8731_i2c, WM8731_PWR, pwr_reg | 0x0010);
+			wm8731_2w_write(wm8731_i2c, WM8731_ACTIVE, act_reg);
+			wm8731_2w_write(wm8731_i2c, WM8731_PWR, 0xff7f);
+			break;
+		case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+			/* everything off, dac mute, inactive */
+			wm8731_2w_write(wm8731_i2c, WM8731_APDIGI, dac_reg | 0x0008);
+			wm8731_2w_write(wm8731_i2c, WM8731_PWR, pwr_reg | 0x0010);
+			wm8731_2w_write(wm8731_i2c, WM8731_ACTIVE, act_reg);
+			wm8731_2w_write(wm8731_i2c, WM8731_PWR, 0xffff);
+			break;
+	}
+	
+	return 0;
+}
+
+static snd_soc_pcm_codec_t wm8731_pcm_client = {
+	.name = "WM8731",
 	.playback = {
-		.sname = "HiFi Playback",
+		.sname = "Playback",
 		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
 		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 |
 		SNDRV_PCM_RATE_96000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
-		.channels_max = 2,},
-/*	.capture = {
-		.sname = "Voice Capture",
+		.channels_max = 2,
+	},
+	.nplayback = 1,
+	.capture = {
+		.sname = "Capture",
 		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | 
 		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 |
 		SNDRV_PCM_RATE_96000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
-		.channels_max = 2,},*/
+		.channels_max = 2,
+	},
+	.ncapture = 1,
 	.ops = {
-		.startup = wm8731_pcm_hifi_startup,
-		.shutdown = wm8731_pcm_hifi_shutdown,
-		.prepare = wm8731_pcm_hifi_prepare,},
+		.prepare = wm8731_pcm_prepare,
+	},
 	.hw = {
-		.num_hmodes = ARRAY_SIZE(wm8731_hifi),
-		.hmodes = &wm8731_hifi[0],},
+		.num_hmodes = ARRAY_SIZE(wm8731_hwfmt),
+		.hmodes = &wm8731_hwfmt[0],
+	},
 };
 
 static snd_soc_codec_t wm8731_soc_codec;
 
+static ssize_t mute_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{        
+	int val = simple_strtoul(buf, NULL, 10);
+	
+	if (val)
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R);
+	else
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R);
+
+	return count;
+}
+
+static DEVICE_ATTR(mute, 0200, NULL, mute_store);
+
+static ssize_t spk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{        
+	int val = simple_strtoul(buf, NULL, 10);
+	
+	if (val)
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
+	else
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
+
+	return count;
+}
+
+static DEVICE_ATTR(spk, 0200, NULL, spk_store);
+
 /*
  * initialise the WM8731 driver
  * register the mixer and dsp interfaces with the kernel 
  */
 static int wm8731_probe(snd_soc_codec_t *codec)
 {
-	int ret;
-	int dev_no = 0;
 	int reg;
 	
-	info("WM8731 Audio Codec %s", WM8731_VERSION);
-
-	
-	/* check platform for interfaces */
-	if(snd_soc_iface_query(SND_SOC_I2S, 0)) {
-		err("I2S interface not available");
-		return -ENODEV;
-	}
+	wm8731_reset(wm8731_i2c);
 	
-	if((ret = snd_soc_pcm_new(codec, dev_no++, &wm8731_pcm_hifi_client, 
-		&wm8731.pcm_hifi, 1, 0, SND_SOC_I2S, 0)) < 0)
-			return ret;
-
-	if ((ret = i2c_add_driver(&wm8731_i2c_driver)) != 0) {
-		err("can't add i2c driver");
-		return ret;
-	}
-
 	reg = wm8731_read_reg_cache(WM8731_PWR);
-	wm8731_2w_write(wm8731.i2c, WM8731_PWR, reg);
+	wm8731_2w_write(wm8731_i2c, WM8731_PWR, reg);
 
 	reg = wm8731_read_reg_cache(WM8731_APANA);
-	wm8731_2w_write(wm8731.i2c, WM8731_APANA, reg);
+	wm8731_2w_write(wm8731_i2c, WM8731_APANA, reg);
 	reg = wm8731_read_reg_cache(WM8731_APDIGI);
-	wm8731_2w_write(wm8731.i2c, WM8731_APDIGI, reg);
+	wm8731_2w_write(wm8731_i2c, WM8731_APDIGI, reg);
+
+	wm8731_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
 	
 	/* set the update bits */
 	reg = wm8731_read_reg_cache(WM8731_LOUT1V);
-	wm8731_2w_write(wm8731.i2c, WM8731_LOUT1V, reg | 0x0100);
+	wm8731_2w_write(wm8731_i2c, WM8731_LOUT1V, reg | 0x0100);
 	reg = wm8731_read_reg_cache(WM8731_ROUT1V);
-	wm8731_2w_write(wm8731.i2c, WM8731_ROUT1V, reg | 0x0100);
+	wm8731_2w_write(wm8731_i2c, WM8731_ROUT1V, reg | 0x0100);
 	reg = wm8731_read_reg_cache(WM8731_LINVOL);
-	wm8731_2w_write(wm8731.i2c, WM8731_LINVOL, reg | 0x0100);
+	wm8731_2w_write(wm8731_i2c, WM8731_LINVOL, reg | 0x0100);
 	reg = wm8731_read_reg_cache(WM8731_RINVOL);
-	wm8731_2w_write(wm8731.i2c, WM8731_RINVOL, reg | 0x0100);
+	wm8731_2w_write(wm8731_i2c, WM8731_RINVOL, reg | 0x0100);
 
 	wm8731_add_controls(&wm8731_soc_codec);
-	//wm8731_add_widgets(&wm8731_soc_codec);
+	wm8731_add_widgets(&wm8731_soc_codec);
 
-	set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON | CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R );	//  All on
+	set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON | CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R );
 
-	return ret;
+	device_create_file(&wm8731_soc_codec.pdev.dev, &dev_attr_mute);
+	device_create_file(&wm8731_soc_codec.pdev.dev, &dev_attr_spk);
+
+	return 0;
 }
 
 /* 
@@ -617,15 +551,18 @@
  */
 static void wm8731_remove(snd_soc_codec_t *codec)
 {
-	i2c_del_driver(&wm8731_i2c_driver);
+	device_remove_file(&wm8731_soc_codec.pdev.dev, &dev_attr_mute);
+	device_remove_file(&wm8731_soc_codec.pdev.dev, &dev_attr_spk);
+
+	wm8731_dpm_event(codec, SNDRV_CTL_POWER_D3cold);
 }
 
 static snd_soc_codec_t wm8731_soc_codec = {
 	.name = "WM8731",
-	.longname = "wm8731 long name",
+	.longname = "WM8731 Portable Codec",
 	.owner = THIS_MODULE,
 	.pdev = {
-		.name		= "wm8731 pdev",
+		.name		= "soc-wm8731",
 		.id		= -1,
 		.dev		= {
 			.release = wm8731_device_release,
@@ -635,16 +572,40 @@
 	.remove = wm8731_remove,
 	.read = wm8731_read_reg_cache,
 	.write = wm8731_write,
+	.dpm_event = wm8731_dpm_event,
+	.pcms = &wm8731_pcm_client,
+	.npcms = 1,
 };	
 
 static int __init wm8731_init(void)
 {	
-	return snd_soc_register_codec(&wm8731_soc_codec);
+	int ret = 0;
+	
+	info("WM8731 Audio Codec %s", WM8731_VERSION);
+
+	if ((ret = i2c_add_driver(&wm8731_i2c_driver)) != 0) {
+		err("can't add i2c driver");
+		return ret;
+	}
+
+	if(!wm8731_i2c) {
+		err("can't find chip on i2c bus");
+		i2c_del_driver(&wm8731_i2c_driver);
+		return -ENODEV;
+	}
+	
+	if((ret = snd_soc_register_codec(&wm8731_soc_codec)) < 0) {
+		err("can't register driver");
+		i2c_del_driver(&wm8731_i2c_driver);
+		return ret;
+	}
+	return ret;
 }
 
 static void __exit wm8731_exit(void)
 {
 	snd_soc_unregister_codec(&wm8731_soc_codec);
+	i2c_del_driver(&wm8731_i2c_driver);
 }
 
 module_init(wm8731_init);
Index: linux-2.6.14/sound/soc/codecs/wm8731.h
===================================================================
--- linux-2.6.14.orig/sound/soc/codecs/wm8731.h	2005-11-02 09:59:20.000000000 +0000
+++ linux-2.6.14/sound/soc/codecs/wm8731.h	2005-11-02 09:59:21.000000000 +0000
@@ -29,25 +29,7 @@
 #define WM8731_ACTIVE   0x09
 #define WM8731_RESET	0x0f
 
-
-/* Voice DAC sample rates */
-#define WM8731_VD8K		(0x6 << 6)
-#define WM8731_VD12K	(0x5 << 6)
-#define WM8731_VD16K	(0x2 << 6)
-#define WM8731_VD24K	(0x4 << 6)
-#define WM8731_VD48K	(0x0 << 6)
-
-
-/* Hifi ADC/DAC sample rates */
-#define WM8731_A8D8		0x0006
-#define WM8731_A8D48	0x0004
-#define WM8731_A12D12	0x0008
-#define WM8731_A16D16	0x000a
-#define WM8731_A24D24	0x001c
-#define WM8731_A32D32	0x000c
-#define WM8731_A48D8	0x0002
-#define WM8731_A48D48	0x0000
-#define WM8731_A96D96	0x000e
+#define WM8731_CACHEREGNUM 	10
 
 struct wm8731_mixer_t {
 	int dev_mixer;
Index: linux-2.6.14/sound/soc/codecs/wm8750.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.14/sound/soc/codecs/wm8750.c	2005-11-02 15:06:44.000000000 +0000
@@ -0,0 +1,877 @@
+/*
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on WM8753.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/pm.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#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"
+
+#define AUDIO_NAME "WM8750"
+#define WM8750_VERSION "0.2"
+
+/*
+ * Debug
+ */
+ 
+#define PFX AUDIO_NAME
+#define WM8750_DEBUG 0
+
+#ifdef WM8750_DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
+
+
+/* 
+ * WM8750 2 wire address is determined by CSB pin state during powerup */
+#define I2C_DRIVERID_WM8750 0xfde
+
+static unsigned short normal_i2c[] = {  0x1a, 0x1b,
+                                       I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+struct i2c_client* wm8750_i2c = NULL;
+
+/*
+ * wm8750 register cache
+ * We can't read the WM8750 register space when we 
+ * are using 2 wire for device control, so we cache them instead. 
+ */
+static u16 reg_cache[] = {
+	0x0097, 0x0097, 0x0079, 0x0079,  //0-3
+	0x0000, 0x0008, 0x0000, 0x000a,  //4
+	0x0000, 0x0000, 0x00ff, 0x00ff,  //8
+	0x000f, 0x000f, 0x0000, 0x0000,  //12
+	0x0000, 0x007b, 0x0000, 0x0032,  //16
+	0x0000, 0x00c3, 0x00c3, 0x00c0,  //20
+	0x0000, 0x0000, 0x0000, 0x0000,  //24
+	0x0000, 0x0000, 0x0000, 0x0000,  //28
+	0x0000, 0x0000, 0x0050, 0x0050,  //32
+	0x0050, 0x0050, 0x0050, 0x0050,  //36
+	0x0079, 0x0079, 0x0079,          //40
+};
+
+#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_NB_NF | SND_SOC_HWFMT_NB_IF | SND_SOC_HWFMT_IB_NF | \
+	SND_SOC_HWFMT_IB_IF)
+
+/* priv1 is srate register setting */
+static snd_soc_hw_mode_t 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},
+
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 11025, 64,  0x0030},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 11025, 96,  0x0032},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 11025, 128, 0x0070},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 11025, 192, 0x0072},
+
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 12000, 64,  0x0010},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 12000, 96,  0x0012},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 12000, 128, 0x0050},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 12000, 192, 0x0052},
+
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 16000, 64,  0x0014},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 16000, 96,  0x0016},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 16000, 128, 0x0054},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 16000, 192, 0x0056},
+
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 22050, 64,  0x0034},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 22050, 96,  0x0036},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 22050, 128, 0x0074},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 22050, 192, 0x0076},
+
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 24000, 64,  0x0038},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 24000, 96,  0x003a},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 24000, 128, 0x0078},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 24000, 192, 0x007a},
+
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 32000,  64, 0x0018},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 32000,  96, 0x001a},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 32000, 128, 0x0058},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 32000, 192, 0x005a},
+
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 44100,  64, 0x0020},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 44100,  96, 0x0022},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 44100, 128, 0x0060},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 44100, 192, 0x0062},
+
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 48000,  64, 0x0000},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 48000,  96, 0x0002},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 48000, 128, 0x0040},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 48000, 192, 0x0042},
+
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 88200,  32, 0x003c},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 88200,  48, 0x003e},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 88200,  64, 0x007c},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 88200,  96, 0x007e},
+
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 96000,  32, 0x001c},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 96000,  48, 0x001e},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 96000,  64, 0x005c},
+	{WM8750_HWFMT, SND_SOC_HWBITS(16), 96000,  96, 0x005e},
+};
+
+/*
+ * read wm8750 register cache
+ */
+static inline unsigned int wm8750_read_reg_cache(u16 reg)
+{
+	if (reg >= WM8750_CACHE_REGNUM)
+		return -1;
+	return reg_cache[reg];
+}
+
+/*
+ * write wm8750 register cache
+ */
+static inline void wm8750_write_reg_cache(u16 reg, unsigned int value)
+{
+	printk("wm8750: Writing %x to %x\n", value, reg);
+	if (reg < WM8750_CACHE_REGNUM)
+		reg_cache[reg] = value;
+}
+
+static struct i2c_client client_template;
+static int wm8750_reset(struct i2c_client *client);
+static int wm8750_2w_write(struct i2c_client *client, u8 reg, u16 value);
+static int wm8750_add_controls(snd_soc_codec_t *codec);
+static int wm8750_add_widgets(snd_soc_codec_t *codec);
+static snd_soc_codec_t wm8750_soc_codec;
+
+	
+/*
+ * Attach WM8750 2 wire client 
+ */
+static int wm8750_i2c_probe(struct i2c_adapter *adap, int addr, int kind)
+{		
+	int reg;
+
+	client_template.adapter = adap;
+	client_template.addr = addr;
+
+	printk("wm8750_i2c_probe: Probing %d\n",addr);
+	
+	if ((wm8750_i2c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+ 
+	memcpy(wm8750_i2c, &client_template, sizeof(struct i2c_client));
+
+	return i2c_attach_client(wm8750_i2c);
+}
+
+static int wm8750_i2c_detach(struct i2c_client *client)
+{
+	i2c_detach_client(client);
+	kfree(client);
+	return 0;
+}
+
+static int wm8750_i2c_attach(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, wm8750_i2c_probe);
+}
+
+/* WM8750 2 Wire layer */ 
+static struct i2c_driver wm8750_i2c_driver = {
+	name:           "i2c wm8750 driver",
+	id:             I2C_DRIVERID_WM8750,
+	flags:          I2C_DF_NOTIFY,
+	attach_adapter: wm8750_i2c_attach,
+	detach_client:  wm8750_i2c_detach,
+	command:        NULL,
+};
+
+static struct i2c_client client_template = {
+	name:   "WM8750",
+	flags:  I2C_CLIENT_ALLOW_USE,
+	driver: &wm8750_i2c_driver,
+};
+
+static int wm8750_2w_write(struct i2c_client *client, u8 reg, u16 value)
+{
+	u8 data[2];
+
+	/* data is 
+	 *   D15..D9 WM8750 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	wm8750_write_reg_cache (reg, value);
+	if (i2c_master_send(client, data, 2) == 2)
+		return 0;
+	else
+		return -1;
+}
+
+static int wm8750_write (u16 reg, unsigned int value)
+{
+	return wm8750_2w_write(wm8750_i2c, reg, value);	
+}
+
+static int wm8750_reset(struct i2c_client *client)
+{
+	return wm8750_2w_write (client, WM8750_RESET, 0);
+}
+
+/*
+ * WM8750 Controls
+ */
+static const char* wm8750_bass[] = {"Linear Control", "Adaptive Boost"};
+static const char* wm8750_bass_filter[] = {"130Hz", "200Hz"};
+static const char* wm8750_treble[] = {"8kHz", "4kHz"};
+static const char* wm8750_3d_lc[] = {"200Hz", "500Hz"};
+static const char* wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"};
+static const char* wm8750_3d_func[] = {"Capture", "Playback"};
+static const char* wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"};
+static const char* wm8750_ng_type[] = {"Constant PGA Gain", "Mute ADC Output"};
+static const char* wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA", "Differential"};
+static const char* wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3", "Differential"};
+static const char* wm8750_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut", "ROUT1"};
+static const char* wm8750_diff_sel[] = {"Line 1", "Line 2"};
+static const char* wm8750_micboost[] = {"Off", "13dB", "20dB", "29dB"};
+static const char* wm8750_adcpol[] = {"Normal", "L Invert", "R Invert", "L + R Invert"};
+static const char* wm8750_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+static const char* wm8750_mono_mux[] = {"Stereo", "Mono (Left)", "Mono (Right)", "Digital Mono"};
+
+static const struct soc_enum wm8750_enum[] = {
+SOC_ENUM_SINGLE(WM8750_BASS, 7, 2, wm8750_bass),
+SOC_ENUM_SINGLE(WM8750_BASS, 6, 2, wm8750_bass_filter),
+SOC_ENUM_SINGLE(WM8750_TREBLE, 6, 2, wm8750_treble),
+SOC_ENUM_SINGLE(WM8750_3D, 5, 2, wm8750_3d_lc),
+SOC_ENUM_SINGLE(WM8750_3D, 6, 2, wm8750_3d_uc),
+SOC_ENUM_SINGLE(WM8750_3D, 7, 2, wm8750_3d_func),
+SOC_ENUM_SINGLE(WM8750_ALC1, 7, 4, wm8750_alc_func),
+SOC_ENUM_SINGLE(WM8750_NGATE, 1, 2, wm8750_ng_type),
+SOC_ENUM_SINGLE(WM8750_LOUTM1, 0, 5, wm8750_line_mux),
+SOC_ENUM_SINGLE(WM8750_ROUTM1, 0, 5, wm8750_line_mux),
+SOC_ENUM_SINGLE(WM8750_LADCIN, 6, 4, wm8750_pga_sel), /* 10 */
+SOC_ENUM_SINGLE(WM8750_RADCIN, 6, 4, wm8750_pga_sel),
+SOC_ENUM_SINGLE(WM8750_ADCTL2, 7, 4, wm8750_out3),
+SOC_ENUM_SINGLE(WM8750_ADCIN, 8, 2, wm8750_diff_sel),
+SOC_ENUM_SINGLE(WM8750_LADCIN, 4, 4, wm8750_micboost),
+SOC_ENUM_SINGLE(WM8750_RADCIN, 4, 4, wm8750_micboost),
+SOC_ENUM_SINGLE(WM8750_ADCDAC, 5, 4, wm8750_adcpol),
+SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph),
+SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 18 */
+
+};
+
+static const snd_kcontrol_new_t wm8750_snd_controls[] = {
+
+SOC_SINGLE("Line In Left Volume", WM8750_LINVOL, 0, 63, 0),
+SOC_SINGLE("Line In Left ZC Switch", WM8750_LINVOL, 6, 1, 0),
+SOC_SINGLE("Line In Left Mute Switch", WM8750_LINVOL, 7, 1, 1),
+SOC_SINGLE("Line In Right Volume", WM8750_RINVOL, 0, 63, 0),
+SOC_SINGLE("Line In Right ZC Switch", WM8750_RINVOL, 6, 1, 0),
+SOC_SINGLE("Line In Right Mute Switch", WM8750_RINVOL, 7, 1, 1),
+
+SOC_SINGLE("Left Out 1 Volume", WM8750_LOUT1V, 0, 127, 0),
+SOC_SINGLE("Left Out 1 ZC Switch", WM8750_LOUT1V, 7, 1, 0),
+SOC_SINGLE("Right Out 1 Volume", WM8750_ROUT1V, 0, 127, 0),
+SOC_SINGLE("Right Out 1 ZC Switch", WM8750_ROUT1V, 7, 1, 0),
+
+SOC_SINGLE("Left Out 2 Volume", WM8750_LOUT2V, 0, 127, 0),
+SOC_SINGLE("Left Out 2 ZC Switch", WM8750_LOUT2V, 7, 1, 0),
+SOC_SINGLE("Right Out 2 Volume", WM8750_ROUT2V, 0, 127, 0),
+SOC_SINGLE("Right Out 2 ZC Switch", WM8750_ROUT2V, 7, 1, 0),
+
+
+SOC_ENUM("De-emphasis Control", wm8750_enum[17]),
+SOC_SINGLE("DAC Mute", WM8750_ADCDAC, 3, 1, 0),
+SOC_ENUM("ADC Polarity", wm8750_enum[16]),
+SOC_SINGLE("DAC 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0),
+SOC_SINGLE("ADC 6dB Attenuate", WM8750_ADCDAC, 8, 1, 0),
+
+SOC_SINGLE("Left PCM Volume", WM8750_LDAC, 0, 255, 0),
+SOC_SINGLE("Right PCM Volume", WM8750_RDAC, 0, 255, 0),
+
+SOC_ENUM("Bass Boost", wm8750_enum[0]),
+SOC_ENUM("Bass Filter", wm8750_enum[1]),
+SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1),
+
+SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 0),
+SOC_ENUM("Treble Cut-off", wm8750_enum[2]),
+
+SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0),
+SOC_SINGLE("3D Volume", WM8750_3D, 1, 15, 0),
+SOC_ENUM("3D Lower Cut-off", wm8750_enum[3]),
+SOC_ENUM("3D Upper Cut-off", wm8750_enum[4]),
+SOC_ENUM("3D Mode", wm8750_enum[5]),
+
+SOC_SINGLE("ALC Target Volume", WM8750_ALC1, 0, 7, 0),
+SOC_SINGLE("ALC Max Volume", WM8750_ALC1, 4, 7, 0),
+SOC_ENUM("ALC Function", wm8750_enum[6]),
+SOC_SINGLE("ALC ZC Switch", WM8750_ALC2, 7, 1, 0),
+SOC_SINGLE("ALC Hold Time", WM8750_ALC2, 0, 15, 0),
+SOC_SINGLE("ALC Decay Time", WM8750_ALC3, 4, 15, 0),
+SOC_SINGLE("ALC Attack Time", WM8750_ALC3, 0, 15, 0),
+SOC_SINGLE("ALC NG Threshold", WM8750_NGATE, 3, 31, 0),
+SOC_ENUM("ALC NG Type", wm8750_enum[4]),
+SOC_SINGLE("ALC NG Switch", WM8750_NGATE, 0, 1, 0),
+
+SOC_SINGLE("Left ADC Volume", WM8750_LADC, 0, 255, 0),
+SOC_SINGLE("Right ADC Volume", WM8750_RADC, 0, 255, 0),
+
+SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0),
+SOC_SINGLE("DAC Invert Switch", WM8750_ADCTL1, 1, 1, 0),
+SOC_SINGLE("Thermal Shutdown Switch", WM8750_ADCTL1, 8, 1, 0),
+
+SOC_SINGLE("Low DAC Oversample", WM8750_ADCTL2, 0, 1, 0),
+SOC_SINGLE("Low ADC Oversample", WM8750_ADCTL2, 1, 1, 0),
+SOC_SINGLE("Right Out 2 Invert Switch", WM8750_ADCTL2, 4, 1, 0),
+SOC_SINGLE("Headphone Polarity Switch", WM8750_ADCTL2, 5, 1, 0),
+SOC_SINGLE("Headphone Detect Switch", WM8750_ADCTL2, 6, 1, 0),
+
+/* Unimplemented */
+/* ADCDAC Bit 0 - ADCHPD */
+/* ADCDAC Bit 4 - HPOR */
+/* ADCTL1 Bit 2,3 - DATSEL */
+/* ADCTL1 Bit 4,5 - DMONOMIX */
+/* ADCTL1 Bit 6,7 - VSEL */
+/* ADCTL2 Bit 2 - LRCM */
+/* ADCTL2 Bit 3 - TRI */
+/* ADCTL3 Bit 5 - HPFLREN */
+/* ADCTL3 Bit 6 - VROI */
+/* ADCTL3 Bit 7,8 - ADCLRM */
+/* ADCIN Bit 4 - LDCM */ 
+/* ADCIN Bit 5 - RDCM */
+
+SOC_ENUM("Left Mic Boost", wm8750_enum[14]),
+SOC_ENUM("Right Mic Boost", wm8750_enum[15]),
+
+SOC_SINGLE("Left Mux to Left Mixer Volume", WM8750_LOUTM1, 4, 7, 1),
+SOC_SINGLE("Right Mux to Left Mixer Volume", WM8750_LOUTM2, 4, 7, 1),
+
+SOC_SINGLE("Left Mux to Right Mixer Volume", WM8750_ROUTM1, 4, 7, 1),
+SOC_SINGLE("Right Mux to Right Mixer Volume", WM8750_ROUTM2, 4, 7, 1),
+
+SOC_SINGLE("Left Mux to Mono Mixer Volume", WM8750_MOUTM1, 4, 7, 1),
+SOC_SINGLE("Right Mux to Mono Mixer Volume", WM8750_MOUTM2, 4, 7, 1), 
+
+SOC_SINGLE("Mono Volume", WM8750_MOUTV, 0, 127, 0),
+SOC_SINGLE("Mono ZC Switch", WM8750_MOUTV, 7, 1, 0),
+
+};
+
+/* add non dpm controls */
+static int wm8750_add_controls(snd_soc_codec_t *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) {
+		if ((err = snd_ctl_add(codec->card, snd_soc_cnew(&wm8750_snd_controls[i],codec, NULL))) < 0)
+			return err;
+	}
+	return 0;
+}
+
+/*
+ * DPM Controls
+ */
+
+/* Left Mixer */
+static const snd_kcontrol_new_t wm8750_left_mixer_controls[] = {
+SOC_DPM_SINGLE("Left DAC Switch", WM8750_LOUTM1, 8, 1, 0),
+SOC_DPM_SINGLE("Left Line Mux Switch", WM8750_LOUTM1, 7, 1, 0),
+SOC_DPM_SINGLE("Right DAC Switch", WM8750_LOUTM2, 8, 1, 0),
+SOC_DPM_SINGLE("Right Line Mux Switch", WM8750_LOUTM2, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const snd_kcontrol_new_t wm8750_right_mixer_controls[] = {
+SOC_DPM_SINGLE("Left DAC Switch", WM8750_ROUTM1, 8, 1, 0),
+SOC_DPM_SINGLE("Left Line Mux Switch", WM8750_ROUTM1, 7, 1, 0),
+SOC_DPM_SINGLE("Right DAC Switch", WM8750_ROUTM2, 8, 1, 0),
+SOC_DPM_SINGLE("Right Line Mux Switch", WM8750_ROUTM2, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const snd_kcontrol_new_t wm8750_mono_mixer_controls[] = {
+SOC_DPM_SINGLE("Left DAC Switch", WM8750_MOUTM1, 8, 1, 0),
+SOC_DPM_SINGLE("Left Line Mux Switch", WM8750_MOUTM1, 7, 1, 0),
+SOC_DPM_SINGLE("Right DAC Switch", WM8750_MOUTM2, 8, 1, 0),
+SOC_DPM_SINGLE("Right Line Mux Switch", WM8750_MOUTM2, 7, 1, 0),
+};
+
+/* Left Line Mux */
+static const snd_kcontrol_new_t wm8750_left_line_controls =
+SOC_DPM_ENUM("Source", wm8750_enum[8]);
+
+/* Right Line Mux */
+static const snd_kcontrol_new_t wm8750_right_line_controls =
+SOC_DPM_ENUM("Source", wm8750_enum[9]);
+
+/* Left PGA Mux */
+static const snd_kcontrol_new_t wm8750_left_pga_controls =
+SOC_DPM_ENUM("Source", wm8750_enum[10]);
+
+/* Right PGA Mux */
+static const snd_kcontrol_new_t wm8750_right_pga_controls =
+SOC_DPM_ENUM("Source", wm8750_enum[11]);
+
+/* Out 3 Mux */
+static const snd_kcontrol_new_t wm8750_out3_controls =
+SOC_DPM_ENUM("Source", wm8750_enum[12]);
+
+/* Differential Mux */
+static const snd_kcontrol_new_t wm8750_diffmux_controls =
+SOC_DPM_ENUM("Source", wm8750_enum[13]);
+
+/* Mono ADC Mux */
+static const snd_kcontrol_new_t wm8750_monomux_controls =
+SOC_DPM_ENUM("Source", wm8750_enum[18]);
+
+
+static const snd_soc_dpm_widget_t wm8750_dpm_widgets[] = {
+	SND_SOC_DPM_CLOCK("WM8750 Clock", WM8750_PWR1, 0, 1),
+	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_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_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),
+
+	SND_SOC_DPM_MUX("Left PGA Mux", WM8750_PWR1, 5, 0, &wm8750_left_pga_controls),
+	SND_SOC_DPM_MUX("Right PGA Mux", WM8750_PWR1, 4, 0, &wm8750_right_pga_controls),
+	SND_SOC_DPM_MUX("Left Line Mux", -1, 0, 0, &wm8750_left_line_controls),
+	SND_SOC_DPM_MUX("Right Line Mux", -1, 0, 0, &wm8750_right_line_controls),
+
+	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_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),
+
+	SND_SOC_DPM_OUTPUT("LOUT1"),
+	SND_SOC_DPM_OUTPUT("ROUT1"),
+	SND_SOC_DPM_OUTPUT("LOUT2"),
+	SND_SOC_DPM_OUTPUT("ROUT2"),
+	SND_SOC_DPM_OUTPUT("MONO"),
+	SND_SOC_DPM_OUTPUT("OUT3"),
+
+	SND_SOC_DPM_INPUT("LINE1"),
+	SND_SOC_DPM_INPUT("LINE2"),
+	SND_SOC_DPM_INPUT("LINE3"),
+};
+
+static int wm8750_add_widgets(snd_soc_codec_t *codec)
+{
+	int i;
+	
+	for(i = 0; i < ARRAY_SIZE(wm8750_dpm_widgets); i++) {
+		snd_soc_dpm_new_control(codec, &wm8750_dpm_widgets[i]);
+	}
+	
+	/* left mixer */
+	snd_soc_dpm_connect_input(codec, "Left Mixer", "Left DAC Switch", "Left DAC");
+	snd_soc_dpm_connect_input(codec, "Left Mixer", "Left Line Mux Switch", "Left Line Mux");
+	snd_soc_dpm_connect_input(codec, "Left Mixer", "Right DAC Switch", "Right DAC");
+	snd_soc_dpm_connect_input(codec, "Left Mixer", "Right Line Mux Switch", "Right Line Mux");
+
+	/* right mixer */
+	snd_soc_dpm_connect_input(codec, "Right Mixer", "Left DAC Switch", "Left DAC");
+	snd_soc_dpm_connect_input(codec, "Right Mixer", "Left Line Mux Switch", "Left Line Mux");
+	snd_soc_dpm_connect_input(codec, "Right Mixer", "Right DAC Switch", "Right DAC");
+	snd_soc_dpm_connect_input(codec, "Right Mixer", "Right Line Mux 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 2 */
+	snd_soc_dpm_connect_input(codec, "Left Out 2", NULL, "Left Mixer");
+	snd_soc_dpm_connect_input(codec, "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 2 */
+	snd_soc_dpm_connect_input(codec, "Right Out 2", NULL, "Right Mixer");
+	snd_soc_dpm_connect_input(codec, "ROUT2", NULL, "Right Out 2");
+
+	/* mono mixer */
+	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Left DAC Switch", "Left DAC");
+	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Left Line Mux Switch", "Left Line Mux");
+	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Right DAC Switch", "Right DAC");
+	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Right Line Mux 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");
+
+	/* 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");
+
+	/* Left Line Mux */
+	snd_soc_dpm_connect_input(codec, "Left Line Mux", "Line 1", "LINE1");
+	snd_soc_dpm_connect_input(codec, "Left Line Mux", "Line 2", "LINE2");
+	snd_soc_dpm_connect_input(codec, "Left Line Mux", "Line 3", "LINE3");
+	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");
+
+	/* Right Line Mux */
+	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Line 1", "LINE1");
+	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Line 2", "LINE2");
+	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Line 3", "LINE3");
+	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");
+
+	/* Left PGA Mux */
+	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Line 1", "LINE1");
+	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Line 2", "LINE2");
+	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Line 3", "LINE3");
+	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Differential", "Differential Mux");
+
+	/* Right PGA Mux */
+	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Line 1", "LINE1");
+	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Line 2", "LINE2");
+	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Line 3", "LINE3");
+	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Differential", "Differential Mux");
+
+	/* Differential Mux */
+	snd_soc_dpm_connect_input(codec, "Differential Mux", "Line 1", "LINE1");
+	snd_soc_dpm_connect_input(codec, "Differential Mux", "Line 2", "LINE2");
+
+	/* 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");
+
+	/* 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");
+
+	/* 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");
+
+	snd_soc_dpm_sync(codec);
+	return 0;
+}
+
+
+static int wm8750_pcm_prepare(snd_pcm_substream_t *substream)
+{
+	snd_soc_pcm_codec_t *pcm_c = substream->private_data;
+	u16 iface = 0;
+	
+	/* set master/slave audio interface */
+	switch(pcm_c->hw_runtime.hformat & SND_SOC_CLOCK_MASK) {
+		//case SND_SOC_HWFMT_CBS_CFM:
+		//	iface |= 0x0020;
+		//	break;
+		case SND_SOC_HWFMT_CBS_CFS:
+			break;
+	}
+	
+	/* interface format */
+	switch(pcm_c->hw_runtime.hformat & SND_SOC_FORMAT_MASK) {
+		case SND_SOC_HWFMT_I2S:
+			iface |= 0x0002;
+			break;
+		case SND_SOC_HWFMT_RIGHT_J:
+			break;
+		case SND_SOC_HWFMT_LEFT_J:
+			iface |= 0x0001;
+			break;
+		case SND_SOC_HWFMT_DSP_A:
+			iface |= 0x0003;
+			break;
+		case SND_SOC_HWFMT_DSP_B:
+			iface |= 0x0013;
+			break;
+	}
+		
+	/* bit size */
+	switch(pcm_c->hw_runtime.hbits) {
+		case SND_SOC_HWBITS(16):
+			break;
+		case SND_SOC_HWBITS(20):
+			iface |= 0x0004;
+			break;
+		case SND_SOC_HWBITS(24):
+			iface |= 0x0008;
+			break;
+		case SND_SOC_HWBITS(32):
+			iface |= 0x000c;
+			break;
+	}
+
+	/* clock inversion */
+	switch(pcm_c->hw_runtime.hformat & SND_SOC_INV_MASK) {
+		case SND_SOC_HWFMT_NB_NF:
+			break;
+		case SND_SOC_HWFMT_IB_IF:
+			iface |= 0x0090;
+			break;
+		case SND_SOC_HWFMT_IB_NF:
+			iface |= 0x0080;
+			break;
+		case SND_SOC_HWFMT_NB_IF:
+			iface |= 0x0010;
+			break;
+	}
+	
+	
+	/* set rate */
+	wm8750_2w_write(wm8750_i2c, WM8750_SRATE, pcm_c->hw_runtime.priv1);
+
+	wm8750_2w_write(wm8750_i2c, WM8750_IFACE, iface);
+	
+	return 0;
+}
+
+static void wm8750_device_release(struct device * dev)
+{
+}
+
+static int wm8750_dpm_event(snd_soc_codec_t *codec, int event)
+{
+	u16 pwr_reg = wm8750_read_reg_cache(WM8750_PWR1) & 0xfe3f;
+	u16 dac_reg = wm8750_read_reg_cache(WM8750_ADCDAC) & 0xfff7;
+
+	switch (event) {
+		case SNDRV_CTL_POWER_D0: /* full On */
+			/* set vmid to 50k and unmute dac */
+			wm8750_2w_write(wm8750_i2c, WM8750_PWR1, pwr_reg | 0x00c0);
+			wm8750_2w_write(wm8750_i2c, WM8750_ADCDAC, 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 */
+			wm8750_2w_write(wm8750_i2c, WM8750_PWR1, pwr_reg | 0x01c0);
+			break;
+		case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+			/* mute dac and set vmid to 500k, enable VREF */
+			wm8750_2w_write(wm8750_i2c, WM8750_ADCDAC, dac_reg | 0x0008);
+			wm8750_2w_write(wm8750_i2c, WM8750_PWR1, pwr_reg | 0x0140);
+			break;
+		case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+			wm8750_2w_write(wm8750_i2c, WM8750_ADCDAC, dac_reg | 0x0008);
+			wm8750_2w_write(wm8750_i2c, WM8750_PWR1, 0x0000);
+			break;
+	}
+	
+	return 0;
+}
+
+static snd_soc_pcm_codec_t wm8750_pcm_client = {
+	.name = "WM8750",
+	.playback = {
+		.sname = "Playback",
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 |
+		SNDRV_PCM_RATE_96000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+	},
+	.nplayback = 1,
+	.capture = {
+		.sname = "Capture",
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | 
+		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 |
+		SNDRV_PCM_RATE_96000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+	},
+	.ncapture = 1,
+	.ops = {
+		.prepare = wm8750_pcm_prepare,
+	},
+	.hw = {
+		.num_hmodes = ARRAY_SIZE(wm8750_hwfmt),
+		.hmodes = &wm8750_hwfmt[0],
+	},
+};
+
+static snd_soc_codec_t wm8750_soc_codec;
+
+ 
+static ssize_t cmd_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{        
+	int val,ret;        
+	sscanf(buf, "%x %x", &val, &ret);	
+	
+	wm8750_2w_write(wm8750_i2c, val, ret);
+
+	return count;
+}   
+
+static DEVICE_ATTR(cmd, 0200, NULL, cmd_store);
+
+static ssize_t mute_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{        
+	int val = simple_strtoul(buf, NULL, 10);
+	
+	if (val)
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R);
+	else
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R);
+
+	return count;
+}
+
+static DEVICE_ATTR(mute, 0200, NULL, mute_store);
+
+/*
+ * initialise the WM8750 driver
+ * register the mixer and dsp interfaces with the kernel 
+ */
+static int wm8750_probe(snd_soc_codec_t *codec)
+{
+	int reg;
+	
+	wm8750_reset(wm8750_i2c);
+	
+	wm8750_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
+
+	/* set the update bits */
+	reg = wm8750_read_reg_cache(WM8750_LDAC);
+	wm8750_2w_write(wm8750_i2c, WM8750_LDAC, reg | 0x0100);
+	reg = wm8750_read_reg_cache(WM8750_RDAC);
+	wm8750_2w_write(wm8750_i2c, WM8750_RDAC, reg | 0x0100);
+	reg = wm8750_read_reg_cache(WM8750_LOUT1V);
+	wm8750_2w_write(wm8750_i2c, WM8750_LOUT1V, reg | 0x0100);
+	reg = wm8750_read_reg_cache(WM8750_ROUT1V);
+	wm8750_2w_write(wm8750_i2c, WM8750_ROUT1V, reg | 0x0100);
+	reg = wm8750_read_reg_cache(WM8750_LOUT2V);
+	wm8750_2w_write(wm8750_i2c, WM8750_LOUT2V, reg | 0x0100);
+	reg = wm8750_read_reg_cache(WM8750_ROUT2V);
+	wm8750_2w_write(wm8750_i2c, WM8750_ROUT2V, reg | 0x0100);
+	reg = wm8750_read_reg_cache(WM8750_LINVOL);
+	wm8750_2w_write(wm8750_i2c, WM8750_LINVOL, reg | 0x0100);
+	reg = wm8750_read_reg_cache(WM8750_RINVOL);
+	wm8750_2w_write(wm8750_i2c, WM8750_RINVOL, reg | 0x0100);
+
+	wm8750_add_controls(&wm8750_soc_codec);
+	wm8750_add_widgets(&wm8750_soc_codec);
+
+	device_create_file(&wm8750_soc_codec.pdev.dev, &dev_attr_cmd);
+	device_create_file(&wm8750_soc_codec.pdev.dev, &dev_attr_mute);
+
+	set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R );
+
+	return 0;
+}
+
+/* 
+ * unregister interfaces and clean up
+ */
+static void wm8750_remove(snd_soc_codec_t *codec)
+{
+	device_remove_file(&wm8750_soc_codec.pdev.dev, &dev_attr_cmd);
+	device_remove_file(&wm8750_soc_codec.pdev.dev, &dev_attr_mute);
+
+	wm8750_dpm_event(codec, SNDRV_CTL_POWER_D3cold);
+}
+
+static snd_soc_codec_t wm8750_soc_codec = {
+	.name = "WM8750",
+	.longname = "WM8750 Portable Codec",
+	.owner = THIS_MODULE,
+	.pdev = {
+		.name		= "soc-wm8750",
+		.id		= -1,
+		.dev		= {.release = wm8750_device_release},
+	},
+	.probe = wm8750_probe,
+	.remove = wm8750_remove,
+	.read = wm8750_read_reg_cache,
+	.write = wm8750_write,
+	.dpm_event = wm8750_dpm_event,
+	.pcms = &wm8750_pcm_client,
+	.npcms = 1,
+};	
+
+static int __init wm8750_init(void)
+{	
+	int ret = 0;
+
+	info("WM8750 Audio Codec %s", WM8750_VERSION);
+
+	if ((ret = i2c_add_driver(&wm8750_i2c_driver)) != 0) {
+		err("can't add i2c driver");
+		return ret;
+	}
+
+	if(!wm8750_i2c) {
+		err("can't find chip on i2c bus");
+		i2c_del_driver(&wm8750_i2c_driver);
+		return -ENODEV;
+	}
+	
+	if((ret = snd_soc_register_codec(&wm8750_soc_codec)) < 0) {
+		err("can't register driver");
+		i2c_del_driver(&wm8750_i2c_driver);
+		return ret;
+	}
+	return ret;
+}
+
+static void __exit wm8750_exit(void)
+{
+	snd_soc_unregister_codec(&wm8750_soc_codec);
+	i2c_del_driver(&wm8750_i2c_driver);
+}
+
+module_init(wm8750_init);
+module_exit(wm8750_exit);
+
+MODULE_DESCRIPTION("Soc WM8750 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
Index: linux-2.6.14/sound/soc/codecs/wm8750.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.14/sound/soc/codecs/wm8750.h	2005-11-02 09:59:21.000000000 +0000
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on WM8753.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _WM8750_H
+#define _WM8750_H
+
+/* WM8750 register space */
+
+#define WM8750_LINVOL    0x00
+#define WM8750_RINVOL    0x01
+#define WM8750_LOUT1V    0x02
+#define WM8750_ROUT1V    0x03
+#define WM8750_ADCDAC    0x05
+#define WM8750_IFACE     0x07
+#define WM8750_SRATE     0x08
+#define WM8750_LDAC      0x0a
+#define WM8750_RDAC      0x0b
+#define WM8750_BASS      0x0c
+#define WM8750_TREBLE    0x0d
+#define WM8750_RESET     0x0f
+#define WM8750_3D        0x10
+#define WM8750_ALC1      0x11
+#define WM8750_ALC2      0x12
+#define WM8750_ALC3      0x13
+#define WM8750_NGATE     0x14
+#define WM8750_LADC      0x15
+#define WM8750_RADC      0x16
+#define WM8750_ADCTL1    0x17
+#define WM8750_ADCTL2    0x18
+#define WM8750_PWR1      0x19
+#define WM8750_PWR2      0x1a
+#define WM8750_ADCTL3    0x1b
+#define WM8750_ADCIN     0x1f
+#define WM8750_LADCIN    0x20
+#define WM8750_RADCIN    0x21
+#define WM8750_LOUTM1    0x22
+#define WM8750_LOUTM2    0x23
+#define WM8750_ROUTM1    0x24
+#define WM8750_ROUTM2    0x25
+#define WM8750_MOUTM1    0x26
+#define WM8750_MOUTM2    0x27
+#define WM8750_LOUT2V    0x28
+#define WM8750_ROUT2V    0x29
+#define WM8750_MOUTV     0x2a
+
+#define WM8750_CACHE_REGNUM 0x2a
+
+
+
+
+
+/* Voice DAC sample rates */
+#define WM8750_VD8K        (0x6 << 6)
+#define WM8750_VD12K    (0x5 << 6)
+#define WM8750_VD16K    (0x2 << 6)
+#define WM8750_VD24K    (0x4 << 6)
+#define WM8750_VD48K    (0x0 << 6)
+
+
+/* Hifi ADC/DAC sample rates */
+#define WM8750_A8D8        0x0006
+#define WM8750_A8D48    0x0004
+#define WM8750_A12D12    0x0008
+#define WM8750_A16D16    0x000a
+#define WM8750_A24D24    0x001c
+#define WM8750_A32D32    0x000c
+#define WM8750_A48D8    0x0002
+#define WM8750_A48D48    0x0000
+#define WM8750_A96D96    0x000e
+
+struct WM8750_mixer_t {
+    int dev_mixer;
+};
+
+#endif

