From eb1a6af39b70375d93ed25e7c916f64463e00614 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 6 Oct 2006 18:34:51 +0200 Subject: [ALSA] ASoC: documentation & maintainer This patch adds documentation describing the ASoC architecture and a maintainer entry for ASoC. The documentation includes the following files:- codec.txt: Codec driver internals. DAI.txt: Description of Digital Audio Interface standards and how to configure a DAI within your codec and CPU DAI drivers. dapm.txt: Dynamic Audio Power Management. platform.txt: Platform audio DMA and DAI. machine.txt: Machine driver internals. pop_clicks.txt: How to minimise audio artifacts. clocking.txt: ASoC clocking for best power performance. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- Documentation/sound/alsa/soc/DAI.txt | 380 +++++++++++++++++++++++++++ Documentation/sound/alsa/soc/clocking.txt | 309 ++++++++++++++++++++++ Documentation/sound/alsa/soc/codec.txt | 232 ++++++++++++++++ Documentation/sound/alsa/soc/dapm.txt | 297 +++++++++++++++++++++ Documentation/sound/alsa/soc/machine.txt | 114 ++++++++ Documentation/sound/alsa/soc/overview.txt | 83 ++++++ Documentation/sound/alsa/soc/platform.txt | 58 ++++ Documentation/sound/alsa/soc/pops_clicks.txt | 52 ++++ 8 files changed, 1525 insertions(+) create mode 100644 Documentation/sound/alsa/soc/DAI.txt create mode 100644 Documentation/sound/alsa/soc/clocking.txt create mode 100644 Documentation/sound/alsa/soc/codec.txt create mode 100644 Documentation/sound/alsa/soc/dapm.txt create mode 100644 Documentation/sound/alsa/soc/machine.txt create mode 100644 Documentation/sound/alsa/soc/overview.txt create mode 100644 Documentation/sound/alsa/soc/platform.txt create mode 100644 Documentation/sound/alsa/soc/pops_clicks.txt (limited to 'Documentation/sound/alsa/soc') diff --git a/Documentation/sound/alsa/soc/DAI.txt b/Documentation/sound/alsa/soc/DAI.txt new file mode 100644 index 00000000000..919de76bab8 --- /dev/null +++ b/Documentation/sound/alsa/soc/DAI.txt @@ -0,0 +1,380 @@ +ASoC currently supports the three main Digital Audio Interfaces (DAI) found on +SoC controllers and portable audio CODECS today, namely AC97, I2S and PCM. + + +AC97 +==== + + AC97 is a five wire interface commonly found on many PC sound cards. It is +now also popular in many portable devices. This DAI has a reset line and time +multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines. +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 is 21uS long and is divided into 13 time slots. + +The AC97 specification can be found at http://intel.com/ + + +I2S +=== + + I2S is a common 4 wire DAI used in HiFi, STB and portable devices. The Tx and +Rx lines are used for audio transmision, whilst the bit clock (BCLK) and +left/right clock (LRC) synchronise the link. I2S is flexible in that either the +controller or CODEC can drive (master) the BCLK and LRC clock lines. Bit clock +usually varies depending on the sample rate and the master system clock +(SYSCLK). LRCLK is the same as the sample rate. A few devices support separate +ADC and DAC LRCLK's, this allows for similtanious capture and playback at +different sample rates. + +I2S has several different operating modes:- + + o I2S - MSB is transmitted on the falling edge of the first BCLK after LRC + transition. + + o Left Justified - MSB is transmitted on transition of LRC. + + o Right Justified - MSB is transmitted sample size BCLK's before LRC + transition. + +PCM +=== + +PCM is another 4 wire interface, very similar to I2S, that can support a more +flexible protocol. It has bit clock (BCLK) and sync (SYNC) lines that are used +to synchronise the link whilst the Tx and Rx lines are used to transmit and +receive the audio data. Bit clock usually varies depending on sample rate +whilst sync runs at the sample rate. PCM also supports Time Division +Multiplexing (TDM) in that several devices can use the bus similtaniuosly (This +is sometimes referred to as network mode). + +Common PCM operating modes:- + + o Mode A - MSB is transmitted on falling edge of first BCLK after FRAME/SYNC. + + o Mode B - MSB is transmitted on rising edge of FRAME/SYNC. + + +ASoC DAI Configuration +====================== + +Every CODEC DAI and SoC DAI must have their capabilities defined in order to +be configured together at runtime when the audio and clocking parameters are +known. This is achieved by creating an array of struct snd_soc_hw_mode in the +the CODEC and SoC interface drivers. Each element in the array describes a DAI +mode and each mode is usually based upon the DAI system clock to sample rate +ratio (FS). + +i.e. 48k sample rate @ 256 FS = sytem clock of 12.288 MHz + 48000 * 256 = 12288000 + +The CPU and Codec DAI modes are then ANDed together at runtime to determine the +rutime DAI configuration for both the Codec and CPU. + +When creating a new codec or SoC DAI it's probably best to start of with a few +sample rates first and then test your interface. + +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 */ +}; + +fmt: +---- +This field defines the DAI mode hardware format (e.g. I2S settings) and +supports the following settings:- + + 1) hardware DAI formats + +#define SND_SOC_DAIFMT_I2S (1 << 0) /* I2S mode */ +#define SND_SOC_DAIFMT_RIGHT_J (1 << 1) /* Right justified mode */ +#define SND_SOC_DAIFMT_LEFT_J (1 << 2) /* Left Justified mode */ +#define SND_SOC_DAIFMT_DSP_A (1 << 3) /* L data msb after FRM */ +#define SND_SOC_DAIFMT_DSP_B (1 << 4) /* L data msb during FRM */ +#define SND_SOC_DAIFMT_AC97 (1 << 5) /* AC97 */ + + 2) hw DAI signal inversions + +#define SND_SOC_DAIFMT_NB_NF (1 << 8) /* normal bit clock + frame */ +#define SND_SOC_DAIFMT_NB_IF (1 << 9) /* normal bclk + inv frm */ +#define SND_SOC_DAIFMT_IB_NF (1 << 10) /* invert bclk + nor frm */ +#define SND_SOC_DAIFMT_IB_IF (1 << 11) /* invert bclk + frm */ + + 3) hw clock masters + This is wrt the codec, the inverse is true for the interface + i.e. if the codec is clk and frm master then the interface is + clk and frame slave. + +#define SND_SOC_DAIFMT_CBM_CFM (1 << 12) /* codec clk & frm master */ +#define SND_SOC_DAIFMT_CBS_CFM (1 << 13) /* codec clk slave & frm master */ +#define SND_SOC_DAIFMT_CBM_CFS (1 << 14) /* codec clk master & frame slave */ +#define SND_SOC_DAIFMT_CBS_CFS (1 << 15) /* codec clk & frm slave */ + +At least one option from each section must be selected. Multiple selections are +also supported e.g. + + .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_RIGHT_J | \ + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_IB_NF | \ + SND_SOC_DAIFMT_IB_IF + + +tdm: +------ +This field defines the Time Division Multiplexing left and right word +positions for the DAI mode if applicable. Set to SND_SOC_DAITDM_LRDW(0,0) for +no TDM. + + +pcmfmt: +--------- +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 | \ + 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 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 + + +pcmdir: +--------- +The stream directions supported by this mode. e.g. playback and capture + + +flags: +-------- +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. + +NOTE: Bitclock division and mulitiplication modes can be safely matched by the +core logic. + + +fs: +----- +The FS supported by this DAI mode FS is the ratio between the system clock and +the sample rate. See above + +bfs: +------ +BFS is the ratio of BCLK to MCLK or the ratio of BCLK to sample rate (this +depends on the codec or CPU DAI). + +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. + +priv: +----- +private codec mode data. + + + +Examples +======== + +Note that Codec DAI and CPU DAI examples are interchangeable in these examples +as long as the bus master is reversed. i.e. + + SND_SOC_DAIFMT_CBM_CFM would become SND_SOC_DAIFMT_CBS_CFS + and vice versa. + +This applies to all SND_SOC_DAIFMT_CB*_CF*. + +Example 1 +--------- + +Simple codec that only runs at 8k & 48k @ 256FS in master mode, can generate a +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)}, + + +Example 2 +--------- +Simple codec that only runs at 8k & 48k @ 256FS in master mode, can generate a +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)}, + + +Example 3 +--------- +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)}, + + /* 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)}, + + +Example 4 +--------- +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 as and does not care about FS or BCLK (as long as there is enough bandwidth). + + #define CODEC_FSB \ + (SND_SOC_FSBD(1) | SND_SOC_FSBD(2) | SND_SOC_FSBD(4) | \ + SND_SOC_FSBD(8) | SND_SOC_FSBD(16)) + + #define CODEC_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 |\ + 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}, + + /* 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}, + + +Example 5 +--------- +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). +Codec can also run in slave mode as and does not care about FS or BCLK (as long +as there is enough bandwidth). Codec can support 16, 24 and 32 bit PCM sample +sizes. + + #define CODEC_FSB \ + (SND_SOC_FSBD(1) | SND_SOC_FSBD(2) | SND_SOC_FSBD(4) | \ + SND_SOC_FSBD(8) | SND_SOC_FSBD(16)) + + #define CODEC_PCM_FORMATS \ + (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ + 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}, + + /* 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}, + + +Example 6 +--------- +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}, + + +Example 7 +--------- + +CPU DAI that supports 8k - 48k @ 256FS and BCLK = MCLK / 4 in master mode. +Slave mode (CPU DAI is FRAME master) supports 8k - 96k at any FS as long as +BCLK = 64 * rate. (Intel XScale I2S controller). + + #define PXA_I2S_DAIFMT \ + (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF) + + #define PXA_I2S_DIR \ + (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) + + #define PXA_I2S_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + + /* 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}, + + /* 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)}, + diff --git a/Documentation/sound/alsa/soc/clocking.txt b/Documentation/sound/alsa/soc/clocking.txt new file mode 100644 index 00000000000..88a16c9e197 --- /dev/null +++ b/Documentation/sound/alsa/soc/clocking.txt @@ -0,0 +1,309 @@ +Audio Clocking +============== + +This text describes the audio clocking terms in ASoC and digital audio in +general. Note: Audio clocking can be complex ! + + +Master Clock +------------ + +Every audio subsystem is driven by a master clock (sometimes refered to as MCLK +or SYSCLK). This audio master clock can be derived from a number of sources +(e.g. crystal, PLL, CPU clock) and is responsible for producing the correct +audio playback and capture sample rates. + +Some master clocks (e.g. PLL's and CPU based clocks) are configuarble in that +their speed can be altered by software (depending on the system use and to save +power). Other master clocks are fixed at at set frequency (i.e. crystals). + + +DAI Clocks +---------- +The Digital Audio Interface is usually driven by a Bit Clock (often referred to +as BCLK). This clock is used to drive the digital audio data across the link +between the codec and CPU. + +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. + +Bit Clock is usually always a ratio of MCLK or a multiple of LRC. i.e. + +BCLK = MCLK / x + + or + +BCLK = LRC * x + +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). + + +ASoC Clocking +------------- + +The ASoC core determines the clocking for each particular configuration at +runtime. This is to allow for dynamic audio clocking wereby the audio clock is +variable and depends on the system state or device usage scenario. i.e. a voice +call requires slower clocks (and hence less power) than MP3 playback. + +ASoC will call the config_sysclock() function for the target machine during the +audio parameters configuration. The function is responsible for then clocking +the machine audio subsytem and returning the audio clock speed to the core. +This function should also call the codec and cpu DAI clock_config() functions +to configure their respective internal clocking if required. + + +ASoC Clocking Control Flow +-------------------------- + +The ASoC core will call the machine drivers config_sysclock() when most of the +DAI capabilities are known. The machine driver is then responsible for calling +the codec and/or CPU DAI drivers with the selected capabilities and the current +MCLK. Note that the machine driver is also resonsible for setting the MCLK (and +enabling it). + + (1) Match Codec and CPU DAI capabilities. At this point we have + matched the majority of the DAI fields and now need to make sure this + mode is currently clockable. + + (2) machine->config_sysclk() is now called with the matched DAI FS, sample + rate and BCLK master. This function then gets/sets the current audio + clock (depening on usage) and calls the codec and CPUI DAI drivers with + the FS, rate, BCLK master and MCLK. + + (3) Codec/CPU DAI config_sysclock(). This function checks that the FS, rate, + BCLK master and MCLK are acceptable for the codec or CPU DAI. It also + sets the DAI internal state to work with said clocks. + +The config_sysclk() functions for CPU, codec and machine should return the MCLK +on success and 0 on failure. + + +Examples (b = BCLK, l = LRC) +============================ + +Example 1 +--------- + +Simple codec that only runs at 48k @ 256FS in master mode. + +CPU only runs as slave DAI, however it generates a variable MCLK. + + -------- --------- + | | <----mclk--- | | + | Codec |b -----------> | CPU | + | |l -----------> | | + | | | | + -------- --------- + +The codec driver has the following config_sysclock() + + static unsigned int config_sysclk(struct snd_soc_codec_dai *dai, + struct snd_soc_clock_info *info, unsigned int clk) + { + /* make sure clock is 256 * rate */ + if(info->rate << 8 == clk) { + dai->mclk = clk; + return clk; + } + + return 0; + } + +The CPU I2S DAI driver has the following config_sysclk() + + static unsigned int config_sysclk(struct snd_soc_codec_dai *dai, + struct snd_soc_clock_info *info, unsigned int clk) + { + /* can we support this clk */ + if(set_audio_clk(clk) < 0) + return -EINVAL; + + dai->mclk = clk; + return dai->clk; + } + +The machine driver config_sysclk() in this example is as follows:- + + unsigned int machine_config_sysclk(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_clock_info *info) + { + int clk = info->rate * info->fs; + + /* check that CPU can deliver clock */ + if(rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, clk) < 0) + return -EINVAL; + + /* can codec work with this clock */ + return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, clk); + } + + +Example 2 +--------- + +Codec that can master at 8k and 48k at various FS (and hence supports a fixed +set of input MCLK's) and can also be slave at various FS . + +The CPU can master at 8k and 48k @256 FS and can be slave at any FS. + +MCLK is a 12.288MHz crystal on this machine. + + -------- --------- + | | <---xtal---> | | + | Codec |b <----------> | CPU | + | |l <----------> | | + | | | | + -------- --------- + + +The codec driver has the following config_sysclock() + + /* supported input clocks */ + const static int hifi_clks[] = {11289600, 12000000, 12288000, + 16934400, 18432000}; + + static unsigned int config_hsysclk(struct snd_soc_codec_dai *dai, + struct snd_soc_clock_info *info, unsigned int clk) + { + int i; + + /* is clk supported */ + for(i = 0; i < ARRAY_SIZE(hifi_clks); i++) { + if(clk == hifi_clks[i]) { + dai->mclk = clk; + return clk; + } + } + + /* this clk is not supported */ + return 0; + } + +The CPU I2S DAI driver has the following config_sysclk() + + static unsigned int config_sysclk(struct snd_soc_codec_dai *dai, + struct snd_soc_clock_info *info, unsigned int clk) + { + /* are we master or slave */ + if (info->bclk_master & + (SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_CBM_CFS)) { + + /* we can only master @ 256FS */ + if(info->rate << 8 == clk) { + dai->mclk = clk; + return dai->mclk; + } + } else { + /* slave we can run at any FS */ + dai->mclk = clk; + return dai->mclk; + } + + /* not supported */ + return dai->clk; + } + +The machine driver config_sysclk() in this example is as follows:- + + unsigned int machine_config_sysclk(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_clock_info *info) + { + int clk = 12288000; /* 12.288MHz */ + + /* who's driving the link */ + if (info->bclk_master & + (SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_CBM_CFS)) { + /* codec master */ + + /* check that CPU can work with clock */ + if(rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, clk) < 0) + return -EINVAL; + + /* can codec work with this clock */ + return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, clk); + } else { + /* cpu master */ + + /* check that codec can work with clock */ + if(rtd->codec_dai->config_sysclk(rtd->codec_dai, info, clk) < 0) + return -EINVAL; + + /* can CPU work with this clock */ + return rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, clk); + } + } + + + +Example 3 +--------- + +Codec that masters at 8k ... 48k @256 FS. Codec can also be slave and +doesn't care about FS. The codec has an internal PLL and dividers to generate +the necessary internal clocks (for 256FS). + +CPU can only be slave and doesn't care about FS. + +MCLK is a non controllable 13MHz clock from the CPU. + + + -------- --------- + | | <----mclk--- | | + | Codec |b <----------> | CPU | + | |l <----------> | | + | | | | + -------- --------- + +The codec driver has the following config_sysclock() + + /* valid PCM clock dividers * 2 */ + static int pcm_divs[] = {2, 6, 11, 4, 8, 12, 16}; + + static unsigned int config_vsysclk(struct snd_soc_codec_dai *dai, + struct snd_soc_clock_info *info, unsigned int clk) + { + int i, j, best_clk = info->fs * info->rate; + + /* can we run at this clk without the PLL ? */ + for (i = 0; i < ARRAY_SIZE(pcm_divs); i++) { + if ((best_clk >> 1) * pcm_divs[i] == clk) { + dai->pll_in = 0; + dai->clk_div = pcm_divs[i]; + dai->mclk = best_clk; + return dai->mclk; + } + } + + /* now check for PLL support */ + for (i = 0; i < ARRAY_SIZE(pll_div); i++) { + if (pll_div[i].pll_in == clk) { + for (j = 0; j < ARRAY_SIZE(pcm_divs); j++) { + if (pll_div[i].pll_out == pcm_divs[j] * (best_clk >> 1)) { + dai->pll_in = clk; + dai->pll_out = pll_div[i].pll_out; + dai->clk_div = pcm_divs[j]; + dai->mclk = best_clk; + return dai->mclk; + } + } + } + } + + /* this clk is not supported */ + return 0; + } + + +The CPU I2S DAI driver has the does not need a config_sysclk() as it can slave +at any FS. + + unsigned int config_sysclk(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_clock_info *info) + { + /* codec has pll that generates mclk from 13MHz xtal */ + return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, 13000000); + } diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt new file mode 100644 index 00000000000..47b36cb1684 --- /dev/null +++ b/Documentation/sound/alsa/soc/codec.txt @@ -0,0 +1,232 @@ +ASoC Codec Driver +================= + +The codec driver is generic and hardware independent code that configures the +codec to provide audio capture and playback. It should contain no code that is +specific to the target platform or machine. All platform and machine specific +code should be added to the platform and machine drivers respectively. + +Each codec driver must provide the following features:- + + 1) Digital audio interface (DAI) description + 2) Digital audio interface configuration + 3) PCM's description + 4) Codec control IO - using I2C, 3 Wire(SPI) or both API's + 5) Mixers and audio controls + 6) Sysclk configuration + 7) Codec audio operations + +Optionally, codec drivers can also provide:- + + 8) DAPM description. + 9) DAPM event handler. +10) DAC Digital mute control. + +It's probably best to use this guide in conjuction with the existing codec +driver code in sound/soc/codecs/ + +ASoC Codec driver breakdown +=========================== + +1 - Digital Audio Interface (DAI) description +--------------------------------------------- +The DAI is a digital audio data transfer link between the codec and host SoC +CPU. It typically has data transfer capabilities in both directions +(playback and capture) and can run at a variety of different speeds. +Supported interfaces currently include AC97, I2S and generic PCM style links. +Please read DAI.txt for implementation information. + + +2 - Digital Audio Interface (DAI) configuration +----------------------------------------------- +DAI configuration is handled by the codec_pcm_prepare function and is +responsible for configuring and starting the DAI on the codec. This can be +called multiple times and is atomic. It can access the runtime parameters. + +This usually consists of a large function with numerous switch statements to +set up each configuration option. These options are set by the core at runtime. + + +3 - Codec PCM's +--------------- +Each codec must have it's PCM's defined. This defines the number of channels, +stream names, callbacks and codec name. It is also used to register the DAI +with the ASoC core. The PCM structure also associates the DAI capabilities with +the ALSA PCM. + +e.g. + +static struct snd_soc_pcm_codec wm8731_pcm_client = { + .name = "WM8731", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + }, + .config_sysclk = wm8731_config_sysclk, + .ops = { + .prepare = wm8731_pcm_prepare, + }, + .caps = { + .num_modes = ARRAY_SIZE(wm8731_hwfmt), + .modes = &wm8731_hwfmt[0], + }, +}; + + +4 - Codec control IO +-------------------- +The codec can ususally be controlled via an I2C or SPI style interface (AC97 +combines control with data in the DAI). The codec drivers will have to provide +functions to read and write the codec registers along with supplying a register +cache:- + + /* IO control data and register cache */ + void *control_data; /* codec control (i2c/3wire) data */ + void *reg_cache; + +Codec read/write should do any data formatting and call the hardware read write +below to perform the IO. These functions are called by the core and alsa when +performing DAPM or changing the mixer:- + + unsigned int (*read)(struct snd_soc_codec *, unsigned int); + int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); + +Codec hardware IO functions - usually points to either the I2C, SPI or AC97 +read/write:- + + hw_write_t hw_write; + hw_read_t hw_read; + + +5 - Mixers and audio controls +----------------------------- +All the codec mixers and audio controls can be defined using the convenience +macros defined in soc.h. + + #define SOC_SINGLE(xname, reg, shift, mask, invert) + +Defines a single control as follows:- + + xname = Control name e.g. "Playback Volume" + reg = codec register + shift = control bit(s) offset in register + mask = control bit size(s) e.g. mask of 7 = 3 bits + invert = the control is inverted + +Other macros include:- + + #define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) + +A stereo control + + #define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) + +A stereo control spanning 2 registers + + #define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) + +Defines an single enumerated control as follows:- + + xreg = register + xshift = control bit(s) offset in register + xmask = control bit(s) size + xtexts = pointer to array of strings that describe each setting + + #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) + +Defines a stereo enumerated control + + +6 - System clock configuration. +------------------------------- +The system clock that drives the audio subsystem can change depending on sample +rate and the system power state. i.e. + +o Higher sample rates sometimes need a higher system clock. +o Low system power states can sometimes limit the available clocks. + +This function is a callback that the machine driver can call to set and +determine if the clock and sample rate combination is supported by the codec at +the present time (and system state). + +NOTE: If the codec has a PLL then it has a lot more flexability wrt clock and +sample rate combinations. + +Your config_sysclock function should return the MCLK if it's a valid +combination for your codec else 0; + +Please read clocking.txt now. + + +7 - Codec Audio Operations +-------------------------- +The codec driver also supports the following alsa operations:- + +/* SoC audio ops */ +struct snd_soc_ops { + int (*startup)(snd_pcm_substream_t *); + void (*shutdown)(snd_pcm_substream_t *); + int (*hw_params)(snd_pcm_substream_t *, snd_pcm_hw_params_t *); + int (*hw_free)(snd_pcm_substream_t *); + int (*prepare)(snd_pcm_substream_t *); +}; + +Please refer to the alsa driver PCM documentation for details. +http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm + + +8 - DAPM description. +--------------------- +The Dynamic Audio Power Management description describes the codec's power +components, their relationships and registers to the ASoC core. Please read +dapm.txt for details of building the description. + +Please also see the examples in other codec drivers. + + +9 - DAPM event handler +---------------------- +This function is a callback that handles codec domain PM calls and system +domain PM calls (e.g. suspend and resume). It's used to put the codec to sleep +when not in use. + +Power states:- + + SNDRV_CTL_POWER_D0: /* full On */ + /* vref/mid, clk and osc on, active */ + + SNDRV_CTL_POWER_D1: /* partial On */ + SNDRV_CTL_POWER_D2: /* partial On */ + + SNDRV_CTL_POWER_D3hot: /* Off, with power */ + /* everything off except vref/vmid, inactive */ + + SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */ + + +10 - Codec DAC digital mute control. +------------------------------------ +Most codecs have a digital mute before the DAC's that can be used to minimise +any system noise. The mute stops any digital data from entering the DAC. + +A callback can be created that is called by the core for each codec DAI when the +mute is applied or freed. + +i.e. + +static int wm8974_mute(struct snd_soc_codec *codec, + struct snd_soc_codec_dai *dai, int mute) +{ + u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf; + if(mute) + wm8974_write(codec, WM8974_DAC, mute_reg | 0x40); + else + wm8974_write(codec, WM8974_DAC, mute_reg); + return 0; +} diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt new file mode 100644 index 00000000000..c11877f5b4a --- /dev/null +++ b/Documentation/sound/alsa/soc/dapm.txt @@ -0,0 +1,297 @@ +Dynamic Audio Power Management for Portable Devices +=================================================== + +1. Description +============== + +Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices +to use the minimum amount of power within the audio subsystem at all times. It +is independent of other kernel PM and as such, can easily co-exist with the +other PM systems. + +DAPM is also completely transparent to all user space applications as all power +switching is done within the ASoC core. No code changes or recompiling are +required for user space applications. DAPM makes power switching descisions based +upon any audio stream (capture/playback) activity and audio mixer settings +within the device. + +DAPM spans the whole machine. It covers power control within the entire audio +subsystem, this includes internal codec power blocks and machine level power +systems. + +There are 4 power domains within DAPM + + 1. Codec domain - VREF, VMID (core codec and audio power) + Usually controlled at codec probe/remove and suspend/resume, although + can be set at stream time if power is not needed for sidetone, etc. + + 2. Platform/Machine domain - physically connected inputs and outputs + Is platform/machine and user action specific, is configured by the + machine driver and responds to asynchronous events e.g when HP + are inserted + + 3. Path domain - audio susbsystem signal paths + Automatically set when mixer and mux settings are changed by the user. + e.g. alsamixer, amixer. + + 4. Stream domain - DAC's and ADC's. + Enabled and disabled when stream playback/capture is started and + stopped respectively. e.g. aplay, arecord. + +All DAPM power switching descisons are made automatically by consulting an audio +routing map of the whole machine. This map is specific to each machine and +consists of the interconnections between every audio component (including +internal codec components). All audio components that effect power are called +widgets hereafter. + + +2. DAPM Widgets +=============== + +Audio DAPM widgets fall into a number of types:- + + o Mixer - Mixes several analog signals into a single analog signal. + o Mux - An analog switch that outputs only 1 of it's inputs. + o PGA - A programmable gain amplifier or attenuation widget. + o ADC - Analog to Digital Converter + o DAC - Digital to Analog Converter + o Switch - An analog switch + o Input - A codec input pin + o Output - A codec output pin + o Headphone - Headphone (and optional Jack) + o Mic - Mic (and optional Jack) + o Line - Line Input/Output (and optional Jack) + o Speaker - Speaker + o Pre - Special PRE widget (exec before all others) + o Post - Special POST widget (exec after all others) + +(Widgets are defined in include/sound/soc-dapm.h) + +Widgets are usually added in the codec driver and the machine driver. There are +convience macros defined in soc-dapm.h that can be used to quickly build a +list of widgets of the codecs and machines DAPM widgets. + +Most widgets have a name, register, shift and invert. Some widgets have extra +parameters for stream name and kcontrols. + + +2.1 Stream Domain Widgets +------------------------- + +Stream Widgets relate to the stream power domain and only consist of ADC's +(analog to digital converters) and DAC's (digital to analog converters). + +Stream widgets have the following format:- + +SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert), + +NOTE: the stream name must match the corresponding stream name in your codecs +snd_soc_codec_dai. + +e.g. stream widgets for HiFi playback and capture + +SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1), +SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1), + + +2.2 Path Domain Widgets +----------------------- + +Path domain widgets have a ability to control or effect the audio signal or +audio paths within the audio subsystem. They have the following form:- + +SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls) + +Any widget kcontrols can be set using the controls and num_controls members. + +e.g. Mixer widget (the kcontrols are declared first) + +/* Output Mixer */ +static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = { +SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), +SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0), +SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), +}; + +SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls, + ARRAY_SIZE(wm8731_output_mixer_controls)), + + +2.3 Platform/Machine domain Widgets +----------------------------------- + +Machine widgets are different from codec widgets in that they don't have a +codec register bit associated with them. A machine widget is assigned to each +machine audio component (non codec) that can be independently powered. e.g. + + o Speaker Amp + o Microphone Bias + o Jack connectors + +A machine widget can have an optional call back. + +e.g. Jack connector widget for an external Mic that enables Mic Bias +when the Mic is inserted:- + +static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event) +{ + if(SND_SOC_DAPM_EVENT_ON(event)) + set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS); + else + reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS); + + return 0; +} + +SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias), + + +2.4 Codec Domain +---------------- + +The Codec power domain has no widgets and is handled by the codecs DAPM event +handler. This handler is called when the codec powerstate is changed wrt to any +stream event or by kernel PM events. + + +2.5 Virtual Widgets +------------------- + +Sometimes widgets exist in the codec or machine audio map that don't have any +corresponding register bit for power control. In this case it's necessary to +create a virtual widget - a widget with no control bits e.g. + +SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0), + +This can be used to merge to signal paths together in software. + +After all the widgets have been defined, they can then be added to the DAPM +subsystem individually with a call to snd_soc_dapm_new_control(). + + +3. Codec Widget Interconnections +================================ + +Widgets are connected to each other within the codec and machine by audio +paths (called interconnections). Each interconnection must be defined in order +to create a map of all audio paths between widgets. +This is easiest with a diagram of the codec (and schematic of the machine audio +system), as it requires joining widgets together via their audio signal paths. + +i.e. from the WM8731 codec's output mixer (wm8731.c) + +The WM8731 output mixer has 3 inputs (sources) + + 1. Line Bypass Input + 2. DAC (HiFi playback) + 3. Mic Sidetone Input + +Each input in this example has a kcontrol associated with it (defined in example +above) and is connected to the output mixer via it's kcontrol name. We can now +connect the destination widget (wrt audio signal) with it's source widgets. + + /* output mixer */ + {"Output Mixer", "Line Bypass Switch", "Line Input"}, + {"Output Mixer", "HiFi Playback Switch", "DAC"}, + {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, + +So we have :- + + Destination Widget <=== Path Name <=== Source Widget + +Or:- + + Sink, Path, Source + +Or :- + + "Output Mixer" is connected to the "DAC" via the "HiFi Playback Switch". + +When there is no path name connecting widgets (e.g. a direct connection) we +pass NULL for the path name. + +Interconnections are created with a call to:- + +snd_soc_dapm_connect_input(codec, sink, path, source); + +Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and +interconnections have been registered with the core. This causes the core to +scan the codec and machine so that the internal DAPM state matches the +physical state of the machine. + + +3.1 Machine Widget Interconnections +----------------------------------- +Machine widget interconnections are created in the same way as codec ones and +directly connect the codec pins to machine level widgets. + +e.g. connects the speaker out codec pins to the internal speaker. + + /* ext speaker connected to codec pins LOUT2, ROUT2 */ + {"Ext Spk", NULL , "ROUT2"}, + {"Ext Spk", NULL , "LOUT2"}, + +This allows the DAPM to power on and off pins that are connected (and in use) +and pins that are NC respectively. + + +4 Endpoint Widgets +=================== +An endpoint is a start or end point (widget) of an audio signal within the +machine and includes the codec. e.g. + + o Headphone Jack + o Internal Speaker + o Internal Mic + o Mic Jack + o Codec Pins + +When a codec pin is NC it can be marked as not used with a call to + +snd_soc_dapm_set_endpoint(codec, "Widget Name", 0); + +The last argument is 0 for inactive and 1 for active. This way the pin and its +input widget will never be powered up and consume power. + +This also applies to machine widgets. e.g. if a headphone is connected to a +jack then the jack can be marked active. If the headphone is removed, then +the headphone jack can be marked inactive. + + +5 DAPM Widget Events +==================== + +Some widgets can register their interest with the DAPM core in PM events. +e.g. A Speaker with an amplifier registers a widget so the amplifier can be +powered only when the spk is in use. + +/* turn speaker amplifier on/off depending on use */ +static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); + else + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); + + return 0; +} + +/* corgi machine dapm widgets */ +static const struct snd_soc_dapm_widget wm8731_dapm_widgets = + SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event); + +Please see soc-dapm.h for all other widgets that support events. + + +5.1 Event types +--------------- + +The following event types are supported by event widgets. + +/* dapm event types */ +#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */ +#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */ +#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */ +#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */ +#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */ +#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */ diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt new file mode 100644 index 00000000000..3014795b173 --- /dev/null +++ b/Documentation/sound/alsa/soc/machine.txt @@ -0,0 +1,114 @@ +ASoC Machine Driver +=================== + +The ASoC machine (or board) driver is the code that glues together the platform +and codec drivers. + +The machine driver can contain codec and platform specific code. It registers +the audio subsystem with the kernel as a platform device and is represented by +the following struct:- + +/* SoC machine */ +struct snd_soc_machine { + char *name; + + int (*probe)(struct platform_device *pdev); + int (*remove)(struct platform_device *pdev); + + /* the pre and post PM functions are used to do any PM work before and + * after the codec and DAI's do any PM work. */ + int (*suspend_pre)(struct platform_device *pdev, pm_message_t state); + int (*suspend_post)(struct platform_device *pdev, pm_message_t state); + int (*resume_pre)(struct platform_device *pdev); + int (*resume_post)(struct platform_device *pdev); + + /* machine stream operations */ + struct snd_soc_ops *ops; + + /* CPU <--> Codec DAI links */ + struct snd_soc_dai_link *dai_link; + int num_links; +}; + +probe()/remove() +---------------- +probe/remove are optional. Do any machine specific probe here. + + +suspend()/resume() +------------------ +The machine driver has pre and post versions of suspend and resume to take care +of any machine audio tasks that have to be done before or after the codec, DAI's +and DMA is suspended and resumed. Optional. + + +Machine operations +------------------ +The machine specific audio operations can be set here. Again this is optional. + + +Machine DAI Configuration +------------------------- +The machine DAI configuration glues all the codec and CPU DAI's together. It can +also be used to set up the DAI system clock and for any machine related DAI +initialisation e.g. the machine audio map can be connected to the codec audio +map, unconnnected codec pins can be set as such. Please see corgi.c, spitz.c +for examples. + +struct snd_soc_dai_link is used to set up each DAI in your machine. e.g. + +/* corgi digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link corgi_dai = { + .name = "WM8731", + .stream_name = "WM8731", + .cpu_dai = &pxa_i2s_dai, + .codec_dai = &wm8731_dai, + .init = corgi_wm8731_init, + .config_sysclk = corgi_config_sysclk, +}; + +struct snd_soc_machine then sets up the machine with it's DAI's. e.g. + +/* corgi audio machine driver */ +static struct snd_soc_machine snd_soc_machine_corgi = { + .name = "Corgi", + .dai_link = &corgi_dai, + .num_links = 1, + .ops = &corgi_ops, +}; + + +Machine Audio Subsystem +----------------------- + +The machine soc device glues the platform, machine and codec driver together. +Private data can also be set here. e.g. + +/* corgi audio private data */ +static struct wm8731_setup_data corgi_wm8731_setup = { + .i2c_address = 0x1b, +}; + +/* corgi audio subsystem */ +static struct snd_soc_device corgi_snd_devdata = { + .machine = &snd_soc_machine_corgi, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_wm8731, + .codec_data = &corgi_wm8731_setup, +}; + + +Machine Power Map +----------------- + +The machine driver can optionally extend the codec power map and to become an +audio power map of the audio subsystem. This allows for automatic power up/down +of speaker/HP amplifiers, etc. Codec pins can be connected to the machines jack +sockets in the machine init function. See soc/pxa/spitz.c and dapm.txt for +details. + + +Machine Controls +---------------- + +Machine specific audio mixer controls can be added in the dai init function. \ No newline at end of file diff --git a/Documentation/sound/alsa/soc/overview.txt b/Documentation/sound/alsa/soc/overview.txt new file mode 100644 index 00000000000..753c5cc5984 --- /dev/null +++ b/Documentation/sound/alsa/soc/overview.txt @@ -0,0 +1,83 @@ +ALSA SoC Layer +============== + +The overall project goal of the ALSA System on Chip (ASoC) layer is to provide +better ALSA support for embedded system on chip procesors (e.g. pxa2xx, au1x00, +iMX, etc) and portable audio codecs. Currently there is some support in the +kernel for SoC audio, however it has some limitations:- + + * Currently, codec drivers are often tightly coupled to the underlying SoC + cpu. This is not ideal and leads to code duplication i.e. Linux now has 4 + different wm8731 drivers for 4 different SoC platforms. + + * There is no standard method to signal user initiated audio events. + e.g. Headphone/Mic insertion, Headphone/Mic detection after an insertion + event. These are quite common events on portable devices and ofter require + machine specific code to re route audio, enable amps etc after such an event. + + * Current drivers tend to power up the entire codec when playing + (or recording) audio. This is fine for a PC, but tends to waste a lot of + power on portable devices. There is also no support for saving power via + changing codec oversampling rates, bias currents, etc. + + +ASoC Design +=========== + +The ASoC layer is designed to address these issues and provide the following +features :- + + * Codec independence. Allows reuse of codec drivers on other platforms + and machines. + + * Easy I2S/PCM audio interface setup between codec and SoC. Each SoC interface + and codec registers it's audio interface capabilities with the core and are + subsequently matched and configured when the application hw params are known. + + * Dynamic Audio Power Management (DAPM). DAPM automatically sets the codec to + it's minimum power state at all times. This includes powering up/down + internal power blocks depending on the internal codec audio routing and any + active streams. + + * Pop and click reduction. Pops and clicks can be reduced by powering the + codec up/down in the correct sequence (including using digital mute). ASoC + signals the codec when to change power states. + + * Machine specific controls: Allow machines to add controls to the sound card + e.g. volume control for speaker amp. + +To achieve all this, ASoC basically splits an embedded audio system into 3 +components :- + + * Codec driver: The codec driver is platform independent and contains audio + controls, audio interface capabilities, codec dapm definition and codec IO + functions. + + * Platform driver: The platform driver contains the audio dma engine and audio + interface drivers (e.g. I2S, AC97, PCM) for that platform. + + * Machine driver: The machine driver handles any machine specific controls and + audio events. i.e. turing on an amp at start of playback. + + +Documentation +============= + +The documentation is spilt into the following sections:- + +overview.txt: This file. + +codec.txt: Codec driver internals. + +DAI.txt: Description of Digital Audio Interface standards and how to configure +a DAI within your codec and CPU DAI drivers. + +dapm.txt: Dynamic Audio Power Management + +platform.txt: Platform audio DMA and DAI. + +machine.txt: Machine driver internals. + +pop_clicks.txt: How to minimise audio artifacts. + +clocking.txt: ASoC clocking for best power performance. \ No newline at end of file diff --git a/Documentation/sound/alsa/soc/platform.txt b/Documentation/sound/alsa/soc/platform.txt new file mode 100644 index 00000000000..c88df261e92 --- /dev/null +++ b/Documentation/sound/alsa/soc/platform.txt @@ -0,0 +1,58 @@ +ASoC Platform Driver +==================== + +An ASoC platform driver can be divided into audio DMA and SoC DAI configuration +and control. The platform drivers only target the SoC CPU and must have no board +specific code. + +Audio DMA +========= + +The platform DMA driver optionally supports the following alsa operations:- + +/* SoC audio ops */ +struct snd_soc_ops { + int (*startup)(snd_pcm_substream_t *); + void (*shutdown)(snd_pcm_substream_t *); + int (*hw_params)(snd_pcm_substream_t *, snd_pcm_hw_params_t *); + int (*hw_free)(snd_pcm_substream_t *); + int (*prepare)(snd_pcm_substream_t *); + int (*trigger)(snd_pcm_substream_t *, int); +}; + +The platform driver exports it's DMA functionailty via struct snd_soc_platform:- + +struct snd_soc_platform { + char *name; + + int (*probe)(struct platform_device *pdev); + int (*remove)(struct platform_device *pdev); + int (*suspend)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai); + int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai); + + /* pcm creation and destruction */ + int (*pcm_new)(snd_card_t *, struct snd_soc_codec_dai *, snd_pcm_t *); + void (*pcm_free)(snd_pcm_t *); + + /* platform stream ops */ + snd_pcm_ops_t *pcm_ops; +}; + +Please refer to the alsa driver documentation for details of audio DMA. +http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm + +An example DMA driver is soc/pxa/pxa2xx-pcm.c + + +SoC DAI Drivers +=============== + +Each SoC DAI driver must provide the following features:- + + 1) Digital audio interface (DAI) description + 2) Digital audio interface configuration + 3) PCM's description + 4) Sysclk configuration + 5) Suspend and resume (optional) + +Please see codec.txt for a description of items 1 - 4. diff --git a/Documentation/sound/alsa/soc/pops_clicks.txt b/Documentation/sound/alsa/soc/pops_clicks.txt new file mode 100644 index 00000000000..f4f8de5a968 --- /dev/null +++ b/Documentation/sound/alsa/soc/pops_clicks.txt @@ -0,0 +1,52 @@ +Audio Pops and Clicks +===================== + +Pops and clicks are unwanted audio artifacts caused by the powering up and down +of components within the audio subsystem. This is noticable on PC's when an audio +module is either loaded or unloaded (at module load time the sound card is +powered up and causes a popping noise on the speakers). + +Pops and clicks can be more frequent on portable systems with DAPM. This is because +the components within the subsystem are being dynamically powered depending on +the audio usage and this can subsequently cause a small pop or click every time a +component power state is changed. + + +Minimising Playback Pops and Clicks +=================================== + +Playback pops in portable audio subsystems cannot be completely eliminated atm, +however future audio codec hardware will have better pop and click supression. +Pops can be reduced within playback by powering the audio components in a +specific order. This order is different for startup and shutdown and follows +some basic rules:- + + Startup Order :- DAC --> Mixers --> Output PGA --> Digital Unmute + + Shutdown Order :- Digital Mute --> Output PGA --> Mixers --> DAC + +This assumes that the codec PCM output path from the DAC is via a mixer and then +a PGA (programmable gain amplifier) before being output to the speakers. + + +Minimising Capture Pops and Clicks +================================== + +Capture artifacts are somewhat easier to get rid as we can delay activating the +ADC until all the pops have occured. This follows similar power rules to +playback in that components are powered in a sequence depending upon stream +startup or shutdown. + + Startup Order - Input PGA --> Mixers --> ADC + + Shutdown Order - ADC --> Mixers --> Input PGA + + +Zipper Noise +============ +An unwanted zipper noise can occur within the audio playback or capture stream +when a volume control is changed near its maximum gain value. The zipper noise +is heard when the gain increase or decrease changes the mean audio signal +amplitude too quickly. It can be minimised by enabling the zero cross setting +for each volume control. The ZC forces the gain change to occur when the signal +crosses the zero amplitude line. -- cgit v1.2.3-70-g09d2 From a71a468a50f1385855e28864e26251b02df829bb Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 19 Oct 2006 20:35:56 +0200 Subject: [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 Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- Documentation/sound/alsa/soc/DAI.txt | 358 ++++++++++++++++++++++-------- Documentation/sound/alsa/soc/clocking.txt | 13 +- include/sound/soc.h | 23 +- sound/soc/codecs/wm8731.c | 33 ++- sound/soc/codecs/wm8750.c | 15 +- sound/soc/pxa/pxa2xx-i2s.c | 3 +- sound/soc/soc-core.c | 215 ++++++++++++++---- 7 files changed, 481 insertions(+), 179 deletions(-) (limited to 'Documentation/sound/alsa/soc') diff --git a/Documentation/sound/alsa/soc/DAI.txt b/Documentation/sound/alsa/soc/DAI.txt index 919de76bab8..251545a8869 100644 --- a/Documentation/sound/alsa/soc/DAI.txt +++ b/Documentation/sound/alsa/soc/DAI.txt @@ -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 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 @@ sample rates first and then test your interface. 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 @@ pcmfmt: 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 @@ flags: -------- 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 @@ depends on the codec or CPU DAI). 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 @@ Simple codec that only runs at 8k & 48k @ 256FS in master mode, can generate a 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 @@ Simple codec that only runs at 8k & 48k @ 256FS in master mode, can generate a 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 @@ 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) /* 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). @@ -298,45 +391,66 @@ sizes. 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. @@ -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_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 88a16c9e197..1f55fd8cb11 100644 --- a/Documentation/sound/alsa/soc/clocking.txt +++ b/Documentation/sound/alsa/soc/clocking.txt @@ -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 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 = 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 diff --git a/include/sound/soc.h b/include/sound/soc.h index ecdd1fac94b..3dfe052e078 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -21,7 +21,7 @@ #include #include -#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 @@ struct snd_soc_dai_mode { 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 9adbd2d401c..412291241ec 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -90,32 +90,36 @@ static struct snd_soc_dai_mode wm8731_modes[] = { .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 @@ static struct snd_soc_dai_mode wm8731_modes[] = { .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 @@ static struct snd_soc_dai_mode wm8731_modes[] = { .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 @@ static struct snd_soc_dai_mode wm8731_modes[] = { .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 @@ static struct snd_soc_dai_mode wm8731_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, }, }; diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 243da712d9c..c5d13a9454d 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -343,7 +343,7 @@ static struct snd_soc_dai_mode wm8750_modes[] = { .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 @@ static inline int get_coeff(int mclk, int rate) 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 inline int get_coeff(int mclk, int rate) 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 @@ static int wm8750_pcm_prepare(struct snd_pcm_substream *substream) 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 99f1da32744..98b167fe68e 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -126,7 +126,8 @@ static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { .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 2ce0c8251dc..6da1616bf77 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 @@ static unsigned inline int soc_get_mclk(struct snd_soc_pcm_runtime *rtd, } /* 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 @@ static u16 soc_bfs_mult_to_div(u16 bfs, int rate, unsigned int mclk, /* 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<= min) { - bfs_ |= SND_SOC_FSBD(mclk/j); - dbgc("mult --> div support mult %d\n", - SND_SOC_FSB_REAL(1< div support mult %d\n", + SND_SOC_FSBD_REAL(1<> i) & 0x1) { - j = mclk / (SND_SOC_FSBD_REAL(1<= min) { - bfs_ |= SND_SOC_FSB(j/rate); - dbgc("div --> mult support div %d\n", - SND_SOC_FSBD_REAL(1< rcw support div %d\n", + SND_SOC_FSBW_REAL(1< 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 @@ 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 *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 @@ static int soc_hw_match_params(struct snd_pcm_substream *substream, * 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 @@ found: 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 @@ found: * 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 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) 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) -- cgit v1.2.3-70-g09d2 From 5b78efd2ef206265aa789485580df9799c54b650 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Nov 2006 16:12:50 +0100 Subject: [ALSA] Fix documentation of ASoC Fixed obsolete *_t typedefs in ASoC documentation. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- Documentation/sound/alsa/soc/codec.txt | 10 +++++----- Documentation/sound/alsa/soc/platform.txt | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'Documentation/sound/alsa/soc') diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt index 47b36cb1684..274657a03e1 100644 --- a/Documentation/sound/alsa/soc/codec.txt +++ b/Documentation/sound/alsa/soc/codec.txt @@ -170,11 +170,11 @@ The codec driver also supports the following alsa operations:- /* SoC audio ops */ struct snd_soc_ops { - int (*startup)(snd_pcm_substream_t *); - void (*shutdown)(snd_pcm_substream_t *); - int (*hw_params)(snd_pcm_substream_t *, snd_pcm_hw_params_t *); - int (*hw_free)(snd_pcm_substream_t *); - int (*prepare)(snd_pcm_substream_t *); + int (*startup)(struct snd_pcm_substream *); + void (*shutdown)(struct snd_pcm_substream *); + int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); + int (*hw_free)(struct snd_pcm_substream *); + int (*prepare)(struct snd_pcm_substream *); }; Please refer to the alsa driver PCM documentation for details. diff --git a/Documentation/sound/alsa/soc/platform.txt b/Documentation/sound/alsa/soc/platform.txt index c88df261e92..e95b16d5a53 100644 --- a/Documentation/sound/alsa/soc/platform.txt +++ b/Documentation/sound/alsa/soc/platform.txt @@ -12,12 +12,12 @@ The platform DMA driver optionally supports the following alsa operations:- /* SoC audio ops */ struct snd_soc_ops { - int (*startup)(snd_pcm_substream_t *); - void (*shutdown)(snd_pcm_substream_t *); - int (*hw_params)(snd_pcm_substream_t *, snd_pcm_hw_params_t *); - int (*hw_free)(snd_pcm_substream_t *); - int (*prepare)(snd_pcm_substream_t *); - int (*trigger)(snd_pcm_substream_t *, int); + int (*startup)(struct snd_pcm_substream *); + void (*shutdown)(struct snd_pcm_substream *); + int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); + int (*hw_free)(struct snd_pcm_substream *); + int (*prepare)(struct snd_pcm_substream *); + int (*trigger)(struct snd_pcm_substream *, int); }; The platform driver exports it's DMA functionailty via struct snd_soc_platform:- @@ -31,11 +31,11 @@ struct snd_soc_platform { int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai); /* pcm creation and destruction */ - int (*pcm_new)(snd_card_t *, struct snd_soc_codec_dai *, snd_pcm_t *); - void (*pcm_free)(snd_pcm_t *); + int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *); + void (*pcm_free)(struct snd_pcm *); /* platform stream ops */ - snd_pcm_ops_t *pcm_ops; + struct snd_pcm_ops *pcm_ops; }; Please refer to the alsa driver documentation for details of audio DMA. -- cgit v1.2.3-70-g09d2 From 10b98527c34dca3f461256f5fcfff9b3790066e0 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 8 Feb 2007 17:06:09 +0100 Subject: [ALSA] ASoC documentation updates This patch updates the documentation for ASoC to reflect the recent changes in API between 0.12.x and 0.13.x Changes:- o Removed all reference to old API's. o Removed references and examples of automatic DAI config and matching. o Fixed 80 char line length on some files. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- Documentation/sound/alsa/soc/DAI.txt | 490 --------------------------- Documentation/sound/alsa/soc/clocking.txt | 273 +-------------- Documentation/sound/alsa/soc/codec.txt | 107 ++---- Documentation/sound/alsa/soc/machine.txt | 3 +- Documentation/sound/alsa/soc/pops_clicks.txt | 12 +- 5 files changed, 48 insertions(+), 837 deletions(-) (limited to 'Documentation/sound/alsa/soc') diff --git a/Documentation/sound/alsa/soc/DAI.txt b/Documentation/sound/alsa/soc/DAI.txt index 251545a8869..58cbfd01ea8 100644 --- a/Documentation/sound/alsa/soc/DAI.txt +++ b/Documentation/sound/alsa/soc/DAI.txt @@ -54,493 +54,3 @@ Common PCM operating modes:- o Mode A - MSB is transmitted on falling edge of first BCLK after FRAME/SYNC. o Mode B - MSB is transmitted on rising edge of FRAME/SYNC. - - -ASoC DAI Configuration -====================== - -Every CODEC DAI and SoC DAI must have their capabilities defined in order to -be configured together at runtime when the audio and clocking parameters are -known. This is achieved by creating an array of struct snd_soc_hw_mode in the -the CODEC and SoC interface drivers. Each element in the array describes a DAI -mode and each mode is usually based upon the DAI system clock to sample rate -ratio (FS). - -i.e. 48k sample rate @ 256 FS = sytem clock of 12.288 MHz - 48000 * 256 = 12288000 - -The CPU and Codec DAI modes are then ANDed together at runtime to determine the -rutime DAI configuration for both the Codec and CPU. - -When creating a new codec or SoC DAI it's probably best to start of with a few -sample rates first and then test your interface. - -struct snd_soc_dai_mode is defined (in soc.h) as:- - -/* SoC DAI mode */ -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: ----- -This field defines the DAI mode hardware format (e.g. I2S settings) and -supports the following settings:- - - 1) hardware DAI formats - -#define SND_SOC_DAIFMT_I2S (1 << 0) /* I2S mode */ -#define SND_SOC_DAIFMT_RIGHT_J (1 << 1) /* Right justified mode */ -#define SND_SOC_DAIFMT_LEFT_J (1 << 2) /* Left Justified mode */ -#define SND_SOC_DAIFMT_DSP_A (1 << 3) /* L data msb after FRM */ -#define SND_SOC_DAIFMT_DSP_B (1 << 4) /* L data msb during FRM */ -#define SND_SOC_DAIFMT_AC97 (1 << 5) /* AC97 */ - - 2) hw DAI signal inversions - -#define SND_SOC_DAIFMT_NB_NF (1 << 8) /* normal bit clock + frame */ -#define SND_SOC_DAIFMT_NB_IF (1 << 9) /* normal bclk + inv frm */ -#define SND_SOC_DAIFMT_IB_NF (1 << 10) /* invert bclk + nor frm */ -#define SND_SOC_DAIFMT_IB_IF (1 << 11) /* invert bclk + frm */ - - 3) hw clock masters - This is wrt the codec, the inverse is true for the interface - i.e. if the codec is clk and frm master then the interface is - clk and frame slave. - -#define SND_SOC_DAIFMT_CBM_CFM (1 << 12) /* codec clk & frm master */ -#define SND_SOC_DAIFMT_CBS_CFM (1 << 13) /* codec clk slave & frm master */ -#define SND_SOC_DAIFMT_CBM_CFS (1 << 14) /* codec clk master & frame slave */ -#define SND_SOC_DAIFMT_CBS_CFS (1 << 15) /* codec clk & frm slave */ - -At least one option from each section must be selected. Multiple selections are -also supported e.g. - - .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_RIGHT_J | \ - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_IB_NF | \ - SND_SOC_DAIFMT_IB_IF - - -tdm: ------- -This field defines the Time Division Multiplexing left and right word -positions for the DAI mode if applicable. Set to SND_SOC_DAITDM_LRDW(0,0) for -no TDM. - - -pcmfmt: ---------- -The hardware PCM format. This describes the PCM formats supported by the DAI -mode e.g. - - .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. - - .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 - - -pcmdir: ---------- -The stream directions supported by this mode. e.g. playback and capture - - -flags: --------- -The DAI hardware flags supported by the mode. - -/* 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. - - -fs: ------ -The FS supported by this DAI mode FS is the ratio between the system clock and -the sample rate. See above - -bfs: ------- -BFS is the ratio of BCLK to MCLK or the ratio of BCLK to sample rate (this -depends on the codec or CPU DAI). - -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 flags above. - -priv: ------ -private codec mode data. - - - -Examples -======== - -Note that Codec DAI and CPU DAI examples are interchangeable in these examples -as long as the bus master is reversed. i.e. - - SND_SOC_DAIFMT_CBM_CFM would become SND_SOC_DAIFMT_CBS_CFS - and vice versa. - -This applies to all SND_SOC_DAIFMT_CB*_CF*. - -Example 1 ---------- - -Simple codec that only runs at 8k & 48k @ 256FS in master mode, can generate a -BCLK of either MCLK/2 or MCLK/4. - - /* codec master */ - { - .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 ---------- -Simple codec that only runs at 8k & 48k @ 256FS in master mode, can generate a -BCLK of either Rate * 32 or Rate * 64. - - /* codec master */ - { - .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 */ - { - .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 */ - { - .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 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 -mode as and does not care about FS or BCLK (as long as there is enough bandwidth). - - #define CODEC_FSB \ - (SND_SOC_FSBD(1) | SND_SOC_FSBD(2) | SND_SOC_FSBD(4) | \ - SND_SOC_FSBD(8) | SND_SOC_FSBD(16)) - - #define CODEC_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 |\ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) - - /* codec master @ 128, 192 & 256 FS */ - { - .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 */ - { - .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 ---------- -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). -Codec can also run in slave mode as and does not care about FS or BCLK (as long -as there is enough bandwidth). Codec can support 16, 24 and 32 bit PCM sample -sizes. - - #define CODEC_FSB \ - (SND_SOC_FSBD(1) | SND_SOC_FSBD(2) | SND_SOC_FSBD(4) | \ - SND_SOC_FSBD(8) | SND_SOC_FSBD(16)) - - #define CODEC_PCM_FORMATS \ - (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ - SNDRV_PCM_FORMAT_S24_3LE | SNDRV_PCM_FORMAT_S24_LE | SNDRV_PCM_FORMAT_S32_LE) - - /* codec master */ - { - .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 */ - { - .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 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 */ - { - .pcmfmt = AC97_PCM_FORMATS, - .pcmrate = SNDRV_PCM_RATE_48000, - } - - -Example 8 ---------- - -CPU DAI that supports 8k - 48k @ 256FS and BCLK = MCLK / 4 in master mode. -Slave mode (CPU DAI is FRAME master) supports 8k - 96k at any FS as long as -BCLK = 64 * rate. (Intel XScale I2S controller). - - #define PXA_I2S_DAIFMT \ - (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF) - - #define PXA_I2S_DIR \ - (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) - - #define PXA_I2S_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) - - /* priv is divider */ - static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { - /* pxa2xx I2S frame and clock master modes */ - { - .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 */ - { - .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 1f55fd8cb11..e93960d53a1 100644 --- a/Documentation/sound/alsa/soc/clocking.txt +++ b/Documentation/sound/alsa/soc/clocking.txt @@ -40,275 +40,12 @@ BCLK = LRC * x BCLK = LRC * Channels * Word Size -This relationship depends on the codec or SoC CPU in particular. ASoC can quite -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). +This relationship depends on the codec or SoC CPU in particular. In general +it's best to configure BCLK to the lowest possible speed (depending on your +rate, number of channels and wordsize) to save on power. +It's also desireable to use the codec (if possible) to drive (or master) the +audio clocks as it's usually gives more accurate sample rates than the CPU. -ASoC Clocking -------------- -The ASoC core determines the clocking for each particular configuration at -runtime. This is to allow for dynamic audio clocking wereby the audio clock is -variable and depends on the system state or device usage scenario. i.e. a voice -call requires slower clocks (and hence less power) than MP3 playback. -ASoC will call the config_sysclock() function for the target machine during the -audio parameters configuration. The function is responsible for then clocking -the machine audio subsytem and returning the audio clock speed to the core. -This function should also call the codec and cpu DAI clock_config() functions -to configure their respective internal clocking if required. - - -ASoC Clocking Control Flow --------------------------- - -The ASoC core will call the machine drivers config_sysclock() when most of the -DAI capabilities are known. The machine driver is then responsible for calling -the codec and/or CPU DAI drivers with the selected capabilities and the current -MCLK. Note that the machine driver is also resonsible for setting the MCLK (and -enabling it). - - (1) Match Codec and CPU DAI capabilities. At this point we have - matched the majority of the DAI fields and now need to make sure this - mode is currently clockable. - - (2) machine->config_sysclk() is now called with the matched DAI FS, sample - rate and BCLK master. This function then gets/sets the current audio - clock (depening on usage) and calls the codec and CPUI DAI drivers with - the FS, rate, BCLK master and MCLK. - - (3) Codec/CPU DAI config_sysclock(). This function checks that the FS, rate, - BCLK master and MCLK are acceptable for the codec or CPU DAI. It also - sets the DAI internal state to work with said clocks. - -The config_sysclk() functions for CPU, codec and machine should return the MCLK -on success and 0 on failure. - - -Examples (b = BCLK, l = LRC) -============================ - -Example 1 ---------- - -Simple codec that only runs at 48k @ 256FS in master mode. - -CPU only runs as slave DAI, however it generates a variable MCLK. - - -------- --------- - | | <----mclk--- | | - | Codec |b -----------> | CPU | - | |l -----------> | | - | | | | - -------- --------- - -The codec driver has the following config_sysclock() - - static unsigned int config_sysclk(struct snd_soc_codec_dai *dai, - struct snd_soc_clock_info *info, unsigned int clk) - { - /* make sure clock is 256 * rate */ - if(info->rate << 8 == clk) { - dai->mclk = clk; - return clk; - } - - return 0; - } - -The CPU I2S DAI driver has the following config_sysclk() - - static unsigned int config_sysclk(struct snd_soc_codec_dai *dai, - struct snd_soc_clock_info *info, unsigned int clk) - { - /* can we support this clk */ - if(set_audio_clk(clk) < 0) - return -EINVAL; - - dai->mclk = clk; - return dai->clk; - } - -The machine driver config_sysclk() in this example is as follows:- - - unsigned int machine_config_sysclk(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_clock_info *info) - { - int clk = info->rate * info->fs; - - /* check that CPU can deliver clock */ - if(rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, clk) < 0) - return -EINVAL; - - /* can codec work with this clock */ - return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, clk); - } - - -Example 2 ---------- - -Codec that can master at 8k and 48k at various FS (and hence supports a fixed -set of input MCLK's) and can also be slave at various FS . - -The CPU can master at 8k and 48k @256 FS and can be slave at any FS. - -MCLK is a 12.288MHz crystal on this machine. - - -------- --------- - | | <---xtal---> | | - | Codec |b <----------> | CPU | - | |l <----------> | | - | | | | - -------- --------- - - -The codec driver has the following config_sysclock() - - /* supported input clocks */ - const static int hifi_clks[] = {11289600, 12000000, 12288000, - 16934400, 18432000}; - - static unsigned int config_hsysclk(struct snd_soc_codec_dai *dai, - struct snd_soc_clock_info *info, unsigned int clk) - { - int i; - - /* is clk supported */ - for(i = 0; i < ARRAY_SIZE(hifi_clks); i++) { - if(clk == hifi_clks[i]) { - dai->mclk = clk; - return clk; - } - } - - /* this clk is not supported */ - return 0; - } - -The CPU I2S DAI driver has the following config_sysclk() - - static unsigned int config_sysclk(struct snd_soc_codec_dai *dai, - struct snd_soc_clock_info *info, unsigned int clk) - { - /* are we master or slave */ - if (info->bclk_master & - (SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_CBM_CFS)) { - - /* we can only master @ 256FS */ - if(info->rate << 8 == clk) { - dai->mclk = clk; - return dai->mclk; - } - } else { - /* slave we can run at any FS */ - dai->mclk = clk; - return dai->mclk; - } - - /* not supported */ - return dai->clk; - } - -The machine driver config_sysclk() in this example is as follows:- - - unsigned int machine_config_sysclk(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_clock_info *info) - { - int clk = 12288000; /* 12.288MHz */ - - /* who's driving the link */ - if (info->bclk_master & - (SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_CBM_CFS)) { - /* codec master */ - - /* check that CPU can work with clock */ - if(rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, clk) < 0) - return -EINVAL; - - /* can codec work with this clock */ - return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, clk); - } else { - /* cpu master */ - - /* check that codec can work with clock */ - if(rtd->codec_dai->config_sysclk(rtd->codec_dai, info, clk) < 0) - return -EINVAL; - - /* can CPU work with this clock */ - return rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, clk); - } - } - - - -Example 3 ---------- - -Codec that masters at 8k ... 48k @256 FS. Codec can also be slave and -doesn't care about FS. The codec has an internal PLL and dividers to generate -the necessary internal clocks (for 256FS). - -CPU can only be slave and doesn't care about FS. - -MCLK is a non controllable 13MHz clock from the CPU. - - - -------- --------- - | | <----mclk--- | | - | Codec |b <----------> | CPU | - | |l <----------> | | - | | | | - -------- --------- - -The codec driver has the following config_sysclock() - - /* valid PCM clock dividers * 2 */ - static int pcm_divs[] = {2, 6, 11, 4, 8, 12, 16}; - - static unsigned int config_vsysclk(struct snd_soc_codec_dai *dai, - struct snd_soc_clock_info *info, unsigned int clk) - { - int i, j, best_clk = info->fs * info->rate; - - /* can we run at this clk without the PLL ? */ - for (i = 0; i < ARRAY_SIZE(pcm_divs); i++) { - if ((best_clk >> 1) * pcm_divs[i] == clk) { - dai->pll_in = 0; - dai->clk_div = pcm_divs[i]; - dai->mclk = best_clk; - return dai->mclk; - } - } - - /* now check for PLL support */ - for (i = 0; i < ARRAY_SIZE(pll_div); i++) { - if (pll_div[i].pll_in == clk) { - for (j = 0; j < ARRAY_SIZE(pcm_divs); j++) { - if (pll_div[i].pll_out == pcm_divs[j] * (best_clk >> 1)) { - dai->pll_in = clk; - dai->pll_out = pll_div[i].pll_out; - dai->clk_div = pcm_divs[j]; - dai->mclk = best_clk; - return dai->mclk; - } - } - } - } - - /* this clk is not supported */ - return 0; - } - - -The CPU I2S DAI driver has the does not need a config_sysclk() as it can slave -at any FS. - - unsigned int config_sysclk(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_clock_info *info) - { - /* codec has pll that generates mclk from 13MHz xtal */ - return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, 13000000); - } diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt index 274657a03e1..48983c75aad 100644 --- a/Documentation/sound/alsa/soc/codec.txt +++ b/Documentation/sound/alsa/soc/codec.txt @@ -6,21 +6,18 @@ codec to provide audio capture and playback. It should contain no code that is specific to the target platform or machine. All platform and machine specific code should be added to the platform and machine drivers respectively. -Each codec driver must provide the following features:- +Each codec driver *must* provide the following features:- - 1) Digital audio interface (DAI) description - 2) Digital audio interface configuration - 3) PCM's description - 4) Codec control IO - using I2C, 3 Wire(SPI) or both API's - 5) Mixers and audio controls - 6) Sysclk configuration - 7) Codec audio operations + 1) Codec DAI and PCM configuration + 2) Codec control IO - using I2C, 3 Wire(SPI) or both API's + 3) Mixers and audio controls + 4) Codec audio operations Optionally, codec drivers can also provide:- - 8) DAPM description. - 9) DAPM event handler. -10) DAC Digital mute control. + 5) DAPM description. + 6) DAPM event handler. + 7) DAC Digital mute control. It's probably best to use this guide in conjuction with the existing codec driver code in sound/soc/codecs/ @@ -28,58 +25,47 @@ driver code in sound/soc/codecs/ ASoC Codec driver breakdown =========================== -1 - Digital Audio Interface (DAI) description ---------------------------------------------- -The DAI is a digital audio data transfer link between the codec and host SoC -CPU. It typically has data transfer capabilities in both directions -(playback and capture) and can run at a variety of different speeds. -Supported interfaces currently include AC97, I2S and generic PCM style links. -Please read DAI.txt for implementation information. - - -2 - Digital Audio Interface (DAI) configuration ------------------------------------------------ -DAI configuration is handled by the codec_pcm_prepare function and is -responsible for configuring and starting the DAI on the codec. This can be -called multiple times and is atomic. It can access the runtime parameters. - -This usually consists of a large function with numerous switch statements to -set up each configuration option. These options are set by the core at runtime. - - -3 - Codec PCM's ---------------- -Each codec must have it's PCM's defined. This defines the number of channels, -stream names, callbacks and codec name. It is also used to register the DAI -with the ASoC core. The PCM structure also associates the DAI capabilities with -the ALSA PCM. +1 - Codec DAI and PCM configuration +----------------------------------- +Each codec driver must have a struct snd_soc_codec_dai to define it's DAI and +PCM's capablities and operations. This struct is exported so that it can be +registered with the core by your machine driver. e.g. -static struct snd_soc_pcm_codec wm8731_pcm_client = { +struct snd_soc_codec_dai wm8731_dai = { .name = "WM8731", + /* playback capabilities */ .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 2, - }, + .rates = WM8731_RATES, + .formats = WM8731_FORMATS,}, + /* capture capabilities */ .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 2, - }, - .config_sysclk = wm8731_config_sysclk, + .rates = WM8731_RATES, + .formats = WM8731_FORMATS,}, + /* pcm operations - see section 4 below */ .ops = { .prepare = wm8731_pcm_prepare, + .hw_params = wm8731_hw_params, + .shutdown = wm8731_shutdown, }, - .caps = { - .num_modes = ARRAY_SIZE(wm8731_hwfmt), - .modes = &wm8731_hwfmt[0], - }, + /* DAI operations - see DAI.txt */ + .dai_ops = { + .digital_mute = wm8731_mute, + .set_sysclk = wm8731_set_dai_sysclk, + .set_fmt = wm8731_set_dai_fmt, + } }; +EXPORT_SYMBOL_GPL(wm8731_dai); -4 - Codec control IO +2 - Codec control IO -------------------- The codec can ususally be controlled via an I2C or SPI style interface (AC97 combines control with data in the DAI). The codec drivers will have to provide @@ -104,7 +90,7 @@ read/write:- hw_read_t hw_read; -5 - Mixers and audio controls +3 - Mixers and audio controls ----------------------------- All the codec mixers and audio controls can be defined using the convenience macros defined in soc.h. @@ -143,28 +129,7 @@ Defines an single enumerated control as follows:- Defines a stereo enumerated control -6 - System clock configuration. -------------------------------- -The system clock that drives the audio subsystem can change depending on sample -rate and the system power state. i.e. - -o Higher sample rates sometimes need a higher system clock. -o Low system power states can sometimes limit the available clocks. - -This function is a callback that the machine driver can call to set and -determine if the clock and sample rate combination is supported by the codec at -the present time (and system state). - -NOTE: If the codec has a PLL then it has a lot more flexability wrt clock and -sample rate combinations. - -Your config_sysclock function should return the MCLK if it's a valid -combination for your codec else 0; - -Please read clocking.txt now. - - -7 - Codec Audio Operations +4 - Codec Audio Operations -------------------------- The codec driver also supports the following alsa operations:- @@ -181,7 +146,7 @@ Please refer to the alsa driver PCM documentation for details. http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm -8 - DAPM description. +5 - DAPM description. --------------------- The Dynamic Audio Power Management description describes the codec's power components, their relationships and registers to the ASoC core. Please read @@ -190,7 +155,7 @@ dapm.txt for details of building the description. Please also see the examples in other codec drivers. -9 - DAPM event handler +6 - DAPM event handler ---------------------- This function is a callback that handles codec domain PM calls and system domain PM calls (e.g. suspend and resume). It's used to put the codec to sleep @@ -210,7 +175,7 @@ Power states:- SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */ -10 - Codec DAC digital mute control. +7 - Codec DAC digital mute control. ------------------------------------ Most codecs have a digital mute before the DAC's that can be used to minimise any system noise. The mute stops any digital data from entering the DAC. diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt index 3014795b173..72bd222f2a2 100644 --- a/Documentation/sound/alsa/soc/machine.txt +++ b/Documentation/sound/alsa/soc/machine.txt @@ -64,7 +64,7 @@ static struct snd_soc_dai_link corgi_dai = { .cpu_dai = &pxa_i2s_dai, .codec_dai = &wm8731_dai, .init = corgi_wm8731_init, - .config_sysclk = corgi_config_sysclk, + .ops = &corgi_ops, }; struct snd_soc_machine then sets up the machine with it's DAI's. e.g. @@ -74,7 +74,6 @@ static struct snd_soc_machine snd_soc_machine_corgi = { .name = "Corgi", .dai_link = &corgi_dai, .num_links = 1, - .ops = &corgi_ops, }; diff --git a/Documentation/sound/alsa/soc/pops_clicks.txt b/Documentation/sound/alsa/soc/pops_clicks.txt index f4f8de5a968..2cf7ee5b3d7 100644 --- a/Documentation/sound/alsa/soc/pops_clicks.txt +++ b/Documentation/sound/alsa/soc/pops_clicks.txt @@ -2,14 +2,14 @@ Audio Pops and Clicks ===================== Pops and clicks are unwanted audio artifacts caused by the powering up and down -of components within the audio subsystem. This is noticable on PC's when an audio -module is either loaded or unloaded (at module load time the sound card is +of components within the audio subsystem. This is noticable on PC's when an +audio module is either loaded or unloaded (at module load time the sound card is powered up and causes a popping noise on the speakers). -Pops and clicks can be more frequent on portable systems with DAPM. This is because -the components within the subsystem are being dynamically powered depending on -the audio usage and this can subsequently cause a small pop or click every time a -component power state is changed. +Pops and clicks can be more frequent on portable systems with DAPM. This is +because the components within the subsystem are being dynamically powered +depending on the audio usage and this can subsequently cause a small pop or +click every time a component power state is changed. Minimising Playback Pops and Clicks -- cgit v1.2.3-70-g09d2