aboutsummaryrefslogtreecommitdiffstats
path: root/Documentation/sound/alsa/soc/clocking.txt
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/sound/alsa/soc/clocking.txt')
-rw-r--r--Documentation/sound/alsa/soc/clocking.txt309
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);
+ }