diff options
Diffstat (limited to 'Documentation/sound/soc')
| -rw-r--r-- | Documentation/sound/soc/clocking.rst | 58 | ||||
| -rw-r--r-- | Documentation/sound/soc/codec-to-codec.rst | 115 | ||||
| -rw-r--r-- | Documentation/sound/soc/codec.rst | 190 | ||||
| -rw-r--r-- | Documentation/sound/soc/dai.rst | 64 | ||||
| -rw-r--r-- | Documentation/sound/soc/dapm-graph.svg | 375 | ||||
| -rw-r--r-- | Documentation/sound/soc/dapm.rst | 422 | ||||
| -rw-r--r-- | Documentation/sound/soc/dpcm.rst | 387 | ||||
| -rw-r--r-- | Documentation/sound/soc/index.rst | 21 | ||||
| -rw-r--r-- | Documentation/sound/soc/jack.rst | 72 | ||||
| -rw-r--r-- | Documentation/sound/soc/machine.rst | 123 | ||||
| -rw-r--r-- | Documentation/sound/soc/overview.rst | 69 | ||||
| -rw-r--r-- | Documentation/sound/soc/platform.rst | 78 | ||||
| -rw-r--r-- | Documentation/sound/soc/pops-clicks.rst | 55 | ||||
| -rw-r--r-- | Documentation/sound/soc/usb.rst | 482 |
14 files changed, 2511 insertions, 0 deletions
diff --git a/Documentation/sound/soc/clocking.rst b/Documentation/sound/soc/clocking.rst new file mode 100644 index 000000000..25d016ea8 --- /dev/null +++ b/Documentation/sound/soc/clocking.rst @@ -0,0 +1,58 @@ +============== +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 referred 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. PLLs and CPU based clocks) are configurable in that +their speed can be altered by software (depending on the system use and to save +power). Other master clocks are fixed at a 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 (LRC = Rate). + +Bit Clock can be generated as follows:- + +- BCLK = MCLK / x, or +- BCLK = LRC * x, or +- BCLK = LRC * Channels * Word Size + +This relationship depends on the codec or SoC CPU in particular. In general +it is best to configure BCLK to the lowest possible speed (depending on your +rate, number of channels and word size) to save on power. + +It is also desirable to use the codec (if possible) to drive (or master) the +audio clocks as it usually gives more accurate sample rates than the CPU. + +ASoC provided clock APIs +------------------------ + +.. kernel-doc:: sound/soc/soc-dai.c + :identifiers: snd_soc_dai_set_sysclk + +.. kernel-doc:: sound/soc/soc-dai.c + :identifiers: snd_soc_dai_set_clkdiv + +.. kernel-doc:: sound/soc/soc-dai.c + :identifiers: snd_soc_dai_set_pll + +.. kernel-doc:: sound/soc/soc-dai.c + :identifiers: snd_soc_dai_set_bclk_ratio diff --git a/Documentation/sound/soc/codec-to-codec.rst b/Documentation/sound/soc/codec-to-codec.rst new file mode 100644 index 000000000..973c147d9 --- /dev/null +++ b/Documentation/sound/soc/codec-to-codec.rst @@ -0,0 +1,115 @@ +============================================== +Creating codec to codec dai link for ALSA dapm +============================================== + +Mostly the flow of audio is always from CPU to codec so your system +will look as below: +:: + + --------- --------- + | | dai | | + CPU -------> codec + | | | | + --------- --------- + +In case your system looks as below: +:: + + --------- + | | + codec-2 + | | + --------- + | + dai-2 + | + ---------- --------- + | | dai-1 | | + CPU -------> codec-1 + | | | | + ---------- --------- + | + dai-3 + | + --------- + | | + codec-3 + | | + --------- + +Suppose codec-2 is a bluetooth chip and codec-3 is connected to +a speaker and you have a below scenario: +codec-2 will receive the audio data and the user wants to play that +audio through codec-3 without involving the CPU.This +aforementioned case is the ideal case when codec to codec +connection should be used. + +Your dai_link should appear as below in your machine +file: +:: + + /* + * this pcm stream only supports 24 bit, 2 channel and + * 48k sampling rate. + */ + static const struct snd_soc_pcm_stream dsp_codec_params = { + .formats = SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + }; + + { + .name = "CPU-DSP", + .stream_name = "CPU-DSP", + .cpu_dai_name = "samsung-i2s.0", + .codec_name = "codec-2, + .codec_dai_name = "codec-2-dai_name", + .platform_name = "samsung-i2s.0", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBP_CFP, + .ignore_suspend = 1, + .c2c_params = &dsp_codec_params, + .num_c2c_params = 1, + }, + { + .name = "DSP-CODEC", + .stream_name = "DSP-CODEC", + .cpu_dai_name = "wm0010-sdi2", + .codec_name = "codec-3, + .codec_dai_name = "codec-3-dai_name", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBP_CFP, + .ignore_suspend = 1, + .c2c_params = &dsp_codec_params, + .num_c2c_params = 1, + }, + +Above code snippet is motivated from sound/soc/samsung/speyside.c. + +Note the "c2c_params" callback which lets the dapm know that this +dai_link is a codec to codec connection. + +In dapm core a route is created between cpu_dai playback widget +and codec_dai capture widget for playback path and vice-versa is +true for capture path. In order for this aforementioned route to get +triggered, DAPM needs to find a valid endpoint which could be either +a sink or source widget corresponding to playback and capture path +respectively. + +In order to trigger this dai_link widget, a thin codec driver for +the speaker amp can be created as demonstrated in wm8727.c file, it +sets appropriate constraints for the device even if it needs no control. + +Make sure to name your corresponding cpu and codec playback and capture +dai names ending with "Playback" and "Capture" respectively as dapm core +will link and power those dais based on the name. + +A dai_link in a "simple-audio-card" will automatically be detected as +codec to codec when all DAIs on the link belong to codec components. +The dai_link will be initialized with the subset of stream parameters +(channels, format, sample rate) supported by all DAIs on the link. Since +there is no way to provide these parameters in the device tree, this is +mostly useful for communication with simple fixed-function codecs, such +as a Bluetooth controller or cellular modem. diff --git a/Documentation/sound/soc/codec.rst b/Documentation/sound/soc/codec.rst new file mode 100644 index 000000000..b9d87a4f9 --- /dev/null +++ b/Documentation/sound/soc/codec.rst @@ -0,0 +1,190 @@ +======================= +ASoC Codec Class Driver +======================= + +The codec class driver is generic and hardware independent code that configures +the codec, FM, MODEM, BT or external DSP 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 class driver *must* provide the following features:- + +1. Codec DAI and PCM configuration +2. Codec control IO - using RegMap API +3. Mixers and audio controls +4. Codec audio operations +5. DAPM description. +6. DAPM event handler. + +Optionally, codec drivers can also provide:- + +7. DAC Digital mute control. + +Its probably best to use this guide in conjunction with the existing codec +driver code in sound/soc/codecs/ + +ASoC Codec driver breakdown +=========================== + +Codec DAI and PCM configuration +------------------------------- +Each codec driver must have a struct snd_soc_dai_driver to define its DAI and +PCM capabilities 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_dai_ops wm8731_dai_ops = { + .prepare = wm8731_pcm_prepare, + .hw_params = wm8731_hw_params, + .shutdown = wm8731_shutdown, + .mute_stream = wm8731_mute, + .set_sysclk = wm8731_set_dai_sysclk, + .set_fmt = wm8731_set_dai_fmt, + }; + + struct snd_soc_dai_driver wm8731_dai = { + .name = "wm8731-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8731_RATES, + .formats = WM8731_FORMATS,}, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8731_RATES, + .formats = WM8731_FORMATS,}, + .ops = &wm8731_dai_ops, + .symmetric_rate = 1, + }; + + +Codec control IO +---------------- +The codec can usually be controlled via an I2C or SPI style interface +(AC97 combines control with data in the DAI). The codec driver should use the +Regmap API for all codec IO. Please see include/linux/regmap.h and existing +codec drivers for example regmap usage. + + +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 + + +Codec Audio Operations +---------------------- +The codec driver also supports the following ALSA PCM operations:- +:: + + /* SoC audio ops */ + struct snd_soc_ops { + 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 :doc:`ALSA driver PCM documentation +<../kernel-api/writing-an-alsa-driver>` for details. + + +DAPM description +---------------- +The Dynamic Audio Power Management description describes the codec power +components and their relationships and registers to the ASoC core. +Please read dapm.rst for details of building the description. + +Please also see the examples in other codec drivers. + + +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 is 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 */ + + +Codec DAC digital mute control +------------------------------ +Most codecs have a digital mute before the DACs 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_dai *dai, int mute, int direction) + { + struct snd_soc_component *component = dai->component; + u16 mute_reg = snd_soc_component_read(component, WM8974_DAC) & 0xffbf; + + if (mute) + snd_soc_component_write(component, WM8974_DAC, mute_reg | 0x40); + else + snd_soc_component_write(component, WM8974_DAC, mute_reg); + return 0; + } diff --git a/Documentation/sound/soc/dai.rst b/Documentation/sound/soc/dai.rst new file mode 100644 index 000000000..bf8431386 --- /dev/null +++ b/Documentation/sound/soc/dai.rst @@ -0,0 +1,64 @@ +================================== +ASoC Digital Audio Interface (DAI) +================================== + +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 : +https://www.intel.com/p/en_US/business/design + + +I2S +=== + +I2S is a common 4 wire DAI used in HiFi, STB and portable devices. The Tx and +Rx lines are used for audio transmission, while 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 LRCLKs, this allows for simultaneous capture and playback at +different sample rates. + +I2S has several different operating modes:- + +I2S + MSB is transmitted on the falling edge of the first BCLK after LRC + transition. + +Left Justified + MSB is transmitted on transition of LRC. + +Right Justified + MSB is transmitted sample size BCLKs before LRC transition. + +PCM +=== + +PCM is another 4 wire interface, very similar to I2S, which can support a more +flexible protocol. It has bit clock (BCLK) and sync (SYNC) lines that are used +to synchronise the link while the Tx and Rx lines are used to transmit and +receive the audio data. Bit clock usually varies depending on sample rate +while sync runs at the sample rate. PCM also supports Time Division +Multiplexing (TDM) in that several devices can use the bus simultaneously (this +is sometimes referred to as network mode). + +Common PCM operating modes:- + +Mode A + MSB is transmitted on falling edge of first BCLK after FRAME/SYNC. + +Mode B + MSB is transmitted on rising edge of FRAME/SYNC. diff --git a/Documentation/sound/soc/dapm-graph.svg b/Documentation/sound/soc/dapm-graph.svg new file mode 100644 index 000000000..d783672db --- /dev/null +++ b/Documentation/sound/soc/dapm-graph.svg @@ -0,0 +1,375 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 2.43.0 (0) + --> +<!-- Title: G Pages: 1 --> +<svg width="900pt" height="630pt" + viewBox="0.00 0.00 900.00 630.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 626)"> +<title>G</title> +<polygon fill="white" stroke="transparent" points="-4,4 -4,-626 896,-626 896,4 -4,4"/> +<g id="clust1" class="cluster"> +<title>ROOT</title> +<polygon fill="none" stroke="dodgerblue" points="8,-537 8,-614 102,-614 102,-537 8,-537"/> +<text text-anchor="middle" x="55" y="-598.8" font-family="sans-serif" font-size="14.00">ROOT</text> +</g> +<g id="clust2" class="cluster"> +<title>4000b000.audio-controller</title> +<polygon fill="none" stroke="dodgerblue" points="120,-378 120,-455 312,-455 312,-378 120,-378"/> +<text text-anchor="middle" x="216" y="-439.8" font-family="sans-serif" font-size="14.00">4000b000.audio-controller</text> +</g> +<g id="clust5" class="cluster"> +<title>cs42l51.0-004a</title> +<polygon fill="none" stroke="dodgerblue" points="330,-8 330,-614 884,-614 884,-8 330,-8"/> +<text text-anchor="middle" x="607" y="-598.8" font-family="sans-serif" font-size="14.00">cs42l51.0-004a</text> +</g> +<g id="clust9" class="cluster"> +<title>hdmi-audio-codec.1.auto</title> +<polygon fill="none" stroke="dodgerblue" points="110,-463 110,-614 314,-614 314,-463 110,-463"/> +<text text-anchor="middle" x="212" y="-598.8" font-family="sans-serif" font-size="14.00">hdmi-audio-codec.1.auto</text> +</g> +<!-- ROOT_Amplifier --> +<g id="node1" class="node"> +<title>ROOT_Amplifier</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="93.5,-583 16.5,-583 16.5,-545 93.5,-545 93.5,-583"/> +<text text-anchor="middle" x="55" y="-567.8" font-family="sans-serif" font-size="14.00">Amplifier</text> +<text text-anchor="middle" x="55" y="-552.8" font-family="sans-serif" font-size="14.00">[out_drv]</text> +</g> +<!-- 4000b000.audio-controller_capture --> +<g id="node2" class="node"> +<title>4000b000.audio-controller_capture</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="202,-424 128,-424 128,-386 202,-386 202,-424"/> +<text text-anchor="middle" x="165" y="-408.8" font-family="sans-serif" font-size="14.00">capture</text> +<text text-anchor="middle" x="165" y="-393.8" font-family="sans-serif" font-size="14.00">[dai_out]</text> +</g> +<!-- 4000b000.audio-controller_playback --> +<g id="node3" class="node"> +<title>4000b000.audio-controller_playback</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="304,-424 230,-424 230,-386 304,-386 304,-424"/> +<text text-anchor="middle" x="267" y="-408.8" font-family="sans-serif" font-size="14.00">playback</text> +<text text-anchor="middle" x="267" y="-393.8" font-family="sans-serif" font-size="14.00">[dai_in]</text> +</g> +<!-- hdmi-audio-codec.1.auto_I2S Playback --> +<g id="node28" class="node"> +<title>hdmi-audio-codec.1.auto_I2S Playback</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="306,-583 208,-583 208,-545 306,-545 306,-583"/> +<text text-anchor="middle" x="257" y="-567.8" font-family="sans-serif" font-size="14.00">I2S Playback</text> +<text text-anchor="middle" x="257" y="-552.8" font-family="sans-serif" font-size="14.00">[dai_in]</text> +</g> +<!-- 4000b000.audio-controller_playback->hdmi-audio-codec.1.auto_I2S Playback --> +<g id="edge21" class="edge"> +<title>4000b000.audio-controller_playback->hdmi-audio-codec.1.auto_I2S Playback</title> +<path fill="none" stroke="black" d="M276.84,-424.14C282.19,-435.06 288.26,-449.42 291,-463 295.05,-483.04 296.67,-489.36 291,-509 288.25,-518.54 283.26,-528.01 277.93,-536.3"/> +<polygon fill="black" stroke="black" points="274.89,-534.55 272.11,-544.78 280.66,-538.51 274.89,-534.55"/> +</g> +<!-- hdmi-audio-codec.1.auto_Capture --> +<g id="node4" class="node"> +<title>hdmi-audio-codec.1.auto_Capture</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="192,-509 118,-509 118,-471 192,-471 192,-509"/> +<text text-anchor="middle" x="155" y="-493.8" font-family="sans-serif" font-size="14.00">Capture</text> +<text text-anchor="middle" x="155" y="-478.8" font-family="sans-serif" font-size="14.00">[dai_out]</text> +</g> +<!-- hdmi-audio-codec.1.auto_Capture->4000b000.audio-controller_capture --> +<g id="edge1" class="edge"> +<title>hdmi-audio-codec.1.auto_Capture->4000b000.audio-controller_capture</title> +<path fill="none" stroke="black" d="M157.17,-470.99C158.46,-460.3 160.12,-446.5 161.58,-434.37"/> +<polygon fill="black" stroke="black" points="165.08,-434.61 162.8,-424.26 158.13,-433.77 165.08,-434.61"/> +</g> +<!-- cs42l51.0-004a_AIN1L --> +<g id="node5" class="node"> +<title>cs42l51.0-004a_AIN1L</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="836.5,-583 775.5,-583 775.5,-545 836.5,-545 836.5,-583"/> +<text text-anchor="middle" x="806" y="-567.8" font-family="sans-serif" font-size="14.00">AIN1L</text> +<text text-anchor="middle" x="806" y="-552.8" font-family="sans-serif" font-size="14.00">[input]</text> +</g> +<!-- cs42l51.0-004a_PGA-ADC Mux Left --> +<g id="node22" class="node"> +<title>cs42l51.0-004a_PGA-ADC Mux Left</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="876,-509 736,-509 736,-471 876,-471 876,-509"/> +<text text-anchor="middle" x="806" y="-493.8" font-family="sans-serif" font-size="14.00">PGA-ADC Mux Left</text> +<text text-anchor="middle" x="806" y="-478.8" font-family="sans-serif" font-size="14.00">[mux]</text> +</g> +<!-- cs42l51.0-004a_AIN1L->cs42l51.0-004a_PGA-ADC Mux Left --> +<g id="edge14" class="edge"> +<title>cs42l51.0-004a_AIN1L->cs42l51.0-004a_PGA-ADC Mux Left</title> +<path fill="none" stroke="black" d="M806,-544.83C806,-537.13 806,-527.97 806,-519.42"/> +<polygon fill="black" stroke="black" points="809.5,-519.41 806,-509.41 802.5,-519.41 809.5,-519.41"/> +</g> +<!-- cs42l51.0-004a_AIN1R --> +<g id="node6" class="node"> +<title>cs42l51.0-004a_AIN1R</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="738.5,-583 677.5,-583 677.5,-545 738.5,-545 738.5,-583"/> +<text text-anchor="middle" x="708" y="-567.8" font-family="sans-serif" font-size="14.00">AIN1R</text> +<text text-anchor="middle" x="708" y="-552.8" font-family="sans-serif" font-size="14.00">[input]</text> +</g> +<!-- cs42l51.0-004a_PGA-ADC Mux Right --> +<g id="node23" class="node"> +<title>cs42l51.0-004a_PGA-ADC Mux Right</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="717.5,-509 568.5,-509 568.5,-471 717.5,-471 717.5,-509"/> +<text text-anchor="middle" x="643" y="-493.8" font-family="sans-serif" font-size="14.00">PGA-ADC Mux Right</text> +<text text-anchor="middle" x="643" y="-478.8" font-family="sans-serif" font-size="14.00">[mux]</text> +</g> +<!-- cs42l51.0-004a_AIN1R->cs42l51.0-004a_PGA-ADC Mux Right --> +<g id="edge15" class="edge"> +<title>cs42l51.0-004a_AIN1R->cs42l51.0-004a_PGA-ADC Mux Right</title> +<path fill="none" stroke="black" d="M691.6,-544.83C683.96,-536.37 674.73,-526.15 666.38,-516.9"/> +<polygon fill="black" stroke="black" points="668.92,-514.49 659.62,-509.41 663.73,-519.18 668.92,-514.49"/> +</g> +<!-- cs42l51.0-004a_AIN2L --> +<g id="node7" class="node"> +<title>cs42l51.0-004a_AIN2L</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="659.5,-583 598.5,-583 598.5,-545 659.5,-545 659.5,-583"/> +<text text-anchor="middle" x="629" y="-567.8" font-family="sans-serif" font-size="14.00">AIN2L</text> +<text text-anchor="middle" x="629" y="-552.8" font-family="sans-serif" font-size="14.00">[input]</text> +</g> +<!-- cs42l51.0-004a_AIN2R --> +<g id="node8" class="node"> +<title>cs42l51.0-004a_AIN2R</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="580.5,-583 519.5,-583 519.5,-545 580.5,-545 580.5,-583"/> +<text text-anchor="middle" x="550" y="-567.8" font-family="sans-serif" font-size="14.00">AIN2R</text> +<text text-anchor="middle" x="550" y="-552.8" font-family="sans-serif" font-size="14.00">[input]</text> +</g> +<!-- cs42l51.0-004a_Capture --> +<g id="node9" class="node"> +<title>cs42l51.0-004a_Capture</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="692,-276 618,-276 618,-238 692,-238 692,-276"/> +<text text-anchor="middle" x="655" y="-260.8" font-family="sans-serif" font-size="14.00">Capture</text> +<text text-anchor="middle" x="655" y="-245.8" font-family="sans-serif" font-size="14.00">[dai_out]</text> +</g> +<!-- cs42l51.0-004a_DAC Mux --> +<g id="node10" class="node"> +<title>cs42l51.0-004a_DAC Mux</title> +<polygon fill="none" stroke="#008b00" stroke-width="2" points="598.5,-202 521.5,-202 521.5,-164 598.5,-164 598.5,-202"/> +<text text-anchor="middle" x="560" y="-186.8" font-family="sans-serif" font-size="14.00">DAC Mux</text> +<text text-anchor="middle" x="560" y="-171.8" font-family="sans-serif" font-size="14.00">[mux]</text> +</g> +<!-- cs42l51.0-004a_Left DAC --> +<g id="node14" class="node"> +<title>cs42l51.0-004a_Left DAC</title> +<polygon fill="none" stroke="#008b00" stroke-width="2" points="548,-128 474,-128 474,-90 548,-90 548,-128"/> +<text text-anchor="middle" x="511" y="-112.8" font-family="sans-serif" font-size="14.00">Left DAC</text> +<text text-anchor="middle" x="511" y="-97.8" font-family="sans-serif" font-size="14.00">[dac]</text> +</g> +<!-- cs42l51.0-004a_DAC Mux->cs42l51.0-004a_Left DAC --> +<g id="edge9" class="edge"> +<title>cs42l51.0-004a_DAC Mux->cs42l51.0-004a_Left DAC</title> +<path fill="none" stroke="black" d="M547.64,-163.83C542.05,-155.62 535.34,-145.76 529.19,-136.73"/> +<polygon fill="black" stroke="black" points="532.05,-134.71 523.53,-128.41 526.26,-138.65 532.05,-134.71"/> +</g> +<!-- cs42l51.0-004a_Right DAC --> +<g id="node26" class="node"> +<title>cs42l51.0-004a_Right DAC</title> +<polygon fill="none" stroke="#008b00" stroke-width="2" points="649.5,-128 566.5,-128 566.5,-90 649.5,-90 649.5,-128"/> +<text text-anchor="middle" x="608" y="-112.8" font-family="sans-serif" font-size="14.00">Right DAC</text> +<text text-anchor="middle" x="608" y="-97.8" font-family="sans-serif" font-size="14.00">[dac]</text> +</g> +<!-- cs42l51.0-004a_DAC Mux->cs42l51.0-004a_Right DAC --> +<g id="edge18" class="edge"> +<title>cs42l51.0-004a_DAC Mux->cs42l51.0-004a_Right DAC</title> +<path fill="none" stroke="black" d="M572.11,-163.83C577.53,-155.71 584.02,-145.96 589.99,-137.01"/> +<polygon fill="black" stroke="black" points="593.09,-138.68 595.72,-128.41 587.27,-134.79 593.09,-138.68"/> +</g> +<!-- cs42l51.0-004a_HPL --> +<g id="node11" class="node"> +<title>cs42l51.0-004a_HPL</title> +<polygon fill="none" stroke="#008b00" stroke-width="2" points="546.5,-54 475.5,-54 475.5,-16 546.5,-16 546.5,-54"/> +<text text-anchor="middle" x="511" y="-38.8" font-family="sans-serif" font-size="14.00">HPL</text> +<text text-anchor="middle" x="511" y="-23.8" font-family="sans-serif" font-size="14.00">[output]</text> +</g> +<!-- cs42l51.0-004a_HPR --> +<g id="node12" class="node"> +<title>cs42l51.0-004a_HPR</title> +<polygon fill="none" stroke="#008b00" stroke-width="2" points="643.5,-54 572.5,-54 572.5,-16 643.5,-16 643.5,-54"/> +<text text-anchor="middle" x="608" y="-38.8" font-family="sans-serif" font-size="14.00">HPR</text> +<text text-anchor="middle" x="608" y="-23.8" font-family="sans-serif" font-size="14.00">[output]</text> +</g> +<!-- cs42l51.0-004a_Left ADC --> +<g id="node13" class="node"> +<title>cs42l51.0-004a_Left ADC</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="822,-350 748,-350 748,-312 822,-312 822,-350"/> +<text text-anchor="middle" x="785" y="-334.8" font-family="sans-serif" font-size="14.00">Left ADC</text> +<text text-anchor="middle" x="785" y="-319.8" font-family="sans-serif" font-size="14.00">[adc]</text> +</g> +<!-- cs42l51.0-004a_Left ADC->cs42l51.0-004a_Capture --> +<g id="edge4" class="edge"> +<title>cs42l51.0-004a_Left ADC->cs42l51.0-004a_Capture</title> +<path fill="none" stroke="black" d="M752.2,-311.83C735.41,-302.54 714.8,-291.12 696.88,-281.2"/> +<polygon fill="black" stroke="black" points="698.24,-277.95 687.79,-276.16 694.85,-284.07 698.24,-277.95"/> +</g> +<!-- cs42l51.0-004a_Left DAC->cs42l51.0-004a_HPL --> +<g id="edge6" class="edge"> +<title>cs42l51.0-004a_Left DAC->cs42l51.0-004a_HPL</title> +<path fill="none" stroke="black" d="M511,-89.83C511,-82.13 511,-72.97 511,-64.42"/> +<polygon fill="black" stroke="black" points="514.5,-64.41 511,-54.41 507.5,-64.41 514.5,-64.41"/> +</g> +<!-- cs42l51.0-004a_Left PGA --> +<g id="node15" class="node"> +<title>cs42l51.0-004a_Left PGA</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="838,-424 764,-424 764,-386 838,-386 838,-424"/> +<text text-anchor="middle" x="801" y="-408.8" font-family="sans-serif" font-size="14.00">Left PGA</text> +<text text-anchor="middle" x="801" y="-393.8" font-family="sans-serif" font-size="14.00">[pga]</text> +</g> +<!-- cs42l51.0-004a_Left PGA->cs42l51.0-004a_Left ADC --> +<g id="edge8" class="edge"> +<title>cs42l51.0-004a_Left PGA->cs42l51.0-004a_Left ADC</title> +<path fill="none" stroke="black" d="M796.96,-385.83C795.25,-378.13 793.22,-368.97 791.31,-360.42"/> +<polygon fill="black" stroke="black" points="794.68,-359.42 789.09,-350.41 787.84,-360.93 794.68,-359.42"/> +</g> +<!-- cs42l51.0-004a_MCLK --> +<g id="node16" class="node"> +<title>cs42l51.0-004a_MCLK</title> +<polygon fill="none" stroke="#008b00" stroke-width="2" points="594.5,-350 525.5,-350 525.5,-312 594.5,-312 594.5,-350"/> +<text text-anchor="middle" x="560" y="-334.8" font-family="sans-serif" font-size="14.00">MCLK</text> +<text text-anchor="middle" x="560" y="-319.8" font-family="sans-serif" font-size="14.00">[supply]</text> +</g> +<!-- cs42l51.0-004a_MCLK->cs42l51.0-004a_Capture --> +<g id="edge2" class="edge"> +<title>cs42l51.0-004a_MCLK->cs42l51.0-004a_Capture</title> +<path fill="none" stroke="black" d="M583.97,-311.83C595.79,-302.88 610.2,-291.96 622.94,-282.3"/> +<polygon fill="black" stroke="black" points="625.18,-284.99 631.04,-276.16 620.95,-279.41 625.18,-284.99"/> +</g> +<!-- cs42l51.0-004a_Playback --> +<g id="node24" class="node"> +<title>cs42l51.0-004a_Playback</title> +<polygon fill="none" stroke="#008b00" stroke-width="2" points="597,-276 523,-276 523,-238 597,-238 597,-276"/> +<text text-anchor="middle" x="560" y="-260.8" font-family="sans-serif" font-size="14.00">Playback</text> +<text text-anchor="middle" x="560" y="-245.8" font-family="sans-serif" font-size="14.00">[dai_in]</text> +</g> +<!-- cs42l51.0-004a_MCLK->cs42l51.0-004a_Playback --> +<g id="edge16" class="edge"> +<title>cs42l51.0-004a_MCLK->cs42l51.0-004a_Playback</title> +<path fill="none" stroke="black" d="M560,-311.83C560,-304.13 560,-294.97 560,-286.42"/> +<polygon fill="black" stroke="black" points="563.5,-286.41 560,-276.41 556.5,-286.41 563.5,-286.41"/> +</g> +<!-- cs42l51.0-004a_MICL --> +<g id="node17" class="node"> +<title>cs42l51.0-004a_MICL</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="399.5,-509 338.5,-509 338.5,-471 399.5,-471 399.5,-509"/> +<text text-anchor="middle" x="369" y="-493.8" font-family="sans-serif" font-size="14.00">MICL</text> +<text text-anchor="middle" x="369" y="-478.8" font-family="sans-serif" font-size="14.00">[input]</text> +</g> +<!-- cs42l51.0-004a_Mic Preamp Left --> +<g id="node20" class="node"> +<title>cs42l51.0-004a_Mic Preamp Left</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="461.5,-424 338.5,-424 338.5,-386 461.5,-386 461.5,-424"/> +<text text-anchor="middle" x="400" y="-408.8" font-family="sans-serif" font-size="14.00">Mic Preamp Left</text> +<text text-anchor="middle" x="400" y="-393.8" font-family="sans-serif" font-size="14.00">[mixer]</text> +</g> +<!-- cs42l51.0-004a_MICL->cs42l51.0-004a_Mic Preamp Left --> +<g id="edge12" class="edge"> +<title>cs42l51.0-004a_MICL->cs42l51.0-004a_Mic Preamp Left</title> +<path fill="none" stroke="black" d="M375.73,-470.99C379.8,-460.08 385.08,-445.94 389.68,-433.64"/> +<polygon fill="black" stroke="black" points="392.96,-434.85 393.18,-424.26 386.4,-432.4 392.96,-434.85"/> +</g> +<!-- cs42l51.0-004a_MICR --> +<g id="node18" class="node"> +<title>cs42l51.0-004a_MICR</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="501.5,-583 440.5,-583 440.5,-545 501.5,-545 501.5,-583"/> +<text text-anchor="middle" x="471" y="-567.8" font-family="sans-serif" font-size="14.00">MICR</text> +<text text-anchor="middle" x="471" y="-552.8" font-family="sans-serif" font-size="14.00">[input]</text> +</g> +<!-- cs42l51.0-004a_Mic Preamp Right --> +<g id="node21" class="node"> +<title>cs42l51.0-004a_Mic Preamp Right</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="550.5,-509 417.5,-509 417.5,-471 550.5,-471 550.5,-509"/> +<text text-anchor="middle" x="484" y="-493.8" font-family="sans-serif" font-size="14.00">Mic Preamp Right</text> +<text text-anchor="middle" x="484" y="-478.8" font-family="sans-serif" font-size="14.00">[mixer]</text> +</g> +<!-- cs42l51.0-004a_MICR->cs42l51.0-004a_Mic Preamp Right --> +<g id="edge13" class="edge"> +<title>cs42l51.0-004a_MICR->cs42l51.0-004a_Mic Preamp Right</title> +<path fill="none" stroke="black" d="M474.28,-544.83C475.67,-537.13 477.32,-527.97 478.87,-519.42"/> +<polygon fill="black" stroke="black" points="482.34,-519.88 480.68,-509.41 475.45,-518.63 482.34,-519.88"/> +</g> +<!-- cs42l51.0-004a_Mic Bias --> +<g id="node19" class="node"> +<title>cs42l51.0-004a_Mic Bias</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="409.5,-583 338.5,-583 338.5,-545 409.5,-545 409.5,-583"/> +<text text-anchor="middle" x="374" y="-567.8" font-family="sans-serif" font-size="14.00">Mic Bias</text> +<text text-anchor="middle" x="374" y="-552.8" font-family="sans-serif" font-size="14.00">[supply]</text> +</g> +<!-- cs42l51.0-004a_Mic Bias->cs42l51.0-004a_MICL --> +<g id="edge11" class="edge"> +<title>cs42l51.0-004a_Mic Bias->cs42l51.0-004a_MICL</title> +<path fill="none" stroke="black" d="M372.74,-544.83C372.2,-537.13 371.57,-527.97 370.97,-519.42"/> +<polygon fill="black" stroke="black" points="374.46,-519.15 370.28,-509.41 367.48,-519.63 374.46,-519.15"/> +</g> +<!-- cs42l51.0-004a_PGA-ADC Mux Left->cs42l51.0-004a_Left PGA --> +<g id="edge10" class="edge"> +<title>cs42l51.0-004a_PGA-ADC Mux Left->cs42l51.0-004a_Left PGA</title> +<path fill="none" stroke="black" d="M804.92,-470.99C804.27,-460.3 803.44,-446.5 802.71,-434.37"/> +<polygon fill="black" stroke="black" points="806.2,-434.03 802.1,-424.26 799.21,-434.45 806.2,-434.03"/> +</g> +<!-- cs42l51.0-004a_Right PGA --> +<g id="node27" class="node"> +<title>cs42l51.0-004a_Right PGA</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="688.5,-424 605.5,-424 605.5,-386 688.5,-386 688.5,-424"/> +<text text-anchor="middle" x="647" y="-408.8" font-family="sans-serif" font-size="14.00">Right PGA</text> +<text text-anchor="middle" x="647" y="-393.8" font-family="sans-serif" font-size="14.00">[pga]</text> +</g> +<!-- cs42l51.0-004a_PGA-ADC Mux Right->cs42l51.0-004a_Right PGA --> +<g id="edge19" class="edge"> +<title>cs42l51.0-004a_PGA-ADC Mux Right->cs42l51.0-004a_Right PGA</title> +<path fill="none" stroke="black" d="M643.87,-470.99C644.38,-460.3 645.05,-446.5 645.63,-434.37"/> +<polygon fill="black" stroke="black" points="649.13,-434.42 646.12,-424.26 642.14,-434.08 649.13,-434.42"/> +</g> +<!-- cs42l51.0-004a_Playback->cs42l51.0-004a_DAC Mux --> +<g id="edge5" class="edge"> +<title>cs42l51.0-004a_Playback->cs42l51.0-004a_DAC Mux</title> +<path fill="none" stroke="black" d="M560,-237.83C560,-230.13 560,-220.97 560,-212.42"/> +<polygon fill="black" stroke="black" points="563.5,-212.41 560,-202.41 556.5,-212.41 563.5,-212.41"/> +</g> +<!-- cs42l51.0-004a_Right ADC --> +<g id="node25" class="node"> +<title>cs42l51.0-004a_Right ADC</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="697,-350 613,-350 613,-312 697,-312 697,-350"/> +<text text-anchor="middle" x="655" y="-334.8" font-family="sans-serif" font-size="14.00">Right ADC</text> +<text text-anchor="middle" x="655" y="-319.8" font-family="sans-serif" font-size="14.00">[adc]</text> +</g> +<!-- cs42l51.0-004a_Right ADC->cs42l51.0-004a_Capture --> +<g id="edge3" class="edge"> +<title>cs42l51.0-004a_Right ADC->cs42l51.0-004a_Capture</title> +<path fill="none" stroke="black" d="M655,-311.83C655,-304.13 655,-294.97 655,-286.42"/> +<polygon fill="black" stroke="black" points="658.5,-286.41 655,-276.41 651.5,-286.41 658.5,-286.41"/> +</g> +<!-- cs42l51.0-004a_Right DAC->cs42l51.0-004a_HPR --> +<g id="edge7" class="edge"> +<title>cs42l51.0-004a_Right DAC->cs42l51.0-004a_HPR</title> +<path fill="none" stroke="black" d="M608,-89.83C608,-82.13 608,-72.97 608,-64.42"/> +<polygon fill="black" stroke="black" points="611.5,-64.41 608,-54.41 604.5,-64.41 611.5,-64.41"/> +</g> +<!-- cs42l51.0-004a_Right PGA->cs42l51.0-004a_Right ADC --> +<g id="edge17" class="edge"> +<title>cs42l51.0-004a_Right PGA->cs42l51.0-004a_Right ADC</title> +<path fill="none" stroke="black" d="M649.02,-385.83C649.87,-378.13 650.89,-368.97 651.84,-360.42"/> +<polygon fill="black" stroke="black" points="655.33,-360.74 652.95,-350.41 648.37,-359.97 655.33,-360.74"/> +</g> +<!-- hdmi-audio-codec.1.auto_TX --> +<g id="node30" class="node"> +<title>hdmi-audio-codec.1.auto_TX</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="281.5,-509 210.5,-509 210.5,-471 281.5,-471 281.5,-509"/> +<text text-anchor="middle" x="246" y="-493.8" font-family="sans-serif" font-size="14.00">TX</text> +<text text-anchor="middle" x="246" y="-478.8" font-family="sans-serif" font-size="14.00">[output]</text> +</g> +<!-- hdmi-audio-codec.1.auto_I2S Playback->hdmi-audio-codec.1.auto_TX --> +<g id="edge22" class="edge"> +<title>hdmi-audio-codec.1.auto_I2S Playback->hdmi-audio-codec.1.auto_TX</title> +<path fill="none" stroke="black" d="M254.22,-544.83C253.05,-537.13 251.65,-527.97 250.34,-519.42"/> +<polygon fill="black" stroke="black" points="253.78,-518.77 248.81,-509.41 246.86,-519.83 253.78,-518.77"/> +</g> +<!-- hdmi-audio-codec.1.auto_RX --> +<g id="node29" class="node"> +<title>hdmi-audio-codec.1.auto_RX</title> +<polygon fill="#f2f2f2" stroke="#4d4d4d" points="189.5,-583 118.5,-583 118.5,-545 189.5,-545 189.5,-583"/> +<text text-anchor="middle" x="154" y="-567.8" font-family="sans-serif" font-size="14.00">RX</text> +<text text-anchor="middle" x="154" y="-552.8" font-family="sans-serif" font-size="14.00">[output]</text> +</g> +<!-- hdmi-audio-codec.1.auto_RX->hdmi-audio-codec.1.auto_Capture --> +<g id="edge20" class="edge"> +<title>hdmi-audio-codec.1.auto_RX->hdmi-audio-codec.1.auto_Capture</title> +<path fill="none" stroke="black" d="M154.25,-544.83C154.36,-537.13 154.49,-527.97 154.61,-519.42"/> +<polygon fill="black" stroke="black" points="158.1,-519.46 154.74,-509.41 151.11,-519.36 158.1,-519.46"/> +</g> +</g> +</svg> diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst new file mode 100644 index 000000000..73a42d5a9 --- /dev/null +++ b/Documentation/sound/soc/dapm.rst @@ -0,0 +1,422 @@ +=================================================== +Dynamic Audio Power Management for Portable Devices +=================================================== + +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 power +management frameworks and, as such, can easily co-exist with them. + +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 decisions based upon any audio stream (capture/playback) +activity and audio mixer settings within the device. + +DAPM is based on two basic elements, called widgets and routes: + + * a **widget** is every part of the audio hardware that can be enabled by + software when in use and disabled to save power when not in use + * a **route** is an interconnection between widgets that exists when sound + can flow from one widget to the other + +All DAPM power switching decisions are made automatically by consulting an +audio routing graph. This graph is specific to each sound card and spans +the whole sound card, so some DAPM routes connect two widgets belonging to +different components (e.g. the LINE OUT pin of a CODEC and the input pin of +an amplifier). + +The graph for the STM32MP1-DK1 sound card is shown in picture: + +.. kernel-figure:: dapm-graph.svg + :alt: Example DAPM graph + :align: center + +You can also generate compatible graph for your sound card using +`tools/sound/dapm-graph` utility. + +DAPM power domains +================== + +There are 4 power domains within DAPM: + +Codec bias 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. + +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 + +Path domain + audio subsystem signal paths + + Automatically set when mixer and mux settings are changed by the user. + e.g. alsamixer, amixer. + +Stream domain + DACs and ADCs. + + Enabled and disabled when stream playback/capture is started and + stopped respectively. e.g. aplay, arecord. + + +DAPM Widgets +============ + +Audio DAPM widgets fall into a number of types: + +Mixer + Mixes several analog signals into a single analog signal. +Mux + An analog switch that outputs only one of many inputs. +PGA + A programmable gain amplifier or attenuation widget. +ADC + Analog to Digital Converter +DAC + Digital to Analog Converter +Switch + An analog switch +Input + A codec input pin +Output + A codec output pin +Headphone + Headphone (and optional Jack) +Mic + Mic (and optional Jack) +Line + Line Input/Output (and optional Jack) +Speaker + Speaker +Supply + Power or clock supply widget used by other widgets. +Regulator + External regulator that supplies power to audio components. +Clock + External clock that supplies clock to audio components. +AIF IN + Audio Interface Input (with TDM slot mask). +AIF OUT + Audio Interface Output (with TDM slot mask). +Siggen + Signal Generator. +DAI IN + Digital Audio Interface Input. +DAI OUT + Digital Audio Interface Output. +DAI Link + DAI Link between two DAI structures +Pre + Special PRE widget (exec before all others) +Post + Special POST widget (exec after all others) +Buffer + Inter widget audio data buffer within a DSP. +Scheduler + DSP internal scheduler that schedules component/pipeline processing + work. +Effect + Widget that performs an audio processing effect. +SRC + Sample Rate Converter within DSP or CODEC +ASRC + Asynchronous Sample Rate Converter within DSP or CODEC +Encoder + Widget that encodes audio data from one format (usually PCM) to another + usually more compressed format. +Decoder + Widget that decodes audio data from a compressed format to an + uncompressed format like PCM. + + +(Widgets are defined in include/sound/soc-dapm.h) + +Widgets can be added to the sound card by any of the component driver types. +There are convenience 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. + + +Stream Domain Widgets +--------------------- + +Stream Widgets relate to the stream power domain and only consist of ADCs +(analog to digital converters), DACs (digital to analog converters), +AIF IN and AIF OUT. + +Stream widgets have the following format: +:: + + SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert), + SND_SOC_DAPM_AIF_IN(name, stream, slot, reg, shift, invert) + +NOTE: the stream name must match the corresponding stream name in your codec +snd_soc_dai_driver. + +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), + +e.g. stream widgets for AIF +:: + + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + + +Path Domain Widgets +------------------- + +Path domain widgets have a ability to control or affect 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)), + +If you don't want the mixer elements prefixed with the name of the mixer widget, +you can use SND_SOC_DAPM_MIXER_NAMED_CTL instead. the parameters are the same +as for SND_SOC_DAPM_MIXER. + + +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 or DSP) that can be independently +powered. e.g. + +* Speaker Amp +* Microphone Bias +* 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) + { + gpio_set_value(SPITZ_GPIO_MIC_BIAS, SND_SOC_DAPM_EVENT_ON(event)); + return 0; + } + + SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias), + + +Codec (BIAS) Domain +------------------- + +The codec bias power domain has no widgets and is handled by the codec DAPM +event handler. This handler is called when the codec powerstate is changed wrt +to any stream event or by kernel PM events. + + +Virtual Widgets +--------------- + +Sometimes widgets exist in the codec or machine audio graph that don't have any +corresponding soft power control. In this case it is necessary to create +a virtual widget - a widget with no control bits e.g. +:: + + SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + +This can be used to merge two signal paths together in software. + +Registering DAPM controls +========================= + +In many cases the DAPM widgets are implemented statically in a ``static +const struct snd_soc_dapm_widget`` array in a codec driver, and simply +declared via the ``dapm_widgets`` and ``num_dapm_widgets`` fields of the +``struct snd_soc_component_driver``. + +Similarly, routes connecting them are implemented statically in a ``static +const struct snd_soc_dapm_route`` array and declared via the +``dapm_routes`` and ``num_dapm_routes`` fields of the same struct. + +With the above declared, the driver registration will take care of +populating them:: + + static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("SPKN"), + SND_SOC_DAPM_OUTPUT("SPKP"), + ... + }; + + /* Target, Path, Source */ + static const struct snd_soc_dapm_route wm2000_audio_map[] = { + { "SPKN", NULL, "ANC Engine" }, + { "SPKP", NULL, "ANC Engine" }, + ... + }; + + static const struct snd_soc_component_driver soc_component_dev_wm2000 = { + ... + .dapm_widgets = wm2000_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm2000_dapm_widgets), + .dapm_routes = wm2000_audio_map, + .num_dapm_routes = ARRAY_SIZE(wm2000_audio_map), + ... + }; + +In more complex cases the list of DAPM widgets and/or routes can be only +known at probe time. This happens for example when a driver supports +different models having a different set of features. In those cases +separate widgets and routes arrays implementing the case-specific features +can be registered programmatically by calling snd_soc_dapm_new_controls() +and snd_soc_dapm_add_routes(). + + +Codec/DSP Widget Interconnections +================================= + +Widgets are connected to each other within the codec, platform and machine by +audio paths (called interconnections). Each interconnection must be defined in +order to create a graph of all audio paths between widgets. + +This is easiest with a diagram of the codec or DSP (and schematic of the machine +audio system), as it requires joining widgets together via their audio signal +paths. + +For example the WM8731 output mixer (wm8731.c) 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 +the example above) and is connected to the output mixer via its kcontrol +name. We can now connect the destination widget (wrt audio signal) with its +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() 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. + + +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. + + +Endpoint Widgets +================ +An endpoint is a start or end point (widget) of an audio signal within the +machine and includes the codec. e.g. + +* Headphone Jack +* Internal Speaker +* Internal Mic +* Mic Jack +* Codec Pins + +Endpoints are added to the DAPM graph so that their usage can be determined in +order to save power. e.g. NC codecs pins will be switched OFF, unconnected +jacks can also be switched OFF. + + +DAPM Widget Events +================== + +Widgets needing to implement a more complex behaviour than what DAPM can do +can set a custom "event handler" by setting a function pointer. An example +is a power supply needing to enable a GPIO:: + + static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) + { + if (SND_SOC_DAPM_EVENT_ON(event)) + gpiod_set_value_cansleep(gpio_pa, true); + else + gpiod_set_value_cansleep(gpio_pa, false); + + return 0; + } + + static const struct snd_soc_dapm_widget st_widgets[] = { + ... + SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, + sof_es8316_speaker_power_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + }; + +See soc-dapm.h for all other widgets that support events. + + +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 */ + #define SND_SOC_DAPM_WILL_PMU 0x40 /* called at start of sequence */ + #define SND_SOC_DAPM_WILL_PMD 0x80 /* called at start of sequence */ + #define SND_SOC_DAPM_PRE_POST_PMD (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD) + #define SND_SOC_DAPM_PRE_POST_PMU (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU) diff --git a/Documentation/sound/soc/dpcm.rst b/Documentation/sound/soc/dpcm.rst new file mode 100644 index 000000000..7b6aeab3c --- /dev/null +++ b/Documentation/sound/soc/dpcm.rst @@ -0,0 +1,387 @@ +=========== +Dynamic PCM +=========== + +Description +=========== + +Dynamic PCM allows an ALSA PCM device to digitally route its PCM audio to +various digital endpoints during the PCM stream runtime. e.g. PCM0 can route +digital audio to I2S DAI0, I2S DAI1 or PDM DAI2. This is useful for on SoC DSP +drivers that expose several ALSA PCMs and can route to multiple DAIs. + +The DPCM runtime routing is determined by the ALSA mixer settings in the same +way as the analog signal is routed in an ASoC codec driver. DPCM uses a DAPM +graph representing the DSP internal audio paths and uses the mixer settings to +determine the path used by each ALSA PCM. + +DPCM re-uses all the existing component codec, platform and DAI drivers without +any modifications. + + +Phone Audio System with SoC based DSP +------------------------------------- + +Consider the following phone audio subsystem. This will be used in this +document for all examples :- +:: + + | Front End PCMs | SoC DSP | Back End DAIs | Audio devices | + + ************* + PCM0 <------------> * * <----DAI0-----> Codec Headset + * * + PCM1 <------------> * * <----DAI1-----> Codec Speakers + * DSP * + PCM2 <------------> * * <----DAI2-----> MODEM + * * + PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +This diagram shows a simple smart phone audio subsystem. It supports Bluetooth, +FM digital radio, Speakers, Headset Jack, digital microphones and cellular +modem. This sound card exposes 4 DSP front end (FE) ALSA PCM devices and +supports 6 back end (BE) DAIs. Each FE PCM can digitally route audio data to any +of the BE DAIs. The FE PCM devices can also route audio to more than 1 BE DAI. + + + +Example - DPCM Switching playback from DAI0 to DAI1 +--------------------------------------------------- + +Audio is being played to the Headset. After a while the user removes the headset +and audio continues playing on the speakers. + +Playback on PCM0 to Headset would look like :- +:: + + ************* + PCM0 <============> * * <====DAI0=====> Codec Headset + * * + PCM1 <------------> * * <----DAI1-----> Codec Speakers + * DSP * + PCM2 <------------> * * <----DAI2-----> MODEM + * * + PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +The headset is removed from the jack by user so the speakers must now be used :- +:: + + ************* + PCM0 <============> * * <----DAI0-----> Codec Headset + * * + PCM1 <------------> * * <====DAI1=====> Codec Speakers + * DSP * + PCM2 <------------> * * <----DAI2-----> MODEM + * * + PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +The audio driver processes this as follows :- + +1. Machine driver receives Jack removal event. + +2. Machine driver OR audio HAL disables the Headset path. + +3. DPCM runs the PCM trigger(stop), hw_free(), shutdown() operations on DAI0 + for headset since the path is now disabled. + +4. Machine driver or audio HAL enables the speaker path. + +5. DPCM runs the PCM ops for startup(), hw_params(), prepare() and + trigger(start) for DAI1 Speakers since the path is enabled. + +In this example, the machine driver or userspace audio HAL can alter the routing +and then DPCM will take care of managing the DAI PCM operations to either bring +the link up or down. Audio playback does not stop during this transition. + + + +DPCM machine driver +=================== + +The DPCM enabled ASoC machine driver is similar to normal machine drivers +except that we also have to :- + +1. Define the FE and BE DAI links. + +2. Define any FE/BE PCM operations. + +3. Define widget graph connections. + + +FE and BE DAI links +------------------- +:: + + | Front End PCMs | SoC DSP | Back End DAIs | Audio devices | + + ************* + PCM0 <------------> * * <----DAI0-----> Codec Headset + * * + PCM1 <------------> * * <----DAI1-----> Codec Speakers + * DSP * + PCM2 <------------> * * <----DAI2-----> MODEM + * * + PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +For the example above we have to define 4 FE DAI links and 6 BE DAI links. The +FE DAI links are defined as follows :- +:: + + SND_SOC_DAILINK_DEFS(pcm0, + DAILINK_COMP_ARRAY(COMP_CPU("System Pin")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_PLATFORM("dsp-audio"))); + + static struct snd_soc_dai_link machine_dais[] = { + { + .name = "PCM0 System", + .stream_name = "System Playback", + SND_SOC_DAILINK_REG(pcm0), + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + }, + .....< other FE and BE DAI links here > + }; + +This FE DAI link is pretty similar to a regular DAI link except that we also +set the DAI link to a DPCM FE with the ``dynamic = 1``. +There is also an option to specify the ordering of the trigger call for +each FE. This allows the ASoC core to trigger the DSP before or after the other +components (as some DSPs have strong requirements for the ordering DAI/DSP +start and stop sequences). + +The FE DAI above sets the codec and code DAIs to dummy devices since the BE is +dynamic and will change depending on runtime config. + +The BE DAIs are configured as follows :- +:: + + SND_SOC_DAILINK_DEFS(headset, + DAILINK_COMP_ARRAY(COMP_CPU("ssp-dai.0")), + DAILINK_COMP_ARRAY(COMP_CODEC("rt5640.0-001c", "rt5640-aif1"))); + + static struct snd_soc_dai_link machine_dais[] = { + .....< FE DAI links here > + { + .name = "Codec Headset", + SND_SOC_DAILINK_REG(headset), + .no_pcm = 1, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = hswult_ssp0_fixup, + .ops = &haswell_ops, + }, + .....< other BE DAI links here > + }; + +This BE DAI link connects DAI0 to the codec (in this case RT5460 AIF1). It sets +the ``no_pcm`` flag to mark it has a BE. + +The BE has also flags set for ignoring suspend and PM down time. This allows +the BE to work in a hostless mode where the host CPU is not transferring data +like a BT phone call :- +:: + + ************* + PCM0 <------------> * * <----DAI0-----> Codec Headset + * * + PCM1 <------------> * * <----DAI1-----> Codec Speakers + * DSP * + PCM2 <------------> * * <====DAI2=====> MODEM + * * + PCM3 <------------> * * <====DAI3=====> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +This allows the host CPU to sleep while the DSP, MODEM DAI and the BT DAI are +still in operation. + +A BE DAI link can also set the codec to a dummy device if the codec is a device +that is managed externally. + +Likewise a BE DAI can also set a dummy cpu DAI if the CPU DAI is managed by the +DSP firmware. + + +FE/BE PCM operations +-------------------- + +The BE above also exports some PCM operations and a ``fixup`` callback. The fixup +callback is used by the machine driver to (re)configure the DAI based upon the +FE hw params. i.e. the DSP may perform SRC or ASRC from the FE to BE. + +e.g. DSP converts all FE hw params to run at fixed rate of 48k, 16bit, stereo for +DAI0. This means all FE hw_params have to be fixed in the machine driver for +DAI0 so that the DAI is running at desired configuration regardless of the FE +configuration. +:: + + static int dai0_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) + { + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + /* The DSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set DAI0 to 16 bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + return 0; + } + +The other PCM operation are the same as for regular DAI links. Use as necessary. + + +Widget graph connections +------------------------ + +The BE DAI links will normally be connected to the graph at initialisation time +by the ASoC DAPM core. However, if the BE codec or BE DAI is a dummy then this +has to be set explicitly in the driver :- +:: + + /* BE for codec Headset - DAI0 is dummy and managed by DSP FW */ + {"DAI0 CODEC IN", NULL, "AIF1 Capture"}, + {"AIF1 Playback", NULL, "DAI0 CODEC OUT"}, + + +Writing a DPCM DSP driver +========================= + +The DPCM DSP driver looks much like a standard platform class ASoC driver +combined with elements from a codec class driver. A DSP platform driver must +implement :- + +1. Front End PCM DAIs - i.e. struct snd_soc_dai_driver. + +2. DAPM graph showing DSP audio routing from FE DAIs to BEs. + +3. DAPM widgets from DSP graph. + +4. Mixers for gains, routing, etc. + +5. DMA configuration. + +6. BE AIF widgets. + +Items 6 is important for routing the audio outside of the DSP. AIF need to be +defined for each BE and each stream direction. e.g for BE DAI0 above we would +have :- +:: + + SND_SOC_DAPM_AIF_IN("DAI0 RX", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DAI0 TX", NULL, 0, SND_SOC_NOPM, 0, 0), + +The BE AIF are used to connect the DSP graph to the graphs for the other +component drivers (e.g. codec graph). + + +Hostless PCM streams +==================== + +A hostless PCM stream is a stream that is not routed through the host CPU. An +example of this would be a phone call from handset to modem. +:: + + ************* + PCM0 <------------> * * <----DAI0-----> Codec Headset + * * + PCM1 <------------> * * <====DAI1=====> Codec Speakers/Mic + * DSP * + PCM2 <------------> * * <====DAI2=====> MODEM + * * + PCM3 <------------> * * <----DAI3-----> BT + * * + * * <----DAI4-----> DMIC + * * + * * <----DAI5-----> FM + ************* + +In this case the PCM data is routed via the DSP. The host CPU in this use case +is only used for control and can sleep during the runtime of the stream. + +The host can control the hostless link either by :- + + 1. Configuring the link as a CODEC <-> CODEC style link. In this case the link + is enabled or disabled by the state of the DAPM graph. This usually means + there is a mixer control that can be used to connect or disconnect the path + between both DAIs. + + 2. Hostless FE. This FE has a virtual connection to the BE DAI links on the DAPM + graph. Control is then carried out by the FE as regular PCM operations. + This method gives more control over the DAI links, but requires much more + userspace code to control the link. Its recommended to use CODEC<->CODEC + unless your HW needs more fine grained sequencing of the PCM ops. + + +CODEC <-> CODEC link +-------------------- + +This DAI link is enabled when DAPM detects a valid path within the DAPM graph. +The machine driver sets some additional parameters to the DAI link i.e. +:: + + static const struct snd_soc_pcm_stream dai_params = { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rate_min = 8000, + .rate_max = 8000, + .channels_min = 2, + .channels_max = 2, + }; + + static struct snd_soc_dai_link dais[] = { + < ... more DAI links above ... > + { + .name = "MODEM", + .stream_name = "MODEM", + .cpu_dai_name = "dai2", + .codec_dai_name = "modem-aif1", + .codec_name = "modem", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBP_CFP, + .c2c_params = &dai_params, + .num_c2c_params = 1, + } + < ... more DAI links here ... > + +These parameters are used to configure the DAI hw_params() when DAPM detects a +valid path and then calls the PCM operations to start the link. DAPM will also +call the appropriate PCM operations to disable the DAI when the path is no +longer valid. + + +Hostless FE +----------- + +The DAI link(s) are enabled by a FE that does not read or write any PCM data. +This means creating a new FE that is connected with a virtual path to both +DAI links. The DAI links will be started when the FE PCM is started and stopped +when the FE PCM is stopped. Note that the FE PCM cannot read or write data in +this configuration. diff --git a/Documentation/sound/soc/index.rst b/Documentation/sound/soc/index.rst new file mode 100644 index 000000000..22878d73f --- /dev/null +++ b/Documentation/sound/soc/index.rst @@ -0,0 +1,21 @@ +============== +ALSA SoC Layer +============== + +The documentation is split into the following sections:- + +.. toctree:: + :maxdepth: 2 + + overview + codec + dai + dapm + platform + machine + pops-clicks + clocking + jack + dpcm + codec-to-codec + usb diff --git a/Documentation/sound/soc/jack.rst b/Documentation/sound/soc/jack.rst new file mode 100644 index 000000000..644b99ecb --- /dev/null +++ b/Documentation/sound/soc/jack.rst @@ -0,0 +1,72 @@ +=================== +ASoC jack detection +=================== + +ALSA has a standard API for representing physical jacks to user space, +the kernel side of which can be seen in include/sound/jack.h. ASoC +provides a version of this API adding two additional features: + + - It allows more than one jack detection method to work together on one + user visible jack. In embedded systems it is common for multiple + to be present on a single jack but handled by separate bits of + hardware. + + - Integration with DAPM, allowing DAPM endpoints to be updated + automatically based on the detected jack status (eg, turning off the + headphone outputs if no headphones are present). + +This is done by splitting the jacks up into three things working +together: the jack itself represented by a struct snd_soc_jack, sets of +snd_soc_jack_pins representing DAPM endpoints to update and blocks of +code providing jack reporting mechanisms. + +For example, a system may have a stereo headset jack with two reporting +mechanisms, one for the headphone and one for the microphone. Some +systems won't be able to use their speaker output while a headphone is +connected and so will want to make sure to update both speaker and +headphone when the headphone jack status changes. + +The jack - struct snd_soc_jack +============================== + +This represents a physical jack on the system and is what is visible to +user space. The jack itself is completely passive, it is set up by the +machine driver and updated by jack detection methods. + +Jacks are created by the machine driver calling snd_soc_jack_new(). + +snd_soc_jack_pin +================ + +These represent a DAPM pin to update depending on some of the status +bits supported by the jack. Each snd_soc_jack has zero or more of these +which are updated automatically. They are created by the machine driver +and associated with the jack using snd_soc_jack_add_pins(). The status +of the endpoint may configured to be the opposite of the jack status if +required (eg, enabling a built in microphone if a microphone is not +connected via a jack). + +Jack detection methods +====================== + +Actual jack detection is done by code which is able to monitor some +input to the system and update a jack by calling snd_soc_jack_report(), +specifying a subset of bits to update. The jack detection code should +be set up by the machine driver, taking configuration for the jack to +update and the set of things to report when the jack is connected. + +Often this is done based on the status of a GPIO - a handler for this is +provided by the snd_soc_jack_add_gpio() function. Other methods are +also available, for example integrated into CODECs. One example of +CODEC integrated jack detection can be see in the WM8350 driver. + +Each jack may have multiple reporting mechanisms, though it will need at +least one to be useful. + +Machine drivers +=============== + +These are all hooked together by the machine driver depending on the +system hardware. The machine driver will set up the snd_soc_jack and +the list of pins to update then set up one or more jack detection +mechanisms to update that jack based on their current status. diff --git a/Documentation/sound/soc/machine.rst b/Documentation/sound/soc/machine.rst new file mode 100644 index 000000000..1828f5edc --- /dev/null +++ b/Documentation/sound/soc/machine.rst @@ -0,0 +1,123 @@ +=================== +ASoC Machine Driver +=================== + +The ASoC machine (or board) driver is the code that glues together all the +component drivers (e.g. codecs, platforms and DAIs). It also describes the +relationships between each component which include audio paths, GPIOs, +interrupts, clocking, jacks and voltage regulators. + +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_card { + 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 DAIs 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); + + ... + + /* 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, DAIs +and DMA is suspended and resumed. Optional. + + +Machine DAI Configuration +------------------------- +The machine DAI configuration glues all the codec and CPU DAIs 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, unconnected codec pins can be set as such. + +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_name = "pxa-is2-dai", + .codec_dai_name = "wm8731-hifi", + .platform_name = "pxa-pcm-audio", + .codec_name = "wm8713-codec.0-001a", + .init = corgi_wm8731_init, + .ops = &corgi_ops, + }; + +In the above struct, dai’s are registered using names but you can pass +either dai name or device tree node but not both. Also, names used here +for cpu/codec/platform dais should be globally unique. + +Additionally below example macro can be used to register cpu, codec and +platform dai:: + + SND_SOC_DAILINK_DEFS(wm2200_cpu_dsp, + DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.0")), + DAILINK_COMP_ARRAY(COMP_CODEC("spi0.0", "wm0010-sdi1")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0"))); + +struct snd_soc_card then sets up the machine with its DAIs. e.g. +:: + + /* corgi audio machine driver */ + static struct snd_soc_card snd_soc_corgi = { + .name = "Corgi", + .dai_link = &corgi_dai, + .num_links = 1, + }; + +Following this, ``devm_snd_soc_register_card`` can be used to register +the sound card. During the registration, the individual components +such as the codec, CPU, and platform are probed. If all these components +are successfully probed, the sound card gets registered. + +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. + + +Machine Controls +---------------- + +Machine specific audio mixer controls can be added in the DAI init function. + + +Clocking Controls +----------------- + +As previously noted, clock configuration is handled within the machine driver. +For details on the clock APIs that the machine driver can utilize for +setup, please refer to Documentation/sound/soc/clocking.rst. However, the +callback needs to be registered by the CPU/Codec/Platform drivers to configure +the clocks that is needed for the corresponding device operation. diff --git a/Documentation/sound/soc/overview.rst b/Documentation/sound/soc/overview.rst new file mode 100644 index 000000000..dc8370bbf --- /dev/null +++ b/Documentation/sound/soc/overview.rst @@ -0,0 +1,69 @@ +======================= +ALSA SoC Layer Overview +======================= + +The overall project goal of the ALSA System on Chip (ASoC) layer is to +provide better ALSA support for embedded system-on-chip processors (e.g. +pxa2xx, au1x00, iMX, etc) and portable audio codecs. Prior to the ASoC +subsystem there was some support in the kernel for SoC audio, however it +had some limitations:- + + * Codec drivers were often tightly coupled to the underlying SoC + CPU. This is not ideal and leads to code duplication - for example, + Linux had different wm8731 drivers for 4 different SoC platforms. + + * There was 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 often require + machine specific code to re-route audio, enable amps, etc., after such an + event. + + * Drivers tended 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 was 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 its audio interface capabilities with the + core and are subsequently matched and configured when the application + hardware parameters are known. + + * Dynamic Audio Power Management (DAPM). DAPM automatically sets the codec to + its 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 amplifier). + +To achieve all this, ASoC basically splits an embedded audio system into +multiple re-usable component drivers :- + + * Codec class drivers: The codec class driver is platform independent and + contains audio controls, audio interface capabilities, codec DAPM + definition and codec IO functions. This class extends to BT, FM and MODEM + ICs if required. Codec class drivers should be generic code that can run + on any architecture and machine. + + * Platform class drivers: The platform class driver includes the audio DMA + engine driver, digital audio interface (DAI) drivers (e.g. I2S, AC97, PCM) + and any audio DSP drivers for that platform. + + * Machine class driver: The machine driver class acts as the glue that + describes and binds the other component drivers together to form an ALSA + "sound card device". It handles any machine specific controls and + machine level audio events (e.g. turning on an amp at start of playback). diff --git a/Documentation/sound/soc/platform.rst b/Documentation/sound/soc/platform.rst new file mode 100644 index 000000000..53caba6ce --- /dev/null +++ b/Documentation/sound/soc/platform.rst @@ -0,0 +1,78 @@ +==================== +ASoC Platform Driver +==================== + +An ASoC platform driver class can be divided into audio DMA drivers, SoC DAI +drivers and DSP drivers. 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)(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 its DMA functionality via struct +snd_soc_component_driver:- +:: + + struct snd_soc_component_driver { + const char *name; + + ... + int (*probe)(struct snd_soc_component *); + void (*remove)(struct snd_soc_component *); + int (*suspend)(struct snd_soc_component *); + int (*resume)(struct snd_soc_component *); + + /* pcm creation and destruction */ + int (*pcm_new)(struct snd_soc_pcm_runtime *); + void (*pcm_free)(struct snd_pcm *); + + ... + const struct snd_pcm_ops *ops; + const struct snd_compr_ops *compr_ops; + ... + }; + +Please refer to the :doc:`ALSA driver documentation +<../kernel-api/writing-an-alsa-driver>` for details of audio DMA. + +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.rst for a description of items 1 - 4. + + +SoC DSP Drivers +=============== + +Each SoC DSP driver usually supplies the following features :- + +1. DAPM graph +2. Mixer controls +3. DMA IO to/from DSP buffers (if applicable) +4. Definition of DSP front end (FE) PCM devices. + +Please see dpcm.rst for a description of item 4. diff --git a/Documentation/sound/soc/pops-clicks.rst b/Documentation/sound/soc/pops-clicks.rst new file mode 100644 index 000000000..de7eb2a66 --- /dev/null +++ b/Documentation/sound/soc/pops-clicks.rst @@ -0,0 +1,55 @@ +===================== +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 noticeable on PCs 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 +currently, however future audio codec hardware will have better pop and click +suppression. 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 occurred. 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. diff --git a/Documentation/sound/soc/usb.rst b/Documentation/sound/soc/usb.rst new file mode 100644 index 000000000..9cb860547 --- /dev/null +++ b/Documentation/sound/soc/usb.rst @@ -0,0 +1,482 @@ +================ +ASoC USB support +================ + +Overview +======== +In order to leverage the existing USB sound device support in ALSA, the +ASoC USB APIs are introduced to allow the subsystems to exchange +configuration information. + +One potential use case would be to support USB audio offloading, which is +an implementation that allows for an alternate power-optimized path in the audio +subsystem to handle the transfer of audio data over the USB bus. This would +let the main processor to stay in lower power modes for longer duration. The +following is an example design of how the ASoC and ALSA pieces can be connected +together to achieve this: + +:: + + USB | ASoC + | _________________________ + | | ASoC Platform card | + | |_________________________| + | | | + | ___V____ ____V____ + | |ASoC BE | |ASoC FE | + | |DAI LNK | |DAI LNK | + | |________| |_________| + | ^ ^ ^ + | | |________| + | ___V____ | + | |SoC-USB | | + ________ ________ | | | + |USB SND |<--->|USBSND |<------------>|________| | + |(card.c)| |offld |<---------- | + |________| |________|___ | | | + ^ ^ | | | ____________V_________ + | | | | | |IPC | + __ V_______________V_____ | | | |______________________| + |USB SND (endpoint.c) | | | | ^ + |_________________________| | | | | + ^ | | | ___________V___________ + | | | |->|audio DSP | + ___________V_____________ | | |_______________________| + |XHCI HCD |<- | + |_________________________| | + + +SoC USB driver +============== +Structures +---------- +``struct snd_soc_usb`` + + - ``list``: list head for SND SoC struct list + - ``component``: reference to ASoC component + - ``connection_status_cb``: callback to notify connection events + - ``update_offload_route_info``: callback to fetch selected USB sound card/PCM + device + - ``priv_data``: driver data + +The snd_soc_usb structure can be referenced using the ASoC platform card +device, or a USB device (udev->dev). This is created by the ASoC BE DAI +link, and the USB sound entity will be able to pass information to the +ASoC BE DAI link using this structure. + +``struct snd_soc_usb_device`` + + - ``card_idx``: sound card index associated with USB sound device + - ``chip_idx``: USB sound chip array index + - ``cpcm_idx``: capture pcm device indexes associated with the USB sound device + - ``ppcm_idx``: playback pcm device indexes associated with the USB sound device + - ``num_playback``: number of playback streams + - ``num_capture``: number of capture streams + - ``list``: list head for the USB sound device list + +The struct snd_soc_usb_device is created by the USB sound offload driver. +This will carry basic parameters/limitations that will be used to +determine the possible offloading paths for this USB audio device. + +Functions +--------- +.. code-block:: rst + + int snd_soc_usb_find_supported_format(int card_idx, + struct snd_pcm_hw_params *params, int direction) +.. + + - ``card_idx``: the index into the USB sound chip array. + - ``params``: Requested PCM parameters from the USB DPCM BE DAI link + - ``direction``: capture or playback + +**snd_soc_usb_find_supported_format()** ensures that the requested audio profile +being requested by the external DSP is supported by the USB device. + +Returns 0 on success, and -EOPNOTSUPP on failure. + +.. code-block:: rst + + int snd_soc_usb_connect(struct device *usbdev, struct snd_soc_usb_device *sdev) +.. + + - ``usbdev``: the usb device that was discovered + - ``sdev``: capabilities of the device + +**snd_soc_usb_connect()** notifies the ASoC USB DPCM BE DAI link of a USB +audio device detection. This can be utilized in the BE DAI +driver to keep track of available USB audio devices. This is intended +to be called by the USB offload driver residing in USB SND. + +Returns 0 on success, negative error code on failure. + +.. code-block:: rst + + int snd_soc_usb_disconnect(struct device *usbdev, struct snd_soc_usb_device *sdev) +.. + + - ``usbdev``: the usb device that was removed + - ``sdev``: capabilities to free + +**snd_soc_usb_disconnect()** notifies the ASoC USB DPCM BE DAI link of a USB +audio device removal. This is intended to be called by the USB offload +driver that resides in USB SND. + +.. code-block:: rst + + void *snd_soc_usb_find_priv_data(struct device *usbdev) +.. + + - ``usbdev``: the usb device to reference to find private data + +**snd_soc_usb_find_priv_data()** fetches the private data saved to the SoC USB +device. + +Returns pointer to priv_data on success, NULL on failure. + +.. code-block:: rst + + int snd_soc_usb_setup_offload_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack) +.. + + - ``component``: ASoC component to add the jack + - ``jack``: jack component to populate + +**snd_soc_usb_setup_offload_jack()** is a helper to add a sound jack control to +the platform sound card. This will allow for consistent naming to be used on +designs that support USB audio offloading. Additionally, this will enable the +jack to notify of changes. + +Returns 0 on success, negative otherwise. + +.. code-block:: rst + + int snd_soc_usb_update_offload_route(struct device *dev, int card, int pcm, + int direction, enum snd_soc_usb_kctl path, + long *route) +.. + + - ``dev``: USB device to look up offload path mapping + - ``card``: USB sound card index + - ``pcm``: USB sound PCM device index + - ``direction``: direction to fetch offload routing information + - ``path``: kcontrol selector - pcm device or card index + - ``route``: mapping of sound card and pcm indexes for the offload path. This is + an array of two integers that will carry the card and pcm device indexes + in that specific order. This can be used as the array for the kcontrol + output. + +**snd_soc_usb_update_offload_route()** calls a registered callback to the USB BE DAI +link to fetch the information about the mapped ASoC devices for executing USB audio +offload for the device. ``route`` may be a pointer to a kcontrol value output array, +which carries values when the kcontrol is read. + +Returns 0 on success, negative otherwise. + +.. code-block:: rst + + struct snd_soc_usb *snd_soc_usb_allocate_port(struct snd_soc_component *component, + void *data); +.. + + - ``component``: DPCM BE DAI link component + - ``data``: private data + +**snd_soc_usb_allocate_port()** allocates a SoC USB device and populates standard +parameters that is used for further operations. + +Returns a pointer to struct soc_usb on success, negative on error. + +.. code-block:: rst + + void snd_soc_usb_free_port(struct snd_soc_usb *usb); +.. + + - ``usb``: SoC USB device to free + +**snd_soc_usb_free_port()** frees a SoC USB device. + +.. code-block:: rst + + void snd_soc_usb_add_port(struct snd_soc_usb *usb); +.. + + - ``usb``: SoC USB device to add + +**snd_soc_usb_add_port()** add an allocated SoC USB device to the SOC USB framework. +Once added, this device can be referenced by further operations. + +.. code-block:: rst + + void snd_soc_usb_remove_port(struct snd_soc_usb *usb); +.. + + - ``usb``: SoC USB device to remove + +**snd_soc_usb_remove_port()** removes a SoC USB device from the SoC USB framework. +After removing a device, any SOC USB operations would not be able to reference the +device removed. + +How to Register to SoC USB +-------------------------- +The ASoC DPCM USB BE DAI link is the entity responsible for allocating and +registering the SoC USB device on the component bind. Likewise, it will +also be responsible for freeing the allocated resources. An example can +be shown below: + +.. code-block:: rst + + static int q6usb_component_probe(struct snd_soc_component *component) + { + ... + data->usb = snd_soc_usb_allocate_port(component, 1, &data->priv); + if (!data->usb) + return -ENOMEM; + + usb->connection_status_cb = q6usb_alsa_connection_cb; + + ret = snd_soc_usb_add_port(usb); + if (ret < 0) { + dev_err(component->dev, "failed to add usb port\n"); + goto free_usb; + } + ... + } + + static void q6usb_component_remove(struct snd_soc_component *component) + { + ... + snd_soc_usb_remove_port(data->usb); + snd_soc_usb_free_port(data->usb); + } + + static const struct snd_soc_component_driver q6usb_dai_component = { + .probe = q6usb_component_probe, + .remove = q6usb_component_remove, + .name = "q6usb-dai-component", + ... + }; +.. + +BE DAI links can pass along vendor specific information as part of the +call to allocate the SoC USB device. This will allow any BE DAI link +parameters or settings to be accessed by the USB offload driver that +resides in USB SND. + +USB Audio Device Connection Flow +-------------------------------- +USB devices can be hotplugged into the USB ports at any point in time. +The BE DAI link should be aware of the current state of the physical USB +port, i.e. if there are any USB devices with audio interface(s) connected. +connection_status_cb() can be used to notify the BE DAI link of any change. + +This is called whenever there is a USB SND interface bind or remove event, +using snd_soc_usb_connect() or snd_soc_usb_disconnect(): + +.. code-block:: rst + + static void qc_usb_audio_offload_probe(struct snd_usb_audio *chip) + { + ... + snd_soc_usb_connect(usb_get_usb_backend(udev), sdev); + ... + } + + static void qc_usb_audio_offload_disconnect(struct snd_usb_audio *chip) + { + ... + snd_soc_usb_disconnect(usb_get_usb_backend(chip->dev), dev->sdev); + ... + } +.. + +In order to account for conditions where driver or device existence is +not guaranteed, USB SND exposes snd_usb_rediscover_devices() to resend the +connect events for any identified USB audio interfaces. Consider the +the following situation: + + **usb_audio_probe()** + | --> USB audio streams allocated and saved to usb_chip[] + | --> Propagate connect event to USB offload driver in USB SND + | --> **snd_soc_usb_connect()** exits as USB BE DAI link is not ready + + BE DAI link component probe + | --> DAI link is probed and SoC USB port is allocated + | --> The USB audio device connect event is missed + +To ensure connection events are not missed, **snd_usb_rediscover_devices()** +is executed when the SoC USB device is registered. Now, when the BE DAI +link component probe occurs, the following highlights the sequence: + + BE DAI link component probe + | --> DAI link is probed and SoC USB port is allocated + | --> SoC USB device added, and **snd_usb_rediscover_devices()** runs + + **snd_usb_rediscover_devices()** + | --> Traverses through usb_chip[] and for non-NULL entries issue + | **connection_status_cb()** + +In the case where the USB offload driver is unbound, while USB SND is ready, +the **snd_usb_rediscover_devices()** is called during module init. This allows +for the offloading path to also be enabled with the following flow: + + **usb_audio_probe()** + | --> USB audio streams allocated and saved to usb_chip[] + | --> Propagate connect event to USB offload driver in USB SND + | --> USB offload driver **NOT** ready! + + BE DAI link component probe + | --> DAI link is probed and SoC USB port is allocated + | --> No USB connect event due to missing USB offload driver + + USB offload driver probe + | --> **qc_usb_audio_offload_init()** + | --> Calls **snd_usb_rediscover_devices()** to notify of devices + +USB Offload Related Kcontrols +============================= +Details +------- +A set of kcontrols can be utilized by applications to help select the proper sound +devices to enable USB audio offloading. SoC USB exposes the get_offload_dev() +callback that designs can use to ensure that the proper indices are returned to the +application. + +Implementation +-------------- + +**Example:** + + **Sound Cards**: + + :: + + 0 [SM8250MTPWCD938]: sm8250 - SM8250-MTP-WCD9380-WSA8810-VA-D + SM8250-MTP-WCD9380-WSA8810-VA-DMIC + 1 [Seri ]: USB-Audio - Plantronics Blackwire 3225 Seri + Plantronics Plantronics Blackwire + 3225 Seri at usb-xhci-hcd.1.auto-1.1, + full sp + 2 [C320M ]: USB-Audio - Plantronics C320-M + Plantronics Plantronics C320-M at usb-xhci-hcd.1.auto-1.2, full speed + + **PCM Devices**: + + :: + + card 0: SM8250MTPWCD938 [SM8250-MTP-WCD9380-WSA8810-VA-D], device 0: MultiMedia1 (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 0: SM8250MTPWCD938 [SM8250-MTP-WCD9380-WSA8810-VA-D], device 1: MultiMedia2 (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 1: Seri [Plantronics Blackwire 3225 Seri], device 0: USB Audio [USB Audio] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 2: C320M [Plantronics C320-M], device 0: USB Audio [USB Audio] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + + **USB Sound Card** - card#1: + + :: + + USB Offload Playback Card Route PCM#0 -1 (range -1->32) + USB Offload Playback PCM Route PCM#0 -1 (range -1->255) + + **USB Sound Card** - card#2: + + :: + + USB Offload Playback Card Route PCM#0 0 (range -1->32) + USB Offload Playback PCM Route PCM#0 1 (range -1->255) + +The above example shows a scenario where the system has one ASoC platform card +(card#0) and two USB sound devices connected (card#1 and card#2). When reading +the available kcontrols for each USB audio device, the following kcontrols lists +the mapped offload card and pcm device indexes for the specific USB device: + + ``USB Offload Playback Card Route PCM#*`` + + ``USB Offload Playback PCM Route PCM#*`` + +The kcontrol is indexed, because a USB audio device could potentially have +several PCM devices. The above kcontrols are defined as: + + - ``USB Offload Playback Card Route PCM#`` **(R)**: Returns the ASoC platform sound + card index for a mapped offload path. The output **"0"** (card index) signifies + that there is an available offload path for the USB SND device through card#0. + If **"-1"** is seen, then no offload path is available for the USB SND device. + This kcontrol exists for each USB audio device that exists in the system, and + its expected to derive the current status of offload based on the output value + for the kcontrol along with the PCM route kcontrol. + + - ``USB Offload Playback PCM Route PCM#`` **(R)**: Returns the ASoC platform sound + PCM device index for a mapped offload path. The output **"1"** (PCM device index) + signifies that there is an available offload path for the USB SND device through + PCM device#0. If **"-1"** is seen, then no offload path is available for the USB\ + SND device. This kcontrol exists for each USB audio device that exists in the + system, and its expected to derive the current status of offload based on the + output value for this kcontrol, in addition to the card route kcontrol. + +USB Offload Playback Route Kcontrol +----------------------------------- +In order to allow for vendor specific implementations on audio offloading device +selection, the SoC USB layer exposes the following: + +.. code-block:: rst + + int (*update_offload_route_info)(struct snd_soc_component *component, + int card, int pcm, int direction, + enum snd_soc_usb_kctl path, + long *route) +.. + +These are specific for the **USB Offload Playback Card Route PCM#** and **USB +Offload PCM Route PCM#** kcontrols. + +When users issue get calls to the kcontrol, the registered SoC USB callbacks will +execute the registered function calls to the DPCM BE DAI link. + +**Callback Registration:** + +.. code-block:: rst + + static int q6usb_component_probe(struct snd_soc_component *component) + { + ... + usb = snd_soc_usb_allocate_port(component, 1, &data->priv); + if (IS_ERR(usb)) + return -ENOMEM; + + usb->connection_status_cb = q6usb_alsa_connection_cb; + usb->update_offload_route_info = q6usb_get_offload_dev; + + ret = snd_soc_usb_add_port(usb); +.. + +Existing USB Sound Kcontrol +--------------------------- +With the introduction of USB offload support, the above USB offload kcontrol +will be added to the pre existing list of kcontrols identified by the USB sound +framework. These kcontrols are still the main controls that are used to +modify characteristics pertaining to the USB audio device. + + :: + + Number of controls: 9 + ctl type num name value + 0 INT 2 Capture Channel Map 0, 0 (range 0->36) + 1 INT 2 Playback Channel Map 0, 0 (range 0->36) + 2 BOOL 1 Headset Capture Switch On + 3 INT 1 Headset Capture Volume 10 (range 0->13) + 4 BOOL 1 Sidetone Playback Switch On + 5 INT 1 Sidetone Playback Volume 4096 (range 0->8192) + 6 BOOL 1 Headset Playback Switch On + 7 INT 2 Headset Playback Volume 20, 20 (range 0->24) + 8 INT 1 USB Offload Playback Card Route PCM#0 0 (range -1->32) + 9 INT 1 USB Offload Playback PCM Route PCM#0 1 (range -1->255) + +Since USB audio device controls are handled over the USB control endpoint, use the +existing mechanisms present in the USB mixer to set parameters, such as volume. |
