diff options
Diffstat (limited to 'Documentation/sound/alsa/soc/clocking.txt')
-rw-r--r-- | Documentation/sound/alsa/soc/clocking.txt | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/Documentation/sound/alsa/soc/clocking.txt b/Documentation/sound/alsa/soc/clocking.txt new file mode 100644 index 0000000..88a16c9 --- /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); + } |