summaryrefslogtreecommitdiffstats
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.txt273
1 files changed, 5 insertions, 268 deletions
diff --git a/Documentation/sound/alsa/soc/clocking.txt b/Documentation/sound/alsa/soc/clocking.txt
index 1f55fd8cb117..e93960d53a1e 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);
- }