| 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); |
| } |