Merge commit 'a5479e389e989acfeca9c32eeb0083d086202280' into for-2.6.32
diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h
index bb154ea..57249bb 100644
--- a/arch/arm/plat-omap/include/mach/mcbsp.h
+++ b/arch/arm/plat-omap/include/mach/mcbsp.h
@@ -387,8 +387,8 @@
 void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config);
 int omap_mcbsp_request(unsigned int id);
 void omap_mcbsp_free(unsigned int id);
-void omap_mcbsp_start(unsigned int id);
-void omap_mcbsp_stop(unsigned int id);
+void omap_mcbsp_start(unsigned int id, int tx, int rx);
+void omap_mcbsp_stop(unsigned int id, int tx, int rx);
 void omap_mcbsp_xmit_word(unsigned int id, u32 word);
 u32 omap_mcbsp_recv_word(unsigned int id);
 
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index efa0e01..a3d2313 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -328,14 +328,15 @@
 EXPORT_SYMBOL(omap_mcbsp_free);
 
 /*
- * Here we start the McBSP, by enabling the sample
- * generator, both transmitter and receivers,
- * and the frame sync.
+ * Here we start the McBSP, by enabling transmitter, receiver or both.
+ * If no transmitter or receiver is active prior calling, then sample-rate
+ * generator and frame sync are started.
  */
-void omap_mcbsp_start(unsigned int id)
+void omap_mcbsp_start(unsigned int id, int tx, int rx)
 {
 	struct omap_mcbsp *mcbsp;
 	void __iomem *io_base;
+	int idle;
 	u16 w;
 
 	if (!omap_mcbsp_check_valid_id(id)) {
@@ -348,32 +349,40 @@
 	mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7;
 	mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7;
 
-	/* Start the sample generator */
-	w = OMAP_MCBSP_READ(io_base, SPCR2);
-	OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
+	idle = !((OMAP_MCBSP_READ(io_base, SPCR2) |
+		  OMAP_MCBSP_READ(io_base, SPCR1)) & 1);
+
+	if (idle) {
+		/* Start the sample generator */
+		w = OMAP_MCBSP_READ(io_base, SPCR2);
+		OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
+	}
 
 	/* Enable transmitter and receiver */
 	w = OMAP_MCBSP_READ(io_base, SPCR2);
-	OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1);
+	OMAP_MCBSP_WRITE(io_base, SPCR2, w | (tx & 1));
 
 	w = OMAP_MCBSP_READ(io_base, SPCR1);
-	OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1);
+	OMAP_MCBSP_WRITE(io_base, SPCR1, w | (rx & 1));
 
 	udelay(100);
 
-	/* Start frame sync */
-	w = OMAP_MCBSP_READ(io_base, SPCR2);
-	OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
+	if (idle) {
+		/* Start frame sync */
+		w = OMAP_MCBSP_READ(io_base, SPCR2);
+		OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
+	}
 
 	/* Dump McBSP Regs */
 	omap_mcbsp_dump_reg(id);
 }
 EXPORT_SYMBOL(omap_mcbsp_start);
 
-void omap_mcbsp_stop(unsigned int id)
+void omap_mcbsp_stop(unsigned int id, int tx, int rx)
 {
 	struct omap_mcbsp *mcbsp;
 	void __iomem *io_base;
+	int idle;
 	u16 w;
 
 	if (!omap_mcbsp_check_valid_id(id)) {
@@ -386,15 +395,20 @@
 
 	/* Reset transmitter */
 	w = OMAP_MCBSP_READ(io_base, SPCR2);
-	OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1));
+	OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(tx & 1));
 
 	/* Reset receiver */
 	w = OMAP_MCBSP_READ(io_base, SPCR1);
-	OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1));
+	OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(rx & 1));
 
-	/* Reset the sample rate generator */
-	w = OMAP_MCBSP_READ(io_base, SPCR2);
-	OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
+	idle = !((OMAP_MCBSP_READ(io_base, SPCR2) |
+		  OMAP_MCBSP_READ(io_base, SPCR1)) & 1);
+
+	if (idle) {
+		/* Reset the sample rate generator */
+		w = OMAP_MCBSP_READ(io_base, SPCR2);
+		OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
+	}
 }
 EXPORT_SYMBOL(omap_mcbsp_stop);
 
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 26af981..15bd3b0 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -47,7 +47,7 @@
 #define N_SLCAN		17	/* Serial / USB serial CAN Adaptors */
 #define N_PPS		18	/* Pulse per Second */
 
-#define N_AMSDELTA	19	/* codec control over modem, board specific */
+#define N_V253		19	/* Codec control over voice modem */
 
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 2d3fa29..97ca9af 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -78,7 +78,13 @@
 #define SND_SOC_CLOCK_IN		0
 #define SND_SOC_CLOCK_OUT		1
 
-#define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S16_LE |\
+#define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S8 |\
+			       SNDRV_PCM_FMTBIT_S16_LE |\
+			       SNDRV_PCM_FMTBIT_S16_BE |\
+			       SNDRV_PCM_FMTBIT_S20_3LE |\
+			       SNDRV_PCM_FMTBIT_S20_3BE |\
+			       SNDRV_PCM_FMTBIT_S24_3LE |\
+			       SNDRV_PCM_FMTBIT_S24_3BE |\
                                SNDRV_PCM_FMTBIT_S32_LE |\
                                SNDRV_PCM_FMTBIT_S32_BE)
 
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 55b3309..dbb1702 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -209,11 +209,20 @@
 
 extern struct snd_ac97_bus_ops soc_ac97_ops;
 
+enum snd_soc_control_type {
+	SND_SOC_CUSTOM,
+	SND_SOC_I2C,
+	SND_SOC_SPI,
+};
+
 int snd_soc_register_platform(struct snd_soc_platform *platform);
 void snd_soc_unregister_platform(struct snd_soc_platform *platform);
 int snd_soc_register_codec(struct snd_soc_codec *codec);
 void snd_soc_unregister_codec(struct snd_soc_codec *codec);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
+int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
+			       int addr_bits, int data_bits,
+			       enum snd_soc_control_type control);
 
 #ifdef CONFIG_PM
 int snd_soc_suspend_device(struct device *dev);
@@ -387,7 +396,7 @@
 	int (*volatile_register)(unsigned int);
 	int (*readable_register)(unsigned int);
 	hw_write_t hw_write;
-	hw_read_t hw_read;
+	unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
 	void *reg_cache;
 	short reg_cache_size;
 	short reg_cache_step;
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 6f1e28d..4eaf48a 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,4 +1,4 @@
-snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o
+snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o
 
 obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
 obj-$(CONFIG_SND_SOC)	+= codecs/
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index cb0d1bf..126b15b 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -145,8 +145,8 @@
 		      u8 *value)
 {
 	*value = reg & 0xff;
-	if (codec->hw_read(codec->control_data, value, 1) != 1)
-		return -EIO;
+
+	value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]);
 
 	aic3x_write_reg_cache(codec, reg, *value);
 	return 0;
@@ -1325,12 +1325,6 @@
 	.id_table = aic3x_i2c_id,
 };
 
-static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len)
-{
-	value[0] = i2c_smbus_read_byte_data(client, value[0]);
-	return (len == 1);
-}
-
 static int aic3x_add_i2c_device(struct platform_device *pdev,
 				 const struct aic3x_setup_data *setup)
 {
@@ -1403,7 +1397,6 @@
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
 		codec->hw_write = (hw_write_t) i2c_master_send;
-		codec->hw_read = (hw_read_t) aic3x_i2c_read;
 		ret = aic3x_add_i2c_device(pdev, setup);
 	}
 #else
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 261d4cb..060d5d0 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -58,55 +58,7 @@
 #define WM8510_POWER1_BIASEN  0x08
 #define WM8510_POWER1_BUFIOEN 0x10
 
-/*
- * read wm8510 register cache
- */
-static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg == WM8510_RESET)
-		return 0;
-	if (reg >= WM8510_CACHEREGNUM)
-		return -1;
-	return cache[reg];
-}
-
-/*
- * write wm8510 register cache
- */
-static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec,
-	u16 reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg >= WM8510_CACHEREGNUM)
-		return;
-	cache[reg] = value;
-}
-
-/*
- * write to the WM8510 register space
- */
-static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	u8 data[2];
-
-	/* data is
-	 *   D15..D9 WM8510 register offset
-	 *   D8...D0 register data
-	 */
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	wm8510_write_reg_cache(codec, reg, value);
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
-}
-
-#define wm8510_reset(c)	wm8510_write(c, WM8510_RESET, 0)
+#define wm8510_reset(c)	snd_soc_write(c, WM8510_RESET, 0)
 
 static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
 static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
@@ -327,27 +279,27 @@
 
 	if (freq_in == 0 || freq_out == 0) {
 		/* Clock CODEC directly from MCLK */
-		reg = wm8510_read_reg_cache(codec, WM8510_CLOCK);
-		wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff);
+		reg = snd_soc_read(codec, WM8510_CLOCK);
+		snd_soc_write(codec, WM8510_CLOCK, reg & 0x0ff);
 
 		/* Turn off PLL */
-		reg = wm8510_read_reg_cache(codec, WM8510_POWER1);
-		wm8510_write(codec, WM8510_POWER1, reg & 0x1df);
+		reg = snd_soc_read(codec, WM8510_POWER1);
+		snd_soc_write(codec, WM8510_POWER1, reg & 0x1df);
 		return 0;
 	}
 
 	pll_factors(freq_out*4, freq_in);
 
-	wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
-	wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18);
-	wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff);
-	wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff);
-	reg = wm8510_read_reg_cache(codec, WM8510_POWER1);
-	wm8510_write(codec, WM8510_POWER1, reg | 0x020);
+	snd_soc_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
+	snd_soc_write(codec, WM8510_PLLK1, pll_div.k >> 18);
+	snd_soc_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff);
+	snd_soc_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff);
+	reg = snd_soc_read(codec, WM8510_POWER1);
+	snd_soc_write(codec, WM8510_POWER1, reg | 0x020);
 
 	/* Run CODEC from PLL instead of MCLK */
-	reg = wm8510_read_reg_cache(codec, WM8510_CLOCK);
-	wm8510_write(codec, WM8510_CLOCK, reg | 0x100);
+	reg = snd_soc_read(codec, WM8510_CLOCK);
+	snd_soc_write(codec, WM8510_CLOCK, reg | 0x100);
 
 	return 0;
 }
@@ -363,24 +315,24 @@
 
 	switch (div_id) {
 	case WM8510_OPCLKDIV:
-		reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf;
-		wm8510_write(codec, WM8510_GPIO, reg | div);
+		reg = snd_soc_read(codec, WM8510_GPIO) & 0x1cf;
+		snd_soc_write(codec, WM8510_GPIO, reg | div);
 		break;
 	case WM8510_MCLKDIV:
-		reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x11f;
-		wm8510_write(codec, WM8510_CLOCK, reg | div);
+		reg = snd_soc_read(codec, WM8510_CLOCK) & 0x11f;
+		snd_soc_write(codec, WM8510_CLOCK, reg | div);
 		break;
 	case WM8510_ADCCLK:
-		reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7;
-		wm8510_write(codec, WM8510_ADC, reg | div);
+		reg = snd_soc_read(codec, WM8510_ADC) & 0x1f7;
+		snd_soc_write(codec, WM8510_ADC, reg | div);
 		break;
 	case WM8510_DACCLK:
-		reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7;
-		wm8510_write(codec, WM8510_DAC, reg | div);
+		reg = snd_soc_read(codec, WM8510_DAC) & 0x1f7;
+		snd_soc_write(codec, WM8510_DAC, reg | div);
 		break;
 	case WM8510_BCLKDIV:
-		reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3;
-		wm8510_write(codec, WM8510_CLOCK, reg | div);
+		reg = snd_soc_read(codec, WM8510_CLOCK) & 0x1e3;
+		snd_soc_write(codec, WM8510_CLOCK, reg | div);
 		break;
 	default:
 		return -EINVAL;
@@ -394,7 +346,7 @@
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
 	u16 iface = 0;
-	u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe;
+	u16 clk = snd_soc_read(codec, WM8510_CLOCK) & 0x1fe;
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -441,8 +393,8 @@
 		return -EINVAL;
 	}
 
-	wm8510_write(codec, WM8510_IFACE, iface);
-	wm8510_write(codec, WM8510_CLOCK, clk);
+	snd_soc_write(codec, WM8510_IFACE, iface);
+	snd_soc_write(codec, WM8510_CLOCK, clk);
 	return 0;
 }
 
@@ -453,8 +405,8 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
-	u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f;
-	u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1;
+	u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
+	u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
 
 	/* bit size */
 	switch (params_format(params)) {
@@ -493,20 +445,20 @@
 		break;
 	}
 
-	wm8510_write(codec, WM8510_IFACE, iface);
-	wm8510_write(codec, WM8510_ADD, adn);
+	snd_soc_write(codec, WM8510_IFACE, iface);
+	snd_soc_write(codec, WM8510_ADD, adn);
 	return 0;
 }
 
 static int wm8510_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf;
+	u16 mute_reg = snd_soc_read(codec, WM8510_DAC) & 0xffbf;
 
 	if (mute)
-		wm8510_write(codec, WM8510_DAC, mute_reg | 0x40);
+		snd_soc_write(codec, WM8510_DAC, mute_reg | 0x40);
 	else
-		wm8510_write(codec, WM8510_DAC, mute_reg);
+		snd_soc_write(codec, WM8510_DAC, mute_reg);
 	return 0;
 }
 
@@ -514,13 +466,13 @@
 static int wm8510_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
 {
-	u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3;
+	u16 power1 = snd_soc_read(codec, WM8510_POWER1) & ~0x3;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 		power1 |= 0x1;  /* VMID 50k */
-		wm8510_write(codec, WM8510_POWER1, power1);
+		snd_soc_write(codec, WM8510_POWER1, power1);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
@@ -528,18 +480,18 @@
 
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
 			/* Initial cap charge at VMID 5k */
-			wm8510_write(codec, WM8510_POWER1, power1 | 0x3);
+			snd_soc_write(codec, WM8510_POWER1, power1 | 0x3);
 			mdelay(100);
 		}
 
 		power1 |= 0x2;  /* VMID 500k */
-		wm8510_write(codec, WM8510_POWER1, power1);
+		snd_soc_write(codec, WM8510_POWER1, power1);
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		wm8510_write(codec, WM8510_POWER1, 0);
-		wm8510_write(codec, WM8510_POWER2, 0);
-		wm8510_write(codec, WM8510_POWER3, 0);
+		snd_soc_write(codec, WM8510_POWER1, 0);
+		snd_soc_write(codec, WM8510_POWER2, 0);
+		snd_soc_write(codec, WM8510_POWER3, 0);
 		break;
 	}
 
@@ -613,15 +565,14 @@
  * initialise the WM8510 driver
  * register the mixer and dsp interfaces with the kernel
  */
-static int wm8510_init(struct snd_soc_device *socdev)
+static int wm8510_init(struct snd_soc_device *socdev,
+		       enum snd_soc_control_type control)
 {
 	struct snd_soc_codec *codec = socdev->card->codec;
 	int ret = 0;
 
 	codec->name = "WM8510";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8510_read_reg_cache;
-	codec->write = wm8510_write;
 	codec->set_bias_level = wm8510_set_bias_level;
 	codec->dai = &wm8510_dai;
 	codec->num_dai = 1;
@@ -631,13 +582,20 @@
 	if (codec->reg_cache == NULL)
 		return -ENOMEM;
 
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n",
+		       ret);
+		goto err;
+	}
+
 	wm8510_reset(codec);
 
 	/* register pcms */
 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8510: failed to create pcms\n");
-		goto pcm_err;
+		goto err;
 	}
 
 	/* power on device */
@@ -656,7 +614,7 @@
 card_err:
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
-pcm_err:
+err:
 	kfree(codec->reg_cache);
 	return ret;
 }
@@ -679,7 +637,7 @@
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	ret = wm8510_init(socdev);
+	ret = wm8510_init(socdev, SND_SOC_I2C);
 	if (ret < 0)
 		pr_err("failed to initialise WM8510\n");
 
@@ -759,7 +717,7 @@
 
 	codec->control_data = spi;
 
-	ret = wm8510_init(socdev);
+	ret = wm8510_init(socdev, SND_SOC_SPI);
 	if (ret < 0)
 		dev_err(&spi->dev, "failed to initialise WM8510\n");
 
@@ -780,30 +738,6 @@
 	.probe		= wm8510_spi_probe,
 	.remove		= __devexit_p(wm8510_spi_remove),
 };
-
-static int wm8510_spi_write(struct spi_device *spi, const char *data, int len)
-{
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[2];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[0];
-	msg[1] = data[1];
-
-	spi_message_init(&m);
-	memset(&t, 0, (sizeof t));
-
-	t.tx_buf = &msg[0];
-	t.len = len;
-
-	spi_message_add_tail(&t, &m);
-	spi_sync(spi, &m);
-
-	return len;
-}
 #endif /* CONFIG_SPI_MASTER */
 
 static int wm8510_probe(struct platform_device *pdev)
@@ -828,13 +762,11 @@
 	wm8510_socdev = socdev;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		codec->hw_write = (hw_write_t)i2c_master_send;
 		ret = wm8510_add_i2c_device(pdev, setup);
 	}
 #endif
 #if defined(CONFIG_SPI_MASTER)
 	if (setup->spi) {
-		codec->hw_write = (hw_write_t)wm8510_spi_write;
 		ret = spi_register_driver(&wm8510_spi_driver);
 		if (ret != 0)
 			printk(KERN_ERR "can't add spi driver");
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 3b499ae..25870a4 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -62,7 +62,7 @@
 	0x0000,     /* R8 - ZERO_DETECT */
 };
 
-static int wm8523_volatile(unsigned int reg)
+static int wm8523_volatile_register(unsigned int reg)
 {
 	switch (reg) {
 	case WM8523_DEVICE_ID:
@@ -73,71 +73,9 @@
 	}
 }
 
-static int wm8523_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	struct wm8523_priv *wm8523 = codec->private_data;
-	u8 data[3];
-
-	BUG_ON(reg > WM8523_MAX_REGISTER);
-
-	data[0] = reg;
-	data[1] = (value >> 8) & 0x00ff;
-	data[2] = value & 0x00ff;
-
-	if (!wm8523_volatile(reg))
-		wm8523->reg_cache[reg] = value;
-	if (codec->hw_write(codec->control_data, data, 3) == 3)
-		return 0;
-	else
-		return -EIO;
-}
-
 static int wm8523_reset(struct snd_soc_codec *codec)
 {
-	return wm8523_write(codec, WM8523_DEVICE_ID, 0);
-}
-
-static unsigned int wm8523_read_hw(struct snd_soc_codec *codec, u8 reg)
-{
-	struct i2c_msg xfer[2];
-	u16 data;
-	int ret;
-	struct i2c_client *i2c = codec->control_data;
-
-	/* Write register */
-	xfer[0].addr = i2c->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 1;
-	xfer[0].buf = &reg;
-
-	/* Read data */
-	xfer[1].addr = i2c->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 2;
-	xfer[1].buf = (u8 *)&data;
-
-	ret = i2c_transfer(i2c->adapter, xfer, 2);
-	if (ret != 2) {
-		dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret);
-		return 0;
-	}
-
-	return (data >> 8) | ((data & 0xff) << 8);
-}
-
-
-static unsigned int wm8523_read(struct snd_soc_codec *codec,
-				unsigned int reg)
-{
-	u16 *reg_cache = codec->reg_cache;
-
-	BUG_ON(reg > WM8523_MAX_REGISTER);
-
-	if (wm8523_volatile(reg))
-		return wm8523_read_hw(codec, reg);
-	else
-		return reg_cache[reg];
+	return snd_soc_write(codec, WM8523_DEVICE_ID, 0);
 }
 
 static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0);
@@ -228,8 +166,8 @@
 	struct snd_soc_codec *codec = socdev->card->codec;
 	struct wm8523_priv *wm8523 = codec->private_data;
 	int i;
-	u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1);
-	u16 aifctrl2 = wm8523_read(codec, WM8523_AIF_CTRL2);
+	u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
+	u16 aifctrl2 = snd_soc_read(codec, WM8523_AIF_CTRL2);
 
 	/* Find a supported LRCLK ratio */
 	for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
@@ -263,8 +201,8 @@
 		break;
 	}
 
-	wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1);
-	wm8523_write(codec, WM8523_AIF_CTRL2, aifctrl2);
+	snd_soc_write(codec, WM8523_AIF_CTRL1, aifctrl1);
+	snd_soc_write(codec, WM8523_AIF_CTRL2, aifctrl2);
 
 	return 0;
 }
@@ -322,7 +260,7 @@
 		unsigned int fmt)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1);
+	u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
 
 	aifctrl1 &= ~(WM8523_BCLK_INV_MASK | WM8523_LRCLK_INV_MASK |
 		      WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK);
@@ -372,7 +310,7 @@
 		return -EINVAL;
 	}
 
-	wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1);
+	snd_soc_write(codec, WM8523_AIF_CTRL1, aifctrl1);
 
 	return 0;
 }
@@ -411,7 +349,7 @@
 			/* Sync back default/cached values */
 			for (i = WM8523_AIF_CTRL1;
 			     i < WM8523_MAX_REGISTER; i++)
-				wm8523_write(codec, i, wm8523->reg_cache[i]);
+				snd_soc_write(codec, i, wm8523->reg_cache[i]);
 
 
 			msleep(100);
@@ -543,7 +481,8 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523);
 
-static int wm8523_register(struct wm8523_priv *wm8523)
+static int wm8523_register(struct wm8523_priv *wm8523,
+			   enum snd_soc_control_type control)
 {
 	int ret;
 	struct snd_soc_codec *codec = &wm8523->codec;
@@ -561,14 +500,13 @@
 	codec->private_data = wm8523;
 	codec->name = "WM8523";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8523_read;
-	codec->write = wm8523_write;
 	codec->bias_level = SND_SOC_BIAS_OFF;
 	codec->set_bias_level = wm8523_set_bias_level;
 	codec->dai = &wm8523_dai;
 	codec->num_dai = 1;
 	codec->reg_cache_size = WM8523_REGISTER_COUNT;
 	codec->reg_cache = &wm8523->reg_cache;
+	codec->volatile_register = wm8523_volatile_register;
 
 	wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
 	wm8523->rate_constraint.count =
@@ -576,6 +514,12 @@
 
 	memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg));
 
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
 		wm8523->supplies[i].supply = wm8523_supply_names[i];
 
@@ -593,7 +537,7 @@
 		goto err_get;
 	}
 
-	ret = wm8523_read(codec, WM8523_DEVICE_ID);
+	ret = snd_soc_read(codec, WM8523_DEVICE_ID);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to read ID register\n");
 		goto err_enable;
@@ -604,7 +548,7 @@
 		goto err_enable;
 	}
 
-	ret = wm8523_read(codec, WM8523_REVISION);
+	ret = snd_soc_read(codec, WM8523_REVISION);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to read revision register\n");
 		goto err_enable;
@@ -684,7 +628,7 @@
 
 	codec->dev = &i2c->dev;
 
-	return wm8523_register(wm8523);
+	return wm8523_register(wm8523, SND_SOC_I2C);
 }
 
 static __devexit int wm8523_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 97b9ed9..d547347 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -205,73 +205,6 @@
 	struct pll_state b;
 };
 
-/*
- * read wm8580 register cache
- */
-static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	BUG_ON(reg >= ARRAY_SIZE(wm8580_reg));
-	return cache[reg];
-}
-
-/*
- * write wm8580 register cache
- */
-static inline void wm8580_write_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-
-	cache[reg] = value;
-}
-
-/*
- * write to the WM8580 register space
- */
-static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	u8 data[2];
-
-	BUG_ON(reg >= ARRAY_SIZE(wm8580_reg));
-
-	/* Registers are 9 bits wide */
-	value &= 0x1ff;
-
-	switch (reg) {
-	case WM8580_RESET:
-		/* Uncached */
-		break;
-	default:
-		if (value == wm8580_read_reg_cache(codec, reg))
-			return 0;
-	}
-
-	/* data is
-	 *   D15..D9 WM8580 register offset
-	 *   D8...D0 register data
-	 */
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	wm8580_write_reg_cache(codec, reg, value);
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
-}
-
-static inline unsigned int wm8580_read(struct snd_soc_codec *codec,
-				       unsigned int reg)
-{
-	switch (reg) {
-	default:
-		return wm8580_read_reg_cache(codec, reg);
-	}
-}
-
 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
 
 static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
@@ -280,25 +213,22 @@
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	u16 *reg_cache = codec->reg_cache;
 	unsigned int reg = mc->reg;
 	unsigned int reg2 = mc->rreg;
 	int ret;
-	u16 val;
 
 	/* Clear the register cache so we write without VU set */
-	wm8580_write_reg_cache(codec, reg, 0);
-	wm8580_write_reg_cache(codec, reg2, 0);
+	reg_cache[reg] = 0;
+	reg_cache[reg2] = 0;
 
 	ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
 	if (ret < 0)
 		return ret;
 
 	/* Now write again with the volume update bit set */
-	val = wm8580_read_reg_cache(codec, reg);
-	wm8580_write(codec, reg, val | 0x0100);
-
-	val = wm8580_read_reg_cache(codec, reg2);
-	wm8580_write(codec, reg2, val | 0x0100);
+	snd_soc_update_bits(codec, reg, 0x100, 0x100);
+	snd_soc_update_bits(codec, reg2, 0x100, 0x100);
 
 	return 0;
 }
@@ -521,27 +451,27 @@
 	/* Always disable the PLL - it is not safe to leave it running
 	 * while reprogramming it.
 	 */
-	reg = wm8580_read(codec, WM8580_PWRDN2);
-	wm8580_write(codec, WM8580_PWRDN2, reg | pwr_mask);
+	reg = snd_soc_read(codec, WM8580_PWRDN2);
+	snd_soc_write(codec, WM8580_PWRDN2, reg | pwr_mask);
 
 	if (!freq_in || !freq_out)
 		return 0;
 
-	wm8580_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff);
-	wm8580_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff);
-	wm8580_write(codec, WM8580_PLLA3 + offset,
+	snd_soc_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff);
+	snd_soc_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff);
+	snd_soc_write(codec, WM8580_PLLA3 + offset,
 		     (pll_div.k >> 18 & 0xf) | (pll_div.n << 4));
 
-	reg = wm8580_read(codec, WM8580_PLLA4 + offset);
+	reg = snd_soc_read(codec, WM8580_PLLA4 + offset);
 	reg &= ~0x3f;
 	reg |= pll_div.prescale | pll_div.postscale << 1 |
 		pll_div.freqmode << 3;
 
-	wm8580_write(codec, WM8580_PLLA4 + offset, reg);
+	snd_soc_write(codec, WM8580_PLLA4 + offset, reg);
 
 	/* All done, turn it on */
-	reg = wm8580_read(codec, WM8580_PWRDN2);
-	wm8580_write(codec, WM8580_PWRDN2, reg & ~pwr_mask);
+	reg = snd_soc_read(codec, WM8580_PWRDN2);
+	snd_soc_write(codec, WM8580_PWRDN2, reg & ~pwr_mask);
 
 	return 0;
 }
@@ -556,7 +486,7 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
-	u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id);
+	u16 paifb = snd_soc_read(codec, WM8580_PAIF3 + dai->id);
 
 	paifb &= ~WM8580_AIF_LENGTH_MASK;
 	/* bit size */
@@ -576,7 +506,7 @@
 		return -EINVAL;
 	}
 
-	wm8580_write(codec, WM8580_PAIF3 + dai->id, paifb);
+	snd_soc_write(codec, WM8580_PAIF3 + dai->id, paifb);
 	return 0;
 }
 
@@ -588,8 +518,8 @@
 	unsigned int aifb;
 	int can_invert_lrclk;
 
-	aifa = wm8580_read(codec, WM8580_PAIF1 + codec_dai->id);
-	aifb = wm8580_read(codec, WM8580_PAIF3 + codec_dai->id);
+	aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->id);
+	aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->id);
 
 	aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP);
 
@@ -655,8 +585,8 @@
 		return -EINVAL;
 	}
 
-	wm8580_write(codec, WM8580_PAIF1 + codec_dai->id, aifa);
-	wm8580_write(codec, WM8580_PAIF3 + codec_dai->id, aifb);
+	snd_soc_write(codec, WM8580_PAIF1 + codec_dai->id, aifa);
+	snd_soc_write(codec, WM8580_PAIF3 + codec_dai->id, aifb);
 
 	return 0;
 }
@@ -669,7 +599,7 @@
 
 	switch (div_id) {
 	case WM8580_MCLK:
-		reg = wm8580_read(codec, WM8580_PLLB4);
+		reg = snd_soc_read(codec, WM8580_PLLB4);
 		reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK;
 
 		switch (div) {
@@ -691,11 +621,11 @@
 		default:
 			return -EINVAL;
 		}
-		wm8580_write(codec, WM8580_PLLB4, reg);
+		snd_soc_write(codec, WM8580_PLLB4, reg);
 		break;
 
 	case WM8580_DAC_CLKSEL:
-		reg = wm8580_read(codec, WM8580_CLKSEL);
+		reg = snd_soc_read(codec, WM8580_CLKSEL);
 		reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK;
 
 		switch (div) {
@@ -713,11 +643,11 @@
 		default:
 			return -EINVAL;
 		}
-		wm8580_write(codec, WM8580_CLKSEL, reg);
+		snd_soc_write(codec, WM8580_CLKSEL, reg);
 		break;
 
 	case WM8580_CLKOUTSRC:
-		reg = wm8580_read(codec, WM8580_PLLB4);
+		reg = snd_soc_read(codec, WM8580_PLLB4);
 		reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK;
 
 		switch (div) {
@@ -739,7 +669,7 @@
 		default:
 			return -EINVAL;
 		}
-		wm8580_write(codec, WM8580_PLLB4, reg);
+		snd_soc_write(codec, WM8580_PLLB4, reg);
 		break;
 
 	default:
@@ -754,14 +684,14 @@
 	struct snd_soc_codec *codec = codec_dai->codec;
 	unsigned int reg;
 
-	reg = wm8580_read(codec, WM8580_DAC_CONTROL5);
+	reg = snd_soc_read(codec, WM8580_DAC_CONTROL5);
 
 	if (mute)
 		reg |= WM8580_DAC_CONTROL5_MUTEALL;
 	else
 		reg &= ~WM8580_DAC_CONTROL5_MUTEALL;
 
-	wm8580_write(codec, WM8580_DAC_CONTROL5, reg);
+	snd_soc_write(codec, WM8580_DAC_CONTROL5, reg);
 
 	return 0;
 }
@@ -778,20 +708,20 @@
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
 			/* Power up and get individual control of the DACs */
-			reg = wm8580_read(codec, WM8580_PWRDN1);
+			reg = snd_soc_read(codec, WM8580_PWRDN1);
 			reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD);
-			wm8580_write(codec, WM8580_PWRDN1, reg);
+			snd_soc_write(codec, WM8580_PWRDN1, reg);
 
 			/* Make VMID high impedence */
-			reg = wm8580_read(codec,  WM8580_ADC_CONTROL1);
+			reg = snd_soc_read(codec,  WM8580_ADC_CONTROL1);
 			reg &= ~0x100;
-			wm8580_write(codec, WM8580_ADC_CONTROL1, reg);
+			snd_soc_write(codec, WM8580_ADC_CONTROL1, reg);
 		}
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		reg = wm8580_read(codec, WM8580_PWRDN1);
-		wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN);
+		reg = snd_soc_read(codec, WM8580_PWRDN1);
+		snd_soc_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN);
 		break;
 	}
 	codec->bias_level = level;
@@ -902,7 +832,8 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
 
-static int wm8580_register(struct wm8580_priv *wm8580)
+static int wm8580_register(struct wm8580_priv *wm8580,
+			   enum snd_soc_control_type control)
 {
 	int ret, i;
 	struct snd_soc_codec *codec = &wm8580->codec;
@@ -920,8 +851,6 @@
 	codec->private_data = wm8580;
 	codec->name = "WM8580";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8580_read_reg_cache;
-	codec->write = wm8580_write;
 	codec->bias_level = SND_SOC_BIAS_OFF;
 	codec->set_bias_level = wm8580_set_bias_level;
 	codec->dai = wm8580_dai;
@@ -931,6 +860,12 @@
 
 	memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg));
 
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++)
 		wm8580->supplies[i].supply = wm8580_supply_names[i];
 
@@ -949,7 +884,7 @@
 	}
 
 	/* Get the codec into a known state */
-	ret = wm8580_write(codec, WM8580_RESET, 0);
+	ret = snd_soc_write(codec, WM8580_RESET, 0);
 	if (ret != 0) {
 		dev_err(codec->dev, "Failed to reset codec: %d\n", ret);
 		goto err_regulator_enable;
@@ -1010,14 +945,13 @@
 		return -ENOMEM;
 
 	codec = &wm8580->codec;
-	codec->hw_write = (hw_write_t)i2c_master_send;
 
 	i2c_set_clientdata(i2c, wm8580);
 	codec->control_data = i2c;
 
 	codec->dev = &i2c->dev;
 
-	return wm8580_register(wm8580);
+	return wm8580_register(wm8580, SND_SOC_I2C);
 }
 
 static int wm8580_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index e7ff212..16e969a 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -43,45 +43,6 @@
 	0x100,
 };
 
-static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults));
-	return cache[reg];
-}
-
-static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec,
-	u16 reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-	BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults));
-	cache[reg] = value;
-}
-
-/*
- * write to the WM8728 register space
- */
-static int wm8728_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	u8 data[2];
-
-	/* data is
-	 *   D15..D9 WM8728 register offset
-	 *   D8...D0 register data
-	 */
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	wm8728_write_reg_cache(codec, reg, value);
-
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
-}
-
 static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);
 
 static const struct snd_kcontrol_new wm8728_snd_controls[] = {
@@ -121,12 +82,12 @@
 static int wm8728_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = wm8728_read_reg_cache(codec, WM8728_DACCTL);
+	u16 mute_reg = snd_soc_read(codec, WM8728_DACCTL);
 
 	if (mute)
-		wm8728_write(codec, WM8728_DACCTL, mute_reg | 1);
+		snd_soc_write(codec, WM8728_DACCTL, mute_reg | 1);
 	else
-		wm8728_write(codec, WM8728_DACCTL, mute_reg & ~1);
+		snd_soc_write(codec, WM8728_DACCTL, mute_reg & ~1);
 
 	return 0;
 }
@@ -138,7 +99,7 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
-	u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL);
+	u16 dac = snd_soc_read(codec, WM8728_DACCTL);
 
 	dac &= ~0x18;
 
@@ -155,7 +116,7 @@
 		return -EINVAL;
 	}
 
-	wm8728_write(codec, WM8728_DACCTL, dac);
+	snd_soc_write(codec, WM8728_DACCTL, dac);
 
 	return 0;
 }
@@ -164,7 +125,7 @@
 		unsigned int fmt)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 iface = wm8728_read_reg_cache(codec, WM8728_IFCTL);
+	u16 iface = snd_soc_read(codec, WM8728_IFCTL);
 
 	/* Currently only I2S is supported by the driver, though the
 	 * hardware is more flexible.
@@ -204,7 +165,7 @@
 		return -EINVAL;
 	}
 
-	wm8728_write(codec, WM8728_IFCTL, iface);
+	snd_soc_write(codec, WM8728_IFCTL, iface);
 	return 0;
 }
 
@@ -220,19 +181,19 @@
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
 			/* Power everything up... */
-			reg = wm8728_read_reg_cache(codec, WM8728_DACCTL);
-			wm8728_write(codec, WM8728_DACCTL, reg & ~0x4);
+			reg = snd_soc_read(codec, WM8728_DACCTL);
+			snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4);
 
 			/* ..then sync in the register cache. */
 			for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++)
-				wm8728_write(codec, i,
-					     wm8728_read_reg_cache(codec, i));
+				snd_soc_write(codec, i,
+					     snd_soc_read(codec, i));
 		}
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		reg = wm8728_read_reg_cache(codec, WM8728_DACCTL);
-		wm8728_write(codec, WM8728_DACCTL, reg | 0x4);
+		reg = snd_soc_read(codec, WM8728_DACCTL);
+		snd_soc_write(codec, WM8728_DACCTL, reg | 0x4);
 		break;
 	}
 	codec->bias_level = level;
@@ -287,15 +248,14 @@
  * initialise the WM8728 driver
  * register the mixer and dsp interfaces with the kernel
  */
-static int wm8728_init(struct snd_soc_device *socdev)
+static int wm8728_init(struct snd_soc_device *socdev,
+		       enum snd_soc_control_type control)
 {
 	struct snd_soc_codec *codec = socdev->card->codec;
 	int ret = 0;
 
 	codec->name = "WM8728";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8728_read_reg_cache;
-	codec->write = wm8728_write;
 	codec->set_bias_level = wm8728_set_bias_level;
 	codec->dai = &wm8728_dai;
 	codec->num_dai = 1;
@@ -307,11 +267,18 @@
 	if (codec->reg_cache == NULL)
 		return -ENOMEM;
 
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",
+		       ret);
+		goto err;
+	}
+
 	/* register pcms */
 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8728: failed to create pcms\n");
-		goto pcm_err;
+		goto err;
 	}
 
 	/* power on device */
@@ -331,7 +298,7 @@
 card_err:
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
-pcm_err:
+err:
 	kfree(codec->reg_cache);
 	return ret;
 }
@@ -357,7 +324,7 @@
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	ret = wm8728_init(socdev);
+	ret = wm8728_init(socdev, SND_SOC_I2C);
 	if (ret < 0)
 		pr_err("failed to initialise WM8728\n");
 
@@ -437,7 +404,7 @@
 
 	codec->control_data = spi;
 
-	ret = wm8728_init(socdev);
+	ret = wm8728_init(socdev, SND_SOC_SPI);
 	if (ret < 0)
 		dev_err(&spi->dev, "failed to initialise WM8728\n");
 
@@ -458,30 +425,6 @@
 	.probe		= wm8728_spi_probe,
 	.remove		= __devexit_p(wm8728_spi_remove),
 };
-
-static int wm8728_spi_write(struct spi_device *spi, const char *data, int len)
-{
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[2];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[0];
-	msg[1] = data[1];
-
-	spi_message_init(&m);
-	memset(&t, 0, (sizeof t));
-
-	t.tx_buf = &msg[0];
-	t.len = len;
-
-	spi_message_add_tail(&t, &m);
-	spi_sync(spi, &m);
-
-	return len;
-}
 #endif /* CONFIG_SPI_MASTER */
 
 static int wm8728_probe(struct platform_device *pdev)
@@ -506,13 +449,11 @@
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		codec->hw_write = (hw_write_t)i2c_master_send;
 		ret = wm8728_add_i2c_device(pdev, setup);
 	}
 #endif
 #if defined(CONFIG_SPI_MASTER)
 	if (setup->spi) {
-		codec->hw_write = (hw_write_t)wm8728_spi_write;
 		ret = spi_register_driver(&wm8728_spi_driver);
 		if (ret != 0)
 			printk(KERN_ERR "can't add spi driver");
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 1560028..d3fd4f2 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -40,9 +40,6 @@
 	unsigned int sysclk;
 };
 
-#ifdef CONFIG_SPI_MASTER
-static int wm8731_spi_write(struct spi_device *spi, const char *data, int len);
-#endif
 
 /*
  * wm8731 register cache
@@ -51,60 +48,12 @@
  * There is no point in caching the reset register
  */
 static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
-    0x0097, 0x0097, 0x0079, 0x0079,
-    0x000a, 0x0008, 0x009f, 0x000a,
-    0x0000, 0x0000
+	0x0097, 0x0097, 0x0079, 0x0079,
+	0x000a, 0x0008, 0x009f, 0x000a,
+	0x0000, 0x0000
 };
 
-/*
- * read wm8731 register cache
- */
-static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg == WM8731_RESET)
-		return 0;
-	if (reg >= WM8731_CACHEREGNUM)
-		return -1;
-	return cache[reg];
-}
-
-/*
- * write wm8731 register cache
- */
-static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec,
-	u16 reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg >= WM8731_CACHEREGNUM)
-		return;
-	cache[reg] = value;
-}
-
-/*
- * write to the WM8731 register space
- */
-static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	u8 data[2];
-
-	/* data is
-	 *   D15..D9 WM8731 register offset
-	 *   D8...D0 register data
-	 */
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	wm8731_write_reg_cache(codec, reg, value);
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
-}
-
-#define wm8731_reset(c)	wm8731_write(c, WM8731_RESET, 0)
+#define wm8731_reset(c)	snd_soc_write(c, WM8731_RESET, 0)
 
 static const char *wm8731_input_select[] = {"Line In", "Mic"};
 static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
@@ -267,12 +216,12 @@
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
 	struct wm8731_priv *wm8731 = codec->private_data;
-	u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3;
+	u16 iface = snd_soc_read(codec, WM8731_IFACE) & 0xfff3;
 	int i = get_coeff(wm8731->sysclk, params_rate(params));
 	u16 srate = (coeff_div[i].sr << 2) |
 		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
 
-	wm8731_write(codec, WM8731_SRATE, srate);
+	snd_soc_write(codec, WM8731_SRATE, srate);
 
 	/* bit size */
 	switch (params_format(params)) {
@@ -286,7 +235,7 @@
 		break;
 	}
 
-	wm8731_write(codec, WM8731_IFACE, iface);
+	snd_soc_write(codec, WM8731_IFACE, iface);
 	return 0;
 }
 
@@ -298,7 +247,7 @@
 	struct snd_soc_codec *codec = socdev->card->codec;
 
 	/* set active */
-	wm8731_write(codec, WM8731_ACTIVE, 0x0001);
+	snd_soc_write(codec, WM8731_ACTIVE, 0x0001);
 
 	return 0;
 }
@@ -313,19 +262,19 @@
 	/* deactivate */
 	if (!codec->active) {
 		udelay(50);
-		wm8731_write(codec, WM8731_ACTIVE, 0x0);
+		snd_soc_write(codec, WM8731_ACTIVE, 0x0);
 	}
 }
 
 static int wm8731_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7;
+	u16 mute_reg = snd_soc_read(codec, WM8731_APDIGI) & 0xfff7;
 
 	if (mute)
-		wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8);
+		snd_soc_write(codec, WM8731_APDIGI, mute_reg | 0x8);
 	else
-		wm8731_write(codec, WM8731_APDIGI, mute_reg);
+		snd_soc_write(codec, WM8731_APDIGI, mute_reg);
 	return 0;
 }
 
@@ -403,7 +352,7 @@
 	}
 
 	/* set iface */
-	wm8731_write(codec, WM8731_IFACE, iface);
+	snd_soc_write(codec, WM8731_IFACE, iface);
 	return 0;
 }
 
@@ -419,12 +368,12 @@
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* Clear PWROFF, gate CLKOUT, everything else as-is */
-		reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;
-		wm8731_write(codec, WM8731_PWR, reg | 0x0040);
+		reg = snd_soc_read(codec, WM8731_PWR) & 0xff7f;
+		snd_soc_write(codec, WM8731_PWR, reg | 0x0040);
 		break;
 	case SND_SOC_BIAS_OFF:
-		wm8731_write(codec, WM8731_ACTIVE, 0x0);
-		wm8731_write(codec, WM8731_PWR, 0xffff);
+		snd_soc_write(codec, WM8731_ACTIVE, 0x0);
+		snd_soc_write(codec, WM8731_PWR, 0xffff);
 		break;
 	}
 	codec->bias_level = level;
@@ -474,7 +423,7 @@
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 	struct snd_soc_codec *codec = socdev->card->codec;
 
-	wm8731_write(codec, WM8731_ACTIVE, 0x0);
+	snd_soc_write(codec, WM8731_ACTIVE, 0x0);
 	wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
 	return 0;
 }
@@ -560,11 +509,11 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
 
-static int wm8731_register(struct wm8731_priv *wm8731)
+static int wm8731_register(struct wm8731_priv *wm8731,
+			   enum snd_soc_control_type control)
 {
 	int ret;
 	struct snd_soc_codec *codec = &wm8731->codec;
-	u16 reg;
 
 	if (wm8731_codec) {
 		dev_err(codec->dev, "Another WM8731 is registered\n");
@@ -579,8 +528,6 @@
 	codec->private_data = wm8731;
 	codec->name = "WM8731";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8731_read_reg_cache;
-	codec->write = wm8731_write;
 	codec->bias_level = SND_SOC_BIAS_OFF;
 	codec->set_bias_level = wm8731_set_bias_level;
 	codec->dai = &wm8731_dai;
@@ -590,6 +537,12 @@
 
 	memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg));
 
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
 	ret = wm8731_reset(codec);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
@@ -601,18 +554,13 @@
 	wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	/* Latch the update bits */
-	reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
-	wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100);
-	reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);
-	wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100);
-	reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);
-	wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100);
-	reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);
-	wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100);
+	snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0);
+	snd_soc_update_bits(codec, WM8731_ROUT1V, 0x100, 0);
+	snd_soc_update_bits(codec, WM8731_LINVOL, 0x100, 0);
+	snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0);
 
 	/* Disable bypass path by default */
-	reg = wm8731_read_reg_cache(codec, WM8731_APANA);
-	wm8731_write(codec, WM8731_APANA, reg & ~0x4);
+	snd_soc_update_bits(codec, WM8731_APANA, 0x4, 0);
 
 	wm8731_codec = codec;
 
@@ -648,30 +596,6 @@
 }
 
 #if defined(CONFIG_SPI_MASTER)
-static int wm8731_spi_write(struct spi_device *spi, const char *data, int len)
-{
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[2];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[0];
-	msg[1] = data[1];
-
-	spi_message_init(&m);
-	memset(&t, 0, (sizeof t));
-
-	t.tx_buf = &msg[0];
-	t.len = len;
-
-	spi_message_add_tail(&t, &m);
-	spi_sync(spi, &m);
-
-	return len;
-}
-
 static int __devinit wm8731_spi_probe(struct spi_device *spi)
 {
 	struct snd_soc_codec *codec;
@@ -683,12 +607,11 @@
 
 	codec = &wm8731->codec;
 	codec->control_data = spi;
-	codec->hw_write = (hw_write_t)wm8731_spi_write;
 	codec->dev = &spi->dev;
 
 	dev_set_drvdata(&spi->dev, wm8731);
 
-	return wm8731_register(wm8731);
+	return wm8731_register(wm8731, SND_SOC_SPI);
 }
 
 static int __devexit wm8731_spi_remove(struct spi_device *spi)
@@ -740,14 +663,13 @@
 		return -ENOMEM;
 
 	codec = &wm8731->codec;
-	codec->hw_write = (hw_write_t)i2c_master_send;
 
 	i2c_set_clientdata(i2c, wm8731);
 	codec->control_data = i2c;
 
 	codec->dev = &i2c->dev;
 
-	return wm8731_register(wm8731);
+	return wm8731_register(wm8731, SND_SOC_I2C);
 }
 
 static __devexit int wm8731_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index b64509b..4ba1e7e 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -55,50 +55,7 @@
 	0x0079, 0x0079, 0x0079,          /* 40 */
 };
 
-/*
- * read wm8750 register cache
- */
-static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg > WM8750_CACHE_REGNUM)
-		return -1;
-	return cache[reg];
-}
-
-/*
- * write wm8750 register cache
- */
-static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg > WM8750_CACHE_REGNUM)
-		return;
-	cache[reg] = value;
-}
-
-static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	u8 data[2];
-
-	/* data is
-	 *   D15..D9 WM8753 register offset
-	 *   D8...D0 register data
-	 */
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	wm8750_write_reg_cache(codec, reg, value);
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
-}
-
-#define wm8750_reset(c)	wm8750_write(c, WM8750_RESET, 0)
+#define wm8750_reset(c)	snd_soc_write(c, WM8750_RESET, 0)
 
 /*
  * WM8750 Controls
@@ -594,7 +551,7 @@
 		return -EINVAL;
 	}
 
-	wm8750_write(codec, WM8750_IFACE, iface);
+	snd_soc_write(codec, WM8750_IFACE, iface);
 	return 0;
 }
 
@@ -606,8 +563,8 @@
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
 	struct wm8750_priv *wm8750 = codec->private_data;
-	u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3;
-	u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0;
+	u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3;
+	u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0;
 	int coeff = get_coeff(wm8750->sysclk, params_rate(params));
 
 	/* bit size */
@@ -626,9 +583,9 @@
 	}
 
 	/* set iface & srate */
-	wm8750_write(codec, WM8750_IFACE, iface);
+	snd_soc_write(codec, WM8750_IFACE, iface);
 	if (coeff >= 0)
-		wm8750_write(codec, WM8750_SRATE, srate |
+		snd_soc_write(codec, WM8750_SRATE, srate |
 			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
 
 	return 0;
@@ -637,35 +594,35 @@
 static int wm8750_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7;
+	u16 mute_reg = snd_soc_read(codec, WM8750_ADCDAC) & 0xfff7;
 
 	if (mute)
-		wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8);
+		snd_soc_write(codec, WM8750_ADCDAC, mute_reg | 0x8);
 	else
-		wm8750_write(codec, WM8750_ADCDAC, mute_reg);
+		snd_soc_write(codec, WM8750_ADCDAC, mute_reg);
 	return 0;
 }
 
 static int wm8750_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
-	u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e;
+	u16 pwr_reg = snd_soc_read(codec, WM8750_PWR1) & 0xfe3e;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* set vmid to 50k and unmute dac */
-		wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0);
+		snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x00c0);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		/* set vmid to 5k for quick power up */
-		wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
+		snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* mute dac and set vmid to 500k, enable VREF */
-		wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141);
+		snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x0141);
 		break;
 	case SND_SOC_BIAS_OFF:
-		wm8750_write(codec, WM8750_PWR1, 0x0001);
+		snd_soc_write(codec, WM8750_PWR1, 0x0001);
 		break;
 	}
 	codec->bias_level = level;
@@ -754,15 +711,14 @@
  * initialise the WM8750 driver
  * register the mixer and dsp interfaces with the kernel
  */
-static int wm8750_init(struct snd_soc_device *socdev)
+static int wm8750_init(struct snd_soc_device *socdev,
+		       enum snd_soc_control_type control)
 {
 	struct snd_soc_codec *codec = socdev->card->codec;
 	int reg, ret = 0;
 
 	codec->name = "WM8750";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8750_read_reg_cache;
-	codec->write = wm8750_write;
 	codec->set_bias_level = wm8750_set_bias_level;
 	codec->dai = &wm8750_dai;
 	codec->num_dai = 1;
@@ -771,13 +727,23 @@
 	if (codec->reg_cache == NULL)
 		return -ENOMEM;
 
-	wm8750_reset(codec);
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
+	ret = wm8750_reset(codec);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8750: failed to reset: %d\n", ret);
+		goto err;
+	}
 
 	/* register pcms */
 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8750: failed to create pcms\n");
-		goto pcm_err;
+		goto err;
 	}
 
 	/* charge output caps */
@@ -786,22 +752,22 @@
 	schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000));
 
 	/* set the update bits */
-	reg = wm8750_read_reg_cache(codec, WM8750_LDAC);
-	wm8750_write(codec, WM8750_LDAC, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_RDAC);
-	wm8750_write(codec, WM8750_RDAC, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V);
-	wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V);
-	wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V);
-	wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V);
-	wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_LINVOL);
-	wm8750_write(codec, WM8750_LINVOL, reg | 0x0100);
-	reg = wm8750_read_reg_cache(codec, WM8750_RINVOL);
-	wm8750_write(codec, WM8750_RINVOL, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8750_LDAC);
+	snd_soc_write(codec, WM8750_LDAC, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8750_RDAC);
+	snd_soc_write(codec, WM8750_RDAC, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8750_LOUT1V);
+	snd_soc_write(codec, WM8750_LOUT1V, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8750_ROUT1V);
+	snd_soc_write(codec, WM8750_ROUT1V, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8750_LOUT2V);
+	snd_soc_write(codec, WM8750_LOUT2V, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8750_ROUT2V);
+	snd_soc_write(codec, WM8750_ROUT2V, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8750_LINVOL);
+	snd_soc_write(codec, WM8750_LINVOL, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8750_RINVOL);
+	snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100);
 
 	snd_soc_add_controls(codec, wm8750_snd_controls,
 				ARRAY_SIZE(wm8750_snd_controls));
@@ -816,7 +782,7 @@
 card_err:
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
-pcm_err:
+err:
 	kfree(codec->reg_cache);
 	return ret;
 }
@@ -844,7 +810,7 @@
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	ret = wm8750_init(socdev);
+	ret = wm8750_init(socdev, SND_SOC_I2C);
 	if (ret < 0)
 		pr_err("failed to initialise WM8750\n");
 
@@ -924,7 +890,7 @@
 
 	codec->control_data = spi;
 
-	ret = wm8750_init(socdev);
+	ret = wm8750_init(socdev, SND_SOC_SPI);
 	if (ret < 0)
 		dev_err(&spi->dev, "failed to initialise WM8750\n");
 
@@ -945,30 +911,6 @@
 	.probe		= wm8750_spi_probe,
 	.remove		= __devexit_p(wm8750_spi_remove),
 };
-
-static int wm8750_spi_write(struct spi_device *spi, const char *data, int len)
-{
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[2];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[0];
-	msg[1] = data[1];
-
-	spi_message_init(&m);
-	memset(&t, 0, (sizeof t));
-
-	t.tx_buf = &msg[0];
-	t.len = len;
-
-	spi_message_add_tail(&t, &m);
-	spi_sync(spi, &m);
-
-	return len;
-}
 #endif
 
 static int wm8750_probe(struct platform_device *pdev)
@@ -1002,13 +944,11 @@
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		codec->hw_write = (hw_write_t)i2c_master_send;
 		ret = wm8750_add_i2c_device(pdev, setup);
 	}
 #endif
 #if defined(CONFIG_SPI_MASTER)
 	if (setup->spi) {
-		codec->hw_write = (hw_write_t)wm8750_spi_write;
 		ret = spi_register_driver(&wm8750_spi_driver);
 		if (ret != 0)
 			printk(KERN_ERR "can't add spi driver");
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index ee12bf8..a9829aa 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -52,51 +52,9 @@
 	0xa6, 0x01, 0x01
 };
 
-/*
- * read wm8776 register cache
- */
-static inline unsigned int wm8776_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg >= WM8776_CACHEREGNUM)
-		return -1;
-	return cache[reg];
-}
-
-/*
- * write wm8776 register cache
- */
-static inline void wm8776_write_reg_cache(struct snd_soc_codec *codec,
-					  u16 reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg >= WM8776_CACHEREGNUM)
-		return;
-	cache[reg] = value;
-}
-
-/*
- * write to the WM8776 register space
- */
-static int wm8776_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	u8 data[2];
-
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	wm8776_write_reg_cache(codec, reg, value);
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
-}
-
 static int wm8776_reset(struct snd_soc_codec *codec)
 {
-	return wm8776_write(codec, WM8776_RESET, 0);
+	return snd_soc_write(codec, WM8776_RESET, 0);
 }
 
 static const DECLARE_TLV_DB_SCALE(hp_tlv, -12100, 100, 1);
@@ -523,7 +481,8 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776);
 
-static int wm8776_register(struct wm8776_priv *wm8776)
+static int wm8776_register(struct wm8776_priv *wm8776,
+			   enum snd_soc_control_type control)
 {
 	int ret, i;
 	struct snd_soc_codec *codec = &wm8776->codec;
@@ -541,8 +500,6 @@
 	codec->private_data = wm8776;
 	codec->name = "WM8776";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8776_read_reg_cache;
-	codec->write = wm8776_write;
 	codec->bias_level = SND_SOC_BIAS_OFF;
 	codec->set_bias_level = wm8776_set_bias_level;
 	codec->dai = wm8776_dai;
@@ -552,6 +509,12 @@
 
 	memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg));
 
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++)
 		wm8776_dai[i].dev = codec->dev;
 
@@ -641,7 +604,7 @@
 
 	dev_set_drvdata(&spi->dev, wm8776);
 
-	return wm8776_register(wm8776);
+	return wm8776_register(wm8776, SND_SOC_SPI);
 }
 
 static int __devexit wm8776_spi_remove(struct spi_device *spi)
@@ -700,7 +663,7 @@
 
 	codec->dev = &i2c->dev;
 
-	return wm8776_register(wm8776);
+	return wm8776_register(wm8776, SND_SOC_I2C);
 }
 
 static __devexit int wm8776_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index ac30899..5e9c855 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -183,111 +183,20 @@
 	/* Remaining registers all zero */
 };
 
-/*
- * read wm8900 register cache
- */
-static inline unsigned int wm8900_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-
-	BUG_ON(reg >= WM8900_MAXREG);
-
-	if (reg == WM8900_REG_ID)
-		return 0;
-
-	return cache[reg];
-}
-
-/*
- * write wm8900 register cache
- */
-static inline void wm8900_write_reg_cache(struct snd_soc_codec *codec,
-	u16 reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-
-	BUG_ON(reg >= WM8900_MAXREG);
-
-	cache[reg] = value;
-}
-
-/*
- * write to the WM8900 register space
- */
-static int wm8900_write(struct snd_soc_codec *codec, unsigned int reg,
-			unsigned int value)
-{
-	u8 data[3];
-
-	if (value == wm8900_read_reg_cache(codec, reg))
-		return 0;
-
-	/* data is
-	 *   D15..D9 WM8900 register offset
-	 *   D8...D0 register data
-	 */
-	data[0] = reg;
-	data[1] = value >> 8;
-	data[2] = value & 0x00ff;
-
-	wm8900_write_reg_cache(codec, reg, value);
-	if (codec->hw_write(codec->control_data, data, 3) == 3)
-		return 0;
-	else
-		return -EIO;
-}
-
-/*
- * Read from the wm8900.
- */
-static unsigned int wm8900_chip_read(struct snd_soc_codec *codec, u8 reg)
-{
-	struct i2c_msg xfer[2];
-	u16 data;
-	int ret;
-	struct i2c_client *client = codec->control_data;
-
-	BUG_ON(reg != WM8900_REG_ID && reg != WM8900_REG_POWER1);
-
-	/* Write register */
-	xfer[0].addr = client->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 1;
-	xfer[0].buf = &reg;
-
-	/* Read data */
-	xfer[1].addr = client->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 2;
-	xfer[1].buf = (u8 *)&data;
-
-	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret != 2) {
-		printk(KERN_CRIT "i2c_transfer returned %d\n", ret);
-		return 0;
-	}
-
-	return (data >> 8) | ((data & 0xff) << 8);
-}
-
-/*
- * Read from the WM8900 register space.  Most registers can't be read
- * and are therefore supplied from cache.
- */
-static unsigned int wm8900_read(struct snd_soc_codec *codec, unsigned int reg)
+static int wm8900_volatile_register(unsigned int reg)
 {
 	switch (reg) {
 	case WM8900_REG_ID:
-		return wm8900_chip_read(codec, reg);
+	case WM8900_REG_POWER1:
+		return 1;
 	default:
-		return wm8900_read_reg_cache(codec, reg);
+		return 0;
 	}
 }
 
 static void wm8900_reset(struct snd_soc_codec *codec)
 {
-	wm8900_write(codec, WM8900_REG_RESET, 0);
+	snd_soc_write(codec, WM8900_REG_RESET, 0);
 
 	memcpy(codec->reg_cache, wm8900_reg_defaults,
 	       sizeof(codec->reg_cache));
@@ -297,14 +206,14 @@
 			   struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	u16 hpctl1 = wm8900_read(codec, WM8900_REG_HPCTL1);
+	u16 hpctl1 = snd_soc_read(codec, WM8900_REG_HPCTL1);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		/* Clamp headphone outputs */
 		hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP |
 			WM8900_REG_HPCTL1_HP_CLAMP_OP;
-		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
 		break;
 
 	case SND_SOC_DAPM_POST_PMU:
@@ -313,41 +222,41 @@
 		hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT |
 			WM8900_REG_HPCTL1_HP_SHORT2 |
 			WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
-		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
 
 		msleep(400);
 
 		/* Enable the output stage */
 		hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP;
 		hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
-		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
 
 		/* Remove the shorts */
 		hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2;
-		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
 		hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT;
-		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
 		/* Short the output */
 		hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT;
-		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
 
 		/* Disable the output stage */
 		hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
-		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
 
 		/* Clamp the outputs and power down input */
 		hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP |
 			WM8900_REG_HPCTL1_HP_CLAMP_OP;
 		hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
-		wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
 		/* Disable everything */
-		wm8900_write(codec, WM8900_REG_HPCTL1, 0);
+		snd_soc_write(codec, WM8900_REG_HPCTL1, 0);
 		break;
 
 	default:
@@ -723,7 +632,7 @@
 	struct snd_soc_codec *codec = socdev->card->codec;
 	u16 reg;
 
-	reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60;
+	reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60;
 
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
@@ -741,17 +650,17 @@
 		return -EINVAL;
 	}
 
-	wm8900_write(codec, WM8900_REG_AUDIO1, reg);
+	snd_soc_write(codec, WM8900_REG_AUDIO1, reg);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		reg = wm8900_read(codec, WM8900_REG_DACCTRL);
+		reg = snd_soc_read(codec, WM8900_REG_DACCTRL);
 
 		if (params_rate(params) <= 24000)
 			reg |= WM8900_REG_DACCTRL_DAC_SB_FILT;
 		else
 			reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT;
 
-		wm8900_write(codec, WM8900_REG_DACCTRL, reg);
+		snd_soc_write(codec, WM8900_REG_DACCTRL, reg);
 	}
 
 	return 0;
@@ -845,18 +754,18 @@
 		return 0;
 
 	/* The digital side should be disabled during any change. */
-	reg = wm8900_read(codec, WM8900_REG_POWER1);
-	wm8900_write(codec, WM8900_REG_POWER1,
+	reg = snd_soc_read(codec, WM8900_REG_POWER1);
+	snd_soc_write(codec, WM8900_REG_POWER1,
 		     reg & (~WM8900_REG_POWER1_FLL_ENA));
 
 	/* Disable the FLL? */
 	if (!freq_in || !freq_out) {
-		reg = wm8900_read(codec, WM8900_REG_CLOCKING1);
-		wm8900_write(codec, WM8900_REG_CLOCKING1,
+		reg = snd_soc_read(codec, WM8900_REG_CLOCKING1);
+		snd_soc_write(codec, WM8900_REG_CLOCKING1,
 			     reg & (~WM8900_REG_CLOCKING1_MCLK_SRC));
 
-		reg = wm8900_read(codec, WM8900_REG_FLLCTL1);
-		wm8900_write(codec, WM8900_REG_FLLCTL1,
+		reg = snd_soc_read(codec, WM8900_REG_FLLCTL1);
+		snd_soc_write(codec, WM8900_REG_FLLCTL1,
 			     reg & (~WM8900_REG_FLLCTL1_OSC_ENA));
 
 		wm8900->fll_in = freq_in;
@@ -873,33 +782,33 @@
 
 	/* The osclilator *MUST* be enabled before we enable the
 	 * digital circuit. */
-	wm8900_write(codec, WM8900_REG_FLLCTL1,
+	snd_soc_write(codec, WM8900_REG_FLLCTL1,
 		     fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA);
 
-	wm8900_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5);
-	wm8900_write(codec, WM8900_REG_FLLCTL5,
+	snd_soc_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5);
+	snd_soc_write(codec, WM8900_REG_FLLCTL5,
 		     (fll_div.fllclk_div << 6) | (fll_div.n & 0x1f));
 
 	if (fll_div.k) {
-		wm8900_write(codec, WM8900_REG_FLLCTL2,
+		snd_soc_write(codec, WM8900_REG_FLLCTL2,
 			     (fll_div.k >> 8) | 0x100);
-		wm8900_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff);
+		snd_soc_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff);
 	} else
-		wm8900_write(codec, WM8900_REG_FLLCTL2, 0);
+		snd_soc_write(codec, WM8900_REG_FLLCTL2, 0);
 
 	if (fll_div.fll_slow_lock_ref)
-		wm8900_write(codec, WM8900_REG_FLLCTL6,
+		snd_soc_write(codec, WM8900_REG_FLLCTL6,
 			     WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF);
 	else
-		wm8900_write(codec, WM8900_REG_FLLCTL6, 0);
+		snd_soc_write(codec, WM8900_REG_FLLCTL6, 0);
 
-	reg = wm8900_read(codec, WM8900_REG_POWER1);
-	wm8900_write(codec, WM8900_REG_POWER1,
+	reg = snd_soc_read(codec, WM8900_REG_POWER1);
+	snd_soc_write(codec, WM8900_REG_POWER1,
 		     reg | WM8900_REG_POWER1_FLL_ENA);
 
 reenable:
-	reg = wm8900_read(codec, WM8900_REG_CLOCKING1);
-	wm8900_write(codec, WM8900_REG_CLOCKING1,
+	reg = snd_soc_read(codec, WM8900_REG_CLOCKING1);
+	snd_soc_write(codec, WM8900_REG_CLOCKING1,
 		     reg | WM8900_REG_CLOCKING1_MCLK_SRC);
 
 	return 0;
@@ -919,38 +828,38 @@
 
 	switch (div_id) {
 	case WM8900_BCLK_DIV:
-		reg = wm8900_read(codec, WM8900_REG_CLOCKING1);
-		wm8900_write(codec, WM8900_REG_CLOCKING1,
+		reg = snd_soc_read(codec, WM8900_REG_CLOCKING1);
+		snd_soc_write(codec, WM8900_REG_CLOCKING1,
 			     div | (reg & WM8900_REG_CLOCKING1_BCLK_MASK));
 		break;
 	case WM8900_OPCLK_DIV:
-		reg = wm8900_read(codec, WM8900_REG_CLOCKING1);
-		wm8900_write(codec, WM8900_REG_CLOCKING1,
+		reg = snd_soc_read(codec, WM8900_REG_CLOCKING1);
+		snd_soc_write(codec, WM8900_REG_CLOCKING1,
 			     div | (reg & WM8900_REG_CLOCKING1_OPCLK_MASK));
 		break;
 	case WM8900_DAC_LRCLK:
-		reg = wm8900_read(codec, WM8900_REG_AUDIO4);
-		wm8900_write(codec, WM8900_REG_AUDIO4,
+		reg = snd_soc_read(codec, WM8900_REG_AUDIO4);
+		snd_soc_write(codec, WM8900_REG_AUDIO4,
 			     div | (reg & WM8900_LRC_MASK));
 		break;
 	case WM8900_ADC_LRCLK:
-		reg = wm8900_read(codec, WM8900_REG_AUDIO3);
-		wm8900_write(codec, WM8900_REG_AUDIO3,
+		reg = snd_soc_read(codec, WM8900_REG_AUDIO3);
+		snd_soc_write(codec, WM8900_REG_AUDIO3,
 			     div | (reg & WM8900_LRC_MASK));
 		break;
 	case WM8900_DAC_CLKDIV:
-		reg = wm8900_read(codec, WM8900_REG_CLOCKING2);
-		wm8900_write(codec, WM8900_REG_CLOCKING2,
+		reg = snd_soc_read(codec, WM8900_REG_CLOCKING2);
+		snd_soc_write(codec, WM8900_REG_CLOCKING2,
 			     div | (reg & WM8900_REG_CLOCKING2_DAC_CLKDIV));
 		break;
 	case WM8900_ADC_CLKDIV:
-		reg = wm8900_read(codec, WM8900_REG_CLOCKING2);
-		wm8900_write(codec, WM8900_REG_CLOCKING2,
+		reg = snd_soc_read(codec, WM8900_REG_CLOCKING2);
+		snd_soc_write(codec, WM8900_REG_CLOCKING2,
 			     div | (reg & WM8900_REG_CLOCKING2_ADC_CLKDIV));
 		break;
 	case WM8900_LRCLK_MODE:
-		reg = wm8900_read(codec, WM8900_REG_DACCTRL);
-		wm8900_write(codec, WM8900_REG_DACCTRL,
+		reg = snd_soc_read(codec, WM8900_REG_DACCTRL);
+		snd_soc_write(codec, WM8900_REG_DACCTRL,
 			     div | (reg & WM8900_REG_DACCTRL_AIF_LRCLKRATE));
 		break;
 	default:
@@ -967,10 +876,10 @@
 	struct snd_soc_codec *codec = codec_dai->codec;
 	unsigned int clocking1, aif1, aif3, aif4;
 
-	clocking1 = wm8900_read(codec, WM8900_REG_CLOCKING1);
-	aif1 = wm8900_read(codec, WM8900_REG_AUDIO1);
-	aif3 = wm8900_read(codec, WM8900_REG_AUDIO3);
-	aif4 = wm8900_read(codec, WM8900_REG_AUDIO4);
+	clocking1 = snd_soc_read(codec, WM8900_REG_CLOCKING1);
+	aif1 = snd_soc_read(codec, WM8900_REG_AUDIO1);
+	aif3 = snd_soc_read(codec, WM8900_REG_AUDIO3);
+	aif4 = snd_soc_read(codec, WM8900_REG_AUDIO4);
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1066,10 +975,10 @@
 		return -EINVAL;
 	}
 
-	wm8900_write(codec, WM8900_REG_CLOCKING1, clocking1);
-	wm8900_write(codec, WM8900_REG_AUDIO1, aif1);
-	wm8900_write(codec, WM8900_REG_AUDIO3, aif3);
-	wm8900_write(codec, WM8900_REG_AUDIO4, aif4);
+	snd_soc_write(codec, WM8900_REG_CLOCKING1, clocking1);
+	snd_soc_write(codec, WM8900_REG_AUDIO1, aif1);
+	snd_soc_write(codec, WM8900_REG_AUDIO3, aif3);
+	snd_soc_write(codec, WM8900_REG_AUDIO4, aif4);
 
 	return 0;
 }
@@ -1079,14 +988,14 @@
 	struct snd_soc_codec *codec = codec_dai->codec;
 	u16 reg;
 
-	reg = wm8900_read(codec, WM8900_REG_DACCTRL);
+	reg = snd_soc_read(codec, WM8900_REG_DACCTRL);
 
 	if (mute)
 		reg |= WM8900_REG_DACCTRL_MUTE;
 	else
 		reg &= ~WM8900_REG_DACCTRL_MUTE;
 
-	wm8900_write(codec, WM8900_REG_DACCTRL, reg);
+	snd_soc_write(codec, WM8900_REG_DACCTRL, reg);
 
 	return 0;
 }
@@ -1135,11 +1044,11 @@
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* Enable thermal shutdown */
-		reg = wm8900_read(codec, WM8900_REG_GPIO);
-		wm8900_write(codec, WM8900_REG_GPIO,
+		reg = snd_soc_read(codec, WM8900_REG_GPIO);
+		snd_soc_write(codec, WM8900_REG_GPIO,
 			     reg | WM8900_REG_GPIO_TEMP_ENA);
-		reg = wm8900_read(codec, WM8900_REG_ADDCTL);
-		wm8900_write(codec, WM8900_REG_ADDCTL,
+		reg = snd_soc_read(codec, WM8900_REG_ADDCTL);
+		snd_soc_write(codec, WM8900_REG_ADDCTL,
 			     reg | WM8900_REG_ADDCTL_TEMP_SD);
 		break;
 
@@ -1150,69 +1059,69 @@
 		/* Charge capacitors if initial power up */
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
 			/* STARTUP_BIAS_ENA on */
-			wm8900_write(codec, WM8900_REG_POWER1,
+			snd_soc_write(codec, WM8900_REG_POWER1,
 				     WM8900_REG_POWER1_STARTUP_BIAS_ENA);
 
 			/* Startup bias mode */
-			wm8900_write(codec, WM8900_REG_ADDCTL,
+			snd_soc_write(codec, WM8900_REG_ADDCTL,
 				     WM8900_REG_ADDCTL_BIAS_SRC |
 				     WM8900_REG_ADDCTL_VMID_SOFTST);
 
 			/* VMID 2x50k */
-			wm8900_write(codec, WM8900_REG_POWER1,
+			snd_soc_write(codec, WM8900_REG_POWER1,
 				     WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1);
 
 			/* Allow capacitors to charge */
 			schedule_timeout_interruptible(msecs_to_jiffies(400));
 
 			/* Enable bias */
-			wm8900_write(codec, WM8900_REG_POWER1,
+			snd_soc_write(codec, WM8900_REG_POWER1,
 				     WM8900_REG_POWER1_STARTUP_BIAS_ENA |
 				     WM8900_REG_POWER1_BIAS_ENA | 0x1);
 
-			wm8900_write(codec, WM8900_REG_ADDCTL, 0);
+			snd_soc_write(codec, WM8900_REG_ADDCTL, 0);
 
-			wm8900_write(codec, WM8900_REG_POWER1,
+			snd_soc_write(codec, WM8900_REG_POWER1,
 				     WM8900_REG_POWER1_BIAS_ENA | 0x1);
 		}
 
-		reg = wm8900_read(codec, WM8900_REG_POWER1);
-		wm8900_write(codec, WM8900_REG_POWER1,
+		reg = snd_soc_read(codec, WM8900_REG_POWER1);
+		snd_soc_write(codec, WM8900_REG_POWER1,
 			     (reg & WM8900_REG_POWER1_FLL_ENA) |
 			     WM8900_REG_POWER1_BIAS_ENA | 0x1);
-		wm8900_write(codec, WM8900_REG_POWER2,
+		snd_soc_write(codec, WM8900_REG_POWER2,
 			     WM8900_REG_POWER2_SYSCLK_ENA);
-		wm8900_write(codec, WM8900_REG_POWER3, 0);
+		snd_soc_write(codec, WM8900_REG_POWER3, 0);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Startup bias enable */
-		reg = wm8900_read(codec, WM8900_REG_POWER1);
-		wm8900_write(codec, WM8900_REG_POWER1,
+		reg = snd_soc_read(codec, WM8900_REG_POWER1);
+		snd_soc_write(codec, WM8900_REG_POWER1,
 			     reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA);
-		wm8900_write(codec, WM8900_REG_ADDCTL,
+		snd_soc_write(codec, WM8900_REG_ADDCTL,
 			     WM8900_REG_ADDCTL_BIAS_SRC |
 			     WM8900_REG_ADDCTL_VMID_SOFTST);
 
 		/* Discharge caps */
-		wm8900_write(codec, WM8900_REG_POWER1,
+		snd_soc_write(codec, WM8900_REG_POWER1,
 			     WM8900_REG_POWER1_STARTUP_BIAS_ENA);
 		schedule_timeout_interruptible(msecs_to_jiffies(500));
 
 		/* Remove clamp */
-		wm8900_write(codec, WM8900_REG_HPCTL1, 0);
+		snd_soc_write(codec, WM8900_REG_HPCTL1, 0);
 
 		/* Power down */
-		wm8900_write(codec, WM8900_REG_ADDCTL, 0);
-		wm8900_write(codec, WM8900_REG_POWER1, 0);
-		wm8900_write(codec, WM8900_REG_POWER2, 0);
-		wm8900_write(codec, WM8900_REG_POWER3, 0);
+		snd_soc_write(codec, WM8900_REG_ADDCTL, 0);
+		snd_soc_write(codec, WM8900_REG_POWER1, 0);
+		snd_soc_write(codec, WM8900_REG_POWER2, 0);
+		snd_soc_write(codec, WM8900_REG_POWER3, 0);
 
 		/* Need to let things settle before stopping the clock
 		 * to ensure that restart works, see "Stopping the
 		 * master clock" in the datasheet. */
 		schedule_timeout_interruptible(msecs_to_jiffies(1));
-		wm8900_write(codec, WM8900_REG_POWER2,
+		snd_soc_write(codec, WM8900_REG_POWER2,
 			     WM8900_REG_POWER2_SYSCLK_ENA);
 		break;
 	}
@@ -1275,7 +1184,7 @@
 
 	if (cache) {
 		for (i = 0; i < WM8900_MAXREG; i++)
-			wm8900_write(codec, i, cache[i]);
+			snd_soc_write(codec, i, cache[i]);
 		kfree(cache);
 	} else
 		dev_err(&pdev->dev, "Unable to allocate register cache\n");
@@ -1308,16 +1217,20 @@
 
 	codec->name = "WM8900";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8900_read;
-	codec->write = wm8900_write;
 	codec->dai = &wm8900_dai;
 	codec->num_dai = 1;
-	codec->hw_write = (hw_write_t)i2c_master_send;
 	codec->control_data = i2c;
 	codec->set_bias_level = wm8900_set_bias_level;
+	codec->volatile_register = wm8900_volatile_register;
 	codec->dev = &i2c->dev;
 
-	reg = wm8900_read(codec, WM8900_REG_ID);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
+	reg = snd_soc_read(codec, WM8900_REG_ID);
 	if (reg != 0x8900) {
 		dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg);
 		ret = -ENODEV;
@@ -1325,7 +1238,7 @@
 	}
 
 	/* Read back from the chip */
-	reg = wm8900_chip_read(codec, WM8900_REG_POWER1);
+	reg = snd_soc_read(codec, WM8900_REG_POWER1);
 	reg = (reg >> 12) & 0xf;
 	dev_info(&i2c->dev, "WM8900 revision %d\n", reg);
 
@@ -1335,29 +1248,29 @@
 	wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	/* Latch the volume update bits */
-	wm8900_write(codec, WM8900_REG_LINVOL,
-		     wm8900_read(codec, WM8900_REG_LINVOL) | 0x100);
-	wm8900_write(codec, WM8900_REG_RINVOL,
-		     wm8900_read(codec, WM8900_REG_RINVOL) | 0x100);
-	wm8900_write(codec, WM8900_REG_LOUT1CTL,
-		     wm8900_read(codec, WM8900_REG_LOUT1CTL) | 0x100);
-	wm8900_write(codec, WM8900_REG_ROUT1CTL,
-		     wm8900_read(codec, WM8900_REG_ROUT1CTL) | 0x100);
-	wm8900_write(codec, WM8900_REG_LOUT2CTL,
-		     wm8900_read(codec, WM8900_REG_LOUT2CTL) | 0x100);
-	wm8900_write(codec, WM8900_REG_ROUT2CTL,
-		     wm8900_read(codec, WM8900_REG_ROUT2CTL) | 0x100);
-	wm8900_write(codec, WM8900_REG_LDAC_DV,
-		     wm8900_read(codec, WM8900_REG_LDAC_DV) | 0x100);
-	wm8900_write(codec, WM8900_REG_RDAC_DV,
-		     wm8900_read(codec, WM8900_REG_RDAC_DV) | 0x100);
-	wm8900_write(codec, WM8900_REG_LADC_DV,
-		     wm8900_read(codec, WM8900_REG_LADC_DV) | 0x100);
-	wm8900_write(codec, WM8900_REG_RADC_DV,
-		     wm8900_read(codec, WM8900_REG_RADC_DV) | 0x100);
+	snd_soc_write(codec, WM8900_REG_LINVOL,
+		      snd_soc_read(codec, WM8900_REG_LINVOL) | 0x100);
+	snd_soc_write(codec, WM8900_REG_RINVOL,
+		      snd_soc_read(codec, WM8900_REG_RINVOL) | 0x100);
+	snd_soc_write(codec, WM8900_REG_LOUT1CTL,
+		      snd_soc_read(codec, WM8900_REG_LOUT1CTL) | 0x100);
+	snd_soc_write(codec, WM8900_REG_ROUT1CTL,
+		      snd_soc_read(codec, WM8900_REG_ROUT1CTL) | 0x100);
+	snd_soc_write(codec, WM8900_REG_LOUT2CTL,
+		      snd_soc_read(codec, WM8900_REG_LOUT2CTL) | 0x100);
+	snd_soc_write(codec, WM8900_REG_ROUT2CTL,
+		      snd_soc_read(codec, WM8900_REG_ROUT2CTL) | 0x100);
+	snd_soc_write(codec, WM8900_REG_LDAC_DV,
+		      snd_soc_read(codec, WM8900_REG_LDAC_DV) | 0x100);
+	snd_soc_write(codec, WM8900_REG_RDAC_DV,
+		      snd_soc_read(codec, WM8900_REG_RDAC_DV) | 0x100);
+	snd_soc_write(codec, WM8900_REG_LADC_DV,
+		      snd_soc_read(codec, WM8900_REG_LADC_DV) | 0x100);
+	snd_soc_write(codec, WM8900_REG_RADC_DV,
+		      snd_soc_read(codec, WM8900_REG_RADC_DV) | 0x100);
 
 	/* Set the DAC and mixer output bias */
-	wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
+	snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
 
 	wm8900_dai.dev = &i2c->dev;
 
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index c9baeae..fe1307b 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -225,94 +225,18 @@
 	struct snd_pcm_substream *slave_substream;
 };
 
-
-static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec,
-						 unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-
-	BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults));
-
-	return cache[reg];
-}
-
-static unsigned int wm8903_hw_read(struct snd_soc_codec *codec, u8 reg)
-{
-	struct i2c_msg xfer[2];
-	u16 data;
-	int ret;
-	struct i2c_client *client = codec->control_data;
-
-	/* Write register */
-	xfer[0].addr = client->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 1;
-	xfer[0].buf = &reg;
-
-	/* Read data */
-	xfer[1].addr = client->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 2;
-	xfer[1].buf = (u8 *)&data;
-
-	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret != 2) {
-		pr_err("i2c_transfer returned %d\n", ret);
-		return 0;
-	}
-
-	return (data >> 8) | ((data & 0xff) << 8);
-}
-
-static unsigned int wm8903_read(struct snd_soc_codec *codec,
-				unsigned int reg)
+static int wm8903_volatile_register(unsigned int reg)
 {
 	switch (reg) {
 	case WM8903_SW_RESET_AND_ID:
 	case WM8903_REVISION_NUMBER:
 	case WM8903_INTERRUPT_STATUS_1:
 	case WM8903_WRITE_SEQUENCER_4:
-		return wm8903_hw_read(codec, reg);
+		return 1;
 
 	default:
-		return wm8903_read_reg_cache(codec, reg);
-	}
-}
-
-static void wm8903_write_reg_cache(struct snd_soc_codec *codec,
-				   u16 reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-
-	BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults));
-
-	switch (reg) {
-	case WM8903_SW_RESET_AND_ID:
-	case WM8903_REVISION_NUMBER:
-		break;
-
-	default:
-		cache[reg] = value;
-		break;
-	}
-}
-
-static int wm8903_write(struct snd_soc_codec *codec, unsigned int reg,
-			unsigned int value)
-{
-	u8 data[3];
-
-	wm8903_write_reg_cache(codec, reg, value);
-
-	/* Data format is 1 byte of address followed by 2 bytes of data */
-	data[0] = reg;
-	data[1] = (value >> 8) & 0xff;
-	data[2] = value & 0xff;
-
-	if (codec->hw_write(codec->control_data, data, 3) == 2)
 		return 0;
-	else
-		return -EIO;
+	}
 }
 
 static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
@@ -323,13 +247,13 @@
 	BUG_ON(start > 48);
 
 	/* Enable the sequencer */
-	reg[0] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_0);
+	reg[0] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_0);
 	reg[0] |= WM8903_WSEQ_ENA;
-	wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]);
+	snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]);
 
 	dev_dbg(&i2c->dev, "Starting sequence at %d\n", start);
 
-	wm8903_write(codec, WM8903_WRITE_SEQUENCER_3,
+	snd_soc_write(codec, WM8903_WRITE_SEQUENCER_3,
 		     start | WM8903_WSEQ_START);
 
 	/* Wait for it to complete.  If we have the interrupt wired up then
@@ -339,13 +263,13 @@
 	do {
 		msleep(10);
 
-		reg[4] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_4);
+		reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4);
 	} while (reg[4] & WM8903_WSEQ_BUSY);
 
 	dev_dbg(&i2c->dev, "Sequence complete\n");
 
 	/* Disable the sequencer again */
-	wm8903_write(codec, WM8903_WRITE_SEQUENCER_0,
+	snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0,
 		     reg[0] & ~WM8903_WSEQ_ENA);
 
 	return 0;
@@ -357,12 +281,12 @@
 
 	/* There really ought to be something better we can do here :/ */
 	for (i = 0; i < ARRAY_SIZE(wm8903_reg_defaults); i++)
-		cache[i] = wm8903_hw_read(codec, i);
+		cache[i] = codec->hw_read(codec, i);
 }
 
 static void wm8903_reset(struct snd_soc_codec *codec)
 {
-	wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0);
+	snd_soc_write(codec, WM8903_SW_RESET_AND_ID, 0);
 	memcpy(codec->reg_cache, wm8903_reg_defaults,
 	       sizeof(wm8903_reg_defaults));
 }
@@ -423,52 +347,52 @@
 	}
 
 	if (event & SND_SOC_DAPM_PRE_PMU) {
-		val = wm8903_read(codec, reg);
+		val = snd_soc_read(codec, reg);
 
 		/* Short the output */
 		val &= ~(WM8903_OUTPUT_SHORT << shift);
-		wm8903_write(codec, reg, val);
+		snd_soc_write(codec, reg, val);
 	}
 
 	if (event & SND_SOC_DAPM_POST_PMU) {
-		val = wm8903_read(codec, reg);
+		val = snd_soc_read(codec, reg);
 
 		val |= (WM8903_OUTPUT_IN << shift);
-		wm8903_write(codec, reg, val);
+		snd_soc_write(codec, reg, val);
 
 		val |= (WM8903_OUTPUT_INT << shift);
-		wm8903_write(codec, reg, val);
+		snd_soc_write(codec, reg, val);
 
 		/* Turn on the output ENA_OUTP */
 		val |= (WM8903_OUTPUT_OUT << shift);
-		wm8903_write(codec, reg, val);
+		snd_soc_write(codec, reg, val);
 
 		/* Enable the DC servo */
-		dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0);
+		dcs_reg = snd_soc_read(codec, WM8903_DC_SERVO_0);
 		dcs_reg |= dcs_bit;
-		wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg);
+		snd_soc_write(codec, WM8903_DC_SERVO_0, dcs_reg);
 
 		/* Remove the short */
 		val |= (WM8903_OUTPUT_SHORT << shift);
-		wm8903_write(codec, reg, val);
+		snd_soc_write(codec, reg, val);
 	}
 
 	if (event & SND_SOC_DAPM_PRE_PMD) {
-		val = wm8903_read(codec, reg);
+		val = snd_soc_read(codec, reg);
 
 		/* Short the output */
 		val &= ~(WM8903_OUTPUT_SHORT << shift);
-		wm8903_write(codec, reg, val);
+		snd_soc_write(codec, reg, val);
 
 		/* Disable the DC servo */
-		dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0);
+		dcs_reg = snd_soc_read(codec, WM8903_DC_SERVO_0);
 		dcs_reg &= ~dcs_bit;
-		wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg);
+		snd_soc_write(codec, WM8903_DC_SERVO_0, dcs_reg);
 
 		/* Then disable the intermediate and output stages */
 		val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT |
 			  WM8903_OUTPUT_IN) << shift);
-		wm8903_write(codec, reg, val);
+		snd_soc_write(codec, reg, val);
 	}
 
 	return 0;
@@ -492,13 +416,13 @@
 	u16 reg;
 	int ret;
 
-	reg = wm8903_read(codec, WM8903_CLASS_W_0);
+	reg = snd_soc_read(codec, WM8903_CLASS_W_0);
 
 	/* Turn it off if we're about to enable bypass */
 	if (ucontrol->value.integer.value[0]) {
 		if (wm8903->class_w_users == 0) {
 			dev_dbg(&i2c->dev, "Disabling Class W\n");
-			wm8903_write(codec, WM8903_CLASS_W_0, reg &
+			snd_soc_write(codec, WM8903_CLASS_W_0, reg &
 				     ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V));
 		}
 		wm8903->class_w_users++;
@@ -511,7 +435,7 @@
 	if (!ucontrol->value.integer.value[0]) {
 		if (wm8903->class_w_users == 1) {
 			dev_dbg(&i2c->dev, "Enabling Class W\n");
-			wm8903_write(codec, WM8903_CLASS_W_0, reg |
+			snd_soc_write(codec, WM8903_CLASS_W_0, reg |
 				     WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
 		}
 		wm8903->class_w_users--;
@@ -1009,55 +933,55 @@
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
-		reg = wm8903_read(codec, WM8903_VMID_CONTROL_0);
+		reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0);
 		reg &= ~(WM8903_VMID_RES_MASK);
 		reg |= WM8903_VMID_RES_50K;
-		wm8903_write(codec, WM8903_VMID_CONTROL_0, reg);
+		snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
-			wm8903_write(codec, WM8903_CLOCK_RATES_2,
+			snd_soc_write(codec, WM8903_CLOCK_RATES_2,
 				     WM8903_CLK_SYS_ENA);
 
 			/* Change DC servo dither level in startup sequence */
-			wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11);
-			wm8903_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257);
-			wm8903_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2);
+			snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11);
+			snd_soc_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257);
+			snd_soc_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2);
 
 			wm8903_run_sequence(codec, 0);
 			wm8903_sync_reg_cache(codec, codec->reg_cache);
 
 			/* Enable low impedence charge pump output */
-			reg = wm8903_read(codec,
+			reg = snd_soc_read(codec,
 					  WM8903_CONTROL_INTERFACE_TEST_1);
-			wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1,
+			snd_soc_write(codec, WM8903_CONTROL_INTERFACE_TEST_1,
 				     reg | WM8903_TEST_KEY);
-			reg2 = wm8903_read(codec, WM8903_CHARGE_PUMP_TEST_1);
-			wm8903_write(codec, WM8903_CHARGE_PUMP_TEST_1,
+			reg2 = snd_soc_read(codec, WM8903_CHARGE_PUMP_TEST_1);
+			snd_soc_write(codec, WM8903_CHARGE_PUMP_TEST_1,
 				     reg2 | WM8903_CP_SW_KELVIN_MODE_MASK);
-			wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1,
+			snd_soc_write(codec, WM8903_CONTROL_INTERFACE_TEST_1,
 				     reg);
 
 			/* By default no bypass paths are enabled so
 			 * enable Class W support.
 			 */
 			dev_dbg(&i2c->dev, "Enabling Class W\n");
-			wm8903_write(codec, WM8903_CLASS_W_0, reg |
+			snd_soc_write(codec, WM8903_CLASS_W_0, reg |
 				     WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
 		}
 
-		reg = wm8903_read(codec, WM8903_VMID_CONTROL_0);
+		reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0);
 		reg &= ~(WM8903_VMID_RES_MASK);
 		reg |= WM8903_VMID_RES_250K;
-		wm8903_write(codec, WM8903_VMID_CONTROL_0, reg);
+		snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		wm8903_run_sequence(codec, 32);
-		reg = wm8903_read(codec, WM8903_CLOCK_RATES_2);
+		reg = snd_soc_read(codec, WM8903_CLOCK_RATES_2);
 		reg &= ~WM8903_CLK_SYS_ENA;
-		wm8903_write(codec, WM8903_CLOCK_RATES_2, reg);
+		snd_soc_write(codec, WM8903_CLOCK_RATES_2, reg);
 		break;
 	}
 
@@ -1081,7 +1005,7 @@
 			      unsigned int fmt)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1);
+	u16 aif1 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_1);
 
 	aif1 &= ~(WM8903_LRCLK_DIR | WM8903_BCLK_DIR | WM8903_AIF_FMT_MASK |
 		  WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV);
@@ -1159,7 +1083,7 @@
 		return -EINVAL;
 	}
 
-	wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
+	snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
 
 	return 0;
 }
@@ -1169,14 +1093,14 @@
 	struct snd_soc_codec *codec = codec_dai->codec;
 	u16 reg;
 
-	reg = wm8903_read(codec, WM8903_DAC_DIGITAL_1);
+	reg = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
 
 	if (mute)
 		reg |= WM8903_DAC_MUTE;
 	else
 		reg &= ~WM8903_DAC_MUTE;
 
-	wm8903_write(codec, WM8903_DAC_DIGITAL_1, reg);
+	snd_soc_write(codec, WM8903_DAC_DIGITAL_1, reg);
 
 	return 0;
 }
@@ -1366,12 +1290,12 @@
 	int cur_val;
 	int clk_sys;
 
-	u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1);
-	u16 aif2 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_2);
-	u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3);
-	u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0);
-	u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1);
-	u16 dac_digital1 = wm8903_read(codec, WM8903_DAC_DIGITAL_1);
+	u16 aif1 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_1);
+	u16 aif2 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_2);
+	u16 aif3 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_3);
+	u16 clock0 = snd_soc_read(codec, WM8903_CLOCK_RATES_0);
+	u16 clock1 = snd_soc_read(codec, WM8903_CLOCK_RATES_1);
+	u16 dac_digital1 = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
 
 	if (substream == wm8903->slave_substream) {
 		dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
@@ -1503,12 +1427,12 @@
 	aif2 |= bclk_divs[bclk_div].div;
 	aif3 |= bclk / fs;
 
-	wm8903_write(codec, WM8903_CLOCK_RATES_0, clock0);
-	wm8903_write(codec, WM8903_CLOCK_RATES_1, clock1);
-	wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
-	wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2);
-	wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3);
-	wm8903_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1);
+	snd_soc_write(codec, WM8903_CLOCK_RATES_0, clock0);
+	snd_soc_write(codec, WM8903_CLOCK_RATES_1, clock1);
+	snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
+	snd_soc_write(codec, WM8903_AUDIO_INTERFACE_2, aif2);
+	snd_soc_write(codec, WM8903_AUDIO_INTERFACE_3, aif3);
+	snd_soc_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1);
 
 	return 0;
 }
@@ -1593,7 +1517,7 @@
 	if (tmp_cache) {
 		for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++)
 			if (tmp_cache[i] != reg_cache[i])
-				wm8903_write(codec, i, tmp_cache[i]);
+				snd_soc_write(codec, i, tmp_cache[i]);
 	} else {
 		dev_err(&i2c->dev, "Failed to allocate temporary cache\n");
 	}
@@ -1624,9 +1548,6 @@
 	codec->dev = &i2c->dev;
 	codec->name = "WM8903";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8903_read;
-	codec->write = wm8903_write;
-	codec->hw_write = (hw_write_t)i2c_master_send;
 	codec->bias_level = SND_SOC_BIAS_OFF;
 	codec->set_bias_level = wm8903_set_bias_level;
 	codec->dai = &wm8903_dai;
@@ -1634,18 +1555,25 @@
 	codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache);
 	codec->reg_cache = &wm8903->reg_cache[0];
 	codec->private_data = wm8903;
+	codec->volatile_register = wm8903_volatile_register;
 
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
+	val = snd_soc_read(codec, WM8903_SW_RESET_AND_ID);
 	if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) {
 		dev_err(&i2c->dev,
 			"Device with ID register %x is not a WM8903\n", val);
 		return -ENODEV;
 	}
 
-	val = wm8903_read(codec, WM8903_REVISION_NUMBER);
+	val = snd_soc_read(codec, WM8903_REVISION_NUMBER);
 	dev_info(&i2c->dev, "WM8903 revision %d\n",
 		 val & WM8903_CHIP_REV_MASK);
 
@@ -1655,35 +1583,35 @@
 	wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	/* Latch volume update bits */
-	val = wm8903_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT);
+	val = snd_soc_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT);
 	val |= WM8903_ADCVU;
-	wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val);
-	wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val);
+	snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val);
+	snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val);
 
-	val = wm8903_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT);
+	val = snd_soc_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT);
 	val |= WM8903_DACVU;
-	wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val);
-	wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val);
+	snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val);
+	snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val);
 
-	val = wm8903_read(codec, WM8903_ANALOGUE_OUT1_LEFT);
+	val = snd_soc_read(codec, WM8903_ANALOGUE_OUT1_LEFT);
 	val |= WM8903_HPOUTVU;
-	wm8903_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val);
-	wm8903_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val);
+	snd_soc_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val);
+	snd_soc_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val);
 
-	val = wm8903_read(codec, WM8903_ANALOGUE_OUT2_LEFT);
+	val = snd_soc_read(codec, WM8903_ANALOGUE_OUT2_LEFT);
 	val |= WM8903_LINEOUTVU;
-	wm8903_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val);
-	wm8903_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val);
+	snd_soc_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val);
+	snd_soc_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val);
 
-	val = wm8903_read(codec, WM8903_ANALOGUE_OUT3_LEFT);
+	val = snd_soc_read(codec, WM8903_ANALOGUE_OUT3_LEFT);
 	val |= WM8903_SPKVU;
-	wm8903_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val);
-	wm8903_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val);
+	snd_soc_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val);
+	snd_soc_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val);
 
 	/* Enable DAC soft mute by default */
-	val = wm8903_read(codec, WM8903_DAC_DIGITAL_1);
+	val = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
 	val |= WM8903_DAC_MUTEMODE;
-	wm8903_write(codec, WM8903_DAC_DIGITAL_1, val);
+	snd_soc_write(codec, WM8903_DAC_DIGITAL_1, val);
 
 	wm8903_dai.dev = &i2c->dev;
 	wm8903_codec = codec;
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index b69210a..da97aae 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -106,50 +106,6 @@
 	0x0000, /* Mono Mixer Control */
 };
 
-static inline unsigned int wm8940_read_reg_cache(struct snd_soc_codec *codec,
-						 unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-
-	if (reg >= ARRAY_SIZE(wm8940_reg_defaults))
-		return -1;
-
-	return cache[reg];
-}
-
-static inline int wm8940_write_reg_cache(struct snd_soc_codec *codec,
-					  u16 reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-
-	if (reg >= ARRAY_SIZE(wm8940_reg_defaults))
-		return -1;
-
-	cache[reg] = value;
-
-	return 0;
-}
-
-static int wm8940_write(struct snd_soc_codec *codec, unsigned int reg,
-			unsigned int value)
-{
-	int ret;
-	u8 data[3] = { reg,
-		       (value & 0xff00) >> 8,
-		       (value & 0x00ff)
-	};
-
-	wm8940_write_reg_cache(codec, reg, value);
-
-	ret = codec->hw_write(codec->control_data, data, 3);
-
-	if (ret < 0)
-		return ret;
-	else if (ret != 3)
-		return -EIO;
-	return 0;
-}
-
 static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
 static const struct soc_enum wm8940_adc_companding_enum
 = SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding);
@@ -348,14 +304,14 @@
 	return ret;
 }
 
-#define wm8940_reset(c) wm8940_write(c, WM8940_SOFTRESET, 0);
+#define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0);
 
 static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int fmt)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFE67;
-	u16 clk = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0x1fe;
+	u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFE67;
+	u16 clk = snd_soc_read(codec, WM8940_CLOCK) & 0x1fe;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -366,7 +322,7 @@
 	default:
 		return -EINVAL;
 	}
-	wm8940_write(codec, WM8940_CLOCK, clk);
+	snd_soc_write(codec, WM8940_CLOCK, clk);
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
@@ -399,7 +355,7 @@
 		break;
 	}
 
-	wm8940_write(codec, WM8940_IFACE, iface);
+	snd_soc_write(codec, WM8940_IFACE, iface);
 
 	return 0;
 }
@@ -411,9 +367,9 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
-	u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFD9F;
-	u16 addcntrl = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFF1;
-	u16 companding =  wm8940_read_reg_cache(codec,
+	u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
+	u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
+	u16 companding =  snd_soc_read(codec,
 						WM8940_COMPANDINGCTL) & 0xFFDF;
 	int ret;
 
@@ -442,7 +398,7 @@
 	case SNDRV_PCM_RATE_48000:
 		break;
 	}
-	ret = wm8940_write(codec, WM8940_ADDCNTRL, addcntrl);
+	ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl);
 	if (ret)
 		goto error_ret;
 
@@ -462,10 +418,10 @@
 		iface |= (3 << 5);
 		break;
 	}
-	ret = wm8940_write(codec, WM8940_COMPANDINGCTL, companding);
+	ret = snd_soc_write(codec, WM8940_COMPANDINGCTL, companding);
 	if (ret)
 		goto error_ret;
-	ret = wm8940_write(codec, WM8940_IFACE, iface);
+	ret = snd_soc_write(codec, WM8940_IFACE, iface);
 
 error_ret:
 	return ret;
@@ -474,19 +430,19 @@
 static int wm8940_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = wm8940_read_reg_cache(codec, WM8940_DAC) & 0xffbf;
+	u16 mute_reg = snd_soc_read(codec, WM8940_DAC) & 0xffbf;
 
 	if (mute)
 		mute_reg |= 0x40;
 
-	return wm8940_write(codec, WM8940_DAC, mute_reg);
+	return snd_soc_write(codec, WM8940_DAC, mute_reg);
 }
 
 static int wm8940_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
 	u16 val;
-	u16 pwr_reg = wm8940_read_reg_cache(codec, WM8940_POWER1) & 0x1F0;
+	u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0;
 	int ret = 0;
 
 	switch (level) {
@@ -494,26 +450,26 @@
 		/* ensure bufioen and biasen */
 		pwr_reg |= (1 << 2) | (1 << 3);
 		/* Enable thermal shutdown */
-		val = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL);
-		ret = wm8940_write(codec, WM8940_OUTPUTCTL, val | 0x2);
+		val = snd_soc_read(codec, WM8940_OUTPUTCTL);
+		ret = snd_soc_write(codec, WM8940_OUTPUTCTL, val | 0x2);
 		if (ret)
 			break;
 		/* set vmid to 75k */
-		ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1);
+		ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		/* ensure bufioen and biasen */
 		pwr_reg |= (1 << 2) | (1 << 3);
-		ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1);
+		ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* ensure bufioen and biasen */
 		pwr_reg |= (1 << 2) | (1 << 3);
 		/* set vmid to 300k for standby */
-		ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x2);
+		ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x2);
 		break;
 	case SND_SOC_BIAS_OFF:
-		ret = wm8940_write(codec, WM8940_POWER1, pwr_reg);
+		ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg);
 		break;
 	}
 
@@ -587,36 +543,36 @@
 	u16 reg;
 
 	/* Turn off PLL */
-	reg = wm8940_read_reg_cache(codec, WM8940_POWER1);
-	wm8940_write(codec, WM8940_POWER1, reg & 0x1df);
+	reg = snd_soc_read(codec, WM8940_POWER1);
+	snd_soc_write(codec, WM8940_POWER1, reg & 0x1df);
 
 	if (freq_in == 0 || freq_out == 0) {
 		/* Clock CODEC directly from MCLK */
-		reg = wm8940_read_reg_cache(codec, WM8940_CLOCK);
-		wm8940_write(codec, WM8940_CLOCK, reg & 0x0ff);
+		reg = snd_soc_read(codec, WM8940_CLOCK);
+		snd_soc_write(codec, WM8940_CLOCK, reg & 0x0ff);
 		/* Pll power down */
-		wm8940_write(codec, WM8940_PLLN, (1 << 7));
+		snd_soc_write(codec, WM8940_PLLN, (1 << 7));
 		return 0;
 	}
 
 	/* Pll is followed by a frequency divide by 4 */
 	pll_factors(freq_out*4, freq_in);
 	if (pll_div.k)
-		wm8940_write(codec, WM8940_PLLN,
+		snd_soc_write(codec, WM8940_PLLN,
 			     (pll_div.pre_scale << 4) | pll_div.n | (1 << 6));
 	else /* No factional component */
-		wm8940_write(codec, WM8940_PLLN,
+		snd_soc_write(codec, WM8940_PLLN,
 			     (pll_div.pre_scale << 4) | pll_div.n);
-	wm8940_write(codec, WM8940_PLLK1, pll_div.k >> 18);
-	wm8940_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff);
-	wm8940_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff);
+	snd_soc_write(codec, WM8940_PLLK1, pll_div.k >> 18);
+	snd_soc_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff);
+	snd_soc_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff);
 	/* Enable the PLL */
-	reg = wm8940_read_reg_cache(codec, WM8940_POWER1);
-	wm8940_write(codec, WM8940_POWER1, reg | 0x020);
+	reg = snd_soc_read(codec, WM8940_POWER1);
+	snd_soc_write(codec, WM8940_POWER1, reg | 0x020);
 
 	/* Run CODEC from PLL instead of MCLK */
-	reg = wm8940_read_reg_cache(codec, WM8940_CLOCK);
-	wm8940_write(codec, WM8940_CLOCK, reg | 0x100);
+	reg = snd_soc_read(codec, WM8940_CLOCK);
+	snd_soc_write(codec, WM8940_CLOCK, reg | 0x100);
 
 	return 0;
 }
@@ -648,16 +604,16 @@
 
 	switch (div_id) {
 	case WM8940_BCLKDIV:
-		reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFFEF3;
-		ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 2));
+		reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFEF3;
+		ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2));
 		break;
 	case WM8940_MCLKDIV:
-		reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFF1F;
-		ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 5));
+		reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFF1F;
+		ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 5));
 		break;
 	case WM8940_OPCLKDIV:
-		reg = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFCF;
-		ret = wm8940_write(codec, WM8940_ADDCNTRL, reg | (div << 4));
+		reg = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFCF;
+		ret = snd_soc_write(codec, WM8940_ADDCNTRL, reg | (div << 4));
 		break;
 	}
 	return ret;
@@ -808,7 +764,8 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940);
 
-static int wm8940_register(struct wm8940_priv *wm8940)
+static int wm8940_register(struct wm8940_priv *wm8940,
+			   enum snd_soc_control_type control)
 {
 	struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data;
 	struct snd_soc_codec *codec = &wm8940->codec;
@@ -825,8 +782,6 @@
 	codec->private_data = wm8940;
 	codec->name = "WM8940";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8940_read_reg_cache;
-	codec->write = wm8940_write;
 	codec->bias_level = SND_SOC_BIAS_OFF;
 	codec->set_bias_level = wm8940_set_bias_level;
 	codec->dai = &wm8940_dai;
@@ -834,6 +789,12 @@
 	codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults);
 	codec->reg_cache = &wm8940->reg_cache;
 
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+	if (ret == 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
 	memcpy(codec->reg_cache, wm8940_reg_defaults,
 	       sizeof(wm8940_reg_defaults));
 
@@ -847,15 +808,15 @@
 
 	wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-	ret = wm8940_write(codec, WM8940_POWER1, 0x180);
+	ret = snd_soc_write(codec, WM8940_POWER1, 0x180);
 	if (ret < 0)
 		return ret;
 
 	if (!pdata)
 		dev_warn(codec->dev, "No platform data supplied\n");
 	else {
-		reg = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL);
-		ret = wm8940_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi);
+		reg = snd_soc_read(codec, WM8940_OUTPUTCTL);
+		ret = snd_soc_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi);
 		if (ret < 0)
 			return ret;
 	}
@@ -904,7 +865,7 @@
 	codec->control_data = i2c;
 	codec->dev = &i2c->dev;
 
-	return wm8940_register(wm8940);
+	return wm8940_register(wm8940, SND_SOC_I2C);
 }
 
 static int __devexit wm8940_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index d1769e6..f59703b 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -69,61 +69,7 @@
 	struct snd_soc_codec codec;
 };
 
-/*
- * read wm8960 register cache
- */
-static inline unsigned int wm8960_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg == WM8960_RESET)
-		return 0;
-	if (reg >= WM8960_CACHEREGNUM)
-		return -1;
-	return cache[reg];
-}
-
-/*
- * write wm8960 register cache
- */
-static inline void wm8960_write_reg_cache(struct snd_soc_codec *codec,
-	u16 reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg >= WM8960_CACHEREGNUM)
-		return;
-	cache[reg] = value;
-}
-
-static inline unsigned int wm8960_read(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	return wm8960_read_reg_cache(codec, reg);
-}
-
-/*
- * write to the WM8960 register space
- */
-static int wm8960_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	u8 data[2];
-
-	/* data is
-	 *   D15..D9 WM8960 register offset
-	 *   D8...D0 register data
-	 */
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	wm8960_write_reg_cache(codec, reg, value);
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
-}
-
-#define wm8960_reset(c)	wm8960_write(c, WM8960_RESET, 0)
+#define wm8960_reset(c)	snd_soc_write(c, WM8960_RESET, 0)
 
 /* enumerated controls */
 static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
@@ -420,7 +366,7 @@
 	}
 
 	/* set iface */
-	wm8960_write(codec, WM8960_IFACE1, iface);
+	snd_soc_write(codec, WM8960_IFACE1, iface);
 	return 0;
 }
 
@@ -431,7 +377,7 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
-	u16 iface = wm8960_read(codec, WM8960_IFACE1) & 0xfff3;
+	u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
 
 	/* bit size */
 	switch (params_format(params)) {
@@ -446,19 +392,19 @@
 	}
 
 	/* set iface */
-	wm8960_write(codec, WM8960_IFACE1, iface);
+	snd_soc_write(codec, WM8960_IFACE1, iface);
 	return 0;
 }
 
 static int wm8960_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = wm8960_read(codec, WM8960_DACCTL1) & 0xfff7;
+	u16 mute_reg = snd_soc_read(codec, WM8960_DACCTL1) & 0xfff7;
 
 	if (mute)
-		wm8960_write(codec, WM8960_DACCTL1, mute_reg | 0x8);
+		snd_soc_write(codec, WM8960_DACCTL1, mute_reg | 0x8);
 	else
-		wm8960_write(codec, WM8960_DACCTL1, mute_reg);
+		snd_soc_write(codec, WM8960_DACCTL1, mute_reg);
 	return 0;
 }
 
@@ -474,16 +420,16 @@
 
 	case SND_SOC_BIAS_PREPARE:
 		/* Set VMID to 2x50k */
-		reg = wm8960_read(codec, WM8960_POWER1);
+		reg = snd_soc_read(codec, WM8960_POWER1);
 		reg &= ~0x180;
 		reg |= 0x80;
-		wm8960_write(codec, WM8960_POWER1, reg);
+		snd_soc_write(codec, WM8960_POWER1, reg);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
 			/* Enable anti-pop features */
-			wm8960_write(codec, WM8960_APOP1,
+			snd_soc_write(codec, WM8960_APOP1,
 				     WM8960_POBCTRL | WM8960_SOFT_ST |
 				     WM8960_BUFDCOPEN | WM8960_BUFIOEN);
 
@@ -491,43 +437,43 @@
 			reg = WM8960_DISOP;
 			if (pdata)
 				reg |= pdata->dres << 4;
-			wm8960_write(codec, WM8960_APOP2, reg);
+			snd_soc_write(codec, WM8960_APOP2, reg);
 
 			msleep(400);
 
-			wm8960_write(codec, WM8960_APOP2, 0);
+			snd_soc_write(codec, WM8960_APOP2, 0);
 
 			/* Enable & ramp VMID at 2x50k */
-			reg = wm8960_read(codec, WM8960_POWER1);
+			reg = snd_soc_read(codec, WM8960_POWER1);
 			reg |= 0x80;
-			wm8960_write(codec, WM8960_POWER1, reg);
+			snd_soc_write(codec, WM8960_POWER1, reg);
 			msleep(100);
 
 			/* Enable VREF */
-			wm8960_write(codec, WM8960_POWER1, reg | WM8960_VREF);
+			snd_soc_write(codec, WM8960_POWER1, reg | WM8960_VREF);
 
 			/* Disable anti-pop features */
-			wm8960_write(codec, WM8960_APOP1, WM8960_BUFIOEN);
+			snd_soc_write(codec, WM8960_APOP1, WM8960_BUFIOEN);
 		}
 
 		/* Set VMID to 2x250k */
-		reg = wm8960_read(codec, WM8960_POWER1);
+		reg = snd_soc_read(codec, WM8960_POWER1);
 		reg &= ~0x180;
 		reg |= 0x100;
-		wm8960_write(codec, WM8960_POWER1, reg);
+		snd_soc_write(codec, WM8960_POWER1, reg);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Enable anti-pop features */
-		wm8960_write(codec, WM8960_APOP1,
+		snd_soc_write(codec, WM8960_APOP1,
 			     WM8960_POBCTRL | WM8960_SOFT_ST |
 			     WM8960_BUFDCOPEN | WM8960_BUFIOEN);
 
 		/* Disable VMID and VREF, let them discharge */
-		wm8960_write(codec, WM8960_POWER1, 0);
+		snd_soc_write(codec, WM8960_POWER1, 0);
 		msleep(600);
 
-		wm8960_write(codec, WM8960_APOP1, 0);
+		snd_soc_write(codec, WM8960_APOP1, 0);
 		break;
 	}
 
@@ -610,33 +556,33 @@
 
 	/* Disable the PLL: even if we are changing the frequency the
 	 * PLL needs to be disabled while we do so. */
-	wm8960_write(codec, WM8960_CLOCK1,
-		     wm8960_read(codec, WM8960_CLOCK1) & ~1);
-	wm8960_write(codec, WM8960_POWER2,
-		     wm8960_read(codec, WM8960_POWER2) & ~1);
+	snd_soc_write(codec, WM8960_CLOCK1,
+		     snd_soc_read(codec, WM8960_CLOCK1) & ~1);
+	snd_soc_write(codec, WM8960_POWER2,
+		     snd_soc_read(codec, WM8960_POWER2) & ~1);
 
 	if (!freq_in || !freq_out)
 		return 0;
 
-	reg = wm8960_read(codec, WM8960_PLL1) & ~0x3f;
+	reg = snd_soc_read(codec, WM8960_PLL1) & ~0x3f;
 	reg |= pll_div.pre_div << 4;
 	reg |= pll_div.n;
 
 	if (pll_div.k) {
 		reg |= 0x20;
 
-		wm8960_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f);
-		wm8960_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff);
-		wm8960_write(codec, WM8960_PLL4, pll_div.k & 0x1ff);
+		snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f);
+		snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff);
+		snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0x1ff);
 	}
-	wm8960_write(codec, WM8960_PLL1, reg);
+	snd_soc_write(codec, WM8960_PLL1, reg);
 
 	/* Turn it on */
-	wm8960_write(codec, WM8960_POWER2,
-		     wm8960_read(codec, WM8960_POWER2) | 1);
+	snd_soc_write(codec, WM8960_POWER2,
+		     snd_soc_read(codec, WM8960_POWER2) | 1);
 	msleep(250);
-	wm8960_write(codec, WM8960_CLOCK1,
-		     wm8960_read(codec, WM8960_CLOCK1) | 1);
+	snd_soc_write(codec, WM8960_CLOCK1,
+		     snd_soc_read(codec, WM8960_CLOCK1) | 1);
 
 	return 0;
 }
@@ -649,28 +595,28 @@
 
 	switch (div_id) {
 	case WM8960_SYSCLKSEL:
-		reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1fe;
-		wm8960_write(codec, WM8960_CLOCK1, reg | div);
+		reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1fe;
+		snd_soc_write(codec, WM8960_CLOCK1, reg | div);
 		break;
 	case WM8960_SYSCLKDIV:
-		reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1f9;
-		wm8960_write(codec, WM8960_CLOCK1, reg | div);
+		reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1f9;
+		snd_soc_write(codec, WM8960_CLOCK1, reg | div);
 		break;
 	case WM8960_DACDIV:
-		reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1c7;
-		wm8960_write(codec, WM8960_CLOCK1, reg | div);
+		reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1c7;
+		snd_soc_write(codec, WM8960_CLOCK1, reg | div);
 		break;
 	case WM8960_OPCLKDIV:
-		reg = wm8960_read(codec, WM8960_PLL1) & 0x03f;
-		wm8960_write(codec, WM8960_PLL1, reg | div);
+		reg = snd_soc_read(codec, WM8960_PLL1) & 0x03f;
+		snd_soc_write(codec, WM8960_PLL1, reg | div);
 		break;
 	case WM8960_DCLKDIV:
-		reg = wm8960_read(codec, WM8960_CLOCK2) & 0x03f;
-		wm8960_write(codec, WM8960_CLOCK2, reg | div);
+		reg = snd_soc_read(codec, WM8960_CLOCK2) & 0x03f;
+		snd_soc_write(codec, WM8960_CLOCK2, reg | div);
 		break;
 	case WM8960_TOCLKSEL:
-		reg = wm8960_read(codec, WM8960_ADDCTL1) & 0x1fd;
-		wm8960_write(codec, WM8960_ADDCTL1, reg | div);
+		reg = snd_soc_read(codec, WM8960_ADDCTL1) & 0x1fd;
+		snd_soc_write(codec, WM8960_ADDCTL1, reg | div);
 		break;
 	default:
 		return -EINVAL;
@@ -801,7 +747,8 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960);
 
-static int wm8960_register(struct wm8960_priv *wm8960)
+static int wm8960_register(struct wm8960_priv *wm8960,
+			   enum snd_soc_control_type control)
 {
 	struct wm8960_data *pdata = wm8960->codec.dev->platform_data;
 	struct snd_soc_codec *codec = &wm8960->codec;
@@ -830,8 +777,6 @@
 	codec->private_data = wm8960;
 	codec->name = "WM8960";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8960_read_reg_cache;
-	codec->write = wm8960_write;
 	codec->bias_level = SND_SOC_BIAS_OFF;
 	codec->set_bias_level = wm8960_set_bias_level;
 	codec->dai = &wm8960_dai;
@@ -841,6 +786,12 @@
 
 	memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg));
 
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
 	ret = wm8960_reset(codec);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to issue reset\n");
@@ -852,26 +803,26 @@
 	wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	/* Latch the update bits */
-	reg = wm8960_read(codec, WM8960_LINVOL);
-	wm8960_write(codec, WM8960_LINVOL, reg | 0x100);
-	reg = wm8960_read(codec, WM8960_RINVOL);
-	wm8960_write(codec, WM8960_RINVOL, reg | 0x100);
-	reg = wm8960_read(codec, WM8960_LADC);
-	wm8960_write(codec, WM8960_LADC, reg | 0x100);
-	reg = wm8960_read(codec, WM8960_RADC);
-	wm8960_write(codec, WM8960_RADC, reg | 0x100);
-	reg = wm8960_read(codec, WM8960_LDAC);
-	wm8960_write(codec, WM8960_LDAC, reg | 0x100);
-	reg = wm8960_read(codec, WM8960_RDAC);
-	wm8960_write(codec, WM8960_RDAC, reg | 0x100);
-	reg = wm8960_read(codec, WM8960_LOUT1);
-	wm8960_write(codec, WM8960_LOUT1, reg | 0x100);
-	reg = wm8960_read(codec, WM8960_ROUT1);
-	wm8960_write(codec, WM8960_ROUT1, reg | 0x100);
-	reg = wm8960_read(codec, WM8960_LOUT2);
-	wm8960_write(codec, WM8960_LOUT2, reg | 0x100);
-	reg = wm8960_read(codec, WM8960_ROUT2);
-	wm8960_write(codec, WM8960_ROUT2, reg | 0x100);
+	reg = snd_soc_read(codec, WM8960_LINVOL);
+	snd_soc_write(codec, WM8960_LINVOL, reg | 0x100);
+	reg = snd_soc_read(codec, WM8960_RINVOL);
+	snd_soc_write(codec, WM8960_RINVOL, reg | 0x100);
+	reg = snd_soc_read(codec, WM8960_LADC);
+	snd_soc_write(codec, WM8960_LADC, reg | 0x100);
+	reg = snd_soc_read(codec, WM8960_RADC);
+	snd_soc_write(codec, WM8960_RADC, reg | 0x100);
+	reg = snd_soc_read(codec, WM8960_LDAC);
+	snd_soc_write(codec, WM8960_LDAC, reg | 0x100);
+	reg = snd_soc_read(codec, WM8960_RDAC);
+	snd_soc_write(codec, WM8960_RDAC, reg | 0x100);
+	reg = snd_soc_read(codec, WM8960_LOUT1);
+	snd_soc_write(codec, WM8960_LOUT1, reg | 0x100);
+	reg = snd_soc_read(codec, WM8960_ROUT1);
+	snd_soc_write(codec, WM8960_ROUT1, reg | 0x100);
+	reg = snd_soc_read(codec, WM8960_LOUT2);
+	snd_soc_write(codec, WM8960_LOUT2, reg | 0x100);
+	reg = snd_soc_read(codec, WM8960_ROUT2);
+	snd_soc_write(codec, WM8960_ROUT2, reg | 0x100);
 
 	wm8960_codec = codec;
 
@@ -916,14 +867,13 @@
 		return -ENOMEM;
 
 	codec = &wm8960->codec;
-	codec->hw_write = (hw_write_t)i2c_master_send;
 
 	i2c_set_clientdata(i2c, wm8960);
 	codec->control_data = i2c;
 
 	codec->dev = &i2c->dev;
 
-	return wm8960_register(wm8960);
+	return wm8960_register(wm8960, SND_SOC_I2C);
 }
 
 static __devexit int wm8960_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index bd1af92..5030320 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -292,9 +292,10 @@
 	u16 reg_cache[WM8961_MAX_REGISTER];
 };
 
-static int wm8961_reg_is_volatile(int reg)
+static int wm8961_volatile_register(unsigned int reg)
 {
 	switch (reg) {
+	case WM8961_SOFTWARE_RESET:
 	case WM8961_WRITE_SEQUENCER_7:
 	case WM8961_DC_SERVO_1:
 		return 1;
@@ -304,76 +305,9 @@
 	}
 }
 
-static unsigned int wm8961_read_reg_cache(struct snd_soc_codec *codec,
-					  unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	BUG_ON(reg > WM8961_MAX_REGISTER);
-	return cache[reg];
-}
-
-static unsigned int wm8961_read_hw(struct snd_soc_codec *codec, u8 reg)
-{
-	struct i2c_msg xfer[2];
-	u16 data;
-	int ret;
-	struct i2c_client *client = codec->control_data;
-
-	BUG_ON(reg > WM8961_MAX_REGISTER);
-
-	/* Write register */
-	xfer[0].addr = client->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 1;
-	xfer[0].buf = &reg;
-
-	/* Read data */
-	xfer[1].addr = client->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 2;
-	xfer[1].buf = (u8 *)&data;
-
-	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret != 2) {
-		dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
-		return 0;
-	}
-
-	return (data >> 8) | ((data & 0xff) << 8);
-}
-
-static unsigned int wm8961_read(struct snd_soc_codec *codec, unsigned int reg)
-{
-	if (wm8961_reg_is_volatile(reg))
-		return wm8961_read_hw(codec, reg);
-	else
-		return wm8961_read_reg_cache(codec, reg);
-}
-
-static int wm8961_write(struct snd_soc_codec *codec, unsigned int reg,
-			unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-	u8 data[3];
-
-	BUG_ON(reg > WM8961_MAX_REGISTER);
-
-	if (!wm8961_reg_is_volatile(reg))
-		cache[reg] = value;
-
-	data[0] = reg;
-	data[1] = value >> 8;
-	data[2] = value & 0x00ff;
-
-	if (codec->hw_write(codec->control_data, data, 3) == 3)
-		return 0;
-	else
-		return -EIO;
-}
-
 static int wm8961_reset(struct snd_soc_codec *codec)
 {
-	return wm8961_write(codec, WM8961_SOFTWARE_RESET, 0);
+	return snd_soc_write(codec, WM8961_SOFTWARE_RESET, 0);
 }
 
 /*
@@ -384,33 +318,33 @@
 			   struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	u16 hp_reg = wm8961_read(codec, WM8961_ANALOGUE_HP_0);
-	u16 cp_reg = wm8961_read(codec, WM8961_CHARGE_PUMP_1);
-	u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2);
-	u16 dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1);
+	u16 hp_reg = snd_soc_read(codec, WM8961_ANALOGUE_HP_0);
+	u16 cp_reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_1);
+	u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
+	u16 dcs_reg = snd_soc_read(codec, WM8961_DC_SERVO_1);
 	int timeout = 500;
 
 	if (event & SND_SOC_DAPM_POST_PMU) {
 		/* Make sure the output is shorted */
 		hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT);
-		wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Enable the charge pump */
 		cp_reg |= WM8961_CP_ENA;
-		wm8961_write(codec, WM8961_CHARGE_PUMP_1, cp_reg);
+		snd_soc_write(codec, WM8961_CHARGE_PUMP_1, cp_reg);
 		mdelay(5);
 
 		/* Enable the PGA */
 		pwr_reg |= WM8961_LOUT1_PGA | WM8961_ROUT1_PGA;
-		wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
+		snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
 
 		/* Enable the amplifier */
 		hp_reg |= WM8961_HPR_ENA | WM8961_HPL_ENA;
-		wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Second stage enable */
 		hp_reg |= WM8961_HPR_ENA_DLY | WM8961_HPL_ENA_DLY;
-		wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Enable the DC servo & trigger startup */
 		dcs_reg |=
@@ -418,10 +352,10 @@
 			WM8961_DCS_ENA_CHAN_HPL | WM8961_DCS_TRIG_STARTUP_HPL;
 		dev_dbg(codec->dev, "Enabling DC servo\n");
 
-		wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg);
+		snd_soc_write(codec, WM8961_DC_SERVO_1, dcs_reg);
 		do {
 			msleep(1);
-			dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1);
+			dcs_reg = snd_soc_read(codec, WM8961_DC_SERVO_1);
 		} while (--timeout &&
 			 dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR |
 				WM8961_DCS_TRIG_STARTUP_HPL));
@@ -433,39 +367,39 @@
 
 		/* Enable the output stage */
 		hp_reg |= WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP;
-		wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Remove the short on the output stage */
 		hp_reg |= WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT;
-		wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
 	}
 
 	if (event & SND_SOC_DAPM_PRE_PMD) {
 		/* Short the output */
 		hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT);
-		wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Disable the output stage */
 		hp_reg &= ~(WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP);
-		wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Disable DC offset cancellation */
 		dcs_reg &= ~(WM8961_DCS_ENA_CHAN_HPR |
 			     WM8961_DCS_ENA_CHAN_HPL);
-		wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg);
+		snd_soc_write(codec, WM8961_DC_SERVO_1, dcs_reg);
 
 		/* Finish up */
 		hp_reg &= ~(WM8961_HPR_ENA_DLY | WM8961_HPR_ENA |
 			    WM8961_HPL_ENA_DLY | WM8961_HPL_ENA);
-		wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Disable the PGA */
 		pwr_reg &= ~(WM8961_LOUT1_PGA | WM8961_ROUT1_PGA);
-		wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
+		snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
 
 		/* Disable the charge pump */
 		dev_dbg(codec->dev, "Disabling charge pump\n");
-		wm8961_write(codec, WM8961_CHARGE_PUMP_1,
+		snd_soc_write(codec, WM8961_CHARGE_PUMP_1,
 			     cp_reg & ~WM8961_CP_ENA);
 	}
 
@@ -476,27 +410,27 @@
 			    struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2);
-	u16 spk_reg = wm8961_read(codec, WM8961_CLASS_D_CONTROL_1);
+	u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
+	u16 spk_reg = snd_soc_read(codec, WM8961_CLASS_D_CONTROL_1);
 
 	if (event & SND_SOC_DAPM_POST_PMU) {
 		/* Enable the PGA */
 		pwr_reg |= WM8961_SPKL_PGA | WM8961_SPKR_PGA;
-		wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
+		snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
 
 		/* Enable the amplifier */
 		spk_reg |= WM8961_SPKL_ENA | WM8961_SPKR_ENA;
-		wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg);
+		snd_soc_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg);
 	}
 
 	if (event & SND_SOC_DAPM_PRE_PMD) {
 		/* Enable the amplifier */
 		spk_reg &= ~(WM8961_SPKL_ENA | WM8961_SPKR_ENA);
-		wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg);
+		snd_soc_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg);
 
 		/* Enable the PGA */
 		pwr_reg &= ~(WM8961_SPKL_PGA | WM8961_SPKR_PGA);
-		wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
+		snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
 	}
 
 	return 0;
@@ -714,10 +648,10 @@
 		    abs(wm8961_srate[best].rate - fs))
 			best = i;
 	}
-	reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_3);
+	reg = snd_soc_read(codec, WM8961_ADDITIONAL_CONTROL_3);
 	reg &= ~WM8961_SAMPLE_RATE_MASK;
 	reg |= wm8961_srate[best].val;
-	wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg);
+	snd_soc_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg);
 	dev_dbg(codec->dev, "Selected SRATE %dHz for %dHz\n",
 		wm8961_srate[best].rate, fs);
 
@@ -747,12 +681,12 @@
 		wm8961_clk_sys_ratio[i].ratio, wm8961->sysclk, fs,
 		wm8961->sysclk / fs);
 
-	reg = wm8961_read(codec, WM8961_CLOCKING_4);
+	reg = snd_soc_read(codec, WM8961_CLOCKING_4);
 	reg &= ~WM8961_CLK_SYS_RATE_MASK;
 	reg |= wm8961_clk_sys_ratio[i].val << WM8961_CLK_SYS_RATE_SHIFT;
-	wm8961_write(codec, WM8961_CLOCKING_4, reg);
+	snd_soc_write(codec, WM8961_CLOCKING_4, reg);
 
-	reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0);
+	reg = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0);
 	reg &= ~WM8961_WL_MASK;
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
@@ -769,15 +703,15 @@
 	default:
 		return -EINVAL;
 	}
-	wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, reg);
+	snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, reg);
 
 	/* Sloping stop-band filter is recommended for <= 24kHz */
-	reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2);
+	reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_2);
 	if (fs <= 24000)
 		reg |= WM8961_DACSLOPE;
 	else
 		reg &= WM8961_DACSLOPE;
-	wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg);
+	snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg);
 
 	return 0;
 }
@@ -788,7 +722,7 @@
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct wm8961_priv *wm8961 = codec->private_data;
-	u16 reg = wm8961_read(codec, WM8961_CLOCKING1);
+	u16 reg = snd_soc_read(codec, WM8961_CLOCKING1);
 
 	if (freq > 33000000) {
 		dev_err(codec->dev, "MCLK must be <33MHz\n");
@@ -804,7 +738,7 @@
 		reg &= WM8961_MCLKDIV;
 	}
 
-	wm8961_write(codec, WM8961_CLOCKING1, reg);
+	snd_soc_write(codec, WM8961_CLOCKING1, reg);
 
 	wm8961->sysclk = freq;
 
@@ -814,7 +748,7 @@
 static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 aif = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0);
+	u16 aif = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0);
 
 	aif &= ~(WM8961_BCLKINV | WM8961_LRP |
 		 WM8961_MS | WM8961_FORMAT_MASK);
@@ -874,26 +808,26 @@
 		return -EINVAL;
 	}
 
-	return wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, aif);
+	return snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, aif);
 }
 
 static int wm8961_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_2);
+	u16 reg = snd_soc_read(codec, WM8961_ADDITIONAL_CONTROL_2);
 
 	if (tristate)
 		reg |= WM8961_TRIS;
 	else
 		reg &= ~WM8961_TRIS;
 
-	return wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_2, reg);
+	return snd_soc_write(codec, WM8961_ADDITIONAL_CONTROL_2, reg);
 }
 
 static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_1);
+	u16 reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_1);
 
 	if (mute)
 		reg |= WM8961_DACMU;
@@ -902,7 +836,7 @@
 
 	msleep(17);
 
-	return wm8961_write(codec, WM8961_ADC_DAC_CONTROL_1, reg);
+	return snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_1, reg);
 }
 
 static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
@@ -912,17 +846,17 @@
 
 	switch (div_id) {
 	case WM8961_BCLK:
-		reg = wm8961_read(codec, WM8961_CLOCKING2);
+		reg = snd_soc_read(codec, WM8961_CLOCKING2);
 		reg &= ~WM8961_BCLKDIV_MASK;
 		reg |= div;
-		wm8961_write(codec, WM8961_CLOCKING2, reg);
+		snd_soc_write(codec, WM8961_CLOCKING2, reg);
 		break;
 
 	case WM8961_LRCLK:
-		reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_2);
+		reg = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_2);
 		reg &= ~WM8961_LRCLK_RATE_MASK;
 		reg |= div;
-		wm8961_write(codec, WM8961_AUDIO_INTERFACE_2, reg);
+		snd_soc_write(codec, WM8961_AUDIO_INTERFACE_2, reg);
 		break;
 
 	default:
@@ -949,34 +883,34 @@
 	case SND_SOC_BIAS_PREPARE:
 		if (codec->bias_level == SND_SOC_BIAS_STANDBY) {
 			/* Enable bias generation */
-			reg = wm8961_read(codec, WM8961_ANTI_POP);
+			reg = snd_soc_read(codec, WM8961_ANTI_POP);
 			reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN;
-			wm8961_write(codec, WM8961_ANTI_POP, reg);
+			snd_soc_write(codec, WM8961_ANTI_POP, reg);
 
 			/* VMID=2*50k, VREF */
-			reg = wm8961_read(codec, WM8961_PWR_MGMT_1);
+			reg = snd_soc_read(codec, WM8961_PWR_MGMT_1);
 			reg &= ~WM8961_VMIDSEL_MASK;
 			reg |= (1 << WM8961_VMIDSEL_SHIFT) | WM8961_VREF;
-			wm8961_write(codec, WM8961_PWR_MGMT_1, reg);
+			snd_soc_write(codec, WM8961_PWR_MGMT_1, reg);
 		}
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->bias_level == SND_SOC_BIAS_PREPARE) {
 			/* VREF off */
-			reg = wm8961_read(codec, WM8961_PWR_MGMT_1);
+			reg = snd_soc_read(codec, WM8961_PWR_MGMT_1);
 			reg &= ~WM8961_VREF;
-			wm8961_write(codec, WM8961_PWR_MGMT_1, reg);
+			snd_soc_write(codec, WM8961_PWR_MGMT_1, reg);
 
 			/* Bias generation off */
-			reg = wm8961_read(codec, WM8961_ANTI_POP);
+			reg = snd_soc_read(codec, WM8961_ANTI_POP);
 			reg &= ~(WM8961_BUFIOEN | WM8961_BUFDCOPEN);
-			wm8961_write(codec, WM8961_ANTI_POP, reg);
+			snd_soc_write(codec, WM8961_ANTI_POP, reg);
 
 			/* VMID off */
-			reg = wm8961_read(codec, WM8961_PWR_MGMT_1);
+			reg = snd_soc_read(codec, WM8961_PWR_MGMT_1);
 			reg &= ~WM8961_VMIDSEL_MASK;
-			wm8961_write(codec, WM8961_PWR_MGMT_1, reg);
+			snd_soc_write(codec, WM8961_PWR_MGMT_1, reg);
 		}
 		break;
 
@@ -1101,7 +1035,7 @@
 		if (i == WM8961_SOFTWARE_RESET)
 			continue;
 
-		wm8961_write(codec, i, reg_cache[i]);
+		snd_soc_write(codec, i, reg_cache[i]);
 	}
 
 	wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1140,26 +1074,32 @@
 	codec->private_data = wm8961;
 	codec->name = "WM8961";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8961_read;
-	codec->write = wm8961_write;
 	codec->dai = &wm8961_dai;
 	codec->num_dai = 1;
 	codec->reg_cache_size = ARRAY_SIZE(wm8961->reg_cache);
 	codec->reg_cache = &wm8961->reg_cache;
 	codec->bias_level = SND_SOC_BIAS_OFF;
 	codec->set_bias_level = wm8961_set_bias_level;
+	codec->volatile_register = wm8961_volatile_register;
 
 	memcpy(codec->reg_cache, wm8961_reg_defaults,
 	       sizeof(wm8961_reg_defaults));
 
-	reg = wm8961_read_hw(codec, WM8961_SOFTWARE_RESET);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
+	reg = snd_soc_read(codec, WM8961_SOFTWARE_RESET);
 	if (reg != 0x1801) {
 		dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg);
 		ret = -EINVAL;
 		goto err;
 	}
 
-	reg = wm8961_read_hw(codec, WM8961_RIGHT_INPUT_VOLUME);
+	/* This isn't volatile - readback doesn't correspond to write */
+	reg = codec->hw_read(codec, WM8961_RIGHT_INPUT_VOLUME);
 	dev_info(codec->dev, "WM8961 family %d revision %c\n",
 		 (reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT,
 		 ((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT)
@@ -1172,37 +1112,37 @@
 	}
 
 	/* Enable class W */
-	reg = wm8961_read(codec, WM8961_CHARGE_PUMP_B);
+	reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_B);
 	reg |= WM8961_CP_DYN_PWR_MASK;
-	wm8961_write(codec, WM8961_CHARGE_PUMP_B, reg);
+	snd_soc_write(codec, WM8961_CHARGE_PUMP_B, reg);
 
 	/* Latch volume update bits (right channel only, we always
 	 * write both out) and default ZC on. */
-	reg = wm8961_read(codec, WM8961_ROUT1_VOLUME);
-	wm8961_write(codec, WM8961_ROUT1_VOLUME,
+	reg = snd_soc_read(codec, WM8961_ROUT1_VOLUME);
+	snd_soc_write(codec, WM8961_ROUT1_VOLUME,
 		     reg | WM8961_LO1ZC | WM8961_OUT1VU);
-	wm8961_write(codec, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC);
-	reg = wm8961_read(codec, WM8961_ROUT2_VOLUME);
-	wm8961_write(codec, WM8961_ROUT2_VOLUME,
+	snd_soc_write(codec, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC);
+	reg = snd_soc_read(codec, WM8961_ROUT2_VOLUME);
+	snd_soc_write(codec, WM8961_ROUT2_VOLUME,
 		     reg | WM8961_SPKRZC | WM8961_SPKVU);
-	wm8961_write(codec, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC);
+	snd_soc_write(codec, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC);
 
-	reg = wm8961_read(codec, WM8961_RIGHT_ADC_VOLUME);
-	wm8961_write(codec, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU);
-	reg = wm8961_read(codec, WM8961_RIGHT_INPUT_VOLUME);
-	wm8961_write(codec, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU);
+	reg = snd_soc_read(codec, WM8961_RIGHT_ADC_VOLUME);
+	snd_soc_write(codec, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU);
+	reg = snd_soc_read(codec, WM8961_RIGHT_INPUT_VOLUME);
+	snd_soc_write(codec, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU);
 
 	/* Use soft mute by default */
-	reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2);
+	reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_2);
 	reg |= WM8961_DACSMM;
-	wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg);
+	snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg);
 
 	/* Use automatic clocking mode by default; for now this is all
 	 * we support.
 	 */
-	reg = wm8961_read(codec, WM8961_CLOCKING_3);
+	reg = snd_soc_read(codec, WM8961_CLOCKING_3);
 	reg &= ~WM8961_MANUAL_MODE;
-	wm8961_write(codec, WM8961_CLOCKING_3, reg);
+	snd_soc_write(codec, WM8961_CLOCKING_3, reg);
 
 	wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -1250,7 +1190,6 @@
 		return -ENOMEM;
 
 	codec = &wm8961->codec;
-	codec->hw_write = (hw_write_t)i2c_master_send;
 
 	i2c_set_clientdata(i2c, wm8961);
 	codec->control_data = i2c;
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 032dca2..d66efb0 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -59,44 +59,7 @@
 	0x0079, 0x0079, 0x0079,          /* 40 */
 };
 
-static inline unsigned int wm8971_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg < WM8971_REG_COUNT)
-		return cache[reg];
-
-	return -1;
-}
-
-static inline void wm8971_write_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg < WM8971_REG_COUNT)
-		cache[reg] = value;
-}
-
-static int wm8971_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	u8 data[2];
-
-	/* data is
-	 *   D15..D9 WM8753 register offset
-	 *   D8...D0 register data
-	 */
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	wm8971_write_reg_cache (codec, reg, value);
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
-}
-
-#define wm8971_reset(c)	wm8971_write(c, WM8971_RESET, 0)
+#define wm8971_reset(c)	snd_soc_write(c, WM8971_RESET, 0)
 
 /* WM8971 Controls */
 static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" };
@@ -521,7 +484,7 @@
 		return -EINVAL;
 	}
 
-	wm8971_write(codec, WM8971_IFACE, iface);
+	snd_soc_write(codec, WM8971_IFACE, iface);
 	return 0;
 }
 
@@ -533,8 +496,8 @@
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
 	struct wm8971_priv *wm8971 = codec->private_data;
-	u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3;
-	u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0;
+	u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
+	u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
 	int coeff = get_coeff(wm8971->sysclk, params_rate(params));
 
 	/* bit size */
@@ -553,9 +516,9 @@
 	}
 
 	/* set iface & srate */
-	wm8971_write(codec, WM8971_IFACE, iface);
+	snd_soc_write(codec, WM8971_IFACE, iface);
 	if (coeff >= 0)
-		wm8971_write(codec, WM8971_SRATE, srate |
+		snd_soc_write(codec, WM8971_SRATE, srate |
 			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
 
 	return 0;
@@ -564,33 +527,33 @@
 static int wm8971_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = wm8971_read_reg_cache(codec, WM8971_ADCDAC) & 0xfff7;
+	u16 mute_reg = snd_soc_read(codec, WM8971_ADCDAC) & 0xfff7;
 
 	if (mute)
-		wm8971_write(codec, WM8971_ADCDAC, mute_reg | 0x8);
+		snd_soc_write(codec, WM8971_ADCDAC, mute_reg | 0x8);
 	else
-		wm8971_write(codec, WM8971_ADCDAC, mute_reg);
+		snd_soc_write(codec, WM8971_ADCDAC, mute_reg);
 	return 0;
 }
 
 static int wm8971_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
 {
-	u16 pwr_reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e;
+	u16 pwr_reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* set vmid to 50k and unmute dac */
-		wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x00c1);
+		snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x00c1);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* mute dac and set vmid to 500k, enable VREF */
-		wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
+		snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
 		break;
 	case SND_SOC_BIAS_OFF:
-		wm8971_write(codec, WM8971_PWR1, 0x0001);
+		snd_soc_write(codec, WM8971_PWR1, 0x0001);
 		break;
 	}
 	codec->bias_level = level;
@@ -667,8 +630,8 @@
 
 	/* charge wm8971 caps */
 	if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
-		reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e;
-		wm8971_write(codec, WM8971_PWR1, reg | 0x01c0);
+		reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
+		snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0);
 		codec->bias_level = SND_SOC_BIAS_ON;
 		queue_delayed_work(wm8971_workq, &codec->delayed_work,
 			msecs_to_jiffies(1000));
@@ -677,15 +640,14 @@
 	return 0;
 }
 
-static int wm8971_init(struct snd_soc_device *socdev)
+static int wm8971_init(struct snd_soc_device *socdev,
+		       enum snd_soc_control_type control)
 {
 	struct snd_soc_codec *codec = socdev->card->codec;
 	int reg, ret = 0;
 
 	codec->name = "WM8971";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8971_read_reg_cache;
-	codec->write = wm8971_write;
 	codec->set_bias_level = wm8971_set_bias_level;
 	codec->dai = &wm8971_dai;
 	codec->reg_cache_size = ARRAY_SIZE(wm8971_reg);
@@ -695,42 +657,48 @@
 	if (codec->reg_cache == NULL)
 		return -ENOMEM;
 
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
 	wm8971_reset(codec);
 
 	/* register pcms */
 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8971: failed to create pcms\n");
-		goto pcm_err;
+		goto err;
 	}
 
 	/* charge output caps - set vmid to 5k for quick power up */
-	reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e;
-	wm8971_write(codec, WM8971_PWR1, reg | 0x01c0);
+	reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
+	snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0);
 	codec->bias_level = SND_SOC_BIAS_STANDBY;
 	queue_delayed_work(wm8971_workq, &codec->delayed_work,
 		msecs_to_jiffies(1000));
 
 	/* set the update bits */
-	reg = wm8971_read_reg_cache(codec, WM8971_LDAC);
-	wm8971_write(codec, WM8971_LDAC, reg | 0x0100);
-	reg = wm8971_read_reg_cache(codec, WM8971_RDAC);
-	wm8971_write(codec, WM8971_RDAC, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8971_LDAC);
+	snd_soc_write(codec, WM8971_LDAC, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8971_RDAC);
+	snd_soc_write(codec, WM8971_RDAC, reg | 0x0100);
 
-	reg = wm8971_read_reg_cache(codec, WM8971_LOUT1V);
-	wm8971_write(codec, WM8971_LOUT1V, reg | 0x0100);
-	reg = wm8971_read_reg_cache(codec, WM8971_ROUT1V);
-	wm8971_write(codec, WM8971_ROUT1V, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8971_LOUT1V);
+	snd_soc_write(codec, WM8971_LOUT1V, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8971_ROUT1V);
+	snd_soc_write(codec, WM8971_ROUT1V, reg | 0x0100);
 
-	reg = wm8971_read_reg_cache(codec, WM8971_LOUT2V);
-	wm8971_write(codec, WM8971_LOUT2V, reg | 0x0100);
-	reg = wm8971_read_reg_cache(codec, WM8971_ROUT2V);
-	wm8971_write(codec, WM8971_ROUT2V, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8971_LOUT2V);
+	snd_soc_write(codec, WM8971_LOUT2V, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8971_ROUT2V);
+	snd_soc_write(codec, WM8971_ROUT2V, reg | 0x0100);
 
-	reg = wm8971_read_reg_cache(codec, WM8971_LINVOL);
-	wm8971_write(codec, WM8971_LINVOL, reg | 0x0100);
-	reg = wm8971_read_reg_cache(codec, WM8971_RINVOL);
-	wm8971_write(codec, WM8971_RINVOL, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8971_LINVOL);
+	snd_soc_write(codec, WM8971_LINVOL, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8971_RINVOL);
+	snd_soc_write(codec, WM8971_RINVOL, reg | 0x0100);
 
 	snd_soc_add_controls(codec, wm8971_snd_controls,
 				ARRAY_SIZE(wm8971_snd_controls));
@@ -745,7 +713,7 @@
 card_err:
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
-pcm_err:
+err:
 	kfree(codec->reg_cache);
 	return ret;
 }
@@ -767,7 +735,7 @@
 
 	codec->control_data = i2c;
 
-	ret = wm8971_init(socdev);
+	ret = wm8971_init(socdev, SND_SOC_I2C);
 	if (ret < 0)
 		pr_err("failed to initialise WM8971\n");
 
@@ -877,7 +845,6 @@
 
 #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		codec->hw_write = (hw_write_t)i2c_master_send;
 		ret = wm8971_add_i2c_device(pdev, setup);
 	}
 #endif
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 6f15acd..1c86535 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -57,50 +57,7 @@
 };
 
 
-/*
- * read wm8988 register cache
- */
-static inline unsigned int wm8988_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg > WM8988_NUM_REG)
-		return -1;
-	return cache[reg];
-}
-
-/*
- * write wm8988 register cache
- */
-static inline void wm8988_write_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg > WM8988_NUM_REG)
-		return;
-	cache[reg] = value;
-}
-
-static int wm8988_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	u8 data[2];
-
-	/* data is
-	 *   D15..D9 WM8753 register offset
-	 *   D8...D0 register data
-	 */
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	wm8988_write_reg_cache(codec, reg, value);
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
-}
-
-#define wm8988_reset(c)	wm8988_write(c, WM8988_RESET, 0)
+#define wm8988_reset(c)	snd_soc_write(c, WM8988_RESET, 0)
 
 /*
  * WM8988 Controls
@@ -226,15 +183,15 @@
 			      struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	u16 adctl2 = wm8988_read_reg_cache(codec, WM8988_ADCTL2);
+	u16 adctl2 = snd_soc_read(codec, WM8988_ADCTL2);
 
 	/* Use the DAC to gate LRC if active, otherwise use ADC */
-	if (wm8988_read_reg_cache(codec, WM8988_PWR2) & 0x180)
+	if (snd_soc_read(codec, WM8988_PWR2) & 0x180)
 		adctl2 &= ~0x4;
 	else
 		adctl2 |= 0x4;
 
-	return wm8988_write(codec, WM8988_ADCTL2, adctl2);
+	return snd_soc_write(codec, WM8988_ADCTL2, adctl2);
 }
 
 static const char *wm8988_line_texts[] = {
@@ -619,7 +576,7 @@
 		return -EINVAL;
 	}
 
-	wm8988_write(codec, WM8988_IFACE, iface);
+	snd_soc_write(codec, WM8988_IFACE, iface);
 	return 0;
 }
 
@@ -653,8 +610,8 @@
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
 	struct wm8988_priv *wm8988 = codec->private_data;
-	u16 iface = wm8988_read_reg_cache(codec, WM8988_IFACE) & 0x1f3;
-	u16 srate = wm8988_read_reg_cache(codec, WM8988_SRATE) & 0x180;
+	u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3;
+	u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180;
 	int coeff;
 
 	coeff = get_coeff(wm8988->sysclk, params_rate(params));
@@ -685,9 +642,9 @@
 	}
 
 	/* set iface & srate */
-	wm8988_write(codec, WM8988_IFACE, iface);
+	snd_soc_write(codec, WM8988_IFACE, iface);
 	if (coeff >= 0)
-		wm8988_write(codec, WM8988_SRATE, srate |
+		snd_soc_write(codec, WM8988_SRATE, srate |
 			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
 
 	return 0;
@@ -696,19 +653,19 @@
 static int wm8988_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = wm8988_read_reg_cache(codec, WM8988_ADCDAC) & 0xfff7;
+	u16 mute_reg = snd_soc_read(codec, WM8988_ADCDAC) & 0xfff7;
 
 	if (mute)
-		wm8988_write(codec, WM8988_ADCDAC, mute_reg | 0x8);
+		snd_soc_write(codec, WM8988_ADCDAC, mute_reg | 0x8);
 	else
-		wm8988_write(codec, WM8988_ADCDAC, mute_reg);
+		snd_soc_write(codec, WM8988_ADCDAC, mute_reg);
 	return 0;
 }
 
 static int wm8988_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
-	u16 pwr_reg = wm8988_read_reg_cache(codec, WM8988_PWR1) & ~0x1c1;
+	u16 pwr_reg = snd_soc_read(codec, WM8988_PWR1) & ~0x1c1;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -716,24 +673,24 @@
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VREF, VMID=2x50k, digital enabled */
-		wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x00c0);
+		snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x00c0);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
 			/* VREF, VMID=2x5k */
-			wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x1c1);
+			snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1);
 
 			/* Charge caps */
 			msleep(100);
 		}
 
 		/* VREF, VMID=2*500k, digital stopped */
-		wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x0141);
+		snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x0141);
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		wm8988_write(codec, WM8988_PWR1, 0x0000);
+		snd_soc_write(codec, WM8988_PWR1, 0x0000);
 		break;
 	}
 	codec->bias_level = level;
@@ -868,7 +825,8 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988);
 
-static int wm8988_register(struct wm8988_priv *wm8988)
+static int wm8988_register(struct wm8988_priv *wm8988,
+			   enum snd_soc_control_type control)
 {
 	struct snd_soc_codec *codec = &wm8988->codec;
 	int ret;
@@ -887,8 +845,6 @@
 	codec->private_data = wm8988;
 	codec->name = "WM8988";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8988_read_reg_cache;
-	codec->write = wm8988_write;
 	codec->dai = &wm8988_dai;
 	codec->num_dai = 1;
 	codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache);
@@ -899,6 +855,12 @@
 	memcpy(codec->reg_cache, wm8988_reg,
 	       sizeof(wm8988_reg));
 
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
 	ret = wm8988_reset(codec);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to issue reset\n");
@@ -906,16 +868,16 @@
 	}
 
 	/* set the update bits (we always update left then right) */
-	reg = wm8988_read_reg_cache(codec, WM8988_RADC);
-	wm8988_write(codec, WM8988_RADC, reg | 0x100);
-	reg = wm8988_read_reg_cache(codec, WM8988_RDAC);
-	wm8988_write(codec, WM8988_RDAC, reg | 0x0100);
-	reg = wm8988_read_reg_cache(codec, WM8988_ROUT1V);
-	wm8988_write(codec, WM8988_ROUT1V, reg | 0x0100);
-	reg = wm8988_read_reg_cache(codec, WM8988_ROUT2V);
-	wm8988_write(codec, WM8988_ROUT2V, reg | 0x0100);
-	reg = wm8988_read_reg_cache(codec, WM8988_RINVOL);
-	wm8988_write(codec, WM8988_RINVOL, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8988_RADC);
+	snd_soc_write(codec, WM8988_RADC, reg | 0x100);
+	reg = snd_soc_read(codec, WM8988_RDAC);
+	snd_soc_write(codec, WM8988_RDAC, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8988_ROUT1V);
+	snd_soc_write(codec, WM8988_ROUT1V, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8988_ROUT2V);
+	snd_soc_write(codec, WM8988_ROUT2V, reg | 0x0100);
+	reg = snd_soc_read(codec, WM8988_RINVOL);
+	snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100);
 
 	wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY);
 
@@ -966,14 +928,13 @@
 		return -ENOMEM;
 
 	codec = &wm8988->codec;
-	codec->hw_write = (hw_write_t)i2c_master_send;
 
 	i2c_set_clientdata(i2c, wm8988);
 	codec->control_data = i2c;
 
 	codec->dev = &i2c->dev;
 
-	return wm8988_register(wm8988);
+	return wm8988_register(wm8988, SND_SOC_I2C);
 }
 
 static int wm8988_i2c_remove(struct i2c_client *client)
@@ -1018,30 +979,6 @@
 #endif
 
 #if defined(CONFIG_SPI_MASTER)
-static int wm8988_spi_write(struct spi_device *spi, const char *data, int len)
-{
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[2];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[0];
-	msg[1] = data[1];
-
-	spi_message_init(&m);
-	memset(&t, 0, (sizeof t));
-
-	t.tx_buf = &msg[0];
-	t.len = len;
-
-	spi_message_add_tail(&t, &m);
-	spi_sync(spi, &m);
-
-	return len;
-}
-
 static int __devinit wm8988_spi_probe(struct spi_device *spi)
 {
 	struct wm8988_priv *wm8988;
@@ -1052,13 +989,12 @@
 		return -ENOMEM;
 
 	codec = &wm8988->codec;
-	codec->hw_write = (hw_write_t)wm8988_spi_write;
 	codec->control_data = spi;
 	codec->dev = &spi->dev;
 
 	spi->dev.driver_data = wm8988;
 
-	return wm8988_register(wm8988);
+	return wm8988_register(wm8988, SND_SOC_SPI);
 }
 
 static int __devexit wm8988_spi_remove(struct spi_device *spi)
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index d029818..2d702db 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -108,53 +108,7 @@
 	0x0000,	    /* R63 - Driver internal */
 };
 
-/*
- * read wm8990 register cache
- */
-static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	BUG_ON(reg >= ARRAY_SIZE(wm8990_reg));
-	return cache[reg];
-}
-
-/*
- * write wm8990 register cache
- */
-static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-
-	/* Reset register and reserved registers are uncached */
-	if (reg == 0 || reg >= ARRAY_SIZE(wm8990_reg))
-		return;
-
-	cache[reg] = value;
-}
-
-/*
- * write to the wm8990 register space
- */
-static int wm8990_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	u8 data[3];
-
-	data[0] = reg & 0xFF;
-	data[1] = (value >> 8) & 0xFF;
-	data[2] = value & 0xFF;
-
-	wm8990_write_reg_cache(codec, reg, value);
-
-	if (codec->hw_write(codec->control_data, data, 3) == 2)
-		return 0;
-	else
-		return -EIO;
-}
-
-#define wm8990_reset(c) wm8990_write(c, WM8990_RESET, 0)
+#define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0)
 
 static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
 
@@ -187,8 +141,8 @@
 		return ret;
 
 	/* now hit the volume update bits (always bit 8) */
-	val = wm8990_read_reg_cache(codec, reg);
-	return wm8990_write(codec, reg, val | 0x0100);
+	val = snd_soc_read(codec, reg);
+	return snd_soc_write(codec, reg, val | 0x0100);
 }
 
 #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\
@@ -427,8 +381,8 @@
 {
 	u16 reg, fakepower;
 
-	reg = wm8990_read_reg_cache(w->codec, WM8990_POWER_MANAGEMENT_2);
-	fakepower = wm8990_read_reg_cache(w->codec, WM8990_INTDRIVBITS);
+	reg = snd_soc_read(w->codec, WM8990_POWER_MANAGEMENT_2);
+	fakepower = snd_soc_read(w->codec, WM8990_INTDRIVBITS);
 
 	if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) |
 		(1 << WM8990_AINLMUX_PWR_BIT))) {
@@ -443,7 +397,7 @@
 	} else {
 		reg &= ~WM8990_AINL_ENA;
 	}
-	wm8990_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg);
+	snd_soc_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg);
 
 	return 0;
 }
@@ -457,7 +411,7 @@
 
 	switch (reg_shift) {
 	case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) :
-		reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER1);
+		reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER1);
 		if (reg & WM8990_LDLO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 1 LDLO Set\n");
@@ -465,7 +419,7 @@
 		}
 		break;
 	case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8):
-		reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER2);
+		reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER2);
 		if (reg & WM8990_RDRO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 2 RDRO Set\n");
@@ -473,7 +427,7 @@
 		}
 		break;
 	case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8):
-		reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER);
+		reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER);
 		if (reg & WM8990_LDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer LDSPK Set\n");
@@ -481,7 +435,7 @@
 		}
 		break;
 	case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8):
-		reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER);
+		reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER);
 		if (reg & WM8990_RDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer RDSPK Set\n");
@@ -1029,24 +983,24 @@
 		pll_factors(&pll_div, freq_out * 4, freq_in);
 
 		/* Turn on PLL */
-		reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2);
+		reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2);
 		reg |= WM8990_PLL_ENA;
-		wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
+		snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
 
 		/* sysclk comes from PLL */
-		reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2);
-		wm8990_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC);
+		reg = snd_soc_read(codec, WM8990_CLOCKING_2);
+		snd_soc_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC);
 
 		/* set up N , fractional mode and pre-divisor if neccessary */
-		wm8990_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM |
+		snd_soc_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM |
 			(pll_div.div2?WM8990_PRESCALE:0));
-		wm8990_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8));
-		wm8990_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF));
+		snd_soc_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8));
+		snd_soc_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF));
 	} else {
 		/* Turn on PLL */
-		reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2);
+		reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2);
 		reg &= ~WM8990_PLL_ENA;
-		wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
+		snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
 	}
 	return 0;
 }
@@ -1073,8 +1027,8 @@
 	struct snd_soc_codec *codec = codec_dai->codec;
 	u16 audio1, audio3;
 
-	audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1);
-	audio3 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_3);
+	audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
+	audio3 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_3);
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1115,8 +1069,8 @@
 		return -EINVAL;
 	}
 
-	wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
-	wm8990_write(codec, WM8990_AUDIO_INTERFACE_3, audio3);
+	snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
+	snd_soc_write(codec, WM8990_AUDIO_INTERFACE_3, audio3);
 	return 0;
 }
 
@@ -1128,24 +1082,24 @@
 
 	switch (div_id) {
 	case WM8990_MCLK_DIV:
-		reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) &
+		reg = snd_soc_read(codec, WM8990_CLOCKING_2) &
 			~WM8990_MCLK_DIV_MASK;
-		wm8990_write(codec, WM8990_CLOCKING_2, reg | div);
+		snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
 		break;
 	case WM8990_DACCLK_DIV:
-		reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) &
+		reg = snd_soc_read(codec, WM8990_CLOCKING_2) &
 			~WM8990_DAC_CLKDIV_MASK;
-		wm8990_write(codec, WM8990_CLOCKING_2, reg | div);
+		snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
 		break;
 	case WM8990_ADCCLK_DIV:
-		reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) &
+		reg = snd_soc_read(codec, WM8990_CLOCKING_2) &
 			~WM8990_ADC_CLKDIV_MASK;
-		wm8990_write(codec, WM8990_CLOCKING_2, reg | div);
+		snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
 		break;
 	case WM8990_BCLK_DIV:
-		reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_1) &
+		reg = snd_soc_read(codec, WM8990_CLOCKING_1) &
 			~WM8990_BCLK_DIV_MASK;
-		wm8990_write(codec, WM8990_CLOCKING_1, reg | div);
+		snd_soc_write(codec, WM8990_CLOCKING_1, reg | div);
 		break;
 	default:
 		return -EINVAL;
@@ -1164,7 +1118,7 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
-	u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1);
+	u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
 
 	audio1 &= ~WM8990_AIF_WL_MASK;
 	/* bit size */
@@ -1182,7 +1136,7 @@
 		break;
 	}
 
-	wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
+	snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
 	return 0;
 }
 
@@ -1191,12 +1145,12 @@
 	struct snd_soc_codec *codec = dai->codec;
 	u16 val;
 
-	val  = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE;
+	val  = snd_soc_read(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE;
 
 	if (mute)
-		wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
+		snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
 	else
-		wm8990_write(codec, WM8990_DAC_CTRL, val);
+		snd_soc_write(codec, WM8990_DAC_CTRL, val);
 
 	return 0;
 }
@@ -1212,21 +1166,21 @@
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID=2*50k */
-		val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) &
+		val = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_1) &
 			~WM8990_VMID_MODE_MASK;
-		wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2);
+		snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
 			/* Enable all output discharge bits */
-			wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
+			snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
 				WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
 				WM8990_DIS_OUT4 | WM8990_DIS_LOUT |
 				WM8990_DIS_ROUT);
 
 			/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
-			wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+			snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
 				     WM8990_BUFDCOPEN | WM8990_POBCTRL |
 				     WM8990_VMIDTOG);
 
@@ -1234,83 +1188,83 @@
 			msleep(msecs_to_jiffies(300));
 
 			/* Disable VMIDTOG */
-			wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+			snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
 				     WM8990_BUFDCOPEN | WM8990_POBCTRL);
 
 			/* disable all output discharge bits */
-			wm8990_write(codec, WM8990_ANTIPOP1, 0);
+			snd_soc_write(codec, WM8990_ANTIPOP1, 0);
 
 			/* Enable outputs */
-			wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00);
+			snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00);
 
 			msleep(msecs_to_jiffies(50));
 
 			/* Enable VMID at 2x50k */
-			wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02);
+			snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02);
 
 			msleep(msecs_to_jiffies(100));
 
 			/* Enable VREF */
-			wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
+			snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
 
 			msleep(msecs_to_jiffies(600));
 
 			/* Enable BUFIOEN */
-			wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+			snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
 				     WM8990_BUFDCOPEN | WM8990_POBCTRL |
 				     WM8990_BUFIOEN);
 
 			/* Disable outputs */
-			wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3);
+			snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3);
 
 			/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-			wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN);
+			snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN);
 
 			/* Enable workaround for ADC clocking issue. */
-			wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0x2);
-			wm8990_write(codec, WM8990_EXT_CTL1, 0xa003);
-			wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0);
+			snd_soc_write(codec, WM8990_EXT_ACCESS_ENA, 0x2);
+			snd_soc_write(codec, WM8990_EXT_CTL1, 0xa003);
+			snd_soc_write(codec, WM8990_EXT_ACCESS_ENA, 0);
 		}
 
 		/* VMID=2*250k */
-		val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) &
+		val = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_1) &
 			~WM8990_VMID_MODE_MASK;
-		wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4);
+		snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Enable POBCTRL and SOFT_ST */
-		wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+		snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
 			WM8990_POBCTRL | WM8990_BUFIOEN);
 
 		/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
-		wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+		snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
 			WM8990_BUFDCOPEN | WM8990_POBCTRL |
 			WM8990_BUFIOEN);
 
 		/* mute DAC */
-		val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL);
-		wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
+		val = snd_soc_read(codec, WM8990_DAC_CTRL);
+		snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
 
 		/* Enable any disabled outputs */
-		wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
+		snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
 
 		/* Disable VMID */
-		wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01);
+		snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01);
 
 		msleep(msecs_to_jiffies(300));
 
 		/* Enable all output discharge bits */
-		wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
+		snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
 			WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
 			WM8990_DIS_OUT4 | WM8990_DIS_LOUT |
 			WM8990_DIS_ROUT);
 
 		/* Disable VREF */
-		wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0);
+		snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0);
 
 		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-		wm8990_write(codec, WM8990_ANTIPOP2, 0x0);
+		snd_soc_write(codec, WM8990_ANTIPOP2, 0x0);
 		break;
 	}
 
@@ -1411,8 +1365,6 @@
 
 	codec->name = "WM8990";
 	codec->owner = THIS_MODULE;
-	codec->read = wm8990_read_reg_cache;
-	codec->write = wm8990_write;
 	codec->set_bias_level = wm8990_set_bias_level;
 	codec->dai = &wm8990_dai;
 	codec->num_dai = 2;
@@ -1422,6 +1374,12 @@
 	if (codec->reg_cache == NULL)
 		return -ENOMEM;
 
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret);
+		goto pcm_err;
+	}
+
 	wm8990_reset(codec);
 
 	/* register pcms */
@@ -1435,18 +1393,18 @@
 	codec->bias_level = SND_SOC_BIAS_OFF;
 	wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-	reg = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_4);
-	wm8990_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1);
+	reg = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_4);
+	snd_soc_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1);
 
-	reg = wm8990_read_reg_cache(codec, WM8990_GPIO1_GPIO2) &
+	reg = snd_soc_read(codec, WM8990_GPIO1_GPIO2) &
 		~WM8990_GPIO1_SEL_MASK;
-	wm8990_write(codec, WM8990_GPIO1_GPIO2, reg | 1);
+	snd_soc_write(codec, WM8990_GPIO1_GPIO2, reg | 1);
 
-	reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2);
-	wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA);
+	reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2);
+	snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA);
 
-	wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
-	wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+	snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+	snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
 
 	snd_soc_add_controls(codec, wm8990_snd_controls,
 				ARRAY_SIZE(wm8990_snd_controls));
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index c965323..c147f2b 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -168,84 +168,19 @@
 	struct wm9081_retune_mobile_config *retune;
 };
 
-static int wm9081_reg_is_volatile(int reg)
+static int wm9081_volatile_register(unsigned int reg)
 {
 	switch (reg) {
+	case WM9081_SOFTWARE_RESET:
+		return 1;
 	default:
 		return 0;
 	}
 }
 
-static unsigned int wm9081_read_reg_cache(struct snd_soc_codec *codec,
-					  unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	BUG_ON(reg > WM9081_MAX_REGISTER);
-	return cache[reg];
-}
-
-static unsigned int wm9081_read_hw(struct snd_soc_codec *codec, u8 reg)
-{
-	struct i2c_msg xfer[2];
-	u16 data;
-	int ret;
-	struct i2c_client *client = codec->control_data;
-
-	BUG_ON(reg > WM9081_MAX_REGISTER);
-
-	/* Write register */
-	xfer[0].addr = client->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 1;
-	xfer[0].buf = &reg;
-
-	/* Read data */
-	xfer[1].addr = client->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 2;
-	xfer[1].buf = (u8 *)&data;
-
-	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret != 2) {
-		dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
-		return 0;
-	}
-
-	return (data >> 8) | ((data & 0xff) << 8);
-}
-
-static unsigned int wm9081_read(struct snd_soc_codec *codec, unsigned int reg)
-{
-	if (wm9081_reg_is_volatile(reg))
-		return wm9081_read_hw(codec, reg);
-	else
-		return wm9081_read_reg_cache(codec, reg);
-}
-
-static int wm9081_write(struct snd_soc_codec *codec, unsigned int reg,
-			unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-	u8 data[3];
-
-	BUG_ON(reg > WM9081_MAX_REGISTER);
-
-	if (!wm9081_reg_is_volatile(reg))
-		cache[reg] = value;
-
-	data[0] = reg;
-	data[1] = value >> 8;
-	data[2] = value & 0x00ff;
-
-	if (codec->hw_write(codec->control_data, data, 3) == 3)
-		return 0;
-	else
-		return -EIO;
-}
-
 static int wm9081_reset(struct snd_soc_codec *codec)
 {
-	return wm9081_write(codec, WM9081_SOFTWARE_RESET, 0);
+	return snd_soc_write(codec, WM9081_SOFTWARE_RESET, 0);
 }
 
 static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0);
@@ -356,7 +291,7 @@
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 	unsigned int reg;
 
-	reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2);
+	reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2);
 	if (reg & WM9081_SPK_MODE)
 		ucontrol->value.integer.value[0] = 1;
 	else
@@ -375,8 +310,8 @@
 			    struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	unsigned int reg_pwr = wm9081_read(codec, WM9081_POWER_MANAGEMENT);
-	unsigned int reg2 = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2);
+	unsigned int reg_pwr = snd_soc_read(codec, WM9081_POWER_MANAGEMENT);
+	unsigned int reg2 = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2);
 
 	/* Are we changing anything? */
 	if (ucontrol->value.integer.value[0] ==
@@ -397,7 +332,7 @@
 		reg2 &= ~WM9081_SPK_MODE;
 	}
 
-	wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2);
+	snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2);
 
 	return 0;
 }
@@ -456,7 +391,7 @@
 			 struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	unsigned int reg = wm9081_read(codec, WM9081_POWER_MANAGEMENT);
+	unsigned int reg = snd_soc_read(codec, WM9081_POWER_MANAGEMENT);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -468,7 +403,7 @@
 		break;
 	}
 
-	wm9081_write(codec, WM9081_POWER_MANAGEMENT, reg);
+	snd_soc_write(codec, WM9081_POWER_MANAGEMENT, reg);
 
 	return 0;
 }
@@ -607,7 +542,7 @@
 	if (ret != 0)
 		return ret;
 
-	reg5 = wm9081_read(codec, WM9081_FLL_CONTROL_5);
+	reg5 = snd_soc_read(codec, WM9081_FLL_CONTROL_5);
 	reg5 &= ~WM9081_FLL_CLK_SRC_MASK;
 
 	switch (fll_id) {
@@ -621,44 +556,44 @@
 	}
 
 	/* Disable CLK_SYS while we reconfigure */
-	clk_sys_reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3);
+	clk_sys_reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_3);
 	if (clk_sys_reg & WM9081_CLK_SYS_ENA)
-		wm9081_write(codec, WM9081_CLOCK_CONTROL_3,
+		snd_soc_write(codec, WM9081_CLOCK_CONTROL_3,
 			     clk_sys_reg & ~WM9081_CLK_SYS_ENA);
 
 	/* Any FLL configuration change requires that the FLL be
 	 * disabled first. */
-	reg1 = wm9081_read(codec, WM9081_FLL_CONTROL_1);
+	reg1 = snd_soc_read(codec, WM9081_FLL_CONTROL_1);
 	reg1 &= ~WM9081_FLL_ENA;
-	wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1);
+	snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1);
 
 	/* Apply the configuration */
 	if (fll_div.k)
 		reg1 |= WM9081_FLL_FRAC_MASK;
 	else
 		reg1 &= ~WM9081_FLL_FRAC_MASK;
-	wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1);
+	snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1);
 
-	wm9081_write(codec, WM9081_FLL_CONTROL_2,
+	snd_soc_write(codec, WM9081_FLL_CONTROL_2,
 		     (fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) |
 		     (fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT));
-	wm9081_write(codec, WM9081_FLL_CONTROL_3, fll_div.k);
+	snd_soc_write(codec, WM9081_FLL_CONTROL_3, fll_div.k);
 
-	reg4 = wm9081_read(codec, WM9081_FLL_CONTROL_4);
+	reg4 = snd_soc_read(codec, WM9081_FLL_CONTROL_4);
 	reg4 &= ~WM9081_FLL_N_MASK;
 	reg4 |= fll_div.n << WM9081_FLL_N_SHIFT;
-	wm9081_write(codec, WM9081_FLL_CONTROL_4, reg4);
+	snd_soc_write(codec, WM9081_FLL_CONTROL_4, reg4);
 
 	reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK;
 	reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT;
-	wm9081_write(codec, WM9081_FLL_CONTROL_5, reg5);
+	snd_soc_write(codec, WM9081_FLL_CONTROL_5, reg5);
 
 	/* Enable the FLL */
-	wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA);
+	snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA);
 
 	/* Then bring CLK_SYS up again if it was disabled */
 	if (clk_sys_reg & WM9081_CLK_SYS_ENA)
-		wm9081_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg);
+		snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg);
 
 	dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
 
@@ -742,19 +677,19 @@
 		return -EINVAL;
 	}
 
-	reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_1);
+	reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_1);
 	if (mclkdiv)
 		reg |= WM9081_MCLKDIV2;
 	else
 		reg &= ~WM9081_MCLKDIV2;
-	wm9081_write(codec, WM9081_CLOCK_CONTROL_1, reg);
+	snd_soc_write(codec, WM9081_CLOCK_CONTROL_1, reg);
 
-	reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3);
+	reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_3);
 	if (fll)
 		reg |= WM9081_CLK_SRC_SEL;
 	else
 		reg &= ~WM9081_CLK_SRC_SEL;
-	wm9081_write(codec, WM9081_CLOCK_CONTROL_3, reg);
+	snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, reg);
 
 	dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate);
 
@@ -854,76 +789,76 @@
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID=2*40k */
-		reg = wm9081_read(codec, WM9081_VMID_CONTROL);
+		reg = snd_soc_read(codec, WM9081_VMID_CONTROL);
 		reg &= ~WM9081_VMID_SEL_MASK;
 		reg |= 0x2;
-		wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+		snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
 
 		/* Normal bias current */
-		reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+		reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
 		reg &= ~WM9081_STBY_BIAS_ENA;
-		wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+		snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
 		/* Initial cold start */
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
 			/* Disable LINEOUT discharge */
-			reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL);
+			reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL);
 			reg &= ~WM9081_LINEOUT_DISCH;
-			wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg);
+			snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg);
 
 			/* Select startup bias source */
-			reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+			reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
 			reg |= WM9081_BIAS_SRC | WM9081_BIAS_ENA;
-			wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+			snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
 
 			/* VMID 2*4k; Soft VMID ramp enable */
-			reg = wm9081_read(codec, WM9081_VMID_CONTROL);
+			reg = snd_soc_read(codec, WM9081_VMID_CONTROL);
 			reg |= WM9081_VMID_RAMP | 0x6;
-			wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+			snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
 
 			mdelay(100);
 
 			/* Normal bias enable & soft start off */
 			reg |= WM9081_BIAS_ENA;
 			reg &= ~WM9081_VMID_RAMP;
-			wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+			snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
 
 			/* Standard bias source */
-			reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+			reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
 			reg &= ~WM9081_BIAS_SRC;
-			wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+			snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
 		}
 
 		/* VMID 2*240k */
-		reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+		reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
 		reg &= ~WM9081_VMID_SEL_MASK;
 		reg |= 0x40;
-		wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+		snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
 
 		/* Standby bias current on */
-		reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+		reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
 		reg |= WM9081_STBY_BIAS_ENA;
-		wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+		snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Startup bias source */
-		reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+		reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
 		reg |= WM9081_BIAS_SRC;
-		wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+		snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
 
 		/* Disable VMID and biases with soft ramping */
-		reg = wm9081_read(codec, WM9081_VMID_CONTROL);
+		reg = snd_soc_read(codec, WM9081_VMID_CONTROL);
 		reg &= ~(WM9081_VMID_SEL_MASK | WM9081_BIAS_ENA);
 		reg |= WM9081_VMID_RAMP;
-		wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+		snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
 
 		/* Actively discharge LINEOUT */
-		reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL);
+		reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL);
 		reg |= WM9081_LINEOUT_DISCH;
-		wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg);
+		snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg);
 		break;
 	}
 
@@ -937,7 +872,7 @@
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct wm9081_priv *wm9081 = codec->private_data;
-	unsigned int aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2);
+	unsigned int aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2);
 
 	aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV |
 		  WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK);
@@ -1018,7 +953,7 @@
 		return -EINVAL;
 	}
 
-	wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);
+	snd_soc_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);
 
 	return 0;
 }
@@ -1032,18 +967,18 @@
 	int ret, i, best, best_val, cur_val;
 	unsigned int clk_ctrl2, aif1, aif2, aif3, aif4;
 
-	clk_ctrl2 = wm9081_read(codec, WM9081_CLOCK_CONTROL_2);
+	clk_ctrl2 = snd_soc_read(codec, WM9081_CLOCK_CONTROL_2);
 	clk_ctrl2 &= ~(WM9081_CLK_SYS_RATE_MASK | WM9081_SAMPLE_RATE_MASK);
 
-	aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1);
+	aif1 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_1);
 
-	aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2);
+	aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2);
 	aif2 &= ~WM9081_AIF_WL_MASK;
 
-	aif3 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_3);
+	aif3 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_3);
 	aif3 &= ~WM9081_BCLK_DIV_MASK;
 
-	aif4 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_4);
+	aif4 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_4);
 	aif4 &= ~WM9081_LRCLK_RATE_MASK;
 
 	/* What BCLK do we need? */
@@ -1157,22 +1092,22 @@
 			s->name, s->rate);
 
 		/* If the EQ is enabled then disable it while we write out */
-		eq1 = wm9081_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA;
+		eq1 = snd_soc_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA;
 		if (eq1 & WM9081_EQ_ENA)
-			wm9081_write(codec, WM9081_EQ_1, 0);
+			snd_soc_write(codec, WM9081_EQ_1, 0);
 
 		/* Write out the other values */
 		for (i = 1; i < ARRAY_SIZE(s->config); i++)
-			wm9081_write(codec, WM9081_EQ_1 + i, s->config[i]);
+			snd_soc_write(codec, WM9081_EQ_1 + i, s->config[i]);
 
 		eq1 |= (s->config[0] & ~WM9081_EQ_ENA);
-		wm9081_write(codec, WM9081_EQ_1, eq1);
+		snd_soc_write(codec, WM9081_EQ_1, eq1);
 	}
 
-	wm9081_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2);
-	wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);
-	wm9081_write(codec, WM9081_AUDIO_INTERFACE_3, aif3);
-	wm9081_write(codec, WM9081_AUDIO_INTERFACE_4, aif4);
+	snd_soc_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2);
+	snd_soc_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);
+	snd_soc_write(codec, WM9081_AUDIO_INTERFACE_3, aif3);
+	snd_soc_write(codec, WM9081_AUDIO_INTERFACE_4, aif4);
 
 	return 0;
 }
@@ -1182,14 +1117,14 @@
 	struct snd_soc_codec *codec = codec_dai->codec;
 	unsigned int reg;
 
-	reg = wm9081_read(codec, WM9081_DAC_DIGITAL_2);
+	reg = snd_soc_read(codec, WM9081_DAC_DIGITAL_2);
 
 	if (mute)
 		reg |= WM9081_DAC_MUTE;
 	else
 		reg &= ~WM9081_DAC_MUTE;
 
-	wm9081_write(codec, WM9081_DAC_DIGITAL_2, reg);
+	snd_soc_write(codec, WM9081_DAC_DIGITAL_2, reg);
 
 	return 0;
 }
@@ -1219,7 +1154,7 @@
 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1);
+	unsigned int aif1 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_1);
 
 	aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK);
 
@@ -1244,7 +1179,7 @@
 		return -EINVAL;
 	}
 
-	wm9081_write(codec, WM9081_AUDIO_INTERFACE_1, aif1);
+	snd_soc_write(codec, WM9081_AUDIO_INTERFACE_1, aif1);
 
 	return 0;
 }
@@ -1366,7 +1301,7 @@
 		if (i == WM9081_SOFTWARE_RESET)
 			continue;
 
-		wm9081_write(codec, i, reg_cache[i]);
+		snd_soc_write(codec, i, reg_cache[i]);
 	}
 
 	wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1386,7 +1321,8 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081);
 
-static int wm9081_register(struct wm9081_priv *wm9081)
+static int wm9081_register(struct wm9081_priv *wm9081,
+			   enum snd_soc_control_type control)
 {
 	struct snd_soc_codec *codec = &wm9081->codec;
 	int ret;
@@ -1405,19 +1341,24 @@
 	codec->private_data = wm9081;
 	codec->name = "WM9081";
 	codec->owner = THIS_MODULE;
-	codec->read = wm9081_read;
-	codec->write = wm9081_write;
 	codec->dai = &wm9081_dai;
 	codec->num_dai = 1;
 	codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache);
 	codec->reg_cache = &wm9081->reg_cache;
 	codec->bias_level = SND_SOC_BIAS_OFF;
 	codec->set_bias_level = wm9081_set_bias_level;
+	codec->volatile_register = wm9081_volatile_register;
 
 	memcpy(codec->reg_cache, wm9081_reg_defaults,
 	       sizeof(wm9081_reg_defaults));
 
-	reg = wm9081_read_hw(codec, WM9081_SOFTWARE_RESET);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
 	if (reg != 0x9081) {
 		dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
 		ret = -EINVAL;
@@ -1433,10 +1374,10 @@
 	wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	/* Enable zero cross by default */
-	reg = wm9081_read(codec, WM9081_ANALOGUE_LINEOUT);
-	wm9081_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
-	reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
-	wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
+	reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT);
+	snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
+	reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
+	snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
 		     reg | WM9081_SPKPGAZC);
 
 	wm9081_dai.dev = codec->dev;
@@ -1491,7 +1432,7 @@
 
 	codec->dev = &i2c->dev;
 
-	return wm9081_register(wm9081);
+	return wm9081_register(wm9081, SND_SOC_I2C);
 }
 
 static __devexit int wm9081_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index 6802dd5..677a538 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -41,3 +41,14 @@
 	help
 	  Say Y if you want to add support for SoC audio on
 	  Lyrtech SFFSDR board.
+
+config  SND_DA830_SOC_EVM
+	tristate "SoC Audio support for DA830/OMAPL137 EVM"
+	depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM
+	select SND_DAVINCI_SOC_MCASP
+	select SND_SOC_TLV320AIC3X
+
+	help
+	  Say Y if you want to add support for SoC audio on TI
+	  DA830/OMAPL137 EVM
+
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile
index 67be54f..5e2195f 100644
--- a/sound/soc/davinci/Makefile
+++ b/sound/soc/davinci/Makefile
@@ -13,4 +13,5 @@
 
 obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o
 obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o
+obj-$(CONFIG_SND_DA830_SOC_EVM) += snd-soc-evm.o
 obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index f3bb6f6..a5a9212 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -54,6 +54,9 @@
 	else if (machine_is_davinci_evm())
 		sysclk = 12288000;
 
+	else if (machine_is_davinci_da830_evm())
+		sysclk = 24576000;
+
 	else
 		return -EINVAL;
 
@@ -162,6 +165,14 @@
 		.ops = &evm_ops,
 	},
 };
+static struct snd_soc_dai_link da830_evm_dai = {
+	.name = "TLV320AIC3X",
+	.stream_name = "AIC3X",
+	.cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI],
+	.codec_dai = &aic3x_dai,
+	.init = evm_aic3x_init,
+	.ops = &evm_ops,
+};
 
 /* davinci-evm audio machine driver */
 static struct snd_soc_card snd_soc_card_evm = {
@@ -179,6 +190,13 @@
 	.num_links = ARRAY_SIZE(dm6467_evm_dai),
 };
 
+static struct snd_soc_card da830_snd_soc_card = {
+	.name = "DA830 EVM",
+	.dai_link = &da830_evm_dai,
+	.platform = &davinci_soc_platform,
+	.num_links = 1,
+};
+
 /* evm audio private data */
 static struct aic3x_setup_data evm_aic3x_setup = {
 	.i2c_bus = 1,
@@ -191,6 +209,11 @@
        .i2c_address = 0x18,
 };
 
+static struct aic3x_setup_data da830_evm_aic3x_setup = {
+	.i2c_bus = 1,
+	.i2c_address = 0x18,
+};
+
 /* evm audio subsystem */
 static struct snd_soc_device evm_snd_devdata = {
 	.card = &snd_soc_card_evm,
@@ -205,6 +228,13 @@
 	.codec_data = &dm6467_evm_aic3x_setup,
 };
 
+/* evm audio subsystem */
+static struct snd_soc_device da830_evm_snd_devdata = {
+	.card = &da830_snd_soc_card,
+	.codec_dev = &soc_codec_dev_aic3x,
+	.codec_data = &da830_evm_aic3x_setup,
+};
+
 static struct platform_device *evm_snd_device;
 
 static int __init evm_init(void)
@@ -222,6 +252,9 @@
 	} else if (machine_is_davinci_dm6467_evm()) {
 		evm_snd_dev_data = &dm6467_evm_snd_devdata;
 		index = 0;
+	} else if (machine_is_davinci_da830_evm()) {
+		evm_snd_dev_data = &da830_evm_snd_devdata;
+		index = 1;
 	} else
 		return -EINVAL;
 
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index e5cd97b..2a56fb7 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -353,9 +353,8 @@
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
-	struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+	struct davinci_pcm_dma_params *dma_params = dai->dma_data;
+	struct davinci_mcbsp_dev *dev = dai->private_data;
 	struct snd_interval *i = NULL;
 	int mcbsp_word_length;
 	unsigned int rcr, xcr, srgr;
@@ -425,8 +424,7 @@
 static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+	struct davinci_mcbsp_dev *dev = dai->private_data;
 	int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 	davinci_mcbsp_stop(dev, playback);
 	if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) {
@@ -439,8 +437,7 @@
 static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 			       struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+	struct davinci_mcbsp_dev *dev = dai->private_data;
 	int ret = 0;
 	int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 	if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0)
@@ -466,8 +463,7 @@
 static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+	struct davinci_mcbsp_dev *dev = dai->private_data;
 	int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 	davinci_mcbsp_stop(dev, playback);
 }
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 8fd0c3c..ab43a53 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -244,6 +244,11 @@
 	int ret = 0;
 
 	snd_soc_set_runtime_hwparams(substream, &davinci_pcm_hardware);
+	/* ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+						SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		return ret;
 
 	prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL);
 	if (prtd == NULL)
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 4f35b1f..5a5166a 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -500,7 +500,7 @@
 	}
 
 	/* Register optional line discipline for over the modem control */
-	ret = tty_register_ldisc(N_AMSDELTA, &cx81801_ops);
+	ret = tty_register_ldisc(N_V253, &cx81801_ops);
 	if (ret) {
 		dev_warn(card->dev,
 				"Failed to register line discipline, "
@@ -625,9 +625,9 @@
 		}
 	}
 
-	if (tty_unregister_ldisc(N_AMSDELTA) != 0)
+	if (tty_unregister_ldisc(N_V253) != 0)
 		dev_warn(&ams_delta_audio_platform_device->dev,
-			"failed to unregister AMSDELTA line discipline\n");
+			"failed to unregister V253 line discipline\n");
 
 	snd_soc_jack_free_gpios(&ams_delta_hook_switch,
 			ARRAY_SIZE(ams_delta_hook_switch_gpios),
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index a5d46a7..6a837ff 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -183,21 +183,21 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 	struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
-	int err = 0;
+	int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (!mcbsp_data->active++)
-			omap_mcbsp_start(mcbsp_data->bus_id);
+		mcbsp_data->active++;
+		omap_mcbsp_start(mcbsp_data->bus_id, play, !play);
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (!--mcbsp_data->active)
-			omap_mcbsp_stop(mcbsp_data->bus_id);
+		omap_mcbsp_stop(mcbsp_data->bus_id, play, !play);
+		mcbsp_data->active--;
 		break;
 	default:
 		err = -EINVAL;
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
index 3f03d5d..bf16f20 100644
--- a/sound/soc/s3c24xx/s3c2443-ac97.c
+++ b/sound/soc/s3c24xx/s3c2443-ac97.c
@@ -47,7 +47,7 @@
 
 static DECLARE_COMPLETION(ac97_completion);
 static u32 codec_ready;
-static DECLARE_MUTEX(ac97_mutex);
+static DEFINE_MUTEX(ac97_mutex);
 
 static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97,
 	unsigned short reg)
@@ -56,7 +56,7 @@
 	u32 ac_codec_cmd;
 	u32 stat, addr, data;
 
-	down(&ac97_mutex);
+	mutex_lock(&ac97_mutex);
 
 	codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
 	ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
@@ -79,7 +79,7 @@
 		printk(KERN_ERR "s3c24xx-ac97: req addr = %02x,"
 				" rep addr = %02x\n", reg, addr);
 
-	up(&ac97_mutex);
+	mutex_unlock(&ac97_mutex);
 
 	return (unsigned short)data;
 }
@@ -90,7 +90,7 @@
 	u32 ac_glbctrl;
 	u32 ac_codec_cmd;
 
-	down(&ac97_mutex);
+	mutex_lock(&ac97_mutex);
 
 	codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
 	ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
@@ -109,7 +109,7 @@
 	ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
 	writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
 
-	up(&ac97_mutex);
+	mutex_unlock(&ac97_mutex);
 
 }
 
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
new file mode 100644
index 0000000..c8ceddc
--- /dev/null
+++ b/sound/soc/soc-cache.c
@@ -0,0 +1,218 @@
+/*
+ * soc-cache.c  --  ASoC register cache helpers
+ *
+ * Copyright 2009 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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
+				     unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg >= codec->reg_cache_size)
+		return -1;
+	return cache[reg];
+}
+
+static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
+			     unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	u8 data[2];
+	int ret;
+
+	BUG_ON(codec->volatile_register);
+
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	if (reg < codec->reg_cache_size)
+		cache[reg] = value;
+	ret = codec->hw_write(codec->control_data, data, 2);
+	if (ret == 2)
+		return 0;
+	if (ret < 0)
+		return ret;
+	else
+		return -EIO;
+}
+
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_7_9_spi_write(void *control_data, const char *data,
+				 int len)
+{
+	struct spi_device *spi = control_data;
+	struct spi_transfer t;
+	struct spi_message m;
+	u8 msg[2];
+
+	if (len <= 0)
+		return 0;
+
+	msg[0] = data[0];
+	msg[1] = data[1];
+
+	spi_message_init(&m);
+	memset(&t, 0, (sizeof t));
+
+	t.tx_buf = &msg[0];
+	t.len = len;
+
+	spi_message_add_tail(&t, &m);
+	spi_sync(spi, &m);
+
+	return len;
+}
+#else
+#define snd_soc_7_9_spi_write NULL
+#endif
+
+static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
+			      unsigned int value)
+{
+	u16 *reg_cache = codec->reg_cache;
+	u8 data[3];
+
+	data[0] = reg;
+	data[1] = (value >> 8) & 0xff;
+	data[2] = value & 0xff;
+
+	if (!snd_soc_codec_volatile_register(codec, reg))
+		reg_cache[reg] = value;
+
+	if (codec->hw_write(codec->control_data, data, 3) == 3)
+		return 0;
+	else
+		return -EIO;
+}
+
+static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
+				      unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+
+	if (reg >= codec->reg_cache_size ||
+	    snd_soc_codec_volatile_register(codec, reg))
+		return codec->hw_read(codec, reg);
+	else
+		return cache[reg];
+}
+
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
+					  unsigned int r)
+{
+	struct i2c_msg xfer[2];
+	u8 reg = r;
+	u16 data;
+	int ret;
+	struct i2c_client *client = codec->control_data;
+
+	/* Write register */
+	xfer[0].addr = client->addr;
+	xfer[0].flags = 0;
+	xfer[0].len = 1;
+	xfer[0].buf = &reg;
+
+	/* Read data */
+	xfer[1].addr = client->addr;
+	xfer[1].flags = I2C_M_RD;
+	xfer[1].len = 2;
+	xfer[1].buf = (u8 *)&data;
+
+	ret = i2c_transfer(client->adapter, xfer, 2);
+	if (ret != 2) {
+		dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+		return 0;
+	}
+
+	return (data >> 8) | ((data & 0xff) << 8);
+}
+#else
+#define snd_soc_8_16_read_i2c NULL
+#endif
+
+static struct {
+	int addr_bits;
+	int data_bits;
+	int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
+	int (*spi_write)(void *, const char *, int);
+	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+	unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
+} io_types[] = {
+	{ 7, 9, snd_soc_7_9_write, snd_soc_7_9_spi_write, snd_soc_7_9_read },
+	{ 8, 16, snd_soc_8_16_write, NULL, snd_soc_8_16_read,
+	  snd_soc_8_16_read_i2c },
+};
+
+/**
+ * snd_soc_codec_set_cache_io: Set up standard I/O functions.
+ *
+ * @codec: CODEC to configure.
+ * @type: Type of cache.
+ * @addr_bits: Number of bits of register address data.
+ * @data_bits: Number of bits of data per register.
+ * @control: Control bus used.
+ *
+ * Register formats are frequently shared between many I2C and SPI
+ * devices.  In order to promote code reuse the ASoC core provides
+ * some standard implementations of CODEC read and write operations
+ * which can be set up using this function.
+ *
+ * The caller is responsible for allocating and initialising the
+ * actual cache.
+ *
+ * Note that at present this code cannot be used by CODECs with
+ * volatile registers.
+ */
+int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
+			       int addr_bits, int data_bits,
+			       enum snd_soc_control_type control)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(io_types); i++)
+		if (io_types[i].addr_bits == addr_bits &&
+		    io_types[i].data_bits == data_bits)
+			break;
+	if (i == ARRAY_SIZE(io_types)) {
+		printk(KERN_ERR
+		       "No I/O functions for %d bit address %d bit data\n",
+		       addr_bits, data_bits);
+		return -EINVAL;
+	}
+
+	codec->write = io_types[i].write;
+	codec->read = io_types[i].read;
+
+	switch (control) {
+	case SND_SOC_CUSTOM:
+		break;
+
+	case SND_SOC_I2C:
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+		codec->hw_write = (hw_write_t)i2c_master_send;
+#endif
+		if (io_types[i].i2c_read)
+			codec->hw_read = io_types[i].i2c_read;
+		break;
+
+	case SND_SOC_SPI:
+		if (io_types[i].spi_write)
+			codec->hw_write = io_types[i].spi_write;
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);