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
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:
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
--------
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.
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:
-----
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
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
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},
-
- {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},
-
- {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 = 128,
+ .bfs = 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
+ },
+
+ {
+ .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).
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},
-
- {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},
-
- {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_8000,
+ .pcmdir = SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE,
+ .flags = SND_SOC_DAI_BFS_DIV,
+ .fs = 1536,
+ .bfs = 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,
+ },
+
+ {
+ .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.
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,
+ },
+};
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
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
#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
/* 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
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 */
};
.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 */
.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 */
.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 */
.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 */
.pcmdir = WM8731_DIR,
.flags = SND_SOC_DAI_BFS_DIV,
.fs = SND_SOC_FS_ALL,
- .bfs = SND_SOC_FSBD_ALL,
+ .bfs = SND_SOC_FSB_ALL,
},
};
.pcmdir = WM8750_DIR,
.flags = SND_SOC_DAI_BFS_DIV,
.fs = SND_SOC_FS_ALL,
- .bfs = SND_SOC_FSBD_ALL,
+ .bfs = SND_SOC_FSB_ALL,
},
};
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;
}
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;
}
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) {
.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,
},
};
#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;
}
/* 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)
/* 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));
}
}
}
/* 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;
/* 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));
}
}
}
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)
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;
* 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);
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
* 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"
);
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)