[ALSA] ASoC: Add support for BCLK based on (Rate * Chn * Word Size)

This patch adds support for the DAI BCLK to be generated by multiplying
Rate * Channels * Word Size (RCW).
This now gives 3 options for BCLK clocking and synchronisation :-
 1. BCLK = Rate * x
 2. BCLK = MCLK / x
 3. BCLK = Rate * Chn * Word Size.  (New)
Changes:-
 o Add support for RCW generation of BCLK
 o Update Documentation to include RCW.
 o Update DAI documentation for label = value DAI modes.
 o Add RCW support to wm8731, wm8750 and pxa2xx-i2s drivers.

Signed-off-by: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
diff --git a/Documentation/sound/alsa/soc/DAI.txt b/Documentation/sound/alsa/soc/DAI.txt
index 919de76..251545a 100644
--- a/Documentation/sound/alsa/soc/DAI.txt
+++ b/Documentation/sound/alsa/soc/DAI.txt
@@ -12,7 +12,8 @@
 frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97
 frame is 21uS long and is divided into 13 time slots.
 
-The AC97 specification can be found at http://intel.com/
+The AC97 specification can be found at :-
+http://www.intel.com/design/chipsets/audio/ac97_r23.pdf
 
 
 I2S
@@ -77,16 +78,16 @@
 struct snd_soc_dai_mode is defined (in soc.h) as:-
 
 /* SoC DAI mode */
-struct snd_soc_hw_mode {
-	unsigned int fmt:16;		/* SND_SOC_DAIFMT_* */
-	unsigned int tdm:16;		/* SND_SOC_DAITDM_* */
-	unsigned int pcmfmt:6; 		/* SNDRV_PCM_FORMAT_* */
-	unsigned int pcmrate:16;	/* SND_SOC_DAIRATE_* */
-	unsigned int pcmdir:2;		/* SND_SOC_DAIDIR_* */
-	unsigned int flags:8;		/* hw flags */
-	unsigned int fs:32;			/* mclk to rate dividers */
-	unsigned int bfs:16;		/* mclk to bclk dividers */
-	unsigned long priv;	        /* private mode data */
+struct snd_soc_dai_mode {
+	u16 fmt;		/* SND_SOC_DAIFMT_* */
+	u16 tdm;		/* SND_SOC_HWTDM_* */
+	u64 pcmfmt; 	/* SNDRV_PCM_FMTBIT_* */
+	u16 pcmrate;	/* SND_SOC_HWRATE_* */
+	u16 pcmdir:2;	/* SND_SOC_HWDIR_* */
+	u16 flags:8;	/* hw flags */
+	u16 fs;			/* mclk to rate divider */
+	u64 bfs;		/* mclk to bclk dividers */
+	unsigned long priv;		/* private mode data */
 };
 
 fmt:
@@ -140,14 +141,14 @@
 The hardware PCM format. This describes the PCM formats supported by the DAI
 mode e.g.
 
- .hwpcmfmt = SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
+ .pcmfmt = SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
  	SNDRV_PCM_FORMAT_S24_3LE
 
 pcmrate:
 ----------
 The PCM sample rates supported by the DAI mode. e.g.
 
- .hwpcmrate = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+ .pcmrate = 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
 
@@ -161,9 +162,14 @@
 --------
 The DAI hardware flags supported by the mode.
 
-SND_SOC_DAI_BFS_DIV
-This flag states that bit clock is generated by dividing MCLK in this mode, if
-this flag is absent the bitclock generated by mulitiplying sample rate.
+/* use bfs mclk divider mode (BCLK = MCLK / x) */
+#define SND_SOC_DAI_BFS_DIV		0x1
+/* use bfs rate mulitplier  (BCLK = RATE * x)*/
+#define SND_SOC_DAI_BFS_RATE	0x2
+/* use bfs rcw multiplier (BCLK = RATE * CHN * WORD SIZE) */
+#define SND_SOC_DAI_BFS_RCW		0x4
+/* capture and playback can use different clocks */
+#define SND_SOC_DAI_ASYNC		0x8
 
 NOTE: Bitclock division and mulitiplication modes can be safely matched by the
 core logic.
@@ -181,7 +187,7 @@
 
 The BFS supported by the DAI mode. This can either be the ratio between the
 bitclock (BCLK) and the sample rate OR the ratio between the system clock and
-the sample rate. Depends on the SND_SOC_DAI_BFS_DIV flag above.
+the sample rate. Depends on the flags above.
 
 priv:
 -----
@@ -207,10 +213,15 @@
 BCLK of either MCLK/2 or MCLK/4.
 
 	/* codec master */
-	{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0),
-	SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
-	SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
-	256, SND_SOC_FSBD(2) | SND_SOC_FSBD(4)},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 256,
+		.bfs = SND_SOC_FSBD(2) | SND_SOC_FSBD(4),
+	}
 
 
 Example 2
@@ -219,32 +230,95 @@
 BCLK of either Rate * 32 or Rate * 64.
 
 	/* codec master */
-	{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0),
-	SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
-	SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, 0,
-	256, SND_SOC_FSB(32) | SND_SOC_FSB(64)},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 256,
+		.bfs = 32,
+	},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 256,
+		.bfs = 64,
+	},
 
 
 Example 3
 ---------
+Codec that runs at 8k & 48k @ 256FS in master mode, can generate a BCLK that
+is a multiple of Rate * channels * word size. (RCW) i.e.
+
+	BCLK = 8000 * 2 * 16 (8k, stereo, 16bit)
+	     = 256kHz
+
+This codecs supports a RCW multiple of 1,2
+
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_RCW,
+		.fs = 256,
+		.bfs = SND_SOC_FSBW(1) | SND_SOC_FSBW(2),
+	}
+
+
+Example 4
+---------
 Codec that only runs at 8k & 48k @ 256FS in master mode, can generate a
 BCLK of either Rate * 32 or Rate * 64. Codec can also run in slave mode as long
 as BCLK is rate * 32 or rate * 64.
 
 	/* codec master */
-	{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0),
-	SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
-	SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, 0,
-	256, SND_SOC_FSB(32) | SND_SOC_FSB(64)},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 256,
+		.bfs = 32,
+	},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 256,
+		.bfs = 64,
+	},
 
 	/* codec slave */
-	{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0),
-	SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
-	SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, 0,
-	SND_SOC_FS_ALL, SND_SOC_FSB(32) | SND_SOC_FSB(64)},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmdir = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = SND_SOC_FS_ALL,
+		.bfs = 32,
+	},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmdir = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = SND_SOC_FS_ALL,
+		.bfs = 64,
+	},
 
 
-Example 4
+Example 5
 ---------
 Codec that only runs at 8k, 16k, 32k, 48k, 96k @ 128FS, 192FS & 256FS in master
 mode and can generate a BCLK of MCLK / (1,2,4,8,16). Codec can also run in slave
@@ -259,29 +333,48 @@
 	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
 
 	/* codec master @ 128, 192 & 256 FS */
-	{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0),
-	SNDRV_PCM_FORMAT_S16_LE, CODEC_RATES,
-	SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
-	128, CODEC_FSB},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = CODEC_RATES,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 128,
+		.bfs = CODEC_FSB,
+	},
 
-	{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0),
-	SNDRV_PCM_FORMAT_S16_LE, CODEC_RATES,
-	SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
-	192, CODEC_FSB},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = CODEC_RATES,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 192,
+		.bfs = CODEC_FSB
+	},
 
-	{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0),
-	SNDRV_PCM_FORMAT_S16_LE, CODEC_RATES,
-	SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
-	256, CODEC_FSB},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = CODEC_RATES,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 256,
+		.bfs = CODEC_FSB,
+	},
 
 	/* codec slave */
-	{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0),
-	SNDRV_PCM_FORMAT_S16_LE, CODEC_RATES,
-	SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, 0,
-	SND_SOC_FS_ALL, SND_SOC_FSB_ALL},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = CODEC_RATES,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.fs = SND_SOC_FS_ALL,
+		.bfs = SND_SOC_FSB_ALL,
+	},
 
 
-Example 5
+Example 6
 ---------
 Codec that only runs at 8k, 44.1k, 48k @ different FS in master mode (for use
 with a fixed MCLK) and can generate a BCLK of MCLK / (1,2,4,8,16).
@@ -298,45 +391,66 @@
 	SNDRV_PCM_FORMAT_S24_3LE | SNDRV_PCM_FORMAT_S24_LE | SNDRV_PCM_FORMAT_S32_LE)
 
 	/* codec master */
-	{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0),
-	SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_RATE_8000,
-	SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
-	1536, CODEC_FSB},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_8000,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 1536,
+		.bfs = CODEC_FSB,
+	},
 
-	{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0),
-	SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_RATE_44100,
-	SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
-	272, CODEC_FSB},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_44100,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 272,
+		.bfs = CODEC_FSB,
+	},
 
-	{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0),
-	SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_RATE_48000,
-	SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
-	256, CODEC_FSB},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_48000,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 256,
+		.bfs = CODEC_FSB,
+	},
 
 	/* codec slave */
-	{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0),
-	SNDRV_PCM_FORMAT_S16_LE, CODEC_RATES,
-	SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, 0,
-	SND_SOC_FS_ALL, SND_SOC_FSB_ALL},
+	{
+		.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+		.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
+		.pcmrate = CODEC_RATES,
+		.pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+		.fs = SND_SOC_FS_ALL,
+		.bfs = SND_SOC_FSB_ALL,
+	},
 
 
-Example 6
+Example 7
 ---------
 AC97 Codec that does not support VRA (i.e only runs at 48k).
 
 	#define AC97_DIR \
 	(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
 
-
 	#define AC97_PCM_FORMATS \
 	(SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S18_3LE | \
 	SNDRV_PCM_FORMAT_S20_3LE)
 
 	/* AC97 with no VRA */
-	{0, 0,	AC97_PCM_FORMATS,	SNDRV_PCM_RATE_48000},
+	{
+		.pcmfmt = AC97_PCM_FORMATS,
+		.pcmrate = SNDRV_PCM_RATE_48000,
+	}
 
 
-Example 7
+Example 8
 ---------
 
 CPU DAI that supports 8k - 48k @ 256FS and BCLK = MCLK / 4 in master mode.
@@ -354,27 +468,79 @@
 	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
 	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
+	/* priv is divider */
+	static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = {
 	/* pxa2xx I2S frame and clock master modes */
-	{PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), SNDRV_PCM_FORMAT_S16_LE,
-		SNDRV_PCM_RATE_8000, PXA_I2S_DIR, SND_SOC_DAI_BFS_DIV, 256,
-		SND_SOC_FSBD(4), 0x48},
-	{PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), SNDRV_PCM_FORMAT_S16_LE,
-		SNDRV_PCM_RATE_11025, PXA_I2S_DIR, SND_SOC_DAI_BFS_DIV, 256,
-		SND_SOC_FSBD(4), 0x34},
-	{PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), SNDRV_PCM_FORMAT_S16_LE,
-		SNDRV_PCM_RATE_16000, PXA_I2S_DIR, SND_SOC_DAI_BFS_DIV, 256,
-		SND_SOC_FSBD(4), 0x24},
-	{PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), SNDRV_PCM_FORMAT_S16_LE,
-		SNDRV_PCM_RATE_22050, PXA_I2S_DIR, SND_SOC_DAI_BFS_DIV, 256,
-		SND_SOC_FSBD(4), 0x1a},
-	{PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), SNDRV_PCM_FORMAT_S16_LE,
-		SNDRV_PCM_RATE_44100, PXA_I2S_DIR, SND_SOC_DAI_BFS_DIV, 256,
-		SND_SOC_FSBD(4), 0xd},
-	{PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), SNDRV_PCM_FORMAT_S16_LE,
-		SNDRV_PCM_RATE_48000, PXA_I2S_DIR, SND_SOC_DAI_BFS_DIV, 256,
-		SND_SOC_FSBD(4), 0xc},
+	{
+		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
+		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_8000,
+		.pcmdir = PXA_I2S_DIR,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 256,
+		.bfs = SND_SOC_FSBD(4),
+		.priv = 0x48,
+	},
+	{
+		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
+		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_11025,
+		.pcmdir = PXA_I2S_DIR,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 256,
+		.bfs = SND_SOC_FSBD(4),
+		.priv = 0x34,
+	},
+	{
+		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
+		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_16000,
+		.pcmdir = PXA_I2S_DIR,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 256,
+		.bfs = SND_SOC_FSBD(4),
+		.priv = 0x24,
+	},
+	{
+		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
+		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_22050,
+		.pcmdir = PXA_I2S_DIR,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 256,
+		.bfs = SND_SOC_FSBD(4),
+		.priv = 0x1a,
+	},
+	{
+		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
+		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_44100,
+		.pcmdir = PXA_I2S_DIR,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 256,
+		.bfs = SND_SOC_FSBD(4),
+		.priv = 0xd,
+	},
+	{
+		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
+		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
+		.pcmrate = SNDRV_PCM_RATE_48000,
+		.pcmdir = PXA_I2S_DIR,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 256,
+		.bfs = SND_SOC_FSBD(4),
+		.priv = 0xc,
+	},
 
 	/* pxa2xx I2S frame master and clock slave mode */
-	{PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS, SND_SOC_DAITDM_LRDW(0,0), SNDRV_PCM_FORMAT_S16_LE,
-		PXA_I2S_RATES, PXA_I2S_DIR, 0, SND_SOC_FS_ALL, SND_SOC_FSB(64)},
-
+	{
+		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS,
+		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
+		.pcmrate = PXA_I2S_RATES,
+		.pcmdir = PXA_I2S_DIR,
+		.fs = SND_SOC_FS_ALL,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.bfs = 64,
+		.priv = 0x48,
+	},
+};
diff --git a/Documentation/sound/alsa/soc/clocking.txt b/Documentation/sound/alsa/soc/clocking.txt
index 88a16c9..1f55fd8 100644
--- a/Documentation/sound/alsa/soc/clocking.txt
+++ b/Documentation/sound/alsa/soc/clocking.txt
@@ -26,9 +26,9 @@
 
 The DAI also has a frame clock to signal the start of each audio frame. This
 clock is sometimes referred to as LRC (left right clock) or FRAME. This clock
-runs at exactly the sample rate.
+runs at exactly the sample rate (LRC = Rate).
 
-Bit Clock is usually always a ratio of MCLK or a multiple of LRC. i.e.
+Bit Clock can be generated as follows:-
 
 BCLK = MCLK / x
 
@@ -36,9 +36,14 @@
 
 BCLK = LRC * x
 
+ or
+
+BCLK = LRC * Channels * Word Size
+
 This relationship depends on the codec or SoC CPU in particular. ASoC can quite
-easily match a codec that generates BCLK by division (FSBD) with a CPU that
-generates BCLK by multiplication (FSB).
+easily match BCLK generated by division (SND_SOC_DAI_BFS_DIV) with BCLK by
+multiplication (SND_SOC_DAI_BFS_RATE) or BCLK generated  by
+Rate * Channels * Word size (RCW or SND_SOC_DAI_BFS_RCW).
 
 
 ASoC Clocking
diff --git a/include/sound/soc.h b/include/sound/soc.h
index ecdd1fa..3dfe052 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -21,7 +21,7 @@
 #include <sound/control.h>
 #include <sound/ac97_codec.h>
 
-#define SND_SOC_VERSION "0.11.8"
+#define SND_SOC_VERSION "0.12"
 
 /*
  * Convenience kcontrol builders
@@ -141,19 +141,24 @@
 /* bit clock dividers */
 #define SND_SOC_FSBD(x)			(1 << (x - 1))	/* ratio mclk:bclk */
 #define SND_SOC_FSBD_REAL(x)	(ffs(x))
-#define SND_SOC_FSBD_ALL		0xffff /* all bit clock dividers supported */
 
-/* bit clock ratio to sample rate */
-#define SND_SOC_FSB(x)			(1 << ((x - 16) / 16))
-#define SND_SOC_FSB_REAL(x)		(((ffs(x) - 1) * 16) + 16)
+/* bit clock ratio to (sample rate * channels * word size) */
+#define SND_SOC_FSBW(x)			(1 << (x - 1))
+#define SND_SOC_FSBW_REAL(x)		(ffs(x))
 /* all bclk ratios supported */
-#define SND_SOC_FSB_ALL			SND_SOC_FSBD_ALL
+#define SND_SOC_FSB_ALL			~0ULL
 
 /*
  * DAI hardware flags
  */
-/* use bfs mclk divider mode, else sample rate ratio */
-#define SND_SOC_DAI_BFS_DIV	0x1
+/* use bfs mclk divider mode (BCLK = MCLK / x) */
+#define SND_SOC_DAI_BFS_DIV		0x1
+/* use bfs rate mulitplier  (BCLK = RATE * x)*/
+#define SND_SOC_DAI_BFS_RATE	0x2
+/* use bfs rcw multiplier (BCLK = RATE * CHN * WORD SIZE) */
+#define SND_SOC_DAI_BFS_RCW		0x4
+/* capture and playback can use different clocks */
+#define SND_SOC_DAI_ASYNC		0x8
 
 /*
  * AC97 codec ID's bitmask
@@ -264,7 +269,7 @@
 	u16 pcmdir:2;	/* SND_SOC_HWDIR_* */
 	u16 flags:8;	/* hw flags */
 	u16 fs;			/* mclk to rate divider */
-	u32 bfs;		/* mclk to bclk dividers */
+	u64 bfs;		/* mclk to bclk dividers */
 	unsigned long priv;		/* private mode data */
 };
 
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 9adbd2d..4122912 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -90,32 +90,36 @@
 		.pcmfmt = WM8731_HIFI_BITS,
 		.pcmrate = SNDRV_PCM_RATE_8000,
 		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
 		.fs = 1536,
-		.bfs = SND_SOC_FSB(64),
+		.bfs = 64,
 	},
 	{
 		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
 		.pcmfmt = WM8731_HIFI_BITS,
 		.pcmrate = SNDRV_PCM_RATE_8000,
 		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
 		.fs = 2304,
-		.bfs = SND_SOC_FSB(64),
+		.bfs = 64,
 	},
 	{
 		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
 		.pcmfmt = WM8731_HIFI_BITS,
 		.pcmrate = SNDRV_PCM_RATE_8000,
 		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
 		.fs = 1408,
-		.bfs = SND_SOC_FSB(64),
+		.bfs = 64,
 	},
 	{
 		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
 		.pcmfmt = WM8731_HIFI_BITS,
 		.pcmrate = SNDRV_PCM_RATE_8000,
 		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
 		.fs = 2112,
-		.bfs = SND_SOC_FSB(64),
+		.bfs = 64,
 	},
 
 	/* 32k */
@@ -124,16 +128,18 @@
 		.pcmfmt = WM8731_HIFI_BITS,
 		.pcmrate = SNDRV_PCM_RATE_32000,
 		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
 		.fs = 384,
-		.bfs = SND_SOC_FSB(64),
+		.bfs = 64,
 	},
 	{
 		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
 		.pcmfmt = WM8731_HIFI_BITS,
 		.pcmrate = SNDRV_PCM_RATE_32000,
 		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
 		.fs = 576,
-		.bfs = SND_SOC_FSB(64),
+		.bfs = 64,
 	},
 
 	/* 44.1k & 48k */
@@ -142,16 +148,18 @@
 		.pcmfmt = WM8731_HIFI_BITS,
 		.pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
 		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
 		.fs = 256,
-		.bfs = SND_SOC_FSB(64),
+		.bfs = 64,
 	},
 	{
 		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
 		.pcmfmt = WM8731_HIFI_BITS,
 		.pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
 		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
 		.fs = 384,
-		.bfs = SND_SOC_FSB(64),
+		.bfs = 64,
 	},
 
 	/* 88.2 & 96k */
@@ -160,17 +168,18 @@
 		.pcmfmt = WM8731_HIFI_BITS,
 		.pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000,
 		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
 		.fs = 128,
-		.bfs = SND_SOC_FSB(64),
-		
+		.bfs = 64,
 	},
 	{
 		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
 		.pcmfmt = WM8731_HIFI_BITS,
 		.pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000,
 		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
 		.fs = 192,
-		.bfs = SND_SOC_FSB(64),
+		.bfs = 64,
 	},
 
 	/* USB codec frame and clock master modes */
@@ -237,7 +246,7 @@
 		.pcmdir = WM8731_DIR,
 		.flags = SND_SOC_DAI_BFS_DIV,
 		.fs = SND_SOC_FS_ALL,
-		.bfs = SND_SOC_FSBD_ALL,
+		.bfs = SND_SOC_FSB_ALL,
 	},
 };
 
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 243da71..c5d13a9 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -343,7 +343,7 @@
 		.pcmdir = WM8750_DIR,
 		.flags = SND_SOC_DAI_BFS_DIV,
 		.fs = SND_SOC_FS_ALL,
-		.bfs = SND_SOC_FSBD_ALL,
+		.bfs = SND_SOC_FSB_ALL,
 	},
 };
 
@@ -829,6 +829,9 @@
 		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
 			return i;
 	}
+
+	printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n",
+		mclk, rate);
 	return -EINVAL;
 }
 
@@ -836,13 +839,7 @@
 static unsigned int wm8750_config_sysclk(struct snd_soc_codec_dai *dai,
 	struct snd_soc_clock_info *info, unsigned int clk)
 {
-	dai->mclk = 0;
-
-	/* check that the calculated FS and rate actually match a clock from
-	 * the machine driver */
-	if (info->fs * info->rate == clk)
-		dai->mclk = clk;
-
+	dai->mclk = clk;
 	return dai->mclk;
 }
 
@@ -859,7 +856,7 @@
 	if (i < 0)
 		return i;
 
-	bfs = SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs);
+	bfs = SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs);
 
 	/* set master/slave audio interface */
 	switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 99f1da3..98b167f 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -126,7 +126,8 @@
 		.pcmrate = PXA_I2S_RATES,
 		.pcmdir = PXA_I2S_DIR,
 		.fs = SND_SOC_FS_ALL,
-		.bfs = SND_SOC_FSB(64),
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.bfs = 64,
 		.priv = 0x48,
 	},
 };
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 2ce0c82..6da1616 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -51,6 +51,8 @@
 #define dbgc(format, arg...)
 #endif
 
+#define CODEC_CPU(codec, cpu)	((codec << 4) | cpu)
+
 static DEFINE_MUTEX(pcm_mutex);
 static DEFINE_MUTEX(io_mutex);
 static struct workqueue_struct *soc_workq;
@@ -150,11 +152,11 @@
 }
 
 /* changes a bitclk multiplier mask to a divider mask */
-static u16 soc_bfs_mult_to_div(u16 bfs, int rate, unsigned int mclk,
+static u64 soc_bfs_rcw_to_div(u64 bfs, int rate, unsigned int mclk,
 	unsigned int pcmfmt, unsigned int chn)
 {
 	int i, j;
-	u16 bfs_ = 0;
+	u64 bfs_ = 0;
 	int size = snd_pcm_format_physical_width(pcmfmt), min = 0;
 
 	if (size <= 0)
@@ -162,17 +164,14 @@
 
 	/* the minimum bit clock that has enough bandwidth */
 	min = size * rate * chn;
-	dbgc("mult --> div min bclk %d with mclk %d\n", min, mclk);
+	dbgc("rcw --> div min bclk %d with mclk %d\n", min, mclk);
 
-	for (i = 0; i < 16; i++) {
+	for (i = 0; i < 64; i++) {
 		if ((bfs >> i) & 0x1) {
-			j = rate * SND_SOC_FSB_REAL(1<<i);
-
-			if (j >= min) {
-				bfs_ |= SND_SOC_FSBD(mclk/j);
-				dbgc("mult --> div support mult %d\n",
-					SND_SOC_FSB_REAL(1<<i));
-			}
+			j = min * (i + 1);
+			bfs_ |= SND_SOC_FSBD(mclk/j);
+			dbgc("rcw --> div support mult %d\n",
+				SND_SOC_FSBD_REAL(1<<i));
 		}
 	}
 
@@ -180,11 +179,11 @@
 }
 
 /* changes a bitclk divider mask to a multiplier mask */
-static u16 soc_bfs_div_to_mult(u16 bfs, int rate, unsigned int mclk,
+static u64 soc_bfs_div_to_rcw(u64 bfs, int rate, unsigned int mclk,
 	unsigned int pcmfmt, unsigned int chn)
 {
 	int i, j;
-	u16 bfs_ = 0;
+	u64 bfs_ = 0;
 
 	int size = snd_pcm_format_physical_width(pcmfmt), min = 0;
 
@@ -193,15 +192,15 @@
 
 	/* the minimum bit clock that has enough bandwidth */
 	min = size * rate * chn;
-	dbgc("div to mult min bclk %d with mclk %d\n", min, mclk);
+	dbgc("div to rcw min bclk %d with mclk %d\n", min, mclk);
 
-	for (i = 0; i < 16; i++) {
+	for (i = 0; i < 64; i++) {
 		if ((bfs >> i) & 0x1) {
-			j = mclk / (SND_SOC_FSBD_REAL(1<<i));
+			j = mclk / (i + 1);
 			if (j >= min) {
-				bfs_ |= SND_SOC_FSB(j/rate);
-				dbgc("div --> mult support div %d\n",
-					SND_SOC_FSBD_REAL(1<<i));
+				bfs_ |= SND_SOC_FSBW(j/min);
+				dbgc("div --> rcw support div %d\n",
+					SND_SOC_FSBW_REAL(1<<i));
 			}
 		}
 	}
@@ -209,6 +208,52 @@
 	return bfs_;
 }
 
+/* changes a constant bitclk to a multiplier mask */
+static u64 soc_bfs_rate_to_rcw(u64 bfs, int rate, unsigned int mclk,
+	unsigned int pcmfmt, unsigned int chn)
+{
+	unsigned int bfs_ = rate * bfs;
+	int size = snd_pcm_format_physical_width(pcmfmt), min = 0;
+
+	if (size <= 0)
+		return 0;
+
+	/* the minimum bit clock that has enough bandwidth */
+	min = size * rate * chn;
+	dbgc("rate --> rcw min bclk %d with mclk %d\n", min, mclk);
+
+	if (bfs_ < min)
+		return 0;
+	else {
+		bfs_ = SND_SOC_FSBW(bfs_/min);
+		dbgc("rate --> rcw support div %d\n", SND_SOC_FSBW_REAL(bfs_));
+		return bfs_;
+	}
+}
+
+/* changes a bitclk multiplier mask to a divider mask */
+static u64 soc_bfs_rate_to_div(u64 bfs, int rate, unsigned int mclk,
+	unsigned int pcmfmt, unsigned int chn)
+{
+	unsigned int bfs_ = rate * bfs;
+	int size = snd_pcm_format_physical_width(pcmfmt), min = 0;
+
+	if (size <= 0)
+		return 0;
+
+	/* the minimum bit clock that has enough bandwidth */
+	min = size * rate * chn;
+	dbgc("rate --> div min bclk %d with mclk %d\n", min, mclk);
+
+	if (bfs_ < min)
+		return 0;
+	else {
+		bfs_ = SND_SOC_FSBW(mclk/bfs_);
+		dbgc("rate --> div support div %d\n", SND_SOC_FSBD_REAL(bfs_));
+		return bfs_;
+	}
+}
+
 /* Matches codec DAI and SoC CPU DAI hardware parameters */
 static int soc_hw_match_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
@@ -217,9 +262,10 @@
 	struct snd_soc_dai_mode *codec_dai_mode = NULL;
 	struct snd_soc_dai_mode *cpu_dai_mode = NULL;
 	struct snd_soc_clock_info clk_info;
-	unsigned int fs, mclk, codec_bfs, cpu_bfs, rate = params_rate(params),
+	unsigned int fs, mclk, rate = params_rate(params),
 		chn, j, k, cpu_bclk, codec_bclk, pcmrate;
 	u16 fmt = 0;
+	u64 codec_bfs, cpu_bfs;
 
 	dbg("asoc: match version %s\n", SND_SOC_VERSION);
 	clk_info.rate = rate;
@@ -309,44 +355,98 @@
 			 * used in the codec and cpu DAI modes. We always choose the
 			 * lowest possible clocks to reduce power.
 			 */
-			if (codec_dai_mode->flags & cpu_dai_mode->flags &
-				SND_SOC_DAI_BFS_DIV) {
+			switch (CODEC_CPU(codec_dai_mode->flags, cpu_dai_mode->flags)) {
+			case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_DIV):
 				/* cpu & codec bfs dividers */
 				rtd->cpu_dai->dai_runtime.bfs =
 					rtd->codec_dai->dai_runtime.bfs =
 					1 << (fls(codec_dai_mode->bfs & cpu_dai_mode->bfs) - 1);
-			} else if (codec_dai_mode->flags & SND_SOC_DAI_BFS_DIV) {
-				/* normalise bfs codec divider & cpu mult */
-				codec_bfs = soc_bfs_div_to_mult(codec_dai_mode->bfs, rate,
+				break;
+			case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_RCW):
+				/* normalise bfs codec divider & cpu rcw mult */
+				codec_bfs = soc_bfs_div_to_rcw(codec_dai_mode->bfs, rate,
 					mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn);
 				rtd->cpu_dai->dai_runtime.bfs =
 					1 << (ffs(codec_bfs & cpu_dai_mode->bfs) - 1);
-				cpu_bfs = soc_bfs_mult_to_div(cpu_dai_mode->bfs, rate, mclk,
+				cpu_bfs = soc_bfs_rcw_to_div(cpu_dai_mode->bfs, rate, mclk,
 						rtd->codec_dai->dai_runtime.pcmfmt, chn);
 				rtd->codec_dai->dai_runtime.bfs =
 					1 << (fls(codec_dai_mode->bfs & cpu_bfs) - 1);
-			} else if (cpu_dai_mode->flags & SND_SOC_DAI_BFS_DIV) {
-				/* normalise bfs codec mult & cpu divider */
-				codec_bfs = soc_bfs_mult_to_div(codec_dai_mode->bfs, rate,
+				break;
+			case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_DIV):
+				/* normalise bfs codec rcw mult & cpu divider */
+				codec_bfs = soc_bfs_rcw_to_div(codec_dai_mode->bfs, rate,
 					mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn);
 				rtd->cpu_dai->dai_runtime.bfs =
 					1 << (fls(codec_bfs & cpu_dai_mode->bfs) -1);
-				cpu_bfs = soc_bfs_div_to_mult(cpu_dai_mode->bfs, rate, mclk,
+				cpu_bfs = soc_bfs_div_to_rcw(cpu_dai_mode->bfs, rate, mclk,
 						rtd->codec_dai->dai_runtime.pcmfmt, chn);
 				rtd->codec_dai->dai_runtime.bfs =
 					1 << (ffs(codec_dai_mode->bfs & cpu_bfs) -1);
-			} else {
-				/* codec & cpu bfs rate multipliers */
+				break;
+			case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_RCW):
+				/* codec & cpu bfs rate rcw multipliers */
 				rtd->cpu_dai->dai_runtime.bfs =
 					rtd->codec_dai->dai_runtime.bfs =
 					1 << (ffs(codec_dai_mode->bfs & cpu_dai_mode->bfs) -1);
+				break;
+			case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_RATE):
+				/* normalise cpu bfs rate const multiplier & codec div */
+				cpu_bfs = soc_bfs_rate_to_div(cpu_dai_mode->bfs, rate,
+					mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn);
+				if(codec_dai_mode->bfs & cpu_bfs) {
+					rtd->codec_dai->dai_runtime.bfs = cpu_bfs;
+					rtd->cpu_dai->dai_runtime.bfs = cpu_dai_mode->bfs;
+				} else
+					rtd->cpu_dai->dai_runtime.bfs = 0;
+				break;
+			case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_RATE):
+				/* normalise cpu bfs rate const multiplier & codec rcw mult */
+				cpu_bfs = soc_bfs_rate_to_rcw(cpu_dai_mode->bfs, rate,
+					mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn);
+				if(codec_dai_mode->bfs & cpu_bfs) {
+					rtd->codec_dai->dai_runtime.bfs = cpu_bfs;
+					rtd->cpu_dai->dai_runtime.bfs = cpu_dai_mode->bfs;
+				} else
+					rtd->cpu_dai->dai_runtime.bfs = 0;
+				break;
+			case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_RCW):
+				/* normalise cpu bfs rate rcw multiplier & codec const mult */
+				codec_bfs = soc_bfs_rate_to_rcw(codec_dai_mode->bfs, rate,
+					mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn);
+				if(cpu_dai_mode->bfs & codec_bfs) {
+					rtd->cpu_dai->dai_runtime.bfs = codec_bfs;
+					rtd->codec_dai->dai_runtime.bfs = codec_dai_mode->bfs;
+				} else
+					rtd->cpu_dai->dai_runtime.bfs = 0;
+				break;
+			case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_DIV):
+				/* normalise cpu bfs div & codec const mult */
+				codec_bfs = soc_bfs_rate_to_div(codec_dai_mode->bfs, rate,
+					mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn);
+				if(codec_dai_mode->bfs & codec_bfs) {
+					rtd->cpu_dai->dai_runtime.bfs = codec_bfs;
+					rtd->codec_dai->dai_runtime.bfs = codec_dai_mode->bfs;
+				} else
+					rtd->cpu_dai->dai_runtime.bfs = 0;
+				break;
+			case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_RATE):
+				/* cpu & codec constant mult */
+				if(codec_dai_mode->bfs == cpu_dai_mode->bfs)
+					rtd->cpu_dai->dai_runtime.bfs =
+						rtd->codec_dai->dai_runtime.bfs =
+						codec_dai_mode->bfs;
+				else
+					rtd->cpu_dai->dai_runtime.bfs =
+						rtd->codec_dai->dai_runtime.bfs = 0;
+				break;
 			}
 
 			/* make sure the bit clock speed is acceptable */
 			if (!rtd->cpu_dai->dai_runtime.bfs ||
 				!rtd->codec_dai->dai_runtime.bfs) {
 				dbgc("asoc: DAI[%d:%d] failed to match BFS\n", j, k);
-				dbgc("asoc: cpu_dai %x codec %x\n",
+				dbgc("asoc: cpu_dai %llu codec %llu\n",
 					rtd->cpu_dai->dai_runtime.bfs,
 					rtd->codec_dai->dai_runtime.bfs);
 				dbgc("asoc: mclk %d hwfmt %x\n", mclk, fmt);
@@ -378,26 +478,41 @@
 		dbg("asoc: codec fs %d mclk %d bfs div %d bclk %d\n",
 			rtd->codec_dai->dai_runtime.fs, mclk,
 			SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs),	codec_bclk);
-	} else {
-		codec_bclk = params_rate(params) *
-			SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs);
-		dbg("asoc: codec fs %d mclk %d bfs mult %d bclk %d\n",
+	} else if(rtd->codec_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RATE) {
+		codec_bclk = params_rate(params) * rtd->codec_dai->dai_runtime.bfs;
+		dbg("asoc: codec fs %d mclk %d bfs rate mult %llu bclk %d\n",
 			rtd->codec_dai->dai_runtime.fs, mclk,
-			SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk);
-	}
+			rtd->codec_dai->dai_runtime.bfs, codec_bclk);
+	} else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RCW) {
+		codec_bclk = params_rate(params) * params_channels(params) *
+			snd_pcm_format_physical_width(rtd->codec_dai->dai_runtime.pcmfmt) *
+			SND_SOC_FSBW_REAL(rtd->codec_dai->dai_runtime.bfs);
+		dbg("asoc: codec fs %d mclk %d bfs rcw mult %d bclk %d\n",
+			rtd->codec_dai->dai_runtime.fs, mclk,
+			SND_SOC_FSBW_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk);
+	} else
+		codec_bclk = 0;
+
 	if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) {
 		cpu_bclk = (rtd->cpu_dai->dai_runtime.fs * params_rate(params)) /
 			SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs);
 		dbg("asoc: cpu fs %d mclk %d bfs div %d bclk %d\n",
 			rtd->cpu_dai->dai_runtime.fs, mclk,
 			SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk);
-	} else {
-		cpu_bclk = params_rate(params) *
-			SND_SOC_FSB_REAL(rtd->cpu_dai->dai_runtime.bfs);
-		dbg("asoc: cpu fs %d mclk %d bfs mult %d bclk %d\n",
+	} else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RATE) {
+		cpu_bclk = params_rate(params) * rtd->cpu_dai->dai_runtime.bfs;
+		dbg("asoc: cpu fs %d mclk %d bfs rate mult %llu bclk %d\n",
 			rtd->cpu_dai->dai_runtime.fs, mclk,
-			SND_SOC_FSB_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk);
-	}
+			rtd->cpu_dai->dai_runtime.bfs, cpu_bclk);
+	} else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RCW) {
+		cpu_bclk = params_rate(params) * params_channels(params) *
+			snd_pcm_format_physical_width(rtd->cpu_dai->dai_runtime.pcmfmt) *
+			SND_SOC_FSBW_REAL(rtd->cpu_dai->dai_runtime.bfs);
+		dbg("asoc: cpu fs %d mclk %d bfs mult rcw %d bclk %d\n",
+			rtd->cpu_dai->dai_runtime.fs, mclk,
+			SND_SOC_FSBW_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk);
+	} else
+		cpu_bclk = 0;
 
 	/*
 	 * Check we have matching bitclocks. If we don't then it means the
@@ -405,7 +520,7 @@
 	 * machine sysclock function) is wrong compared with the supported DAI
 	 * modes for the codec or cpu DAI.
 	 */
-	if (cpu_bclk != codec_bclk){
+	if (cpu_bclk != codec_bclk && cpu_bclk){
 		printk(KERN_ERR
 			"asoc: codec and cpu bitclocks differ, audio may be wrong speed\n"
 			);
@@ -723,14 +838,18 @@
 	mutex_lock(&pcm_mutex);
 	if (platform->pcm_ops->prepare) {
 		ret = platform->pcm_ops->prepare(substream);
-		if (ret < 0)
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: platform prepare error\n");
 			goto out;
+		}
 	}
 
 	if (rtd->codec_dai->ops.prepare) {
 		ret = rtd->codec_dai->ops.prepare(substream);
-		if (ret < 0)
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: codec DAI prepare error\n");
 			goto out;
+		}
 	}
 
 	if (rtd->cpu_dai->ops.prepare)