This series applies various improvements to the DAPM documentation: a
rewrite of a few sections for clarity, style improvements and typo fixes.
Signed-off-by: Luca Ceresoli <[email protected]>
---
Luca Ceresoli (12):
ASoC: doc: dapm: fix typos
ASoC: doc: dapm: fix struct name
ASoC: doc: dapm: minor rewording
ASoC: doc: dapm: remove dash after colon
ASoC: doc: dapm: clarify it's an internal API
ASoC: doc: dapm: replace "map" with "graph"
ASoC: doc: dapm: extend initial descrption
ASoC: doc: dapm: describe how widgets and routes are registered
ASoC: doc: dapm: fix and improve section "Registering DAPM controls"
ASoC: doc: dapm: improve section "Codec/DSP Widget Interconnections"
ASoC: doc: dapm: update section "DAPM Widget Events"
ASoC: doc: dapm: update event types
Documentation/sound/soc/dapm-graph.svg | 375 +++++++++++++++++++++++++++++++++
Documentation/sound/soc/dapm.rst | 178 ++++++++++------
2 files changed, 494 insertions(+), 59 deletions(-)
---
base-commit: 8f2c057754b25075aa3da132cd4fd4478cdab854
change-id: 20240315-dapm-docs-79bd51f267db
Best regards,
--
Luca Ceresoli <[email protected]>
struct snd_soc_codec_dai does not exist.
Signed-off-by: Luca Ceresoli <[email protected]>
---
Documentation/sound/soc/dapm.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
index 59f65b181828..68ef79f539f2 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -148,7 +148,7 @@ Stream widgets have the following format:-
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_codec_dai.
+snd_soc_dai_driver.
e.g. stream widgets for HiFi playback and capture
::
--
2.34.1
Fix various typos.
Signed-off-by: Luca Ceresoli <[email protected]>
---
Documentation/sound/soc/dapm.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
index c3154ce6e1b2..59f65b181828 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -50,7 +50,7 @@ Stream domain
All DAPM power switching decisions are made automatically by consulting an audio
routing map of the whole machine. This map is specific to each machine and
consists of the interconnections between every audio component (including
-internal codec components). All audio components that effect power are called
+internal codec components). All audio components that affect power are called
widgets hereafter.
@@ -221,7 +221,7 @@ when the Mic is inserted:-::
Codec (BIAS) Domain
-------------------
-The codec bias power domain has no widgets and is handled by the codecs DAPM
+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.
@@ -236,7 +236,7 @@ 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 to signal paths together in software.
+This can be used to merge two signal paths together in software.
After all the widgets have been defined, they can then be added to the DAPM
subsystem individually with a call to snd_soc_dapm_new_control().
--
2.34.1
Slightly reword for better readability: replace "PM" -> "power management
frameworks", add missing comma.
Signed-off-by: Luca Ceresoli <[email protected]>
---
Documentation/sound/soc/dapm.rst | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
index 68ef79f539f2..4dfa60519a76 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -5,10 +5,10 @@ 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 PM and as
-such, can easily co-exist with the other PM systems.
+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
--
2.34.1
There is no need for a dash after colons. Also fix an incorrect ":-::"
sequence.
Signed-off-by: Luca Ceresoli <[email protected]>
---
Documentation/sound/soc/dapm.rst | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
index 4dfa60519a76..e3b399201622 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -20,7 +20,7 @@ DAPM spans the whole machine. It covers power control within the entire
audio subsystem, this includes internal codec power blocks and machine
level power systems.
-There are 4 power domains within DAPM
+There are 4 power domains within DAPM:
Codec bias domain
VREF, VMID (core codec and audio power)
@@ -57,7 +57,7 @@ widgets hereafter.
DAPM Widgets
============
-Audio DAPM widgets fall into a number of types:-
+Audio DAPM widgets fall into a number of types:
Mixer
Mixes several analog signals into a single analog signal.
@@ -141,7 +141,7 @@ 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:-
+Stream widgets have the following format:
::
SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert),
@@ -167,7 +167,7 @@ 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:-
+audio paths within the audio subsystem. They have the following form:
::
SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls)
@@ -207,7 +207,7 @@ powered. e.g.
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:-::
+when the Mic is inserted::
static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event)
{
@@ -271,7 +271,7 @@ connect the destination widget (wrt audio signal) with its source widgets.
{"Output Mixer", "HiFi Playback Switch", "DAC"},
{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
-So we have :-
+So we have :
* Destination Widget <=== Path Name <=== Source Widget, or
* Sink, Path, Source, or
@@ -280,7 +280,7 @@ So we have :-
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:-
+Interconnections are created with a call to:
::
snd_soc_dapm_connect_input(codec, sink, path, source);
--
2.34.1
DAPM is actually based on a graph, so use this specific term instead of the
more generic "map".
Signed-off-by: Luca Ceresoli <[email protected]>
---
Documentation/sound/soc/dapm.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
index 4200bcf18fcd..cab40a6b4c96 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -49,7 +49,7 @@ Stream domain
stopped respectively. e.g. aplay, arecord.
All DAPM power switching decisions are made automatically by consulting an audio
-routing map of the whole machine. This map is specific to each machine and
+routing graph of the whole machine. This graph is specific to each machine and
consists of the interconnections between every audio component (including
internal codec components). All audio components that affect power are called
widgets hereafter.
@@ -230,7 +230,7 @@ to any stream event or by kernel PM events.
Virtual Widgets
---------------
-Sometimes widgets exist in the codec or machine audio map that don't have any
+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.
::
@@ -248,7 +248,7 @@ 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 map of all audio paths between widgets.
+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
--
2.34.1
The small paragraph describing how to register widgets is incomplete (does
not mention routes) and mentions snd_soc_dapm_new_control() which is not
really used. Moreover it appears as a part of the "Virtual Widgets"
subsection.
Replace it with a detailed and current description of how widgets and
routes are registered, mentioning both static declaration and runtime
registration. Also make this a section on its own.
Signed-off-by: Luca Ceresoli <[email protected]>
---
Documentation/sound/soc/dapm.rst | 38 ++++++++++++++++++++++++++++++++++++--
1 file changed, 36 insertions(+), 2 deletions(-)
diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
index 3a2fde1d31bf..3aca913c99fc 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -251,8 +251,42 @@ a virtual widget - a widget with no control bits e.g.
This can be used to merge two signal paths together in software.
-After all the widgets have been defined, they can then be added to the DAPM
-subsystem individually with a call to snd_soc_dapm_new_control().
+Registering DAPM controls
+=========================
+
+In many cases the DAPM widgets implemented statically in a ``static const
+struct snd_soc_dapm_widget`` array and the routes connecting them in a
+``static const struct snd_soc_dapm_route`` array in a codec driver, and
+simply declared via the ``dapm_widgets`` and ``num_dapm_widgets`` fields of
+the ``struct snd_soc_component_driver`` so 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),
+ ...
+ };
+
+In more complex cases the list of DAPM widgets and/or routes can be only
+known at build 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
--
2.34.1
Extend the first paragraph to mention the {,num_}dapm_routes fields just
like the widget conterparts. Mention the route fields also in the code
example. Fix "at build time", this really means "at probe time".
Signed-off-by: Luca Ceresoli <[email protected]>
---
Documentation/sound/soc/dapm.rst | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
index 3aca913c99fc..ab7d48582cf7 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -254,12 +254,17 @@ This can be used to merge two signal paths together in software.
Registering DAPM controls
=========================
-In many cases the DAPM widgets implemented statically in a ``static const
-struct snd_soc_dapm_widget`` array and the routes connecting them in a
-``static const struct snd_soc_dapm_route`` array in a codec driver, and
-simply declared via the ``dapm_widgets`` and ``num_dapm_widgets`` fields of
-the ``struct snd_soc_component_driver`` so the driver registration will
-take care of populating them::
+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"),
@@ -278,11 +283,13 @@ take care of populating them::
...
.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 build time. This happens for example when a driver supports
+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()
--
2.34.1
Clarify DAPM does not expose any API to user space, and adapt the paragraph
accordingly.
Signed-off-by: Luca Ceresoli <[email protected]>
---
Documentation/sound/soc/dapm.rst | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
index e3b399201622..4200bcf18fcd 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -11,9 +11,10 @@ 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)
+all power switching is done internally to the ASoC core. For this reason
+DAPM does not expose a kernel API to user space and no code changes or
+recompiling are required for user space applications to use it. DAPM makes
+power switching decisions based upon any audio stream (capture/playback)
activity and audio mixer settings within the device.
DAPM spans the whole machine. It covers power control within the entire
--
2.34.1
Improve wording in a few places, cleanup ReST colon syntax, remove space
before colon, and remove the "codec" parameter in the parentheses of
snd_soc_dapm_new_widgets() (there should be no parameters in the docs, and
that function takes a card, not a codec).
Signed-off-by: Luca Ceresoli <[email protected]>
---
Documentation/sound/soc/dapm.rst | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
index ab7d48582cf7..5b370daed499 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -307,25 +307,23 @@ 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.
-e.g., from the WM8731 output mixer (wm8731.c)
-
-The WM8731 output mixer has 3 inputs (sources)
+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 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.
-::
+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 :
+So we have:
* Destination Widget <=== Path Name <=== Source Widget, or
* Sink, Path, Source, or
@@ -334,12 +332,11 @@ So we have :
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:
-::
+Interconnections are created with a call to::
snd_soc_dapm_connect_input(codec, sink, path, source);
-Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and
+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.
--
2.34.1
The example in this section is not in the kernel sources anymore. Replace
it with an up to date code fragment. Reword the initial paragraph. Remove
"Please" which is not standard practice in documentation.
Signed-off-by: Luca Ceresoli <[email protected]>
---
Documentation/sound/soc/dapm.rst | 30 ++++++++++++++++++------------
1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
index 5b370daed499..75a85c9e33ff 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -377,23 +377,29 @@ jacks can also be switched OFF.
DAPM Widget Events
==================
-Some widgets can register their interest with the DAPM core in PM events.
-e.g. A Speaker with an amplifier registers a widget so the amplifier can be
-powered only when the spk is in use.
-::
+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::
- /* turn speaker amplifier on/off depending on use */
- static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event)
+ static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
{
- gpio_set_value(CORGI_GPIO_APM_ON, SND_SOC_DAPM_EVENT_ON(event));
- return 0;
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ gpiod_set_value_cansleep(gpio_pa, true);
+ else
+ gpiod_set_value_cansleep(gpio_pa, false);
+
+ return 0;
}
- /* corgi machine dapm widgets */
- static const struct snd_soc_dapm_widget wm8731_dapm_widgets =
- SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event);
+ 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),
+ };
-Please see soc-dapm.h for all other widgets that support events.
+See soc-dapm.h for all other widgets that support events.
Event types
--
2.34.1
Some new event types now exist, so update the code fragment.
Signed-off-by: Luca Ceresoli <[email protected]>
---
Documentation/sound/soc/dapm.rst | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
index 75a85c9e33ff..f76fc97dd162 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -405,13 +405,16 @@ See soc-dapm.h for all other widgets that support events.
Event types
-----------
-The following event types are supported by event widgets.
-::
+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_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)
--
2.34.1
Extend the initial description providing clearer definitions of "widget"
and "route", and to stop using the word "component" to mean "widget". Give
more details and clarify wording and add a picture representing a real DAPM
graph.
Group all the introductory paragraphs before the "DAPM power domains", and
split the latter to a specific section.
Signed-off-by: Luca Ceresoli <[email protected]>
---
Documentation/sound/soc/dapm-graph.svg | 375 +++++++++++++++++++++++++++++++++
Documentation/sound/soc/dapm.rst | 30 ++-
2 files changed, 396 insertions(+), 9 deletions(-)
diff --git a/Documentation/sound/soc/dapm-graph.svg b/Documentation/sound/soc/dapm-graph.svg
new file mode 100644
index 000000000000..d783672db815
--- /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
index cab40a6b4c96..3a2fde1d31bf 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -17,9 +17,27 @@ recompiling are required for user space applications to use it. DAPM makes
power switching decisions based upon any audio stream (capture/playback)
activity and audio mixer settings within the device.
-DAPM spans the whole machine. It covers power control within the entire
-audio subsystem, this includes internal codec power blocks and machine
-level power systems.
+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
+
+DAPM power domains
+==================
There are 4 power domains within DAPM:
@@ -48,12 +66,6 @@ Stream domain
Enabled and disabled when stream playback/capture is started and
stopped respectively. e.g. aplay, arecord.
-All DAPM power switching decisions are made automatically by consulting an audio
-routing graph of the whole machine. This graph is specific to each machine and
-consists of the interconnections between every audio component (including
-internal codec components). All audio components that affect power are called
-widgets hereafter.
-
DAPM Widgets
============
--
2.34.1
On 16/04/2024 07:56:06+0200, Luca Ceresoli wrote:
> This series applies various improvements to the DAPM documentation: a
> rewrite of a few sections for clarity, style improvements and typo fixes.
>
> Signed-off-by: Luca Ceresoli <[email protected]>
Reviewed-by: Alexandre Belloni <[email protected]>
> ---
> Luca Ceresoli (12):
> ASoC: doc: dapm: fix typos
> ASoC: doc: dapm: fix struct name
> ASoC: doc: dapm: minor rewording
I'm wondering whether you could improve this patch by not rewrapping the
whole paragraph.
> ASoC: doc: dapm: remove dash after colon
> ASoC: doc: dapm: clarify it's an internal API
> ASoC: doc: dapm: replace "map" with "graph"
> ASoC: doc: dapm: extend initial descrption
> ASoC: doc: dapm: describe how widgets and routes are registered
> ASoC: doc: dapm: fix and improve section "Registering DAPM controls"
> ASoC: doc: dapm: improve section "Codec/DSP Widget Interconnections"
> ASoC: doc: dapm: update section "DAPM Widget Events"
> ASoC: doc: dapm: update event types
>
> Documentation/sound/soc/dapm-graph.svg | 375 +++++++++++++++++++++++++++++++++
> Documentation/sound/soc/dapm.rst | 178 ++++++++++------
> 2 files changed, 494 insertions(+), 59 deletions(-)
> ---
> base-commit: 8f2c057754b25075aa3da132cd4fd4478cdab854
> change-id: 20240315-dapm-docs-79bd51f267db
>
> Best regards,
> --
> Luca Ceresoli <[email protected]>
>
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
On Tue, Apr 16, 2024 at 07:56:07AM +0200, Luca Ceresoli wrote:
> diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
> index c3154ce6e1b2..59f65b181828 100644
> --- a/Documentation/sound/soc/dapm.rst
> +++ b/Documentation/sound/soc/dapm.rst
> @@ -50,7 +50,7 @@ Stream domain
> All DAPM power switching decisions are made automatically by consulting an audio
> routing map of the whole machine. This map is specific to each machine and
> consists of the interconnections between every audio component (including
> -internal codec components). All audio components that effect power are called
> +internal codec components). All audio components that affect power are called
> widgets hereafter.
>
>
> @@ -221,7 +221,7 @@ when the Mic is inserted:-::
> Codec (BIAS) Domain
> -------------------
>
> -The codec bias power domain has no widgets and is handled by the codecs DAPM
> +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.
>
> @@ -236,7 +236,7 @@ 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 to signal paths together in software.
> +This can be used to merge two signal paths together in software.
>
> After all the widgets have been defined, they can then be added to the DAPM
> subsystem individually with a call to snd_soc_dapm_new_control().
>
LGTM, thanks!
Reviewed-by: Bagas Sanjaya <[email protected]>
--
An old man doll... just what I always wanted! - Clara
On Tue, Apr 16, 2024 at 07:56:09AM +0200, Luca Ceresoli wrote:
> diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
> index 68ef79f539f2..4dfa60519a76 100644
> --- a/Documentation/sound/soc/dapm.rst
> +++ b/Documentation/sound/soc/dapm.rst
> @@ -5,10 +5,10 @@ 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 PM and as
> -such, can easily co-exist with the other PM systems.
> +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
>
LGTM, thanks!
Reviewed-by: Bagas Sanjaya <[email protected]>
--
An old man doll... just what I always wanted! - Clara
On Tue, Apr 16, 2024 at 07:56:11AM +0200, Luca Ceresoli wrote:
> diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
> index e3b399201622..4200bcf18fcd 100644
> --- a/Documentation/sound/soc/dapm.rst
> +++ b/Documentation/sound/soc/dapm.rst
> @@ -11,9 +11,10 @@ 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)
> +all power switching is done internally to the ASoC core. For this reason
> +DAPM does not expose a kernel API to user space and no code changes or
> +recompiling are required for user space applications to use it. DAPM makes
> +power switching decisions based upon any audio stream (capture/playback)
> activity and audio mixer settings within the device.
>
> DAPM spans the whole machine. It covers power control within the entire
>
LGTM, thanks!
Reviewed-by: Bagas Sanjaya <[email protected]>
--
An old man doll... just what I always wanted! - Clara
On Tue, Apr 16, 2024 at 07:56:13AM +0200, Luca Ceresoli wrote:
> diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
> index cab40a6b4c96..3a2fde1d31bf 100644
> --- a/Documentation/sound/soc/dapm.rst
> +++ b/Documentation/sound/soc/dapm.rst
> @@ -17,9 +17,27 @@ recompiling are required for user space applications to use it. DAPM makes
> power switching decisions based upon any audio stream (capture/playback)
> activity and audio mixer settings within the device.
>
> -DAPM spans the whole machine. It covers power control within the entire
> -audio subsystem, this includes internal codec power blocks and machine
> -level power systems.
> +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
> +
> +DAPM power domains
> +==================
>
> There are 4 power domains within DAPM:
>
> @@ -48,12 +66,6 @@ Stream domain
> Enabled and disabled when stream playback/capture is started and
> stopped respectively. e.g. aplay, arecord.
>
> -All DAPM power switching decisions are made automatically by consulting an audio
> -routing graph of the whole machine. This graph is specific to each machine and
> -consists of the interconnections between every audio component (including
> -internal codec components). All audio components that affect power are called
> -widgets hereafter.
> -
>
> DAPM Widgets
> ============
>
The wording LGTM, thanks!
Reviewed-by: Bagas Sanjaya <[email protected]>
--
An old man doll... just what I always wanted! - Clara
On Tue, Apr 16, 2024 at 07:56:14AM +0200, Luca Ceresoli wrote:
> diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
> index 3a2fde1d31bf..3aca913c99fc 100644
> --- a/Documentation/sound/soc/dapm.rst
> +++ b/Documentation/sound/soc/dapm.rst
> @@ -251,8 +251,42 @@ a virtual widget - a widget with no control bits e.g.
>
> This can be used to merge two signal paths together in software.
>
> -After all the widgets have been defined, they can then be added to the DAPM
> -subsystem individually with a call to snd_soc_dapm_new_control().
> +Registering DAPM controls
> +=========================
> +
> +In many cases the DAPM widgets implemented statically in a ``static const
> +struct snd_soc_dapm_widget`` array and the routes connecting them in a
> +``static const struct snd_soc_dapm_route`` array in a codec driver, and
> +simply declared via the ``dapm_widgets`` and ``num_dapm_widgets`` fields of
> +the ``struct snd_soc_component_driver`` so 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),
> + ...
> + };
> +
> +In more complex cases the list of DAPM widgets and/or routes can be only
> +known at build 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
>
LGTM, thanks!
Reviewed-by: Bagas Sanjaya <[email protected]>
--
An old man doll... just what I always wanted! - Clara
On Tue, Apr 16, 2024 at 07:56:15AM +0200, Luca Ceresoli wrote:
> Extend the first paragraph to mention the {,num_}dapm_routes fields just
> like the widget conterparts. Mention the route fields also in the code
> example. Fix "at build time", this really means "at probe time".
>
> Signed-off-by: Luca Ceresoli <[email protected]>
LGTM, thanks!
Reviewed-by: Bagas Sanjaya <[email protected]>
--
An old man doll... just what I always wanted! - Clara
On Tue, Apr 16, 2024 at 07:56:16AM +0200, Luca Ceresoli wrote:
> -Each input in this example has a kcontrol associated with it (defined in 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.
> -::
> +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. ::
> <snipped>...
> -Interconnections are created with a call to:
> -::
> +Interconnections are created with a call to::
>
Not strictly related to this patch, but for consistency, I'd like
to write remaining literal block markers at the end of previous
paragraph:
---- >8 ----
diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst
index f76fc97dd16219..e4c44d08c8380b 100644
--- a/Documentation/sound/soc/dapm.rst
+++ b/Documentation/sound/soc/dapm.rst
@@ -180,15 +180,13 @@ 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:
-::
+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)
-::
+e.g. Mixer widget (the kcontrols are declared first)::
/* Output Mixer */
static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = {
@@ -244,8 +242,7 @@ 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.
-::
+a virtual widget - a widget with no control bits e.g::
SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -316,7 +313,7 @@ For example the WM8731 output mixer (wm8731.c) has 3 inputs (sources):
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. ::
+source widgets::
/* output mixer */
{"Output Mixer", "Line Bypass Switch", "Line Input"},
@@ -347,8 +344,7 @@ 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.
-::
+e.g. connects the speaker out codec pins to the internal speaker::
/* ext speaker connected to codec pins LOUT2, ROUT2 */
{"Ext Spk", NULL , "ROUT2"},
Thanks.
--
An old man doll... just what I always wanted! - Clara
Hi Alex,
thanks for the review!
On Tue, 16 Apr 2024 23:23:49 +0200
Alexandre Belloni <[email protected]> wrote:
> On 16/04/2024 07:56:06+0200, Luca Ceresoli wrote:
> > This series applies various improvements to the DAPM documentation: a
> > rewrite of a few sections for clarity, style improvements and typo fixes.
> >
> > Signed-off-by: Luca Ceresoli <[email protected]>
>
> Reviewed-by: Alexandre Belloni <[email protected]>
>
> > ---
> > Luca Ceresoli (12):
> > ASoC: doc: dapm: fix typos
> > ASoC: doc: dapm: fix struct name
> > ASoC: doc: dapm: minor rewording
>
> I'm wondering whether you could improve this patch by not rewrapping the
> whole paragraph.
Sure. I'm waiting a few more days for any additional comments and then
send a v2 with this change.
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
Hello Bagas,
thanks for reviewing!
On Wed, 17 Apr 2024 11:33:12 +0700
Bagas Sanjaya <[email protected]> wrote:
> On Tue, Apr 16, 2024 at 07:56:16AM +0200, Luca Ceresoli wrote:
> > -Each input in this example has a kcontrol associated with it (defined in 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.
> > -::
> > +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. ::
> > <snipped>...
> > -Interconnections are created with a call to:
> > -::
> > +Interconnections are created with a call to::
> >
>
> Not strictly related to this patch, but for consistency, I'd like
> to write remaining literal block markers at the end of previous
> paragraph:
Makes sense, sure. I can add a patch doing this in v2, or send a
separate patch after this series.
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
Hi Alex,
On Tue, 16 Apr 2024 23:23:49 +0200
Alexandre Belloni <[email protected]> wrote:
> On 16/04/2024 07:56:06+0200, Luca Ceresoli wrote:
> > This series applies various improvements to the DAPM documentation: a
> > rewrite of a few sections for clarity, style improvements and typo fixes.
> >
> > Signed-off-by: Luca Ceresoli <[email protected]>
>
> Reviewed-by: Alexandre Belloni <[email protected]>
Thanks for reviewing.
> > ---
> > Luca Ceresoli (12):
> > ASoC: doc: dapm: fix typos
> > ASoC: doc: dapm: fix struct name
> > ASoC: doc: dapm: minor rewording
>
> I'm wondering whether you could improve this patch by not rewrapping the
> whole paragraph.
Yes, sure. Will do in v2.
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com