Merge commit 'v2.6.34-rc1' into for-2.6.35
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 061f16d..6cf76a4 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -182,6 +182,12 @@
 		struct snd_soc_dai *);
 	int (*trigger)(struct snd_pcm_substream *, int,
 		struct snd_soc_dai *);
+	/*
+	 * For hardware based FIFO caused delay reporting.
+	 * Optional.
+	 */
+	snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
+		struct snd_soc_dai *);
 };
 
 /*
@@ -215,7 +221,6 @@
 	unsigned int symmetric_rates:1;
 
 	/* DAI runtime info */
-	struct snd_pcm_runtime *runtime;
 	struct snd_soc_codec *codec;
 	unsigned int active;
 	unsigned char pop_wait:1;
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index c0922a0..2c8eb0a 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -427,7 +427,6 @@
 	unsigned char ext:1;			/* has external widgets */
 	unsigned char muted:1;			/* muted for pop reduction */
 	unsigned char suspend:1;		/* was active before suspend */
-	unsigned char pmdown:1;			/* waiting for timeout */
 
 	int (*power_check)(struct snd_soc_dapm_widget *w);
 
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 5d234a8..dbfec16 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -212,6 +212,7 @@
 struct snd_soc_pcm_runtime;
 struct snd_soc_dai;
 struct snd_soc_platform;
+struct snd_soc_dai_link;
 struct snd_soc_codec;
 struct soc_enum;
 struct snd_soc_ac97_ops;
@@ -374,7 +375,7 @@
 	unsigned int rate_max;		/* max rate */
 	unsigned int channels_min;	/* min channels */
 	unsigned int channels_max;	/* max channels */
-	unsigned int active:1;		/* stream is in use */
+	unsigned int active;		/* num of active users of the stream */
 };
 
 /* SoC audio ops */
@@ -461,14 +462,21 @@
 
 	int (*probe)(struct platform_device *pdev);
 	int (*remove)(struct platform_device *pdev);
-	int (*suspend)(struct snd_soc_dai *dai);
-	int (*resume)(struct snd_soc_dai *dai);
+	int (*suspend)(struct snd_soc_dai_link *dai_link);
+	int (*resume)(struct snd_soc_dai_link *dai_link);
 
 	/* pcm creation and destruction */
 	int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
 		struct snd_pcm *);
 	void (*pcm_free)(struct snd_pcm *);
 
+	/*
+	 * For platform caused delay reporting.
+	 * Optional.
+	 */
+	snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
+		struct snd_soc_dai *);
+
 	/* platform stream ops */
 	struct snd_pcm_ops *pcm_ops;
 };
diff --git a/include/sound/wm8960.h b/include/sound/wm8960.h
new file mode 100644
index 0000000..74e9a95
--- /dev/null
+++ b/include/sound/wm8960.h
@@ -0,0 +1,24 @@
+/*
+ * wm8960.h  --  WM8960 Soc Audio driver platform data
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8960_PDATA_H
+#define _WM8960_PDATA_H
+
+#define WM8960_DRES_400R 0
+#define WM8960_DRES_200R 1
+#define WM8960_DRES_600R 2
+#define WM8960_DRES_150R 3
+#define WM8960_DRES_MAX  3
+
+struct wm8960_data {
+	bool capless;  /* Headphone outputs configured in capless mode */
+
+	int dres;  /* Discharge resistance for headphone outputs */
+};
+
+#endif
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index 9ef6b96..fdb2553 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -415,9 +415,12 @@
 }
 
 #ifdef CONFIG_PM
-static int atmel_pcm_suspend(struct snd_soc_dai *dai)
+static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
 {
-	struct snd_pcm_runtime *runtime = dai->runtime;
+	struct snd_pcm *pcm = dai_link->pcm;
+	struct snd_pcm_str *stream = &pcm->streams[0];
+	struct snd_pcm_substream *substream = stream->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct atmel_runtime_data *prtd;
 	struct atmel_pcm_dma_params *params;
 
@@ -439,9 +442,12 @@
 	return 0;
 }
 
-static int atmel_pcm_resume(struct snd_soc_dai *dai)
+static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
 {
-	struct snd_pcm_runtime *runtime = dai->runtime;
+	struct snd_pcm *pcm = dai_link->pcm;
+	struct snd_pcm_str *stream = &pcm->streams[0];
+	struct snd_pcm_substream *substream = stream->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct atmel_runtime_data *prtd;
 	struct atmel_pcm_dma_params *params;
 
diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h
index 2e63dea..a86e8cc 100644
--- a/sound/soc/blackfin/bf5xx-sport.h
+++ b/sound/soc/blackfin/bf5xx-sport.h
@@ -34,33 +34,7 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <asm/dma.h>
-
-struct sport_register {
-	u16 tcr1;	u16 reserved0;
-	u16 tcr2;	u16 reserved1;
-	u16 tclkdiv;	u16 reserved2;
-	u16 tfsdiv;	u16 reserved3;
-	u32 tx;
-	u32 reserved_l0;
-	u32 rx;
-	u32 reserved_l1;
-	u16 rcr1;	u16 reserved4;
-	u16 rcr2;	u16 reserved5;
-	u16 rclkdiv;	u16 reserved6;
-	u16 rfsdiv;	u16 reserved7;
-	u16 stat;	u16 reserved8;
-	u16 chnl;	u16 reserved9;
-	u16 mcmc1;	u16 reserved10;
-	u16 mcmc2;	u16 reserved11;
-	u32 mtcs0;
-	u32 mtcs1;
-	u32 mtcs2;
-	u32 mtcs3;
-	u32 mrcs0;
-	u32 mrcs1;
-	u32 mrcs2;
-	u32 mrcs3;
-};
+#include <asm/bfin_sport.h>
 
 #define DESC_ELEMENT_COUNT 9
 
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index cf2975a..3bd867d 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -74,15 +74,14 @@
 /* INMIX_R bit fields */
 #define DA7210_IN_R_EN			(1 << 7)
 
-/* ADC_HPF bit fields */
-#define DA7210_ADC_VOICE_EN		(1 << 7)
-
 /* ADC bit fields */
 #define DA7210_ADC_L_EN			(1 << 3)
 #define DA7210_ADC_R_EN			(1 << 7)
 
-/* DAC_HPF fields */
-#define DA7210_DAC_VOICE_EN		(1 << 7)
+/* DAC/ADC HPF fields */
+#define DA7210_VOICE_F0_MASK		(0x7 << 4)
+#define DA7210_VOICE_F0_25		(1 << 4)
+#define DA7210_VOICE_EN			(1 << 7)
 
 /* DAC_SEL bit fields */
 #define DA7210_DAC_L_SRC_DAI_L		(4 << 0)
@@ -123,7 +122,15 @@
 #define DA7210_PLL_BYP			(1 << 6)
 
 /* PLL bit fields */
-#define DA7210_PLL_FS_48000		(11 << 0)
+#define DA7210_PLL_FS_MASK		(0xF << 0)
+#define DA7210_PLL_FS_8000		(0x1 << 0)
+#define DA7210_PLL_FS_12000		(0x3 << 0)
+#define DA7210_PLL_FS_16000		(0x5 << 0)
+#define DA7210_PLL_FS_24000		(0x7 << 0)
+#define DA7210_PLL_FS_32000		(0x9 << 0)
+#define DA7210_PLL_FS_48000		(0xB << 0)
+#define DA7210_PLL_FS_96000		(0xF << 0)
+
 
 #define DA7210_VERSION "0.0.1"
 
@@ -241,7 +248,8 @@
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
 	u32 dai_cfg1;
-	u32 reg, mask;
+	u32 hpf_reg, hpf_mask, hpf_value;
+	u32 fs;
 
 	/* set DAI source to Left and Right ADC */
 	da7210_write(codec, DA7210_DAI_SRC_SEL,
@@ -265,25 +273,46 @@
 
 	da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1);
 
-	/* FIXME
-	 *
-	 * It support 48K only now
-	 */
+	hpf_reg = (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) ?
+		DA7210_DAC_HPF : DA7210_ADC_HPF;
+
 	switch (params_rate(params)) {
+	case 8000:
+		fs		= DA7210_PLL_FS_8000;
+		hpf_mask	= DA7210_VOICE_F0_MASK	| DA7210_VOICE_EN;
+		hpf_value	= DA7210_VOICE_F0_25	| DA7210_VOICE_EN;
+		break;
+	case 12000:
+		fs		= DA7210_PLL_FS_12000;
+		hpf_mask	= DA7210_VOICE_F0_MASK	| DA7210_VOICE_EN;
+		hpf_value	= DA7210_VOICE_F0_25	| DA7210_VOICE_EN;
+		break;
+	case 16000:
+		fs		= DA7210_PLL_FS_16000;
+		hpf_mask	= DA7210_VOICE_F0_MASK	| DA7210_VOICE_EN;
+		hpf_value	= DA7210_VOICE_F0_25	| DA7210_VOICE_EN;
+		break;
+	case 32000:
+		fs		= DA7210_PLL_FS_32000;
+		hpf_mask	= DA7210_VOICE_EN;
+		hpf_value	= 0;
+		break;
 	case 48000:
-		if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
-			reg  = DA7210_DAC_HPF;
-			mask = DA7210_DAC_VOICE_EN;
-		} else {
-			reg  = DA7210_ADC_HPF;
-			mask = DA7210_ADC_VOICE_EN;
-		}
+		fs		= DA7210_PLL_FS_48000;
+		hpf_mask	= DA7210_VOICE_EN;
+		hpf_value	= 0;
+		break;
+	case 96000:
+		fs		= DA7210_PLL_FS_96000;
+		hpf_mask	= DA7210_VOICE_EN;
+		hpf_value	= 0;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, reg, mask, 0);
+	snd_soc_update_bits(codec, hpf_reg, hpf_mask, hpf_value);
+	snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_FS_MASK, fs);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index d2ff1cd..942f5dc 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -139,6 +139,7 @@
 SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
 
 SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
+SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 7, 1, 0),
 SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
 
 SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1),
@@ -604,8 +605,7 @@
 	reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V);
 	ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
 	/*select Line in as default input*/
-	ssm2602_write(codec, SSM2602_APANA,
-			APANA_ENABLE_MIC_BOOST2 | APANA_SELECT_DAC |
+	ssm2602_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
 			APANA_ENABLE_MIC_BOOST);
 	ssm2602_write(codec, SSM2602_PWR, 0);
 
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index d07bcc1..c2960d3 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -22,6 +22,7 @@
 #include <sound/soc-dapm.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
+#include <sound/wm8960.h>
 
 #include "wm8960.h"
 
@@ -30,8 +31,14 @@
 struct snd_soc_codec_device soc_codec_dev_wm8960;
 
 /* R25 - Power 1 */
+#define WM8960_VMID_MASK 0x180
 #define WM8960_VREF      0x40
 
+/* R26 - Power 2 */
+#define WM8960_PWR2_LOUT1	0x40
+#define WM8960_PWR2_ROUT1	0x20
+#define WM8960_PWR2_OUT3	0x02
+
 /* R28 - Anti-pop 1 */
 #define WM8960_POBCTRL   0x80
 #define WM8960_BUFDCOPEN 0x10
@@ -41,6 +48,7 @@
 
 /* R29 - Anti-pop 2 */
 #define WM8960_DISOP     0x40
+#define WM8960_DRES_MASK 0x30
 
 /*
  * wm8960 register cache
@@ -67,6 +75,9 @@
 struct wm8960_priv {
 	u16 reg_cache[WM8960_CACHEREGNUM];
 	struct snd_soc_codec codec;
+	struct snd_soc_dapm_widget *lout1;
+	struct snd_soc_dapm_widget *rout1;
+	struct snd_soc_dapm_widget *out3;
 };
 
 #define wm8960_reset(c)	snd_soc_write(c, WM8960_RESET, 0)
@@ -225,10 +236,6 @@
 	&wm8960_routput_mixer[0],
 	ARRAY_SIZE(wm8960_routput_mixer)),
 
-SND_SOC_DAPM_MIXER("Mono Output Mixer", WM8960_POWER2, 1, 0,
-	&wm8960_mono_out[0],
-	ARRAY_SIZE(wm8960_mono_out)),
-
 SND_SOC_DAPM_PGA("LOUT1 PGA", WM8960_POWER2, 6, 0, NULL, 0),
 SND_SOC_DAPM_PGA("ROUT1 PGA", WM8960_POWER2, 5, 0, NULL, 0),
 
@@ -247,6 +254,17 @@
 SND_SOC_DAPM_OUTPUT("OUT3"),
 };
 
+static const struct snd_soc_dapm_widget wm8960_dapm_widgets_out3[] = {
+SND_SOC_DAPM_MIXER("Mono Output Mixer", WM8960_POWER2, 1, 0,
+	&wm8960_mono_out[0],
+	ARRAY_SIZE(wm8960_mono_out)),
+};
+
+/* Represent OUT3 as a PGA so that it gets turned on with LOUT1/ROUT1 */
+static const struct snd_soc_dapm_widget wm8960_dapm_widgets_capless[] = {
+SND_SOC_DAPM_PGA("OUT3 VMID", WM8960_POWER2, 1, 0, NULL, 0),
+};
+
 static const struct snd_soc_dapm_route audio_paths[] = {
 	{ "Left Boost Mixer", "LINPUT1 Switch", "LINPUT1" },
 	{ "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" },
@@ -277,9 +295,6 @@
 	{ "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" } ,
 	{ "Right Output Mixer", "PCM Playback Switch", "Right DAC" },
 
-	{ "Mono Output Mixer", "Left Switch", "Left Output Mixer" },
-	{ "Mono Output Mixer", "Right Switch", "Right Output Mixer" },
-
 	{ "LOUT1 PGA", NULL, "Left Output Mixer" },
 	{ "ROUT1 PGA", NULL, "Right Output Mixer" },
 
@@ -296,17 +311,65 @@
 	{ "SPK_LP", NULL, "Left Speaker Output" },
 	{ "SPK_RN", NULL, "Right Speaker Output" },
 	{ "SPK_RP", NULL, "Right Speaker Output" },
+};
+
+static const struct snd_soc_dapm_route audio_paths_out3[] = {
+	{ "Mono Output Mixer", "Left Switch", "Left Output Mixer" },
+	{ "Mono Output Mixer", "Right Switch", "Right Output Mixer" },
 
 	{ "OUT3", NULL, "Mono Output Mixer", }
 };
 
+static const struct snd_soc_dapm_route audio_paths_capless[] = {
+	{ "HP_L", NULL, "OUT3 VMID" },
+	{ "HP_R", NULL, "OUT3 VMID" },
+
+	{ "OUT3 VMID", NULL, "Left Output Mixer" },
+	{ "OUT3 VMID", NULL, "Right Output Mixer" },
+};
+
 static int wm8960_add_widgets(struct snd_soc_codec *codec)
 {
+	struct wm8960_data *pdata = codec->dev->platform_data;
+	struct wm8960_priv *wm8960 = codec->private_data;
+	struct snd_soc_dapm_widget *w;
+
 	snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets,
 				  ARRAY_SIZE(wm8960_dapm_widgets));
 
 	snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
+	/* In capless mode OUT3 is used to provide VMID for the
+	 * headphone outputs, otherwise it is used as a mono mixer.
+	 */
+	if (pdata && pdata->capless) {
+		snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets_capless,
+					  ARRAY_SIZE(wm8960_dapm_widgets_capless));
+
+		snd_soc_dapm_add_routes(codec, audio_paths_capless,
+					ARRAY_SIZE(audio_paths_capless));
+	} else {
+		snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets_out3,
+					  ARRAY_SIZE(wm8960_dapm_widgets_out3));
+
+		snd_soc_dapm_add_routes(codec, audio_paths_out3,
+					ARRAY_SIZE(audio_paths_out3));
+	}
+
+	/* We need to power up the headphone output stage out of
+	 * sequence for capless mode.  To save scanning the widget
+	 * list each time to find the desired power state do so now
+	 * and save the result.
+	 */
+	list_for_each_entry(w, &codec->dapm_widgets, list) {
+		if (strcmp(w->name, "LOUT1 PGA") == 0)
+			wm8960->lout1 = w;
+		if (strcmp(w->name, "ROUT1 PGA") == 0)
+			wm8960->rout1 = w;
+		if (strcmp(w->name, "OUT3 VMID") == 0)
+			wm8960->out3 = w;
+	}
+	
 	return 0;
 }
 
@@ -407,10 +470,9 @@
 	return 0;
 }
 
-static int wm8960_set_bias_level(struct snd_soc_codec *codec,
-				 enum snd_soc_bias_level level)
+static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
+				      enum snd_soc_bias_level level)
 {
-	struct wm8960_data *pdata = codec->dev->platform_data;
 	u16 reg;
 
 	switch (level) {
@@ -429,18 +491,8 @@
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
 			/* Enable anti-pop features */
 			snd_soc_write(codec, WM8960_APOP1,
-				     WM8960_POBCTRL | WM8960_SOFT_ST |
-				     WM8960_BUFDCOPEN | WM8960_BUFIOEN);
-
-			/* Discharge HP output */
-			reg = WM8960_DISOP;
-			if (pdata)
-				reg |= pdata->dres << 4;
-			snd_soc_write(codec, WM8960_APOP2, reg);
-
-			msleep(400);
-
-			snd_soc_write(codec, WM8960_APOP2, 0);
+				      WM8960_POBCTRL | WM8960_SOFT_ST |
+				      WM8960_BUFDCOPEN | WM8960_BUFIOEN);
 
 			/* Enable & ramp VMID at 2x50k */
 			reg = snd_soc_read(codec, WM8960_POWER1);
@@ -471,8 +523,101 @@
 		/* Disable VMID and VREF, let them discharge */
 		snd_soc_write(codec, WM8960_POWER1, 0);
 		msleep(600);
+		break;
+	}
 
-		snd_soc_write(codec, WM8960_APOP1, 0);
+	codec->bias_level = level;
+
+	return 0;
+}
+
+static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
+					 enum snd_soc_bias_level level)
+{
+	struct wm8960_priv *wm8960 = codec->private_data;
+	int reg;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		switch (codec->bias_level) {
+		case SND_SOC_BIAS_STANDBY:
+			/* Enable anti pop mode */
+			snd_soc_update_bits(codec, WM8960_APOP1,
+					    WM8960_POBCTRL | WM8960_SOFT_ST |
+					    WM8960_BUFDCOPEN,
+					    WM8960_POBCTRL | WM8960_SOFT_ST |
+					    WM8960_BUFDCOPEN);
+
+			/* Enable LOUT1, ROUT1 and OUT3 if they're enabled */
+			reg = 0;
+			if (wm8960->lout1 && wm8960->lout1->power)
+				reg |= WM8960_PWR2_LOUT1;
+			if (wm8960->rout1 && wm8960->rout1->power)
+				reg |= WM8960_PWR2_ROUT1;
+			if (wm8960->out3 && wm8960->out3->power)
+				reg |= WM8960_PWR2_OUT3;
+			snd_soc_update_bits(codec, WM8960_POWER2,
+					    WM8960_PWR2_LOUT1 |
+					    WM8960_PWR2_ROUT1 |
+					    WM8960_PWR2_OUT3, reg);
+
+			/* Enable VMID at 2*50k */
+			snd_soc_update_bits(codec, WM8960_POWER1,
+					    WM8960_VMID_MASK, 0x80);
+
+			/* Ramp */
+			msleep(100);
+
+			/* Enable VREF */
+			snd_soc_update_bits(codec, WM8960_POWER1,
+					    WM8960_VREF, WM8960_VREF);
+
+			msleep(100);
+			break;
+
+		case SND_SOC_BIAS_ON:
+			/* Enable anti-pop mode */
+			snd_soc_update_bits(codec, WM8960_APOP1,
+					    WM8960_POBCTRL | WM8960_SOFT_ST |
+					    WM8960_BUFDCOPEN,
+					    WM8960_POBCTRL | WM8960_SOFT_ST |
+					    WM8960_BUFDCOPEN);
+
+			/* Disable VMID and VREF */
+			snd_soc_update_bits(codec, WM8960_POWER1,
+					    WM8960_VREF | WM8960_VMID_MASK, 0);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		switch (codec->bias_level) {
+		case SND_SOC_BIAS_PREPARE:
+			/* Disable HP discharge */
+			snd_soc_update_bits(codec, WM8960_APOP2,
+					    WM8960_DISOP | WM8960_DRES_MASK,
+					    0);
+
+			/* Disable anti-pop features */
+			snd_soc_update_bits(codec, WM8960_APOP1,
+					    WM8960_POBCTRL | WM8960_SOFT_ST |
+					    WM8960_BUFDCOPEN,
+					    WM8960_POBCTRL | WM8960_SOFT_ST |
+					    WM8960_BUFDCOPEN);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
 		break;
 	}
 
@@ -662,7 +807,7 @@
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 	struct snd_soc_codec *codec = socdev->card->codec;
 
-	wm8960_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	codec->set_bias_level(codec, SND_SOC_BIAS_OFF);
 	return 0;
 }
 
@@ -681,8 +826,8 @@
 		codec->hw_write(codec->control_data, data, 2);
 	}
 
-	wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	wm8960_set_bias_level(codec, codec->suspend_bias_level);
+	codec->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	codec->set_bias_level(codec, codec->suspend_bias_level);
 	return 0;
 }
 
@@ -752,6 +897,8 @@
 		goto err;
 	}
 
+	codec->set_bias_level = wm8960_set_bias_level_out3;
+
 	if (!pdata) {
 		dev_warn(codec->dev, "No platform data supplied\n");
 	} else {
@@ -759,6 +906,9 @@
 			dev_err(codec->dev, "Invalid DRES: %d\n", pdata->dres);
 			pdata->dres = 0;
 		}
+
+		if (pdata->capless)
+			codec->set_bias_level = wm8960_set_bias_level_capless;
 	}
 
 	mutex_init(&codec->mutex);
@@ -769,7 +919,6 @@
 	codec->name = "WM8960";
 	codec->owner = THIS_MODULE;
 	codec->bias_level = SND_SOC_BIAS_OFF;
-	codec->set_bias_level = wm8960_set_bias_level;
 	codec->dai = &wm8960_dai;
 	codec->num_dai = 1;
 	codec->reg_cache_size = WM8960_CACHEREGNUM;
@@ -791,7 +940,7 @@
 
 	wm8960_dai.dev = codec->dev;
 
-	wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	codec->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	/* Latch the update bits */
 	reg = snd_soc_read(codec, WM8960_LINVOL);
@@ -840,7 +989,7 @@
 
 static void wm8960_unregister(struct wm8960_priv *wm8960)
 {
-	wm8960_set_bias_level(&wm8960->codec, SND_SOC_BIAS_OFF);
+	wm8960->codec.set_bias_level(&wm8960->codec, SND_SOC_BIAS_OFF);
 	snd_soc_unregister_dai(&wm8960_dai);
 	snd_soc_unregister_codec(&wm8960->codec);
 	kfree(wm8960);
@@ -882,7 +1031,7 @@
 
 static struct i2c_driver wm8960_i2c_driver = {
 	.driver = {
-		.name = "WM8960 I2C Codec",
+		.name = "wm8960",
 		.owner = THIS_MODULE,
 	},
 	.probe =    wm8960_i2c_probe,
diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h
index c9af56c..d67bfe1 100644
--- a/sound/soc/codecs/wm8960.h
+++ b/sound/soc/codecs/wm8960.h
@@ -114,14 +114,4 @@
 extern struct snd_soc_dai wm8960_dai;
 extern struct snd_soc_codec_device soc_codec_dev_wm8960;
 
-#define WM8960_DRES_400R 0
-#define WM8960_DRES_200R 1
-#define WM8960_DRES_600R 2
-#define WM8960_DRES_150R 3
-#define WM8960_DRES_MAX  3
-
-struct wm8960_data {
-	int dres;
-};
-
 #endif
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 7ccbe66..dba6651 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -81,10 +81,24 @@
 	return 0;
 }
 
+static int evm_spdif_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	/* set cpu DAI configuration */
+	return snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
+}
+
 static struct snd_soc_ops evm_ops = {
 	.hw_params = evm_hw_params,
 };
 
+static struct snd_soc_ops evm_spdif_ops = {
+	.hw_params = evm_spdif_hw_params,
+};
+
 /* davinci-evm machine dapm widgets */
 static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
 	SND_SOC_DAPM_HP("Headphone Jack", NULL),
@@ -165,7 +179,7 @@
 		.stream_name = "spdif",
 		.cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_DIT_DAI],
 		.codec_dai = &dit_stub_dai,
-		.ops = &evm_ops,
+		.ops = &evm_spdif_ops,
 	},
 };
 static struct snd_soc_dai_link da8xx_evm_dai = {
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index c7d0fd9..c045da8 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -11,3 +11,11 @@
 config SND_MXC_SOC_SSI
 	tristate
 
+config SND_MXC_SOC_WM1133_EV1
+	tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
+	depends on SND_IMX_SOC && EXPERIMENTAL
+	select SND_SOC_WM8350
+	select SND_MXC_SOC_SSI
+	help
+	  Enable support for audio on the i.MX31ADS with the WM1133-EV1
+	  PMIC board with WM8835x fitted.
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index 9f8bb92..2d20363 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -9,4 +9,7 @@
 
 # i.MX Machine Support
 snd-soc-phycore-ac97-objs := phycore-ac97.o
+snd-soc-wm1133-ev1-objs := wm1133-ev1.o
+
 obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
+obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
diff --git a/sound/soc/imx/wm1133-ev1.c b/sound/soc/imx/wm1133-ev1.c
new file mode 100644
index 0000000..b75fcde
--- /dev/null
+++ b/sound/soc/imx/wm1133-ev1.c
@@ -0,0 +1,291 @@
+/*
+ *  wm1133-ev1.c - Audio for WM1133-EV1 on i.MX31ADS
+ *
+ *  Copyright (c) 2010 Wolfson Microelectronics plc
+ *  Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  Based on an earlier driver for the same hardware by Liam Girdwood.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <mach/audmux.h>
+
+#include "imx-ssi.h"
+#include "../codecs/wm8350.h"
+
+/* There is a silicon mic on the board optionally connected via a solder pad
+ * SP1.  Define this to enable it.
+ */
+#undef USE_SIMIC
+
+struct _wm8350_audio {
+	unsigned int channels;
+	snd_pcm_format_t format;
+	unsigned int rate;
+	unsigned int sysclk;
+	unsigned int bclkdiv;
+	unsigned int clkdiv;
+	unsigned int lr_rate;
+};
+
+/* in order of power consumption per rate (lowest first) */
+static const struct _wm8350_audio wm8350_audio[] = {
+	/* 16bit mono modes */
+	{1, SNDRV_PCM_FORMAT_S16_LE, 8000, 12288000 >> 1,
+	 WM8350_BCLK_DIV_48, WM8350_DACDIV_3, 16,},
+
+	/* 16 bit stereo modes */
+	{2, SNDRV_PCM_FORMAT_S16_LE, 8000, 12288000,
+	 WM8350_BCLK_DIV_48, WM8350_DACDIV_6, 32,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 16000, 12288000,
+	 WM8350_BCLK_DIV_24, WM8350_DACDIV_3, 32,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 32000, 12288000,
+	 WM8350_BCLK_DIV_12, WM8350_DACDIV_1_5, 32,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 48000, 12288000,
+	 WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 96000, 24576000,
+	 WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 11025, 11289600,
+	 WM8350_BCLK_DIV_32, WM8350_DACDIV_4, 32,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 22050, 11289600,
+	 WM8350_BCLK_DIV_16, WM8350_DACDIV_2, 32,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 44100, 11289600,
+	 WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 88200, 22579200,
+	 WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
+
+	/* 24bit stereo modes */
+	{2, SNDRV_PCM_FORMAT_S24_LE, 48000, 12288000,
+	 WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
+	{2, SNDRV_PCM_FORMAT_S24_LE, 96000, 24576000,
+	 WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
+	{2, SNDRV_PCM_FORMAT_S24_LE, 44100, 11289600,
+	 WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
+	{2, SNDRV_PCM_FORMAT_S24_LE, 88200, 22579200,
+	 WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
+};
+
+static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int i, found = 0;
+	snd_pcm_format_t format = params_format(params);
+	unsigned int rate = params_rate(params);
+	unsigned int channels = params_channels(params);
+	u32 dai_format;
+
+	/* find the correct audio parameters */
+	for (i = 0; i < ARRAY_SIZE(wm8350_audio); i++) {
+		if (rate == wm8350_audio[i].rate &&
+		    format == wm8350_audio[i].format &&
+		    channels == wm8350_audio[i].channels) {
+			found = 1;
+			break;
+		}
+	}
+	if (!found)
+		return -EINVAL;
+
+	/* codec FLL input is 14.75 MHz from MCLK */
+	snd_soc_dai_set_pll(codec_dai, 0, 0, 14750000, wm8350_audio[i].sysclk);
+
+	dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		SND_SOC_DAIFMT_CBM_CFM;
+
+	/* set codec DAI configuration */
+	snd_soc_dai_set_fmt(codec_dai, dai_format);
+
+	/* set cpu DAI configuration */
+	snd_soc_dai_set_fmt(cpu_dai, dai_format);
+
+	/* TODO: The SSI driver should figure this out for us */
+	switch (channels) {
+	case 2:
+		snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
+		break;
+	case 1:
+		snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffe, 0xffffffe, 1, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set MCLK as the codec system clock for DAC and ADC */
+	snd_soc_dai_set_sysclk(codec_dai, WM8350_MCLK_SEL_PLL_MCLK,
+			       wm8350_audio[i].sysclk, SND_SOC_CLOCK_IN);
+
+	/* set codec BCLK division for sample rate */
+	snd_soc_dai_set_clkdiv(codec_dai, WM8350_BCLK_CLKDIV,
+			       wm8350_audio[i].bclkdiv);
+
+	/* DAI is synchronous and clocked with DAC LRCLK & ADC LRC */
+	snd_soc_dai_set_clkdiv(codec_dai,
+			       WM8350_DACLR_CLKDIV, wm8350_audio[i].lr_rate);
+	snd_soc_dai_set_clkdiv(codec_dai,
+			       WM8350_ADCLR_CLKDIV, wm8350_audio[i].lr_rate);
+
+	/* now configure DAC and ADC clocks */
+	snd_soc_dai_set_clkdiv(codec_dai,
+			       WM8350_DAC_CLKDIV, wm8350_audio[i].clkdiv);
+
+	snd_soc_dai_set_clkdiv(codec_dai,
+			       WM8350_ADC_CLKDIV, wm8350_audio[i].clkdiv);
+
+	return 0;
+}
+
+static struct snd_soc_ops wm1133_ev1_ops = {
+	.hw_params = wm1133_ev1_hw_params,
+};
+
+static const struct snd_soc_dapm_widget wm1133_ev1_widgets[] = {
+#ifdef USE_SIMIC
+	SND_SOC_DAPM_MIC("SiMIC", NULL),
+#endif
+	SND_SOC_DAPM_MIC("Mic1 Jack", NULL),
+	SND_SOC_DAPM_MIC("Mic2 Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In Jack", NULL),
+	SND_SOC_DAPM_LINE("Line Out Jack", NULL),
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+};
+
+/* imx32ads soc_card audio map */
+static const struct snd_soc_dapm_route wm1133_ev1_map[] = {
+
+#ifdef USE_SIMIC
+	/* SiMIC --> IN1LN (with automatic bias) via SP1 */
+	{ "IN1LN", NULL, "Mic Bias" },
+	{ "Mic Bias", NULL, "SiMIC" },
+#endif
+
+	/* Mic 1 Jack --> IN1LN and IN1LP (with automatic bias) */
+	{ "IN1LN", NULL, "Mic Bias" },
+	{ "IN1LP", NULL, "Mic1 Jack" },
+	{ "Mic Bias", NULL, "Mic1 Jack" },
+
+	/* Mic 2 Jack --> IN1RN and IN1RP (with automatic bias) */
+	{ "IN1RN", NULL, "Mic Bias" },
+	{ "IN1RP", NULL, "Mic1 Jack" },
+	{ "Mic Bias", NULL, "Mic1 Jack" },
+
+	/* Line in Jack --> AUX (L+R) */
+	{ "IN3R", NULL, "Line In Jack" },
+	{ "IN3L", NULL, "Line In Jack" },
+
+	/* Out1 --> Headphone Jack */
+	{ "Headphone Jack", NULL, "OUT1R" },
+	{ "Headphone Jack", NULL, "OUT1L" },
+
+	/* Out1 --> Line Out Jack */
+	{ "Line Out Jack", NULL, "OUT2R" },
+	{ "Line Out Jack", NULL, "OUT2L" },
+};
+
+static struct snd_soc_jack hp_jack;
+
+static struct snd_soc_jack_pin hp_jack_pins[] = {
+	{ .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE },
+};
+
+static int wm1133_ev1_init(struct snd_soc_codec *codec)
+{
+	struct snd_soc_card *card = codec->socdev->card;
+
+	snd_soc_dapm_new_controls(codec, wm1133_ev1_widgets,
+				  ARRAY_SIZE(wm1133_ev1_widgets));
+
+	snd_soc_dapm_add_routes(codec, wm1133_ev1_map,
+				ARRAY_SIZE(wm1133_ev1_map));
+
+	/* Headphone jack detection */
+	snd_soc_jack_new(card, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
+	snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
+			      hp_jack_pins);
+	wm8350_hp_jack_detect(codec, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
+
+	return 0;
+}
+
+
+static struct snd_soc_dai_link wm1133_ev1_dai = {
+	.name = "WM1133-EV1",
+	.stream_name = "Audio",
+	.cpu_dai = &imx_ssi_pcm_dai[0],
+	.codec_dai = &wm8350_dai,
+	.init = wm1133_ev1_init,
+	.ops = &wm1133_ev1_ops,
+	.symmetric_rates = 1,
+};
+
+static struct snd_soc_card wm1133_ev1 = {
+	.name = "WM1133-EV1",
+	.platform = &imx_soc_platform,
+	.dai_link = &wm1133_ev1_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device wm1133_ev1_snd_devdata = {
+	.card = &wm1133_ev1,
+	.codec_dev = &soc_codec_dev_wm8350,
+};
+
+static struct platform_device *wm1133_ev1_snd_device;
+
+static int __init wm1133_ev1_audio_init(void)
+{
+	int ret;
+	unsigned int ptcr, pdcr;
+
+	/* SSI0 mastered by port 5 */
+	ptcr = MXC_AUDMUX_V2_PTCR_SYN |
+		MXC_AUDMUX_V2_PTCR_TFSDIR |
+		MXC_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT5_SSI_PINS_5) |
+		MXC_AUDMUX_V2_PTCR_TCLKDIR |
+		MXC_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT5_SSI_PINS_5);
+	pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT5_SSI_PINS_5);
+	mxc_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, ptcr, pdcr);
+
+	ptcr = MXC_AUDMUX_V2_PTCR_SYN;
+	pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0);
+	mxc_audmux_v2_configure_port(MX31_AUDMUX_PORT5_SSI_PINS_5, ptcr, pdcr);
+
+	wm1133_ev1_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!wm1133_ev1_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1_snd_devdata);
+	wm1133_ev1_snd_devdata.dev = &wm1133_ev1_snd_device->dev;
+	ret = platform_device_add(wm1133_ev1_snd_device);
+
+	if (ret)
+		platform_device_put(wm1133_ev1_snd_device);
+
+	return ret;
+}
+module_init(wm1133_ev1_audio_init);
+
+static void __exit wm1133_ev1_audio_exit(void)
+{
+	platform_device_unregister(wm1133_ev1_snd_device);
+}
+module_exit(wm1133_ev1_audio_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Audio for WM1133-EV1 on i.MX31ADS");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index e994d83..b846f56 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -16,18 +16,12 @@
  * option) any later version.
  */
 
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-#include <linux/kernel.h>
 #include <linux/io.h>
 
-#include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
 
 #include <plat/regs-s3c2412-iis.h>
@@ -469,29 +463,25 @@
 
 	switch (div_id) {
 	case S3C_I2SV2_DIV_BCLK:
-		if (div > 3) {
-			/* convert value to bit field */
+		switch (div) {
+		case 16:
+			div = S3C2412_IISMOD_BCLK_16FS;
+			break;
 
-			switch (div) {
-			case 16:
-				div = S3C2412_IISMOD_BCLK_16FS;
-				break;
+		case 32:
+			div = S3C2412_IISMOD_BCLK_32FS;
+			break;
 
-			case 32:
-				div = S3C2412_IISMOD_BCLK_32FS;
-				break;
+		case 24:
+			div = S3C2412_IISMOD_BCLK_24FS;
+			break;
 
-			case 24:
-				div = S3C2412_IISMOD_BCLK_24FS;
-				break;
+		case 48:
+			div = S3C2412_IISMOD_BCLK_48FS;
+			break;
 
-			case 48:
-				div = S3C2412_IISMOD_BCLK_48FS;
-				break;
-
-			default:
-				return -EINVAL;
-			}
+		default:
+			return -EINVAL;
 		}
 
 		reg = readl(i2s->regs + S3C2412_IISMOD);
@@ -502,29 +492,25 @@
 		break;
 
 	case S3C_I2SV2_DIV_RCLK:
-		if (div > 3) {
-			/* convert value to bit field */
+		switch (div) {
+		case 256:
+			div = S3C2412_IISMOD_RCLK_256FS;
+			break;
 
-			switch (div) {
-			case 256:
-				div = S3C2412_IISMOD_RCLK_256FS;
-				break;
+		case 384:
+			div = S3C2412_IISMOD_RCLK_384FS;
+			break;
 
-			case 384:
-				div = S3C2412_IISMOD_RCLK_384FS;
-				break;
+		case 512:
+			div = S3C2412_IISMOD_RCLK_512FS;
+			break;
 
-			case 512:
-				div = S3C2412_IISMOD_RCLK_512FS;
-				break;
+		case 768:
+			div = S3C2412_IISMOD_RCLK_768FS;
+			break;
 
-			case 768:
-				div = S3C2412_IISMOD_RCLK_768FS;
-				break;
-
-			default:
-				return -EINVAL;
-			}
+		default:
+			return -EINVAL;
 		}
 
 		reg = readl(i2s->regs + S3C2412_IISMOD);
@@ -550,6 +536,21 @@
 	return 0;
 }
 
+static snd_pcm_sframes_t s3c2412_i2s_delay(struct snd_pcm_substream *substream,
+					   struct snd_soc_dai *dai)
+{
+	struct s3c_i2sv2_info *i2s = to_info(dai);
+	u32 reg = readl(i2s->regs + S3C2412_IISFIC);
+	snd_pcm_sframes_t delay;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		delay = S3C2412_IISFIC_TXCOUNT(reg);
+	else
+		delay = S3C2412_IISFIC_RXCOUNT(reg);
+
+	return delay;
+}
+
 /* default table of all avaialable root fs divisors */
 static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
 
@@ -736,6 +737,10 @@
 	ops->set_fmt = s3c2412_i2s_set_fmt;
 	ops->set_clkdiv = s3c2412_i2s_set_clkdiv;
 
+	/* Allow overriding by (for example) IISv4 */
+	if (!ops->delay)
+		ops->delay = s3c2412_i2s_delay;
+
 	dai->suspend = s3c2412_i2s_suspend;
 	dai->resume = s3c2412_i2s_resume;
 
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h
index ecf8eaa..b094d3c 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.h
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.h
@@ -25,6 +25,10 @@
 #define S3C_I2SV2_DIV_RCLK	(2)
 #define S3C_I2SV2_DIV_PRESCALER	(3)
 
+#define S3C_I2SV2_CLKSRC_PCLK		0
+#define S3C_I2SV2_CLKSRC_AUDIOBUS	1
+#define S3C_I2SV2_CLKSRC_CDCLK		2
+
 /**
  * struct s3c_i2sv2_info - S3C I2S-V2 information
  * @dev: The parent device passed to use from the probe.
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h
index 92848e5..60cac00 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.h
+++ b/sound/soc/s3c24xx/s3c2412-i2s.h
@@ -21,8 +21,8 @@
 #define S3C2412_DIV_RCLK	S3C_I2SV2_DIV_RCLK
 #define S3C2412_DIV_PRESCALER	S3C_I2SV2_DIV_PRESCALER
 
-#define S3C2412_CLKSRC_PCLK	(0)
-#define S3C2412_CLKSRC_I2SCLK	(1)
+#define S3C2412_CLKSRC_PCLK	S3C_I2SV2_CLKSRC_PCLK
+#define S3C2412_CLKSRC_I2SCLK	S3C_I2SV2_CLKSRC_AUDIOBUS
 
 extern struct clk *s3c2412_get_iisclk(void);
 
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index 93ed3aa..6552894 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -12,9 +12,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
@@ -130,15 +127,6 @@
 }
 
 
-#define S3C64XX_I2S_RATES \
-	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
-	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-
-#define S3C64XX_I2S_FMTS \
-	(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
-	 SNDRV_PCM_FMTBIT_S24_LE)
-
 static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = {
 	.set_sysclk	= s3c64xx_i2s_set_sysclk,	
 };
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
index abe7253..53d2a0a 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.h
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.h
@@ -23,9 +23,18 @@
 #define S3C64XX_DIV_RCLK	S3C_I2SV2_DIV_RCLK
 #define S3C64XX_DIV_PRESCALER	S3C_I2SV2_DIV_PRESCALER
 
-#define S3C64XX_CLKSRC_PCLK	(0)
-#define S3C64XX_CLKSRC_MUX	(1)
-#define S3C64XX_CLKSRC_CDCLK    (2)
+#define S3C64XX_CLKSRC_PCLK	S3C_I2SV2_CLKSRC_PCLK
+#define S3C64XX_CLKSRC_MUX	S3C_I2SV2_CLKSRC_AUDIOBUS
+#define S3C64XX_CLKSRC_CDCLK    S3C_I2SV2_CLKSRC_CDCLK
+
+#define S3C64XX_I2S_RATES \
+	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define S3C64XX_I2S_FMTS \
+	(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
+	 SNDRV_PCM_FMTBIT_S24_LE)
 
 extern struct snd_soc_dai s3c64xx_i2s_dai[];
 
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index 5869dc3..bf593a8 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -366,6 +366,84 @@
 #define snd_soc_16_8_spi_write NULL
 #endif
 
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
+					   unsigned int r)
+{
+	struct i2c_msg xfer[2];
+	u16 reg = cpu_to_be16(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 = 2;
+	xfer[0].buf = (u8 *)&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 be16_to_cpu(data);
+}
+#else
+#define snd_soc_16_16_read_i2c NULL
+#endif
+
+static unsigned int snd_soc_16_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)) {
+		if (codec->cache_only)
+			return -EINVAL;
+
+		return codec->hw_read(codec, reg);
+	}
+
+	return cache[reg];
+}
+
+static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
+			       unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	u8 data[4];
+	int ret;
+
+	data[0] = (reg >> 8) & 0xff;
+	data[1] = reg & 0xff;
+	data[2] = (value >> 8) & 0xff;
+	data[3] = value & 0xff;
+
+	if (reg < codec->reg_cache_size)
+		cache[reg] = value;
+
+	if (codec->cache_only) {
+		codec->cache_sync = 1;
+		return 0;
+	}
+
+	ret = codec->hw_write(codec->control_data, data, 4);
+	if (ret == 4)
+		return 0;
+	if (ret < 0)
+		return ret;
+	else
+		return -EIO;
+}
 
 static struct {
 	int addr_bits;
@@ -400,6 +478,11 @@
 		.i2c_read = snd_soc_16_8_read_i2c,
 		.spi_write = snd_soc_16_8_spi_write,
 	},
+	{
+		.addr_bits = 16, .data_bits = 16,
+		.write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
+		.i2c_read = snd_soc_16_16_read_i2c,
+	},
 };
 
 /**
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c8b0556..06c38d1 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -315,7 +315,7 @@
 
 	if (codec_dai->symmetric_rates || cpu_dai->symmetric_rates ||
 	    machine->symmetric_rates) {
-		dev_dbg(card->dev, "Symmetry forces %dHz rate\n", 
+		dev_dbg(card->dev, "Symmetry forces %dHz rate\n",
 			machine->rate);
 
 		ret = snd_pcm_hw_constraint_minmax(substream->runtime,
@@ -454,12 +454,15 @@
 	pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
 		 runtime->hw.rate_max);
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		cpu_dai->playback.active = codec_dai->playback.active = 1;
-	else
-		cpu_dai->capture.active = codec_dai->capture.active = 1;
-	cpu_dai->active = codec_dai->active = 1;
-	cpu_dai->runtime = runtime;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		cpu_dai->playback.active++;
+		codec_dai->playback.active++;
+	} else {
+		cpu_dai->capture.active++;
+		codec_dai->capture.active++;
+	}
+	cpu_dai->active++;
+	codec_dai->active++;
 	card->codec->active++;
 	mutex_unlock(&pcm_mutex);
 	return 0;
@@ -535,15 +538,16 @@
 
 	mutex_lock(&pcm_mutex);
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		cpu_dai->playback.active = codec_dai->playback.active = 0;
-	else
-		cpu_dai->capture.active = codec_dai->capture.active = 0;
-
-	if (codec_dai->playback.active == 0 &&
-		codec_dai->capture.active == 0) {
-		cpu_dai->active = codec_dai->active = 0;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		cpu_dai->playback.active--;
+		codec_dai->playback.active--;
+	} else {
+		cpu_dai->capture.active--;
+		codec_dai->capture.active--;
 	}
+
+	cpu_dai->active--;
+	codec_dai->active--;
 	codec->active--;
 
 	/* Muting the DAC suppresses artifacts caused during digital
@@ -563,7 +567,6 @@
 
 	if (platform->pcm_ops->close)
 		platform->pcm_ops->close(substream);
-	cpu_dai->runtime = NULL;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/* start delayed pop wq here for playback streams */
@@ -801,6 +804,41 @@
 	return 0;
 }
 
+/*
+ * soc level wrapper for pointer callback
+ * If cpu_dai, codec_dai, platform driver has the delay callback, than
+ * the runtime->delay will be updated accordingly.
+ */
+static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_card *card = socdev->card;
+	struct snd_soc_platform *platform = card->platform;
+	struct snd_soc_dai_link *machine = rtd->dai;
+	struct snd_soc_dai *cpu_dai = machine->cpu_dai;
+	struct snd_soc_dai *codec_dai = machine->codec_dai;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_pcm_uframes_t offset = 0;
+	snd_pcm_sframes_t delay = 0;
+
+	if (platform->pcm_ops->pointer)
+		offset = platform->pcm_ops->pointer(substream);
+
+	if (cpu_dai->ops->delay)
+		delay += cpu_dai->ops->delay(substream, cpu_dai);
+
+	if (codec_dai->ops->delay)
+		delay += codec_dai->ops->delay(substream, codec_dai);
+
+	if (platform->delay)
+		delay += platform->delay(substream, codec_dai);
+
+	runtime->delay = delay;
+
+	return offset;
+}
+
 /* ASoC PCM operations */
 static struct snd_pcm_ops soc_pcm_ops = {
 	.open		= soc_pcm_open,
@@ -809,6 +847,7 @@
 	.hw_free	= soc_pcm_hw_free,
 	.prepare	= soc_pcm_prepare,
 	.trigger	= soc_pcm_trigger,
+	.pointer	= soc_pcm_pointer,
 };
 
 #ifdef CONFIG_PM
@@ -858,7 +897,7 @@
 		if (cpu_dai->suspend && !cpu_dai->ac97_control)
 			cpu_dai->suspend(cpu_dai);
 		if (platform->suspend)
-			platform->suspend(cpu_dai);
+			platform->suspend(&card->dai_link[i]);
 	}
 
 	/* close any waiting streams and save state */
@@ -947,7 +986,7 @@
 		if (cpu_dai->resume && !cpu_dai->ac97_control)
 			cpu_dai->resume(cpu_dai);
 		if (platform->resume)
-			platform->resume(cpu_dai);
+			platform->resume(&card->dai_link[i]);
 	}
 
 	if (card->resume_post)
@@ -1335,7 +1374,6 @@
 	dai_link->pcm = pcm;
 	pcm->private_data = rtd;
 	soc_pcm_ops.mmap = platform->pcm_ops->mmap;
-	soc_pcm_ops.pointer = platform->pcm_ops->pointer;
 	soc_pcm_ops.ioctl = platform->pcm_ops->ioctl;
 	soc_pcm_ops.copy = platform->pcm_ops->copy;
 	soc_pcm_ops.silence = platform->pcm_ops->silence;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 6c33510..86ded22 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -97,7 +97,6 @@
 
 	if (pop_time) {
 		vprintk(fmt, args);
-		pop_wait(pop_time);
 	}
 
 	va_end(args);
@@ -314,8 +313,8 @@
 		pop_dbg(codec->pop_time, "pop test %s : %s in %d ms\n",
 			widget->name, widget->power ? "on" : "off",
 			codec->pop_time);
-		snd_soc_write(codec, widget->reg, new);
 		pop_wait(codec->pop_time);
+		snd_soc_write(codec, widget->reg, new);
 	}
 	pr_debug("reg %x old %x new %x change %d\n", widget->reg,
 		 old, new, change);
@@ -1075,6 +1074,7 @@
 
 	pop_dbg(codec->pop_time, "DAPM sequencing finished, waiting %dms\n",
 		codec->pop_time);
+	pop_wait(codec->pop_time);
 
 	return 0;
 }