mirror of
https://github.com/torvalds/linux.git
synced 2024-12-27 21:33:00 +00:00
[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>
This commit is contained in:
parent
543a0fbe18
commit
a71a468a50
@ -12,7 +12,8 @@ The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the
|
|||||||
frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97
|
frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97
|
||||||
frame is 21uS long and is divided into 13 time slots.
|
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
|
I2S
|
||||||
@ -77,16 +78,16 @@ sample rates first and then test your interface.
|
|||||||
struct snd_soc_dai_mode is defined (in soc.h) as:-
|
struct snd_soc_dai_mode is defined (in soc.h) as:-
|
||||||
|
|
||||||
/* SoC DAI mode */
|
/* SoC DAI mode */
|
||||||
struct snd_soc_hw_mode {
|
struct snd_soc_dai_mode {
|
||||||
unsigned int fmt:16; /* SND_SOC_DAIFMT_* */
|
u16 fmt; /* SND_SOC_DAIFMT_* */
|
||||||
unsigned int tdm:16; /* SND_SOC_DAITDM_* */
|
u16 tdm; /* SND_SOC_HWTDM_* */
|
||||||
unsigned int pcmfmt:6; /* SNDRV_PCM_FORMAT_* */
|
u64 pcmfmt; /* SNDRV_PCM_FMTBIT_* */
|
||||||
unsigned int pcmrate:16; /* SND_SOC_DAIRATE_* */
|
u16 pcmrate; /* SND_SOC_HWRATE_* */
|
||||||
unsigned int pcmdir:2; /* SND_SOC_DAIDIR_* */
|
u16 pcmdir:2; /* SND_SOC_HWDIR_* */
|
||||||
unsigned int flags:8; /* hw flags */
|
u16 flags:8; /* hw flags */
|
||||||
unsigned int fs:32; /* mclk to rate dividers */
|
u16 fs; /* mclk to rate divider */
|
||||||
unsigned int bfs:16; /* mclk to bclk dividers */
|
u64 bfs; /* mclk to bclk dividers */
|
||||||
unsigned long priv; /* private mode data */
|
unsigned long priv; /* private mode data */
|
||||||
};
|
};
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
@ -140,14 +141,14 @@ pcmfmt:
|
|||||||
The hardware PCM format. This describes the PCM formats supported by the DAI
|
The hardware PCM format. This describes the PCM formats supported by the DAI
|
||||||
mode e.g.
|
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
|
SNDRV_PCM_FORMAT_S24_3LE
|
||||||
|
|
||||||
pcmrate:
|
pcmrate:
|
||||||
----------
|
----------
|
||||||
The PCM sample rates supported by the DAI mode. e.g.
|
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_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
|
||||||
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000
|
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000
|
||||||
|
|
||||||
@ -161,9 +162,14 @@ flags:
|
|||||||
--------
|
--------
|
||||||
The DAI hardware flags supported by the mode.
|
The DAI hardware flags supported by the mode.
|
||||||
|
|
||||||
SND_SOC_DAI_BFS_DIV
|
/* use bfs mclk divider mode (BCLK = MCLK / x) */
|
||||||
This flag states that bit clock is generated by dividing MCLK in this mode, if
|
#define SND_SOC_DAI_BFS_DIV 0x1
|
||||||
this flag is absent the bitclock generated by mulitiplying sample rate.
|
/* 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
|
NOTE: Bitclock division and mulitiplication modes can be safely matched by the
|
||||||
core logic.
|
core logic.
|
||||||
@ -181,7 +187,7 @@ depends on the codec or CPU DAI).
|
|||||||
|
|
||||||
The BFS supported by the DAI mode. This can either be the ratio between the
|
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
|
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:
|
priv:
|
||||||
-----
|
-----
|
||||||
@ -207,10 +213,15 @@ Simple codec that only runs at 8k & 48k @ 256FS in master mode, can generate a
|
|||||||
BCLK of either MCLK/2 or MCLK/4.
|
BCLK of either MCLK/2 or MCLK/4.
|
||||||
|
|
||||||
/* codec master */
|
/* 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,
|
.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
|
.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
|
||||||
256, SND_SOC_FSBD(2) | SND_SOC_FSBD(4)},
|
.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
|
Example 2
|
||||||
@ -219,32 +230,95 @@ Simple codec that only runs at 8k & 48k @ 256FS in master mode, can generate a
|
|||||||
BCLK of either Rate * 32 or Rate * 64.
|
BCLK of either Rate * 32 or Rate * 64.
|
||||||
|
|
||||||
/* codec master */
|
/* 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,
|
.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, 0,
|
.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
|
||||||
256, SND_SOC_FSB(32) | SND_SOC_FSB(64)},
|
.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
|
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
|
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
|
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.
|
as BCLK is rate * 32 or rate * 64.
|
||||||
|
|
||||||
/* codec master */
|
/* 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,
|
.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, 0,
|
.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
|
||||||
256, SND_SOC_FSB(32) | SND_SOC_FSB(64)},
|
.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 */
|
/* 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,
|
.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
|
||||||
SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, 0,
|
.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
|
||||||
SND_SOC_FS_ALL, SND_SOC_FSB(32) | SND_SOC_FSB(64)},
|
.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
|
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
|
mode and can generate a BCLK of MCLK / (1,2,4,8,16). Codec can also run in slave
|
||||||
@ -259,29 +333,48 @@ mode as and does not care about FS or BCLK (as long as there is enough bandwidth
|
|||||||
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
|
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
|
||||||
|
|
||||||
/* codec master @ 128, 192 & 256 FS */
|
/* 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,
|
.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
|
.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
|
||||||
128, CODEC_FSB},
|
.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,
|
.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
|
.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
|
||||||
192, CODEC_FSB},
|
.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,
|
.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
|
.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
|
||||||
256, CODEC_FSB},
|
.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 */
|
/* codec slave */
|
||||||
{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0),
|
{
|
||||||
SNDRV_PCM_FORMAT_S16_LE, CODEC_RATES,
|
.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
|
||||||
SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, 0,
|
.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
|
||||||
SND_SOC_FS_ALL, SND_SOC_FSB_ALL},
|
.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
|
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).
|
with a fixed MCLK) and can generate a BCLK of MCLK / (1,2,4,8,16).
|
||||||
@ -298,45 +391,66 @@ sizes.
|
|||||||
SNDRV_PCM_FORMAT_S24_3LE | SNDRV_PCM_FORMAT_S24_LE | SNDRV_PCM_FORMAT_S32_LE)
|
SNDRV_PCM_FORMAT_S24_3LE | SNDRV_PCM_FORMAT_S24_LE | SNDRV_PCM_FORMAT_S32_LE)
|
||||||
|
|
||||||
/* codec master */
|
/* 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,
|
.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
|
.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
|
||||||
1536, CODEC_FSB},
|
.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,
|
.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
|
.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
|
||||||
272, CODEC_FSB},
|
.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,
|
.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, SND_SOC_DAI_BFS_DIV,
|
.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
|
||||||
256, CODEC_FSB},
|
.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 */
|
/* codec slave */
|
||||||
{SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0),
|
{
|
||||||
SNDRV_PCM_FORMAT_S16_LE, CODEC_RATES,
|
.fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
|
||||||
SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE, 0,
|
.pcmfmt = SNDRV_PCM_FORMAT_S16_LE,
|
||||||
SND_SOC_FS_ALL, SND_SOC_FSB_ALL},
|
.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).
|
AC97 Codec that does not support VRA (i.e only runs at 48k).
|
||||||
|
|
||||||
#define AC97_DIR \
|
#define AC97_DIR \
|
||||||
(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
|
(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
|
||||||
|
|
||||||
|
|
||||||
#define AC97_PCM_FORMATS \
|
#define AC97_PCM_FORMATS \
|
||||||
(SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S18_3LE | \
|
(SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S18_3LE | \
|
||||||
SNDRV_PCM_FORMAT_S20_3LE)
|
SNDRV_PCM_FORMAT_S20_3LE)
|
||||||
|
|
||||||
/* AC97 with no VRA */
|
/* 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.
|
CPU DAI that supports 8k - 48k @ 256FS and BCLK = MCLK / 4 in master mode.
|
||||||
@ -354,27 +468,79 @@ BCLK = 64 * rate. (Intel XScale I2S controller).
|
|||||||
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
|
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
|
||||||
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
|
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 */
|
/* 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,
|
.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
|
||||||
SND_SOC_FSBD(4), 0x48},
|
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
|
||||||
{PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), SNDRV_PCM_FORMAT_S16_LE,
|
.pcmrate = SNDRV_PCM_RATE_8000,
|
||||||
SNDRV_PCM_RATE_11025, PXA_I2S_DIR, SND_SOC_DAI_BFS_DIV, 256,
|
.pcmdir = PXA_I2S_DIR,
|
||||||
SND_SOC_FSBD(4), 0x34},
|
.flags = SND_SOC_DAI_BFS_DIV,
|
||||||
{PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), SNDRV_PCM_FORMAT_S16_LE,
|
.fs = 256,
|
||||||
SNDRV_PCM_RATE_16000, PXA_I2S_DIR, SND_SOC_DAI_BFS_DIV, 256,
|
.bfs = SND_SOC_FSBD(4),
|
||||||
SND_SOC_FSBD(4), 0x24},
|
.priv = 0x48,
|
||||||
{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},
|
.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
|
||||||
{PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), SNDRV_PCM_FORMAT_S16_LE,
|
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
|
||||||
SNDRV_PCM_RATE_44100, PXA_I2S_DIR, SND_SOC_DAI_BFS_DIV, 256,
|
.pcmrate = SNDRV_PCM_RATE_11025,
|
||||||
SND_SOC_FSBD(4), 0xd},
|
.pcmdir = PXA_I2S_DIR,
|
||||||
{PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), SNDRV_PCM_FORMAT_S16_LE,
|
.flags = SND_SOC_DAI_BFS_DIV,
|
||||||
SNDRV_PCM_RATE_48000, PXA_I2S_DIR, SND_SOC_DAI_BFS_DIV, 256,
|
.fs = 256,
|
||||||
SND_SOC_FSBD(4), 0xc},
|
.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 */
|
/* 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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -26,9 +26,9 @@ between the codec and CPU.
|
|||||||
|
|
||||||
The DAI also has a frame clock to signal the start of each audio frame. This
|
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
|
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 = MCLK / x
|
||||||
|
|
||||||
@ -36,9 +36,14 @@ BCLK = MCLK / x
|
|||||||
|
|
||||||
BCLK = LRC * x
|
BCLK = LRC * x
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
BCLK = LRC * Channels * Word Size
|
||||||
|
|
||||||
This relationship depends on the codec or SoC CPU in particular. ASoC can quite
|
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
|
easily match BCLK generated by division (SND_SOC_DAI_BFS_DIV) with BCLK by
|
||||||
generates BCLK by multiplication (FSB).
|
multiplication (SND_SOC_DAI_BFS_RATE) or BCLK generated by
|
||||||
|
Rate * Channels * Word size (RCW or SND_SOC_DAI_BFS_RCW).
|
||||||
|
|
||||||
|
|
||||||
ASoC Clocking
|
ASoC Clocking
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
#include <sound/ac97_codec.h>
|
#include <sound/ac97_codec.h>
|
||||||
|
|
||||||
#define SND_SOC_VERSION "0.11.8"
|
#define SND_SOC_VERSION "0.12"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convenience kcontrol builders
|
* Convenience kcontrol builders
|
||||||
@ -141,19 +141,24 @@
|
|||||||
/* bit clock dividers */
|
/* bit clock dividers */
|
||||||
#define SND_SOC_FSBD(x) (1 << (x - 1)) /* ratio mclk:bclk */
|
#define SND_SOC_FSBD(x) (1 << (x - 1)) /* ratio mclk:bclk */
|
||||||
#define SND_SOC_FSBD_REAL(x) (ffs(x))
|
#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 */
|
/* bit clock ratio to (sample rate * channels * word size) */
|
||||||
#define SND_SOC_FSB(x) (1 << ((x - 16) / 16))
|
#define SND_SOC_FSBW(x) (1 << (x - 1))
|
||||||
#define SND_SOC_FSB_REAL(x) (((ffs(x) - 1) * 16) + 16)
|
#define SND_SOC_FSBW_REAL(x) (ffs(x))
|
||||||
/* all bclk ratios supported */
|
/* all bclk ratios supported */
|
||||||
#define SND_SOC_FSB_ALL SND_SOC_FSBD_ALL
|
#define SND_SOC_FSB_ALL ~0ULL
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DAI hardware flags
|
* DAI hardware flags
|
||||||
*/
|
*/
|
||||||
/* use bfs mclk divider mode, else sample rate ratio */
|
/* use bfs mclk divider mode (BCLK = MCLK / x) */
|
||||||
#define SND_SOC_DAI_BFS_DIV 0x1
|
#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
|
* AC97 codec ID's bitmask
|
||||||
@ -264,7 +269,7 @@ struct snd_soc_dai_mode {
|
|||||||
u16 pcmdir:2; /* SND_SOC_HWDIR_* */
|
u16 pcmdir:2; /* SND_SOC_HWDIR_* */
|
||||||
u16 flags:8; /* hw flags */
|
u16 flags:8; /* hw flags */
|
||||||
u16 fs; /* mclk to rate divider */
|
u16 fs; /* mclk to rate divider */
|
||||||
u32 bfs; /* mclk to bclk dividers */
|
u64 bfs; /* mclk to bclk dividers */
|
||||||
unsigned long priv; /* private mode data */
|
unsigned long priv; /* private mode data */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -90,32 +90,36 @@ static struct snd_soc_dai_mode wm8731_modes[] = {
|
|||||||
.pcmfmt = WM8731_HIFI_BITS,
|
.pcmfmt = WM8731_HIFI_BITS,
|
||||||
.pcmrate = SNDRV_PCM_RATE_8000,
|
.pcmrate = SNDRV_PCM_RATE_8000,
|
||||||
.pcmdir = WM8731_DIR,
|
.pcmdir = WM8731_DIR,
|
||||||
|
.flags = SND_SOC_DAI_BFS_RATE,
|
||||||
.fs = 1536,
|
.fs = 1536,
|
||||||
.bfs = SND_SOC_FSB(64),
|
.bfs = 64,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
|
.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
.pcmfmt = WM8731_HIFI_BITS,
|
.pcmfmt = WM8731_HIFI_BITS,
|
||||||
.pcmrate = SNDRV_PCM_RATE_8000,
|
.pcmrate = SNDRV_PCM_RATE_8000,
|
||||||
.pcmdir = WM8731_DIR,
|
.pcmdir = WM8731_DIR,
|
||||||
|
.flags = SND_SOC_DAI_BFS_RATE,
|
||||||
.fs = 2304,
|
.fs = 2304,
|
||||||
.bfs = SND_SOC_FSB(64),
|
.bfs = 64,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
|
.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
.pcmfmt = WM8731_HIFI_BITS,
|
.pcmfmt = WM8731_HIFI_BITS,
|
||||||
.pcmrate = SNDRV_PCM_RATE_8000,
|
.pcmrate = SNDRV_PCM_RATE_8000,
|
||||||
.pcmdir = WM8731_DIR,
|
.pcmdir = WM8731_DIR,
|
||||||
|
.flags = SND_SOC_DAI_BFS_RATE,
|
||||||
.fs = 1408,
|
.fs = 1408,
|
||||||
.bfs = SND_SOC_FSB(64),
|
.bfs = 64,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
|
.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
.pcmfmt = WM8731_HIFI_BITS,
|
.pcmfmt = WM8731_HIFI_BITS,
|
||||||
.pcmrate = SNDRV_PCM_RATE_8000,
|
.pcmrate = SNDRV_PCM_RATE_8000,
|
||||||
.pcmdir = WM8731_DIR,
|
.pcmdir = WM8731_DIR,
|
||||||
|
.flags = SND_SOC_DAI_BFS_RATE,
|
||||||
.fs = 2112,
|
.fs = 2112,
|
||||||
.bfs = SND_SOC_FSB(64),
|
.bfs = 64,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* 32k */
|
/* 32k */
|
||||||
@ -124,16 +128,18 @@ static struct snd_soc_dai_mode wm8731_modes[] = {
|
|||||||
.pcmfmt = WM8731_HIFI_BITS,
|
.pcmfmt = WM8731_HIFI_BITS,
|
||||||
.pcmrate = SNDRV_PCM_RATE_32000,
|
.pcmrate = SNDRV_PCM_RATE_32000,
|
||||||
.pcmdir = WM8731_DIR,
|
.pcmdir = WM8731_DIR,
|
||||||
|
.flags = SND_SOC_DAI_BFS_RATE,
|
||||||
.fs = 384,
|
.fs = 384,
|
||||||
.bfs = SND_SOC_FSB(64),
|
.bfs = 64,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
|
.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
.pcmfmt = WM8731_HIFI_BITS,
|
.pcmfmt = WM8731_HIFI_BITS,
|
||||||
.pcmrate = SNDRV_PCM_RATE_32000,
|
.pcmrate = SNDRV_PCM_RATE_32000,
|
||||||
.pcmdir = WM8731_DIR,
|
.pcmdir = WM8731_DIR,
|
||||||
|
.flags = SND_SOC_DAI_BFS_RATE,
|
||||||
.fs = 576,
|
.fs = 576,
|
||||||
.bfs = SND_SOC_FSB(64),
|
.bfs = 64,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* 44.1k & 48k */
|
/* 44.1k & 48k */
|
||||||
@ -142,16 +148,18 @@ static struct snd_soc_dai_mode wm8731_modes[] = {
|
|||||||
.pcmfmt = WM8731_HIFI_BITS,
|
.pcmfmt = WM8731_HIFI_BITS,
|
||||||
.pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
|
.pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
|
||||||
.pcmdir = WM8731_DIR,
|
.pcmdir = WM8731_DIR,
|
||||||
|
.flags = SND_SOC_DAI_BFS_RATE,
|
||||||
.fs = 256,
|
.fs = 256,
|
||||||
.bfs = SND_SOC_FSB(64),
|
.bfs = 64,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
|
.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
.pcmfmt = WM8731_HIFI_BITS,
|
.pcmfmt = WM8731_HIFI_BITS,
|
||||||
.pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
|
.pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
|
||||||
.pcmdir = WM8731_DIR,
|
.pcmdir = WM8731_DIR,
|
||||||
|
.flags = SND_SOC_DAI_BFS_RATE,
|
||||||
.fs = 384,
|
.fs = 384,
|
||||||
.bfs = SND_SOC_FSB(64),
|
.bfs = 64,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* 88.2 & 96k */
|
/* 88.2 & 96k */
|
||||||
@ -160,17 +168,18 @@ static struct snd_soc_dai_mode wm8731_modes[] = {
|
|||||||
.pcmfmt = WM8731_HIFI_BITS,
|
.pcmfmt = WM8731_HIFI_BITS,
|
||||||
.pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000,
|
.pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000,
|
||||||
.pcmdir = WM8731_DIR,
|
.pcmdir = WM8731_DIR,
|
||||||
|
.flags = SND_SOC_DAI_BFS_RATE,
|
||||||
.fs = 128,
|
.fs = 128,
|
||||||
.bfs = SND_SOC_FSB(64),
|
.bfs = 64,
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
|
.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
|
||||||
.pcmfmt = WM8731_HIFI_BITS,
|
.pcmfmt = WM8731_HIFI_BITS,
|
||||||
.pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000,
|
.pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000,
|
||||||
.pcmdir = WM8731_DIR,
|
.pcmdir = WM8731_DIR,
|
||||||
|
.flags = SND_SOC_DAI_BFS_RATE,
|
||||||
.fs = 192,
|
.fs = 192,
|
||||||
.bfs = SND_SOC_FSB(64),
|
.bfs = 64,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* USB codec frame and clock master modes */
|
/* USB codec frame and clock master modes */
|
||||||
@ -237,7 +246,7 @@ static struct snd_soc_dai_mode wm8731_modes[] = {
|
|||||||
.pcmdir = WM8731_DIR,
|
.pcmdir = WM8731_DIR,
|
||||||
.flags = SND_SOC_DAI_BFS_DIV,
|
.flags = SND_SOC_DAI_BFS_DIV,
|
||||||
.fs = SND_SOC_FS_ALL,
|
.fs = SND_SOC_FS_ALL,
|
||||||
.bfs = SND_SOC_FSBD_ALL,
|
.bfs = SND_SOC_FSB_ALL,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -343,7 +343,7 @@ static struct snd_soc_dai_mode wm8750_modes[] = {
|
|||||||
.pcmdir = WM8750_DIR,
|
.pcmdir = WM8750_DIR,
|
||||||
.flags = SND_SOC_DAI_BFS_DIV,
|
.flags = SND_SOC_DAI_BFS_DIV,
|
||||||
.fs = SND_SOC_FS_ALL,
|
.fs = SND_SOC_FS_ALL,
|
||||||
.bfs = SND_SOC_FSBD_ALL,
|
.bfs = SND_SOC_FSB_ALL,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -829,6 +829,9 @@ static inline int get_coeff(int mclk, int rate)
|
|||||||
if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
|
if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n",
|
||||||
|
mclk, rate);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,13 +839,7 @@ static inline int get_coeff(int mclk, int rate)
|
|||||||
static unsigned int wm8750_config_sysclk(struct snd_soc_codec_dai *dai,
|
static unsigned int wm8750_config_sysclk(struct snd_soc_codec_dai *dai,
|
||||||
struct snd_soc_clock_info *info, unsigned int clk)
|
struct snd_soc_clock_info *info, unsigned int clk)
|
||||||
{
|
{
|
||||||
dai->mclk = 0;
|
dai->mclk = clk;
|
||||||
|
|
||||||
/* check that the calculated FS and rate actually match a clock from
|
|
||||||
* the machine driver */
|
|
||||||
if (info->fs * info->rate == clk)
|
|
||||||
dai->mclk = clk;
|
|
||||||
|
|
||||||
return dai->mclk;
|
return dai->mclk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -859,7 +856,7 @@ static int wm8750_pcm_prepare(struct snd_pcm_substream *substream)
|
|||||||
if (i < 0)
|
if (i < 0)
|
||||||
return i;
|
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 */
|
/* set master/slave audio interface */
|
||||||
switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
|
switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
|
||||||
|
@ -126,7 +126,8 @@ static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = {
|
|||||||
.pcmrate = PXA_I2S_RATES,
|
.pcmrate = PXA_I2S_RATES,
|
||||||
.pcmdir = PXA_I2S_DIR,
|
.pcmdir = PXA_I2S_DIR,
|
||||||
.fs = SND_SOC_FS_ALL,
|
.fs = SND_SOC_FS_ALL,
|
||||||
.bfs = SND_SOC_FSB(64),
|
.flags = SND_SOC_DAI_BFS_RATE,
|
||||||
|
.bfs = 64,
|
||||||
.priv = 0x48,
|
.priv = 0x48,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -51,6 +51,8 @@
|
|||||||
#define dbgc(format, arg...)
|
#define dbgc(format, arg...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define CODEC_CPU(codec, cpu) ((codec << 4) | cpu)
|
||||||
|
|
||||||
static DEFINE_MUTEX(pcm_mutex);
|
static DEFINE_MUTEX(pcm_mutex);
|
||||||
static DEFINE_MUTEX(io_mutex);
|
static DEFINE_MUTEX(io_mutex);
|
||||||
static struct workqueue_struct *soc_workq;
|
static struct workqueue_struct *soc_workq;
|
||||||
@ -150,11 +152,11 @@ static unsigned inline int soc_get_mclk(struct snd_soc_pcm_runtime *rtd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* changes a bitclk multiplier mask to a divider mask */
|
/* 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)
|
unsigned int pcmfmt, unsigned int chn)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
u16 bfs_ = 0;
|
u64 bfs_ = 0;
|
||||||
int size = snd_pcm_format_physical_width(pcmfmt), min = 0;
|
int size = snd_pcm_format_physical_width(pcmfmt), min = 0;
|
||||||
|
|
||||||
if (size <= 0)
|
if (size <= 0)
|
||||||
@ -162,17 +164,14 @@ static u16 soc_bfs_mult_to_div(u16 bfs, int rate, unsigned int mclk,
|
|||||||
|
|
||||||
/* the minimum bit clock that has enough bandwidth */
|
/* the minimum bit clock that has enough bandwidth */
|
||||||
min = size * rate * chn;
|
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) {
|
if ((bfs >> i) & 0x1) {
|
||||||
j = rate * SND_SOC_FSB_REAL(1<<i);
|
j = min * (i + 1);
|
||||||
|
bfs_ |= SND_SOC_FSBD(mclk/j);
|
||||||
if (j >= min) {
|
dbgc("rcw --> div support mult %d\n",
|
||||||
bfs_ |= SND_SOC_FSBD(mclk/j);
|
SND_SOC_FSBD_REAL(1<<i));
|
||||||
dbgc("mult --> div support mult %d\n",
|
|
||||||
SND_SOC_FSB_REAL(1<<i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,11 +179,11 @@ static u16 soc_bfs_mult_to_div(u16 bfs, int rate, unsigned int mclk,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* changes a bitclk divider mask to a multiplier mask */
|
/* 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)
|
unsigned int pcmfmt, unsigned int chn)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
u16 bfs_ = 0;
|
u64 bfs_ = 0;
|
||||||
|
|
||||||
int size = snd_pcm_format_physical_width(pcmfmt), min = 0;
|
int size = snd_pcm_format_physical_width(pcmfmt), min = 0;
|
||||||
|
|
||||||
@ -193,15 +192,15 @@ static u16 soc_bfs_div_to_mult(u16 bfs, int rate, unsigned int mclk,
|
|||||||
|
|
||||||
/* the minimum bit clock that has enough bandwidth */
|
/* the minimum bit clock that has enough bandwidth */
|
||||||
min = size * rate * chn;
|
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) {
|
if ((bfs >> i) & 0x1) {
|
||||||
j = mclk / (SND_SOC_FSBD_REAL(1<<i));
|
j = mclk / (i + 1);
|
||||||
if (j >= min) {
|
if (j >= min) {
|
||||||
bfs_ |= SND_SOC_FSB(j/rate);
|
bfs_ |= SND_SOC_FSBW(j/min);
|
||||||
dbgc("div --> mult support div %d\n",
|
dbgc("div --> rcw support div %d\n",
|
||||||
SND_SOC_FSBD_REAL(1<<i));
|
SND_SOC_FSBW_REAL(1<<i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,6 +208,52 @@ static u16 soc_bfs_div_to_mult(u16 bfs, int rate, unsigned int mclk,
|
|||||||
return bfs_;
|
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 */
|
/* Matches codec DAI and SoC CPU DAI hardware parameters */
|
||||||
static int soc_hw_match_params(struct snd_pcm_substream *substream,
|
static int soc_hw_match_params(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_params *params)
|
struct snd_pcm_hw_params *params)
|
||||||
@ -217,9 +262,10 @@ static int soc_hw_match_params(struct snd_pcm_substream *substream,
|
|||||||
struct snd_soc_dai_mode *codec_dai_mode = NULL;
|
struct snd_soc_dai_mode *codec_dai_mode = NULL;
|
||||||
struct snd_soc_dai_mode *cpu_dai_mode = NULL;
|
struct snd_soc_dai_mode *cpu_dai_mode = NULL;
|
||||||
struct snd_soc_clock_info clk_info;
|
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;
|
chn, j, k, cpu_bclk, codec_bclk, pcmrate;
|
||||||
u16 fmt = 0;
|
u16 fmt = 0;
|
||||||
|
u64 codec_bfs, cpu_bfs;
|
||||||
|
|
||||||
dbg("asoc: match version %s\n", SND_SOC_VERSION);
|
dbg("asoc: match version %s\n", SND_SOC_VERSION);
|
||||||
clk_info.rate = rate;
|
clk_info.rate = rate;
|
||||||
@ -309,44 +355,98 @@ static int soc_hw_match_params(struct snd_pcm_substream *substream,
|
|||||||
* used in the codec and cpu DAI modes. We always choose the
|
* used in the codec and cpu DAI modes. We always choose the
|
||||||
* lowest possible clocks to reduce power.
|
* lowest possible clocks to reduce power.
|
||||||
*/
|
*/
|
||||||
if (codec_dai_mode->flags & cpu_dai_mode->flags &
|
switch (CODEC_CPU(codec_dai_mode->flags, cpu_dai_mode->flags)) {
|
||||||
SND_SOC_DAI_BFS_DIV) {
|
case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_DIV):
|
||||||
/* cpu & codec bfs dividers */
|
/* cpu & codec bfs dividers */
|
||||||
rtd->cpu_dai->dai_runtime.bfs =
|
rtd->cpu_dai->dai_runtime.bfs =
|
||||||
rtd->codec_dai->dai_runtime.bfs =
|
rtd->codec_dai->dai_runtime.bfs =
|
||||||
1 << (fls(codec_dai_mode->bfs & cpu_dai_mode->bfs) - 1);
|
1 << (fls(codec_dai_mode->bfs & cpu_dai_mode->bfs) - 1);
|
||||||
} else if (codec_dai_mode->flags & SND_SOC_DAI_BFS_DIV) {
|
break;
|
||||||
/* normalise bfs codec divider & cpu mult */
|
case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_RCW):
|
||||||
codec_bfs = soc_bfs_div_to_mult(codec_dai_mode->bfs, rate,
|
/* 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);
|
mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn);
|
||||||
rtd->cpu_dai->dai_runtime.bfs =
|
rtd->cpu_dai->dai_runtime.bfs =
|
||||||
1 << (ffs(codec_bfs & cpu_dai_mode->bfs) - 1);
|
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.pcmfmt, chn);
|
||||||
rtd->codec_dai->dai_runtime.bfs =
|
rtd->codec_dai->dai_runtime.bfs =
|
||||||
1 << (fls(codec_dai_mode->bfs & cpu_bfs) - 1);
|
1 << (fls(codec_dai_mode->bfs & cpu_bfs) - 1);
|
||||||
} else if (cpu_dai_mode->flags & SND_SOC_DAI_BFS_DIV) {
|
break;
|
||||||
/* normalise bfs codec mult & cpu divider */
|
case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_DIV):
|
||||||
codec_bfs = soc_bfs_mult_to_div(codec_dai_mode->bfs, rate,
|
/* 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);
|
mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn);
|
||||||
rtd->cpu_dai->dai_runtime.bfs =
|
rtd->cpu_dai->dai_runtime.bfs =
|
||||||
1 << (fls(codec_bfs & cpu_dai_mode->bfs) -1);
|
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.pcmfmt, chn);
|
||||||
rtd->codec_dai->dai_runtime.bfs =
|
rtd->codec_dai->dai_runtime.bfs =
|
||||||
1 << (ffs(codec_dai_mode->bfs & cpu_bfs) -1);
|
1 << (ffs(codec_dai_mode->bfs & cpu_bfs) -1);
|
||||||
} else {
|
break;
|
||||||
/* codec & cpu bfs rate multipliers */
|
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->cpu_dai->dai_runtime.bfs =
|
||||||
rtd->codec_dai->dai_runtime.bfs =
|
rtd->codec_dai->dai_runtime.bfs =
|
||||||
1 << (ffs(codec_dai_mode->bfs & cpu_dai_mode->bfs) -1);
|
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 */
|
/* make sure the bit clock speed is acceptable */
|
||||||
if (!rtd->cpu_dai->dai_runtime.bfs ||
|
if (!rtd->cpu_dai->dai_runtime.bfs ||
|
||||||
!rtd->codec_dai->dai_runtime.bfs) {
|
!rtd->codec_dai->dai_runtime.bfs) {
|
||||||
dbgc("asoc: DAI[%d:%d] failed to match BFS\n", j, k);
|
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->cpu_dai->dai_runtime.bfs,
|
||||||
rtd->codec_dai->dai_runtime.bfs);
|
rtd->codec_dai->dai_runtime.bfs);
|
||||||
dbgc("asoc: mclk %d hwfmt %x\n", mclk, fmt);
|
dbgc("asoc: mclk %d hwfmt %x\n", mclk, fmt);
|
||||||
@ -378,26 +478,41 @@ found:
|
|||||||
dbg("asoc: codec fs %d mclk %d bfs div %d bclk %d\n",
|
dbg("asoc: codec fs %d mclk %d bfs div %d bclk %d\n",
|
||||||
rtd->codec_dai->dai_runtime.fs, mclk,
|
rtd->codec_dai->dai_runtime.fs, mclk,
|
||||||
SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk);
|
SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk);
|
||||||
} else {
|
} else if(rtd->codec_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RATE) {
|
||||||
codec_bclk = params_rate(params) *
|
codec_bclk = params_rate(params) * rtd->codec_dai->dai_runtime.bfs;
|
||||||
SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs);
|
dbg("asoc: codec fs %d mclk %d bfs rate mult %llu bclk %d\n",
|
||||||
dbg("asoc: codec fs %d mclk %d bfs mult %d bclk %d\n",
|
|
||||||
rtd->codec_dai->dai_runtime.fs, mclk,
|
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) {
|
if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) {
|
||||||
cpu_bclk = (rtd->cpu_dai->dai_runtime.fs * params_rate(params)) /
|
cpu_bclk = (rtd->cpu_dai->dai_runtime.fs * params_rate(params)) /
|
||||||
SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs);
|
SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs);
|
||||||
dbg("asoc: cpu fs %d mclk %d bfs div %d bclk %d\n",
|
dbg("asoc: cpu fs %d mclk %d bfs div %d bclk %d\n",
|
||||||
rtd->cpu_dai->dai_runtime.fs, mclk,
|
rtd->cpu_dai->dai_runtime.fs, mclk,
|
||||||
SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk);
|
SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk);
|
||||||
} else {
|
} else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RATE) {
|
||||||
cpu_bclk = params_rate(params) *
|
cpu_bclk = params_rate(params) * rtd->cpu_dai->dai_runtime.bfs;
|
||||||
SND_SOC_FSB_REAL(rtd->cpu_dai->dai_runtime.bfs);
|
dbg("asoc: cpu fs %d mclk %d bfs rate mult %llu bclk %d\n",
|
||||||
dbg("asoc: cpu fs %d mclk %d bfs mult %d bclk %d\n",
|
|
||||||
rtd->cpu_dai->dai_runtime.fs, mclk,
|
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
|
* Check we have matching bitclocks. If we don't then it means the
|
||||||
@ -405,7 +520,7 @@ found:
|
|||||||
* machine sysclock function) is wrong compared with the supported DAI
|
* machine sysclock function) is wrong compared with the supported DAI
|
||||||
* modes for the codec or cpu DAI.
|
* modes for the codec or cpu DAI.
|
||||||
*/
|
*/
|
||||||
if (cpu_bclk != codec_bclk){
|
if (cpu_bclk != codec_bclk && cpu_bclk){
|
||||||
printk(KERN_ERR
|
printk(KERN_ERR
|
||||||
"asoc: codec and cpu bitclocks differ, audio may be wrong speed\n"
|
"asoc: codec and cpu bitclocks differ, audio may be wrong speed\n"
|
||||||
);
|
);
|
||||||
@ -723,14 +838,18 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
|
|||||||
mutex_lock(&pcm_mutex);
|
mutex_lock(&pcm_mutex);
|
||||||
if (platform->pcm_ops->prepare) {
|
if (platform->pcm_ops->prepare) {
|
||||||
ret = platform->pcm_ops->prepare(substream);
|
ret = platform->pcm_ops->prepare(substream);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
printk(KERN_ERR "asoc: platform prepare error\n");
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtd->codec_dai->ops.prepare) {
|
if (rtd->codec_dai->ops.prepare) {
|
||||||
ret = rtd->codec_dai->ops.prepare(substream);
|
ret = rtd->codec_dai->ops.prepare(substream);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
printk(KERN_ERR "asoc: codec DAI prepare error\n");
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtd->cpu_dai->ops.prepare)
|
if (rtd->cpu_dai->ops.prepare)
|
||||||
|
Loading…
Reference in New Issue
Block a user