diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 44db053..069f21b 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -4,12 +4,6 @@ config SND_SOC_AC97_CODEC
 	help
 	  Say Y or M if you want to support AC97 codecs under ALSA SoC.
 
-config SND_SOC_WM8753
-	tristate "SoC driver for the WM8753 codec"
-	depends SND_SOC
-	help
-	  Say Y or M if you want to support the WM8753 codec.
-
 config SND_SOC_WM8731
 	tristate "SoC driver for the WM8731 codec"
 	depends SND_SOC
@@ -22,6 +16,18 @@ config SND_SOC_WM8750
 	help
 	  Say Y or M if you want to support the WM8750 codec.
 	  
+config SND_SOC_WM8753
+	tristate "SoC driver for the WM8753 codec"
+	depends SND_SOC
+	help
+	  Say Y or M if you want to support the WM8753 codec.
+	  
+config SND_SOC_WM8772
+	tristate "SoC driver for the WM8772 codec"
+	depends SND_SOC
+	help
+	  Say Y or M if you want to support the WM8772 codec.
+	  
 config SND_SOC_WM8971
 	tristate "SoC driver for the WM8971 codec"
 	depends SND_SOC
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 9421304..818703a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,13 +1,15 @@
 snd-soc-ac97-objs := ac97.o
-snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8731-objs := wm8731.o
 snd-soc-wm8750-objs := wm8750.o
+snd-soc-wm8753-objs := wm8753.o
+snd-soc-wm8772-objs := wm8772.o
 snd-soc-wm8971-objs := wm8971.o
 snd-soc-wm9713-voice-objs := wm9713-voice.o
 
 obj-$(CONFIG_SND_SOC_AC97_CODEC)	+= snd-soc-ac97.o
-obj-$(CONFIG_SND_SOC_WM8753)	+= snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM8731)	+= snd-soc-wm8731.o
 obj-$(CONFIG_SND_SOC_WM8750)	+= snd-soc-wm8750.o
+obj-$(CONFIG_SND_SOC_WM8753)	+= snd-soc-wm8753.o
+obj-$(CONFIG_SND_SOC_WM8772)	+= snd-soc-wm8772.o
 obj-$(CONFIG_SND_SOC_WM8971)	+= snd-soc-wm8971.o
 obj-$(CONFIG_SND_SOC_WM9713_VOICE)	+= snd-soc-wm9713-voice.o
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 6b7f6c2..f73bd4a 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -472,6 +472,7 @@ static int wm8731_init(struct snd_soc_de
 	return 0;
 }
 
+static struct snd_soc_device *wm8731_socdev;
 
 #ifdef CONFIG_I2C
 
@@ -493,7 +494,6 @@ static struct i2c_client client_template
 
 /* If the i2c layer weren't so broken, we could pass this kind of data
    around */
-static struct snd_soc_device *wm8731_socdev;
 
 static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind)
 {
@@ -562,6 +562,7 @@ static struct i2c_client client_template
 	.flags =  I2C_CLIENT_ALLOW_USE,
 	.driver = &wm8731_i2c_driver,
 };
+#endif
 
 static int wm8731_probe(struct platform_device *pdev)
 {
@@ -580,21 +581,19 @@ static int wm8731_probe(struct platform_
 	INIT_LIST_HEAD(&codec->dpm_paths);
 
 	wm8731_socdev = socdev;
-
+#ifdef CONFIG_I2C
 	if (setup->i2c_address) {
 		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
 		if ((ret = i2c_add_driver(&wm8731_i2c_driver)) != 0)
 			printk(KERN_ERR "can't add i2c driver");
-	} else {
-		/* Add other interfaces here */
-	}
-
+	} 
+#else		
+	/* Add other interfaces here */
+#endif
 	return ret;
 }
 
-#endif
-
 /* power down chip */
 static int wm8731_remove(struct platform_device *pdev)
 {
@@ -605,7 +604,9 @@ static int wm8731_remove(struct platform
 		wm8731_dpm_event(codec, SNDRV_CTL_POWER_D3cold);
 
 	snd_soc_free_pcms(socdev);
+#ifdef CONFIG_I2C
 	i2c_del_driver(&wm8731_i2c_driver);
+#endif
 	kfree(codec);
 
 	return 0;
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index fcbea37..b894c6d 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -768,6 +768,10 @@ static int wm8750_init(struct snd_soc_de
 	return 0;
 }
 
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+static struct snd_soc_device *wm8750_socdev;
+
 #ifdef CONFIG_I2C
 
 /*
@@ -786,10 +790,6 @@ I2C_CLIENT_INSMOD;
 static struct i2c_driver wm8750_i2c_driver;
 static struct i2c_client client_template;
 
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-static struct snd_soc_device *wm8750_socdev;
-
 static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind)
 {
 	struct snd_soc_device *socdev = wm8750_socdev;
@@ -857,6 +857,7 @@ static struct i2c_client client_template
 	.flags =  I2C_CLIENT_ALLOW_USE,
 	.driver = &wm8750_i2c_driver,
 };
+#endif
 
 static int wm8750_probe(struct platform_device *pdev)
 {
@@ -879,21 +880,20 @@ static int wm8750_probe(struct platform_
 		kfree(codec);
 		return -ENOMEM;
 	}
-
+#ifdef CONFIG_I2C
 	if (setup->i2c_address) {
 		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
 		if ((ret = i2c_add_driver(&wm8750_i2c_driver)) != 0)
 			printk(KERN_ERR "can't add i2c driver");
-	} else {
-		/* Add other interfaces here */
 	}
+#else
+		/* Add other interfaces here */
+#endif
 
 	return ret;
 }
 
-#endif
-
 /* power down chip */
 static int wm8750_remove(struct platform_device *pdev)
 {
@@ -905,7 +905,9 @@ static int wm8750_remove(struct platform
 	if(wm8750_workq)
 		destroy_workqueue(wm8750_workq);
 	snd_soc_free_pcms(socdev);
+#ifdef CONFIG_I2C
 	i2c_del_driver(&wm8750_i2c_driver);
+#endif
 	kfree(codec);
 
 	return 0;
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index c5fd078..35fd56e 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1170,6 +1170,10 @@ static int wm8753_init(struct snd_soc_de
 	return ret;
 }
 
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+static struct snd_soc_device *wm8753_socdev;
+
 #ifdef CONFIG_I2C
 
 /*
@@ -1188,10 +1192,6 @@ I2C_CLIENT_INSMOD;
 static struct i2c_driver wm8753_i2c_driver;
 static struct i2c_client client_template;
 
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-static struct snd_soc_device *wm8753_socdev;
-
 static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind)
 {
 	struct snd_soc_device *socdev = wm8753_socdev;
@@ -1258,6 +1258,7 @@ static struct i2c_client client_template
 	.flags =  I2C_CLIENT_ALLOW_USE,
 	.driver = &wm8753_i2c_driver,
 };
+#endif
 
 static int wm8753_probe(struct platform_device *pdev)
 {
@@ -1281,21 +1282,19 @@ static int wm8753_probe(struct platform_
 		kfree(codec);
 		return -ENOMEM;
 	}
-	
+#ifdef CONFIG_I2C	
 	if (setup->i2c_address) {
 		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
 		if ((ret = i2c_add_driver(&wm8753_i2c_driver)) != 0)
 			printk(KERN_ERR "can't add i2c driver");
-	} else {
-		/* Add other interfaces here */
 	}
-
+#else
+		/* Add other interfaces here */
+#endif
 	return ret;
 }
 
-#endif
-
 /* power down chip */
 static int wm8753_remove(struct platform_device *pdev)
 {
@@ -1307,7 +1306,9 @@ static int wm8753_remove(struct platform
 	if(wm8753_workq)
 		destroy_workqueue(wm8753_workq);
 	snd_soc_free_pcms(socdev);
+#ifdef CONFIG_I2C
 	i2c_del_driver(&wm8753_i2c_driver);
+#endif
 	kfree(codec);
 
 	return 0;
diff --git a/sound/soc/codecs/wm8772.c b/sound/soc/codecs/wm8772.c
index c630c7b..b745ad4 100644
--- a/sound/soc/codecs/wm8772.c
+++ b/sound/soc/codecs/wm8772.c
@@ -1,7 +1,7 @@
 /*
  * wm8772.c  --  WM8772 Soc Audio driver
  *
- * Copyright 2003 Wolfson Microelectronics PLC.
+ * Copyright 2005 Wolfson Microelectronics PLC.
  * Author: Liam Girdwood
  *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
  *
@@ -10,9 +10,6 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  *
- * Notes:
- *  The WM8753 is a low power, high quality stereo codec with integrated PCM
- *  codec designed for portable digital telephony applications.
  */
  
 #include <linux/module.h>
@@ -35,37 +32,7 @@
 #include "wm8772.h"
 
 #define AUDIO_NAME "WM8772"
-#define WM8750_VERSION "0.1"
-
-/*
- * Debug
- */
- 
-#define PFX AUDIO_NAME
-#define WM8750_DEBUG 0
-
-#ifdef WM8772_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_WM8772 0xfde
-
-static unsigned short normal_i2c[] = {  0x1a, 0x1b,
-                                       I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8750_i2c_driver;
-static struct i2c_client client_template;
+#define WM8772_VERSION "0.1"
 	
 /*
  * wm8772 register cache
@@ -73,789 +40,453 @@ static struct i2c_client client_template
  * are using 2 wire for device control, so we cache them instead. 
  */
 static const u16 wm8772_reg[] = {
-	0x0097, 0x0097, 0x0079, 0x0079,  /*  0 */
-	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 */
+	0x00ff, 0x00ff, 0x0120, 0x0000,  /*  0 */
+	0x00ff, 0x00ff, 0x00ff, 0x00ff,  /*  4 */
+	0x00ff, 0x0000, 0x0080, 0x0040,  /*  8 */
+	0x0000
 };
 
 #define WM8772_HWFMT \
 	(SND_SOC_HWFMT_I2S | SND_SOC_HWFMT_LEFT_J | SND_SOC_HWFMT_RIGHT_J | \
-	SND_SOC_HWFMT_CBS_CFS | SND_SOC_HWFMT_CBM_CFM |\
-	SND_SOC_HWFMT_NB_NF | SND_SOC_HWFMT_NB_IF | SND_SOC_HWFMT_IB_NF | \
-	SND_SOC_HWFMT_IB_IF)
+	SND_SOC_HWFMT_CBS_CFS | SND_SOC_HWFMT_CBM_CFM | SND_SOC_HWFMT_NB_NF | \
+	SND_SOC_HWFMT_IB_NF)
 
 /* priv1 is srate register setting */
-static struct snd_soc_hw_mode wm8750_hwfmt[] = {
-	{WM8750_HWFMT, SND_SOC_HWBITS(16), 8000,   64, 0x000c},
-	{WM8750_HWFMT, SND_SOC_HWBITS(16), 8000,   96, 0x000e},
-	{WM8750_HWFMT, SND_SOC_HWBITS(16), 8000,  128, 0x004c},
-	{WM8750_HWFMT, SND_SOC_HWBITS(16), 8000,  192, 0x004e},
-
-	{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},
+static struct snd_soc_hw_mode wm8772_hwfmt[] = {
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_32000, 128, 0x0000},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_32000, 192, 0x0001},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_32000, 256, 0x0002},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_32000, 384, 0x0003},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_32000, 512, 0x0004},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_32000, 768, 0x0005},
+	
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_44100, 128, 0x0000},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_44100, 192, 0x0001},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_44100, 256, 0x0002},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_44100, 384, 0x0003},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_44100, 512, 0x0004},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_44100, 768, 0x0005},
+
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, 128, 0x0000},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, 196, 0x0001},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, 256, 0x0002},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, 384, 0x0003},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, 512, 0x0004},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, 768, 0x0005},
+
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_96000, 128, 0x0000},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_96000, 192, 0x0001},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_96000, 256, 0x0002},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_96000, 384, 0x0003},
+	
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_192000, 128, 0x0000},
+	{WM8772_HWFMT, SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_192000, 192, 0x0001},
 };
 
 /*
- * read wm8750 register cache
+ * read wm8772 register cache
  */
-static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec * codec, 
+static inline unsigned int wm8772_read_reg_cache(struct snd_soc_codec * codec, 
 	unsigned int reg)
 {
 	u16 *cache = codec->reg_cache;
-	if (reg > WM8750_CACHE_REGNUM)
+	if (reg > WM8772_CACHE_REGNUM)
 		return -1;
 	return cache[reg];
 }
 
 /*
- * write wm8750 register cache
+ * write wm8772 register cache
  */
-static inline void wm8750_write_reg_cache(struct snd_soc_codec * codec, 
+static inline void wm8772_write_reg_cache(struct snd_soc_codec * codec, 
 	unsigned int reg, unsigned int value)
 {
 	u16 *cache = codec->reg_cache;
-	if (reg > WM8750_CACHE_REGNUM)
+	if (reg > WM8772_CACHE_REGNUM)
 		return;
 	cache[reg] = value;
 }
 
-static int wm8750_write(struct snd_soc_codec * codec, unsigned int reg, 
+static int wm8772_write(struct snd_soc_codec * codec, unsigned int reg, 
 	unsigned int value)
 {
 	u8 data[2];
-	struct i2c_client *i2c = (struct i2c_client*)codec->control_data;
 
 	/* data is 
-	 *   D15..D9 WM8750 register offset
+	 *   D15..D9 WM8772 register offset
 	 *   D8...D0 register data
 	 */
 	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
 	data[1] = value & 0x00ff;
 
-	wm8750_write_reg_cache (codec, reg, value);
-	if (i2c_master_send(i2c, data, 2) == 2)
+	wm8772_write_reg_cache (codec, reg, value);
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
 		return 0;
 	else
 		return -1;
 }
 
-#define wm8750_reset(c)	wm8750_write(c, WM8750_RESET, 0)
+#define wm8772_reset(c)	wm8772_write(c, WM8772_RESET, 0)
 
 /*
- * WM8750 Controls
+ * WM8772 Controls
  */
-static const char* wm8750_bass[] = {"Linear Control", "Adaptive Boost"};
-static const char* wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
-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_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_ADCDAC, 5, 4, wm8750_adcpol),
-SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph),
-SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 16 */
+static const char* wm8772_zero_flag[] = {"All Ch", "Ch 1", "Ch 2", "Ch3"};
 
+static const struct soc_enum wm8772_enum[] = {
+SOC_ENUM_SINGLE(WM8772_DACCTRL, 0, 4, wm8772_zero_flag),
 };
 
-static const snd_kcontrol_new_t wm8750_snd_controls[] = {
-
-SOC_SINGLE("Left Capture Volume", WM8750_LINVOL, 0, 63, 0),
-SOC_SINGLE("Left Capture ZC Switch", WM8750_LINVOL, 6, 1, 0),
-SOC_SINGLE("Left Capture Switch", WM8750_LINVOL, 7, 1, 1),
-SOC_SINGLE("Right Capture Volume", WM8750_RINVOL, 0, 63, 0),
-SOC_SINGLE("Right Capture ZC Switch", WM8750_RINVOL, 6, 1, 0),
-SOC_SINGLE("Right Capture Switch", WM8750_RINVOL, 7, 1, 1),
-
-SOC_SINGLE("Left Out1 Playback ZC Switch", WM8750_LOUT1V, 7, 1, 0),
-SOC_SINGLE("Right Out1 Playback ZC Switch", WM8750_ROUT1V, 7, 1, 0),
-
-SOC_SINGLE("Left Out2 Playback ZC Switch", WM8750_LOUT2V, 7, 1, 0),
-SOC_SINGLE("Right Out2 Playback ZC Switch", WM8750_ROUT2V, 7, 1, 0),
-
-SOC_ENUM("Playback De-emphasis", wm8750_enum[15]),
-
-SOC_ENUM("Capture Polarity", wm8750_enum[14]),
-SOC_SINGLE("Playback 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0),
-SOC_SINGLE("Capture 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 Capture Target Volume", WM8750_ALC1, 0, 7, 0),
-SOC_SINGLE("ALC Capture Max Volume", WM8750_ALC1, 4, 7, 0),
-SOC_ENUM("ALC Capture Function", wm8750_enum[6]),
-SOC_SINGLE("ALC Capture ZC Switch", WM8750_ALC2, 7, 1, 0),
-SOC_SINGLE("ALC Capture Hold Time", WM8750_ALC2, 0, 15, 0),
-SOC_SINGLE("ALC Capture Decay Time", WM8750_ALC3, 4, 15, 0),
-SOC_SINGLE("ALC Capture Attack Time", WM8750_ALC3, 0, 15, 0),
-SOC_SINGLE("ALC Capture NG Threshold", WM8750_NGATE, 3, 31, 0),
-SOC_ENUM("ALC Capture NG Type", wm8750_enum[4]),
-SOC_SINGLE("ALC Capture NG Switch", WM8750_NGATE, 0, 1, 0),
-
-SOC_SINGLE("Left ADC Capture Volume", WM8750_LADC, 0, 255, 0),
-SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0),
-
-SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0),
-SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0),
-
-SOC_SINGLE("Right Out2 Playback Invert Switch", WM8750_ADCTL2, 4, 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_SINGLE("Left Mic Boost", WM8750_LADCIN, 4, 3, 0),
-SOC_SINGLE("Right Mic Boost", WM8750_RADCIN, 4, 3, 0),
-
-SOC_SINGLE("Left Bypass Left Playback Volume", WM8750_LOUTM1, 4, 7, 1),
-SOC_SINGLE("Right Bypass Left Playback Volume", WM8750_LOUTM2, 4, 7, 1),
+static const snd_kcontrol_new_t wm8772_snd_controls[] = {
 
-SOC_SINGLE("Left Bypass Right Playback Volume", WM8750_ROUTM1, 4, 7, 1),
-SOC_SINGLE("Right Bypass Right Playback Volume", WM8750_ROUTM2, 4, 7, 1),
+SOC_SINGLE("Left1 Playback Volume", WM8772_LDAC1VOL, 0, 255, 0),
+SOC_SINGLE("Left2 Playback Volume", WM8772_LDAC2VOL, 0, 255, 0),
+SOC_SINGLE("Left3 Playback Volume", WM8772_LDAC3VOL, 0, 255, 0),
+SOC_SINGLE("Right1 Playback Volume", WM8772_RDAC1VOL, 0, 255, 0),
+SOC_SINGLE("Right1 Playback Volume", WM8772_RDAC2VOL, 0, 255, 0),
+SOC_SINGLE("Right1 Playback Volume", WM8772_RDAC3VOL, 0, 255, 0),
+SOC_SINGLE("Master Playback Volume", WM8772_MDACVOL, 0, 255, 0),
 
-SOC_SINGLE("Left Bypass Mono Playback Volume", WM8750_MOUTM1, 4, 7, 1),
-SOC_SINGLE("Right Bypass Mono Playback Volume", WM8750_MOUTM2, 4, 7, 1), 
+SOC_SINGLE("Playback Switch", WM8772_DACCH, 0, 1, 0),
+SOC_SINGLE("Capture Switch", WM8772_ADCCTRL, 2, 1, 0),
+	
+SOC_SINGLE("Demp1 Playback Switch", WM8772_DACCTRL, 6, 1, 0),
+SOC_SINGLE("Demp2 Playback Switch", WM8772_DACCTRL, 7, 1, 0),
+SOC_SINGLE("Demp3 Playback Switch", WM8772_DACCTRL, 8, 1, 0),
 
-SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0),
+SOC_SINGLE("Phase Invert 1 Switch", WM8772_IFACE, 6, 1, 0),
+SOC_SINGLE("Phase Invert 2 Switch", WM8772_IFACE, 7, 1, 0),
+SOC_SINGLE("Phase Invert 3 Switch", WM8772_IFACE, 8, 1, 0),
+	
+SOC_SINGLE("Playback ZC Switch", WM8772_DACCTRL, 0, 1, 0),
 
+SOC_SINGLE("Capture High Pass Switch", WM8772_ADCCTRL, 3, 1, 0),
 };
 
 /* add non dpm controls */
-static int wm8750_add_controls(struct snd_soc_codec *codec)
+static int wm8772_add_controls(struct snd_soc_codec *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)
+	for (i = 0; i < ARRAY_SIZE(wm8772_snd_controls); i++) {
+		if ((err = snd_ctl_add(codec->card, snd_soc_cnew(&wm8772_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("Playback Switch", WM8750_LOUTM1, 8, 1, 0),
-SOC_DPM_SINGLE("Left Bypass Switch", WM8750_LOUTM1, 7, 1, 0),
-SOC_DPM_SINGLE("Right Playback Switch", WM8750_LOUTM2, 8, 1, 0),
-SOC_DPM_SINGLE("Right Bypass Switch", WM8750_LOUTM2, 7, 1, 0),
-};
-
-/* Right Mixer */
-static const snd_kcontrol_new_t wm8750_right_mixer_controls[] = {
-SOC_DPM_SINGLE("Left Playback Switch", WM8750_ROUTM1, 8, 1, 0),
-SOC_DPM_SINGLE("Left Bypass Switch", WM8750_ROUTM1, 7, 1, 0),
-SOC_DPM_SINGLE("Playback Switch", WM8750_ROUTM2, 8, 1, 0),
-SOC_DPM_SINGLE("Right Bypass Switch", WM8750_ROUTM2, 7, 1, 0),
-};
-
-/* Mono Mixer */
-static const snd_kcontrol_new_t wm8750_mono_mixer_controls[] = {
-SOC_DPM_SINGLE("Left Playback Switch", WM8750_MOUTM1, 8, 1, 0),
-SOC_DPM_SINGLE("Left Bypass Switch", WM8750_MOUTM1, 7, 1, 0),
-SOC_DPM_SINGLE("Right Playback Switch", WM8750_MOUTM2, 8, 1, 0),
-SOC_DPM_SINGLE("Right Bypass Switch", WM8750_MOUTM2, 7, 1, 0),
-};
-
-/* Left Line Mux */
-static const snd_kcontrol_new_t wm8750_left_line_controls =
-SOC_DPM_ENUM("Route", wm8750_enum[8]);
-
-/* Right Line Mux */
-static const snd_kcontrol_new_t wm8750_right_line_controls =
-SOC_DPM_ENUM("Route", wm8750_enum[9]);
-
-/* Left PGA Mux */
-static const snd_kcontrol_new_t wm8750_left_pga_controls =
-SOC_DPM_ENUM("Route", wm8750_enum[10]);
-
-/* Right PGA Mux */
-static const snd_kcontrol_new_t wm8750_right_pga_controls =
-SOC_DPM_ENUM("Route", wm8750_enum[11]);
-
-/* Out 3 Mux */
-static const snd_kcontrol_new_t wm8750_out3_controls =
-SOC_DPM_ENUM("Route", wm8750_enum[12]);
-
-/* Differential Mux */
-static const snd_kcontrol_new_t wm8750_diffmux_controls =
-SOC_DPM_ENUM("Route", wm8750_enum[13]);
-
-/* Mono ADC Mux */
-static const snd_kcontrol_new_t wm8750_monomux_controls =
-SOC_DPM_ENUM("Route", wm8750_enum[16]);
-
-/* LOUT 1 Volume */
-static const snd_kcontrol_new_t wm8750_lout1_vol_controls =
-SOC_DPM_SINGLE("Left Out1 Playback Volume", WM8750_LOUT1V, 0, 127, 0);
-
-/* ROUT 1 Volume */
-static const snd_kcontrol_new_t wm8750_rout1_vol_controls =
-SOC_DPM_SINGLE("Right Out1 Playback Volume", WM8750_ROUT1V, 0, 127, 0);
-
-/* LOUT 2 Volume */
-static const snd_kcontrol_new_t wm8750_lout2_vol_controls =
-SOC_DPM_SINGLE("Left Out2 Playback Volume", WM8750_LOUT2V, 0, 127, 0);
-
-/* ROUT 2 Volume */
-static const snd_kcontrol_new_t wm8750_rout2_vol_controls =
-SOC_DPM_SINGLE("Right Out2 Playback Volume", WM8750_ROUT2V, 0, 127, 0);
-
-/* Mono Volume */
-static const snd_kcontrol_new_t wm8750_mout_vol_controls =
-SOC_DPM_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0);
-
-static const struct snd_soc_dpm_widget wm8750_dpm_widgets[] = {
-	SND_SOC_DPM_CLOCK("WM8750 Clock", WM8750_PWR1, 0, 1),
-	SND_SOC_DPM_MUTE("DAC Mute", WM8750_ADCDAC, 3, 0),
-	SND_SOC_DPM_MIXER("Left Mixer", -1, 0, 0, &wm8750_left_mixer_controls[0], ARRAY_SIZE(wm8750_left_mixer_controls)),
-	SND_SOC_DPM_MIXER("Right Mixer", -1, 0, 0, &wm8750_right_mixer_controls[0], ARRAY_SIZE(wm8750_right_mixer_controls)),
-	SND_SOC_DPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0, &wm8750_mono_mixer_controls[0], ARRAY_SIZE(wm8750_mono_mixer_controls)),
-
-	SND_SOC_DPM_VOLUME("Right Out 2", WM8750_PWR2, 3, 0, &wm8750_rout2_vol_controls, 1),
-	SND_SOC_DPM_VOLUME("Left Out 2", WM8750_PWR2, 4, 0, &wm8750_lout2_vol_controls, 1),
-	SND_SOC_DPM_VOLUME("Right Out 1", WM8750_PWR2, 5, 0, &wm8750_rout1_vol_controls, 1),
-	SND_SOC_DPM_VOLUME("Left Out 1", WM8750_PWR2, 6, 0, &wm8750_lout1_vol_controls, 1),
-	SND_SOC_DPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0, NULL, 0),
-	SND_SOC_DPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0, NULL, 0),
-
-	//"Mic Bias", WM8750_PWR1, 1, 0
-	SND_SOC_DPM_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_VOLUME("Mono Out 1", WM8750_PWR2, 2, 0, &wm8750_mout_vol_controls, 1),
-	
-	SND_SOC_DPM_MUX("Differential Mux", -1, 0, 0, &wm8750_diffmux_controls),
-	SND_SOC_DPM_MUX("Left ADC Mux", -1, 0, 0, &wm8750_monomux_controls),
-	SND_SOC_DPM_MUX("Right ADC Mux", -1, 0, 0, &wm8750_monomux_controls),
-
-	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("LINPUT1"),
-	SND_SOC_DPM_INPUT("LINPUT2"),
-	SND_SOC_DPM_INPUT("LINPUT3"),
-	SND_SOC_DPM_INPUT("RINPUT1"),
-	SND_SOC_DPM_INPUT("RINPUT2"),
-	SND_SOC_DPM_INPUT("RINPUT3"),
-};
-
-static int wm8750_add_widgets(struct snd_soc_codec *codec)
+static int wm8772_pcm_prepare(snd_pcm_substream_t *substream)
 {
-	int i;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	u16 diface = wm8772_read_reg_cache(codec, WM8772_IFACE) & 0xffc0;
+	u16 diface_ctrl = wm8772_read_reg_cache(codec, WM8772_DACRATE) & 0xfe1f;
+	u16 aiface = 0;
+	u16 aiface_ctrl = wm8772_read_reg_cache(codec, WM8772_ADCCTRL) & 0xfcff;
 	
-	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", "Playback Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Left Bypass Switch", "Left Line Mux");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Right Playback Switch", "Right DAC");
-	snd_soc_dpm_connect_input(codec, "Left Mixer", "Right Bypass Switch", "Right Line Mux");
-
-	/* right mixer */
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Left Playback Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Left Bypass Switch", "Left Line Mux");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Playback Switch", "Right DAC");
-	snd_soc_dpm_connect_input(codec, "Right Mixer", "Right Bypass Switch", "Right Line Mux");
-
-	/* 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 Playback Switch", "Left DAC");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Left Bypass Switch", "Left Line Mux");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Right Playback Switch", "Right DAC");
-	snd_soc_dpm_connect_input(codec, "Mono Mixer", "Right Bypass Switch", "Right Line Mux");
-	
-	/* mono 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", "LINPUT1");
-	snd_soc_dpm_connect_input(codec, "Left Line Mux", "Line 2", "LINPUT2");
-	snd_soc_dpm_connect_input(codec, "Left Line Mux", "Line 3", "LINPUT3");
-	snd_soc_dpm_connect_input(codec, "Left Line Mux", "PGA", "Left PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Left Line Mux", "Differential", "Differential Mux");
-
-	/* Right Line Mux */
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Line 1", "RINPUT1");
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Line 2", "RINPUT2");
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Line 3", "RINPUT3");
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "PGA", "Right PGA Mux");
-	snd_soc_dpm_connect_input(codec, "Right Line Mux", "Differential", "Differential Mux");
-
-	/* Left PGA Mux */
-	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Line 1", "LINPUT1");
-	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Line 2", "LINPUT2");
-	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Line 3", "LINPUT3");
-	snd_soc_dpm_connect_input(codec, "Left PGA Mux", "Differential", "Differential Mux");
-
-	/* Right PGA Mux */
-	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Line 1", "RINPUT1");
-	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Line 2", "RINPUT2");
-	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Line 3", "RINPUT3");
-	snd_soc_dpm_connect_input(codec, "Right PGA Mux", "Differential", "Differential Mux");
-
-	/* Differential Mux */
-	snd_soc_dpm_connect_input(codec, "Differential Mux", "Line 1", "LINPUT1");
-	snd_soc_dpm_connect_input(codec, "Differential Mux", "Line 1", "RINPUT1");
-	snd_soc_dpm_connect_input(codec, "Differential Mux", "Line 2", "LINPUT2");
-	snd_soc_dpm_connect_input(codec, "Differential Mux", "Line 2", "RINPUT2");
-
-	/* 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)
-{
-	struct snd_soc_pcm_codec *pcm_c = substream->private_data;
-	struct snd_soc_codec *codec = pcm_c->codec;
-	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 |= 0x0040;
-			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;
-	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		
-	/* 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;
+		/* set master/slave audio interface */
+		switch(rtd->pcm_c->hw_runtime.hformat & SND_SOC_CLOCK_MASK) {
+			case SND_SOC_HWFMT_CBM_CFM:
+				diface_ctrl |= 0x0010;
+				break;
+			case SND_SOC_HWFMT_CBS_CFS:
+				break;
+		}
+		
+		/* interface format */
+		switch(rtd->pcm_c->hw_runtime.hformat & SND_SOC_FORMAT_MASK) {
+			case SND_SOC_HWFMT_I2S:
+				diface |= 0x0002;
+				break;
+			case SND_SOC_HWFMT_RIGHT_J:
+				break;
+			case SND_SOC_HWFMT_LEFT_J:
+				diface |= 0x0001;
+				break;
+			case SND_SOC_HWFMT_DSP_A:
+				diface |= 0x0003;
+				break;
+			case SND_SOC_HWFMT_DSP_B:
+				diface |= 0x0007;
+				break;
+		}
+			
+		/* bit size */
+		switch(rtd->pcm_c->hw_runtime.hbits) {
+			case SNDRV_PCM_FMTBIT_S16_LE:
+				break;
+			case SNDRV_PCM_FMTBIT_S20_3LE:
+				diface |= 0x0010;
+				break;
+			case SNDRV_PCM_FMTBIT_S24_3LE:
+				diface |= 0x0020;
+				break;
+			case SNDRV_PCM_FMTBIT_S32_LE:
+				diface |= 0x0030;
+				break;
+		}
+	
+		/* clock inversion */
+		switch(rtd->pcm_c->hw_runtime.hformat & SND_SOC_INV_MASK) {
+			case SND_SOC_HWFMT_NB_NF:
+				break;
+			case SND_SOC_HWFMT_IB_NF:
+				diface |= 0x0008;
+				break;
+		}
+		
+		/* set rate */
+		wm8772_write(codec, WM8772_DACRATE, diface_ctrl | 
+			rtd->pcm_c->hw_runtime. priv1 << 6);
+		wm8772_write(codec, WM8772_IFACE, diface);
+		
+	} else {
+		
+		/* set master/slave audio interface */
+		switch(rtd->pcm_c->hw_runtime.hformat & SND_SOC_CLOCK_MASK) {
+			case SND_SOC_HWFMT_CBM_CFM:
+				aiface |= 0x0010;
+				break;
+			case SND_SOC_HWFMT_CBS_CFS:
+				break;
+		}
+		
+		/* interface format */
+		switch(rtd->pcm_c->hw_runtime.hformat & SND_SOC_FORMAT_MASK) {
+			case SND_SOC_HWFMT_I2S:
+				aiface |= 0x0002;
+				break;
+			case SND_SOC_HWFMT_RIGHT_J:
+				break;
+			case SND_SOC_HWFMT_LEFT_J:
+				aiface |= 0x0001;
+				break;
+			case SND_SOC_HWFMT_DSP_A:
+				aiface |= 0x0003;
+				break;
+			case SND_SOC_HWFMT_DSP_B:
+				aiface |= 0x0003;
+				aiface_ctrl |= 0x0010;
+				break;
+		}
+			
+		/* bit size */
+		switch(rtd->pcm_c->hw_runtime.hbits) {
+			case SNDRV_PCM_FMTBIT_S16_LE:
+				break;
+			case SNDRV_PCM_FMTBIT_S20_3LE:
+				aiface |= 0x0004;
+				break;
+			case SNDRV_PCM_FMTBIT_S24_3LE:
+				aiface |= 0x0008;
+				break;
+			case SNDRV_PCM_FMTBIT_S32_LE:
+				aiface |= 0x000c;
+				break;
+		}
+	
+		/* clock inversion */
+		switch(rtd->pcm_c->hw_runtime.hformat & SND_SOC_INV_MASK) {
+			case SND_SOC_HWFMT_NB_NF:
+				break;
+			case SND_SOC_HWFMT_IB_NF:
+				aiface_ctrl |= 0x0020;
+				break;
+		}
+		
+		/* set rate */
+		wm8772_write(codec, WM8772_ADCCTRL, aiface_ctrl);
+		wm8772_write(codec, WM8772_ADCRATE, aiface | 
+			rtd->pcm_c->hw_runtime. priv1 << 5);
 	}
 
-	/* 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_write(codec, WM8750_SRATE, pcm_c->hw_runtime.priv1);
-	wm8750_write(codec, WM8750_IFACE, iface);
-	
 	return 0;
 }
 
-static void wm8750_device_release(struct device * dev)
+static int wm8772_dpm_event(struct snd_soc_codec *codec, int event)
 {
-}
-
-static int wm8750_dpm_event(struct snd_soc_codec *codec, int event)
-{
-	u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3f;
+	u16 master = wm8772_read_reg_cache(codec, WM8772_DACRATE) & 0xffe0;
 	
 	switch (event) {
 		case SNDRV_CTL_POWER_D0: /* full On */
-			/* set vmid to 50k and unmute dac */
-			wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0);
+			/* vref/mid, clk and osc on, dac unmute, active */
+			wm8772_write(codec, WM8772_DACRATE, master);
 			break;
 		case SNDRV_CTL_POWER_D1: /* partial On */
 		case SNDRV_CTL_POWER_D2: /* partial On */
-			/* set vmid to 5k for quick power up */
-			wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c0);
 			break;
 		case SNDRV_CTL_POWER_D3hot: /* Off, with power */
-			/* mute dac and set vmid to 500k, enable VREF */
-			wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0140);
+			/* everything off except vref/vmid, dac mute, inactive */
+			wm8772_write(codec, WM8772_DACRATE, master | 0x0f);
 			break;
 		case SNDRV_CTL_POWER_D3cold: /* Off, without power */
-			wm8750_write(codec, WM8750_PWR1, 0x0000);
+			/* everything off, dac mute, inactive */
+			wm8772_write(codec, WM8772_DACRATE, master | 0x1f);
 			break;
 	}
-	
+	codec->dpm_state = event;
 	return 0;
 }
 
-static struct snd_soc_pcm_codec wm8750_pcm_client = {
-	.name = "WM8750",
+static struct snd_soc_pcm_codec wm8772_pcm_client = {
+	.name = "WM8772",
 	.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,
+	.nplayback = 3,
 	.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,
+		.prepare = wm8772_pcm_prepare,
 	},
 	.hw = {
-		.num_hmodes = ARRAY_SIZE(wm8750_hwfmt),
-		.hmodes = &wm8750_hwfmt[0],
+		.num_hmodes = ARRAY_SIZE(wm8772_hwfmt),
+		.hmodes = &wm8772_hwfmt[0],
 	},
 };
 
-/*
- * initialise the WM8750 driver
- * register the mixer and dsp interfaces with the kernel 
- */
-static int wm8750_probe(struct snd_soc_codec *codec)
+static int wm8772_suspend(struct platform_device *pdev, pm_message_t state)
 {
-	int reg;
-	
-	info("WM8750 Audio Codec %s", WM8750_VERSION);
-	
-	wm8750_reset(codec);
-	
-	/* charge output caps */
-	wm8750_dpm_event(codec, SNDRV_CTL_POWER_D2);
-
-	/* set the update bits */
-	reg = wm8750_read_reg_cache(codec, WM8750_LDAC);
-	wm8750_write(codec, WM8750_LDAC, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_RDAC);
-	wm8750_write(codec, WM8750_RDAC, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V);
-	wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V);
-	wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V);
-	wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V);
-	wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_LINVOL);
-	wm8750_write(codec, WM8750_LINVOL, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_RINVOL);
-	wm8750_write(codec, WM8750_RINVOL, reg | 0x0100);
-
-	wm8750_add_controls(codec);
-	wm8750_add_widgets(codec);
-	
-	/* wait for caps to finish charging - liam make this thread */
-	ssleep(1);
-	wm8750_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec* codec = socdev->codec;
 
+	wm8772_dpm_event(codec, SNDRV_CTL_POWER_D3cold);
 	return 0;
 }
 
-/* 
- * unregister interfaces and clean up
- */
-static void wm8750_remove(struct snd_soc_codec *codec)
+static int wm8772_resume(struct platform_device *pdev)
 {
-	wm8750_dpm_event(codec, SNDRV_CTL_POWER_D3cold);
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec* codec = socdev->codec;
+	int i;
+	u8 data[2];
+	u16 *cache = codec->reg_cache;
+
+	/* Sync reg_cache with the hardware */
+	for (i = 0; i < ARRAY_SIZE(wm8772_reg); i++) {
+		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+		data[1] = cache[i] & 0x00ff;
+		codec->hw_write(codec->control_data, data, 2);
+	}
+	wm8772_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
+	wm8772_dpm_event(codec, codec->suspend_dpm_state);
+	return 0;
 }
 
 /*
- * Attach WM8750 2 wire client 
+ * initialise the WM8772 driver
+ * register the mixer and dsp interfaces with the kernel 
  */
-static int wm8750_i2c_probe(struct i2c_adapter *adap, int addr, int kind)
-{		
-	int ret = 0;
-	struct snd_soc_codec *codec;
-	struct i2c_client *i2c;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-	
-	if ((codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL)) == NULL)
-		return -ENOMEM;
- 
-	if ((i2c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL)) == NULL){
-		kfree(codec);
-		return -ENOMEM;
-	}
-	memcpy(i2c, &client_template, sizeof(struct i2c_client));
-	codec->control_data = i2c;
-	i2c->dev.platform_data = codec;
-
-	if((ret = i2c_attach_client(i2c)) < 0) {
-		err("failed to attach codec at addr %x\n", addr);
-		kfree(i2c);
-		kfree(codec);
-		return ret;
-	}
+static int wm8772_init(struct snd_soc_device* socdev)
+{
+	struct snd_soc_codec* codec = socdev->codec;
+	int reg, ret = 0;
 
-	codec->name = "WM8750";
-	codec->longname = "WM8750 Portable Codec";
+	codec->name = "WM8772";
 	codec->owner = THIS_MODULE;
-	codec->pdev.name = "alsa-wm8750";
-	codec->pdev.id = -1;
-	codec->pdev.dev.release = wm8750_device_release;
-	codec->probe = wm8750_probe;
-	codec->remove = wm8750_remove;
-	codec->read = wm8750_read_reg_cache;
-	codec->write = wm8750_write;
-	codec->dpm_event = wm8750_dpm_event;
-	codec->pcms = &wm8750_pcm_client;
+	codec->read = wm8772_read_reg_cache;
+	codec->write = wm8772_write;
+	codec->dpm_event = wm8772_dpm_event;
+	codec->pcms = &wm8772_pcm_client;
 	codec->npcms = 1;
 	if ((codec->reg_cache = 
-			kzalloc(sizeof(u16) * ARRAY_SIZE(wm8750_reg), GFP_KERNEL)) == NULL)
+			kzalloc(sizeof(u16) * ARRAY_SIZE(wm8772_reg), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	memcpy(codec->reg_cache, wm8750_reg, sizeof(u16) * ARRAY_SIZE(wm8750_reg));
+	memcpy(codec->reg_cache, wm8772_reg, sizeof(u16) * ARRAY_SIZE(wm8772_reg));
+	
+	wm8772_reset(codec);
 
-	if((ret = snd_soc_register_codec(codec)) < 0) {
-		err("can't register codec");
-		i2c_del_driver(&wm8750_i2c_driver);
-		kfree(i2c);
+	/* register pcms */
+	if((ret = snd_soc_register_pcms(socdev)) < 0) {
 		kfree(codec->reg_cache);
-		kfree(codec);
+		return ret;
 	}
+	
+	/* power on device */
+	wm8772_dpm_event(codec, SNDRV_CTL_POWER_D3hot);
+	
+	/* set the update bits */
+	reg = wm8772_read_reg_cache(codec, WM8772_MDACVOL);
+	wm8772_write(codec, WM8772_MDACVOL, reg | 0x0100);
+	reg = wm8772_read_reg_cache(codec, WM8772_LDAC1VOL);
+	wm8772_write(codec, WM8772_LDAC1VOL, reg | 0x0100);
+	reg = wm8772_read_reg_cache(codec, WM8772_LDAC2VOL);
+	wm8772_write(codec, WM8772_LDAC2VOL, reg | 0x0100);
+	reg = wm8772_read_reg_cache(codec, WM8772_LDAC3VOL);
+	wm8772_write(codec, WM8772_LDAC3VOL, reg | 0x0100);
+	reg = wm8772_read_reg_cache(codec, WM8772_RDAC1VOL);
+	wm8772_write(codec, WM8772_RDAC1VOL, reg | 0x0100);
+	reg = wm8772_read_reg_cache(codec, WM8772_RDAC2VOL);
+	wm8772_write(codec, WM8772_RDAC2VOL, reg | 0x0100);
+	reg = wm8772_read_reg_cache(codec, WM8772_RDAC3VOL);
+	wm8772_write(codec, WM8772_RDAC3VOL, reg | 0x0100);
 
-	return ret;
-}
-
-static int wm8750_i2c_detach(struct i2c_client *client)
-{
-	struct snd_soc_codec *codec = 
-		(struct snd_soc_codec*)client->dev.platform_data;
-			
-	i2c_detach_client(client);
-	snd_soc_unregister_codec(codec);
-	kfree(codec->control_data);
-	kfree(codec->reg_cache);
-	kfree(codec);
+	wm8772_add_controls(codec);
+	snd_soc_register_card(socdev);
+	
 	return 0;
 }
 
-static int wm8750_i2c_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, wm8750_i2c_probe);
-}
+static struct snd_soc_device *wm8772_socdev;
 
-/* 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 int wm8772_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct wm8772_setup_data *setup = socdev->codec_data;
+	struct snd_soc_codec* codec;
+	int ret = 0;
 
-static struct i2c_client client_template = {
-	.name =   "WM8750",
-	.flags =  I2C_CLIENT_ALLOW_USE,
-	.driver = &wm8750_i2c_driver,
-};
+	printk(KERN_INFO "WM8772 Audio Codec %s", WM8772_VERSION);
 
-static int __init wm8750_init(void)
-{	
-	int ret = 0;
+	if ((codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
 
-	info("WM8750 Audio Codec %s", WM8750_VERSION);
+	socdev->codec = codec;
+	INIT_LIST_HEAD(&codec->dpm_widgets);
+	INIT_LIST_HEAD(&codec->dpm_paths);
 
-	if ((ret = i2c_add_driver(&wm8750_i2c_driver)) != 0)
-		err("can't add i2c driver");
+	wm8772_socdev = socdev;
+	
+	/* Add other interfaces here */
+#warning do 3 wire device probe here and then call wm8772_init()
 	
 	return ret;
 }
 
-static void __exit wm8750_exit(void)
+/* power down chip */
+static int wm8772_remove(struct platform_device *pdev)
 {
-	i2c_del_driver(&wm8750_i2c_driver);
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec* codec = socdev->codec;
+
+	if (codec->control_data)
+		wm8772_dpm_event(codec, SNDRV_CTL_POWER_D3cold);
+
+	snd_soc_free_pcms(socdev);
+	kfree(codec);
+
+	return 0;
 }
 
-module_init(wm8750_init);
-module_exit(wm8750_exit);
 
-MODULE_DESCRIPTION("Soc WM8750 driver");
+struct snd_soc_codec_device soc_codec_dev_wm8772 = {
+	.probe = 	wm8772_probe,
+	.remove = 	wm8772_remove,
+	.suspend = 	wm8772_suspend,
+	.resume =	wm8772_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8772);
+
+MODULE_DESCRIPTION("Soc WM8772 driver");
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8772.h b/sound/soc/codecs/wm8772.h
index 94dee3a..e1c1a3d 100644
--- a/sound/soc/codecs/wm8772.h
+++ b/sound/soc/codecs/wm8772.h
@@ -17,18 +17,23 @@
 
 /* WM8772 register space */
 
-#define WM8731_LINVOL   0x00
-#define WM8731_RINVOL   0x01
-#define WM8731_LOUT1V   0x02
-#define WM8731_ROUT1V   0x03
-#define WM8731_APANA    0x04
-#define WM8731_APDIGI   0x05
-#define WM8731_PWR      0x06
-#define WM8731_IFACE    0x07
-#define WM8731_SRATE    0x08
-#define WM8731_ACTIVE   0x09
-#define WM8731_RESET	0x0f
+#define WM8772_LDAC1VOL   0x00
+#define WM8772_RDAC1VOL   0x01
+#define WM8772_DACCH      0x02
+#define WM8772_IFACE      0x03
+#define WM8772_LDAC2VOL   0x04
+#define WM8772_RDAC2VOL   0x05
+#define WM8772_LDAC3VOL   0x06
+#define WM8772_RDAC3VOL   0x07
+#define WM8772_MDACVOL    0x08
+#define WM8772_DACCTRL    0x09
+#define WM8772_DACRATE    0x0a
+#define WM8772_ADCRATE    0x0b
+#define WM8772_ADCCTRL    0x0c
+#define WM8772_RESET	  0x1f
 
-#define WM8731_CACHEREGNUM 	10
+#define WM8772_CACHE_REGNUM 	10
+
+extern struct snd_soc_codec_device soc_codec_dev_wm8772;
 
 #endif
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index f36f1e1..da4b2f3 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -705,6 +705,10 @@ static int wm8971_init(struct snd_soc_de
 	return 0;
 }
 
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+static struct snd_soc_device *wm8971_socdev;
+	
 #ifdef CONFIG_I2C
 
 /*
@@ -723,10 +727,6 @@ I2C_CLIENT_INSMOD;
 static struct i2c_driver wm8971_i2c_driver;
 static struct i2c_client client_template;
 
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-static struct snd_soc_device *wm8971_socdev;
-
 static int wm8971_codec_probe(struct i2c_adapter *adap, int addr, int kind)
 {
 	struct snd_soc_device *socdev = wm8971_socdev;
@@ -793,6 +793,7 @@ static struct i2c_client client_template
 	.flags =  I2C_CLIENT_ALLOW_USE,
 	.driver = &wm8971_i2c_driver,
 };
+#endif
 
 static int wm8971_probe(struct platform_device *pdev)
 {
@@ -816,21 +817,20 @@ static int wm8971_probe(struct platform_
 		kfree(codec);
 		return -ENOMEM;
 	}
-	
+#ifdef CONFIG_I2C	
 	if (setup->i2c_address) {
 		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
 		if ((ret = i2c_add_driver(&wm8971_i2c_driver)) != 0)
 			printk(KERN_ERR "can't add i2c driver");
-	} else {
-		/* Add other interfaces here */
 	}
+#else
+		/* Add other interfaces here */
+#endif
 
 	return ret;
 }
 
-#endif
-
 /* power down chip */
 static int wm8971_remove(struct platform_device *pdev)
 {
@@ -842,7 +842,9 @@ static int wm8971_remove(struct platform
 	if(wm8971_workq)
 		destroy_workqueue(wm8971_workq);
 	snd_soc_free_pcms(socdev);
+#ifdef CONFIG_I2C
 	i2c_del_driver(&wm8971_i2c_driver);
+#endif
 	kfree(codec);
 
 	return 0;
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index d1d7cd5..6c8ff3a 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -39,8 +39,19 @@
 #include "../codecs/wm8731.h"
 #include "pxa2xx-pcm.h"
 
+#define CORGI_HP	0
+#define CORGI_MIC	1
+#define CORGI_LINE	2
+#define CORGI_HEADSET	3
+#define CORGI_SPK_AUTO	0
+#define CORGI_SPK_ON	1
+#define CORGI_SPK_OFF	2
+
 static struct workqueue_struct *corgi_hp_workq = NULL;
 static struct work_struct corgi_hp_event_work;
+static int corgi_hp_status = 0;
+static int corgi_jack_func = 0;
+static int corgi_spk_func = 0;
 
 static irqreturn_t corgi_hp_isr(int irq, void *dev_id, struct pt_regs *fp)
 {
@@ -50,80 +61,173 @@ static irqreturn_t corgi_hp_isr(int irq,
 	return IRQ_HANDLED;
 }
 
-#define READ_GPIO_BIT(x)    (GPLR(x) & GPIO_bit(x))
-
-static void corgi_hp_work(void *data)
+static void corgi_ext_control(struct snd_soc_codec *codec)
 {
-	int hp_status = (READ_GPIO_BIT(CORGI_GPIO_AK_INT) != 0);
-	struct snd_soc_codec *codec = (struct snd_soc_codec *)data;
-	
-	printk("HP Status: %d\n", hp_status);
-	corgikbd_report_hp(hp_status);
-	
 	/* change the dpm status depending on the insertion */
-	if(hp_status == 1) {
-		snd_soc_dpm_set_connection(codec, "ROUT", 0);
-		snd_soc_dpm_set_connection(codec, "LOUT", 0);
-		snd_soc_dpm_set_connection(codec, "LHPOUT", 1);
-		snd_soc_dpm_set_connection(codec, "RHPOUT", 1);
+	if (corgi_hp_status == 1) {
+		
+		/* do we need to mute spk */
+		if(corgi_spk_func != CORGI_SPK_ON) {
+			reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); // RP spk off ?
+			snd_soc_dpm_set_connection(codec, "Ext Spk", 0);
+		} else {
+			snd_soc_dpm_set_connection(codec, "Ext Spk", 1);
+			set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); // RP spk on ?
+		}
+			
+		/* set up jack connection */
+		switch(corgi_jack_func) {
+		case CORGI_HP:
+			/* enable and unmute hp jack, disable mic bias */
+			snd_soc_dpm_set_connection(codec, "Mic Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Line Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Headphone Jack", 1);
+			reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS); //RP
+			set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);// RP
+			set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);//RP
+			break;
+		case CORGI_MIC:
+			/* enable mic jack and bias, mute hp */
+			snd_soc_dpm_set_connection(codec, "Headphone Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Line Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Mic Jack", 1);
+			set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);//RP
+			reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);// RP
+			reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);//RP
+			break;
+		case CORGI_LINE:
+			/* enable line jack, disable mic bias and mute hp */
+			snd_soc_dpm_set_connection(codec, "Headphone Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Mic Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Line Jack", 1);
+			reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);//RP
+			reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);// RP
+			reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);//RP
+			break;
+		case CORGI_HEADSET:
+			/* enable and unmute headset jack enable mic bias, mute L hp */
+			snd_soc_dpm_set_connection(codec, "Headphone Jack", 1);
+			snd_soc_dpm_set_connection(codec, "Mic Jack", 1);
+			snd_soc_dpm_set_connection(codec, "Line Jack", 0);
+			reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);//RP
+			reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);// RP
+			set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);//RP
+			break;
+		}	
 	} else {
-		snd_soc_dpm_set_connection(codec, "ROUT", 1);
-		snd_soc_dpm_set_connection(codec, "LOUT", 1);
-		snd_soc_dpm_set_connection(codec, "LHPOUT", 0);
-		snd_soc_dpm_set_connection(codec, "RHPOUT", 0);
+		/* jack removed, so revert to spk if enabled */
+		snd_soc_dpm_set_connection(codec, "Headphone Jack", 0);
+		snd_soc_dpm_set_connection(codec, "Mic Jack", 0);
+		snd_soc_dpm_set_connection(codec, "Line Jack", 0);
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);//RP
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);// RP
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);//RP
+		
+		if(corgi_spk_func != CORGI_SPK_OFF) {
+			snd_soc_dpm_set_connection(codec, "Ext Spk", 1);
+			set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); // RP on ?
+		} else {
+			reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); // RP off ?
+			snd_soc_dpm_set_connection(codec, "Ext Spk", 0);
+		}
 	}
 	snd_soc_dpm_sync(codec);
 }
 
-int corgi_get_snd_scoop(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+#define READ_GPIO_BIT(x)    (GPLR(x) & GPIO_bit(x))
+
+static int corgi_startup(snd_pcm_substream_t *substream)
 {
-	unsigned short reg = kcontrol->private_value;
-	
-	ucontrol->value.integer.value[0] = ((read_scoop_reg(&corgiscoop_device.dev, SCOOP_GPWR) & reg) == 0);
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	/* check the jack status at stream startup */	
+	corgi_hp_status = (READ_GPIO_BIT(CORGI_GPIO_AK_INT) != 0);
+	corgi_ext_control(codec);
 	return 0;
 }
 
-int corgi_put_snd_scoop(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static struct snd_soc_ops corgi_ops = {
+	.startup = corgi_startup,
+};
+
+static void corgi_hp_work(void *data)
 {
-	unsigned short reg = kcontrol->private_value & 0xffff;
+	struct snd_soc_codec *codec = (struct snd_soc_codec *)data;
+	corgi_hp_status = (READ_GPIO_BIT(CORGI_GPIO_AK_INT) != 0);
 	
-	if (ucontrol->value.integer.value[0])
-		reset_scoop_gpio(&corgiscoop_device.dev, reg);
-	else
-		set_scoop_gpio(&corgiscoop_device.dev, reg);
+	printk("HP Status: %d\n", corgi_hp_status);
+	corgikbd_report_hp(corgi_hp_status);
+	corgi_ext_control(codec);
+}
+
+static int corgi_get_jack(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ucontrol->value.integer.value[0] = corgi_jack_func;
+	return 0;
+}
+
+static int corgi_set_jack(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{	
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+	corgi_jack_func = ucontrol->value.integer.value[0];
+	corgi_ext_control(codec);
+	return 0;
+}
+
+static int corgi_get_spk(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ucontrol->value.integer.value[0] = corgi_spk_func;
+	return 0;
+}
+
+static int corgi_set_spk(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+	corgi_spk_func = ucontrol->value.integer.value[0];
+	corgi_ext_control(codec);
 	return 0;
 }
 
 /* corgi machine dpm widgets */
 static const struct snd_soc_dpm_widget wm8731_dpm_widgets[] = {
 SND_SOC_DPM_HP("Headphone Jack"),
-SND_SOC_DPM_MIC("Mic1 Jack"),
+SND_SOC_DPM_MIC("Mic Jack"),
+SND_SOC_DPM_SPK("Ext Spk"),
+SND_SOC_DPM_LINE("Line Jack"),
 };
 
-/* example machine interconnections */
+/* Corgi machine interconnections */
 static const char* intercon[][3] = {
 	
-	/* headphone connected to LOUT1, ROUT1 */
+	/* headphone connected to LHPOUT1, RHPOUT1 */
 	{"Headphone Jack", NULL, "LHPOUT"},
 	{"Headphone Jack", NULL, "RHPOUT"},
 	
-	/* ext speaker connected to LOUT2, ROUT2 via amp */
-	{"Ext Amp", NULL, "ROUT"},
-	{"Ext Amp", NULL, "LOUT"},
+	/* speaker connected to LOUT, ROUT */
+	{"Ext Spk", NULL, "ROUT"},
+	{"Ext Spk", NULL, "LOUT"},
 	
-	/* mic is connected to mic1 - with bias */
-	{"MICIN", NULL, "Mic Bias"},
+	/* mic is connected to LINEIN - with bias */
 	{"LLINEIN", NULL, "Mic Bias"},
-	{"Mic Bias", NULL, "Mic1 Jack"},
+	{"Mic Bias", NULL, "Mic Jack"},
+	
+	/* line is connected to LINEIN - no bias */
+	{"LLINEIN", NULL, "Line Jack"},
 
 	{NULL, NULL, NULL},
 };
 
+static const char* jack_function[] = {"Headphone", "Mic", "Line", "Headset"};
+static const char* spk_function[] = {"Auto", "On", "Off"};
+static const struct soc_enum corgi_enum[] = {
+	SOC_ENUM_SINGLE_EXT(4, jack_function),
+	SOC_ENUM_SINGLE_EXT(3, spk_function),
+};
+
 static const snd_kcontrol_new_t wm8731_corgi_controls[] = {
-	SOC_SINGLE_BOOL_EXT("Left Mute Switch", CORGI_SCP_MUTE_L, corgi_get_snd_scoop, corgi_put_snd_scoop),
-	SOC_SINGLE_BOOL_EXT("Right Mute Switch", CORGI_SCP_MUTE_R, corgi_get_snd_scoop, corgi_put_snd_scoop),
-	SOC_SINGLE_BOOL_EXT("Speaker Mute Switch", CORGI_SCP_APM_ON, corgi_get_snd_scoop, corgi_put_snd_scoop),
-	SOC_SINGLE_BOOL_EXT("Mic Bias Switch", CORGI_SCP_MIC_BIAS, corgi_get_snd_scoop, corgi_put_snd_scoop),
+	SOC_ENUM_EXT("Jack Function", corgi_enum[0], corgi_get_jack, corgi_set_jack),
+	SOC_ENUM_EXT("Speaker Function", corgi_enum[1], corgi_get_spk, corgi_set_spk),
 };
 
 /*
@@ -169,6 +273,7 @@ static struct snd_soc_machine snd_soc_ma
 	.name = "Corgi",
 	.config = &codecs,
 	.nconfigs = 1,
+	.ops = &corgi_ops,
 };
 
 static struct wm8731_setup_data corgi_wm8731_setup = {
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index 7f4baf1..7d6e0c7 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -39,8 +39,20 @@
 #include "../codecs/wm8750.h"
 #include "pxa2xx-pcm.h"
 
+#define SPITZ_HP		0
+#define SPITZ_MIC		1
+#define SPITZ_LINE		2
+#define SPITZ_HEADSET	3
+#define SPITZ_SPK_AUTO	0
+#define SPITZ_SPK_ON	1
+#define SPITZ_SPK_OFF	2
+
 static struct workqueue_struct *spitz_hp_workq = NULL;
 static struct work_struct spitz_hp_event_work;
+static int spitz_jack_func = 0;
+static int spitz_spk_func = 0;
+static int spitz_hp_status = 0;
+static int ld2ro = 0; /* left DAC to R mixer status - for headset */
 
 static irqreturn_t spitz_hp_isr(int irq, void *dev_id, struct pt_regs *fp)
 {
@@ -52,132 +64,208 @@ static irqreturn_t spitz_hp_isr(int irq,
 
 #define READ_GPIO_BIT(x)    (GPLR(x) & GPIO_bit(x))
 
-static void spitz_hp_work(void *data)
+static inline void set_bias(int on)
 {
-	int hp_status = (READ_GPIO_BIT(SPITZ_GPIO_AK_INT) != 0);
-	struct snd_soc_codec *codec = (struct snd_soc_codec *)data;
+	if (machine_is_borzoi() || machine_is_spitz()) {	
+		if(on)
+			set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
+		else
+			reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
+	}
 	
-	printk("HP Status: %d\n", hp_status);
-	spitzkbd_report_hp(hp_status);
+	if(machine_is_akita()){
+		if(on)
+			akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_MIC_BIAS);
+		else
+			akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_MIC_BIAS);
+	}
+}
+
+static void spitz_ext_control(struct snd_soc_codec *codec)
+{
+	int new_ld2ro = codec->read(codec, WM8750_ROUTM1);
 	
 	/* change the dpm status depending on the insertion */
-	if (hp_status == 1) {
-		snd_soc_dpm_set_connection(codec, "LOUT1", 1);
-		snd_soc_dpm_set_connection(codec, "ROUT1", 1);
-		snd_soc_dpm_set_connection(codec, "RINPUT1", 1);
-		snd_soc_dpm_set_connection(codec, "LINPUT1", 1);
+	if (spitz_hp_status == 1) {
+		
+		/* do we need to mute spk */
+		if(spitz_spk_func != SPITZ_SPK_ON)
+			snd_soc_dpm_set_connection(codec, "Ext Spk", 0);
+		else
+			snd_soc_dpm_set_connection(codec, "Ext Spk", 1);
+			
+		/* set up jack connection */
+		switch(spitz_jack_func) {
+		case SPITZ_HP:
+			/* enable and unmute hp jack, disable mic bias */
+			codec->write(codec, WM8750_ROUTM1, ld2ro | new_ld2ro);
+			snd_soc_dpm_set_connection(codec, "Headset Headphone Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Mic Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Line Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Headphone Jack", 1);
+			set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+			set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+			set_bias(0);
+			break;
+		case SPITZ_MIC:
+			/* enable mic jack and bias, mute hp */
+			codec->write(codec, WM8750_ROUTM1, ld2ro | new_ld2ro);
+			snd_soc_dpm_set_connection(codec, "Headphone Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Headset Headphone Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Line Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Mic Jack", 1);
+			reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+			reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+			set_bias(1);
+			break;
+		case SPITZ_LINE:
+			/* enable line jack, disable mic bias and mute hp */
+			codec->write(codec, WM8750_ROUTM1, ld2ro | new_ld2ro);
+			snd_soc_dpm_set_connection(codec, "Headphone Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Headset Headphone Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Mic Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Line Jack", 1);
+			reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+			reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+			set_bias(0);
+			break;
+		case SPITZ_HEADSET:
+			
+			/* route LDAC audio into R mixer */
+			ld2ro = codec->read(codec, WM8750_ROUTM1);
+			codec->write(codec, WM8750_ROUTM1, ld2ro | 0x100);
+			ld2ro &= 0x100;
+			
+			/* enable and unmute headset jack enable mic bias, mute L hp */
+			snd_soc_dpm_set_connection(codec, "Headphone Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Mic Jack", 1);
+			snd_soc_dpm_set_connection(codec, "Line Jack", 0);
+			snd_soc_dpm_set_connection(codec, "Headset Headphone Jack", 1);
+			reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+			set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+			set_bias(1);
+			break;
+		}	
 	} else {
-		snd_soc_dpm_set_connection(codec, "LOUT1", 0);
-		snd_soc_dpm_set_connection(codec, "ROUT1", 0);
-		snd_soc_dpm_set_connection(codec, "RINPUT1", 0);
-		snd_soc_dpm_set_connection(codec, "LINPUT1", 0);
+		/* jack removed, so revert to spk if enabled */
+		codec->write(codec, WM8750_ROUTM1, ld2ro | new_ld2ro);
+		snd_soc_dpm_set_connection(codec, "Headphone Jack", 0);
+		snd_soc_dpm_set_connection(codec, "Headset Headphone Jack", 0);
+		snd_soc_dpm_set_connection(codec, "Mic Jack", 0);
+		snd_soc_dpm_set_connection(codec, "Line Jack", 0);
+		reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+		set_bias(0);
+		
+		if(spitz_spk_func != SPITZ_SPK_OFF)
+			snd_soc_dpm_set_connection(codec, "Ext Spk", 1);
+		else
+			snd_soc_dpm_set_connection(codec, "Ext Spk", 0);
 	}
 	snd_soc_dpm_sync(codec);
 }
 
-int spitz_get_snd_scoop(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int spitz_startup(snd_pcm_substream_t *substream)
 {
-	unsigned short reg = kcontrol->private_value;
-	
-	ucontrol->value.integer.value[0] = ((read_scoop_reg(&spitzscoop_device.dev, SCOOP_GPWR) & reg) == 0);
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	/* check the jack status at stream startup */	
+	spitz_hp_status = (READ_GPIO_BIT(SPITZ_GPIO_AK_INT) != 0);
+	ld2ro = codec->read(codec, WM8750_ROUTM1);
+	spitz_ext_control(codec);
 	return 0;
 }
 
-int spitz_put_snd_scoop(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static struct snd_soc_ops spitz_ops = {
+	.startup = spitz_startup,
+};
+
+static void spitz_hp_work(void *data)
 {
-	unsigned short reg = kcontrol->private_value & 0xffff;
+	struct snd_soc_codec *codec = (struct snd_soc_codec *)data;
 	
-	if (ucontrol->value.integer.value[0])
-		reset_scoop_gpio(&spitzscoop_device.dev, reg);
-	else
-		set_scoop_gpio(&spitzscoop_device.dev, reg);
-	return 0;
+	spitz_hp_status = (READ_GPIO_BIT(SPITZ_GPIO_AK_INT) != 0);
+	printk("HP Status: %d\n", spitz_hp_status);
+	spitzkbd_report_hp(spitz_hp_status);
+	spitz_ext_control(codec);
 }
 
-int spitz_get_snd_scoop2(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int spitz_get_jack(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
-	unsigned short reg = kcontrol->private_value;
-	
-	ucontrol->value.integer.value[0] = ((read_scoop_reg(&spitzscoop2_device.dev, SCOOP_GPWR) & reg) == 0);
+	ucontrol->value.integer.value[0] = spitz_jack_func;
 	return 0;
 }
 
-int spitz_put_snd_scoop2(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	unsigned short reg = kcontrol->private_value & 0xffff;
-	
-	if (ucontrol->value.integer.value[0])
-		reset_scoop_gpio(&spitzscoop2_device.dev, reg);
-	else
-		set_scoop_gpio(&spitzscoop2_device.dev, reg);
+static int spitz_set_jack(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{	
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	spitz_jack_func = ucontrol->value.integer.value[0];
+	spitz_ext_control(codec);
 	return 0;
 }
 
-#ifdef CONFIG_MACH_AKITA
-static int akita_ioexp_status;
-
-int akita_get_snd_ioexp(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int spitz_get_spk(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
-	unsigned short reg = kcontrol->private_value;
-	ucontrol->value.integer.value[0] = akita_ioexp_status;
+	ucontrol->value.integer.value[0] = spitz_spk_func;
 	return 0;
 }
 
-int akita_put_snd_ioexp(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int spitz_set_spk(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
-	unsigned short reg = kcontrol->private_value & 0xffff;
-	
-	if (ucontrol->value.integer.value[0]) {
-		akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_MIC_BIAS);
-		akita_ioexp_status = 0;
-        } else {
-		akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_MIC_BIAS);
-		akita_ioexp_status = 1;		
-	}
-
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+	spitz_spk_func = ucontrol->value.integer.value[0];
+	spitz_ext_control(codec);
 	return 0;
 }
-#endif
 
 /* spitz machine dpm widgets */
 static const struct snd_soc_dpm_widget wm8750_dpm_widgets[] = {
-SND_SOC_DPM_HP("Headphone Jack"),
-SND_SOC_DPM_MIC("Mic1 Jack"),
+	SND_SOC_DPM_HP("Headphone Jack"),
+	SND_SOC_DPM_MIC("Mic Jack"),
+	SND_SOC_DPM_SPK("Ext Spk"),
+	SND_SOC_DPM_LINE("Line Jack"),
+	
+	/* headset is a mic and mono headphone */
+	SND_SOC_DPM_HP("Headset Headphone Jack"),
 };
 
-/* example machine interconnections */
+/* Spitz machine audio interconnections */
 static const char* intercon[][3] = {
 	
 	/* headphone connected to LOUT1, ROUT1 */
 	{"Headphone Jack", NULL, "LOUT1"},
 	{"Headphone Jack", NULL, "ROUT1"},
 	
-	/* ext speaker connected to LOUT2, ROUT2 via amp */
-	{"Ext Amp", NULL , "ROUT2"},
-	{"Ext Amp", NULL , "LOUT2"},
-	
-	/* mic is connected to mic1 - with bias */
-	{"MICIN", NULL, "Mic Bias"},
-	{"LLINEIN", NULL, "Mic Bias"},
-	{"Mic Bias", NULL, "Mic1 Jack"},
+	/* headset connected to ROUT1 and LINPUT1 with bias (def below) */
+	{"Headset Headphone Jack", NULL, "ROUT1"},
+	
+	/* ext speaker connected to LOUT2, ROUT2  */
+	{"Ext Spk", NULL , "ROUT2"},
+	{"Ext Spk", NULL , "LOUT2"},
+	
+	/* mic is connected to input 1 - with bias */
+	{"LINPUT1", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic Jack"},
+	
+	/* line is connected to input 1 - no bias */
+	{"LINPUT1", NULL, "Line Jack"},
 
 	{NULL, NULL, NULL},
 };
 
-static const snd_kcontrol_new_t wm8750_spitz_controls[] = {
-	SOC_SINGLE_BOOL_EXT("Left Mute Switch", SPITZ_SCP_MUTE_L, spitz_get_snd_scoop, spitz_put_snd_scoop),
-	SOC_SINGLE_BOOL_EXT("Right Mute Switch", SPITZ_SCP_MUTE_R, spitz_get_snd_scoop, spitz_put_snd_scoop),
+static const char* jack_function[] = {"Headphone", "Mic", "Line", "Headset"};
+static const char* spk_function[] = {"Auto", "On", "Off"};
+static const struct soc_enum spitz_enum[] = {
+	SOC_ENUM_SINGLE_EXT(4, jack_function),
+	SOC_ENUM_SINGLE_EXT(3, spk_function),
 };
 
-static const snd_kcontrol_new_t wm8750_spitz_controls2[] = {
-	SOC_SINGLE_BOOL_EXT("Mic Bias Switch", SPITZ_SCP2_MIC_BIAS, spitz_get_snd_scoop2, spitz_put_snd_scoop2),
-};
-
-#ifdef CONFIG_MACH_AKITA
-static const snd_kcontrol_new_t wm8750_akita_controls[] = {
-	SOC_SINGLE_BOOL_EXT("Mic Bias Switch", AKITA_IOEXP_MIC_BIAS, akita_get_snd_ioexp, akita_put_snd_ioexp),
+static const snd_kcontrol_new_t wm8750_spitz_controls[] = {
+	SOC_ENUM_EXT("Jack Function", spitz_enum[0], spitz_get_jack, spitz_set_jack),
+	SOC_ENUM_EXT("Speaker Function", spitz_enum[1], spitz_get_spk, spitz_set_spk),
 };
-#endif
 
 /*
  * Logic for a wm8750 as connected on a Sharp SL-Cxx00 Device
@@ -186,9 +274,14 @@ static int spitz_wm8750_init(struct snd_
 {
 	int i, err;
 
-	codec->longname = "Corgi Audio Codec";
+	codec->longname = "Spitz Audio Codec";
+	snd_soc_dpm_set_connection(codec, "RINPUT1", 0);
 	snd_soc_dpm_set_connection(codec, "LINPUT2", 0);
 	snd_soc_dpm_set_connection(codec, "RINPUT2", 0);
+	snd_soc_dpm_set_connection(codec, "LINPUT3", 0);
+	snd_soc_dpm_set_connection(codec, "RINPUT3", 0);
+	snd_soc_dpm_set_connection(codec, "OUT3", 0);
+	snd_soc_dpm_set_connection(codec, "MONO", 0);
 
 	/* Add spitz specific controls */
 	for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) {
@@ -196,16 +289,6 @@ static int spitz_wm8750_init(struct snd_
 			return err;
 	}
 
-	if (machine_is_borzoi() || machine_is_spitz())
-		if ((err = snd_ctl_add(codec->card, snd_soc_cnew(&wm8750_spitz_controls2[0], codec, NULL))) < 0)
-			return err;
-
-#ifdef CONFIG_MACH_AKITA
-	if (machine_is_akita())
-		if ((err = snd_ctl_add(codec->card, snd_soc_cnew(&wm8750_akita_controls[0], codec, NULL))) < 0)
-			return err;
-#endif
-
 	/* Add spitz specific widgets */
 	for(i = 0; i < ARRAY_SIZE(wm8750_dpm_widgets); i++) {
 		snd_soc_dpm_new_control(codec, &wm8750_dpm_widgets[i]);
@@ -233,6 +316,7 @@ static struct snd_soc_machine snd_soc_ma
 	.name = "Spitz",
 	.config = &codecs,
 	.nconfigs = 1,
+	.ops = &spitz_ops,
 };
 
 static struct wm8750_setup_data spitz_wm8750_setup = {
@@ -271,7 +355,7 @@ static int __init spitz_init(void) 
 	platform_set_drvdata(spitz_snd_device, &spitz_snd_devdata);
 	spitz_snd_devdata.dev = &spitz_snd_device->dev;
 	ret = platform_device_add(spitz_snd_device);
-
+	
 	if (ret)
 		platform_device_put(spitz_snd_device);
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index ff36759..ce90ace 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -974,6 +974,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card)
 
 static int __devinit snd_soc_init(void)
 {
+	printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION);
 	return platform_driver_register(&soc_driver);
 }
 
diff --git a/sound/soc/soc-dpm.c b/sound/soc/soc-dpm.c
index eb665ac..ea27ab3 100644
--- a/sound/soc/soc-dpm.c
+++ b/sound/soc/soc-dpm.c
@@ -13,6 +13,7 @@
  *  Revision history
  *    12th Aug 2005   Initial version.
  *    25th Oct 2005   Implemented path power domain.
+ *    18th Dec 2005   Implemented machine and stream level power domain.
  *
  *  Features:
  *    o Changes power status of internal codec blocks depending on the 
@@ -20,6 +21,9 @@
  *      DAC's/ADC's.
  *    o Platform power domain - can support external components i.e. amps and
  *      mic/meadphone insertion events.
+ *    o Automatic Mic Bias support
+ *    o Jack insertion power event initiation - e.g. hp insertion will enable
+ *      outputs, dacs, etc
  * 
  *  Todo:
  *    o DPM power change sequencing - allow for configurable sequences
@@ -44,6 +48,15 @@
 #include <sound/soc-dpm.h>
 #include <sound/initval.h>
 
+static int dpm_up_seq[] = {
+	snd_soc_dpm_micbias, snd_soc_dpm_adc, snd_soc_dpm_mux,
+	snd_soc_dpm_dac, snd_soc_dpm_mixer, snd_soc_dpm_volume, snd_soc_dpm_mute
+};
+static int dpm_down_seq[] = {
+	snd_soc_dpm_volume, snd_soc_dpm_mixer, snd_soc_dpm_dac, snd_soc_dpm_mute,
+	snd_soc_dpm_adc, snd_soc_dpm_micbias, snd_soc_dpm_mux
+};
+
 
 static int dpm_status = 1;
 module_param(dpm_status, int, 0);
@@ -105,13 +118,14 @@ static void dpm_set_path_status(struct s
 	case snd_soc_dpm_dac:
 	case snd_soc_dpm_clock:
 	case snd_soc_dpm_vref:	
-	case snd_soc_dpm_amp:
 	case snd_soc_dpm_micbias:
 		p->connect = 1;
 	case snd_soc_dpm_mute:
 	/* does effect routing - dynamically connected */
 	case snd_soc_dpm_hp:
-	case snd_soc_dpm_mic:			
+	case snd_soc_dpm_mic:
+	case snd_soc_dpm_spk:
+	case snd_soc_dpm_line:
 		p->connect = 0;
 	break;
 	}
@@ -194,11 +208,13 @@ int snd_soc_dpm_connect_input(struct snd
 
 	/* check for external widgets */
 	if(dest->id == snd_soc_dpm_input) {	
-		if (src->id == snd_soc_dpm_micbias || src->id == snd_soc_dpm_mic)
+		if (src->id == snd_soc_dpm_micbias || src->id == snd_soc_dpm_mic ||
+			dest->id == snd_soc_dpm_line)
 			dest->ext = 1;
 	}
 	if(src->id == snd_soc_dpm_output) {	
-		if (dest->id == snd_soc_dpm_amp || dest->id == snd_soc_dpm_hp)
+		if (dest->id == snd_soc_dpm_spk || dest->id == snd_soc_dpm_hp ||
+			dest->id == snd_soc_dpm_line)
 			src->ext = 1;
 	}
 	
@@ -220,7 +236,6 @@ int snd_soc_dpm_connect_input(struct snd
 	case snd_soc_dpm_vref:
 	case snd_soc_dpm_micbias:
 	case snd_soc_dpm_mute:
-	case snd_soc_dpm_amp:
 		list_add(&path->list, &codec->dpm_paths);
 		list_add(&path->list_out, &dest->inputs);
 		list_add(&path->list_in, &src->outputs);
@@ -236,6 +251,8 @@ int snd_soc_dpm_connect_input(struct snd
 		break;
 	case snd_soc_dpm_hp:
 	case snd_soc_dpm_mic:
+	case snd_soc_dpm_line:
+	case snd_soc_dpm_spk:
 		list_add(&path->list, &codec->dpm_paths);
 		list_add(&path->list_out, &dest->inputs);
 		list_add(&path->list_in, &src->outputs);
@@ -430,12 +447,18 @@ static int is_connected_output_ep(struct
 
 	if(widget->id == snd_soc_dpm_adc && widget->active)
 		return 1;
-	if(widget->id == snd_soc_dpm_output && widget->connected && !widget->ext)
-		return 1;
-	if(widget->id == snd_soc_dpm_hp && widget->connected)
-		return 1;
-	if(widget->id == snd_soc_dpm_amp && widget->connected)
-		return 1;
+	
+	if(widget->connected) {
+		
+		/* connected pin ? */
+		if(widget->id == snd_soc_dpm_output && !widget->ext)
+			return 1;
+		
+		/* connected jack or spk ? */	
+		if(widget->id == snd_soc_dpm_hp || widget->id == snd_soc_dpm_spk ||
+			widget->id == snd_soc_dpm_line)
+			return 1;
+	}
 	
 	list_for_each(lp, &widget->outputs)
 	{
@@ -463,10 +486,17 @@ static int is_connected_input_ep(struct 
 	
 	if(widget->id == snd_soc_dpm_dac && widget->active)
 		return 1;
-	if(widget->id == snd_soc_dpm_input && widget->connected && !widget->ext)
-		return 1;
-	if(widget->id == snd_soc_dpm_mic && widget->connected)
-		return 1;
+		
+	if(widget->connected) {
+	
+		/* connected pin ? */
+		if(widget->id == snd_soc_dpm_input && !widget->ext)
+			return 1;
+	
+		/* connected jack ? */		
+		if(widget->id == snd_soc_dpm_mic || widget->id == snd_soc_dpm_line)
+			return 1;
+	}
 	
 	list_for_each(lp, &widget->inputs)
 	{
@@ -488,15 +518,13 @@ static int dpm_power_widgets(struct snd_
 	struct snd_soc_dpm_widget *w;
 	struct list_head *l;
 	int in, out, pm = 0, i, c = 1, *seq = NULL;
-	int up_seq[] = {snd_soc_dpm_dac, snd_soc_dpm_mixer, snd_soc_dpm_volume, snd_soc_dpm_mute};
-	int down_seq[] = {snd_soc_dpm_volume, snd_soc_dpm_mixer, snd_soc_dpm_dac, snd_soc_dpm_mute};
 
 	if(event == SND_SOC_DPM_STREAM_START) {
-		c = ARRAY_SIZE(up_seq);
-		seq = up_seq;
+		c = ARRAY_SIZE(dpm_up_seq);
+		seq = dpm_up_seq;
 	} else if (event == SND_SOC_DPM_STREAM_STOP) {
-		c = ARRAY_SIZE(down_seq);
-		seq = down_seq;
+		c = ARRAY_SIZE(dpm_down_seq);
+		seq = dpm_down_seq;
 	}
 	
 	for(i = 0; i < c; i++){
@@ -561,8 +589,8 @@ static int dpm_power_widgets(struct snd_
 			dpm_update_bits(w, pm);
 			if(w->ext_event)
 				w->ext_event(w->codec, pm);
-			/*printk("widget %s\n in %d out %d pm %s ext %d con %d\n", 
-				w->name, in, out, pm ? "On":"Off", w->ext, w->connected);*/	
+			/*printk("widget %s\n in %d out %d pm %s ext %d con %d act %d\n", 
+				w->name, in, out, pm ? "On":"Off", w->ext, w->connected, w->active);*/	
 		}
 	}
 	
@@ -598,7 +626,7 @@ static int dpm_mux_update_power(struct s
 			path->connect = 0; /* old connection must be powered down */	
 	}
 	
-	dpm_power_widgets(widget->codec, 0);			
+	dpm_power_widgets(widget->codec, SND_SOC_DPM_STREAM_NOP);			
 	return 0;
 }
 
@@ -629,7 +657,7 @@ static int dpm_mixer_update_power(struct
 		break;
 	}
 	
-	dpm_power_widgets(widget->codec, 0);
+	dpm_power_widgets(widget->codec, SND_SOC_DPM_STREAM_NOP);
 	return 0;
 }
 
@@ -718,15 +746,16 @@ int snd_soc_dpm_sync(struct snd_soc_code
 		case snd_soc_dpm_vref:
 		case snd_soc_dpm_micbias:
 		case snd_soc_dpm_mute:
-		case snd_soc_dpm_amp:
+		case snd_soc_dpm_spk:
 		case snd_soc_dpm_hp:
-		case snd_soc_dpm_mic:  				
+		case snd_soc_dpm_mic:
+		case snd_soc_dpm_line:
 			break;
 		}
 		w->sync = 1;
 	}
 	
-	dpm_power_widgets(codec, 0);
+	dpm_power_widgets(codec, SND_SOC_DPM_STREAM_NOP);
 	return 0;
 }
 
diff --git a/include/sound/soc-dpm.h b/include/sound/soc-dpm.h
index 6b2bbcc..4993bc5 100644
--- a/include/sound/soc-dpm.h
+++ b/include/sound/soc-dpm.h
@@ -57,9 +57,12 @@
 #define SND_SOC_DPM_HP(wname) \
 {.id = snd_soc_dpm_hp, .name = wname, .kcontrols = NULL, \
  .num_kcontrols = 0}
-#define SND_SOC_DPM_AMP(wname, wext_event) \
-{.id = snd_soc_dpm_amp, .name = wname, .kcontrols = NULL, \
- .num_kcontrols = 0, .ext_event = wext_event}
+#define SND_SOC_DPM_SPK(wname) \
+{.id = snd_soc_dpm_spk, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0}
+#define SND_SOC_DPM_LINE(wname) \
+{.id = snd_soc_dpm_line, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0}
  
 /* path domain */
 #define SND_SOC_DPM_VOLUME(wname, preg, pshift, pinvert, wcontrols, wncontrols) \
@@ -96,6 +99,7 @@
   .get = snd_soc_dpm_get_enum_double, .put = snd_soc_dpm_put_enum_double, \
   .private_value = (unsigned long)&xenum }
 
+#define SND_SOC_DPM_STREAM_NOP			0x0
 #define SND_SOC_DPM_STREAM_START		0x1
 #define SND_SOC_DPM_STREAM_STOP			0x2
 #define SND_SOC_DPM_STREAM_SUSPEND		0x4
@@ -138,7 +142,8 @@ enum snd_soc_dpm_type {
 	snd_soc_dpm_mute,
 	snd_soc_dpm_mic,
 	snd_soc_dpm_hp,
-	snd_soc_dpm_amp,
+	snd_soc_dpm_spk,
+	snd_soc_dpm_line,
 };
 
 struct snd_soc_dpm_path {
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 0c101aa..f864459 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -21,7 +21,7 @@
 #include <sound/control.h>
 #include <sound/ac97_codec.h>
 
-#define SND_SOC_VERSION "0.9"
+#define SND_SOC_VERSION "0.10pre1"
 
 /*
  * Convenience kcontrol builders

