diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index d79aead..b1db115 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -266,3 +266,6 @@ IOMAP
   pcim_iounmap()
   pcim_iomap_table()	: array of mapped addresses indexed by BAR
   pcim_iomap_regions()	: do request_region() and iomap() on multiple BARs
+
+REGULATOR
+  devm_regulator_get()
diff --git a/Makefile b/Makefile
index ea51081..adddd11 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 2
 SUBLEVEL = 0
-EXTRAVERSION = -rc7
+EXTRAVERSION =
 NAME = Saber-toothed Squirrel
 
 # *DOCUMENTATION*
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 0573c8a..1ed9342 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_REGMAP) += regmap.o regcache.o regcache-indexed.o regcache-rbtree.o regcache-lzo.o
+obj-$(CONFIG_REGMAP) += regmap.o regcache.o regcache-rbtree.o regcache-lzo.o
 obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
 obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
 obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 348ff02..d141b80 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -74,6 +74,10 @@ struct regmap {
 	struct reg_default *reg_defaults;
 	const void *reg_defaults_raw;
 	void *cache;
+	bool cache_dirty;
+
+	struct reg_default *patch;
+	int patch_regs;
 };
 
 struct regcache_ops {
@@ -105,7 +109,7 @@ static inline void regmap_debugfs_exit(struct regmap *map) { }
 #endif
 
 /* regcache core declarations */
-int regcache_init(struct regmap *map);
+int regcache_init(struct regmap *map, const struct regmap_config *config);
 void regcache_exit(struct regmap *map);
 int regcache_read(struct regmap *map,
 		       unsigned int reg, unsigned int *value);
@@ -118,10 +122,7 @@ unsigned int regcache_get_val(const void *base, unsigned int idx,
 bool regcache_set_val(void *base, unsigned int idx,
 		      unsigned int val, unsigned int word_size);
 int regcache_lookup_reg(struct regmap *map, unsigned int reg);
-int regcache_insert_reg(struct regmap *map, unsigned int reg,
-			unsigned int val);
 
-extern struct regcache_ops regcache_indexed_ops;
 extern struct regcache_ops regcache_rbtree_ops;
 extern struct regcache_ops regcache_lzo_ops;
 
diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c
index 066aeec..b7d1614 100644
--- a/drivers/base/regmap/regcache-lzo.c
+++ b/drivers/base/regmap/regcache-lzo.c
@@ -15,6 +15,8 @@
 
 #include "internal.h"
 
+static int regcache_lzo_exit(struct regmap *map);
+
 struct regcache_lzo_ctx {
 	void *wmem;
 	void *dst;
@@ -27,7 +29,7 @@ struct regcache_lzo_ctx {
 };
 
 #define LZO_BLOCK_NUM 8
-static int regcache_lzo_block_count(void)
+static int regcache_lzo_block_count(struct regmap *map)
 {
 	return LZO_BLOCK_NUM;
 }
@@ -106,19 +108,22 @@ static inline int regcache_lzo_get_blkindex(struct regmap *map,
 					    unsigned int reg)
 {
 	return (reg * map->cache_word_size) /
-		DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count());
+		DIV_ROUND_UP(map->cache_size_raw,
+			     regcache_lzo_block_count(map));
 }
 
 static inline int regcache_lzo_get_blkpos(struct regmap *map,
 					  unsigned int reg)
 {
-	return reg % (DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count()) /
+	return reg % (DIV_ROUND_UP(map->cache_size_raw,
+				   regcache_lzo_block_count(map)) /
 		      map->cache_word_size);
 }
 
 static inline int regcache_lzo_get_blksize(struct regmap *map)
 {
-	return DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count());
+	return DIV_ROUND_UP(map->cache_size_raw,
+			    regcache_lzo_block_count(map));
 }
 
 static int regcache_lzo_init(struct regmap *map)
@@ -131,7 +136,7 @@ static int regcache_lzo_init(struct regmap *map)
 
 	ret = 0;
 
-	blkcount = regcache_lzo_block_count();
+	blkcount = regcache_lzo_block_count(map);
 	map->cache = kzalloc(blkcount * sizeof *lzo_blocks,
 			     GFP_KERNEL);
 	if (!map->cache)
@@ -190,7 +195,7 @@ static int regcache_lzo_init(struct regmap *map)
 
 	return 0;
 err:
-	regcache_exit(map);
+	regcache_lzo_exit(map);
 	return ret;
 }
 
@@ -203,7 +208,7 @@ static int regcache_lzo_exit(struct regmap *map)
 	if (!lzo_blocks)
 		return 0;
 
-	blkcount = regcache_lzo_block_count();
+	blkcount = regcache_lzo_block_count(map);
 	/*
 	 * the pointer to the bitmap used for syncing the cache
 	 * is shared amongst all lzo_blocks.  Ensure it is freed
@@ -351,7 +356,7 @@ static int regcache_lzo_sync(struct regmap *map)
 }
 
 struct regcache_ops regcache_lzo_ops = {
-	.type = REGCACHE_LZO,
+	.type = REGCACHE_COMPRESSED,
 	.name = "lzo",
 	.init = regcache_lzo_init,
 	.exit = regcache_lzo_exit,
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index e314984..32620c4 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -11,12 +11,15 @@
  */
 
 #include <linux/slab.h>
+#include <linux/debugfs.h>
 #include <linux/rbtree.h>
+#include <linux/seq_file.h>
 
 #include "internal.h"
 
 static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
 				 unsigned int value);
+static int regcache_rbtree_exit(struct regmap *map);
 
 struct regcache_rbtree_node {
 	/* the actual rbtree node holding this block */
@@ -124,6 +127,60 @@ static int regcache_rbtree_insert(struct rb_root *root,
 	return 1;
 }
 
+#ifdef CONFIG_DEBUG_FS
+static int rbtree_show(struct seq_file *s, void *ignored)
+{
+	struct regmap *map = s->private;
+	struct regcache_rbtree_ctx *rbtree_ctx = map->cache;
+	struct regcache_rbtree_node *n;
+	struct rb_node *node;
+	unsigned int base, top;
+	int nodes = 0;
+	int registers = 0;
+
+	mutex_lock(&map->lock);
+
+	for (node = rb_first(&rbtree_ctx->root); node != NULL;
+	     node = rb_next(node)) {
+		n = container_of(node, struct regcache_rbtree_node, node);
+
+		regcache_rbtree_get_base_top_reg(n, &base, &top);
+		seq_printf(s, "%x-%x (%d)\n", base, top, top - base + 1);
+
+		nodes++;
+		registers += top - base + 1;
+	}
+
+	seq_printf(s, "%d nodes, %d registers, average %d registers\n",
+		   nodes, registers, registers / nodes);
+
+	mutex_unlock(&map->lock);
+
+	return 0;
+}
+
+static int rbtree_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, rbtree_show, inode->i_private);
+}
+
+static const struct file_operations rbtree_fops = {
+	.open		= rbtree_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void rbtree_debugfs_init(struct regmap *map)
+{
+	debugfs_create_file("rbtree", 0400, map->debugfs, map, &rbtree_fops);
+}
+#else
+static void rbtree_debugfs_init(struct regmap *map)
+{
+}
+#endif
+
 static int regcache_rbtree_init(struct regmap *map)
 {
 	struct regcache_rbtree_ctx *rbtree_ctx;
@@ -146,10 +203,12 @@ static int regcache_rbtree_init(struct regmap *map)
 			goto err;
 	}
 
+	rbtree_debugfs_init(map);
+
 	return 0;
 
 err:
-	regcache_exit(map);
+	regcache_rbtree_exit(map);
 	return ret;
 }
 
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 666f6f5..ee36bed 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -19,7 +19,6 @@
 #include "internal.h"
 
 static const struct regcache_ops *cache_types[] = {
-	&regcache_indexed_ops,
 	&regcache_rbtree_ops,
 	&regcache_lzo_ops,
 };
@@ -61,8 +60,10 @@ static int regcache_hw_init(struct regmap *map)
 
 	map->reg_defaults = kmalloc(count * sizeof(struct reg_default),
 				      GFP_KERNEL);
-	if (!map->reg_defaults)
-		return -ENOMEM;
+	if (!map->reg_defaults) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
 
 	/* fill the reg_defaults */
 	map->num_reg_defaults = count;
@@ -77,9 +78,15 @@ static int regcache_hw_init(struct regmap *map)
 	}
 
 	return 0;
+
+err_free:
+	if (map->cache_free)
+		kfree(map->reg_defaults_raw);
+
+	return ret;
 }
 
-int regcache_init(struct regmap *map)
+int regcache_init(struct regmap *map, const struct regmap_config *config)
 {
 	int ret;
 	int i;
@@ -100,6 +107,12 @@ int regcache_init(struct regmap *map)
 		return -EINVAL;
 	}
 
+	map->num_reg_defaults = config->num_reg_defaults;
+	map->num_reg_defaults_raw = config->num_reg_defaults_raw;
+	map->reg_defaults_raw = config->reg_defaults_raw;
+	map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8);
+	map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw;
+
 	map->cache = NULL;
 	map->cache_ops = cache_types[i];
 
@@ -112,10 +125,10 @@ int regcache_init(struct regmap *map)
 	 * won't vanish from under us.  We'll need to make
 	 * a copy of it.
 	 */
-	if (map->reg_defaults) {
+	if (config->reg_defaults) {
 		if (!map->num_reg_defaults)
 			return -EINVAL;
-		tmp_buf = kmemdup(map->reg_defaults, map->num_reg_defaults *
+		tmp_buf = kmemdup(config->reg_defaults, map->num_reg_defaults *
 				  sizeof(struct reg_default), GFP_KERNEL);
 		if (!tmp_buf)
 			return -ENOMEM;
@@ -136,9 +149,18 @@ int regcache_init(struct regmap *map)
 	if (map->cache_ops->init) {
 		dev_dbg(map->dev, "Initializing %s cache\n",
 			map->cache_ops->name);
-		return map->cache_ops->init(map);
+		ret = map->cache_ops->init(map);
+		if (ret)
+			goto err_free;
 	}
 	return 0;
+
+err_free:
+	kfree(map->reg_defaults);
+	if (map->cache_free)
+		kfree(map->reg_defaults_raw);
+
+	return ret;
 }
 
 void regcache_exit(struct regmap *map)
@@ -171,16 +193,21 @@ void regcache_exit(struct regmap *map)
 int regcache_read(struct regmap *map,
 		  unsigned int reg, unsigned int *value)
 {
+	int ret;
+
 	if (map->cache_type == REGCACHE_NONE)
 		return -ENOSYS;
 
 	BUG_ON(!map->cache_ops);
 
-	if (!regmap_readable(map, reg))
-		return -EIO;
+	if (!regmap_volatile(map, reg)) {
+		ret = map->cache_ops->read(map, reg, value);
 
-	if (!regmap_volatile(map, reg))
-		return map->cache_ops->read(map, reg, value);
+		if (ret == 0)
+			trace_regmap_reg_read_cache(map->dev, reg, *value);
+
+		return ret;
+	}
 
 	return -EINVAL;
 }
@@ -241,6 +268,22 @@ int regcache_sync(struct regmap *map)
 		map->cache_ops->name);
 	name = map->cache_ops->name;
 	trace_regcache_sync(map->dev, name, "start");
+
+	if (!map->cache_dirty)
+		goto out;
+
+	/* Apply any patch first */
+	map->cache_bypass = 1;
+	for (i = 0; i < map->patch_regs; i++) {
+		ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
+		if (ret != 0) {
+			dev_err(map->dev, "Failed to write %x = %x: %d\n",
+				map->patch[i].reg, map->patch[i].def, ret);
+			goto out;
+		}
+	}
+	map->cache_bypass = 0;
+
 	if (map->cache_ops->sync) {
 		ret = map->cache_ops->sync(map);
 	} else {
@@ -291,6 +334,23 @@ void regcache_cache_only(struct regmap *map, bool enable)
 EXPORT_SYMBOL_GPL(regcache_cache_only);
 
 /**
+ * regcache_mark_dirty: Mark the register cache as dirty
+ *
+ * @map: map to mark
+ *
+ * Mark the register cache as dirty, for example due to the device
+ * having been powered down for suspend.  If the cache is not marked
+ * as dirty then the cache sync will be suppressed.
+ */
+void regcache_mark_dirty(struct regmap *map)
+{
+	mutex_lock(&map->lock);
+	map->cache_dirty = true;
+	mutex_unlock(&map->lock);
+}
+EXPORT_SYMBOL_GPL(regcache_mark_dirty);
+
+/**
  * regcache_cache_bypass: Put a register map into cache bypass mode
  *
  * @map: map to configure
@@ -381,22 +441,3 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg)
 	else
 		return -ENOENT;
 }
-
-int regcache_insert_reg(struct regmap *map, unsigned int reg,
-			unsigned int val)
-{
-	void *tmp;
-
-	tmp = krealloc(map->reg_defaults,
-		       (map->num_reg_defaults + 1) * sizeof(struct reg_default),
-		       GFP_KERNEL);
-	if (!tmp)
-		return -ENOMEM;
-	map->reg_defaults = tmp;
-	map->num_reg_defaults++;
-	map->reg_defaults[map->num_reg_defaults - 1].reg = reg;
-	map->reg_defaults[map->num_reg_defaults - 1].def = val;
-	sort(map->reg_defaults, map->num_reg_defaults,
-	     sizeof(struct reg_default), regcache_default_cmp, NULL);
-	return 0;
-}
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index bf441db..28e89fd 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -64,6 +64,18 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
 	return false;
 }
 
+static bool regmap_volatile_range(struct regmap *map, unsigned int reg,
+	unsigned int num)
+{
+	unsigned int i;
+
+	for (i = 0; i < num; i++)
+		if (!regmap_volatile(map, reg + i))
+			return false;
+
+	return true;
+}
+
 static void regmap_format_4_12_write(struct regmap *map,
 				     unsigned int reg, unsigned int val)
 {
@@ -78,6 +90,16 @@ static void regmap_format_7_9_write(struct regmap *map,
 	*out = cpu_to_be16((reg << 9) | val);
 }
 
+static void regmap_format_10_14_write(struct regmap *map,
+				    unsigned int reg, unsigned int val)
+{
+	u8 *out = map->work_buf;
+
+	out[2] = val;
+	out[1] = (val >> 8) | (reg << 6);
+	out[0] = reg >> 2;
+}
+
 static void regmap_format_8(void *buf, unsigned int val)
 {
 	u8 *b = buf;
@@ -127,7 +149,7 @@ struct regmap *regmap_init(struct device *dev,
 	int ret = -EINVAL;
 
 	if (!bus || !config)
-		return NULL;
+		goto err;
 
 	map = kzalloc(sizeof(*map), GFP_KERNEL);
 	if (map == NULL) {
@@ -147,12 +169,6 @@ struct regmap *regmap_init(struct device *dev,
 	map->volatile_reg = config->volatile_reg;
 	map->precious_reg = config->precious_reg;
 	map->cache_type = config->cache_type;
-	map->reg_defaults = config->reg_defaults;
-	map->num_reg_defaults = config->num_reg_defaults;
-	map->num_reg_defaults_raw = config->num_reg_defaults_raw;
-	map->reg_defaults_raw = config->reg_defaults_raw;
-	map->cache_size_raw = (config->val_bits / 8) * config->num_reg_defaults_raw;
-	map->cache_word_size = config->val_bits / 8;
 
 	if (config->read_flag_mask || config->write_flag_mask) {
 		map->read_flag_mask = config->read_flag_mask;
@@ -182,6 +198,16 @@ struct regmap *regmap_init(struct device *dev,
 		}
 		break;
 
+	case 10:
+		switch (config->val_bits) {
+		case 14:
+			map->format.format_write = regmap_format_10_14_write;
+			break;
+		default:
+			goto err_map;
+		}
+		break;
+
 	case 8:
 		map->format.format_reg = regmap_format_8;
 		break;
@@ -215,14 +241,16 @@ struct regmap *regmap_init(struct device *dev,
 		goto err_map;
 	}
 
-	ret = regcache_init(map);
-	if (ret < 0)
-		goto err_map;
-
 	regmap_debugfs_init(map);
 
+	ret = regcache_init(map, config);
+	if (ret < 0)
+		goto err_free_workbuf;
+
 	return map;
 
+err_free_workbuf:
+	kfree(map->work_buf);
 err_map:
 	kfree(map);
 err:
@@ -231,6 +259,39 @@ err:
 EXPORT_SYMBOL_GPL(regmap_init);
 
 /**
+ * regmap_reinit_cache(): Reinitialise the current register cache
+ *
+ * @map: Register map to operate on.
+ * @config: New configuration.  Only the cache data will be used.
+ *
+ * Discard any existing register cache for the map and initialize a
+ * new cache.  This can be used to restore the cache to defaults or to
+ * update the cache configuration to reflect runtime discovery of the
+ * hardware.
+ */
+int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
+{
+	int ret;
+
+	mutex_lock(&map->lock);
+
+	regcache_exit(map);
+
+	map->max_register = config->max_register;
+	map->writeable_reg = config->writeable_reg;
+	map->readable_reg = config->readable_reg;
+	map->volatile_reg = config->volatile_reg;
+	map->precious_reg = config->precious_reg;
+	map->cache_type = config->cache_type;
+
+	ret = regcache_init(map, config);
+
+	mutex_unlock(&map->lock);
+
+	return ret;
+}
+
+/**
  * regmap_exit(): Free a previously allocated register map
  */
 void regmap_exit(struct regmap *map)
@@ -306,8 +367,10 @@ int _regmap_write(struct regmap *map, unsigned int reg,
 		ret = regcache_write(map, reg, val);
 		if (ret != 0)
 			return ret;
-		if (map->cache_only)
+		if (map->cache_only) {
+			map->cache_dirty = true;
 			return 0;
+		}
 	}
 
 	trace_regmap_reg_write(map->dev, reg, val);
@@ -375,9 +438,11 @@ EXPORT_SYMBOL_GPL(regmap_write);
 int regmap_raw_write(struct regmap *map, unsigned int reg,
 		     const void *val, size_t val_len)
 {
+	size_t val_count = val_len / map->format.val_bytes;
 	int ret;
 
-	WARN_ON(map->cache_type != REGCACHE_NONE);
+	WARN_ON(!regmap_volatile_range(map, reg, val_count) &&
+		map->cache_type != REGCACHE_NONE);
 
 	mutex_lock(&map->lock);
 
@@ -422,15 +487,15 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
 {
 	int ret;
 
-	if (!map->format.parse_val)
-		return -EINVAL;
-
 	if (!map->cache_bypass) {
 		ret = regcache_read(map, reg, val);
 		if (ret == 0)
 			return 0;
 	}
 
+	if (!map->format.parse_val)
+		return -EINVAL;
+
 	if (map->cache_only)
 		return -EBUSY;
 
@@ -481,15 +546,11 @@ EXPORT_SYMBOL_GPL(regmap_read);
 int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 		    size_t val_len)
 {
+	size_t val_count = val_len / map->format.val_bytes;
 	int ret;
-	int i;
-	bool vol = true;
 
-	for (i = 0; i < val_len / map->format.val_bytes; i++)
-		if (!regmap_volatile(map, reg + i))
-			vol = false;
-
-	WARN_ON(!vol && map->cache_type != REGCACHE_NONE);
+	WARN_ON(!regmap_volatile_range(map, reg, val_count) &&
+		map->cache_type != REGCACHE_NONE);
 
 	mutex_lock(&map->lock);
 
@@ -517,16 +578,11 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
 {
 	int ret, i;
 	size_t val_bytes = map->format.val_bytes;
-	bool vol = true;
+	bool vol = regmap_volatile_range(map, reg, val_count);
 
 	if (!map->format.parse_val)
 		return -EINVAL;
 
-	/* Is this a block of volatile registers? */
-	for (i = 0; i < val_count; i++)
-		if (!regmap_volatile(map, reg + i))
-			vol = false;
-
 	if (vol || map->cache_type == REGCACHE_NONE) {
 		ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
 		if (ret != 0)
@@ -546,8 +602,37 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
 }
 EXPORT_SYMBOL_GPL(regmap_bulk_read);
 
+static int _regmap_update_bits(struct regmap *map, unsigned int reg,
+			       unsigned int mask, unsigned int val,
+			       bool *change)
+{
+	int ret;
+	unsigned int tmp, orig;
+
+	mutex_lock(&map->lock);
+
+	ret = _regmap_read(map, reg, &orig);
+	if (ret != 0)
+		goto out;
+
+	tmp = orig & ~mask;
+	tmp |= val & mask;
+
+	if (tmp != orig) {
+		ret = _regmap_write(map, reg, tmp);
+		*change = true;
+	} else {
+		*change = false;
+	}
+
+out:
+	mutex_unlock(&map->lock);
+
+	return ret;
+}
+
 /**
- * remap_update_bits: Perform a read/modify/write cycle on the register map
+ * regmap_update_bits: Perform a read/modify/write cycle on the register map
  *
  * @map: Register map to update
  * @reg: Register to update
@@ -559,26 +644,88 @@ EXPORT_SYMBOL_GPL(regmap_bulk_read);
 int regmap_update_bits(struct regmap *map, unsigned int reg,
 		       unsigned int mask, unsigned int val)
 {
-	int ret;
-	unsigned int tmp;
+	bool change;
+	return _regmap_update_bits(map, reg, mask, val, &change);
+}
+EXPORT_SYMBOL_GPL(regmap_update_bits);
+
+/**
+ * regmap_update_bits_check: Perform a read/modify/write cycle on the
+ *                           register map and report if updated
+ *
+ * @map: Register map to update
+ * @reg: Register to update
+ * @mask: Bitmask to change
+ * @val: New value for bitmask
+ * @change: Boolean indicating if a write was done
+ *
+ * Returns zero for success, a negative number on error.
+ */
+int regmap_update_bits_check(struct regmap *map, unsigned int reg,
+			     unsigned int mask, unsigned int val,
+			     bool *change)
+{
+	return _regmap_update_bits(map, reg, mask, val, change);
+}
+EXPORT_SYMBOL_GPL(regmap_update_bits_check);
+
+/**
+ * regmap_register_patch: Register and apply register updates to be applied
+ *                        on device initialistion
+ *
+ * @map: Register map to apply updates to.
+ * @regs: Values to update.
+ * @num_regs: Number of entries in regs.
+ *
+ * Register a set of register updates to be applied to the device
+ * whenever the device registers are synchronised with the cache and
+ * apply them immediately.  Typically this is used to apply
+ * corrections to be applied to the device defaults on startup, such
+ * as the updates some vendors provide to undocumented registers.
+ */
+int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
+			  int num_regs)
+{
+	int i, ret;
+	bool bypass;
+
+	/* If needed the implementation can be extended to support this */
+	if (map->patch)
+		return -EBUSY;
 
 	mutex_lock(&map->lock);
 
-	ret = _regmap_read(map, reg, &tmp);
-	if (ret != 0)
-		goto out;
+	bypass = map->cache_bypass;
 
-	tmp &= ~mask;
-	tmp |= val & mask;
+	map->cache_bypass = true;
+
+	/* Write out first; it's useful to apply even if we fail later. */
+	for (i = 0; i < num_regs; i++) {
+		ret = _regmap_write(map, regs[i].reg, regs[i].def);
+		if (ret != 0) {
+			dev_err(map->dev, "Failed to write %x = %x: %d\n",
+				regs[i].reg, regs[i].def, ret);
+			goto out;
+		}
+	}
 
-	ret = _regmap_write(map, reg, tmp);
+	map->patch = kcalloc(sizeof(struct reg_default), num_regs, GFP_KERNEL);
+	if (map->patch != NULL) {
+		memcpy(map->patch, regs,
+		       num_regs * sizeof(struct reg_default));
+		map->patch_regs = num_regs;
+	} else {
+		ret = -ENOMEM;
+	}
 
 out:
+	map->cache_bypass = bypass;
+
 	mutex_unlock(&map->lock);
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(regmap_update_bits);
+EXPORT_SYMBOL_GPL(regmap_register_patch);
 
 static int __init regmap_initcall(void)
 {
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 61894fc..4103957 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -252,6 +252,20 @@ static int wm8994_suspend(struct device *dev)
 		break;
 	}
 
+	switch (wm8994->type) {
+	case WM1811:
+		ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2);
+		if (ret < 0) {
+			dev_err(dev, "Failed to read jackdet: %d\n", ret);
+		} else if (ret & WM1811_JACKDET_MODE_MASK) {
+			dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+			return 0;
+		}
+		break;
+	default:
+		break;
+	}
+
 	/* Disable LDO pulldowns while the device is suspended if we
 	 * don't know that something will be driving them. */
 	if (!wm8994->ldo_ena_always_driven)
@@ -374,6 +388,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
 	struct wm8994_pdata *pdata = wm8994->dev->platform_data;
 	const char *devname;
 	int ret, i;
+	int pulls = 0;
 
 	dev_set_drvdata(wm8994->dev, wm8994);
 
@@ -516,12 +531,16 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
 		}
 
 		wm8994->ldo_ena_always_driven = pdata->ldo_ena_always_driven;
+
+		if (pdata->spkmode_pu)
+			pulls |= WM8994_SPKMODE_PU;
 	}
 
-	/* Disable LDO pulldowns while the device is active */
+	/* Disable unneeded pulls */
 	wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
-			WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
-			0);
+			WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD |
+			WM8994_SPKMODE_PU | WM8994_CSNADDR_PD,
+			pulls);
 
 	/* In some system designs where the regulators are not in use,
 	 * we can achieve a small reduction in leakage currents by
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 938398f..4d684dc 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1259,6 +1259,40 @@ struct regulator *regulator_get(struct device *dev, const char *id)
 }
 EXPORT_SYMBOL_GPL(regulator_get);
 
+static void devm_regulator_release(struct device *dev, void *res)
+{
+	regulator_put(*(struct regulator **)res);
+}
+
+/**
+ * devm_regulator_get - Resource managed regulator_get()
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Managed regulator_get(). Regulators returned from this function are
+ * automatically regulator_put() on driver detach. See regulator_get() for more
+ * information.
+ */
+struct regulator *devm_regulator_get(struct device *dev, const char *id)
+{
+	struct regulator **ptr, *regulator;
+
+	ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	regulator = regulator_get(dev, id);
+	if (!IS_ERR(regulator)) {
+		*ptr = regulator;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return regulator;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_get);
+
 /**
  * regulator_get_exclusive - obtain exclusive access to a regulator.
  * @dev: device for regulator "consumer"
diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h
index ea32f30..36d0d50 100644
--- a/include/linux/mfd/wm8994/pdata.h
+++ b/include/linux/mfd/wm8994/pdata.h
@@ -113,6 +113,23 @@ struct wm8958_enh_eq_cfg {
 	u16 regs[WM8958_ENH_EQ_REGS];
 };
 
+/**
+ * Microphone detection rates, used to tune response rates and power
+ * consumption for WM8958/WM1811 microphone detection.
+ *
+ * @sysclk: System clock rate to use this configuration for.
+ * @idle: True if this configuration should use when no accessory is detected,
+ *        false otherwise.
+ * @start: Value for MICD_BIAS_START_TIME register field (not shifted).
+ * @rate: Value for MICD_RATE register field (not shifted).
+ */
+struct wm8958_micd_rate {
+	int sysclk;
+	bool idle;
+	int start;
+	int rate;
+};
+
 struct wm8994_pdata {
 	int gpio_base;
 
@@ -144,6 +161,9 @@ struct wm8994_pdata {
 	int num_enh_eq_cfgs;
 	struct wm8958_enh_eq_cfg *enh_eq_cfgs;
 
+	int num_micd_rates;
+	struct wm8958_micd_rate *micd_rates;
+
         /* LINEOUT can be differential or single ended */
         unsigned int lineout1_diff:1;
         unsigned int lineout2_diff:1;
@@ -168,12 +188,21 @@ struct wm8994_pdata {
 	/* WM8958 microphone bias configuration */
 	int micbias[2];
 
+	/* WM8958 microphone detection ranges */
+	u16 micd_lvl_sel;
+
 	/* Disable the internal pull downs on the LDOs if they are
 	 * always driven (eg, connected to an always on supply or
 	 * GPIO that always drives an output.  If they float power
 	 * consumption will rise.
 	 */
 	bool ldo_ena_always_driven;
+
+	/*
+	 * SPKMODE must be pulled internally by the device on this
+	 * system.
+	 */
+	bool spkmode_pu;
 };
 
 #endif
diff --git a/include/linux/mfd/wm8994/registers.h b/include/linux/mfd/wm8994/registers.h
index 83a9cae..ebfc92f 100644
--- a/include/linux/mfd/wm8994/registers.h
+++ b/include/linux/mfd/wm8994/registers.h
@@ -242,6 +242,7 @@
 #define WM8994_GPIO_4                           0x703
 #define WM8994_GPIO_5                           0x704
 #define WM8994_GPIO_6                           0x705
+#define WM1811_JACKDET_CTRL			0x705
 #define WM8994_GPIO_7                           0x706
 #define WM8994_GPIO_8                           0x707
 #define WM8994_GPIO_9                           0x708
@@ -1852,6 +1853,9 @@
 /*
  * R57 (0x39) - AntiPOP (2)
  */
+#define WM1811_JACKDET_MODE_MASK                0x0180  /* JACKDET_MODE - [8:7] */
+#define WM1811_JACKDET_MODE_SHIFT                    7  /* JACKDET_MODE - [8:7] */
+#define WM1811_JACKDET_MODE_WIDTH                    2  /* JACKDET_MODE - [8:7] */
 #define WM8994_MICB2_DISCH                      0x0100  /* MICB2_DISCH */
 #define WM8994_MICB2_DISCH_MASK                 0x0100  /* MICB2_DISCH */
 #define WM8994_MICB2_DISCH_SHIFT                     8  /* MICB2_DISCH */
@@ -4187,6 +4191,18 @@
 #define WM8994_STL_SEL_WIDTH                         1  /* STL_SEL */
 
 /*
+ * R1797 (0x705) - JACKDET Ctrl
+ */
+#define WM1811_JACKDET_DB                       0x0100  /* JACKDET_DB */
+#define WM1811_JACKDET_DB_MASK                  0x0100  /* JACKDET_DB */
+#define WM1811_JACKDET_DB_SHIFT                      8  /* JACKDET_DB */
+#define WM1811_JACKDET_DB_WIDTH                      1  /* JACKDET_DB */
+#define WM1811_JACKDET_LVL                      0x0040  /* JACKDET_LVL */
+#define WM1811_JACKDET_LVL_MASK                 0x0040  /* JACKDET_LVL */
+#define WM1811_JACKDET_LVL_SHIFT                     6  /* JACKDET_LVL */
+#define WM1811_JACKDET_LVL_WIDTH                     1  /* JACKDET_LVL */
+
+/*
  * R1824 (0x720) - Pull Control (1)
  */
 #define WM8994_DMICDAT2_PU                      0x0800  /* DMICDAT2_PU */
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 690276a..860739a 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -23,9 +23,8 @@ struct spi_device;
 /* An enum of all the supported cache types */
 enum regcache_type {
 	REGCACHE_NONE,
-	REGCACHE_INDEXED,
 	REGCACHE_RBTREE,
-	REGCACHE_LZO
+	REGCACHE_COMPRESSED
 };
 
 /**
@@ -83,7 +82,7 @@ struct regmap_config {
 	bool (*precious_reg)(struct device *dev, unsigned int reg);
 
 	unsigned int max_register;
-	struct reg_default *reg_defaults;
+	const struct reg_default *reg_defaults;
 	unsigned int num_reg_defaults;
 	enum regcache_type cache_type;
 	const void *reg_defaults_raw;
@@ -129,6 +128,8 @@ struct regmap *regmap_init_spi(struct spi_device *dev,
 			       const struct regmap_config *config);
 
 void regmap_exit(struct regmap *map);
+int regmap_reinit_cache(struct regmap *map,
+			const struct regmap_config *config);
 int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);
 int regmap_raw_write(struct regmap *map, unsigned int reg,
 		     const void *val, size_t val_len);
@@ -139,9 +140,64 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
 		     size_t val_count);
 int regmap_update_bits(struct regmap *map, unsigned int reg,
 		       unsigned int mask, unsigned int val);
+int regmap_update_bits_check(struct regmap *map, unsigned int reg,
+			     unsigned int mask, unsigned int val,
+			     bool *change);
 
 int regcache_sync(struct regmap *map);
 void regcache_cache_only(struct regmap *map, bool enable);
 void regcache_cache_bypass(struct regmap *map, bool enable);
+void regcache_mark_dirty(struct regmap *map);
+
+int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
+			  int num_regs);
+
+/**
+ * Description of an IRQ for the generic regmap irq_chip.
+ *
+ * @reg_offset: Offset of the status/mask register within the bank
+ * @mask:       Mask used to flag/control the register.
+ */
+struct regmap_irq {
+	unsigned int reg_offset;
+	unsigned int mask;
+};
+
+/**
+ * Description of a generic regmap irq_chip.  This is not intended to
+ * handle every possible interrupt controller, but it should handle a
+ * substantial proportion of those that are found in the wild.
+ *
+ * @name:        Descriptive name for IRQ controller.
+ *
+ * @status_base: Base status register address.
+ * @mask_base:   Base mask register address.
+ * @ack_base:    Base ack address.  If zero then the chip is clear on read.
+ *
+ * @num_regs:    Number of registers in each control bank.
+ * @irqs:        Descriptors for individual IRQs.  Interrupt numbers are
+ *               assigned based on the index in the array of the interrupt.
+ * @num_irqs:    Number of descriptors.
+ */
+struct regmap_irq_chip {
+	const char *name;
+
+	unsigned int status_base;
+	unsigned int mask_base;
+	unsigned int ack_base;
+
+	int num_regs;
+
+	const struct regmap_irq *irqs;
+	int num_irqs;
+};
+
+struct regmap_irq_chip_data;
+
+int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
+			int irq_base, struct regmap_irq_chip *chip,
+			struct regmap_irq_chip_data **data);
+void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
+int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
 
 #endif
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index f7756d1..253d165 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -132,6 +132,8 @@ struct regulator_bulk_data {
 /* regulator get and put */
 struct regulator *__must_check regulator_get(struct device *dev,
 					     const char *id);
+struct regulator *__must_check devm_regulator_get(struct device *dev,
+					     const char *id);
 struct regulator *__must_check regulator_get_exclusive(struct device *dev,
 						       const char *id);
 void regulator_put(struct regulator *regulator);
@@ -198,6 +200,13 @@ static inline struct regulator *__must_check regulator_get(struct device *dev,
 	 */
 	return NULL;
 }
+
+static inline struct regulator *__must_check
+devm_regulator_get(struct device *dev, const char *id)
+{
+	return NULL;
+}
+
 static inline void regulator_put(struct regulator *regulator)
 {
 }
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 17a4c17..3d4c036 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -43,6 +43,9 @@
 	.num_kcontrols = 0}
 
 /* platform domain */
+#define SND_SOC_DAPM_SIGGEN(wname) \
+{	.id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \
+	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_INPUT(wname) \
 {	.id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
@@ -240,6 +243,10 @@
 {	.id = snd_soc_dapm_supply, .name = wname, .reg = wreg,	\
 	.shift = wshift, .invert = winvert, .event = wevent, \
 	.event_flags = wflags}
+#define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay) \
+{	.id = snd_soc_dapm_regulator_supply, .name = wname, \
+	.reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
+	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
 
 /* dapm kcontrol types */
 #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
@@ -319,6 +326,8 @@ struct snd_soc_dapm_context;
 
 int dapm_reg_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event);
+int dapm_regulator_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event);
 
 /* dapm controls */
 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
@@ -407,8 +416,10 @@ enum snd_soc_dapm_type {
 	snd_soc_dapm_pre,			/* machine specific pre widget - exec first */
 	snd_soc_dapm_post,			/* machine specific post widget - exec last */
 	snd_soc_dapm_supply,		/* power/clock supply */
+	snd_soc_dapm_regulator_supply,	/* external regulator */
 	snd_soc_dapm_aif_in,		/* audio interface input */
 	snd_soc_dapm_aif_out,		/* audio interface output */
+	snd_soc_dapm_siggen,		/* signal generator */
 };
 
 /*
@@ -460,6 +471,8 @@ struct snd_soc_dapm_widget {
 	struct list_head list;
 	struct snd_soc_dapm_context *dapm;
 
+	void *priv;				/* widget specific data */
+
 	/* dapm control */
 	short reg;						/* negative reg = no direct dapm */
 	unsigned char shift;			/* bits to shift */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 11cfb59..c252635 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -325,6 +325,12 @@ int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
 int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots);
 int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms);
 
+/* Utility functions to get clock rates from various things */
+int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
+int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
+int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots);
+int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms);
+
 /* set runtime hw params */
 int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
 	const struct snd_pcm_hardware *hw);
diff --git a/include/sound/wm2200.h b/include/sound/wm2200.h
new file mode 100644
index 0000000..79bf55b
--- /dev/null
+++ b/include/sound/wm2200.h
@@ -0,0 +1,41 @@
+/*
+ * linux/sound/wm2200.h -- Platform data for WM2200
+ *
+ * Copyright 2012 Wolfson Microelectronics. PLC.
+ *
+ * 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 __LINUX_SND_WM2200_H
+#define __LINUX_SND_WM2200_H
+
+#define WM2200_GPIO_SET 0x10000
+
+enum wm2200_in_mode {
+	WM2200_IN_SE = 0,
+	WM2200_IN_DIFF = 1,
+	WM2200_IN_DMIC = 2,
+};
+
+enum wm2200_dmic_sup {
+	WM2200_DMIC_SUP_MICVDD = 0,
+	WM2200_DMIC_SUP_MICBIAS1 = 1,
+	WM2200_DMIC_SUP_MICBIAS2 = 2,
+};
+
+struct wm2200_pdata {
+	int reset;      /** GPIO controlling /RESET, if any */
+	int ldo_ena;    /** GPIO controlling LODENA, if any */
+	int irq_flags;
+
+	int gpio_defaults[4];
+
+	enum wm2200_in_mode in_mode[3];
+	enum wm2200_dmic_sup dmic_sup[3];
+
+	int micbias_cfg[2];  /** Register value to configure MICBIAS */
+};
+
+#endif
diff --git a/include/trace/events/regmap.h b/include/trace/events/regmap.h
index 1e3193b..12fbf43 100644
--- a/include/trace/events/regmap.h
+++ b/include/trace/events/regmap.h
@@ -55,6 +55,15 @@ DEFINE_EVENT(regmap_reg, regmap_reg_read,
 
 );
 
+DEFINE_EVENT(regmap_reg, regmap_reg_read_cache,
+
+	TP_PROTO(struct device *dev, unsigned int reg,
+		 unsigned int val),
+
+	TP_ARGS(dev, reg, val)
+
+);
+
 DECLARE_EVENT_CLASS(regmap_block,
 
 	TP_PROTO(struct device *dev, unsigned int reg, int count),
diff --git a/sound/soc/au1x/dbdma.c b/sound/soc/au1x/dbdma.c
new file mode 100644
index 0000000..88fb475
--- /dev/null
+++ b/sound/soc/au1x/dbdma.c
@@ -0,0 +1,417 @@
+/* 
+ * dbdma - DBDMA for Au1200/Au1550 PSC Audio interfaces (AC97/I2S)
+ *
+ * Copyright (c) 2007 MSC Vertriebsges.m.b.H, <mlau@msc-ge.com>
+ *
+ * licensed under the GPLv2.
+ *
+ */
+
+/*
+ * TODO: the au1200/au1550 DBDMA API needs an overhaul or least a few
+ *	 extensions:
+ *	  - change STS/DTS (access size) for a descriptor ring on the fly:
+ *		au1xxx_dbdma_adjust_size(chanid, int sts, int dts);
+ *	  - maybe even a way to add/remove descriptor from the ring, to support
+ *	    varying number of periods.
+ *	  - destroy/free a ring (certainly required for the above)
+ *	  - probably more I haven't thought about yet
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+
+#include "psc.h"
+
+/*#define PCM_DEBUG*/
+
+#ifdef PCM_DEBUG
+#define MSG(x...)	printk(KERN_INFO "au1x-pcm: " x)
+#else
+#define MSG(x...)	do {} while (0)
+#endif
+
+struct au1xpsc_pcm_dmadata {
+	struct snd_pcm_substream *substream;
+	unsigned long pos;		/* current byte position being played */
+	unsigned long periods;		/* number of SG segments in total */
+	unsigned long curr_period;	/* current segment DDMA is working on */
+	unsigned long period_bytes;	/* size in bytes of one SG segment */
+};
+
+static struct au1xpsc_pcm {
+	unsigned long pscbase;
+	unsigned int	dmatx;
+	unsigned int	dmarx;
+
+	u32		tx_chan;
+	u32		rx_chan;
+	struct au1xpsc_pcm_dmadata dma_play;
+	struct au1xpsc_pcm_dmadata dma_rec;
+} au1xpsc_pcm_data[PSC_COUNT] = {
+	{
+		.pscbase	= PSC0_BASE,
+		.dmatx		= DSCR_CMD0_PSC0_TX,
+		.dmarx		= DSCR_CMD0_PSC0_RX,
+	},
+	{
+		.pscbase	= PSC1_BASE,
+		.dmatx		= DSCR_CMD0_PSC1_TX,
+		.dmarx		= DSCR_CMD0_PSC1_RX,
+	},
+#ifdef CONFIG_SOC_AU1550
+	{
+		.pscbase	= PSC2_BASE,
+		.dmatx		= DSCR_CMD0_PSC2_TX,
+		.dmarx		= DSCR_CMD0_PSC2_RX,
+	},
+	{
+		.pscbase	= PSC3_BASE,
+		.dmatx		= DSCR_CMD0_PSC3_TX,
+		.dmarx		= DSCR_CMD0_PSC3_RX,
+	},
+#endif
+};
+
+
+/*
+ * These settings are somewhat okay, at least on my machine audio plays almost
+ * skip-free. Especially the 64kB buffer seems to help a LOT.
+ */
+#define AU1XPSC_PERIOD_MIN_BYTES	1024
+#define AU1XPSC_BUFFER_MIN_BYTES	65536
+#define AU1XPSC_PERIODS_MIN		4
+
+/* PCM hardware DMA capabilities - platform specific */
+static const struct snd_pcm_hardware au1xpsc_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+				/* later also S24 would be possible
+				  SNDRV_PCM_FMTBIT_S24_LE, */
+	.period_bytes_min	= AU1XPSC_PERIOD_MIN_BYTES,
+	.period_bytes_max	= 4096 * 1024 - 1,
+	.periods_min		= AU1XPSC_PERIODS_MIN,
+	.periods_max		= AU1XPSC_PERIODS_MIN,
+	.buffer_bytes_max	= 4096 * 1024 - 1,
+	.fifo_size		= 16,	/* fifo entries of AC97/I2S PSC */
+};
+
+/* one descriptor completed, update dma data */
+static inline void dma_update(struct au1xpsc_pcm_dmadata *dd)
+{
+	dd->curr_period++;
+	if (dd->curr_period >= dd->periods) {
+		/* if the NOCV flag is set, DBDMA should start with the
+		  first descriptor again. Wrap around here too */
+		dd->pos = 0;
+		dd->curr_period = 0;
+	} else
+		dd->pos += dd->period_bytes;
+}
+
+static void au1x_dbdma_tx_callback(int irq, void *dev_id)
+{
+	struct au1xpsc_pcm *psc = dev_id;
+	dma_update(&psc->dma_play);
+	snd_pcm_period_elapsed(psc->dma_play.substream);
+}
+
+static void au1x_dbdma_rx_callback(int irq, void *dev_id)
+{
+	struct au1xpsc_pcm *psc = dev_id;
+	dma_update(&psc->dma_rec);
+	snd_pcm_period_elapsed(psc->dma_rec.substream);
+}
+
+/*
+ * Called by ALSA when the hardware params are set by application. This
+ * function can also be called multiple times and can allocate buffers
+ * (using snd_pcm_lib_* ). It's non-atomic.
+ */
+static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct au1xpsc_pcm *psc = &au1xpsc_pcm_data[rtd->dai->cpu_dai->id];
+	struct au1xpsc_pcm_dmadata *dd;
+	int dir, len, segs, i, ret;
+
+	MSG("pcm_hw_params() enter\n");
+
+	ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+	if (ret < 0)
+		goto out;
+
+	dir  = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+	segs = params_periods(params);
+	len = params_period_bytes(params);
+
+	dd = (dir) ? &psc->dma_rec : &psc->dma_play;
+
+	/* invalidate whole DBDMA ring */
+	au1xxx_dbdma_stop(dir ? psc->rx_chan : psc->tx_chan);
+	au1xxx_dbdma_reset(dir ? psc->rx_chan : psc->tx_chan);
+
+	MSG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d\n",
+		(unsigned long)runtime->dma_area,
+		(unsigned long)runtime->dma_addr, runtime->dma_bytes);
+
+	for (i = 0; i < segs; i++) {
+		if (dir == 0) {
+			ret = au1xxx_dbdma_put_source_flags(psc->tx_chan,
+				(void *)(unsigned long)runtime->dma_addr + (i * len),
+				len,
+				DDMA_FLAGS_IE | DDMA_FLAGS_NOCV);
+		} else {
+			ret = au1xxx_dbdma_put_dest_flags(psc->rx_chan,
+				(void *)(unsigned long)runtime->dma_addr + (i * len),
+				len,
+				DDMA_FLAGS_IE | DDMA_FLAGS_NOCV);
+		}
+		if (!ret) {
+			printk(KERN_INFO "au1x-pcm: error adding DMA data\n");
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+#ifdef PCM_DEBUG
+	au1xxx_dbdma_dump(dir ? psc->rx_chan : psc->tx_chan);
+#endif
+	dd->pos = 0;
+	dd->substream = substream;
+	dd->period_bytes = len;
+	dd->periods = segs;
+	ret = 0;
+out:
+	MSG("pcm_hw_params() leave %d\n", ret);
+	return ret;
+}
+
+/*
+ * Free's resources allocated by hw_params, can be called multiple times
+ */
+static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct au1xpsc_pcm *psc = &au1xpsc_pcm_data[rtd->dai->cpu_dai->id];
+	struct au1xpsc_pcm_dmadata *dd;
+
+	MSG("pcm_hw_free() enter\n");
+
+	dd = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? &psc->dma_play
+							      : &psc->dma_rec;
+
+	dd->substream = NULL;
+	dd->pos = 0;
+	dd->periods = 0;
+	dd->period_bytes = 0;
+
+	snd_pcm_lib_free_pages(substream);
+
+	MSG("pcm_hw_free() leave\n");
+	return 0;
+}
+
+/*
+ * Called by ALSA when the PCM substream is prepared, can set format, sample
+ * rate, etc.  This function is non atomic and can be called multiple times,
+ * it can refer to the runtime info.
+ */
+static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	MSG("prepare() enter\n");
+	MSG("prepare() leave\n");
+	return 0;
+}
+
+/*
+ * Starts (Triggers) audio playback or capture.
+ * Usually only needed for DMA
+ */
+static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct au1xpsc_pcm *psc = &au1xpsc_pcm_data[rtd->dai->cpu_dai->id];
+	u32 dmachan;
+
+	dmachan = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			? psc->tx_chan : psc->rx_chan;
+	
+	switch (cmd)
+	{
+	case SNDRV_PCM_TRIGGER_START:
+		au1xxx_dbdma_start(dmachan);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		au1xxx_dbdma_stop(dmachan);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * Returns the DMA audio frame position
+ */
+static snd_pcm_uframes_t
+au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct au1xpsc_pcm *psc = &au1xpsc_pcm_data[rtd->dai->cpu_dai->id];
+	int dir;
+	snd_pcm_uframes_t ret;
+	unsigned long off;
+
+	dir  = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+	if (dir != 0) {
+		off = psc->dma_rec.pos;
+	} else {
+		off = psc->dma_play.pos;
+	}
+	ret = bytes_to_frames(runtime, off);
+
+	return ret;
+}
+
+ /*
+ * Called by ALSA when a PCM substream is opened, private data can be allocated.
+ */
+static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
+{
+	MSG("pcm_open() enter\n");
+	
+	snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware);
+
+	MSG("pcm_open() leave\n");
+	return 0;
+}
+
+/*
+ * Called by ALSA when a PCM substream is closed. Private data can be
+ * freed here.
+ */
+static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
+{
+	MSG("pcm_close() enter\n");
+	
+	MSG("pcm_close() leave\n");
+	return 0;
+}
+
+/* ALSA PCM operations */
+struct snd_pcm_ops au1xpsc_pcm_ops = {
+	.open		= au1xpsc_pcm_open,
+	.close		= au1xpsc_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= au1xpsc_pcm_hw_params,
+	.hw_free	= au1xpsc_pcm_hw_free,
+	.prepare	= au1xpsc_pcm_prepare,
+	.trigger	= au1xpsc_pcm_trigger,
+	.pointer	= au1xpsc_pcm_pointer,
+};
+
+/*
+ * Called by ASoC core to free platform DMA.
+ */
+static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	MSG("pcm_free_dma() enter\n");	
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+	MSG("pcm_free_dma() leave\n");
+}
+
+static dbdev_tab_t au1xpsc_mem_dbdev =
+{
+	DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 16, 0x00000000, 0, 0
+};
+
+/*
+ * Called by the ASoC core to create and initialise the platform DMA.
+ */
+static int au1xpsc_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
+	struct snd_pcm *pcm)
+{
+	int memid;
+	struct au1xpsc_pcm *psc = &au1xpsc_pcm_data[1];	/* HACK!!!! */
+
+	/*
+	struct platform_device *pdev = to_platform_device(card->dev);
+	struct au1xpsc_pcm *psc = platform_get_drvdata(pdev);
+	*/
+	MSG("pcm_new() enter\n");
+	MSG("psc_base 0x%08lx\n", psc->pscbase);
+
+/* FIXME: THIS STUFF SHOULD BE MOVED TO pcm_open(), and the whole DMA
+	 descriptor ring torn down again in pcm_close(). This is necessary to
+	 support different amounts of periods and/or sampledepths!!
+*/
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, NULL,
+		AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1);
+
+	/* allocate DBDMA channels */
+	memid = au1xxx_ddma_add_device(&au1xpsc_mem_dbdev);
+
+	psc->tx_chan = au1xxx_dbdma_chan_alloc(memid, psc->dmatx,
+					 au1x_dbdma_tx_callback, (void *)psc);
+
+	psc->rx_chan = au1xxx_dbdma_chan_alloc(psc->dmarx, memid,
+					 au1x_dbdma_rx_callback, (void *)psc);
+
+	/* this needs to be adjusted for the requested bitdepth! */
+	au1xxx_dbdma_set_devwidth(psc->tx_chan, 16);
+	au1xxx_dbdma_set_devwidth(psc->rx_chan, 16);
+
+	au1xxx_dbdma_ring_alloc(psc->tx_chan, AU1XPSC_PERIODS_MIN);
+	au1xxx_dbdma_ring_alloc(psc->rx_chan, AU1XPSC_PERIODS_MIN);
+
+	MSG("pcm_new() leave\n");
+	return 0;
+}
+
+static int au1xpsc_pcm_probe(struct platform_device *pdev)
+{
+	MSG("probe() enter\n");
+	MSG("probe() leave\n");
+	return 0;
+}
+
+static int au1xpsc_pcm_remove(struct platform_device *pdev)
+{
+	MSG("remove() enter\n");	
+	MSG("remove() leave\n");
+	return 0;
+}
+
+/* au1xpsc audio platform */
+struct snd_soc_platform au1xpsc_soc_platform = {
+	.name		= "au1xpsc-pcm-dbdma",
+	.probe		= au1xpsc_pcm_probe,
+	.remove		= au1xpsc_pcm_remove,
+	.pcm_ops 	= &au1xpsc_pcm_ops,
+	.pcm_new	= au1xpsc_pcm_new,
+	.pcm_free	= au1xpsc_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Au1200/Au1550 Audio DMA driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/au1x/exmmb-ac97.c b/sound/soc/au1x/exmmb-ac97.c
new file mode 100644
index 0000000..629e3d2
--- /dev/null
+++ b/sound/soc/au1x/exmmb-ac97.c
@@ -0,0 +1,200 @@
+/*
+ * EXM32 Motherboard AC97 sound support; for Au1200 based systems.
+ *
+ * Copyright (c) 2007 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
+ * http://www.exm32.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-exm1200/exm1200.h>
+
+#include <linux/exm32.h>
+
+#include "../codecs/ac97.h"
+#include "psc.h"
+
+/* #define MACH_DEBUG */
+
+#ifdef MACH_DEBUG
+#define MSG(x...)	printk(KERN_INFO "exmmb-ac97: " x)
+#else
+#define MSG(x...)	do {} while (0)
+#endif
+
+/*
+ * Alsa operations
+ * Only implement the required operations for your platform.
+ * These operations are specific to the machine only.
+ */
+
+/*
+ * Initialise the machine audio subsystem.
+ */
+static int exm1200_mobo_ac97_machine_init(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_sync(codec);
+	return 0;
+}
+
+/* template digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link exm1200_mobo_ac97_dai = {
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &au1xpsc_ac97_dai[1],	/* we use PSC1 for I2S */
+	.codec_dai = &ac97_dai,
+	.init = exm1200_mobo_ac97_machine_init,
+	.ops = NULL,
+};
+
+/* template audio machine driver */
+static struct snd_soc_machine snd_soc_machine_exm97 = {
+	.name = "EXM32 Motherboard AC97",
+	.dai_link = &exm1200_mobo_ac97_dai,
+	.num_links = 1,
+};
+
+/* template audio subsystem */
+static struct snd_soc_device exm1200_mobo_ac97_snd_devdata = {
+	.machine = &snd_soc_machine_exm97,
+	.platform = &au1xpsc_soc_platform,
+	.codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct resource au1x_psc_res[] = {
+	[0] = {
+		.start	= PSC1_BASE,
+		.end	= PSC1_BASE + 0xffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 11,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= 16,
+		.flags	= IORESOURCE_DMA,
+	},
+	[3] = {
+		.start	= 17,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+
+static struct platform_device *exm1200_mobo_ac97_snd_device;
+
+static int psc_to_ac97(void)
+{
+	unsigned long io;
+	unsigned int i;
+
+	/* modify sys_pinfunc for AC97 on PSC1 */
+	io = au_readl(0xb190002c);
+	io |= (1<<14);
+	io &= ~((3<<21)|(1<<20));
+	au_writel(io, 0xb190002c);
+	au_sync();
+
+	/* AC97 mode */
+	io = 0xb1b00000;
+	(void)au_readl(io + PSC_CTL);
+	au_writel(0, io + PSC_CTL);
+	au_writel(0, io + PSC_SEL);
+	au_sync();
+	au_writel(4 | (1<<5), io + PSC_SEL);
+
+	/* cold reset */
+	au_writel(2, io + PSC_AC97RST);
+	au_sync();
+	msleep(1200);
+	au_writel(0, io + PSC_AC97RST);
+	au_sync();
+
+	/* enable PSC */
+	au_writel(3, io + PSC_CTL);
+	au_sync();
+
+	i = 1000;
+	while (((au_readl(io + PSC_AC97STAT) & 1) == 0) && (--i))
+		au_sync();
+
+	if (i == 0)
+		printk(KERN_INFO "PSC down!\n");
+
+	/* en ac97 core */
+	au_writel(0x04000000, io + PSC_AC97CFG);
+	au_sync();
+
+	i = 1000;
+	while (((au_readl(io + PSC_AC97STAT) & 2) == 0) && (--i))
+		au_sync();
+
+	if (i == 0)
+		printk(KERN_INFO "PSC-AC97 not ready\n");
+	return (i == 0);
+}
+
+static int exm1200_mobo_ac97_init(void)
+{
+	int ret = -ENOMEM;
+	unsigned short brdctl;
+
+	MSG("module_init() enter\n");
+
+	/* switch FPGA to AC97 mode */
+	brdctl = au_readw(EXM1200_FPGA_BRDCTRL);
+	brdctl &= ~(1 << 13);
+	au_writew(brdctl, EXM1200_FPGA_BRDCTRL);
+	au_sync();
+
+	if (psc_to_ac97()) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	exm1200_mobo_ac97_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!exm1200_mobo_ac97_snd_device)
+		goto out;
+
+	exm1200_mobo_ac97_snd_device->resource = au1x_psc_res;
+	exm1200_mobo_ac97_snd_device->num_resources = ARRAY_SIZE(au1x_psc_res);
+	exm1200_mobo_ac97_snd_device->id = 1;
+
+	platform_set_drvdata(exm1200_mobo_ac97_snd_device, &exm1200_mobo_ac97_snd_devdata);
+	exm1200_mobo_ac97_snd_devdata.dev = &exm1200_mobo_ac97_snd_device->dev;
+	ret = platform_device_add(exm1200_mobo_ac97_snd_device);
+
+	if (ret)
+		platform_device_put(exm1200_mobo_ac97_snd_device);
+
+out:
+	MSG("module_init() exit (ret %d)\n", ret);
+	return ret;
+}
+
+static void exm1200_mobo_ac97_exit(void)
+{
+	platform_device_del(exm1200_mobo_ac97_snd_device);
+}
+
+module_init(exm1200_mobo_ac97_init);
+module_exit(exm1200_mobo_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MSC EXM32 Development Motherboard AC97 Audio support");
+MODULE_AUTHOR("Manuel Lauss <mlau@msc-ge.com>");
diff --git a/sound/soc/au1x/exmmb-i2s.c b/sound/soc/au1x/exmmb-i2s.c
new file mode 100644
index 0000000..2e0108d
--- /dev/null
+++ b/sound/soc/au1x/exmmb-i2s.c
@@ -0,0 +1,214 @@
+/*
+ * EXM32 mobo I2S, for the Crystal CS42518 codec and Au1200 based CPU Modules.
+ *
+ * Copyright (c) 2007 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
+ * see http://www.exm32.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-exm1200/exm1200.h>
+
+#include <linux/exm32.h>
+
+#include "../codecs/cs4251x.h"
+#include "psc.h"
+
+/* #define MACH_DEBUG */
+
+#ifdef MACH_DEBUG
+#define MSG(x...)	printk(KERN_INFO "exmmb-i2s: " x)
+#else
+#define MSG(x...)	do {} while (0)
+#endif
+
+static int exm1200_mobo_i2s_machine_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret;
+
+	MSG("machine_hw_params() enter\n");
+
+	/* set codec and i2s interfaces to slave mode */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0) {
+		MSG("codec dai setfmt() failed!\n");
+		goto out;
+	}
+
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, 24576000, 0);
+	if (ret < 0) {
+		MSG("codec does not want sysclk\n");
+		goto out;
+	}
+
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_LEFT_J |
+			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0) {
+		MSG("cpu-i2s dai setfmt() failed!\n");
+		goto out;
+	}
+
+	ret = 0;
+out:
+	MSG("machine_hw_params() leave\n");
+	return ret;
+}
+
+/* machine Alsa PCM operations */
+static struct snd_soc_ops exm1200_mobo_i2s_ops = {
+	.hw_params = exm1200_mobo_i2s_machine_hw_params,
+};
+
+/*
+ * Initialise the machine audio subsystem.
+ */
+static int exm1200_mobo_i2s_machine_init(struct snd_soc_codec *codec)
+{
+	/* EXM32 Motherboard uses the codec in MASTER mode (DSP possible)
+	 *  with ADC (recording) data output at the SAI_SDOUT/SAI_SPCLK pins,
+	 *  the chip clocked at 24.576 MHz from an external clocksource.
+	 * RXP5/6 determine DAC input source:
+	 *	RXP5 ----\
+	 *	RXP6 ---\|
+	 *		||
+	 *		00 I2S data from CPU
+	 *		01 DSP
+	 *		10 I2S audio from GSM phone on navi module
+	 *		11 SPDIF input from motherboard/IEEE1394 controller, ...
+	 */
+	cs4251x_write(codec, CS4251X_CLKCTL, CS4251X_CLKSRC_AUTO_PLL_OMCK | CS4251X_CLKSRC_OMCK_245760MHZ);
+	cs4251x_write(codec, CS4251X_FUNCMODE, CS4251X_ADCDAI_SAISDOUT_SAISP_CLK);
+	cs4251x_write(codec, CS4251X_MUTEC, 0x1f);
+	cs4251x_write(codec, CS4251X_RCVMODECTL, 0x80);
+	cs4251x_write(codec, CS4251X_RCVMODECTL2, 0x02);
+	/* set DAC input to I2S from CPU */
+	cs4251x_gpio_mode(codec, CS4251X_RXP_5, CS4251X_GPIO_MODE_GPOLOW, 0, 0);
+	cs4251x_gpio_mode(codec, CS4251X_RXP_6, CS4251X_GPIO_MODE_GPOLOW, 0, 0);
+
+	/* mark unused codec pins as NC */
+
+	/* Add template specific controls */
+
+	/* Add template specific widgets */
+
+	/* Set up template specific audio path audio_map */
+
+	/* synchronise subsystem */
+	snd_soc_dapm_sync(codec);
+
+	return 0;
+}
+
+static struct snd_soc_dai_link exm1200_mobo_i2s_dai = {
+	.name = "CS4251X",
+	.stream_name = "CS4251X",
+	.cpu_dai = &au1xpsc_i2s_dai[1],	/* we use PSC1 for I2S */
+	.codec_dai = &cs4251x_dai,
+	.init = exm1200_mobo_i2s_machine_init,
+	.ops = &exm1200_mobo_i2s_ops,
+};
+
+static struct snd_soc_machine snd_soc_machine_template = {
+	.name = "EXM32 Motherboard I2S",
+	.dai_link = &exm1200_mobo_i2s_dai,
+	.num_links = 1,
+};
+
+/* CS42518 setup data. */
+static struct cs4251x_setup_data exm1200_mobo_i2s_codec_setup = {
+	.i2c_address = 0x9e >> 1,
+	.irq = EXMMB_CODEC_IRQ,
+};
+
+static struct snd_soc_device exm1200_mobo_i2s_snd_devdata = {
+	.machine = &snd_soc_machine_template,
+	.platform = &au1xpsc_soc_platform,
+	.codec_dev = &soc_codec_dev_cs4251x,
+	.codec_data = &exm1200_mobo_i2s_codec_setup,
+};
+
+static struct platform_device *exm1200_mobo_i2s_snd_device;
+
+static struct resource au1x_psc_res[] = {
+	[0] = {
+		.start	= PSC1_BASE,
+		.end	= PSC1_BASE + 0xffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 11,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= 16,
+		.flags	= IORESOURCE_DMA,
+	},
+	[3] = {
+		.start	= 17,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static int exm1200_mobo_i2s_init(void)
+{
+	int ret = -ENOMEM;
+	unsigned short brdctl;
+
+	MSG("module_init() enter\n");
+
+	/* switch FPGA to I2S mode */
+	brdctl = au_readw(EXM1200_FPGA_BRDCTRL);
+	brdctl |= (1 << 13);
+	au_writew(brdctl, EXM1200_FPGA_BRDCTRL);
+	au_sync();
+
+	exm1200_mobo_i2s_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!exm1200_mobo_i2s_snd_device)
+		goto out;
+
+	exm1200_mobo_i2s_snd_device->resource = au1x_psc_res;
+	exm1200_mobo_i2s_snd_device->num_resources = ARRAY_SIZE(au1x_psc_res);
+	exm1200_mobo_i2s_snd_device->id = 1;
+
+	platform_set_drvdata(exm1200_mobo_i2s_snd_device, &exm1200_mobo_i2s_snd_devdata);
+	exm1200_mobo_i2s_snd_devdata.dev = &exm1200_mobo_i2s_snd_device->dev;
+	ret = platform_device_add(exm1200_mobo_i2s_snd_device);
+
+	if (ret)
+		platform_device_put(exm1200_mobo_i2s_snd_device);
+
+out:
+	MSG("module_init() exit (ret %d)\n", ret);
+	return ret;
+}
+
+static void exm1200_mobo_i2s_exit(void)
+{
+	platform_device_del(exm1200_mobo_i2s_snd_device);
+}
+
+module_init(exm1200_mobo_i2s_init);
+module_exit(exm1200_mobo_i2s_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MSC EXM32 Development Motherboard I2S Audio support");
+MODULE_AUTHOR("Manuel Lauss <mlau@msc-ge.com>");
diff --git a/sound/soc/blackfin/bf548-ezkit.c b/sound/soc/blackfin/bf548-ezkit.c
new file mode 100644
index 0000000..17b4cbb
--- /dev/null
+++ b/sound/soc/blackfin/bf548-ezkit.c
@@ -0,0 +1,182 @@
+/*
+ * bf548_ezkit.c  --  SoC audio for bf548 ezkit
+ *
+ * Copyright 2007 Analog Device Inc.
+ *
+ * Authors: Roy Huang <roy.huang@analog.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    8th June 2007   Initial version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <asm/dma.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/gpio.h>
+#include <asm/portmux.h>
+#include "../codecs/ad1980.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-pcm.h"
+#include "bf5xx-ac97.h"
+
+#define PIN_REQ_SPORT_0 {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
+		 P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}
+
+#define PIN_REQ_SPORT_1 {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
+		 P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}
+
+#define PIN_REQ_SPORT_2 {P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS, \
+		 P_SPORT2_DRPRI, P_SPORT2_RSCLK, 0}
+
+#define PIN_REQ_SPORT_3 {P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS, \
+		 P_SPORT3_DRPRI, P_SPORT3_RSCLK, 0}
+
+
+static int	sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
+
+static struct sport_param sport_params[4] = {
+	{
+		.dma_rx_chan	= CH_SPORT0_RX,
+		.dma_tx_chan	= CH_SPORT0_TX,
+		.err_irq	= IRQ_SPORT0_ERR,
+		.regs		= (struct sport_register*)SPORT0_TCR1,
+	},
+	{
+		.dma_rx_chan	= CH_SPORT1_RX,
+		.dma_tx_chan	= CH_SPORT1_TX,
+		.err_irq	= IRQ_SPORT1_ERR,
+		.regs		= (struct sport_register*)SPORT1_TCR1,
+	},
+	{
+		.dma_rx_chan	= CH_SPORT2_RX,
+		.dma_tx_chan	= CH_SPORT2_TX,
+		.err_irq	= IRQ_SPORT2_ERR,
+		.regs		= (struct sport_register*)SPORT2_TCR1,
+	},
+	{
+		.dma_rx_chan	= CH_SPORT3_RX,
+		.dma_tx_chan	= CH_SPORT3_TX,
+		.err_irq	= IRQ_SPORT3_ERR,
+		.regs		= (struct sport_register*)SPORT3_TCR1,
+	}
+};
+
+struct sport_device *sport_handle;
+
+static struct snd_soc_machine bf548_ezkit;
+
+static int bf548_ezkit_startup(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static struct snd_soc_ops bf548_ezkit_ops = {
+	.startup = bf548_ezkit_startup,
+};
+
+static int bf548_ezkit_ac97_init(struct snd_soc_codec *codec)
+{
+	return 0;
+}
+
+static struct snd_soc_dai_link bf548_ezkit_dai = {
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &bfin_ac97_dai,
+	.codec_dai = &ad1980_dai,
+	.init = bf548_ezkit_ac97_init,
+	.ops = &bf548_ezkit_ops,
+};
+
+static int bf548_probe(struct platform_device *pdev)
+{
+
+	u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1,
+				 PIN_REQ_SPORT_2, PIN_REQ_SPORT_3};
+
+	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
+		printk(KERN_ERR "Requesting Peripherals faild\n");
+		return -EFAULT;
+		}
+
+	/* Request PB3 as reset pin */
+	if (gpio_request(GPIO_PB3, NULL)) {
+		printk(KERN_ERR "Failed to request PB3 for reset\n");
+		peripheral_free_list(&sport_req[sport_num][0]);
+		return -1;
+	}
+	gpio_direction_output(GPIO_PB3);
+	gpio_set_value(GPIO_PB3, 1);
+
+	sport_handle = sport_init(&sport_params[sport_num], 2, \
+			10 * sizeof(struct ac97_frame), NULL);
+	if (!sport_handle) {
+		peripheral_free_list(&sport_req[sport_num][0]);
+		gpio_free(GPIO_PB3);
+		return -ENODEV;
+	}
+
+	sport_set_multichannel(sport_handle, 16, 0x1F, 1);
+	sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
+	sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
+
+	return 0;
+}
+
+static struct snd_soc_machine bf548_ezkit = {
+	.name = "bf548-ezkit",
+	.probe = bf548_probe,
+	.dai_link = &bf548_ezkit_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device bf548_ezkit_snd_devdata = {
+	.machine = &bf548_ezkit,
+	.platform = &bf5xx_soc_platform,
+	.codec_dev = &soc_codec_dev_ad1980,
+};
+
+static struct platform_device *bf548_ezkit_snd_device;
+
+static int __init bf548_ezkit_init(void)
+{
+	int ret;
+
+	bf548_ezkit_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!bf548_ezkit_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(bf548_ezkit_snd_device, &bf548_ezkit_snd_devdata);
+	bf548_ezkit_snd_devdata.dev = &bf548_ezkit_snd_device->dev;
+	ret = platform_device_add(bf548_ezkit_snd_device);
+
+	if (ret)
+		platform_device_put(bf548_ezkit_snd_device);
+
+	return ret;
+}
+
+static void __exit bf548_ezkit_exit(void)
+{
+	platform_device_unregister(bf548_ezkit_snd_device);
+}
+
+module_init(bf548_ezkit_init);
+module_exit(bf548_ezkit_exit);
+
+/* Module information */
+MODULE_AUTHOR("Roy Huang");
+MODULE_DESCRIPTION("ALSA SoC BF548-EZKIT");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-board.c b/sound/soc/blackfin/bf5xx-board.c
new file mode 100644
index 0000000..4acd154
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-board.c
@@ -0,0 +1,167 @@
+/*
+ * bf5xx_board.c  --  SoC audio for Blackfin Processors
+ *
+ * Copyright 2007 Analog Device Inc.
+ *
+ * Authors: Roy Huang <roy.huang@analog.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    8th June 2007   Initial version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <asm/dma.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/gpio.h>
+#include <asm/portmux.h>
+#include "../codecs/ad1980.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-pcm.h"
+#include "bf5xx-ac97.h"
+
+#define PIN_REQ_SPORT_0 {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
+		 P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}
+
+#define PIN_REQ_SPORT_1 {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
+		 P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}
+
+
+static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
+
+static struct sport_param sport_params[2] = {
+	{
+		.dma_rx_chan	= CH_SPORT0_RX,
+		.dma_tx_chan	= CH_SPORT0_TX,
+		.err_irq	= IRQ_SPORT0_ERROR,
+		.regs		= (struct sport_register *)SPORT0_TCR1,
+	},
+	{
+		.dma_rx_chan	= CH_SPORT1_RX,
+		.dma_tx_chan	= CH_SPORT1_TX,
+		.err_irq	= IRQ_SPORT1_ERROR,
+		.regs		= (struct sport_register *)SPORT1_TCR1,
+	}
+};
+
+struct sport_device *sport_handle;
+
+static struct snd_soc_machine bf5xx_board;
+
+static int bf5xx_board_startup(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static struct snd_soc_ops bf5xx_board_ops = {
+	.startup = bf5xx_board_startup,
+};
+
+static int bf5xx_board_ac97_init(struct snd_soc_codec *codec)
+{
+	return 0;
+}
+
+static struct snd_soc_dai_link bf5xx_board_dai = {
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &bfin_ac97_dai,
+	.codec_dai = &ad1980_dai,
+	.init = bf5xx_board_ac97_init,
+	.ops = &bf5xx_board_ops,
+};
+
+static int bf5xx_probe(struct platform_device *pdev)
+{
+
+	u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1};
+
+	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
+		printk(KERN_ERR "Requesting Peripherals faild\n");
+		return -EFAULT;
+		}
+
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+	/* Request PB3 as reset pin */
+	if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) {
+		printk(KERN_ERR "Failed to request GPIO_%d for reset\n",
+				CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+		peripheral_free_list(&sport_req[sport_num][0]);
+		return -1;
+	}
+	gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+	gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
+#endif
+	sport_handle = sport_init(&sport_params[sport_num], 2, \
+			10 * sizeof(struct ac97_frame), NULL);
+	if (!sport_handle) {
+		peripheral_free_list(&sport_req[sport_num][0]);
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+		gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+		return -ENODEV;
+	}
+
+	sport_set_multichannel(sport_handle, 16, 0x1F, 1);
+	sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
+	sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
+
+	return 0;
+}
+
+static struct snd_soc_machine bf5xx_board = {
+	.name = "bf5xx-board",
+	.probe = bf5xx_probe,
+	.dai_link = &bf5xx_board_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_board_snd_devdata = {
+	.machine = &bf5xx_board,
+	.platform = &bf5xx_soc_platform,
+	.codec_dev = &soc_codec_dev_ad1980,
+};
+
+static struct platform_device *bf5xx_board_snd_device;
+
+static int __init bf5xx_board_init(void)
+{
+	int ret;
+
+	bf5xx_board_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!bf5xx_board_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board_snd_devdata);
+	bf5xx_board_snd_devdata.dev = &bf5xx_board_snd_device->dev;
+	ret = platform_device_add(bf5xx_board_snd_device);
+
+	if (ret)
+		platform_device_put(bf5xx_board_snd_device);
+
+	return ret;
+}
+
+static void __exit bf5xx_board_exit(void)
+{
+	platform_device_unregister(bf5xx_board_snd_device);
+}
+
+module_init(bf5xx_board_init);
+module_exit(bf5xx_board_exit);
+
+/* Module information */
+MODULE_AUTHOR("Roy Huang");
+MODULE_DESCRIPTION("ALSA SoC BF5xx Board");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-pcm.c b/sound/soc/blackfin/bf5xx-pcm.c
new file mode 100644
index 0000000..a87e807
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-pcm.c
@@ -0,0 +1,285 @@
+/*
+ * linux/sound/arm/bf5xx-pcm.c -- ALSA PCM interface for the Blackfin
+ *
+ * Author:	Roy Huang <roy.huang@analog.com>
+ * Copyright:	(C) 2007 Analog Device Inc.
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+
+#include "bf5xx-pcm.h"
+#include "bf5xx-ac97.h"
+#include "bf5xx-sport.h"
+
+
+static void bf5xx_dma_irq(void *data)
+{
+	struct snd_pcm_substream *pcm = data;
+
+	pr_debug("%s enter \n", __FUNCTION__);
+	snd_pcm_period_elapsed(pcm);
+}
+
+/* The memory size for pure pcm data is 128*1024 = 0x20000 bytes.
+ * The total rx/tx buffer is for ac97 frame to hold all pcm data
+ * is  0x20000 * sizeof(struct ac97_frame) / 4.
+ */
+static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 0x10000,
+	.periods_min		= 1,
+	.periods_max		= PAGE_SIZE/32,
+	.buffer_bytes_max	= 0x20000, /* 128 kbytes */
+	.fifo_size		= 16,
+};
+
+static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	size_t size = bf5xx_pcm_hardware.buffer_bytes_max * \
+			sizeof(struct ac97_frame) / 4;
+
+	snd_pcm_lib_malloc_pages(substream, size);
+
+	return 0;
+}
+
+static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_lib_free_pages(substream);
+	return 0;
+}
+
+static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
+		sport_config_tx_dma(sport, runtime->dma_area, runtime->periods,
+				runtime->period_size * sizeof(struct ac97_frame));
+	} else {
+		sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
+		sport_config_rx_dma(sport, runtime->dma_area, runtime->periods,
+				runtime->period_size * sizeof(struct ac97_frame));
+	}
+	return 0;
+}
+
+static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct sport_device *sport = substream->runtime->private_data;
+	int ret = 0;
+
+	pr_debug("%s %s\n", substream->stream?"Capture":"Playback", \
+			cmd?" start":" stop");
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sport_tx_start(sport);
+		else
+			sport_rx_start(sport);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			pr_debug("stop dma\n");
+			sport_tx_stop(sport);
+		} else
+			sport_rx_stop(sport);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
+	unsigned int curr;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		curr = sport_curr_offset_tx(sport) / sizeof(struct ac97_frame);
+	else
+		curr = sport_curr_offset_rx(sport) / sizeof(struct ac97_frame);
+	pr_debug("%s pointer curr:0x%0x\n", substream->stream ? \
+			"Capture":"Playback", curr);
+
+	return curr;
+}
+
+static	int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
+		    snd_pcm_uframes_t pos,
+		    void __user *buf, snd_pcm_uframes_t count)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	pr_debug("%s copy pos:0x%lx count:0x%lx\n",
+			substream->stream?"Capture":"Playback", pos, count);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		bf5xx_ac97_pcm32_to_frame(
+				(struct ac97_frame *)runtime->dma_area + pos,
+				buf, count);
+	} else
+		bf5xx_ac97_frame_to_pcm32(
+				(struct ac97_frame *)runtime->dma_area + pos,
+				buf, count);
+
+	return 0;
+}
+
+static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret;
+
+	pr_debug("%s enter\n", __FUNCTION__);
+	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
+
+	ret = snd_pcm_hw_constraint_integer(runtime, \
+			SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		goto out;
+
+	if (sport_handle != NULL)
+		runtime->private_data = sport_handle;
+	else {
+		printk(KERN_ERR "sport_handle is NULL\n");
+		return -1;
+	}
+	return 0;
+
+ out:
+	return ret;
+}
+
+static int bf5xx_pcm_close(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+struct snd_pcm_ops bf5xx_pcm_ops = {
+	.open		= bf5xx_pcm_open,
+	.close		= bf5xx_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= bf5xx_pcm_hw_params,
+	.hw_free	= bf5xx_pcm_hw_free,
+	.prepare	= bf5xx_pcm_prepare,
+	.trigger	= bf5xx_pcm_trigger,
+	.pointer	= bf5xx_pcm_pointer,
+	.copy		= bf5xx_pcm_copy,
+};
+
+static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = bf5xx_pcm_hardware.buffer_bytes_max * \
+			sizeof(struct ac97_frame) / 4;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size, &buf->addr, GFP_KERNEL);
+	if (!buf->area) {
+		printk(KERN_ERR "Failed to allocate dma memory\n");
+		return -ENOMEM;
+	}
+	buf->bytes = size;
+
+	pr_debug("%s, area:%p, size:0x%08lx\n", __FUNCTION__, buf->area, buf->bytes);
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		sport_handle->tx_buf = buf->area;
+	else
+		sport_handle->rx_buf = buf->area;
+
+	return 0;
+}
+
+static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
+		buf->area = NULL;
+	}
+}
+
+static u64 bf5xx_pcm_dmamask = DMA_32BIT_MASK;
+
+int bf5xx_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
+	struct snd_pcm *pcm)
+{
+	int ret = 0;
+
+	pr_debug("%s enter\n", __FUNCTION__);
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &bf5xx_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+
+	if (dai->playback.channels_min) {
+		ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			goto out;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			goto out;
+	}
+ out:
+	return ret;
+}
+
+struct snd_soc_platform bf5xx_soc_platform = {
+	.name		= "bf5xx-audio",
+	.pcm_ops 	= &bf5xx_pcm_ops,
+	.pcm_new	= bf5xx_pcm_new,
+	.pcm_free	= bf5xx_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(bf5xx_soc_platform);
+
+MODULE_AUTHOR("Roy Huang");
+MODULE_DESCRIPTION("ADI Blackfin PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-pcm.h b/sound/soc/blackfin/bf5xx-pcm.h
new file mode 100644
index 0000000..75e6829
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-pcm.h
@@ -0,0 +1,29 @@
+/*
+ * linux/sound/arm/bf5xx-pcm.h -- ALSA PCM interface for the Blackfin
+ *
+ * Copyright 2007 Analog Device Inc.
+ *
+ * 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 _BF5XX_PCM_H
+#define _BF5XX_PCM_H
+
+struct bf5xx_pcm_dma_params {
+	char *name;			/* stream identifier */
+};
+
+struct bf5xx_gpio {
+	u32 sys;
+	u32	rx;
+	u32 tx;
+	u32 clk;
+	u32 frm;
+};
+
+/* platform data */
+extern struct snd_soc_platform bf5xx_soc_platform;
+
+#endif
diff --git a/sound/soc/blackfin/bf5xx-wm8750.c b/sound/soc/blackfin/bf5xx-wm8750.c
new file mode 100644
index 0000000..4e0d2ab
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-wm8750.c
@@ -0,0 +1,260 @@
+/*
+ * bf5xx_wm8750.c  --  SoC audio for bf5xx WM8750
+ *
+ * Copyright 2007 Analog Device Inc.
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ * Based on bf548_ezkit.c by Roy Huang <roy.huang@analog.com>
+ *          
+ * Authors:  Liam Girdwood <lg@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    29th Aug 2007   Initial version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
+
+#include <asm/dma.h>
+#include <asm/gpio.h>
+#include <asm/portmux.h>
+#include "../codecs/wm8750.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-pcm.h"
+#include "bf5xx-i2s.h"
+
+#define BF53X_WM8750_DEBUG
+
+#ifdef  BF53X_WM8750_DEBUG
+#define printd(format, arg...) printk("bfin-wm8750: " format, ## arg)
+#endif
+
+
+#define PIN_REQ_SPORT_0 {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
+		 P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}
+
+#define PIN_REQ_SPORT_1 {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
+		 P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}
+
+#define PIN_REQ_SPORT_2 {P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS, \
+		 P_SPORT2_DRPRI, P_SPORT2_RSCLK, 0}
+
+#define PIN_REQ_SPORT_3 {P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS, \
+		 P_SPORT3_DRPRI, P_SPORT3_RSCLK, 0}
+
+
+static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
+
+static struct sport_param sport_params[4] = {
+	{
+		.dma_rx_chan	= CH_SPORT0_RX,
+		.dma_tx_chan	= CH_SPORT0_TX,
+		.err_irq	= IRQ_SPORT0_ERR,
+		.regs		= (struct sport_register*)SPORT0_TCR1,
+	},
+	{
+		.dma_rx_chan	= CH_SPORT1_RX,
+		.dma_tx_chan	= CH_SPORT1_TX,
+		.err_irq	= IRQ_SPORT1_ERR,
+		.regs		= (struct sport_register*)SPORT1_TCR1,
+	},
+	{
+		.dma_rx_chan	= CH_SPORT2_RX,
+		.dma_tx_chan	= CH_SPORT2_TX,
+		.err_irq	= IRQ_SPORT2_ERR,
+		.regs		= (struct sport_register*)SPORT2_TCR1,
+	},
+	{
+		.dma_rx_chan	= CH_SPORT3_RX,
+		.dma_tx_chan	= CH_SPORT3_TX,
+		.err_irq	= IRQ_SPORT3_ERR,
+		.regs		= (struct sport_register*)SPORT3_TCR1,
+	}
+};
+
+struct sport_device *sport_handle;
+
+static struct snd_soc_machine bf5xx_wm8750;
+
+static int bf5xx_wm8750_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	
+	cpu_dai->private_data = sport_handle;		
+	return 0;
+}
+
+static int bf5xx_wm8750_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int clk = 0;
+	int ret = 0;
+
+	printd("%s rate %d format %x\n", __func__, params_rate(params), 
+		params_format(params));
+	/*
+	 * WARNING - TODO
+	 * 
+	 * This code assumes there is a variable clocksource for the WM8750.
+	 * i.e. it supplies MCLK depending on rate.
+	 * 
+	 * If you are using a crystal source then modify the below case 
+	 * statement with a static frequency.
+	 * 
+	 * If you are using the SPORT to generate clocking then this is 
+	 * where to do it. 
+	 */
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		clk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 11289600;
+		break;
+	}
+
+	/*
+	 * CODEC is master for BCLK and LRC in this configuration.
+	 */
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock for DAC and ADC */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops bf5xx_wm8750_ops = {
+	.startup = bf5xx_wm8750_startup,
+	.hw_params = bf5xx_wm8750_hw_params,
+};
+
+static int bf5xx_wm8750_init_dev(struct snd_soc_codec *codec)
+{
+	/* 
+	 * NC codec pins -
+	 * Add any NC codec pins as follows :-
+	 * 
+	 * snd_soc_dapm_disable_pin(codec, "RINPUT1");
+	 */
+	printd("%s\n", __func__);
+	snd_soc_dapm_sync(codec);
+	return 0;
+}
+
+static struct snd_soc_dai_link bf5xx_wm8750_dai = {
+	.name = "wm8750",
+	.stream_name = "WM8750",
+	.cpu_dai = &bf5xx_i2s_dai[CONFIG_SND_BF5XX_SPORT_NUM],
+	.codec_dai = &wm8750_dai,
+	.init = bf5xx_wm8750_init_dev,
+	.ops = &bf5xx_wm8750_ops,
+};
+
+static int bf5xx_probe(struct platform_device *pdev)
+{
+
+	u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1,
+				 PIN_REQ_SPORT_2, PIN_REQ_SPORT_3};
+	
+	printd("%s\n", __func__);
+	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
+		printk(KERN_ERR "Requesting Peripherals faild\n");
+		return -EFAULT;
+	}
+
+	/* TODO: not sure of correct dummy size */
+	sport_handle = sport_init(&sport_params[sport_num], 2, \
+			10 * sizeof(u16), NULL);
+	if (!sport_handle) {
+		peripheral_free_list(&sport_req[sport_num][0]);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_machine bf5xx_wm8750 = {
+	.name = "bf5xx-wm8750",
+	.probe = bf5xx_probe,
+	.dai_link = &bf5xx_wm8750_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_wm8750_snd_devdata = {
+	.machine = &bf5xx_wm8750,
+	.platform = &bf5xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8750,
+};
+
+static struct platform_device *bf54xx_wm8750_snd_device;
+
+static int __init bf5xx_wm8750_init(void)
+{
+	int ret;
+	
+	printd("%s\n", __func__);
+	bf54xx_wm8750_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!bf54xx_wm8750_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(bf54xx_wm8750_snd_device, &bf5xx_wm8750_snd_devdata);
+	bf5xx_wm8750_snd_devdata.dev = &bf54xx_wm8750_snd_device->dev;
+	ret = platform_device_add(bf54xx_wm8750_snd_device);
+
+	if (ret)
+		platform_device_put(bf54xx_wm8750_snd_device);
+
+	return ret;
+}
+
+static void __exit bf5xx_wm8750_exit(void)
+{
+	printd("%s\n", __func__);
+	platform_device_unregister(bf54xx_wm8750_snd_device);
+}
+
+module_init(bf5xx_wm8750_init);
+module_exit(bf5xx_wm8750_exit);
+
+/* Module information */
+MODULE_AUTHOR("Roy Huang");
+MODULE_DESCRIPTION("ALSA SoC BF548-EZKIT");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index fa787d4..ef5fc5f 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -60,6 +60,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_WL1273 if MFD_WL1273_CORE
 	select SND_SOC_WM1250_EV1 if I2C
 	select SND_SOC_WM2000 if I2C
+	select SND_SOC_WM2200 if I2C
 	select SND_SOC_WM5100 if I2C
 	select SND_SOC_WM8350 if MFD_WM8350
 	select SND_SOC_WM8400 if MFD_WM8400
@@ -75,6 +76,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8770 if SPI_MASTER
+	select SND_SOC_WM8772 if SPI_MASTER
 	select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8782
 	select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
@@ -82,13 +84,16 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_WM8903 if I2C
 	select SND_SOC_WM8904 if I2C
 	select SND_SOC_WM8940 if I2C
+	select SND_SOC_WM8950 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8955 if I2C
 	select SND_SOC_WM8960 if I2C
 	select SND_SOC_WM8961 if I2C
 	select SND_SOC_WM8962 if I2C
 	select SND_SOC_WM8971 if I2C
 	select SND_SOC_WM8974 if I2C
+	select SND_SOC_WM8976 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8978 if I2C
+	select SND_SOC_WM8980 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8983 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
@@ -124,7 +129,9 @@ config SND_SOC_WM_HUBS
 
 config SND_SOC_AC97_CODEC
 	tristate
-	select SND_AC97_CODEC
+
+config SND_SOC_AD1939
+	tristate
 
 config SND_SOC_AD1836
 	tristate
@@ -163,6 +170,9 @@ config SND_SOC_AK4641
 config SND_SOC_AK4642
 	tristate
 
+config SND_SOC_CS4251X
+	tristate
+
 config SND_SOC_AK4671
 	tristate
 
@@ -270,7 +280,7 @@ config SND_SOC_UDA134X
        tristate
 
 config SND_SOC_UDA1380
-        tristate
+	tristate
 
 config SND_SOC_WL1273
 	tristate
@@ -278,6 +288,9 @@ config SND_SOC_WL1273
 config SND_SOC_WM1250_EV1
 	tristate
 
+config SND_SOC_WM2200
+	tristate
+
 config SND_SOC_WM5100
 	tristate
 
@@ -323,6 +336,9 @@ config SND_SOC_WM8753
 config SND_SOC_WM8770
 	tristate
 
+config SND_SOC_WM8772
+	tristate
+
 config SND_SOC_WM8776
 	tristate
 
@@ -344,9 +360,15 @@ config SND_SOC_WM8904
 config SND_SOC_WM8940
         tristate
 
+config SND_SOC_WM8950
+	tristate
+	
 config SND_SOC_WM8955
 	tristate
 
+config SND_SOC_WM8956
+	tristate
+
 config SND_SOC_WM8960
 	tristate
 
@@ -362,9 +384,15 @@ config SND_SOC_WM8971
 config SND_SOC_WM8974
 	tristate
 
+config SND_SOC_WM8976
+	tristate
+	
 config SND_SOC_WM8978
 	tristate
 
+config SND_SOC_WM8980
+	tristate
+
 config SND_SOC_WM8983
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index a2c7842..3439db0 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -3,6 +3,7 @@ snd-soc-ac97-objs := ac97.o
 snd-soc-ad1836-objs := ad1836.o
 snd-soc-ad193x-objs := ad193x.o
 snd-soc-ad1980-objs := ad1980.o
+snd-soc-ak4535-objs := ak4535.o
 snd-soc-ad73311-objs := ad73311.o
 snd-soc-adau1701-objs := adau1701.o
 snd-soc-adau1373-objs := adau1373.o
@@ -14,6 +15,7 @@ snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-cq93vc-objs := cq93vc.o
+snd-soc-cs4251x-objs := cs4251x.o
 snd-soc-cs42l51-objs := cs42l51.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cs4271-objs := cs4271.o
@@ -45,6 +47,7 @@ snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
+snd-soc-wm2200-objs := wm2200.o
 snd-soc-wm5100-objs := wm5100.o wm5100-tables.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8400-objs := wm8400.o
@@ -60,6 +63,7 @@ snd-soc-wm8741-objs := wm8741.o
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8770-objs := wm8770.o
+snd-soc-wm8772-objs := wm8772.o
 snd-soc-wm8776-objs := wm8776.o
 snd-soc-wm8782-objs := wm8782.o
 snd-soc-wm8804-objs := wm8804.o
@@ -68,13 +72,18 @@ snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8904-objs := wm8904.o
 snd-soc-wm8996-objs := wm8996.o
 snd-soc-wm8940-objs := wm8940.o
+snd-soc-wm8950-objs := wm8950.o
+snd-soc-wm8951-objs := wm8951.o
 snd-soc-wm8955-objs := wm8955.o
+snd-soc-wm8956-objs := wm8956.o
 snd-soc-wm8960-objs := wm8960.o
 snd-soc-wm8961-objs := wm8961.o
 snd-soc-wm8962-objs := wm8962.o
 snd-soc-wm8971-objs := wm8971.o
 snd-soc-wm8974-objs := wm8974.o
+snd-soc-wm8976-objs := wm8976.o
 snd-soc-wm8978-objs := wm8978.o
+snd-soc-wm8980-objs := wm8980.o
 snd-soc-wm8983-objs := wm8983.o
 snd-soc-wm8985-objs := wm8985.o
 snd-soc-wm8988-objs := wm8988.o
@@ -114,6 +123,7 @@ obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
+obj-$(CONFIG_SND_SOC_CS4251X)	+= snd-soc-cs4251x.o
 obj-$(CONFIG_SND_SOC_CS42L51)	+= snd-soc-cs42l51.o
 obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CS4271)	+= snd-soc-cs4271.o
@@ -145,6 +155,7 @@ obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
+obj-$(CONFIG_SND_SOC_WM2200)	+= snd-soc-wm2200.o
 obj-$(CONFIG_SND_SOC_WM5100)	+= snd-soc-wm5100.o
 obj-$(CONFIG_SND_SOC_WM8350)	+= snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8400)	+= snd-soc-wm8400.o
@@ -160,6 +171,7 @@ obj-$(CONFIG_SND_SOC_WM8741)	+= snd-soc-wm8741.o
 obj-$(CONFIG_SND_SOC_WM8750)	+= snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)	+= snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM8770)	+= snd-soc-wm8770.o
+obj-$(CONFIG_SND_SOC_WM8772)	+= snd-soc-wm8772.o
 obj-$(CONFIG_SND_SOC_WM8776)	+= snd-soc-wm8776.o
 obj-$(CONFIG_SND_SOC_WM8782)	+= snd-soc-wm8782.o
 obj-$(CONFIG_SND_SOC_WM8804)	+= snd-soc-wm8804.o
@@ -168,13 +180,18 @@ obj-$(CONFIG_SND_SOC_WM8903)	+= snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8904)	+= snd-soc-wm8904.o
 obj-$(CONFIG_SND_SOC_WM8996)	+= snd-soc-wm8996.o
 obj-$(CONFIG_SND_SOC_WM8940)	+= snd-soc-wm8940.o
+obj-$(CONFIG_SND_SOC_WM8950)	+= snd-soc-wm8950.o
+obj-$(CONFIG_SND_SOC_WM8951)	+= snd-soc-wm8951.o
 obj-$(CONFIG_SND_SOC_WM8955)	+= snd-soc-wm8955.o
+obj-$(CONFIG_SND_SOC_WM8956)	+= snd-soc-wm8956.o
 obj-$(CONFIG_SND_SOC_WM8960)	+= snd-soc-wm8960.o
 obj-$(CONFIG_SND_SOC_WM8961)	+= snd-soc-wm8961.o
 obj-$(CONFIG_SND_SOC_WM8962)	+= snd-soc-wm8962.o
 obj-$(CONFIG_SND_SOC_WM8971)	+= snd-soc-wm8971.o
 obj-$(CONFIG_SND_SOC_WM8974)	+= snd-soc-wm8974.o
+obj-$(CONFIG_SND_SOC_WM8976)	+= snd-soc-wm8976.o
 obj-$(CONFIG_SND_SOC_WM8978)	+= snd-soc-wm8978.o
+obj-$(CONFIG_SND_SOC_WM8980)	+= snd-soc-wm8980.o
 obj-$(CONFIG_SND_SOC_WM8983)	+= snd-soc-wm8983.o
 obj-$(CONFIG_SND_SOC_WM8985)	+= snd-soc-wm8985.o
 obj-$(CONFIG_SND_SOC_WM8988)	+= snd-soc-wm8988.o
diff --git a/sound/soc/codecs/ad1939.c b/sound/soc/codecs/ad1939.c
new file mode 100644
index 0000000..63098bc
--- /dev/null
+++ b/sound/soc/codecs/ad1939.c
@@ -0,0 +1,681 @@
+/*
+ * AD1939 I2S Codec driver
+ *
+ * (c) 2007 MSC Vertriebsges.m.b.H, <mlau@msc-ge.com>
+ *
+ * licensed under the GPLv2
+ */
+
+/*
+ * Analog Devices AD1939 I2S codec; with I2C or SPI interface.
+ *  supports 2 channels in plain I2S mode,
+ *  and up to 16 channels in TDM modes.
+ * As Master, the codec always assumes a frame is a multiple of 32bits!
+ * TDM Modes:
+ *	- multiple channels over I2S
+ *	- 32 fixed slot width, TDM stereo is I2S with 32bits/sample.
+ *
+ * TODO: driver switches between stereo and TDM mode based on the number
+ *	 of  channels  for record / playback (ad1939_hw_params()).  This
+ *	 should be  overhauled if someone  wants to daisy-chain a few of
+ *	 these  together  (to  get 8 DAC channels total).  Maybe use TDM
+ *	 mode  exclusively  when codec  is LRCK/BCK  master, and let the
+ *	 user set WHICH TDM mode to use through setup_data.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "ad1939.h"
+
+#define AUDIO_NAME "AD1939"
+
+struct ad1939_private {
+	struct snd_soc_codec *codec;
+	unsigned long sysclk;
+	unsigned char tdm_mode;
+};
+
+/* default register contents after reset */
+static const u16 ad1939_regcache[AD1939_REGCOUNT] __devinitdata = {
+	0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int ad1939_i2c_write(struct snd_soc_codec *codec, unsigned int r,
+			    unsigned int v)
+{
+	struct i2c_msg msg;
+	struct i2c_client *c;
+	u8 data[2];
+	u16 *cache = codec->reg_cache;
+	int ret;
+
+	if (cache[r] == v)
+		return 0;
+
+	/* oh noes, now we have to talk to the codec */
+	c = (struct i2c_client *)codec->control_data;
+	data[0] = r & 0xff;
+	data[1] = v & 0xff;
+	msg.addr = c->addr;
+	msg.flags = 0;	/* write */
+	msg.buf = &data[0];
+	msg.len = 2;
+
+	ret = i2c_transfer(c->adapter, &msg, 1);
+	if (ret == 1)
+		cache[r] = v;
+	return (ret == 1) ? 0 : -EIO;
+}
+
+static unsigned int ad1939_i2c_read(struct snd_soc_codec *codec,
+				    unsigned int r)
+{
+	struct i2c_msg msg[2];
+	struct i2c_client *c;
+	u16 *cache = codec->reg_cache;
+	u8 data[2];
+	int ret;
+
+	/* the PLLCTL1 has one read-only bit: PLL lock indicator.
+	 * all other regs keep what was set
+	 */
+	if (likely(r != AD1939_PLLCTL1))
+		return cache[r];
+
+	c = (struct i2c_client *)codec->control_data;
+	data[0] = r & 0xff;
+	msg[0].addr = c->addr;
+	msg[0].flags = 0;
+	msg[0].buf = &data[0];
+	msg[0].len = 1;
+	
+	msg[1].addr = c->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].buf = &data[1];
+	msg[1].len = 1;
+
+	ret = i2c_transfer(c->adapter, &msg[0], 2);
+	return (ret == 2) ? data[1] : -EIO;
+}
+#endif
+
+static inline unsigned int ad1939_read(struct snd_soc_codec *codec,
+				unsigned int r)
+{
+	return codec->read(codec, r);
+}
+
+static inline int ad1939_write(struct snd_soc_codec *codec,
+			       unsigned int r, unsigned int v)
+{
+	return codec->write(codec, r, v);
+}
+
+/***** controls ******/
+
+static const char *dac_deemph[] = {"Flat", "48kHz", "44.1kHz", "32kHz"};
+static const char *dac_outpol[] = {"Normal", "Inverted"};
+
+static const struct soc_enum ad1939_enum[] = {
+      /*SOC_ENUM_SINGLE(register, startbit, choices, choices-texts) */
+	SOC_ENUM_SINGLE(AD1939_DACCTL2, 1, 4, dac_deemph),
+	SOC_ENUM_SINGLE(AD1939_DACCTL2, 5, 1, dac_outpol),
+};
+
+static const struct snd_kcontrol_new ad1939_snd_ctls[] = {
+SOC_DOUBLE_R("Master Playback", AD1939_VOL1L, AD1939_VOL1R, 0, 255, 1),
+SOC_DOUBLE_R("Channel 2 Playback", AD1939_VOL2L, AD1939_VOL2R, 0, 255, 1),
+SOC_DOUBLE_R("Channel 3 Playback", AD1939_VOL3L, AD1939_VOL3R, 0, 255, 1),
+SOC_DOUBLE_R("Channel 4 Playback", AD1939_VOL4L, AD1939_VOL4R, 0, 255, 1),
+SOC_ENUM("DAC Deemphasis", ad1939_enum[0]),
+SOC_ENUM("DAC output polarity", ad1939_enum[1]),
+};
+
+/* add non dapm controls */
+static int ad1939_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(ad1939_snd_ctls); i++) {
+		err = snd_ctl_add(codec->card,
+			snd_soc_cnew(&ad1939_snd_ctls[i], codec, NULL));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+
+/***** chip interface config ******/
+
+
+static int ad1939_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct ad1939_private *ad = codec->private_data;
+	unsigned char dac0, dac1, dac2, adc0, adc1, adc2;
+	unsigned long rate;
+	unsigned int bits;
+
+	pr_debug("ad1939_hw_params");
+
+	dac0 = ad1939_read(codec, AD1939_DACCTL0);
+	dac1 = ad1939_read(codec, AD1939_DACCTL1);
+	dac2 = ad1939_read(codec, AD1939_DACCTL2);
+	adc0 = ad1939_read(codec, AD1939_ADCCTL0);
+	adc1 = ad1939_read(codec, AD1939_ADCCTL1);
+	adc2 = ad1939_read(codec, AD1939_ADCCTL2);
+
+	rate = params_rate(params);
+	bits = params->msbits;
+
+	pr_debug("bits %d srate %lu/%d chans %d\n", bits, rate,
+	       params->rate_den, params_channels(params));
+
+	/*
+	 * sample rate
+	 */
+	dac0 &= ~(3<<1);	/* 48kHz */
+	adc0 &= ~(3<<6);	/* 48kHz */
+	switch (rate) {
+	case 32000 ... 48000:
+		break;
+	case 64000 ... 96000:
+		dac0 |= (1<<1);
+		adc0 |= (1<<6);
+		break;
+	case 128000 ... 192000:
+		dac0 |= (2<<1);
+		adc0 |= (2<<6);
+		break;
+	default:
+		pr_debug("rejecting srate %lu\n", rate);
+		return -EINVAL;
+	}
+
+	/*
+	 * sample width (bits)
+	 */
+	dac2 &= ~(3<<3);	/* 24 bits */
+	adc1 &= ~(3<<0);	/* 24 bits */
+	switch (bits) {
+	case 16: dac2 |= (3<<3); adc1 |= (3<<0); break;
+	case 20: dac2 |= (1<<3); adc1 |= (1<<0); break;
+	case 24: break;
+	default:
+		pr_debug("rejecting bits %d\n", bits);
+		return -EINVAL;
+	}
+
+	/*
+	 * channels
+	 */
+	dac0 &= ~(3<<6);	/* DAC I2S stereo */
+	dac1 &= ~(3<<1);	/* 2 channels */
+	adc1 &= ~(3<<5);	/* ADC I2S stereo */
+	adc2 &= ~(3<<4);	/* 2 channels */
+	switch (params_channels(params)) {
+	case 2:	/* I2S stereo mode */
+		break;
+	case 4:	/* TDM mode */
+		dac0 |= (ad->tdm_mode & 3) << 6;
+		dac1 |= (1<<1);
+		adc1 |= (ad->tdm_mode & 3) << 5;
+		adc2 |= (1<<4);
+		break;
+	case 8:	/* TDM mode */
+		dac0 |= (ad->tdm_mode & 3) << 6;
+		dac1 |= (2<<1);
+		adc1 |= (ad->tdm_mode & 3) << 5;
+		adc2 |= (2<<4);
+		break;
+	case 16: /* TDM mode */
+		dac0 |= (ad->tdm_mode & 3) << 6;
+		dac1 |= (3<<1);
+		adc1 |= (ad->tdm_mode & 3) << 5;
+		adc2 |= (3<<4);
+		break;
+	default:
+		pr_debug("%d channels not supported\n",
+			params_channels(params));
+		return -EINVAL;
+	}
+
+	ad1939_write(codec, AD1939_DACCTL0, dac0);
+	ad1939_write(codec, AD1939_DACCTL1, dac1);
+	ad1939_write(codec, AD1939_DACCTL2, dac2);
+	ad1939_write(codec, AD1939_ADCCTL0, adc0);
+	ad1939_write(codec, AD1939_ADCCTL1, adc1);
+	ad1939_write(codec, AD1939_ADCCTL2, adc2);
+
+	return 0;
+}
+
+static int ad1939_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	unsigned char dac0, dac1, adc1, adc2;
+
+	pr_debug("ad1939_set_dai_fmt(0x%08x)", fmt);
+
+	dac0 = ad1939_read(codec, AD1939_DACCTL0);
+	dac1 = ad1939_read(codec, AD1939_DACCTL1);
+	adc1 = ad1939_read(codec, AD1939_ADCCTL1);
+	adc2 = ad1939_read(codec, AD1939_ADCCTL2);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		dac1 |= (1<<4) | (1<<5); /* LRCK master, BCK master */
+		adc2 |= (1<<3) | (1<<6); /* LRCK master, BCK master */
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		dac1 |= (1<<4);		/* LRCK master */
+		dac1 &= ~(1<<5);	/* BCK slave */
+		adc2 |= (1<<3);		/* LRCK master */
+		adc2 &= ~(1<<6);	/* BCK slave */
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		dac1 &= ~(1<<4);	/* LRCK slave */
+		dac1 |= (1<<5);		/* BCK master */
+		adc2 &= ~(1<<3);	/* LRCK slave */
+		adc2 |= (1<<6);		/* BCK master */
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		dac1 &= ~((1<<4) | (1<<5)); /* LRCK BCK slave */
+		adc2 &= ~((1<<3) | (1<<6)); /* LRCK BCK slave */
+		break;
+	default:
+		pr_debug("invalid master/slave configuration\n");
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		dac0 &= ~(7<<3); /* DAC: SDATA delay 1 */
+		adc1 &= ~(7<<2); /* ADC: SDATA delay 1 */
+		break;
+	case SND_SOC_DAIFMT_MSB: /* LEFT_J */
+		dac0 |= (1<<3);	/* no SDATA delay */
+		adc1 |= (1<<2); /* no SDATA delay */
+		break;
+#if 0
+	case SND_SOC_DAIFMT_LSB:
+		/* FIXME: need to know if in TDM/Master mode and sample
+		 * size, then program bitdelay accordingly
+		 */
+		break;
+#endif
+	default:
+		pr_err("invalid I2S interface format\n");
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	dac1 &= ~((1<<7) | (1<<3)); /* norm BCK LRCK */
+	adc2 &= ~((1<<1) | (1<<2)); /* norm BCK LRCK */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		dac1 |= (1<<3);		/* inv LRCK */
+		adc2 |= (1<<2);
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		dac1 |= (1<<7);		/* inv BCK */
+		adc2 |= (1<<1);
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		dac1 |= (1<<3) | (1<<7); /* inv LRCK BCK */
+		adc2 |= (1<<1) | (1<<2);
+		break;
+	default:
+		pr_err("invalid clock inversion configuration\n");
+		return -EINVAL;
+	}
+
+	ad1939_write(codec, AD1939_DACCTL0, dac0);
+	ad1939_write(codec, AD1939_DACCTL1, dac1);
+	ad1939_write(codec, AD1939_ADCCTL1, adc1);
+	ad1939_write(codec, AD1939_ADCCTL2, adc2);
+
+	return 0;
+}
+
+static int ad1939_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level event)
+{
+	unsigned char pll0, adc0, dac0;
+
+	/* the codec doesn't really have  sophisticated PM like the
+	 * WM8731 for example; one can merely turn off DAC, ADC and
+	 * the internal PLL
+	 */
+	pll0 = ad1939_read(codec, AD1939_PLLCTL0) & 0xfe;
+	dac0 = ad1939_read(codec, AD1939_DACCTL0) & 0xfe;
+	adc0 = ad1939_read(codec, AD1939_ADCCTL0) & 0xfe;
+
+	switch (event)
+	{
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		ad1939_write(codec, AD1939_PLLCTL0, pll0);
+		ad1939_write(codec, AD1939_DACCTL0, dac0);
+		ad1939_write(codec, AD1939_ADCCTL0, adc0);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+	case SND_SOC_BIAS_OFF:
+		/* turn off internal PLL and DAC/ADCs */
+		ad1939_write(codec, AD1939_PLLCTL0, pll0 | 1);
+		ad1939_write(codec, AD1939_DACCTL0, dac0 | 1);
+		ad1939_write(codec, AD1939_ADCCTL0, adc0 | 1);
+		break;
+	}
+	codec->bias_level = event;
+	return 0;
+}
+
+static int ad1939_digmute(struct snd_soc_dai *dai, int mute)
+{
+	dai->codec->write(dai->codec, AD1939_DACMUTE, mute ? 0xff : 0);
+	return 0;
+}
+
+static int ad1939_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct ad1939_private *ad = codec->private_data;
+
+	pr_debug("sysck id %d f %d dir %d\n", clk_id, freq, dir);
+	switch (freq) {
+	case 11288000:
+		ad->sysclk = freq;
+		break;
+	default:
+		pr_err("invalid sysclk\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+#define AD1939_RATES	\
+	(SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
+	 SNDRV_PCM_RATE_192000)
+
+#define AD1939_FORMATS	\
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops ad1939_ops = {
+	.hw_params = ad1939_hw_params,
+	.digital_mute = ad1939_digmute,
+	.set_sysclk = ad1939_set_dai_sysclk,
+	.set_fmt = ad1939_set_dai_fmt,
+};
+
+struct snd_soc_dai ad1939_dai = {
+	.name = "AD1939",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 4,	/* 4/8 in single/dualline TDM */
+		.rates = AD1939_RATES,
+		.formats = AD1939_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 4,	/* yes, 2 DACs! */
+		.rates = AD1939_RATES,
+		.formats = AD1939_FORMATS,},
+	.ops = &ad1939_ops,
+};
+EXPORT_SYMBOL_GPL(ad1939_dai);
+
+
+static int ad1939_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct ad1939_setup_data *setup = socdev->codec_data;
+	struct ad1939_private *ad = codec->private_data;
+	unsigned char r0, r1;
+	int ret;
+
+	codec->owner = THIS_MODULE;
+	codec->set_bias_level = ad1939_set_bias_level;
+	codec->dai = &ad1939_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = ARRAY_SIZE(ad1939_regcache);
+	codec->reg_cache = kzalloc(sizeof(ad1939_regcache), GFP_KERNEL);
+	if (!codec->reg_cache)
+		return -ENOMEM;
+
+	/* "initialize" the codec with default data */
+	for (r0 = 0; r0 < AD1939_REGCOUNT; r0++)
+		ad1939_write(codec, r0, ad1939_regcache[r0]);
+
+	/*
+	 * remember TDM mode and setup clock routing
+	 */
+	ad->tdm_mode = setup->tdm_mode;
+	/* use default TDM mode if noone wants one */
+	if ((ad->tdm_mode > AD1939_TDM_MODE_DUALLINE) || (ad->tdm_mode < 1))
+		ad->tdm_mode = AD1939_TDM_MODE_TDM;
+
+	r0 = ad1939_read(codec, AD1939_PLLCTL0) & ~(3<<5);
+	r1 = ad1939_read(codec, AD1939_PLLCTL1) & 3;
+
+	r0 |= (setup->pll_src & 3) << 5;
+	r0 |= (1<<7);	/* enable internal master clock (i.e. the DAC/ADCs) */
+	r1 |= setup->dac_adc_clksrc & 3;
+	ad1939_write(codec, AD1939_PLLCTL0, r0);
+	ad1939_write(codec, AD1939_PLLCTL1, r1);
+
+	/* Bitclock sources for the ADC and DAC I2S interfaces */
+	r0 = ad1939_read(codec, AD1939_DACCTL1);
+	r1 = ad1939_read(codec, AD1939_ADCCTL2);
+	r0 &= ~AD1939_BCLKSRC_DAC_PLL;
+	r1 &= ~AD1939_BCLKSRC_ADC_PLL;
+	r0 |= setup->dac_adc_clksrc & AD1939_BCLKSRC_DAC_PLL;
+	r1 |= setup->dac_adc_clksrc & AD1939_BCLKSRC_ADC_PLL;
+	ad1939_write(codec, AD1939_DACCTL1, r0);
+	ad1939_write(codec, AD1939_ADCCTL2, r1);
+
+	ad1939_add_controls(codec);
+	ad1939_set_bias_level(codec, SND_SOC_BIAS_ON);
+
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		pr_err("failed to register card\n");
+		goto card_err;
+	}
+
+	return 0;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+	kfree(codec->reg_cache);
+	return ret;
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver ad1939_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 *ad1939_socdev;
+
+static int ad1939_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+	struct snd_soc_device *socdev = ad1939_socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct ad1939_setup_data *setup = socdev->codec_data;
+	struct i2c_client *i2c;
+	int ret;
+
+	if (addr != setup->i2c_address)
+		return -ENODEV;
+
+	client_template.adapter = adap;
+	client_template.addr = addr;
+
+	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+	if (i2c == NULL) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
+	ret = i2c_attach_client(i2c);
+	if (ret < 0) {
+		pr_err("failed to attach codec at addr %x\n", addr);
+		goto err;
+	}
+
+	codec->read = ad1939_i2c_read;
+	codec->write = ad1939_i2c_write;
+
+	ret = ad1939_init(socdev);
+	if (ret < 0) {
+		pr_err("failed to initialise AD1939 codec\n");
+		goto err;
+	}
+	return ret;
+
+err:
+	kfree(codec);
+	kfree(i2c);
+	return ret;
+}
+
+static int ad1939_i2c_detach(struct i2c_client *client)
+{
+	struct snd_soc_codec* codec = i2c_get_clientdata(client);
+
+	i2c_detach_client(client);
+	kfree(codec->reg_cache);
+	kfree(client);
+
+	return 0;
+}
+
+static int ad1939_i2c_attach(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, ad1939_codec_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver ad1939_i2c_driver = {
+	.driver = {
+		.name = "AD1939",
+		.owner = THIS_MODULE,
+	},
+	.id =	103, /* I2C_DRIVERID_AD1939 */
+	.attach_adapter = ad1939_i2c_attach,
+	.detach_client =  ad1939_i2c_detach,
+	.command =        NULL,
+};
+
+static struct i2c_client client_template = {
+	.name =   "AD1939",
+	.driver = &ad1939_i2c_driver,
+};
+#endif	/* I2C */
+
+static int ad1939_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct ad1939_setup_data *setup;
+	struct snd_soc_codec *codec;
+	struct ad1939_private *ad;
+	int ret;
+
+	ret = -ENOMEM;
+	setup = socdev->codec_data;
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		goto out;
+
+	ad = kzalloc(sizeof(struct ad1939_private), GFP_KERNEL);
+	if (ad == NULL) {
+		kfree(codec);
+		goto out;
+	}
+	ad->codec = codec;
+	codec->private_data = ad;
+	socdev->card->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	ad1939_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	if (setup->i2c_address) {
+		normal_i2c[0] = setup->i2c_address;
+		ret = i2c_add_driver(&ad1939_i2c_driver);
+		if (ret != 0)
+			pr_err("can't add i2c driver");
+	}
+#endif
+	ret = 0;
+out:
+	return ret;
+}
+
+static int ad1939_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	if (codec->control_data)
+		ad1939_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&ad1939_i2c_driver);
+#endif
+	kfree(codec->private_data);
+	kfree(codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ad1939 = {
+	.probe = 	ad1939_probe,
+	.remove = 	ad1939_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ad1939);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ASoC AD1939 I2S Codec driver");
+MODULE_AUTHOR("Manuel Lauss <mlau@msc-ge.com>");
diff --git a/sound/soc/codecs/ad1939.h b/sound/soc/codecs/ad1939.h
new file mode 100644
index 0000000..464a70a
--- /dev/null
+++ b/sound/soc/codecs/ad1939.h
@@ -0,0 +1,70 @@
+/*
+ * AD1939 I2S codec
+ *
+ */
+
+#ifndef _AD1939_H_
+#define _AD1939_H_
+
+#define AD1939_PLLCTL0	0x00
+#define AD1939_PLLCTL1	0x01
+#define AD1939_DACCTL0	0x02
+#define AD1939_DACCTL1	0x03
+#define AD1939_DACCTL2	0x04
+#define AD1939_DACMUTE	0x05
+#define AD1939_VOL1L	0x06
+#define AD1939_VOL1R	0x07
+#define AD1939_VOL2L	0x08
+#define AD1939_VOL2R	0x09
+#define AD1939_VOL3L	0x0A
+#define AD1939_VOL3R	0x0B
+#define AD1939_VOL4L	0x0C
+#define AD1939_VOL4R	0x0D
+#define AD1939_ADCCTL0	0x0E
+#define AD1939_ADCCTL1	0x0F
+#define AD1939_ADCCTL2	0x10
+
+#define AD1939_REGCOUNT	0x11
+
+/*
+ * AD1939 setup data
+ */
+
+/* TDM modes. Have a look at the manual to understand what these do. */
+#define AD1939_TDM_MODE_TDM		1
+#define AD1939_TDM_MODE_AUX		2
+#define AD1939_TDM_MODE_DUALLINE	3
+
+/* Master PLL clock source, select one */
+#define AD1939_PLL_SRC_MCLK		0	/* external clock */
+#define AD1939_PLL_SRC_DACLRCK		1	/* get from DAC LRCLK */
+#define AD1939_PLL_SRC_ADCLRCK		2	/* get from ADC LRCLK */
+
+/* clock sources for ADC, DAC. Refer to the manual for more information
+ * (for 192000kHz modes, internal PLL _MUST_ be used). Select one for ADC
+ * and DAC.
+ */
+#define AD1939_CLKSRC_DAC_PLL		0	/* DAC clocked by int. PLL */
+#define AD1939_CLKSRC_DAC_MCLK		(1<<0)	/* DAC clocked by ext. MCK */
+#define AD1939_CLKSRC_ADC_PLL		0	/* ADC clocked by int. PLL */
+#define AD1939_CLKSRC_ADC_MCLK		(1<<1)	/* ADC clocked by ext. MCK */
+
+/* I2S Bitclock sources for DAC and ADC I2S interfaces.
+ * OR it to ad1939_setup_data.dac_adc_clksrc. Select one for ADC and DAC.
+ */
+#define AD1939_BCLKSRC_DAC_EXT		0	/* DAC I2SCLK from DBCLK pin */
+#define AD1939_BCLKSRC_DAC_PLL		(1<<6)	/* DAC I2SCLK from int. PLL */
+#define AD1939_BCLKSRC_ADC_EXT		0	/* DAC I2SCLK from DBCLK pin */
+#define AD1939_BCLKSRC_ADC_PLL		(1<<7)	/* DAC I2SCLK from int. PLL */
+
+struct ad1939_setup_data {
+	unsigned char i2c_address;
+	unsigned char tdm_mode;		/* one of AD1939_TDM_MODE_* */
+	unsigned char pll_src;		/* one of AD1939_PLL_SRC_* */
+	unsigned char dac_adc_clksrc;	/* AD1939_{B,}CLKSRC_* or'ed together */
+};
+
+extern struct snd_soc_codec_device soc_codec_dev_ad1939;
+extern struct snd_soc_dai ad1939_dai;
+
+#endif
diff --git a/sound/soc/codecs/cs4251x.c b/sound/soc/codecs/cs4251x.c
new file mode 100644
index 0000000..867e8f3
--- /dev/null
+++ b/sound/soc/codecs/cs4251x.c
@@ -0,0 +1,755 @@
+/*
+ * cs4251x.h -- Cirrus/Crystal CS42516/42518 I2C Codec Soc Audio driver
+ *
+ * Copyright 2007 MSC Vertriebsges.m.b.h, <mlau@msc-ge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The CS4251X is quite complex; please have a look at the manual before
+ * using it: http:///www.cirrus.com/en/pubs/proDatasheet/CS42518_F1.pdf
+ */
+
+/*
+ * FIXME: A LOT of this code assumes that the CODEC_SP interface is used
+ *	  for playback and the SAI_SP for recording (because this is the
+ *	  configuration I'm working with).  Look  at  the hw_params
+ *	  function for example (setting the Fs ratio based on OMCK)
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "cs4251x.h"
+
+#define AUDIO_NAME "cs4251x"
+
+/* codec private data */
+struct cs_priv {
+	struct snd_soc_codec	*codec;
+	struct work_struct	irq_work;
+	unsigned long sysclk;
+	int irq;
+};
+
+#define FS_RATIO_CNT	3
+/* oversampling clock ratios.
+ * OMCK/ratio = samplerate.
+ */
+static const unsigned int cs_fs_ratios[FS_RATIO_CNT] = {
+	512, 256, 128
+};
+
+/* codec register values after reset */
+static const u16 cs4251x_regcache[CS4251X_REGNUM] __devinitdata = {
+	0x00, 0xE3, 0x81, 0x00, 0x40, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x09, 0x09, 0x09, 0x09, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+	0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+};
+
+/*
+ * write to the cs4251x register space
+ */
+static int cs_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
+			     unsigned int value)
+{
+	struct i2c_msg msg;
+	struct i2c_client *c;
+	u16 *cache = codec->reg_cache;
+	u8 data[2];
+	int ret;	
+
+	reg &= 0x7f;	/* kill the auto-addr-increment bit */
+
+	/* exclude read-only regs */
+	switch (reg) {
+	case 0 ... 1:
+	case 0x07 ... 0x0c:
+	case 0x20:
+	case 0x25:
+	case 0x26:
+	case 0x30 ... 0x51:
+		return 0;
+	}
+
+	if (value == cache[reg])
+		return 0;
+
+	c = (struct i2c_client *)codec->control_data;
+	data[0] = reg & 0xff;
+	data[1] = value & 0xff;
+	msg.addr = c->addr;
+	msg.flags = 0;	/* write */
+	msg.buf = &data[0];
+	msg.len = 2;
+
+	ret = i2c_transfer(c->adapter, &msg, 1);
+	if (ret == 1)
+		cache[reg] = value;
+	return (ret == 1) ? 0 : -EIO;
+}
+
+static unsigned int cs_i2c_read(struct snd_soc_codec *codec,
+				     unsigned int reg)
+{
+	struct i2c_msg msg[2];
+	struct i2c_client *c;
+	u8 data[2];
+	u16 *cache = codec->reg_cache;
+	int ret;
+
+	/* check for the uncachables */
+	switch (reg) {
+	case 1:
+	case 0x07 ... 0x0c:
+	case 0x20:
+	case 0x25:
+	case 0x26:
+	case 0x30 ... 0x51:
+		break;
+	default:
+		return cache[reg];
+	}
+
+	c = (struct i2c_client *)codec->control_data;
+	data[0] = reg & 0xff;
+	msg[0].addr = c->addr;
+	msg[0].flags = 0;
+	msg[0].buf = &data[0];
+	msg[0].len = 1;
+	
+	msg[1].addr = c->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].buf = &data[1];
+	msg[1].len = 1;
+
+	ret = i2c_transfer(c->adapter, &msg[0], 2);
+	return (ret == 2) ? data[1] : -EIO;
+}
+
+int cs4251x_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	return codec->write(codec, reg, value);
+}
+EXPORT_SYMBOL_GPL(cs4251x_write);
+
+unsigned int cs4251x_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+	return codec->read(codec, reg);
+}
+EXPORT_SYMBOL_GPL(cs4251x_read);
+
+/**
+ * cs4251x_gpio_set - set gpio output level (high/low)
+ * @codec:	snd_soc_codec structure for this codec.
+ * @gpio:	index of GPIO pin to set (0-6).
+ * @val:	0 for low-leve, 1 for high-level.
+ */
+void cs4251x_gpio_set(struct snd_soc_codec *codec, unsigned char gpio, 
+			unsigned char val)
+{
+	unsigned char v;
+
+	if (gpio > 6)
+		return;
+
+	v = cs4251x_read(codec, CS4251X_GPIO_0 + gpio);
+	v &= 0x3f;
+	if (val)
+		v |= 3 << 6;	/* GPO, high level */
+	else	
+		v |= 2 << 6;	/* GPO, low level */
+	cs4251x_write(codec, CS4251X_GPIO_0 + gpio, v);
+}
+EXPORT_SYMBOL_GPL(cs4251x_gpio_set);
+
+/**
+ * cs4251x_gpio_mode - set gpio/rxp pin mode.
+ * @codec:	snd_soc_codec structure for this codec.
+ * @gpio:	index of GPIO pin to set (0-6).
+ * @val:	see GPIO_MODE_xxx constants.
+ */
+void cs4251x_gpio_mode(struct snd_soc_codec *codec, unsigned char gpio,
+			unsigned char mode, unsigned char polarity,
+			unsigned char funcmode)
+{
+	unsigned char v;
+
+	if (unlikely(gpio > 6))
+		return;
+
+	switch (mode)
+	{
+	case CS4251X_GPIO_MODE_RXP:	v = (0 << 6); break;
+	case CS4251X_GPIO_MODE_GPOHI:	v = (3 << 6); break;
+	case CS4251X_GPIO_MODE_GPOLOW:
+		v = (2 << 6) | (funcmode & 1) | ((funcmode & 1) << 1);
+		break;
+	case CS4251X_GPIO_MODE_MUTE:
+		v = (1 << 6) | ((polarity & 1) << 5) | 
+			(funcmode & CS4251X_FUNCMODE_MUTE_MASK);
+		break;
+	default:
+		return;
+	}
+	cs4251x_write(codec, CS4251X_GPIO_0 + gpio, v);
+}
+EXPORT_SYMBOL_GPL(cs4251x_gpio_mode);
+
+static void cs_irq_work(struct work_struct *data)
+{
+	struct cs_priv *cs = 
+		container_of(data, struct cs_priv, irq_work);
+	unsigned char r;
+
+	r = cs4251x_read(cs->codec, CS4251X_IRQSTAT);
+	pr_debug("IRQ: istat 0x%02x", r);
+}
+
+static irqreturn_t cs_irq(int irq, void *dev_id)
+{
+	struct cs_priv *cs = dev_id;
+	schedule_work(&cs->irq_work);
+	return IRQ_HANDLED;
+}
+
+static const char *cs_vol_transition[] = {
+	"Immediate", "Zero-Cross", "Soft-Ramp", 
+	"Soft-Ramp on Zero-Crossings"
+};
+static const char *cs_off_on[] = {"Off", "On"};
+
+static const struct soc_enum cs_enum[] = {
+      /*SOC_ENUM_SINGLE(reg, startbit, choicecount, choices-texts), */
+	SOC_ENUM_SINGLE(CS4251X_VOLTRANSCTL, 4, 4, cs_vol_transition),
+	SOC_ENUM_SINGLE(CS4251X_VOLTRANSCTL, 6, 2, cs_off_on),
+	SOC_ENUM_SINGLE(CS4251X_VOLTRANSCTL, 3, 2, cs_off_on),
+	SOC_ENUM_SINGLE(CS4251X_VOLTRANSCTL, 1, 2, cs_off_on),
+	SOC_ENUM_SINGLE(CS4251X_VOLTRANSCTL, 0, 2, cs_off_on),
+	SOC_ENUM_SINGLE(CS4251X_FUNCMODE, 1, 2, cs_off_on),
+	SOC_ENUM_SINGLE(CS4251X_FUNCMODE, 0, 2, cs_off_on),
+};
+
+static const struct snd_kcontrol_new cs_snd_controls[] = {
+SOC_DOUBLE_R("Master Playback Volume", CS4251X_L1VOL, CS4251X_R1VOL, 0, 255, 1),
+SOC_DOUBLE_R("Channel 2 Playback Volume", CS4251X_L2VOL, CS4251X_R2VOL, 0, 255, 1),
+SOC_DOUBLE_R("Channel 3 Playback Volume", CS4251X_L3VOL, CS4251X_R3VOL, 0, 255, 1),
+SOC_DOUBLE_R("Channel 4 Playback Volume", CS4251X_L4VOL, CS4251X_R4VOL, 0, 255, 1),
+
+SOC_DOUBLE_R("Capture Volume", CS4251X_LADCGAIN, CS4251X_RADCGAIN, 0, 255, 0),
+
+SOC_ENUM("Volume Transition", cs_enum[0]),
+SOC_ENUM("Soft Volume Ramp-Up after Error", cs_enum[3]),
+SOC_ENUM("Soft Volume Ramp-Down before Filter Change", cs_enum[4]),
+SOC_ENUM("DAC Auto-Mute", cs_enum[2]),
+SOC_ENUM("DAC Deemphasis", cs_enum[5]),
+SOC_ENUM("Receiver Deemphasis", cs_enum[6]),
+
+};
+
+/* add non dapm controls */
+static int cs_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(cs_snd_controls); i++) {
+		err = snd_ctl_add(codec->card,
+		   snd_soc_cnew(&cs_snd_controls[i], codec, NULL));
+
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int cs_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct cs_priv *cs = codec->private_data;
+	unsigned long rate;
+	unsigned char funcmode;
+	int i;
+
+	pr_debug("cs_hw_params");
+
+	rate = params->rate_num / params->rate_den;
+	for (i = 0; i < FS_RATIO_CNT; i++) {
+
+		pr_debug("%d sck %lu rat %d res %lu rate %lu", i, cs->sysclk,
+			 cs_fs_ratios[i],
+			 (cs->sysclk / cs_fs_ratios[i]), rate);
+
+		if ((cs->sysclk / cs_fs_ratios[i]) == rate) {
+			/* found a suitable ratio, program it */
+			funcmode = cs4251x_read(codec, CS4251X_FUNCMODE);
+			/* set both CODEC_SP and SAI_SP */
+			pr_debug("funcmode: was    %x", funcmode);
+			funcmode &= ~(15<<4);
+			funcmode |= (i<<4) | (i<<6);
+			pr_debug("funcmode: is now %x", funcmode);
+			cs4251x_write(codec, CS4251X_FUNCMODE, funcmode);
+			return 0;
+		}
+	}
+	/* eek, nothing suitable found */
+	return -EINVAL;
+}
+
+static int cs_mute(struct snd_soc_dai *dai, int mute)
+{
+	cs4251x_write(dai->codec, CS4251X_MUTE, mute ? 0xff : 0);
+	return 0;
+}
+
+/*
+ * someone wants to tell us the OMCK frequency we're running with.
+ */
+static int cs_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs_priv *cs = codec->private_data;
+	unsigned char ckctl;
+	unsigned long rates;
+
+	pr_debug("cs_set_dai_sysclk(%d, %ul, %d)", clk_id, freq, dir);
+
+	ckctl = cs4251x_read(codec, CS4251X_CLKCTL);
+	ckctl &= ~(3<<4);
+	
+	/* NOTE: these clock rates come from the datasheet... */
+	switch (freq) {
+	case 11289600:
+		rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |
+			SNDRV_PCM_RATE_88200;
+		break;
+	case 12288000:
+		rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000;
+		break;
+	case 16934400:
+	case 18432000:
+		/* well, none that ALSA has #defines for:
+		 * 33075Hz, 66150Hz, 132300Hz, 36, 72, 144kHz
+		 */
+		rates = 0;
+		ckctl |= (1<<4);
+		break;
+	case 22579200:
+		rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |
+			SNDRV_PCM_RATE_176400;
+		ckctl |= (2<<4);
+		break;
+	case 24576000:
+		rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+			SNDRV_PCM_RATE_192000;
+		ckctl |= (2<<4);
+		break;
+	default:
+		pr_debug("invalid sysclk %uHz", freq);
+		return -EINVAL;
+	}
+
+	/* tell the codec about the new OMCK range */
+	cs4251x_write(codec, CS4251X_CLKCTL, ckctl);
+	cs->sysclk = freq;	/* need to know in hw_params */
+
+#if 0	/* does not work, boooooooo */
+	/* update the DAI's supported rates mask */
+	codec_dai->playback.rates = rates;
+	codec_dai->capture.rates = rates;
+#endif
+	return 0;
+}
+
+/*
+ * set Interface Format.
+ * FIXME: this code applies the same values to the CODEC_SP and SAI_SP
+ *	 interfaces, although technically they're independent.
+ */
+static int cs_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 iffmt, misc;
+
+	pr_debug("cs_set_dai_fmt(0x%08x)", fmt);
+
+	iffmt = cs4251x_read(codec, CS4251X_IFFMT);
+	misc = cs4251x_read(codec, CS4251X_MISCCTL);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		misc |= 3;	/* CODEC_SP and SAI in master mode */
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		misc &= ~2;	/* CODEC_SP_and SAI in slave mode */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iffmt &= ~0xc0;
+		iffmt |= 1 << 6;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		iffmt &= ~0xc0;
+		iffmt |= 1 << 7;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iffmt &= ~0xc0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface */
+	cs4251x_write(codec, CS4251X_IFFMT, iffmt);
+	cs4251x_write(codec, CS4251X_MISCCTL, misc);
+
+	return 0;
+}
+
+static int cs_bias_level(struct snd_soc_codec *codec,
+			 enum snd_soc_bias_level event)
+{
+	switch (event)
+	{
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		cs4251x_write(codec, CS4251X_PM, 0);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+	case SND_SOC_BIAS_OFF:
+		/* all DAC/ADCs off, power down */
+		cs4251x_write(codec, CS4251X_PM, 0xff);
+		break;
+	}
+	codec->bias_level = event;
+	return 0;
+}
+
+/* FIXME: really depends on sysclk! */
+#define CS4251X_RATES	\
+	(SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |	\
+	 SNDRV_PCM_RATE_192000)
+
+#define CS4251X_FORMATS	\
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+/*
+ * This is slightly incorrect: The codec has 4 CODEC_SP interfaces (each
+ * connected to a DAC; 1st also connected to ADCs) and 1 SAI_SP interface
+ * (connected to ADC and SPDIF receiver). The 4 CODEC_SP and the SAI_SP
+ * can be configured independently.
+ */
+struct snd_soc_dai cs4251x_dai = {
+	.name = "CS4251x",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = CS4251X_RATES,    /* depends on clock source */
+		.formats = CS4251X_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = CS4251X_RATES,
+		.formats = CS4251X_FORMATS,},
+	.ops = {
+		.hw_params = cs_hw_params,
+		.digital_mute = cs_mute,
+		.set_sysclk = cs_set_dai_sysclk,
+		.set_fmt = cs_set_dai_fmt,
+	}
+};
+EXPORT_SYMBOL_GPL(cs4251x_dai);
+
+/*
+ * initialise the cs42516/8/28 codec.
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int cs_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	struct cs_priv *cs = codec->private_data;
+	struct cs4251x_setup_data *setup = socdev->codec_data;
+	int reg, ret;
+
+	codec->owner = THIS_MODULE;
+	codec->set_bias_level = cs_bias_level;
+	codec->dai = &cs4251x_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = ARRAY_SIZE(cs4251x_regcache);
+	codec->reg_cache = kzalloc(sizeof(cs4251x_regcache), GFP_KERNEL);
+	if (!codec->reg_cache)
+		return -ENOMEM;
+
+	ret = -ENODEV;
+	/* init the chip, populate regcache */
+	for (reg = 1; reg < CS4251X_REGNUM; reg++)
+		cs4251x_write(codec, reg, cs4251x_regcache[reg]);
+
+	/* identify the chip */
+	reg = cs4251x_read(codec, CS4251X_CHIPID);
+	if (unlikely(reg < 0))
+		goto pcm_err;
+
+	switch (reg & 0xf0)
+	{
+	case 0xe0:
+		codec->name = "CS42518";
+		break;
+	case 0xf0:
+		codec->name = "CS42516/CS42528";
+		break;
+	default:
+		pr_info("unknown chip-id %02x; skipping", reg);
+		goto pcm_err;
+	}
+
+	/* Hello, World! */
+	printk(KERN_INFO "%s Rev. %c I2S Audio Codec\n",
+		codec->name, 'A' - 1 + (reg & 15));
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1,
+			       SNDRV_DEFAULT_STR1);
+	if (unlikely(ret < 0)) {
+		pr_err("failed to create pcms");
+		goto pcm_err;
+	}
+
+	cs_add_controls(codec);
+	cs_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	ret = snd_soc_init_card(socdev);
+	if (unlikely(ret < 0)) {
+		pr_err("failed to register card\n");
+		goto card_err;
+	}
+
+	cs->irq = setup->irq;
+	if (cs->irq != CS4251X_NOIRQ) {
+		INIT_WORK(&cs->irq_work, cs_irq_work);
+		reg = request_irq(cs->irq, cs_irq, 0, "cs4251x", cs);
+		if (unlikely(reg)) {
+			pr_info("irq attach failed");
+			cs->irq = CS4251X_NOIRQ;
+		}
+	}
+
+	return 0;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+	return ret;
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver cs_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 *cs_socdev;
+
+static int cs_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+	struct snd_soc_device *socdev = cs_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct cs4251x_setup_data *setup = socdev->codec_data;
+	struct i2c_client *i2c;
+	int ret;
+
+	if (addr != setup->i2c_address)
+		return -ENODEV;
+
+	client_template.adapter = adap;
+	client_template.addr = addr;
+
+	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+	if (unlikely(i2c == NULL)) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
+	ret = i2c_attach_client(i2c);
+	if (unlikely(ret < 0)) {
+		pr_err("failed to attach codec at addr %x", addr);
+		goto err;
+	}
+
+	codec->read = cs_i2c_read;
+	codec->write = cs_i2c_write;
+
+	ret = cs_init(socdev);
+	if (unlikely(ret < 0)) {
+		pr_err("failed to initialise CS4251x");
+		goto err;
+	}
+	return ret;
+
+err:
+	kfree(codec);
+	kfree(i2c);
+	return ret;
+}
+
+static int cs_i2c_detach(struct i2c_client *client)
+{
+	struct snd_soc_codec *codec = i2c_get_clientdata(client);
+	struct cs_priv *cs = codec->private_data;
+
+	if (cs->irq != CS4251X_NOIRQ) {
+		free_irq(cs->irq, cs);
+		flush_scheduled_work();
+	}
+
+	i2c_detach_client(client);
+	kfree(codec->reg_cache);
+	kfree(client);
+
+	return 0;
+}
+
+static int cs_i2c_attach(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, cs_codec_probe);
+}
+
+static struct i2c_driver cs_i2c_driver = {
+	.driver = {
+		.name	= "cs4251x",
+		.owner	= THIS_MODULE,
+	},
+	.id		= 102, /* I2C_DRIVERID_CS4251X */
+	.attach_adapter	= cs_i2c_attach,
+	.detach_client	= cs_i2c_detach,
+};
+
+static struct i2c_client client_template = {
+	.name =   "CS425XX",
+	.driver = &cs_i2c_driver,
+};
+#endif
+
+static int cs_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct cs4251x_setup_data *setup = socdev->codec_data;
+	struct snd_soc_codec *codec;
+	struct cs_priv *cs;
+	int ret;
+
+	ret = -ENOMEM;
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		goto out;
+
+	cs = kzalloc(sizeof(struct cs_priv), GFP_KERNEL);
+	if (cs == NULL) {
+		kfree(codec);
+		goto out;
+	}
+	ret = 0;
+
+	cs->codec = codec;
+	codec->private_data = cs;
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+	cs_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	if (setup->i2c_address) {
+		normal_i2c[0] = setup->i2c_address;
+		ret = i2c_add_driver(&cs_i2c_driver);
+		if (ret)
+			pr_err("can't add i2c driver");
+	}
+#endif
+
+out:
+	return ret;
+}
+
+/* power down chip */
+static int cs_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec->control_data)
+		cs_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&cs_i2c_driver);
+#endif
+	kfree(codec->private_data);
+	kfree(codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_cs4251x = {
+	.probe		= cs_probe,
+	.remove		= cs_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_cs4251x);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ASoC CS42516/42518 I2S codec driver");
+MODULE_AUTHOR("Manuel Lauss <mlau@msc-ge.com>");
diff --git a/sound/soc/codecs/cs4251x.h b/sound/soc/codecs/cs4251x.h
new file mode 100644
index 0000000..9f52038
--- /dev/null
+++ b/sound/soc/codecs/cs4251x.h
@@ -0,0 +1,174 @@
+/*
+ * cs4251x.h -- Cirrus/Crystal CS42516/42518 I2C Codec Soc Audio driver
+ *
+ * Copyright 2007 MSC Vertriebsges.m.b.h, <mlau@msc-ge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The CS4251X is quite complex; please have a look at the manual before
+ * using it: http:///www.cirrus.com/en/pubs/proDatasheet/CS42518_F1.pdf
+ *
+ */
+
+#ifndef _CS4251X_H
+#define _CS4251X_H
+
+struct cs4251x_setup_data {
+	unsigned short i2c_address;
+	unsigned int irq;	/* yeah, the CS4251X has an IRQ line! */
+};
+
+#define CS4251X_NOIRQ	(-1)
+
+/*
+ * Codec clock control
+ * see manual pages 53-54, chapter 6.7
+ */
+
+/* always use OMCK clock */
+#define CS4251X_CLKSRC_OMCK		(0 << 1)
+/* always use PLL recovered clk */
+#define CS4251X_CLKSRC_PLL		(1 << 1)
+/* keep current; on unlock stay with OMCK forever */
+#define CS4251X_CLKSRC_CURRENT_OMCK	(2 << 1)
+/* use PLL when locked, otherwise OMCK */
+#define CS4251X_CLKSRC_AUTO_PLL_OMCK	(3 << 1)
+#define CS4251X_CLKSRC_MCK_MASK		(3 << 1)
+
+/* PLL input is SPDIF receiver */
+#define CS4251X_CLKSRC_PLL_SPDIF	0
+/* PLL input is SAI_LRCLK */
+#define CS4251X_CLKSRC_PLL_LRCLK	(1 << 2)	
+
+/* force lock on PLL. CLKSRC_OMCK MUST be used! */
+#define CS4251X_CLKSRC_PLL_FORCE_LOCK	(1 << 0)
+
+#define CS4251X_CLKSRC_RMCK_DIV_1	(0 << 7)
+#define CS4251X_CLKSRC_RMCK_DIV_2	(1 << 7)
+#define CS4251X_CLKSRC_RMCK_DIV_4	(2 << 7)
+#define CS4251X_CLKSRC_RMCK_MUL_2	(3 << 7)
+
+#define CS4251X_CLKSRC_OMCK_112896MHZ	(0 << 4)
+#define CS4251X_CLKSRC_OMCK_122880MHZ	(0 << 4)
+#define CS4251X_CLKSRC_OMCK_169344MHZ	(1 << 4)
+#define CS4251X_CLKSRC_OMCK_184320MHZ	(1 << 4)
+#define CS4251X_CLKSRC_OMCK_225792MHZ	(2 << 4)
+#define CS4251X_CLKSRC_OMCK_245760MHZ	(2 << 4)
+#define CS4251X_CLKSRC_OMCK_FMASK	(3 << 4)
+
+/*
+ * ADC serial interface flags
+ * See manual page 49, (ch 6.4.3)
+ */
+/* ADC data on CX_SDOUT, clock provided by CODEC_SP,
+ * SPDIF data on SAI_SDOUT
+ */
+#define CS4251X_ADCDAI_CXSDOUT_CODECSP_CLK	(0 << 2)
+/* ADC data on CX_SDOUT, clock provided by SAI_SP.
+ * SPDIF data on SAI_SDOUT
+ */
+#define CS4251X_ADCDAI_CXSDOUT_SAISP_CLK	(1 << 2)
+/* ADC data on SAI_SDOUT, clock provided by SAI_SP.
+ * No SPDIF data
+ */
+#define CS4251X_ADCDAI_SAISDOUT_SAISP_CLK	(2 << 2)
+
+/** miscctl flags */
+/* SAI interface is I2S master/slave */
+#define CS4251X_MISC_SAISP_MASTER	(1 << 0)
+#define CS4251X_MISC_SAISP_SLAVE	0
+/* CODEC_SP interface is I2S master/slave */
+#define CS4251X_MISC_CODECSP_MASTER	(1 << 1)
+#define CS4251X_MISC_CODECSP_SLAVE	0
+
+#define CS4251X_MISC_HIGHPASS_FREEZE	(1 << 2)
+
+#define CS4251X_MISC_DAC_FAST_ROLLOFF	(1 << 3)
+#define CS4251X_MISC_DAC_SLOW_ROLLOFF	0
+
+#define CS4251X_MISC_RMCK_HIGHZ		(1 << 6)
+
+/** CS4251X internal registers **/
+
+/* register 0 does not exist */
+#define CS4251X_CHIPID		0x01
+#define CS4251X_PM		0x02
+#define CS4251X_FUNCMODE	0x03
+#define CS4251X_IFFMT		0x04
+#define CS4251X_MISCCTL		0x05
+#define CS4251X_CLKCTL		0x06
+#define CS4251X_PLLOMCKRATIO	0x07
+#define CS4251X_RCVSTAT		0x08
+#define CS4251X_VOLTRANSCTL	0x0D
+#define CS4251X_MUTE		0x0E
+#define CS4251X_L1VOL		0x0F
+#define CS4251X_R1VOL		0x10
+#define CS4251X_L2VOL		0x11
+#define CS4251X_R2VOL		0x12
+#define CS4251X_L3VOL		0x13
+#define CS4251X_R3VOL		0x14
+#define CS4251X_L4VOL		0x15
+#define CS4251X_R4VOL		0x16
+#define CS4251X_LADCGAIN	0x1C
+#define CS4251X_RADCGAIN	0x1D
+#define CS4251X_RCVMODECTL	0x1E
+#define CS4251X_RCVMODECTL2	0x1F
+#define CS4251X_IRQSTAT		0x20
+#define CS4251X_IRQMASK		0x21
+#define CS4251X_MUTEC		0x28
+#define CS4251X_GPIO_0		0x29
+/* there are more, but irrelevant for now ;-) */
+#define CS4251X_REGNUM		0x52
+
+/*
+ * GPIO control
+ */
+#define CS4251X_RXP_0			7
+#define CS4251X_RXP_1			6
+#define CS4251X_RXP_2			5
+#define CS4251X_RXP_3			4
+#define CS4251X_RXP_4			3
+#define CS4251X_RXP_5			2
+#define CS4251X_RXP_6			1
+#define CS4251X_RXP_7			0
+
+#define CS4251X_GPIO_MODE_RXP		0
+#define CS4251X_GPIO_MODE_MUTE		1
+#define CS4251X_GPIO_MODE_GPOLOW	2
+#define CS4251X_GPIO_MODE_GPOHI		3
+
+#define CS4251X_GPIO_MUTEPOL_LOW	0
+#define CS4251X_GPIO_MUTEPOL_HIGH	1
+
+/* just use as low-level GPO */
+#define CS4251X_FUNCMODE_GPO_DRIVELOW	0
+/* pin indicates ADC overflow */
+#define CS4251X_FUNCMODE_GPO_OVERFLOW	1
+
+/* in mutemode, a bitmask determines which DACs are muted by which RXP
+ * pins.  Please have a look at CS42518_PP5.pdf datasheet, page 71 for
+ * the matrix */
+#define CS4251X_FUNCMODE_MUTE_MASK	0x1f	
+
+void cs4251x_gpio_set(struct snd_soc_codec *codec, unsigned char gpio, 
+			unsigned char val);
+void cs4251x_gpio_mode(struct snd_soc_codec *codec, unsigned char gpio,
+			unsigned char mode, unsigned char polarity,
+			unsigned char funcmode);
+
+/*
+ * access to the codec registers
+ */
+int cs4251x_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value);
+
+unsigned int cs4251x_read(struct snd_soc_codec *codec, unsigned int reg);
+
+
+/* ASoC DAI */
+extern struct snd_soc_dai cs4251x_dai;
+extern struct snd_soc_codec_device soc_codec_dev_cs4251x;
+
+#endif
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
new file mode 100644
index 0000000..956490d
--- /dev/null
+++ b/sound/soc/codecs/wm2200.c
@@ -0,0 +1,2285 @@
+/*
+ * wm2200.c  --  WM2200 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/fixed.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm2200.h>
+
+#include "wm2200.h"
+
+/* The code assumes DCVDD is generated internally */
+#define WM2200_NUM_CORE_SUPPLIES 2
+static const char *wm2200_core_supply_names[WM2200_NUM_CORE_SUPPLIES] = {
+	"DBVDD",
+	"LDOVDD",
+};
+
+struct wm2200_fll {
+	int fref;
+	int fout;
+	int src;
+	struct completion lock;
+};
+
+/* codec private data */
+struct wm2200_priv {
+	struct regmap *regmap;
+	struct device *dev;
+	struct snd_soc_codec *codec;
+	struct wm2200_pdata pdata;
+	struct regulator_bulk_data core_supplies[WM2200_NUM_CORE_SUPPLIES];
+
+	struct completion fll_lock;
+	int fll_fout;
+	int fll_fref;
+	int fll_src;
+
+	int rev;
+	int sysclk;
+};
+
+static struct reg_default wm2200_reg_defaults[] = {
+	{ 0x000B, 0x0000 },   /* R11    - Tone Generator 1 */ 
+	{ 0x0102, 0x0000 },   /* R258   - Clocking 3 */ 
+	{ 0x0103, 0x0011 },   /* R259   - Clocking 4 */ 
+	{ 0x0111, 0x0000 },   /* R273   - FLL Control 1 */ 
+	{ 0x0112, 0x0000 },   /* R274   - FLL Control 2 */ 
+	{ 0x0113, 0x0000 },   /* R275   - FLL Control 3 */ 
+	{ 0x0114, 0x0000 },   /* R276   - FLL Control 4 */ 
+	{ 0x0116, 0x0177 },   /* R278   - FLL Control 6 */ 
+	{ 0x0117, 0x0004 },   /* R279   - FLL Control 7 */ 
+	{ 0x0119, 0x0000 },   /* R281   - FLL EFS 1 */ 
+	{ 0x011A, 0x0002 },   /* R282   - FLL EFS 2 */ 
+	{ 0x0200, 0x0000 },   /* R512   - Mic Charge Pump 1 */ 
+	{ 0x0201, 0x03FF },   /* R513   - Mic Charge Pump 2 */ 
+	{ 0x0202, 0x9BDE },   /* R514   - DM Charge Pump 1 */ 
+	{ 0x020C, 0x0000 },   /* R524   - Mic Bias Ctrl 1 */ 
+	{ 0x020D, 0x0000 },   /* R525   - Mic Bias Ctrl 2 */ 
+	{ 0x020F, 0x0000 },   /* R527   - Ear Piece Ctrl 1 */ 
+	{ 0x0210, 0x0000 },   /* R528   - Ear Piece Ctrl 2 */ 
+	{ 0x0301, 0x0000 },   /* R769   - Input Enables */ 
+	{ 0x0302, 0x2240 },   /* R770   - IN1L Control */ 
+	{ 0x0303, 0x0040 },   /* R771   - IN1R Control */ 
+	{ 0x0304, 0x2240 },   /* R772   - IN2L Control */ 
+	{ 0x0305, 0x0040 },   /* R773   - IN2R Control */ 
+	{ 0x0306, 0x2240 },   /* R774   - IN3L Control */ 
+	{ 0x0307, 0x0040 },   /* R775   - IN3R Control */ 
+	{ 0x030A, 0x0000 },   /* R778   - RXANC_SRC */ 
+	{ 0x030B, 0x0022 },   /* R779   - Input Volume Ramp */ 
+	{ 0x030C, 0x0180 },   /* R780   - ADC Digital Volume 1L */ 
+	{ 0x030D, 0x0180 },   /* R781   - ADC Digital Volume 1R */ 
+	{ 0x030E, 0x0180 },   /* R782   - ADC Digital Volume 2L */ 
+	{ 0x030F, 0x0180 },   /* R783   - ADC Digital Volume 2R */ 
+	{ 0x0310, 0x0180 },   /* R784   - ADC Digital Volume 3L */ 
+	{ 0x0311, 0x0180 },   /* R785   - ADC Digital Volume 3R */ 
+	{ 0x0400, 0x0000 },   /* R1024  - Output Enables */ 
+	{ 0x0401, 0x0000 },   /* R1025  - DAC Volume Limit 1L */ 
+	{ 0x0402, 0x0000 },   /* R1026  - DAC Volume Limit 1R */ 
+	{ 0x0403, 0x0000 },   /* R1027  - DAC Volume Limit 2L */ 
+	{ 0x0404, 0x0000 },   /* R1028  - DAC Volume Limit 2R */ 
+	{ 0x0409, 0x0000 },   /* R1033  - DAC AEC Control 1 */ 
+	{ 0x040A, 0x0022 },   /* R1034  - Output Volume Ramp */ 
+	{ 0x040B, 0x0180 },   /* R1035  - DAC Digital Volume 1L */ 
+	{ 0x040C, 0x0180 },   /* R1036  - DAC Digital Volume 1R */ 
+	{ 0x040D, 0x0180 },   /* R1037  - DAC Digital Volume 2L */ 
+	{ 0x040E, 0x0180 },   /* R1038  - DAC Digital Volume 2R */ 
+	{ 0x0417, 0x0069 },   /* R1047  - PDM 1 */ 
+	{ 0x0418, 0x0000 },   /* R1048  - PDM 2 */ 
+	{ 0x0500, 0x0000 },   /* R1280  - Audio IF 1_1 */ 
+	{ 0x0501, 0x0008 },   /* R1281  - Audio IF 1_2 */ 
+	{ 0x0502, 0x0000 },   /* R1282  - Audio IF 1_3 */ 
+	{ 0x0503, 0x0000 },   /* R1283  - Audio IF 1_4 */ 
+	{ 0x0504, 0x0000 },   /* R1284  - Audio IF 1_5 */ 
+	{ 0x0505, 0x0001 },   /* R1285  - Audio IF 1_6 */ 
+	{ 0x0506, 0x0001 },   /* R1286  - Audio IF 1_7 */ 
+	{ 0x0507, 0x0000 },   /* R1287  - Audio IF 1_8 */ 
+	{ 0x0508, 0x0000 },   /* R1288  - Audio IF 1_9 */ 
+	{ 0x0509, 0x0000 },   /* R1289  - Audio IF 1_10 */ 
+	{ 0x050A, 0x0000 },   /* R1290  - Audio IF 1_11 */ 
+	{ 0x050B, 0x0000 },   /* R1291  - Audio IF 1_12 */ 
+	{ 0x050C, 0x0000 },   /* R1292  - Audio IF 1_13 */ 
+	{ 0x050D, 0x0000 },   /* R1293  - Audio IF 1_14 */ 
+	{ 0x050E, 0x0000 },   /* R1294  - Audio IF 1_15 */ 
+	{ 0x050F, 0x0000 },   /* R1295  - Audio IF 1_16 */ 
+	{ 0x0510, 0x0000 },   /* R1296  - Audio IF 1_17 */ 
+	{ 0x0511, 0x0000 },   /* R1297  - Audio IF 1_18 */ 
+	{ 0x0512, 0x0000 },   /* R1298  - Audio IF 1_19 */ 
+	{ 0x0513, 0x0000 },   /* R1299  - Audio IF 1_20 */ 
+	{ 0x0514, 0x0000 },   /* R1300  - Audio IF 1_21 */ 
+	{ 0x0515, 0x0001 },   /* R1301  - Audio IF 1_22 */ 
+	{ 0x0600, 0x0000 },   /* R1536  - OUT1LMIX Input 1 Source */ 
+	{ 0x0601, 0x0080 },   /* R1537  - OUT1LMIX Input 1 Volume */ 
+	{ 0x0602, 0x0000 },   /* R1538  - OUT1LMIX Input 2 Source */ 
+	{ 0x0603, 0x0080 },   /* R1539  - OUT1LMIX Input 2 Volume */ 
+	{ 0x0604, 0x0000 },   /* R1540  - OUT1LMIX Input 3 Source */ 
+	{ 0x0605, 0x0080 },   /* R1541  - OUT1LMIX Input 3 Volume */ 
+	{ 0x0606, 0x0000 },   /* R1542  - OUT1LMIX Input 4 Source */ 
+	{ 0x0607, 0x0080 },   /* R1543  - OUT1LMIX Input 4 Volume */ 
+	{ 0x0608, 0x0000 },   /* R1544  - OUT1RMIX Input 1 Source */ 
+	{ 0x0609, 0x0080 },   /* R1545  - OUT1RMIX Input 1 Volume */ 
+	{ 0x060A, 0x0000 },   /* R1546  - OUT1RMIX Input 2 Source */ 
+	{ 0x060B, 0x0080 },   /* R1547  - OUT1RMIX Input 2 Volume */ 
+	{ 0x060C, 0x0000 },   /* R1548  - OUT1RMIX Input 3 Source */ 
+	{ 0x060D, 0x0080 },   /* R1549  - OUT1RMIX Input 3 Volume */ 
+	{ 0x060E, 0x0000 },   /* R1550  - OUT1RMIX Input 4 Source */ 
+	{ 0x060F, 0x0080 },   /* R1551  - OUT1RMIX Input 4 Volume */ 
+	{ 0x0610, 0x0000 },   /* R1552  - OUT2LMIX Input 1 Source */ 
+	{ 0x0611, 0x0080 },   /* R1553  - OUT2LMIX Input 1 Volume */ 
+	{ 0x0612, 0x0000 },   /* R1554  - OUT2LMIX Input 2 Source */ 
+	{ 0x0613, 0x0080 },   /* R1555  - OUT2LMIX Input 2 Volume */ 
+	{ 0x0614, 0x0000 },   /* R1556  - OUT2LMIX Input 3 Source */ 
+	{ 0x0615, 0x0080 },   /* R1557  - OUT2LMIX Input 3 Volume */ 
+	{ 0x0616, 0x0000 },   /* R1558  - OUT2LMIX Input 4 Source */ 
+	{ 0x0617, 0x0080 },   /* R1559  - OUT2LMIX Input 4 Volume */ 
+	{ 0x0618, 0x0000 },   /* R1560  - OUT2RMIX Input 1 Source */ 
+	{ 0x0619, 0x0080 },   /* R1561  - OUT2RMIX Input 1 Volume */ 
+	{ 0x061A, 0x0000 },   /* R1562  - OUT2RMIX Input 2 Source */ 
+	{ 0x061B, 0x0080 },   /* R1563  - OUT2RMIX Input 2 Volume */ 
+	{ 0x061C, 0x0000 },   /* R1564  - OUT2RMIX Input 3 Source */ 
+	{ 0x061D, 0x0080 },   /* R1565  - OUT2RMIX Input 3 Volume */ 
+	{ 0x061E, 0x0000 },   /* R1566  - OUT2RMIX Input 4 Source */ 
+	{ 0x061F, 0x0080 },   /* R1567  - OUT2RMIX Input 4 Volume */ 
+	{ 0x0620, 0x0000 },   /* R1568  - AIF1TX1MIX Input 1 Source */ 
+	{ 0x0621, 0x0080 },   /* R1569  - AIF1TX1MIX Input 1 Volume */ 
+	{ 0x0622, 0x0000 },   /* R1570  - AIF1TX1MIX Input 2 Source */ 
+	{ 0x0623, 0x0080 },   /* R1571  - AIF1TX1MIX Input 2 Volume */ 
+	{ 0x0624, 0x0000 },   /* R1572  - AIF1TX1MIX Input 3 Source */ 
+	{ 0x0625, 0x0080 },   /* R1573  - AIF1TX1MIX Input 3 Volume */ 
+	{ 0x0626, 0x0000 },   /* R1574  - AIF1TX1MIX Input 4 Source */ 
+	{ 0x0627, 0x0080 },   /* R1575  - AIF1TX1MIX Input 4 Volume */ 
+	{ 0x0628, 0x0000 },   /* R1576  - AIF1TX2MIX Input 1 Source */ 
+	{ 0x0629, 0x0080 },   /* R1577  - AIF1TX2MIX Input 1 Volume */ 
+	{ 0x062A, 0x0000 },   /* R1578  - AIF1TX2MIX Input 2 Source */ 
+	{ 0x062B, 0x0080 },   /* R1579  - AIF1TX2MIX Input 2 Volume */ 
+	{ 0x062C, 0x0000 },   /* R1580  - AIF1TX2MIX Input 3 Source */ 
+	{ 0x062D, 0x0080 },   /* R1581  - AIF1TX2MIX Input 3 Volume */ 
+	{ 0x062E, 0x0000 },   /* R1582  - AIF1TX2MIX Input 4 Source */ 
+	{ 0x062F, 0x0080 },   /* R1583  - AIF1TX2MIX Input 4 Volume */ 
+	{ 0x0630, 0x0000 },   /* R1584  - AIF1TX3MIX Input 1 Source */ 
+	{ 0x0631, 0x0080 },   /* R1585  - AIF1TX3MIX Input 1 Volume */ 
+	{ 0x0632, 0x0000 },   /* R1586  - AIF1TX3MIX Input 2 Source */ 
+	{ 0x0633, 0x0080 },   /* R1587  - AIF1TX3MIX Input 2 Volume */ 
+	{ 0x0634, 0x0000 },   /* R1588  - AIF1TX3MIX Input 3 Source */ 
+	{ 0x0635, 0x0080 },   /* R1589  - AIF1TX3MIX Input 3 Volume */ 
+	{ 0x0636, 0x0000 },   /* R1590  - AIF1TX3MIX Input 4 Source */ 
+	{ 0x0637, 0x0080 },   /* R1591  - AIF1TX3MIX Input 4 Volume */ 
+	{ 0x0638, 0x0000 },   /* R1592  - AIF1TX4MIX Input 1 Source */ 
+	{ 0x0639, 0x0080 },   /* R1593  - AIF1TX4MIX Input 1 Volume */ 
+	{ 0x063A, 0x0000 },   /* R1594  - AIF1TX4MIX Input 2 Source */ 
+	{ 0x063B, 0x0080 },   /* R1595  - AIF1TX4MIX Input 2 Volume */ 
+	{ 0x063C, 0x0000 },   /* R1596  - AIF1TX4MIX Input 3 Source */ 
+	{ 0x063D, 0x0080 },   /* R1597  - AIF1TX4MIX Input 3 Volume */ 
+	{ 0x063E, 0x0000 },   /* R1598  - AIF1TX4MIX Input 4 Source */ 
+	{ 0x063F, 0x0080 },   /* R1599  - AIF1TX4MIX Input 4 Volume */ 
+	{ 0x0640, 0x0000 },   /* R1600  - AIF1TX5MIX Input 1 Source */ 
+	{ 0x0641, 0x0080 },   /* R1601  - AIF1TX5MIX Input 1 Volume */ 
+	{ 0x0642, 0x0000 },   /* R1602  - AIF1TX5MIX Input 2 Source */ 
+	{ 0x0643, 0x0080 },   /* R1603  - AIF1TX5MIX Input 2 Volume */ 
+	{ 0x0644, 0x0000 },   /* R1604  - AIF1TX5MIX Input 3 Source */ 
+	{ 0x0645, 0x0080 },   /* R1605  - AIF1TX5MIX Input 3 Volume */ 
+	{ 0x0646, 0x0000 },   /* R1606  - AIF1TX5MIX Input 4 Source */ 
+	{ 0x0647, 0x0080 },   /* R1607  - AIF1TX5MIX Input 4 Volume */ 
+	{ 0x0648, 0x0000 },   /* R1608  - AIF1TX6MIX Input 1 Source */ 
+	{ 0x0649, 0x0080 },   /* R1609  - AIF1TX6MIX Input 1 Volume */ 
+	{ 0x064A, 0x0000 },   /* R1610  - AIF1TX6MIX Input 2 Source */ 
+	{ 0x064B, 0x0080 },   /* R1611  - AIF1TX6MIX Input 2 Volume */ 
+	{ 0x064C, 0x0000 },   /* R1612  - AIF1TX6MIX Input 3 Source */ 
+	{ 0x064D, 0x0080 },   /* R1613  - AIF1TX6MIX Input 3 Volume */ 
+	{ 0x064E, 0x0000 },   /* R1614  - AIF1TX6MIX Input 4 Source */ 
+	{ 0x064F, 0x0080 },   /* R1615  - AIF1TX6MIX Input 4 Volume */ 
+	{ 0x0650, 0x0000 },   /* R1616  - EQLMIX Input 1 Source */ 
+	{ 0x0651, 0x0080 },   /* R1617  - EQLMIX Input 1 Volume */ 
+	{ 0x0652, 0x0000 },   /* R1618  - EQLMIX Input 2 Source */ 
+	{ 0x0653, 0x0080 },   /* R1619  - EQLMIX Input 2 Volume */ 
+	{ 0x0654, 0x0000 },   /* R1620  - EQLMIX Input 3 Source */ 
+	{ 0x0655, 0x0080 },   /* R1621  - EQLMIX Input 3 Volume */ 
+	{ 0x0656, 0x0000 },   /* R1622  - EQLMIX Input 4 Source */ 
+	{ 0x0657, 0x0080 },   /* R1623  - EQLMIX Input 4 Volume */ 
+	{ 0x0658, 0x0000 },   /* R1624  - EQRMIX Input 1 Source */ 
+	{ 0x0659, 0x0080 },   /* R1625  - EQRMIX Input 1 Volume */ 
+	{ 0x065A, 0x0000 },   /* R1626  - EQRMIX Input 2 Source */ 
+	{ 0x065B, 0x0080 },   /* R1627  - EQRMIX Input 2 Volume */ 
+	{ 0x065C, 0x0000 },   /* R1628  - EQRMIX Input 3 Source */ 
+	{ 0x065D, 0x0080 },   /* R1629  - EQRMIX Input 3 Volume */ 
+	{ 0x065E, 0x0000 },   /* R1630  - EQRMIX Input 4 Source */ 
+	{ 0x065F, 0x0080 },   /* R1631  - EQRMIX Input 4 Volume */ 
+	{ 0x0660, 0x0000 },   /* R1632  - LHPF1MIX Input 1 Source */ 
+	{ 0x0661, 0x0080 },   /* R1633  - LHPF1MIX Input 1 Volume */ 
+	{ 0x0662, 0x0000 },   /* R1634  - LHPF1MIX Input 2 Source */ 
+	{ 0x0663, 0x0080 },   /* R1635  - LHPF1MIX Input 2 Volume */ 
+	{ 0x0664, 0x0000 },   /* R1636  - LHPF1MIX Input 3 Source */ 
+	{ 0x0665, 0x0080 },   /* R1637  - LHPF1MIX Input 3 Volume */ 
+	{ 0x0666, 0x0000 },   /* R1638  - LHPF1MIX Input 4 Source */ 
+	{ 0x0667, 0x0080 },   /* R1639  - LHPF1MIX Input 4 Volume */ 
+	{ 0x0668, 0x0000 },   /* R1640  - LHPF2MIX Input 1 Source */ 
+	{ 0x0669, 0x0080 },   /* R1641  - LHPF2MIX Input 1 Volume */ 
+	{ 0x066A, 0x0000 },   /* R1642  - LHPF2MIX Input 2 Source */ 
+	{ 0x066B, 0x0080 },   /* R1643  - LHPF2MIX Input 2 Volume */ 
+	{ 0x066C, 0x0000 },   /* R1644  - LHPF2MIX Input 3 Source */ 
+	{ 0x066D, 0x0080 },   /* R1645  - LHPF2MIX Input 3 Volume */ 
+	{ 0x066E, 0x0000 },   /* R1646  - LHPF2MIX Input 4 Source */ 
+	{ 0x066F, 0x0080 },   /* R1647  - LHPF2MIX Input 4 Volume */ 
+	{ 0x0670, 0x0000 },   /* R1648  - DSP1LMIX Input 1 Source */ 
+	{ 0x0671, 0x0080 },   /* R1649  - DSP1LMIX Input 1 Volume */ 
+	{ 0x0672, 0x0000 },   /* R1650  - DSP1LMIX Input 2 Source */ 
+	{ 0x0673, 0x0080 },   /* R1651  - DSP1LMIX Input 2 Volume */ 
+	{ 0x0674, 0x0000 },   /* R1652  - DSP1LMIX Input 3 Source */ 
+	{ 0x0675, 0x0080 },   /* R1653  - DSP1LMIX Input 3 Volume */ 
+	{ 0x0676, 0x0000 },   /* R1654  - DSP1LMIX Input 4 Source */ 
+	{ 0x0677, 0x0080 },   /* R1655  - DSP1LMIX Input 4 Volume */ 
+	{ 0x0678, 0x0000 },   /* R1656  - DSP1RMIX Input 1 Source */ 
+	{ 0x0679, 0x0080 },   /* R1657  - DSP1RMIX Input 1 Volume */ 
+	{ 0x067A, 0x0000 },   /* R1658  - DSP1RMIX Input 2 Source */ 
+	{ 0x067B, 0x0080 },   /* R1659  - DSP1RMIX Input 2 Volume */ 
+	{ 0x067C, 0x0000 },   /* R1660  - DSP1RMIX Input 3 Source */ 
+	{ 0x067D, 0x0080 },   /* R1661  - DSP1RMIX Input 3 Volume */ 
+	{ 0x067E, 0x0000 },   /* R1662  - DSP1RMIX Input 4 Source */ 
+	{ 0x067F, 0x0080 },   /* R1663  - DSP1RMIX Input 4 Volume */ 
+	{ 0x0680, 0x0000 },   /* R1664  - DSP1AUX1MIX Input 1 Source */ 
+	{ 0x0681, 0x0000 },   /* R1665  - DSP1AUX2MIX Input 1 Source */ 
+	{ 0x0682, 0x0000 },   /* R1666  - DSP1AUX3MIX Input 1 Source */ 
+	{ 0x0683, 0x0000 },   /* R1667  - DSP1AUX4MIX Input 1 Source */ 
+	{ 0x0684, 0x0000 },   /* R1668  - DSP1AUX5MIX Input 1 Source */ 
+	{ 0x0685, 0x0000 },   /* R1669  - DSP1AUX6MIX Input 1 Source */ 
+	{ 0x0686, 0x0000 },   /* R1670  - DSP2LMIX Input 1 Source */ 
+	{ 0x0687, 0x0080 },   /* R1671  - DSP2LMIX Input 1 Volume */ 
+	{ 0x0688, 0x0000 },   /* R1672  - DSP2LMIX Input 2 Source */ 
+	{ 0x0689, 0x0080 },   /* R1673  - DSP2LMIX Input 2 Volume */ 
+	{ 0x068A, 0x0000 },   /* R1674  - DSP2LMIX Input 3 Source */ 
+	{ 0x068B, 0x0080 },   /* R1675  - DSP2LMIX Input 3 Volume */ 
+	{ 0x068C, 0x0000 },   /* R1676  - DSP2LMIX Input 4 Source */ 
+	{ 0x068D, 0x0080 },   /* R1677  - DSP2LMIX Input 4 Volume */ 
+	{ 0x068E, 0x0000 },   /* R1678  - DSP2RMIX Input 1 Source */ 
+	{ 0x068F, 0x0080 },   /* R1679  - DSP2RMIX Input 1 Volume */ 
+	{ 0x0690, 0x0000 },   /* R1680  - DSP2RMIX Input 2 Source */ 
+	{ 0x0691, 0x0080 },   /* R1681  - DSP2RMIX Input 2 Volume */ 
+	{ 0x0692, 0x0000 },   /* R1682  - DSP2RMIX Input 3 Source */ 
+	{ 0x0693, 0x0080 },   /* R1683  - DSP2RMIX Input 3 Volume */ 
+	{ 0x0694, 0x0000 },   /* R1684  - DSP2RMIX Input 4 Source */ 
+	{ 0x0695, 0x0080 },   /* R1685  - DSP2RMIX Input 4 Volume */ 
+	{ 0x0696, 0x0000 },   /* R1686  - DSP2AUX1MIX Input 1 Source */ 
+	{ 0x0697, 0x0000 },   /* R1687  - DSP2AUX2MIX Input 1 Source */ 
+	{ 0x0698, 0x0000 },   /* R1688  - DSP2AUX3MIX Input 1 Source */ 
+	{ 0x0699, 0x0000 },   /* R1689  - DSP2AUX4MIX Input 1 Source */ 
+	{ 0x069A, 0x0000 },   /* R1690  - DSP2AUX5MIX Input 1 Source */ 
+	{ 0x069B, 0x0000 },   /* R1691  - DSP2AUX6MIX Input 1 Source */ 
+	{ 0x0700, 0xA101 },   /* R1792  - GPIO CTRL 1 */ 
+	{ 0x0701, 0xA101 },   /* R1793  - GPIO CTRL 2 */ 
+	{ 0x0702, 0xA101 },   /* R1794  - GPIO CTRL 3 */ 
+	{ 0x0703, 0xA101 },   /* R1795  - GPIO CTRL 4 */ 
+	{ 0x0709, 0x0000 },   /* R1801  - Misc Pad Ctrl 1 */ 
+	{ 0x0801, 0x00FF },   /* R2049  - Interrupt Status 1 Mask */ 
+	{ 0x0804, 0xFFFF },   /* R2052  - Interrupt Status 2 Mask */ 
+	{ 0x0808, 0x0000 },   /* R2056  - Interrupt Control */ 
+	{ 0x0900, 0x0000 },   /* R2304  - EQL_1 */ 
+	{ 0x0901, 0x0000 },   /* R2305  - EQL_2 */ 
+	{ 0x0902, 0x0000 },   /* R2306  - EQL_3 */ 
+	{ 0x0903, 0x0000 },   /* R2307  - EQL_4 */ 
+	{ 0x0904, 0x0000 },   /* R2308  - EQL_5 */ 
+	{ 0x0905, 0x0000 },   /* R2309  - EQL_6 */ 
+	{ 0x0906, 0x0000 },   /* R2310  - EQL_7 */ 
+	{ 0x0907, 0x0000 },   /* R2311  - EQL_8 */ 
+	{ 0x0908, 0x0000 },   /* R2312  - EQL_9 */ 
+	{ 0x0909, 0x0000 },   /* R2313  - EQL_10 */ 
+	{ 0x090A, 0x0000 },   /* R2314  - EQL_11 */ 
+	{ 0x090B, 0x0000 },   /* R2315  - EQL_12 */ 
+	{ 0x090C, 0x0000 },   /* R2316  - EQL_13 */ 
+	{ 0x090D, 0x0000 },   /* R2317  - EQL_14 */ 
+	{ 0x090E, 0x0000 },   /* R2318  - EQL_15 */ 
+	{ 0x090F, 0x0000 },   /* R2319  - EQL_16 */ 
+	{ 0x0910, 0x0000 },   /* R2320  - EQL_17 */ 
+	{ 0x0911, 0x0000 },   /* R2321  - EQL_18 */ 
+	{ 0x0912, 0x0000 },   /* R2322  - EQL_19 */ 
+	{ 0x0913, 0x0000 },   /* R2323  - EQL_20 */ 
+	{ 0x0916, 0x0000 },   /* R2326  - EQR_1 */ 
+	{ 0x0917, 0x0000 },   /* R2327  - EQR_2 */ 
+	{ 0x0918, 0x0000 },   /* R2328  - EQR_3 */ 
+	{ 0x0919, 0x0000 },   /* R2329  - EQR_4 */ 
+	{ 0x091A, 0x0000 },   /* R2330  - EQR_5 */ 
+	{ 0x091B, 0x0000 },   /* R2331  - EQR_6 */ 
+	{ 0x091C, 0x0000 },   /* R2332  - EQR_7 */ 
+	{ 0x091D, 0x0000 },   /* R2333  - EQR_8 */ 
+	{ 0x091E, 0x0000 },   /* R2334  - EQR_9 */ 
+	{ 0x091F, 0x0000 },   /* R2335  - EQR_10 */ 
+	{ 0x0920, 0x0000 },   /* R2336  - EQR_11 */ 
+	{ 0x0921, 0x0000 },   /* R2337  - EQR_12 */ 
+	{ 0x0922, 0x0000 },   /* R2338  - EQR_13 */ 
+	{ 0x0923, 0x0000 },   /* R2339  - EQR_14 */ 
+	{ 0x0924, 0x0000 },   /* R2340  - EQR_15 */ 
+	{ 0x0925, 0x0000 },   /* R2341  - EQR_16 */ 
+	{ 0x0926, 0x0000 },   /* R2342  - EQR_17 */ 
+	{ 0x0927, 0x0000 },   /* R2343  - EQR_18 */ 
+	{ 0x0928, 0x0000 },   /* R2344  - EQR_19 */ 
+	{ 0x0929, 0x0000 },   /* R2345  - EQR_20 */ 
+	{ 0x093E, 0x0000 },   /* R2366  - HPLPF1_1 */ 
+	{ 0x093F, 0x0000 },   /* R2367  - HPLPF1_2 */ 
+	{ 0x0942, 0x0000 },   /* R2370  - HPLPF2_1 */ 
+	{ 0x0943, 0x0000 },   /* R2371  - HPLPF2_2 */ 
+	{ 0x0A00, 0x0000 },   /* R2560  - DSP1 Control 1 */ 
+	{ 0x0A02, 0x0000 },   /* R2562  - DSP1 Control 2 */ 
+	{ 0x0A03, 0x0000 },   /* R2563  - DSP1 Control 3 */ 
+	{ 0x0A04, 0x0000 },   /* R2564  - DSP1 Control 4 */ 
+	{ 0x0A06, 0x0000 },   /* R2566  - DSP1 Control 5 */ 
+	{ 0x0A07, 0x0000 },   /* R2567  - DSP1 Control 6 */ 
+	{ 0x0A08, 0x0000 },   /* R2568  - DSP1 Control 7 */ 
+	{ 0x0A09, 0x0000 },   /* R2569  - DSP1 Control 8 */ 
+	{ 0x0A0A, 0x0000 },   /* R2570  - DSP1 Control 9 */ 
+	{ 0x0A0B, 0x0000 },   /* R2571  - DSP1 Control 10 */ 
+	{ 0x0A0C, 0x0000 },   /* R2572  - DSP1 Control 11 */ 
+	{ 0x0A0D, 0x0000 },   /* R2573  - DSP1 Control 12 */ 
+	{ 0x0A0F, 0x0000 },   /* R2575  - DSP1 Control 13 */ 
+	{ 0x0A10, 0x0000 },   /* R2576  - DSP1 Control 14 */ 
+	{ 0x0A11, 0x0000 },   /* R2577  - DSP1 Control 15 */ 
+	{ 0x0A12, 0x0000 },   /* R2578  - DSP1 Control 16 */ 
+	{ 0x0A13, 0x0000 },   /* R2579  - DSP1 Control 17 */ 
+	{ 0x0A14, 0x0000 },   /* R2580  - DSP1 Control 18 */ 
+	{ 0x0A16, 0x0000 },   /* R2582  - DSP1 Control 19 */ 
+	{ 0x0A17, 0x0000 },   /* R2583  - DSP1 Control 20 */ 
+	{ 0x0A18, 0x0000 },   /* R2584  - DSP1 Control 21 */ 
+	{ 0x0A1A, 0x1800 },   /* R2586  - DSP1 Control 22 */ 
+	{ 0x0A1B, 0x1000 },   /* R2587  - DSP1 Control 23 */ 
+	{ 0x0A1C, 0x0400 },   /* R2588  - DSP1 Control 24 */ 
+	{ 0x0A1E, 0x0000 },   /* R2590  - DSP1 Control 25 */ 
+	{ 0x0A20, 0x0000 },   /* R2592  - DSP1 Control 26 */ 
+	{ 0x0A21, 0x0000 },   /* R2593  - DSP1 Control 27 */ 
+	{ 0x0A22, 0x0000 },   /* R2594  - DSP1 Control 28 */ 
+	{ 0x0A23, 0x0000 },   /* R2595  - DSP1 Control 29 */ 
+	{ 0x0A24, 0x0000 },   /* R2596  - DSP1 Control 30 */ 
+	{ 0x0A26, 0x0000 },   /* R2598  - DSP1 Control 31 */ 
+	{ 0x0B00, 0x0000 },   /* R2816  - DSP2 Control 1 */ 
+	{ 0x0B02, 0x0000 },   /* R2818  - DSP2 Control 2 */ 
+	{ 0x0B03, 0x0000 },   /* R2819  - DSP2 Control 3 */ 
+	{ 0x0B04, 0x0000 },   /* R2820  - DSP2 Control 4 */ 
+	{ 0x0B06, 0x0000 },   /* R2822  - DSP2 Control 5 */ 
+	{ 0x0B07, 0x0000 },   /* R2823  - DSP2 Control 6 */ 
+	{ 0x0B08, 0x0000 },   /* R2824  - DSP2 Control 7 */ 
+	{ 0x0B09, 0x0000 },   /* R2825  - DSP2 Control 8 */ 
+	{ 0x0B0A, 0x0000 },   /* R2826  - DSP2 Control 9 */ 
+	{ 0x0B0B, 0x0000 },   /* R2827  - DSP2 Control 10 */ 
+	{ 0x0B0C, 0x0000 },   /* R2828  - DSP2 Control 11 */ 
+	{ 0x0B0D, 0x0000 },   /* R2829  - DSP2 Control 12 */ 
+	{ 0x0B0F, 0x0000 },   /* R2831  - DSP2 Control 13 */ 
+	{ 0x0B10, 0x0000 },   /* R2832  - DSP2 Control 14 */ 
+	{ 0x0B11, 0x0000 },   /* R2833  - DSP2 Control 15 */ 
+	{ 0x0B12, 0x0000 },   /* R2834  - DSP2 Control 16 */ 
+	{ 0x0B13, 0x0000 },   /* R2835  - DSP2 Control 17 */ 
+	{ 0x0B14, 0x0000 },   /* R2836  - DSP2 Control 18 */ 
+	{ 0x0B16, 0x0000 },   /* R2838  - DSP2 Control 19 */ 
+	{ 0x0B17, 0x0000 },   /* R2839  - DSP2 Control 20 */ 
+	{ 0x0B18, 0x0000 },   /* R2840  - DSP2 Control 21 */ 
+	{ 0x0B1A, 0x0800 },   /* R2842  - DSP2 Control 22 */ 
+	{ 0x0B1B, 0x1000 },   /* R2843  - DSP2 Control 23 */ 
+	{ 0x0B1C, 0x0400 },   /* R2844  - DSP2 Control 24 */ 
+	{ 0x0B1E, 0x0000 },   /* R2846  - DSP2 Control 25 */ 
+	{ 0x0B20, 0x0000 },   /* R2848  - DSP2 Control 26 */ 
+	{ 0x0B21, 0x0000 },   /* R2849  - DSP2 Control 27 */ 
+	{ 0x0B22, 0x0000 },   /* R2850  - DSP2 Control 28 */ 
+	{ 0x0B23, 0x0000 },   /* R2851  - DSP2 Control 29 */ 
+	{ 0x0B24, 0x0000 },   /* R2852  - DSP2 Control 30 */ 
+	{ 0x0B26, 0x0000 },   /* R2854  - DSP2 Control 31 */ 
+};
+
+static bool wm2200_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM2200_SOFTWARE_RESET:
+	case WM2200_DEVICE_REVISION:
+	case WM2200_ADPS1_IRQ0:
+	case WM2200_ADPS1_IRQ1:
+	case WM2200_INTERRUPT_STATUS_1:
+	case WM2200_INTERRUPT_STATUS_2:
+	case WM2200_INTERRUPT_RAW_STATUS_2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm2200_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM2200_SOFTWARE_RESET:
+	case WM2200_DEVICE_REVISION:
+	case WM2200_TONE_GENERATOR_1:
+	case WM2200_CLOCKING_3:
+	case WM2200_CLOCKING_4:
+	case WM2200_FLL_CONTROL_1:
+	case WM2200_FLL_CONTROL_2:
+	case WM2200_FLL_CONTROL_3:
+	case WM2200_FLL_CONTROL_4:
+	case WM2200_FLL_CONTROL_6:
+	case WM2200_FLL_CONTROL_7:
+	case WM2200_FLL_EFS_1:
+	case WM2200_FLL_EFS_2:
+	case WM2200_MIC_CHARGE_PUMP_1:
+	case WM2200_MIC_CHARGE_PUMP_2:
+	case WM2200_DM_CHARGE_PUMP_1:
+	case WM2200_MIC_BIAS_CTRL_1:
+	case WM2200_MIC_BIAS_CTRL_2:
+	case WM2200_EAR_PIECE_CTRL_1:
+	case WM2200_EAR_PIECE_CTRL_2:
+	case WM2200_INPUT_ENABLES:
+	case WM2200_IN1L_CONTROL:
+	case WM2200_IN1R_CONTROL:
+	case WM2200_IN2L_CONTROL:
+	case WM2200_IN2R_CONTROL:
+	case WM2200_IN3L_CONTROL:
+	case WM2200_IN3R_CONTROL:
+	case WM2200_RXANC_SRC:
+	case WM2200_INPUT_VOLUME_RAMP:
+	case WM2200_ADC_DIGITAL_VOLUME_1L:
+	case WM2200_ADC_DIGITAL_VOLUME_1R:
+	case WM2200_ADC_DIGITAL_VOLUME_2L:
+	case WM2200_ADC_DIGITAL_VOLUME_2R:
+	case WM2200_ADC_DIGITAL_VOLUME_3L:
+	case WM2200_ADC_DIGITAL_VOLUME_3R:
+	case WM2200_OUTPUT_ENABLES:
+	case WM2200_DAC_VOLUME_LIMIT_1L:
+	case WM2200_DAC_VOLUME_LIMIT_1R:
+	case WM2200_DAC_VOLUME_LIMIT_2L:
+	case WM2200_DAC_VOLUME_LIMIT_2R:
+	case WM2200_DAC_AEC_CONTROL_1:
+	case WM2200_OUTPUT_VOLUME_RAMP:
+	case WM2200_DAC_DIGITAL_VOLUME_1L:
+	case WM2200_DAC_DIGITAL_VOLUME_1R:
+	case WM2200_DAC_DIGITAL_VOLUME_2L:
+	case WM2200_DAC_DIGITAL_VOLUME_2R:
+	case WM2200_PDM_1:
+	case WM2200_PDM_2:
+	case WM2200_AUDIO_IF_1_1:
+	case WM2200_AUDIO_IF_1_2:
+	case WM2200_AUDIO_IF_1_3:
+	case WM2200_AUDIO_IF_1_4:
+	case WM2200_AUDIO_IF_1_5:
+	case WM2200_AUDIO_IF_1_6:
+	case WM2200_AUDIO_IF_1_7:
+	case WM2200_AUDIO_IF_1_8:
+	case WM2200_AUDIO_IF_1_9:
+	case WM2200_AUDIO_IF_1_10:
+	case WM2200_AUDIO_IF_1_11:
+	case WM2200_AUDIO_IF_1_12:
+	case WM2200_AUDIO_IF_1_13:
+	case WM2200_AUDIO_IF_1_14:
+	case WM2200_AUDIO_IF_1_15:
+	case WM2200_AUDIO_IF_1_16:
+	case WM2200_AUDIO_IF_1_17:
+	case WM2200_AUDIO_IF_1_18:
+	case WM2200_AUDIO_IF_1_19:
+	case WM2200_AUDIO_IF_1_20:
+	case WM2200_AUDIO_IF_1_21:
+	case WM2200_AUDIO_IF_1_22:
+	case WM2200_OUT1LMIX_INPUT_1_SOURCE:
+	case WM2200_OUT1LMIX_INPUT_1_VOLUME:
+	case WM2200_OUT1LMIX_INPUT_2_SOURCE:
+	case WM2200_OUT1LMIX_INPUT_2_VOLUME:
+	case WM2200_OUT1LMIX_INPUT_3_SOURCE:
+	case WM2200_OUT1LMIX_INPUT_3_VOLUME:
+	case WM2200_OUT1LMIX_INPUT_4_SOURCE:
+	case WM2200_OUT1LMIX_INPUT_4_VOLUME:
+	case WM2200_OUT1RMIX_INPUT_1_SOURCE:
+	case WM2200_OUT1RMIX_INPUT_1_VOLUME:
+	case WM2200_OUT1RMIX_INPUT_2_SOURCE:
+	case WM2200_OUT1RMIX_INPUT_2_VOLUME:
+	case WM2200_OUT1RMIX_INPUT_3_SOURCE:
+	case WM2200_OUT1RMIX_INPUT_3_VOLUME:
+	case WM2200_OUT1RMIX_INPUT_4_SOURCE:
+	case WM2200_OUT1RMIX_INPUT_4_VOLUME:
+	case WM2200_OUT2LMIX_INPUT_1_SOURCE:
+	case WM2200_OUT2LMIX_INPUT_1_VOLUME:
+	case WM2200_OUT2LMIX_INPUT_2_SOURCE:
+	case WM2200_OUT2LMIX_INPUT_2_VOLUME:
+	case WM2200_OUT2LMIX_INPUT_3_SOURCE:
+	case WM2200_OUT2LMIX_INPUT_3_VOLUME:
+	case WM2200_OUT2LMIX_INPUT_4_SOURCE:
+	case WM2200_OUT2LMIX_INPUT_4_VOLUME:
+	case WM2200_OUT2RMIX_INPUT_1_SOURCE:
+	case WM2200_OUT2RMIX_INPUT_1_VOLUME:
+	case WM2200_OUT2RMIX_INPUT_2_SOURCE:
+	case WM2200_OUT2RMIX_INPUT_2_VOLUME:
+	case WM2200_OUT2RMIX_INPUT_3_SOURCE:
+	case WM2200_OUT2RMIX_INPUT_3_VOLUME:
+	case WM2200_OUT2RMIX_INPUT_4_SOURCE:
+	case WM2200_OUT2RMIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX1MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX1MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX1MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX1MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX1MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX1MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX1MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX1MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX2MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX2MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX2MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX2MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX2MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX2MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX2MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX2MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX3MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX3MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX3MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX3MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX3MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX3MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX3MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX3MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX4MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX4MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX4MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX4MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX4MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX4MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX4MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX4MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX5MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX5MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX5MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX5MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX5MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX5MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX5MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX5MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX6MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX6MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX6MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX6MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX6MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX6MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX6MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX6MIX_INPUT_4_VOLUME:
+	case WM2200_EQLMIX_INPUT_1_SOURCE:
+	case WM2200_EQLMIX_INPUT_1_VOLUME:
+	case WM2200_EQLMIX_INPUT_2_SOURCE:
+	case WM2200_EQLMIX_INPUT_2_VOLUME:
+	case WM2200_EQLMIX_INPUT_3_SOURCE:
+	case WM2200_EQLMIX_INPUT_3_VOLUME:
+	case WM2200_EQLMIX_INPUT_4_SOURCE:
+	case WM2200_EQLMIX_INPUT_4_VOLUME:
+	case WM2200_EQRMIX_INPUT_1_SOURCE:
+	case WM2200_EQRMIX_INPUT_1_VOLUME:
+	case WM2200_EQRMIX_INPUT_2_SOURCE:
+	case WM2200_EQRMIX_INPUT_2_VOLUME:
+	case WM2200_EQRMIX_INPUT_3_SOURCE:
+	case WM2200_EQRMIX_INPUT_3_VOLUME:
+	case WM2200_EQRMIX_INPUT_4_SOURCE:
+	case WM2200_EQRMIX_INPUT_4_VOLUME:
+	case WM2200_LHPF1MIX_INPUT_1_SOURCE:
+	case WM2200_LHPF1MIX_INPUT_1_VOLUME:
+	case WM2200_LHPF1MIX_INPUT_2_SOURCE:
+	case WM2200_LHPF1MIX_INPUT_2_VOLUME:
+	case WM2200_LHPF1MIX_INPUT_3_SOURCE:
+	case WM2200_LHPF1MIX_INPUT_3_VOLUME:
+	case WM2200_LHPF1MIX_INPUT_4_SOURCE:
+	case WM2200_LHPF1MIX_INPUT_4_VOLUME:
+	case WM2200_LHPF2MIX_INPUT_1_SOURCE:
+	case WM2200_LHPF2MIX_INPUT_1_VOLUME:
+	case WM2200_LHPF2MIX_INPUT_2_SOURCE:
+	case WM2200_LHPF2MIX_INPUT_2_VOLUME:
+	case WM2200_LHPF2MIX_INPUT_3_SOURCE:
+	case WM2200_LHPF2MIX_INPUT_3_VOLUME:
+	case WM2200_LHPF2MIX_INPUT_4_SOURCE:
+	case WM2200_LHPF2MIX_INPUT_4_VOLUME:
+	case WM2200_DSP1LMIX_INPUT_1_SOURCE:
+	case WM2200_DSP1LMIX_INPUT_1_VOLUME:
+	case WM2200_DSP1LMIX_INPUT_2_SOURCE:
+	case WM2200_DSP1LMIX_INPUT_2_VOLUME:
+	case WM2200_DSP1LMIX_INPUT_3_SOURCE:
+	case WM2200_DSP1LMIX_INPUT_3_VOLUME:
+	case WM2200_DSP1LMIX_INPUT_4_SOURCE:
+	case WM2200_DSP1LMIX_INPUT_4_VOLUME:
+	case WM2200_DSP1RMIX_INPUT_1_SOURCE:
+	case WM2200_DSP1RMIX_INPUT_1_VOLUME:
+	case WM2200_DSP1RMIX_INPUT_2_SOURCE:
+	case WM2200_DSP1RMIX_INPUT_2_VOLUME:
+	case WM2200_DSP1RMIX_INPUT_3_SOURCE:
+	case WM2200_DSP1RMIX_INPUT_3_VOLUME:
+	case WM2200_DSP1RMIX_INPUT_4_SOURCE:
+	case WM2200_DSP1RMIX_INPUT_4_VOLUME:
+	case WM2200_DSP1AUX1MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX2MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX3MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX4MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX5MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX6MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_1_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_1_VOLUME:
+	case WM2200_DSP2LMIX_INPUT_2_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_2_VOLUME:
+	case WM2200_DSP2LMIX_INPUT_3_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_3_VOLUME:
+	case WM2200_DSP2LMIX_INPUT_4_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_4_VOLUME:
+	case WM2200_DSP2RMIX_INPUT_1_SOURCE:
+	case WM2200_DSP2RMIX_INPUT_1_VOLUME:
+	case WM2200_DSP2RMIX_INPUT_2_SOURCE:
+	case WM2200_DSP2RMIX_INPUT_2_VOLUME:
+	case WM2200_DSP2RMIX_INPUT_3_SOURCE:
+	case WM2200_DSP2RMIX_INPUT_3_VOLUME:
+	case WM2200_DSP2RMIX_INPUT_4_SOURCE:
+	case WM2200_DSP2RMIX_INPUT_4_VOLUME:
+	case WM2200_DSP2AUX1MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX2MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX3MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX4MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX5MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX6MIX_INPUT_1_SOURCE:
+	case WM2200_GPIO_CTRL_1:
+	case WM2200_GPIO_CTRL_2:
+	case WM2200_GPIO_CTRL_3:
+	case WM2200_GPIO_CTRL_4:
+	case WM2200_ADPS1_IRQ0:
+	case WM2200_ADPS1_IRQ1:
+	case WM2200_MISC_PAD_CTRL_1:
+	case WM2200_INTERRUPT_STATUS_1:
+	case WM2200_INTERRUPT_STATUS_1_MASK:
+	case WM2200_INTERRUPT_STATUS_2:
+	case WM2200_INTERRUPT_RAW_STATUS_2:
+	case WM2200_INTERRUPT_STATUS_2_MASK:
+	case WM2200_INTERRUPT_CONTROL:
+	case WM2200_EQL_1:
+	case WM2200_EQL_2:
+	case WM2200_EQL_3:
+	case WM2200_EQL_4:
+	case WM2200_EQL_5:
+	case WM2200_EQL_6:
+	case WM2200_EQL_7:
+	case WM2200_EQL_8:
+	case WM2200_EQL_9:
+	case WM2200_EQL_10:
+	case WM2200_EQL_11:
+	case WM2200_EQL_12:
+	case WM2200_EQL_13:
+	case WM2200_EQL_14:
+	case WM2200_EQL_15:
+	case WM2200_EQL_16:
+	case WM2200_EQL_17:
+	case WM2200_EQL_18:
+	case WM2200_EQL_19:
+	case WM2200_EQL_20:
+	case WM2200_EQR_1:
+	case WM2200_EQR_2:
+	case WM2200_EQR_3:
+	case WM2200_EQR_4:
+	case WM2200_EQR_5:
+	case WM2200_EQR_6:
+	case WM2200_EQR_7:
+	case WM2200_EQR_8:
+	case WM2200_EQR_9:
+	case WM2200_EQR_10:
+	case WM2200_EQR_11:
+	case WM2200_EQR_12:
+	case WM2200_EQR_13:
+	case WM2200_EQR_14:
+	case WM2200_EQR_15:
+	case WM2200_EQR_16:
+	case WM2200_EQR_17:
+	case WM2200_EQR_18:
+	case WM2200_EQR_19:
+	case WM2200_EQR_20:
+	case WM2200_HPLPF1_1:
+	case WM2200_HPLPF1_2:
+	case WM2200_HPLPF2_1:
+	case WM2200_HPLPF2_2:
+	case WM2200_DSP1_CONTROL_1:
+	case WM2200_DSP1_CONTROL_2:
+	case WM2200_DSP1_CONTROL_3:
+	case WM2200_DSP1_CONTROL_4:
+	case WM2200_DSP1_CONTROL_5:
+	case WM2200_DSP1_CONTROL_6:
+	case WM2200_DSP1_CONTROL_7:
+	case WM2200_DSP1_CONTROL_8:
+	case WM2200_DSP1_CONTROL_9:
+	case WM2200_DSP1_CONTROL_10:
+	case WM2200_DSP1_CONTROL_11:
+	case WM2200_DSP1_CONTROL_12:
+	case WM2200_DSP1_CONTROL_13:
+	case WM2200_DSP1_CONTROL_14:
+	case WM2200_DSP1_CONTROL_15:
+	case WM2200_DSP1_CONTROL_16:
+	case WM2200_DSP1_CONTROL_17:
+	case WM2200_DSP1_CONTROL_18:
+	case WM2200_DSP1_CONTROL_19:
+	case WM2200_DSP1_CONTROL_20:
+	case WM2200_DSP1_CONTROL_21:
+	case WM2200_DSP1_CONTROL_22:
+	case WM2200_DSP1_CONTROL_23:
+	case WM2200_DSP1_CONTROL_24:
+	case WM2200_DSP1_CONTROL_25:
+	case WM2200_DSP1_CONTROL_26:
+	case WM2200_DSP1_CONTROL_27:
+	case WM2200_DSP1_CONTROL_28:
+	case WM2200_DSP1_CONTROL_29:
+	case WM2200_DSP1_CONTROL_30:
+	case WM2200_DSP1_CONTROL_31:
+	case WM2200_DSP2_CONTROL_1:
+	case WM2200_DSP2_CONTROL_2:
+	case WM2200_DSP2_CONTROL_3:
+	case WM2200_DSP2_CONTROL_4:
+	case WM2200_DSP2_CONTROL_5:
+	case WM2200_DSP2_CONTROL_6:
+	case WM2200_DSP2_CONTROL_7:
+	case WM2200_DSP2_CONTROL_8:
+	case WM2200_DSP2_CONTROL_9:
+	case WM2200_DSP2_CONTROL_10:
+	case WM2200_DSP2_CONTROL_11:
+	case WM2200_DSP2_CONTROL_12:
+	case WM2200_DSP2_CONTROL_13:
+	case WM2200_DSP2_CONTROL_14:
+	case WM2200_DSP2_CONTROL_15:
+	case WM2200_DSP2_CONTROL_16:
+	case WM2200_DSP2_CONTROL_17:
+	case WM2200_DSP2_CONTROL_18:
+	case WM2200_DSP2_CONTROL_19:
+	case WM2200_DSP2_CONTROL_20:
+	case WM2200_DSP2_CONTROL_21:
+	case WM2200_DSP2_CONTROL_22:
+	case WM2200_DSP2_CONTROL_23:
+	case WM2200_DSP2_CONTROL_24:
+	case WM2200_DSP2_CONTROL_25:
+	case WM2200_DSP2_CONTROL_26:
+	case WM2200_DSP2_CONTROL_27:
+	case WM2200_DSP2_CONTROL_28:
+	case WM2200_DSP2_CONTROL_29:
+	case WM2200_DSP2_CONTROL_30:
+	case WM2200_DSP2_CONTROL_31:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct reg_default wm2200_reva_patch[] = {
+	{ 0x07, 0x0003 },
+	{ 0x102, 0x0200 },
+	{ 0x203, 0x0084 },
+	{ 0x201, 0x83FF },
+	{ 0x20C, 0x0062 },
+	{ 0x20D, 0x0062 },
+	{ 0x207, 0x2002 },
+	{ 0x208, 0x20C0 },
+	{ 0x21D, 0x01C0 },
+	{ 0x50A, 0x0001 },
+	{ 0x50B, 0x0002 },
+	{ 0x50C, 0x0003 },
+	{ 0x50D, 0x0004 },
+	{ 0x50E, 0x0005 },
+	{ 0x510, 0x0001 },
+	{ 0x511, 0x0002 },
+	{ 0x512, 0x0003 },
+	{ 0x513, 0x0004 },
+	{ 0x514, 0x0005 },
+	{ 0x515, 0x0000 },
+	{ 0x201, 0x8084 },
+	{ 0x202, 0xBBDE },
+	{ 0x203, 0x00EC },
+	{ 0x500, 0x8000 },
+	{ 0x507, 0x1820 },
+	{ 0x508, 0x1820 },
+	{ 0x505, 0x0300 },
+	{ 0x506, 0x0300 },
+	{ 0x302, 0x2280 },
+	{ 0x303, 0x0080 },
+	{ 0x304, 0x2280 },
+	{ 0x305, 0x0080 },
+	{ 0x306, 0x2280 },
+	{ 0x307, 0x0080 },
+	{ 0x401, 0x0080 },
+	{ 0x402, 0x0080 },
+	{ 0x417, 0x3069 },
+	{ 0x900, 0x6318 },
+	{ 0x901, 0x6300 },
+	{ 0x902, 0x0FC8 },
+	{ 0x903, 0x03FE },
+	{ 0x904, 0x00E0 },
+	{ 0x905, 0x1EC4 },
+	{ 0x906, 0xF136 },
+	{ 0x907, 0x0409 },
+	{ 0x908, 0x04CC },
+	{ 0x909, 0x1C9B },
+	{ 0x90A, 0xF337 },
+	{ 0x90B, 0x040B },
+	{ 0x90C, 0x0CBB },
+	{ 0x90D, 0x16F8 },
+	{ 0x90E, 0xF7D9 },
+	{ 0x90F, 0x040A },
+	{ 0x910, 0x1F14 },
+	{ 0x911, 0x058C },
+	{ 0x912, 0x0563 },
+	{ 0x913, 0x4000 },
+	{ 0x916, 0x6318 },
+	{ 0x917, 0x6300 },
+	{ 0x918, 0x0FC8 },
+	{ 0x919, 0x03FE },
+	{ 0x91A, 0x00E0 },
+	{ 0x91B, 0x1EC4 },
+	{ 0x91C, 0xF136 },
+	{ 0x91D, 0x0409 },
+	{ 0x91E, 0x04CC },
+	{ 0x91F, 0x1C9B },
+	{ 0x920, 0xF337 },
+	{ 0x921, 0x040B },
+	{ 0x922, 0x0CBB },
+	{ 0x923, 0x16F8 },
+	{ 0x924, 0xF7D9 },
+	{ 0x925, 0x040A },
+	{ 0x926, 0x1F14 },
+	{ 0x927, 0x058C },
+	{ 0x928, 0x0563 },
+	{ 0x929, 0x4000 },
+	{ 0x709, 0x2000 },
+	{ 0x207, 0x200E },
+	{ 0x208, 0x20D4 },
+	{ 0x20A, 0x0080 },
+	{ 0x07, 0x0000 },
+};
+
+static int wm2200_reset(struct wm2200_priv *wm2200)
+{
+	if (wm2200->pdata.reset) {
+		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
+		gpio_set_value_cansleep(wm2200->pdata.reset, 1);
+
+		return 0;
+	} else {
+		return regmap_write(wm2200->regmap, WM2200_SOFTWARE_RESET,
+				    0x2200);
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0);
+
+static const char *wm2200_mixer_texts[] = {
+	"None",
+	"Tone Generator",
+	"AEC loopback",
+	"IN1L",
+	"IN1R",
+	"IN2L",
+	"IN2R",
+	"IN3L",
+	"IN3R",
+	"AIF1RX1",
+	"AIF1RX2",
+	"AIF1RX3",
+	"AIF1RX4",
+	"AIF1RX5",
+	"AIF1RX6",
+	"EQL",
+	"EQR",
+	"LHPF1",
+	"LHPF2",
+	"LHPF3",
+	"LHPF4",
+	"DSP1.1",
+	"DSP1.2",
+	"DSP1.3",
+	"DSP1.4",
+	"DSP1.5",
+	"DSP1.6",
+	"DSP2.1",
+	"DSP2.2",
+	"DSP2.3",
+	"DSP2.4",
+	"DSP2.5",
+	"DSP2.6",
+};
+
+static int wm2200_mixer_values[] = {
+	0x00,
+	0x04,   /* Tone */
+	0x08,   /* AEC */
+	0x10,   /* Input */
+	0x11,
+	0x12,
+	0x13,
+	0x14,
+	0x15,
+	0x20,   /* AIF */
+	0x21,
+	0x22,
+	0x23,
+	0x24,
+	0x25,
+	0x50,   /* EQ */
+	0x51,
+	0x52,
+	0x60,   /* LHPF1 */
+	0x61,   /* LHPF2 */
+	0x68,   /* DSP1 */
+	0x69,
+	0x6a,
+	0x6b,
+	0x6c,
+	0x6d,
+	0x70,   /* DSP2 */
+	0x71,
+	0x72,
+	0x73,
+	0x74,
+	0x75,
+};
+
+#define WM2200_MIXER_CONTROLS(name, base) \
+	SOC_SINGLE_TLV(name " Input 1 Volume", base + 1 , \
+		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+	SOC_SINGLE_TLV(name " Input 2 Volume", base + 3 , \
+		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+	SOC_SINGLE_TLV(name " Input 3 Volume", base + 5 , \
+		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+	SOC_SINGLE_TLV(name " Input 4 Volume", base + 7 , \
+		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv)
+
+#define WM2200_MUX_ENUM_DECL(name, reg) \
+	SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, 			\
+				   wm2200_mixer_texts, wm2200_mixer_values)
+
+#define WM2200_MUX_CTL_DECL(name) \
+	const struct snd_kcontrol_new name##_mux =	\
+		SOC_DAPM_VALUE_ENUM("Route", name##_enum)
+
+#define WM2200_MIXER_ENUMS(name, base_reg) \
+	static WM2200_MUX_ENUM_DECL(name##_in1_enum, base_reg);	     \
+	static WM2200_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2);  \
+	static WM2200_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4);  \
+	static WM2200_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6);  \
+	static WM2200_MUX_CTL_DECL(name##_in1); \
+	static WM2200_MUX_CTL_DECL(name##_in2); \
+	static WM2200_MUX_CTL_DECL(name##_in3); \
+	static WM2200_MUX_CTL_DECL(name##_in4) 
+
+static const struct snd_kcontrol_new wm2200_snd_controls[] = {
+SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL,
+	   WM2200_IN1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN2 High Performance Switch", WM2200_IN2L_CONTROL,
+	   WM2200_IN2_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN3 High Performance Switch", WM2200_IN3L_CONTROL,
+	   WM2200_IN3_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R_TLV("IN1 Volume", WM2200_IN1L_CONTROL, WM2200_IN1R_CONTROL,
+		 WM2200_IN1L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
+SOC_DOUBLE_R_TLV("IN2 Volume", WM2200_IN2L_CONTROL, WM2200_IN2R_CONTROL,
+		 WM2200_IN2L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
+SOC_DOUBLE_R_TLV("IN3 Volume", WM2200_IN3L_CONTROL, WM2200_IN3R_CONTROL,
+		 WM2200_IN3L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
+
+SOC_DOUBLE_R("IN1 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
+	     WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
+	     WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
+	     WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_1L,
+		 WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_DIG_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN2 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_2L,
+		 WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_DIG_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_3L,
+		 WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_DIG_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+
+SOC_SINGLE("OUT1 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
+	   WM2200_OUT1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("OUT2 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_2L,
+	   WM2200_OUT2_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("OUT1 Digital Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
+	     WM2200_DAC_DIGITAL_VOLUME_1R, WM2200_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R_TLV("OUT1 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_1L,
+		 WM2200_DAC_DIGITAL_VOLUME_1R, WM2200_OUT1L_VOL_SHIFT, 0x9f, 0,
+		 digital_tlv),
+SOC_DOUBLE_R_TLV("OUT1 Volume", WM2200_DAC_VOLUME_LIMIT_1L,
+		 WM2200_DAC_VOLUME_LIMIT_1R, WM2200_OUT1L_PGA_VOL_SHIFT,
+		 0x46, 0, out_tlv),
+
+SOC_DOUBLE_R("OUT2 Digital Switch", WM2200_DAC_DIGITAL_VOLUME_2L,
+	     WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L,
+		 WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_VOL_SHIFT, 0x9f, 0,
+		 digital_tlv),
+SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT,
+	   WM2200_SPK1R_MUTE_SHIFT, 1, 0),
+};
+
+WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(OUT1R, WM2200_OUT1RMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(OUT2L, WM2200_OUT2LMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(OUT2R, WM2200_OUT2RMIX_INPUT_1_SOURCE);
+
+WM2200_MIXER_ENUMS(AIF1TX1, WM2200_AIF1TX1MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX2, WM2200_AIF1TX2MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX3, WM2200_AIF1TX3MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX4, WM2200_AIF1TX4MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX5, WM2200_AIF1TX5MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX6, WM2200_AIF1TX6MIX_INPUT_1_SOURCE);
+
+WM2200_MIXER_ENUMS(EQL, WM2200_EQLMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(EQR, WM2200_EQRMIX_INPUT_1_SOURCE);
+
+WM2200_MIXER_ENUMS(DSP1L, WM2200_DSP1LMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(DSP1R, WM2200_DSP1RMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(DSP2L, WM2200_DSP2LMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(DSP2R, WM2200_DSP2RMIX_INPUT_1_SOURCE);
+
+WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);
+
+#define WM2200_MUX(name, ctrl) \
+	SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+
+#define WM2200_MIXER_WIDGETS(name, name_str)	\
+	WM2200_MUX(name_str " Input 1", &name##_in1_mux), \
+	WM2200_MUX(name_str " Input 2", &name##_in2_mux), \
+	WM2200_MUX(name_str " Input 3", &name##_in3_mux), \
+	WM2200_MUX(name_str " Input 4", &name##_in4_mux), \
+	SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
+
+#define WM2200_MIXER_INPUT_ROUTES(name)	\
+	{ name, "Tone Generator", "Tone Generator" }, \
+        { name, "IN1L", "IN1L PGA" }, \
+        { name, "IN1R", "IN1R PGA" }, \
+        { name, "IN2L", "IN2L PGA" }, \
+        { name, "IN2R", "IN2R PGA" }, \
+        { name, "IN3L", "IN3L PGA" }, \
+        { name, "IN3R", "IN3R PGA" }, \
+        { name, "DSP1.1", "DSP1" }, \
+        { name, "DSP1.2", "DSP1" }, \
+        { name, "DSP1.3", "DSP1" }, \
+        { name, "DSP1.4", "DSP1" }, \
+        { name, "DSP1.5", "DSP1" }, \
+        { name, "DSP1.6", "DSP1" }, \
+        { name, "DSP2.1", "DSP2" }, \
+        { name, "DSP2.2", "DSP2" }, \
+        { name, "DSP2.3", "DSP2" }, \
+        { name, "DSP2.4", "DSP2" }, \
+        { name, "DSP2.5", "DSP2" }, \
+        { name, "DSP2.6", "DSP2" }, \
+        { name, "AIF1RX1", "AIF1RX1" }, \
+        { name, "AIF1RX2", "AIF1RX2" }, \
+        { name, "AIF1RX3", "AIF1RX3" }, \
+        { name, "AIF1RX4", "AIF1RX4" }, \
+        { name, "AIF1RX5", "AIF1RX5" }, \
+        { name, "AIF1RX6", "AIF1RX6" }, \
+        { name, "EQL", "EQL" }, \
+        { name, "EQR", "EQR" }, \
+        { name, "LHPF1", "LHPF1" }, \
+        { name, "LHPF2", "LHPF2" }
+
+#define WM2200_MIXER_ROUTES(widget, name) \
+	{ widget, NULL, name " Mixer" },         \
+	{ name " Mixer", NULL, name " Input 1" }, \
+	{ name " Mixer", NULL, name " Input 2" }, \
+	{ name " Mixer", NULL, name " Input 3" }, \
+	{ name " Mixer", NULL, name " Input 4" }, \
+	WM2200_MIXER_INPUT_ROUTES(name " Input 1"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Input 2"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Input 3"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Input 4")
+
+static const struct snd_soc_dapm_widget wm2200_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM2200_CLOCKING_3, WM2200_SYSCLK_ENA_SHIFT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("CP1", WM2200_DM_CHARGE_PUMP_1, WM2200_CPDM_ENA_SHIFT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("CP2", WM2200_MIC_CHARGE_PUMP_1, WM2200_CPMIC_ENA_SHIFT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS1", WM2200_MIC_BIAS_CTRL_1, WM2200_MICB1_ENA_SHIFT,
+		    0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", WM2200_MIC_BIAS_CTRL_2, WM2200_MICB2_ENA_SHIFT,
+		    0, NULL, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20),
+SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 20),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_PGA("Tone Generator", WM2200_TONE_GENERATOR_1,
+		 WM2200_TONE_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("IN1L PGA", WM2200_INPUT_ENABLES, WM2200_IN1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN1R PGA", WM2200_INPUT_ENABLES, WM2200_IN1R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN2L PGA", WM2200_INPUT_ENABLES, WM2200_IN2L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN2R PGA", WM2200_INPUT_ENABLES, WM2200_IN2R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN3L PGA", WM2200_INPUT_ENABLES, WM2200_IN3L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN3R PGA", WM2200_INPUT_ENABLES, WM2200_IN3R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", "Playback", 0,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", "Playback", 1,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", "Playback", 2,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", "Playback", 3,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", "Playback", 4,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", "Playback", 5,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA("EQL", WM2200_EQL_1, WM2200_EQL_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQR", WM2200_EQR_1, WM2200_EQR_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", WM2200_HPLPF1_1, WM2200_LHPF1_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", WM2200_HPLPF2_1, WM2200_LHPF2_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0),
+SND_SOC_DAPM_PGA_E("DSP2", SND_SOC_NOPM, 1, 0, NULL, 0, NULL, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 1,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 2,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 3,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 4,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 5,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA_S("OUT1L", 0, WM2200_OUTPUT_ENABLES,
+		   WM2200_OUT1L_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("OUT1R", 0, WM2200_OUTPUT_ENABLES,
+		   WM2200_OUT1R_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("EPD_LP", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_LP_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_OUTP_LP", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_OUTP_LP_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_LP", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_RMV_SHRT_LP_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("EPD_LN", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_LN_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_OUTP_LN", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_OUTP_LN_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_LN", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_RMV_SHRT_LN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("EPD_RP", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_RP_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_OUTP_RP", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_OUTP_RP_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_RP", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_RMV_SHRT_RP_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("EPD_RN", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_RN_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_OUTP_RN", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_OUTP_RN_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_RN", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_RMV_SHRT_RN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("OUT2L", WM2200_OUTPUT_ENABLES, WM2200_OUT2L_ENA_SHIFT,
+		 0, NULL, 0),
+SND_SOC_DAPM_PGA("OUT2R", WM2200_OUTPUT_ENABLES, WM2200_OUT2R_ENA_SHIFT,
+		 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("EPOUTLN"),
+SND_SOC_DAPM_OUTPUT("EPOUTLP"),
+SND_SOC_DAPM_OUTPUT("EPOUTRN"),
+SND_SOC_DAPM_OUTPUT("EPOUTRP"),
+SND_SOC_DAPM_OUTPUT("SPK"),
+
+WM2200_MIXER_WIDGETS(EQL, "EQL"),
+WM2200_MIXER_WIDGETS(EQR, "EQR"),
+
+WM2200_MIXER_WIDGETS(LHPF1, "LHPF1"),
+WM2200_MIXER_WIDGETS(LHPF2, "LHPF2"),
+
+WM2200_MIXER_WIDGETS(DSP1L, "DSP1L"),
+WM2200_MIXER_WIDGETS(DSP1R, "DSP1R"),
+WM2200_MIXER_WIDGETS(DSP2L, "DSP2L"),
+WM2200_MIXER_WIDGETS(DSP2R, "DSP2R"),
+
+WM2200_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+WM2200_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+WM2200_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+WM2200_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+WM2200_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+WM2200_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+
+WM2200_MIXER_WIDGETS(OUT1L, "OUT1L"),
+WM2200_MIXER_WIDGETS(OUT1R, "OUT1R"),
+WM2200_MIXER_WIDGETS(OUT2L, "OUT2L"),
+WM2200_MIXER_WIDGETS(OUT2R, "OUT2R"),
+};
+
+static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
+	/* Everything needs SYSCLK but only hook up things on the edge
+	 * of the chip */
+	{ "IN1L", NULL, "SYSCLK" },
+	{ "IN1R", NULL, "SYSCLK" },
+	{ "IN2L", NULL, "SYSCLK" },
+	{ "IN2R", NULL, "SYSCLK" },
+	{ "IN3L", NULL, "SYSCLK" },
+	{ "IN3R", NULL, "SYSCLK" },
+	{ "OUT1L", NULL, "SYSCLK" },
+	{ "OUT1R", NULL, "SYSCLK" },
+	{ "OUT2L", NULL, "SYSCLK" },
+	{ "OUT2R", NULL, "SYSCLK" },
+	{ "AIF1RX1", NULL, "SYSCLK" },
+	{ "AIF1RX2", NULL, "SYSCLK" },
+	{ "AIF1RX3", NULL, "SYSCLK" },
+	{ "AIF1RX4", NULL, "SYSCLK" },
+	{ "AIF1RX5", NULL, "SYSCLK" },
+	{ "AIF1RX6", NULL, "SYSCLK" },
+	{ "AIF1TX1", NULL, "SYSCLK" },
+	{ "AIF1TX2", NULL, "SYSCLK" },
+	{ "AIF1TX3", NULL, "SYSCLK" },
+	{ "AIF1TX4", NULL, "SYSCLK" },
+	{ "AIF1TX5", NULL, "SYSCLK" },
+	{ "AIF1TX6", NULL, "SYSCLK" },
+
+	{ "IN1L", NULL, "AVDD" },
+	{ "IN1R", NULL, "AVDD" },
+	{ "IN2L", NULL, "AVDD" },
+	{ "IN2R", NULL, "AVDD" },
+	{ "IN3L", NULL, "AVDD" },
+	{ "IN3R", NULL, "AVDD" },
+	{ "OUT1L", NULL, "AVDD" },
+	{ "OUT1R", NULL, "AVDD" },
+
+	{ "IN1L PGA", NULL, "IN1L" },
+	{ "IN1R PGA", NULL, "IN1R" },
+	{ "IN2L PGA", NULL, "IN2L" },
+	{ "IN2R PGA", NULL, "IN2R" },
+	{ "IN3L PGA", NULL, "IN3L" },
+	{ "IN3R PGA", NULL, "IN3R" },
+
+	{ "Tone Generator", NULL, "TONE" },
+
+	{ "CP2", NULL, "CPVDD" },
+	{ "MICBIAS1", NULL, "CP2" },
+	{ "MICBIAS2", NULL, "CP2" },
+
+	{ "CP1", NULL, "CPVDD" },
+	{ "EPD_LN", NULL, "CP1" },
+	{ "EPD_LP", NULL, "CP1" },
+	{ "EPD_RN", NULL, "CP1" },
+	{ "EPD_RP", NULL, "CP1" },
+
+	{ "EPD_LP", NULL, "OUT1L" },
+	{ "EPD_OUTP_LP", NULL, "EPD_LP" },
+	{ "EPD_RMV_SHRT_LP", NULL, "EPD_OUTP_LP" },
+	{ "EPOUTLP", NULL, "EPD_RMV_SHRT_LP" },
+
+	{ "EPD_LN", NULL, "OUT1L" },
+	{ "EPD_OUTP_LN", NULL, "EPD_LN" },
+	{ "EPD_RMV_SHRT_LN", NULL, "EPD_OUTP_LN" },
+	{ "EPOUTLN", NULL, "EPD_RMV_SHRT_LN" },
+
+	{ "EPD_RP", NULL, "OUT1R" },
+	{ "EPD_OUTP_RP", NULL, "EPD_RP" },
+	{ "EPD_RMV_SHRT_RP", NULL, "EPD_OUTP_RP" },
+	{ "EPOUTRP", NULL, "EPD_RMV_SHRT_RP" },
+
+	{ "EPD_RN", NULL, "OUT1R" },
+	{ "EPD_OUTP_RN", NULL, "EPD_RN" },
+	{ "EPD_RMV_SHRT_RN", NULL, "EPD_OUTP_RN" },
+	{ "EPOUTRN", NULL, "EPD_RMV_SHRT_RN" },
+
+	{ "SPK", NULL, "OUT2L" },
+	{ "SPK", NULL, "OUT2R" },
+
+	WM2200_MIXER_ROUTES("DSP1", "DSP1L"),
+	WM2200_MIXER_ROUTES("DSP1", "DSP1R"),
+	WM2200_MIXER_ROUTES("DSP2", "DSP2L"),
+	WM2200_MIXER_ROUTES("DSP2", "DSP2R"),
+
+	WM2200_MIXER_ROUTES("OUT1L", "OUT1L"),
+	WM2200_MIXER_ROUTES("OUT1R", "OUT1R"),
+	WM2200_MIXER_ROUTES("OUT2L", "OUT2L"),
+	WM2200_MIXER_ROUTES("OUT2R", "OUT2R"),
+
+	WM2200_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+	WM2200_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+	WM2200_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+	WM2200_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+	WM2200_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+	WM2200_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+
+	WM2200_MIXER_ROUTES("EQL", "EQL"),
+	WM2200_MIXER_ROUTES("EQR", "EQR"),
+
+	WM2200_MIXER_ROUTES("LHPF1", "LHPF1"),
+	WM2200_MIXER_ROUTES("LHPF2", "LHPF2"),
+};
+
+static int wm2200_probe(struct snd_soc_codec *codec)
+{
+	struct wm2200_priv *wm2200 = dev_get_drvdata(codec->dev);
+	int ret;
+
+	wm2200->codec = codec;
+	codec->control_data = wm2200->regmap;
+	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
+
+	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	int lrclk, bclk, fmt_val;
+
+	lrclk = 0;
+	bclk = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		fmt_val = 0;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		fmt_val = 1;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		fmt_val = 2;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		fmt_val = 3;
+		break;
+	default:
+		dev_err(codec->dev, "Unsupported DAI format %d\n",
+			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		lrclk |= WM2200_AIF1TX_LRCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		bclk |= WM2200_AIF1_BCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		lrclk |= WM2200_AIF1TX_LRCLK_MSTR;
+		bclk |= WM2200_AIF1_BCLK_MSTR;
+		break;
+	default:
+		dev_err(codec->dev, "Unsupported master mode %d\n",
+			fmt & SND_SOC_DAIFMT_MASTER_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		bclk |= WM2200_AIF1_BCLK_INV;
+		lrclk |= WM2200_AIF1TX_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		bclk |= WM2200_AIF1_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrclk |= WM2200_AIF1TX_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_1, WM2200_AIF1_BCLK_MSTR |
+			    WM2200_AIF1_BCLK_INV, bclk);
+	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_2,
+			    WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
+			    lrclk);
+	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_3,
+			    WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
+			    lrclk);
+	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_5,
+			    WM2200_AIF1_FMT_MASK << 1, fmt_val << 1);
+
+	return 0;
+}
+
+static int wm2200_sr_code[] = {
+	0,
+	12000,
+	24000,
+	48000,
+	96000,
+	192000,
+	384000,
+	768000,
+	0,
+	11025,
+	22050,
+	44100,
+	88200,
+	176400,
+	352800,
+	705600,
+	4000,
+	8000,
+	16000,
+	32000,
+	64000,
+	128000,
+	256000,
+	512000,
+};
+
+#define WM2200_NUM_BCLK_RATES 12
+
+static int wm2200_bclk_rates_dat[WM2200_NUM_BCLK_RATES] = {
+	6144000,
+	3072000,
+	2048000,
+	1536000,
+	768000,
+	512000,
+	384000,
+	256000,
+	192000,
+	128000,
+	96000,
+	64000,
+};	
+
+static int wm2200_bclk_rates_cd[WM2200_NUM_BCLK_RATES] = {
+	5644800,
+	2882400,
+	1881600,
+	1411200,
+	705600,
+	470400,
+	352800,
+	176400,
+	117600,
+	88200,
+	58800,
+};
+
+static int wm2200_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
+	int i, bclk, lrclk, wl, fl, sr_code;
+	int *bclk_rates;
+
+	/* Data sizes if not using TDM */
+	wl = snd_pcm_format_width(params_format(params));
+	if (wl < 0)
+		return wl;
+	fl = snd_soc_params_to_frame_size(params);
+	if (fl < 0)
+		return fl;
+
+	dev_dbg(codec->dev, "Word length %d bits, frame length %d bits\n",
+		wl, fl);
+
+	/* Target BCLK rate */
+	bclk = snd_soc_params_to_bclk(params);
+	if (bclk < 0)
+		return bclk;
+
+	if (!wm2200->sysclk) {
+		dev_err(codec->dev, "SYSCLK has no rate set\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm2200_sr_code); i++)
+		if (wm2200_sr_code[i] == params_rate(params))
+			break;
+	if (i == ARRAY_SIZE(wm2200_sr_code)) {
+		dev_err(codec->dev, "Unsupported sample rate: %dHz\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	sr_code = i;
+
+	dev_dbg(codec->dev, "Target BCLK is %dHz, using %dHz SYSCLK\n",
+		bclk, wm2200->sysclk);
+
+	if (wm2200->sysclk % 4000)
+		bclk_rates = wm2200_bclk_rates_cd;
+	else
+		bclk_rates = wm2200_bclk_rates_dat;
+
+	for (i = 0; i < WM2200_NUM_BCLK_RATES; i++)
+		if (bclk_rates[i] >= bclk && (bclk_rates[i] % bclk == 0))
+			break;
+	if (i == WM2200_NUM_BCLK_RATES) {
+		dev_err(codec->dev,
+			"No valid BCLK for %dHz found from %dHz SYSCLK\n",
+			bclk, wm2200->sysclk);
+		return -EINVAL;
+	}
+
+	bclk = i;
+	dev_dbg(codec->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
+	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_1,
+			    WM2200_AIF1_BCLK_DIV_MASK, bclk);
+
+	lrclk = bclk_rates[bclk] / params_rate(params);
+	dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+	    dai->symmetric_rates)
+		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_7,
+				    WM2200_AIF1RX_BCPF_MASK, lrclk);
+	else
+		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_6,
+				    WM2200_AIF1TX_BCPF_MASK, lrclk);
+
+	i = (wl << WM2200_AIF1TX_WL_SHIFT) | wl;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_9,
+				    WM2200_AIF1RX_WL_MASK |
+				    WM2200_AIF1RX_SLOT_LEN_MASK, i);
+	else
+		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_8,
+				    WM2200_AIF1TX_WL_MASK |
+				    WM2200_AIF1TX_SLOT_LEN_MASK, i);
+
+	snd_soc_update_bits(codec, WM2200_CLOCKING_4,
+			    WM2200_SAMPLE_RATE_1_MASK, sr_code);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops wm2200_dai_ops = {
+	.set_fmt = wm2200_set_fmt,
+	.hw_params = wm2200_hw_params,
+};
+
+static int wm2200_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+			     int source, unsigned int freq, int dir)
+{
+	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
+	int fval;
+
+	switch (clk_id) {
+	case WM2200_CLK_SYSCLK:
+		break;
+
+	default:
+		dev_err(codec->dev, "Unknown clock %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	switch (source) {
+	case WM2200_CLKSRC_MCLK1:
+	case WM2200_CLKSRC_MCLK2:
+	case WM2200_CLKSRC_FLL:
+	case WM2200_CLKSRC_BCLK1:
+		break;
+	default:
+		dev_err(codec->dev, "Invalid source %d\n", source);
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case 22579200:
+	case 24576000:
+		fval = 2;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid clock rate: %d\n", freq);
+		return -EINVAL;
+	}
+
+	/* TODO: Check if MCLKs are in use and enable/disable pulls to
+	 * match.
+	 */
+
+	snd_soc_update_bits(codec, WM2200_CLOCKING_3, WM2200_SYSCLK_FREQ_MASK |
+			    WM2200_SYSCLK_SRC_MASK,
+			    fval << WM2200_SYSCLK_FREQ_SHIFT | source);
+
+	wm2200->sysclk = freq;
+
+	return 0;
+}
+
+struct _fll_div {
+	u16 fll_fratio;
+	u16 fll_outdiv;
+	u16 fll_refclk_div;
+	u16 n;
+	u16 theta;
+	u16 lambda;
+};
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 fll_fratio;
+	int ratio;
+} fll_fratios[] = {
+	{       0,    64000, 4, 16 },
+	{   64000,   128000, 3,  8 },
+	{  128000,   256000, 2,  4 },
+	{  256000,  1000000, 1,  2 },
+	{ 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+		       unsigned int Fout)
+{
+	unsigned int target;
+	unsigned int div;
+	unsigned int fratio, gcd_fll;
+	int i;
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	fll_div->fll_refclk_div = 0;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+		fll_div->fll_refclk_div++;
+
+		if (div > 8) {
+			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+			       Fref);
+			return -EINVAL;
+		}
+	}
+
+	pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* Apply the division for our remaining calculations */
+	Fref /= div;
+
+	/* Fvco should be 90-100MHz; don't check the upper bound */
+	div = 2;
+	while (Fout * div < 90000000) {
+		div++;
+		if (div > 64) {
+			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+			       Fout);
+			return -EINVAL;
+		}
+	}
+	target = Fout * div;
+	fll_div->fll_outdiv = div - 1;
+
+	pr_debug("FLL Fvco=%dHz\n", target);
+
+	/* Find an appropraite FLL_FRATIO and factor it out of the target */
+	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+			fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+			fratio = fll_fratios[i].ratio;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_fratios)) {
+		pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+		return -EINVAL;
+	}
+
+	fll_div->n = target / (fratio * Fref);
+
+	if (target % Fref == 0) {
+		fll_div->theta = 0;
+		fll_div->lambda = 0;
+	} else {
+		gcd_fll = gcd(target, fratio * Fref);
+
+		fll_div->theta = (target - (fll_div->n * fratio * Fref))
+			/ gcd_fll;
+		fll_div->lambda = (fratio * Fref) / gcd_fll;
+	}
+
+	pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+		 fll_div->n, fll_div->theta, fll_div->lambda);
+	pr_debug("FLL_FRATIO=%x(%d) FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+		 fll_div->fll_fratio, fratio, fll_div->fll_outdiv,
+		 fll_div->fll_refclk_div);
+
+	return 0;
+}
+
+static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
+	struct _fll_div factors;
+	int ret, i, timeout;
+
+	if (!Fout) {
+		dev_dbg(codec->dev, "FLL disabled");
+
+		if (wm2200->fll_fout)
+			pm_runtime_put(codec->dev);
+
+		wm2200->fll_fout = 0;
+		snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1,
+				    WM2200_FLL_ENA, 0);
+		return 0;
+	}
+
+	switch (source) {
+	case WM2200_FLL_SRC_MCLK1:
+	case WM2200_FLL_SRC_MCLK2:
+	case WM2200_FLL_SRC_BCLK:
+		break;
+	default:
+		dev_err(codec->dev, "Invalid FLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = fll_factors(&factors, Fref, Fout);
+	if (ret < 0)
+		return ret;
+
+	/* Disable the FLL while we reconfigure */
+	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1, WM2200_FLL_ENA, 0);
+
+	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_2,
+			    WM2200_FLL_OUTDIV_MASK | WM2200_FLL_FRATIO_MASK,
+			    (factors.fll_outdiv << WM2200_FLL_OUTDIV_SHIFT) |
+			    factors.fll_fratio);
+	if (factors.theta) {
+		snd_soc_update_bits(codec, WM2200_FLL_CONTROL_3,
+				    WM2200_FLL_FRACN_ENA,
+				    WM2200_FLL_FRACN_ENA);
+		snd_soc_update_bits(codec, WM2200_FLL_EFS_2,
+				    WM2200_FLL_EFS_ENA,
+				    WM2200_FLL_EFS_ENA);
+	} else {
+		snd_soc_update_bits(codec, WM2200_FLL_CONTROL_3,
+				    WM2200_FLL_FRACN_ENA, 0);
+		snd_soc_update_bits(codec, WM2200_FLL_EFS_2,
+				    WM2200_FLL_EFS_ENA, 0);
+	}
+
+	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_4, WM2200_FLL_THETA_MASK,
+			    factors.theta);
+	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_6, WM2200_FLL_N_MASK,
+			    factors.n);
+	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_7,
+			    WM2200_FLL_CLK_REF_DIV_MASK |
+			    WM2200_FLL_CLK_REF_SRC_MASK,
+			    (factors.fll_refclk_div
+			     << WM2200_FLL_CLK_REF_DIV_SHIFT) | source);
+	snd_soc_update_bits(codec, WM2200_FLL_EFS_1,
+			    WM2200_FLL_LAMBDA_MASK, factors.lambda);
+
+	/* Clear any pending completions */
+	try_wait_for_completion(&wm2200->fll_lock);
+
+	pm_runtime_get_sync(codec->dev);
+
+	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1,
+			    WM2200_FLL_ENA, WM2200_FLL_ENA);
+
+	if (i2c->irq)
+		timeout = 2;
+	else
+		timeout = 50;
+
+	snd_soc_update_bits(codec, WM2200_CLOCKING_3, WM2200_SYSCLK_ENA,
+			    WM2200_SYSCLK_ENA);
+
+	/* Poll for the lock; will use the interrupt to exit quickly */
+	for (i = 0; i < timeout; i++) {
+		if (i2c->irq) {
+			ret = wait_for_completion_timeout(&wm2200->fll_lock,
+							  msecs_to_jiffies(25));
+			if (ret > 0)
+				break;
+		} else {
+			msleep(1);
+		}
+
+		ret = snd_soc_read(codec,
+				   WM2200_INTERRUPT_RAW_STATUS_2);
+		if (ret < 0) {
+			dev_err(codec->dev,
+				"Failed to read FLL status: %d\n",
+				ret);
+			continue;
+		}
+		if (ret & WM2200_FLL_LOCK_STS)
+			break;
+	}
+	if (i == timeout) {
+		dev_err(codec->dev, "FLL lock timed out\n");
+		pm_runtime_put(codec->dev);
+		return -ETIMEDOUT;
+	}
+
+	wm2200->fll_src = source;
+	wm2200->fll_fref = Fref;
+	wm2200->fll_fout = Fout;
+
+	dev_dbg(codec->dev, "FLL running %dHz->%dHz\n", Fref, Fout);
+
+	return 0;
+}
+
+static int wm2200_dai_probe(struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned int val = 0;
+	int ret;
+
+	ret = snd_soc_read(codec, WM2200_GPIO_CTRL_1);
+	if (ret >= 0) {
+		if ((ret & WM2200_GP1_FN_MASK) != 0) {
+			dai->symmetric_rates = true;
+			val = WM2200_AIF1TX_LRCLK_SRC;
+		}
+	} else {
+		dev_err(codec->dev, "Failed to read GPIO 1 config: %d\n", ret);
+	}
+
+	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_2,
+			    WM2200_AIF1TX_LRCLK_SRC, val);
+
+	return 0;
+}
+
+#define WM2200_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM2200_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm2200_dai = {
+	.name = "wm2200",
+	.probe = wm2200_dai_probe,
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM2200_RATES,
+		.formats = WM2200_FORMATS,
+	},
+	.capture = {
+		 .stream_name = "Capture",
+		 .channels_min = 2,
+		 .channels_max = 2,
+		 .rates = WM2200_RATES,
+		 .formats = WM2200_FORMATS,
+	 },
+	.ops = &wm2200_dai_ops,
+};
+
+static struct snd_soc_codec_driver soc_codec_wm2200 = {
+	.probe = wm2200_probe,
+
+	.idle_bias_off = true,
+	.set_sysclk = wm2200_set_sysclk,
+	.set_pll = wm2200_set_fll,
+
+	.controls = wm2200_snd_controls,
+	.num_controls = ARRAY_SIZE(wm2200_snd_controls),
+	.dapm_widgets = wm2200_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm2200_dapm_widgets),
+	.dapm_routes = wm2200_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm2200_dapm_routes),
+};
+
+static irqreturn_t wm2200_irq(int irq, void *data)
+{
+	struct wm2200_priv *wm2200 = data;
+	unsigned int val, mask;
+	int ret;
+
+	ret = regmap_read(wm2200->regmap, WM2200_INTERRUPT_STATUS_2, &val);
+	if (ret != 0) {
+		dev_err(wm2200->dev, "Failed to read IRQ status: %d\n", ret);
+		return IRQ_NONE;
+	}
+
+	ret = regmap_read(wm2200->regmap, WM2200_INTERRUPT_STATUS_2_MASK,
+			   &mask);
+	if (ret != 0) {
+		dev_warn(wm2200->dev, "Failed to read IRQ mask: %d\n", ret);
+		mask = 0;
+	}
+
+	val &= ~mask;
+
+	if (val & WM2200_FLL_LOCK_EINT) {
+		dev_dbg(wm2200->dev, "FLL locked\n");
+		complete(&wm2200->fll_lock);
+	}
+
+	if (val) {
+		regmap_write(wm2200->regmap, WM2200_INTERRUPT_STATUS_2, val);
+		
+		return IRQ_HANDLED;
+	} else {
+		return IRQ_NONE;
+	}
+}
+
+static const struct regmap_config wm2200_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+
+	.max_register = WM2200_MAX_REGISTER,
+	.reg_defaults = wm2200_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults),
+	.volatile_reg = wm2200_volatile_register,
+	.readable_reg = wm2200_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const unsigned int wm2200_dig_vu[] = {
+	WM2200_DAC_DIGITAL_VOLUME_1L,
+	WM2200_DAC_DIGITAL_VOLUME_1R,
+	WM2200_DAC_DIGITAL_VOLUME_2L,
+	WM2200_DAC_DIGITAL_VOLUME_2R,
+	WM2200_ADC_DIGITAL_VOLUME_1L,
+	WM2200_ADC_DIGITAL_VOLUME_1R,
+	WM2200_ADC_DIGITAL_VOLUME_2L,
+	WM2200_ADC_DIGITAL_VOLUME_2R,
+	WM2200_ADC_DIGITAL_VOLUME_3L,
+	WM2200_ADC_DIGITAL_VOLUME_3R,
+};
+
+static const unsigned int wm2200_mic_ctrl_reg[] = {
+	WM2200_IN1L_CONTROL,
+	WM2200_IN2L_CONTROL,
+	WM2200_IN3L_CONTROL,
+};
+
+static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct wm2200_pdata *pdata = dev_get_platdata(&i2c->dev);
+	struct wm2200_priv *wm2200;
+	unsigned int reg;
+	int ret, i;
+
+	wm2200 = devm_kzalloc(&i2c->dev, sizeof(struct wm2200_priv),
+			      GFP_KERNEL);
+	if (wm2200 == NULL)
+		return -ENOMEM;
+
+	wm2200->dev = &i2c->dev;
+	init_completion(&wm2200->fll_lock);
+
+	wm2200->regmap = regmap_init_i2c(i2c, &wm2200_regmap);
+	if (IS_ERR(wm2200->regmap)) {
+		ret = PTR_ERR(wm2200->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		goto err;
+	}
+
+	if (pdata)
+		wm2200->pdata = *pdata;
+
+	i2c_set_clientdata(i2c, wm2200);
+
+	for (i = 0; i < ARRAY_SIZE(wm2200->core_supplies); i++)
+		wm2200->core_supplies[i].supply = wm2200_core_supply_names[i];
+
+	ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm2200->core_supplies),
+				 wm2200->core_supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
+			ret);
+		goto err_regmap;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies),
+				    wm2200->core_supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
+			ret);
+		goto err_core;
+	}
+
+	if (wm2200->pdata.ldo_ena) {
+		ret = gpio_request_one(wm2200->pdata.ldo_ena,
+				       GPIOF_OUT_INIT_HIGH, "WM2200 LDOENA");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
+				wm2200->pdata.ldo_ena, ret);
+			goto err_enable;
+		}
+		msleep(2);
+	}
+
+	if (wm2200->pdata.reset) {
+		ret = gpio_request_one(wm2200->pdata.reset,
+				       GPIOF_OUT_INIT_HIGH, "WM2200 /RESET");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
+				wm2200->pdata.reset, ret);
+			goto err_ldo;
+		}
+	}
+
+	ret = regmap_read(wm2200->regmap, WM2200_SOFTWARE_RESET, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
+		goto err_reset;
+	}
+	switch (reg) {
+	case 0x2200:
+		break;
+
+	default:
+		dev_err(&i2c->dev, "Device is not a WM2200, ID is %x\n", reg);
+		ret = -EINVAL;
+		goto err_reset;
+	}
+
+	ret = regmap_read(wm2200->regmap, WM2200_DEVICE_REVISION, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read revision register\n");
+		goto err_reset;
+	}
+
+	wm2200->rev = ret & WM2200_DEVICE_REVISION_MASK;
+
+	dev_info(&i2c->dev, "revision %c\n", wm2200->rev + 'A');
+
+	switch (wm2200->rev) {
+	case 0:
+		ret = regmap_register_patch(wm2200->regmap, wm2200_reva_patch,
+					    ARRAY_SIZE(wm2200_reva_patch));
+		if (ret != 0) {
+			dev_err(&i2c->dev, "Failed to register patch: %d\n",
+				ret);
+		}
+		break;
+	default:
+		break;
+	}
+
+	ret = wm2200_reset(wm2200);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to issue reset\n");
+		goto err_reset;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm2200->pdata.gpio_defaults); i++) {
+		if (!wm2200->pdata.gpio_defaults[i])
+			continue;
+
+		regmap_write(wm2200->regmap, WM2200_GPIO_CTRL_1 + i,
+			     wm2200->pdata.gpio_defaults[i]);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm2200_dig_vu); i++)
+		regmap_update_bits(wm2200->regmap, wm2200_dig_vu[i],
+				   WM2200_OUT_VU, WM2200_OUT_VU);
+
+	/* Assign slots 1-6 to channels 1-6 for both TX and RX */
+	for (i = 0; i < 6; i++) {
+		regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_10 + i, i);
+		regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_16 + i, i);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm2200->pdata.in_mode); i++) {
+		regmap_update_bits(wm2200->regmap, wm2200_mic_ctrl_reg[i],
+				   WM2200_IN1_MODE_MASK |
+				   WM2200_IN1_DMIC_SUP_MASK,
+				   (wm2200->pdata.in_mode[i] <<
+				    WM2200_IN1_MODE_SHIFT) |
+				   (wm2200->pdata.dmic_sup[i] <<
+				    WM2200_IN1_DMIC_SUP_SHIFT));
+	}
+
+	if (i2c->irq) {
+		ret = request_threaded_irq(i2c->irq, NULL, wm2200_irq,
+					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					   "wm2200", wm2200);
+		if (ret == 0)
+			regmap_update_bits(wm2200->regmap,
+					   WM2200_INTERRUPT_STATUS_2_MASK,
+					   WM2200_FLL_LOCK_EINT, 0);
+		else
+			dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
+				i2c->irq, ret);
+	}
+
+	pm_runtime_set_active(&i2c->dev);
+	pm_runtime_enable(&i2c->dev);
+	pm_request_idle(&i2c->dev);
+
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_wm2200,
+				     &wm2200_dai, 1);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		goto err_pm_runtime;
+	}
+
+	return 0;
+
+err_pm_runtime:
+	pm_runtime_disable(&i2c->dev);
+err_reset:
+	if (wm2200->pdata.reset) {
+		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
+		gpio_free(wm2200->pdata.reset);
+	}
+err_ldo:
+	if (wm2200->pdata.ldo_ena) {
+		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+		gpio_free(wm2200->pdata.ldo_ena);
+	}
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
+			       wm2200->core_supplies);
+err_core:
+	regulator_bulk_free(ARRAY_SIZE(wm2200->core_supplies),
+			    wm2200->core_supplies);
+err_regmap:
+	regmap_exit(wm2200->regmap);
+err:
+	return ret;
+}
+
+static __devexit int wm2200_i2c_remove(struct i2c_client *i2c)
+{
+	struct wm2200_priv *wm2200 = i2c_get_clientdata(i2c);
+
+	snd_soc_unregister_codec(&i2c->dev);
+	if (i2c->irq)
+		free_irq(i2c->irq, wm2200);
+	if (wm2200->pdata.reset) {
+		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
+		gpio_free(wm2200->pdata.reset);
+	}
+	if (wm2200->pdata.ldo_ena) {
+		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+		gpio_free(wm2200->pdata.ldo_ena);
+	}
+	regulator_bulk_free(ARRAY_SIZE(wm2200->core_supplies),
+			    wm2200->core_supplies);
+	regmap_exit(wm2200->regmap);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int wm2200_runtime_suspend(struct device *dev)
+{
+	struct wm2200_priv *wm2200 = dev_get_drvdata(dev);
+
+	regcache_cache_only(wm2200->regmap, true);
+	regcache_mark_dirty(wm2200->regmap);
+	if (wm2200->pdata.ldo_ena)
+		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+	regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
+			       wm2200->core_supplies);
+
+	return 0;
+}
+
+static int wm2200_runtime_resume(struct device *dev)
+{
+	struct wm2200_priv *wm2200 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies),
+				    wm2200->core_supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (wm2200->pdata.ldo_ena) {
+		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 1);
+		msleep(2);
+	}
+
+	regcache_cache_only(wm2200->regmap, false);
+	regcache_sync(wm2200->regmap);
+
+	return 0;
+}
+#endif
+
+static struct dev_pm_ops wm2200_pm = {
+	SET_RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume,
+			   NULL)
+};
+
+static const struct i2c_device_id wm2200_i2c_id[] = {
+	{ "wm2200", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id);
+
+static struct i2c_driver wm2200_i2c_driver = {
+	.driver = {
+		.name = "wm2200",
+		.owner = THIS_MODULE,
+		.pm = &wm2200_pm,
+	},
+	.probe =    wm2200_i2c_probe,
+	.remove =   __devexit_p(wm2200_i2c_remove),
+	.id_table = wm2200_i2c_id,
+};
+
+static int __init wm2200_modinit(void)
+{
+	return i2c_add_driver(&wm2200_i2c_driver);
+}
+module_init(wm2200_modinit);
+
+static void __exit wm2200_exit(void)
+{
+	i2c_del_driver(&wm2200_i2c_driver);
+}
+module_exit(wm2200_exit);
+
+MODULE_DESCRIPTION("ASoC WM2200 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm2200.h b/sound/soc/codecs/wm2200.h
new file mode 100644
index 0000000..5d719d6
--- /dev/null
+++ b/sound/soc/codecs/wm2200.h
@@ -0,0 +1,3674 @@
+/*
+ * wm2200.h - WM2200 audio codec interface
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _WM2200_H
+#define _WM2200_H
+
+#define WM2200_CLK_SYSCLK 1
+
+#define WM2200_CLKSRC_MCLK1  0
+#define WM2200_CLKSRC_MCLK2  1
+#define WM2200_CLKSRC_FLL    4
+#define WM2200_CLKSRC_BCLK1  8
+
+#define WM2200_FLL_SRC_MCLK1 0
+#define WM2200_FLL_SRC_MCLK2 1
+#define WM2200_FLL_SRC_BCLK  2
+
+/*
+ * Register values.
+ */
+#define WM2200_SOFTWARE_RESET                   0x00
+#define WM2200_DEVICE_REVISION                  0x01
+#define WM2200_TONE_GENERATOR_1                 0x0B
+#define WM2200_CLOCKING_3                       0x102
+#define WM2200_CLOCKING_4                       0x103
+#define WM2200_FLL_CONTROL_1                    0x111
+#define WM2200_FLL_CONTROL_2                    0x112
+#define WM2200_FLL_CONTROL_3                    0x113
+#define WM2200_FLL_CONTROL_4                    0x114
+#define WM2200_FLL_CONTROL_6                    0x116
+#define WM2200_FLL_CONTROL_7                    0x117
+#define WM2200_FLL_EFS_1                        0x119
+#define WM2200_FLL_EFS_2                        0x11A
+#define WM2200_MIC_CHARGE_PUMP_1                0x200
+#define WM2200_MIC_CHARGE_PUMP_2                0x201
+#define WM2200_DM_CHARGE_PUMP_1                 0x202
+#define WM2200_MIC_BIAS_CTRL_1                  0x20C
+#define WM2200_MIC_BIAS_CTRL_2                  0x20D
+#define WM2200_EAR_PIECE_CTRL_1                 0x20F
+#define WM2200_EAR_PIECE_CTRL_2                 0x210
+#define WM2200_INPUT_ENABLES                    0x301
+#define WM2200_IN1L_CONTROL                     0x302
+#define WM2200_IN1R_CONTROL                     0x303
+#define WM2200_IN2L_CONTROL                     0x304
+#define WM2200_IN2R_CONTROL                     0x305
+#define WM2200_IN3L_CONTROL                     0x306
+#define WM2200_IN3R_CONTROL                     0x307
+#define WM2200_RXANC_SRC                        0x30A
+#define WM2200_INPUT_VOLUME_RAMP                0x30B
+#define WM2200_ADC_DIGITAL_VOLUME_1L            0x30C
+#define WM2200_ADC_DIGITAL_VOLUME_1R            0x30D
+#define WM2200_ADC_DIGITAL_VOLUME_2L            0x30E
+#define WM2200_ADC_DIGITAL_VOLUME_2R            0x30F
+#define WM2200_ADC_DIGITAL_VOLUME_3L            0x310
+#define WM2200_ADC_DIGITAL_VOLUME_3R            0x311
+#define WM2200_OUTPUT_ENABLES                   0x400
+#define WM2200_DAC_VOLUME_LIMIT_1L              0x401
+#define WM2200_DAC_VOLUME_LIMIT_1R              0x402
+#define WM2200_DAC_VOLUME_LIMIT_2L              0x403
+#define WM2200_DAC_VOLUME_LIMIT_2R              0x404
+#define WM2200_DAC_AEC_CONTROL_1                0x409
+#define WM2200_OUTPUT_VOLUME_RAMP               0x40A
+#define WM2200_DAC_DIGITAL_VOLUME_1L            0x40B
+#define WM2200_DAC_DIGITAL_VOLUME_1R            0x40C
+#define WM2200_DAC_DIGITAL_VOLUME_2L            0x40D
+#define WM2200_DAC_DIGITAL_VOLUME_2R            0x40E
+#define WM2200_PDM_1                            0x417
+#define WM2200_PDM_2                            0x418
+#define WM2200_AUDIO_IF_1_1                     0x500
+#define WM2200_AUDIO_IF_1_2                     0x501
+#define WM2200_AUDIO_IF_1_3                     0x502
+#define WM2200_AUDIO_IF_1_4                     0x503
+#define WM2200_AUDIO_IF_1_5                     0x504
+#define WM2200_AUDIO_IF_1_6                     0x505
+#define WM2200_AUDIO_IF_1_7                     0x506
+#define WM2200_AUDIO_IF_1_8                     0x507
+#define WM2200_AUDIO_IF_1_9                     0x508
+#define WM2200_AUDIO_IF_1_10                    0x509
+#define WM2200_AUDIO_IF_1_11                    0x50A
+#define WM2200_AUDIO_IF_1_12                    0x50B
+#define WM2200_AUDIO_IF_1_13                    0x50C
+#define WM2200_AUDIO_IF_1_14                    0x50D
+#define WM2200_AUDIO_IF_1_15                    0x50E
+#define WM2200_AUDIO_IF_1_16                    0x50F
+#define WM2200_AUDIO_IF_1_17                    0x510
+#define WM2200_AUDIO_IF_1_18                    0x511
+#define WM2200_AUDIO_IF_1_19                    0x512
+#define WM2200_AUDIO_IF_1_20                    0x513
+#define WM2200_AUDIO_IF_1_21                    0x514
+#define WM2200_AUDIO_IF_1_22                    0x515
+#define WM2200_OUT1LMIX_INPUT_1_SOURCE          0x600
+#define WM2200_OUT1LMIX_INPUT_1_VOLUME          0x601
+#define WM2200_OUT1LMIX_INPUT_2_SOURCE          0x602
+#define WM2200_OUT1LMIX_INPUT_2_VOLUME          0x603
+#define WM2200_OUT1LMIX_INPUT_3_SOURCE          0x604
+#define WM2200_OUT1LMIX_INPUT_3_VOLUME          0x605
+#define WM2200_OUT1LMIX_INPUT_4_SOURCE          0x606
+#define WM2200_OUT1LMIX_INPUT_4_VOLUME          0x607
+#define WM2200_OUT1RMIX_INPUT_1_SOURCE          0x608
+#define WM2200_OUT1RMIX_INPUT_1_VOLUME          0x609
+#define WM2200_OUT1RMIX_INPUT_2_SOURCE          0x60A
+#define WM2200_OUT1RMIX_INPUT_2_VOLUME          0x60B
+#define WM2200_OUT1RMIX_INPUT_3_SOURCE          0x60C
+#define WM2200_OUT1RMIX_INPUT_3_VOLUME          0x60D
+#define WM2200_OUT1RMIX_INPUT_4_SOURCE          0x60E
+#define WM2200_OUT1RMIX_INPUT_4_VOLUME          0x60F
+#define WM2200_OUT2LMIX_INPUT_1_SOURCE          0x610
+#define WM2200_OUT2LMIX_INPUT_1_VOLUME          0x611
+#define WM2200_OUT2LMIX_INPUT_2_SOURCE          0x612
+#define WM2200_OUT2LMIX_INPUT_2_VOLUME          0x613
+#define WM2200_OUT2LMIX_INPUT_3_SOURCE          0x614
+#define WM2200_OUT2LMIX_INPUT_3_VOLUME          0x615
+#define WM2200_OUT2LMIX_INPUT_4_SOURCE          0x616
+#define WM2200_OUT2LMIX_INPUT_4_VOLUME          0x617
+#define WM2200_OUT2RMIX_INPUT_1_SOURCE          0x618
+#define WM2200_OUT2RMIX_INPUT_1_VOLUME          0x619
+#define WM2200_OUT2RMIX_INPUT_2_SOURCE          0x61A
+#define WM2200_OUT2RMIX_INPUT_2_VOLUME          0x61B
+#define WM2200_OUT2RMIX_INPUT_3_SOURCE          0x61C
+#define WM2200_OUT2RMIX_INPUT_3_VOLUME          0x61D
+#define WM2200_OUT2RMIX_INPUT_4_SOURCE          0x61E
+#define WM2200_OUT2RMIX_INPUT_4_VOLUME          0x61F
+#define WM2200_AIF1TX1MIX_INPUT_1_SOURCE        0x620
+#define WM2200_AIF1TX1MIX_INPUT_1_VOLUME        0x621
+#define WM2200_AIF1TX1MIX_INPUT_2_SOURCE        0x622
+#define WM2200_AIF1TX1MIX_INPUT_2_VOLUME        0x623
+#define WM2200_AIF1TX1MIX_INPUT_3_SOURCE        0x624
+#define WM2200_AIF1TX1MIX_INPUT_3_VOLUME        0x625
+#define WM2200_AIF1TX1MIX_INPUT_4_SOURCE        0x626
+#define WM2200_AIF1TX1MIX_INPUT_4_VOLUME        0x627
+#define WM2200_AIF1TX2MIX_INPUT_1_SOURCE        0x628
+#define WM2200_AIF1TX2MIX_INPUT_1_VOLUME        0x629
+#define WM2200_AIF1TX2MIX_INPUT_2_SOURCE        0x62A
+#define WM2200_AIF1TX2MIX_INPUT_2_VOLUME        0x62B
+#define WM2200_AIF1TX2MIX_INPUT_3_SOURCE        0x62C
+#define WM2200_AIF1TX2MIX_INPUT_3_VOLUME        0x62D
+#define WM2200_AIF1TX2MIX_INPUT_4_SOURCE        0x62E
+#define WM2200_AIF1TX2MIX_INPUT_4_VOLUME        0x62F
+#define WM2200_AIF1TX3MIX_INPUT_1_SOURCE        0x630
+#define WM2200_AIF1TX3MIX_INPUT_1_VOLUME        0x631
+#define WM2200_AIF1TX3MIX_INPUT_2_SOURCE        0x632
+#define WM2200_AIF1TX3MIX_INPUT_2_VOLUME        0x633
+#define WM2200_AIF1TX3MIX_INPUT_3_SOURCE        0x634
+#define WM2200_AIF1TX3MIX_INPUT_3_VOLUME        0x635
+#define WM2200_AIF1TX3MIX_INPUT_4_SOURCE        0x636
+#define WM2200_AIF1TX3MIX_INPUT_4_VOLUME        0x637
+#define WM2200_AIF1TX4MIX_INPUT_1_SOURCE        0x638
+#define WM2200_AIF1TX4MIX_INPUT_1_VOLUME        0x639
+#define WM2200_AIF1TX4MIX_INPUT_2_SOURCE        0x63A
+#define WM2200_AIF1TX4MIX_INPUT_2_VOLUME        0x63B
+#define WM2200_AIF1TX4MIX_INPUT_3_SOURCE        0x63C
+#define WM2200_AIF1TX4MIX_INPUT_3_VOLUME        0x63D
+#define WM2200_AIF1TX4MIX_INPUT_4_SOURCE        0x63E
+#define WM2200_AIF1TX4MIX_INPUT_4_VOLUME        0x63F
+#define WM2200_AIF1TX5MIX_INPUT_1_SOURCE        0x640
+#define WM2200_AIF1TX5MIX_INPUT_1_VOLUME        0x641
+#define WM2200_AIF1TX5MIX_INPUT_2_SOURCE        0x642
+#define WM2200_AIF1TX5MIX_INPUT_2_VOLUME        0x643
+#define WM2200_AIF1TX5MIX_INPUT_3_SOURCE        0x644
+#define WM2200_AIF1TX5MIX_INPUT_3_VOLUME        0x645
+#define WM2200_AIF1TX5MIX_INPUT_4_SOURCE        0x646
+#define WM2200_AIF1TX5MIX_INPUT_4_VOLUME        0x647
+#define WM2200_AIF1TX6MIX_INPUT_1_SOURCE        0x648
+#define WM2200_AIF1TX6MIX_INPUT_1_VOLUME        0x649
+#define WM2200_AIF1TX6MIX_INPUT_2_SOURCE        0x64A
+#define WM2200_AIF1TX6MIX_INPUT_2_VOLUME        0x64B
+#define WM2200_AIF1TX6MIX_INPUT_3_SOURCE        0x64C
+#define WM2200_AIF1TX6MIX_INPUT_3_VOLUME        0x64D
+#define WM2200_AIF1TX6MIX_INPUT_4_SOURCE        0x64E
+#define WM2200_AIF1TX6MIX_INPUT_4_VOLUME        0x64F
+#define WM2200_EQLMIX_INPUT_1_SOURCE            0x650
+#define WM2200_EQLMIX_INPUT_1_VOLUME            0x651
+#define WM2200_EQLMIX_INPUT_2_SOURCE            0x652
+#define WM2200_EQLMIX_INPUT_2_VOLUME            0x653
+#define WM2200_EQLMIX_INPUT_3_SOURCE            0x654
+#define WM2200_EQLMIX_INPUT_3_VOLUME            0x655
+#define WM2200_EQLMIX_INPUT_4_SOURCE            0x656
+#define WM2200_EQLMIX_INPUT_4_VOLUME            0x657
+#define WM2200_EQRMIX_INPUT_1_SOURCE            0x658
+#define WM2200_EQRMIX_INPUT_1_VOLUME            0x659
+#define WM2200_EQRMIX_INPUT_2_SOURCE            0x65A
+#define WM2200_EQRMIX_INPUT_2_VOLUME            0x65B
+#define WM2200_EQRMIX_INPUT_3_SOURCE            0x65C
+#define WM2200_EQRMIX_INPUT_3_VOLUME            0x65D
+#define WM2200_EQRMIX_INPUT_4_SOURCE            0x65E
+#define WM2200_EQRMIX_INPUT_4_VOLUME            0x65F
+#define WM2200_LHPF1MIX_INPUT_1_SOURCE          0x660
+#define WM2200_LHPF1MIX_INPUT_1_VOLUME          0x661
+#define WM2200_LHPF1MIX_INPUT_2_SOURCE          0x662
+#define WM2200_LHPF1MIX_INPUT_2_VOLUME          0x663
+#define WM2200_LHPF1MIX_INPUT_3_SOURCE          0x664
+#define WM2200_LHPF1MIX_INPUT_3_VOLUME          0x665
+#define WM2200_LHPF1MIX_INPUT_4_SOURCE          0x666
+#define WM2200_LHPF1MIX_INPUT_4_VOLUME          0x667
+#define WM2200_LHPF2MIX_INPUT_1_SOURCE          0x668
+#define WM2200_LHPF2MIX_INPUT_1_VOLUME          0x669
+#define WM2200_LHPF2MIX_INPUT_2_SOURCE          0x66A
+#define WM2200_LHPF2MIX_INPUT_2_VOLUME          0x66B
+#define WM2200_LHPF2MIX_INPUT_3_SOURCE          0x66C
+#define WM2200_LHPF2MIX_INPUT_3_VOLUME          0x66D
+#define WM2200_LHPF2MIX_INPUT_4_SOURCE          0x66E
+#define WM2200_LHPF2MIX_INPUT_4_VOLUME          0x66F
+#define WM2200_DSP1LMIX_INPUT_1_SOURCE          0x670
+#define WM2200_DSP1LMIX_INPUT_1_VOLUME          0x671
+#define WM2200_DSP1LMIX_INPUT_2_SOURCE          0x672
+#define WM2200_DSP1LMIX_INPUT_2_VOLUME          0x673
+#define WM2200_DSP1LMIX_INPUT_3_SOURCE          0x674
+#define WM2200_DSP1LMIX_INPUT_3_VOLUME          0x675
+#define WM2200_DSP1LMIX_INPUT_4_SOURCE          0x676
+#define WM2200_DSP1LMIX_INPUT_4_VOLUME          0x677
+#define WM2200_DSP1RMIX_INPUT_1_SOURCE          0x678
+#define WM2200_DSP1RMIX_INPUT_1_VOLUME          0x679
+#define WM2200_DSP1RMIX_INPUT_2_SOURCE          0x67A
+#define WM2200_DSP1RMIX_INPUT_2_VOLUME          0x67B
+#define WM2200_DSP1RMIX_INPUT_3_SOURCE          0x67C
+#define WM2200_DSP1RMIX_INPUT_3_VOLUME          0x67D
+#define WM2200_DSP1RMIX_INPUT_4_SOURCE          0x67E
+#define WM2200_DSP1RMIX_INPUT_4_VOLUME          0x67F
+#define WM2200_DSP1AUX1MIX_INPUT_1_SOURCE       0x680
+#define WM2200_DSP1AUX2MIX_INPUT_1_SOURCE       0x681
+#define WM2200_DSP1AUX3MIX_INPUT_1_SOURCE       0x682
+#define WM2200_DSP1AUX4MIX_INPUT_1_SOURCE       0x683
+#define WM2200_DSP1AUX5MIX_INPUT_1_SOURCE       0x684
+#define WM2200_DSP1AUX6MIX_INPUT_1_SOURCE       0x685
+#define WM2200_DSP2LMIX_INPUT_1_SOURCE          0x686
+#define WM2200_DSP2LMIX_INPUT_1_VOLUME          0x687
+#define WM2200_DSP2LMIX_INPUT_2_SOURCE          0x688
+#define WM2200_DSP2LMIX_INPUT_2_VOLUME          0x689
+#define WM2200_DSP2LMIX_INPUT_3_SOURCE          0x68A
+#define WM2200_DSP2LMIX_INPUT_3_VOLUME          0x68B
+#define WM2200_DSP2LMIX_INPUT_4_SOURCE          0x68C
+#define WM2200_DSP2LMIX_INPUT_4_VOLUME          0x68D
+#define WM2200_DSP2RMIX_INPUT_1_SOURCE          0x68E
+#define WM2200_DSP2RMIX_INPUT_1_VOLUME          0x68F
+#define WM2200_DSP2RMIX_INPUT_2_SOURCE          0x690
+#define WM2200_DSP2RMIX_INPUT_2_VOLUME          0x691
+#define WM2200_DSP2RMIX_INPUT_3_SOURCE          0x692
+#define WM2200_DSP2RMIX_INPUT_3_VOLUME          0x693
+#define WM2200_DSP2RMIX_INPUT_4_SOURCE          0x694
+#define WM2200_DSP2RMIX_INPUT_4_VOLUME          0x695
+#define WM2200_DSP2AUX1MIX_INPUT_1_SOURCE       0x696
+#define WM2200_DSP2AUX2MIX_INPUT_1_SOURCE       0x697
+#define WM2200_DSP2AUX3MIX_INPUT_1_SOURCE       0x698
+#define WM2200_DSP2AUX4MIX_INPUT_1_SOURCE       0x699
+#define WM2200_DSP2AUX5MIX_INPUT_1_SOURCE       0x69A
+#define WM2200_DSP2AUX6MIX_INPUT_1_SOURCE       0x69B
+#define WM2200_GPIO_CTRL_1                      0x700
+#define WM2200_GPIO_CTRL_2                      0x701
+#define WM2200_GPIO_CTRL_3                      0x702
+#define WM2200_GPIO_CTRL_4                      0x703
+#define WM2200_ADPS1_IRQ0                       0x707
+#define WM2200_ADPS1_IRQ1                       0x708
+#define WM2200_MISC_PAD_CTRL_1                  0x709
+#define WM2200_INTERRUPT_STATUS_1               0x800
+#define WM2200_INTERRUPT_STATUS_1_MASK          0x801
+#define WM2200_INTERRUPT_STATUS_2               0x802
+#define WM2200_INTERRUPT_RAW_STATUS_2           0x803
+#define WM2200_INTERRUPT_STATUS_2_MASK          0x804
+#define WM2200_INTERRUPT_CONTROL                0x808
+#define WM2200_EQL_1                            0x900
+#define WM2200_EQL_2                            0x901
+#define WM2200_EQL_3                            0x902
+#define WM2200_EQL_4                            0x903
+#define WM2200_EQL_5                            0x904
+#define WM2200_EQL_6                            0x905
+#define WM2200_EQL_7                            0x906
+#define WM2200_EQL_8                            0x907
+#define WM2200_EQL_9                            0x908
+#define WM2200_EQL_10                           0x909
+#define WM2200_EQL_11                           0x90A
+#define WM2200_EQL_12                           0x90B
+#define WM2200_EQL_13                           0x90C
+#define WM2200_EQL_14                           0x90D
+#define WM2200_EQL_15                           0x90E
+#define WM2200_EQL_16                           0x90F
+#define WM2200_EQL_17                           0x910
+#define WM2200_EQL_18                           0x911
+#define WM2200_EQL_19                           0x912
+#define WM2200_EQL_20                           0x913
+#define WM2200_EQR_1                            0x916
+#define WM2200_EQR_2                            0x917
+#define WM2200_EQR_3                            0x918
+#define WM2200_EQR_4                            0x919
+#define WM2200_EQR_5                            0x91A
+#define WM2200_EQR_6                            0x91B
+#define WM2200_EQR_7                            0x91C
+#define WM2200_EQR_8                            0x91D
+#define WM2200_EQR_9                            0x91E
+#define WM2200_EQR_10                           0x91F
+#define WM2200_EQR_11                           0x920
+#define WM2200_EQR_12                           0x921
+#define WM2200_EQR_13                           0x922
+#define WM2200_EQR_14                           0x923
+#define WM2200_EQR_15                           0x924
+#define WM2200_EQR_16                           0x925
+#define WM2200_EQR_17                           0x926
+#define WM2200_EQR_18                           0x927
+#define WM2200_EQR_19                           0x928
+#define WM2200_EQR_20                           0x929
+#define WM2200_HPLPF1_1                         0x93E
+#define WM2200_HPLPF1_2                         0x93F
+#define WM2200_HPLPF2_1                         0x942
+#define WM2200_HPLPF2_2                         0x943
+#define WM2200_DSP1_CONTROL_1                   0xA00
+#define WM2200_DSP1_CONTROL_2                   0xA02
+#define WM2200_DSP1_CONTROL_3                   0xA03
+#define WM2200_DSP1_CONTROL_4                   0xA04
+#define WM2200_DSP1_CONTROL_5                   0xA06
+#define WM2200_DSP1_CONTROL_6                   0xA07
+#define WM2200_DSP1_CONTROL_7                   0xA08
+#define WM2200_DSP1_CONTROL_8                   0xA09
+#define WM2200_DSP1_CONTROL_9                   0xA0A
+#define WM2200_DSP1_CONTROL_10                  0xA0B
+#define WM2200_DSP1_CONTROL_11                  0xA0C
+#define WM2200_DSP1_CONTROL_12                  0xA0D
+#define WM2200_DSP1_CONTROL_13                  0xA0F
+#define WM2200_DSP1_CONTROL_14                  0xA10
+#define WM2200_DSP1_CONTROL_15                  0xA11
+#define WM2200_DSP1_CONTROL_16                  0xA12
+#define WM2200_DSP1_CONTROL_17                  0xA13
+#define WM2200_DSP1_CONTROL_18                  0xA14
+#define WM2200_DSP1_CONTROL_19                  0xA16
+#define WM2200_DSP1_CONTROL_20                  0xA17
+#define WM2200_DSP1_CONTROL_21                  0xA18
+#define WM2200_DSP1_CONTROL_22                  0xA1A
+#define WM2200_DSP1_CONTROL_23                  0xA1B
+#define WM2200_DSP1_CONTROL_24                  0xA1C
+#define WM2200_DSP1_CONTROL_25                  0xA1E
+#define WM2200_DSP1_CONTROL_26                  0xA20
+#define WM2200_DSP1_CONTROL_27                  0xA21
+#define WM2200_DSP1_CONTROL_28                  0xA22
+#define WM2200_DSP1_CONTROL_29                  0xA23
+#define WM2200_DSP1_CONTROL_30                  0xA24
+#define WM2200_DSP1_CONTROL_31                  0xA26
+#define WM2200_DSP2_CONTROL_1                   0xB00
+#define WM2200_DSP2_CONTROL_2                   0xB02
+#define WM2200_DSP2_CONTROL_3                   0xB03
+#define WM2200_DSP2_CONTROL_4                   0xB04
+#define WM2200_DSP2_CONTROL_5                   0xB06
+#define WM2200_DSP2_CONTROL_6                   0xB07
+#define WM2200_DSP2_CONTROL_7                   0xB08
+#define WM2200_DSP2_CONTROL_8                   0xB09
+#define WM2200_DSP2_CONTROL_9                   0xB0A
+#define WM2200_DSP2_CONTROL_10                  0xB0B
+#define WM2200_DSP2_CONTROL_11                  0xB0C
+#define WM2200_DSP2_CONTROL_12                  0xB0D
+#define WM2200_DSP2_CONTROL_13                  0xB0F
+#define WM2200_DSP2_CONTROL_14                  0xB10
+#define WM2200_DSP2_CONTROL_15                  0xB11
+#define WM2200_DSP2_CONTROL_16                  0xB12
+#define WM2200_DSP2_CONTROL_17                  0xB13
+#define WM2200_DSP2_CONTROL_18                  0xB14
+#define WM2200_DSP2_CONTROL_19                  0xB16
+#define WM2200_DSP2_CONTROL_20                  0xB17
+#define WM2200_DSP2_CONTROL_21                  0xB18
+#define WM2200_DSP2_CONTROL_22                  0xB1A
+#define WM2200_DSP2_CONTROL_23                  0xB1B
+#define WM2200_DSP2_CONTROL_24                  0xB1C
+#define WM2200_DSP2_CONTROL_25                  0xB1E
+#define WM2200_DSP2_CONTROL_26                  0xB20
+#define WM2200_DSP2_CONTROL_27                  0xB21
+#define WM2200_DSP2_CONTROL_28                  0xB22
+#define WM2200_DSP2_CONTROL_29                  0xB23
+#define WM2200_DSP2_CONTROL_30                  0xB24
+#define WM2200_DSP2_CONTROL_31                  0xB26
+#define WM2200_ANC_CTRL1                        0xD00
+#define WM2200_ANC_CTRL2                        0xD01
+#define WM2200_ANC_CTRL3                        0xD02
+#define WM2200_ANC_CTRL7                        0xD08
+#define WM2200_ANC_CTRL8                        0xD09
+#define WM2200_ANC_CTRL9                        0xD0A
+#define WM2200_ANC_CTRL10                       0xD0B
+#define WM2200_ANC_CTRL11                       0xD0C
+#define WM2200_ANC_CTRL12                       0xD0D
+#define WM2200_ANC_CTRL13                       0xD0E
+#define WM2200_ANC_CTRL14                       0xD0F
+#define WM2200_ANC_CTRL15                       0xD10
+#define WM2200_ANC_CTRL16                       0xD11
+#define WM2200_ANC_CTRL17                       0xD12
+#define WM2200_ANC_CTRL18                       0xD15
+#define WM2200_ANC_CTRL19                       0xD16
+#define WM2200_ANC_CTRL20                       0xD17
+#define WM2200_ANC_CTRL21                       0xD18
+#define WM2200_ANC_CTRL22                       0xD19
+#define WM2200_ANC_CTRL23                       0xD1A
+#define WM2200_ANC_CTRL24                       0xD1B
+#define WM2200_ANC_CTRL25                       0xD1C
+#define WM2200_ANC_CTRL26                       0xD1D
+#define WM2200_ANC_CTRL27                       0xD1E
+#define WM2200_ANC_CTRL28                       0xD1F
+#define WM2200_ANC_CTRL29                       0xD20
+#define WM2200_ANC_CTRL30                       0xD21
+#define WM2200_ANC_CTRL31                       0xD23
+#define WM2200_ANC_CTRL32                       0xD24
+#define WM2200_ANC_CTRL33                       0xD25
+#define WM2200_ANC_CTRL34                       0xD27
+#define WM2200_ANC_CTRL35                       0xD28
+#define WM2200_ANC_CTRL36                       0xD29
+#define WM2200_ANC_CTRL37                       0xD2A
+#define WM2200_ANC_CTRL38                       0xD2B
+#define WM2200_ANC_CTRL39                       0xD2C
+#define WM2200_ANC_CTRL40                       0xD2D
+#define WM2200_ANC_CTRL41                       0xD2E
+#define WM2200_ANC_CTRL42                       0xD2F
+#define WM2200_ANC_CTRL43                       0xD30
+#define WM2200_ANC_CTRL44                       0xD31
+#define WM2200_ANC_CTRL45                       0xD32
+#define WM2200_ANC_CTRL46                       0xD33
+#define WM2200_ANC_CTRL47                       0xD34
+#define WM2200_ANC_CTRL48                       0xD35
+#define WM2200_ANC_CTRL49                       0xD36
+#define WM2200_ANC_CTRL50                       0xD37
+#define WM2200_ANC_CTRL51                       0xD38
+#define WM2200_ANC_CTRL52                       0xD39
+#define WM2200_ANC_CTRL53                       0xD3A
+#define WM2200_ANC_CTRL54                       0xD3B
+#define WM2200_ANC_CTRL55                       0xD3C
+#define WM2200_ANC_CTRL56                       0xD3D
+#define WM2200_ANC_CTRL57                       0xD3E
+#define WM2200_ANC_CTRL58                       0xD3F
+#define WM2200_ANC_CTRL59                       0xD40
+#define WM2200_ANC_CTRL60                       0xD41
+#define WM2200_ANC_CTRL61                       0xD42
+#define WM2200_ANC_CTRL62                       0xD43
+#define WM2200_ANC_CTRL63                       0xD44
+#define WM2200_ANC_CTRL64                       0xD45
+#define WM2200_ANC_CTRL65                       0xD46
+#define WM2200_ANC_CTRL66                       0xD47
+#define WM2200_ANC_CTRL67                       0xD48
+#define WM2200_ANC_CTRL68                       0xD49
+#define WM2200_ANC_CTRL69                       0xD4A
+#define WM2200_ANC_CTRL70                       0xD4B
+#define WM2200_ANC_CTRL71                       0xD4C
+#define WM2200_ANC_CTRL72                       0xD4D
+#define WM2200_ANC_CTRL73                       0xD4E
+#define WM2200_ANC_CTRL74                       0xD4F
+#define WM2200_ANC_CTRL75                       0xD50
+#define WM2200_ANC_CTRL76                       0xD51
+#define WM2200_ANC_CTRL77                       0xD52
+#define WM2200_ANC_CTRL78                       0xD53
+#define WM2200_ANC_CTRL79                       0xD54
+#define WM2200_ANC_CTRL80                       0xD55
+#define WM2200_ANC_CTRL81                       0xD56
+#define WM2200_ANC_CTRL82                       0xD57
+#define WM2200_ANC_CTRL83                       0xD58
+#define WM2200_ANC_CTRL84                       0xD5B
+#define WM2200_ANC_CTRL85                       0xD5C
+#define WM2200_ANC_CTRL86                       0xD5F
+#define WM2200_ANC_CTRL87                       0xD60
+#define WM2200_ANC_CTRL88                       0xD61
+#define WM2200_ANC_CTRL89                       0xD62
+#define WM2200_ANC_CTRL90                       0xD63
+#define WM2200_ANC_CTRL91                       0xD64
+#define WM2200_ANC_CTRL92                       0xD65
+#define WM2200_ANC_CTRL93                       0xD66
+#define WM2200_ANC_CTRL94                       0xD67
+#define WM2200_ANC_CTRL95                       0xD68
+#define WM2200_ANC_CTRL96                       0xD69
+#define WM2200_DSP1_DM_0                        0x3000
+#define WM2200_DSP1_DM_1                        0x3001
+#define WM2200_DSP1_DM_2                        0x3002
+#define WM2200_DSP1_DM_3                        0x3003
+#define WM2200_DSP1_DM_2044                     0x37FC
+#define WM2200_DSP1_DM_2045                     0x37FD
+#define WM2200_DSP1_DM_2046                     0x37FE
+#define WM2200_DSP1_DM_2047                     0x37FF
+#define WM2200_DSP1_PM_0                        0x3800
+#define WM2200_DSP1_PM_1                        0x3801
+#define WM2200_DSP1_PM_2                        0x3802
+#define WM2200_DSP1_PM_3                        0x3803
+#define WM2200_DSP1_PM_4                        0x3804
+#define WM2200_DSP1_PM_5                        0x3805
+#define WM2200_DSP1_PM_762                      0x3AFA
+#define WM2200_DSP1_PM_763                      0x3AFB
+#define WM2200_DSP1_PM_764                      0x3AFC
+#define WM2200_DSP1_PM_765                      0x3AFD
+#define WM2200_DSP1_PM_766                      0x3AFE
+#define WM2200_DSP1_PM_767                      0x3AFF
+#define WM2200_DSP1_ZM_0                        0x3C00
+#define WM2200_DSP1_ZM_1                        0x3C01
+#define WM2200_DSP1_ZM_2                        0x3C02
+#define WM2200_DSP1_ZM_3                        0x3C03
+#define WM2200_DSP1_ZM_1020                     0x3FFC
+#define WM2200_DSP1_ZM_1021                     0x3FFD
+#define WM2200_DSP1_ZM_1022                     0x3FFE
+#define WM2200_DSP1_ZM_1023                     0x3FFF
+#define WM2200_DSP2_DM_0                        0x4000
+#define WM2200_DSP2_DM_1                        0x4001
+#define WM2200_DSP2_DM_2                        0x4002
+#define WM2200_DSP2_DM_3                        0x4003
+#define WM2200_DSP2_DM_2044                     0x47FC
+#define WM2200_DSP2_DM_2045                     0x47FD
+#define WM2200_DSP2_DM_2046                     0x47FE
+#define WM2200_DSP2_DM_2047                     0x47FF
+#define WM2200_DSP2_PM_0                        0x4800
+#define WM2200_DSP2_PM_1                        0x4801
+#define WM2200_DSP2_PM_2                        0x4802
+#define WM2200_DSP2_PM_3                        0x4803
+#define WM2200_DSP2_PM_4                        0x4804
+#define WM2200_DSP2_PM_5                        0x4805
+#define WM2200_DSP2_PM_762                      0x4AFA
+#define WM2200_DSP2_PM_763                      0x4AFB
+#define WM2200_DSP2_PM_764                      0x4AFC
+#define WM2200_DSP2_PM_765                      0x4AFD
+#define WM2200_DSP2_PM_766                      0x4AFE
+#define WM2200_DSP2_PM_767                      0x4AFF
+#define WM2200_DSP2_ZM_0                        0x4C00
+#define WM2200_DSP2_ZM_1                        0x4C01
+#define WM2200_DSP2_ZM_2                        0x4C02
+#define WM2200_DSP2_ZM_3                        0x4C03
+#define WM2200_DSP2_ZM_1020                     0x4FFC
+#define WM2200_DSP2_ZM_1021                     0x4FFD
+#define WM2200_DSP2_ZM_1022                     0x4FFE
+#define WM2200_DSP2_ZM_1023                     0x4FFF
+
+#define WM2200_REGISTER_COUNT                   494
+#define WM2200_MAX_REGISTER                     0x4FFF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - software reset
+ */
+#define WM2200_SW_RESET_CHIP_ID1_MASK           0xFFFF  /* SW_RESET_CHIP_ID1 - [15:0] */
+#define WM2200_SW_RESET_CHIP_ID1_SHIFT               0  /* SW_RESET_CHIP_ID1 - [15:0] */
+#define WM2200_SW_RESET_CHIP_ID1_WIDTH              16  /* SW_RESET_CHIP_ID1 - [15:0] */
+
+/*
+ * R1 (0x01) - Device Revision
+ */
+#define WM2200_DEVICE_REVISION_MASK             0x000F  /* DEVICE_REVISION - [3:0] */
+#define WM2200_DEVICE_REVISION_SHIFT                 0  /* DEVICE_REVISION - [3:0] */
+#define WM2200_DEVICE_REVISION_WIDTH                 4  /* DEVICE_REVISION - [3:0] */
+
+/*
+ * R11 (0x0B) - Tone Generator 1
+ */
+#define WM2200_TONE_ENA                         0x0001  /* TONE_ENA */
+#define WM2200_TONE_ENA_MASK                    0x0001  /* TONE_ENA */
+#define WM2200_TONE_ENA_SHIFT                        0  /* TONE_ENA */
+#define WM2200_TONE_ENA_WIDTH                        1  /* TONE_ENA */
+
+/*
+ * R258 (0x102) - Clocking 3
+ */
+#define WM2200_SYSCLK_FREQ_MASK                 0x0700  /* SYSCLK_FREQ - [10:8] */
+#define WM2200_SYSCLK_FREQ_SHIFT                     8  /* SYSCLK_FREQ - [10:8] */
+#define WM2200_SYSCLK_FREQ_WIDTH                     3  /* SYSCLK_FREQ - [10:8] */
+#define WM2200_SYSCLK_ENA                       0x0040  /* SYSCLK_ENA */
+#define WM2200_SYSCLK_ENA_MASK                  0x0040  /* SYSCLK_ENA */
+#define WM2200_SYSCLK_ENA_SHIFT                      6  /* SYSCLK_ENA */
+#define WM2200_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+#define WM2200_SYSCLK_SRC_MASK                  0x000F  /* SYSCLK_SRC - [3:0] */
+#define WM2200_SYSCLK_SRC_SHIFT                      0  /* SYSCLK_SRC - [3:0] */
+#define WM2200_SYSCLK_SRC_WIDTH                      4  /* SYSCLK_SRC - [3:0] */
+
+/*
+ * R259 (0x103) - Clocking 4
+ */
+#define WM2200_SAMPLE_RATE_1_MASK               0x001F  /* SAMPLE_RATE_1 - [4:0] */
+#define WM2200_SAMPLE_RATE_1_SHIFT                   0  /* SAMPLE_RATE_1 - [4:0] */
+#define WM2200_SAMPLE_RATE_1_WIDTH                   5  /* SAMPLE_RATE_1 - [4:0] */
+
+/*
+ * R273 (0x111) - FLL Control 1
+ */
+#define WM2200_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM2200_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM2200_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM2200_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R274 (0x112) - FLL Control 2
+ */
+#define WM2200_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM2200_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM2200_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM2200_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM2200_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM2200_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R275 (0x113) - FLL Control 3
+ */
+#define WM2200_FLL_FRACN_ENA                    0x0001  /* FLL_FRACN_ENA */
+#define WM2200_FLL_FRACN_ENA_MASK               0x0001  /* FLL_FRACN_ENA */
+#define WM2200_FLL_FRACN_ENA_SHIFT                   0  /* FLL_FRACN_ENA */
+#define WM2200_FLL_FRACN_ENA_WIDTH                   1  /* FLL_FRACN_ENA */
+
+/*
+ * R276 (0x114) - FLL Control 4
+ */
+#define WM2200_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
+#define WM2200_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
+#define WM2200_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
+
+/*
+ * R278 (0x116) - FLL Control 6
+ */
+#define WM2200_FLL_N_MASK                       0x03FF  /* FLL_N - [9:0] */
+#define WM2200_FLL_N_SHIFT                           0  /* FLL_N - [9:0] */
+#define WM2200_FLL_N_WIDTH                          10  /* FLL_N - [9:0] */
+
+/*
+ * R279 (0x117) - FLL Control 7
+ */
+#define WM2200_FLL_CLK_REF_DIV_MASK             0x0030  /* FLL_CLK_REF_DIV - [5:4] */
+#define WM2200_FLL_CLK_REF_DIV_SHIFT                 4  /* FLL_CLK_REF_DIV - [5:4] */
+#define WM2200_FLL_CLK_REF_DIV_WIDTH                 2  /* FLL_CLK_REF_DIV - [5:4] */
+#define WM2200_FLL_CLK_REF_SRC_MASK             0x0003  /* FLL_CLK_REF_SRC - [1:0] */
+#define WM2200_FLL_CLK_REF_SRC_SHIFT                 0  /* FLL_CLK_REF_SRC - [1:0] */
+#define WM2200_FLL_CLK_REF_SRC_WIDTH                 2  /* FLL_CLK_REF_SRC - [1:0] */
+
+/*
+ * R281 (0x119) - FLL EFS 1
+ */
+#define WM2200_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
+#define WM2200_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
+#define WM2200_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R282 (0x11A) - FLL EFS 2
+ */
+#define WM2200_FLL_EFS_ENA                      0x0001  /* FLL_EFS_ENA */
+#define WM2200_FLL_EFS_ENA_MASK                 0x0001  /* FLL_EFS_ENA */
+#define WM2200_FLL_EFS_ENA_SHIFT                     0  /* FLL_EFS_ENA */
+#define WM2200_FLL_EFS_ENA_WIDTH                     1  /* FLL_EFS_ENA */
+
+/*
+ * R512 (0x200) - Mic Charge Pump 1
+ */
+#define WM2200_CPMIC_BYPASS_MODE                0x0020  /* CPMIC_BYPASS_MODE */
+#define WM2200_CPMIC_BYPASS_MODE_MASK           0x0020  /* CPMIC_BYPASS_MODE */
+#define WM2200_CPMIC_BYPASS_MODE_SHIFT               5  /* CPMIC_BYPASS_MODE */
+#define WM2200_CPMIC_BYPASS_MODE_WIDTH               1  /* CPMIC_BYPASS_MODE */
+#define WM2200_CPMIC_ENA                        0x0001  /* CPMIC_ENA */
+#define WM2200_CPMIC_ENA_MASK                   0x0001  /* CPMIC_ENA */
+#define WM2200_CPMIC_ENA_SHIFT                       0  /* CPMIC_ENA */
+#define WM2200_CPMIC_ENA_WIDTH                       1  /* CPMIC_ENA */
+
+/*
+ * R513 (0x201) - Mic Charge Pump 2
+ */
+#define WM2200_CPMIC_LDO_VSEL_OVERRIDE_MASK     0xF800  /* CPMIC_LDO_VSEL_OVERRIDE - [15:11] */
+#define WM2200_CPMIC_LDO_VSEL_OVERRIDE_SHIFT        11  /* CPMIC_LDO_VSEL_OVERRIDE - [15:11] */
+#define WM2200_CPMIC_LDO_VSEL_OVERRIDE_WIDTH         5  /* CPMIC_LDO_VSEL_OVERRIDE - [15:11] */
+
+/*
+ * R514 (0x202) - DM Charge Pump 1
+ */
+#define WM2200_CPDM_ENA                         0x0001  /* CPDM_ENA */
+#define WM2200_CPDM_ENA_MASK                    0x0001  /* CPDM_ENA */
+#define WM2200_CPDM_ENA_SHIFT                        0  /* CPDM_ENA */
+#define WM2200_CPDM_ENA_WIDTH                        1  /* CPDM_ENA */
+
+/*
+ * R524 (0x20C) - Mic Bias Ctrl 1
+ */
+#define WM2200_MICB1_DISCH                      0x0040  /* MICB1_DISCH */
+#define WM2200_MICB1_DISCH_MASK                 0x0040  /* MICB1_DISCH */
+#define WM2200_MICB1_DISCH_SHIFT                     6  /* MICB1_DISCH */
+#define WM2200_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
+#define WM2200_MICB1_RATE                       0x0020  /* MICB1_RATE */
+#define WM2200_MICB1_RATE_MASK                  0x0020  /* MICB1_RATE */
+#define WM2200_MICB1_RATE_SHIFT                      5  /* MICB1_RATE */
+#define WM2200_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
+#define WM2200_MICB1_LVL_MASK                   0x001C  /* MICB1_LVL - [4:2] */
+#define WM2200_MICB1_LVL_SHIFT                       2  /* MICB1_LVL - [4:2] */
+#define WM2200_MICB1_LVL_WIDTH                       3  /* MICB1_LVL - [4:2] */
+#define WM2200_MICB1_MODE                       0x0002  /* MICB1_MODE */
+#define WM2200_MICB1_MODE_MASK                  0x0002  /* MICB1_MODE */
+#define WM2200_MICB1_MODE_SHIFT                      1  /* MICB1_MODE */
+#define WM2200_MICB1_MODE_WIDTH                      1  /* MICB1_MODE */
+#define WM2200_MICB1_ENA                        0x0001  /* MICB1_ENA */
+#define WM2200_MICB1_ENA_MASK                   0x0001  /* MICB1_ENA */
+#define WM2200_MICB1_ENA_SHIFT                       0  /* MICB1_ENA */
+#define WM2200_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
+
+/*
+ * R525 (0x20D) - Mic Bias Ctrl 2
+ */
+#define WM2200_MICB2_DISCH                      0x0040  /* MICB2_DISCH */
+#define WM2200_MICB2_DISCH_MASK                 0x0040  /* MICB2_DISCH */
+#define WM2200_MICB2_DISCH_SHIFT                     6  /* MICB2_DISCH */
+#define WM2200_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
+#define WM2200_MICB2_RATE                       0x0020  /* MICB2_RATE */
+#define WM2200_MICB2_RATE_MASK                  0x0020  /* MICB2_RATE */
+#define WM2200_MICB2_RATE_SHIFT                      5  /* MICB2_RATE */
+#define WM2200_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
+#define WM2200_MICB2_LVL_MASK                   0x001C  /* MICB2_LVL - [4:2] */
+#define WM2200_MICB2_LVL_SHIFT                       2  /* MICB2_LVL - [4:2] */
+#define WM2200_MICB2_LVL_WIDTH                       3  /* MICB2_LVL - [4:2] */
+#define WM2200_MICB2_MODE                       0x0002  /* MICB2_MODE */
+#define WM2200_MICB2_MODE_MASK                  0x0002  /* MICB2_MODE */
+#define WM2200_MICB2_MODE_SHIFT                      1  /* MICB2_MODE */
+#define WM2200_MICB2_MODE_WIDTH                      1  /* MICB2_MODE */
+#define WM2200_MICB2_ENA                        0x0001  /* MICB2_ENA */
+#define WM2200_MICB2_ENA_MASK                   0x0001  /* MICB2_ENA */
+#define WM2200_MICB2_ENA_SHIFT                       0  /* MICB2_ENA */
+#define WM2200_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
+
+/*
+ * R527 (0x20F) - Ear Piece Ctrl 1
+ */
+#define WM2200_EPD_LP_ENA                       0x4000  /* EPD_LP_ENA */
+#define WM2200_EPD_LP_ENA_MASK                  0x4000  /* EPD_LP_ENA */
+#define WM2200_EPD_LP_ENA_SHIFT                     14  /* EPD_LP_ENA */
+#define WM2200_EPD_LP_ENA_WIDTH                      1  /* EPD_LP_ENA */
+#define WM2200_EPD_OUTP_LP_ENA                  0x2000  /* EPD_OUTP_LP_ENA */
+#define WM2200_EPD_OUTP_LP_ENA_MASK             0x2000  /* EPD_OUTP_LP_ENA */
+#define WM2200_EPD_OUTP_LP_ENA_SHIFT                13  /* EPD_OUTP_LP_ENA */
+#define WM2200_EPD_OUTP_LP_ENA_WIDTH                 1  /* EPD_OUTP_LP_ENA */
+#define WM2200_EPD_RMV_SHRT_LP                  0x1000  /* EPD_RMV_SHRT_LP */
+#define WM2200_EPD_RMV_SHRT_LP_MASK             0x1000  /* EPD_RMV_SHRT_LP */
+#define WM2200_EPD_RMV_SHRT_LP_SHIFT                12  /* EPD_RMV_SHRT_LP */
+#define WM2200_EPD_RMV_SHRT_LP_WIDTH                 1  /* EPD_RMV_SHRT_LP */
+#define WM2200_EPD_LN_ENA                       0x0800  /* EPD_LN_ENA */
+#define WM2200_EPD_LN_ENA_MASK                  0x0800  /* EPD_LN_ENA */
+#define WM2200_EPD_LN_ENA_SHIFT                     11  /* EPD_LN_ENA */
+#define WM2200_EPD_LN_ENA_WIDTH                      1  /* EPD_LN_ENA */
+#define WM2200_EPD_OUTP_LN_ENA                  0x0400  /* EPD_OUTP_LN_ENA */
+#define WM2200_EPD_OUTP_LN_ENA_MASK             0x0400  /* EPD_OUTP_LN_ENA */
+#define WM2200_EPD_OUTP_LN_ENA_SHIFT                10  /* EPD_OUTP_LN_ENA */
+#define WM2200_EPD_OUTP_LN_ENA_WIDTH                 1  /* EPD_OUTP_LN_ENA */
+#define WM2200_EPD_RMV_SHRT_LN                  0x0200  /* EPD_RMV_SHRT_LN */
+#define WM2200_EPD_RMV_SHRT_LN_MASK             0x0200  /* EPD_RMV_SHRT_LN */
+#define WM2200_EPD_RMV_SHRT_LN_SHIFT                 9  /* EPD_RMV_SHRT_LN */
+#define WM2200_EPD_RMV_SHRT_LN_WIDTH                 1  /* EPD_RMV_SHRT_LN */
+
+/*
+ * R528 (0x210) - Ear Piece Ctrl 2
+ */
+#define WM2200_EPD_RP_ENA                       0x4000  /* EPD_RP_ENA */
+#define WM2200_EPD_RP_ENA_MASK                  0x4000  /* EPD_RP_ENA */
+#define WM2200_EPD_RP_ENA_SHIFT                     14  /* EPD_RP_ENA */
+#define WM2200_EPD_RP_ENA_WIDTH                      1  /* EPD_RP_ENA */
+#define WM2200_EPD_OUTP_RP_ENA                  0x2000  /* EPD_OUTP_RP_ENA */
+#define WM2200_EPD_OUTP_RP_ENA_MASK             0x2000  /* EPD_OUTP_RP_ENA */
+#define WM2200_EPD_OUTP_RP_ENA_SHIFT                13  /* EPD_OUTP_RP_ENA */
+#define WM2200_EPD_OUTP_RP_ENA_WIDTH                 1  /* EPD_OUTP_RP_ENA */
+#define WM2200_EPD_RMV_SHRT_RP                  0x1000  /* EPD_RMV_SHRT_RP */
+#define WM2200_EPD_RMV_SHRT_RP_MASK             0x1000  /* EPD_RMV_SHRT_RP */
+#define WM2200_EPD_RMV_SHRT_RP_SHIFT                12  /* EPD_RMV_SHRT_RP */
+#define WM2200_EPD_RMV_SHRT_RP_WIDTH                 1  /* EPD_RMV_SHRT_RP */
+#define WM2200_EPD_RN_ENA                       0x0800  /* EPD_RN_ENA */
+#define WM2200_EPD_RN_ENA_MASK                  0x0800  /* EPD_RN_ENA */
+#define WM2200_EPD_RN_ENA_SHIFT                     11  /* EPD_RN_ENA */
+#define WM2200_EPD_RN_ENA_WIDTH                      1  /* EPD_RN_ENA */
+#define WM2200_EPD_OUTP_RN_ENA                  0x0400  /* EPD_OUTP_RN_ENA */
+#define WM2200_EPD_OUTP_RN_ENA_MASK             0x0400  /* EPD_OUTP_RN_ENA */
+#define WM2200_EPD_OUTP_RN_ENA_SHIFT                10  /* EPD_OUTP_RN_ENA */
+#define WM2200_EPD_OUTP_RN_ENA_WIDTH                 1  /* EPD_OUTP_RN_ENA */
+#define WM2200_EPD_RMV_SHRT_RN                  0x0200  /* EPD_RMV_SHRT_RN */
+#define WM2200_EPD_RMV_SHRT_RN_MASK             0x0200  /* EPD_RMV_SHRT_RN */
+#define WM2200_EPD_RMV_SHRT_RN_SHIFT                 9  /* EPD_RMV_SHRT_RN */
+#define WM2200_EPD_RMV_SHRT_RN_WIDTH                 1  /* EPD_RMV_SHRT_RN */
+
+/*
+ * R769 (0x301) - Input Enables
+ */
+#define WM2200_IN3L_ENA                         0x0020  /* IN3L_ENA */
+#define WM2200_IN3L_ENA_MASK                    0x0020  /* IN3L_ENA */
+#define WM2200_IN3L_ENA_SHIFT                        5  /* IN3L_ENA */
+#define WM2200_IN3L_ENA_WIDTH                        1  /* IN3L_ENA */
+#define WM2200_IN3R_ENA                         0x0010  /* IN3R_ENA */
+#define WM2200_IN3R_ENA_MASK                    0x0010  /* IN3R_ENA */
+#define WM2200_IN3R_ENA_SHIFT                        4  /* IN3R_ENA */
+#define WM2200_IN3R_ENA_WIDTH                        1  /* IN3R_ENA */
+#define WM2200_IN2L_ENA                         0x0008  /* IN2L_ENA */
+#define WM2200_IN2L_ENA_MASK                    0x0008  /* IN2L_ENA */
+#define WM2200_IN2L_ENA_SHIFT                        3  /* IN2L_ENA */
+#define WM2200_IN2L_ENA_WIDTH                        1  /* IN2L_ENA */
+#define WM2200_IN2R_ENA                         0x0004  /* IN2R_ENA */
+#define WM2200_IN2R_ENA_MASK                    0x0004  /* IN2R_ENA */
+#define WM2200_IN2R_ENA_SHIFT                        2  /* IN2R_ENA */
+#define WM2200_IN2R_ENA_WIDTH                        1  /* IN2R_ENA */
+#define WM2200_IN1L_ENA                         0x0002  /* IN1L_ENA */
+#define WM2200_IN1L_ENA_MASK                    0x0002  /* IN1L_ENA */
+#define WM2200_IN1L_ENA_SHIFT                        1  /* IN1L_ENA */
+#define WM2200_IN1L_ENA_WIDTH                        1  /* IN1L_ENA */
+#define WM2200_IN1R_ENA                         0x0001  /* IN1R_ENA */
+#define WM2200_IN1R_ENA_MASK                    0x0001  /* IN1R_ENA */
+#define WM2200_IN1R_ENA_SHIFT                        0  /* IN1R_ENA */
+#define WM2200_IN1R_ENA_WIDTH                        1  /* IN1R_ENA */
+
+/*
+ * R770 (0x302) - IN1L Control
+ */
+#define WM2200_IN1_OSR                          0x2000  /* IN1_OSR */
+#define WM2200_IN1_OSR_MASK                     0x2000  /* IN1_OSR */
+#define WM2200_IN1_OSR_SHIFT                        13  /* IN1_OSR */
+#define WM2200_IN1_OSR_WIDTH                         1  /* IN1_OSR */
+#define WM2200_IN1_DMIC_SUP_MASK                0x1800  /* IN1_DMIC_SUP - [12:11] */
+#define WM2200_IN1_DMIC_SUP_SHIFT                   11  /* IN1_DMIC_SUP - [12:11] */
+#define WM2200_IN1_DMIC_SUP_WIDTH                    2  /* IN1_DMIC_SUP - [12:11] */
+#define WM2200_IN1_MODE_MASK                    0x0600  /* IN1_MODE - [10:9] */
+#define WM2200_IN1_MODE_SHIFT                        9  /* IN1_MODE - [10:9] */
+#define WM2200_IN1_MODE_WIDTH                        2  /* IN1_MODE - [10:9] */
+#define WM2200_IN1L_PGA_VOL_MASK                0x00FE  /* IN1L_PGA_VOL - [7:1] */
+#define WM2200_IN1L_PGA_VOL_SHIFT                    1  /* IN1L_PGA_VOL - [7:1] */
+#define WM2200_IN1L_PGA_VOL_WIDTH                    7  /* IN1L_PGA_VOL - [7:1] */
+
+/*
+ * R771 (0x303) - IN1R Control
+ */
+#define WM2200_IN1R_PGA_VOL_MASK                0x00FE  /* IN1R_PGA_VOL - [7:1] */
+#define WM2200_IN1R_PGA_VOL_SHIFT                    1  /* IN1R_PGA_VOL - [7:1] */
+#define WM2200_IN1R_PGA_VOL_WIDTH                    7  /* IN1R_PGA_VOL - [7:1] */
+
+/*
+ * R772 (0x304) - IN2L Control
+ */
+#define WM2200_IN2_OSR                          0x2000  /* IN2_OSR */
+#define WM2200_IN2_OSR_MASK                     0x2000  /* IN2_OSR */
+#define WM2200_IN2_OSR_SHIFT                        13  /* IN2_OSR */
+#define WM2200_IN2_OSR_WIDTH                         1  /* IN2_OSR */
+#define WM2200_IN2_DMIC_SUP_MASK                0x1800  /* IN2_DMIC_SUP - [12:11] */
+#define WM2200_IN2_DMIC_SUP_SHIFT                   11  /* IN2_DMIC_SUP - [12:11] */
+#define WM2200_IN2_DMIC_SUP_WIDTH                    2  /* IN2_DMIC_SUP - [12:11] */
+#define WM2200_IN2_MODE_MASK                    0x0600  /* IN2_MODE - [10:9] */
+#define WM2200_IN2_MODE_SHIFT                        9  /* IN2_MODE - [10:9] */
+#define WM2200_IN2_MODE_WIDTH                        2  /* IN2_MODE - [10:9] */
+#define WM2200_IN2L_PGA_VOL_MASK                0x00FE  /* IN2L_PGA_VOL - [7:1] */
+#define WM2200_IN2L_PGA_VOL_SHIFT                    1  /* IN2L_PGA_VOL - [7:1] */
+#define WM2200_IN2L_PGA_VOL_WIDTH                    7  /* IN2L_PGA_VOL - [7:1] */
+
+/*
+ * R773 (0x305) - IN2R Control
+ */
+#define WM2200_IN2R_PGA_VOL_MASK                0x00FE  /* IN2R_PGA_VOL - [7:1] */
+#define WM2200_IN2R_PGA_VOL_SHIFT                    1  /* IN2R_PGA_VOL - [7:1] */
+#define WM2200_IN2R_PGA_VOL_WIDTH                    7  /* IN2R_PGA_VOL - [7:1] */
+
+/*
+ * R774 (0x306) - IN3L Control
+ */
+#define WM2200_IN3_OSR                          0x2000  /* IN3_OSR */
+#define WM2200_IN3_OSR_MASK                     0x2000  /* IN3_OSR */
+#define WM2200_IN3_OSR_SHIFT                        13  /* IN3_OSR */
+#define WM2200_IN3_OSR_WIDTH                         1  /* IN3_OSR */
+#define WM2200_IN3_DMIC_SUP_MASK                0x1800  /* IN3_DMIC_SUP - [12:11] */
+#define WM2200_IN3_DMIC_SUP_SHIFT                   11  /* IN3_DMIC_SUP - [12:11] */
+#define WM2200_IN3_DMIC_SUP_WIDTH                    2  /* IN3_DMIC_SUP - [12:11] */
+#define WM2200_IN3_MODE_MASK                    0x0600  /* IN3_MODE - [10:9] */
+#define WM2200_IN3_MODE_SHIFT                        9  /* IN3_MODE - [10:9] */
+#define WM2200_IN3_MODE_WIDTH                        2  /* IN3_MODE - [10:9] */
+#define WM2200_IN3L_PGA_VOL_MASK                0x00FE  /* IN3L_PGA_VOL - [7:1] */
+#define WM2200_IN3L_PGA_VOL_SHIFT                    1  /* IN3L_PGA_VOL - [7:1] */
+#define WM2200_IN3L_PGA_VOL_WIDTH                    7  /* IN3L_PGA_VOL - [7:1] */
+
+/*
+ * R775 (0x307) - IN3R Control
+ */
+#define WM2200_IN3R_PGA_VOL_MASK                0x00FE  /* IN3R_PGA_VOL - [7:1] */
+#define WM2200_IN3R_PGA_VOL_SHIFT                    1  /* IN3R_PGA_VOL - [7:1] */
+#define WM2200_IN3R_PGA_VOL_WIDTH                    7  /* IN3R_PGA_VOL - [7:1] */
+
+/*
+ * R778 (0x30A) - RXANC_SRC
+ */
+#define WM2200_IN_RXANC_SEL_MASK                0x0007  /* IN_RXANC_SEL - [2:0] */
+#define WM2200_IN_RXANC_SEL_SHIFT                    0  /* IN_RXANC_SEL - [2:0] */
+#define WM2200_IN_RXANC_SEL_WIDTH                    3  /* IN_RXANC_SEL - [2:0] */
+
+/*
+ * R779 (0x30B) - Input Volume Ramp
+ */
+#define WM2200_IN_VD_RAMP_MASK                  0x0070  /* IN_VD_RAMP - [6:4] */
+#define WM2200_IN_VD_RAMP_SHIFT                      4  /* IN_VD_RAMP - [6:4] */
+#define WM2200_IN_VD_RAMP_WIDTH                      3  /* IN_VD_RAMP - [6:4] */
+#define WM2200_IN_VI_RAMP_MASK                  0x0007  /* IN_VI_RAMP - [2:0] */
+#define WM2200_IN_VI_RAMP_SHIFT                      0  /* IN_VI_RAMP - [2:0] */
+#define WM2200_IN_VI_RAMP_WIDTH                      3  /* IN_VI_RAMP - [2:0] */
+
+/*
+ * R780 (0x30C) - ADC Digital Volume 1L
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN1L_MUTE                        0x0100  /* IN1L_MUTE */
+#define WM2200_IN1L_MUTE_MASK                   0x0100  /* IN1L_MUTE */
+#define WM2200_IN1L_MUTE_SHIFT                       8  /* IN1L_MUTE */
+#define WM2200_IN1L_MUTE_WIDTH                       1  /* IN1L_MUTE */
+#define WM2200_IN1L_DIG_VOL_MASK                0x00FF  /* IN1L_DIG_VOL - [7:0] */
+#define WM2200_IN1L_DIG_VOL_SHIFT                    0  /* IN1L_DIG_VOL - [7:0] */
+#define WM2200_IN1L_DIG_VOL_WIDTH                    8  /* IN1L_DIG_VOL - [7:0] */
+
+/*
+ * R781 (0x30D) - ADC Digital Volume 1R
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN1R_MUTE                        0x0100  /* IN1R_MUTE */
+#define WM2200_IN1R_MUTE_MASK                   0x0100  /* IN1R_MUTE */
+#define WM2200_IN1R_MUTE_SHIFT                       8  /* IN1R_MUTE */
+#define WM2200_IN1R_MUTE_WIDTH                       1  /* IN1R_MUTE */
+#define WM2200_IN1R_DIG_VOL_MASK                0x00FF  /* IN1R_DIG_VOL - [7:0] */
+#define WM2200_IN1R_DIG_VOL_SHIFT                    0  /* IN1R_DIG_VOL - [7:0] */
+#define WM2200_IN1R_DIG_VOL_WIDTH                    8  /* IN1R_DIG_VOL - [7:0] */
+
+/*
+ * R782 (0x30E) - ADC Digital Volume 2L
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN2L_MUTE                        0x0100  /* IN2L_MUTE */
+#define WM2200_IN2L_MUTE_MASK                   0x0100  /* IN2L_MUTE */
+#define WM2200_IN2L_MUTE_SHIFT                       8  /* IN2L_MUTE */
+#define WM2200_IN2L_MUTE_WIDTH                       1  /* IN2L_MUTE */
+#define WM2200_IN2L_DIG_VOL_MASK                0x00FF  /* IN2L_DIG_VOL - [7:0] */
+#define WM2200_IN2L_DIG_VOL_SHIFT                    0  /* IN2L_DIG_VOL - [7:0] */
+#define WM2200_IN2L_DIG_VOL_WIDTH                    8  /* IN2L_DIG_VOL - [7:0] */
+
+/*
+ * R783 (0x30F) - ADC Digital Volume 2R
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN2R_MUTE                        0x0100  /* IN2R_MUTE */
+#define WM2200_IN2R_MUTE_MASK                   0x0100  /* IN2R_MUTE */
+#define WM2200_IN2R_MUTE_SHIFT                       8  /* IN2R_MUTE */
+#define WM2200_IN2R_MUTE_WIDTH                       1  /* IN2R_MUTE */
+#define WM2200_IN2R_DIG_VOL_MASK                0x00FF  /* IN2R_DIG_VOL - [7:0] */
+#define WM2200_IN2R_DIG_VOL_SHIFT                    0  /* IN2R_DIG_VOL - [7:0] */
+#define WM2200_IN2R_DIG_VOL_WIDTH                    8  /* IN2R_DIG_VOL - [7:0] */
+
+/*
+ * R784 (0x310) - ADC Digital Volume 3L
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN3L_MUTE                        0x0100  /* IN3L_MUTE */
+#define WM2200_IN3L_MUTE_MASK                   0x0100  /* IN3L_MUTE */
+#define WM2200_IN3L_MUTE_SHIFT                       8  /* IN3L_MUTE */
+#define WM2200_IN3L_MUTE_WIDTH                       1  /* IN3L_MUTE */
+#define WM2200_IN3L_DIG_VOL_MASK                0x00FF  /* IN3L_DIG_VOL - [7:0] */
+#define WM2200_IN3L_DIG_VOL_SHIFT                    0  /* IN3L_DIG_VOL - [7:0] */
+#define WM2200_IN3L_DIG_VOL_WIDTH                    8  /* IN3L_DIG_VOL - [7:0] */
+
+/*
+ * R785 (0x311) - ADC Digital Volume 3R
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN3R_MUTE                        0x0100  /* IN3R_MUTE */
+#define WM2200_IN3R_MUTE_MASK                   0x0100  /* IN3R_MUTE */
+#define WM2200_IN3R_MUTE_SHIFT                       8  /* IN3R_MUTE */
+#define WM2200_IN3R_MUTE_WIDTH                       1  /* IN3R_MUTE */
+#define WM2200_IN3R_DIG_VOL_MASK                0x00FF  /* IN3R_DIG_VOL - [7:0] */
+#define WM2200_IN3R_DIG_VOL_SHIFT                    0  /* IN3R_DIG_VOL - [7:0] */
+#define WM2200_IN3R_DIG_VOL_WIDTH                    8  /* IN3R_DIG_VOL - [7:0] */
+
+/*
+ * R1024 (0x400) - Output Enables
+ */
+#define WM2200_OUT2L_ENA                        0x0008  /* OUT2L_ENA */
+#define WM2200_OUT2L_ENA_MASK                   0x0008  /* OUT2L_ENA */
+#define WM2200_OUT2L_ENA_SHIFT                       3  /* OUT2L_ENA */
+#define WM2200_OUT2L_ENA_WIDTH                       1  /* OUT2L_ENA */
+#define WM2200_OUT2R_ENA                        0x0004  /* OUT2R_ENA */
+#define WM2200_OUT2R_ENA_MASK                   0x0004  /* OUT2R_ENA */
+#define WM2200_OUT2R_ENA_SHIFT                       2  /* OUT2R_ENA */
+#define WM2200_OUT2R_ENA_WIDTH                       1  /* OUT2R_ENA */
+#define WM2200_OUT1L_ENA                        0x0002  /* OUT1L_ENA */
+#define WM2200_OUT1L_ENA_MASK                   0x0002  /* OUT1L_ENA */
+#define WM2200_OUT1L_ENA_SHIFT                       1  /* OUT1L_ENA */
+#define WM2200_OUT1L_ENA_WIDTH                       1  /* OUT1L_ENA */
+#define WM2200_OUT1R_ENA                        0x0001  /* OUT1R_ENA */
+#define WM2200_OUT1R_ENA_MASK                   0x0001  /* OUT1R_ENA */
+#define WM2200_OUT1R_ENA_SHIFT                       0  /* OUT1R_ENA */
+#define WM2200_OUT1R_ENA_WIDTH                       1  /* OUT1R_ENA */
+
+/*
+ * R1025 (0x401) - DAC Volume Limit 1L
+ */
+#define WM2200_OUT1_OSR                         0x2000  /* OUT1_OSR */
+#define WM2200_OUT1_OSR_MASK                    0x2000  /* OUT1_OSR */
+#define WM2200_OUT1_OSR_SHIFT                       13  /* OUT1_OSR */
+#define WM2200_OUT1_OSR_WIDTH                        1  /* OUT1_OSR */
+#define WM2200_OUT1L_ANC_SRC                    0x0800  /* OUT1L_ANC_SRC */
+#define WM2200_OUT1L_ANC_SRC_MASK               0x0800  /* OUT1L_ANC_SRC */
+#define WM2200_OUT1L_ANC_SRC_SHIFT                  11  /* OUT1L_ANC_SRC */
+#define WM2200_OUT1L_ANC_SRC_WIDTH                   1  /* OUT1L_ANC_SRC */
+#define WM2200_OUT1L_PGA_VOL_MASK               0x00FE  /* OUT1L_PGA_VOL - [7:1] */
+#define WM2200_OUT1L_PGA_VOL_SHIFT                   1  /* OUT1L_PGA_VOL - [7:1] */
+#define WM2200_OUT1L_PGA_VOL_WIDTH                   7  /* OUT1L_PGA_VOL - [7:1] */
+
+/*
+ * R1026 (0x402) - DAC Volume Limit 1R
+ */
+#define WM2200_OUT1R_ANC_SRC                    0x0800  /* OUT1R_ANC_SRC */
+#define WM2200_OUT1R_ANC_SRC_MASK               0x0800  /* OUT1R_ANC_SRC */
+#define WM2200_OUT1R_ANC_SRC_SHIFT                  11  /* OUT1R_ANC_SRC */
+#define WM2200_OUT1R_ANC_SRC_WIDTH                   1  /* OUT1R_ANC_SRC */
+#define WM2200_OUT1R_PGA_VOL_MASK               0x00FE  /* OUT1R_PGA_VOL - [7:1] */
+#define WM2200_OUT1R_PGA_VOL_SHIFT                   1  /* OUT1R_PGA_VOL - [7:1] */
+#define WM2200_OUT1R_PGA_VOL_WIDTH                   7  /* OUT1R_PGA_VOL - [7:1] */
+
+/*
+ * R1027 (0x403) - DAC Volume Limit 2L
+ */
+#define WM2200_OUT2_OSR                         0x2000  /* OUT2_OSR */
+#define WM2200_OUT2_OSR_MASK                    0x2000  /* OUT2_OSR */
+#define WM2200_OUT2_OSR_SHIFT                       13  /* OUT2_OSR */
+#define WM2200_OUT2_OSR_WIDTH                        1  /* OUT2_OSR */
+#define WM2200_OUT2L_ANC_SRC                    0x0800  /* OUT2L_ANC_SRC */
+#define WM2200_OUT2L_ANC_SRC_MASK               0x0800  /* OUT2L_ANC_SRC */
+#define WM2200_OUT2L_ANC_SRC_SHIFT                  11  /* OUT2L_ANC_SRC */
+#define WM2200_OUT2L_ANC_SRC_WIDTH                   1  /* OUT2L_ANC_SRC */
+
+/*
+ * R1028 (0x404) - DAC Volume Limit 2R
+ */
+#define WM2200_OUT2R_ANC_SRC                    0x0800  /* OUT2R_ANC_SRC */
+#define WM2200_OUT2R_ANC_SRC_MASK               0x0800  /* OUT2R_ANC_SRC */
+#define WM2200_OUT2R_ANC_SRC_SHIFT                  11  /* OUT2R_ANC_SRC */
+#define WM2200_OUT2R_ANC_SRC_WIDTH                   1  /* OUT2R_ANC_SRC */
+
+/*
+ * R1033 (0x409) - DAC AEC Control 1
+ */
+#define WM2200_AEC_LOOPBACK_ENA                 0x0004  /* AEC_LOOPBACK_ENA */
+#define WM2200_AEC_LOOPBACK_ENA_MASK            0x0004  /* AEC_LOOPBACK_ENA */
+#define WM2200_AEC_LOOPBACK_ENA_SHIFT                2  /* AEC_LOOPBACK_ENA */
+#define WM2200_AEC_LOOPBACK_ENA_WIDTH                1  /* AEC_LOOPBACK_ENA */
+#define WM2200_AEC_LOOPBACK_SRC_MASK            0x0003  /* AEC_LOOPBACK_SRC - [1:0] */
+#define WM2200_AEC_LOOPBACK_SRC_SHIFT                0  /* AEC_LOOPBACK_SRC - [1:0] */
+#define WM2200_AEC_LOOPBACK_SRC_WIDTH                2  /* AEC_LOOPBACK_SRC - [1:0] */
+
+/*
+ * R1034 (0x40A) - Output Volume Ramp
+ */
+#define WM2200_OUT_VD_RAMP_MASK                 0x0070  /* OUT_VD_RAMP - [6:4] */
+#define WM2200_OUT_VD_RAMP_SHIFT                     4  /* OUT_VD_RAMP - [6:4] */
+#define WM2200_OUT_VD_RAMP_WIDTH                     3  /* OUT_VD_RAMP - [6:4] */
+#define WM2200_OUT_VI_RAMP_MASK                 0x0007  /* OUT_VI_RAMP - [2:0] */
+#define WM2200_OUT_VI_RAMP_SHIFT                     0  /* OUT_VI_RAMP - [2:0] */
+#define WM2200_OUT_VI_RAMP_WIDTH                     3  /* OUT_VI_RAMP - [2:0] */
+
+/*
+ * R1035 (0x40B) - DAC Digital Volume 1L
+ */
+#define WM2200_OUT_VU                           0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM2200_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM2200_OUT1L_MUTE                       0x0100  /* OUT1L_MUTE */
+#define WM2200_OUT1L_MUTE_MASK                  0x0100  /* OUT1L_MUTE */
+#define WM2200_OUT1L_MUTE_SHIFT                      8  /* OUT1L_MUTE */
+#define WM2200_OUT1L_MUTE_WIDTH                      1  /* OUT1L_MUTE */
+#define WM2200_OUT1L_VOL_MASK                   0x00FF  /* OUT1L_VOL - [7:0] */
+#define WM2200_OUT1L_VOL_SHIFT                       0  /* OUT1L_VOL - [7:0] */
+#define WM2200_OUT1L_VOL_WIDTH                       8  /* OUT1L_VOL - [7:0] */
+
+/*
+ * R1036 (0x40C) - DAC Digital Volume 1R
+ */
+#define WM2200_OUT_VU                           0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM2200_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM2200_OUT1R_MUTE                       0x0100  /* OUT1R_MUTE */
+#define WM2200_OUT1R_MUTE_MASK                  0x0100  /* OUT1R_MUTE */
+#define WM2200_OUT1R_MUTE_SHIFT                      8  /* OUT1R_MUTE */
+#define WM2200_OUT1R_MUTE_WIDTH                      1  /* OUT1R_MUTE */
+#define WM2200_OUT1R_VOL_MASK                   0x00FF  /* OUT1R_VOL - [7:0] */
+#define WM2200_OUT1R_VOL_SHIFT                       0  /* OUT1R_VOL - [7:0] */
+#define WM2200_OUT1R_VOL_WIDTH                       8  /* OUT1R_VOL - [7:0] */
+
+/*
+ * R1037 (0x40D) - DAC Digital Volume 2L
+ */
+#define WM2200_OUT_VU                           0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM2200_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM2200_OUT2L_MUTE                       0x0100  /* OUT2L_MUTE */
+#define WM2200_OUT2L_MUTE_MASK                  0x0100  /* OUT2L_MUTE */
+#define WM2200_OUT2L_MUTE_SHIFT                      8  /* OUT2L_MUTE */
+#define WM2200_OUT2L_MUTE_WIDTH                      1  /* OUT2L_MUTE */
+#define WM2200_OUT2L_VOL_MASK                   0x00FF  /* OUT2L_VOL - [7:0] */
+#define WM2200_OUT2L_VOL_SHIFT                       0  /* OUT2L_VOL - [7:0] */
+#define WM2200_OUT2L_VOL_WIDTH                       8  /* OUT2L_VOL - [7:0] */
+
+/*
+ * R1038 (0x40E) - DAC Digital Volume 2R
+ */
+#define WM2200_OUT_VU                           0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM2200_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM2200_OUT2R_MUTE                       0x0100  /* OUT2R_MUTE */
+#define WM2200_OUT2R_MUTE_MASK                  0x0100  /* OUT2R_MUTE */
+#define WM2200_OUT2R_MUTE_SHIFT                      8  /* OUT2R_MUTE */
+#define WM2200_OUT2R_MUTE_WIDTH                      1  /* OUT2R_MUTE */
+#define WM2200_OUT2R_VOL_MASK                   0x00FF  /* OUT2R_VOL - [7:0] */
+#define WM2200_OUT2R_VOL_SHIFT                       0  /* OUT2R_VOL - [7:0] */
+#define WM2200_OUT2R_VOL_WIDTH                       8  /* OUT2R_VOL - [7:0] */
+
+/*
+ * R1047 (0x417) - PDM 1
+ */
+#define WM2200_SPK1R_MUTE                       0x2000  /* SPK1R_MUTE */
+#define WM2200_SPK1R_MUTE_MASK                  0x2000  /* SPK1R_MUTE */
+#define WM2200_SPK1R_MUTE_SHIFT                     13  /* SPK1R_MUTE */
+#define WM2200_SPK1R_MUTE_WIDTH                      1  /* SPK1R_MUTE */
+#define WM2200_SPK1L_MUTE                       0x1000  /* SPK1L_MUTE */
+#define WM2200_SPK1L_MUTE_MASK                  0x1000  /* SPK1L_MUTE */
+#define WM2200_SPK1L_MUTE_SHIFT                     12  /* SPK1L_MUTE */
+#define WM2200_SPK1L_MUTE_WIDTH                      1  /* SPK1L_MUTE */
+#define WM2200_SPK1_MUTE_ENDIAN                 0x0100  /* SPK1_MUTE_ENDIAN */
+#define WM2200_SPK1_MUTE_ENDIAN_MASK            0x0100  /* SPK1_MUTE_ENDIAN */
+#define WM2200_SPK1_MUTE_ENDIAN_SHIFT                8  /* SPK1_MUTE_ENDIAN */
+#define WM2200_SPK1_MUTE_ENDIAN_WIDTH                1  /* SPK1_MUTE_ENDIAN */
+#define WM2200_SPK1_MUTE_SEQL_MASK              0x00FF  /* SPK1_MUTE_SEQL - [7:0] */
+#define WM2200_SPK1_MUTE_SEQL_SHIFT                  0  /* SPK1_MUTE_SEQL - [7:0] */
+#define WM2200_SPK1_MUTE_SEQL_WIDTH                  8  /* SPK1_MUTE_SEQL - [7:0] */
+
+/*
+ * R1048 (0x418) - PDM 2
+ */
+#define WM2200_SPK1_FMT                         0x0001  /* SPK1_FMT */
+#define WM2200_SPK1_FMT_MASK                    0x0001  /* SPK1_FMT */
+#define WM2200_SPK1_FMT_SHIFT                        0  /* SPK1_FMT */
+#define WM2200_SPK1_FMT_WIDTH                        1  /* SPK1_FMT */
+
+/*
+ * R1280 (0x500) - Audio IF 1_1
+ */
+#define WM2200_AIF1_BCLK_INV                    0x0040  /* AIF1_BCLK_INV */
+#define WM2200_AIF1_BCLK_INV_MASK               0x0040  /* AIF1_BCLK_INV */
+#define WM2200_AIF1_BCLK_INV_SHIFT                   6  /* AIF1_BCLK_INV */
+#define WM2200_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
+#define WM2200_AIF1_BCLK_FRC                    0x0020  /* AIF1_BCLK_FRC */
+#define WM2200_AIF1_BCLK_FRC_MASK               0x0020  /* AIF1_BCLK_FRC */
+#define WM2200_AIF1_BCLK_FRC_SHIFT                   5  /* AIF1_BCLK_FRC */
+#define WM2200_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
+#define WM2200_AIF1_BCLK_MSTR                   0x0010  /* AIF1_BCLK_MSTR */
+#define WM2200_AIF1_BCLK_MSTR_MASK              0x0010  /* AIF1_BCLK_MSTR */
+#define WM2200_AIF1_BCLK_MSTR_SHIFT                  4  /* AIF1_BCLK_MSTR */
+#define WM2200_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
+#define WM2200_AIF1_BCLK_DIV_MASK               0x000F  /* AIF1_BCLK_DIV - [3:0] */
+#define WM2200_AIF1_BCLK_DIV_SHIFT                   0  /* AIF1_BCLK_DIV - [3:0] */
+#define WM2200_AIF1_BCLK_DIV_WIDTH                   4  /* AIF1_BCLK_DIV - [3:0] */
+
+/*
+ * R1281 (0x501) - Audio IF 1_2
+ */
+#define WM2200_AIF1TX_DAT_TRI                   0x0020  /* AIF1TX_DAT_TRI */
+#define WM2200_AIF1TX_DAT_TRI_MASK              0x0020  /* AIF1TX_DAT_TRI */
+#define WM2200_AIF1TX_DAT_TRI_SHIFT                  5  /* AIF1TX_DAT_TRI */
+#define WM2200_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
+#define WM2200_AIF1TX_LRCLK_SRC                 0x0008  /* AIF1TX_LRCLK_SRC */
+#define WM2200_AIF1TX_LRCLK_SRC_MASK            0x0008  /* AIF1TX_LRCLK_SRC */
+#define WM2200_AIF1TX_LRCLK_SRC_SHIFT                3  /* AIF1TX_LRCLK_SRC */
+#define WM2200_AIF1TX_LRCLK_SRC_WIDTH                1  /* AIF1TX_LRCLK_SRC */
+#define WM2200_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
+#define WM2200_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
+#define WM2200_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
+#define WM2200_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
+#define WM2200_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM2200_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM2200_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
+#define WM2200_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
+#define WM2200_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM2200_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM2200_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
+#define WM2200_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
+
+/*
+ * R1282 (0x502) - Audio IF 1_3
+ */
+#define WM2200_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
+#define WM2200_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
+#define WM2200_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
+#define WM2200_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
+#define WM2200_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM2200_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM2200_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
+#define WM2200_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
+#define WM2200_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM2200_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM2200_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
+#define WM2200_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
+
+/*
+ * R1283 (0x503) - Audio IF 1_4
+ */
+#define WM2200_AIF1_TRI                         0x0040  /* AIF1_TRI */
+#define WM2200_AIF1_TRI_MASK                    0x0040  /* AIF1_TRI */
+#define WM2200_AIF1_TRI_SHIFT                        6  /* AIF1_TRI */
+#define WM2200_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
+
+/*
+ * R1284 (0x504) - Audio IF 1_5
+ */
+#define WM2200_AIF1_FMT_MASK                    0x0007  /* AIF1_FMT - [2:0] */
+#define WM2200_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [2:0] */
+#define WM2200_AIF1_FMT_WIDTH                        3  /* AIF1_FMT - [2:0] */
+
+/*
+ * R1285 (0x505) - Audio IF 1_6
+ */
+#define WM2200_AIF1TX_BCPF_MASK                 0x07FF  /* AIF1TX_BCPF - [10:0] */
+#define WM2200_AIF1TX_BCPF_SHIFT                     0  /* AIF1TX_BCPF - [10:0] */
+#define WM2200_AIF1TX_BCPF_WIDTH                    11  /* AIF1TX_BCPF - [10:0] */
+
+/*
+ * R1286 (0x506) - Audio IF 1_7
+ */
+#define WM2200_AIF1RX_BCPF_MASK                 0x07FF  /* AIF1RX_BCPF - [10:0] */
+#define WM2200_AIF1RX_BCPF_SHIFT                     0  /* AIF1RX_BCPF - [10:0] */
+#define WM2200_AIF1RX_BCPF_WIDTH                    11  /* AIF1RX_BCPF - [10:0] */
+
+/*
+ * R1287 (0x507) - Audio IF 1_8
+ */
+#define WM2200_AIF1TX_WL_MASK                   0x3F00  /* AIF1TX_WL - [13:8] */
+#define WM2200_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [13:8] */
+#define WM2200_AIF1TX_WL_WIDTH                       6  /* AIF1TX_WL - [13:8] */
+#define WM2200_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM2200_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM2200_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
+
+/*
+ * R1288 (0x508) - Audio IF 1_9
+ */
+#define WM2200_AIF1RX_WL_MASK                   0x3F00  /* AIF1RX_WL - [13:8] */
+#define WM2200_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [13:8] */
+#define WM2200_AIF1RX_WL_WIDTH                       6  /* AIF1RX_WL - [13:8] */
+#define WM2200_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM2200_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM2200_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
+
+/*
+ * R1289 (0x509) - Audio IF 1_10
+ */
+#define WM2200_AIF1TX1_SLOT_MASK                0x003F  /* AIF1TX1_SLOT - [5:0] */
+#define WM2200_AIF1TX1_SLOT_SHIFT                    0  /* AIF1TX1_SLOT - [5:0] */
+#define WM2200_AIF1TX1_SLOT_WIDTH                    6  /* AIF1TX1_SLOT - [5:0] */
+
+/*
+ * R1290 (0x50A) - Audio IF 1_11
+ */
+#define WM2200_AIF1TX2_SLOT_MASK                0x003F  /* AIF1TX2_SLOT - [5:0] */
+#define WM2200_AIF1TX2_SLOT_SHIFT                    0  /* AIF1TX2_SLOT - [5:0] */
+#define WM2200_AIF1TX2_SLOT_WIDTH                    6  /* AIF1TX2_SLOT - [5:0] */
+
+/*
+ * R1291 (0x50B) - Audio IF 1_12
+ */
+#define WM2200_AIF1TX3_SLOT_MASK                0x003F  /* AIF1TX3_SLOT - [5:0] */
+#define WM2200_AIF1TX3_SLOT_SHIFT                    0  /* AIF1TX3_SLOT - [5:0] */
+#define WM2200_AIF1TX3_SLOT_WIDTH                    6  /* AIF1TX3_SLOT - [5:0] */
+
+/*
+ * R1292 (0x50C) - Audio IF 1_13
+ */
+#define WM2200_AIF1TX4_SLOT_MASK                0x003F  /* AIF1TX4_SLOT - [5:0] */
+#define WM2200_AIF1TX4_SLOT_SHIFT                    0  /* AIF1TX4_SLOT - [5:0] */
+#define WM2200_AIF1TX4_SLOT_WIDTH                    6  /* AIF1TX4_SLOT - [5:0] */
+
+/*
+ * R1293 (0x50D) - Audio IF 1_14
+ */
+#define WM2200_AIF1TX5_SLOT_MASK                0x003F  /* AIF1TX5_SLOT - [5:0] */
+#define WM2200_AIF1TX5_SLOT_SHIFT                    0  /* AIF1TX5_SLOT - [5:0] */
+#define WM2200_AIF1TX5_SLOT_WIDTH                    6  /* AIF1TX5_SLOT - [5:0] */
+
+/*
+ * R1294 (0x50E) - Audio IF 1_15
+ */
+#define WM2200_AIF1TX6_SLOT_MASK                0x003F  /* AIF1TX6_SLOT - [5:0] */
+#define WM2200_AIF1TX6_SLOT_SHIFT                    0  /* AIF1TX6_SLOT - [5:0] */
+#define WM2200_AIF1TX6_SLOT_WIDTH                    6  /* AIF1TX6_SLOT - [5:0] */
+
+/*
+ * R1295 (0x50F) - Audio IF 1_16
+ */
+#define WM2200_AIF1RX1_SLOT_MASK                0x003F  /* AIF1RX1_SLOT - [5:0] */
+#define WM2200_AIF1RX1_SLOT_SHIFT                    0  /* AIF1RX1_SLOT - [5:0] */
+#define WM2200_AIF1RX1_SLOT_WIDTH                    6  /* AIF1RX1_SLOT - [5:0] */
+
+/*
+ * R1296 (0x510) - Audio IF 1_17
+ */
+#define WM2200_AIF1RX2_SLOT_MASK                0x003F  /* AIF1RX2_SLOT - [5:0] */
+#define WM2200_AIF1RX2_SLOT_SHIFT                    0  /* AIF1RX2_SLOT - [5:0] */
+#define WM2200_AIF1RX2_SLOT_WIDTH                    6  /* AIF1RX2_SLOT - [5:0] */
+
+/*
+ * R1297 (0x511) - Audio IF 1_18
+ */
+#define WM2200_AIF1RX3_SLOT_MASK                0x003F  /* AIF1RX3_SLOT - [5:0] */
+#define WM2200_AIF1RX3_SLOT_SHIFT                    0  /* AIF1RX3_SLOT - [5:0] */
+#define WM2200_AIF1RX3_SLOT_WIDTH                    6  /* AIF1RX3_SLOT - [5:0] */
+
+/*
+ * R1298 (0x512) - Audio IF 1_19
+ */
+#define WM2200_AIF1RX4_SLOT_MASK                0x003F  /* AIF1RX4_SLOT - [5:0] */
+#define WM2200_AIF1RX4_SLOT_SHIFT                    0  /* AIF1RX4_SLOT - [5:0] */
+#define WM2200_AIF1RX4_SLOT_WIDTH                    6  /* AIF1RX4_SLOT - [5:0] */
+
+/*
+ * R1299 (0x513) - Audio IF 1_20
+ */
+#define WM2200_AIF1RX5_SLOT_MASK                0x003F  /* AIF1RX5_SLOT - [5:0] */
+#define WM2200_AIF1RX5_SLOT_SHIFT                    0  /* AIF1RX5_SLOT - [5:0] */
+#define WM2200_AIF1RX5_SLOT_WIDTH                    6  /* AIF1RX5_SLOT - [5:0] */
+
+/*
+ * R1300 (0x514) - Audio IF 1_21
+ */
+#define WM2200_AIF1RX6_SLOT_MASK                0x003F  /* AIF1RX6_SLOT - [5:0] */
+#define WM2200_AIF1RX6_SLOT_SHIFT                    0  /* AIF1RX6_SLOT - [5:0] */
+#define WM2200_AIF1RX6_SLOT_WIDTH                    6  /* AIF1RX6_SLOT - [5:0] */
+
+/*
+ * R1301 (0x515) - Audio IF 1_22
+ */
+#define WM2200_AIF1RX6_ENA                      0x0800  /* AIF1RX6_ENA */
+#define WM2200_AIF1RX6_ENA_MASK                 0x0800  /* AIF1RX6_ENA */
+#define WM2200_AIF1RX6_ENA_SHIFT                    11  /* AIF1RX6_ENA */
+#define WM2200_AIF1RX6_ENA_WIDTH                     1  /* AIF1RX6_ENA */
+#define WM2200_AIF1RX5_ENA                      0x0400  /* AIF1RX5_ENA */
+#define WM2200_AIF1RX5_ENA_MASK                 0x0400  /* AIF1RX5_ENA */
+#define WM2200_AIF1RX5_ENA_SHIFT                    10  /* AIF1RX5_ENA */
+#define WM2200_AIF1RX5_ENA_WIDTH                     1  /* AIF1RX5_ENA */
+#define WM2200_AIF1RX4_ENA                      0x0200  /* AIF1RX4_ENA */
+#define WM2200_AIF1RX4_ENA_MASK                 0x0200  /* AIF1RX4_ENA */
+#define WM2200_AIF1RX4_ENA_SHIFT                     9  /* AIF1RX4_ENA */
+#define WM2200_AIF1RX4_ENA_WIDTH                     1  /* AIF1RX4_ENA */
+#define WM2200_AIF1RX3_ENA                      0x0100  /* AIF1RX3_ENA */
+#define WM2200_AIF1RX3_ENA_MASK                 0x0100  /* AIF1RX3_ENA */
+#define WM2200_AIF1RX3_ENA_SHIFT                     8  /* AIF1RX3_ENA */
+#define WM2200_AIF1RX3_ENA_WIDTH                     1  /* AIF1RX3_ENA */
+#define WM2200_AIF1RX2_ENA                      0x0080  /* AIF1RX2_ENA */
+#define WM2200_AIF1RX2_ENA_MASK                 0x0080  /* AIF1RX2_ENA */
+#define WM2200_AIF1RX2_ENA_SHIFT                     7  /* AIF1RX2_ENA */
+#define WM2200_AIF1RX2_ENA_WIDTH                     1  /* AIF1RX2_ENA */
+#define WM2200_AIF1RX1_ENA                      0x0040  /* AIF1RX1_ENA */
+#define WM2200_AIF1RX1_ENA_MASK                 0x0040  /* AIF1RX1_ENA */
+#define WM2200_AIF1RX1_ENA_SHIFT                     6  /* AIF1RX1_ENA */
+#define WM2200_AIF1RX1_ENA_WIDTH                     1  /* AIF1RX1_ENA */
+#define WM2200_AIF1TX6_ENA                      0x0020  /* AIF1TX6_ENA */
+#define WM2200_AIF1TX6_ENA_MASK                 0x0020  /* AIF1TX6_ENA */
+#define WM2200_AIF1TX6_ENA_SHIFT                     5  /* AIF1TX6_ENA */
+#define WM2200_AIF1TX6_ENA_WIDTH                     1  /* AIF1TX6_ENA */
+#define WM2200_AIF1TX5_ENA                      0x0010  /* AIF1TX5_ENA */
+#define WM2200_AIF1TX5_ENA_MASK                 0x0010  /* AIF1TX5_ENA */
+#define WM2200_AIF1TX5_ENA_SHIFT                     4  /* AIF1TX5_ENA */
+#define WM2200_AIF1TX5_ENA_WIDTH                     1  /* AIF1TX5_ENA */
+#define WM2200_AIF1TX4_ENA                      0x0008  /* AIF1TX4_ENA */
+#define WM2200_AIF1TX4_ENA_MASK                 0x0008  /* AIF1TX4_ENA */
+#define WM2200_AIF1TX4_ENA_SHIFT                     3  /* AIF1TX4_ENA */
+#define WM2200_AIF1TX4_ENA_WIDTH                     1  /* AIF1TX4_ENA */
+#define WM2200_AIF1TX3_ENA                      0x0004  /* AIF1TX3_ENA */
+#define WM2200_AIF1TX3_ENA_MASK                 0x0004  /* AIF1TX3_ENA */
+#define WM2200_AIF1TX3_ENA_SHIFT                     2  /* AIF1TX3_ENA */
+#define WM2200_AIF1TX3_ENA_WIDTH                     1  /* AIF1TX3_ENA */
+#define WM2200_AIF1TX2_ENA                      0x0002  /* AIF1TX2_ENA */
+#define WM2200_AIF1TX2_ENA_MASK                 0x0002  /* AIF1TX2_ENA */
+#define WM2200_AIF1TX2_ENA_SHIFT                     1  /* AIF1TX2_ENA */
+#define WM2200_AIF1TX2_ENA_WIDTH                     1  /* AIF1TX2_ENA */
+#define WM2200_AIF1TX1_ENA                      0x0001  /* AIF1TX1_ENA */
+#define WM2200_AIF1TX1_ENA_MASK                 0x0001  /* AIF1TX1_ENA */
+#define WM2200_AIF1TX1_ENA_SHIFT                     0  /* AIF1TX1_ENA */
+#define WM2200_AIF1TX1_ENA_WIDTH                     1  /* AIF1TX1_ENA */
+
+/*
+ * R1536 (0x600) - OUT1LMIX Input 1 Source
+ */
+#define WM2200_OUT1LMIX_SRC1_MASK               0x007F  /* OUT1LMIX_SRC1 - [6:0] */
+#define WM2200_OUT1LMIX_SRC1_SHIFT                   0  /* OUT1LMIX_SRC1 - [6:0] */
+#define WM2200_OUT1LMIX_SRC1_WIDTH                   7  /* OUT1LMIX_SRC1 - [6:0] */
+
+/*
+ * R1537 (0x601) - OUT1LMIX Input 1 Volume
+ */
+#define WM2200_OUT1LMIX_VOL1_MASK               0x00FE  /* OUT1LMIX_VOL1 - [7:1] */
+#define WM2200_OUT1LMIX_VOL1_SHIFT                   1  /* OUT1LMIX_VOL1 - [7:1] */
+#define WM2200_OUT1LMIX_VOL1_WIDTH                   7  /* OUT1LMIX_VOL1 - [7:1] */
+
+/*
+ * R1538 (0x602) - OUT1LMIX Input 2 Source
+ */
+#define WM2200_OUT1LMIX_SRC2_MASK               0x007F  /* OUT1LMIX_SRC2 - [6:0] */
+#define WM2200_OUT1LMIX_SRC2_SHIFT                   0  /* OUT1LMIX_SRC2 - [6:0] */
+#define WM2200_OUT1LMIX_SRC2_WIDTH                   7  /* OUT1LMIX_SRC2 - [6:0] */
+
+/*
+ * R1539 (0x603) - OUT1LMIX Input 2 Volume
+ */
+#define WM2200_OUT1LMIX_VOL2_MASK               0x00FE  /* OUT1LMIX_VOL2 - [7:1] */
+#define WM2200_OUT1LMIX_VOL2_SHIFT                   1  /* OUT1LMIX_VOL2 - [7:1] */
+#define WM2200_OUT1LMIX_VOL2_WIDTH                   7  /* OUT1LMIX_VOL2 - [7:1] */
+
+/*
+ * R1540 (0x604) - OUT1LMIX Input 3 Source
+ */
+#define WM2200_OUT1LMIX_SRC3_MASK               0x007F  /* OUT1LMIX_SRC3 - [6:0] */
+#define WM2200_OUT1LMIX_SRC3_SHIFT                   0  /* OUT1LMIX_SRC3 - [6:0] */
+#define WM2200_OUT1LMIX_SRC3_WIDTH                   7  /* OUT1LMIX_SRC3 - [6:0] */
+
+/*
+ * R1541 (0x605) - OUT1LMIX Input 3 Volume
+ */
+#define WM2200_OUT1LMIX_VOL3_MASK               0x00FE  /* OUT1LMIX_VOL3 - [7:1] */
+#define WM2200_OUT1LMIX_VOL3_SHIFT                   1  /* OUT1LMIX_VOL3 - [7:1] */
+#define WM2200_OUT1LMIX_VOL3_WIDTH                   7  /* OUT1LMIX_VOL3 - [7:1] */
+
+/*
+ * R1542 (0x606) - OUT1LMIX Input 4 Source
+ */
+#define WM2200_OUT1LMIX_SRC4_MASK               0x007F  /* OUT1LMIX_SRC4 - [6:0] */
+#define WM2200_OUT1LMIX_SRC4_SHIFT                   0  /* OUT1LMIX_SRC4 - [6:0] */
+#define WM2200_OUT1LMIX_SRC4_WIDTH                   7  /* OUT1LMIX_SRC4 - [6:0] */
+
+/*
+ * R1543 (0x607) - OUT1LMIX Input 4 Volume
+ */
+#define WM2200_OUT1LMIX_VOL4_MASK               0x00FE  /* OUT1LMIX_VOL4 - [7:1] */
+#define WM2200_OUT1LMIX_VOL4_SHIFT                   1  /* OUT1LMIX_VOL4 - [7:1] */
+#define WM2200_OUT1LMIX_VOL4_WIDTH                   7  /* OUT1LMIX_VOL4 - [7:1] */
+
+/*
+ * R1544 (0x608) - OUT1RMIX Input 1 Source
+ */
+#define WM2200_OUT1RMIX_SRC1_MASK               0x007F  /* OUT1RMIX_SRC1 - [6:0] */
+#define WM2200_OUT1RMIX_SRC1_SHIFT                   0  /* OUT1RMIX_SRC1 - [6:0] */
+#define WM2200_OUT1RMIX_SRC1_WIDTH                   7  /* OUT1RMIX_SRC1 - [6:0] */
+
+/*
+ * R1545 (0x609) - OUT1RMIX Input 1 Volume
+ */
+#define WM2200_OUT1RMIX_VOL1_MASK               0x00FE  /* OUT1RMIX_VOL1 - [7:1] */
+#define WM2200_OUT1RMIX_VOL1_SHIFT                   1  /* OUT1RMIX_VOL1 - [7:1] */
+#define WM2200_OUT1RMIX_VOL1_WIDTH                   7  /* OUT1RMIX_VOL1 - [7:1] */
+
+/*
+ * R1546 (0x60A) - OUT1RMIX Input 2 Source
+ */
+#define WM2200_OUT1RMIX_SRC2_MASK               0x007F  /* OUT1RMIX_SRC2 - [6:0] */
+#define WM2200_OUT1RMIX_SRC2_SHIFT                   0  /* OUT1RMIX_SRC2 - [6:0] */
+#define WM2200_OUT1RMIX_SRC2_WIDTH                   7  /* OUT1RMIX_SRC2 - [6:0] */
+
+/*
+ * R1547 (0x60B) - OUT1RMIX Input 2 Volume
+ */
+#define WM2200_OUT1RMIX_VOL2_MASK               0x00FE  /* OUT1RMIX_VOL2 - [7:1] */
+#define WM2200_OUT1RMIX_VOL2_SHIFT                   1  /* OUT1RMIX_VOL2 - [7:1] */
+#define WM2200_OUT1RMIX_VOL2_WIDTH                   7  /* OUT1RMIX_VOL2 - [7:1] */
+
+/*
+ * R1548 (0x60C) - OUT1RMIX Input 3 Source
+ */
+#define WM2200_OUT1RMIX_SRC3_MASK               0x007F  /* OUT1RMIX_SRC3 - [6:0] */
+#define WM2200_OUT1RMIX_SRC3_SHIFT                   0  /* OUT1RMIX_SRC3 - [6:0] */
+#define WM2200_OUT1RMIX_SRC3_WIDTH                   7  /* OUT1RMIX_SRC3 - [6:0] */
+
+/*
+ * R1549 (0x60D) - OUT1RMIX Input 3 Volume
+ */
+#define WM2200_OUT1RMIX_VOL3_MASK               0x00FE  /* OUT1RMIX_VOL3 - [7:1] */
+#define WM2200_OUT1RMIX_VOL3_SHIFT                   1  /* OUT1RMIX_VOL3 - [7:1] */
+#define WM2200_OUT1RMIX_VOL3_WIDTH                   7  /* OUT1RMIX_VOL3 - [7:1] */
+
+/*
+ * R1550 (0x60E) - OUT1RMIX Input 4 Source
+ */
+#define WM2200_OUT1RMIX_SRC4_MASK               0x007F  /* OUT1RMIX_SRC4 - [6:0] */
+#define WM2200_OUT1RMIX_SRC4_SHIFT                   0  /* OUT1RMIX_SRC4 - [6:0] */
+#define WM2200_OUT1RMIX_SRC4_WIDTH                   7  /* OUT1RMIX_SRC4 - [6:0] */
+
+/*
+ * R1551 (0x60F) - OUT1RMIX Input 4 Volume
+ */
+#define WM2200_OUT1RMIX_VOL4_MASK               0x00FE  /* OUT1RMIX_VOL4 - [7:1] */
+#define WM2200_OUT1RMIX_VOL4_SHIFT                   1  /* OUT1RMIX_VOL4 - [7:1] */
+#define WM2200_OUT1RMIX_VOL4_WIDTH                   7  /* OUT1RMIX_VOL4 - [7:1] */
+
+/*
+ * R1552 (0x610) - OUT2LMIX Input 1 Source
+ */
+#define WM2200_OUT2LMIX_SRC1_MASK               0x007F  /* OUT2LMIX_SRC1 - [6:0] */
+#define WM2200_OUT2LMIX_SRC1_SHIFT                   0  /* OUT2LMIX_SRC1 - [6:0] */
+#define WM2200_OUT2LMIX_SRC1_WIDTH                   7  /* OUT2LMIX_SRC1 - [6:0] */
+
+/*
+ * R1553 (0x611) - OUT2LMIX Input 1 Volume
+ */
+#define WM2200_OUT2LMIX_VOL1_MASK               0x00FE  /* OUT2LMIX_VOL1 - [7:1] */
+#define WM2200_OUT2LMIX_VOL1_SHIFT                   1  /* OUT2LMIX_VOL1 - [7:1] */
+#define WM2200_OUT2LMIX_VOL1_WIDTH                   7  /* OUT2LMIX_VOL1 - [7:1] */
+
+/*
+ * R1554 (0x612) - OUT2LMIX Input 2 Source
+ */
+#define WM2200_OUT2LMIX_SRC2_MASK               0x007F  /* OUT2LMIX_SRC2 - [6:0] */
+#define WM2200_OUT2LMIX_SRC2_SHIFT                   0  /* OUT2LMIX_SRC2 - [6:0] */
+#define WM2200_OUT2LMIX_SRC2_WIDTH                   7  /* OUT2LMIX_SRC2 - [6:0] */
+
+/*
+ * R1555 (0x613) - OUT2LMIX Input 2 Volume
+ */
+#define WM2200_OUT2LMIX_VOL2_MASK               0x00FE  /* OUT2LMIX_VOL2 - [7:1] */
+#define WM2200_OUT2LMIX_VOL2_SHIFT                   1  /* OUT2LMIX_VOL2 - [7:1] */
+#define WM2200_OUT2LMIX_VOL2_WIDTH                   7  /* OUT2LMIX_VOL2 - [7:1] */
+
+/*
+ * R1556 (0x614) - OUT2LMIX Input 3 Source
+ */
+#define WM2200_OUT2LMIX_SRC3_MASK               0x007F  /* OUT2LMIX_SRC3 - [6:0] */
+#define WM2200_OUT2LMIX_SRC3_SHIFT                   0  /* OUT2LMIX_SRC3 - [6:0] */
+#define WM2200_OUT2LMIX_SRC3_WIDTH                   7  /* OUT2LMIX_SRC3 - [6:0] */
+
+/*
+ * R1557 (0x615) - OUT2LMIX Input 3 Volume
+ */
+#define WM2200_OUT2LMIX_VOL3_MASK               0x00FE  /* OUT2LMIX_VOL3 - [7:1] */
+#define WM2200_OUT2LMIX_VOL3_SHIFT                   1  /* OUT2LMIX_VOL3 - [7:1] */
+#define WM2200_OUT2LMIX_VOL3_WIDTH                   7  /* OUT2LMIX_VOL3 - [7:1] */
+
+/*
+ * R1558 (0x616) - OUT2LMIX Input 4 Source
+ */
+#define WM2200_OUT2LMIX_SRC4_MASK               0x007F  /* OUT2LMIX_SRC4 - [6:0] */
+#define WM2200_OUT2LMIX_SRC4_SHIFT                   0  /* OUT2LMIX_SRC4 - [6:0] */
+#define WM2200_OUT2LMIX_SRC4_WIDTH                   7  /* OUT2LMIX_SRC4 - [6:0] */
+
+/*
+ * R1559 (0x617) - OUT2LMIX Input 4 Volume
+ */
+#define WM2200_OUT2LMIX_VOL4_MASK               0x00FE  /* OUT2LMIX_VOL4 - [7:1] */
+#define WM2200_OUT2LMIX_VOL4_SHIFT                   1  /* OUT2LMIX_VOL4 - [7:1] */
+#define WM2200_OUT2LMIX_VOL4_WIDTH                   7  /* OUT2LMIX_VOL4 - [7:1] */
+
+/*
+ * R1560 (0x618) - OUT2RMIX Input 1 Source
+ */
+#define WM2200_OUT2RMIX_SRC1_MASK               0x007F  /* OUT2RMIX_SRC1 - [6:0] */
+#define WM2200_OUT2RMIX_SRC1_SHIFT                   0  /* OUT2RMIX_SRC1 - [6:0] */
+#define WM2200_OUT2RMIX_SRC1_WIDTH                   7  /* OUT2RMIX_SRC1 - [6:0] */
+
+/*
+ * R1561 (0x619) - OUT2RMIX Input 1 Volume
+ */
+#define WM2200_OUT2RMIX_VOL1_MASK               0x00FE  /* OUT2RMIX_VOL1 - [7:1] */
+#define WM2200_OUT2RMIX_VOL1_SHIFT                   1  /* OUT2RMIX_VOL1 - [7:1] */
+#define WM2200_OUT2RMIX_VOL1_WIDTH                   7  /* OUT2RMIX_VOL1 - [7:1] */
+
+/*
+ * R1562 (0x61A) - OUT2RMIX Input 2 Source
+ */
+#define WM2200_OUT2RMIX_SRC2_MASK               0x007F  /* OUT2RMIX_SRC2 - [6:0] */
+#define WM2200_OUT2RMIX_SRC2_SHIFT                   0  /* OUT2RMIX_SRC2 - [6:0] */
+#define WM2200_OUT2RMIX_SRC2_WIDTH                   7  /* OUT2RMIX_SRC2 - [6:0] */
+
+/*
+ * R1563 (0x61B) - OUT2RMIX Input 2 Volume
+ */
+#define WM2200_OUT2RMIX_VOL2_MASK               0x00FE  /* OUT2RMIX_VOL2 - [7:1] */
+#define WM2200_OUT2RMIX_VOL2_SHIFT                   1  /* OUT2RMIX_VOL2 - [7:1] */
+#define WM2200_OUT2RMIX_VOL2_WIDTH                   7  /* OUT2RMIX_VOL2 - [7:1] */
+
+/*
+ * R1564 (0x61C) - OUT2RMIX Input 3 Source
+ */
+#define WM2200_OUT2RMIX_SRC3_MASK               0x007F  /* OUT2RMIX_SRC3 - [6:0] */
+#define WM2200_OUT2RMIX_SRC3_SHIFT                   0  /* OUT2RMIX_SRC3 - [6:0] */
+#define WM2200_OUT2RMIX_SRC3_WIDTH                   7  /* OUT2RMIX_SRC3 - [6:0] */
+
+/*
+ * R1565 (0x61D) - OUT2RMIX Input 3 Volume
+ */
+#define WM2200_OUT2RMIX_VOL3_MASK               0x00FE  /* OUT2RMIX_VOL3 - [7:1] */
+#define WM2200_OUT2RMIX_VOL3_SHIFT                   1  /* OUT2RMIX_VOL3 - [7:1] */
+#define WM2200_OUT2RMIX_VOL3_WIDTH                   7  /* OUT2RMIX_VOL3 - [7:1] */
+
+/*
+ * R1566 (0x61E) - OUT2RMIX Input 4 Source
+ */
+#define WM2200_OUT2RMIX_SRC4_MASK               0x007F  /* OUT2RMIX_SRC4 - [6:0] */
+#define WM2200_OUT2RMIX_SRC4_SHIFT                   0  /* OUT2RMIX_SRC4 - [6:0] */
+#define WM2200_OUT2RMIX_SRC4_WIDTH                   7  /* OUT2RMIX_SRC4 - [6:0] */
+
+/*
+ * R1567 (0x61F) - OUT2RMIX Input 4 Volume
+ */
+#define WM2200_OUT2RMIX_VOL4_MASK               0x00FE  /* OUT2RMIX_VOL4 - [7:1] */
+#define WM2200_OUT2RMIX_VOL4_SHIFT                   1  /* OUT2RMIX_VOL4 - [7:1] */
+#define WM2200_OUT2RMIX_VOL4_WIDTH                   7  /* OUT2RMIX_VOL4 - [7:1] */
+
+/*
+ * R1568 (0x620) - AIF1TX1MIX Input 1 Source
+ */
+#define WM2200_AIF1TX1MIX_SRC1_MASK             0x007F  /* AIF1TX1MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC1_SHIFT                 0  /* AIF1TX1MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC1_WIDTH                 7  /* AIF1TX1MIX_SRC1 - [6:0] */
+
+/*
+ * R1569 (0x621) - AIF1TX1MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX1MIX_VOL1_MASK             0x00FE  /* AIF1TX1MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL1_SHIFT                 1  /* AIF1TX1MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL1_WIDTH                 7  /* AIF1TX1MIX_VOL1 - [7:1] */
+
+/*
+ * R1570 (0x622) - AIF1TX1MIX Input 2 Source
+ */
+#define WM2200_AIF1TX1MIX_SRC2_MASK             0x007F  /* AIF1TX1MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC2_SHIFT                 0  /* AIF1TX1MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC2_WIDTH                 7  /* AIF1TX1MIX_SRC2 - [6:0] */
+
+/*
+ * R1571 (0x623) - AIF1TX1MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX1MIX_VOL2_MASK             0x00FE  /* AIF1TX1MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL2_SHIFT                 1  /* AIF1TX1MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL2_WIDTH                 7  /* AIF1TX1MIX_VOL2 - [7:1] */
+
+/*
+ * R1572 (0x624) - AIF1TX1MIX Input 3 Source
+ */
+#define WM2200_AIF1TX1MIX_SRC3_MASK             0x007F  /* AIF1TX1MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC3_SHIFT                 0  /* AIF1TX1MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC3_WIDTH                 7  /* AIF1TX1MIX_SRC3 - [6:0] */
+
+/*
+ * R1573 (0x625) - AIF1TX1MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX1MIX_VOL3_MASK             0x00FE  /* AIF1TX1MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL3_SHIFT                 1  /* AIF1TX1MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL3_WIDTH                 7  /* AIF1TX1MIX_VOL3 - [7:1] */
+
+/*
+ * R1574 (0x626) - AIF1TX1MIX Input 4 Source
+ */
+#define WM2200_AIF1TX1MIX_SRC4_MASK             0x007F  /* AIF1TX1MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC4_SHIFT                 0  /* AIF1TX1MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC4_WIDTH                 7  /* AIF1TX1MIX_SRC4 - [6:0] */
+
+/*
+ * R1575 (0x627) - AIF1TX1MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX1MIX_VOL4_MASK             0x00FE  /* AIF1TX1MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL4_SHIFT                 1  /* AIF1TX1MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL4_WIDTH                 7  /* AIF1TX1MIX_VOL4 - [7:1] */
+
+/*
+ * R1576 (0x628) - AIF1TX2MIX Input 1 Source
+ */
+#define WM2200_AIF1TX2MIX_SRC1_MASK             0x007F  /* AIF1TX2MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC1_SHIFT                 0  /* AIF1TX2MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC1_WIDTH                 7  /* AIF1TX2MIX_SRC1 - [6:0] */
+
+/*
+ * R1577 (0x629) - AIF1TX2MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX2MIX_VOL1_MASK             0x00FE  /* AIF1TX2MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL1_SHIFT                 1  /* AIF1TX2MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL1_WIDTH                 7  /* AIF1TX2MIX_VOL1 - [7:1] */
+
+/*
+ * R1578 (0x62A) - AIF1TX2MIX Input 2 Source
+ */
+#define WM2200_AIF1TX2MIX_SRC2_MASK             0x007F  /* AIF1TX2MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC2_SHIFT                 0  /* AIF1TX2MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC2_WIDTH                 7  /* AIF1TX2MIX_SRC2 - [6:0] */
+
+/*
+ * R1579 (0x62B) - AIF1TX2MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX2MIX_VOL2_MASK             0x00FE  /* AIF1TX2MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL2_SHIFT                 1  /* AIF1TX2MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL2_WIDTH                 7  /* AIF1TX2MIX_VOL2 - [7:1] */
+
+/*
+ * R1580 (0x62C) - AIF1TX2MIX Input 3 Source
+ */
+#define WM2200_AIF1TX2MIX_SRC3_MASK             0x007F  /* AIF1TX2MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC3_SHIFT                 0  /* AIF1TX2MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC3_WIDTH                 7  /* AIF1TX2MIX_SRC3 - [6:0] */
+
+/*
+ * R1581 (0x62D) - AIF1TX2MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX2MIX_VOL3_MASK             0x00FE  /* AIF1TX2MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL3_SHIFT                 1  /* AIF1TX2MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL3_WIDTH                 7  /* AIF1TX2MIX_VOL3 - [7:1] */
+
+/*
+ * R1582 (0x62E) - AIF1TX2MIX Input 4 Source
+ */
+#define WM2200_AIF1TX2MIX_SRC4_MASK             0x007F  /* AIF1TX2MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC4_SHIFT                 0  /* AIF1TX2MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC4_WIDTH                 7  /* AIF1TX2MIX_SRC4 - [6:0] */
+
+/*
+ * R1583 (0x62F) - AIF1TX2MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX2MIX_VOL4_MASK             0x00FE  /* AIF1TX2MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL4_SHIFT                 1  /* AIF1TX2MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL4_WIDTH                 7  /* AIF1TX2MIX_VOL4 - [7:1] */
+
+/*
+ * R1584 (0x630) - AIF1TX3MIX Input 1 Source
+ */
+#define WM2200_AIF1TX3MIX_SRC1_MASK             0x007F  /* AIF1TX3MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC1_SHIFT                 0  /* AIF1TX3MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC1_WIDTH                 7  /* AIF1TX3MIX_SRC1 - [6:0] */
+
+/*
+ * R1585 (0x631) - AIF1TX3MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX3MIX_VOL1_MASK             0x00FE  /* AIF1TX3MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL1_SHIFT                 1  /* AIF1TX3MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL1_WIDTH                 7  /* AIF1TX3MIX_VOL1 - [7:1] */
+
+/*
+ * R1586 (0x632) - AIF1TX3MIX Input 2 Source
+ */
+#define WM2200_AIF1TX3MIX_SRC2_MASK             0x007F  /* AIF1TX3MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC2_SHIFT                 0  /* AIF1TX3MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC2_WIDTH                 7  /* AIF1TX3MIX_SRC2 - [6:0] */
+
+/*
+ * R1587 (0x633) - AIF1TX3MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX3MIX_VOL2_MASK             0x00FE  /* AIF1TX3MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL2_SHIFT                 1  /* AIF1TX3MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL2_WIDTH                 7  /* AIF1TX3MIX_VOL2 - [7:1] */
+
+/*
+ * R1588 (0x634) - AIF1TX3MIX Input 3 Source
+ */
+#define WM2200_AIF1TX3MIX_SRC3_MASK             0x007F  /* AIF1TX3MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC3_SHIFT                 0  /* AIF1TX3MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC3_WIDTH                 7  /* AIF1TX3MIX_SRC3 - [6:0] */
+
+/*
+ * R1589 (0x635) - AIF1TX3MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX3MIX_VOL3_MASK             0x00FE  /* AIF1TX3MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL3_SHIFT                 1  /* AIF1TX3MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL3_WIDTH                 7  /* AIF1TX3MIX_VOL3 - [7:1] */
+
+/*
+ * R1590 (0x636) - AIF1TX3MIX Input 4 Source
+ */
+#define WM2200_AIF1TX3MIX_SRC4_MASK             0x007F  /* AIF1TX3MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC4_SHIFT                 0  /* AIF1TX3MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC4_WIDTH                 7  /* AIF1TX3MIX_SRC4 - [6:0] */
+
+/*
+ * R1591 (0x637) - AIF1TX3MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX3MIX_VOL4_MASK             0x00FE  /* AIF1TX3MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL4_SHIFT                 1  /* AIF1TX3MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL4_WIDTH                 7  /* AIF1TX3MIX_VOL4 - [7:1] */
+
+/*
+ * R1592 (0x638) - AIF1TX4MIX Input 1 Source
+ */
+#define WM2200_AIF1TX4MIX_SRC1_MASK             0x007F  /* AIF1TX4MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC1_SHIFT                 0  /* AIF1TX4MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC1_WIDTH                 7  /* AIF1TX4MIX_SRC1 - [6:0] */
+
+/*
+ * R1593 (0x639) - AIF1TX4MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX4MIX_VOL1_MASK             0x00FE  /* AIF1TX4MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL1_SHIFT                 1  /* AIF1TX4MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL1_WIDTH                 7  /* AIF1TX4MIX_VOL1 - [7:1] */
+
+/*
+ * R1594 (0x63A) - AIF1TX4MIX Input 2 Source
+ */
+#define WM2200_AIF1TX4MIX_SRC2_MASK             0x007F  /* AIF1TX4MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC2_SHIFT                 0  /* AIF1TX4MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC2_WIDTH                 7  /* AIF1TX4MIX_SRC2 - [6:0] */
+
+/*
+ * R1595 (0x63B) - AIF1TX4MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX4MIX_VOL2_MASK             0x00FE  /* AIF1TX4MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL2_SHIFT                 1  /* AIF1TX4MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL2_WIDTH                 7  /* AIF1TX4MIX_VOL2 - [7:1] */
+
+/*
+ * R1596 (0x63C) - AIF1TX4MIX Input 3 Source
+ */
+#define WM2200_AIF1TX4MIX_SRC3_MASK             0x007F  /* AIF1TX4MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC3_SHIFT                 0  /* AIF1TX4MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC3_WIDTH                 7  /* AIF1TX4MIX_SRC3 - [6:0] */
+
+/*
+ * R1597 (0x63D) - AIF1TX4MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX4MIX_VOL3_MASK             0x00FE  /* AIF1TX4MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL3_SHIFT                 1  /* AIF1TX4MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL3_WIDTH                 7  /* AIF1TX4MIX_VOL3 - [7:1] */
+
+/*
+ * R1598 (0x63E) - AIF1TX4MIX Input 4 Source
+ */
+#define WM2200_AIF1TX4MIX_SRC4_MASK             0x007F  /* AIF1TX4MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC4_SHIFT                 0  /* AIF1TX4MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC4_WIDTH                 7  /* AIF1TX4MIX_SRC4 - [6:0] */
+
+/*
+ * R1599 (0x63F) - AIF1TX4MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX4MIX_VOL4_MASK             0x00FE  /* AIF1TX4MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL4_SHIFT                 1  /* AIF1TX4MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL4_WIDTH                 7  /* AIF1TX4MIX_VOL4 - [7:1] */
+
+/*
+ * R1600 (0x640) - AIF1TX5MIX Input 1 Source
+ */
+#define WM2200_AIF1TX5MIX_SRC1_MASK             0x007F  /* AIF1TX5MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC1_SHIFT                 0  /* AIF1TX5MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC1_WIDTH                 7  /* AIF1TX5MIX_SRC1 - [6:0] */
+
+/*
+ * R1601 (0x641) - AIF1TX5MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX5MIX_VOL1_MASK             0x00FE  /* AIF1TX5MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL1_SHIFT                 1  /* AIF1TX5MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL1_WIDTH                 7  /* AIF1TX5MIX_VOL1 - [7:1] */
+
+/*
+ * R1602 (0x642) - AIF1TX5MIX Input 2 Source
+ */
+#define WM2200_AIF1TX5MIX_SRC2_MASK             0x007F  /* AIF1TX5MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC2_SHIFT                 0  /* AIF1TX5MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC2_WIDTH                 7  /* AIF1TX5MIX_SRC2 - [6:0] */
+
+/*
+ * R1603 (0x643) - AIF1TX5MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX5MIX_VOL2_MASK             0x00FE  /* AIF1TX5MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL2_SHIFT                 1  /* AIF1TX5MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL2_WIDTH                 7  /* AIF1TX5MIX_VOL2 - [7:1] */
+
+/*
+ * R1604 (0x644) - AIF1TX5MIX Input 3 Source
+ */
+#define WM2200_AIF1TX5MIX_SRC3_MASK             0x007F  /* AIF1TX5MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC3_SHIFT                 0  /* AIF1TX5MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC3_WIDTH                 7  /* AIF1TX5MIX_SRC3 - [6:0] */
+
+/*
+ * R1605 (0x645) - AIF1TX5MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX5MIX_VOL3_MASK             0x00FE  /* AIF1TX5MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL3_SHIFT                 1  /* AIF1TX5MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL3_WIDTH                 7  /* AIF1TX5MIX_VOL3 - [7:1] */
+
+/*
+ * R1606 (0x646) - AIF1TX5MIX Input 4 Source
+ */
+#define WM2200_AIF1TX5MIX_SRC4_MASK             0x007F  /* AIF1TX5MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC4_SHIFT                 0  /* AIF1TX5MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC4_WIDTH                 7  /* AIF1TX5MIX_SRC4 - [6:0] */
+
+/*
+ * R1607 (0x647) - AIF1TX5MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX5MIX_VOL4_MASK             0x00FE  /* AIF1TX5MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL4_SHIFT                 1  /* AIF1TX5MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL4_WIDTH                 7  /* AIF1TX5MIX_VOL4 - [7:1] */
+
+/*
+ * R1608 (0x648) - AIF1TX6MIX Input 1 Source
+ */
+#define WM2200_AIF1TX6MIX_SRC1_MASK             0x007F  /* AIF1TX6MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC1_SHIFT                 0  /* AIF1TX6MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC1_WIDTH                 7  /* AIF1TX6MIX_SRC1 - [6:0] */
+
+/*
+ * R1609 (0x649) - AIF1TX6MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX6MIX_VOL1_MASK             0x00FE  /* AIF1TX6MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL1_SHIFT                 1  /* AIF1TX6MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL1_WIDTH                 7  /* AIF1TX6MIX_VOL1 - [7:1] */
+
+/*
+ * R1610 (0x64A) - AIF1TX6MIX Input 2 Source
+ */
+#define WM2200_AIF1TX6MIX_SRC2_MASK             0x007F  /* AIF1TX6MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC2_SHIFT                 0  /* AIF1TX6MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC2_WIDTH                 7  /* AIF1TX6MIX_SRC2 - [6:0] */
+
+/*
+ * R1611 (0x64B) - AIF1TX6MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX6MIX_VOL2_MASK             0x00FE  /* AIF1TX6MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL2_SHIFT                 1  /* AIF1TX6MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL2_WIDTH                 7  /* AIF1TX6MIX_VOL2 - [7:1] */
+
+/*
+ * R1612 (0x64C) - AIF1TX6MIX Input 3 Source
+ */
+#define WM2200_AIF1TX6MIX_SRC3_MASK             0x007F  /* AIF1TX6MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC3_SHIFT                 0  /* AIF1TX6MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC3_WIDTH                 7  /* AIF1TX6MIX_SRC3 - [6:0] */
+
+/*
+ * R1613 (0x64D) - AIF1TX6MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX6MIX_VOL3_MASK             0x00FE  /* AIF1TX6MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL3_SHIFT                 1  /* AIF1TX6MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL3_WIDTH                 7  /* AIF1TX6MIX_VOL3 - [7:1] */
+
+/*
+ * R1614 (0x64E) - AIF1TX6MIX Input 4 Source
+ */
+#define WM2200_AIF1TX6MIX_SRC4_MASK             0x007F  /* AIF1TX6MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC4_SHIFT                 0  /* AIF1TX6MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC4_WIDTH                 7  /* AIF1TX6MIX_SRC4 - [6:0] */
+
+/*
+ * R1615 (0x64F) - AIF1TX6MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX6MIX_VOL4_MASK             0x00FE  /* AIF1TX6MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL4_SHIFT                 1  /* AIF1TX6MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL4_WIDTH                 7  /* AIF1TX6MIX_VOL4 - [7:1] */
+
+/*
+ * R1616 (0x650) - EQLMIX Input 1 Source
+ */
+#define WM2200_EQLMIX_SRC1_MASK                 0x007F  /* EQLMIX_SRC1 - [6:0] */
+#define WM2200_EQLMIX_SRC1_SHIFT                     0  /* EQLMIX_SRC1 - [6:0] */
+#define WM2200_EQLMIX_SRC1_WIDTH                     7  /* EQLMIX_SRC1 - [6:0] */
+
+/*
+ * R1617 (0x651) - EQLMIX Input 1 Volume
+ */
+#define WM2200_EQLMIX_VOL1_MASK                 0x00FE  /* EQLMIX_VOL1 - [7:1] */
+#define WM2200_EQLMIX_VOL1_SHIFT                     1  /* EQLMIX_VOL1 - [7:1] */
+#define WM2200_EQLMIX_VOL1_WIDTH                     7  /* EQLMIX_VOL1 - [7:1] */
+
+/*
+ * R1618 (0x652) - EQLMIX Input 2 Source
+ */
+#define WM2200_EQLMIX_SRC2_MASK                 0x007F  /* EQLMIX_SRC2 - [6:0] */
+#define WM2200_EQLMIX_SRC2_SHIFT                     0  /* EQLMIX_SRC2 - [6:0] */
+#define WM2200_EQLMIX_SRC2_WIDTH                     7  /* EQLMIX_SRC2 - [6:0] */
+
+/*
+ * R1619 (0x653) - EQLMIX Input 2 Volume
+ */
+#define WM2200_EQLMIX_VOL2_MASK                 0x00FE  /* EQLMIX_VOL2 - [7:1] */
+#define WM2200_EQLMIX_VOL2_SHIFT                     1  /* EQLMIX_VOL2 - [7:1] */
+#define WM2200_EQLMIX_VOL2_WIDTH                     7  /* EQLMIX_VOL2 - [7:1] */
+
+/*
+ * R1620 (0x654) - EQLMIX Input 3 Source
+ */
+#define WM2200_EQLMIX_SRC3_MASK                 0x007F  /* EQLMIX_SRC3 - [6:0] */
+#define WM2200_EQLMIX_SRC3_SHIFT                     0  /* EQLMIX_SRC3 - [6:0] */
+#define WM2200_EQLMIX_SRC3_WIDTH                     7  /* EQLMIX_SRC3 - [6:0] */
+
+/*
+ * R1621 (0x655) - EQLMIX Input 3 Volume
+ */
+#define WM2200_EQLMIX_VOL3_MASK                 0x00FE  /* EQLMIX_VOL3 - [7:1] */
+#define WM2200_EQLMIX_VOL3_SHIFT                     1  /* EQLMIX_VOL3 - [7:1] */
+#define WM2200_EQLMIX_VOL3_WIDTH                     7  /* EQLMIX_VOL3 - [7:1] */
+
+/*
+ * R1622 (0x656) - EQLMIX Input 4 Source
+ */
+#define WM2200_EQLMIX_SRC4_MASK                 0x007F  /* EQLMIX_SRC4 - [6:0] */
+#define WM2200_EQLMIX_SRC4_SHIFT                     0  /* EQLMIX_SRC4 - [6:0] */
+#define WM2200_EQLMIX_SRC4_WIDTH                     7  /* EQLMIX_SRC4 - [6:0] */
+
+/*
+ * R1623 (0x657) - EQLMIX Input 4 Volume
+ */
+#define WM2200_EQLMIX_VOL4_MASK                 0x00FE  /* EQLMIX_VOL4 - [7:1] */
+#define WM2200_EQLMIX_VOL4_SHIFT                     1  /* EQLMIX_VOL4 - [7:1] */
+#define WM2200_EQLMIX_VOL4_WIDTH                     7  /* EQLMIX_VOL4 - [7:1] */
+
+/*
+ * R1624 (0x658) - EQRMIX Input 1 Source
+ */
+#define WM2200_EQRMIX_SRC1_MASK                 0x007F  /* EQRMIX_SRC1 - [6:0] */
+#define WM2200_EQRMIX_SRC1_SHIFT                     0  /* EQRMIX_SRC1 - [6:0] */
+#define WM2200_EQRMIX_SRC1_WIDTH                     7  /* EQRMIX_SRC1 - [6:0] */
+
+/*
+ * R1625 (0x659) - EQRMIX Input 1 Volume
+ */
+#define WM2200_EQRMIX_VOL1_MASK                 0x00FE  /* EQRMIX_VOL1 - [7:1] */
+#define WM2200_EQRMIX_VOL1_SHIFT                     1  /* EQRMIX_VOL1 - [7:1] */
+#define WM2200_EQRMIX_VOL1_WIDTH                     7  /* EQRMIX_VOL1 - [7:1] */
+
+/*
+ * R1626 (0x65A) - EQRMIX Input 2 Source
+ */
+#define WM2200_EQRMIX_SRC2_MASK                 0x007F  /* EQRMIX_SRC2 - [6:0] */
+#define WM2200_EQRMIX_SRC2_SHIFT                     0  /* EQRMIX_SRC2 - [6:0] */
+#define WM2200_EQRMIX_SRC2_WIDTH                     7  /* EQRMIX_SRC2 - [6:0] */
+
+/*
+ * R1627 (0x65B) - EQRMIX Input 2 Volume
+ */
+#define WM2200_EQRMIX_VOL2_MASK                 0x00FE  /* EQRMIX_VOL2 - [7:1] */
+#define WM2200_EQRMIX_VOL2_SHIFT                     1  /* EQRMIX_VOL2 - [7:1] */
+#define WM2200_EQRMIX_VOL2_WIDTH                     7  /* EQRMIX_VOL2 - [7:1] */
+
+/*
+ * R1628 (0x65C) - EQRMIX Input 3 Source
+ */
+#define WM2200_EQRMIX_SRC3_MASK                 0x007F  /* EQRMIX_SRC3 - [6:0] */
+#define WM2200_EQRMIX_SRC3_SHIFT                     0  /* EQRMIX_SRC3 - [6:0] */
+#define WM2200_EQRMIX_SRC3_WIDTH                     7  /* EQRMIX_SRC3 - [6:0] */
+
+/*
+ * R1629 (0x65D) - EQRMIX Input 3 Volume
+ */
+#define WM2200_EQRMIX_VOL3_MASK                 0x00FE  /* EQRMIX_VOL3 - [7:1] */
+#define WM2200_EQRMIX_VOL3_SHIFT                     1  /* EQRMIX_VOL3 - [7:1] */
+#define WM2200_EQRMIX_VOL3_WIDTH                     7  /* EQRMIX_VOL3 - [7:1] */
+
+/*
+ * R1630 (0x65E) - EQRMIX Input 4 Source
+ */
+#define WM2200_EQRMIX_SRC4_MASK                 0x007F  /* EQRMIX_SRC4 - [6:0] */
+#define WM2200_EQRMIX_SRC4_SHIFT                     0  /* EQRMIX_SRC4 - [6:0] */
+#define WM2200_EQRMIX_SRC4_WIDTH                     7  /* EQRMIX_SRC4 - [6:0] */
+
+/*
+ * R1631 (0x65F) - EQRMIX Input 4 Volume
+ */
+#define WM2200_EQRMIX_VOL4_MASK                 0x00FE  /* EQRMIX_VOL4 - [7:1] */
+#define WM2200_EQRMIX_VOL4_SHIFT                     1  /* EQRMIX_VOL4 - [7:1] */
+#define WM2200_EQRMIX_VOL4_WIDTH                     7  /* EQRMIX_VOL4 - [7:1] */
+
+/*
+ * R1632 (0x660) - LHPF1MIX Input 1 Source
+ */
+#define WM2200_LHPF1MIX_SRC1_MASK               0x007F  /* LHPF1MIX_SRC1 - [6:0] */
+#define WM2200_LHPF1MIX_SRC1_SHIFT                   0  /* LHPF1MIX_SRC1 - [6:0] */
+#define WM2200_LHPF1MIX_SRC1_WIDTH                   7  /* LHPF1MIX_SRC1 - [6:0] */
+
+/*
+ * R1633 (0x661) - LHPF1MIX Input 1 Volume
+ */
+#define WM2200_LHPF1MIX_VOL1_MASK               0x00FE  /* LHPF1MIX_VOL1 - [7:1] */
+#define WM2200_LHPF1MIX_VOL1_SHIFT                   1  /* LHPF1MIX_VOL1 - [7:1] */
+#define WM2200_LHPF1MIX_VOL1_WIDTH                   7  /* LHPF1MIX_VOL1 - [7:1] */
+
+/*
+ * R1634 (0x662) - LHPF1MIX Input 2 Source
+ */
+#define WM2200_LHPF1MIX_SRC2_MASK               0x007F  /* LHPF1MIX_SRC2 - [6:0] */
+#define WM2200_LHPF1MIX_SRC2_SHIFT                   0  /* LHPF1MIX_SRC2 - [6:0] */
+#define WM2200_LHPF1MIX_SRC2_WIDTH                   7  /* LHPF1MIX_SRC2 - [6:0] */
+
+/*
+ * R1635 (0x663) - LHPF1MIX Input 2 Volume
+ */
+#define WM2200_LHPF1MIX_VOL2_MASK               0x00FE  /* LHPF1MIX_VOL2 - [7:1] */
+#define WM2200_LHPF1MIX_VOL2_SHIFT                   1  /* LHPF1MIX_VOL2 - [7:1] */
+#define WM2200_LHPF1MIX_VOL2_WIDTH                   7  /* LHPF1MIX_VOL2 - [7:1] */
+
+/*
+ * R1636 (0x664) - LHPF1MIX Input 3 Source
+ */
+#define WM2200_LHPF1MIX_SRC3_MASK               0x007F  /* LHPF1MIX_SRC3 - [6:0] */
+#define WM2200_LHPF1MIX_SRC3_SHIFT                   0  /* LHPF1MIX_SRC3 - [6:0] */
+#define WM2200_LHPF1MIX_SRC3_WIDTH                   7  /* LHPF1MIX_SRC3 - [6:0] */
+
+/*
+ * R1637 (0x665) - LHPF1MIX Input 3 Volume
+ */
+#define WM2200_LHPF1MIX_VOL3_MASK               0x00FE  /* LHPF1MIX_VOL3 - [7:1] */
+#define WM2200_LHPF1MIX_VOL3_SHIFT                   1  /* LHPF1MIX_VOL3 - [7:1] */
+#define WM2200_LHPF1MIX_VOL3_WIDTH                   7  /* LHPF1MIX_VOL3 - [7:1] */
+
+/*
+ * R1638 (0x666) - LHPF1MIX Input 4 Source
+ */
+#define WM2200_LHPF1MIX_SRC4_MASK               0x007F  /* LHPF1MIX_SRC4 - [6:0] */
+#define WM2200_LHPF1MIX_SRC4_SHIFT                   0  /* LHPF1MIX_SRC4 - [6:0] */
+#define WM2200_LHPF1MIX_SRC4_WIDTH                   7  /* LHPF1MIX_SRC4 - [6:0] */
+
+/*
+ * R1639 (0x667) - LHPF1MIX Input 4 Volume
+ */
+#define WM2200_LHPF1MIX_VOL4_MASK               0x00FE  /* LHPF1MIX_VOL4 - [7:1] */
+#define WM2200_LHPF1MIX_VOL4_SHIFT                   1  /* LHPF1MIX_VOL4 - [7:1] */
+#define WM2200_LHPF1MIX_VOL4_WIDTH                   7  /* LHPF1MIX_VOL4 - [7:1] */
+
+/*
+ * R1640 (0x668) - LHPF2MIX Input 1 Source
+ */
+#define WM2200_LHPF2MIX_SRC1_MASK               0x007F  /* LHPF2MIX_SRC1 - [6:0] */
+#define WM2200_LHPF2MIX_SRC1_SHIFT                   0  /* LHPF2MIX_SRC1 - [6:0] */
+#define WM2200_LHPF2MIX_SRC1_WIDTH                   7  /* LHPF2MIX_SRC1 - [6:0] */
+
+/*
+ * R1641 (0x669) - LHPF2MIX Input 1 Volume
+ */
+#define WM2200_LHPF2MIX_VOL1_MASK               0x00FE  /* LHPF2MIX_VOL1 - [7:1] */
+#define WM2200_LHPF2MIX_VOL1_SHIFT                   1  /* LHPF2MIX_VOL1 - [7:1] */
+#define WM2200_LHPF2MIX_VOL1_WIDTH                   7  /* LHPF2MIX_VOL1 - [7:1] */
+
+/*
+ * R1642 (0x66A) - LHPF2MIX Input 2 Source
+ */
+#define WM2200_LHPF2MIX_SRC2_MASK               0x007F  /* LHPF2MIX_SRC2 - [6:0] */
+#define WM2200_LHPF2MIX_SRC2_SHIFT                   0  /* LHPF2MIX_SRC2 - [6:0] */
+#define WM2200_LHPF2MIX_SRC2_WIDTH                   7  /* LHPF2MIX_SRC2 - [6:0] */
+
+/*
+ * R1643 (0x66B) - LHPF2MIX Input 2 Volume
+ */
+#define WM2200_LHPF2MIX_VOL2_MASK               0x00FE  /* LHPF2MIX_VOL2 - [7:1] */
+#define WM2200_LHPF2MIX_VOL2_SHIFT                   1  /* LHPF2MIX_VOL2 - [7:1] */
+#define WM2200_LHPF2MIX_VOL2_WIDTH                   7  /* LHPF2MIX_VOL2 - [7:1] */
+
+/*
+ * R1644 (0x66C) - LHPF2MIX Input 3 Source
+ */
+#define WM2200_LHPF2MIX_SRC3_MASK               0x007F  /* LHPF2MIX_SRC3 - [6:0] */
+#define WM2200_LHPF2MIX_SRC3_SHIFT                   0  /* LHPF2MIX_SRC3 - [6:0] */
+#define WM2200_LHPF2MIX_SRC3_WIDTH                   7  /* LHPF2MIX_SRC3 - [6:0] */
+
+/*
+ * R1645 (0x66D) - LHPF2MIX Input 3 Volume
+ */
+#define WM2200_LHPF2MIX_VOL3_MASK               0x00FE  /* LHPF2MIX_VOL3 - [7:1] */
+#define WM2200_LHPF2MIX_VOL3_SHIFT                   1  /* LHPF2MIX_VOL3 - [7:1] */
+#define WM2200_LHPF2MIX_VOL3_WIDTH                   7  /* LHPF2MIX_VOL3 - [7:1] */
+
+/*
+ * R1646 (0x66E) - LHPF2MIX Input 4 Source
+ */
+#define WM2200_LHPF2MIX_SRC4_MASK               0x007F  /* LHPF2MIX_SRC4 - [6:0] */
+#define WM2200_LHPF2MIX_SRC4_SHIFT                   0  /* LHPF2MIX_SRC4 - [6:0] */
+#define WM2200_LHPF2MIX_SRC4_WIDTH                   7  /* LHPF2MIX_SRC4 - [6:0] */
+
+/*
+ * R1647 (0x66F) - LHPF2MIX Input 4 Volume
+ */
+#define WM2200_LHPF2MIX_VOL4_MASK               0x00FE  /* LHPF2MIX_VOL4 - [7:1] */
+#define WM2200_LHPF2MIX_VOL4_SHIFT                   1  /* LHPF2MIX_VOL4 - [7:1] */
+#define WM2200_LHPF2MIX_VOL4_WIDTH                   7  /* LHPF2MIX_VOL4 - [7:1] */
+
+/*
+ * R1648 (0x670) - DSP1LMIX Input 1 Source
+ */
+#define WM2200_DSP1LMIX_SRC1_MASK               0x007F  /* DSP1LMIX_SRC1 - [6:0] */
+#define WM2200_DSP1LMIX_SRC1_SHIFT                   0  /* DSP1LMIX_SRC1 - [6:0] */
+#define WM2200_DSP1LMIX_SRC1_WIDTH                   7  /* DSP1LMIX_SRC1 - [6:0] */
+
+/*
+ * R1649 (0x671) - DSP1LMIX Input 1 Volume
+ */
+#define WM2200_DSP1LMIX_VOL1_MASK               0x00FE  /* DSP1LMIX_VOL1 - [7:1] */
+#define WM2200_DSP1LMIX_VOL1_SHIFT                   1  /* DSP1LMIX_VOL1 - [7:1] */
+#define WM2200_DSP1LMIX_VOL1_WIDTH                   7  /* DSP1LMIX_VOL1 - [7:1] */
+
+/*
+ * R1650 (0x672) - DSP1LMIX Input 2 Source
+ */
+#define WM2200_DSP1LMIX_SRC2_MASK               0x007F  /* DSP1LMIX_SRC2 - [6:0] */
+#define WM2200_DSP1LMIX_SRC2_SHIFT                   0  /* DSP1LMIX_SRC2 - [6:0] */
+#define WM2200_DSP1LMIX_SRC2_WIDTH                   7  /* DSP1LMIX_SRC2 - [6:0] */
+
+/*
+ * R1651 (0x673) - DSP1LMIX Input 2 Volume
+ */
+#define WM2200_DSP1LMIX_VOL2_MASK               0x00FE  /* DSP1LMIX_VOL2 - [7:1] */
+#define WM2200_DSP1LMIX_VOL2_SHIFT                   1  /* DSP1LMIX_VOL2 - [7:1] */
+#define WM2200_DSP1LMIX_VOL2_WIDTH                   7  /* DSP1LMIX_VOL2 - [7:1] */
+
+/*
+ * R1652 (0x674) - DSP1LMIX Input 3 Source
+ */
+#define WM2200_DSP1LMIX_SRC3_MASK               0x007F  /* DSP1LMIX_SRC3 - [6:0] */
+#define WM2200_DSP1LMIX_SRC3_SHIFT                   0  /* DSP1LMIX_SRC3 - [6:0] */
+#define WM2200_DSP1LMIX_SRC3_WIDTH                   7  /* DSP1LMIX_SRC3 - [6:0] */
+
+/*
+ * R1653 (0x675) - DSP1LMIX Input 3 Volume
+ */
+#define WM2200_DSP1LMIX_VOL3_MASK               0x00FE  /* DSP1LMIX_VOL3 - [7:1] */
+#define WM2200_DSP1LMIX_VOL3_SHIFT                   1  /* DSP1LMIX_VOL3 - [7:1] */
+#define WM2200_DSP1LMIX_VOL3_WIDTH                   7  /* DSP1LMIX_VOL3 - [7:1] */
+
+/*
+ * R1654 (0x676) - DSP1LMIX Input 4 Source
+ */
+#define WM2200_DSP1LMIX_SRC4_MASK               0x007F  /* DSP1LMIX_SRC4 - [6:0] */
+#define WM2200_DSP1LMIX_SRC4_SHIFT                   0  /* DSP1LMIX_SRC4 - [6:0] */
+#define WM2200_DSP1LMIX_SRC4_WIDTH                   7  /* DSP1LMIX_SRC4 - [6:0] */
+
+/*
+ * R1655 (0x677) - DSP1LMIX Input 4 Volume
+ */
+#define WM2200_DSP1LMIX_VOL4_MASK               0x00FE  /* DSP1LMIX_VOL4 - [7:1] */
+#define WM2200_DSP1LMIX_VOL4_SHIFT                   1  /* DSP1LMIX_VOL4 - [7:1] */
+#define WM2200_DSP1LMIX_VOL4_WIDTH                   7  /* DSP1LMIX_VOL4 - [7:1] */
+
+/*
+ * R1656 (0x678) - DSP1RMIX Input 1 Source
+ */
+#define WM2200_DSP1RMIX_SRC1_MASK               0x007F  /* DSP1RMIX_SRC1 - [6:0] */
+#define WM2200_DSP1RMIX_SRC1_SHIFT                   0  /* DSP1RMIX_SRC1 - [6:0] */
+#define WM2200_DSP1RMIX_SRC1_WIDTH                   7  /* DSP1RMIX_SRC1 - [6:0] */
+
+/*
+ * R1657 (0x679) - DSP1RMIX Input 1 Volume
+ */
+#define WM2200_DSP1RMIX_VOL1_MASK               0x00FE  /* DSP1RMIX_VOL1 - [7:1] */
+#define WM2200_DSP1RMIX_VOL1_SHIFT                   1  /* DSP1RMIX_VOL1 - [7:1] */
+#define WM2200_DSP1RMIX_VOL1_WIDTH                   7  /* DSP1RMIX_VOL1 - [7:1] */
+
+/*
+ * R1658 (0x67A) - DSP1RMIX Input 2 Source
+ */
+#define WM2200_DSP1RMIX_SRC2_MASK               0x007F  /* DSP1RMIX_SRC2 - [6:0] */
+#define WM2200_DSP1RMIX_SRC2_SHIFT                   0  /* DSP1RMIX_SRC2 - [6:0] */
+#define WM2200_DSP1RMIX_SRC2_WIDTH                   7  /* DSP1RMIX_SRC2 - [6:0] */
+
+/*
+ * R1659 (0x67B) - DSP1RMIX Input 2 Volume
+ */
+#define WM2200_DSP1RMIX_VOL2_MASK               0x00FE  /* DSP1RMIX_VOL2 - [7:1] */
+#define WM2200_DSP1RMIX_VOL2_SHIFT                   1  /* DSP1RMIX_VOL2 - [7:1] */
+#define WM2200_DSP1RMIX_VOL2_WIDTH                   7  /* DSP1RMIX_VOL2 - [7:1] */
+
+/*
+ * R1660 (0x67C) - DSP1RMIX Input 3 Source
+ */
+#define WM2200_DSP1RMIX_SRC3_MASK               0x007F  /* DSP1RMIX_SRC3 - [6:0] */
+#define WM2200_DSP1RMIX_SRC3_SHIFT                   0  /* DSP1RMIX_SRC3 - [6:0] */
+#define WM2200_DSP1RMIX_SRC3_WIDTH                   7  /* DSP1RMIX_SRC3 - [6:0] */
+
+/*
+ * R1661 (0x67D) - DSP1RMIX Input 3 Volume
+ */
+#define WM2200_DSP1RMIX_VOL3_MASK               0x00FE  /* DSP1RMIX_VOL3 - [7:1] */
+#define WM2200_DSP1RMIX_VOL3_SHIFT                   1  /* DSP1RMIX_VOL3 - [7:1] */
+#define WM2200_DSP1RMIX_VOL3_WIDTH                   7  /* DSP1RMIX_VOL3 - [7:1] */
+
+/*
+ * R1662 (0x67E) - DSP1RMIX Input 4 Source
+ */
+#define WM2200_DSP1RMIX_SRC4_MASK               0x007F  /* DSP1RMIX_SRC4 - [6:0] */
+#define WM2200_DSP1RMIX_SRC4_SHIFT                   0  /* DSP1RMIX_SRC4 - [6:0] */
+#define WM2200_DSP1RMIX_SRC4_WIDTH                   7  /* DSP1RMIX_SRC4 - [6:0] */
+
+/*
+ * R1663 (0x67F) - DSP1RMIX Input 4 Volume
+ */
+#define WM2200_DSP1RMIX_VOL4_MASK               0x00FE  /* DSP1RMIX_VOL4 - [7:1] */
+#define WM2200_DSP1RMIX_VOL4_SHIFT                   1  /* DSP1RMIX_VOL4 - [7:1] */
+#define WM2200_DSP1RMIX_VOL4_WIDTH                   7  /* DSP1RMIX_VOL4 - [7:1] */
+
+/*
+ * R1664 (0x680) - DSP1AUX1MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX1MIX_SRC1_MASK            0x007F  /* DSP1AUX1MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX1MIX_SRC1_SHIFT                0  /* DSP1AUX1MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX1MIX_SRC1_WIDTH                7  /* DSP1AUX1MIX_SRC1 - [6:0] */
+
+/*
+ * R1665 (0x681) - DSP1AUX2MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX2MIX_SRC1_MASK            0x007F  /* DSP1AUX2MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX2MIX_SRC1_SHIFT                0  /* DSP1AUX2MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX2MIX_SRC1_WIDTH                7  /* DSP1AUX2MIX_SRC1 - [6:0] */
+
+/*
+ * R1666 (0x682) - DSP1AUX3MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX3MIX_SRC1_MASK            0x007F  /* DSP1AUX3MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX3MIX_SRC1_SHIFT                0  /* DSP1AUX3MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX3MIX_SRC1_WIDTH                7  /* DSP1AUX3MIX_SRC1 - [6:0] */
+
+/*
+ * R1667 (0x683) - DSP1AUX4MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX4MIX_SRC1_MASK            0x007F  /* DSP1AUX4MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX4MIX_SRC1_SHIFT                0  /* DSP1AUX4MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX4MIX_SRC1_WIDTH                7  /* DSP1AUX4MIX_SRC1 - [6:0] */
+
+/*
+ * R1668 (0x684) - DSP1AUX5MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX5MIX_SRC1_MASK            0x007F  /* DSP1AUX5MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX5MIX_SRC1_SHIFT                0  /* DSP1AUX5MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX5MIX_SRC1_WIDTH                7  /* DSP1AUX5MIX_SRC1 - [6:0] */
+
+/*
+ * R1669 (0x685) - DSP1AUX6MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX6MIX_SRC1_MASK            0x007F  /* DSP1AUX6MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX6MIX_SRC1_SHIFT                0  /* DSP1AUX6MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX6MIX_SRC1_WIDTH                7  /* DSP1AUX6MIX_SRC1 - [6:0] */
+
+/*
+ * R1670 (0x686) - DSP2LMIX Input 1 Source
+ */
+#define WM2200_DSP2LMIX_SRC1_MASK               0x007F  /* DSP2LMIX_SRC1 - [6:0] */
+#define WM2200_DSP2LMIX_SRC1_SHIFT                   0  /* DSP2LMIX_SRC1 - [6:0] */
+#define WM2200_DSP2LMIX_SRC1_WIDTH                   7  /* DSP2LMIX_SRC1 - [6:0] */
+
+/*
+ * R1671 (0x687) - DSP2LMIX Input 1 Volume
+ */
+#define WM2200_DSP2LMIX_VOL1_MASK               0x00FE  /* DSP2LMIX_VOL1 - [7:1] */
+#define WM2200_DSP2LMIX_VOL1_SHIFT                   1  /* DSP2LMIX_VOL1 - [7:1] */
+#define WM2200_DSP2LMIX_VOL1_WIDTH                   7  /* DSP2LMIX_VOL1 - [7:1] */
+
+/*
+ * R1672 (0x688) - DSP2LMIX Input 2 Source
+ */
+#define WM2200_DSP2LMIX_SRC2_MASK               0x007F  /* DSP2LMIX_SRC2 - [6:0] */
+#define WM2200_DSP2LMIX_SRC2_SHIFT                   0  /* DSP2LMIX_SRC2 - [6:0] */
+#define WM2200_DSP2LMIX_SRC2_WIDTH                   7  /* DSP2LMIX_SRC2 - [6:0] */
+
+/*
+ * R1673 (0x689) - DSP2LMIX Input 2 Volume
+ */
+#define WM2200_DSP2LMIX_VOL2_MASK               0x00FE  /* DSP2LMIX_VOL2 - [7:1] */
+#define WM2200_DSP2LMIX_VOL2_SHIFT                   1  /* DSP2LMIX_VOL2 - [7:1] */
+#define WM2200_DSP2LMIX_VOL2_WIDTH                   7  /* DSP2LMIX_VOL2 - [7:1] */
+
+/*
+ * R1674 (0x68A) - DSP2LMIX Input 3 Source
+ */
+#define WM2200_DSP2LMIX_SRC3_MASK               0x007F  /* DSP2LMIX_SRC3 - [6:0] */
+#define WM2200_DSP2LMIX_SRC3_SHIFT                   0  /* DSP2LMIX_SRC3 - [6:0] */
+#define WM2200_DSP2LMIX_SRC3_WIDTH                   7  /* DSP2LMIX_SRC3 - [6:0] */
+
+/*
+ * R1675 (0x68B) - DSP2LMIX Input 3 Volume
+ */
+#define WM2200_DSP2LMIX_VOL3_MASK               0x00FE  /* DSP2LMIX_VOL3 - [7:1] */
+#define WM2200_DSP2LMIX_VOL3_SHIFT                   1  /* DSP2LMIX_VOL3 - [7:1] */
+#define WM2200_DSP2LMIX_VOL3_WIDTH                   7  /* DSP2LMIX_VOL3 - [7:1] */
+
+/*
+ * R1676 (0x68C) - DSP2LMIX Input 4 Source
+ */
+#define WM2200_DSP2LMIX_SRC4_MASK               0x007F  /* DSP2LMIX_SRC4 - [6:0] */
+#define WM2200_DSP2LMIX_SRC4_SHIFT                   0  /* DSP2LMIX_SRC4 - [6:0] */
+#define WM2200_DSP2LMIX_SRC4_WIDTH                   7  /* DSP2LMIX_SRC4 - [6:0] */
+
+/*
+ * R1677 (0x68D) - DSP2LMIX Input 4 Volume
+ */
+#define WM2200_DSP2LMIX_VOL4_MASK               0x00FE  /* DSP2LMIX_VOL4 - [7:1] */
+#define WM2200_DSP2LMIX_VOL4_SHIFT                   1  /* DSP2LMIX_VOL4 - [7:1] */
+#define WM2200_DSP2LMIX_VOL4_WIDTH                   7  /* DSP2LMIX_VOL4 - [7:1] */
+
+/*
+ * R1678 (0x68E) - DSP2RMIX Input 1 Source
+ */
+#define WM2200_DSP2RMIX_SRC1_MASK               0x007F  /* DSP2RMIX_SRC1 - [6:0] */
+#define WM2200_DSP2RMIX_SRC1_SHIFT                   0  /* DSP2RMIX_SRC1 - [6:0] */
+#define WM2200_DSP2RMIX_SRC1_WIDTH                   7  /* DSP2RMIX_SRC1 - [6:0] */
+
+/*
+ * R1679 (0x68F) - DSP2RMIX Input 1 Volume
+ */
+#define WM2200_DSP2RMIX_VOL1_MASK               0x00FE  /* DSP2RMIX_VOL1 - [7:1] */
+#define WM2200_DSP2RMIX_VOL1_SHIFT                   1  /* DSP2RMIX_VOL1 - [7:1] */
+#define WM2200_DSP2RMIX_VOL1_WIDTH                   7  /* DSP2RMIX_VOL1 - [7:1] */
+
+/*
+ * R1680 (0x690) - DSP2RMIX Input 2 Source
+ */
+#define WM2200_DSP2RMIX_SRC2_MASK               0x007F  /* DSP2RMIX_SRC2 - [6:0] */
+#define WM2200_DSP2RMIX_SRC2_SHIFT                   0  /* DSP2RMIX_SRC2 - [6:0] */
+#define WM2200_DSP2RMIX_SRC2_WIDTH                   7  /* DSP2RMIX_SRC2 - [6:0] */
+
+/*
+ * R1681 (0x691) - DSP2RMIX Input 2 Volume
+ */
+#define WM2200_DSP2RMIX_VOL2_MASK               0x00FE  /* DSP2RMIX_VOL2 - [7:1] */
+#define WM2200_DSP2RMIX_VOL2_SHIFT                   1  /* DSP2RMIX_VOL2 - [7:1] */
+#define WM2200_DSP2RMIX_VOL2_WIDTH                   7  /* DSP2RMIX_VOL2 - [7:1] */
+
+/*
+ * R1682 (0x692) - DSP2RMIX Input 3 Source
+ */
+#define WM2200_DSP2RMIX_SRC3_MASK               0x007F  /* DSP2RMIX_SRC3 - [6:0] */
+#define WM2200_DSP2RMIX_SRC3_SHIFT                   0  /* DSP2RMIX_SRC3 - [6:0] */
+#define WM2200_DSP2RMIX_SRC3_WIDTH                   7  /* DSP2RMIX_SRC3 - [6:0] */
+
+/*
+ * R1683 (0x693) - DSP2RMIX Input 3 Volume
+ */
+#define WM2200_DSP2RMIX_VOL3_MASK               0x00FE  /* DSP2RMIX_VOL3 - [7:1] */
+#define WM2200_DSP2RMIX_VOL3_SHIFT                   1  /* DSP2RMIX_VOL3 - [7:1] */
+#define WM2200_DSP2RMIX_VOL3_WIDTH                   7  /* DSP2RMIX_VOL3 - [7:1] */
+
+/*
+ * R1684 (0x694) - DSP2RMIX Input 4 Source
+ */
+#define WM2200_DSP2RMIX_SRC4_MASK               0x007F  /* DSP2RMIX_SRC4 - [6:0] */
+#define WM2200_DSP2RMIX_SRC4_SHIFT                   0  /* DSP2RMIX_SRC4 - [6:0] */
+#define WM2200_DSP2RMIX_SRC4_WIDTH                   7  /* DSP2RMIX_SRC4 - [6:0] */
+
+/*
+ * R1685 (0x695) - DSP2RMIX Input 4 Volume
+ */
+#define WM2200_DSP2RMIX_VOL4_MASK               0x00FE  /* DSP2RMIX_VOL4 - [7:1] */
+#define WM2200_DSP2RMIX_VOL4_SHIFT                   1  /* DSP2RMIX_VOL4 - [7:1] */
+#define WM2200_DSP2RMIX_VOL4_WIDTH                   7  /* DSP2RMIX_VOL4 - [7:1] */
+
+/*
+ * R1686 (0x696) - DSP2AUX1MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX1MIX_SRC1_MASK            0x007F  /* DSP2AUX1MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX1MIX_SRC1_SHIFT                0  /* DSP2AUX1MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX1MIX_SRC1_WIDTH                7  /* DSP2AUX1MIX_SRC1 - [6:0] */
+
+/*
+ * R1687 (0x697) - DSP2AUX2MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX2MIX_SRC1_MASK            0x007F  /* DSP2AUX2MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX2MIX_SRC1_SHIFT                0  /* DSP2AUX2MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX2MIX_SRC1_WIDTH                7  /* DSP2AUX2MIX_SRC1 - [6:0] */
+
+/*
+ * R1688 (0x698) - DSP2AUX3MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX3MIX_SRC1_MASK            0x007F  /* DSP2AUX3MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX3MIX_SRC1_SHIFT                0  /* DSP2AUX3MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX3MIX_SRC1_WIDTH                7  /* DSP2AUX3MIX_SRC1 - [6:0] */
+
+/*
+ * R1689 (0x699) - DSP2AUX4MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX4MIX_SRC1_MASK            0x007F  /* DSP2AUX4MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX4MIX_SRC1_SHIFT                0  /* DSP2AUX4MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX4MIX_SRC1_WIDTH                7  /* DSP2AUX4MIX_SRC1 - [6:0] */
+
+/*
+ * R1690 (0x69A) - DSP2AUX5MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX5MIX_SRC1_MASK            0x007F  /* DSP2AUX5MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX5MIX_SRC1_SHIFT                0  /* DSP2AUX5MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX5MIX_SRC1_WIDTH                7  /* DSP2AUX5MIX_SRC1 - [6:0] */
+
+/*
+ * R1691 (0x69B) - DSP2AUX6MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX6MIX_SRC1_MASK            0x007F  /* DSP2AUX6MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX6MIX_SRC1_SHIFT                0  /* DSP2AUX6MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX6MIX_SRC1_WIDTH                7  /* DSP2AUX6MIX_SRC1 - [6:0] */
+
+/*
+ * R1792 (0x700) - GPIO CTRL 1
+ */
+#define WM2200_GP1_DIR                          0x8000  /* GP1_DIR */
+#define WM2200_GP1_DIR_MASK                     0x8000  /* GP1_DIR */
+#define WM2200_GP1_DIR_SHIFT                        15  /* GP1_DIR */
+#define WM2200_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM2200_GP1_PU                           0x4000  /* GP1_PU */
+#define WM2200_GP1_PU_MASK                      0x4000  /* GP1_PU */
+#define WM2200_GP1_PU_SHIFT                         14  /* GP1_PU */
+#define WM2200_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM2200_GP1_PD                           0x2000  /* GP1_PD */
+#define WM2200_GP1_PD_MASK                      0x2000  /* GP1_PD */
+#define WM2200_GP1_PD_SHIFT                         13  /* GP1_PD */
+#define WM2200_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM2200_GP1_POL                          0x0400  /* GP1_POL */
+#define WM2200_GP1_POL_MASK                     0x0400  /* GP1_POL */
+#define WM2200_GP1_POL_SHIFT                        10  /* GP1_POL */
+#define WM2200_GP1_POL_WIDTH                         1  /* GP1_POL */
+#define WM2200_GP1_OP_CFG                       0x0200  /* GP1_OP_CFG */
+#define WM2200_GP1_OP_CFG_MASK                  0x0200  /* GP1_OP_CFG */
+#define WM2200_GP1_OP_CFG_SHIFT                      9  /* GP1_OP_CFG */
+#define WM2200_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM2200_GP1_DB                           0x0100  /* GP1_DB */
+#define WM2200_GP1_DB_MASK                      0x0100  /* GP1_DB */
+#define WM2200_GP1_DB_SHIFT                          8  /* GP1_DB */
+#define WM2200_GP1_DB_WIDTH                          1  /* GP1_DB */
+#define WM2200_GP1_LVL                          0x0040  /* GP1_LVL */
+#define WM2200_GP1_LVL_MASK                     0x0040  /* GP1_LVL */
+#define WM2200_GP1_LVL_SHIFT                         6  /* GP1_LVL */
+#define WM2200_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM2200_GP1_FN_MASK                      0x003F  /* GP1_FN - [5:0] */
+#define WM2200_GP1_FN_SHIFT                          0  /* GP1_FN - [5:0] */
+#define WM2200_GP1_FN_WIDTH                          6  /* GP1_FN - [5:0] */
+
+/*
+ * R1793 (0x701) - GPIO CTRL 2
+ */
+#define WM2200_GP2_DIR                          0x8000  /* GP2_DIR */
+#define WM2200_GP2_DIR_MASK                     0x8000  /* GP2_DIR */
+#define WM2200_GP2_DIR_SHIFT                        15  /* GP2_DIR */
+#define WM2200_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM2200_GP2_PU                           0x4000  /* GP2_PU */
+#define WM2200_GP2_PU_MASK                      0x4000  /* GP2_PU */
+#define WM2200_GP2_PU_SHIFT                         14  /* GP2_PU */
+#define WM2200_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM2200_GP2_PD                           0x2000  /* GP2_PD */
+#define WM2200_GP2_PD_MASK                      0x2000  /* GP2_PD */
+#define WM2200_GP2_PD_SHIFT                         13  /* GP2_PD */
+#define WM2200_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM2200_GP2_POL                          0x0400  /* GP2_POL */
+#define WM2200_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM2200_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM2200_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM2200_GP2_OP_CFG                       0x0200  /* GP2_OP_CFG */
+#define WM2200_GP2_OP_CFG_MASK                  0x0200  /* GP2_OP_CFG */
+#define WM2200_GP2_OP_CFG_SHIFT                      9  /* GP2_OP_CFG */
+#define WM2200_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM2200_GP2_DB                           0x0100  /* GP2_DB */
+#define WM2200_GP2_DB_MASK                      0x0100  /* GP2_DB */
+#define WM2200_GP2_DB_SHIFT                          8  /* GP2_DB */
+#define WM2200_GP2_DB_WIDTH                          1  /* GP2_DB */
+#define WM2200_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM2200_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM2200_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM2200_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM2200_GP2_FN_MASK                      0x003F  /* GP2_FN - [5:0] */
+#define WM2200_GP2_FN_SHIFT                          0  /* GP2_FN - [5:0] */
+#define WM2200_GP2_FN_WIDTH                          6  /* GP2_FN - [5:0] */
+
+/*
+ * R1794 (0x702) - GPIO CTRL 3
+ */
+#define WM2200_GP3_DIR                          0x8000  /* GP3_DIR */
+#define WM2200_GP3_DIR_MASK                     0x8000  /* GP3_DIR */
+#define WM2200_GP3_DIR_SHIFT                        15  /* GP3_DIR */
+#define WM2200_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM2200_GP3_PU                           0x4000  /* GP3_PU */
+#define WM2200_GP3_PU_MASK                      0x4000  /* GP3_PU */
+#define WM2200_GP3_PU_SHIFT                         14  /* GP3_PU */
+#define WM2200_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM2200_GP3_PD                           0x2000  /* GP3_PD */
+#define WM2200_GP3_PD_MASK                      0x2000  /* GP3_PD */
+#define WM2200_GP3_PD_SHIFT                         13  /* GP3_PD */
+#define WM2200_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM2200_GP3_POL                          0x0400  /* GP3_POL */
+#define WM2200_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM2200_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM2200_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM2200_GP3_OP_CFG                       0x0200  /* GP3_OP_CFG */
+#define WM2200_GP3_OP_CFG_MASK                  0x0200  /* GP3_OP_CFG */
+#define WM2200_GP3_OP_CFG_SHIFT                      9  /* GP3_OP_CFG */
+#define WM2200_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM2200_GP3_DB                           0x0100  /* GP3_DB */
+#define WM2200_GP3_DB_MASK                      0x0100  /* GP3_DB */
+#define WM2200_GP3_DB_SHIFT                          8  /* GP3_DB */
+#define WM2200_GP3_DB_WIDTH                          1  /* GP3_DB */
+#define WM2200_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM2200_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM2200_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM2200_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM2200_GP3_FN_MASK                      0x003F  /* GP3_FN - [5:0] */
+#define WM2200_GP3_FN_SHIFT                          0  /* GP3_FN - [5:0] */
+#define WM2200_GP3_FN_WIDTH                          6  /* GP3_FN - [5:0] */
+
+/*
+ * R1795 (0x703) - GPIO CTRL 4
+ */
+#define WM2200_GP4_DIR                          0x8000  /* GP4_DIR */
+#define WM2200_GP4_DIR_MASK                     0x8000  /* GP4_DIR */
+#define WM2200_GP4_DIR_SHIFT                        15  /* GP4_DIR */
+#define WM2200_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM2200_GP4_PU                           0x4000  /* GP4_PU */
+#define WM2200_GP4_PU_MASK                      0x4000  /* GP4_PU */
+#define WM2200_GP4_PU_SHIFT                         14  /* GP4_PU */
+#define WM2200_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM2200_GP4_PD                           0x2000  /* GP4_PD */
+#define WM2200_GP4_PD_MASK                      0x2000  /* GP4_PD */
+#define WM2200_GP4_PD_SHIFT                         13  /* GP4_PD */
+#define WM2200_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM2200_GP4_POL                          0x0400  /* GP4_POL */
+#define WM2200_GP4_POL_MASK                     0x0400  /* GP4_POL */
+#define WM2200_GP4_POL_SHIFT                        10  /* GP4_POL */
+#define WM2200_GP4_POL_WIDTH                         1  /* GP4_POL */
+#define WM2200_GP4_OP_CFG                       0x0200  /* GP4_OP_CFG */
+#define WM2200_GP4_OP_CFG_MASK                  0x0200  /* GP4_OP_CFG */
+#define WM2200_GP4_OP_CFG_SHIFT                      9  /* GP4_OP_CFG */
+#define WM2200_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM2200_GP4_DB                           0x0100  /* GP4_DB */
+#define WM2200_GP4_DB_MASK                      0x0100  /* GP4_DB */
+#define WM2200_GP4_DB_SHIFT                          8  /* GP4_DB */
+#define WM2200_GP4_DB_WIDTH                          1  /* GP4_DB */
+#define WM2200_GP4_LVL                          0x0040  /* GP4_LVL */
+#define WM2200_GP4_LVL_MASK                     0x0040  /* GP4_LVL */
+#define WM2200_GP4_LVL_SHIFT                         6  /* GP4_LVL */
+#define WM2200_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM2200_GP4_FN_MASK                      0x003F  /* GP4_FN - [5:0] */
+#define WM2200_GP4_FN_SHIFT                          0  /* GP4_FN - [5:0] */
+#define WM2200_GP4_FN_WIDTH                          6  /* GP4_FN - [5:0] */
+
+/*
+ * R1799 (0x707) - ADPS1 IRQ0
+ */
+#define WM2200_DSP_IRQ1                         0x0002  /* DSP_IRQ1 */
+#define WM2200_DSP_IRQ1_MASK                    0x0002  /* DSP_IRQ1 */
+#define WM2200_DSP_IRQ1_SHIFT                        1  /* DSP_IRQ1 */
+#define WM2200_DSP_IRQ1_WIDTH                        1  /* DSP_IRQ1 */
+#define WM2200_DSP_IRQ0                         0x0001  /* DSP_IRQ0 */
+#define WM2200_DSP_IRQ0_MASK                    0x0001  /* DSP_IRQ0 */
+#define WM2200_DSP_IRQ0_SHIFT                        0  /* DSP_IRQ0 */
+#define WM2200_DSP_IRQ0_WIDTH                        1  /* DSP_IRQ0 */
+
+/*
+ * R1800 (0x708) - ADPS1 IRQ1
+ */
+#define WM2200_DSP_IRQ3                         0x0002  /* DSP_IRQ3 */
+#define WM2200_DSP_IRQ3_MASK                    0x0002  /* DSP_IRQ3 */
+#define WM2200_DSP_IRQ3_SHIFT                        1  /* DSP_IRQ3 */
+#define WM2200_DSP_IRQ3_WIDTH                        1  /* DSP_IRQ3 */
+#define WM2200_DSP_IRQ2                         0x0001  /* DSP_IRQ2 */
+#define WM2200_DSP_IRQ2_MASK                    0x0001  /* DSP_IRQ2 */
+#define WM2200_DSP_IRQ2_SHIFT                        0  /* DSP_IRQ2 */
+#define WM2200_DSP_IRQ2_WIDTH                        1  /* DSP_IRQ2 */
+
+/*
+ * R1801 (0x709) - Misc Pad Ctrl 1
+ */
+#define WM2200_LDO1ENA_PD                       0x8000  /* LDO1ENA_PD */
+#define WM2200_LDO1ENA_PD_MASK                  0x8000  /* LDO1ENA_PD */
+#define WM2200_LDO1ENA_PD_SHIFT                     15  /* LDO1ENA_PD */
+#define WM2200_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
+#define WM2200_MCLK2_PD                         0x2000  /* MCLK2_PD */
+#define WM2200_MCLK2_PD_MASK                    0x2000  /* MCLK2_PD */
+#define WM2200_MCLK2_PD_SHIFT                       13  /* MCLK2_PD */
+#define WM2200_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
+#define WM2200_MCLK1_PD                         0x1000  /* MCLK1_PD */
+#define WM2200_MCLK1_PD_MASK                    0x1000  /* MCLK1_PD */
+#define WM2200_MCLK1_PD_SHIFT                       12  /* MCLK1_PD */
+#define WM2200_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
+#define WM2200_DACLRCLK1_PU                     0x0400  /* DACLRCLK1_PU */
+#define WM2200_DACLRCLK1_PU_MASK                0x0400  /* DACLRCLK1_PU */
+#define WM2200_DACLRCLK1_PU_SHIFT                   10  /* DACLRCLK1_PU */
+#define WM2200_DACLRCLK1_PU_WIDTH                    1  /* DACLRCLK1_PU */
+#define WM2200_DACLRCLK1_PD                     0x0200  /* DACLRCLK1_PD */
+#define WM2200_DACLRCLK1_PD_MASK                0x0200  /* DACLRCLK1_PD */
+#define WM2200_DACLRCLK1_PD_SHIFT                    9  /* DACLRCLK1_PD */
+#define WM2200_DACLRCLK1_PD_WIDTH                    1  /* DACLRCLK1_PD */
+#define WM2200_BCLK1_PU                         0x0100  /* BCLK1_PU */
+#define WM2200_BCLK1_PU_MASK                    0x0100  /* BCLK1_PU */
+#define WM2200_BCLK1_PU_SHIFT                        8  /* BCLK1_PU */
+#define WM2200_BCLK1_PU_WIDTH                        1  /* BCLK1_PU */
+#define WM2200_BCLK1_PD                         0x0080  /* BCLK1_PD */
+#define WM2200_BCLK1_PD_MASK                    0x0080  /* BCLK1_PD */
+#define WM2200_BCLK1_PD_SHIFT                        7  /* BCLK1_PD */
+#define WM2200_BCLK1_PD_WIDTH                        1  /* BCLK1_PD */
+#define WM2200_DACDAT1_PU                       0x0040  /* DACDAT1_PU */
+#define WM2200_DACDAT1_PU_MASK                  0x0040  /* DACDAT1_PU */
+#define WM2200_DACDAT1_PU_SHIFT                      6  /* DACDAT1_PU */
+#define WM2200_DACDAT1_PU_WIDTH                      1  /* DACDAT1_PU */
+#define WM2200_DACDAT1_PD                       0x0020  /* DACDAT1_PD */
+#define WM2200_DACDAT1_PD_MASK                  0x0020  /* DACDAT1_PD */
+#define WM2200_DACDAT1_PD_SHIFT                      5  /* DACDAT1_PD */
+#define WM2200_DACDAT1_PD_WIDTH                      1  /* DACDAT1_PD */
+#define WM2200_DMICDAT3_PD                      0x0010  /* DMICDAT3_PD */
+#define WM2200_DMICDAT3_PD_MASK                 0x0010  /* DMICDAT3_PD */
+#define WM2200_DMICDAT3_PD_SHIFT                     4  /* DMICDAT3_PD */
+#define WM2200_DMICDAT3_PD_WIDTH                     1  /* DMICDAT3_PD */
+#define WM2200_DMICDAT2_PD                      0x0008  /* DMICDAT2_PD */
+#define WM2200_DMICDAT2_PD_MASK                 0x0008  /* DMICDAT2_PD */
+#define WM2200_DMICDAT2_PD_SHIFT                     3  /* DMICDAT2_PD */
+#define WM2200_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
+#define WM2200_DMICDAT1_PD                      0x0004  /* DMICDAT1_PD */
+#define WM2200_DMICDAT1_PD_MASK                 0x0004  /* DMICDAT1_PD */
+#define WM2200_DMICDAT1_PD_SHIFT                     2  /* DMICDAT1_PD */
+#define WM2200_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
+#define WM2200_RSTB_PU                          0x0002  /* RSTB_PU */
+#define WM2200_RSTB_PU_MASK                     0x0002  /* RSTB_PU */
+#define WM2200_RSTB_PU_SHIFT                         1  /* RSTB_PU */
+#define WM2200_RSTB_PU_WIDTH                         1  /* RSTB_PU */
+#define WM2200_ADDR_PD                          0x0001  /* ADDR_PD */
+#define WM2200_ADDR_PD_MASK                     0x0001  /* ADDR_PD */
+#define WM2200_ADDR_PD_SHIFT                         0  /* ADDR_PD */
+#define WM2200_ADDR_PD_WIDTH                         1  /* ADDR_PD */
+
+/*
+ * R2048 (0x800) - Interrupt Status 1
+ */
+#define WM2200_DSP_IRQ0_EINT                    0x0080  /* DSP_IRQ0_EINT */
+#define WM2200_DSP_IRQ0_EINT_MASK               0x0080  /* DSP_IRQ0_EINT */
+#define WM2200_DSP_IRQ0_EINT_SHIFT                   7  /* DSP_IRQ0_EINT */
+#define WM2200_DSP_IRQ0_EINT_WIDTH                   1  /* DSP_IRQ0_EINT */
+#define WM2200_DSP_IRQ1_EINT                    0x0040  /* DSP_IRQ1_EINT */
+#define WM2200_DSP_IRQ1_EINT_MASK               0x0040  /* DSP_IRQ1_EINT */
+#define WM2200_DSP_IRQ1_EINT_SHIFT                   6  /* DSP_IRQ1_EINT */
+#define WM2200_DSP_IRQ1_EINT_WIDTH                   1  /* DSP_IRQ1_EINT */
+#define WM2200_DSP_IRQ2_EINT                    0x0020  /* DSP_IRQ2_EINT */
+#define WM2200_DSP_IRQ2_EINT_MASK               0x0020  /* DSP_IRQ2_EINT */
+#define WM2200_DSP_IRQ2_EINT_SHIFT                   5  /* DSP_IRQ2_EINT */
+#define WM2200_DSP_IRQ2_EINT_WIDTH                   1  /* DSP_IRQ2_EINT */
+#define WM2200_DSP_IRQ3_EINT                    0x0010  /* DSP_IRQ3_EINT */
+#define WM2200_DSP_IRQ3_EINT_MASK               0x0010  /* DSP_IRQ3_EINT */
+#define WM2200_DSP_IRQ3_EINT_SHIFT                   4  /* DSP_IRQ3_EINT */
+#define WM2200_DSP_IRQ3_EINT_WIDTH                   1  /* DSP_IRQ3_EINT */
+#define WM2200_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM2200_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM2200_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM2200_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM2200_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM2200_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM2200_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM2200_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM2200_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM2200_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM2200_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM2200_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM2200_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM2200_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM2200_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM2200_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R2049 (0x801) - Interrupt Status 1 Mask
+ */
+#define WM2200_IM_DSP_IRQ0_EINT                 0x0080  /* IM_DSP_IRQ0_EINT */
+#define WM2200_IM_DSP_IRQ0_EINT_MASK            0x0080  /* IM_DSP_IRQ0_EINT */
+#define WM2200_IM_DSP_IRQ0_EINT_SHIFT                7  /* IM_DSP_IRQ0_EINT */
+#define WM2200_IM_DSP_IRQ0_EINT_WIDTH                1  /* IM_DSP_IRQ0_EINT */
+#define WM2200_IM_DSP_IRQ1_EINT                 0x0040  /* IM_DSP_IRQ1_EINT */
+#define WM2200_IM_DSP_IRQ1_EINT_MASK            0x0040  /* IM_DSP_IRQ1_EINT */
+#define WM2200_IM_DSP_IRQ1_EINT_SHIFT                6  /* IM_DSP_IRQ1_EINT */
+#define WM2200_IM_DSP_IRQ1_EINT_WIDTH                1  /* IM_DSP_IRQ1_EINT */
+#define WM2200_IM_DSP_IRQ2_EINT                 0x0020  /* IM_DSP_IRQ2_EINT */
+#define WM2200_IM_DSP_IRQ2_EINT_MASK            0x0020  /* IM_DSP_IRQ2_EINT */
+#define WM2200_IM_DSP_IRQ2_EINT_SHIFT                5  /* IM_DSP_IRQ2_EINT */
+#define WM2200_IM_DSP_IRQ2_EINT_WIDTH                1  /* IM_DSP_IRQ2_EINT */
+#define WM2200_IM_DSP_IRQ3_EINT                 0x0010  /* IM_DSP_IRQ3_EINT */
+#define WM2200_IM_DSP_IRQ3_EINT_MASK            0x0010  /* IM_DSP_IRQ3_EINT */
+#define WM2200_IM_DSP_IRQ3_EINT_SHIFT                4  /* IM_DSP_IRQ3_EINT */
+#define WM2200_IM_DSP_IRQ3_EINT_WIDTH                1  /* IM_DSP_IRQ3_EINT */
+#define WM2200_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM2200_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM2200_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM2200_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM2200_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM2200_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM2200_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM2200_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM2200_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM2200_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM2200_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM2200_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM2200_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM2200_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM2200_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM2200_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R2050 (0x802) - Interrupt Status 2
+ */
+#define WM2200_WSEQ_BUSY_EINT                   0x0100  /* WSEQ_BUSY_EINT */
+#define WM2200_WSEQ_BUSY_EINT_MASK              0x0100  /* WSEQ_BUSY_EINT */
+#define WM2200_WSEQ_BUSY_EINT_SHIFT                  8  /* WSEQ_BUSY_EINT */
+#define WM2200_WSEQ_BUSY_EINT_WIDTH                  1  /* WSEQ_BUSY_EINT */
+#define WM2200_FLL_LOCK_EINT                    0x0002  /* FLL_LOCK_EINT */
+#define WM2200_FLL_LOCK_EINT_MASK               0x0002  /* FLL_LOCK_EINT */
+#define WM2200_FLL_LOCK_EINT_SHIFT                   1  /* FLL_LOCK_EINT */
+#define WM2200_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM2200_CLKGEN_EINT                      0x0001  /* CLKGEN_EINT */
+#define WM2200_CLKGEN_EINT_MASK                 0x0001  /* CLKGEN_EINT */
+#define WM2200_CLKGEN_EINT_SHIFT                     0  /* CLKGEN_EINT */
+#define WM2200_CLKGEN_EINT_WIDTH                     1  /* CLKGEN_EINT */
+
+/*
+ * R2051 (0x803) - Interrupt Raw Status 2
+ */
+#define WM2200_WSEQ_BUSY_STS                    0x0100  /* WSEQ_BUSY_STS */
+#define WM2200_WSEQ_BUSY_STS_MASK               0x0100  /* WSEQ_BUSY_STS */
+#define WM2200_WSEQ_BUSY_STS_SHIFT                   8  /* WSEQ_BUSY_STS */
+#define WM2200_WSEQ_BUSY_STS_WIDTH                   1  /* WSEQ_BUSY_STS */
+#define WM2200_FLL_LOCK_STS                     0x0002  /* FLL_LOCK_STS */
+#define WM2200_FLL_LOCK_STS_MASK                0x0002  /* FLL_LOCK_STS */
+#define WM2200_FLL_LOCK_STS_SHIFT                    1  /* FLL_LOCK_STS */
+#define WM2200_FLL_LOCK_STS_WIDTH                    1  /* FLL_LOCK_STS */
+#define WM2200_CLKGEN_STS                       0x0001  /* CLKGEN_STS */
+#define WM2200_CLKGEN_STS_MASK                  0x0001  /* CLKGEN_STS */
+#define WM2200_CLKGEN_STS_SHIFT                      0  /* CLKGEN_STS */
+#define WM2200_CLKGEN_STS_WIDTH                      1  /* CLKGEN_STS */
+
+/*
+ * R2052 (0x804) - Interrupt Status 2 Mask
+ */
+#define WM2200_IM_WSEQ_BUSY_EINT                0x0100  /* IM_WSEQ_BUSY_EINT */
+#define WM2200_IM_WSEQ_BUSY_EINT_MASK           0x0100  /* IM_WSEQ_BUSY_EINT */
+#define WM2200_IM_WSEQ_BUSY_EINT_SHIFT               8  /* IM_WSEQ_BUSY_EINT */
+#define WM2200_IM_WSEQ_BUSY_EINT_WIDTH               1  /* IM_WSEQ_BUSY_EINT */
+#define WM2200_IM_FLL_LOCK_EINT                 0x0002  /* IM_FLL_LOCK_EINT */
+#define WM2200_IM_FLL_LOCK_EINT_MASK            0x0002  /* IM_FLL_LOCK_EINT */
+#define WM2200_IM_FLL_LOCK_EINT_SHIFT                1  /* IM_FLL_LOCK_EINT */
+#define WM2200_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM2200_IM_CLKGEN_EINT                   0x0001  /* IM_CLKGEN_EINT */
+#define WM2200_IM_CLKGEN_EINT_MASK              0x0001  /* IM_CLKGEN_EINT */
+#define WM2200_IM_CLKGEN_EINT_SHIFT                  0  /* IM_CLKGEN_EINT */
+#define WM2200_IM_CLKGEN_EINT_WIDTH                  1  /* IM_CLKGEN_EINT */
+
+/*
+ * R2056 (0x808) - Interrupt Control
+ */
+#define WM2200_IM_IRQ                           0x0001  /* IM_IRQ */
+#define WM2200_IM_IRQ_MASK                      0x0001  /* IM_IRQ */
+#define WM2200_IM_IRQ_SHIFT                          0  /* IM_IRQ */
+#define WM2200_IM_IRQ_WIDTH                          1  /* IM_IRQ */
+
+/*
+ * R2304 (0x900) - EQL_1
+ */
+#define WM2200_EQL_B1_GAIN_MASK                 0xF800  /* EQL_B1_GAIN - [15:11] */
+#define WM2200_EQL_B1_GAIN_SHIFT                    11  /* EQL_B1_GAIN - [15:11] */
+#define WM2200_EQL_B1_GAIN_WIDTH                     5  /* EQL_B1_GAIN - [15:11] */
+#define WM2200_EQL_B2_GAIN_MASK                 0x07C0  /* EQL_B2_GAIN - [10:6] */
+#define WM2200_EQL_B2_GAIN_SHIFT                     6  /* EQL_B2_GAIN - [10:6] */
+#define WM2200_EQL_B2_GAIN_WIDTH                     5  /* EQL_B2_GAIN - [10:6] */
+#define WM2200_EQL_B3_GAIN_MASK                 0x003E  /* EQL_B3_GAIN - [5:1] */
+#define WM2200_EQL_B3_GAIN_SHIFT                     1  /* EQL_B3_GAIN - [5:1] */
+#define WM2200_EQL_B3_GAIN_WIDTH                     5  /* EQL_B3_GAIN - [5:1] */
+#define WM2200_EQL_ENA                          0x0001  /* EQL_ENA */
+#define WM2200_EQL_ENA_MASK                     0x0001  /* EQL_ENA */
+#define WM2200_EQL_ENA_SHIFT                         0  /* EQL_ENA */
+#define WM2200_EQL_ENA_WIDTH                         1  /* EQL_ENA */
+
+/*
+ * R2305 (0x901) - EQL_2
+ */
+#define WM2200_EQL_B4_GAIN_MASK                 0xF800  /* EQL_B4_GAIN - [15:11] */
+#define WM2200_EQL_B4_GAIN_SHIFT                    11  /* EQL_B4_GAIN - [15:11] */
+#define WM2200_EQL_B4_GAIN_WIDTH                     5  /* EQL_B4_GAIN - [15:11] */
+#define WM2200_EQL_B5_GAIN_MASK                 0x07C0  /* EQL_B5_GAIN - [10:6] */
+#define WM2200_EQL_B5_GAIN_SHIFT                     6  /* EQL_B5_GAIN - [10:6] */
+#define WM2200_EQL_B5_GAIN_WIDTH                     5  /* EQL_B5_GAIN - [10:6] */
+
+/*
+ * R2306 (0x902) - EQL_3
+ */
+#define WM2200_EQL_B1_A_MASK                    0xFFFF  /* EQL_B1_A - [15:0] */
+#define WM2200_EQL_B1_A_SHIFT                        0  /* EQL_B1_A - [15:0] */
+#define WM2200_EQL_B1_A_WIDTH                       16  /* EQL_B1_A - [15:0] */
+
+/*
+ * R2307 (0x903) - EQL_4
+ */
+#define WM2200_EQL_B1_B_MASK                    0xFFFF  /* EQL_B1_B - [15:0] */
+#define WM2200_EQL_B1_B_SHIFT                        0  /* EQL_B1_B - [15:0] */
+#define WM2200_EQL_B1_B_WIDTH                       16  /* EQL_B1_B - [15:0] */
+
+/*
+ * R2308 (0x904) - EQL_5
+ */
+#define WM2200_EQL_B1_PG_MASK                   0xFFFF  /* EQL_B1_PG - [15:0] */
+#define WM2200_EQL_B1_PG_SHIFT                       0  /* EQL_B1_PG - [15:0] */
+#define WM2200_EQL_B1_PG_WIDTH                      16  /* EQL_B1_PG - [15:0] */
+
+/*
+ * R2309 (0x905) - EQL_6
+ */
+#define WM2200_EQL_B2_A_MASK                    0xFFFF  /* EQL_B2_A - [15:0] */
+#define WM2200_EQL_B2_A_SHIFT                        0  /* EQL_B2_A - [15:0] */
+#define WM2200_EQL_B2_A_WIDTH                       16  /* EQL_B2_A - [15:0] */
+
+/*
+ * R2310 (0x906) - EQL_7
+ */
+#define WM2200_EQL_B2_B_MASK                    0xFFFF  /* EQL_B2_B - [15:0] */
+#define WM2200_EQL_B2_B_SHIFT                        0  /* EQL_B2_B - [15:0] */
+#define WM2200_EQL_B2_B_WIDTH                       16  /* EQL_B2_B - [15:0] */
+
+/*
+ * R2311 (0x907) - EQL_8
+ */
+#define WM2200_EQL_B2_C_MASK                    0xFFFF  /* EQL_B2_C - [15:0] */
+#define WM2200_EQL_B2_C_SHIFT                        0  /* EQL_B2_C - [15:0] */
+#define WM2200_EQL_B2_C_WIDTH                       16  /* EQL_B2_C - [15:0] */
+
+/*
+ * R2312 (0x908) - EQL_9
+ */
+#define WM2200_EQL_B2_PG_MASK                   0xFFFF  /* EQL_B2_PG - [15:0] */
+#define WM2200_EQL_B2_PG_SHIFT                       0  /* EQL_B2_PG - [15:0] */
+#define WM2200_EQL_B2_PG_WIDTH                      16  /* EQL_B2_PG - [15:0] */
+
+/*
+ * R2313 (0x909) - EQL_10
+ */
+#define WM2200_EQL_B3_A_MASK                    0xFFFF  /* EQL_B3_A - [15:0] */
+#define WM2200_EQL_B3_A_SHIFT                        0  /* EQL_B3_A - [15:0] */
+#define WM2200_EQL_B3_A_WIDTH                       16  /* EQL_B3_A - [15:0] */
+
+/*
+ * R2314 (0x90A) - EQL_11
+ */
+#define WM2200_EQL_B3_B_MASK                    0xFFFF  /* EQL_B3_B - [15:0] */
+#define WM2200_EQL_B3_B_SHIFT                        0  /* EQL_B3_B - [15:0] */
+#define WM2200_EQL_B3_B_WIDTH                       16  /* EQL_B3_B - [15:0] */
+
+/*
+ * R2315 (0x90B) - EQL_12
+ */
+#define WM2200_EQL_B3_C_MASK                    0xFFFF  /* EQL_B3_C - [15:0] */
+#define WM2200_EQL_B3_C_SHIFT                        0  /* EQL_B3_C - [15:0] */
+#define WM2200_EQL_B3_C_WIDTH                       16  /* EQL_B3_C - [15:0] */
+
+/*
+ * R2316 (0x90C) - EQL_13
+ */
+#define WM2200_EQL_B3_PG_MASK                   0xFFFF  /* EQL_B3_PG - [15:0] */
+#define WM2200_EQL_B3_PG_SHIFT                       0  /* EQL_B3_PG - [15:0] */
+#define WM2200_EQL_B3_PG_WIDTH                      16  /* EQL_B3_PG - [15:0] */
+
+/*
+ * R2317 (0x90D) - EQL_14
+ */
+#define WM2200_EQL_B4_A_MASK                    0xFFFF  /* EQL_B4_A - [15:0] */
+#define WM2200_EQL_B4_A_SHIFT                        0  /* EQL_B4_A - [15:0] */
+#define WM2200_EQL_B4_A_WIDTH                       16  /* EQL_B4_A - [15:0] */
+
+/*
+ * R2318 (0x90E) - EQL_15
+ */
+#define WM2200_EQL_B4_B_MASK                    0xFFFF  /* EQL_B4_B - [15:0] */
+#define WM2200_EQL_B4_B_SHIFT                        0  /* EQL_B4_B - [15:0] */
+#define WM2200_EQL_B4_B_WIDTH                       16  /* EQL_B4_B - [15:0] */
+
+/*
+ * R2319 (0x90F) - EQL_16
+ */
+#define WM2200_EQL_B4_C_MASK                    0xFFFF  /* EQL_B4_C - [15:0] */
+#define WM2200_EQL_B4_C_SHIFT                        0  /* EQL_B4_C - [15:0] */
+#define WM2200_EQL_B4_C_WIDTH                       16  /* EQL_B4_C - [15:0] */
+
+/*
+ * R2320 (0x910) - EQL_17
+ */
+#define WM2200_EQL_B4_PG_MASK                   0xFFFF  /* EQL_B4_PG - [15:0] */
+#define WM2200_EQL_B4_PG_SHIFT                       0  /* EQL_B4_PG - [15:0] */
+#define WM2200_EQL_B4_PG_WIDTH                      16  /* EQL_B4_PG - [15:0] */
+
+/*
+ * R2321 (0x911) - EQL_18
+ */
+#define WM2200_EQL_B5_A_MASK                    0xFFFF  /* EQL_B5_A - [15:0] */
+#define WM2200_EQL_B5_A_SHIFT                        0  /* EQL_B5_A - [15:0] */
+#define WM2200_EQL_B5_A_WIDTH                       16  /* EQL_B5_A - [15:0] */
+
+/*
+ * R2322 (0x912) - EQL_19
+ */
+#define WM2200_EQL_B5_B_MASK                    0xFFFF  /* EQL_B5_B - [15:0] */
+#define WM2200_EQL_B5_B_SHIFT                        0  /* EQL_B5_B - [15:0] */
+#define WM2200_EQL_B5_B_WIDTH                       16  /* EQL_B5_B - [15:0] */
+
+/*
+ * R2323 (0x913) - EQL_20
+ */
+#define WM2200_EQL_B5_PG_MASK                   0xFFFF  /* EQL_B5_PG - [15:0] */
+#define WM2200_EQL_B5_PG_SHIFT                       0  /* EQL_B5_PG - [15:0] */
+#define WM2200_EQL_B5_PG_WIDTH                      16  /* EQL_B5_PG - [15:0] */
+
+/*
+ * R2326 (0x916) - EQR_1
+ */
+#define WM2200_EQR_B1_GAIN_MASK                 0xF800  /* EQR_B1_GAIN - [15:11] */
+#define WM2200_EQR_B1_GAIN_SHIFT                    11  /* EQR_B1_GAIN - [15:11] */
+#define WM2200_EQR_B1_GAIN_WIDTH                     5  /* EQR_B1_GAIN - [15:11] */
+#define WM2200_EQR_B2_GAIN_MASK                 0x07C0  /* EQR_B2_GAIN - [10:6] */
+#define WM2200_EQR_B2_GAIN_SHIFT                     6  /* EQR_B2_GAIN - [10:6] */
+#define WM2200_EQR_B2_GAIN_WIDTH                     5  /* EQR_B2_GAIN - [10:6] */
+#define WM2200_EQR_B3_GAIN_MASK                 0x003E  /* EQR_B3_GAIN - [5:1] */
+#define WM2200_EQR_B3_GAIN_SHIFT                     1  /* EQR_B3_GAIN - [5:1] */
+#define WM2200_EQR_B3_GAIN_WIDTH                     5  /* EQR_B3_GAIN - [5:1] */
+#define WM2200_EQR_ENA                          0x0001  /* EQR_ENA */
+#define WM2200_EQR_ENA_MASK                     0x0001  /* EQR_ENA */
+#define WM2200_EQR_ENA_SHIFT                         0  /* EQR_ENA */
+#define WM2200_EQR_ENA_WIDTH                         1  /* EQR_ENA */
+
+/*
+ * R2327 (0x917) - EQR_2
+ */
+#define WM2200_EQR_B4_GAIN_MASK                 0xF800  /* EQR_B4_GAIN - [15:11] */
+#define WM2200_EQR_B4_GAIN_SHIFT                    11  /* EQR_B4_GAIN - [15:11] */
+#define WM2200_EQR_B4_GAIN_WIDTH                     5  /* EQR_B4_GAIN - [15:11] */
+#define WM2200_EQR_B5_GAIN_MASK                 0x07C0  /* EQR_B5_GAIN - [10:6] */
+#define WM2200_EQR_B5_GAIN_SHIFT                     6  /* EQR_B5_GAIN - [10:6] */
+#define WM2200_EQR_B5_GAIN_WIDTH                     5  /* EQR_B5_GAIN - [10:6] */
+
+/*
+ * R2328 (0x918) - EQR_3
+ */
+#define WM2200_EQR_B1_A_MASK                    0xFFFF  /* EQR_B1_A - [15:0] */
+#define WM2200_EQR_B1_A_SHIFT                        0  /* EQR_B1_A - [15:0] */
+#define WM2200_EQR_B1_A_WIDTH                       16  /* EQR_B1_A - [15:0] */
+
+/*
+ * R2329 (0x919) - EQR_4
+ */
+#define WM2200_EQR_B1_B_MASK                    0xFFFF  /* EQR_B1_B - [15:0] */
+#define WM2200_EQR_B1_B_SHIFT                        0  /* EQR_B1_B - [15:0] */
+#define WM2200_EQR_B1_B_WIDTH                       16  /* EQR_B1_B - [15:0] */
+
+/*
+ * R2330 (0x91A) - EQR_5
+ */
+#define WM2200_EQR_B1_PG_MASK                   0xFFFF  /* EQR_B1_PG - [15:0] */
+#define WM2200_EQR_B1_PG_SHIFT                       0  /* EQR_B1_PG - [15:0] */
+#define WM2200_EQR_B1_PG_WIDTH                      16  /* EQR_B1_PG - [15:0] */
+
+/*
+ * R2331 (0x91B) - EQR_6
+ */
+#define WM2200_EQR_B2_A_MASK                    0xFFFF  /* EQR_B2_A - [15:0] */
+#define WM2200_EQR_B2_A_SHIFT                        0  /* EQR_B2_A - [15:0] */
+#define WM2200_EQR_B2_A_WIDTH                       16  /* EQR_B2_A - [15:0] */
+
+/*
+ * R2332 (0x91C) - EQR_7
+ */
+#define WM2200_EQR_B2_B_MASK                    0xFFFF  /* EQR_B2_B - [15:0] */
+#define WM2200_EQR_B2_B_SHIFT                        0  /* EQR_B2_B - [15:0] */
+#define WM2200_EQR_B2_B_WIDTH                       16  /* EQR_B2_B - [15:0] */
+
+/*
+ * R2333 (0x91D) - EQR_8
+ */
+#define WM2200_EQR_B2_C_MASK                    0xFFFF  /* EQR_B2_C - [15:0] */
+#define WM2200_EQR_B2_C_SHIFT                        0  /* EQR_B2_C - [15:0] */
+#define WM2200_EQR_B2_C_WIDTH                       16  /* EQR_B2_C - [15:0] */
+
+/*
+ * R2334 (0x91E) - EQR_9
+ */
+#define WM2200_EQR_B2_PG_MASK                   0xFFFF  /* EQR_B2_PG - [15:0] */
+#define WM2200_EQR_B2_PG_SHIFT                       0  /* EQR_B2_PG - [15:0] */
+#define WM2200_EQR_B2_PG_WIDTH                      16  /* EQR_B2_PG - [15:0] */
+
+/*
+ * R2335 (0x91F) - EQR_10
+ */
+#define WM2200_EQR_B3_A_MASK                    0xFFFF  /* EQR_B3_A - [15:0] */
+#define WM2200_EQR_B3_A_SHIFT                        0  /* EQR_B3_A - [15:0] */
+#define WM2200_EQR_B3_A_WIDTH                       16  /* EQR_B3_A - [15:0] */
+
+/*
+ * R2336 (0x920) - EQR_11
+ */
+#define WM2200_EQR_B3_B_MASK                    0xFFFF  /* EQR_B3_B - [15:0] */
+#define WM2200_EQR_B3_B_SHIFT                        0  /* EQR_B3_B - [15:0] */
+#define WM2200_EQR_B3_B_WIDTH                       16  /* EQR_B3_B - [15:0] */
+
+/*
+ * R2337 (0x921) - EQR_12
+ */
+#define WM2200_EQR_B3_C_MASK                    0xFFFF  /* EQR_B3_C - [15:0] */
+#define WM2200_EQR_B3_C_SHIFT                        0  /* EQR_B3_C - [15:0] */
+#define WM2200_EQR_B3_C_WIDTH                       16  /* EQR_B3_C - [15:0] */
+
+/*
+ * R2338 (0x922) - EQR_13
+ */
+#define WM2200_EQR_B3_PG_MASK                   0xFFFF  /* EQR_B3_PG - [15:0] */
+#define WM2200_EQR_B3_PG_SHIFT                       0  /* EQR_B3_PG - [15:0] */
+#define WM2200_EQR_B3_PG_WIDTH                      16  /* EQR_B3_PG - [15:0] */
+
+/*
+ * R2339 (0x923) - EQR_14
+ */
+#define WM2200_EQR_B4_A_MASK                    0xFFFF  /* EQR_B4_A - [15:0] */
+#define WM2200_EQR_B4_A_SHIFT                        0  /* EQR_B4_A - [15:0] */
+#define WM2200_EQR_B4_A_WIDTH                       16  /* EQR_B4_A - [15:0] */
+
+/*
+ * R2340 (0x924) - EQR_15
+ */
+#define WM2200_EQR_B4_B_MASK                    0xFFFF  /* EQR_B4_B - [15:0] */
+#define WM2200_EQR_B4_B_SHIFT                        0  /* EQR_B4_B - [15:0] */
+#define WM2200_EQR_B4_B_WIDTH                       16  /* EQR_B4_B - [15:0] */
+
+/*
+ * R2341 (0x925) - EQR_16
+ */
+#define WM2200_EQR_B4_C_MASK                    0xFFFF  /* EQR_B4_C - [15:0] */
+#define WM2200_EQR_B4_C_SHIFT                        0  /* EQR_B4_C - [15:0] */
+#define WM2200_EQR_B4_C_WIDTH                       16  /* EQR_B4_C - [15:0] */
+
+/*
+ * R2342 (0x926) - EQR_17
+ */
+#define WM2200_EQR_B4_PG_MASK                   0xFFFF  /* EQR_B4_PG - [15:0] */
+#define WM2200_EQR_B4_PG_SHIFT                       0  /* EQR_B4_PG - [15:0] */
+#define WM2200_EQR_B4_PG_WIDTH                      16  /* EQR_B4_PG - [15:0] */
+
+/*
+ * R2343 (0x927) - EQR_18
+ */
+#define WM2200_EQR_B5_A_MASK                    0xFFFF  /* EQR_B5_A - [15:0] */
+#define WM2200_EQR_B5_A_SHIFT                        0  /* EQR_B5_A - [15:0] */
+#define WM2200_EQR_B5_A_WIDTH                       16  /* EQR_B5_A - [15:0] */
+
+/*
+ * R2344 (0x928) - EQR_19
+ */
+#define WM2200_EQR_B5_B_MASK                    0xFFFF  /* EQR_B5_B - [15:0] */
+#define WM2200_EQR_B5_B_SHIFT                        0  /* EQR_B5_B - [15:0] */
+#define WM2200_EQR_B5_B_WIDTH                       16  /* EQR_B5_B - [15:0] */
+
+/*
+ * R2345 (0x929) - EQR_20
+ */
+#define WM2200_EQR_B5_PG_MASK                   0xFFFF  /* EQR_B5_PG - [15:0] */
+#define WM2200_EQR_B5_PG_SHIFT                       0  /* EQR_B5_PG - [15:0] */
+#define WM2200_EQR_B5_PG_WIDTH                      16  /* EQR_B5_PG - [15:0] */
+
+/*
+ * R2366 (0x93E) - HPLPF1_1
+ */
+#define WM2200_LHPF1_MODE                       0x0002  /* LHPF1_MODE */
+#define WM2200_LHPF1_MODE_MASK                  0x0002  /* LHPF1_MODE */
+#define WM2200_LHPF1_MODE_SHIFT                      1  /* LHPF1_MODE */
+#define WM2200_LHPF1_MODE_WIDTH                      1  /* LHPF1_MODE */
+#define WM2200_LHPF1_ENA                        0x0001  /* LHPF1_ENA */
+#define WM2200_LHPF1_ENA_MASK                   0x0001  /* LHPF1_ENA */
+#define WM2200_LHPF1_ENA_SHIFT                       0  /* LHPF1_ENA */
+#define WM2200_LHPF1_ENA_WIDTH                       1  /* LHPF1_ENA */
+
+/*
+ * R2367 (0x93F) - HPLPF1_2
+ */
+#define WM2200_LHPF1_COEFF_MASK                 0xFFFF  /* LHPF1_COEFF - [15:0] */
+#define WM2200_LHPF1_COEFF_SHIFT                     0  /* LHPF1_COEFF - [15:0] */
+#define WM2200_LHPF1_COEFF_WIDTH                    16  /* LHPF1_COEFF - [15:0] */
+
+/*
+ * R2370 (0x942) - HPLPF2_1
+ */
+#define WM2200_LHPF2_MODE                       0x0002  /* LHPF2_MODE */
+#define WM2200_LHPF2_MODE_MASK                  0x0002  /* LHPF2_MODE */
+#define WM2200_LHPF2_MODE_SHIFT                      1  /* LHPF2_MODE */
+#define WM2200_LHPF2_MODE_WIDTH                      1  /* LHPF2_MODE */
+#define WM2200_LHPF2_ENA                        0x0001  /* LHPF2_ENA */
+#define WM2200_LHPF2_ENA_MASK                   0x0001  /* LHPF2_ENA */
+#define WM2200_LHPF2_ENA_SHIFT                       0  /* LHPF2_ENA */
+#define WM2200_LHPF2_ENA_WIDTH                       1  /* LHPF2_ENA */
+
+/*
+ * R2371 (0x943) - HPLPF2_2
+ */
+#define WM2200_LHPF2_COEFF_MASK                 0xFFFF  /* LHPF2_COEFF - [15:0] */
+#define WM2200_LHPF2_COEFF_SHIFT                     0  /* LHPF2_COEFF - [15:0] */
+#define WM2200_LHPF2_COEFF_WIDTH                    16  /* LHPF2_COEFF - [15:0] */
+
+/*
+ * R2560 (0xA00) - DSP1 Control 1
+ */
+#define WM2200_DSP1_RW_SEQUENCE_ENA             0x0001  /* DSP1_RW_SEQUENCE_ENA */
+#define WM2200_DSP1_RW_SEQUENCE_ENA_MASK        0x0001  /* DSP1_RW_SEQUENCE_ENA */
+#define WM2200_DSP1_RW_SEQUENCE_ENA_SHIFT            0  /* DSP1_RW_SEQUENCE_ENA */
+#define WM2200_DSP1_RW_SEQUENCE_ENA_WIDTH            1  /* DSP1_RW_SEQUENCE_ENA */
+
+/*
+ * R2562 (0xA02) - DSP1 Control 2
+ */
+#define WM2200_DSP1_PAGE_BASE_PM_0_MASK         0xFF00  /* DSP1_PAGE_BASE_PM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_PM_0_SHIFT             8  /* DSP1_PAGE_BASE_PM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_PM_0_WIDTH             8  /* DSP1_PAGE_BASE_PM - [15:8] */
+
+/*
+ * R2563 (0xA03) - DSP1 Control 3
+ */
+#define WM2200_DSP1_PAGE_BASE_DM_0_MASK         0xFF00  /* DSP1_PAGE_BASE_DM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_DM_0_SHIFT             8  /* DSP1_PAGE_BASE_DM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_DM_0_WIDTH             8  /* DSP1_PAGE_BASE_DM - [15:8] */
+
+/*
+ * R2564 (0xA04) - DSP1 Control 4
+ */
+#define WM2200_DSP1_PAGE_BASE_ZM_0_MASK         0xFF00  /* DSP1_PAGE_BASE_ZM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT             8  /* DSP1_PAGE_BASE_ZM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_ZM_0_WIDTH             8  /* DSP1_PAGE_BASE_ZM - [15:8] */
+
+/*
+ * R2566 (0xA06) - DSP1 Control 5
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_0_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_0_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_0_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+
+/*
+ * R2567 (0xA07) - DSP1 Control 6
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_1_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_1_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_1_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+
+/*
+ * R2568 (0xA08) - DSP1 Control 7
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_2_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_2_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_2_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+
+/*
+ * R2569 (0xA09) - DSP1 Control 8
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_3_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_3_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_3_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+
+/*
+ * R2570 (0xA0A) - DSP1 Control 9
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_4_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_4_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_4_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+
+/*
+ * R2571 (0xA0B) - DSP1 Control 10
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_5_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_5_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_5_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+
+/*
+ * R2572 (0xA0C) - DSP1 Control 11
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_6_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_6_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_6_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+
+/*
+ * R2573 (0xA0D) - DSP1 Control 12
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_7_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_7_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_7_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+
+/*
+ * R2575 (0xA0F) - DSP1 Control 13
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_0_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_0_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_0_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+
+/*
+ * R2576 (0xA10) - DSP1 Control 14
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_1_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_1_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_1_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+
+/*
+ * R2577 (0xA11) - DSP1 Control 15
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_2_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_2_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_2_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+
+/*
+ * R2578 (0xA12) - DSP1 Control 16
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_3_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_3_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_3_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+
+/*
+ * R2579 (0xA13) - DSP1 Control 17
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_4_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_4_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_4_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+
+/*
+ * R2580 (0xA14) - DSP1 Control 18
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_5_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_5_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_5_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+
+/*
+ * R2582 (0xA16) - DSP1 Control 19
+ */
+#define WM2200_DSP1_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+#define WM2200_DSP1_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+#define WM2200_DSP1_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+
+/*
+ * R2583 (0xA17) - DSP1 Control 20
+ */
+#define WM2200_DSP1_WDMA_CHANNEL_ENABLE_MASK    0x00FF  /* DSP1_WDMA_CHANNEL_ENABLE - [7:0] */
+#define WM2200_DSP1_WDMA_CHANNEL_ENABLE_SHIFT        0  /* DSP1_WDMA_CHANNEL_ENABLE - [7:0] */
+#define WM2200_DSP1_WDMA_CHANNEL_ENABLE_WIDTH        8  /* DSP1_WDMA_CHANNEL_ENABLE - [7:0] */
+
+/*
+ * R2584 (0xA18) - DSP1 Control 21
+ */
+#define WM2200_DSP1_RDMA_CHANNEL_ENABLE_MASK    0x003F  /* DSP1_RDMA_CHANNEL_ENABLE - [5:0] */
+#define WM2200_DSP1_RDMA_CHANNEL_ENABLE_SHIFT        0  /* DSP1_RDMA_CHANNEL_ENABLE - [5:0] */
+#define WM2200_DSP1_RDMA_CHANNEL_ENABLE_WIDTH        6  /* DSP1_RDMA_CHANNEL_ENABLE - [5:0] */
+
+/*
+ * R2586 (0xA1A) - DSP1 Control 22
+ */
+#define WM2200_DSP1_DM_SIZE_MASK                0xFFFF  /* DSP1_DM_SIZE - [15:0] */
+#define WM2200_DSP1_DM_SIZE_SHIFT                    0  /* DSP1_DM_SIZE - [15:0] */
+#define WM2200_DSP1_DM_SIZE_WIDTH                   16  /* DSP1_DM_SIZE - [15:0] */
+
+/*
+ * R2587 (0xA1B) - DSP1 Control 23
+ */
+#define WM2200_DSP1_PM_SIZE_MASK                0xFFFF  /* DSP1_PM_SIZE - [15:0] */
+#define WM2200_DSP1_PM_SIZE_SHIFT                    0  /* DSP1_PM_SIZE - [15:0] */
+#define WM2200_DSP1_PM_SIZE_WIDTH                   16  /* DSP1_PM_SIZE - [15:0] */
+
+/*
+ * R2588 (0xA1C) - DSP1 Control 24
+ */
+#define WM2200_DSP1_ZM_SIZE_MASK                0xFFFF  /* DSP1_ZM_SIZE - [15:0] */
+#define WM2200_DSP1_ZM_SIZE_SHIFT                    0  /* DSP1_ZM_SIZE - [15:0] */
+#define WM2200_DSP1_ZM_SIZE_WIDTH                   16  /* DSP1_ZM_SIZE - [15:0] */
+
+/*
+ * R2590 (0xA1E) - DSP1 Control 25
+ */
+#define WM2200_DSP1_PING_FULL                   0x8000  /* DSP1_PING_FULL */
+#define WM2200_DSP1_PING_FULL_MASK              0x8000  /* DSP1_PING_FULL */
+#define WM2200_DSP1_PING_FULL_SHIFT                 15  /* DSP1_PING_FULL */
+#define WM2200_DSP1_PING_FULL_WIDTH                  1  /* DSP1_PING_FULL */
+#define WM2200_DSP1_PONG_FULL                   0x4000  /* DSP1_PONG_FULL */
+#define WM2200_DSP1_PONG_FULL_MASK              0x4000  /* DSP1_PONG_FULL */
+#define WM2200_DSP1_PONG_FULL_SHIFT                 14  /* DSP1_PONG_FULL */
+#define WM2200_DSP1_PONG_FULL_WIDTH                  1  /* DSP1_PONG_FULL */
+#define WM2200_DSP1_WDMA_ACTIVE_CHANNELS_MASK   0x00FF  /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define WM2200_DSP1_WDMA_ACTIVE_CHANNELS_SHIFT       0  /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define WM2200_DSP1_WDMA_ACTIVE_CHANNELS_WIDTH       8  /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */
+
+/*
+ * R2592 (0xA20) - DSP1 Control 26
+ */
+#define WM2200_DSP1_SCRATCH_0_MASK              0xFFFF  /* DSP1_SCRATCH_0 - [15:0] */
+#define WM2200_DSP1_SCRATCH_0_SHIFT                  0  /* DSP1_SCRATCH_0 - [15:0] */
+#define WM2200_DSP1_SCRATCH_0_WIDTH                 16  /* DSP1_SCRATCH_0 - [15:0] */
+
+/*
+ * R2593 (0xA21) - DSP1 Control 27
+ */
+#define WM2200_DSP1_SCRATCH_1_MASK              0xFFFF  /* DSP1_SCRATCH_1 - [15:0] */
+#define WM2200_DSP1_SCRATCH_1_SHIFT                  0  /* DSP1_SCRATCH_1 - [15:0] */
+#define WM2200_DSP1_SCRATCH_1_WIDTH                 16  /* DSP1_SCRATCH_1 - [15:0] */
+
+/*
+ * R2594 (0xA22) - DSP1 Control 28
+ */
+#define WM2200_DSP1_SCRATCH_2_MASK              0xFFFF  /* DSP1_SCRATCH_2 - [15:0] */
+#define WM2200_DSP1_SCRATCH_2_SHIFT                  0  /* DSP1_SCRATCH_2 - [15:0] */
+#define WM2200_DSP1_SCRATCH_2_WIDTH                 16  /* DSP1_SCRATCH_2 - [15:0] */
+
+/*
+ * R2595 (0xA23) - DSP1 Control 29
+ */
+#define WM2200_DSP1_SCRATCH_3_MASK              0xFFFF  /* DSP1_SCRATCH_3 - [15:0] */
+#define WM2200_DSP1_SCRATCH_3_SHIFT                  0  /* DSP1_SCRATCH_3 - [15:0] */
+#define WM2200_DSP1_SCRATCH_3_WIDTH                 16  /* DSP1_SCRATCH_3 - [15:0] */
+
+/*
+ * R2596 (0xA24) - DSP1 Control 30
+ */
+#define WM2200_DSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
+#define WM2200_DSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
+#define WM2200_DSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
+#define WM2200_DSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
+#define WM2200_DSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
+#define WM2200_DSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
+#define WM2200_DSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
+#define WM2200_DSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
+#define WM2200_DSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
+#define WM2200_DSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
+#define WM2200_DSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
+#define WM2200_DSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
+#define WM2200_DSP1_START                       0x0001  /* DSP1_START */
+#define WM2200_DSP1_START_MASK                  0x0001  /* DSP1_START */
+#define WM2200_DSP1_START_SHIFT                      0  /* DSP1_START */
+#define WM2200_DSP1_START_WIDTH                      1  /* DSP1_START */
+
+/*
+ * R2598 (0xA26) - DSP1 Control 31
+ */
+#define WM2200_DSP1_CLK_RATE_MASK               0x0018  /* DSP1_CLK_RATE - [4:3] */
+#define WM2200_DSP1_CLK_RATE_SHIFT                   3  /* DSP1_CLK_RATE - [4:3] */
+#define WM2200_DSP1_CLK_RATE_WIDTH                   2  /* DSP1_CLK_RATE - [4:3] */
+#define WM2200_DSP1_CLK_AVAIL                   0x0004  /* DSP1_CLK_AVAIL */
+#define WM2200_DSP1_CLK_AVAIL_MASK              0x0004  /* DSP1_CLK_AVAIL */
+#define WM2200_DSP1_CLK_AVAIL_SHIFT                  2  /* DSP1_CLK_AVAIL */
+#define WM2200_DSP1_CLK_AVAIL_WIDTH                  1  /* DSP1_CLK_AVAIL */
+#define WM2200_DSP1_CLK_REQ_MASK                0x0003  /* DSP1_CLK_REQ - [1:0] */
+#define WM2200_DSP1_CLK_REQ_SHIFT                    0  /* DSP1_CLK_REQ - [1:0] */
+#define WM2200_DSP1_CLK_REQ_WIDTH                    2  /* DSP1_CLK_REQ - [1:0] */
+
+/*
+ * R2816 (0xB00) - DSP2 Control 1
+ */
+#define WM2200_DSP2_RW_SEQUENCE_ENA             0x0001  /* DSP2_RW_SEQUENCE_ENA */
+#define WM2200_DSP2_RW_SEQUENCE_ENA_MASK        0x0001  /* DSP2_RW_SEQUENCE_ENA */
+#define WM2200_DSP2_RW_SEQUENCE_ENA_SHIFT            0  /* DSP2_RW_SEQUENCE_ENA */
+#define WM2200_DSP2_RW_SEQUENCE_ENA_WIDTH            1  /* DSP2_RW_SEQUENCE_ENA */
+
+/*
+ * R2818 (0xB02) - DSP2 Control 2
+ */
+#define WM2200_DSP2_PAGE_BASE_PM_0_MASK         0xFF00  /* DSP2_PAGE_BASE_PM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_PM_0_SHIFT             8  /* DSP2_PAGE_BASE_PM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_PM_0_WIDTH             8  /* DSP2_PAGE_BASE_PM - [15:8] */
+
+/*
+ * R2819 (0xB03) - DSP2 Control 3
+ */
+#define WM2200_DSP2_PAGE_BASE_DM_0_MASK         0xFF00  /* DSP2_PAGE_BASE_DM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_DM_0_SHIFT             8  /* DSP2_PAGE_BASE_DM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_DM_0_WIDTH             8  /* DSP2_PAGE_BASE_DM - [15:8] */
+
+/*
+ * R2820 (0xB04) - DSP2 Control 4
+ */
+#define WM2200_DSP2_PAGE_BASE_ZM_0_MASK         0xFF00  /* DSP2_PAGE_BASE_ZM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_ZM_0_SHIFT             8  /* DSP2_PAGE_BASE_ZM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_ZM_0_WIDTH             8  /* DSP2_PAGE_BASE_ZM - [15:8] */
+
+/*
+ * R2822 (0xB06) - DSP2 Control 5
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_0_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_0_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_0_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+
+/*
+ * R2823 (0xB07) - DSP2 Control 6
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_1_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_1_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_1_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+
+/*
+ * R2824 (0xB08) - DSP2 Control 7
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_2_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_2_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_2_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+
+/*
+ * R2825 (0xB09) - DSP2 Control 8
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_3_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_3_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_3_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+
+/*
+ * R2826 (0xB0A) - DSP2 Control 9
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_4_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_4_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_4_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+
+/*
+ * R2827 (0xB0B) - DSP2 Control 10
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_5_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_5_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_5_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+
+/*
+ * R2828 (0xB0C) - DSP2 Control 11
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_6_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_6_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_6_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+
+/*
+ * R2829 (0xB0D) - DSP2 Control 12
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_7_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_7_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_7_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+
+/*
+ * R2831 (0xB0F) - DSP2 Control 13
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_0_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_0_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_0_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+
+/*
+ * R2832 (0xB10) - DSP2 Control 14
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_1_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_1_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_1_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+
+/*
+ * R2833 (0xB11) - DSP2 Control 15
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_2_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_2_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_2_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+
+/*
+ * R2834 (0xB12) - DSP2 Control 16
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_3_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_3_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_3_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+
+/*
+ * R2835 (0xB13) - DSP2 Control 17
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_4_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_4_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_4_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+
+/*
+ * R2836 (0xB14) - DSP2 Control 18
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_5_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_5_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_5_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+
+/*
+ * R2838 (0xB16) - DSP2 Control 19
+ */
+#define WM2200_DSP2_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP2_WDMA_BUFFER_LENGTH - [7:0] */
+#define WM2200_DSP2_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP2_WDMA_BUFFER_LENGTH - [7:0] */
+#define WM2200_DSP2_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP2_WDMA_BUFFER_LENGTH - [7:0] */
+
+/*
+ * R2839 (0xB17) - DSP2 Control 20
+ */
+#define WM2200_DSP2_WDMA_CHANNEL_ENABLE_MASK    0x00FF  /* DSP2_WDMA_CHANNEL_ENABLE - [7:0] */
+#define WM2200_DSP2_WDMA_CHANNEL_ENABLE_SHIFT        0  /* DSP2_WDMA_CHANNEL_ENABLE - [7:0] */
+#define WM2200_DSP2_WDMA_CHANNEL_ENABLE_WIDTH        8  /* DSP2_WDMA_CHANNEL_ENABLE - [7:0] */
+
+/*
+ * R2840 (0xB18) - DSP2 Control 21
+ */
+#define WM2200_DSP2_RDMA_CHANNEL_ENABLE_MASK    0x003F  /* DSP2_RDMA_CHANNEL_ENABLE - [5:0] */
+#define WM2200_DSP2_RDMA_CHANNEL_ENABLE_SHIFT        0  /* DSP2_RDMA_CHANNEL_ENABLE - [5:0] */
+#define WM2200_DSP2_RDMA_CHANNEL_ENABLE_WIDTH        6  /* DSP2_RDMA_CHANNEL_ENABLE - [5:0] */
+
+/*
+ * R2842 (0xB1A) - DSP2 Control 22
+ */
+#define WM2200_DSP2_DM_SIZE_MASK                0xFFFF  /* DSP2_DM_SIZE - [15:0] */
+#define WM2200_DSP2_DM_SIZE_SHIFT                    0  /* DSP2_DM_SIZE - [15:0] */
+#define WM2200_DSP2_DM_SIZE_WIDTH                   16  /* DSP2_DM_SIZE - [15:0] */
+
+/*
+ * R2843 (0xB1B) - DSP2 Control 23
+ */
+#define WM2200_DSP2_PM_SIZE_MASK                0xFFFF  /* DSP2_PM_SIZE - [15:0] */
+#define WM2200_DSP2_PM_SIZE_SHIFT                    0  /* DSP2_PM_SIZE - [15:0] */
+#define WM2200_DSP2_PM_SIZE_WIDTH                   16  /* DSP2_PM_SIZE - [15:0] */
+
+/*
+ * R2844 (0xB1C) - DSP2 Control 24
+ */
+#define WM2200_DSP2_ZM_SIZE_MASK                0xFFFF  /* DSP2_ZM_SIZE - [15:0] */
+#define WM2200_DSP2_ZM_SIZE_SHIFT                    0  /* DSP2_ZM_SIZE - [15:0] */
+#define WM2200_DSP2_ZM_SIZE_WIDTH                   16  /* DSP2_ZM_SIZE - [15:0] */
+
+/*
+ * R2846 (0xB1E) - DSP2 Control 25
+ */
+#define WM2200_DSP2_PING_FULL                   0x8000  /* DSP2_PING_FULL */
+#define WM2200_DSP2_PING_FULL_MASK              0x8000  /* DSP2_PING_FULL */
+#define WM2200_DSP2_PING_FULL_SHIFT                 15  /* DSP2_PING_FULL */
+#define WM2200_DSP2_PING_FULL_WIDTH                  1  /* DSP2_PING_FULL */
+#define WM2200_DSP2_PONG_FULL                   0x4000  /* DSP2_PONG_FULL */
+#define WM2200_DSP2_PONG_FULL_MASK              0x4000  /* DSP2_PONG_FULL */
+#define WM2200_DSP2_PONG_FULL_SHIFT                 14  /* DSP2_PONG_FULL */
+#define WM2200_DSP2_PONG_FULL_WIDTH                  1  /* DSP2_PONG_FULL */
+#define WM2200_DSP2_WDMA_ACTIVE_CHANNELS_MASK   0x00FF  /* DSP2_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define WM2200_DSP2_WDMA_ACTIVE_CHANNELS_SHIFT       0  /* DSP2_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define WM2200_DSP2_WDMA_ACTIVE_CHANNELS_WIDTH       8  /* DSP2_WDMA_ACTIVE_CHANNELS - [7:0] */
+
+/*
+ * R2848 (0xB20) - DSP2 Control 26
+ */
+#define WM2200_DSP2_SCRATCH_0_MASK              0xFFFF  /* DSP2_SCRATCH_0 - [15:0] */
+#define WM2200_DSP2_SCRATCH_0_SHIFT                  0  /* DSP2_SCRATCH_0 - [15:0] */
+#define WM2200_DSP2_SCRATCH_0_WIDTH                 16  /* DSP2_SCRATCH_0 - [15:0] */
+
+/*
+ * R2849 (0xB21) - DSP2 Control 27
+ */
+#define WM2200_DSP2_SCRATCH_1_MASK              0xFFFF  /* DSP2_SCRATCH_1 - [15:0] */
+#define WM2200_DSP2_SCRATCH_1_SHIFT                  0  /* DSP2_SCRATCH_1 - [15:0] */
+#define WM2200_DSP2_SCRATCH_1_WIDTH                 16  /* DSP2_SCRATCH_1 - [15:0] */
+
+/*
+ * R2850 (0xB22) - DSP2 Control 28
+ */
+#define WM2200_DSP2_SCRATCH_2_MASK              0xFFFF  /* DSP2_SCRATCH_2 - [15:0] */
+#define WM2200_DSP2_SCRATCH_2_SHIFT                  0  /* DSP2_SCRATCH_2 - [15:0] */
+#define WM2200_DSP2_SCRATCH_2_WIDTH                 16  /* DSP2_SCRATCH_2 - [15:0] */
+
+/*
+ * R2851 (0xB23) - DSP2 Control 29
+ */
+#define WM2200_DSP2_SCRATCH_3_MASK              0xFFFF  /* DSP2_SCRATCH_3 - [15:0] */
+#define WM2200_DSP2_SCRATCH_3_SHIFT                  0  /* DSP2_SCRATCH_3 - [15:0] */
+#define WM2200_DSP2_SCRATCH_3_WIDTH                 16  /* DSP2_SCRATCH_3 - [15:0] */
+
+/*
+ * R2852 (0xB24) - DSP2 Control 30
+ */
+#define WM2200_DSP2_DBG_CLK_ENA                 0x0008  /* DSP2_DBG_CLK_ENA */
+#define WM2200_DSP2_DBG_CLK_ENA_MASK            0x0008  /* DSP2_DBG_CLK_ENA */
+#define WM2200_DSP2_DBG_CLK_ENA_SHIFT                3  /* DSP2_DBG_CLK_ENA */
+#define WM2200_DSP2_DBG_CLK_ENA_WIDTH                1  /* DSP2_DBG_CLK_ENA */
+#define WM2200_DSP2_SYS_ENA                     0x0004  /* DSP2_SYS_ENA */
+#define WM2200_DSP2_SYS_ENA_MASK                0x0004  /* DSP2_SYS_ENA */
+#define WM2200_DSP2_SYS_ENA_SHIFT                    2  /* DSP2_SYS_ENA */
+#define WM2200_DSP2_SYS_ENA_WIDTH                    1  /* DSP2_SYS_ENA */
+#define WM2200_DSP2_CORE_ENA                    0x0002  /* DSP2_CORE_ENA */
+#define WM2200_DSP2_CORE_ENA_MASK               0x0002  /* DSP2_CORE_ENA */
+#define WM2200_DSP2_CORE_ENA_SHIFT                   1  /* DSP2_CORE_ENA */
+#define WM2200_DSP2_CORE_ENA_WIDTH                   1  /* DSP2_CORE_ENA */
+#define WM2200_DSP2_START                       0x0001  /* DSP2_START */
+#define WM2200_DSP2_START_MASK                  0x0001  /* DSP2_START */
+#define WM2200_DSP2_START_SHIFT                      0  /* DSP2_START */
+#define WM2200_DSP2_START_WIDTH                      1  /* DSP2_START */
+
+/*
+ * R2854 (0xB26) - DSP2 Control 31
+ */
+#define WM2200_DSP2_CLK_RATE_MASK               0x0018  /* DSP2_CLK_RATE - [4:3] */
+#define WM2200_DSP2_CLK_RATE_SHIFT                   3  /* DSP2_CLK_RATE - [4:3] */
+#define WM2200_DSP2_CLK_RATE_WIDTH                   2  /* DSP2_CLK_RATE - [4:3] */
+#define WM2200_DSP2_CLK_AVAIL                   0x0004  /* DSP2_CLK_AVAIL */
+#define WM2200_DSP2_CLK_AVAIL_MASK              0x0004  /* DSP2_CLK_AVAIL */
+#define WM2200_DSP2_CLK_AVAIL_SHIFT                  2  /* DSP2_CLK_AVAIL */
+#define WM2200_DSP2_CLK_AVAIL_WIDTH                  1  /* DSP2_CLK_AVAIL */
+#define WM2200_DSP2_CLK_REQ_MASK                0x0003  /* DSP2_CLK_REQ - [1:0] */
+#define WM2200_DSP2_CLK_REQ_SHIFT                    0  /* DSP2_CLK_REQ - [1:0] */
+#define WM2200_DSP2_CLK_REQ_WIDTH                    2  /* DSP2_CLK_REQ - [1:0] */
+
+#endif
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 42d9039..45cde81 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2454,6 +2454,8 @@ static int wm5100_probe(struct snd_soc_codec *codec)
 
 	wm5100->codec = codec;
 
+	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
+
 	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
 	if (ret != 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index dc13be2..f29bc26 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -1059,7 +1059,7 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	wm8400_write(codec, WM8400_FLL_CONTROL_3, factors.n);
 
 	reg = wm8400_read(codec, WM8400_FLL_CONTROL_4);
-	reg &= WM8400_FLL_OUTDIV_MASK;
+	reg &= ~WM8400_FLL_OUTDIV_MASK;
 	reg |= factors.outdiv;
 	wm8400_write(codec, WM8400_FLL_CONTROL_4, reg);
 
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index 076bdb9..16c65ef 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/spi/spi.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
diff --git a/sound/soc/codecs/wm8772.c b/sound/soc/codecs/wm8772.c
new file mode 100644
index 0000000..17b1ff0
--- /dev/null
+++ b/sound/soc/codecs/wm8772.c
@@ -0,0 +1,520 @@
+/*
+ * wm8772.c  --  WM8772 ALSA Soc Audio driver
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#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/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8772.h"
+
+struct wm8772_priv {
+	enum snd_soc_control_type control_type;
+	unsigned int adcclk;
+	unsigned int dacclk;
+};
+
+static const u16 wm8772_reg_defs[] = {
+	0x00ff, 0x00ff, 0x0120, 0x0000,  /*  0 */
+	0x00ff, 0x00ff, 0x00ff, 0x00ff,  /*  4 */
+	0x00ff, 0x0000, 0x0080, 0x0040,  /*  8 */
+	0x0000
+};
+
+#define wm8772_reset(c)	snd_soc_write(c, WM8772_RESET, 0)
+
+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 struct snd_kcontrol_new wm8772_snd_controls[] = {
+
+	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("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("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),
+};
+
+static int wm8772_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct wm8772_priv *wm8772 = snd_soc_codec_get_drvdata(codec);
+
+	switch (freq) {
+	case 4096000:
+	case 5644800:
+	case 6144000:
+	case 8192000:
+	case 8467000:
+	case 9216000:
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+	case 22579200:
+	case 24576000:
+	case 33868800:
+	case 36864000:
+		if (clk_id == WM8772_DACCLK) {
+			wm8772->dacclk = freq;
+			return 0;
+		} else if (clk_id == WM8772_ADCCLK) {
+			wm8772->adcclk = freq;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static int wm8772_set_dac_dai_fmt(struct snd_soc_dai *codec_dai,
+				  unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 diface = snd_soc_read(codec, WM8772_IFACE) & 0x1f0;
+	u16 diface_ctrl = snd_soc_read(codec, WM8772_DACRATE) & 0x1ef;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		diface_ctrl |= 0x0010;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		diface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		diface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		diface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		diface |= 0x0007;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		diface |= 0x0008;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_write(codec, WM8772_DACRATE, diface_ctrl);
+	snd_soc_write(codec, WM8772_IFACE, diface);
+	return 0;
+}
+
+static int wm8772_set_adc_dai_fmt(struct snd_soc_dai *codec_dai,
+				  unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 aiface = 0;
+	u16 aiface_ctrl = snd_soc_read(codec, WM8772_ADCCTRL) & 0x1cf;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aiface |= 0x0010;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		aiface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aiface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		aiface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		aiface |= 0x0003;
+		aiface_ctrl |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		aiface_ctrl |= 0x0020;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_write(codec, WM8772_ADCCTRL, aiface_ctrl);
+	snd_soc_write(codec, WM8772_ADCRATE, aiface);
+	return 0;
+}
+
+static int wm8772_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct wm8772_priv *wm8772 = snd_soc_codec_get_drvdata(codec);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+		u16 diface = snd_soc_read(codec, WM8772_IFACE) & 0x1cf;
+		u16 diface_ctrl = snd_soc_read(codec, WM8772_DACRATE) & 0x3f;
+
+		/* bit size */
+		switch (params_format(params)) {
+		case SNDRV_PCM_FORMAT_S16_LE:
+			break;
+		case SNDRV_PCM_FORMAT_S20_3LE:
+			diface |= 0x0010;
+			break;
+		case SNDRV_PCM_FORMAT_S24_3LE:
+			diface |= 0x0020;
+			break;
+		case SNDRV_PCM_FORMAT_S32_LE:
+			diface |= 0x0030;
+			break;
+		}
+
+		/* set rate */
+		switch (wm8772->dacclk / params_rate(params)) {
+		case 768:
+			diface_ctrl |= (0x5 << 6);
+			break;
+		case 512:
+			diface_ctrl |= (0x4 << 6);
+			break;
+		case 384:
+			diface_ctrl |= (0x3 << 6);
+			break;
+		case 256:
+			diface_ctrl |= (0x2 << 6);
+			break;
+		case 192:
+			diface_ctrl |= (0x1 << 6);
+			break;
+		}
+
+		snd_soc_write(codec, WM8772_DACRATE, diface_ctrl);
+		snd_soc_write(codec, WM8772_IFACE, diface);
+
+	} else {
+
+		u16 aiface = snd_soc_read(codec, WM8772_ADCRATE) & 0x113;
+
+		/* bit size */
+		switch (params_format(params)) {
+		case SNDRV_PCM_FORMAT_S16_LE:
+			break;
+		case SNDRV_PCM_FORMAT_S20_3LE:
+			aiface |= 0x0004;
+			break;
+		case SNDRV_PCM_FORMAT_S24_LE:
+			aiface |= 0x0008;
+			break;
+		case SNDRV_PCM_FORMAT_S32_LE:
+			aiface |= 0x000c;
+			break;
+		}
+
+		/* set rate */
+		switch (wm8772->adcclk / params_rate(params)) {
+		case 768:
+			aiface |= (0x5 << 5);
+			break;
+		case 512:
+			aiface |= (0x4 << 5);
+			break;
+		case 384:
+			aiface |= (0x3 << 5);
+			break;
+		case 256:
+			aiface |= (0x2 << 5);
+			break;
+		}
+
+		snd_soc_write(codec, WM8772_ADCRATE, aiface);
+	}
+
+	return 0;
+}
+
+static int wm8772_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 master = snd_soc_read(codec, WM8772_DACRATE) & 0xffe0;
+	u16 *cache;
+	int i;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_write(codec, WM8772_DACRATE, master);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			if (codec->cache_sync) {
+				cache = codec->reg_cache;
+				for (i = 0; i < codec->driver->reg_cache_size; ++i) {
+					if (i == WM8772_RESET || cache[i] == wm8772_reg_defs[i])
+						continue;
+					snd_soc_write(codec, i, cache[i]);
+				}
+				codec->cache_sync = 0;
+			}
+		}
+		snd_soc_write(codec, WM8772_DACRATE, master | 0x0f);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_write(codec, WM8772_DACRATE, master | 0x1f);
+		codec->cache_sync = 1;
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+static int wm8772_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+	wm8772_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8772_resume(struct snd_soc_codec *codec)
+{
+	wm8772_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	return 0;
+}
+
+static int wm8772_remove(struct snd_soc_codec *codec)
+{
+	wm8772_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8772_probe(struct snd_soc_codec *codec)
+{
+	struct wm8772_priv *wm8772;
+	int reg, ret;
+
+	wm8772 = snd_soc_codec_get_drvdata(codec);
+
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8772->control_type);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
+		return ret;
+	}
+
+	wm8772_reset(codec);
+
+	/* power on device */
+	wm8772_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	/* set the update bits */
+	reg = snd_soc_read(codec, WM8772_MDACVOL);
+	snd_soc_write(codec, WM8772_MDACVOL, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8772_LDAC1VOL);
+	snd_soc_write(codec, WM8772_LDAC1VOL, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8772_LDAC2VOL);
+	snd_soc_write(codec, WM8772_LDAC2VOL, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8772_LDAC3VOL);
+	snd_soc_write(codec, WM8772_LDAC3VOL, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8772_RDAC1VOL);
+	snd_soc_write(codec, WM8772_RDAC1VOL, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8772_RDAC2VOL);
+	snd_soc_write(codec, WM8772_RDAC2VOL, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8772_RDAC3VOL);
+	snd_soc_write(codec, WM8772_RDAC3VOL, reg | 0x0100);
+
+	snd_soc_add_controls(codec, wm8772_snd_controls,
+			     ARRAY_SIZE(wm8772_snd_controls));
+	return 0;
+}
+
+static struct snd_soc_dai_ops wm8772_dac_ops = {
+	.hw_params = wm8772_hw_params,
+	.set_fmt = wm8772_set_dac_dai_fmt,
+	.set_sysclk = wm8772_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops wm8772_adc_ops = {
+	.hw_params = wm8772_hw_params,
+	.set_fmt = wm8772_set_adc_dai_fmt,
+	.set_sysclk = wm8772_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8772_dai[] = {
+	{
+		.name = "WM8772",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 2,
+			.channels_max = 6,
+		},
+		.ops = &wm8772_dac_ops
+	},
+	{
+		.name = "WM8772",
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.ops = &wm8772_adc_ops
+	}
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8772 = {
+	.probe = wm8772_probe,
+	.remove = wm8772_remove,
+	.suspend = wm8772_suspend,
+	.resume = wm8772_resume,
+	.set_bias_level = wm8772_set_bias_level,
+	.reg_cache_size = ARRAY_SIZE(wm8772_reg_defs),
+	.reg_word_size = sizeof(u16),
+	.reg_cache_default = wm8772_reg_defs
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8772_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct wm8772_priv *wm8772;
+	int ret;
+
+	wm8772 = kzalloc(sizeof *wm8772, GFP_KERNEL);
+	if (!wm8772)
+		return -ENOMEM;
+
+	wm8772->control_type = SND_SOC_I2C;
+	i2c_set_clientdata(i2c, wm8772);
+
+	ret = snd_soc_register_codec(&i2c->dev,
+				     &soc_codec_dev_wm8772, wm8772_dai,
+				     ARRAY_SIZE(wm8772_dai));
+	if (ret < 0)
+		kfree(wm8772);
+	return ret;
+}
+
+static __devexit int wm8772_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static const struct i2c_device_id wm8772_i2c_id[] = {
+	{ "wm8772", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8772_i2c_id);
+
+static struct i2c_driver wm8772_i2c_driver = {
+	.driver = {
+		.name = "wm8772",
+		.owner = THIS_MODULE,
+	},
+	.probe = wm8772_i2c_probe,
+	.remove = __devexit_p(wm8772_i2c_remove),
+	.id_table = wm8772_i2c_id
+};
+#endif
+
+static int __init wm8772_modinit(void)
+{
+	int ret = 0;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	ret = i2c_add_driver(&wm8772_i2c_driver);
+	if (ret) {
+		printk(KERN_ERR "Failed to register wm8772 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(wm8772_modinit);
+
+static void __exit wm8772_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&wm8772_i2c_driver);
+#endif
+}
+module_exit(wm8772_exit);
+
+MODULE_DESCRIPTION("ASoC WM8772 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8772.h b/sound/soc/codecs/wm8772.h
new file mode 100644
index 0000000..190a117
--- /dev/null
+++ b/sound/soc/codecs/wm8772.h
@@ -0,0 +1,42 @@
+/*
+ * wm8772.h  --  audio driver for WM8772
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _WM8772_H
+#define _WM8772_H
+
+/* WM8772 register space */
+
+#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 WM8772_CACHE_REGNUM 	10
+
+#define WM8772_DACCLK	0
+#define WM8772_ADCCLK	1
+
+#define WM8753_DAI_DAC		0
+#define WM8753_DAI_ADC		1
+
+#endif
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index de9ec9b..1b5856b 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -629,8 +629,8 @@ static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 		ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 5));
 		break;
 	case WM8940_OPCLKDIV:
-		reg = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFCF;
-		ret = snd_soc_write(codec, WM8940_ADDCNTRL, reg | (div << 4));
+		reg = snd_soc_read(codec, WM8940_GPIO) & 0xFFCF;
+		ret = snd_soc_write(codec, WM8940_GPIO, reg | (div << 4));
 		break;
 	}
 	return ret;
diff --git a/sound/soc/codecs/wm8950.c b/sound/soc/codecs/wm8950.c
new file mode 100644
index 0000000..6ff7605
--- /dev/null
+++ b/sound/soc/codecs/wm8950.c
@@ -0,0 +1,615 @@
+/*
+ * wm8950.c  --  WM8950 ALSA Soc Audio driver
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8950.h"
+
+static const u16 wm8950_reg_defs[WM8950_CACHEREGNUM] = {
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0050, 0x0000, 0x0140, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x00ff,
+	0x0000, 0x0000, 0x0100, 0x00ff,
+	0x0000, 0x0000, 0x012c, 0x002c,
+	0x002c, 0x002c, 0x002c, 0x0000,
+	0x0032, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0038, 0x000b, 0x0032, 0x0000,
+	0x0008, 0x000c, 0x0093, 0x00e9,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0003, 0x0010, 0x0000, 0x0000,
+	0x0000, 0x0002, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0039, 0x0000,
+	0x0000,
+};
+
+struct wm8950_priv {
+	enum snd_soc_control_type control_type;
+};
+
+static const char *wm8950_companding[] = {"Off", "NC", "u-law", "A-law" };
+static const char *wm8950_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" };
+static const char *wm8950_bw[] = {"Narrow", "Wide" };
+static const char *wm8950_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz" };
+static const char *wm8950_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz" };
+static const char *wm8950_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz" };
+static const char *wm8950_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" };
+static const char *wm8950_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz" };
+static const char *wm8950_alc[] = {"ALC", "Limiter" };
+
+static const struct soc_enum wm8950_enum[] = {
+	SOC_ENUM_SINGLE(WM8950_COMP, 1, 4, wm8950_companding), /* adc */
+	SOC_ENUM_SINGLE(WM8950_DAC,  4, 4, wm8950_deemp),
+
+	SOC_ENUM_SINGLE(WM8950_EQ1,  5, 4, wm8950_eq1),
+	SOC_ENUM_SINGLE(WM8950_EQ2,  8, 2, wm8950_bw),
+	SOC_ENUM_SINGLE(WM8950_EQ2,  5, 4, wm8950_eq2),
+	SOC_ENUM_SINGLE(WM8950_EQ3,  8, 2, wm8950_bw),
+
+	SOC_ENUM_SINGLE(WM8950_EQ3,  5, 4, wm8950_eq3),
+	SOC_ENUM_SINGLE(WM8950_EQ4,  8, 2, wm8950_bw),
+	SOC_ENUM_SINGLE(WM8950_EQ4,  5, 4, wm8950_eq4),
+
+	SOC_ENUM_SINGLE(WM8950_EQ5,  5, 4, wm8950_eq5),
+	SOC_ENUM_SINGLE(WM8950_ALC3,  8, 2, wm8950_alc),
+};
+
+static const struct snd_kcontrol_new wm8950_snd_controls[] = {
+
+	SOC_SINGLE("Digital Loopback Switch", WM8950_COMP, 0, 1, 0),
+
+	SOC_ENUM("ADC Companding", wm8950_enum[0]),
+
+	SOC_SINGLE("High Pass Filter Switch", WM8950_ADC, 8, 1, 0),
+	SOC_SINGLE("High Pass Cut Off", WM8950_ADC, 4, 7, 0),
+	SOC_SINGLE("ADC Inversion Switch", WM8950_COMP, 0, 1, 0),
+
+	SOC_SINGLE("Capture Volume", WM8950_ADCVOL,  0, 127, 0),
+
+	SOC_ENUM("Equaliser Function", wm8950_enum[3]),
+	SOC_ENUM("EQ1 Cut Off", wm8950_enum[4]),
+	SOC_SINGLE("EQ1 Volume", WM8950_EQ1,  0, 31, 1),
+
+	SOC_ENUM("Equaliser EQ2 Bandwith", wm8950_enum[5]),
+	SOC_ENUM("EQ2 Cut Off", wm8950_enum[6]),
+	SOC_SINGLE("EQ2 Volume", WM8950_EQ2,  0, 31, 1),
+
+	SOC_ENUM("Equaliser EQ3 Bandwith", wm8950_enum[7]),
+	SOC_ENUM("EQ3 Cut Off", wm8950_enum[8]),
+	SOC_SINGLE("EQ3 Volume", WM8950_EQ3,  0, 31, 1),
+
+	SOC_ENUM("Equaliser EQ4 Bandwith", wm8950_enum[9]),
+	SOC_ENUM("EQ4 Cut Off", wm8950_enum[10]),
+	SOC_SINGLE("EQ4 Volume", WM8950_EQ4,  0, 31, 1),
+
+	SOC_ENUM("EQ5 Cut Off", wm8950_enum[12]),
+	SOC_SINGLE("EQ5 Volume", WM8950_EQ5,  0, 31, 1),
+
+	SOC_SINGLE("ALC Enable Switch", WM8950_ALC1,  8, 1, 0),
+	SOC_SINGLE("ALC Capture Max Gain", WM8950_ALC1,  3, 7, 0),
+	SOC_SINGLE("ALC Capture Min Gain", WM8950_ALC1,  0, 7, 0),
+
+	SOC_SINGLE("ALC Capture ZC Switch", WM8950_ALC2,  8, 1, 0),
+	SOC_SINGLE("ALC Capture Hold", WM8950_ALC2,  4, 7, 0),
+	SOC_SINGLE("ALC Capture Target", WM8950_ALC2,  0, 15, 0),
+
+	SOC_ENUM("ALC Capture Mode", wm8950_enum[13]),
+	SOC_SINGLE("ALC Capture Decay", WM8950_ALC3,  4, 15, 0),
+	SOC_SINGLE("ALC Capture Attack", WM8950_ALC3,  0, 15, 0),
+
+	SOC_SINGLE("ALC Capture Noise Gate Switch", WM8950_NGATE,  3, 1, 0),
+	SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8950_NGATE,  0, 7, 0),
+
+	SOC_SINGLE("Capture PGA ZC Switch", WM8950_INPPGA,  7, 1, 0),
+	SOC_SINGLE("Capture PGA Volume", WM8950_INPPGA,  0, 63, 0),
+
+	SOC_SINGLE("Capture Boost(+20dB)", WM8950_ADCBOOST,  8, 1, 0),
+};
+
+/* AUX Input boost vol */
+static const struct snd_kcontrol_new wm8950_aux_boost_controls =
+	SOC_DAPM_SINGLE("Aux Volume", WM8950_ADCBOOST, 0, 7, 0);
+
+/* Mic Input boost vol */
+static const struct snd_kcontrol_new wm8950_mic_boost_controls =
+	SOC_DAPM_SINGLE("Mic Volume", WM8950_ADCBOOST, 4, 7, 0);
+
+/* Capture boost switch */
+static const struct snd_kcontrol_new wm8950_capture_boost_controls =
+	SOC_DAPM_SINGLE("Capture Boost Switch", WM8950_INPPGA,  6, 1, 0);
+
+/* Aux In to PGA */
+static const struct snd_kcontrol_new wm8950_aux_capture_boost_controls =
+	SOC_DAPM_SINGLE("Aux Capture Boost Switch", WM8950_INPPGA,  2, 1, 0);
+
+/* Mic P In to PGA */
+static const struct snd_kcontrol_new wm8950_micp_capture_boost_controls =
+	SOC_DAPM_SINGLE("Mic P Capture Boost Switch", WM8950_INPPGA,  0, 1, 0);
+
+/* Mic N In to PGA */
+static const struct snd_kcontrol_new wm8950_micn_capture_boost_controls =
+	SOC_DAPM_SINGLE("Mic N Capture Boost Switch", WM8950_INPPGA,  1, 1, 0);
+
+static const struct snd_soc_dapm_widget wm8950_dapm_widgets[] = {
+	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8950_POWER3, 0, 0),
+	SND_SOC_DAPM_PGA("Aux Input", WM8950_POWER1, 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic PGA", WM8950_POWER2, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Aux Boost", SND_SOC_NOPM, 0, 0,
+	&wm8950_aux_boost_controls, 1),
+	SND_SOC_DAPM_PGA("Mic Boost", SND_SOC_NOPM, 0, 0,
+	&wm8950_mic_boost_controls, 1),
+	SND_SOC_DAPM_SWITCH("Capture Boost", SND_SOC_NOPM, 0, 0,
+	&wm8950_capture_boost_controls),
+
+	SND_SOC_DAPM_MIXER("Boost Mixer", WM8950_POWER2, 4, 0, NULL, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8950_POWER1, 4, 0),
+
+	SND_SOC_DAPM_INPUT("MICN"),
+	SND_SOC_DAPM_INPUT("MICP"),
+	SND_SOC_DAPM_INPUT("AUX"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* Boost Mixer */
+	{"Boost Mixer", NULL, "ADC"},
+	{"Capture Boost Switch", "Aux Capture Boost Switch", "AUX"},
+	{"Aux Boost", "Aux Volume", "Boost Mixer"},
+	{"Capture Boost", "Capture Switch", "Boost Mixer"},
+	{"Mic Boost", "Mic Volume", "Boost Mixer"},
+
+	/* Inputs */
+	{"MICP", NULL, "Mic Boost"},
+	{"MICN", NULL, "Mic PGA"},
+	{"Mic PGA", NULL, "Capture Boost"},
+	{"AUX", NULL, "Aux Input"},
+};
+
+struct pll_ {
+	unsigned int in_hz, out_hz;
+	unsigned int pre:4; /* prescale - 1 */
+	unsigned int n:4;
+	unsigned int k;
+};
+
+static struct pll_ pll[] = {
+	{12000000, 11289600, 0, 7, 0x86c220},
+	{12000000, 12288000, 0, 8, 0x3126e8},
+	{13000000, 11289600, 0, 6, 0xf28bd4},
+	{13000000, 12288000, 0, 7, 0x8fd525},
+	{12288000, 11289600, 0, 7, 0x59999a},
+	{11289600, 12288000, 0, 8, 0x80dee9},
+	/* TODO: liam - add more entries */
+};
+
+static int wm8950_set_dai_pll(struct snd_soc_dai *codec_dai,
+			      int pll_id, int src, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	int i;
+	u16 reg;
+
+	if (freq_in == 0 || freq_out == 0) {
+		reg = snd_soc_read(codec, WM8950_POWER1);
+		snd_soc_write(codec, WM8950_POWER1, reg & 0x1df);
+		return 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pll); i++) {
+		if (freq_in == pll[i].in_hz && freq_out == pll[i].out_hz) {
+			snd_soc_write(codec, WM8950_PLLN,
+				      (pll[i].pre << 4) | pll[i].n);
+			snd_soc_write(codec, WM8950_PLLK1, pll[i].k >> 18);
+			snd_soc_write(codec, WM8950_PLLK1,
+				      (pll[i].k >> 9) && 0x1ff);
+			snd_soc_write(codec, WM8950_PLLK1, pll[i].k && 0x1ff);
+			reg = snd_soc_read(codec, WM8950_POWER1);
+			snd_soc_write(codec, WM8950_POWER1, reg | 0x020);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+/*
+ * Configure WM8950 clock dividers.
+ */
+static int wm8950_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+				 int div_id, int div)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+
+	switch (div_id) {
+	case WM8950_OPCLKDIV:
+		reg = snd_soc_read(codec, WM8950_GPIO & 0x1cf);
+		snd_soc_write(codec, WM8950_GPIO, reg | div);
+		break;
+	case WM8950_MCLKDIV:
+		reg = snd_soc_read(codec, WM8950_CLOCK & 0x1f);
+		snd_soc_write(codec, WM8950_CLOCK, reg | div);
+		break;
+	case WM8950_ADCCLK:
+		reg = snd_soc_read(codec, WM8950_ADC & 0x1f7);
+		snd_soc_write(codec, WM8950_ADC, reg | div);
+		break;
+	case WM8950_BCLKDIV:
+		reg = snd_soc_read(codec, WM8950_CLOCK & 0x1e3);
+		snd_soc_write(codec, WM8950_CLOCK, reg | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8950_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = 0;
+	u16 clk = snd_soc_read(codec, WM8950_CLOCK) & 0x1fe;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clk |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0010;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0008;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x00018;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0180;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0100;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0080;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_write(codec, WM8950_IFACE, iface);
+	snd_soc_write(codec, WM8950_CLOCK, clk);
+	return 0;
+}
+
+static int wm8950_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 iface = snd_soc_read(codec, WM8950_IFACE) & 0x19f;
+	u16 adn = snd_soc_read(codec, WM8950_ADD) & 0x1f1;
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0020;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0040;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		iface |= 0x0060;
+		break;
+	}
+
+	/* filter coefficient */
+	switch (params_rate(params)) {
+	case SNDRV_PCM_RATE_8000:
+		adn |= 0x5 << 1;
+		break;
+	case SNDRV_PCM_RATE_11025:
+		adn |= 0x4 << 1;
+		break;
+	case SNDRV_PCM_RATE_16000:
+		adn |= 0x3 << 1;
+		break;
+	case SNDRV_PCM_RATE_22050:
+		adn |= 0x2 << 1;
+		break;
+	case SNDRV_PCM_RATE_32000:
+		adn |= 0x1 << 1;
+		break;
+	case SNDRV_PCM_RATE_44100:
+		break;
+	}
+
+	snd_soc_write(codec, WM8950_IFACE, iface);
+	snd_soc_write(codec, WM8950_ADD, adn);
+	return 0;
+}
+
+static int wm8950_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 *cache;
+	int i;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_write(codec, WM8950_POWER1, 0x1ff);
+		snd_soc_write(codec, WM8950_POWER2, 0x1ff);
+		snd_soc_write(codec, WM8950_POWER3, 0x1ff);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			if (codec->cache_sync) {
+				cache = codec->reg_cache;
+				for (i = 0; i < codec->driver->reg_cache_size; ++i) {
+					if (i == WM8950_RESET || cache[i] == wm8950_reg_defs[i])
+						continue;
+					snd_soc_write(codec, i, cache[i]);
+				}
+				codec->cache_sync = 0;
+			}
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* everything off, dac mute, inactive */
+		snd_soc_write(codec, WM8950_POWER1, 0x0);
+		snd_soc_write(codec, WM8950_POWER2, 0x0);
+		snd_soc_write(codec, WM8950_POWER3, 0x0);
+		codec->cache_sync = 1;
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+static int wm8950_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+	wm8950_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8950_resume(struct snd_soc_codec *codec)
+{
+	wm8950_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	return 0;
+}
+
+static int wm8950_remove(struct snd_soc_codec *codec)
+{
+	wm8950_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8950_probe(struct snd_soc_codec *codec)
+{
+	struct wm8950_priv *wm8950;
+	int ret;
+
+	wm8950 = snd_soc_codec_get_drvdata(codec);
+
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8950->control_type);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_write(codec, WM8950_RESET, 0);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	wm8950_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	snd_soc_add_controls(codec, wm8950_snd_controls,
+			     ARRAY_SIZE(wm8950_snd_controls));
+	snd_soc_dapm_new_controls(&codec->dapm, wm8950_dapm_widgets,
+				  ARRAY_SIZE(wm8950_dapm_widgets));
+	snd_soc_dapm_add_routes(&codec->dapm, audio_map,
+				ARRAY_SIZE(audio_map));
+	return 0;
+}
+
+#define WM8950_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8950_ops = {
+	.hw_params = wm8950_pcm_hw_params,
+	.set_fmt = wm8950_set_dai_fmt,
+	.set_clkdiv = wm8950_set_dai_clkdiv,
+	.set_pll = wm8950_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver wm8950_dai = {
+	.name = "wm8950",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = WM8950_FORMATS,
+	},
+	.ops = &wm8950_ops,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8950 = {
+	.probe = wm8950_probe,
+	.remove = wm8950_remove,
+	.suspend = wm8950_suspend,
+	.resume = wm8950_resume,
+	.set_bias_level = wm8950_set_bias_level,
+	.reg_cache_size = WM8950_CACHEREGNUM,
+	.reg_word_size = sizeof(u16),
+	.reg_cache_default = wm8950_reg_defs
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8950_spi_probe(struct spi_device *spi)
+{
+	struct wm8950_priv *wm8950;
+	int ret;
+
+	wm8950 = kzalloc(sizeof *wm8950, GFP_KERNEL);
+	if (!wm8950)
+		return -ENOMEM;
+
+	wm8950->control_type = SND_SOC_SPI;
+	spi_set_drvdata(spi, wm8950);
+
+	ret = snd_soc_register_codec(&spi->dev,
+				     &soc_codec_dev_wm8950, &wm8950_dai, 1);
+	if (ret < 0)
+		kfree(wm8950);
+	return ret;
+}
+
+static int __devexit wm8950_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	kfree(spi_get_drvdata(spi));
+	return 0;
+}
+
+static struct spi_driver wm8950_spi_driver = {
+	.driver = {
+		.name = "wm8950",
+		.bus = &spi_bus_type,
+		.owner = THIS_MODULE,
+	},
+	.probe = wm8950_spi_probe,
+	.remove = __devexit_p(wm8950_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8950_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct wm8950_priv *wm8950;
+	int ret;
+
+	wm8950 = kzalloc(sizeof(struct wm8950_priv), GFP_KERNEL);
+	if (wm8950 == NULL)
+		return -ENOMEM;
+
+	wm8950->control_type = SND_SOC_I2C;
+	i2c_set_clientdata(i2c, wm8950);
+
+	ret = snd_soc_register_codec(&i2c->dev,
+				     &soc_codec_dev_wm8950, &wm8950_dai, 1);
+	if (ret < 0)
+		kfree(wm8950);
+	return ret;
+}
+
+static __devexit int wm8950_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static const struct i2c_device_id wm8950_i2c_id[] = {
+	{ "wm8950", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8950_i2c_id);
+
+static struct i2c_driver wm8950_i2c_driver = {
+	.driver = {
+		.name = "wm8950",
+		.owner = THIS_MODULE,
+	},
+	.probe = wm8950_i2c_probe,
+	.remove = __devexit_p(wm8950_i2c_remove),
+	.id_table = wm8950_i2c_id,
+};
+#endif
+
+static int __init wm8950_modinit(void)
+{
+	int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	ret = i2c_add_driver(&wm8950_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8950 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8950_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8950 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return 0;
+}
+module_init(wm8950_modinit);
+
+static void __exit wm8950_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&wm8950_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8950_spi_driver);
+#endif
+}
+module_exit(wm8950_exit);
+
+MODULE_DESCRIPTION("ASoC WM8950 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8950.h b/sound/soc/codecs/wm8950.h
new file mode 100644
index 0000000..f185e37
--- /dev/null
+++ b/sound/soc/codecs/wm8950.h
@@ -0,0 +1,85 @@
+/*
+ * wm8950.h  --  WM8950 Soc Audio driver
+ *
+ * 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 _WM8950_H
+#define _WM8950_H
+
+/* WM8950 register space */
+
+#define WM8950_RESET		0x0
+#define WM8950_POWER1		0x1
+#define WM8950_POWER2		0x2
+#define WM8950_POWER3		0x3
+#define WM8950_IFACE		0x4
+#define WM8950_COMP			0x5
+#define WM8950_CLOCK		0x6
+#define WM8950_ADD			0x7
+#define WM8950_GPIO			0x8
+#define WM8950_DAC			0xa
+#define WM8950_ADC			0xe
+#define WM8950_ADCVOL		0xf
+#define WM8950_EQ1			0x12
+#define WM8950_EQ2			0x13
+#define WM8950_EQ3			0x14
+#define WM8950_EQ4			0x15
+#define WM8950_EQ5			0x16
+#define WM8950_NOTCH1		0x1b
+#define WM8950_NOTCH2		0x1c
+#define WM8950_NOTCH3		0x1d
+#define WM8950_NOTCH4		0x1e
+#define WM8950_ALC1			0x20
+#define WM8950_ALC2			0x21
+#define WM8950_ALC3			0x22
+#define WM8950_NGATE		0x23
+#define WM8950_PLLN			0x24
+#define WM8950_PLLK1		0x25
+#define WM8950_PLLK2		0x26
+#define WM8950_PLLK3		0x27
+#define WM8950_INPUT		0x2c
+#define WM8950_INPPGA		0x2d
+#define WM8950_ADCBOOST		0x2f
+#define WM8950_OUTPUT		0x31
+
+#define WM8950_CACHEREGNUM 	57
+
+/* Clock divider Id's */
+#define WM8950_OPCLKDIV		0
+#define WM8950_MCLKDIV		1
+#define WM8950_ADCCLK		2
+#define WM8950_BCLKDIV		3
+
+
+/* ADC clock dividers */
+#define WM8950_ADCCLK_F2	(1 << 3)
+#define WM8950_ADCCLK_F4	(0 << 3)
+
+/* PLL Out dividers */
+#define WM8950_OPCLKDIV_1	(0 << 4)
+#define WM8950_OPCLKDIV_2	(1 << 4)
+#define WM8950_OPCLKDIV_3	(2 << 4)
+#define WM8950_OPCLKDIV_4	(3 << 4)
+
+/* BCLK clock dividers */
+#define WM8950_BCLKDIV_1	(0 << 2)
+#define WM8950_BCLKDIV_2	(1 << 2)
+#define WM8950_BCLKDIV_4	(2 << 2)
+#define WM8950_BCLKDIV_8	(3 << 2)
+#define WM8950_BCLKDIV_16	(4 << 2)
+#define WM8950_BCLKDIV_32	(5 << 2)
+
+/* MCLK clock dividers */
+#define WM8950_MCLKDIV_1	(0 << 5)
+#define WM8950_MCLKDIV_1_5	(1 << 5)
+#define WM8950_MCLKDIV_2	(2 << 5)
+#define WM8950_MCLKDIV_3	(3 << 5)
+#define WM8950_MCLKDIV_4	(4 << 5)
+#define WM8950_MCLKDIV_6	(5 << 5)
+#define WM8950_MCLKDIV_8	(6 << 5)
+#define WM8950_MCLKDIV_12	(7 << 5)
+
+#endif
diff --git a/sound/soc/codecs/wm8951.c b/sound/soc/codecs/wm8951.c
new file mode 100644
index 0000000..b721609
--- /dev/null
+++ b/sound/soc/codecs/wm8951.c
@@ -0,0 +1,680 @@
+/*
+ * wm8951.c  --  WM8951 ALSA SoC Audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on wm8753.c by Liam Girdwood
+ *
+ * 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/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8951.h"
+
+#define AUDIO_NAME "wm8951"
+#define WM8951_VERSION "0.1"
+
+struct snd_soc_codec_device soc_codec_dev_wm8951;
+
+/* codec private data */
+struct wm8951_priv {
+	unsigned int sysclk;
+};
+
+/*
+ * wm8951 register cache
+ * We can't read the WM8951 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 const u16 wm8951_reg[WM8951_CACHEREGNUM] = {
+    0x0097, 0x0097, 0x0079, 0x0079,
+    0x000a, 0x0008, 0x009f, 0x000a,
+    0x0000, 0x0000
+};
+
+/*
+ * read wm8951 register cache
+ */
+static inline unsigned int wm8951_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg == WM8951_RESET)
+		return 0;
+	if (reg >= WM8951_CACHEREGNUM)
+		return -1;
+	return cache[reg];
+}
+
+/*
+ * write wm8951 register cache
+ */
+static inline void wm8951_write_reg_cache(struct snd_soc_codec *codec,
+	u16 reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg >= WM8951_CACHEREGNUM)
+		return;
+	cache[reg] = value;
+}
+
+/*
+ * write to the WM8951 register space
+ */
+static int wm8951_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	u8 data[2];
+
+	/* data is
+	 *   D15..D9 WM8951 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	wm8951_write_reg_cache (codec, reg, value);
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+#define wm8951_reset(c)	wm8951_write(c, WM8951_RESET, 0)
+
+static const char *wm8951_input_select[] = {"Line In", "Mic"};
+static const char *wm8951_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum wm8951_enum[] = {
+	SOC_ENUM_SINGLE(WM8951_APANA, 2, 2, wm8951_input_select),
+	SOC_ENUM_SINGLE(WM8951_APDIGI, 1, 4, wm8951_deemph),
+};
+
+static const struct snd_kcontrol_new wm8951_snd_controls[] = {
+
+SOC_DOUBLE_R("Capture Volume", WM8951_LINVOL, WM8951_RINVOL, 0, 31, 0),
+SOC_DOUBLE_R("Line Capture Switch", WM8951_LINVOL, WM8951_RINVOL, 7, 1, 1),
+
+SOC_SINGLE("Mic Boost (+20dB)", WM8951_APANA, 0, 1, 0),
+SOC_SINGLE("Capture Mic Switch", WM8951_APANA, 1, 1, 1),
+
+SOC_SINGLE("ADC High Pass Filter Switch", WM8951_APDIGI, 0, 1, 1),
+SOC_SINGLE("Store DC Offset Switch", WM8951_APDIGI, 4, 1, 0),
+};
+
+/* add non dapm controls */
+static int wm8951_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8951_snd_controls); i++) {
+		if ((err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&wm8951_snd_controls[i],codec, NULL))) < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+/* Input mux */
+static const struct snd_kcontrol_new wm8951_input_mux_controls =
+SOC_DAPM_ENUM("Input Select", wm8951_enum[0]);
+
+static const struct snd_soc_dapm_widget wm8951_dapm_widgets[] = {
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8951_PWR, 2, 1),
+SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &wm8951_input_mux_controls),
+SND_SOC_DAPM_PGA("Line Input", WM8951_PWR, 0, 1, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias", WM8951_PWR, 1, 1),
+SND_SOC_DAPM_INPUT("MICIN"),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	/* input mux */
+	{"Input Mux", "Line In", "Line Input"},
+	{"Input Mux", "Mic", "Mic Bias"},
+	{"ADC", NULL, "Input Mux"},
+
+	/* inputs */
+	{"Line Input", NULL, "LLINEIN"},
+	{"Line Input", NULL, "RLINEIN"},
+	{"Mic Bias", NULL, "MICIN"},
+};
+
+static int wm8951_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, wm8951_dapm_widgets,
+				  ARRAY_SIZE(wm8951_dapm_widgets));
+
+	/* set up audio path interconnects */
+	snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+	snd_soc_dapm_new_widgets(codec);
+	return 0;
+}
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:4;
+	u8 bosr:1;
+	u8 usb:1;
+};
+
+/* codec mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0, 0x0},
+	{18432000, 48000, 384, 0x0, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x0, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0x6, 0x0, 0x0},
+	{18432000, 32000, 576, 0x6, 0x1, 0x0},
+	{12000000, 32000, 375, 0x6, 0x0, 0x1},
+
+	/* 8k */
+	{12288000, 8000, 1536, 0x3, 0x0, 0x0},
+	{18432000, 8000, 2304, 0x3, 0x1, 0x0},
+	{11289600, 8000, 1408, 0xb, 0x0, 0x0},
+	{16934400, 8000, 2112, 0xb, 0x1, 0x0},
+	{12000000, 8000, 1500, 0x3, 0x0, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0x7, 0x0, 0x0},
+	{18432000, 96000, 192, 0x7, 0x1, 0x0},
+	{12000000, 96000, 125, 0x7, 0x0, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x8, 0x0, 0x0},
+	{16934400, 44100, 384, 0x8, 0x1, 0x0},
+	{12000000, 44100, 272, 0x8, 0x1, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0xf, 0x0, 0x0},
+	{16934400, 88200, 192, 0xf, 0x1, 0x0},
+	{12000000, 88200, 136, 0xf, 0x1, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return 0;
+}
+
+static int wm8951_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct wm8951_priv *wm8951 = codec->private_data;
+	u16 iface = wm8951_read_reg_cache(codec, WM8951_IFACE) & 0xfff3;
+	int i = get_coeff(wm8951->sysclk, params_rate(params));
+	u16 srate = (coeff_div[i].sr << 2) |
+		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
+
+	wm8951_write(codec, WM8951_SRATE, srate);
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0004;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0008;
+		break;
+	}
+
+	wm8951_write(codec, WM8951_IFACE, iface);
+	return 0;
+}
+
+static int wm8951_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+
+	/* set active */
+	wm8951_write(codec, WM8951_ACTIVE, 0x0001);
+
+	return 0;
+}
+
+static void wm8951_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+
+	/* deactivate */
+	if (!codec->active) {
+		udelay(50);
+		wm8951_write(codec, WM8951_ACTIVE, 0x0);
+	}
+}
+
+static int wm8951_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = wm8951_read_reg_cache(codec, WM8951_APDIGI) & 0xfff7;
+
+	if (mute)
+		wm8951_write(codec, WM8951_APDIGI, mute_reg | 0x8);
+	else
+		wm8951_write(codec, WM8951_APDIGI, mute_reg);
+	return 0;
+}
+
+static int wm8951_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct wm8951_priv *wm8951 = codec->private_data;
+
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		wm8951->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+
+static int wm8951_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface |= 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface */
+	wm8951_write(codec, WM8951_IFACE, iface);
+	return 0;
+}
+
+static int wm8951_set_bias_level(struct snd_soc_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	u16 reg = wm8951_read_reg_cache(codec, WM8951_PWR) & 0xff7f;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		wm8951_write(codec, WM8951_PWR, reg);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		wm8951_write(codec, WM8951_PWR, reg | 0x0040);
+		break;
+	case SND_SOC_BIAS_OFF:
+		wm8951_write(codec, WM8951_ACTIVE, 0x0);
+		wm8951_write(codec, WM8951_PWR, 0xffff);
+		break;
+	}
+	codec->suspend_bias_level = level;
+	return 0;
+}
+
+#define WM8951_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
+		SNDRV_PCM_RATE_96000)
+
+#define WM8951_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_dai wm8951_dai = {
+	.name = "WM8951",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8951_RATES,
+		.formats = WM8951_FORMATS,},
+	.ops = {
+		.prepare = wm8951_pcm_prepare,
+		.hw_params = wm8951_hw_params,
+		.shutdown = wm8951_shutdown,
+	},
+	.dai_ops = {
+		.digital_mute = wm8951_mute,
+		.set_sysclk = wm8951_set_dai_sysclk,
+		.set_fmt = wm8951_set_dai_fmt,
+	}
+};
+EXPORT_SYMBOL_GPL(wm8951_dai);
+
+static int wm8951_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	wm8951_write(codec, WM8951_ACTIVE, 0x0);
+	wm8951_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8951_resume(struct platform_device *pdev)
+{
+	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(wm8951_reg); i++) {
+		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+		data[1] = cache[i] & 0x00ff;
+		codec->hw_write(codec->control_data, data, 2);
+	}
+	wm8951_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	wm8951_set_bias_level(codec, codec->suspend_bias_level);
+	return 0;
+}
+
+/*
+ * initialise the WM8951 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8951_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	int reg, ret = 0;
+
+	codec->name = "WM8951";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8951_read_reg_cache;
+	codec->write = wm8951_write;
+	codec->set_bias_level = wm8951_set_bias_level;
+	codec->dai = &wm8951_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = ARRAY_SIZE(wm8951_reg);
+	codec->reg_cache = kmemdup(wm8951_reg, sizeof(wm8951_reg), GFP_KERNEL);
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	wm8951_reset(codec);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8951: failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	/* power on device */
+	wm8951_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	/* set the update bits */
+	reg = wm8951_read_reg_cache(codec, WM8951_LINVOL);
+	wm8951_write(codec, WM8951_LINVOL, reg | 0x0100);
+	reg = wm8951_read_reg_cache(codec, WM8951_RINVOL);
+	wm8951_write(codec, WM8951_RINVOL, reg | 0x0100);
+
+	wm8951_add_controls(codec);
+	wm8951_add_widgets(codec);
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8951: failed to register card\n");
+		goto card_err;
+	}
+
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+	return ret;
+}
+
+static struct snd_soc_device *wm8951_socdev;
+
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+
+/*
+ * WM8951 2 wire address is determined by GPIO5
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver wm8951_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 int wm8951_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+	struct snd_soc_device *socdev = wm8951_socdev;
+	struct wm8951_setup_data *setup = socdev->codec_data;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct i2c_client *i2c;
+	int ret;
+
+	if (addr != setup->i2c_address)
+		return -ENODEV;
+
+	client_template.adapter = adap;
+	client_template.addr = addr;
+
+	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+	if (i2c == NULL) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
+	ret = i2c_attach_client(i2c);
+	if (ret < 0) {
+		pr_err("failed to attach codec at addr %x\n", addr);
+		goto err;
+	}
+
+	ret = wm8951_init(socdev);
+	if (ret < 0) {
+		pr_err("failed to initialise WM8951\n");
+		goto err;
+	}
+	return ret;
+
+err:
+	kfree(codec);
+	kfree(i2c);
+	return ret;
+}
+
+static int wm8951_i2c_detach(struct i2c_client *client)
+{
+	struct snd_soc_codec* codec = i2c_get_clientdata(client);
+	i2c_detach_client(client);
+	kfree(codec->reg_cache);
+	kfree(client);
+	return 0;
+}
+
+static int wm8951_i2c_attach(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, wm8951_codec_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver wm8951_i2c_driver = {
+	.driver = {
+		.name = "WM8951 I2C Codec",
+		.owner = THIS_MODULE,
+	},
+	.attach_adapter = wm8951_i2c_attach,
+	.detach_client =  wm8951_i2c_detach,
+	.command =        NULL,
+};
+
+static struct i2c_client client_template = {
+	.name =   "WM8951",
+	.driver = &wm8951_i2c_driver,
+};
+#endif
+
+static int wm8951_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct wm8951_setup_data *setup;
+	struct snd_soc_codec *codec;
+	struct wm8951_priv *wm8951;
+	int ret = 0;
+
+	pr_info("WM8951 Audio Codec %s", WM8951_VERSION);
+
+	setup = socdev->codec_data;
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	wm8951 = kzalloc(sizeof(struct wm8951_priv), GFP_KERNEL);
+	if (wm8951 == NULL) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+
+	codec->private_data = wm8951;
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	wm8951_socdev = socdev;
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+	if (setup->i2c_address) {
+		normal_i2c[0] = setup->i2c_address;
+		codec->hw_write = (hw_write_t)i2c_master_send;
+		ret = i2c_add_driver(&wm8951_i2c_driver);
+		if (ret != 0)
+			printk(KERN_ERR "can't add i2c driver");
+	}
+#else
+	/* Add other interfaces here */
+#endif
+	return ret;
+}
+
+/* power down chip */
+static int wm8951_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec->control_data)
+		wm8951_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+	i2c_del_driver(&wm8951_i2c_driver);
+#endif
+	kfree(codec->private_data);
+	kfree(codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8951 = {
+	.probe = 	wm8951_probe,
+	.remove = 	wm8951_remove,
+	.suspend = 	wm8951_suspend,
+	.resume =	wm8951_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8951);
+
+MODULE_DESCRIPTION("ASoC WM8951 driver");
+MODULE_AUTHOR("Richard Purdie");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8951.h b/sound/soc/codecs/wm8951.h
new file mode 100644
index 0000000..2260cdc
--- /dev/null
+++ b/sound/soc/codecs/wm8951.h
@@ -0,0 +1,42 @@
+/*
+ * wm8951.h  --  WM8951 Soc Audio driver
+ *
+ * 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 _WM8951_H
+#define _WM8951_H
+
+/* WM8951 register space */
+
+#define WM8951_LINVOL   0x00
+#define WM8951_RINVOL   0x01
+#define WM8951_APANA    0x04
+#define WM8951_APDIGI   0x05
+#define WM8951_PWR      0x06
+#define WM8951_IFACE    0x07
+#define WM8951_SRATE    0x08
+#define WM8951_ACTIVE   0x09
+#define WM8951_RESET	0x0f
+
+#define WM8951_CACHEREGNUM 	10
+
+#define WM8951_SYSCLK	0
+#define WM8951_DAI		0
+
+struct wm8951_setup_data {
+	unsigned short i2c_address;
+};
+
+extern struct snd_soc_dai wm8951_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8951;
+
+#endif
diff --git a/sound/soc/codecs/wm8956.c b/sound/soc/codecs/wm8956.c
new file mode 100644
index 0000000..85924a0
--- /dev/null
+++ b/sound/soc/codecs/wm8956.c
@@ -0,0 +1,634 @@
+/*
+ * wm8956.c  --  WM8956 ALSA SoC Audio driver
+ *
+ * Author: Liam Girdwood
+ *
+ * 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/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8956.h"
+
+struct snd_soc_codec_device soc_codec_dev_wm8956;
+
+/*
+ * wm8956 register cache
+ * We can't read the WM8956 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ */
+static const u16 wm8956_reg[WM8956_CACHEREGNUM] = {
+	0x0097, 0x0097, 0x0000, 0x0000,
+	0x0000, 0x0008, 0x0000, 0x000a,
+	0x01c0, 0x0000, 0x00ff, 0x00ff,
+	0x0000, 0x0000, 0x0000, 0x0000, /* r15 */
+	0x0000, 0x007b, 0x0100, 0x0032,
+	0x0000, 0x00c3, 0x00c3, 0x01c0,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, /* r31 */
+	0x0100, 0x0100, 0x0050, 0x0050,
+	0x0050, 0x0050, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0040, 0x0000,
+	0x0000, 0x0050, 0x0050, 0x0000, /* r47 */
+	0x0002, 0x0037, 0x004d, 0x0080,
+	0x0008, 0x0031, 0x0026, 0x00e9,
+};
+
+struct wm8956_priv {
+	struct snd_soc_codec codec;
+	u16 reg_cache[WM8956_CACHEREGNUM];
+};
+
+static struct snd_soc_codec *wm8956_codec;
+
+/*
+ * read wm8956 register cache
+ */
+static inline unsigned int wm8956_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg == WM8956_RESET)
+		return 0;
+	if (reg >= WM8956_CACHEREGNUM)
+		return -1;
+	return cache[reg];
+}
+
+/*
+ * write wm8956 register cache
+ */
+static inline void wm8956_write_reg_cache(struct snd_soc_codec *codec,
+	u16 reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg >= WM8956_CACHEREGNUM)
+		return;
+	cache[reg] = value;
+}
+
+/*
+ * write to the WM8956 register space
+ */
+static int wm8956_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	u8 data[2];
+
+	/* data is
+	 *   D15..D9 WM8956 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	wm8956_write_reg_cache (codec, reg, value);
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+#define wm8956_reset(c)	wm8956_write(c, WM8956_RESET, 0)
+
+/* todo - complete enumerated controls */
+static const char *wm8956_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum wm8956_enum[] = {
+	SOC_ENUM_SINGLE(WM8956_DACCTL1, 1, 4, wm8956_deemph),
+};
+
+/* to complete */
+static const struct snd_kcontrol_new wm8956_snd_controls[] = {
+
+SOC_DOUBLE_R("Headphone Playback Volume", WM8956_LOUT1, WM8956_ROUT1,
+	0, 127, 0),
+SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8956_LOUT1, WM8956_ROUT1,
+	7, 1, 0),
+SOC_DOUBLE_R("PCM Volume", WM8956_LDAC, WM8956_RDAC,
+	0, 127, 0),
+
+SOC_ENUM("Playback De-emphasis", wm8956_enum[0]),
+};
+
+/* Left Output Mixer */
+static const struct snd_kcontrol_new wm8956_loutput_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left PCM Playback Switch", WM8956_LOUTMIX1, 8, 1, 0),
+};
+
+/* Right Output Mixer */
+static const struct snd_kcontrol_new wm8956_routput_mixer_controls[] = {
+SOC_DAPM_SINGLE("Right PCM Playback Switch", WM8956_ROUTMIX2, 8, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8956_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+	&wm8956_loutput_mixer_controls[0],
+	ARRAY_SIZE(wm8956_loutput_mixer_controls)),
+SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+	&wm8956_loutput_mixer_controls[0],
+	ARRAY_SIZE(wm8956_routput_mixer_controls)),
+};
+
+static int wm8956_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, wm8956_dapm_widgets,
+				  ARRAY_SIZE(wm8956_dapm_widgets));
+
+	snd_soc_dapm_new_widgets(codec);
+	return 0;
+}
+
+static int wm8956_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface |= 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface */
+	wm8956_write(codec, WM8956_IFACE1, iface);
+	return 0;
+}
+
+static int wm8956_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	u16 iface = wm8956_read_reg_cache(codec, WM8956_IFACE1) & 0xfff3;
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0004;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0008;
+		break;
+	}
+
+	/* set iface */
+	wm8956_write(codec, WM8956_IFACE1, iface);
+	return 0;
+}
+
+static int wm8956_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = wm8956_read_reg_cache(codec, WM8956_DACCTL1) & 0xfff7;
+
+	if (mute)
+		wm8956_write(codec, WM8956_DACCTL1, mute_reg | 0x8);
+	else
+		wm8956_write(codec, WM8956_DACCTL1, mute_reg);
+	return 0;
+}
+
+static int wm8956_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level event)
+{
+#if 0
+	switch (event) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+	case SND_SOC_BIAS_STANDBY:
+	case SND_SOC_BIAS_OFF:
+		break;
+	}
+#endif
+	// tmp
+	wm8956_write(codec, WM8956_POWER1, 0xfffe);
+	wm8956_write(codec, WM8956_POWER2, 0xffff);
+	wm8956_write(codec, WM8956_POWER3, 0xffff);
+	codec->bias_level = event;
+	return 0;
+}
+
+/* PLL divisors */
+struct _pll_div {
+	u32 pre_div:1;
+	u32 n:4;
+	u32 k:24;
+};
+
+static struct _pll_div pll_div;
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 24) * 10)
+
+static void pll_factors(unsigned int target, unsigned int source)
+{
+	unsigned long long Kpart;
+	unsigned int K, Ndiv, Nmod;
+
+	Ndiv = target / source;
+	if (Ndiv < 6) {
+		source >>= 1;
+		pll_div.pre_div = 1;
+		Ndiv = target / source;
+	} else
+		pll_div.pre_div = 0;
+
+	if ((Ndiv < 6) || (Ndiv > 12))
+		printk(KERN_WARNING
+			"WM8956 N value outwith recommended range! N = %d\n",Ndiv);
+
+	pll_div.n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div.k = K;
+}
+
+static int wm8956_set_dai_pll(struct snd_soc_dai *codec_dai,
+	int pll_id, int src, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+	int found = 0;
+#if 0
+	if (freq_in == 0 || freq_out == 0) {
+		/* disable the pll */
+		/* turn PLL power off */
+	}
+#endif
+
+	pll_factors(freq_out * 8, freq_in);
+
+	if (!found)
+		return -EINVAL;
+
+	reg = wm8956_read_reg_cache(codec, WM8956_PLLN) & 0x1e0;
+	wm8956_write(codec, WM8956_PLLN, reg | (1<<5) | (pll_div.pre_div << 4)
+		| pll_div.n);
+	wm8956_write(codec, WM8956_PLLK1, pll_div.k >> 16 );
+	wm8956_write(codec, WM8956_PLLK2, (pll_div.k >> 8) & 0xff);
+	wm8956_write(codec, WM8956_PLLK3, pll_div.k &0xff);
+	wm8956_write(codec, WM8956_CLOCK1, 4);
+
+	return 0;
+}
+
+static int wm8956_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+		int div_id, int div)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+
+	switch (div_id) {
+	case WM8956_SYSCLKSEL:
+		reg = wm8956_read_reg_cache(codec, WM8956_CLOCK1) & 0x1fe;
+		wm8956_write(codec, WM8956_CLOCK1, reg | div);
+		break;
+	case WM8956_SYSCLKDIV:
+		reg = wm8956_read_reg_cache(codec, WM8956_CLOCK1) & 0x1f9;
+		wm8956_write(codec, WM8956_CLOCK1, reg | div);
+		break;
+	case WM8956_DACDIV:
+		reg = wm8956_read_reg_cache(codec, WM8956_CLOCK1) & 0x1c7;
+		wm8956_write(codec, WM8956_CLOCK1, reg | div);
+		break;
+	case WM8956_OPCLKDIV:
+		reg = wm8956_read_reg_cache(codec, WM8956_PLLN) & 0x03f;
+		wm8956_write(codec, WM8956_PLLN, reg | div);
+		break;
+	case WM8956_DCLKDIV:
+		reg = wm8956_read_reg_cache(codec, WM8956_CLOCK2) & 0x03f;
+		wm8956_write(codec, WM8956_CLOCK2, reg | div);
+		break;
+	case WM8956_TOCLKSEL:
+		reg = wm8956_read_reg_cache(codec, WM8956_ADDCTL1) & 0x1fd;
+		wm8956_write(codec, WM8956_ADDCTL1, reg | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#define WM8956_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8956_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8956_dai_ops = {
+	.hw_params = wm8956_hw_params,
+	.digital_mute = wm8956_mute,
+	.set_fmt = wm8956_set_dai_fmt,
+	.set_clkdiv = wm8956_set_dai_clkdiv,
+	.set_pll = wm8956_set_dai_pll,
+};
+
+struct snd_soc_dai wm8956_dai = {
+	.name = "WM8956",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8956_RATES,
+		.formats = WM8956_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8956_RATES,
+		.formats = WM8956_FORMATS,},
+	.ops = &wm8956_dai_ops,
+};
+EXPORT_SYMBOL_GPL(wm8956_dai);
+
+
+/* To complete PM */
+static int wm8956_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	wm8956_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8956_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+	int i;
+	u8 data[2];
+	u16 *cache = codec->reg_cache;
+
+	/* Sync reg_cache with the hardware */
+	for (i = 0; i < ARRAY_SIZE(wm8956_reg); i++) {
+		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+		data[1] = cache[i] & 0x00ff;
+		codec->hw_write(codec->control_data, data, 2);
+	}
+	wm8956_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	wm8956_set_bias_level(codec, codec->suspend_bias_level);
+	return 0;
+}
+
+static int wm8956_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	if (wm8956_codec == NULL) {
+		dev_err(&pdev->dev, "Codec device not registered\n");
+		return -ENODEV;
+	}
+
+	socdev->card->codec = wm8956_codec;
+	codec = wm8956_codec;
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+		goto pcm_err;
+	}
+
+	snd_soc_add_controls(codec, wm8956_snd_controls,
+			     ARRAY_SIZE(wm8956_snd_controls));
+	wm8956_add_widgets(codec);
+
+	return 0;
+
+pcm_err:
+	return ret;
+}
+
+/* power down chip */
+static int wm8956_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8956 = {
+	.probe = 	wm8956_probe,
+	.remove = 	wm8956_remove,
+	.suspend = 	wm8956_suspend,
+	.resume =	wm8956_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8956);
+
+static int wm8956_register(struct wm8956_priv *wm8956)
+{
+	int ret;
+	struct snd_soc_codec *codec = &wm8956->codec;
+
+	if (wm8956_codec) {
+		dev_err(codec->dev, "Another WM8956 is registered\n");
+		return -EINVAL;
+	}
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	codec->private_data = wm8956;
+	codec->name = "WM8956";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8956_read_reg_cache;
+	codec->write = wm8956_write;
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	codec->set_bias_level = wm8956_set_bias_level;
+	codec->dai = &wm8956_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = WM8956_CACHEREGNUM;
+	codec->reg_cache = &wm8956->reg_cache;
+
+	memcpy(codec->reg_cache, wm8956_reg, sizeof(wm8956_reg));
+
+	ret = wm8956_reset(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	wm8956_dai.dev = codec->dev;
+
+	wm8956_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	wm8956_codec = codec;
+
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_dai(&wm8956_dai);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+		snd_soc_unregister_codec(codec);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void wm8956_unregister(struct wm8956_priv *wm8956)
+{
+	wm8956_set_bias_level(&wm8956->codec, SND_SOC_BIAS_OFF);
+	snd_soc_unregister_dai(&wm8956_dai);
+	snd_soc_unregister_codec(&wm8956->codec);
+	kfree(wm8956);
+	wm8956_codec = NULL;
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8956_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct wm8956_priv *wm8956;
+	struct snd_soc_codec *codec;
+
+	wm8956 = kzalloc(sizeof(struct wm8956_priv), GFP_KERNEL);
+	if (wm8956 == NULL)
+		return -ENOMEM;
+
+	codec = &wm8956->codec;
+	codec->hw_write = (hw_write_t)i2c_master_send;
+
+	i2c_set_clientdata(i2c, wm8956);
+	codec->control_data = i2c;
+
+	codec->dev = &i2c->dev;
+
+	return wm8956_register(wm8956);
+}
+
+static __devexit int wm8956_i2c_remove(struct i2c_client *client)
+{
+	struct wm8956_priv *wm8956 = i2c_get_clientdata(client);
+	wm8956_unregister(wm8956);
+	return 0;
+}
+
+static const struct i2c_device_id wm8956_i2c_id[] = {
+	{ "wm8956", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8956_i2c_id);
+
+static struct i2c_driver wm8956_i2c_driver = {
+	.driver = {
+		.name = "WM8956 I2C Codec",
+		.owner = THIS_MODULE,
+	},
+	.probe =    wm8956_i2c_probe,
+	.remove =   __devexit_p(wm8956_i2c_remove),
+	.id_table = wm8956_i2c_id,
+};
+#endif
+
+static int __init wm8956_modinit(void)
+{
+	int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	ret = i2c_add_driver(&wm8956_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8956 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+	return 0;
+}
+module_init(wm8956_modinit);
+
+static void __exit wm8956_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&wm8956_i2c_driver);
+#endif
+}
+module_exit(wm8956_exit);
+
+MODULE_DESCRIPTION("ASoC WM8956 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8956.h b/sound/soc/codecs/wm8956.h
new file mode 100644
index 0000000..2503012
--- /dev/null
+++ b/sound/soc/codecs/wm8956.h
@@ -0,0 +1,112 @@
+/*
+ * wm8956.h  --  WM8956 Soc Audio driver
+ *
+ * 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 _WM8956_H
+#define _WM8956_H
+
+/* WM8956 register space */
+
+
+#define WM8956_CACHEREGNUM 	56
+
+#define WM8956_LINVOL		0x0
+#define WM8956_RINVOL	0x1
+#define WM8956_LOUT1		0x2
+#define WM8956_ROUT1		0x3
+#define WM8956_CLOCK1	0x4
+#define WM8956_DACCTL1	0x5
+#define WM8956_DACCTL2	0x6
+#define WM8956_IFACE1		0x7
+#define WM8956_CLOCK2	0x8
+#define WM8956_IFACE2		0x9
+#define WM8956_LDAC		0xa
+#define WM8956_RDAC		0xb
+
+#define WM8956_RESET		0xf
+#define WM8956_3D				0x10
+
+#define WM8956_ADDCTL1		0x17
+#define WM8956_ADDCTL2		0x18
+#define WM8956_POWER1	0x19
+#define WM8956_POWER2	0x1a
+#define WM8956_ADDCTL3	0x1b
+#define WM8956_APOP1		0x1c
+#define WM8956_APOP2		0x1d
+
+#define WM8956_LINPATH	0x20
+#define WM8956_RINPATH	0x21
+#define WM8956_LOUTMIX1	0x22
+
+#define WM8956_ROUTMIX2	0x25
+#define WM8956_MONOMIX1	0x26
+#define WM8956_MONOMIX2	0x27
+#define WM8956_LOUT2		0x28
+#define WM8956_ROUT2		0x29
+#define WM8956_MONO		0x2a
+#define WM8956_INBMIX1	0x2b
+#define WM8956_INBMIX2	0x2c
+#define WM8956_BYPASS1	0x2d
+#define WM8956_BYPASS2	0x2e
+#define WM8956_POWER3	0x2f
+#define WM8956_ADDCTL4		0x30
+#define WM8956_CLASSD1		0x31
+
+#define WM8956_CLASSD3		0x33
+#define WM8956_PLLN		0x34
+#define WM8956_PLLK1		0x35
+#define WM8956_PLLK2		0x36
+#define WM8956_PLLK3		0x37
+
+
+/*
+ * WM8956 Clock dividers
+ */
+#define WM8956_SYSCLKDIV 		0
+#define WM8956_DACDIV			1
+#define WM8956_OPCLKDIV			2
+#define WM8956_DCLKDIV			3
+#define WM8956_TOCLKSEL			4
+#define WM8956_SYSCLKSEL		5
+
+#define WM8956_SYSCLK_DIV_1		(0 << 1)
+#define WM8956_SYSCLK_DIV_2		(2 << 1)
+
+#define WM8956_SYSCLK_MCLK		(0 << 0)
+#define WM8956_SYSCLK_PLL		(1 << 0)
+
+#define WM8956_DAC_DIV_1		(0 << 3)
+#define WM8956_DAC_DIV_1_5		(1 << 3)
+#define WM8956_DAC_DIV_2		(2 << 3)
+#define WM8956_DAC_DIV_3		(3 << 3)
+#define WM8956_DAC_DIV_4		(4 << 3)
+#define WM8956_DAC_DIV_5_5		(5 << 3)
+#define WM8956_DAC_DIV_6		(6 << 3)
+
+#define WM8956_DCLK_DIV_1_5		(0 << 6)
+#define WM8956_DCLK_DIV_2		(1 << 6)
+#define WM8956_DCLK_DIV_3		(2 << 6)
+#define WM8956_DCLK_DIV_4		(3 << 6)
+#define WM8956_DCLK_DIV_6		(4 << 6)
+#define WM8956_DCLK_DIV_8		(5 << 6)
+#define WM8956_DCLK_DIV_12		(6 << 6)
+#define WM8956_DCLK_DIV_16		(7 << 6)
+
+#define WM8956_TOCLK_F19		(0 << 1)
+#define WM8956_TOCLK_F21		(1 << 1)
+
+#define WM8956_OPCLK_DIV_1		(0 << 0)
+#define WM8956_OPCLK_DIV_2		(1 << 0)
+#define WM8956_OPCLK_DIV_3		(2 << 0)
+#define WM8956_OPCLK_DIV_4		(3 << 0)
+#define WM8956_OPCLK_DIV_5_5	(4 << 0)
+#define WM8956_OPCLK_DIV_6		(5 << 0)
+
+extern struct snd_soc_dai wm8956_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8956;
+
+#endif
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 53edd9a..3dc4d2b 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2681,6 +2681,8 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, sysclk_event,
 SND_SOC_DAPM_SUPPLY("Charge Pump", WM8962_CHARGE_PUMP_1, 0, 0, cp_event,
 		    SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TEMP_HP", WM8962_ADDITIONAL_CONTROL_4, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TEMP_SPK", WM8962_ADDITIONAL_CONTROL_4, 1, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY_S("DSP2", 1, WM8962_DSP2_POWER_MANAGEMENT,
 		      WM8962_DSP2_ENA_SHIFT, 0, dsp2_event,
 		      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -2839,6 +2841,9 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = {
 
 	{ "HPOUTL", NULL, "HPOUT" },
 	{ "HPOUTR", NULL, "HPOUT" },
+
+	{ "HPOUTL", NULL, "TEMP_HP" },
+	{ "HPOUTR", NULL, "TEMP_HP" },
 };
 
 static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = {
@@ -2855,6 +2860,7 @@ static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = {
 	{ "Speaker Output", NULL, "Speaker PGA" },
 	{ "Speaker Output", NULL, "SYSCLK" },
 	{ "Speaker Output", NULL, "TOCLK" },
+	{ "Speaker Output", NULL, "TEMP_SPK" },
 
 	{ "SPKOUT", NULL, "Speaker Output" },
 };
@@ -2883,10 +2889,12 @@ static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
 	{ "SPKOUTL Output", NULL, "SPKOUTL PGA" },
 	{ "SPKOUTL Output", NULL, "SYSCLK" },
 	{ "SPKOUTL Output", NULL, "TOCLK" },
+	{ "SPKOUTL Output", NULL, "TEMP_SPK" },
 
 	{ "SPKOUTR Output", NULL, "SPKOUTR PGA" },
 	{ "SPKOUTR Output", NULL, "SYSCLK" },
 	{ "SPKOUTR Output", NULL, "TOCLK" },
+	{ "SPKOUTR Output", NULL, "TEMP_SPK" },
 
 	{ "SPKOUTL", NULL, "SPKOUTL Output" },
 	{ "SPKOUTR", NULL, "SPKOUTR Output" },
@@ -3172,13 +3180,13 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_FORMAT_S16_LE:
 		break;
 	case SNDRV_PCM_FORMAT_S20_3LE:
-		aif0 |= 0x40;
+		aif0 |= 0x4;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
-		aif0 |= 0x80;
+		aif0 |= 0x8;
 		break;
 	case SNDRV_PCM_FORMAT_S32_LE:
-		aif0 |= 0xc0;
+		aif0 |= 0xc;
 		break;
 	default:
 		return -EINVAL;
@@ -3662,6 +3670,14 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 	snd_soc_jack_report(wm8962->jack, 0,
 			    SND_JACK_MICROPHONE | SND_JACK_BTN_0);
 
+	if (jack) {
+		snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
+		snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS");
+	} else {
+		snd_soc_dapm_disable_pin(&codec->dapm, "SYSCLK");
+		snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS");
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(wm8962_mic_detect);
diff --git a/sound/soc/codecs/wm8976.c b/sound/soc/codecs/wm8976.c
new file mode 100644
index 0000000..c540fa2
--- /dev/null
+++ b/sound/soc/codecs/wm8976.c
@@ -0,0 +1,742 @@
+/*
+ * wm8976.c  --  WM8976 ALSA Soc Audio driver
+ *
+ * Copyright 2007-9 Wolfson Microelectronics PLC.
+ *
+ * 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/pm.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8976.h"
+
+static const u16 wm8976_reg_defs[WM8976_CACHEREGNUM] = {
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0050, 0x0000, 0x0140, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x00ff,
+	0x00ff, 0x0000, 0x0100, 0x00ff,
+	0x00ff, 0x0000, 0x012c, 0x002c,
+	0x002c, 0x002c, 0x002c, 0x0000,
+	0x0032, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0038, 0x000b, 0x0032, 0x0000,
+	0x0008, 0x000c, 0x0093, 0x00e9,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0033, 0x0010, 0x0010, 0x0100,
+	0x0100, 0x0002, 0x0001, 0x0001,
+	0x0039, 0x0039, 0x0039, 0x0039,
+	0x0001, 0x0001,
+};
+
+struct wm8976_priv {
+	enum snd_soc_control_type control_type;
+};
+
+#define wm8976_reset(c)	snd_soc_write(c, WM8976_RESET, 0)
+
+static const char *wm8976_companding[] = {"Off", "NC", "u-law", "A-law" };
+static const char *wm8976_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" };
+static const char *wm8976_eqmode[] = {"Capture", "Playback" };
+static const char *wm8976_bw[] = {"Narrow", "Wide" };
+static const char *wm8976_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz" };
+static const char *wm8976_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz" };
+static const char *wm8976_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz" };
+static const char *wm8976_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" };
+static const char *wm8976_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz" };
+static const char *wm8976_alc[] =
+{"ALC both on", "ALC left only", "ALC right only", "Limiter" };
+
+static const struct soc_enum wm8976_enum[] = {
+	SOC_ENUM_SINGLE(WM8976_COMP, 1, 4, wm8976_companding), /* adc */
+	SOC_ENUM_SINGLE(WM8976_COMP, 3, 4, wm8976_companding), /* dac */
+	SOC_ENUM_SINGLE(WM8976_DAC,  4, 4, wm8976_deemp),
+	SOC_ENUM_SINGLE(WM8976_EQ1,  8, 2, wm8976_eqmode),
+
+	SOC_ENUM_SINGLE(WM8976_EQ1,  5, 4, wm8976_eq1),
+	SOC_ENUM_SINGLE(WM8976_EQ2,  8, 2, wm8976_bw),
+	SOC_ENUM_SINGLE(WM8976_EQ2,  5, 4, wm8976_eq2),
+	SOC_ENUM_SINGLE(WM8976_EQ3,  8, 2, wm8976_bw),
+
+	SOC_ENUM_SINGLE(WM8976_EQ3,  5, 4, wm8976_eq3),
+	SOC_ENUM_SINGLE(WM8976_EQ4,  8, 2, wm8976_bw),
+	SOC_ENUM_SINGLE(WM8976_EQ4,  5, 4, wm8976_eq4),
+	SOC_ENUM_SINGLE(WM8976_EQ5,  8, 2, wm8976_bw),
+
+	SOC_ENUM_SINGLE(WM8976_EQ5,  5, 4, wm8976_eq5),
+	SOC_ENUM_SINGLE(WM8976_ALC3,  8, 2, wm8976_alc),
+};
+
+static const struct snd_kcontrol_new wm8976_snd_controls[] = {
+	SOC_SINGLE("Digital Loopback Switch", WM8976_COMP, 0, 1, 0),
+
+	SOC_ENUM("ADC Companding", wm8976_enum[0]),
+	SOC_ENUM("DAC Companding", wm8976_enum[1]),
+
+	SOC_SINGLE("Jack Detection Enable", WM8976_JACK1, 6, 1, 0),
+
+	SOC_DOUBLE("DAC Inversion Switch", WM8976_DAC, 0, 1, 1, 0),
+
+	SOC_DOUBLE_R("Headphone Playback Volume", WM8976_DACVOLL, WM8976_DACVOLR, 0, 127, 0),
+
+	SOC_SINGLE("High Pass Filter Switch", WM8976_ADC, 8, 1, 0),
+	SOC_SINGLE("High Pass Filter Switch", WM8976_ADC, 8, 1, 0),
+	SOC_SINGLE("High Pass Cut Off", WM8976_ADC, 4, 7, 0),
+
+	SOC_DOUBLE("ADC Inversion Switch", WM8976_ADC, 0, 1, 1, 0),
+
+	SOC_SINGLE("Capture Volume", WM8976_ADCVOL,  0, 127, 0),
+
+	SOC_ENUM("Equaliser Function", wm8976_enum[3]),
+	SOC_ENUM("EQ1 Cut Off", wm8976_enum[4]),
+	SOC_SINGLE("EQ1 Volume", WM8976_EQ1,  0, 31, 1),
+
+	SOC_ENUM("Equaliser EQ2 Bandwith", wm8976_enum[5]),
+	SOC_ENUM("EQ2 Cut Off", wm8976_enum[6]),
+	SOC_SINGLE("EQ2 Volume", WM8976_EQ2,  0, 31, 1),
+
+	SOC_ENUM("Equaliser EQ3 Bandwith", wm8976_enum[7]),
+	SOC_ENUM("EQ3 Cut Off", wm8976_enum[8]),
+	SOC_SINGLE("EQ3 Volume", WM8976_EQ3,  0, 31, 1),
+
+	SOC_ENUM("Equaliser EQ4 Bandwith", wm8976_enum[9]),
+	SOC_ENUM("EQ4 Cut Off", wm8976_enum[10]),
+	SOC_SINGLE("EQ4 Volume", WM8976_EQ4,  0, 31, 1),
+
+	SOC_ENUM("Equaliser EQ5 Bandwith", wm8976_enum[11]),
+	SOC_ENUM("EQ5 Cut Off", wm8976_enum[12]),
+	SOC_SINGLE("EQ5 Volume", WM8976_EQ5,  0, 31, 1),
+
+	SOC_SINGLE("DAC Playback Limiter Switch", WM8976_DACLIM1,  8, 1, 0),
+	SOC_SINGLE("DAC Playback Limiter Decay", WM8976_DACLIM1,  4, 15, 0),
+	SOC_SINGLE("DAC Playback Limiter Attack", WM8976_DACLIM1,  0, 15, 0),
+
+	SOC_SINGLE("DAC Playback Limiter Threshold", WM8976_DACLIM2,  4, 7, 0),
+	SOC_SINGLE("DAC Playback Limiter Boost", WM8976_DACLIM2,  0, 15, 0),
+
+	SOC_SINGLE("ALC Enable Switch", WM8976_ALC1,  8, 1, 0),
+	SOC_SINGLE("ALC Capture Max Gain", WM8976_ALC1,  3, 7, 0),
+	SOC_SINGLE("ALC Capture Min Gain", WM8976_ALC1,  0, 7, 0),
+
+	SOC_SINGLE("ALC Capture ZC Switch", WM8976_ALC2,  8, 1, 0),
+	SOC_SINGLE("ALC Capture Hold", WM8976_ALC2,  4, 7, 0),
+	SOC_SINGLE("ALC Capture Target", WM8976_ALC2,  0, 15, 0),
+
+	SOC_ENUM("ALC Capture Mode", wm8976_enum[13]),
+	SOC_SINGLE("ALC Capture Decay", WM8976_ALC3,  4, 15, 0),
+	SOC_SINGLE("ALC Capture Attack", WM8976_ALC3,  0, 15, 0),
+
+	SOC_SINGLE("ALC Capture Noise Gate Switch", WM8976_NGATE,  3, 1, 0),
+	SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8976_NGATE,  0, 7, 0),
+
+	SOC_SINGLE("Capture PGA ZC Switch", WM8976_INPPGA,  7, 1, 0),
+	SOC_SINGLE("Capture PGA Volume", WM8976_INPPGA,  0, 63, 0),
+
+	SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8976_HPVOLL,  WM8976_HPVOLR, 7, 1, 0),
+	SOC_DOUBLE_R("Headphone Playback Switch", WM8976_HPVOLL,  WM8976_HPVOLR, 6, 1, 1),
+	SOC_DOUBLE_R("Headphone Playback Volume", WM8976_HPVOLL,  WM8976_HPVOLR, 0, 63, 0),
+
+	SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8976_SPKVOLL,  WM8976_SPKVOLR, 7, 1, 0),
+	SOC_DOUBLE_R("Speaker Playback Switch", WM8976_SPKVOLL,  WM8976_SPKVOLR, 6, 1, 1),
+	SOC_DOUBLE_R("Speaker Playback Volume", WM8976_SPKVOLL,  WM8976_SPKVOLR, 0, 63, 0),
+
+	SOC_SINGLE("Capture Boost(+20dB)", WM8976_ADCBOOST, 8, 1, 0),
+};
+
+/* Left Output Mixer */
+static const struct snd_kcontrol_new wm8976_left_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Right PCM Playback Switch", WM8976_OUTPUT, 6, 1, 1),
+	SOC_DAPM_SINGLE("Left PCM Playback Switch", WM8976_MIXL, 0, 1, 1),
+	SOC_DAPM_SINGLE("Line Bypass Switch", WM8976_MIXL, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux Playback Switch", WM8976_MIXL, 5, 1, 0),
+};
+
+/* Right Output Mixer */
+static const struct snd_kcontrol_new wm8976_right_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left PCM Playback Switch", WM8976_OUTPUT, 5, 1, 1),
+	SOC_DAPM_SINGLE("Right PCM Playback Switch", WM8976_MIXR, 0, 1, 1),
+	SOC_DAPM_SINGLE("Line Bypass Switch", WM8976_MIXR, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux Playback Switch", WM8976_MIXR, 5, 1, 0),
+};
+
+/* Left AUX Input boost vol */
+static const struct snd_kcontrol_new wm8976_laux_boost_controls =
+	SOC_DAPM_SINGLE("Aux Volume", WM8976_ADCBOOST, 0, 3, 0);
+
+/* Left Input boost vol */
+static const struct snd_kcontrol_new wm8976_lmic_boost_controls =
+	SOC_DAPM_SINGLE("Input Volume", WM8976_ADCBOOST, 4, 3, 0);
+
+/* Left Aux In to PGA */
+static const struct snd_kcontrol_new wm8976_laux_capture_boost_controls =
+	SOC_DAPM_SINGLE("Capture Switch", WM8976_ADCBOOST,  8, 1, 0);
+
+/* Left Input P In to PGA */
+static const struct snd_kcontrol_new wm8976_lmicp_capture_boost_controls =
+	SOC_DAPM_SINGLE("Input P Capture Boost Switch", WM8976_INPUT,  0, 1, 0);
+
+/* Left Input N In to PGA */
+static const struct snd_kcontrol_new wm8976_lmicn_capture_boost_controls =
+	SOC_DAPM_SINGLE("Input N Capture Boost Switch", WM8976_INPUT,  1, 1, 0);
+
+// TODO Widgets
+static const struct snd_soc_dapm_widget wm8976_dapm_widgets[] = {
+#if 0
+//SND_SOC_DAPM_MUTE("Mono Mute", WM8976_MONOMIX, 6, 0),
+//SND_SOC_DAPM_MUTE("Speaker Mute", WM8976_SPKMIX, 6, 0),
+
+	SND_SOC_DAPM_MIXER("Speaker Mixer", WM8976_POWER3, 2, 0,
+	&wm8976_speaker_mixer_controls[0],
+	ARRAY_SIZE(wm8976_speaker_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono Mixer", WM8976_POWER3, 3, 0,
+	&wm8976_mono_mixer_controls[0],
+	ARRAY_SIZE(wm8976_mono_mixer_controls)),
+	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8976_POWER3, 0, 0),
+	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8976_POWER3, 0, 0),
+	SND_SOC_DAPM_PGA("Aux Input", WM8976_POWER1, 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SpkN Out", WM8976_POWER3, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SpkP Out", WM8976_POWER3, 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out", WM8976_POWER3, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic PGA", WM8976_POWER2, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Aux Boost", SND_SOC_NOPM, 0, 0,
+	&wm8976_aux_boost_controls, 1),
+	SND_SOC_DAPM_PGA("Mic Boost", SND_SOC_NOPM, 0, 0,
+	&wm8976_mic_boost_controls, 1),
+	SND_SOC_DAPM_SWITCH("Capture Boost", SND_SOC_NOPM, 0, 0,
+	&wm8976_capture_boost_controls),
+
+	SND_SOC_DAPM_MIXER("Boost Mixer", WM8976_POWER2, 4, 0, NULL, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8976_POWER1, 4, 0),
+
+	SND_SOC_DAPM_INPUT("MICN"),
+	SND_SOC_DAPM_INPUT("MICP"),
+	SND_SOC_DAPM_INPUT("AUX"),
+	SND_SOC_DAPM_OUTPUT("MONOOUT"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+#endif
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* Mono output mixer */
+	{"Mono Mixer", "PCM Playback Switch", "DAC"},
+	{"Mono Mixer", "Aux Playback Switch", "Aux Input"},
+	{"Mono Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+	/* Speaker output mixer */
+	{"Speaker Mixer", "PCM Playback Switch", "DAC"},
+	{"Speaker Mixer", "Aux Playback Switch", "Aux Input"},
+	{"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+	/* Outputs */
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONOOUT", NULL, "Mono Out"},
+	{"SpkN Out", NULL, "Speaker Mixer"},
+	{"SpkP Out", NULL, "Speaker Mixer"},
+	{"SPKOUTN", NULL, "SpkN Out"},
+	{"SPKOUTP", NULL, "SpkP Out"},
+
+	/* Boost Mixer */
+	{"Boost Mixer", NULL, "ADC"},
+	{"Capture Boost Switch", "Aux Capture Boost Switch", "AUX"},
+	{"Aux Boost", "Aux Volume", "Boost Mixer"},
+	{"Capture Boost", "Capture Switch", "Boost Mixer"},
+	{"Mic Boost", "Mic Volume", "Boost Mixer"},
+
+	/* Inputs */
+	{"MICP", NULL, "Mic Boost"},
+	{"MICN", NULL, "Mic PGA"},
+	{"Mic PGA", NULL, "Capture Boost"},
+	{"AUX", NULL, "Aux Input"},
+};
+
+struct _pll_div {
+	unsigned int pre:4; /* prescale - 1 */
+	unsigned int n:4;
+	unsigned int k;
+};
+
+static struct _pll_div pll_div;
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 24) * 10)
+
+static void pll_factors(unsigned int target, unsigned int source)
+{
+	unsigned long long Kpart;
+	unsigned int K, Ndiv, Nmod;
+
+	Ndiv = target / source;
+	if (Ndiv < 6) {
+		source >>= 1;
+		pll_div.pre = 1;
+		Ndiv = target / source;
+	} else
+		pll_div.pre = 0;
+
+	if ((Ndiv < 6) || (Ndiv > 12))
+		printk(KERN_WARNING
+		       "WM8976 N value outwith recommended range! N = %d\n",Ndiv);
+
+	pll_div.n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div.k = K;
+}
+
+static int wm8976_set_dai_pll(struct snd_soc_dai *codec_dai,
+			      int pll_id, int src, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+
+	if(freq_in == 0 || freq_out == 0) {
+		reg = snd_soc_read(codec, WM8976_POWER1);
+		snd_soc_write(codec, WM8976_POWER1, reg & 0x1df);
+		return 0;
+	}
+
+	pll_factors(freq_out * 8, freq_in);
+
+	snd_soc_write(codec, WM8976_PLLN, (pll_div.pre << 4) | pll_div.n);
+	snd_soc_write(codec, WM8976_PLLK1, pll_div.k >> 18);
+	snd_soc_write(codec, WM8976_PLLK1, (pll_div.k >> 9) && 0x1ff);
+	snd_soc_write(codec, WM8976_PLLK1, pll_div.k && 0x1ff);
+	reg = snd_soc_read(codec, WM8976_POWER1);
+	snd_soc_write(codec, WM8976_POWER1, reg | 0x020);
+
+
+	return 0;
+}
+
+static int wm8976_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = snd_soc_read(codec, WM8976_IFACE) & 0x3;
+	u16 clk = snd_soc_read(codec, WM8976_CLOCK) & 0xfffe;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clk |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0010;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0008;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x00018;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0180;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0100;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0080;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_write(codec, WM8976_IFACE, iface);
+	snd_soc_write(codec, WM8976_CLOCK, clk);
+
+	return 0;
+}
+
+static int wm8976_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 iface = snd_soc_read(codec, WM8976_IFACE) & 0xff9f;
+	u16 adn = snd_soc_read(codec, WM8976_ADD) & 0x1f1;
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0020;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0040;
+		break;
+	}
+
+	/* filter coefficient */
+	switch (params_rate(params)) {
+	case SNDRV_PCM_RATE_8000:
+		adn |= 0x5 << 1;
+		break;
+	case SNDRV_PCM_RATE_11025:
+		adn |= 0x4 << 1;
+		break;
+	case SNDRV_PCM_RATE_16000:
+		adn |= 0x3 << 1;
+		break;
+	case SNDRV_PCM_RATE_22050:
+		adn |= 0x2 << 1;
+		break;
+	case SNDRV_PCM_RATE_32000:
+		adn |= 0x1 << 1;
+		break;
+	}
+
+	/* set iface */
+	snd_soc_write(codec, WM8976_IFACE, iface);
+	snd_soc_write(codec, WM8976_ADD, adn);
+	return 0;
+}
+
+static int wm8976_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+				 int div_id, int div)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+
+	switch (div_id) {
+	case WM8976_MCLKDIV:
+		reg = snd_soc_read(codec, WM8976_CLOCK) & 0x11f;
+		snd_soc_write(codec, WM8976_CLOCK, reg | div);
+		break;
+	case WM8976_BCLKDIV:
+		reg = snd_soc_read(codec, WM8976_CLOCK) & 0x1c7;
+		snd_soc_write(codec, WM8976_CLOCK, reg | div);
+		break;
+	case WM8976_OPCLKDIV:
+		reg = snd_soc_read(codec, WM8976_GPIO) & 0x1cf;
+		snd_soc_write(codec, WM8976_GPIO, reg | div);
+		break;
+	case WM8976_DACOSR:
+		reg = snd_soc_read(codec, WM8976_DAC) & 0x1f7;
+		snd_soc_write(codec, WM8976_DAC, reg | div);
+		break;
+	case WM8976_ADCOSR:
+		reg = snd_soc_read(codec, WM8976_ADC) & 0x1f7;
+		snd_soc_write(codec, WM8976_ADC, reg | div);
+		break;
+	case WM8976_MCLKSEL:
+		reg = snd_soc_read(codec, WM8976_CLOCK) & 0x0ff;
+		snd_soc_write(codec, WM8976_CLOCK, reg | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8976_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = snd_soc_read(codec, WM8976_DAC) & 0xffbf;
+
+	if(mute)
+		snd_soc_write(codec, WM8976_DAC, mute_reg | 0x40);
+	else
+		snd_soc_write(codec, WM8976_DAC, mute_reg);
+
+	return 0;
+}
+
+static int wm8976_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 *cache;
+	int i;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_write(codec, WM8976_POWER1, 0x1ff);
+		snd_soc_write(codec, WM8976_POWER2, 0x1ff);
+		snd_soc_write(codec, WM8976_POWER3, 0x1ff);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			if (codec->cache_sync) {
+				cache = codec->reg_cache;
+				for (i = 0; i < codec->driver->reg_cache_size; ++i) {
+					if (i == WM8976_RESET || cache[i] == wm8976_reg_defs[i])
+						continue;
+					snd_soc_write(codec, i, cache[i]);
+				}
+				codec->cache_sync = 0;
+			}
+		}
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_write(codec, WM8976_POWER1, 0x0);
+		snd_soc_write(codec, WM8976_POWER2, 0x0);
+		snd_soc_write(codec, WM8976_POWER3, 0x0);
+		codec->cache_sync = 1;
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+static int wm8976_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+	wm8976_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8976_resume(struct snd_soc_codec *codec)
+{
+	wm8976_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8976_remove(struct snd_soc_codec *codec)
+{
+	wm8976_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8976_probe(struct snd_soc_codec *codec)
+{
+	struct wm8976_priv *wm8976;
+	int ret;
+
+	wm8976 = snd_soc_codec_get_drvdata(codec);
+
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8976->control_type);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
+		return ret;
+	}
+
+	ret = wm8976_reset(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	wm8976_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	snd_soc_add_controls(codec, wm8976_snd_controls,
+			     ARRAY_SIZE(wm8976_snd_controls));
+	snd_soc_dapm_new_controls(&codec->dapm, wm8976_dapm_widgets,
+				  ARRAY_SIZE(wm8976_dapm_widgets));
+	snd_soc_dapm_add_routes(&codec->dapm, audio_map,
+				ARRAY_SIZE(audio_map));
+	return 0;
+}
+
+#define WM8976_FORMATS \
+	(SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
+	 SNDRV_PCM_FORMAT_S24_3LE | SNDRV_PCM_FORMAT_S24_LE)
+
+static struct snd_soc_dai_ops wm8976_dai_ops = {
+	.hw_params = wm8976_hw_params,
+	.digital_mute = wm8976_mute,
+	.set_fmt = wm8976_set_dai_fmt,
+	.set_clkdiv = wm8976_set_dai_clkdiv,
+	.set_pll = wm8976_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver wm8976_dai = {
+	.name = "wm8976",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = WM8976_FORMATS
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = WM8976_FORMATS
+	},
+	.ops = &wm8976_dai_ops
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8976 = {
+	.probe = wm8976_probe,
+	.remove = wm8976_remove,
+	.suspend = wm8976_suspend,
+	.resume = wm8976_resume,
+	.set_bias_level = wm8976_set_bias_level,
+	.reg_cache_size = WM8976_CACHEREGNUM,
+	.reg_word_size = sizeof(u16),
+	.reg_cache_default = wm8976_reg_defs
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8976_spi_probe(struct spi_device *spi)
+{
+	struct wm8976_priv *wm8976;
+	int ret;
+
+	wm8976 = kzalloc(sizeof *wm8976, GFP_KERNEL);
+	if (!wm8976)
+		return -ENOMEM;
+
+	wm8976->control_type = SND_SOC_SPI;
+	spi_set_drvdata(spi, wm8976);
+
+	ret = snd_soc_register_codec(&spi->dev,
+				     &soc_codec_dev_wm8976, &wm8976_dai, 1);
+	if (ret < 0)
+		kfree(wm8976);
+	return ret;
+}
+
+static int __devexit wm8976_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	kfree(spi_get_drvdata(spi));
+	return 0;
+}
+
+static struct spi_driver wm8976_spi_driver = {
+	.driver = {
+		.name	= "wm8976",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm8976_spi_probe,
+	.remove		= __devexit_p(wm8976_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8976_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct wm8976_priv *wm8976;
+	int ret;
+
+	wm8976 = kzalloc(sizeof *wm8976, GFP_KERNEL);
+	if (!wm8976)
+		return -ENOMEM;
+
+	wm8976->control_type = SND_SOC_I2C;
+	i2c_set_clientdata(i2c, wm8976);
+
+	ret = snd_soc_register_codec(&i2c->dev,
+				     &soc_codec_dev_wm8976, &wm8976_dai, 1);
+	if (ret < 0)
+		kfree(wm8976);
+	return ret;
+}
+
+static __devexit int wm8976_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static const struct i2c_device_id wm8976_i2c_id[] = {
+	{ "wm8976", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8976_i2c_id);
+
+static struct i2c_driver wm8976_i2c_driver = {
+	.driver = {
+		.name = "WM8976",
+		.owner = THIS_MODULE,
+	},
+	.probe =    wm8976_i2c_probe,
+	.remove =   __devexit_p(wm8976_i2c_remove),
+	.id_table = wm8976_i2c_id,
+};
+#endif
+
+static int __init wm8976_modinit(void)
+{
+	int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	ret = i2c_add_driver(&wm8976_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8976 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8976_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8976 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return 0;
+}
+module_init(wm8976_modinit);
+
+static void __exit wm8976_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&wm8976_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8976_spi_driver);
+#endif
+}
+module_exit(wm8976_exit);
+
+MODULE_DESCRIPTION("ASoC WM8976 driver");
+MODULE_AUTHOR("Graeme Gregory");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8976.h b/sound/soc/codecs/wm8976.h
new file mode 100644
index 0000000..adeba48
--- /dev/null
+++ b/sound/soc/codecs/wm8976.h
@@ -0,0 +1,105 @@
+/*
+ * wm8976.h  --  WM8976 Soc Audio driver
+ *
+ * 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 _WM8976_H
+#define _WM8976_H
+
+/* WM8976 register space */
+
+#define WM8976_RESET		0x0
+#define WM8976_POWER1		0x1
+#define WM8976_POWER2		0x2
+#define WM8976_POWER3		0x3
+#define WM8976_IFACE		0x4
+#define WM8976_COMP			0x5
+#define WM8976_CLOCK		0x6
+#define WM8976_ADD			0x7
+#define WM8976_GPIO			0x8
+#define WM8976_JACK1        0x9
+#define WM8976_DAC			0xa
+#define WM8976_DACVOLL	    0xb
+#define WM8976_DACVOLR      0xc
+#define WM8976_JACK2        0xd
+#define WM8976_ADC			0xe
+#define WM8976_ADCVOL		0xf
+#define WM8976_EQ1			0x12
+#define WM8976_EQ2			0x13
+#define WM8976_EQ3			0x14
+#define WM8976_EQ4			0x15
+#define WM8976_EQ5			0x16
+#define WM8976_DACLIM1		0x18
+#define WM8976_DACLIM2		0x19
+#define WM8976_NOTCH1		0x1b
+#define WM8976_NOTCH2		0x1c
+#define WM8976_NOTCH3		0x1d
+#define WM8976_NOTCH4		0x1e
+#define WM8976_ALC1			0x20
+#define WM8976_ALC2			0x21
+#define WM8976_ALC3			0x22
+#define WM8976_NGATE		0x23
+#define WM8976_PLLN			0x24
+#define WM8976_PLLK1		0x25
+#define WM8976_PLLK2		0x26
+#define WM8976_PLLK3		0x27
+#define WM8976_3D           0x29
+#define WM8976_BEEP         0x2b
+#define WM8976_INPUT		0x2c
+#define WM8976_INPPGA	  	0x2d
+#define WM8976_ADCBOOST		0x2f
+#define WM8976_OUTPUT		0x31
+#define WM8976_MIXL	        0x32
+#define WM8976_MIXR         0x33
+#define WM8976_HPVOLL		0x34
+#define WM8976_HPVOLR       0x35
+#define WM8976_SPKVOLL      0x36
+#define WM8976_SPKVOLR      0x37
+#define WM8976_OUT3MIX		0x38
+#define WM8976_MONOMIX      0x39
+
+#define WM8976_CACHEREGNUM 	58
+
+/*
+ * WM8976 Clock dividers
+ */
+#define WM8976_MCLKDIV 		0
+#define WM8976_BCLKDIV		1
+#define WM8976_OPCLKDIV		2
+#define WM8976_DACOSR		3
+#define WM8976_ADCOSR		4
+#define WM8976_MCLKSEL		5
+
+#define WM8976_MCLK_MCLK		(0 << 8)
+#define WM8976_MCLK_PLL			(1 << 8)
+
+#define WM8976_MCLK_DIV_1		(0 << 5)
+#define WM8976_MCLK_DIV_1_5		(1 << 5)
+#define WM8976_MCLK_DIV_2		(2 << 5)
+#define WM8976_MCLK_DIV_3		(3 << 5)
+#define WM8976_MCLK_DIV_4		(4 << 5)
+#define WM8976_MCLK_DIV_5_5		(5 << 5)
+#define WM8976_MCLK_DIV_6		(6 << 5)
+
+#define WM8976_BCLK_DIV_1		(0 << 2)
+#define WM8976_BCLK_DIV_2		(1 << 2)
+#define WM8976_BCLK_DIV_4		(2 << 2)
+#define WM8976_BCLK_DIV_8		(3 << 2)
+#define WM8976_BCLK_DIV_16		(4 << 2)
+#define WM8976_BCLK_DIV_32		(5 << 2)
+
+#define WM8976_DACOSR_64		(0 << 3)
+#define WM8976_DACOSR_128		(1 << 3)
+
+#define WM8976_ADCOSR_64		(0 << 3)
+#define WM8976_ADCOSR_128		(1 << 3)
+
+#define WM8976_OPCLK_DIV_1		(0 << 4)
+#define WM8976_OPCLK_DIV_2		(1 << 4)
+#define WM8976_OPCLK_DIV_3		(2 << 4)
+#define WM8976_OPCLK_DIV_4		(3 << 4)
+
+#endif
diff --git a/sound/soc/codecs/wm8980.c b/sound/soc/codecs/wm8980.c
new file mode 100644
index 0000000..e03abb3
--- /dev/null
+++ b/sound/soc/codecs/wm8980.c
@@ -0,0 +1,756 @@
+/*
+ * wm8980.c  --  WM8980 ALSA Soc Audio driver
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ *
+ * Authors:
+ * Mike Arthur      <linux@wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8980.h"
+
+struct wm8980_priv {
+	enum snd_soc_control_type control_type;
+};
+
+static const u16 wm8980_reg_defs[WM8980_CACHEREGNUM] = {
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0050, 0x0000, 0x0140, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x00ff,
+	0x00ff, 0x0000, 0x0100, 0x00ff,
+	0x00ff, 0x0000, 0x012c, 0x002c,
+	0x002c, 0x002c, 0x002c, 0x0000,
+	0x0032, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0038, 0x000b, 0x0032, 0x0000,
+	0x0008, 0x000c, 0x0093, 0x00e9,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0033, 0x0010, 0x0010, 0x0100,
+	0x0100, 0x0002, 0x0001, 0x0001,
+	0x0039, 0x0039, 0x0039, 0x0039,
+	0x0001, 0x0001,
+};
+
+#define wm8980_reset(c)	snd_soc_write(c, WM8980_RESET, 0)
+
+static const char *wm8980_companding[] = {"Off", "NC", "u-law", "A-law" };
+static const char *wm8980_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" };
+static const char *wm8980_eqmode[] = {"Capture", "Playback" };
+static const char *wm8980_bw[] = {"Narrow", "Wide" };
+static const char *wm8980_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz" };
+static const char *wm8980_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz" };
+static const char *wm8980_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz" };
+static const char *wm8980_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" };
+static const char *wm8980_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz" };
+static const char *wm8980_alc[] =
+{"ALC both on", "ALC left only", "ALC right only", "Limiter" };
+
+static const struct soc_enum wm8980_enum[] = {
+	SOC_ENUM_SINGLE(WM8980_COMP, 1, 4, wm8980_companding), /* adc */
+	SOC_ENUM_SINGLE(WM8980_COMP, 3, 4, wm8980_companding), /* dac */
+	SOC_ENUM_SINGLE(WM8980_DAC,  4, 4, wm8980_deemp),
+	SOC_ENUM_SINGLE(WM8980_EQ1,  8, 2, wm8980_eqmode),
+
+	SOC_ENUM_SINGLE(WM8980_EQ1,  5, 4, wm8980_eq1),
+	SOC_ENUM_SINGLE(WM8980_EQ2,  8, 2, wm8980_bw),
+	SOC_ENUM_SINGLE(WM8980_EQ2,  5, 4, wm8980_eq2),
+	SOC_ENUM_SINGLE(WM8980_EQ3,  8, 2, wm8980_bw),
+
+	SOC_ENUM_SINGLE(WM8980_EQ3,  5, 4, wm8980_eq3),
+	SOC_ENUM_SINGLE(WM8980_EQ4,  8, 2, wm8980_bw),
+	SOC_ENUM_SINGLE(WM8980_EQ4,  5, 4, wm8980_eq4),
+	SOC_ENUM_SINGLE(WM8980_EQ5,  8, 2, wm8980_bw),
+
+	SOC_ENUM_SINGLE(WM8980_EQ5,  5, 4, wm8980_eq5),
+	SOC_ENUM_SINGLE(WM8980_ALC3,  8, 2, wm8980_alc),
+};
+
+static const struct snd_kcontrol_new wm8980_snd_controls[] = {
+	SOC_SINGLE("Digital Loopback Switch", WM8980_COMP, 0, 1, 0),
+
+	SOC_ENUM("ADC Companding", wm8980_enum[0]),
+	SOC_ENUM("DAC Companding", wm8980_enum[1]),
+
+	SOC_SINGLE("Jack Detection Enable", WM8980_JACK1, 6, 1, 0),
+
+	SOC_SINGLE("DAC Right Inversion Switch", WM8980_DAC, 1, 1, 0),
+	SOC_SINGLE("DAC Left Inversion Switch", WM8980_DAC, 0, 1, 0),
+
+	SOC_SINGLE("Left Playback Volume", WM8980_DACVOLL, 0, 127, 0),
+	SOC_SINGLE("Right Playback Volume", WM8980_DACVOLR, 0, 127, 0),
+
+	SOC_SINGLE("High Pass Filter Switch", WM8980_ADC, 8, 1, 0),
+	SOC_SINGLE("High Pass Filter Switch", WM8980_ADC, 8, 1, 0),
+	SOC_SINGLE("High Pass Cut Off", WM8980_ADC, 4, 7, 0),
+	SOC_SINGLE("Right ADC Inversion Switch", WM8980_ADC, 1, 1, 0),
+	SOC_SINGLE("Left ADC Inversion Switch", WM8980_ADC, 0, 1, 0),
+
+	SOC_SINGLE("Left Capture Volume", WM8980_ADCVOLL,  0, 127, 0),
+	SOC_SINGLE("Right Capture Volume", WM8980_ADCVOLR,  0, 127, 0),
+
+	SOC_ENUM("Equaliser Function", wm8980_enum[3]),
+	SOC_ENUM("EQ1 Cut Off", wm8980_enum[4]),
+	SOC_SINGLE("EQ1 Volume", WM8980_EQ1,  0, 31, 1),
+
+	SOC_ENUM("Equaliser EQ2 Bandwith", wm8980_enum[5]),
+	SOC_ENUM("EQ2 Cut Off", wm8980_enum[6]),
+	SOC_SINGLE("EQ2 Volume", WM8980_EQ2,  0, 31, 1),
+
+	SOC_ENUM("Equaliser EQ3 Bandwith", wm8980_enum[7]),
+	SOC_ENUM("EQ3 Cut Off", wm8980_enum[8]),
+	SOC_SINGLE("EQ3 Volume", WM8980_EQ3,  0, 31, 1),
+
+	SOC_ENUM("Equaliser EQ4 Bandwith", wm8980_enum[9]),
+	SOC_ENUM("EQ4 Cut Off", wm8980_enum[10]),
+	SOC_SINGLE("EQ4 Volume", WM8980_EQ4,  0, 31, 1),
+
+	SOC_ENUM("Equaliser EQ5 Bandwith", wm8980_enum[11]),
+	SOC_ENUM("EQ5 Cut Off", wm8980_enum[12]),
+	SOC_SINGLE("EQ5 Volume", WM8980_EQ5,  0, 31, 1),
+
+	SOC_SINGLE("DAC Playback Limiter Switch", WM8980_DACLIM1,  8, 1, 0),
+	SOC_SINGLE("DAC Playback Limiter Decay", WM8980_DACLIM1,  4, 15, 0),
+	SOC_SINGLE("DAC Playback Limiter Attack", WM8980_DACLIM1,  0, 15, 0),
+
+	SOC_SINGLE("DAC Playback Limiter Threshold", WM8980_DACLIM2,  4, 7, 0),
+	SOC_SINGLE("DAC Playback Limiter Boost", WM8980_DACLIM2,  0, 15, 0),
+
+	SOC_SINGLE("ALC Enable Switch", WM8980_ALC1,  8, 1, 0),
+	SOC_SINGLE("ALC Capture Max Gain", WM8980_ALC1,  3, 7, 0),
+	SOC_SINGLE("ALC Capture Min Gain", WM8980_ALC1,  0, 7, 0),
+
+	SOC_SINGLE("ALC Capture ZC Switch", WM8980_ALC2,  8, 1, 0),
+	SOC_SINGLE("ALC Capture Hold", WM8980_ALC2,  4, 7, 0),
+	SOC_SINGLE("ALC Capture Target", WM8980_ALC2,  0, 15, 0),
+
+	SOC_ENUM("ALC Capture Mode", wm8980_enum[13]),
+	SOC_SINGLE("ALC Capture Decay", WM8980_ALC3,  4, 15, 0),
+	SOC_SINGLE("ALC Capture Attack", WM8980_ALC3,  0, 15, 0),
+
+	SOC_SINGLE("ALC Capture Noise Gate Switch", WM8980_NGATE,  3, 1, 0),
+	SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8980_NGATE,  0, 7, 0),
+
+	SOC_SINGLE("Left Capture PGA ZC Switch", WM8980_INPPGAL,  7, 1, 0),
+	SOC_SINGLE("Left Capture PGA Volume", WM8980_INPPGAL,  0, 63, 0),
+
+	SOC_SINGLE("Right Capture PGA ZC Switch", WM8980_INPPGAR,  7, 1, 0),
+	SOC_SINGLE("Right Capture PGA Volume", WM8980_INPPGAR,  0, 63, 0),
+
+	SOC_SINGLE("Left Headphone Playback ZC Switch", WM8980_HPVOLL,  7, 1, 0),
+	SOC_SINGLE("Left Headphone Playback Switch", WM8980_HPVOLL,  6, 1, 1),
+	SOC_SINGLE("Left Headphone Playback Volume", WM8980_HPVOLL,  0, 63, 0),
+
+	SOC_SINGLE("Right Headphone Playback ZC Switch", WM8980_HPVOLR,  7, 1, 0),
+	SOC_SINGLE("Right Headphone Playback Switch", WM8980_HPVOLR,  6, 1, 1),
+	SOC_SINGLE("Right Headphone Playback Volume", WM8980_HPVOLR,  0, 63, 0),
+
+	SOC_SINGLE("Left Speaker Playback ZC Switch", WM8980_SPKVOLL,  7, 1, 0),
+	SOC_SINGLE("Left Speaker Playback Switch", WM8980_SPKVOLL,  6, 1, 1),
+	SOC_SINGLE("Left Speaker Playback Volume", WM8980_SPKVOLL,  0, 63, 0),
+
+	SOC_SINGLE("Right Speaker Playback ZC Switch", WM8980_SPKVOLR,  7, 1, 0),
+	SOC_SINGLE("Right Speaker Playback Switch", WM8980_SPKVOLR,  6, 1, 1),
+	SOC_SINGLE("Right Speaker Playback Volume", WM8980_SPKVOLR,  0, 63, 0),
+
+	SOC_DOUBLE_R("Capture Boost(+20dB)", WM8980_ADCBOOSTL, WM8980_ADCBOOSTR,
+	8, 1, 0),
+};
+
+/* Left Output Mixer */
+static const struct snd_kcontrol_new wm8980_left_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Right PCM Playback Switch", WM8980_OUTPUT, 6, 1, 1),
+	SOC_DAPM_SINGLE("Left PCM Playback Switch", WM8980_MIXL, 0, 1, 1),
+	SOC_DAPM_SINGLE("Line Bypass Switch", WM8980_MIXL, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux Playback Switch", WM8980_MIXL, 5, 1, 0),
+};
+
+/* Right Output Mixer */
+static const struct snd_kcontrol_new wm8980_right_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left PCM Playback Switch", WM8980_OUTPUT, 5, 1, 1),
+	SOC_DAPM_SINGLE("Right PCM Playback Switch", WM8980_MIXR, 0, 1, 1),
+	SOC_DAPM_SINGLE("Line Bypass Switch", WM8980_MIXR, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux Playback Switch", WM8980_MIXR, 5, 1, 0),
+};
+
+/* Left AUX Input boost vol */
+static const struct snd_kcontrol_new wm8980_laux_boost_controls =
+	SOC_DAPM_SINGLE("Left Aux Volume", WM8980_ADCBOOSTL, 0, 3, 0);
+
+/* Right AUX Input boost vol */
+static const struct snd_kcontrol_new wm8980_raux_boost_controls =
+	SOC_DAPM_SINGLE("Right Aux Volume", WM8980_ADCBOOSTR, 0, 3, 0);
+
+/* Left Input boost vol */
+static const struct snd_kcontrol_new wm8980_lmic_boost_controls =
+	SOC_DAPM_SINGLE("Left Input Volume", WM8980_ADCBOOSTL, 4, 3, 0);
+
+/* Right Input boost vol */
+static const struct snd_kcontrol_new wm8980_rmic_boost_controls =
+	SOC_DAPM_SINGLE("Right Input Volume", WM8980_ADCBOOSTR, 4, 3, 0);
+
+/* Left Aux In to PGA */
+static const struct snd_kcontrol_new wm8980_laux_capture_boost_controls =
+	SOC_DAPM_SINGLE("Left Capture Switch", WM8980_ADCBOOSTL,  8, 1, 0);
+
+/* Right  Aux In to PGA */
+static const struct snd_kcontrol_new wm8980_raux_capture_boost_controls =
+	SOC_DAPM_SINGLE("Right Capture Switch", WM8980_ADCBOOSTR,  8, 1, 0);
+
+/* Left Input P In to PGA */
+static const struct snd_kcontrol_new wm8980_lmicp_capture_boost_controls =
+	SOC_DAPM_SINGLE("Left Input P Capture Boost Switch", WM8980_INPUT,  0, 1, 0);
+
+/* Right Input P In to PGA */
+static const struct snd_kcontrol_new wm8980_rmicp_capture_boost_controls =
+	SOC_DAPM_SINGLE("Right Input P Capture Boost Switch", WM8980_INPUT,  4, 1, 0);
+
+/* Left Input N In to PGA */
+static const struct snd_kcontrol_new wm8980_lmicn_capture_boost_controls =
+	SOC_DAPM_SINGLE("Left Input N Capture Boost Switch", WM8980_INPUT,  1, 1, 0);
+
+/* Right Input N In to PGA */
+static const struct snd_kcontrol_new wm8980_rmicn_capture_boost_controls =
+	SOC_DAPM_SINGLE("Right Input N Capture Boost Switch", WM8980_INPUT,  5, 1, 0);
+
+// TODO Widgets
+static const struct snd_soc_dapm_widget wm8980_dapm_widgets[] = {
+#if 0
+//SND_SOC_DAPM_MUTE("Mono Mute", WM8980_MONOMIX, 6, 0),
+//SND_SOC_DAPM_MUTE("Speaker Mute", WM8980_SPKMIX, 6, 0),
+
+	SND_SOC_DAPM_MIXER("Speaker Mixer", WM8980_POWER3, 2, 0,
+	&wm8980_speaker_mixer_controls[0],
+	ARRAY_SIZE(wm8980_speaker_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono Mixer", WM8980_POWER3, 3, 0,
+	&wm8980_mono_mixer_controls[0],
+	ARRAY_SIZE(wm8980_mono_mixer_controls)),
+	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8980_POWER3, 0, 0),
+	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8980_POWER3, 0, 0),
+	SND_SOC_DAPM_PGA("Aux Input", WM8980_POWER1, 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SpkN Out", WM8980_POWER3, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SpkP Out", WM8980_POWER3, 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out", WM8980_POWER3, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic PGA", WM8980_POWER2, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Aux Boost", SND_SOC_NOPM, 0, 0,
+	&wm8980_aux_boost_controls, 1),
+	SND_SOC_DAPM_PGA("Mic Boost", SND_SOC_NOPM, 0, 0,
+	&wm8980_mic_boost_controls, 1),
+	SND_SOC_DAPM_SWITCH("Capture Boost", SND_SOC_NOPM, 0, 0,
+	&wm8980_capture_boost_controls),
+
+	SND_SOC_DAPM_MIXER("Boost Mixer", WM8980_POWER2, 4, 0, NULL, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8980_POWER1, 4, 0),
+
+	SND_SOC_DAPM_INPUT("MICN"),
+	SND_SOC_DAPM_INPUT("MICP"),
+	SND_SOC_DAPM_INPUT("AUX"),
+	SND_SOC_DAPM_OUTPUT("MONOOUT"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+#endif
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* Mono output mixer */
+	{"Mono Mixer", "PCM Playback Switch", "DAC"},
+	{"Mono Mixer", "Aux Playback Switch", "Aux Input"},
+	{"Mono Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+	/* Speaker output mixer */
+	{"Speaker Mixer", "PCM Playback Switch", "DAC"},
+	{"Speaker Mixer", "Aux Playback Switch", "Aux Input"},
+	{"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+	/* Outputs */
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONOOUT", NULL, "Mono Out"},
+	{"SpkN Out", NULL, "Speaker Mixer"},
+	{"SpkP Out", NULL, "Speaker Mixer"},
+	{"SPKOUTN", NULL, "SpkN Out"},
+	{"SPKOUTP", NULL, "SpkP Out"},
+
+	/* Boost Mixer */
+	{"Boost Mixer", NULL, "ADC"},
+	{"Capture Boost Switch", "Aux Capture Boost Switch", "AUX"},
+	{"Aux Boost", "Aux Volume", "Boost Mixer"},
+	{"Capture Boost", "Capture Switch", "Boost Mixer"},
+	{"Mic Boost", "Mic Volume", "Boost Mixer"},
+
+	/* Inputs */
+	{"MICP", NULL, "Mic Boost"},
+	{"MICN", NULL, "Mic PGA"},
+	{"Mic PGA", NULL, "Capture Boost"},
+	{"AUX", NULL, "Aux Input"},
+};
+
+static int wm8980_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(&codec->dapm, wm8980_dapm_widgets,
+				  ARRAY_SIZE(wm8980_dapm_widgets));
+	snd_soc_dapm_add_routes(&codec->dapm, audio_map, ARRAY_SIZE(audio_map));
+	return 0;
+}
+
+struct pll_ {
+	unsigned int in_hz, out_hz;
+	unsigned int pre:4; /* prescale - 1 */
+	unsigned int n:4;
+	unsigned int k;
+};
+
+static struct pll_ pll[] = {
+	{12000000, 11289600, 0, 7, 0x86c220},
+	{12000000, 12288000, 0, 8, 0x3126e8},
+	{13000000, 11289600, 0, 6, 0xf28bd4},
+	{13000000, 12288000, 0, 7, 0x8fd525},
+	{12288000, 11289600, 0, 7, 0x59999a},
+	{11289600, 12288000, 0, 8, 0x80dee9},
+	/* TODO: liam - add more entries */
+};
+
+static int wm8980_set_dai_pll(struct snd_soc_dai *codec_dai,
+			      int pll_id, int src, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	int i;
+	u16 reg;
+
+	if(freq_in == 0 || freq_out == 0) {
+		reg = snd_soc_read(codec, WM8980_POWER1);
+		snd_soc_write(codec, WM8980_POWER1, reg & 0x1df);
+		return 0;
+	}
+
+	for(i = 0; i < ARRAY_SIZE(pll); i++) {
+		if (freq_in == pll[i].in_hz && freq_out == pll[i].out_hz) {
+			snd_soc_write(codec, WM8980_PLLN, (pll[i].pre << 4) | pll[i].n);
+			snd_soc_write(codec, WM8980_PLLK1, pll[i].k >> 18);
+			snd_soc_write(codec, WM8980_PLLK1, (pll[i].k >> 9) && 0x1ff);
+			snd_soc_write(codec, WM8980_PLLK1, pll[i].k && 0x1ff);
+			reg = snd_soc_read(codec, WM8980_POWER1);
+			snd_soc_write(codec, WM8980_POWER1, reg | 0x020);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static int wm8980_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = snd_soc_read(codec, WM8980_IFACE) & 0x3;
+	u16 clk = snd_soc_read(codec, WM8980_CLOCK) & 0xfffe;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clk |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0010;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0008;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x00018;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0180;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0100;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0080;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_write(codec, WM8980_IFACE, iface);
+	return 0;
+}
+
+static int wm8980_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 iface = snd_soc_read(codec, WM8980_IFACE) & 0xff9f;
+	u16 adn = snd_soc_read(codec, WM8980_ADD) & 0x1f1;
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0020;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0040;
+		break;
+	}
+
+	/* filter coefficient */
+	switch (params_rate(params)) {
+	case SNDRV_PCM_RATE_8000:
+		adn |= 0x5 << 1;
+		break;
+	case SNDRV_PCM_RATE_11025:
+		adn |= 0x4 << 1;
+		break;
+	case SNDRV_PCM_RATE_16000:
+		adn |= 0x3 << 1;
+		break;
+	case SNDRV_PCM_RATE_22050:
+		adn |= 0x2 << 1;
+		break;
+	case SNDRV_PCM_RATE_32000:
+		adn |= 0x1 << 1;
+		break;
+	}
+
+	/* set iface */
+	snd_soc_write(codec, WM8980_IFACE, iface);
+	snd_soc_write(codec, WM8980_ADD, adn);
+	return 0;
+}
+
+static int wm8980_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+				 int div_id, int div)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+
+	switch (div_id) {
+	case WM8980_MCLKDIV:
+		reg = snd_soc_read(codec, WM8980_CLOCK) & 0x11f;
+		snd_soc_write(codec, WM8980_CLOCK, reg | div);
+		break;
+	case WM8980_BCLKDIV:
+		reg = snd_soc_read(codec, WM8980_CLOCK) & 0x1c7;
+		snd_soc_write(codec, WM8980_CLOCK, reg | div);
+		break;
+	case WM8980_OPCLKDIV:
+		reg = snd_soc_read(codec, WM8980_GPIO) & 0x1cf;
+		snd_soc_write(codec, WM8980_GPIO, reg | div);
+		break;
+	case WM8980_DACOSR:
+		reg = snd_soc_read(codec, WM8980_DAC) & 0x1f7;
+		snd_soc_write(codec, WM8980_DAC, reg | div);
+		break;
+	case WM8980_ADCOSR:
+		reg = snd_soc_read(codec, WM8980_ADC) & 0x1f7;
+		snd_soc_write(codec, WM8980_ADC, reg | div);
+		break;
+	case WM8980_MCLKSEL:
+		reg = snd_soc_read(codec, WM8980_CLOCK) & 0x0ff;
+		snd_soc_write(codec, WM8980_CLOCK, reg | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8980_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = snd_soc_read(codec, WM8980_DAC) & 0xffbf;
+
+	if(mute)
+		snd_soc_write(codec, WM8980_DAC, mute_reg | 0x40);
+	else
+		snd_soc_write(codec, WM8980_DAC, mute_reg);
+
+	return 0;
+}
+
+static int wm8980_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 *cache;
+	int i;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_write(codec, WM8980_POWER1, 0x1ff);
+		snd_soc_write(codec, WM8980_POWER2, 0x1ff);
+		snd_soc_write(codec, WM8980_POWER3, 0x1ff);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			if (codec->cache_sync) {
+				cache = codec->reg_cache;
+				for (i = 0; i < codec->driver->reg_cache_size; i++) {
+					if (i == WM8980_RESET || cache[i] == wm8980_reg_defs[i])
+						continue;
+					snd_soc_write(codec, i, cache[i]);
+				}
+				codec->cache_sync = 0;
+			}
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_write(codec, WM8980_POWER1, 0x0);
+		snd_soc_write(codec, WM8980_POWER2, 0x0);
+		snd_soc_write(codec, WM8980_POWER3, 0x0);
+		codec->cache_sync = 1;
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+
+static int wm8980_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+	wm8980_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8980_resume(struct snd_soc_codec *codec)
+{
+	wm8980_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	return 0;
+}
+
+static int wm8980_remove(struct snd_soc_codec *codec)
+{
+	wm8980_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8980_probe(struct snd_soc_codec *codec)
+{
+	struct wm8980_priv *wm8980;
+	int ret;
+
+	wm8980 = snd_soc_codec_get_drvdata(codec);
+
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8980->control_type);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
+		return ret;
+	}
+
+	ret = wm8980_reset(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	wm8980_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	snd_soc_add_controls(codec, wm8980_snd_controls,
+			     ARRAY_SIZE(wm8980_snd_controls));
+	wm8980_add_widgets(codec);
+	return ret;
+}
+
+#define WM8980_FORMATS \
+	(SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
+	 SNDRV_PCM_FORMAT_S24_3LE | SNDRV_PCM_FORMAT_S24_LE)
+
+static struct snd_soc_dai_ops wm8980_ops = {
+	.hw_params = wm8980_hw_params,
+	.digital_mute = wm8980_mute,
+	.set_fmt = wm8980_set_dai_fmt,
+	.set_clkdiv = wm8980_set_dai_clkdiv,
+	.set_pll = wm8980_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver wm8980_dai = {
+	.name = "wm8980",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = WM8980_FORMATS
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = WM8980_FORMATS
+	},
+	.ops = &wm8980_ops
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8980 = {
+	.probe = wm8980_probe,
+	.remove = wm8980_remove,
+	.suspend = wm8980_suspend,
+	.resume = wm8980_resume,
+	.set_bias_level = wm8980_set_bias_level,
+	.reg_cache_size = ARRAY_SIZE(wm8980_reg_defs),
+	.reg_word_size = sizeof(u16),
+	.reg_cache_default = wm8980_reg_defs
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8980_spi_probe(struct spi_device *spi)
+{
+	struct wm8980_priv *wm8980;
+	int ret;
+
+	wm8980 = kzalloc(sizeof *wm8980, GFP_KERNEL);
+	if (!wm8980)
+		return -ENOMEM;
+
+	wm8980->control_type = SND_SOC_SPI;
+	spi_set_drvdata(spi, wm8980);
+
+	ret = snd_soc_register_codec(&spi->dev,
+				     &soc_codec_dev_wm8980, &wm8980_dai, 1);
+	if (ret < 0)
+		kfree(wm8980);
+	return ret;
+}
+
+static int __devexit wm8980_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	kfree(spi_get_drvdata(spi));
+	return 0;
+}
+
+static struct spi_driver wm8980_spi_driver = {
+	.driver = {
+		.name	= "wm8980",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm8980_spi_probe,
+	.remove		= __devexit_p(wm8980_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8980_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct wm8980_priv *wm8980;
+	int ret;
+
+	wm8980 = kzalloc(sizeof *wm8980, GFP_KERNEL);
+	if (!wm8980)
+		return -ENOMEM;
+
+	wm8980->control_type = SND_SOC_I2C;
+	i2c_set_clientdata(i2c, wm8980);
+
+	ret = snd_soc_register_codec(&i2c->dev,
+				     &soc_codec_dev_wm8980, &wm8980_dai, 1);
+	if (ret < 0)
+		kfree(wm8980);
+	return ret;
+}
+
+static __devexit int wm8980_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static const struct i2c_device_id wm8980_i2c_id[] = {
+	{ "wm8980", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8980_i2c_id);
+
+static struct i2c_driver wm8980_i2c_driver = {
+	.driver = {
+		.name = "wm8980",
+		.owner = THIS_MODULE,
+	},
+	.probe = wm8980_i2c_probe,
+	.remove = __devexit_p(wm8980_i2c_remove),
+	.id_table = wm8980_i2c_id,
+};
+#endif
+
+static int __init wm8980_modinit(void)
+{
+	int ret;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	ret = i2c_add_driver(&wm8980_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8980 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8980_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8980 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return 0;
+}
+module_init(wm8980_modinit);
+
+static void __exit wm8980_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&wm8980_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8980_spi_driver);
+#endif
+}
+module_exit(wm8980_exit);
+
+MODULE_DESCRIPTION("ASoC WM8980 driver");
+MODULE_AUTHOR("Mike Arthur");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8980.h b/sound/soc/codecs/wm8980.h
new file mode 100644
index 0000000..c7c214a
--- /dev/null
+++ b/sound/soc/codecs/wm8980.h
@@ -0,0 +1,109 @@
+/*
+ * wm8980.h  --  WM8980 Soc Audio driver
+ *
+ * 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 _WM8980_H
+#define _WM8980_H
+
+/* WM8980 register space */
+
+#define WM8980_RESET		0x0
+#define WM8980_POWER1		0x1
+#define WM8980_POWER2		0x2
+#define WM8980_POWER3		0x3
+#define WM8980_IFACE		0x4
+#define WM8980_COMP			0x5
+#define WM8980_CLOCK		0x6
+#define WM8980_ADD			0x7
+#define WM8980_GPIO			0x8
+#define WM8980_JACK1        0x9
+#define WM8980_DAC			0xa
+#define WM8980_DACVOLL	    0xb
+#define WM8980_DACVOLR      0xc
+#define WM8980_JACK2        0xd
+#define WM8980_ADC			0xe
+#define WM8980_ADCVOLL		0xf
+#define WM8980_ADCVOLR      0x10
+#define WM8980_EQ1			0x12
+#define WM8980_EQ2			0x13
+#define WM8980_EQ3			0x14
+#define WM8980_EQ4			0x15
+#define WM8980_EQ5			0x16
+#define WM8980_DACLIM1		0x18
+#define WM8980_DACLIM2		0x19
+#define WM8980_NOTCH1		0x1b
+#define WM8980_NOTCH2		0x1c
+#define WM8980_NOTCH3		0x1d
+#define WM8980_NOTCH4		0x1e
+#define WM8980_ALC1			0x20
+#define WM8980_ALC2			0x21
+#define WM8980_ALC3			0x22
+#define WM8980_NGATE		0x23
+#define WM8980_PLLN			0x24
+#define WM8980_PLLK1		0x25
+#define WM8980_PLLK2		0x26
+#define WM8980_PLLK3		0x27
+#define WM8980_VIDEO		0x28
+#define WM8980_3D           0x29
+#define WM8980_BEEP         0x2b
+#define WM8980_INPUT		0x2c
+#define WM8980_INPPGAL  	0x2d
+#define WM8980_INPPGAR      0x2e
+#define WM8980_ADCBOOSTL	0x2f
+#define WM8980_ADCBOOSTR    0x30
+#define WM8980_OUTPUT		0x31
+#define WM8980_MIXL	        0x32
+#define WM8980_MIXR         0x33
+#define WM8980_HPVOLL		0x34
+#define WM8980_HPVOLR       0x35
+#define WM8980_SPKVOLL      0x36
+#define WM8980_SPKVOLR      0x37
+#define WM8980_OUT3MIX		0x38
+#define WM8980_MONOMIX      0x39
+
+#define WM8980_CACHEREGNUM 	58
+
+/*
+ * WM8980 Clock dividers
+ */
+#define WM8980_MCLKDIV 		0
+#define WM8980_BCLKDIV		1
+#define WM8980_OPCLKDIV		2
+#define WM8980_DACOSR		3
+#define WM8980_ADCOSR		4
+#define WM8980_MCLKSEL		5
+
+#define WM8980_MCLK_MCLK		(0 << 8)
+#define WM8980_MCLK_PLL			(1 << 8)
+
+#define WM8980_MCLK_DIV_1		(0 << 5)
+#define WM8980_MCLK_DIV_1_5		(1 << 5)
+#define WM8980_MCLK_DIV_2		(2 << 5)
+#define WM8980_MCLK_DIV_3		(3 << 5)
+#define WM8980_MCLK_DIV_4		(4 << 5)
+#define WM8980_MCLK_DIV_5_5		(5 << 5)
+#define WM8980_MCLK_DIV_6		(6 << 5)
+
+#define WM8980_BCLK_DIV_1		(0 << 2)
+#define WM8980_BCLK_DIV_2		(1 << 2)
+#define WM8980_BCLK_DIV_4		(2 << 2)
+#define WM8980_BCLK_DIV_8		(3 << 2)
+#define WM8980_BCLK_DIV_16		(4 << 2)
+#define WM8980_BCLK_DIV_32		(5 << 2)
+
+#define WM8980_DACOSR_64		(0 << 3)
+#define WM8980_DACOSR_128		(1 << 3)
+
+#define WM8980_ADCOSR_64		(0 << 3)
+#define WM8980_ADCOSR_128		(1 << 3)
+
+#define WM8980_OPCLK_DIV_1		(0 << 4)
+#define WM8980_OPCLK_DIV_2		(1 << 4)
+#define WM8980_OPCLK_DIV_3		(2 << 4)
+#define WM8980_OPCLK_DIV_4		(3 << 4)
+
+#endif
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index 93ee284..17f04ec 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -1007,7 +1007,7 @@ static int wm8983_probe(struct snd_soc_codec *codec)
 		return ret;
 	}
 
-	ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0);
+	ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0x8983);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
 		return ret;
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index d0c545b..bea285f 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -26,9 +26,9 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
-#include <trace/events/asoc.h>
 
 #include <linux/mfd/wm8994/core.h>
 #include <linux/mfd/wm8994/registers.h>
@@ -38,6 +38,11 @@
 #include "wm8994.h"
 #include "wm_hubs.h"
 
+#define WM1811_JACKDET_MODE_NONE  0x0000
+#define WM1811_JACKDET_MODE_JACK  0x0100
+#define WM1811_JACKDET_MODE_MIC   0x0080
+#define WM1811_JACKDET_MODE_AUDIO 0x0180
+
 #define WM8994_NUM_DRC 3
 #define WM8994_NUM_EQ  3
 
@@ -53,9 +58,73 @@ static int wm8994_retune_mobile_base[] = {
 	WM8994_AIF2_EQ_GAINS_1,
 };
 
-static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
+static void wm8958_default_micdet(u16 status, void *data);
+
+static const struct wm8958_micd_rate micdet_rates[] = {
+	{ 32768,       true,  1, 4 },
+	{ 32768,       false, 1, 1 },
+	{ 44100 * 256, true,  7, 10 },
+	{ 44100 * 256, false, 7, 10 },
+};
+
+static const struct wm8958_micd_rate jackdet_rates[] = {
+	{ 32768,       true,  0, 1 },
+	{ 32768,       false, 0, 1 },
+	{ 44100 * 256, true,  7, 10 },
+	{ 44100 * 256, false, 7, 10 },
+};
+
+static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
 {
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	int best, i, sysclk, val;
+	bool idle;
+	const struct wm8958_micd_rate *rates;
+	int num_rates;
+
+	if (wm8994->jack_cb != wm8958_default_micdet)
+		return;
+
+	idle = !wm8994->jack_mic;
+
+	sysclk = snd_soc_read(codec, WM8994_CLOCKING_1);
+	if (sysclk & WM8994_SYSCLK_SRC)
+		sysclk = wm8994->aifclk[1];
+	else
+		sysclk = wm8994->aifclk[0];
+
+	if (wm8994->pdata && wm8994->pdata->micd_rates) {
+		rates = wm8994->pdata->micd_rates;
+		num_rates = wm8994->pdata->num_micd_rates;
+	} else if (wm8994->jackdet) {
+		rates = jackdet_rates;
+		num_rates = ARRAY_SIZE(jackdet_rates);
+	} else {
+		rates = micdet_rates;
+		num_rates = ARRAY_SIZE(micdet_rates);
+	}
+
+	best = 0;
+	for (i = 0; i < num_rates; i++) {
+		if (rates[i].idle != idle)
+			continue;
+		if (abs(rates[i].sysclk - sysclk) <
+		    abs(rates[best].sysclk - sysclk))
+			best = i;
+		else if (rates[best].idle != idle)
+			best = i;
+	}
+
+	val = rates[best].start << WM8958_MICD_BIAS_STARTTIME_SHIFT
+		| rates[best].rate << WM8958_MICD_RATE_SHIFT;
+
+	snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+			    WM8958_MICD_BIAS_STARTTIME_MASK |
+			    WM8958_MICD_RATE_MASK, val);
+}
+
+static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
+{
 	struct wm8994 *control = codec->control_data;
 
 	switch (reg) {
@@ -128,6 +197,8 @@ static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg,
 				reg, ret);
 	}
 
+	dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
+
 	return wm8994_reg_write(codec->control_data, reg, value);
 }
 
@@ -221,8 +292,10 @@ static int configure_clock(struct snd_soc_codec *codec)
 	 */
 
 	/* If they're equal it doesn't matter which is used */
-	if (wm8994->aifclk[0] == wm8994->aifclk[1])
+	if (wm8994->aifclk[0] == wm8994->aifclk[1]) {
+		wm8958_micd_set_rate(codec);
 		return 0;
+	}
 
 	if (wm8994->aifclk[0] < wm8994->aifclk[1])
 		new = WM8994_SYSCLK_SRC;
@@ -588,9 +661,6 @@ SOC_DOUBLE("AIF1ADC2 HPF Switch", WM8994_AIF1_ADC2_FILTERS, 12, 11, 1, 0),
 SOC_ENUM("AIF2ADC HPF Mode", aif2adc_hpf),
 SOC_DOUBLE("AIF2ADC HPF Switch", WM8994_AIF2_ADC_FILTERS, 12, 11, 1, 0),
 
-SOC_ENUM("ADC OSR", adc_osr),
-SOC_ENUM("DAC OSR", dac_osr),
-
 SOC_DOUBLE_R_TLV("DAC1 Volume", WM8994_DAC1_LEFT_VOLUME,
 		 WM8994_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
 SOC_DOUBLE_R("DAC1 Switch", WM8994_DAC1_LEFT_VOLUME,
@@ -613,15 +683,15 @@ SOC_SINGLE_TLV("SPKR DAC1 Volume", WM8994_SPKMIXR_ATTENUATION,
 
 SOC_SINGLE_TLV("AIF1DAC1 3D Stereo Volume", WM8994_AIF1_DAC1_FILTERS_2,
 	       10, 15, 0, wm8994_3d_tlv),
-SOC_SINGLE("AIF1DAC1 3D Stereo Switch", WM8994_AIF1_DAC1_FILTERS_2,
+SOC_SINGLE("AIF1DAC1 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2,
 	   8, 1, 0),
 SOC_SINGLE_TLV("AIF1DAC2 3D Stereo Volume", WM8994_AIF1_DAC2_FILTERS_2,
 	       10, 15, 0, wm8994_3d_tlv),
 SOC_SINGLE("AIF1DAC2 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2,
 	   8, 1, 0),
-SOC_SINGLE_TLV("AIF2DAC 3D Stereo Volume", WM8994_AIF2_DAC_FILTERS_2,
+SOC_SINGLE_TLV("AIF2DAC 3D Stereo Volume", WM8994_AIF1_DAC1_FILTERS_2,
 	       10, 15, 0, wm8994_3d_tlv),
-SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF2_DAC_FILTERS_2,
+SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2,
 	   8, 1, 0),
 };
 
@@ -708,6 +778,74 @@ SOC_SINGLE_TLV("MIXINL IN1RP Boost Volume", WM8994_INPUT_MIXER_1, 8, 1, 0,
 	       mixin_boost_tlv),
 };
 
+/* We run all mode setting through a function to enforce audio mode */
+static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (wm8994->active_refcount)
+		mode = WM1811_JACKDET_MODE_AUDIO;
+
+	snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+			    WM1811_JACKDET_MODE_MASK, mode);
+
+	if (mode == WM1811_JACKDET_MODE_MIC)
+		msleep(2);
+}
+
+static void active_reference(struct snd_soc_codec *codec)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	mutex_lock(&wm8994->accdet_lock);
+
+	wm8994->active_refcount++;
+
+	dev_dbg(codec->dev, "Active refcount incremented, now %d\n",
+		wm8994->active_refcount);
+
+	if (wm8994->active_refcount == 1) {
+		/* If we're using jack detection go into audio mode */
+		if (wm8994->jackdet && wm8994->jack_cb) {
+			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+					    WM1811_JACKDET_MODE_MASK,
+					    WM1811_JACKDET_MODE_AUDIO);
+			msleep(2);
+		}
+	}
+
+	mutex_unlock(&wm8994->accdet_lock);
+}
+
+static void active_dereference(struct snd_soc_codec *codec)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	u16 mode;
+
+	mutex_lock(&wm8994->accdet_lock);
+
+	wm8994->active_refcount--;
+
+	dev_dbg(codec->dev, "Active refcount decremented, now %d\n",
+		wm8994->active_refcount);
+
+	if (wm8994->active_refcount == 0) {
+		/* Go into appropriate detection only mode */
+		if (wm8994->jackdet && wm8994->jack_cb) {
+			if (wm8994->jack_mic || wm8994->mic_detecting)
+				mode = WM1811_JACKDET_MODE_MIC;
+			else
+				mode = WM1811_JACKDET_MODE_JACK;
+
+			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+					    WM1811_JACKDET_MODE_MASK,
+					    mode);
+		}
+	}
+
+	mutex_unlock(&wm8994->accdet_lock);
+}
+
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
@@ -1319,7 +1457,7 @@ SND_SOC_DAPM_DAC_E("DAC1R", NULL, SND_SOC_NOPM, 0, 0,
 
 static const struct snd_soc_dapm_widget wm8994_dac_widgets[] = {
 SND_SOC_DAPM_DAC("DAC2L", NULL, WM8994_POWER_MANAGEMENT_5, 3, 0),
-SND_SOC_DAPM_DAC("DAC2R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0),
+SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0),
 SND_SOC_DAPM_DAC("DAC1L", NULL, WM8994_POWER_MANAGEMENT_5, 1, 0),
 SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0),
 };
@@ -1865,6 +2003,8 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 	if (freq_out) {
 		/* Enable VMID if we need it */
 		if (!was_enabled) {
+			active_reference(codec);
+
 			switch (control->type) {
 			case WM8994:
 				vmid_reference(codec);
@@ -1908,6 +2048,8 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 			default:
 				break;
 			}
+
+			active_dereference(codec);
 		}
 	}
 
@@ -2025,6 +2167,21 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
+		/* MICBIAS into regulating mode */
+		switch (control->type) {
+		case WM8958:
+		case WM1811:
+			snd_soc_update_bits(codec, WM8958_MICBIAS1,
+					    WM8958_MICB1_MODE, 0);
+			snd_soc_update_bits(codec, WM8958_MICBIAS2,
+					    WM8958_MICB2_MODE, 0);
+			break;
+		default:
+			break;
+		}
+
+		if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+			active_reference(codec);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
@@ -2077,7 +2234,23 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
 					    WM8994_LINEOUT2_DISCH);
 		}
 
+		if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE)
+			active_dereference(codec);
 
+		/* MICBIAS into bypass mode on newer devices */
+		switch (control->type) {
+		case WM8958:
+		case WM1811:
+			snd_soc_update_bits(codec, WM8958_MICBIAS1,
+					    WM8958_MICB1_MODE,
+					    WM8958_MICB1_MODE);
+			snd_soc_update_bits(codec, WM8958_MICBIAS2,
+					    WM8958_MICB2_MODE,
+					    WM8958_MICB2_MODE);
+			break;
+		default:
+			break;
+		}
 		break;
 
 	case SND_SOC_BIAS_OFF:
@@ -2089,6 +2262,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	}
 	codec->dapm.bias_level = level;
+
 	return 0;
 }
 
@@ -2236,6 +2410,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994 *control = codec->control_data;
 	int aif1_reg;
 	int aif2_reg;
 	int bclk_reg;
@@ -2277,6 +2452,15 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 			dev_dbg(codec->dev, "AIF2 using split LRCLK\n");
 		}
 		break;
+	case 3:
+		switch (control->type) {
+		case WM1811:
+		case WM8958:
+			aif1_reg = WM8958_AIF3_CONTROL_1;
+			break;
+		default:
+			return 0;
+		}
 	default:
 		return -EINVAL;
 	}
@@ -2346,12 +2530,15 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 	 */
 	best = 0;
 	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
-		cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
+		if (bclk_divs[i] < 0)
+			continue;
+		cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i])
+			- bclk_rate;
 		if (cur_val < 0) /* BCLK table is sorted */
 			break;
 		best = i;
 	}
-	bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best];
+	bclk_rate = wm8994->aifclk[id] / bclk_divs[best];
 	dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
 		bclk_divs[best], bclk_rate);
 	bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT;
@@ -2634,6 +2821,9 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 		snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0);
 		break;
 	case WM1811:
+		snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+				    WM1811_JACKDET_MODE_MASK, 0);
+		/* Fall through */
 	case WM8958:
 		snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
 				    WM8958_MICD_ENA, 0);
@@ -2703,6 +2893,13 @@ static int wm8994_resume(struct snd_soc_codec *codec)
 					    WM8994_MICD_ENA, WM8994_MICD_ENA);
 		break;
 	case WM1811:
+		if (wm8994->jackdet && wm8994->jack_cb) {
+			/* Restart from idle */
+			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+					    WM1811_JACKDET_MODE_MASK,
+					    WM1811_JACKDET_MODE_JACK);
+			break;
+		}
 	case WM8958:
 		if (wm8994->jack_cb)
 			snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
@@ -2923,10 +3120,6 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
 	int reg;
 	int report;
 
-#ifndef CONFIG_SND_SOC_WM8994_MODULE
-	trace_snd_soc_jack_irq(dev_name(codec->dev));
-#endif
-
 	reg = snd_soc_read(codec, WM8994_INTERRUPT_RAW_STATUS_2);
 	if (reg < 0) {
 		dev_err(codec->dev, "Failed to read microphone status: %d\n",
@@ -2962,21 +3155,136 @@ static void wm8958_default_micdet(u16 status, void *data)
 {
 	struct snd_soc_codec *codec = data;
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-	int report = 0;
+	int report;
+
+	dev_dbg(codec->dev, "MICDET %x\n", status);
+
+	/* Either nothing present or just starting detection */
+	if (!(status & WM8958_MICD_STS)) {
+		if (!wm8994->jackdet) {
+			/* If nothing present then clear our statuses */
+			dev_dbg(codec->dev, "Detected open circuit\n");
+			wm8994->jack_mic = false;
+			wm8994->mic_detecting = true;
+
+			wm8958_micd_set_rate(codec);
+
+			snd_soc_jack_report(wm8994->micdet[0].jack, 0,
+					    wm8994->btn_mask |
+					     SND_JACK_HEADSET);
+		}
+		return;
+	}
+
+	/* If the measurement is showing a high impedence we've got a
+	 * microphone.
+	 */
+	if (wm8994->mic_detecting && (status & 0x600)) {
+		dev_dbg(codec->dev, "Detected microphone\n");
+
+		wm8994->mic_detecting = false;
+		wm8994->jack_mic = true;
+
+		wm8958_micd_set_rate(codec);
+
+		snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADSET,
+				    SND_JACK_HEADSET);
+	}
+
+
+	if (wm8994->mic_detecting && status & 0x4) {
+		dev_dbg(codec->dev, "Detected headphone\n");
+		wm8994->mic_detecting = false;
+
+		wm8958_micd_set_rate(codec);
+
+		snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
+				    SND_JACK_HEADSET);
 
-	/* If nothing present then clear our statuses */
-	if (!(status & WM8958_MICD_STS))
-		goto done;
+		/* If we have jackdet that will detect removal */
+		if (wm8994->jackdet) {
+			snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+					    WM8958_MICD_ENA, 0);
+
+			wm1811_jackdet_set_mode(codec,
+						WM1811_JACKDET_MODE_JACK);
+		}
+	}
+
+	/* Report short circuit as a button */
+	if (wm8994->jack_mic) {
+		report = 0;
+		if (status & 0x4)
+			report |= SND_JACK_BTN_0;
+
+		if (status & 0x8)
+			report |= SND_JACK_BTN_1;
+
+		if (status & 0x10)
+			report |= SND_JACK_BTN_2;
+
+		if (status & 0x20)
+			report |= SND_JACK_BTN_3;
+
+		if (status & 0x40)
+			report |= SND_JACK_BTN_4;
+
+		if (status & 0x80)
+			report |= SND_JACK_BTN_5;
+
+		snd_soc_jack_report(wm8994->micdet[0].jack, report,
+				    wm8994->btn_mask);
+	}
+}
+
+static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
+{
+	struct wm8994_priv *wm8994 = data;
+	struct snd_soc_codec *codec = wm8994->codec;
+	int reg;
+
+	mutex_lock(&wm8994->accdet_lock);
+
+	reg = snd_soc_read(codec, WM1811_JACKDET_CTRL);
+	if (reg < 0) {
+		dev_err(codec->dev, "Failed to read jack status: %d\n", reg);
+		mutex_unlock(&wm8994->accdet_lock);
+		return IRQ_NONE;
+	}
+
+	dev_dbg(codec->dev, "JACKDET %x\n", reg);
+
+	if (reg & WM1811_JACKDET_LVL) {
+		dev_dbg(codec->dev, "Jack detected\n");
+
+		snd_soc_jack_report(wm8994->micdet[0].jack,
+				    SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
+
+		/*
+		 * Start off measument of microphone impedence to find
+		 * out what's actually there.
+		 */
+		wm8994->mic_detecting = true;
+		wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC);
+		snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+				    WM8958_MICD_ENA, WM8958_MICD_ENA);
+	} else {
+		dev_dbg(codec->dev, "Jack not detected\n");
 
-	report = SND_JACK_MICROPHONE;
+		snd_soc_jack_report(wm8994->micdet[0].jack, 0,
+				    SND_JACK_MECHANICAL | SND_JACK_HEADSET |
+				    wm8994->btn_mask);
 
-	/* Everything else is buttons; just assign slots */
-	if (status & 0x1c)
-		report |= SND_JACK_BTN_0;
+		wm8994->mic_detecting = false;
+		wm8994->jack_mic = false;
+		snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+				    WM8958_MICD_ENA, 0);
+		wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK);
+	}
+
+	mutex_unlock(&wm8994->accdet_lock);
 
-done:
-	snd_soc_jack_report(wm8994->micdet[0].jack, report,
-			    SND_JACK_BTN_0 | SND_JACK_MICROPHONE);
+	return IRQ_HANDLED;
 }
 
 /**
@@ -3000,6 +3308,7 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 {
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 	struct wm8994 *control = codec->control_data;
+	u16 micd_lvl_sel;
 
 	switch (control->type) {
 	case WM1811:
@@ -3016,15 +3325,50 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 			cb_data = codec;
 		}
 
+		snd_soc_dapm_force_enable_pin(&codec->dapm, "CLK_SYS");
+
 		wm8994->micdet[0].jack = jack;
 		wm8994->jack_cb = cb;
 		wm8994->jack_cb_data = cb_data;
 
-		snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
-				    WM8958_MICD_ENA, WM8958_MICD_ENA);
+		wm8994->mic_detecting = true;
+		wm8994->jack_mic = false;
+
+		wm8958_micd_set_rate(codec);
+
+		/* Detect microphones and short circuits by default */
+		if (wm8994->pdata->micd_lvl_sel)
+			micd_lvl_sel = wm8994->pdata->micd_lvl_sel;
+		else
+			micd_lvl_sel = 0x41;
+
+		wm8994->btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+			SND_JACK_BTN_4 | SND_JACK_BTN_5;
+
+		snd_soc_update_bits(codec, WM8958_MIC_DETECT_2,
+				    WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel);
+
+		WARN_ON(codec->dapm.bias_level > SND_SOC_BIAS_STANDBY);
+
+		/*
+		 * If we can use jack detection start off with that,
+		 * otherwise jump straight to microphone detection.
+		 */
+		if (wm8994->jackdet) {
+			snd_soc_update_bits(codec, WM8994_LDO_1,
+					    WM8994_LDO1_DISCH, 0);
+			wm1811_jackdet_set_mode(codec,
+						WM1811_JACKDET_MODE_JACK);
+		} else {
+			snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+					    WM8958_MICD_ENA, WM8958_MICD_ENA);
+		}
+
 	} else {
 		snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
 				    WM8958_MICD_ENA, 0);
+		snd_soc_dapm_disable_pin(&codec->dapm, "CLK_SYS");
 	}
 
 	return 0;
@@ -3037,6 +3381,8 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
 	struct snd_soc_codec *codec = wm8994->codec;
 	int reg, count;
 
+	mutex_lock(&wm8994->accdet_lock);
+
 	/* We may occasionally read a detection without an impedence
 	 * range being provided - if that happens loop again.
 	 */
@@ -3064,9 +3410,33 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
 	if (count == 0)
 		dev_warn(codec->dev, "No impedence range reported for jack\n");
 
-#ifndef CONFIG_SND_SOC_WM8994_MODULE
-	trace_snd_soc_jack_irq(dev_name(codec->dev));
-#endif
+	/* We may occasionally read a detection without an impedence
+	 * range being provided - if that happens loop again.
+	 */
+	count = 10;
+	do {
+		reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
+		if (reg < 0) {
+			mutex_unlock(&wm8994->accdet_lock);
+			dev_err(codec->dev,
+				"Failed to read mic detect status: %d\n",
+				reg);
+			return IRQ_NONE;
+		}
+
+		if (!(reg & WM8958_MICD_VALID)) {
+			dev_dbg(codec->dev, "Mic detect data not valid\n");
+			goto out;
+		}
+
+		if (!(reg & WM8958_MICD_STS) || (reg & WM8958_MICD_LVL_MASK))
+			break;
+
+		msleep(1);
+	} while (count--);
+
+	if (count == 0)
+		dev_warn(codec->dev, "No impedence range reported for jack\n");
 
 	if (wm8994->jack_cb)
 		wm8994->jack_cb(reg, wm8994->jack_cb_data);
@@ -3074,6 +3444,8 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
 		dev_warn(codec->dev, "Accessory detection with no callback\n");
 
 out:
+	mutex_unlock(&wm8994->accdet_lock);
+
 	return IRQ_HANDLED;
 }
 
@@ -3106,9 +3478,9 @@ static irqreturn_t wm8994_temp_shut(int irq, void *data)
 
 static int wm8994_codec_probe(struct snd_soc_codec *codec)
 {
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	struct wm8994 *control;
 	struct wm8994_priv *wm8994;
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret, i;
 
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
@@ -3122,6 +3494,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	wm8994->pdata = dev_get_platdata(codec->dev->parent);
 	wm8994->codec = codec;
 
+	mutex_init(&wm8994->accdet_lock);
+
 	for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
 		init_completion(&wm8994->fll_locked[i]);
 
@@ -3270,6 +3644,21 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		}
 	}
 
+	switch (control->type) {
+	case WM1811:
+		if (wm8994->revision > 1) {
+			ret = wm8994_request_irq(codec->control_data,
+						 WM8994_IRQ_GPIO(6),
+						 wm1811_jackdet_irq, "JACKDET",
+						 wm8994);
+			if (ret == 0)
+				wm8994->jackdet = true;
+		}
+		break;
+	default:
+		break;
+	}
+
 	wm8994->fll_locked_irq = true;
 	for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) {
 		ret = wm8994_request_irq(codec->control_data,
@@ -3368,6 +3757,19 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		break;
 	}
 
+	/* Put MICBIAS into bypass mode by default on newer devices */
+	switch (control->type) {
+	case WM8958:
+	case WM1811:
+		snd_soc_update_bits(codec, WM8958_MICBIAS1,
+				    WM8958_MICB1_MODE, WM8958_MICB1_MODE);
+		snd_soc_update_bits(codec, WM8958_MICBIAS2,
+				    WM8958_MICB2_MODE, WM8958_MICB2_MODE);
+		break;
+	default:
+		break;
+	}
+
 	wm8994_update_class_w(codec);
 
 	wm8994_handle_pdata(wm8994);
@@ -3375,26 +3777,26 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	wm_hubs_add_analogue_controls(codec);
 	snd_soc_add_controls(codec, wm8994_snd_controls,
 			     ARRAY_SIZE(wm8994_snd_controls));
-	snd_soc_dapm_new_controls(dapm, wm8994_dapm_widgets,
+	snd_soc_dapm_new_controls(&codec->dapm, wm8994_dapm_widgets,
 				  ARRAY_SIZE(wm8994_dapm_widgets));
 
 	switch (control->type) {
 	case WM8994:
-		snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
+		snd_soc_dapm_new_controls(&codec->dapm, wm8994_specific_dapm_widgets,
 					  ARRAY_SIZE(wm8994_specific_dapm_widgets));
 		if (wm8994->revision < 4) {
-			snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
+			snd_soc_dapm_new_controls(&codec->dapm, wm8994_lateclk_revd_widgets,
 						  ARRAY_SIZE(wm8994_lateclk_revd_widgets));
-			snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
+			snd_soc_dapm_new_controls(&codec->dapm, wm8994_adc_revd_widgets,
 						  ARRAY_SIZE(wm8994_adc_revd_widgets));
-			snd_soc_dapm_new_controls(dapm, wm8994_dac_revd_widgets,
+			snd_soc_dapm_new_controls(&codec->dapm, wm8994_dac_revd_widgets,
 						  ARRAY_SIZE(wm8994_dac_revd_widgets));
 		} else {
-			snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
+			snd_soc_dapm_new_controls(&codec->dapm, wm8994_lateclk_widgets,
 						  ARRAY_SIZE(wm8994_lateclk_widgets));
-			snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
+			snd_soc_dapm_new_controls(&codec->dapm, wm8994_adc_widgets,
 						  ARRAY_SIZE(wm8994_adc_widgets));
-			snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
+			snd_soc_dapm_new_controls(&codec->dapm, wm8994_dac_widgets,
 						  ARRAY_SIZE(wm8994_dac_widgets));
 		}
 		break;
@@ -3436,20 +3838,20 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		
 
 	wm_hubs_add_analogue_routes(codec, 0, 0);
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+	snd_soc_dapm_add_routes(&codec->dapm, intercon, ARRAY_SIZE(intercon));
 
 	switch (control->type) {
 	case WM8994:
-		snd_soc_dapm_add_routes(dapm, wm8994_intercon,
+		snd_soc_dapm_add_routes(&codec->dapm, wm8994_intercon,
 					ARRAY_SIZE(wm8994_intercon));
 
 		if (wm8994->revision < 4) {
-			snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
+			snd_soc_dapm_add_routes(&codec->dapm, wm8994_revd_intercon,
 						ARRAY_SIZE(wm8994_revd_intercon));
-			snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
+			snd_soc_dapm_add_routes(&codec->dapm, wm8994_lateclk_revd_intercon,
 						ARRAY_SIZE(wm8994_lateclk_revd_intercon));
 		} else {
-			snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
+			snd_soc_dapm_add_routes(&codec->dapm, wm8994_lateclk_intercon,
 						ARRAY_SIZE(wm8994_lateclk_intercon));
 		}
 		break;
@@ -3479,6 +3881,9 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 
 err_irq:
+	if (wm8994->jackdet)
+		wm8994_free_irq(wm8994->control_data, WM8994_IRQ_GPIO(6),
+				wm8994);
 	wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
 	wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
 	wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
@@ -3517,6 +3922,10 @@ static int  wm8994_codec_remove(struct snd_soc_codec *codec)
 	wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_SHUT, codec);
 	wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_WARN, codec);
 
+	if (wm8994->jackdet)
+		wm8994_free_irq(wm8994->control_data, WM8994_IRQ_GPIO(6),
+				wm8994);
+
 	switch (control->type) {
 	case WM8994:
 		if (wm8994->micdet_irq)
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index f4f1355..8ad1e90 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -84,6 +84,7 @@ struct wm8994_priv {
 	bool fll_locked_irq;
 
 	int vmid_refcount;
+	int active_refcount;
 
 	int dac_rates[2];
 	int lrclk_shared[2];
@@ -125,7 +126,12 @@ struct wm8994_priv {
 	const char **enh_eq_texts;
 	struct soc_enum enh_eq_enum;
 
+	struct mutex accdet_lock;
 	struct wm8994_micdet micdet[2];
+	bool mic_detecting;
+	bool jack_mic;
+	int btn_mask;
+	bool jackdet;
 
 	wm8958_micdet_cb jack_cb;
 	void *jack_cb_data;
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index a33b04d..aba2e14 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -1920,7 +1920,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
 	snd_soc_update_bits(codec, lrclk_reg, WM8996_AIF1RX_RATE_MASK,
 			    lrclk);
 	snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_2,
-			    WM8996_DSP1_DIV_MASK << dsp_shift, dsp);
+			    WM8996_DSP1_DIV_SHIFT << dsp_shift, dsp);
 
 	return 0;
 }
@@ -2502,8 +2502,10 @@ static void wm8996_micd(struct snd_soc_codec *codec)
 				    SND_JACK_BTN_0);
 
 		snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
-				    WM8996_MICD_RATE_MASK,
-				    WM8996_MICD_RATE_MASK);
+				    WM8996_MICD_RATE_MASK |
+				    WM8996_MICD_BIAS_STARTTIME_MASK,
+				    WM8996_MICD_RATE_MASK |
+				    9 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
 		return;
 	}
 
@@ -2520,8 +2522,10 @@ static void wm8996_micd(struct snd_soc_codec *codec)
 			/* Increase poll rate to give better responsiveness
 			 * for buttons */
 			snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
-					    WM8996_MICD_RATE_MASK,
-					    5 << WM8996_MICD_RATE_SHIFT);
+					    WM8996_MICD_RATE_MASK |
+					    WM8996_MICD_BIAS_STARTTIME_MASK,
+					    5 << WM8996_MICD_RATE_SHIFT |
+					    7 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
 		} else {
 			dev_dbg(codec->dev, "Mic button up\n");
 			snd_soc_jack_report(wm8996->jack, 0, SND_JACK_BTN_0);
@@ -2569,8 +2573,10 @@ static void wm8996_micd(struct snd_soc_codec *codec)
 			 * responsiveness.
 			 */
 			snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
-					    WM8996_MICD_RATE_MASK,
-					    7 << WM8996_MICD_RATE_SHIFT);
+					    WM8996_MICD_RATE_MASK |
+					    WM8996_MICD_BIAS_STARTTIME_MASK,
+					    7 << WM8996_MICD_RATE_SHIFT |
+					    7 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
 		}
 	}
 }
@@ -2707,6 +2713,7 @@ static int wm8996_probe(struct snd_soc_codec *codec)
 	init_completion(&wm8996->fll_lock);
 
 	dapm->idle_bias_off = true;
+	dapm->bias_level = SND_SOC_BIAS_OFF;
 
 	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
 	if (ret != 0) {
@@ -3145,7 +3152,7 @@ static __devexit int wm8996_i2c_remove(struct i2c_client *client)
 	snd_soc_unregister_codec(&client->dev);
 	if (wm8996->pdata.ldo_ena > 0)
 		gpio_free(wm8996->pdata.ldo_ena);
-	kfree(i2c_get_clientdata(client));
+	kfree(wm8996);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 4a398c3..e3c1bc4 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -737,6 +737,7 @@ SND_SOC_DAPM_SUPPLY("CLK_SYS", WM9081_CLOCK_CONTROL_3, 0, 0, clk_sys_event,
 		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("CLK_DSP", WM9081_CLOCK_CONTROL_3, 1, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("TOCLK", WM9081_CLOCK_CONTROL_3, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TSENSE", WM9081_POWER_MANAGEMENT, 7, 0, NULL, 0),
 };
 
 
@@ -759,6 +760,7 @@ static const struct snd_soc_dapm_route wm9081_audio_paths[] = {
 	{ "Speaker PGA", NULL, "CLK_SYS" },
 
 	{ "Speaker", NULL, "Speaker PGA" },
+	{ "Speaker", NULL, "TSENSE" },
 
 	{ "SPKN", NULL, "Speaker" },
 	{ "SPKP", NULL, "Speaker" },
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 48e61e9..0d0de6d 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -178,6 +178,29 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
 
 	dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
 
+	/* Different chips in the family support different readback
+	 * methods.
+	 */
+	switch (hubs->dcs_readback_mode) {
+	case 0:
+		reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
+			& WM8993_DCS_INTEG_CHAN_0_MASK;;
+		reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
+			& WM8993_DCS_INTEG_CHAN_1_MASK;
+		break;
+	case 1:
+		reg = snd_soc_read(codec, dcs_reg);
+		reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
+			>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+		reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
+		break;
+	default:
+		WARN(1, "Unknown DCS readback method");
+		break;
+	}
+
+	dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
+
 	/* Apply correction to DC servo result */
 	if (hubs->dcs_codes_l || hubs->dcs_codes_r) {
 		dev_dbg(codec->dev,
@@ -587,14 +610,14 @@ SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
 };
 
 static const struct snd_kcontrol_new line2_mix[] = {
-SOC_DAPM_SINGLE("IN2R Switch", WM8993_LINE_MIXER2, 2, 1, 0),
-SOC_DAPM_SINGLE("IN2L Switch", WM8993_LINE_MIXER2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 1, 1, 0),
 SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
 };
 
 static const struct snd_kcontrol_new line2n_mix[] = {
-SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 6, 1, 0),
-SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 5, 1, 0),
+SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 5, 1, 0),
+SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 6, 1, 0),
 };
 
 static const struct snd_kcontrol_new line2p_mix[] = {
@@ -614,6 +637,8 @@ SND_SOC_DAPM_INPUT("IN2RP:VXRP"),
 SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0),
 SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0),
 
+SND_SOC_DAPM_SUPPLY("LINEOUT_VMID_BUF", WM8993_ANTIPOP1, 7, 0, NULL, 0),
+
 SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
 		   in1l_pga, ARRAY_SIZE(in1l_pga)),
 SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0,
@@ -654,6 +679,7 @@ SND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0,
 SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0,
 		   right_speaker_boost, ARRAY_SIZE(right_speaker_boost)),
 
+SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0),
 SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
 		 NULL, 0),
 SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
@@ -789,10 +815,12 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
 	{ "SPKL Driver", NULL, "VMID" },
 	{ "SPKL Driver", NULL, "SPKL Boost" },
 	{ "SPKL Driver", NULL, "CLK_SYS" },
+	{ "SPKL Driver", NULL, "TSHUT" },
 
 	{ "SPKR Driver", NULL, "VMID" },
 	{ "SPKR Driver", NULL, "SPKR Boost" },
 	{ "SPKR Driver", NULL, "CLK_SYS" },
+	{ "SPKR Driver", NULL, "TSHUT" },
 
 	{ "SPKOUTLP", NULL, "SPKL Driver" },
 	{ "SPKOUTLN", NULL, "SPKL Driver" },
@@ -832,9 +860,11 @@ static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
 };
 
 static const struct snd_soc_dapm_route lineout1_se_routes[] = {
+	{ "LINEOUT1N Mixer", NULL, "LINEOUT_VMID_BUF" },
 	{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" },
 	{ "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" },
 
+	{ "LINEOUT1P Mixer", NULL, "LINEOUT_VMID_BUF" },
 	{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" },
 
 	{ "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
@@ -842,8 +872,8 @@ static const struct snd_soc_dapm_route lineout1_se_routes[] = {
 };
 
 static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
-	{ "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" },
-	{ "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" },
+	{ "LINEOUT2 Mixer", "IN1L Switch", "IN1L PGA" },
+	{ "LINEOUT2 Mixer", "IN1R Switch", "IN1R PGA" },
 	{ "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" },
 
 	{ "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
@@ -851,9 +881,11 @@ static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
 };
 
 static const struct snd_soc_dapm_route lineout2_se_routes[] = {
+	{ "LINEOUT2N Mixer", NULL, "LINEOUT_VMID_BUF" },
 	{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" },
 	{ "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" },
 
+	{ "LINEOUT2P Mixer", NULL, "LINEOUT_VMID_BUF" },
 	{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" },
 
 	{ "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
diff --git a/sound/soc/imx/imx-ac97.c b/sound/soc/imx/imx-ac97.c
new file mode 100644
index 0000000..2587180
--- /dev/null
+++ b/sound/soc/imx/imx-ac97.c
@@ -0,0 +1,222 @@
+/*
+ * imx-ssi.c  --  SSI driver for Freescale IMX
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  Based on mxc-alsa-mc13783 (C) 2006 Freescale.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    29th Aug 2006   Initial version.
+ *
+ */
+
+
+static imx_pcm_dma_params_t imx_ssi1_pcm_stereo_out = {
+	.name			= "SSI1 PCM Stereo out",
+	.params = {
+		.bd_number = 1,
+		.transfer_type = emi_2_per,
+		.watermark_level = SDMA_TXFIFO_WATERMARK,
+		.word_size = TRANSFER_16BIT, // maybe add this in setup func
+		.per_address = SSI1_STX0,
+		.event_id = DMA_REQ_SSI1_TX1,
+		.peripheral_type = SSI,
+	},
+};
+
+static imx_pcm_dma_params_t imx_ssi1_pcm_stereo_in = {
+	.name			= "SSI1 PCM Stereo in",
+	.params = {
+		.bd_number = 1,
+		.transfer_type = per_2_emi,
+		.watermark_level = SDMA_RXFIFO_WATERMARK,
+		.word_size = TRANSFER_16BIT, // maybe add this in setup func
+		.per_address = SSI1_SRX0,
+		.event_id = DMA_REQ_SSI1_RX1,
+		.peripheral_type = SSI,
+	},
+};
+
+static imx_pcm_dma_params_t imx_ssi2_pcm_stereo_out = {
+	.name			= "SSI2 PCM Stereo out",
+	.params = {
+		.bd_number = 1,
+		.transfer_type = per_2_emi,
+		.watermark_level = SDMA_TXFIFO_WATERMARK,
+		.word_size = TRANSFER_16BIT, // maybe add this in setup func
+		.per_address = SSI2_STX0,
+		.event_id = DMA_REQ_SSI2_TX1,
+		.peripheral_type = SSI,
+	},
+};
+
+static imx_pcm_dma_params_t imx_ssi2_pcm_stereo_in = {
+	.name			= "SSI2 PCM Stereo in",
+	.params = {
+		.bd_number = 1,
+		.transfer_type = per_2_emi,
+		.watermark_level = SDMA_RXFIFO_WATERMARK,
+		.word_size = TRANSFER_16BIT, // maybe add this in setup func
+		.per_address = SSI2_SRX0,
+		.event_id = DMA_REQ_SSI2_RX1,
+		.peripheral_type = SSI,
+	},
+};
+
+static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
+{
+}
+
+static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
+{
+}
+
+static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+}
+
+static void imx_ssi_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+	.read	= imx_ssi_ac97_read,
+	.write	= imx_ssi_ac97_write,
+	.warm_reset	= imx_ssi_ac97_warm_reset,
+	.reset	= imx_ssi_ac97_cold_reset,
+};
+
+
+static intimx_ssi1_ac97_probe(struct platform_device *pdev)
+{
+	int ret;
+
+
+	return ret;
+}
+
+static void imx_ssi1_ac97_remove(struct platform_device *pdev)
+{
+	/* shutdown SSI */
+		if(rtd->cpu_dai->id == 0)
+			SSI1_SCR &= ~SSI_SCR_SSIEN;
+		else
+			SSI2_SCR &= ~SSI_SCR_SSIEN;
+	}
+
+}
+
+static int imx_ssi1_ac97_prepare(struct snd_pcm_substream *substream)
+{
+	// set vra
+}
+
+static int imx_ssi_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	if (!rtd->cpu_dai->active) {
+
+	}
+
+	return 0;
+}
+
+static int imx_ssi1_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+
+	return ret;
+}
+
+static void imx_ssi_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+
+}
+
+#ifdef CONFIG_PM
+static int imx_ssi_suspend(struct platform_device *dev,
+	struct snd_soc_cpu_dai *dai)
+{
+	if(!dai->active)
+		return 0;
+
+
+	return 0;
+}
+
+static int imx_ssi_resume(struct platform_device *pdev,
+	struct snd_soc_cpu_dai *dai)
+{
+	if(!dai->active)
+		return 0;
+
+	return 0;
+}
+
+#else
+#define imx_ssi_suspend	NULL
+#define imx_ssi_resume	NULL
+#endif
+
+#define IMX_AC97_RATES \
+	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+	SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+	SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+	SNDRV_PCM_RATE_48000)
+
+struct snd_soc_cpu_dai imx_ssi_ac97_dai = {
+	.name = "imx-ac97-1",
+	.id = 0,
+	.type = SND_SOC_DAI_AC97,
+	.suspend = imx_ssi_suspend,
+	.resume = imx_ssi_resume,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = IMX_AC97_RATES,},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = IMX_AC97_RATES,},
+	.ops = {
+		.probe = imx_ac97_probe,
+		.remove = imx_ac97_shutdown,
+		.trigger = imx_ssi_trigger,
+		.prepare = imx_ssi_ac97_prepare,},
+},
+{
+	.name = "imx-ac97-2",
+	.id = 1,
+	.type = SND_SOC_DAI_AC97,
+	.suspend = imx_ssi_suspend,
+	.resume = imx_ssi_resume,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = IMX_AC97_RATES,},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = IMX_AC97_RATES,},
+	.ops = {
+		.probe = imx_ac97_probe,
+		.remove = imx_ac97_shutdown,
+		.trigger = imx_ssi_trigger,
+		.prepare = imx_ssi_ac97_prepare,},
+};
+
+EXPORT_SYMBOL_GPL(imx_ssi_ac97_dai);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("i.MX ASoC AC97 driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/imx21-pcm.c b/sound/soc/imx/imx21-pcm.c
new file mode 100644
index 0000000..de6de85
--- /dev/null
+++ b/sound/soc/imx/imx21-pcm.c
@@ -0,0 +1,454 @@
+/*
+ * linux/sound/arm/mxc-pcm.c -- ALSA SoC interface for the Freescale i.MX CPU's
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * Based on pxa2xx-pcm.c by	Nicolas Pitre, (C) 2004 MontaVista Software, Inc.
+ * and on mxc-alsa-mc13783 (C) 2006 Freescale.
+ *
+ * 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.
+ *
+ *  Revision history
+ *    29th Aug 2006   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <asm/dma.h>
+#include <asm/hardware.h>
+
+#include "imx-pcm.h"
+
+/* debug */
+#define IMX_DEBUG 0
+#if IMX_DEBUG
+#define dbg(format, arg...) printk(format, ## arg)
+#else
+#define dbg(format, arg...)
+#endif
+
+static const struct snd_pcm_hardware mxc_pcm_hardware = {
+	.info			= (SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				   SNDRV_PCM_INFO_MMAP |
+				   SNDRV_PCM_INFO_MMAP_VALID |
+				   SNDRV_PCM_INFO_PAUSE |
+				   SNDRV_PCM_INFO_RESUME),
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
+					SNDRV_PCM_FMTBIT_S24_LE,
+	.buffer_bytes_max	= 32 * 1024,
+	.period_bytes_min	= 64,
+	.period_bytes_max	= 8 * 1024,
+	.periods_min		= 2,
+	.periods_max		= 255,
+	.fifo_size		= 0,
+};
+
+struct mxc_runtime_data {
+	int dma_ch;
+	struct mxc_pcm_dma_param *dma_params;
+};
+
+/*!
+  * This function stops the current dma transfert for playback
+  * and clears the dma pointers.
+  *
+  * @param	substream	pointer to the structure of the current stream.
+  *
+  */
+static void audio_stop_dma(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxc_runtime_data *prtd = runtime->private_data;
+	unsigned int dma_size = frames_to_bytes(runtime, runtime->period_size);
+	unsigned int offset  dma_size * s->periods;
+	unsigned long flags;
+
+	spin_lock_irqsave(&prtd->dma_lock, flags);
+
+	dbg("MXC : audio_stop_dma active = 0\n");
+	prtd->active = 0;
+	prtd->period = 0;
+	prtd->periods = 0;
+
+	/* this stops the dma channel and clears the buffer ptrs */
+	mxc_dma_stop(prtd->dma_wchannel);
+	if(substream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_unmap_single(NULL, runtime->dma_addr + offset, dma_size,
+							DMA_TO_DEVICE);
+	else
+		dma_unmap_single(NULL, runtime->dma_addr + offset, dma_size,
+							DMA_FROM_DEVICE);
+
+	spin_unlock_irqrestore(&prtd->dma_lock, flags);
+}
+
+/*!
+  * This function is called whenever a new audio block needs to be
+  * transferred to mc13783. The function receives the address and the size
+  * of the new block and start a new DMA transfer.
+  *
+  * @param	substream	pointer to the structure of the current stream.
+  *
+  */
+static int dma_new_period(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime =  substream->runtime;
+	struct mxc_runtime_data *prtd = runtime->private_data;
+	unsigned int dma_size;
+	unsigned int offset;
+	int ret=0;
+	dma_request_t sdma_request;
+
+	if (prtd->active){
+		memset(&sdma_request, 0, sizeof(dma_request_t));
+		dma_size = frames_to_bytes(runtime, runtime->period_size);
+	    dbg("s->period (%x) runtime->periods (%d)\n",
+			s->period,runtime->periods);
+		dbg("runtime->period_size (%d) dma_size (%d)\n",
+			(unsigned int)runtime->period_size,
+			runtime->dma_bytes);
+
+       	offset = dma_size * prtd->period;
+		snd_assert(dma_size <= DMA_BUF_SIZE, );
+		if(substream == SNDRV_PCM_STREAM_PLAYBACK)
+			sdma_request.sourceAddr = (char*)(dma_map_single(NULL,
+				runtime->dma_area + offset, dma_size, DMA_TO_DEVICE));
+		else
+			sdma_request.destAddr = (char*)(dma_map_single(NULL,
+				runtime->dma_area + offset, dma_size, DMA_FROM_DEVICE));
+		sdma_request.count = dma_size;
+
+		dbg("MXC: Start DMA offset (%d) size (%d)\n", offset,
+						 runtime->dma_bytes);
+
+       	mxc_dma_set_config(prtd->dma_wchannel, &sdma_request, 0);
+		if((ret = mxc_dma_start(prtd->dma_wchannel)) < 0) {
+			dbg("audio_process_dma: cannot queue DMA buffer\
+							(%i)\n", ret);
+			return err;
+		}
+		prtd->tx_spin = 1; /* FGA little trick to retrieve DMA pos */
+		prtd->period++;
+		prtd->period %= runtime->periods;
+    }
+	return ret;
+}
+
+
+/*!
+  * This is a callback which will be called
+  * when a TX transfer finishes. The call occurs
+  * in interrupt context.
+  *
+  * @param	dat	pointer to the structure of the current stream.
+  *
+  */
+static void audio_dma_irq(void *data)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_pcm_runtime *runtime;
+	struct mxc_runtime_data *prtd;
+	unsigned int dma_size;
+	unsigned int previous_period;
+	unsigned int offset;
+
+	substream = data;
+	runtime = substream->runtime;
+	prtd = runtime->private_data;
+	previous_period  = prtd->periods;
+	dma_size = frames_to_bytes(runtime, runtime->period_size);
+	offset = dma_size * previous_period;
+
+	prtd->tx_spin = 0;
+	prtd->periods++;
+	prtd->periods %= runtime->periods;
+
+	/*
+	  * Give back to the CPU the access to the non cached memory
+	  */
+	if(substream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_unmap_single(NULL, runtime->dma_addr + offset, dma_size,
+							DMA_TO_DEVICE);
+	else
+		dma_unmap_single(NULL, runtime->dma_addr + offset, dma_size,
+							DMA_FROM_DEVICE);
+	/*
+	  * If we are getting a callback for an active stream then we inform
+	  * the PCM middle layer we've finished a period
+	  */
+ 	if (prtd->active)
+		snd_pcm_period_elapsed(substream);
+
+	/*
+	  * Trig next DMA transfer
+	  */
+	dma_new_period(substream);
+}
+
+/*!
+  * This function configures the hardware to allow audio
+  * playback operations. It is called by ALSA framework.
+  *
+  * @param	substream	pointer to the structure of the current stream.
+  *
+  * @return              0 on success, -1 otherwise.
+  */
+static int
+snd_mxc_prepare(struct snd_pcm_substream *substream)
+{
+	struct mxc_runtime_data *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	int ret = 0;
+	prtd->period = 0;
+	prtd->periods = 0;
+
+	dma_channel_params params;
+	int channel = 0; // passed in ?
+
+	if ((ret  = mxc_request_dma(&channel, "ALSA TX SDMA") < 0)){
+		dbg("error requesting a write dma channel\n");
+		return ret;
+	}
+
+	/* configure DMA params */
+	memset(&params, 0, sizeof(dma_channel_params));
+	params.bd_number = 1;
+	params.arg = s;
+	params.callback = callback;
+	params.transfer_type = emi_2_per;
+	params.watermark_level = SDMA_TXFIFO_WATERMARK;
+	params.word_size = TRANSFER_16BIT;
+	//dbg(KERN_ERR "activating connection SSI1 - SDMA\n");
+	params.per_address = SSI1_BASE_ADDR;
+	params.event_id = DMA_REQ_SSI1_TX1;
+	params.peripheral_type = SSI;
+
+	/* set up chn with params */
+	mxc_dma_setup_channel(channel, &params);
+	s->dma_wchannel = channel;
+
+	return ret;
+}
+
+static int mxc_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret;
+
+	if((ret=snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+		return ret;
+	runtime->dma_addr = virt_to_phys(runtime->dma_area);
+
+	return ret;
+}
+
+static int mxc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int mxc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct mxc_runtime_data *prtd = substream->runtime->private_data;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		prtd->tx_spin = 0;
+		/* requested stream startup */
+		prtd->active = 1;
+        ret = dma_new_period(substream);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		/* requested stream shutdown */
+		ret = audio_stop_dma(substream);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		prtd->active = 0;
+		prtd->periods = 0;
+		break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+		prtd->active = 1;
+		prtd->tx_spin = 0;
+		ret = dma_new_period(substream);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		prtd->active = 0;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		prtd->active = 1;
+		if (prtd->old_offset) {
+			prtd->tx_spin = 0;
+            ret = dma_new_period(substream);
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t mxc_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxc_runtime_data *prtd = runtime->private_data;
+	unsigned int offset = 0;
+
+	/* tx_spin value is used here to check if a transfert is active */
+	if (prtd->tx_spin){
+		offset = (runtime->period_size * (prtd->periods)) +
+						(runtime->period_size >> 1);
+		if (offset >= runtime->buffer_size)
+			offset = runtime->period_size >> 1;
+	} else {
+		offset = (runtime->period_size * (s->periods));
+		if (offset >= runtime->buffer_size)
+			offset = 0;
+	}
+
+	return offset;
+}
+
+
+static int mxc_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxc_runtime_data *prtd;
+	int ret;
+
+	snd_soc_set_runtime_hwparams(substream, &mxc_pcm_hardware);
+
+	if ((err = snd_pcm_hw_constraint_integer(runtime,
+					SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+		return err;
+	if ((err = snd_pcm_hw_constraint_list(runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE, &hw_playback_rates)) < 0)
+		return err;
+	msleep(10); // liam - why
+
+	/* setup DMA controller for playback */
+	if((err = configure_write_channel(&mxc_mc13783->s[SNDRV_PCM_STREAM_PLAYBACK],
+					audio_dma_irq)) < 0 )
+		return err;
+
+	if((prtd = kzalloc(sizeof(struct mxc_runtime_data), GFP_KERNEL)) == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	runtime->private_data = prtd;
+	return 0;
+
+ err1:
+	kfree(prtd);
+ out:
+	return ret;
+}
+
+static int mxc_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxc_runtime_data *prtd = runtime->private_data;
+
+//	mxc_mc13783_t *chip;
+	audio_stream_t *s;
+	device_data_t* device;
+	int ssi;
+
+	//chip = snd_pcm_substream_chip(substream);
+	s = &chip->s[substream->pstr->stream];
+	device = &s->stream_device;
+	ssi = device->ssi;
+
+	//disable_stereodac();
+
+	ssi_transmit_enable(ssi, false);
+	ssi_interrupt_disable(ssi, ssi_tx_dma_interrupt_enable);
+	ssi_tx_fifo_enable(ssi, ssi_fifo_0, false);
+	ssi_enable(ssi, false);
+
+	chip->s[substream->pstr->stream].stream = NULL;
+
+	return 0;
+}
+
+static int
+mxc_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+}
+
+struct snd_pcm_ops mxc_pcm_ops = {
+	.open		= mxc_pcm_open,
+	.close		= mxc_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= mxc_pcm_hw_params,
+	.hw_free	= mxc_pcm_hw_free,
+	.prepare	= mxc_pcm_prepare,
+	.trigger	= mxc_pcm_trigger,
+	.pointer	= mxc_pcm_pointer,
+	.mmap		= mxc_pcm_mmap,
+};
+
+static u64 mxc_pcm_dmamask = 0xffffffff;
+
+int mxc_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
+	struct snd_pcm *pcm)
+{
+	int ret = 0;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &mxc_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (dai->playback.channels_min) {
+		ret = mxc_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			goto out;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = mxc_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			goto out;
+	}
+ out:
+	return ret;
+}
+
+struct snd_soc_platform mxc_soc_platform = {
+	.name		= "mxc-audio",
+	.pcm_ops 	= &mxc_pcm_ops,
+	.pcm_new	= mxc_pcm_new,
+	.pcm_free	= mxc_pcm_free_dma_buffers,
+};
+
+EXPORT_SYMBOL_GPL(mxc_soc_platform);
+
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_DESCRIPTION("Freescale i.MX PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/imx21-pcm.h b/sound/soc/imx/imx21-pcm.h
new file mode 100644
index 0000000..990ae6a
--- /dev/null
+++ b/sound/soc/imx/imx21-pcm.h
@@ -0,0 +1,237 @@
+/*
+ * mxc-pcm.h :- ASoC platform header for Freescale i.MX
+ *
+ * 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 _MXC_PCM_H
+#define _MXC_PCM_H
+
+struct {
+	char *name;			/* stream identifier */
+	dma_channel_params dma_params;
+} mxc_pcm_dma_param;
+
+extern struct snd_soc_cpu_dai mxc_ssi_dai[3];
+
+/* platform data */
+extern struct snd_soc_platform mxc_soc_platform;
+extern struct snd_ac97_bus_ops mxc_ac97_ops;
+
+/* temp until imx-regs.h is up2date */
+#define SSI1_STX0   __REG(IMX_SSI1_BASE + 0x00)
+#define SSI1_STX0_PHYS   __PHYS_REG(IMX_SSI1_BASE + 0x00)
+#define SSI1_STX1   __REG(IMX_SSI1_BASE + 0x04)
+#define SSI1_STX1_PHYS   __PHYS_REG(IMX_SSI1_BASE + 0x04)
+#define SSI1_SRX0   __REG(IMX_SSI1_BASE + 0x08)
+#define SSI1_SRX0_PHYS   __PHYS_REG(IMX_SSI1_BASE + 0x08)
+#define SSI1_SRX1   __REG(IMX_SSI1_BASE + 0x0c)
+#define SSI1_SRX1_PHYS   __PHYS_REG(IMX_SSI1_BASE + 0x0c)
+#define SSI1_SCR    __REG(IMX_SSI1_BASE + 0x10)
+#define SSI1_SISR   __REG(IMX_SSI1_BASE + 0x14)
+#define SSI1_SIER   __REG(IMX_SSI1_BASE + 0x18)
+#define SSI1_STCR   __REG(IMX_SSI1_BASE + 0x1c)
+#define SSI1_SRCR   __REG(IMX_SSI1_BASE + 0x20)
+#define SSI1_STCCR  __REG(IMX_SSI1_BASE + 0x24)
+#define SSI1_SRCCR  __REG(IMX_SSI1_BASE + 0x28)
+#define SSI1_SFCSR  __REG(IMX_SSI1_BASE + 0x2c)
+#define SSI1_STR    __REG(IMX_SSI1_BASE + 0x30)
+#define SSI1_SOR    __REG(IMX_SSI1_BASE + 0x34)
+#define SSI1_SACNT  __REG(IMX_SSI1_BASE + 0x38)
+#define SSI1_SACADD __REG(IMX_SSI1_BASE + 0x3c)
+#define SSI1_SACDAT __REG(IMX_SSI1_BASE + 0x40)
+#define SSI1_SATAG  __REG(IMX_SSI1_BASE + 0x44)
+#define SSI1_STMSK  __REG(IMX_SSI1_BASE + 0x48)
+#define SSI1_SRMSK  __REG(IMX_SSI1_BASE + 0x4c)
+
+#define SSI2_STX0   __REG(IMX_SSI2_BASE + 0x00)
+#define SSI2_STX0_PHYS   __PHYS_REG(IMX_SSI2_BASE + 0x00)
+#define SSI2_STX1   __REG(IMX_SSI2_BASE + 0x04)
+#define SSI2_STX1_PHYS   __PHYS_REG(IMX_SSI2_BASE + 0x04)
+#define SSI2_SRX0   __REG(IMX_SSI2_BASE + 0x08)
+#define SSI2_SRX0_PHYS   __PHYS_REG(IMX_SSI2_BASE + 0x08)
+#define SSI2_SRX1   __REG(IMX_SSI2_BASE + 0x0c)
+#define SSI2_SRX1_PHYS   __PHYS_REG(IMX_SSI2_BASE + 0x0c)
+#define SSI2_SCR    __REG(IMX_SSI2_BASE + 0x10)
+#define SSI2_SISR   __REG(IMX_SSI2_BASE + 0x14)
+#define SSI2_SIER   __REG(IMX_SSI2_BASE + 0x18)
+#define SSI2_STCR   __REG(IMX_SSI2_BASE + 0x1c)
+#define SSI2_SRCR   __REG(IMX_SSI2_BASE + 0x20)
+#define SSI2_STCCR  __REG(IMX_SSI2_BASE + 0x24)
+#define SSI2_SRCCR  __REG(IMX_SSI2_BASE + 0x28)
+#define SSI2_SFCSR  __REG(IMX_SSI2_BASE + 0x2c)
+#define SSI2_STR    __REG(IMX_SSI2_BASE + 0x30)
+#define SSI2_SOR    __REG(IMX_SSI2_BASE + 0x34)
+#define SSI2_SACNT  __REG(IMX_SSI2_BASE + 0x38)
+#define SSI2_SACADD __REG(IMX_SSI2_BASE + 0x3c)
+#define SSI2_SACDAT __REG(IMX_SSI2_BASE + 0x40)
+#define SSI2_SATAG  __REG(IMX_SSI2_BASE + 0x44)
+#define SSI2_STMSK  __REG(IMX_SSI2_BASE + 0x48)
+#define SSI2_SRMSK  __REG(IMX_SSI2_BASE + 0x4c)
+
+#define SSI_SCR_CLK_IST        (1 << 9)
+#define SSI_SCR_TCH_EN         (1 << 8)
+#define SSI_SCR_SYS_CLK_EN     (1 << 7)
+#define SSI_SCR_I2S_MODE_NORM  (0 << 5)
+#define SSI_SCR_I2S_MODE_MSTR  (1 << 5)
+#define SSI_SCR_I2S_MODE_SLAVE (2 << 5)
+#define SSI_SCR_SYN            (1 << 4)
+#define SSI_SCR_NET            (1 << 3)
+#define SSI_SCR_RE             (1 << 2)
+#define SSI_SCR_TE             (1 << 1)
+#define SSI_SCR_SSIEN          (1 << 0)
+
+#define SSI_SISR_CMDAU         (1 << 18)
+#define SSI_SISR_CMDDU         (1 << 17)
+#define SSI_SISR_RXT           (1 << 16)
+#define SSI_SISR_RDR1          (1 << 15)
+#define SSI_SISR_RDR0          (1 << 14)
+#define SSI_SISR_TDE1          (1 << 13)
+#define SSI_SISR_TDE0          (1 << 12)
+#define SSI_SISR_ROE1          (1 << 11)
+#define SSI_SISR_ROE0          (1 << 10)
+#define SSI_SISR_TUE1          (1 << 9)
+#define SSI_SISR_TUE0          (1 << 8)
+#define SSI_SISR_TFS           (1 << 7)
+#define SSI_SISR_RFS           (1 << 6)
+#define SSI_SISR_TLS           (1 << 5)
+#define SSI_SISR_RLS           (1 << 4)
+#define SSI_SISR_RFF1          (1 << 3)
+#define SSI_SISR_RFF0          (1 << 2)
+#define SSI_SISR_TFE1          (1 << 1)
+#define SSI_SISR_TFE0          (1 << 0)
+
+#define SSI_SIER_RDMAE         (1 << 22)
+#define SSI_SIER_RIE           (1 << 21)
+#define SSI_SIER_TDMAE         (1 << 20)
+#define SSI_SIER_TIE           (1 << 19)
+#define SSI_SIER_CMDAU_EN      (1 << 18)
+#define SSI_SIER_CMDDU_EN      (1 << 17)
+#define SSI_SIER_RXT_EN        (1 << 16)
+#define SSI_SIER_RDR1_EN       (1 << 15)
+#define SSI_SIER_RDR0_EN       (1 << 14)
+#define SSI_SIER_TDE1_EN       (1 << 13)
+#define SSI_SIER_TDE0_EN       (1 << 12)
+#define SSI_SIER_ROE1_EN       (1 << 11)
+#define SSI_SIER_ROE0_EN       (1 << 10)
+#define SSI_SIER_TUE1_EN       (1 << 9)
+#define SSI_SIER_TUE0_EN       (1 << 8)
+#define SSI_SIER_TFS_EN        (1 << 7)
+#define SSI_SIER_RFS_EN        (1 << 6)
+#define SSI_SIER_TLS_EN        (1 << 5)
+#define SSI_SIER_RLS_EN        (1 << 4)
+#define SSI_SIER_RFF1_EN       (1 << 3)
+#define SSI_SIER_RFF0_EN       (1 << 2)
+#define SSI_SIER_TFE1_EN       (1 << 1)
+#define SSI_SIER_TFE0_EN       (1 << 0)
+
+#define SSI_STCR_TXBIT0        (1 << 9)
+#define SSI_STCR_TFEN1         (1 << 8)
+#define SSI_STCR_TFEN0         (1 << 7)
+#define SSI_STCR_TFDIR         (1 << 6)
+#define SSI_STCR_TXDIR         (1 << 5)
+#define SSI_STCR_TSHFD         (1 << 4)
+#define SSI_STCR_TSCKP         (1 << 3)
+#define SSI_STCR_TFSI          (1 << 2)
+#define SSI_STCR_TFSL          (1 << 1)
+#define SSI_STCR_TEFS          (1 << 0)
+
+#define SSI_SRCR_RXBIT0        (1 << 9)
+#define SSI_SRCR_RFEN1         (1 << 8)
+#define SSI_SRCR_RFEN0         (1 << 7)
+#define SSI_SRCR_RFDIR         (1 << 6)
+#define SSI_SRCR_RXDIR         (1 << 5)
+#define SSI_SRCR_RSHFD         (1 << 4)
+#define SSI_SRCR_RSCKP         (1 << 3)
+#define SSI_SRCR_RFSI          (1 << 2)
+#define SSI_SRCR_RFSL          (1 << 1)
+#define SSI_SRCR_REFS          (1 << 0)
+
+#define SSI_STCCR_DIV2         (1 << 18)
+#define SSI_STCCR_PSR          (1 << 15)
+#define SSI_STCCR_WL(x)        ((((x) - 2) >> 1) << 13)
+#define SSI_STCCR_DC(x)        (((x) & 0x1f) << 8)
+#define SSI_STCCR_PM(x)        (((x) & 0xff) << 0)
+
+#define SSI_SRCCR_DIV2         (1 << 18)
+#define SSI_SRCCR_PSR          (1 << 15)
+#define SSI_SRCCR_WL(x)        ((((x) - 2) >> 1) << 13)
+#define SSI_SRCCR_DC(x)        (((x) & 0x1f) << 8)
+#define SSI_SRCCR_PM(x)        (((x) & 0xff) << 0)
+
+
+#define SSI_SFCSR_RFCNT1(x)   (((x) & 0xf) << 28)
+#define SSI_SFCSR_TFCNT1(x)   (((x) & 0xf) << 24)
+#define SSI_SFCSR_RFWM1(x)    (((x) & 0xf) << 20)
+#define SSI_SFCSR_TFWM1(x)    (((x) & 0xf) << 16)
+#define SSI_SFCSR_RFCNT0(x)   (((x) & 0xf) << 12)
+#define SSI_SFCSR_TFCNT0(x)   (((x) & 0xf) <<  8)
+#define SSI_SFCSR_RFWM0(x)    (((x) & 0xf) <<  4)
+#define SSI_SFCSR_TFWM0(x)    (((x) & 0xf) <<  0)
+
+#define SSI_STR_TEST          (1 << 15)
+#define SSI_STR_RCK2TCK       (1 << 14)
+#define SSI_STR_RFS2TFS       (1 << 13)
+#define SSI_STR_RXSTATE(x)    (((x) & 0xf) << 8)
+#define SSI_STR_TXD2RXD       (1 <<  7)
+#define SSI_STR_TCK2RCK       (1 <<  6)
+#define SSI_STR_TFS2RFS       (1 <<  5)
+#define SSI_STR_TXSTATE(x)    (((x) & 0xf) << 0)
+
+#define SSI_SOR_CLKOFF        (1 << 6)
+#define SSI_SOR_RX_CLR        (1 << 5)
+#define SSI_SOR_TX_CLR        (1 << 4)
+#define SSI_SOR_INIT          (1 << 3)
+#define SSI_SOR_WAIT(x)       (((x) & 0x3) << 1)
+#define SSI_SOR_SYNRST        (1 << 0)
+
+#define SSI_SACNT_FRDIV(x)    (((x) & 0x3f) << 5)
+#define SSI_SACNT_WR          (x << 4)
+#define SSI_SACNT_RD          (x << 3)
+#define SSI_SACNT_TIF         (x << 2)
+#define SSI_SACNT_FV          (x << 1)
+#define SSI_SACNT_A97EN       (x << 0)
+
+
+/* AUDMUX registers */
+#define AUDMUX_HPCR1         __REG(IMX_AUDMUX_BASE + 0x00)
+#define AUDMUX_HPCR2         __REG(IMX_AUDMUX_BASE + 0x04)
+#define AUDMUX_HPCR3         __REG(IMX_AUDMUX_BASE + 0x08)
+#define AUDMUX_PPCR1         __REG(IMX_AUDMUX_BASE + 0x10)
+#define AUDMUX_PPCR2         __REG(IMX_AUDMUX_BASE + 0x14)
+#define AUDMUX_PPCR3         __REG(IMX_AUDMUX_BASE + 0x18)
+
+#define AUDMUX_HPCR_TFSDIR         (1 << 31)
+#define AUDMUX_HPCR_TCLKDIR        (1 << 30)
+#define AUDMUX_HPCR_TFCSEL_TX      (0 << 26)
+#define AUDMUX_HPCR_TFCSEL_RX      (8 << 26)
+#define AUDMUX_HPCR_TFCSEL(x)      (((x) & 0x7) << 26)
+#define AUDMUX_HPCR_RFSDIR         (1 << 25)
+#define AUDMUX_HPCR_RCLKDIR        (1 << 24)
+#define AUDMUX_HPCR_RFCSEL_TX      (0 << 20)
+#define AUDMUX_HPCR_RFCSEL_RX      (8 << 20)
+#define AUDMUX_HPCR_RFCSEL(x)      (((x) & 0x7) << 20)
+#define AUDMUX_HPCR_RXDSEL(x)      (((x) & 0x7) << 13)
+#define AUDMUX_HPCR_SYN            (1 << 12)
+#define AUDMUX_HPCR_TXRXEN         (1 << 10)
+#define AUDMUX_HPCR_INMEN          (1 <<  8)
+#define AUDMUX_HPCR_INMMASK(x)     (((x) & 0xff) << 0)
+
+#define AUDMUX_PPCR_TFSDIR         (1 << 31)
+#define AUDMUX_PPCR_TCLKDIR        (1 << 30)
+#define AUDMUX_PPCR_TFCSEL_TX      (0 << 26)
+#define AUDMUX_PPCR_TFCSEL_RX      (8 << 26)
+#define AUDMUX_PPCR_TFCSEL(x)      (((x) & 0x7) << 26)
+#define AUDMUX_PPCR_RFSDIR         (1 << 25)
+#define AUDMUX_PPCR_RCLKDIR        (1 << 24)
+#define AUDMUX_PPCR_RFCSEL_TX      (0 << 20)
+#define AUDMUX_PPCR_RFCSEL_RX      (8 << 20)
+#define AUDMUX_PPCR_RFCSEL(x)      (((x) & 0x7) << 20)
+#define AUDMUX_PPCR_RXDSEL(x)      (((x) & 0x7) << 13)
+#define AUDMUX_PPCR_SYN            (1 << 12)
+#define AUDMUX_PPCR_TXRXEN         (1 << 10)
+
+
+#endif
diff --git a/sound/soc/imx/imx31-pcm.c b/sound/soc/imx/imx31-pcm.c
new file mode 100644
index 0000000..fc530ac
--- /dev/null
+++ b/sound/soc/imx/imx31-pcm.c
@@ -0,0 +1,502 @@
+/*
+ * imx31-pcm.c -- ALSA SoC interface for the Freescale i.MX CPU's
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * Based on pxa2xx-pcm.c by	Nicolas Pitre, (C) 2004 MontaVista Software, Inc.
+ * and on mxc-alsa-mc13783 (C) 2006 Freescale.
+ *
+ * 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.
+ *
+ *  Revision history
+ *    29th Aug 2006   Initial version.
+ * 
+ * TODO:
+ *  Refactor for new SDMA API when Freescale have it ready 
+ *  (I am assuming the SDMA iapi needs rework for mainline).
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/spba.h>
+#include <asm/arch/clock.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+#include "imx31-pcm.h"
+
+/* debug */
+#define IMX_PCM_DEBUG 0
+#if IMX_PCM_DEBUG
+#define dbg(format, arg...) printk(format, ## arg)
+#else
+#define dbg(format, arg...)
+#endif
+
+/*
+ * Coherent DMA memory is used by default, although Freescale have used 
+ * bounce buffers in all their drivers for i.MX31 to date. If you have any 
+ * issues, please select bounce buffers. 
+ */
+#define IMX31_DMA_BOUNCE 0
+
+static const struct snd_pcm_hardware imx31_pcm_hardware = {
+	.info			= (SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				   SNDRV_PCM_INFO_MMAP |
+				   SNDRV_PCM_INFO_MMAP_VALID |
+				   SNDRV_PCM_INFO_PAUSE |
+				   SNDRV_PCM_INFO_RESUME),
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
+					SNDRV_PCM_FMTBIT_S24_LE,
+	.buffer_bytes_max	= 32 * 1024,
+	.period_bytes_min	= 64,
+	.period_bytes_max	= 8 * 1024,
+	.periods_min		= 2,
+	.periods_max		= 255,
+	.fifo_size		= 0,
+};
+
+struct mxc_runtime_data {
+	int dma_ch;
+	struct imx31_pcm_dma_param *dma_params;
+	spinlock_t dma_lock;
+	int active, period, periods;
+	int dma_wchannel;
+	int dma_active;
+	int old_offset;
+	int dma_alloc;
+};
+
+static void audio_stop_dma(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxc_runtime_data *prtd = runtime->private_data;
+	unsigned long flags;
+#if IMX31_DMA_BOUNCE
+	unsigned int dma_size;
+	unsigned int offset;
+	
+	dma_size = frames_to_bytes(runtime, runtime->period_size);
+	offset = dma_size * prtd->periods;
+#endif
+
+	/* stops the dma channel and clears the buffer ptrs */
+	spin_lock_irqsave(&prtd->dma_lock, flags);
+	prtd->active = 0;
+	prtd->period = 0;
+	prtd->periods = 0;
+	mxc_dma_stop(prtd->dma_wchannel);
+
+#if IMX31_DMA_BOUNCE
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_unmap_single(NULL, runtime->dma_addr + offset, dma_size,
+					DMA_TO_DEVICE);
+	else
+		dma_unmap_single(NULL, runtime->dma_addr + offset, dma_size,
+					DMA_FROM_DEVICE);
+#endif	
+	spin_unlock_irqrestore(&prtd->dma_lock, flags);
+}
+
+static int dma_new_period(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime =  substream->runtime;
+	struct mxc_runtime_data *prtd = runtime->private_data;
+	unsigned int dma_size = frames_to_bytes(runtime, runtime->period_size);
+	unsigned int offset = dma_size * prtd->period;
+	int ret = 0;
+	dma_request_t sdma_request;
+	
+	if (!prtd->active) 
+		return 0;
+		
+	memset(&sdma_request, 0, sizeof(dma_request_t));
+	
+	dbg("period pos  ALSA %x DMA %x\n",runtime->periods, prtd->period);
+	dbg("period size ALSA %x DMA %x Offset %x dmasize %x\n",
+		(unsigned int) runtime->period_size, runtime->dma_bytes, 
+			offset, dma_size);
+	dbg("DMA addr %x\n", runtime->dma_addr + offset);
+	
+#if IMX31_DMA_BOUNCE
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		sdma_request.sourceAddr = (char*)(dma_map_single(NULL,
+			runtime->dma_area + offset, dma_size, DMA_TO_DEVICE));
+	else
+		sdma_request.destAddr = (char*)(dma_map_single(NULL,
+			runtime->dma_area + offset, dma_size, DMA_FROM_DEVICE));	
+#else
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		sdma_request.sourceAddr = (char*)(runtime->dma_addr + offset);
+	else
+		sdma_request.destAddr = (char*)(runtime->dma_addr + offset);
+#endif
+	sdma_request.count = dma_size;
+
+	ret = mxc_dma_set_config(prtd->dma_wchannel, &sdma_request, 0);
+	if (ret < 0) {
+		printk(KERN_ERR "imx31-pcm: cannot configure audio DMA channel\n");
+		goto out;
+	}
+	
+	ret = mxc_dma_start(prtd->dma_wchannel);
+	if (ret < 0) {
+		printk(KERN_ERR "imx31-pcm: cannot queue audio DMA buffer\n");
+		goto out;
+	}
+	prtd->dma_active = 1;
+	prtd->period++;
+	prtd->period %= runtime->periods;
+out:
+	return ret;
+}
+
+static void audio_dma_irq(void *data)
+{
+	struct snd_pcm_substream *substream = 
+		(struct snd_pcm_substream *)data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxc_runtime_data *prtd = runtime->private_data;
+#if IMX31_DMA_BOUNCE
+	unsigned int dma_size = frames_to_bytes(runtime, runtime->period_size);
+	unsigned int offset = dma_size * prtd->periods;
+#endif
+
+	prtd->dma_active = 0;
+	prtd->periods++;
+	prtd->periods %= runtime->periods;
+
+	dbg("irq per %d offset %x\n", prtd->periods, offset);
+#if IMX31_DMA_BOUNCE
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_unmap_single(NULL, runtime->dma_addr + offset, dma_size,
+							DMA_TO_DEVICE);
+	else
+		dma_unmap_single(NULL, runtime->dma_addr + offset, dma_size,
+							DMA_FROM_DEVICE);
+						
+#endif
+	
+ 	if (prtd->active)
+		snd_pcm_period_elapsed(substream);
+	dma_new_period(substream);
+}
+
+static int imx31_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime =  substream->runtime;
+	struct mxc_runtime_data *prtd = runtime->private_data;
+
+	prtd->period = 0;
+	prtd->periods = 0;
+	return 0;
+}
+
+static int imx31_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxc_runtime_data *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mxc_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
+	int ret = 0, channel = 0;
+	
+	/* only allocate the DMA chn once */
+	if (!prtd->dma_alloc) {
+		if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			ret  = mxc_request_dma(&channel, "ALSA TX SDMA");
+			if (ret < 0) {
+				printk(KERN_ERR "imx31-pcm: error requesting a write dma channel\n");
+				return ret;
+			}
+	
+		} else {
+			ret = mxc_request_dma(&channel, "ALSA RX SDMA");
+			if (ret < 0) {
+				printk(KERN_ERR "imx31-pcm: error requesting a read dma channel\n");
+				return ret;
+			}
+		}
+		prtd->dma_wchannel = channel;
+		prtd->dma_alloc = 1;
+		
+		/* set up chn with params */
+		dma->params.callback = audio_dma_irq;
+		dma->params.arg = substream;
+	}
+	
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		dma->params.word_size = TRANSFER_16BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+	case SNDRV_PCM_FORMAT_S24_LE:
+		dma->params.word_size = TRANSFER_24BIT;
+		break;
+	}
+	
+	ret = mxc_dma_setup_channel(channel, &dma->params);
+	if (ret < 0) {
+		printk(KERN_ERR "imx31-pcm: failed to setup audio DMA chn %d\n", channel);
+		mxc_free_dma(channel);
+		return ret;
+	}
+	
+#if IMX31_DMA_BOUNCE
+	ret = snd_pcm_lib_malloc_pages(substream, 
+		params_buffer_bytes(params));
+	if (ret < 0) {
+		printk(KERN_ERR "imx31-pcm: failed to malloc pcm pages\n");
+		if (channel)
+			mxc_free_dma(channel);
+		return ret;
+	}
+	runtime->dma_addr = virt_to_phys(runtime->dma_area);
+#else
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+#endif
+	return ret;
+}
+
+static int imx31_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxc_runtime_data *prtd = runtime->private_data;
+	
+	if (prtd->dma_wchannel) {
+		mxc_free_dma(prtd->dma_wchannel);
+		prtd->dma_wchannel = 0;
+		prtd->dma_alloc = 0;
+	}
+#if IMX31_DMA_BOUNCE
+	snd_pcm_lib_free_pages(substream);
+#endif
+	return 0;
+}
+
+static int imx31_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct mxc_runtime_data *prtd = substream->runtime->private_data;
+	int ret = 0;
+	
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		prtd->dma_active = 0;
+		/* requested stream startup */
+		prtd->active = 1;
+		ret = dma_new_period(substream);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		/* requested stream shutdown */
+		audio_stop_dma(substream);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		prtd->active = 0;
+		prtd->periods = 0;
+		break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+		prtd->active = 1;
+		prtd->dma_active = 0;
+		ret = dma_new_period(substream);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		prtd->active = 0;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		prtd->active = 1;
+		if (prtd->old_offset) {
+			prtd->dma_active = 0;
+			ret = dma_new_period(substream);
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t imx31_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxc_runtime_data *prtd = runtime->private_data;
+	unsigned int offset = 0;
+
+	/* is a transfer active ? */
+	if (prtd->dma_active){
+		offset = (runtime->period_size * (prtd->periods)) +
+						(runtime->period_size >> 1);
+		if (offset >= runtime->buffer_size)
+			offset = runtime->period_size >> 1;
+	} else {
+		offset = (runtime->period_size * (prtd->periods));
+		if (offset >= runtime->buffer_size)
+			offset = 0;
+	}
+	dbg("pointer offset %x\n", offset);
+	
+	return offset;
+}
+
+
+static int imx31_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxc_runtime_data *prtd;
+	int ret;
+
+	snd_soc_set_runtime_hwparams(substream, &imx31_pcm_hardware);
+
+	ret = snd_pcm_hw_constraint_integer(runtime, 
+		SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		return ret;
+
+	prtd = kzalloc(sizeof(struct mxc_runtime_data), GFP_KERNEL);
+	if (prtd == NULL)
+		return -ENOMEM;
+
+	runtime->private_data = prtd;
+	return 0;
+}
+
+static int imx31_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxc_runtime_data *prtd = runtime->private_data;
+	
+	kfree(prtd);
+	return 0;
+}
+
+static int
+imx31_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+}
+
+struct snd_pcm_ops imx31_pcm_ops = {
+	.open		= imx31_pcm_open,
+	.close		= imx31_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= imx31_pcm_hw_params,
+	.hw_free	= imx31_pcm_hw_free,
+	.prepare	= imx31_pcm_prepare,
+	.trigger	= imx31_pcm_trigger,
+	.pointer	= imx31_pcm_pointer,
+	.mmap		= imx31_pcm_mmap,
+};
+
+static int imx31_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = imx31_pcm_hardware.buffer_bytes_max;
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+		
+	buf->bytes = size;
+	return 0;
+}
+
+static void imx31_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_writecombine(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static u64 imx31_pcm_dmamask = 0xffffffff;
+
+int imx31_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
+	struct snd_pcm *pcm)
+{
+	int ret = 0;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &imx31_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+#if IMX31_DMA_BOUNCE
+	ret = snd_pcm_lib_preallocate_pages_for_all(pcm, 
+				SNDRV_DMA_TYPE_CONTINUOUS,
+				snd_dma_continuous_data(GFP_KERNEL),
+				imx31_pcm_hardware.buffer_bytes_max * 2, 
+				imx31_pcm_hardware.buffer_bytes_max * 2);
+	if (ret < 0) {
+		printk(KERN_ERR "imx31-pcm: failed to preallocate pages\n");
+		goto out;
+	}	
+#else
+	if (dai->playback.channels_min) {
+		ret = imx31_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			goto out;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = imx31_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			goto out;
+	}
+#endif
+ out:
+	return ret;
+}
+
+struct snd_soc_platform imx31_soc_platform = {
+	.name		= "imx31-audio",
+	.pcm_ops 	= &imx31_pcm_ops,
+	.pcm_new	= imx31_pcm_new,
+#if IMX31_DMA_BOUNCE
+	.pcm_free	= NULL,
+#else
+	.pcm_free	= imx31_pcm_free_dma_buffers,
+#endif
+};
+EXPORT_SYMBOL_GPL(imx31_soc_platform);
+
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_DESCRIPTION("Freescale i.MX31 PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/imx31-pcm.h b/sound/soc/imx/imx31-pcm.h
new file mode 100644
index 0000000..ba34a28
--- /dev/null
+++ b/sound/soc/imx/imx31-pcm.h
@@ -0,0 +1,71 @@
+/*
+ * mxc-pcm.h :- ASoC platform header for Freescale i.MX
+ *
+ * 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 _MXC_PCM_H
+#define _MXC_PCM_H
+
+#include <asm/arch/dma.h>
+
+/* AUDMUX regs definition - MOVE to asm/arch when stable */
+#define AUDMUX_IO_BASE_ADDR	IO_ADDRESS(AUDMUX_BASE_ADDR)
+
+#define DAM_PTCR1	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x00)))
+#define DAM_PDCR1	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x04)))
+#define DAM_PTCR2	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x08)))
+#define DAM_PDCR2	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x0C)))
+#define DAM_PTCR3	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x10)))
+#define DAM_PDCR3	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x14)))
+#define DAM_PTCR4	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x18)))
+#define DAM_PDCR4	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x1C)))
+#define DAM_PTCR5	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x20)))
+#define DAM_PDCR5	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x24)))
+#define DAM_PTCR6	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x28)))
+#define DAM_PDCR6	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x2C)))
+#define DAM_PTCR7	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x30)))
+#define DAM_PDCR7	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x34)))
+#define DAM_CNMCR	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x38)))
+#define DAM_PTCR(a)	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + a*8)))
+#define DAM_PDCR(a)	(*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 4 + a*8)))
+
+
+#define AUDMUX_PTCR_TFSDIR		(1 << 31)
+#define AUDMUX_PTCR_TFSSEL(x, y)		((x << 30) | (((y - 1) & 0x7) << 27))
+#define AUDMUX_PTCR_TCLKDIR		(1 << 26)
+#define AUDMUX_PTCR_TCSEL(x, y)		((x << 25) | (((y - 1) & 0x7) << 22))
+#define AUDMUX_PTCR_RFSDIR		(1 << 21)
+#define AUDMUX_PTCR_RFSSEL(x, y)		((x << 20) | (((y - 1) & 0x7) << 17))
+#define AUDMUX_PTCR_RCLKDIR		(1 << 16)
+#define AUDMUX_PTCR_RCSEL(x, y)		((x << 15) | (((y - 1) & 0x7) << 12))
+#define AUDMUX_PTCR_SYN		(1 << 11)
+
+#define AUDMUX_FROM_TXFS	0
+#define AUDMUX_FROM_RXFS	1
+
+#define AUDMUX_PDCR_RXDSEL(x)		(((x - 1) & 0x7) << 13)
+#define AUDMUX_PDCR_TXDXEN		(1 << 12)
+#define AUDMUX_PDCR_MODE(x)		(((x) & 0x3) << 8)
+#define AUDMUX_PDCR_INNMASK(x)		(((x) & 0xff) << 0)
+
+#define AUDMUX_CNMCR_CEN		(1 << 18)
+#define AUDMUX_CNMCR_FSPOL		(1 << 17)
+#define AUDMUX_CNMCR_CLKPOL		(1 << 16)
+#define AUDMUX_CNMCR_CNTHI(x)		(((x) & 0xff) << 8)
+#define AUDMUX_CNMCR_CNTLOW(x)		(((x) & 0xff) << 0)
+
+struct mxc_pcm_dma_params {
+	char *name;			/* stream identifier */
+	dma_channel_params params;
+};
+
+extern struct snd_soc_cpu_dai mxc_ssi_dai[3];
+
+/* platform data */
+extern struct snd_soc_platform imx31_soc_platform;
+extern struct snd_ac97_bus_ops imx31_ac97_ops;
+
+#endif
diff --git a/sound/soc/imx/mx31ads_wm8753.c b/sound/soc/imx/mx31ads_wm8753.c
new file mode 100644
index 0000000..d137bda
--- /dev/null
+++ b/sound/soc/imx/mx31ads_wm8753.c
@@ -0,0 +1,400 @@
+/*
+ * mx31ads_wm8753.c  --  SoC audio for mx31ads
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  mx31ads audio amplifier code taken from arch/arm/mach-pxa/mx31ads.c
+ *  Copyright:	MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    30th Oct 2005   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/hardware.h>
+
+#include "../codecs/wm8753.h"
+#include "imx31-pcm.h"
+#include "imx-ssi.h"
+
+static struct snd_soc_machine mx31ads;
+
+static int mx31ads_hifi_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int pll_out = 0, bclk = 0, fmt = 0;
+	int ret = 0;
+
+	/*
+	 * The WM8753 is better at generating accurate audio clocks than the
+	 * MX31 SSI controller, so we will use it as master when we can.
+	 */
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+		fmt = SND_SOC_DAIFMT_CBS_CFS;
+		pll_out = 12288000;
+		break;
+	case 48000:
+		fmt = SND_SOC_DAIFMT_CBM_CFS;
+		bclk = WM8753_BCLK_DIV_4;
+		pll_out = 12288000;
+		break;
+	case 96000:
+		fmt = SND_SOC_DAIFMT_CBM_CFS;
+		bclk = WM8753_BCLK_DIV_2;
+		pll_out = 12288000;
+		break;
+	case 11025:
+		fmt = SND_SOC_DAIFMT_CBM_CFS;
+		bclk = WM8753_BCLK_DIV_16;
+		pll_out = 11289600;
+		break;
+	case 22050:
+		fmt = SND_SOC_DAIFMT_CBM_CFS;
+		bclk = WM8753_BCLK_DIV_8;
+		pll_out = 11289600;
+		break;
+	case 44100:
+		fmt = SND_SOC_DAIFMT_CBM_CFS;
+		bclk = WM8753_BCLK_DIV_4;
+		pll_out = 11289600;
+		break;
+	case 88200:
+		fmt = SND_SOC_DAIFMT_CBM_CFS;
+		bclk = WM8753_BCLK_DIV_2;
+		pll_out = 11289600;
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai,
+		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | fmt);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
+		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | fmt);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock for DAC and ADC */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the SSI system clock as input (unused) */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set codec BCLK division for sample rate */
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
+	if (ret < 0)
+		return ret;
+
+	/* codec PLL input is 13 MHz */
+	ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 13000000, pll_out);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int mx31ads_hifi_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+
+	/* disable the PLL */
+	return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0);
+}
+
+/*
+ * mx31ads WM8753 HiFi DAI opserations.
+ */
+static struct snd_soc_ops mx31ads_hifi_ops = {
+	.hw_params = mx31ads_hifi_hw_params,
+	.hw_free = mx31ads_hifi_hw_free,
+};
+
+static int mx31ads_voice_startup(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static void mx31ads_voice_shutdown(struct snd_pcm_substream *substream)
+{
+}
+
+static int mx31ads_voice_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int pll_out = 0, bclk = 0, pcmdiv = 0;
+	int ret = 0;
+
+	/*
+	 * The WM8753 is far better at generating accurate audio clocks than the
+	 * pxa2xx SSP controller, so we will use it as master when we can.
+	 */
+	switch (params_rate(params)) {
+	case 8000:
+		pll_out = 12288000;
+		pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
+		bclk = WM8753_VXCLK_DIV_8; /* 256kHz */
+		break;
+	case 16000:
+		pll_out = 12288000;
+		pcmdiv = WM8753_PCM_DIV_3; /* 4.096 MHz */
+		bclk = WM8753_VXCLK_DIV_8; /* 512kHz */
+		break;
+	case 48000:
+		pll_out = 12288000;
+		pcmdiv = WM8753_PCM_DIV_1; /* 12.288 MHz */
+		bclk = WM8753_VXCLK_DIV_8; /* 1.536 MHz */
+		break;
+	case 11025:
+		pll_out = 11289600;
+		pcmdiv = WM8753_PCM_DIV_4; /* 11.2896 MHz */
+		bclk = WM8753_VXCLK_DIV_8; /* 352.8 kHz */
+		break;
+	case 22050:
+		pll_out = 11289600;
+		pcmdiv = WM8753_PCM_DIV_2; /* 11.2896 MHz */
+		bclk = WM8753_VXCLK_DIV_8; /* 705.6 kHz */
+		break;
+	case 44100:
+		pll_out = 11289600;
+		pcmdiv = WM8753_PCM_DIV_1; /* 11.2896 MHz */
+		bclk = WM8753_VXCLK_DIV_8; /* 1.4112 MHz */
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock for DAC and ADC */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, pll_out,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the SSP system clock as input (unused) */
+//	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_SSP_CLK_PLL, 0,
+//		SND_SOC_CLOCK_IN);
+//	if (ret < 0)
+//		return ret;
+
+	/* set codec BCLK division for sample rate */
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_VXCLKDIV, bclk);
+	if (ret < 0)
+		return ret;
+
+	/* set codec PCM division for sample rate */
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
+	if (ret < 0)
+		return ret;
+
+	/* codec PLL input is 13 MHz */
+	ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 13000000, pll_out);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int mx31ads_voice_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+
+	/* disable the PLL */
+	return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0);
+}
+
+static struct snd_soc_ops mx31ads_voice_ops = {
+	.startup = mx31ads_voice_startup,
+	.shutdown = mx31ads_voice_shutdown,
+	.hw_params = mx31ads_voice_hw_params,
+	.hw_free = mx31ads_voice_hw_free,
+};
+
+static int mx31ads_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	return 0;
+}
+
+static int mx31ads_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int mx31ads_probe(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int mx31ads_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+/* example machine audio_mapnections */
+static const char* audio_map[][3] = {
+
+	/* mic is connected to mic1 - with bias */
+	{"MIC1", NULL, "Mic Bias"},
+	{"MIC1N", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic1 Jack"},
+	{"Mic Bias", NULL, "Mic1 Jack"},
+
+	{"ACIN", NULL, "ACOP"},
+	{NULL, NULL, NULL},
+};
+
+/* headphone detect support on my board */
+static const char * hp_pol[] = {"Headphone", "Speaker"};
+static const struct soc_enum wm8753_enum =
+	SOC_ENUM_SINGLE(WM8753_OUTCTL, 1, 2, hp_pol);
+
+static const struct snd_kcontrol_new wm8753_mx31ads_controls[] = {
+	SOC_SINGLE("Headphone Detect Switch", WM8753_OUTCTL, 6, 1, 0),
+	SOC_ENUM("Headphone Detect Polarity", wm8753_enum),
+};
+
+/*
+ * This is an example machine initialisation for a wm8753 connected to a
+ * mx31ads II. It is missing logic to detect hp/mic insertions and logic
+ * to re-route the audio in such an event.
+ */
+static int mx31ads_wm8753_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+
+	/* set up mx31ads codec pins */
+	snd_soc_dapm_disable_pin(codec, "RXP", 0);
+	snd_soc_dapm_disable_pin(codec, "RXN", 0);
+	snd_soc_dapm_disable_pin(codec, "MIC2", 0);
+
+	/* add mx31ads specific controls */
+	for (i = 0; i < ARRAY_SIZE(wm8753_mx31ads_controls); i++) {
+		if ((err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&wm8753_mx31ads_controls[i],codec, NULL))) < 0)
+			return err;
+	}
+
+	/* set up mx31ads specific audio path audio_mapnects */
+	for(i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0], audio_map[i][1], audio_map[i][2]);
+	}
+
+	snd_soc_dapm_sync(codec);
+	return 0;
+}
+
+static struct snd_soc_dai_link mx31ads_dai[] = {
+{ /* Hifi Playback - for similatious use with voice below */
+	.name = "WM8753",
+	.stream_name = "WM8753 HiFi",
+	.cpu_dai = &imx_ssi_pcm_dai[0],
+	.codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+	.init = mx31ads_wm8753_init,
+	.ops = &mx31ads_hifi_ops,
+},
+//{ /* Voice via BT */
+//	.name = "Bluetooth",
+//	.stream_name = "Voice",
+//	.cpu_dai = &pxa_ssp_dai[1],
+//	.codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+//	.ops = &mx31ads_voice_ops,
+//},
+};
+
+static struct snd_soc_machine mx31ads = {
+	.name = "mx31ads",
+	.probe = mx31ads_probe,
+	.remove = mx31ads_remove,
+	.suspend_pre = mx31ads_suspend,
+	.resume_post = mx31ads_resume,
+	.dai_link = mx31ads_dai,
+	.num_links = ARRAY_SIZE(mx31ads_dai),
+};
+
+static struct wm8753_setup_data mx31ads_wm8753_setup = {
+	.i2c_address = 0x1a,
+};
+
+static struct snd_soc_device mx31ads_snd_devdata = {
+	.machine = &mx31ads,
+	.platform = &mxc_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8753,
+	.codec_data = &mx31ads_wm8753_setup,
+};
+
+static struct platform_device *mx31ads_snd_device;
+
+static int __init mx31ads_init(void)
+{
+	int ret;
+
+	mx31ads_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!mx31ads_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mx31ads_snd_device, &mx31ads_snd_devdata);
+	mx31ads_snd_devdata.dev = &mx31ads_snd_device->dev;
+	ret = platform_device_add(mx31ads_snd_device);
+
+	if (ret)
+		platform_device_put(mx31ads_snd_device);
+
+	return ret;
+}
+
+static void __exit mx31ads_exit(void)
+{
+	platform_device_unregister(mx31ads_snd_device);
+}
+
+module_init(mx31ads_init);
+module_exit(mx31ads_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM8753 mx31ads");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index a0f7d3c..2f0c581 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -8,10 +8,6 @@ config SND_PXA2XX_SOC
 	  the PXA2xx AC97, I2S or SSP interface. You will also need
 	  to select the audio interfaces to support below.
 
-config SND_PXA2XX_AC97
-	tristate
-	select SND_AC97_CODEC
-
 config SND_PXA2XX_SOC_AC97
 	tristate
 	select AC97_BUS
@@ -22,6 +18,10 @@ config SND_PXA2XX_SOC_AC97
 config SND_PXA2XX_SOC_I2S
 	tristate
 
+config SND_PXA2XX_SOC_SSP
+	tristate
+	select PXA_SSP
+
 config SND_PXA_SOC_SSP
 	tristate
 	select PXA_SSP
@@ -108,6 +108,107 @@ config SND_PXA2XX_SOC_EM_X270
 	  Say Y if you want to add support for SoC audio on
 	  CompuLab EM-x270, eXeda and CM-X300 machines.
 
+config SND_PXA2XX_SOC_MAGICIAN
+	tristate "SoC Audio support for HTC Magician"
+	depends on SND_PXA2XX_SOC
+	select SND_PXA2XX_SOC_I2S
+	select SND_PXA2XX_SOC_SSP
+	select SND_SOC_UDA1380
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  HTC Magician.
+
+config SND_PXA2XX_SOC_AMESOM_TLV320
+	tristate "SoC SSP Audio support for AMESOM - TLV320AIC24k"
+	depends on SND_PXA2XX_SOC && MACH_AMESOM
+	select SND_PXA2XX_SOC_I2S
+	select SND_PXA2XX_SOC_SSP
+	select SND_SOC_TLV320
+	help
+	  Say Y if you want to add support for SoC audio on Amesom
+	  with the tlv320.
+	  
+config SND_PXA2XX_SOC_H5000
+	tristate "ASoC support for H5000"
+	depends on SND_PXA2XX_SOC && MACH_PXA
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_AK4535
+	help
+	  Say Y if you want to add support for ASoC audio for H5000.
+
+config SND_PXA2XX_SOC_MAINSTONE
+	tristate "SoC AC97 Audio support for Intel Mainstone"
+	depends on SND_PXA2XX_SOC && MACH_MAINSTONE
+	select SND_PXA2XX_SOC_AC97
+	select SND_SOC_AC97_CODEC
+	help
+	  Say Y if you want to add support for generic AC97 SoC audio on Mainstone.
+
+config SND_PXA2XX_SOC_MAINSTONE_WM8731
+	tristate "SoC I2S Audio support for Intel Mainstone - WM8731"
+	depends on SND_PXA2XX_SOC && MACH_MAINSTONE
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_WM8731
+	help
+	  Say Y if you want to add support for SoC audio on Mainstone
+	  with the WM8731.
+
+config SND_PXA2XX_SOC_MAINSTONE_WM8753
+	tristate "SoC I2S/SSP Audio support for Intel Mainstone - WM8753"
+	depends on SND_PXA2XX_SOC && MACH_MAINSTONE
+	select SND_PXA2XX_SOC_I2S
+	select SND_PXA2XX_SOC_SSP
+	select SND_SOC_WM8753
+	help
+	  Say Y if you want to add support for SoC audio on Mainstone
+	  with the WM8753.
+
+config SND_PXA2XX_SOC_MAINSTONE_WM8974
+	tristate "SoC I2S Audio support for Intel Mainstone - WM8974"
+	depends on SND_PXA2XX_SOC && MACH_MAINSTONE
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_WM8974
+	help
+	  Say Y if you want to add support for SoC audio on Mainstone
+	  with the WM8974.
+
+config SND_PXA2XX_SOC_MAINSTONE_WM9713
+	tristate "SoC I2S/SSP Audio support for Intel Mainstone - WM9713"
+	depends on SND_PXA2XX_SOC && MACH_MAINSTONE
+	select SND_PXA2XX_SOC_AC97
+	select SND_PXA2XX_SOC_SSP
+	select SND_SOC_WM9713
+	help
+	  Say Y if you want to add support for SoC voice audio on Mainstone
+	  with the WM9713.
+
+config SND_MAINSTONE_BASEBAND
+	tristate "Example SoC Baseband Audio support for Intel Mainstone"
+	depends on SND_PXA2XX_SOC && MACH_MAINSTONE
+	select SND_PXA2XX_SOC_AC97
+	select SND_SOC_WM9713
+	help
+	  Say Y if you want to add support for SoC baseband on Mainstone
+	  with the WM9713 and example Baseband modem.
+
+config SND_MAINSTONE_BLUETOOTH
+	tristate "Example SoC Bluetooth Audio support for Intel Mainstone"
+	depends on SND_PXA2XX_SOC && MACH_MAINSTONE
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_WM8753
+	help
+	  Say Y if you want to add support for SoC bluetooth on Mainstone
+	  with the WM8753 and example Bluetooth codec.
+
+config SND_PXA2xx_SOC_MAINSTONE_WM9712
+	tristate "SoC I2S/SSP Audio support for Intel Mainstone - WM9712"
+	depends on SND_PXA2XX_SOC && MACH_MAINSTONE
+	select SND_PXA2XX_SOC_AC97
+	select SND_SOC_WM9712
+	help
+	  Say Y if you want to add support for SoC voice audio on Mainstone
+	  with the WM9712.
+
 config SND_PXA2XX_SOC_PALM27X
 	bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive"
 	depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index af35762..488d903 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -2,11 +2,13 @@
 snd-soc-pxa2xx-objs := pxa2xx-pcm.o
 snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
 snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
+snd-soc-pxa2xx-ssp-objs := pxa2xx-ssp.o
 snd-soc-pxa-ssp-objs := pxa-ssp.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
 obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
 obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
+obj-$(CONFIG_SND_PXA2XX_SOC_SSP) += snd-soc-pxa2xx-ssp.o
 obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o
 
 # PXA Machine Support
@@ -16,8 +18,19 @@ snd-soc-tosa-objs := tosa.o
 snd-soc-e740-objs := e740_wm9705.o
 snd-soc-e750-objs := e750_wm9705.o
 snd-soc-e800-objs := e800_wm9712.o
-snd-soc-spitz-objs := spitz.o
 snd-soc-em-x270-objs := em-x270.o
+snd-soc-spitz-objs := spitz.o
+snd-soc-amesom-tlv320-objs := amesom_tlv320.o
+snd-soc-magician-objs := magician.o
+snd-soc-h5000-objs := h5000.o
+snd-soc-mainstone-objs := mainstone.o
+snd-soc-mainstone-wm8731-objs := mainstone_wm8731.o
+snd-soc-mainstone-wm8753-objs := mainstone_wm8753.o
+snd-soc-mainstone-wm8974-objs := mainstone_wm8974.o
+snd-soc-mainstone-wm9713-objs := mainstone_wm9713.o
+snd-soc-mainstone-wm9712-objs := mainstone_wm9712.o
+snd-soc-mainstone-baseband-objs := mainstone_baseband.o
+snd-soc-mainstone-bluetooth-objs := mainstone_bluetooth.o
 snd-soc-palm27x-objs := palm27x.o
 snd-soc-saarb-objs := saarb.o
 snd-soc-tavorevb3-objs := tavorevb3.o
@@ -35,8 +48,19 @@ obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o
 obj-$(CONFIG_SND_PXA2XX_SOC_E740) += snd-soc-e740.o
 obj-$(CONFIG_SND_PXA2XX_SOC_E750) += snd-soc-e750.o
 obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o
-obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
 obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
+obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
+obj-$(CONFIG_SND_PXA2XX_SOC_AMESOM_TLV320) += snd-soc-amesom-tlv320.o
+obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
+obj-$(CONFIG_SND_PXA2XX_SOC_H5000) += snd-soc-h5000.o
+obj-$(CONFIG_SND_PXA2XX_SOC_MAINSTONE) += snd-soc-mainstone.o
+obj-$(CONFIG_SND_PXA2XX_SOC_MAINSTONE_WM8731) += snd-soc-mainstone-wm8731.o
+obj-$(CONFIG_SND_PXA2XX_SOC_MAINSTONE_WM8753) += snd-soc-mainstone-wm8753.o
+obj-$(CONFIG_SND_PXA2XX_SOC_MAINSTONE_WM8974) += snd-soc-mainstone-wm8974.o
+obj-$(CONFIG_SND_PXA2XX_SOC_MAINSTONE_WM9713) += snd-soc-mainstone-wm9713.o
+obj-$(CONFIG_SND_PXA2xx_SOC_MAINSTONE_WM9712) += snd-soc-mainstone-wm9712.o
+obj-$(CONFIG_SND_MAINSTONE_BASEBAND) += snd-soc-mainstone-baseband.o
+obj-$(CONFIG_SND_MAINSTONE_BLUETOOTH) += snd-soc-mainstone-bluetooth.o
 obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
 obj-$(CONFIG_SND_PXA2XX_SOC_HX4700) += snd-soc-hx4700.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
diff --git a/sound/soc/pxa/amesom_tlv320.c b/sound/soc/pxa/amesom_tlv320.c
new file mode 100644
index 0000000..d4f1ac4
--- /dev/null
+++ b/sound/soc/pxa/amesom_tlv320.c
@@ -0,0 +1,211 @@
+/*
+ * amesom_tlv320.c  --  SoC audio for Amesom
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2006 Atlab srl.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *          Nicola Perrino <nicola.perrino@atlab.it>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    5th Dec 2006   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/audio.h>
+
+#include "../codecs/tlv320.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+#include "pxa2xx-ssp.h"
+
+
+/*
+ * SSP2 GPIO's
+ */
+
+#define GPIO11_SSP2RX_MD	(11 | GPIO_ALT_FN_2_IN)
+#define GPIO13_SSP2TX_MD	(13 | GPIO_ALT_FN_1_OUT)
+#define GPIO50_SSP2CLKS_MD	(50 | GPIO_ALT_FN_3_IN)
+#define GPIO14_SSP2FRMS_MD	(14 | GPIO_ALT_FN_2_IN)
+#define GPIO50_SSP2CLKM_MD	(50 | GPIO_ALT_FN_3_OUT)
+#define GPIO14_SSP2FRMM_MD	(14 | GPIO_ALT_FN_2_OUT)
+
+
+static struct snd_soc_machine amesom;
+
+
+static int amesom_probe(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int amesom_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int tlv320_voice_startup(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static void tlv320_voice_shutdown(struct snd_pcm_substream *substream)
+{
+	return;
+}
+
+/*
+ * Tlv320 uses SSP port for playback.
+ */
+static int tlv320_voice_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret = 0;
+
+	//printk("tlv320_voice_hw_params enter\n");
+	switch(params_rate(params)) {
+	case 8000:
+		//printk("tlv320_voice_hw_params 8000\n");
+		break;
+	case 16000:
+		//printk("tlv320_voice_hw_params 16000\n");
+		break;
+	default:
+		break;
+	}
+
+	// CODEC MASTER, SSP SLAVE
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_MSB |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_MSB |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set the SSP system clock as input (unused) */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_SSP_CLK_NET_PLL, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set SSP slots */
+	//ret = cpu_dai->dai_ops.set_tdm_slot(cpu_dai, 0x1, slots);
+	ret = cpu_dai->dai_ops.set_tdm_slot(cpu_dai, 0x3, 1);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int tlv320_voice_hw_free(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static struct snd_soc_ops tlv320_voice_ops = {
+	.startup = tlv320_voice_startup,
+	.shutdown = tlv320_voice_shutdown,
+	.hw_params = tlv320_voice_hw_params,
+	.hw_free = tlv320_voice_hw_free,
+};
+
+
+static struct snd_soc_dai_link amesom_dai[] = {
+{
+	.name = "TLV320",
+	.stream_name = "TLV320 Voice",
+	.cpu_dai = &pxa_ssp_dai[PXA2XX_DAI_SSP2],
+	.codec_dai = &tlv320_dai[TLV320_DAI_MODE1_VOICE],
+	.ops = &tlv320_voice_ops,
+},
+};
+
+static struct snd_soc_machine amesom = {
+	.name = "Amesom",
+	.probe = amesom_probe,
+	.remove = amesom_remove,
+	.dai_link = amesom_dai,
+	.num_links = ARRAY_SIZE(amesom_dai),
+};
+
+static struct tlv320_setup_data amesom_tlv320_setup = {
+#ifdef TLV320AIC24K //codec2
+	.i2c_address = 0x41,
+#else // TLV320AIC14k
+	.i2c_address = 0x40,
+#endif
+};
+
+static struct snd_soc_device amesom_snd_devdata = {
+	.machine = &amesom,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_tlv320,
+	.codec_data = &amesom_tlv320_setup,
+};
+
+static struct platform_device *amesom_snd_device;
+
+static int __init amesom_init(void)
+{
+	int ret;
+
+	amesom_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!amesom_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(amesom_snd_device, &amesom_snd_devdata);
+	amesom_snd_devdata.dev = &amesom_snd_device->dev;
+	ret = platform_device_add(amesom_snd_device);
+
+	if (ret)
+		platform_device_put(amesom_snd_device);
+
+
+	/* SSP port 2 slave */
+	pxa_gpio_mode(GPIO11_SSP2RX_MD);
+	pxa_gpio_mode(GPIO13_SSP2TX_MD);
+	pxa_gpio_mode(GPIO50_SSP2CLKS_MD);
+	pxa_gpio_mode(GPIO14_SSP2FRMS_MD);
+
+	return ret;
+}
+
+static void __exit amesom_exit(void)
+{
+	platform_device_unregister(amesom_snd_device);
+}
+
+module_init(amesom_init);
+module_exit(amesom_exit);
+
+/* Module information */
+MODULE_AUTHOR("Nicola Perrino");
+MODULE_DESCRIPTION("ALSA SoC TLV320 Amesom");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/h5000.c b/sound/soc/pxa/h5000.c
new file mode 100644
index 0000000..e03c5e5
--- /dev/null
+++ b/sound/soc/pxa/h5000.c
@@ -0,0 +1,363 @@
+/*
+ *
+ * Copyright (c) 2007 Milan Plzik <mmp@handhelds.org>
+ *
+ * based on spitz.c,
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *          Richard Purdie <richard@openedhand.com>
+ *
+ * This code is released under GPL (GNU Public License) with
+ * absolutely no warranty. Please see http://www.gnu.org/ for a
+ * complete discussion of the GPL.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm-arm/arch/gpio.h>
+#include <asm/arch-pxa/h5400-asic.h>
+#include <asm/arch-pxa/h5400-gpio.h>
+#include <asm/hardware/samcop_base.h>
+
+#include "pxa2xx-i2s.h"
+#include "pxa2xx-pcm.h"
+#include "../codecs/ak4535.h"
+
+
+#define H5000_OFF	0
+#define H5000_HP	1
+#define H5000_MIC	2
+
+#define H5000_SPK_OFF	0
+#define H5000_SPK_ON	1
+
+static int h5000_spk_func = 0;
+static int h5000_jack_func = 0;
+
+
+static void h5000_ext_control(struct snd_soc_codec *codec)
+{
+	switch (h5000_spk_func) {
+	case H5000_SPK_OFF:
+		snd_soc_dapm_disable_pin(codec, "Ext Spk");
+		break;
+	case H5000_SPK_ON:
+		snd_soc_dapm_enable_pin(codec, "Ext Spk");
+		break;
+	default:
+		printk (KERN_ERR "%s: invalid value %d for h5000_spk_func\n", 
+			__FUNCTION__, h5000_spk_func);
+		break;
+	};
+
+	switch (h5000_jack_func) {
+	case H5000_OFF:
+		snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+		snd_soc_dapm_enable_pin(codec, "Internal Mic");
+		snd_soc_dapm_disable_pin(codec, "Mic Jack");
+		break;
+	case H5000_HP:
+		snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+		snd_soc_dapm_enable_pin(codec, "Internal Mic");
+		snd_soc_dapm_disable_pin(codec, "Mic Jack");
+		break;
+	case H5000_MIC:
+		snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+		snd_soc_dapm_disable_pin(codec, "Internal Mic");
+		snd_soc_dapm_enable_pin(codec, "Mic Jack");
+		break;
+	default:
+		printk(KERN_ERR "%s: invalid value %d for h5000_jack_func\n", 
+			__FUNCTION__, h5000_jack_func);
+		break;
+	};
+
+	snd_soc_dapm_sync(codec);
+};
+
+static int h5000_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	h5000_ext_control(codec);
+	return 0;
+};
+
+static void h5000_shutdown(struct snd_pcm_substream *substream)
+{
+};
+
+static int h5000_hw_params(struct snd_pcm_substream *substream, 
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int clk = 0;
+	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		clk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 11289600;
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock for DAC and ADC */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as input (unused) */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+		SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+};
+
+static struct snd_soc_ops h5000_ops = {
+	.startup = h5000_startup,
+	.shutdown = h5000_shutdown,
+	.hw_params = h5000_hw_params,
+};
+
+static int h5000_get_jack(struct snd_kcontrol *kcontrol, 
+	struct snd_ctl_elem_value *ucontrol) 
+{
+	ucontrol->value.integer.value [0] = h5000_jack_func;
+	return 0;
+};
+
+static int h5000_set_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip (kcontrol);
+	
+	if (h5000_jack_func == ucontrol->value.integer.value [0])
+		return 0;
+	
+	h5000_jack_func = ucontrol->value.integer.value [0];
+	h5000_ext_control(codec);
+	return 1;
+};
+
+static int h5000_get_spk(struct snd_kcontrol *kcontrol, 
+	struct snd_ctl_elem_value *ucontrol) 
+{	
+	ucontrol->value.integer.value [0] = h5000_spk_func;
+	return 0;
+};
+
+static int h5000_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip (kcontrol);
+	
+	if (h5000_spk_func == ucontrol->value.integer.value [0])
+		return 0;
+	
+	h5000_spk_func = ucontrol->value.integer.value [0];
+	h5000_ext_control(codec);
+	return 1;
+};
+
+static int h5000_audio_power(struct snd_soc_dapm_widget *widget, int event) 
+{
+	// mp - why do we need the ref count, dapm core should ref count all widget use.
+	static int power_use_count = 0;
+	
+	if (SND_SOC_DAPM_EVENT_ON (event))
+		power_use_count ++;
+	else
+		power_use_count --;
+	
+	samcop_set_gpio_b (&h5400_samcop.dev, SAMCOP_GPIO_GPB_AUDIO_POWER_ON, 
+		(power_use_count > 0) ? SAMCOP_GPIO_GPB_AUDIO_POWER_ON : 0 );
+
+	return 0;
+};
+
+static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = {
+	SND_SOC_DAPM_SPK ("Ext Spk", h5000_audio_power),
+	SND_SOC_DAPM_HP ("Headphone Jack", h5000_audio_power),
+	SND_SOC_DAPM_MIC ("Internal Mic", h5000_audio_power),
+};
+
+/* I'm really not sure about this, please fix if neccessary */
+static const char *audio_map [][3] = {
+	/* Speaker is connected to speaker +- pins */
+	{ "Ext Spk", NULL, "SPP" },
+	{ "Ext Spk", NULL, "SPN" },
+
+	/* Mono input to MOUT2 according to reference */
+	{ "MIN", NULL, "MOUT2" },
+
+	/* Headphone output is connected to left and right output */
+	{ "Headphone Jack", NULL, "HPL" },
+	{ "Headphone Jack", NULL, "HPR" },
+
+	/* MICOUT is connected to AIN */
+	{ "AIN", NULL, "MICOUT"},
+
+	/* Microphones */
+	{ "MICIN", NULL, "Internal Mic" },
+	{ "MICEXT", NULL, "Mic Jack" },
+
+	{ NULL, NULL, NULL },
+};
+
+static const char *jack_function [] = { "Off", "Headphone", "Mic", };
+static const char *spk_function [] = { "Off", "On", };
+
+static const struct soc_enum h5000_enum [] = {
+	SOC_ENUM_SINGLE_EXT (2, jack_function),
+	SOC_ENUM_SINGLE_EXT (2, spk_function),
+};
+
+static const struct snd_kcontrol_new ak4535_h5000_controls[] = {
+	SOC_ENUM_EXT ("Jack Function", h5000_enum[0], h5000_get_jack, h5000_set_jack),
+	SOC_ENUM_EXT ("Speaker Function", h5000_enum[1], h5000_get_spk, h5000_set_spk),
+
+};
+
+static int h5000_ak4535_init (struct snd_soc_codec *codec)
+{
+	int i, err;
+	
+	/* NC codec pins */
+	snd_soc_dapm_disable_pin(codec, "MOUT1");
+	snd_soc_dapm_disable_pin(codec, "LOUT");
+	snd_soc_dapm_disable_pin(codec, "ROUT");
+	
+	// mp - not sure I understand here, is the codec driver wrong ?
+	snd_soc_dapm_disable_pin(codec, "MOUT2");	/* FIXME: These pins are marked as INPUTS */
+	snd_soc_dapm_disable_pin(codec, "MIN");	/* FIXME: and OUTPUTS in ak4535.c . We need to do this in order */
+	snd_soc_dapm_disable_pin(codec, "AIN");	/* FIXME: to get DAPM working properly, because the pins are connected */
+	snd_soc_dapm_disable_pin(codec, "MICOUT");	/* FIXME: OUTPUT -> INPUT. */
+
+	/* Add h5000 specific controls */
+	for (i = 0; i < ARRAY_SIZE (ak4535_h5000_controls); i++) {
+		err = snd_ctl_add (codec->card,
+			snd_soc_cnew(&ak4535_h5000_controls[i], codec, NULL));
+		if (err < 0)
+			return err;
+	};
+		
+	/* Add h5000 specific widgets */
+	for (i = 0; i < ARRAY_SIZE (ak4535_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &ak4535_dapm_widgets [i]);
+	};
+
+	/* Set up h5000 specific audio path audio_map */
+	for (i = 0; audio_map [i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map [i][0], 
+			audio_map [i][1], audio_map [i][2]);
+	};
+
+	snd_soc_dapm_sync(codec);
+	return 0;
+};
+
+
+static struct snd_soc_dai_link h5000_dai = {
+	.name = "ak4535",
+	.stream_name = "AK4535",
+	.cpu_dai = &pxa_i2s_dai,
+	.codec_dai = &ak4535_dai,
+	.init = h5000_ak4535_init,
+	.ops = &h5000_ops,
+};
+
+static struct snd_soc_machine snd_soc_machine_h5000 = {
+	.name = "h5000",
+	.dai_link = &h5000_dai,
+	.num_links = 1,
+};
+
+static struct ak4535_setup_data h5000_codec_setup = {
+	.i2c_address = 0x10,
+};
+
+static struct snd_soc_device h5000_snd_devdata = {
+	.machine = &snd_soc_machine_h5000,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_ak4535,
+	.codec_data = &h5000_codec_setup,
+};
+
+static struct platform_device *h5000_snd_device;
+
+static int __init h5000_init(void)
+{
+	int ret;
+
+	if (!machine_is_h5400 ())
+		return -ENODEV;
+
+	request_module("i2c-pxa");
+
+	h5000_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!h5000_snd_device)
+		return -ENOMEM;
+	
+	/* enable audio codec */
+	samcop_set_gpio_b(&h5400_samcop.dev, 
+		SAMCOP_GPIO_GPB_CODEC_POWER_ON, SAMCOP_GPIO_GPB_CODEC_POWER_ON);
+
+	platform_set_drvdata(h5000_snd_device, &h5000_snd_devdata);
+
+	h5000_snd_devdata.dev = &h5000_snd_device->dev;
+	ret = platform_device_add(h5000_snd_device);
+	if (ret)
+		platform_device_put(h5000_snd_device);
+
+	return ret;
+	
+};
+
+static void __exit h5000_exit(void)
+{
+	platform_device_unregister(h5000_snd_device);
+	
+	samcop_set_gpio_b(&h5400_samcop.dev, 
+		SAMCOP_GPIO_GPB_CODEC_POWER_ON | SAMCOP_GPIO_GPB_AUDIO_POWER_ON, 0);
+};
+
+module_init (h5000_init);
+module_exit (h5000_exit);
+
+MODULE_AUTHOR ("Milan Plzik");
+MODULE_DESCRIPTION ("ALSA SoC iPAQ h5000");
+MODULE_LICENSE ("GPL");
diff --git a/sound/soc/pxa/mainstone.c b/sound/soc/pxa/mainstone.c
new file mode 100644
index 0000000..0103235
--- /dev/null
+++ b/sound/soc/pxa/mainstone.c
@@ -0,0 +1,123 @@
+/*
+ * mainstone.c  --  SoC audio for Mainstone
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  Mainstone audio amplifier code taken from arch/arm/mach-pxa/mainstone.c
+ *  Copyright:	MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    30th Oct 2005   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <mach/pxa-regs.h>
+#include <mach/mainstone.h>
+#include <mach/audio.h>
+
+#include "../codecs/ac97.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+static struct snd_soc_machine mainstone;
+static long mst_audio_suspend_mask;
+
+static int mainstone_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	mst_audio_suspend_mask = MST_MSCWR2;
+	MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_resume(struct platform_device *pdev)
+{
+	MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_probe(struct platform_device *pdev)
+{
+	MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_remove(struct platform_device *pdev)
+{
+	MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static struct snd_soc_dai_link codecs[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+	.codec_dai = &ac97_dai,
+},
+};
+
+static struct snd_soc_machine mainstone = {
+	.name = "Mainstone",
+	.probe = mainstone_probe,
+	.remove = mainstone_remove,
+	.suspend_pre = mainstone_suspend,
+	.resume_post = mainstone_resume,
+	.dai_link = codecs,
+	.num_links = ARRAY_SIZE(codecs),
+};
+
+static struct snd_soc_device mainstone_snd_devdata = {
+	.machine = &mainstone,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *mainstone_snd_device;
+
+static int __init mainstone_init(void)
+{
+	int ret;
+
+	mainstone_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!mainstone_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mainstone_snd_device, &mainstone_snd_devdata);
+	mainstone_snd_devdata.dev = &mainstone_snd_device->dev;
+	ret = platform_device_add(mainstone_snd_device);
+
+	if (ret)
+		platform_device_put(mainstone_snd_device);
+
+	return ret;
+}
+
+static void __exit mainstone_exit(void)
+{
+	platform_device_unregister(mainstone_snd_device);
+}
+
+module_init(mainstone_init);
+module_exit(mainstone_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC Mainstone");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/mainstone_baseband.c b/sound/soc/pxa/mainstone_baseband.c
new file mode 100644
index 0000000..9fa813b
--- /dev/null
+++ b/sound/soc/pxa/mainstone_baseband.c
@@ -0,0 +1,210 @@
+/*
+ * mainstone_baseband.c
+ * Mainstone Example Baseband modem  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    15th Apr 2006   Initial version.
+ *
+ * This is example code to demonstrate connecting a baseband modem to the PCM
+ * DAI on the WM9713 codec on the Intel Mainstone platform. It is by no means
+ * complete as it requires code to control the modem.
+ *
+ * The architecture consists of the WM9713 AC97 DAI connected to the PXA27x
+ * AC97 controller and the WM9713 PCM DAI connected to the basebands DAI. The
+ * baseband is controlled via a serial port. Audio is routed between the PXA27x
+ * and the baseband via internal WM9713 analog paths.
+ *
+ * This driver is not the baseband modem driver. This driver only calls
+ * functions from the Baseband driver to set up it's PCM DAI.
+ *
+ * It's intended to use this driver as follows:-
+ *
+ *  1. open() WM9713 PCM audio device.
+ *  2. open() serial device (for AT commands).
+ *  3. configure PCM audio device (rate etc) - sets up WM9713 PCM DAI,
+ *      this will also set up the baseband PCM DAI (via calling baseband driver).
+ *  4. send any further AT commands to set up baseband.
+ *  5. configure codec audio mixer paths.
+ *  6. open(), configure and read/write AC97 audio device - to Tx/Rx voice
+ *
+ * The PCM audio device is opened but IO is never performed on it as the IO is
+ * directly between the codec and the baseband (and not the CPU).
+ *
+ * TODO:
+ *  o Implement callbacks
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <mach/pxa-regs.h>
+#include <mach/audio.h>
+#include <mach/ssp.h>
+
+#include "../codecs/wm9713.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+#include "pxa2xx-ssp.h"
+
+static struct snd_soc_machine mainstone;
+
+/* Do specific baseband PCM voice startup here */
+static int baseband_startup(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+/* Do specific baseband PCM voice shutdown here */
+static void baseband_shutdown (struct snd_pcm_substream *substream)
+{
+}
+
+/* Do specific baseband modem PCM voice hw params init here */
+static int baseband_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	return 0;
+}
+
+/* Do specific baseband modem PCM voice hw params free here */
+static int baseband_hw_free(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+/*
+ * Baseband Processor DAI
+ */
+static struct snd_soc_dai baseband_dai =
+{	.name = "Baseband",
+	.id = 0,
+	.type = SND_SOC_DAI_PCM,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.startup = baseband_startup,
+		.shutdown = baseband_shutdown,
+		.hw_params = baseband_hw_params,
+		.hw_free = baseband_hw_free,
+		},
+};
+
+/* PM */
+static int mainstone_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	return 0;
+}
+
+static int mainstone_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int mainstone_probe(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int mainstone_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int mainstone_wm9713_init(struct snd_soc_codec *codec)
+{
+	return 0;
+}
+
+/* the physical audio connections between the WM9713, Baseband and pxa2xx */
+static struct snd_soc_dai_link mainstone_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+	.codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+	.init = mainstone_wm9713_init,
+},
+{
+	.name = "AC97 Aux",
+	.stream_name = "AC97 Aux",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+	.codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+},
+{
+	.name = "Baseband",
+	.stream_name = "Voice",
+	.cpu_dai = &baseband_dai,
+	.codec_dai = &wm9713_dai[WM9713_DAI_PCM_VOICE],
+},
+};
+
+static struct snd_soc_machine mainstone = {
+	.name = "Mainstone",
+	.probe = mainstone_probe,
+	.remove = mainstone_remove,
+	.suspend_pre = mainstone_suspend,
+	.resume_post = mainstone_resume,
+	.dai_link = mainstone_dai,
+	.num_links = ARRAY_SIZE(mainstone_dai),
+};
+
+static struct snd_soc_device mainstone_snd_ac97_devdata = {
+	.machine = &mainstone,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm9713,
+};
+
+static struct platform_device *mainstone_snd_ac97_device;
+
+static int __init mainstone_init(void)
+{
+	int ret;
+
+	mainstone_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+	if (!mainstone_snd_ac97_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mainstone_snd_ac97_device, &mainstone_snd_ac97_devdata);
+	mainstone_snd_ac97_devdata.dev = &mainstone_snd_ac97_device->dev;
+
+	if((ret = platform_device_add(mainstone_snd_ac97_device)) != 0)
+		platform_device_put(mainstone_snd_ac97_device);
+
+	return ret;
+}
+
+static void __exit mainstone_exit(void)
+{
+	platform_device_unregister(mainstone_snd_ac97_device);
+}
+
+module_init(mainstone_init);
+module_exit(mainstone_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("Mainstone Example Baseband PCM Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/mainstone_bluetooth.c b/sound/soc/pxa/mainstone_bluetooth.c
new file mode 100644
index 0000000..262d5d6
--- /dev/null
+++ b/sound/soc/pxa/mainstone_bluetooth.c
@@ -0,0 +1,379 @@
+/*
+ * mainstone_bluetooth.c
+ * Mainstone Example Bluetooth  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    15th May 2006   Initial version.
+ *
+ * This is example code to demonstrate connecting a bluetooth codec to the PCM
+ * DAI on the WM8753 codec on the Intel Mainstone platform. It is by no means
+ * complete as it requires code to control the BT codec.
+ *
+ * The architecture consists of the WM8753 HIFI DAI connected to the PXA27x
+ * I2S controller and the WM8753 PCM DAI connected to the bluetooth DAI. The
+ * bluetooth codec and wm8753 are controlled via I2C. Audio is routed between
+ * the PXA27x and the bluetooth via internal WM8753 analog paths.
+ *
+ * This example supports the following audio input/outputs.
+ *
+ *  o Board mounted Mic and Speaker (spk has amplifier)
+ *  o Headphones via jack socket
+ *  o BT source and sink
+ *
+ * This driver is not the bluetooth codec driver. This driver only calls
+ * functions from the Bluetooth driver to set up it's PCM DAI.
+ *
+ * It's intended to use the driver as follows:-
+ *
+ *  1. open() WM8753 PCM audio device.
+ *  2. configure PCM audio device (rate etc) - sets up WM8753 PCM DAI,
+ *      this should also set up the BT codec DAI (via calling bt driver).
+ *  3. configure codec audio mixer paths.
+ *  4. open(), configure and read/write HIFI audio device - to Tx/Rx voice
+ *
+ * The PCM audio device is opened but IO is never performed on it as the IO is
+ * directly between the codec and the BT codec (and not the CPU).
+ *
+ * TODO:
+ *  o Implement callbacks
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <mach/pxa-regs.h>
+#include <mach/audio.h>
+#include <mach/ssp.h>
+
+#include "../codecs/wm8753.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+#include "pxa2xx-ssp.h"
+
+static struct snd_soc_machine mainstone;
+
+/* Do specific bluetooth PCM startup here */
+static int bt_startup(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+/* Do specific bluetooth PCM shutdown here */
+static void bt_shutdown (struct snd_pcm_substream *substream)
+{
+}
+
+/* Do pecific bluetooth PCM hw params init here */
+static int bt_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	return 0;
+}
+
+/* Do specific bluetooth PCM hw params free here */
+static int bt_hw_free(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+#define BT_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100)
+
+/*
+ * BT Codec DAI
+ */
+static struct snd_soc_dai bt_dai =
+{	.name = "Bluetooth",
+	.id = 0,
+	.type = SND_SOC_DAI_PCM,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = BT_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = BT_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.startup = bt_startup,
+		.shutdown = bt_shutdown,
+		.hw_params = bt_hw_params,
+		.hw_free = bt_hw_free,
+		},
+};
+
+/* PM */
+static int mainstone_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	return 0;
+}
+
+static int mainstone_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int mainstone_probe(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int mainstone_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+/*
+ * Machine audio functions.
+ *
+ * The machine now has 3 extra audio controls.
+ *
+ * Jack function: Sets function (device plugged into Jack) to nothing (Off)
+ *                or Headphones.
+ *
+ * Mic function: Set the on board Mic to On or Off
+ * Spk function: Set the on board Spk to On or Off
+ *
+ * example: BT playback (of far end) and capture (of near end)
+ *  Set Mic and Speaker to On, open BT alsa interface as above and set up
+ *  internal audio paths.
+ */
+
+static int machine_jack_func = 0;
+static int machine_spk_func = 0;
+static int machine_mic_func = 0;
+
+static int machine_get_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = machine_jack_func;
+	return 0;
+}
+
+static int machine_set_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+	machine_jack_func = ucontrol->value.integer.value[0];
+	if (machine_jack_func)
+		snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+	else
+		snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+	return 0;
+}
+
+static int machine_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = machine_spk_func;
+	return 0;
+}
+
+static int machine_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+	if (machine_spk_func == ucontrol->value.integer.value[0])
+		return 0;
+
+	machine_spk_func = ucontrol->value.integer.value[0];
+	if (machine_spk_func)
+		snd_soc_dapm_enable_pin(codec, "Spk");
+	else
+		snd_soc_dapm_disable_pin(codec, "Spk");
+
+	return 1;
+}
+
+static int machine_get_mic(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = machine_spk_func;
+	return 0;
+}
+
+static int machine_set_mic(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+	if (machine_spk_func == ucontrol->value.integer.value[0])
+		return 0;
+
+	machine_spk_func = ucontrol->value.integer.value[0];
+	if (machine_spk_func)
+		snd_soc_dapm_enable_pin(codec, "Mic");
+	else
+		snd_soc_dapm_disable_pin(codec, "Mic");
+	return 1;
+}
+
+/* turns on board speaker amp on/off */
+static int machine_amp_event(struct snd_soc_dapm_widget *w, int event)
+{
+#if 0
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		/* on */
+	else
+		/* off */
+#endif
+	return 0;
+}
+
+/* machine dapm widgets */
+static const struct snd_soc_dapm_widget machine_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", NULL),
+SND_SOC_DAPM_SPK("Spk", machine_amp_event),
+SND_SOC_DAPM_MIC("Mic", NULL),
+};
+
+/* machine connections to the codec pins */
+static const char* audio_map[][3] = {
+
+	/* headphone connected to LOUT1, ROUT1 */
+	{"Headphone Jack", NULL, "LOUT"},
+	{"Headphone Jack", NULL, "ROUT"},
+
+	/* speaker connected to LOUT2, ROUT2 */
+	{"Spk", NULL, "ROUT2"},
+	{"Spk", NULL, "LOUT2"},
+
+	/* mic is connected to MIC1 (via Mic Bias) */
+	{"MIC1", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic"},
+
+	{NULL, NULL, NULL},
+};
+
+static const char* jack_function[] = {"Off", "Headphone"};
+static const char* spk_function[] = {"Off", "On"};
+static const char* mic_function[] = {"Off", "On"};
+static const struct soc_enum machine_ctl_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, jack_function),
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+	SOC_ENUM_SINGLE_EXT(2, mic_function),
+};
+
+static const struct snd_kcontrol_new wm8753_machine_controls[] = {
+	SOC_ENUM_EXT("Jack Function", machine_ctl_enum[0], machine_get_jack, machine_set_jack),
+	SOC_ENUM_EXT("Speaker Function", machine_ctl_enum[1], machine_get_spk, machine_set_spk),
+	SOC_ENUM_EXT("Mic Function", machine_ctl_enum[2], machine_get_mic, machine_set_mic),
+};
+
+static int mainstone_wm8753_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+
+	/* not used on this machine - e.g. will never be powered up */
+	snd_soc_dapm_disable_pin(codec, "OUT3");
+	snd_soc_dapm_disable_pin(codec, "OUT4");
+	snd_soc_dapm_disable_pin(codec, "MONO2");
+	snd_soc_dapm_disable_pin(codec, "MONO1");
+	snd_soc_dapm_disable_pin(codec, "LINE1");
+	snd_soc_dapm_disable_pin(codec, "LINE2");
+	snd_soc_dapm_disable_pin(codec, "RXP");
+	snd_soc_dapm_disable_pin(codec, "RXN");
+	snd_soc_dapm_disable_pin(codec, "MIC2");
+
+	/* Add machine specific controls */
+	for (i = 0; i < ARRAY_SIZE(wm8753_machine_controls); i++) {
+		if ((err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&wm8753_machine_controls[i],codec, NULL))) < 0)
+			return err;
+	}
+
+	/* Add machine specific widgets */
+	for(i = 0; i < ARRAY_SIZE(machine_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &machine_dapm_widgets[i]);
+	}
+
+	/* Set up machine specific audio path audio_mapnects */
+	for(i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0], audio_map[i][1], audio_map[i][2]);
+	}
+
+	snd_soc_dapm_sync(codec);
+	return 0;
+}
+
+static struct snd_soc_dai_link mainstone_dai[] = {
+{ /* Hifi Playback - for similatious use with voice below */
+	.name = "WM8753",
+	.stream_name = "WM8753 HiFi",
+	.cpu_dai = &pxa_i2s_dai,
+	.codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+	.init = mainstone_wm8753_init,
+},
+{ /* Voice via BT */
+	.name = "Bluetooth",
+	.stream_name = "Voice",
+	.cpu_dai = &bt_dai,
+	.codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+},
+};
+
+static struct snd_soc_machine mainstone = {
+	.name = "Mainstone",
+	.probe = mainstone_probe,
+	.remove = mainstone_remove,
+	.suspend_pre = mainstone_suspend,
+	.resume_post = mainstone_resume,
+	.dai_link = mainstone_dai,
+	.num_links = ARRAY_SIZE(mainstone_dai),
+};
+
+static struct snd_soc_device mainstone_snd_wm8753_devdata = {
+	.machine = &mainstone,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8753,
+};
+
+static struct platform_device *mainstone_snd_wm8753_device;
+
+static int __init mainstone_init(void)
+{
+	int ret;
+
+	mainstone_snd_wm8753_device = platform_device_alloc("soc-audio", -1);
+	if (!mainstone_snd_wm8753_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mainstone_snd_wm8753_device, &mainstone_snd_wm8753_devdata);
+	mainstone_snd_wm8753_devdata.dev = &mainstone_snd_wm8753_device->dev;
+
+	if((ret = platform_device_add(mainstone_snd_wm8753_device)) != 0)
+		platform_device_put(mainstone_snd_wm8753_device);
+
+	return ret;
+}
+
+static void __exit mainstone_exit(void)
+{
+	platform_device_unregister(mainstone_snd_wm8753_device);
+}
+
+module_init(mainstone_init);
+module_exit(mainstone_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("Mainstone Example Bluetooth PCM Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/mainstone_wm8731.c b/sound/soc/pxa/mainstone_wm8731.c
new file mode 100644
index 0000000..a32faa1
--- /dev/null
+++ b/sound/soc/pxa/mainstone_wm8731.c
@@ -0,0 +1,209 @@
+/*
+ * mainstone.c  --  SoC audio for Mainstone
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  Mainstone audio amplifier code taken from arch/arm/mach-pxa/mainstone.c
+ *  Copyright:	MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    5th June 2006   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mainstone.h>
+#include <asm/arch/audio.h>
+
+#include "../codecs/wm8731.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+
+static struct snd_soc_machine mainstone;
+
+static int mainstone_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int clk = 0;
+	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		clk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 11289600;
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock for DAC and ADC */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as input (unused) */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops mainstone_ops = {
+	.hw_params = mainstone_hw_params,
+};
+
+static const struct snd_soc_dapm_widget dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("Int Mic", NULL),
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const char* intercon[][3] = {
+
+	/* speaker connected to LHPOUT */
+	{"Ext Spk", NULL, "LHPOUT"},
+
+	/* mic is connected to Mic Jack, with WM8731 Mic Bias */
+	{"MICIN", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Int Mic"},
+
+	/* terminator */
+	{NULL, NULL, NULL},
+};
+
+/*
+ * Logic for a wm8731 as connected on a Endrelia ETI-B1 board.
+ */
+static int mainstone_wm8731_init(struct snd_soc_codec *codec)
+{
+	int i;
+
+
+	/* Add specific widgets */
+	for(i = 0; i < ARRAY_SIZE(dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &dapm_widgets[i]);
+	}
+
+	/* Set up specific audio path interconnects */
+	for(i = 0; intercon[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, intercon[i][0], intercon[i][1], intercon[i][2]);
+	}
+
+	/* not connected */
+	snd_soc_dapm_disable_pin(codec, "RLINEIN");
+	snd_soc_dapm_disable_pin(codec, "LLINEIN");
+
+	/* always connected */
+	snd_soc_dapm_enable_pin(codec, "Int Mic");
+	snd_soc_dapm_enable_pin(codec, "Ext Spk");
+
+	snd_soc_dapm_sync(codec);
+
+	return 0;
+}
+
+static struct snd_soc_dai_link mainstone_dai[] = {
+{
+	.name = "WM8731",
+	.stream_name = "WM8731 HiFi",
+	.cpu_dai = &pxa_i2s_dai,
+	.codec_dai = &wm8731_dai,
+	.init = mainstone_wm8731_init,
+	.ops = &mainstone_ops,
+	},
+};
+
+static struct snd_soc_machine mainstone = {
+	.name = "Mainstone",
+	.dai_link = mainstone_dai,
+	.num_links = ARRAY_SIZE(mainstone_dai),
+};
+
+static struct wm8731_setup_data corgi_wm8731_setup = {
+	.i2c_address = 0x1b,
+};
+
+static struct snd_soc_device mainstone_snd_devdata = {
+	.machine = &mainstone,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8731,
+	.codec_data = &corgi_wm8731_setup,
+};
+
+static struct platform_device *mainstone_snd_device;
+
+static int __init mainstone_init(void)
+{
+	int ret;
+
+	mainstone_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!mainstone_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mainstone_snd_device, &mainstone_snd_devdata);
+	mainstone_snd_devdata.dev = &mainstone_snd_device->dev;
+	ret = platform_device_add(mainstone_snd_device);
+
+	if (ret)
+		platform_device_put(mainstone_snd_device);
+
+	/* I2S SoC master */
+	pxa_gpio_mode(GPIO29_SDATA_IN_I2S_MD);
+	pxa_gpio_mode(GPIO30_SDATA_OUT_I2S_MD);
+	pxa_gpio_mode(GPIO31_SYNC_I2S_MD);
+	pxa_gpio_mode(GPIO28_BITCLK_OUT_I2S_MD);
+
+	return ret;
+}
+
+static void __exit mainstone_exit(void)
+{
+	platform_device_unregister(mainstone_snd_device);
+}
+
+module_init(mainstone_init);
+module_exit(mainstone_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM8731 Mainstone");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/mainstone_wm8753.c b/sound/soc/pxa/mainstone_wm8753.c
new file mode 100644
index 0000000..8331645
--- /dev/null
+++ b/sound/soc/pxa/mainstone_wm8753.c
@@ -0,0 +1,557 @@
+/*
+ * mainstone.c  --  SoC audio for Mainstone
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  Mainstone audio amplifier code taken from arch/arm/mach-pxa/mainstone.c
+ *  Copyright:	MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    30th Oct 2005   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mainstone.h>
+#include <asm/arch/audio.h>
+
+#include "../codecs/wm8753.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+#include "pxa2xx-ssp.h"
+
+/*
+ * SSP GPIO's
+ */
+#define GPIO26_SSP1RX_MD	(26 | GPIO_ALT_FN_1_IN)
+#define GPIO25_SSP1TX_MD	(25 | GPIO_ALT_FN_2_OUT)
+#define GPIO23_SSP1CLKS_MD	(23 | GPIO_ALT_FN_2_IN)
+#define GPIO24_SSP1FRMS_MD	(24 | GPIO_ALT_FN_2_IN)
+#define GPIO23_SSP1CLKM_MD	(23 | GPIO_ALT_FN_2_OUT)
+#define GPIO24_SSP1FRMM_MD	(24 | GPIO_ALT_FN_2_OUT)
+#define GPIO53_SSP1SYSCLK_MD	(53 | GPIO_ALT_FN_2_OUT)
+
+#define GPIO11_SSP2RX_MD	(11 | GPIO_ALT_FN_2_IN)
+#define GPIO13_SSP2TX_MD	(13 | GPIO_ALT_FN_1_OUT)
+#define GPIO22_SSP2CLKS_MD	(22 | GPIO_ALT_FN_3_IN)
+#define GPIO88_SSP2FRMS_MD	(88 | GPIO_ALT_FN_3_IN)
+#define GPIO22_SSP2CLKM_MD	(22 | GPIO_ALT_FN_3_OUT)
+#define GPIO88_SSP2FRMM_MD	(88 | GPIO_ALT_FN_3_OUT)
+#define GPIO22_SSP2SYSCLK_MD	(22 | GPIO_ALT_FN_2_OUT)
+
+#define GPIO82_SSP3RX_MD	(82 | GPIO_ALT_FN_1_IN)
+#define GPIO81_SSP3TX_MD	(81 | GPIO_ALT_FN_1_OUT)
+#define GPIO84_SSP3CLKS_MD	(84 | GPIO_ALT_FN_1_IN)
+#define GPIO83_SSP3FRMS_MD	(83 | GPIO_ALT_FN_1_IN)
+#define GPIO84_SSP3CLKM_MD	(84 | GPIO_ALT_FN_1_OUT)
+#define GPIO83_SSP3FRMM_MD	(83 | GPIO_ALT_FN_1_OUT)
+#define GPIO45_SSP3SYSCLK_MD	(45 | GPIO_ALT_FN_3_OUT)
+
+#if 0
+static struct pxa2xx_gpio ssp_gpios[3][4] = {
+	{{ /* SSP1 SND_SOC_DAIFMT_CBM_CFM */
+		.rx = GPIO26_SSP1RX_MD,
+		.tx = GPIO25_SSP1TX_MD,
+		.clk = (23 | GPIO_ALT_FN_2_IN),
+		.frm = (24 | GPIO_ALT_FN_2_IN),
+		.sys = GPIO53_SSP1SYSCLK_MD,
+	},
+	{ /* SSP1 SND_SOC_DAIFMT_CBS_CFS */
+		.rx = GPIO26_SSP1RX_MD,
+		.tx = GPIO25_SSP1TX_MD,
+		.clk = (23 | GPIO_ALT_FN_2_OUT),
+		.frm = (24 | GPIO_ALT_FN_2_OUT),
+		.sys = GPIO53_SSP1SYSCLK_MD,
+	},
+	{ /* SSP1 SND_SOC_DAIFMT_CBS_CFM */
+		.rx = GPIO26_SSP1RX_MD,
+		.tx = GPIO25_SSP1TX_MD,
+		.clk = (23 | GPIO_ALT_FN_2_OUT),
+		.frm = (24 | GPIO_ALT_FN_2_IN),
+		.sys = GPIO53_SSP1SYSCLK_MD,
+	},
+	{ /* SSP1 SND_SOC_DAIFMT_CBM_CFS */
+		.rx = GPIO26_SSP1RX_MD,
+		.tx = GPIO25_SSP1TX_MD,
+		.clk = (23 | GPIO_ALT_FN_2_IN),
+		.frm = (24 | GPIO_ALT_FN_2_OUT),
+		.sys = GPIO53_SSP1SYSCLK_MD,
+	}},
+	{{ /* SSP2 SND_SOC_DAIFMT_CBM_CFM */
+		.rx = GPIO11_SSP2RX_MD,
+		.tx = GPIO13_SSP2TX_MD,
+		.clk = (22 | GPIO_ALT_FN_3_IN),
+		.frm = (88 | GPIO_ALT_FN_3_IN),
+		.sys = GPIO22_SSP2SYSCLK_MD,
+	},
+	{ /* SSP2 SND_SOC_DAIFMT_CBS_CFS */
+		.rx = GPIO11_SSP2RX_MD,
+		.tx = GPIO13_SSP2TX_MD,
+		.clk = (22 | GPIO_ALT_FN_3_OUT),
+		.frm = (88 | GPIO_ALT_FN_3_OUT),
+		.sys = GPIO22_SSP2SYSCLK_MD,
+	},
+	{ /* SSP2 SND_SOC_DAIFMT_CBS_CFM */
+		.rx = GPIO11_SSP2RX_MD,
+		.tx = GPIO13_SSP2TX_MD,
+		.clk = (22 | GPIO_ALT_FN_3_OUT),
+		.frm = (88 | GPIO_ALT_FN_3_IN),
+		.sys = GPIO22_SSP2SYSCLK_MD,
+	},
+	{ /* SSP2 SND_SOC_DAIFMT_CBM_CFS */
+		.rx = GPIO11_SSP2RX_MD,
+		.tx = GPIO13_SSP2TX_MD,
+		.clk = (22 | GPIO_ALT_FN_3_IN),
+		.frm = (88 | GPIO_ALT_FN_3_OUT),
+		.sys = GPIO22_SSP2SYSCLK_MD,
+	}},
+	{{ /* SSP3 SND_SOC_DAIFMT_CBM_CFM */
+		.rx = GPIO82_SSP3RX_MD,
+		.tx = GPIO81_SSP3TX_MD,
+		.clk = (84 | GPIO_ALT_FN_3_IN),
+		.frm = (83 | GPIO_ALT_FN_3_IN),
+		.sys = GPIO45_SSP3SYSCLK_MD,
+	},
+	{ /* SSP3 SND_SOC_DAIFMT_CBS_CFS */
+		.rx = GPIO82_SSP3RX_MD,
+		.tx = GPIO81_SSP3TX_MD,
+		.clk = (84 | GPIO_ALT_FN_3_OUT),
+		.frm = (83 | GPIO_ALT_FN_3_OUT),
+		.sys = GPIO45_SSP3SYSCLK_MD,
+	},
+	{ /* SSP3 SND_SOC_DAIFMT_CBS_CFM */
+		.rx = GPIO82_SSP3RX_MD,
+		.tx = GPIO81_SSP3TX_MD,
+		.clk = (84 | GPIO_ALT_FN_3_OUT),
+		.frm = (83 | GPIO_ALT_FN_3_IN),
+		.sys = GPIO45_SSP3SYSCLK_MD,
+	},
+	{ /* SSP3 SND_SOC_DAIFMT_CBM_CFS */
+		.rx = GPIO82_SSP3RX_MD,
+		.tx = GPIO81_SSP3TX_MD,
+		.clk = (84 | GPIO_ALT_FN_3_IN),
+		.frm = (83 | GPIO_ALT_FN_3_OUT),
+		.sys = GPIO45_SSP3SYSCLK_MD,
+	}},
+};
+#endif
+
+static struct snd_soc_machine mainstone;
+
+static int mainstone_hifi_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int pll_out = 0, bclk = 0, fmt = 0;
+	int ret = 0;
+
+	/*
+	 * The WM8753 is far better at generating accurate audio clocks than the
+	 * pxa2xx I2S controller, so we will use it as master when we can.
+	 * i.e all rates except 8k and 16k as BCLK must be 64 * rate when the
+	 * pxa27x or pxa25x is slave. Note this restriction does not apply to SSP
+	 * I2S emulation mode.
+	 */
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+		fmt = SND_SOC_DAIFMT_CBS_CFS;
+		pll_out = 12288000;
+		break;
+	case 48000:
+		fmt = SND_SOC_DAIFMT_CBM_CFS;
+		bclk = WM8753_BCLK_DIV_4;
+		pll_out = 12288000;
+		break;
+	case 96000:
+		fmt = SND_SOC_DAIFMT_CBM_CFS;
+		bclk = WM8753_BCLK_DIV_2;
+		pll_out = 12288000;
+		break;
+	case 11025:
+		fmt = SND_SOC_DAIFMT_CBM_CFS;
+		bclk = WM8753_BCLK_DIV_16;
+		pll_out = 11289600;
+		break;
+	case 22050:
+		fmt = SND_SOC_DAIFMT_CBM_CFS;
+		bclk = WM8753_BCLK_DIV_8;
+		pll_out = 11289600;
+		break;
+	case 44100:
+		fmt = SND_SOC_DAIFMT_CBM_CFS;
+		bclk = WM8753_BCLK_DIV_4;
+		pll_out = 11289600;
+		break;
+	case 88200:
+		fmt = SND_SOC_DAIFMT_CBM_CFS;
+		bclk = WM8753_BCLK_DIV_2;
+		pll_out = 11289600;
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai,
+		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | fmt);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
+		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | fmt);
+	if (ret < 0)
+		return ret;
+
+	if (fmt == SND_SOC_DAIFMT_CBM_CFS)
+		pxa_gpio_mode(GPIO28_BITCLK_IN_I2S_MD);
+	else
+		pxa_gpio_mode(GPIO28_BITCLK_OUT_I2S_MD);
+
+	/* set the codec system clock for DAC and ADC */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as input (unused) */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set codec BCLK division for sample rate */
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
+	if (ret < 0)
+		return ret;
+
+	/* codec PLL input is 13 MHz */
+	ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 13000000, pll_out);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int mainstone_hifi_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+
+	/* disable the PLL */
+	return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0);
+}
+
+/*
+ * Mainstone WM8753 HiFi DAI opserations.
+ */
+static struct snd_soc_ops mainstone_hifi_ops = {
+	.hw_params = mainstone_hifi_hw_params,
+	.hw_free = mainstone_hifi_hw_free,
+};
+
+static int mainstone_voice_startup(struct snd_pcm_substream *substream)
+{
+	/* enable USB on the go MUX so we can use SSPFRM2 */
+	MST_MSCWR2 |= MST_MSCWR2_USB_OTG_SEL;
+	MST_MSCWR2 &= ~MST_MSCWR2_USB_OTG_RST;
+
+	return 0;
+}
+
+static void mainstone_voice_shutdown(struct snd_pcm_substream *substream)
+{
+//	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	/* disable USB on the go MUX so we can use ttyS0 */
+	MST_MSCWR2 &= ~MST_MSCWR2_USB_OTG_SEL;
+	MST_MSCWR2 |= MST_MSCWR2_USB_OTG_RST;
+
+	/* liam may need to tristate DAI */
+}
+
+static int mainstone_voice_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int pll_out = 0, bclk = 0, pcmdiv = 0;
+	int ret = 0;
+
+	/*
+	 * The WM8753 is far better at generating accurate audio clocks than the
+	 * pxa2xx SSP controller, so we will use it as master when we can.
+	 */
+	switch (params_rate(params)) {
+	case 8000:
+		pll_out = 12288000;
+		pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
+		bclk = WM8753_VXCLK_DIV_8; /* 256kHz */
+		break;
+	case 16000:
+		pll_out = 12288000;
+		pcmdiv = WM8753_PCM_DIV_3; /* 4.096 MHz */
+		bclk = WM8753_VXCLK_DIV_8; /* 512kHz */
+		break;
+	case 48000:
+		pll_out = 12288000;
+		pcmdiv = WM8753_PCM_DIV_1; /* 12.288 MHz */
+		bclk = WM8753_VXCLK_DIV_8; /* 1.536 MHz */
+		break;
+	case 11025:
+		pll_out = 11289600;
+		pcmdiv = WM8753_PCM_DIV_4; /* 11.2896 MHz */
+		bclk = WM8753_VXCLK_DIV_8; /* 352.8 kHz */
+		break;
+	case 22050:
+		pll_out = 11289600;
+		pcmdiv = WM8753_PCM_DIV_2; /* 11.2896 MHz */
+		bclk = WM8753_VXCLK_DIV_8; /* 705.6 kHz */
+		break;
+	case 44100:
+		pll_out = 11289600;
+		pcmdiv = WM8753_PCM_DIV_1; /* 11.2896 MHz */
+		bclk = WM8753_VXCLK_DIV_8; /* 1.4112 MHz */
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock for DAC and ADC */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, pll_out,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the SSP system clock as input (unused) */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_SSP_CLK_PLL, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set codec BCLK division for sample rate */
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_VXCLKDIV, bclk);
+	if (ret < 0)
+		return ret;
+
+	/* set codec PCM division for sample rate */
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
+	if (ret < 0)
+		return ret;
+
+	/* codec PLL input is 13 MHz */
+	ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 13000000, pll_out);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int mainstone_voice_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+
+	/* disable the PLL */
+	return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0);
+}
+
+static struct snd_soc_ops mainstone_voice_ops = {
+	.startup = mainstone_voice_startup,
+	.shutdown = mainstone_voice_shutdown,
+	.hw_params = mainstone_voice_hw_params,
+	.hw_free = mainstone_voice_hw_free,
+};
+
+static long mst_audio_suspend_mask;
+
+static int mainstone_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	mst_audio_suspend_mask = MST_MSCWR2;
+	MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_resume(struct platform_device *pdev)
+{
+	MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_probe(struct platform_device *pdev)
+{
+	MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_remove(struct platform_device *pdev)
+{
+	MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+/* example machine audio_mapnections */
+static const char* audio_map[][3] = {
+
+	/* mic is connected to mic1 - with bias */
+	{"MIC1", NULL, "Mic Bias"},
+	{"MIC1N", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic1 Jack"},
+	{"Mic Bias", NULL, "Mic1 Jack"},
+
+	{"ACIN", NULL, "ACOP"},
+	{NULL, NULL, NULL},
+};
+
+/* headphone detect support on my board */
+static const char * hp_pol[] = {"Headphone", "Speaker"};
+static const struct soc_enum wm8753_enum =
+	SOC_ENUM_SINGLE(WM8753_OUTCTL, 1, 2, hp_pol);
+
+static const struct snd_kcontrol_new wm8753_mainstone_controls[] = {
+	SOC_SINGLE("Headphone Detect Switch", WM8753_OUTCTL, 6, 1, 0),
+	SOC_ENUM("Headphone Detect Polarity", wm8753_enum),
+};
+
+/*
+ * This is an example machine initialisation for a wm8753 connected to a
+ * Mainstone II. It is missing logic to detect hp/mic insertions and logic
+ * to re-route the audio in such an event.
+ */
+static int mainstone_wm8753_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+
+	/* set up mainstone codec pins */
+	snd_soc_dapm_disable_pin(codec, "RXP");
+	snd_soc_dapm_disable_pin(codec, "RXN");
+	snd_soc_dapm_disable_pin(codec, "MIC2");
+
+	/* add mainstone specific controls */
+	for (i = 0; i < ARRAY_SIZE(wm8753_mainstone_controls); i++) {
+		if ((err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&wm8753_mainstone_controls[i],codec, NULL))) < 0)
+			return err;
+	}
+
+	/* set up mainstone specific audio path audio_mapnects */
+	for(i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0], audio_map[i][1], audio_map[i][2]);
+	}
+
+	snd_soc_dapm_sync(codec);
+	return 0;
+}
+
+static struct snd_soc_dai_link mainstone_dai[] = {
+{ /* Hifi Playback - for similatious use with voice below */
+	.name = "WM8753",
+	.stream_name = "WM8753 HiFi",
+	.cpu_dai = &pxa_i2s_dai,
+	.codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+	.init = mainstone_wm8753_init,
+	.ops = &mainstone_hifi_ops,
+},
+{ /* Voice via BT */
+	.name = "Bluetooth",
+	.stream_name = "Voice",
+	.cpu_dai = &pxa_ssp_dai[1],
+	.codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+	.ops = &mainstone_voice_ops,
+},
+};
+
+static struct snd_soc_machine mainstone = {
+	.name = "Mainstone",
+	.probe = mainstone_probe,
+	.remove = mainstone_remove,
+	.suspend_pre = mainstone_suspend,
+	.resume_post = mainstone_resume,
+	.dai_link = mainstone_dai,
+	.num_links = ARRAY_SIZE(mainstone_dai),
+};
+
+static struct wm8753_setup_data mainstone_wm8753_setup = {
+	.i2c_address = 0x1a,
+};
+
+static struct snd_soc_device mainstone_snd_devdata = {
+	.machine = &mainstone,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8753,
+	.codec_data = &mainstone_wm8753_setup,
+};
+
+static struct platform_device *mainstone_snd_device;
+
+static int __init mainstone_init(void)
+{
+	int ret;
+
+	mainstone_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!mainstone_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mainstone_snd_device, &mainstone_snd_devdata);
+	mainstone_snd_devdata.dev = &mainstone_snd_device->dev;
+	ret = platform_device_add(mainstone_snd_device);
+
+	if (ret)
+		platform_device_put(mainstone_snd_device);
+
+	/* SSP port 2 slave */
+	pxa_gpio_mode(GPIO11_SSP2RX_MD);
+	pxa_gpio_mode(GPIO13_SSP2TX_MD);
+	pxa_gpio_mode(GPIO22_SSP2CLKS_MD);
+	pxa_gpio_mode(GPIO88_SSP2FRMS_MD);
+
+	/* I2S SoC */
+	pxa_gpio_mode(GPIO29_SDATA_IN_I2S_MD);
+	pxa_gpio_mode(GPIO30_SDATA_OUT_I2S_MD);
+	pxa_gpio_mode(GPIO31_SYNC_I2S_MD);
+
+	return ret;
+}
+
+static void __exit mainstone_exit(void)
+{
+	platform_device_unregister(mainstone_snd_device);
+}
+
+module_init(mainstone_init);
+module_exit(mainstone_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM8753 Mainstone");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/mainstone_wm8956.c b/sound/soc/pxa/mainstone_wm8956.c
new file mode 100644
index 0000000..b73b623
--- /dev/null
+++ b/sound/soc/pxa/mainstone_wm8956.c
@@ -0,0 +1,104 @@
+/*
+ * mainstone.c  --  SoC audio for Mainstone
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  Mainstone audio amplifier code taken from arch/arm/mach-pxa/mainstone.c
+ *  Copyright:	MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mainstone.h>
+#include <asm/arch/audio.h>
+
+#include "../codecs/wm8956.h"
+#include "pxa2xx-pcm.h"
+
+static struct snd_soc_machine mainstone;
+
+/*
+ * Init - to complete.
+ */
+static int mainstone_wm8956_init(struct snd_soc_codec *codec)
+{
+	return 0;
+}
+
+static struct snd_soc_dai_link mainstone_dai[] = {
+{
+	.name = "WM8956",
+	.stream_name = "WM8956 HiFi",
+	.cpu_dai = &pxa_i2s_dai,
+	.codec_dai = &wm8956_dai,
+	.init = mainstone_wm8956_init,
+	.config_sysclk = mainstone_config_sysclk,
+},
+};
+
+static struct snd_soc_machine mainstone = {
+	.name = "Mainstone",
+	.dai_link = mainstone_dai,
+	.num_links = ARRAY_SIZE(mainstone_dai),
+};
+
+static struct wm8956_setup_data wm8956_setup = {
+	.i2c_address = 0x1a,
+};
+
+static struct snd_soc_device mainstone_snd_devdata = {
+	.machine = &mainstone,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8956,
+	.codec_data = &wm8956_setup,
+};
+
+static struct platform_device *mainstone_snd_device;
+
+static int __init mainstone_init(void)
+{
+	int ret;
+
+	mainstone_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!mainstone_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mainstone_snd_device, &mainstone_snd_devdata);
+	mainstone_snd_devdata.dev = &mainstone_snd_device->dev;
+	ret = platform_device_add(mainstone_snd_device);
+
+	if (ret)
+		platform_device_put(mainstone_snd_device);
+
+	return ret;
+}
+
+static void __exit mainstone_exit(void)
+{
+	platform_device_unregister(mainstone_snd_device);
+}
+
+module_init(mainstone_init);
+module_exit(mainstone_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM8956 Mainstone");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/mainstone_wm8974.c b/sound/soc/pxa/mainstone_wm8974.c
new file mode 100644
index 0000000..2d2bb92
--- /dev/null
+++ b/sound/soc/pxa/mainstone_wm8974.c
@@ -0,0 +1,104 @@
+/*
+ * mainstone.c  --  SoC audio for Mainstone
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  Mainstone audio amplifier code taken from arch/arm/mach-pxa/mainstone.c
+ *  Copyright:	MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    30th Oct 2005   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mainstone.h>
+#include <asm/arch/audio.h>
+
+#include "../codecs/wm8974.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+
+static struct snd_soc_machine mainstone;
+
+static int mainstone_wm8974_init(struct snd_soc_codec *codec)
+{
+	return 0;
+}
+
+static struct snd_soc_dai_link mainstone_dai[] = {
+{
+	.name = "WM8974",
+	.stream_name = "WM8974 HiFi",
+	.cpu_dai = &pxa_i2s_dai,
+	.codec_dai = &wm8974_dai,
+	.init = mainstone_wm8974_init,
+},
+};
+
+static struct snd_soc_machine mainstone = {
+	.name = "Mainstone",
+	.dai_link = mainstone_dai,
+	.num_links = ARRAY_SIZE(mainstone_dai),
+};
+
+static struct wm8974_setup_data mainstone_wm8974_setup = {
+	.i2c_address = 0x1a,
+};
+
+static struct snd_soc_device mainstone_snd_devdata = {
+	.machine = &mainstone,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8974,
+	.codec_data = &mainstone_wm8974_setup,
+};
+
+static struct platform_device *mainstone_snd_device;
+
+static int __init mainstone_init(void)
+{
+	int ret;
+
+	mainstone_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!mainstone_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mainstone_snd_device, &mainstone_snd_devdata);
+	mainstone_snd_devdata.dev = &mainstone_snd_device->dev;
+	ret = platform_device_add(mainstone_snd_device);
+
+	if (ret)
+		platform_device_put(mainstone_snd_device);
+
+	return ret;
+}
+
+static void __exit mainstone_exit(void)
+{
+	platform_device_unregister(mainstone_snd_device);
+}
+
+module_init(mainstone_init);
+module_exit(mainstone_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC Mainstone");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/mainstone_wm9712.c b/sound/soc/pxa/mainstone_wm9712.c
new file mode 100644
index 0000000..570aa4e
--- /dev/null
+++ b/sound/soc/pxa/mainstone_wm9712.c
@@ -0,0 +1,172 @@
+/*
+ * mainstone.c  --  SoC audio for Mainstone
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  Mainstone audio amplifier code taken from arch/arm/mach-pxa/mainstone.c
+ *  Copyright:	MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    29th Jan 2006   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mainstone.h>
+#include <asm/arch/audio.h>
+
+#include "../codecs/wm9712.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+static struct snd_soc_machine mainstone;
+static long mst_audio_suspend_mask;
+
+static int mainstone_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	mst_audio_suspend_mask = MST_MSCWR2;
+	MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_resume(struct platform_device *pdev)
+{
+	MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_probe(struct platform_device *pdev)
+{
+	MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_remove(struct platform_device *pdev)
+{
+	MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+/* mainstone machine dapm widgets */
+static const struct snd_soc_dapm_widget mainstone_dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+};
+
+/* example machine interconnections */
+static const char* intercon[][3] = {
+
+	/* mic is connected to mic1 - with bias */
+	{"MIC1", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic (Internal)"},
+
+	{NULL, NULL, NULL},
+};
+
+/*
+ * This is an example machine initialisation for a wm8753 connected to a
+ * Mainstone II. It is missing logic to detect hp/mic insertions and logic
+ * to re-route the audio in such an event.
+ */
+static int mainstone_wm9712_init(struct snd_soc_codec *codec)
+{
+	int i;
+
+	/* set up mainstone codec pins */
+	snd_soc_dapm_disable_pin(codec, "RXP");
+	snd_soc_dapm_disable_pin(codec, "RXN");
+	//snd_soc_dapm_disable_pin(codec, "MIC2");
+
+	/* Add mainstone specific widgets */
+	for(i = 0; i < ARRAY_SIZE(mainstone_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &mainstone_dapm_widgets[i]);
+	}
+
+	/* set up mainstone specific audio path interconnects */
+	for(i = 0; intercon[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, intercon[i][0], intercon[i][1], intercon[i][2]);
+	}
+
+	snd_soc_dapm_sync(codec);
+	return 0;
+}
+
+static struct snd_soc_dai_link mainstone_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+	.codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+	.init = mainstone_wm9712_init,
+},
+{
+	.name = "AC97 Aux",
+	.stream_name = "AC97 Aux",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+	.codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+},
+};
+
+static struct snd_soc_machine mainstone = {
+	.name = "Mainstone",
+	.probe = mainstone_probe,
+	.remove = mainstone_remove,
+	.suspend_pre = mainstone_suspend,
+	.resume_post = mainstone_resume,
+	.dai_link = mainstone_dai,
+	.num_links = ARRAY_SIZE(mainstone_dai),
+};
+
+static struct snd_soc_device mainstone_snd_ac97_devdata = {
+	.machine = &mainstone,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm9712,
+};
+
+static struct platform_device *mainstone_snd_ac97_device;
+
+static int __init mainstone_init(void)
+{
+	int ret;
+
+	mainstone_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+	if (!mainstone_snd_ac97_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mainstone_snd_ac97_device, &mainstone_snd_ac97_devdata);
+	mainstone_snd_ac97_devdata.dev = &mainstone_snd_ac97_device->dev;
+
+	if((ret = platform_device_add(mainstone_snd_ac97_device)) != 0)
+		platform_device_put(mainstone_snd_ac97_device);
+
+	return ret;
+}
+
+static void __exit mainstone_exit(void)
+{
+	platform_device_unregister(mainstone_snd_ac97_device);
+}
+
+module_init(mainstone_init);
+module_exit(mainstone_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM9712 Mainstone");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/mainstone_wm9713.c b/sound/soc/pxa/mainstone_wm9713.c
new file mode 100644
index 0000000..5195b9c
--- /dev/null
+++ b/sound/soc/pxa/mainstone_wm9713.c
@@ -0,0 +1,319 @@
+/*
+ * mainstone.c  --  SoC audio for Mainstone
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  Mainstone audio amplifier code taken from arch/arm/mach-pxa/mainstone.c
+ *  Copyright:	MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    29th Jan 2006   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mainstone.h>
+#include <asm/arch/audio.h>
+#include <asm/arch/hardware.h>
+
+#include "../codecs/wm9713.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+#include "pxa2xx-ssp.h"
+
+#define GPIO11_SSP2RX_MD	(11 | GPIO_ALT_FN_2_IN)
+#define GPIO13_SSP2TX_MD	(13 | GPIO_ALT_FN_1_OUT)
+#define GPIO22_SSP2CLKS_MD	(22 | GPIO_ALT_FN_3_IN)
+#define GPIO88_SSP2FRMS_MD	(88 | GPIO_ALT_FN_3_IN)
+#define GPIO22_SSP2CLKM_MD	(22 | GPIO_ALT_FN_3_OUT)
+#define GPIO88_SSP2FRMM_MD	(88 | GPIO_ALT_FN_3_OUT)
+#define GPIO22_SSP2SYSCLK_MD	(22 | GPIO_ALT_FN_2_OUT)
+
+static struct snd_soc_machine mainstone;
+
+static int mainstone_voice_startup(struct snd_pcm_substream *substream)
+{
+	/* enable USB on the go MUX so we can use SSPFRM2 */
+	MST_MSCWR2 |= MST_MSCWR2_USB_OTG_SEL;
+	MST_MSCWR2 &= ~MST_MSCWR2_USB_OTG_RST;
+	return 0;
+}
+
+static void mainstone_voice_shutdown(struct snd_pcm_substream *substream)
+{
+	/* disable USB on the go MUX so we can use ttyS0 */
+	MST_MSCWR2 &= ~MST_MSCWR2_USB_OTG_SEL;
+	MST_MSCWR2 |= MST_MSCWR2_USB_OTG_RST;
+}
+
+static int mainstone_voice_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int bclk = 0, pcmdiv = 0;
+	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+		pcmdiv = WM9713_PCMDIV(12); /* 2.048 MHz */
+		bclk = WM9713_PCMBCLK_DIV_16; /* 128kHz */
+		break;
+	case 16000:
+		pcmdiv = WM9713_PCMDIV(6); /* 4.096 MHz */
+		bclk = WM9713_PCMBCLK_DIV_16; /* 256kHz */
+		break;
+	case 48000:
+		pcmdiv = WM9713_PCMDIV(2); /* 12.288 MHz */
+		bclk = WM9713_PCMBCLK_DIV_16; /* 512kHz */
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set the SSP system clock as input (unused) */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_SSP_CLK_PLL, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set codec BCLK division for sample rate */
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM9713_PCMBCLK_DIV, bclk);
+	if (ret < 0)
+		return ret;
+
+	/* set codec PCM division for sample rate */
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, pcmdiv);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops mainstone_voice_ops = {
+	.startup = mainstone_voice_startup,
+	.shutdown = mainstone_voice_shutdown,
+	.hw_params = mainstone_voice_hw_params,
+};
+
+static int test = 0;
+static int get_test(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = test;
+	return 0;
+}
+
+static int set_test(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	test = ucontrol->value.integer.value[0];
+	if(test) {
+
+	} else {
+
+	}
+	return 0;
+}
+
+static long mst_audio_suspend_mask;
+
+static int mainstone_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	mst_audio_suspend_mask = MST_MSCWR2;
+	MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_resume(struct platform_device *pdev)
+{
+	MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_probe(struct platform_device *pdev)
+{
+	MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static int mainstone_remove(struct platform_device *pdev)
+{
+	MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+	return 0;
+}
+
+static const char* test_function[] = {"Off", "On"};
+static const struct soc_enum mainstone_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, test_function),
+};
+
+static const struct snd_kcontrol_new mainstone_controls[] = {
+	SOC_ENUM_EXT("ATest Function", mainstone_enum[0], get_test, set_test),
+};
+
+/* mainstone machine dapm widgets */
+static const struct snd_soc_dapm_widget mainstone_dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("Mic 1", NULL),
+	SND_SOC_DAPM_MIC("Mic 2", NULL),
+	SND_SOC_DAPM_MIC("Mic 3", NULL),
+};
+
+/* example machine audio_mapnections */
+static const char* audio_map[][3] = {
+
+	/* mic is connected to mic1 - with bias */
+	{"MIC1", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic 1"},
+	/* mic is connected to mic2A - with bias */
+	{"MIC2A", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic 2"},
+	/* mic is connected to mic2B - with bias */
+	{"MIC2B", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic 3"},
+
+	{NULL, NULL, NULL},
+};
+
+/*
+ * This is an example machine initialisation for a wm9713 connected to a
+ * Mainstone II. It is missing logic to detect hp/mic insertions and logic
+ * to re-route the audio in such an event.
+ */
+static int mainstone_wm9713_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+
+	/* set up mainstone codec pins */
+	snd_soc_dapm_disable_pin(codec, "RXP");
+	snd_soc_dapm_disable_pin(codec, "RXN");
+	//snd_soc_dapm_disable_pin(codec, "MIC2");
+
+	/* Add test specific controls */
+	for (i = 0; i < ARRAY_SIZE(mainstone_controls); i++) {
+		if ((err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&mainstone_controls[i],codec, NULL))) < 0)
+			return err;
+	}
+
+	/* Add mainstone specific widgets */
+	for(i = 0; i < ARRAY_SIZE(mainstone_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &mainstone_dapm_widgets[i]);
+	}
+
+	/* set up mainstone specific audio path audio_mapnects */
+	for(i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0], audio_map[i][1],
+			audio_map[i][2]);
+	}
+
+	snd_soc_dapm_sync(codec);
+	return 0;
+}
+
+static struct snd_soc_dai_link mainstone_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+	.codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+	.init = mainstone_wm9713_init,
+},
+{
+	.name = "AC97 Aux",
+	.stream_name = "AC97 Aux",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+	.codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+},
+{
+	.name = "WM9713",
+	.stream_name = "WM9713 Voice",
+	.cpu_dai = &pxa_ssp_dai[PXA2XX_DAI_SSP2],
+	.codec_dai = &wm9713_dai[WM9713_DAI_PCM_VOICE],
+	.ops = &mainstone_voice_ops,
+},
+};
+
+static struct snd_soc_machine mainstone = {
+	.name = "Mainstone",
+	.probe = mainstone_probe,
+	.remove = mainstone_remove,
+	.suspend_pre = mainstone_suspend,
+	.resume_post = mainstone_resume,
+	.dai_link = mainstone_dai,
+	.num_links = ARRAY_SIZE(mainstone_dai),
+};
+
+static struct snd_soc_device mainstone_snd_ac97_devdata = {
+	.machine = &mainstone,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm9713,
+};
+
+static struct platform_device *mainstone_snd_ac97_device;
+
+static int __init mainstone_init(void)
+{
+	int ret;
+
+	mainstone_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+	if (!mainstone_snd_ac97_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mainstone_snd_ac97_device, &mainstone_snd_ac97_devdata);
+	mainstone_snd_ac97_devdata.dev = &mainstone_snd_ac97_device->dev;
+
+	if((ret = platform_device_add(mainstone_snd_ac97_device)) != 0)
+		platform_device_put(mainstone_snd_ac97_device);
+
+	/* SSP port 2 slave */
+	pxa_gpio_mode(GPIO11_SSP2RX_MD);
+	pxa_gpio_mode(GPIO13_SSP2TX_MD);
+	pxa_gpio_mode(GPIO22_SSP2CLKS_MD);
+	pxa_gpio_mode(GPIO88_SSP2FRMS_MD);
+
+	return ret;
+}
+
+static void __exit mainstone_exit(void)
+{
+	platform_device_unregister(mainstone_snd_ac97_device);
+}
+
+module_init(mainstone_init);
+module_exit(mainstone_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM9713 Mainstone");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-ssp.c b/sound/soc/pxa/pxa2xx-ssp.c
new file mode 100644
index 0000000..6b1baee
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-ssp.c
@@ -0,0 +1,706 @@
+/*
+ * pxa2xx-ssp.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    12th Aug 2005   Initial version.
+ *
+ * TODO:
+ *  o Test network mode for > 16bit sample size
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/regs-ssp.h>
+#include <asm/arch/audio.h>
+#include <asm/arch/ssp.h>
+
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ssp.h"
+
+/*
+ * SSP audio private data
+ */
+struct ssp_priv {
+	unsigned int sysclk;
+};
+
+static struct ssp_priv ssp_clk[3];
+static struct ssp_dev ssp[3];
+#ifdef CONFIG_PM
+static struct ssp_state ssp_state[3];
+#endif
+
+#define PXA2xx_SSP1_BASE	0x41000000
+#define PXA27x_SSP2_BASE	0x41700000
+#define PXA27x_SSP3_BASE	0x41900000
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ssp1_pcm_mono_out = {
+	.name			= "SSP1 PCM Mono out",
+	.dev_addr		= PXA2xx_SSP1_BASE + SSDR,
+	.drcmr			= &DRCMRTXSSDR,
+	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
+				  DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ssp1_pcm_mono_in = {
+	.name			= "SSP1 PCM Mono in",
+	.dev_addr		= PXA2xx_SSP1_BASE + SSDR,
+	.drcmr			= &DRCMRRXSSDR,
+	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
+				  DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ssp1_pcm_stereo_out = {
+	.name			= "SSP1 PCM Stereo out",
+	.dev_addr		= PXA2xx_SSP1_BASE + SSDR,
+	.drcmr			= &DRCMRTXSSDR,
+	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
+				  DCMD_BURST16 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ssp1_pcm_stereo_in = {
+	.name			= "SSP1 PCM Stereo in",
+	.dev_addr		= PXA2xx_SSP1_BASE + SSDR,
+	.drcmr			= &DRCMRRXSSDR,
+	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
+				  DCMD_BURST16 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ssp2_pcm_mono_out = {
+	.name			= "SSP2 PCM Mono out",
+	.dev_addr		= PXA27x_SSP2_BASE + SSDR,
+	.drcmr			= &DRCMRTXSS2DR,
+	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
+				  DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ssp2_pcm_mono_in = {
+	.name			= "SSP2 PCM Mono in",
+	.dev_addr		= PXA27x_SSP2_BASE + SSDR,
+	.drcmr			= &DRCMRRXSS2DR,
+	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
+				  DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ssp2_pcm_stereo_out = {
+	.name			= "SSP2 PCM Stereo out",
+	.dev_addr		= PXA27x_SSP2_BASE + SSDR,
+	.drcmr			= &DRCMRTXSS2DR,
+	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
+				  DCMD_BURST16 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ssp2_pcm_stereo_in = {
+	.name			= "SSP2 PCM Stereo in",
+	.dev_addr		= PXA27x_SSP2_BASE + SSDR,
+	.drcmr			= &DRCMRRXSS2DR,
+	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
+				  DCMD_BURST16 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ssp3_pcm_mono_out = {
+	.name			= "SSP3 PCM Mono out",
+	.dev_addr		= PXA27x_SSP3_BASE + SSDR,
+	.drcmr			= &DRCMRTXSS3DR,
+	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
+				  DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ssp3_pcm_mono_in = {
+	.name			= "SSP3 PCM Mono in",
+	.dev_addr		= PXA27x_SSP3_BASE + SSDR,
+	.drcmr			= &DRCMRRXSS3DR,
+	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
+				  DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ssp3_pcm_stereo_out = {
+	.name			= "SSP3 PCM Stereo out",
+	.dev_addr		= PXA27x_SSP3_BASE + SSDR,
+	.drcmr			= &DRCMRTXSS3DR,
+	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
+				  DCMD_BURST16 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ssp3_pcm_stereo_in = {
+	.name			= "SSP3 PCM Stereo in",
+	.dev_addr		= PXA27x_SSP3_BASE + SSDR,
+	.drcmr			= &DRCMRRXSS3DR,
+	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
+				  DCMD_BURST16 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_pcm_dma_params *ssp_dma_params[3][4] = {
+	{&pxa2xx_ssp1_pcm_mono_out, &pxa2xx_ssp1_pcm_mono_in,
+	&pxa2xx_ssp1_pcm_stereo_out, &pxa2xx_ssp1_pcm_stereo_in,},
+	{&pxa2xx_ssp2_pcm_mono_out, &pxa2xx_ssp2_pcm_mono_in,
+	&pxa2xx_ssp2_pcm_stereo_out, &pxa2xx_ssp2_pcm_stereo_in,},
+	{&pxa2xx_ssp3_pcm_mono_out, &pxa2xx_ssp3_pcm_mono_in,
+	&pxa2xx_ssp3_pcm_stereo_out, &pxa2xx_ssp3_pcm_stereo_in,},
+};
+
+static int pxa2xx_ssp_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret = 0;
+
+	if (!rtd->dai->cpu_dai->active) {
+		ret = ssp_init(&ssp[cpu_dai->id], cpu_dai->id + 1,
+			SSP_NO_IRQ);
+		if (ret < 0)
+			return ret;
+		ssp_disable(&ssp[cpu_dai->id]);
+	}
+	return ret;
+}
+
+static void pxa2xx_ssp_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	if (!cpu_dai->active) {
+		ssp_disable(&ssp[cpu_dai->id]);
+		ssp_exit(&ssp[cpu_dai->id]);
+	}
+}
+
+#ifdef CONFIG_PM
+
+static int pxa2xx_ssp_suspend(struct platform_device *pdev,
+	struct snd_soc_cpu_dai *dai)
+{
+	if (!dai->active)
+		return 0;
+
+	ssp_save_state(&ssp[dai->id], &ssp_state[dai->id]);
+	clk_disable(ssp[dai->id].ssp->clk);
+	return 0;
+}
+
+static int pxa2xx_ssp_resume(struct platform_device *pdev,
+	struct snd_soc_cpu_dai *dai)
+{
+	if (!dai->active)
+		return 0;
+
+	clk_enable(ssp[dai->id].ssp->clk);
+	ssp_restore_state(&ssp[dai->id], &ssp_state[dai->id]);
+	ssp_enable(&ssp[dai->id]);
+
+	return 0;
+}
+
+#else
+#define pxa2xx_ssp_suspend	NULL
+#define pxa2xx_ssp_resume	NULL
+#endif
+
+/**
+ * ssp_set_clkdiv - set SSP clock divider
+ * @div: serial clock rate divider
+ */
+void ssp_set_scr(struct ssp_dev *dev, u32 div)
+{
+	struct ssp_device *ssp = dev->ssp;
+	u32 sscr0 = __raw_readl(ssp->mmio_base + SSCR0) & ~SSCR0_SCR;
+
+	__raw_writel(sscr0 | SSCR0_SerClkDiv(div), ssp->mmio_base + SSCR0);
+}
+
+/*
+ * Set the SSP ports SYSCLK.
+ */
+static int pxa2xx_ssp_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+	int clk_id, unsigned int freq, int dir)
+{
+	void __iomem *mmio_base = ssp[cpu_dai->id].ssp->mmio_base;
+	int val;
+
+	u32 sscr0 = __raw_readl(mmio_base + SSCR0) &
+		~(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ADC);
+
+	pr_debug("pxa2xx_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d",
+		cpu_dai->id, clk_id, freq);
+
+	switch (clk_id) {
+	case PXA2XX_SSP_CLK_NET_PLL:
+		sscr0 |= SSCR0_MOD;
+	case PXA2XX_SSP_CLK_PLL:
+		/* Internal PLL is fixed on pxa25x and pxa27x */
+		if (cpu_is_pxa25x())
+			ssp_clk[cpu_dai->id].sysclk = 1843200;
+		else
+			ssp_clk[cpu_dai->id].sysclk = 13000000;
+		break;
+	case PXA2XX_SSP_CLK_EXT:
+		ssp_clk[cpu_dai->id].sysclk = freq;
+		sscr0 |= SSCR0_ECS;
+		break;
+	case PXA2XX_SSP_CLK_NET:
+		ssp_clk[cpu_dai->id].sysclk = freq;
+		sscr0 |= SSCR0_NCS | SSCR0_MOD;
+		break;
+	case PXA2XX_SSP_CLK_AUDIO:
+		ssp_clk[cpu_dai->id].sysclk = 0;
+		ssp_set_scr(&ssp[cpu_dai->id], 1);
+		sscr0 |= SSCR0_ADC;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	/* the SSP CKEN clock must be disabled when changing SSP clock mode */
+	clk_disable(ssp[cpu_dai->id].ssp->clk);
+	val = __raw_readl(mmio_base + SSCR0) | sscr0;
+	__raw_writel(val, mmio_base + SSCR0);
+	clk_enable(ssp[cpu_dai->id].ssp->clk);
+	return 0;
+}
+
+/*
+ * Set the SSP clock dividers.
+ */
+static int pxa2xx_ssp_set_dai_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
+	int div_id, int div)
+{
+	void __iomem *mmio_base = ssp[cpu_dai->id].ssp->mmio_base;
+	int val;
+
+	switch (div_id) {
+	case PXA2XX_SSP_AUDIO_DIV_ACDS:
+		val = (__raw_readl(mmio_base + SSACD) & ~0x7) | SSACD_ACDS(div);
+		__raw_writel(val, mmio_base + SSACD);
+		break;
+	case PXA2XX_SSP_AUDIO_DIV_SCDB:
+		val = __raw_readl(mmio_base + SSACD) & ~0x8;
+		if (div == PXA2XX_SSP_CLK_SCDB_1)
+			val |= SSACD_SCDB;
+		__raw_writel(val, mmio_base + SSACD);
+		break;
+	case PXA2XX_SSP_DIV_SCR:
+		ssp_set_scr(&ssp[cpu_dai->id], div);
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/*
+ * Configure the PLL frequency pxa27x and (afaik - pxa320 only)
+ */
+static int pxa2xx_ssp_set_dai_pll(struct snd_soc_cpu_dai *cpu_dai,
+	int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+	void __iomem *mmio_base = ssp[cpu_dai->id].ssp->mmio_base;
+	u32 ssacd;
+
+	ssacd = __raw_readl(mmio_base + SSACD) & ~0x70;
+	switch (freq_out) {
+	case 5622000:
+		break;
+	case 11345000:
+		ssacd |= (0x1 << 4);
+		break;
+	case 12235000:
+		ssacd |= (0x2 << 4);
+		break;
+	case 14857000:
+		ssacd |= (0x3 << 4);
+		break;
+	case 32842000:
+		ssacd |= (0x4 << 4);
+		break;
+	case 48000000:
+		ssacd |= (0x5 << 4);
+		break;
+	}
+	__raw_writel(ssacd, mmio_base + SSACD);
+	return 0;
+}
+
+/*
+ * Set the active slots in TDM/Network mode
+ */
+static int pxa2xx_ssp_set_dai_tdm_slot(struct snd_soc_cpu_dai *cpu_dai,
+	unsigned int mask, int slots)
+{
+	void __iomem *mmio_base = ssp[cpu_dai->id].ssp->mmio_base;
+	u32 sscr0;
+
+	sscr0 = __raw_readl(mmio_base + SSCR0) & ~SSCR0_SlotsPerFrm(7);
+
+	/* set number of active slots */
+	sscr0 |= SSCR0_SlotsPerFrm(slots);
+	__raw_writel(sscr0, mmio_base + SSCR0);
+
+	/* set active slot mask */
+	__raw_writel(mask, mmio_base + SSTSA);
+	__raw_writel(mask, mmio_base + SSRSA);
+	return 0;
+}
+
+/*
+ * Tristate the SSP DAI lines
+ */
+static int pxa2xx_ssp_set_dai_tristate(struct snd_soc_cpu_dai *cpu_dai,
+	int tristate)
+{
+	void __iomem *mmio_base = ssp[cpu_dai->id].ssp->mmio_base;
+	u32 sscr1;
+
+	sscr1 = __raw_readl(mmio_base + SSCR1);
+	if (tristate)
+		sscr1 &= ~SSCR1_TTE;
+	else
+		sscr1 |= SSCR1_TTE;
+	__raw_writel(sscr1, mmio_base + SSCR1);
+
+	return 0;
+}
+
+/*
+ * Set up the SSP DAI format.
+ * The SSP Port must be inactive before calling this function as the
+ * physical interface format is changed.
+ */
+static int pxa2xx_ssp_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
+		unsigned int fmt)
+{
+	void __iomem *mmio_base = ssp[cpu_dai->id].ssp->mmio_base;
+	int val;
+
+	/* reset port settings */
+	__raw_writel(0, mmio_base + SSCR0);
+	__raw_writel(0, mmio_base + SSCR1);
+	__raw_writel(0, mmio_base + SSPSP);
+
+	/* NOTE: I2S emulation is still very much work in progress here */
+
+	/* FIXME: this is what wince uses for msb */
+	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_MSB) {
+		__raw_writel(SSCR0_EDSS | SSCR0_TISSP | SSCR0_DataSize(16),
+				mmio_base + SSCR0);
+		goto master;
+	}
+
+	/* check for I2S emulation mode - handle it separately  */
+	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) {
+		/* 8.4.11 */
+
+		/* Only SSCR0[NCS] or SSCR0[ECS] bit fields settings are optional */
+		__raw_writel(SSCR0_EDSS | SSCR0_PSP | SSCR0_DataSize(16),
+				mmio_base + SSCR0);
+
+		/* set FIFO thresholds */
+		__raw_writel(SSCR1_RxTresh(14) | SSCR1_TxTresh(1),
+				mmio_base + SSCR1);
+
+		/* normal: */
+		/* all bit fields must be cleared except: FSRT = 1 and
+		 * SFRMWDTH = 16, DMYSTART=0,1) */
+		__raw_writel(SSPSP_FSRT | SSPSP_SFRMWDTH(16) | SSPSP_DMYSTRT(0),
+				mmio_base + SSPSP);
+		goto master;
+	}
+
+	val = __raw_readl(mmio_base + SSCR0) | SSCR0_PSP;
+	__raw_writel(val, mmio_base + SSCR0);
+	__raw_writel(SSCR1_RxTresh(14) | SSCR1_TxTresh(1) |
+			SSCR1_TRAIL | SSCR1_RWOT,
+			mmio_base + SSCR1);
+
+master:
+	val = __raw_readl(mmio_base + SSCR1);
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		val |= (SSCR1_SCLKDIR | SSCR1_SFRMDIR);
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		val |= SSCR1_SCLKDIR;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		val |= SSCR1_SFRMDIR;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+	__raw_writel(val, mmio_base + SSCR1);
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		val = __raw_readl(mmio_base + SSPSP) | SSPSP_SFRMP | SSPSP_FSRT;
+		__raw_writel(val, mmio_base + SSPSP);
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val = __raw_readl(mmio_base + SSPSP);
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		val |= SSPSP_DMYSTRT(1);
+	case SND_SOC_DAIFMT_DSP_B:
+		val |= SSPSP_SCMODE(2);
+		break;
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_MSB:
+		/* handled above */
+		break;
+	default:
+		return -EINVAL;
+	}
+	__raw_writel(val, mmio_base + SSPSP);
+
+	return 0;
+}
+
+/*
+ * Set the SSP audio DMA parameters and sample size.
+ * Can be called multiple times by oss emulation.
+ */
+static int pxa2xx_ssp_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	int dma = 0, chn = params_channels(params);
+	void __iomem *mmio_base = ssp[cpu_dai->id].ssp->mmio_base;
+	u32 sscr0;
+
+	/* select correct DMA params */
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		dma = 1; /* capture DMA offset is 1,3 */
+	if (chn == 2)
+		dma += 2; /* stereo DMA offset is 2, mono is 0 */
+	cpu_dai->dma_data = ssp_dma_params[cpu_dai->id][dma];
+
+	pr_debug("pxa2xx_ssp_hw_params: dma %d", dma);
+
+	/* we can only change the settings if the port is not in use */
+	if (__raw_readl(mmio_base + SSCR0) & SSCR0_SSE)
+		return 0;
+
+	/* clear selected SSP bits */
+	sscr0 = __raw_readl(mmio_base + SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
+	__raw_writel(sscr0, mmio_base + SSCR0);
+
+	/* bit size */
+	sscr0 = __raw_readl(mmio_base + SSCR0);
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		sscr0 |= SSCR0_DataSize(16);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8));
+		/* we must be in network mode (2 slots) for 24 bit stereo */
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16));
+		/* we must be in network mode (2 slots) for 32 bit stereo */
+		break;
+	}
+	__raw_writel(sscr0, mmio_base + SSCR0);
+
+	pr_debug("SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x SSPSP 0x%08x SSSR 0x%08x SSACD 0x%08x",
+		__raw_readl(mmio_base + SSCR0), __raw_readl(mmio_base + SSCR1),
+		__raw_readl(mmio_base + SSTO), __raw_readl(mmio_base + SSPSP),
+		__raw_readl(mmio_base + SSSR), __raw_readl(mmio_base + SSACD));
+
+	return 0;
+}
+
+static int pxa2xx_ssp_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret = 0;
+	void __iomem *mmio_base = ssp[cpu_dai->id].ssp->mmio_base;
+	int val;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_RESUME:
+		ssp_enable(&ssp[cpu_dai->id]);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		val = __raw_readl(mmio_base + SSCR1);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			val |= SSCR1_TSRE;
+		else
+			val |= SSCR1_RSRE;
+		__raw_writel(val, mmio_base + SSCR1);
+		/* SSSR_P(port) |= SSSR_P(port); */
+		val = __raw_readl(mmio_base + SSSR);
+		__raw_writel(val, mmio_base + SSSR);
+		break;
+	case SNDRV_PCM_TRIGGER_START:
+		val = __raw_readl(mmio_base + SSCR1);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			val |= SSCR1_TSRE;
+		else
+			val |= SSCR1_RSRE;
+		__raw_writel(val, mmio_base + SSCR1);
+		ssp_enable(&ssp[cpu_dai->id]);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		val = __raw_readl(mmio_base + SSCR1);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			val &= ~SSCR1_TSRE;
+		else
+			val &= ~SSCR1_RSRE;
+		__raw_writel(val, mmio_base + SSCR1);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		ssp_disable(&ssp[cpu_dai->id]);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		val = __raw_readl(mmio_base + SSCR1);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			val &= ~SSCR1_TSRE;
+		else
+			val &= ~SSCR1_RSRE;
+		__raw_writel(val, mmio_base + SSCR1);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	pr_debug("SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x SSPSP 0x%08x SSSR 0x%08x",
+		__raw_readl(mmio_base + SSCR0), __raw_readl(mmio_base + SSCR1),
+		__raw_readl(mmio_base + SSTO), __raw_readl(mmio_base + SSPSP),
+		__raw_readl(mmio_base + SSSR));
+
+	return ret;
+}
+
+#define PXA2XX_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define PXA2XX_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_cpu_dai pxa_ssp_dai[] = {
+	{	.name = "pxa2xx-ssp1",
+		.id = 0,
+		.type = SND_SOC_DAI_PCM,
+		.suspend = pxa2xx_ssp_suspend,
+		.resume = pxa2xx_ssp_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA2XX_SSP_RATES,
+			.formats = PXA2XX_SSP_FORMATS,},
+		.capture = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA2XX_SSP_RATES,
+			.formats = PXA2XX_SSP_FORMATS,},
+		.ops = {
+			.startup = pxa2xx_ssp_startup,
+			.shutdown = pxa2xx_ssp_shutdown,
+			.trigger = pxa2xx_ssp_trigger,
+			.hw_params = pxa2xx_ssp_hw_params,},
+		.dai_ops = {
+			.set_sysclk = pxa2xx_ssp_set_dai_sysclk,
+			.set_clkdiv = pxa2xx_ssp_set_dai_clkdiv,
+			.set_pll = pxa2xx_ssp_set_dai_pll,
+			.set_fmt = pxa2xx_ssp_set_dai_fmt,
+			.set_tdm_slot = pxa2xx_ssp_set_dai_tdm_slot,
+			.set_tristate = pxa2xx_ssp_set_dai_tristate,
+		},
+	},
+	{	.name = "pxa2xx-ssp2",
+		.id = 1,
+		.type = SND_SOC_DAI_PCM,
+		.suspend = pxa2xx_ssp_suspend,
+		.resume = pxa2xx_ssp_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA2XX_SSP_RATES,
+			.formats = PXA2XX_SSP_FORMATS,},
+		.capture = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA2XX_SSP_RATES,
+			.formats = PXA2XX_SSP_FORMATS,},
+		.ops = {
+			.startup = pxa2xx_ssp_startup,
+			.shutdown = pxa2xx_ssp_shutdown,
+			.trigger = pxa2xx_ssp_trigger,
+			.hw_params = pxa2xx_ssp_hw_params,},
+		.dai_ops = {
+			.set_sysclk = pxa2xx_ssp_set_dai_sysclk,
+			.set_clkdiv = pxa2xx_ssp_set_dai_clkdiv,
+			.set_pll = pxa2xx_ssp_set_dai_pll,
+			.set_fmt = pxa2xx_ssp_set_dai_fmt,
+			.set_tdm_slot = pxa2xx_ssp_set_dai_tdm_slot,
+			.set_tristate = pxa2xx_ssp_set_dai_tristate,
+		},
+	},
+	{	.name = "pxa2xx-ssp3",
+		.id = 2,
+		.type = SND_SOC_DAI_PCM,
+		.suspend = pxa2xx_ssp_suspend,
+		.resume = pxa2xx_ssp_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA2XX_SSP_RATES,
+			.formats = PXA2XX_SSP_FORMATS,},
+		.capture = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA2XX_SSP_RATES,
+			.formats = PXA2XX_SSP_FORMATS,},
+		.ops = {
+			.startup = pxa2xx_ssp_startup,
+			.shutdown = pxa2xx_ssp_shutdown,
+			.trigger = pxa2xx_ssp_trigger,
+			.hw_params = pxa2xx_ssp_hw_params,},
+		.dai_ops = {
+			.set_sysclk = pxa2xx_ssp_set_dai_sysclk,
+			.set_clkdiv = pxa2xx_ssp_set_dai_clkdiv,
+			.set_pll = pxa2xx_ssp_set_dai_pll,
+			.set_fmt = pxa2xx_ssp_set_dai_fmt,
+			.set_tdm_slot = pxa2xx_ssp_set_dai_tdm_slot,
+			.set_tristate = pxa2xx_ssp_set_dai_tristate,
+		},
+	},
+};
+EXPORT_SYMBOL_GPL(pxa_ssp_dai);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("pxa2xx SSP/PCM SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-ssp.h b/sound/soc/pxa/pxa2xx-ssp.h
new file mode 100644
index 0000000..3d0fd4b
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-ssp.h
@@ -0,0 +1,43 @@
+/*
+ * linux/sound/arm/pxa2xx-ssp.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 _PXA2XX_SSP_H
+#define _PXA2XX_SSP_H
+
+/* pxa2xx DAI SSP ID's */
+#define PXA2XX_DAI_SSP1			0
+#define PXA2XX_DAI_SSP2			1
+#define PXA2XX_DAI_SSP3			2
+
+/* SSP clock sources */
+#define PXA2XX_SSP_CLK_PLL	0
+#define PXA2XX_SSP_CLK_EXT	1
+#define PXA2XX_SSP_CLK_NET	2
+#define PXA2XX_SSP_CLK_AUDIO	3
+#define PXA2XX_SSP_CLK_NET_PLL	4
+
+/* SSP audio dividers */
+#define PXA2XX_SSP_AUDIO_DIV_ACDS		0
+#define PXA2XX_SSP_AUDIO_DIV_SCDB		1
+#define PXA2XX_SSP_DIV_SCR				2
+
+/* SSP ACDS audio dividers values */
+#define PXA2XX_SSP_CLK_AUDIO_DIV_1		0
+#define PXA2XX_SSP_CLK_AUDIO_DIV_2		1
+#define PXA2XX_SSP_CLK_AUDIO_DIV_4		2
+#define PXA2XX_SSP_CLK_AUDIO_DIV_8		3
+#define PXA2XX_SSP_CLK_AUDIO_DIV_16	4
+#define PXA2XX_SSP_CLK_AUDIO_DIV_32	5
+
+/* SSP divider bypass */
+#define PXA2XX_SSP_CLK_SCDB_4		0
+#define PXA2XX_SSP_CLK_SCDB_1		1
+
+extern struct snd_soc_dai pxa_ssp_dai[3];
+
+#endif
diff --git a/sound/soc/s3c24xx/smdk2440.c b/sound/soc/s3c24xx/smdk2440.c
new file mode 100644
index 0000000..2c88fcd
--- /dev/null
+++ b/sound/soc/s3c24xx/smdk2440.c
@@ -0,0 +1,319 @@
+/*
+ * smdk2440.c  --  ALSA Soc Audio Layer
+ *
+ * (c) 2006 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * (c) 2004-2005 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ * This module is a modified version of the s3c24xx I2S driver supplied by
+ * Ben Dooks of Simtec and rejigged to the ASoC style at Wolfson Microelectronics
+ *
+ *  Revision history
+ *    11th Dec 2006   Merged with Simtec driver
+ *    10th Nov 2006   Initial version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/hardware.h>
+#include <asm/arch/audio.h>
+#include <asm/io.h>
+#include <asm/arch/spi-gpio.h>
+#include "../codecs/uda1380.h"
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-i2s.h"
+
+#define SMDK2440_DEBUG 0
+#if SMDK2440_DEBUG
+#define DBG(x...) printk(KERN_DEBUG x)
+#else
+#define DBG(x...)
+#endif
+
+/* audio clock in Hz */
+#define SMDK_CLOCK_SOURCE S3C24XX_CLKSRC_MPLL
+#define SMDK_CRYSTAL_CLOCK 16934400
+
+static int smdk2440_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	DBG("Entered smdk2440_startup\n");
+
+	return 0;
+}
+
+static int smdk2440_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	DBG("Entered smdk2440_shutdown\n");
+
+	return 0;
+}
+
+static int smdk2440_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	unsigned long iis_clkrate;
+	int div, div256, div384, diff256, diff384, bclk, mclk;
+	int ret;
+	unsigned int rate=params_rate(params);
+
+	DBG("Entered %s\n",__FUNCTION__);
+
+	iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+	/* Using PCLK doesnt seem to suit audio particularly well on these cpu's
+	 */
+
+	div256 = iis_clkrate / (rate * 256);
+	div384 = iis_clkrate / (rate * 384);
+
+	if (((iis_clkrate / div256) - (rate * 256)) <
+		((rate * 256) - (iis_clkrate / (div256 + 1)))) {
+		diff256 = (iis_clkrate / div256) - (rate * 256);
+	} else {
+		div256++;
+		diff256 = (iis_clkrate / div256) - (rate * 256);
+	}
+
+	if (((iis_clkrate / div384) - (rate * 384)) <
+		((rate * 384) - (iis_clkrate / (div384 + 1)))) {
+		diff384 = (iis_clkrate / div384) - (rate * 384);
+	} else {
+		div384++;
+		diff384 = (iis_clkrate / div384) - (rate * 384);
+	}
+
+	DBG("diff256 %d, diff384 %d\n", diff256, diff384);
+
+	if (diff256<=diff384) {
+		DBG("Selected 256FS\n");
+		div = div256 - 1;
+		bclk = S3C2410_IISMOD_256FS;
+	} else {
+		DBG("Selected 384FS\n");
+		div = div384 - 1;
+		bclk = S3C2410_IISMOD_384FS;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set the audio system clock for DAC and ADC */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, S3C24XX_CLKSRC_PCLK,
+		rate, SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	/* set MCLK division for sample rate */
+	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, S3C2410_IISMOD_32FS );
+	if (ret < 0)
+		return ret;
+
+	/* set BCLK division for sample rate */
+	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, bclk);
+	if (ret < 0)
+		return ret;
+
+	/* set prescaler division for sample rate */
+	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+		S3C24XX_PRESCALE(div,div));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops smdk2440_ops = {
+	.startup = smdk2440_startup,
+	.shutdown = smdk2440_shutdown,
+	.hw_params = smdk2440_hw_params,
+};
+
+/* smdk2440 machine dapm widgets */
+static const struct snd_soc_dapm_widget smdk2440_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", NULL),
+SND_SOC_DAPM_MIC("Mic Jack", NULL),
+SND_SOC_DAPM_LINE("Line Jack", NULL),
+};
+
+/* smdk2440 machine audio map (connections to the codec pins) */
+static const char* audio_map[][3] = {
+	/* headphone connected to  HPOUT */
+	{"Headphone Jack", NULL, "HPOUT"},
+
+	/* mic is connected to MICIN (via right channel of headphone jack) */
+	{"MICIN", NULL, "Mic Jack"},
+	{"MICIN", NULL, "Line Jack"},
+
+	{NULL, NULL, NULL},
+};
+
+/*
+ * Logic for a UDA1341 as attached to SMDK2440
+ */
+static int smdk2440_uda1341_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+
+	DBG("Staring smdk2440 init\n");
+
+	/* Add smdk2440 specific widgets */
+	snd_soc_dapm_new_controls(codec, smdk2440_dapm_widgets,
+				  ARRAY_SIZE(smdk2440_dapm_widgets));
+
+	/* Set up smdk2440 specific audio path audio_mapnects */
+	for(i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0],
+			audio_map[i][1], audio_map[i][2]);
+	}
+
+	snd_soc_dapm_sync(codec);
+
+	DBG("Ending smdk2440 init\n");
+
+	return 0;
+}
+
+/* s3c24xx digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link s3c24xx_dai = {
+	.name = "WM8731",
+	.stream_name = "WM8731",
+	.cpu_dai = &s3c24xx_i2s_dai,
+	.codec_dai = &uda1380_dai,
+	.init = smdk2440_uda1341_init,
+	.ops = &smdk2440_ops,
+};
+
+/* smdk2440 audio machine driver */
+static struct snd_soc_machine snd_soc_machine_smdk2440 = {
+	.name = "SMDK2440",
+	.dai_link = &s3c24xx_dai,
+	.num_links = 1,
+};
+
+static struct uda1380_setup_data smdk2440_uda1380_setup = {
+	.i2c_address = 0x00,
+};
+
+/* s3c24xx audio subsystem */
+static struct snd_soc_device s3c24xx_snd_devdata = {
+	.machine = &snd_soc_machine_smdk2440,
+	.platform = &s3c24xx_soc_platform,
+	.codec_dev = &soc_codec_dev_uda1380,
+	.codec_data = &smdk2440_uda1380_setup,
+};
+
+static struct platform_device *s3c24xx_snd_device;
+
+struct smdk2440_spi_device {
+	struct device *dev;
+};
+
+static struct smdk2440_spi_device smdk2440_spi_devdata = {
+};
+
+struct s3c2410_spigpio_info smdk2440_spi_devinfo = {
+	.pin_clk = S3C2410_GPF4,
+	.pin_mosi = S3C2410_GPF5,
+	.pin_miso = S3C2410_GPF6,
+	//.board_size,
+	//.board_info,
+	.chip_select=NULL,
+};
+
+static struct platform_device *smdk2440_spi_device;
+
+static int __init smdk2440_init(void)
+{
+	int ret;
+
+	if (!machine_is_smdk2440() && !machine_is_s3c2440()) {
+		DBG("%d\n",machine_arch_type);
+		DBG("Not a SMDK2440\n");
+		return -ENODEV;
+	}
+
+	s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!s3c24xx_snd_device) {
+		DBG("platform_dev_alloc failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(s3c24xx_snd_device, &s3c24xx_snd_devdata);
+	s3c24xx_snd_devdata.dev = &s3c24xx_snd_device->dev;
+	ret = platform_device_add(s3c24xx_snd_device);
+
+	if (ret)
+		platform_device_put(s3c24xx_snd_device);
+
+	// Create a bitbanged SPI device
+
+	smdk2440_spi_device = platform_device_alloc("s3c24xx-spi-gpio",-1);
+	if (!smdk2440_spi_device) {
+		DBG("smdk2440_spi_device : platform_dev_alloc failed\n");
+		return -ENOMEM;
+	}
+	DBG("Return Code %d\n",ret);
+
+	platform_set_drvdata(smdk2440_spi_device, &smdk2440_spi_devdata);
+	smdk2440_spi_devdata.dev = &smdk2440_spi_device->dev;
+	smdk2440_spi_devdata.dev->platform_data = &smdk2440_spi_devinfo;
+	ret = platform_device_add(smdk2440_spi_device);
+
+	if (ret)
+		platform_device_put(smdk2440_spi_device);
+
+	return ret;
+}
+
+static void __exit smdk2440_exit(void)
+{
+	platform_device_unregister(s3c24xx_snd_device);
+}
+
+module_init(smdk2440_init);
+module_exit(smdk2440_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("ALSA SoC SMDK2440");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk2440_wm8956.c b/sound/soc/s3c24xx/smdk2440_wm8956.c
new file mode 100644
index 0000000..008f4ca
--- /dev/null
+++ b/sound/soc/s3c24xx/smdk2440_wm8956.c
@@ -0,0 +1,334 @@
+/*
+ * smdk2440.c  --  ALSA Soc Audio Layer
+ *
+ * (c) 2006 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * (c) 2004-2005 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ * This module is a modified version of the s3c24xx I2S driver supplied by
+ * Ben Dooks of Simtec and rejigged to the ASoC style at Wolfson Microelectronics
+ *
+ *  Revision history
+ *    11th Dec 2006   Merged with Simtec driver
+ *    10th Nov 2006   Initial version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/audio.h>
+#include <asm/io.h>
+#include <asm/arch/spi-gpio.h>
+#include "../codecs/wm8956.h"
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-i2s.h"
+
+#define SMDK2440_DEBUG 0
+#if SMDK2440_DEBUG
+#define DBG(x...) printk(KERN_DEBUG x)
+#else
+#define DBG(x...)
+#endif
+
+/* audio clock in Hz */
+#define SMDK_CLOCK_SOURCE S3C24XX_CLKSRC_MPLL
+#define SMDK_CRYSTAL_CLOCK 12000000
+
+static int smdk2440_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	DBG("Entered %s\n",__FUNCTION__);
+
+	return 0;
+}
+
+static int smdk2440_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	DBG("Entered %s\n",__FUNCTION__);
+
+	return 0;
+}
+
+static int smdk2440_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	int bclk, mclk;
+	int ret;
+	int pll;
+	int div=0,sysclkdiv=0;
+	unsigned int rate = params_rate(params);
+
+	DBG("Entered %s\n",__FUNCTION__);
+
+	/* Work out the pll dividers */
+	switch(rate)
+	{
+		case 8000:
+		case 16000:
+		case 32000:
+		case 48000:
+			pll=12288000;
+			break;
+		case 96000:
+			pll=24576000;
+			break;
+		case 11025:
+		case 22050:
+		case 44100:
+			pll=11289600;
+			break;
+		case 88200:
+			pll=22579200;
+			break;
+		default:
+			pll=12288000;
+	}
+
+	/* Work out the DAV Div */
+	switch(rate)
+	{
+		 case 96000:
+		 case 88200:
+		 case 48000:
+		 case 44100:
+		 	div=0;
+		 	break;
+		 case 32000:
+		 	div=1;
+		 	break;
+		 case 22050;
+		 	div=2;
+		 	break;
+		 case 16000:
+		 	div=1;
+		 	sysclkdiv=2;
+			break;
+		case 11025:
+			div=4;
+			break;
+		case 8000:
+			div=6;
+			break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	ret = codec_dai->dai_ops.set_pll(codec_dai, 0, SMDK_CRYSTAL_CLOCK, pll);
+	if (ret < 0)
+		return ret;
+
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8956_SYSCLKDIV, sysclkdiv);
+	if (ret < 0)
+		return ret;
+
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8956_DACDIV, div);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set the audio system clock for DAC and ADC */
+	/* 12Mhz crystal for this example */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, S3C24XX_CLKSRC_MPLL,
+		SMDK_CRYSTAL_CLOCK, SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	/* set MCLK division for sample rate */
+	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, S3C2410_IISMOD_32FS );
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops smdk2440_ops = {
+	.startup = smdk2440_startup,
+	.shutdown = smdk2440_shutdown,
+	.hw_params = smdk2440_hw_params,
+};
+
+/* smdk2440 machine dapm widgets */
+static const struct snd_soc_dapm_widget smdk2440_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", NULL),
+SND_SOC_DAPM_MIC("Mic Jack", NULL),
+SND_SOC_DAPM_LINE("Line Jack", NULL),
+};
+
+/* smdk2440 machine audio map (connections to the codec pins) */
+static const char* audio_map[][3] = {
+	/* headphone connected to  HPOUT */
+	{"Headphone Jack", NULL, "HPOUT"},
+	{"MICIN", NULL, "Mic Jack"},
+	{"MICIN", NULL, "Line Jack"},
+
+	{NULL, NULL, NULL},
+};
+
+/*
+ * Logic for a wm8956 as attached to SMDK2440
+ */
+static int smdk2440_wm8956_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+
+	DBG("Entered %s\n",__FUNCTION__);
+
+
+	/* Add smdk2440 specific widgets */
+	snd_soc_dapm_new_controls(codec, &smdk2440_dapm_widgets,
+				 ARRAY_SIZE(smdk2440_dapm_widgets));
+
+	/* Set up smdk2440 specific audio path audio_mapnects */
+	for(i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0],
+			audio_map[i][1], audio_map[i][2]);
+	}
+
+	snd_soc_dapm_sync(codec);
+
+	return 0;
+}
+
+/* s3c24xx digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link s3c24xx_dai = {
+	.name = "WM8731",
+	.stream_name = "WM8731",
+	.cpu_dai = &s3c24xx_i2s_dai,
+	.codec_dai = &wm8956_dai,
+	.init = smdk2440_wm8956_init,
+	.ops = &smdk2440_ops,
+};
+
+/* smdk2440 audio machine driver */
+static struct snd_soc_machine snd_soc_machine_smdk2440 = {
+	.name = "SMDK2440",
+	.dai_link = &s3c24xx_dai,
+	.num_links = 1,
+};
+
+static struct wm8956_setup_data smdk2440_wm8956_setup = {
+	.i2c_address = 0x00,
+};
+
+/* s3c24xx audio subsystem */
+static struct snd_soc_device s3c24xx_snd_devdata = {
+	.machine = &snd_soc_machine_smdk2440,
+	.platform = &s3c24xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8956,
+	.codec_data = &smdk2440_wm8956_setup,
+};
+
+static struct platform_device *s3c24xx_snd_device;
+
+struct smdk2440_spi_device {
+	struct device *dev;
+};
+
+static struct smdk2440_spi_device smdk2440_spi_devdata = {
+};
+
+struct s3c2410_spigpio_info smdk2440_spi_devinfo = {
+	.pin_clk = S3C2410_GPF4,
+	.pin_mosi = S3C2410_GPF5,
+	.pin_miso = S3C2410_GPF6,
+	//.board_size,
+	//.board_info,
+	.chip_select=NULL,
+};
+
+static struct platform_device *smdk2440_spi_device;
+
+static int __init smdk2440_init(void)
+{
+	int ret;
+
+	if (!machine_is_smdk2440() && !machine_is_s3c2440()) {
+		DBG("%d\n",machine_arch_type);
+		DBG("Not a SMDK2440\n");
+		return -ENODEV;
+	}
+
+	s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!s3c24xx_snd_device) {
+		DBG("platform_dev_alloc failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(s3c24xx_snd_device, &s3c24xx_snd_devdata);
+	s3c24xx_snd_devdata.dev = &s3c24xx_snd_device->dev;
+	ret = platform_device_add(s3c24xx_snd_device);
+
+	if (ret)
+		platform_device_put(s3c24xx_snd_device);
+
+	// Create a bitbanged SPI device
+
+	smdk2440_spi_device = platform_device_alloc("s3c24xx-spi-gpio",-1);
+	if (!smdk2440_spi_device) {
+		DBG("smdk2440_spi_device : platform_dev_alloc failed\n");
+		return -ENOMEM;
+	}
+	DBG("Return Code %d\n",ret);
+
+	platform_set_drvdata(smdk2440_spi_device, &smdk2440_spi_devdata);
+	smdk2440_spi_devdata.dev = &smdk2440_spi_device->dev;
+	smdk2440_spi_devdata.dev->platform_data = &smdk2440_spi_devinfo;
+	ret = platform_device_add(smdk2440_spi_device);
+
+	if (ret)
+		platform_device_put(smdk2440_spi_device);
+
+	return ret;
+}
+
+static void __exit smdk2440_exit(void)
+{
+	platform_device_unregister(s3c24xx_snd_device);
+}
+
+module_init(smdk2440_init);
+module_exit(smdk2440_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("ALSA SoC SMDK2440");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk2440_wm8991.c b/sound/soc/s3c24xx/smdk2440_wm8991.c
new file mode 100644
index 0000000..7744606
--- /dev/null
+++ b/sound/soc/s3c24xx/smdk2440_wm8991.c
@@ -0,0 +1,293 @@
+/*
+ * smdk2440_wm8991.c  --  SoC audio for smdk2440 with wm8991
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    10th Jul 2007   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/hardware.h>
+#include <asm/arch/audio.h>
+#include <asm/io.h>
+#include <asm/arch/spi-gpio.h>
+#include "../codecs/wm8991.h"
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-i2s.h"
+
+#define SMDK2440_DEBUG 0
+#if SMDK2440_DEBUG
+#define DBG(x...) printk(KERN_DEBUG x)
+#else
+#define DBG(x...)
+#endif
+
+static struct snd_soc_machine smdk2440;
+
+static int smdk2440_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int pll_out = 0, bclk = 0, mclk = 0, dacclk = 0;
+	int ret = 0;
+	unsigned long iis_clkrate;
+
+	iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+	printk("iis_clkrate %ld\n", iis_clkrate);
+
+	switch (params_rate(params)) {
+	case 96000:
+		dacclk = WM8991_DAC_CLKDIV_1;
+		bclk = WM8991_BCLK_DIV_4;
+		mclk = WM8991_MCLK_DIV_1;
+		pll_out = 12288000*2;
+		break;
+	case 48000:
+		dacclk = WM8991_DAC_CLKDIV_1;
+		bclk = WM8991_BCLK_DIV_4;
+		mclk = WM8991_MCLK_DIV_2;
+		pll_out = 12288000*2;
+		break;
+	case 16000:
+		dacclk = WM8991_DAC_CLKDIV_1;
+		bclk = WM8991_BCLK_DIV_12;
+		mclk = WM8991_MCLK_DIV_2;
+		pll_out = 12288000*2;
+		break;
+	case 8000:
+		dacclk = WM8991_DAC_CLKDIV_1;
+		bclk = WM8991_BCLK_DIV_24;
+		mclk = WM8991_MCLK_DIV_2;
+		pll_out = 12288000*2;
+		break;
+	case 88200:
+		dacclk = WM8991_DAC_CLKDIV_1;
+		bclk = WM8991_BCLK_DIV_4;
+		mclk = WM8991_MCLK_DIV_1;
+		pll_out = 11289600*2;
+		break;
+	case 44100:
+		dacclk = WM8991_DAC_CLKDIV_1;
+		bclk = WM8991_BCLK_DIV_4;
+		mclk = WM8991_MCLK_DIV_2;
+		pll_out = 11289600*2;
+		break;
+	case 22050:
+		dacclk = WM8991_DAC_CLKDIV_1;
+		bclk = WM8991_BCLK_DIV_8;
+		mclk = WM8991_MCLK_DIV_2;
+		pll_out = 11289600*2;
+		break;
+	case 11025:
+		dacclk = WM8991_DAC_CLKDIV_1;
+		bclk = WM8991_BCLK_DIV_16;
+		mclk = WM8991_MCLK_DIV_2;
+		pll_out = 11289600*2;
+		break;
+
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai,
+		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
+		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set MCLK division for sample rate */
+	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+		S3C2410_IISMOD_32FS );
+	if (ret < 0)
+		return ret;
+
+	/* Setupd Codec Clocks */
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8991_BCLK_DIV, bclk);
+	if (ret < 0)
+		return ret;
+
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8991_MCLK_DIV, mclk);
+	if (ret < 0)
+		return ret;
+
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8991_DACCLK_DIV, dacclk);
+	if (ret < 0)
+		return ret;
+
+	/* set prescaler division for sample rate */
+	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+		S3C24XX_PRESCALE(4,4));
+	if (ret < 0)
+		return ret;
+
+	/* codec PLL input is PCLK/4 */
+
+	ret = codec_dai->dai_ops.set_pll(codec_dai, 0, iis_clkrate/4,
+		pll_out);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int smdk2440_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+
+	/* disable the PLL */
+	return codec_dai->dai_ops.set_pll(codec_dai, 0, 0, 0);
+}
+
+/*
+ * Hxd8 WM8976 HiFi DAI opserations.
+ */
+static struct snd_soc_ops smdk2440_ops = {
+	.hw_params = smdk2440_hw_params,
+	.hw_free = smdk2440_hw_free,
+};
+
+static const struct snd_soc_dapm_widget wm8976_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphones", NULL),
+	SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+
+/* example machine audio_mapnections */
+static const char* audio_map[][3] = {
+
+	/* Connections to the lm4857 amp */
+	{"Headphones", NULL, "LOUT"},
+	{"Headphones", NULL, "ROUT"},
+
+	{"LIN2", NULL, "Line In"},
+	{"RIN2", NULL, "Line In"},
+
+	{NULL, NULL, NULL},
+};
+
+
+/*
+ * This is an example machine initialisation for a wm8991 connected to a
+ * smdk2440.
+ */
+
+static int smdk2440_wm8991_init(struct snd_soc_codec *codec)
+{
+	int i;
+
+	/* set up NC codec pins */
+	snd_soc_dapm_enable_pin(codec, "Internal DAC Sink", 1);
+	snd_soc_dapm_enable_pin(codec, "Internal ADC Source", 1);
+
+	/* Add smdk2440 specific widgets */
+	snd_soc_dapm_new_controls(codec, &wm8976_dapm_widgets,
+				  ARRAY_SIZE(wm8976_dapm_widgets));
+
+	/* set up smdk2440 specific audio path audio_map connects */
+	for(i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0], audio_map[i][1],
+			audio_map[i][2]);
+	}
+
+	snd_soc_dapm_enable_pin(codec, "Headphones", 1);
+	snd_soc_dapm_enable_pin(codec, "Line In", 1);
+
+	snd_soc_dapm_sync(codec);
+
+	return 0;
+}
+
+static struct snd_soc_dai_link smdk2440_dai[] = {
+{ /* Hifi Playback */
+	.name = "WM8991",
+	.stream_name = "WM8991 Primary",
+	.cpu_dai = &s3c24xx_i2s_dai,
+	.codec_dai = &wm8991_dai,
+	.init = smdk2440_wm8991_init,
+	.ops = &smdk2440_ops,
+},
+};
+
+static struct snd_soc_machine smdk2440 = {
+	.name = "smdk2440",
+	.dai_link = smdk2440_dai,
+	.num_links = ARRAY_SIZE(smdk2440_dai),
+};
+
+/* spitz audio private data */
+static struct wm8991_setup_data smdk2440_wm8991_setup = {
+	.i2c_address = 0x34 >> 1,
+};
+
+static struct snd_soc_device smdk2440_snd_devdata = {
+	.machine = &smdk2440,
+	.platform = &s3c24xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8991,
+	.codec_data = &smdk2440_wm8991_setup,
+};
+
+static struct platform_device *smdk2440_snd_device;
+
+static int __init smdk2440_init(void)
+{
+	int ret;
+
+	smdk2440_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!smdk2440_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(smdk2440_snd_device, &smdk2440_snd_devdata);
+	smdk2440_snd_devdata.dev = &smdk2440_snd_device->dev;
+	ret = platform_device_add(smdk2440_snd_device);
+
+	if (ret)
+		platform_device_put(smdk2440_snd_device);
+
+	return ret;
+}
+
+static void __exit smdk2440_exit(void)
+{
+	platform_device_unregister(smdk2440_snd_device);
+}
+
+module_init(smdk2440_init);
+module_exit(smdk2440_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM8991 SMDK2440");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/exmmb-ac97.c b/sound/soc/sh/exmmb-ac97.c
new file mode 100644
index 0000000..b0b4a20
--- /dev/null
+++ b/sound/soc/sh/exmmb-ac97.c
@@ -0,0 +1,121 @@
+/*
+ * EXM32 Motherboard AC97 sound; for SH7760 based CPU Modules.
+ *
+ * Copyright (c) 2007 MSC Vertriebsges.m.b.H.
+ * Written by Manuel Lauss <mlau@msc-ge.com>
+ * see http://www.exm32.com
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/exm7760/exm7760.h>
+#include <asm/io.h>
+
+#include <linux/exm32.h>
+#include "../codecs/ac97.h"
+
+/* #define MACH_DEBUG */
+
+#ifdef MACH_DEBUG
+#define MSG(x...)	printk(KERN_INFO "exm7760-ac97: " x)
+#else
+#define MSG(x...)	do {} while (0)
+#endif
+
+#define IPSEL 0xFE400034
+
+/* platform specific structs can be declared here */
+extern struct snd_soc_cpu_dai sh4_hac_dai[2];
+extern struct snd_soc_platform sh7760_soc_platform;
+extern struct snd_ac97_bus_ops soc_ac97_ops;
+
+/*
+ * Initialise the machine audio subsystem.
+ */
+static int exm7760_ac97_machine_init(struct snd_soc_codec *codec)
+{
+	MSG("machine_init() enter\n");
+
+	snd_soc_dapm_sync(codec);
+
+	MSG("machine_init() leave\n");
+	return 0;
+}
+
+static struct snd_soc_dai_link exm7760_ac97_dai = {
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &sh4_hac_dai[0],	/* SH7760 HAC channel 0 */
+	.codec_dai = &ac97_dai,
+	.init = exm7760_ac97_machine_init,
+	.ops = NULL,
+};
+
+static struct snd_soc_machine snd_soc_machine_exm97 = {
+	.name = "EXM32 Motherboard AC97",
+	.dai_link = &exm7760_ac97_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device exm7760_ac97_snd_devdata = {
+	.machine = &snd_soc_machine_exm97,
+	.platform = &sh7760_soc_platform,
+	.codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *exm7760_ac97_snd_device;
+
+static int exm7760_ac97_init(void)
+{
+	int ret = -ENOMEM;
+	unsigned short ipsel;
+
+	MSG("module_init() enter\n");
+
+	printk(KERN_INFO "MSC EXM32 Motherboard AC97 sound support\n");
+
+	/* enable both AC97 controllers in pinmux reg */
+	ipsel = ctrl_inw(IPSEL);
+	ipsel |= (3<<10);
+	ctrl_outw(ipsel, IPSEL);
+
+	exm7760_ac97_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!exm7760_ac97_snd_device)
+		goto out;
+
+	platform_set_drvdata(exm7760_ac97_snd_device,
+			     &exm7760_ac97_snd_devdata);
+	exm7760_ac97_snd_devdata.dev = &exm7760_ac97_snd_device->dev;
+	ret = platform_device_add(exm7760_ac97_snd_device);
+
+	if (ret)
+		platform_device_put(exm7760_ac97_snd_device);
+
+out:
+	MSG("module_init() exit (ret %d)\n", ret);
+	return ret;
+}
+
+static void exm7760_ac97_exit(void)
+{
+	MSG("exm7760_ac97_exit enter\n");
+	platform_device_del(exm7760_ac97_snd_device);
+	MSG("exm7760_ac97_exit leave\n");
+}
+
+module_init(exm7760_ac97_init);
+module_exit(exm7760_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MSC EXM32 Motherboard AC97 sound support");
+MODULE_AUTHOR("Manuel Lauss <mlau@msc-ge.com>");
diff --git a/sound/soc/sh/exmmb-i2s.c b/sound/soc/sh/exmmb-i2s.c
new file mode 100644
index 0000000..f253f94
--- /dev/null
+++ b/sound/soc/sh/exmmb-i2s.c
@@ -0,0 +1,199 @@
+/*
+ * EXM32 Development Motherboard I2S, for the Crystal CS42518 codec
+ * and SH7760 based CPU Modules.
+ *
+ * Copyright (c) 2007 MSC Vertriebsges.m.b.H.
+ * Written by Manuel Lauss <mlau@msc-ge.com>
+ * http://www.exm32.com
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/exm7760/exm7760.h>
+#include <asm/io.h>
+
+#include <linux/exm32.h>
+#include "../codecs/cs4251x.h"
+
+/* #define MACH_DEBUG */
+
+#ifdef MACH_DEBUG
+#define MSG(x...)	printk(KERN_INFO "exmmb-i2s: " x)
+#else
+#define MSG(x...)	do {} while (0)
+#endif
+
+/* SH7760 pinmux config register */
+#define IPSEL 0xFE400034
+
+extern struct snd_soc_cpu_dai sh4_ssi_dai[2];
+extern struct snd_soc_platform sh7760_soc_platform;
+
+static int
+exm7760_i2s_machine_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	int ret;
+	MSG("machine_hw_params() enter\n");
+
+	/* set codec and i2s interfaces to slave mode */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0) {
+		MSG("codec dai setfmt() failed!\n");
+		goto out;
+	}
+
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, 24576000, 0);
+	if (ret < 0) {
+		MSG("codec does not want sysclk\n");
+		goto out;
+	}
+
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_LEFT_J |
+			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0) {
+		MSG("cpu-i2s dai setfmt() failed!\n");
+		goto out;
+	}
+
+	ret = 0;
+out:
+	MSG("machine_hw_params() leave\n");
+	return ret;
+}
+
+static struct snd_soc_ops exm7760_i2s_ops = {
+	.hw_params = exm7760_i2s_machine_hw_params,
+};
+
+static int exm7760_i2s_machine_init(struct snd_soc_codec *codec)
+{
+	unsigned short ipsel;
+
+	ipsel = ctrl_inw(IPSEL);
+	ipsel &= ~(3<<11);	/* switch to SSI on channels 0,1 */
+	ctrl_outw(ipsel, IPSEL);
+
+	/* EXM32 Motherboard uses the codec in MASTER mode (DSP possible)
+	 *  with ADC (recording) data output at the SAI_SDOUT/SAI_SPCLK pins,
+	 *  the chip clocked at 24.576 MHz from an external clocksource.
+	 * RXP5/6 determine DAC input source:
+	 *	RXP5 ----\
+	 *	RXP6 ---\|
+	 *		||
+	 *		00 I2S data from CPU
+	 *		01 DSP
+	 *		10 I2S audio from GSM phone on navi module
+	 *		11 SPDIF input from motherboard/IEEE1394 controller, ...
+	 */
+	cs4251x_write(codec, CS4251X_CLKCTL,
+		      CS4251X_CLKSRC_AUTO_PLL_OMCK |
+		      CS4251X_CLKSRC_OMCK_245760MHZ);
+	cs4251x_write(codec, CS4251X_FUNCMODE,
+		      CS4251X_ADCDAI_SAISDOUT_SAISP_CLK);
+	cs4251x_write(codec, CS4251X_MUTEC, 0x1f);
+	cs4251x_write(codec, CS4251X_RCVMODECTL, 0x80);
+	cs4251x_write(codec, CS4251X_RCVMODECTL2, 0x02);
+
+	/* set DAC input to I2S from CPU */
+	cs4251x_gpio_mode(codec, CS4251X_RXP_5,
+			  CS4251X_GPIO_MODE_GPOLOW, 0, 0);
+	cs4251x_gpio_mode(codec, CS4251X_RXP_6,
+			  CS4251X_GPIO_MODE_GPOLOW, 0, 0);
+
+	snd_soc_dapm_sync(codec);
+
+	return 0;
+}
+
+/* FIXME: units are simplex, and both are wired up (SSI0 = playback,
+ *	  SSI1 = capture
+ */
+static struct snd_soc_dai_link exm7760_i2s_dai = {
+	.name = "CS4251X",
+	.stream_name = "CS4251X",
+	.cpu_dai = &sh4_ssi_dai[0],
+	.codec_dai = &cs4251x_dai,
+	.init = exm7760_i2s_machine_init,
+	.ops = &exm7760_i2s_ops,
+};
+
+static struct snd_soc_machine snd_soc_machine_template = {
+	.name = "EXM32 Motherboard I2S",
+	.dai_link = &exm7760_i2s_dai,
+	.num_links = 1,
+};
+
+/* CS42518 setup data. */
+static struct cs4251x_setup_data exm7760_i2s_codec_setup = {
+	.i2c_address = 0x9e >> 1,
+	.irq = EXMMB_CODEC_IRQ,
+};
+
+static struct snd_soc_device exm7760_i2s_snd_devdata = {
+	.machine = &snd_soc_machine_template,
+	.platform = &sh7760_soc_platform,
+	.codec_dev = &soc_codec_dev_cs4251x,
+	.codec_data = &exm7760_i2s_codec_setup,
+};
+
+static struct platform_device *exm7760_i2s_snd_device;
+
+static int exm7760_i2s_init(void)
+{
+	int ret;
+	unsigned short ipsel;
+
+	printk(KERN_INFO "EXM32 Motherboard I2S Audio support\n");
+
+	/* switch PFC to I2S on both audio paths */
+	ipsel = ctrl_inw(IPSEL);
+	ipsel &= ~(3<<10);
+	ctrl_outw(ipsel, IPSEL);
+
+	ret = -ENOMEM;
+	exm7760_i2s_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!exm7760_i2s_snd_device)
+		goto out;
+
+	platform_set_drvdata(exm7760_i2s_snd_device,
+			     &exm7760_i2s_snd_devdata);
+	exm7760_i2s_snd_devdata.dev = &exm7760_i2s_snd_device->dev;
+	ret = platform_device_add(exm7760_i2s_snd_device);
+
+	if (ret)
+		platform_device_put(exm7760_i2s_snd_device);
+
+out:
+	MSG("module_init() exit (ret %d)\n", ret);
+	return ret;
+}
+
+static void exm7760_i2s_exit(void)
+{
+	MSG("exm7760_i2s_exit enter\n");
+	platform_device_del(exm7760_i2s_snd_device);
+	MSG("exm7760_i2s_exit leave\n");
+}
+
+module_init(exm7760_i2s_init);
+module_exit(exm7760_i2s_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MSC EXM32 Motherboard I2S sound support");
+MODULE_AUTHOR("Manuel Lauss <mlau@msc-ge.com>");
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index f42e8b9..fcd4cb5 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -39,6 +39,8 @@
 #include <linux/platform_device.h>
 #include <linux/jiffies.h>
 #include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -54,6 +56,7 @@
 static int dapm_up_seq[] = {
 	[snd_soc_dapm_pre] = 0,
 	[snd_soc_dapm_supply] = 1,
+	[snd_soc_dapm_regulator_supply] = 1,
 	[snd_soc_dapm_micbias] = 2,
 	[snd_soc_dapm_aif_in] = 3,
 	[snd_soc_dapm_aif_out] = 3,
@@ -89,6 +92,7 @@ static int dapm_down_seq[] = {
 	[snd_soc_dapm_value_mux] = 9,
 	[snd_soc_dapm_aif_in] = 10,
 	[snd_soc_dapm_aif_out] = 10,
+	[snd_soc_dapm_regulator_supply] = 11,
 	[snd_soc_dapm_supply] = 11,
 	[snd_soc_dapm_post] = 12,
 };
@@ -339,10 +343,12 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
 	case snd_soc_dapm_output:
 	case snd_soc_dapm_adc:
 	case snd_soc_dapm_input:
+	case snd_soc_dapm_siggen:
 	case snd_soc_dapm_dac:
 	case snd_soc_dapm_micbias:
 	case snd_soc_dapm_vmid:
 	case snd_soc_dapm_supply:
+	case snd_soc_dapm_regulator_supply:
 	case snd_soc_dapm_aif_in:
 	case snd_soc_dapm_aif_out:
 	case snd_soc_dapm_hp:
@@ -671,8 +677,13 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
 
 	DAPM_UPDATE_STAT(widget, path_checks);
 
-	if (widget->id == snd_soc_dapm_supply)
+	switch (widget->id) {
+	case snd_soc_dapm_supply:
+	case snd_soc_dapm_regulator_supply:
 		return 0;
+	default:
+		break;
+	}
 
 	switch (widget->id) {
 	case snd_soc_dapm_adc:
@@ -736,8 +747,13 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
 
 	DAPM_UPDATE_STAT(widget, path_checks);
 
-	if (widget->id == snd_soc_dapm_supply)
+	switch (widget->id) {
+	case snd_soc_dapm_supply:
+	case snd_soc_dapm_regulator_supply:
 		return 0;
+	default:
+		break;
+	}
 
 	/* active stream ? */
 	switch (widget->id) {
@@ -772,6 +788,11 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
 			return widget->inputs;
 		}
 
+		/* signal generator */
+		if (widget->id == snd_soc_dapm_siggen) {
+			widget->inputs = snd_soc_dapm_suspend_check(widget);
+			return widget->inputs;
+		}
 	}
 
 	list_for_each_entry(path, &widget->sources, list_sink) {
@@ -814,6 +835,19 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(dapm_reg_event);
 
+/*
+ * Handler for regulator supply widget.
+ */
+int dapm_regulator_event(struct snd_soc_dapm_widget *w,
+		   struct snd_kcontrol *kcontrol, int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		return regulator_enable(w->priv);
+	else
+		return regulator_disable_deferred(w->priv, w->shift);
+}
+EXPORT_SYMBOL_GPL(dapm_regulator_event);
+
 static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
 {
 	if (w->power_checked)
@@ -1200,6 +1234,9 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
 	/* If we're off and we're not supposed to be go into STANDBY */
 	if (d->bias_level == SND_SOC_BIAS_OFF &&
 	    d->target_bias_level != SND_SOC_BIAS_OFF) {
+		if (d->dev)
+			pm_runtime_get_sync(d->dev);
+
 		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
 		if (ret != 0)
 			dev_err(d->dev,
@@ -1239,6 +1276,9 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
 		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
 		if (ret != 0)
 			dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
+
+		if (d->dev)
+			pm_runtime_put_sync(d->dev);
 	}
 
 	/* If we just powered up then move to active bias */
@@ -1288,6 +1328,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
 	}
 	switch (w->id) {
 	case snd_soc_dapm_supply:
+	case snd_soc_dapm_regulator_supply:
 		/* Supplies can't affect their outputs, only their inputs */
 		break;
 	default:
@@ -1391,6 +1432,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
 			 */
 			switch (w->id) {
 			case snd_soc_dapm_supply:
+			case snd_soc_dapm_regulator_supply:
 			case snd_soc_dapm_micbias:
 				if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
 					d->target_bias_level = SND_SOC_BIAS_STANDBY;
@@ -1750,6 +1792,7 @@ static ssize_t dapm_widget_show(struct device *dev,
 		case snd_soc_dapm_mixer:
 		case snd_soc_dapm_mixer_named_ctl:
 		case snd_soc_dapm_supply:
+		case snd_soc_dapm_regulator_supply:
 			if (w->name)
 				count += sprintf(buf + count, "%s: %s\n",
 					w->name, w->power ? "On":"Off");
@@ -1982,11 +2025,13 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
 	case snd_soc_dapm_out_drv:
 	case snd_soc_dapm_input:
 	case snd_soc_dapm_output:
+	case snd_soc_dapm_siggen:
 	case snd_soc_dapm_micbias:
 	case snd_soc_dapm_vmid:
 	case snd_soc_dapm_pre:
 	case snd_soc_dapm_post:
 	case snd_soc_dapm_supply:
+	case snd_soc_dapm_regulator_supply:
 	case snd_soc_dapm_aif_in:
 	case snd_soc_dapm_aif_out:
 		list_add(&path->list, &dapm->card->paths);
@@ -2653,10 +2698,25 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 {
 	struct snd_soc_dapm_widget *w;
 	size_t name_len;
+	int ret;
 
 	if ((w = dapm_cnew_widget(widget)) == NULL)
 		return -ENOMEM;
 
+	switch (w->id) {
+	case snd_soc_dapm_regulator_supply:
+		w->priv = devm_regulator_get(dapm->dev, w->name);
+		if (IS_ERR(w->priv)) {
+			ret = PTR_ERR(w->priv);
+			dev_err(dapm->dev, "Failed to request %s: %d\n",
+				w->name, ret);
+			return ret;
+		}
+		break;
+	default:
+		break;
+	}
+
 	name_len = strlen(widget->name) + 1;
 	if (dapm->codec && dapm->codec->name_prefix)
 		name_len += 1 + strlen(dapm->codec->name_prefix);
@@ -2702,6 +2762,7 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 		w->power_check = dapm_generic_check_power;
 		break;
 	case snd_soc_dapm_supply:
+	case snd_soc_dapm_regulator_supply:
 		w->power_check = dapm_supply_check_power;
 		break;
 	default:

