∿KERNEL/NOISEFIELD MANUALS
OFFLINE-READY // AUDIO / SOC // REV. 2026.10
➜ /kernel/sound/socengineer's field reference
[REFERENCE / 001]LINUX KERNEL · SOUND SUBSYSTEM
THE SOUND OF THE MACHINE

ASoC_
FIELD MANUAL.

From the first PCM sample to a reviewed upstream patch. Codec drivers, DAPM, clocking, Device Tree, the physical bench, and the next Rust frontier.

29 chapters · 12k+ words · no dependencies
ASOC / PIPELINE
01 PCM / userspace → ALSA
│
02 machine · DAI links → ASoC
│
03 CPU DAI / DMA → I²S
│
04 codec · regmap → DAC
│
05 speaker / headphones → OUT
● PATH ACTIVE _
FIELD MANUAL/CHAPTER 01 OF 29/FOUNDATIONS

Start here

ASoC Field Manual · Linux Audio / From digital samples to upstream patches. A working reference for engineers who need to understand, implement, diagnose and submit Linux ASoC drivers. Read sequentially or jump to an incident.

This guide is aimed at embedded Linux developers who already know the kernel basics. It concentrates on what happens on a board, where to look in kernel source, which assumptions break, and how to demonstrate that a driver actually works. The examples are illustrative, not guaranteed drop-in drivers: consult the exact kernel tree and device datasheet before coding.

Select your mission

Your situation Begin with Then
aplay -l shows no cards Probe & binding Diagnostics → Hardware lab
Card exists, silence at the jack DAPM & controls Clocks → Signal tracing
Writing a new I²C codec driver Codec walkthrough Regmap → DAI ops → DAPM
Audio breaks only at 44.1 kHz Clocking & formats Hardware lab → XRUNs
Board DTS needs a sound card Device Tree Machine links → Probe
Preparing first ASoC RFC Upstream Tests → Rust frontier

What this manual does and does not assert

  • ASoC is a coordination framework, not a single driver. A sound card is assembled from separately registered components, DAIs and links.
  • Runtime evidence matters. Successful I²C probe, a listed ALSA card and audible playback are different milestones.
  • Audio terminology is overloaded. “Codec” can mean ADC/DAC hardware; ASoC components also represent CPU DAIs, DMA and other functions. “Platform” in older documentation does not map one-to-one to every modern design.
  • Kernel APIs change. Source and headers in the target tree are normative. The linked official docs are the starting map, not a substitute for compiling.
  • Rust ASoC is explored as an experimental design problem, not advertised as a stable upstream-ready Rust codec API.

Source paths worth pinning

sh
# Inside a checked-out Linux kernel tree
ls sound/soc/
ls sound/soc/codecs/
ls sound/soc/fsl/
rg 'struct snd_soc_component_driver' sound/soc/codecs | head
rg 'devm_snd_soc_register_component' sound/soc/codecs | head
rg 'struct snd_soc_dai_ops' include/sound/soc-dai.h
rg 'struct snd_soc_dai_link' include/sound/soc.h

The manual's examples reference upstream ASoC overview, DAPM, clocking, machine drivers, patch process, and real SGTL5000 codec and i.MX card sources; see the References chapter for links.

Field notes convention

CHECK = read-only inspection; CHANGE = may reconfigure hardware; RISK = can be loud, destructive or disrupt production. Commands that write registers, change mixer volume, modify clocking, or reload drivers require an expendable development board. Take a baseline first. Always start with a quiet volume, known speaker/headphone load and current-limited supply when appropriate.

FIELD MANUAL/CHAPTER 02 OF 29/FOUNDATIONS

Digital audio essentials

Before ASoC, keep three separate notions straight: samples, frames, and serial slots. Each affects your registers and constraints.

Samples and PCM frames

A sample is an instantaneous value for one channel. An interleaved stereo PCM frame contains one left and one right sample. At 48,000 frames/s, stereo S16_LE data carries 48,000 × 2 × 16 = 1,536,000 payload bits/s before serialization, padding or framing. PCM period/buffer sizes count frames in many ALSA APIs; byte/frame conversions depend on format and channels.

Common sample formats: S16_LE, S24_LE (24 valid bits in a 32-bit container), S24_3LE (3 packed bytes/sample), S32_LE. Do not confuse valid bits, memory container width and I²S slot width. A 24-bit sample may travel in a 32-bit slot.

Example: 48 kHz, stereo, 32-bit slots → BCLK = 48,000 × 2 × 32 = 3.072 MHz. MCLK might be 256 × Fs = 12.288 MHz for a device that supports that ratio, but do not assume any ratio without checking its datasheet.

Playback and capture directions

Playback: application → ALSA PCM ring buffer → DMA → CPU DAI shift register → serial wires → codec DAC → analog output. Capture: microphone → codec ADC → serial wires → CPU DAI → DMA → ALSA ring buffer → application.

A CPU DAI configures the SoC serial engine (SSI/SAI/I²S), while the codec DAI configures the endpoint audio interface. The machine/card configuration tells the core which ones are connected and who provides clocks.

The physical wires

Signal Common name Purpose
BCLK SCK / bit clock Shift one serial bit per active edge
LRCLK WS / frame sync Channel/frame boundary (often Fs in stereo)
SDOUT / SDIN SD / TX / RX Serial sample payload
MCLK SYSCLK Optional or required clock input for codec PLL/DAC/ADC
I²C / SPI control bus Configure codec registers; not the PCM sample stream

I²S conventionally carries a one-BCLK delay after LRCLK transition. Left-justified and DSP/TDM modes differ. Align both ends on polarity, slot allocation, sample delay and clock-provider roles.

Audio quality vocabulary

  • XRUN: buffer underrun/overrun. Often DMA scheduling, rate mismatch, period sizing or userspace issues.
  • Pops/clicks: discontinuity or incorrectly sequenced power/mute, not necessarily a PCM data corruption issue.
  • Noise/hum: analog grounding, supplies, gain staging, clocking or measurement setup.
  • Channel swap: slot mapping, codec routing, and left/right alignment.
  • Pitch shift: sample clocks disagree with the requested nominal rate.

Lab question: if aplay reports a successful write but output is silent, which five independent parts of the chain would you inspect before editing the driver?

FIELD MANUAL/CHAPTER 03 OF 29/FOUNDATIONS

The ASoC architecture

ASoC sits on top of ALSA to let reusable components form an audio card. The crucial boundaries are the CPU DAI, codec DAI, PCM/DMA component, and machine/card description. Add DAPM for power-aware audio routing.

USERSPACEaplay / PipeWire / ALSA libPCM open · hw_params · write/read
↓
ASoC COREsnd_soc_card · snd_soc_pcm_runtimeDAI links · PCM setup · constraints · DAPM
↓
SOC SIDECPU DAI + DMASSI / SAI / I²S · ring buffer
EXTERNAL DEVICECodec DAI + componentDAC / ADC · regmap · kcontrols
↓
HARDWAREI²S / TDM / analog signalsBCLK · LRCLK · DATA · MCLK · headphones
◈ SIGNAL MAP / 01TRANSPARENT SVG · OFFLINE
ALSA / userspacePCM open / write / readASoC core / card runtimeDAI links · constraints · DAPMCPU-side DAI + DMAserial port · sample transportCodec DAI + componentcontrols · Regmap · DAPM widgetsPins / digital bus / analogBCLK · LRCLK · DATA → DAC → OUTcard binds endpoints; codec != DMA
Conceptual path: PCM data usually travels through DMA and the CPU DAI; codec registers are configured separately over a control bus. The exact card topology varies.

What registers what?

Kernel object Why it exists Usually provided by
snd_soc_component_driver Lifecycle, mixer controls, DAPM, optional PCM callbacks Codec or SoC-side component
snd_soc_dai_driver Audio interface capabilities and callbacks Codec/CPU DAI driver
snd_soc_dai_ops startup, set_fmt, hw_params, set_sysclk, etc. Driver implementing a DAI
snd_soc_card Assembled sound-card instance Machine/card driver
snd_soc_dai_link Connects CPU, codec and platform endpoints Machine/card driver
snd_soc_pcm_runtime Bound runtime association for one link ASoC core
snd_soc_dapm_widget Route graph and power-switchable hardware blocks Codec and machine

A component's registration does not guarantee a sound card. The card generally appears when matching pieces exist and binding/probing completes. Missing components can cause probe deferral or failed card registration.

Historical terminology trap

Older docs discuss “codec / platform / machine” classes. Modern ASoC is component-based: a component isn't necessarily an external codec; the SoC-side PCM engine and digital interfaces can be components too. Check include/sound/soc*.h and actual drivers for your tree. Avoid copying decade-old callback signatures mechanically.

Trace a concrete card

For the NXP i.MX53 with SGTL5000: an I²C codec driver exposes an audio DAI; an i.MX SSI DAI exposes the other side; DMA powers the PCM samples; the machine driver binds the pieces. Useful source files: sound/soc/codecs/sgtl5000.c, sound/soc/fsl/imx-sgtl5000.c, plus the relevant SoC DAI/DMA drivers.

Exercise: locate the snd_soc_dai_link setup in imx-sgtl5000.c. Identify codec DAI name, CPU DAI identification, platform side and when the sysclk is configured. Don't assume a generic simple-audio-card implementation represents every legacy board.

Contributor guide: trace the contracts, not just the files

The board-specific machine/card driver describes how the CPU DAI, codec DAI, clocks, routing, and optional amplifiers fit together. The CPU DAI owns the SoC-side serial interface; the codec component owns codec controls, DAPM widgets/routes, and codec-specific register behavior. The PCM/platform side supplies the data-transfer engine where applicable.

Reading rule: follow one working board from Device Tree match → card registration → DAI link setup → stream hw_params → trigger → DAPM power-up. A driver is only one part of that contract.

Contributor mental model: follow contracts, not filenames

When reading an unfamiliar board, map the contracts in this order: machine/card link → CPU DAI and PCM platform → codec component/DAI → Device Tree connections. The card joins endpoints; the CPU DAI controls the SoC serial port; the PCM platform moves samples (often via DMA); the codec component owns chip controls and DAPM; firmware describes the actual board topology. A file name alone does not tell you which layer owns a failure.

↳ SOURCE TRACE / FOLLOW THE COMPONENT-TO-CARD CONTRACTBundled snapshot line numbers. Use ← FIELD MANUAL in the source explorer to return here.
FIELD MANUAL/CHAPTER 04 OF 29/FOUNDATIONS

From probe to playback: the lifecycle

If you can describe the lifecycle without looking at the source, you can debug most ASoC integration failures methodically.

◈ SIGNAL MAP / 02TRANSPARENT SVG · OFFLINE
PCM openstartup · constraintsLink configset_fmt / sysclkhw_paramsFs · format · widthsprepare / triggerDMA + serial startDAPM + muteroutes · power · outputILLUSTRATIVE RELATIONSHIPS — NOT A GUARANTEED CALL ORDERCore coordinates callbacks and state transitions; machine code may set up clocks earlier.DAPM and mute can run at different points depending on stream and card topology.
The source explorer links this overview to WM8731 startup, DAI format, clock selection, hw_params, mute and DAPM implementations.

Device / component bring-up

  1. Device Tree or ACPI/platform enumeration creates devices, or an existing bus enumerates them.
  2. I²C/SPI/platform driver probe acquires regulators, clocks, reset GPIOs, and regmap, checks presence where possible, then registers ASoC component(s) and DAI(s).
  3. A machine/card driver provides a snd_soc_card and DAI links; ASoC binds the required pieces. The system may wait for other drivers with -EPROBE_DEFER.
  4. Once card registration succeeds, ALSA exposes card/control/PCM devices. Cards may register with no viable output route: enumeration is not proof of audible sound.

PCM playback call path (conceptual)

text
open /dev/snd/pcmC?D?p
   └─ startup constraints, DAI startup, clock/power preparation as appropriate
hw_params(rate, channels, format, buffer)
   └─ machine link + CPU/codec DAI hw_params + PCM/DMA allocation/setup
prepare
   └─ prepare DMA and hardware for transfer
trigger(START)
   └─ start engine / streams → DMA advances ring-buffer pointer
write / period notifications / pointer updates
trigger(STOP) → hw_free → shutdown → close

This is an ordering guide, not a promised identical callback sequence. ASoC versions, topology, compressed audio paths, and driver implementation details affect exact order. Inspect sound/soc/soc-pcm.c, runtime code and instrument tracepoints.

Startup vs hw_params vs trigger

  • startup: per-stream constraints or activation; don't assume final rate/format yet.
  • hw_params: final negotiated hardware parameters are available; set clock divider, data width and channel slots.
  • set_fmt / set_sysclk / set_tdm_slot: control hardware protocol and clocking; callbacks may be invoked by machine setup or driver paths, depending on configuration.
  • prepare: prepares a configured stream to run.
  • trigger: start/stop/pause transition where latency and locking matter. Don't sleep from a callback that can execute in atomic context; verify callback contract.
  • shutdown: inverse cleanup for stream lifetime; distinguish per-device lifecycle from per-PCM-stream lifecycle.

A diagnostic ladder

Observed stage Strongest initial lead
No I²C device, no probe Bus wiring / address / DT enumeration / reset / power
Codec probes, no ALSA card Machine card, unresolved link, missing DAI, deferred probe
Card appears, no PCM playback device DAI link design, PCM engine, no_pcm, DPCM FE/BE configuration
PCM opens but rejects rate Constraints, codec and CPU DAI supported formats/rates
aplay runs but silence DAPM routing, mixer, clock, amplifier enable, pins
Starts then XRUN DMA/rate/timing/interrupts/period configuration

Important: dmesg saying “codec detected” alone means little about the rest of this chain.

Contributor guide: playback investigation ladder

When playback fails, move one layer at a time rather than changing several drivers at once:

  1. Confirm the device-tree node matches and the relevant probe functions complete.
  2. Confirm the sound card and PCM device exist.
  3. Confirm the stream opens and hw_params succeeds.
  4. Check the DAI format, sample rate, channel count, and clock master/slave roles.
  5. Confirm BCLK and frame-sync at the pins, then inspect codec register state and DAPM paths.
  6. Only then investigate analog mute, amplifier enable, gain, and speaker wiring.

Keep a known-good command, kernel revision, dmesg excerpt, and measured clock values with every reproduction.

↳ SOURCE TRACE / FOLLOW ONE STREAM THROUGH THE CODECBundled snapshot line numbers. Use ← FIELD MANUAL in the source explorer to return here.
FIELD MANUAL/CHAPTER 05 OF 29/SIGNALS & CLOCKS

DAI protocol, formats & TDM

A DAI (Digital Audio Interface) is a configuration boundary. Both endpoints must agree on sample encoding and clocks. An I²C codec's control bus is separate from its digital audio DAI.

◈ SIGNAL MAP / 04TRANSPARENT SVG · OFFLINE
BCLKLRCLK / WSSDATAWS transitionLEFT MSBRIGHT MSBLEFT CHANNEL / 16 CLOCKSRIGHT CHANNEL / 16 CLOCKS
Illustrative I2S-style timing with two 16-clock slots. WS transitions one BCLK before each word’s MSB. Real data, edge polarity and bit widths depend on controller/codec configuration.

Relevant snd_soc_dai_ops

Callback Purpose Typical failure
set_fmt I²S vs left/right justified vs DSP; polarity; clock roles Codec interprets shifted samples
set_sysclk External/system clock frequency and direction PLL/divider can't derive Fs
set_pll Configure codec PLL, when supported Invalid rate range or unlocked PLL
set_tdm_slot Time-slot masks/count/slot width Wrong channel positions
hw_params Configure rate, sample width, channels Unsupported combination
mute_stream Digital stream mute Pops or unexpectedly silent playback
startup / shutdown Per-stream setup/teardown Missing constraints or leaks

Callback signatures, enum names and layout must be taken from your exact tree. E.g. modern SND_SOC_DAIFMT_CBC_CFC notation expresses consumer of bit clock and frame clock; older source may use older provider/master terminology.

I²S, left-justified and DSP/TDM

  • I²S: WS changes one BCLK before the next word's MSB; two-channel standard framing.
  • Left-justified: MSB aligned with frame boundary; can look close on a logic analyzer but be wrong.
  • DSP_A/DSP_B: pulse framing and different bit alignment, used by some TDM buses.
  • TDM: more slots than live channels; slot mask and width matter. slots × slot_width × Fs commonly determines BCLK, not channels × valid_sample_bits × Fs.

Validate a 4-slot example

text
Sample rate    = 48,000 frames/s
Slots          = 4
Slot width     = 32 bits
BCLK           = 48,000 × 4 × 32 = 6.144 MHz
Live channels  = 2 (slots 0 and 2, for example)

Even with only two live channels, four slots still consume 128 serial bits/frame. Check the controller supports the desired inactive-slot behavior.

Forensics

On a scope / analyzer, measure BCLK and LRCLK, then decode data relative to frame sync. Wrong BCLK: inspect divider. Correct BCLK, shifted samples: inspect set_fmt protocol and polarity. Correct clocks/data, no analog sound: inspect codec DAC path, DAPM and supplies.

Useful source: sound/soc/codecs/sgtl5000.c implements format, hw_params, MCLK constraints and mute handling. It is intentionally more realistic than a toy driver's two callbacks.

↳ SOURCE TRACE / DAI CALLBACK IMPLEMENTATIONSBundled snapshot line numbers. Use ← FIELD MANUAL in the source explorer to return here.
FIELD MANUAL/CHAPTER 06 OF 29/SIGNALS & CLOCKS

Clock trees, PLLs & rate families

Most “audio works at 48k, fails at 44.1k” bugs are clocking mismatches. Work from measured signals backward, not from the requested ALSA rate forward.

◈ SIGNAL MAP / 03TRANSPARENT SVG · OFFLINE
MCLK / SYSCLK12.288 MHz at 48k × 256codec clock treeSRATE coeff / dividersDAC / ADCconversion timingPCM frame rate (Fs)48,000 frames / sserial slot layout2 slots × 32 bitsBCLK3.072 MHzSeparate clock paths: serial BCLK need not equal codec MCLK.A 44.1 kHz-family reference might be 11.2896 MHz; the codec must actually support it.
Example configuration, not a universal clock plan: use the BCLK calculator above and check real pins, PLL modes and supported coefficient rows.

Independent clocks

MCLK / SYSCLK is the codec's reference clock (from an oscillator or SoC clock). BCLK serializes bits. LRCLK/FS marks frames. Some codecs derive internal DAC/ADC clocks from PLLs and dividers; some can operate without an external MCLK in specific modes. These are independent constraints.

text
48,000 Hz × 256 = 12.288 MHz  (one possible codec SYSCLK)
44,100 Hz × 256 = 11.2896 MHz (different clock family)
48,000 Hz × 2 slots × 32 = 3.072 MHz BCLK

Ratios above are examples. Check the exact codec datasheet's permitted ratios, PLL lock criteria and oversampling modes. Don't assume a codec accepts arbitrary MCLK.

Clock-provider roles

A DAI link normally needs a coherent choice about who produces BCLK and LRCLK. MCLK may be sourced separately. Naming in older docs: “master/slave”; newer preferred terms: “provider/consumer.” Inspect bitclock-master, frame-master and format properties in relevant bindings.

Debug procedure

  1. Record requested rate, channels, PCM sample format, slot width, BCLK/LRCLK polarity and clock providers.
  2. Measure the actual LRCLK and BCLK on pads, ideally with a logic analyzer; verify frequency at both endpoints.
  3. Check the codec's PLL/source/divider registers through a read-only regmap dump where available.
  4. Trace set_sysclk, set_fmt, hw_params; compare programmed rates with measured ones.
  5. Repeat for 44.1k and 48k families; for 8/16/32/96k if supported. Check power-cycle recovery, not just warm stream restarts.

Pitfalls

  • assigned-clock-rates may change the input to a parent/divider, but doesn't guarantee the codec sees that frequency.
  • Hardware can report success while selecting a slightly wrong divider. Listen for pitch changes or measure LRCLK.
  • Clock provider/consumer settings must agree; two drivers both trying to drive BCLK causes contention, neither drives causes a flat line.
  • Runtime PM or DAPM may gate clocks when streams stop; an idle scope trace is not necessarily evidence of a broken DAI.

See the kernel clocking documentation for framework terminology, then read your codec and controller source for the actual constraints.

↳ SOURCE TRACE / CLOCK-TABLE CODE WORTH READINGBundled snapshot line numbers. Use ← FIELD MANUAL in the source explorer to return here.
FIELD MANUAL/CHAPTER 07 OF 29/SIGNALS & CLOCKS

Device Tree & sound cards

A correct codec driver may work on zero boards if the Device Tree card/link topology is wrong. DT describes devices and connectivity; it is not a substitute for runtime verification.

Three separate layers

  1. Codec node: I²C/SPI address, supply names, reset, clock, audio DAI cells; compatible selects the codec driver.
  2. SoC audio controller node: serial peripheral, DMA channels, clocks, pinctrl, and #sound-dai-cells when used by a binding.
  3. Sound-card / machine node: joins DAIs and defines bus protocol, clock roles and analog routing. Some existing boards use a dedicated machine driver's binding, others simple-audio-card or an audio graph binding.

Illustrative simple-audio-card pattern

dts
/ {
    sound {
        compatible = "simple-audio-card";
        simple-audio-card,name = "example-board-audio";
        simple-audio-card,format = "i2s";
        /* Provider/consumer clock configuration depends on bindings */
        simple-audio-card,cpu {
            sound-dai = <&i2s0>;
        };
        simple-audio-card,codec {
            sound-dai = <&codec>;
        };
    };
};

&i2c1 {
    status = "okay";
    codec: codec@1a {
        compatible = "vendor,actual-codec"; /* replace with real binding */
        reg = <0x1a>;
        #sound-dai-cells = <0>;
        /* supplies, clocks, etc. per binding */
    };
};

&i2s0 {
    status = "okay";
    /* DMA, clocks and pinctrl per SoC binding */
};

Concept only: vendor,actual-codec is not a real device and the example is intentionally incomplete. Use your exact codec's YAML schema; don't copy into a production DTS without pinmux, supplies, clock role and DAI details.

sound-dai and phandle argument cells

#sound-dai-cells = <0> means the reference carries no additional DAI-selector cells. Multi-DAI components might use one or more selector cells depending on binding. Never interpret sound-dai = <&device 1> without checking the provider's number of DAI cells and schema.

reg belongs to the parent bus

For codec@1a under I²C, reg = <0x1a> is an I²C address, not a CPU physical MMIO base. For an SoC I²S controller, reg typically describes MMIO ranges with parent address/size cells and possibly translation via ranges. Don't mix them.

Useful validation commands

sh
# From the kernel source root; exact DT_SCHEMA_FILES matching depends on tree
make dt_binding_check DT_SCHEMA_FILES=/sound/
make ARCH=arm dtbs_check DT_SCHEMA_FILES=/sound/

# Decode a binary for investigation; may lose source provenance
 dtc -I dtb -O dts -o /tmp/board.decoded.dts arch/arm/boot/dts/.../board.dtb

# Check running, bootloader-supplied blob if accessible
ls /sys/firmware/fdt /proc/device-tree 2>/dev/null

DTB cannot reveal original DTS/DTSI override history. Review source files and preprocessing behavior to learn who set the final property. Bindings can use unevaluatedProperties: false / additionalProperties: false where appropriate; learn schema conventions rather than hard-coding allowed properties.

Cross-check against known boards

The i.MX53 Voipac SGTL5000 example uses a dedicated fsl,imx-audio-sgtl5000 sound binding with ssi-controller and audio-codec phandles. That's not the same wiring syntax as the simple-audio-card example. Look at sound/soc/fsl/imx-sgtl5000.c and the matching bindings before translating.

Contributor source-navigation routine

Start from the board DTS and the codec's compatible, then follow the match table to the driver. Search for the card's sound-dai references and compare the binding schema with the board's clock-provider, bus-format, supply and routing properties. Useful source-reading commands:

sh
grep -R 'compatible.*wm8731' sound/ arch/
grep -R 'SND_SOC_DAPM' sound/soc/codecs
git log --oneline -- sound/soc/codecs/wm8731.c
git blame sound/soc/codecs/wm8731.c

Treat snippets in tutorials as navigation aids, not as substitutes for the exact source and YAML binding in the kernel revision being built.

FIELD MANUAL/CHAPTER 08 OF 29/DRIVER ANATOMY

Codec component registration

A codec typically has two registration surfaces: the bus driver that discovers/manages it, and the ASoC component/DAI registered by that driver. Keeping these roles separate helps avoid ownership, lifetime and deferral bugs.

Skeleton: illustrative C pattern

c
// Schematic API shape — not a standalone buildable kernel module.
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <sound/soc.h>

static const struct snd_soc_dai_ops demo_dai_ops = {
    .hw_params = demo_hw_params,
    .set_fmt = demo_set_fmt,
};

static struct snd_soc_dai_driver demo_dai = {
    .name = "demo-hifi",
    .playback = {
        .stream_name = "Playback",
        .channels_min = 2,
        .channels_max = 2,
        .rates = SNDRV_PCM_RATE_48000,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
    },
    .ops = &demo_dai_ops,
};

static const struct snd_soc_component_driver demo_component = {
    .name = "demo-codec",
    /* controls, DAPM widgets and routes go here */
};

static int demo_i2c_probe(struct i2c_client *client)
{
    struct demo_priv *priv;
    int ret;

    priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;

    /* Acquire supplies, reset, clock, regmap; validate chip ID. */
    i2c_set_clientdata(client, priv);
    ret = demo_hw_init(client, priv); /* your implementation */
    if (ret)
        return dev_err_probe(&client->dev, ret, "init failed\n");

    return devm_snd_soc_register_component(&client->dev,
                                          &demo_component,
                                          &demo_dai, 1);
}

No demo_priv, demo_hw_init, demo_hw_params or demo_set_fmt implementations are supplied here: this is a contract sketch, not a compilable driver. Real driver needs OF/I²C match tables, driver registration, Kconfig/Makefile, resource management, safety and format coverage.

What belongs where?

Bus probe: obtain mandatory supplies/clock/reset, establish regmap, check chip ID/revision, initialize safe register defaults, then register component. ASoC component: controls, DAPM, optional component callbacks/PCM services. DAI callbacks: serial audio format/clock/stream-specific logic. Machine/card: board-specific links and analog endpoints; avoid embedding a fixed board's routing into a reusable codec.

Lifetime and cleanup

devm_* resource ownership is tied to the device, not to each PCM stream. priv must remain alive for all callbacks until unregistration. If your driver uses un-managed work, IRQs or worker threads, cancel or synchronize them before lifetime ends. The right cleanup order depends on resource ownership and callback execution context.

Chip ID strategy

  • Ensure reset and regulators are ready before reading the ID; otherwise an I²C ACK may not mean the analog side is powered.
  • Compare silicon revision to supported range, not arbitrary assumptions. Handle variants intentionally.
  • Return useful errno and dev_err_probe() for a missing dependency. -EPROBE_DEFER may be correct for not-yet-ready suppliers.
  • Initialize mute before enabling output power where applicable. Avoid blasting speakers during first probe.

Minimal component: the S/PDIF DIT case

The upstream sound/soc/codecs/spdif_transmitter.c is a useful contrast with a register-heavy codec: it provides a component descriptor, a playback DAI capability declaration, one DAPM output and a platform-probe registration path. It does not program a physical codec over I²C/SPI. The DAPM route connects the Playback stream to spdif-out; the controller is responsible for emitting the digital S/PDIF stream. Read the complete upstream file in the interactive source walkthrough.

↳ SOURCE TRACE / REGISTRATION SITESBundled snapshot line numbers. Use ← FIELD MANUAL in the source explorer to return here.
FIELD MANUAL/CHAPTER 09 OF 29/DRIVER ANATOMY

Regmap, reset, regulators & clocks

Regmap separates how the hardware is accessed (I²C/SPI/MMIO) from how the driver talks about register values, defaults, read permissions and caching.

Register map pattern

c
static bool demo_volatile_reg(struct device *dev, unsigned int reg)
{
    return reg == DEMO_STATUS || reg == DEMO_IRQ_STATUS;
}

static const struct regmap_config demo_regmap_config = {
    .reg_bits = 8,       /* device register address width */
    .val_bits = 16,      /* register data width */
    .max_register = DEMO_MAX_REGISTER,
    .volatile_reg = demo_volatile_reg,
    .cache_type = REGCACHE_MAPLE, /* example; verify availability in tree */
};

/* In I2C probe, AFTER appropriate device resources are prepared: */
priv->regmap = devm_regmap_init_i2c(client, &demo_regmap_config);
if (IS_ERR(priv->regmap))
    return dev_err_probe(&client->dev, PTR_ERR(priv->regmap),
                         "regmap init failed\n");

Choose register/val widths, endianness and cache from the datasheet. Check actual cache types in your kernel: examples use typical values, not a portable guarantee. Regmap caching can hide physical register values after suspended power-off.

Regmap API mental model

  • regmap_read, regmap_write, regmap_update_bits: read/modify/write register fields, serialized as documented by regmap.
  • regmap_bulk_read/write: useful for adjacent registers if bus semantics permit.
  • regcache_cache_only(map, true) prevents writes to powered-off hardware while updating cached state (depending on cache).
  • regcache_mark_dirty(map), regcache_sync(map) help restore state after register loss; sequence is critical around power domains and reset.
  • regmap_irq_chip can centralize mapped interrupt handling for devices with interrupt/status/mask registers.

Resource sequencing

text
Acquire supplies + clocks + reset GPIO
   → enable essential supplies
   → assert/deassert reset with specified timings
   → wait for oscillator / analog stabilization
   → read chip ID (if supported)
   → configure safe defaults / mute
   → register ASoC component
   → use DAPM/runtime PM for on-demand blocks

Not every codec permits this sequence; consult hardware docs for rail ordering and bias settle times. Never assume a regulator's regulator-always-on means the device can ignore power sequencing.

Typical mistakes

Mistake Symptom
Mark every register nonvolatile Stale status reads, confusing jack detection
Forget regcache sync after power loss First playback after resume silent
Confuse reset delay with PLL lock time Intermittent probe or garbled startup
Writes to powered-off bus I²C failures after suspend
Unbalanced clock enable / PM reference Audio works once or never powers down

Practical exercise: compare cached control values with actual silicon after cold boot vs resume. Ensure debug dumps are safe and don't trigger read-to-clear status unexpectedly.

WM8731 as a register-map case study

The WM8731 driver combines a register-default table, a volatile reset register, controls expressed as register fields, and regulator/clock handling. When tracing a control, follow its ALSA control declaration to the register and bit field, then check how regcache is synchronized across power transitions. The dedicated WM8731 source walkthrough presents the complete upstream file line by line.

↳ SOURCE TRACE / REGISTER USAGE IN A REAL CODECBundled snapshot line numbers. Use ← FIELD MANUAL in the source explorer to return here.
FIELD MANUAL/CHAPTER 10 OF 29/DRIVER ANATOMY

DAPM — the power-aware audio graph

Dynamic Audio Power Management powers only the hardware blocks required by active routes and streams. It is not a software equalizer, and it is not simply the Linux runtime PM framework. It responds to stream state, mixer state, and routing, not just driver probe.

◈ SIGNAL MAP / 05TRANSPARENT SVG · OFFLINE
PlaybackDAI streamDACPWR bitOutput mixerHiFi switchLOUT / ROUTanalog endpointLINE INanalog pinInput muxline / micADCPWR bitCaptureDAI streamDAPM ROUTES = { sink, control, source }Route reachability and enabled controls drive codec power, not arbitrary widget order.
Simplified paths: the real graph contains MIC/line bypass, sidetone, oscillator/supplies and conditional mixer routes. See the complete arrays in the source.

Widgets and routes

A widget represents an audio block or endpoint: DAC, ADC, PGA, MIXER, MUX, SUPPLY, INPUT, OUTPUT, AIF_IN, AIF_OUT. Routes define how a signal could flow, optionally conditioned by mixer/mux controls.

c
static const struct snd_soc_dapm_widget demo_widgets[] = {
    SND_SOC_DAPM_DAC("DAC", "Playback", DEMO_POWER, 0, 0),
    SND_SOC_DAPM_OUTPUT("LINEOUT"),
};

static const struct snd_soc_dapm_route demo_routes[] = {
    /* Sink, optional control name, source */
    { "LINEOUT", NULL, "DAC" },
};

static const struct snd_soc_component_driver demo_component = {
    .dapm_widgets = demo_widgets,
    .num_dapm_widgets = ARRAY_SIZE(demo_widgets),
    .dapm_routes = demo_routes,
    .num_dapm_routes = ARRAY_SIZE(demo_routes),
};

Illustrative only: real widgets need correct register names and controls, and complete paths from stream to physical output. Route string names must match exactly. Sink/source order is easy to reverse!

Debugging silent audio via DAPM

  1. Does the codec DAI advertise the correct stream name? Is it consistent with DAPM AIF/DAC stream associations?
  2. Does a continuous route exist between active stream and physical endpoint?
  3. Are board machine routes added for speakers/headphones? Are endpoints enabled?
  4. Is a mux/mixer switch gating the intended path?
  5. Did DAPM actually power the expected widgets when stream started? Check debugfs path for your board/kernel.
sh
# CHECK: debugfs may not be mounted or CONFIG_DEBUG_FS may be off
sudo mount -t debugfs debugfs /sys/kernel/debug 2>/dev/null || true
find /sys/kernel/debug/asoc -maxdepth 4 -type f 2>/dev/null | head -40
# Browse widget files after identifying your card; paths vary by kernel.

DAPM event callbacks

Use SND_SOC_DAPM_PRE_PMU, POST_PMU, PRE_PMD, POST_PMD (as supported by widget and event flags) for strict device-specific sequencing. This can avoid pops by muting before removing analog power and delaying during analog bias stabilization.

Be precise about locking and sleepability. An event may execute under DAPM locks; callbacks must honor execution context, avoid recursion into operations that deadlock, and use only justified delays.

Common failure signature

Card and PCM appear; register dump indicates all rails on; playback runs; DAPM shows DAC powered but LINEOUT off. Likely route/control/endpoint inconsistency. Fix graph rather than forcing register power bits in hw_params and breaking future suspend.

Contributor guide: silent playback symptom checklist

A PCM stream can run while the output remains silent. Verify that the active route reaches a powered output widget, that mixer switches and volume controls permit the signal, and that the codec's output pins and external amplifier are enabled. DAPM describes the logical power graph; it does not prove the external analog wiring is correct.

Reading a real signal graph

In the WM8731, DAPM widgets describe the DAC/ADC, output mixer, input mux, line input, microphone bias and physical endpoints. Routes connect those widgets and may use control names such as HiFi Playback Switch or Input Select. If a stream opens but no signal appears, inspect the route graph and active controls as well as the serial bus; DAPM can correctly leave an unconnected path powered down.

↳ SOURCE TRACE / REAL DAPM DEFINITIONS AND PATHSBundled snapshot line numbers. Use ← FIELD MANUAL in the source explorer to return here.
FIELD MANUAL/CHAPTER 11 OF 29/DRIVER ANATOMY

Mixer controls, TLV, jacks & bias

Userspace sees kcontrols through ALSA (amixer, alsamixer). In ASoC, controls frequently map register bitfields and also participate in the DAPM route graph.

Controls and volumes

c
/* Simplified illustration: correct register/bitfield constants required */
static const DECLARE_TLV_DB_SCALE(demo_dac_tlv, -6300, 100, 0);

static const struct snd_kcontrol_new demo_controls[] = {
    SOC_SINGLE_TLV("DAC Playback Volume", DEMO_DAC_VOL,
                   0, 63, 0, demo_dac_tlv),
    SOC_SINGLE("DAC Playback Switch", DEMO_CTRL, 0, 1, 0),
};

In real codecs volume scales are rarely guessed. Read the datasheet: is step size linear in dB? Is register encoding inverted? Are extreme values “mute”? Does the control represent per-channel registers? Correct range and TLV scaling matter to user-visible behavior.

Command-line workflow

sh
aplay -l                      # list hardware devices (cards)
cat /proc/asound/cards
amixer -c 0 scontrols          # simple controls, if exposed
amixer -c 0 controls           # all control metadata
amixer -c 0 contents           # detailed values and types
alsamixer -c 0                 # interactive; start at low gain

amixer -c 0 set 'Some Control' ... is a write operation and can affect volume instantly. Never set arbitrary “100%” values on an unknown board with headphones connected.

Jack reporting

snd_soc_jack represents a physical jack state to ASoC/ALSA. Reporting may come from codec IRQ, GPIO, ADC button ladder or other mechanisms. Machine-level jack pins can switch DAPM endpoints based on the state; the sound card may expose ALSA jack controls or input events depending on drivers.

Gain staging and pops

Distinguish digital gain (PCM/DSP), DAC output levels, analog PGA/headphone amplifier, external power amplifier and speaker acoustics. Poor gain staging can clip even at conservative mixer percentages. Pops can result from bias/VMID settling or abrupt unmute; the solution is sequencing, not hiding the noise with a userspace delay.

Test: headphones unplugged vs plugged, mic capture levels, repeat rapid open/close and suspend/resume. If jack events are interrupt-driven, ensure no stale or bouncing state after resume.

↳ SOURCE TRACE / INSPECT CONCRETE CONTROLSBundled snapshot line numbers. Use ← FIELD MANUAL in the source explorer to return here.
FIELD MANUAL/CHAPTER 12 OF 29/DRIVER ANATOMY

Machine cards, DAI links & DPCM

The machine/card layer assembles the system. It can be handwritten C, simple-audio-card, audio-graph-card, or a subsystem-specific card framework. Be cautious about duplicating responsibilities: a reusable codec driver should not hardcode your evaluation board's connectors.

Typical machine card setup

text
snd_soc_card
  ├─ dai_link[0]: CPU DAI ↔ codec DAI (+ PCM component)
  ├─ dai_link[1]: optional second link / HDMI / amplifier / DSP
  ├─ board DAPM widgets: Speaker, Headphone, Mic
  └─ board routes: Headphone Jack ← codec output

DAI link fields and binding syntax have evolved. Current ASoC supports multi-component links and helper macros; use a current in-tree driver in the same subsystem rather than copying obsolete codec_name/platform_name single-string patterns.

DPCM: frontend vs backend

Dynamic PCM adds Front End (FE) links visible to userspace and Back End (BE) links connecting DSP and hardware endpoints. An FE may route dynamically to different BEs, change runtime paths, and operate with no_pcm backends. aplay -l showing an FE does not imply every backend codec is active.

  • FE: represents the PCM the application opens; often connects to DSP.
  • BE: represents a hardware link, often to external codec or SoC DAI.
  • DAPM graph selects route; machine constraints and fixups can adapt backend params.
  • Hostless paths may route between hardware endpoints without userspace PCM I/O.

Common integration bugs

Problem Check
-EPROBE_DEFER forever Component/DAI never registered, missing clock/regulator, mismatched DT phandle
Card registered but wrong PCM names DAI link names and FE/BE type
Playback opens but BE not active DPCM routing, DAPM mux, FE/BE constraints
No sound after capture starts Shared clock/PLL ownership and symmetric-rate constraints

Read sound/soc/soc-core.c, soc-pcm.c, soc-dapm.c and current audio graph/simple card implementations to see when ASoC core makes its decisions.

↳ SOURCE TRACE / INSPECT WHAT A LINK MUST CONSUMEBundled snapshot line numbers. Use ← FIELD MANUAL in the source explorer to return here.
FIELD MANUAL/CHAPTER 13 OF 29/ON REAL HARDWARE

Board bring-up: prove every layer

The best way to debug an ASoC board is to move from the lowest observable layer to the next, recording evidence at each step. Avoid changing five things at once.

Preparation

  1. Save the kernel commit/version, DTS/DTB digest, rootfs image, boot arguments, codec chip revision, and wiring notes.
  2. Identify the codec control bus and address; I²C address in DT is 7-bit for ordinary devices (check vendor datasheet notation).
  3. Collect supply voltages (absolute and under load), reset sequence, external MCLK, pad mux and wire topology.
  4. Ensure physical connections are safe: headphone/line output vs speaker-level power amplifier, common ground, accessible analog test points.

Staged bring-up checklist

Gate Evidence of success Failing next move
0: DT enumerates device of_node exists; correct compatible/address Inspect DT status, parent bus and phandles
1: Control bus I²C transaction / safe chip-ID read Check power, pullups, reset, pins
2: Codec probe driver bound, regmap initialized Inspect dmesg, driver match / dependencies
3: Card registration cat /proc/asound/cards Inspect machine driver, DAI link, deferral
4: PCM exposure aplay -l, aplay -D hw:C,D ... Check CPU DMA component and card links
5: Digital clocks Correct BCLK/LRCLK/MCLK while running Clock tree, fmt, pad mux, dividers
6: Digital data Serial waveform contains samples DMA/DAI transfer/format/trigger
7: Analog path Signal at codec pin DAPM, gain, mute, codec supplies
8: Product path Speaker/headphone/test input functional External amp enable, jack/route, shielding

Baseline commands

sh
uname -a
cat /proc/asound/cards
aplay -l
arecord -l
cat /proc/interrupts | head -60
dmesg --color=never | grep -Ei 'asoc|snd|audio|codec|i2s|ssi|sai|defer'
find /sys/bus/i2c/devices -maxdepth 2 -name driver -type l -print 2>/dev/null

You can use i2cdetect only after examining whether probing unknown addresses could interfere with hardware. Some devices respond badly to SMBus probe sequences. A bus scanner is not a universal safe diagnostic.

Build/install without losing recovery

Keep a known-good kernel and DTB available. If using Yocto, capture the image recipe, kernel source revision and module deployment mechanism. Don't replace production boot artifacts without an A/B or serial-console recovery path. A driver module can often be tested with an out-of-tree build, but a new in-tree codec usually changes Kconfig/Makefile/bindings and may need a kernel rebuild and reboot.

Exit criterion: reproduce the same playback/capture on cold boot and after suspend/resume, not just one lucky development-board run.

Contributor guide: useful source-navigation commands

sh
cd linux
grep -R 'compatible.*spdif' sound/soc
grep -R 'SND_SOC_DAPM' sound/soc/codecs
git log --oneline -- sound/soc/codecs/
git blame sound/soc/codecs/spdif_transmitter.c

Read the binding, probe path, nearby drivers, and file history together. Kernel APIs evolve, so verify every example against the target kernel revision rather than transplanting code from an unrelated version.

Compare probe styles

A simple S/PDIF DIT driver registers its component and DAI from platform probe, with no chip registers to initialize. A physical codec such as WM8731 additionally needs a control bus, regmap, clock/supply management, reset behavior and safe power sequencing. Do not copy the minimal DIT probe shape into a physical codec driver without those responsibilities. The code walkthrough page includes both upstream files.

↳ SOURCE TRACE / PROBE AND POWER PATH IN SOURCEBundled snapshot line numbers. Use ← FIELD MANUAL in the source explorer to return here.
FIELD MANUAL/CHAPTER 14 OF 29/ON REAL HARDWARE

Debugging: logs, debugfs, tracepoints

Kernel audio failures are evidence problems. Work from an observed failure boundary: card not registered, PCM not advancing, DAPM disconnected, or analog stage silent.

Inventory without changing state

sh
cat /proc/asound/cards
cat /proc/asound/pcm
ls -l /dev/snd/
cat /proc/asound/card0/pcm0p/sub0/status 2>/dev/null
cat /proc/asound/card0/pcm0p/sub0/hw_params 2>/dev/null
find /sys/kernel/debug/asoc -maxdepth 3 -type f 2>/dev/null | head

Paths like pcm0p are illustrative: enumerate your actual cards/devices and confirm the node exists. ASoC debugfs files vary with kernel configuration and version.

Live ALSA stream state

sh
# Start playback in another terminal, then inspect rapidly:
watch -n 0.5 'cat /proc/asound/card0/pcm0p/sub0/status'
# Compare hw_ptr / appl_ptr progression (where exposed)

If the DMA pointer stalls, investigate DMA channel, IRQs, trigger and CPU DAI. If pointers progress but output is silent, move down the chain to serial pins and DAPM.

Tracefs

sh
# CHECK: available event names are kernel-configuration-dependent
sudo mount -t tracefs tracefs /sys/kernel/tracing 2>/dev/null || true
sudo grep -Ei 'snd|asoc|soc|pcm' /sys/kernel/tracing/available_events | head -60

# Pick an EVENT confirmed in available_events, not a guessed name.
# Then, as root, use set_event / trace to capture a short run:
#   echo 'subsystem:event' > /sys/kernel/tracing/set_event
#   echo 1 > /sys/kernel/tracing/tracing_on
#   cat /sys/kernel/tracing/trace
#   echo 0 > /sys/kernel/tracing/tracing_on
#   : > /sys/kernel/tracing/set_event

Tracing, dynamic debug and debugfs are not guaranteed available. For instrumentation you control, add temporary tracepoints or dev_dbg() and avoid printing heavily in time-sensitive callbacks. For upstream, keep only useful permanent diagnostics.

Dynamic debug (if configured)

sh
# CHECK support first
ls /proc/dynamic_debug/control
# Example inspection: do not blindly enable every line in a hot path
sudo grep 'sound/soc' /proc/dynamic_debug/control | head

Use targeted file/function filters. Document exact debug commands in your test log, and restore the original settings afterward.

Diagnose deferred probe

Check device dependencies, -EPROBE_DEFER and whether a supplier (regulator/clock/GPIO) has registered. On supported kernels /sys/kernel/debug/devices_deferred lists deferring devices. Remember that missing ASoC card can be a symptom of a codec, CPU DAI or unrelated supplier not ready.

Use the waveform as evidence

A logic analyzer validates framing (BCLK/LRCLK/data); oscilloscope checks signal integrity, voltage levels and slew. Analog scope probes should be high impedance, properly grounded and not cause accidental shorts. Never attach a bench scope ground clip indiscriminately to an isolated or mains-referenced circuit.

FIELD MANUAL/CHAPTER 15 OF 29/ON REAL HARDWARE

Hardware lab: from the bench to sound

A codec driver isn't proven until you can explain what voltage, clock and waveform physically appears on its pins. Keep a reproducible notebook for each configuration.

Instrument checklist

  • UART/serial console and a known-good boot image for recovery.
  • DMM for I/O supply rails, analog supplies, reset line and DC offset.
  • Oscilloscope for MCLK, BCLK, LRCLK, analog waveform and power-up timing.
  • Logic analyzer for I²S/TDM format decoding; bandwidth sufficient for the actual BCLK.
  • Safe audio input stimulus, attenuator/load, and speakers/headphones only after validating signal level.
  • Optional USB audio interface for analog loopback recording, or calibrated audio analyzer for THD+N/SNR.

Golden stimulus

A pure 1 kHz sine at conservative level is a starting test (it won't identify all channel/format bugs). For channel mapping, use L-only and R-only tones; for clipping/gain, stepped amplitudes; for sample rate, compare measured frequency and LRCLK to expected value.

sh
# Use aplay with a WAV file whose actual header is 48kHz, stereo, 16-bit.
# Replace CARD,DEV based on `aplay -l`; no resampling with `hw:`.
aplay -D hw:CARD,DEV test-48k-stereo.wav

# Capture: only if card supports it; adapt format to hardware
arecord -D hw:CARD,DEV -f S16_LE -c 2 -r 48000 -d 10 capture.wav

# Inspect supported hardware params (some versions/syntax differ)
aplay --dump-hw-params -D hw:CARD,DEV test-48k-stereo.wav

hw: avoids transparent plugin resampling, which is crucial when testing the codec's actual hardware constraints. plughw: is useful for applications but can hide failures by adapting formats. Expect noisy captures, test fixture artifacts and user-space tool differences.

Measure digital signals

  1. Probe BCLK and LRCLK during active playback; record measured frequency, duty and voltage swing.
  2. Verify 48k/44.1k setting and BCLK ratio for slot count and slot width.
  3. Decode serial data; check MSB delay/alignment, sign and channel sequence.
  4. Check playback and capture independently; a codec with shared pins may use different directions and enable bits.
  5. Confirm no unexpected clock contention when switching between playback and capture.

Analog test checklist

Measurement What it reveals
DC offset on outputs Unsafe bias or output path configuration
Small-signal 1 kHz tone Basic DAC/ADC functionality
L/R isolated stimulus Channel swap and cross-talk
Step/ramp amplitude Gain range, clipping, pops
Silence with output enabled Noise floor, hum, clock spurs
Stop/start repeats Sequencing pops and stuck clocks
Power suspend/resume Regcache, reset and power-domain bugs

Risk: Do not connect speaker amplifier outputs directly to a sound-card line input; do not connect a low-impedance load to a line output that cannot drive it. Respect common-ground and differential output requirements.

Record a useful result

text
Board:                 revision B / serial REDACTED
Kernel / commit:       6.x / <git commit>
DTB SHA256:            <sha256>
Codec / revision:      <model + die revision>
Supplies / reset:      measured values + timing
I2S mode:              provider, polarity, bit delay, slots
PCM:                   48k stereo S16_LE / period & buffer
MCLK / BCLK / LRCLK:   measured, not just configured
Tools:                 aplay version / analyzer model
Audio:                 successful/failed, measured issues
Artifacts:             dmesg, trace, scope shot, recording

Contributor guide: inspect the physical signal path

Follow the signal from board wiring and Device Tree through the CPU DAI, serial bus, codec DAC/ADC, amplifier, and endpoint. At each boundary, ask what evidence proves the stage is working.

  • Digital bus: confirm BCLK, frame sync/LRCLK, data direction, slot width, and format.
  • Codec/control bus: confirm I²C/SPI transactions, reset, supplies, register defaults, and mute state.
  • Analog path: confirm DAPM routes, output driver power, amplifier enable/mute, gain, and physical wiring.

Use the existing interactive signal-path graph above as a map, then validate each connection with logs, register reads, or measurements.

Interactive contributor hardware tour

Tap each block to inspect what it does and what evidence to collect.

04 / Hardware tour: follow the bits

Tap a component to inspect its job

BOARDDT + wiringpower rails CPU DAII²S / TDMBCLK / FS CODECDAC / ADCI²C / SPI AMPenable pingain / mute SPEAKERanalog outputacoustic sound Digital samples → serial bus → analog signal → soundSelect a block below to inspect what can fail at that layer.
Choose a hardware block.

Digital bus checklist

  • Is BCLK present?
  • Is frame sync at the expected rate?
  • Who drives BCLK and FS?
  • Correct bit/frame polarity?
  • Slots, masks and slot widths match?

Analog & control checklist

  • Codec supplies and reset deasserted?
  • Correct DAC route and output widget?
  • Amplifier enable / mute state?
  • Jack detect and board routing correct?
  • Check schematic before changing code.
FIELD MANUAL/CHAPTER 16 OF 29/ON REAL HARDWARE

Troubleshooting matrix

Start with symptom → discriminating test → evidence → smallest change. Avoid assuming any single symptom implicates the codec.

Symptom First discriminating test Common directions
No card in aplay -l dmesg + /sys/bus/*/devices + deferred devices machine link, probe deferral, DT match
I²C ACK but driver does not bind readlink .../driver + codec ID read wrong compatible, reset/rails, register width
Card exists, aplay refuses format --dump-hw-params on hw: supported DAI rates, channels, formats, clock policy
aplay succeeds, no BCLK Scope during active PCM DAI trigger, clock gate, pinmux, PM
BCLK/LRCLK present, data line static Logic analyzer + PCM hw_ptr wrong data pin, DMA, TDM masks, mute
Valid data, analog silence Inspect DAPM + mux + analog rails muted DAC, missing route, amp enable
White noise / harsh static Decode bit alignment and slot width incorrect I²S vs LJ, clock edge or data width
Audio too fast/slow Measure LRCLK clock divider or clock family mismatch
Only one channel plays L-only/R-only test + DAPM routes channel mapping, mute, slot mask
XRUN after seconds PCM status pointer + IRQ counters DMA/period, CPU load, clock drift
Works once only Cold boot and warm restart trace PM refcount, register cache, mute sequencing
Resume loses sound Power rail/regcache before/after dirty cache, clocks, reset recovery
Crackling at startup Analog output + DAPM event sequence VMID/bias ramp, mute unmute order
Jack button not detected IRQ/GPIO and input events polarity, debounce, PM, jack report

Investigate without random patching

Build a four-column incident log: hypothesis / measurement / observation / next experiment. Freeze every other variable. If testing a new codec, make one format work (e.g. 48k stereo S16_LE) before adding rates/channels/advanced features.

Typical traps

The ALSA default device isn't always the hardware device. aplay without -D hw:... can pass through plugins and resampling. “Driver bound” doesn't prove audio. “No warnings” doesn't prove schema correctness. “MCLK configured” doesn't prove it toggles. “I²S captured” doesn't prove analog path. Let each measurement answer one question.

Decision drill

Your SGTL5000 I²C registers read successfully, card appears and playback stream advances. BCLK = 3.072 MHz, LRCLK = 48 kHz, decoded I²S data looks valid, but analog lineout is silent. Next actions: inspect DAPM route and widget power, DAC digital mute, analog output-enable bits, regulator rails, external amplifier GPIO, and analog pin with a high-impedance scope probe. Rewriting DMA is low-priority because digital transfer has been observed.

Contributor guide: debug by symptom

Symptom First checks
No sound card Device Tree match, probe logs, deferred probes, card registration
Card exists but PCM will not open PCM device nodes, stream direction, busy state, constraints
PCM starts but no serial clocks DAI link format, clock provider, hw_params, trigger path
Clocks exist but output is silent DAPM route, codec mute/gain, output driver, amplifier enable, analog wiring

Change one variable at a time and capture evidence before applying a patch.

Silent-playback investigation ladder

  1. Confirm the PCM device opens and the stream reaches hw_params.
  2. Verify card/DAI link selection, format and clock-provider roles.
  3. Measure LRCLK and BCLK at the pins rather than trusting requested ALSA parameters.
  4. Check codec supplies, reset, regmap state and DAPM route/control state.
  5. Verify the CPU-side DMA/PCM path and inspect logs around probe and stream startup.

Change one variable at a time and capture the working/failing configuration. The DIT source helps isolate the component/DAI contract; the WM8731 source shows the additional clock, register and power paths.

FIELD MANUAL/CHAPTER 17 OF 29/ON REAL HARDWARE

Automated checks, matrices & regression tests

Audio regressions frequently hide outside the happy path: suspend/resume, capture, two streams, different sample-rate families, and module removal. Design tests around interfaces and failure modes, not just the green LED.

Kernel-side checks

sh
# Inside kernel checkout; target may need prerequisites
make W=1 -j"$(nproc)" sound/soc/codecs/
# Or configure a targeted architecture/kernel and build it; the exact target
# is dependent on the tree and Kconfig settings.

# Inspect expected generated config
rg '^CONFIG_SND_SOC|^CONFIG_SND_PCM|^CONFIG_REGMAP' .config

# Review patch style (adjust patch path)
./scripts/checkpatch.pl --strict outgoing/0001-*.patch

# Sparse where supported; check tool version / arch
make C=1 sound/soc/codecs/

Caution: Building a directory may not compile a driver that's disabled by Kconfig. Verify the object exists and use multiple =y, =m, =n configurations where sensible. sparse, dt-schema, and toolchains may need installation.

Board test matrix

Scenario Objective
Cold power-on x10 Detect supply/reset/PLL races
48k and 44.1k, playback Distinct rate families / PLL
8k / 16k / 96k if supported Rate constraints, divider corners
Mono/stereo; 16/24/32 valid-bit formats Slot/data alignment
Capture separate and simultaneous Direction sharing and MCLK ownership
Short periods vs large periods DMA latency/XRUN robustness
100 stream open/close cycles PM/clock refcounts, stale state
Suspend/resume x20 regcache, clock/regulator restart
Jack insertion while suspended Wake policy, IRQ, DAPM path
Unplug power during active PCM Recoverability / safe stop if hardware permits
Module reload / driver unbind on test board Resource lifecycle; not on production
Stress CPU/network alongside audio Timing robustness, IRQ priorities

Do not claim a test passed without its exact kernel/board/setup/format. Record known limitations, e.g. if playback is verified but capture wiring is absent.

PCM test script sketch

sh
#!/bin/sh
set -eu
DEV="${1:?usage: test.sh CARD,DEV WAV}"
WAV="${2:?usage: test.sh CARD,DEV WAV}"

printf 'kernel: '; uname -r
cat /proc/asound/cards
aplay -D "hw:$DEV" --dump-hw-params "$WAV"
for n in 1 2 3 4 5; do
  printf 'loop %s\n' "$n"
  aplay -D "hw:$DEV" "$WAV"
done

This only tests repeated playback, not audible quality or safe gain. Use low-volume fixture and inspect failures and dmesg afterwards. Add Python/Shell scripts carefully with clear return codes and proper cleanup. For precise latency or THD+N, use calibrated external test gear.

Source and compile quality

Use static analysis, targeted KUnit tests for isolated computations (format, divider selection, constraints), fault-injection for allocation/error paths, and reproducible CI builds with changing compiler/kernel configurations. KUnit cannot simulate real analog hardware; CI green doesn't replace bench testing.

FIELD MANUAL/CHAPTER 18 OF 29/CASE STUDIES

Case study: i.MX53 + SGTL5000

This is a reading lab based on real upstream code. It bridges the architecture into three source artifacts: a codec driver, a machine driver and a board DTB. It isn't a recipe to rewrite a mature upstream codec.

Real source files

  • SGTL5000 codec driver — clocking, DAI format, PCM parameters, controls, DAPM, supplies, regmap.
  • i.MX SGTL5000 machine driver — DAI association and board setup; legacy/machine-specific context.
  • Relevant DTS and bindings for the exact board and kernel tree; do not assume the public mainline DTS matches your deployed DTB.

Device Tree correlation

The supplied i.MX53 Voipac DTB declares a sound node with ssi-controller and audio-codec phandles. Its SGTL5000 codec sits on I²C at 7-bit address 0x0a, with a clock and supply references. Those three things describe three different types of relationships: data link, control bus, and power/clock dependency.

A focused 60-minute reading path

  1. Find struct i2c_driver and the of_device_id table. Record the compatible string and private structure lifecycle.
  2. Find the regmap config: widths, defaults, volatile/readable register rules and cache type.
  3. Find devm_snd_soc_register_component and identify the component and DAI descriptors.
  4. Identify set_fmt and explain supported clock roles, I²S/LJ/RJ/DSP formats and invalid combinations.
  5. Find hw_params and write down the format/rate/clock constraints.
  6. Find mute_stream and DAPM routes/events; explain why muting might use a digital block rather than shutting the entire analog DAC.
  7. In the machine driver, locate snd_soc_dai_set_sysclk use and determine what supplies the codec clock.
  8. Identify what would have to change for another SoC DAI while keeping the codec driver reusable.

Code-reading questions

  • Which state belongs to sgtl5000_priv and which is provided by the ASoC framework?
  • Are there callbacks whose lifetime assumptions would be hard to express safely in Rust?
  • Which clocking checks are portable helpers and which are SGTL5000-specific?
  • Do DAPM route names have direct analog hardware meaning or a software abstraction?
  • What evidence distinguishes bad machine wiring from bad codec hw_params?

Debug scenario

Card missing but codec bound: inspect machine driver and CPU DAI registration, deferred probe, clock provider and sound node. Card exists but left channel silent: run L/R isolated stimulus, observe physical SD frame/slot data, inspect DAPM/controls. Keep those diagnoses separate.

FIELD MANUAL/CHAPTER 19 OF 29/CASE STUDIES

Codec selection & driver archetypes

Choose a target to expose a specific abstraction problem. Complexity is a feature only when it produces useful learning.

Three sensible driver labs

Lab Hardware You learn Limit
A: Minimal I²S DAC PCM5102A-like fixed-function DAC Simple component/DAI, format expectations No I²C regmap or complex DAPM; some drivers can be platform-only
B: I²C stereo codec SGTL5000 or WM8731 class Regmap, supplies, set_fmt, hw_params, DAPM Significant chip-specific sequencing
C: DSP/multi-DAI codec feature-rich codec/amp Firmware, topology, DPCM, multiple links Too large for first Rust PoC

What does 'minimal codec' really mean?

A playback-only DAC without register bus still needs a DAI advertised to ASoC and board audio links. It may not need PCM runtime data handling or hw_params complexity if hardware's accepted format is truly fixed. You still need correct lifecycle and hardware routing.

A controllable codec adds a bus driver, register defaults/cache, reset/power management, clocks, stream format validation, mixer controls and DAPM. That is a much stronger stress test for abstractions but increases the scope substantially.

Picking a board for hands-on work

Prefer a board with known audio wiring, working C driver and measurable test points. Keep a verified DTS and ASoC card configuration. For a hardware-free prototype, implement registration tests and callback signatures, but do not claim DAC playback until there is a CPU DAI + codec + link + physical device.

Incremental feature order

First identify hardware and register component/DAI; then exactly one 48 kHz, stereo, S16_LE playback mode; then proper MCLK/format validation; then minimal DAPM output path; then capture, additional rates, jack, PM and polished kcontrols. Resist adding features before each prior layer is observable and tested.

FIELD MANUAL/CHAPTER 20 OF 29/CASE STUDIES

ALSA PCM engine, DMA & XRUNs

The codec knows how to consume/produce serial samples. The DMA engine and ALSA PCM layer manage buffer movement and stream timing. Their failures are often misdiagnosed as codec problems.

◈ SIGNAL MAP / 06TRANSPARENT SVG · OFFLINE
PCM RING BUFFER / ILLUSTRATIVE 4 PERIODSPERIOD 0frames [..........]PERIOD 1frames [..........]PERIOD 2frames [..........]PERIOD 3frames [..........]hw_ptr: hardware progressappl_ptr: queued by userspaceXRUN: the required separation collapses (playback underrun / capture overrun).
Locations are schematic, not literal hardware pointer values. PCM period elapsed notifications allow ALSA to track hw_ptr while userspace advances appl_ptr.

PCM ring buffer concepts

  • Hardware pointer (hw_ptr): location of samples already played/recorded by hardware, reflected via driver pointer and period notifications.
  • Application pointer (appl_ptr): samples written or read by application.
  • Period: notification/work granularity; buffer: total ring capacity, typically multiple periods.
  • XRUN: playback underrun or capture overrun when software and hardware lose the required relative position.

DMAengine PCM helpers are common on ARM SoCs. Controllers may provide dma-names = "tx", "rx" and dmas references. Actual DMA channels, bit widths, handshake IDs and burst configuration must match the SoC binding/driver.

Is the DMA channel alive?

sh
cat /proc/asound/pcm
cat /proc/asound/card0/pcm0p/sub0/status 2>/dev/null
cat /proc/interrupts | grep -Ei 'dma|sai|ssi|i2s'
dmesg | grep -Ei 'dma|xrun|underrun|overrun|snd|asoc'

Watch period progress and CPU DAI registers while streaming. If hw_ptr does not advance, trace PCM trigger, DMA submission, DMA IRQ and runtime PM. If it advances but BCLK is absent, controller/DMA might not be connected to the intended physical output.

Buffer sizing and latency tradeoffs

At 48 kHz, a period of 240 frames represents 5 ms. Two periods provide only ~10 ms ring capacity—sensitive to scheduling gaps. Larger buffers tolerate jitter but increase latency. The ideal settings depend on product requirements, DMA hardware, CPU load and userspace scheduling. Don't “fix” a kernel DMA bug by hiding it behind huge buffers without measuring.

aplay warnings aren't all codec bugs

When using ALSA default / PipeWire routing, plugins can resample and route to other devices. Start reproducible tests with hw:C,D. A -EBUSY may indicate an exclusive substream already in use; -EINVAL from hw_params may indicate unsupported data configuration. Different errors point to different layers.

Advanced PCM topics

Capture timestamping, mmap vs read/write, DMA coherent vs noncoherent buffers, cache maintenance, 64-bit pointer wrapping, underrun recovery, and DPCM FE/BE interactions deserve explicit testing where relevant. Never assume you need to hand-write an ALSA PCM driver for a generic DMAengine-capable SoC DAI; check existing helpers first.

↳ SOURCE TRACE / CODEC BOUNDARY VS DMA BOUNDARYBundled snapshot line numbers. Use ← FIELD MANUAL in the source explorer to return here.
FIELD MANUAL/CHAPTER 21 OF 29/CASE STUDIES

Power management, suspend & pops

A codec can register and stream perfectly but fail only after suspend. This is often a regmap + supply + clock + DAPM sequencing bug.

Separate power mechanisms

DAPM reacts to active signal paths and powers audio blocks; runtime PM can gate an otherwise idle device's power/clock; system sleep PM handles suspend/resume of the whole system; regmap cache can preserve software register state while hardware loses it. These interact but aren't interchangeable.

Example suspend thought experiment

text
playback active
 → trigger STOP
 → DAPM disables DAC / output amplifier in correct order
 → runtime suspend gates MCLK and device supply
 → hardware register contents lost
 → resume re-enables supply and reset timing
 → regcache marks dirty/syncs when hardware accessible
 → DAPM restores needed active path
 → playback starts again

If a codec is powered off, make sure regmap cache-only mode and restore sequencing match actual silicon. Syncing a cache too early, before reset deassert and clock availability, can fail silently or return bus errors.

Stress plan

  • Stream while allowing auto-suspend; compare idle drain and clock state.
  • Start a stream after idle for 5 minutes; repeat multiple times.
  • Repeat suspend/resume with headset plugged/unplugged; verify jack state.
  • Capture before and after suspend. Compare mixer values and register dumps.
  • Exercise rapid start/stop; inspect clicks on analog output and current spike.
  • Validate removal/unbind and device re-probe on a safe test board.

Pops and clicks

Sequence mute → ramp/bias settle → power enable → unmute as required by hardware, and reverse appropriately on shutdown. A zero-valued PCM sample is not enough to avoid an analog bias transient. DAPM event sequencing and codec-specific mute registers are your tools; exact delays must come from datasheet and measurement.

A warning on kernel upgrades: power management callback ownership and regmap API details move over time. Verify which callback executes in which context and whether the relevant ASoC helper already manages the resources.

↳ SOURCE TRACE / POWER-RELATED IMPLEMENTATIONBundled snapshot line numbers. Use ← FIELD MANUAL in the source explorer to return here.
FIELD MANUAL/CHAPTER 22 OF 29/UPSTREAM ENGINEERING

From local change to upstream patch

The upstream submission is a reviewable explanation of a specific problem and its verified solution. A patch isn't just a diff, and a green compile isn't evidence of functional hardware behavior.

Before you start

Read MAINTAINERS for SOUND - SOC LAYER / relevant codec, the appropriate subsystem tree, mailing lists and reviewing conventions. ASoC is managed through maintainers' trees; your patch should apply cleanly to a relevant current base, typically maintainer or recent integration tree as appropriate. Check the exact preferred branch rather than guessing.

Suggested commit slicing for a new codec

  1. dt-bindings: sound: Document example-vendor,example-codec (only if new binding is needed).
  2. ASoC: codecs: Add ... codec driver — with Kconfig and Makefile.
  3. Board DTS enablement (often different maintainers/tree; consider whether it belongs in a separate series).

For a Rust ASoC foundation RFC, separate binding/trait API, any C glue, minimal demonstration and tests if useful; justify every abstraction through real codec requirements. Discuss architecture with Mark Brown, Liam Girdwood and Rust maintainers before building a broad wrapper library.

Minimum git workflow

sh
# Work in the official kernel git tree
 git status --short
 git switch -c asoc/my-codec
 # edit, compile, test, commit each logical unit
 git diff --check
 git log --oneline -5

 # Generate series against the agreed base branch
 git format-patch --base=auto --cover-letter -o outgoing/ BASE_BRANCH

 # Review all patch emails yourself
 ./scripts/checkpatch.pl --strict outgoing/*.patch
 ./scripts/get_maintainer.pl outgoing/0001-*.patch

 # Confirm email identity / route before ANY real send
 git send-email --dry-run outgoing/*.patch

Replace BASE_BRANCH with the actual tree/branch; --base=auto works best with a properly configured topical branch. Check get_maintainer.pl output, don't blindly CC dozens of unrelated addresses. If the series includes binding + ASoC + board patches, determine recipients for each file.

What reviewers need to know

  • What was broken/missing? Why does the chosen API/structure fix it?
  • What board(s), codec revisions, PCM modes and kernel base were used?
  • What build checks and physical tests passed/failed? Include exact test methods.
  • How are ownership/lifetimes, regmap cache, clocks, DAPM routes and error unwinding handled?
  • What happens with dependencies disabled (=n, =m, =y)? Suspend/resume?
  • Are DT bindings valid? Does the driver still follow common patterns?

Commit message anatomy

text
ASoC: codecs: Fix demo codec clock divider selection

The codec currently selects the 48 kHz divider for all sample rates.
This causes playback at 44.1 kHz to run at an incorrect clock.

Choose the divider from the actual requested PCM sample rate.

Tested on <board revision> with <codec revision>, measuring LRCLK
at 44.1 and 48 kHz before and after the change.

Signed-off-by: Developer Name <address@example.org>

Example only. Fixes: appropriate for genuine introduced bugs, with accurate originating commit. Only add Tested-by: / Reviewed-by: with permission and actual evidence. Use Co-developed-by: and proper associated sign-offs for co-authors.

Review etiquette

Send plain text patches using git send-email; preserve threads when responding, not when arbitrarily linking independent revision histories. A v2 needs a clear after---- changelog of what changed since v1. Respond with technical evidence to criticism. If no response, follow subsystem expectations rather than bumping daily.

Docs: submitting patches · submission checklist · coding style.

Contributor guide: first-contribution checklist

  • Build and boot a kernel you can debug.
  • Trace a known-good board's complete audio path.
  • Find a small, reproducible bug or documentation gap.
  • Define expected behavior and capture a baseline.
  • Make one focused change and add a test or validation notes.
  • Run relevant builds and checks, inspect the diff, and explain hardware/kernel limitations.
  • Send a concise commit message and include the exact reproduction and results in the cover letter or commit description.

Review full upstream context before proposing a change

For driver patches, inspect the complete source file, nearby call sites, binding schema, git log and git blame. Avoid sending a patch based only on a copied tutorial excerpt: validate against the exact target branch and include build/runtime evidence. The separate interactive driver source walkthroughs use mainline source files as their source of truth.

FIELD MANUAL/CHAPTER 23 OF 29/UPSTREAM ENGINEERING

Devicetree bindings & review discipline

For new hardware, the YAML schema is part of the interface between firmware description and drivers. Write the binding for the device, not for your board's particular wiring preferences. Separate reusable codec requirements from machine-level integration.

Binding checklist

  • Correct $id, $schema, title, maintainers, description as applicable; check current conventions.
  • Specific compatible identifiers for supported silicon/variants.
  • reg, supplies, clocks, reset GPIO, interrupt and #sound-dai-cells according to real hardware.
  • required includes genuinely mandatory properties; avoid making optional features mandatory.
  • unevaluatedProperties: false / additionalProperties: false in the correct context and schema design.
  • examples: compile and use realistic phandle providers / cell counts.
  • No Linux implementation-specific knob that could be better modeled as standard electrical hardware property.

Example sketch

yaml
# This is illustrative YAML, not a valid complete schema.
properties:
  compatible:
    const: vendor,sample-codec
  reg:
    maxItems: 1
  '#sound-dai-cells':
    const: 0
  AVDD-supply:
    description: Analog supply
required:
  - compatible
  - reg
  - '#sound-dai-cells'

Real schemas need the canonical schema headers, declared types and examples. See the binding authoring guide.

Validation commands

sh
make dt_binding_check DT_SCHEMA_FILES=/sound/
make ARCH=arm dtbs_check DT_SCHEMA_FILES=/sound/
# DT_SCHEMA_FILES is an optional filter, not a substitute for full checks.

Review dt_binding_check output first; schema errors can cause dtbs_check to skip a binding and mislead you. A valid schema doesn't guarantee physical hardware wiring. Keep MAINTAINERS, board DTS changes and ASoC review routes in mind.

Why it matters for Rust ASoC

Rust support should not invent alternate device bindings if a C driver already describes the codec. Rust driver probe must consume the same stable DT/firmware description and obey the same lifecycle and device-model invariants.

FIELD MANUAL/CHAPTER 24 OF 29/UPSTREAM ENGINEERING

Rust-for-Linux / ASoC research track

Goal: explore the minimum safe abstractions required to implement an ASoC component and DAI from Rust, without claiming that current upstream has a complete Rust ASoC API. Before implementation, seek subsystem and Rust maintainer guidance, because API/lifetime design determines reviewability.

Start from the C contracts

Review these actual kernel structures in your target tree:

sh
rg 'struct snd_soc_component_driver' include/sound/
rg 'struct snd_soc_dai_driver' include/sound/
rg 'struct snd_soc_dai_ops' include/sound/
rg 'devm_snd_soc_register_component' sound/soc/ include/sound/
rg 'snd_soc_component_get_drvdata|snd_soc_dai_get_drvdata' sound/soc/codecs/ | head

Map C contract → Rust ownership for every callback. Who owns component data? Who keeps callbacks alive? Are callbacks invoked after unregister begins? Can callbacks sleep? How are raw pointers represented safely? What cleanup runs on registration failure? Where can mutable access be shared across two simultaneous streams?

Minimal proof-of-concept scope

  1. Get an upstream-compatible Rust kernel toolchain working; make LLVM=1 rustavailable is the first gate.
  2. Identify a tiny codec registration surface; ideally reuse generic kernel device abstractions rather than creating one bespoke wrapper per codec.
  3. Support one component, one playback DAI and one narrow callback (e.g. hw_params) that validates one supported PCM mode.
  4. Ensure static callback storage/lifetimes, pinned driver state as required, and safe device-managed or explicit unregister.
  5. Add failure-path tests: invalid format, duplicate register, remove during idle, callback state after probe failure.
  6. Only after maintainers accept the shape, consider regmap, DAPM, controls, sysclk and capture.

Architecture questions for an RFC

Problem A Rust abstraction needs to demonstrate
snd_soc_component_driver static data Safe callback table lifetime and ownership
snd_soc_dai_driver descriptor Compile-time supported caps/ops, validated names
drvdata raw pointer Typed device state, borrow/sync rules and teardown safety
Errors / errno Map Rust errors to existing C expected return codes
Callback context What is allowed to block or sleep, at each call site?
DAPM static arrays Safe C ABI declarations or validated build-time construction
Mixed C / Rust Tight, reviewed FFI boundary; avoid unsafe in every codec

Avoid writing a giant “sound crate” before a real codec shows the need. A Rust abstraction should make a real driver easier to understand and safer, not simply mirror every C struct.

Toolchain sanity

sh
rustc --version
clang --version
bindgen --version
make LLVM=1 rustavailable
# Follow the target tree's rust/quick-start guide for compiler constraints
make LLVM=1 rust-analyzer

Rust tool versions are tightly coupled to the kernel being built; the distro's default compiler can be unsupported. The upstream Rust Quick Start is a living reference.

Suggested RFC technical note

Write two pages, not 2,000 lines of speculative code: (a) exact minimal C contracts and lifetime diagram, (b) annotated example of a codec's registration and hw_params from Rust, plus limitations. Include what you're not proposing (complete DAPM or regmap bindings yet). Ask ASoC and Rust maintainers where they see ownership and API issues before coding the full framework.

FIELD MANUAL/CHAPTER 25 OF 29/FIELD TOOLS

Labs & exercises — actually do the work

These exercises start with reading, proceed to source code and end on hardware. Capture findings in your own notes; avoid turning it into a checklist you never use.

Lab 01: Trace the working C codec (60–90 min)

Open sgtl5000.c. Record bus matching, regmap, supplies, snd_soc_component_driver, snd_soc_dai_driver and snd_soc_dai_ops. Build a diagram mapping probe → component registration → DAI link → hw_params → DAPM. For each arrow, note the callback or API responsible.

Deliverable: a 1-page “ASoC codec lifecycle” drawing with 5 source references.

Lab 02: Diagnose missing soundcard (45 min)

Situation: SGTL5000 I²C ID reads correctly, but aplay -l reports no cards. Don't touch format code yet. Check DT sound node, ssi-controller/audio-codec references (binding-specific), CPU DAI registration, machine/card probe, deferred suppliers and ASoC component names.

Deliverable: four observations proving where binding stops. Bonus: find one deliberately broken sound DT reference and explain its effect.

Lab 03: Explain serial clocks with a scope (60 min)

On a supported development board, request 48k stereo playback, observe actual BCLK and LRCLK, infer slot width, and compare to the DAI setting. Do the same at 44.1k if supported. Confirm your codec's SYSCLK relation from datasheet, not from assumptions.

Deliverable: table with requested, configured and measured clock values and sample framing screenshot.

Lab 04: Fix a DAPM route (45 min)

Use a known-good output and safe test volume. Disable a mixer route through ALSA controls (where controllable), inspect the DAPM widget state, reenable it, and demonstrate changes to hardware power in debugfs or instrumentation.

Deliverable: a DAPM path sketch including endpoints and controls; before/after observation.

Lab 05: Build a codec driver incrementally (multi-session)

Write a private toy codec using a real target and datasheet. Begin with I²C probe, chip ID and safe reset; add regmap; component/DAI registration; fixed playback format; DAPM; additional rate formats; suspend/resume. Build each stage and add a negative test. Never guess register constants.

Deliverable: commits with working stages and board test evidence, not necessarily an upstream patch.

Lab 06: Review-ready patch series (90 min)

Take a simple bug fix or documentation improvement. Make it build; run affected tests, git diff --check, checkpatch, relevant DT schema tests and get_maintainer.pl; generate a cover letter that describes why the change is needed and exactly how it was verified. Do not send until reviewed.

Deliverable: local format-patch series and clear test matrix.

Lab 07: Rust design drill (90 min)

Take only devm_snd_soc_register_component plus a no-op or constraint-checking DAI callback. Annotate every pointer's owner and lifetime, where Rust might require Pin, and what unsafe must prove. Compare whether a C bridge or generated bindings yield a smaller trusted boundary in the target tree.

Deliverable: a maintainer-readable RFC problem statement, architecture sketch and known limitations.

FIELD MANUAL/CHAPTER 26 OF 29/FIELD TOOLS

Command reference & field checklist

A fast reference when you're at a board with serial console attached.

Userspace ALSA

sh
aplay -l && arecord -l
cat /proc/asound/cards
cat /proc/asound/pcm
amixer -c 0 scontrols
amixer -c 0 contents
aplay --dump-hw-params -D hw:0,0 test.wav
aplay -D hw:0,0 test.wav
arecord -D hw:0,0 -f S16_LE -c 2 -r 48000 -d 10 /tmp/test.wav

Adjust card index and test-file format. Start low volume. amixer output differs with drivers.

Kernel sources and modules

sh
rg 'devm_snd_soc_register_component' sound/soc/codecs/
rg 'snd_soc_dai_set_sysclk|snd_soc_dai_set_fmt' sound/soc/
git log --oneline -- sound/soc/codecs/sgtl5000.c
uname -r
lsmod | grep -Ei 'snd|soc|codec|regmap'
dmesg | grep -Ei 'asoc|snd|codec|i2s|sai|ssi|dma|defer'

Hardware interfaces

sh
ls -l /sys/bus/i2c/devices/
cat /proc/interrupts
find /sys/kernel/debug/asoc -maxdepth 4 -type f 2>/dev/null
cat /sys/kernel/tracing/available_events 2>/dev/null | grep -Ei 'snd|asoc'

Never assume debugfs is enabled or that register reads are harmless. Select specific paths relevant to your device.

Source and review

sh
make LLVM=1 rustavailable
make dt_binding_check DT_SCHEMA_FILES=/sound/
make dtbs_check DT_SCHEMA_FILES=/sound/
git diff --check
./scripts/checkpatch.pl --strict /path/to/patch.patch
./scripts/get_maintainer.pl /path/to/patch.patch
git format-patch --base=auto --cover-letter -o outgoing/ BASE_BRANCH
git send-email --dry-run outgoing/*.patch

Bring-up acceptance criteria

  • Chip physically powered and correctly reset; safe voltage levels measured.
  • Codec matches correct bus address/compatible and reads chip ID if available.
  • Component + DAI registered, sound card and PCM listed.
  • hw: device accepts stated formats and rejects unsupported combinations.
  • Measured MCLK/BCLK/LRCLK and serial framing match hardware configuration.
  • DAPM endpoints/routes/controls power the intended audio path.
  • Low-volume L/R playback and capture verified on real hardware.
  • PCM xrun/latency and suspend/resume exercised and logged.
  • Binding/build/static checks pass on appropriate kernel base.
  • Tests, failure modes, known limitations and board revision recorded.
FIELD MANUAL/CHAPTER 27 OF 29/FIELD TOOLS

Glossary & where to read the code

Term Meaning
ASoC ALSA System on Chip framework coordinating components, DAIs, machine links and DAPM
ALSA PCM Linux API/engine for sampled audio streams and ring buffers
DAI Digital Audio Interface: serialized audio endpoint with format and clock capabilities
CPU DAI SoC serial audio endpoint, e.g. SSI/SAI/I²S
Codec DAI Audio endpoint exposed by external DAC/ADC/codec driver
DAI link Describes CPU/codec/PCM component connection on a sound card
snd_soc_card Assembled ASoC card instance
Regmap Generic register-access abstraction with caching, width, readable/volatile rules
DAPM Dynamic Audio Power Management; route-driven block power control
Kcontrol ALSA mixer/control element exposed to userspace
MCLK/SYSCLK Codec/system reference clock, usually above sample rate
BCLK Serial audio bit clock
LRCLK/WS/FS Channel/frame sync clock
I²S Digital audio bus protocol with one-bit data delay relative to channel edge
TDM Multi-slot serial frame, often more slots than channels
hw_params Agreed PCM rate, format, channels and buffer geometry for a stream
DMAengine PCM Helpers for DMA-driven ALSA PCM on suitable SoCs
DPCM Dynamic PCM FE/BE model, often in DSP/complex SoCs
FE / BE Front End userspace PCM / Back End hardware link
XRUN Playback underrun / capture overrun
-EPROBE_DEFER Probe should retry after a required supplier becomes available
dt_binding_check Validates DT YAML binding schemas
dtbs_check Validates compiled Device Trees against schemas
get_maintainer.pl Finds kernel maintainers/lists from patch paths and metadata

High-value source map

text
include/sound/soc.h            ASoC structures and APIs
include/sound/soc-dai.h        DAI definitions (version-dependent)
include/sound/soc-dapm.h       DAPM widgets, routes and API
sound/soc/soc-core.c          card and component lifecycle
sound/soc/soc-pcm.c           PCM runtime and DAI orchestration
sound/soc/soc-dapm.c          DAPM graph/power logic
sound/soc/codecs/            codec implementations
sound/soc/fsl/               NXP/Freescale ASoC drivers
sound/soc/generic/           generic card drivers
Documentation/sound/soc/     subsystem manual
Documentation/devicetree/bindings/sound/ bindings
Documentation/process/       upstream workflow

Paths and symbols evolve. Use rg/git log in the exact tested kernel commit.

FIELD MANUAL/CHAPTER 28 OF 29/FIELD TOOLS

References, cautions & maintenance

This manual is an independent learning and field-use guide, not official upstream documentation. It is based on public Linux kernel documentation and source patterns; exact structures/callbacks change between releases. Always build against the kernel tree you intend to ship.

Primary official resources

Code to study

What isn't covered exhaustively

Specialized SoC audio DSP firmware architectures (SOF/SoundWire), ASoC topology v2, compressed-offload internals, each vendor's register sets, all USB offload mechanisms, every PCM timestamp/audio-policy corner case, and every Rust sound RFC deserve their own manuals. Treat this as a deep practical foundation and navigation atlas, not a claim to document every internal kernel path.

Practical license and publication note

Text and examples in this guide are newly written educational explanations; upstream links point to materials governed by their own licenses. The schematic code intentionally omits implementation details and real hardware constants. No source copying from kernel files was necessary for the tutorial. If you publish, review code snippets and choose a license for the guide itself.

Revision discipline

Last editorial pass: October 2026. For every kernel upgrade: reread current include/sound/soc*.h, test example snippets or mark them schematic, verify links, and update the test matrix. Keep edition separate from the kernel you validated against.

Interactive full-source walkthroughs

The S/PDIF transmitter and WM8731 source walkthroughs are the only separate learning page added from the contributor guide. The main manual integrates architecture, hardware checks, source navigation, debugging and upstream workflow into the chapters where they belong.

FIELD MANUAL/CHAPTER 29 OF 29/DRIVER WALKTHROUGHS

Driver deep dives: S/PDIF DIT and WM8731

This chapter links to three integrated, offline source explorers. Each page contains the complete bundled source and a line-by-line explanation focused on the ASoC design: component/DAI registration, stream constraints, DAPM graph semantics, register access, clocking, bias and power sequencing, and the relationship between callbacks and the core.

Open WM8731 register map and private-state header → · Inspect get_coeff() fallback → · Inspect hw_params →

Reading method: read the architecture explanation first, then use the source line references to follow each callback into the ASoC core. These are bundled source snapshots; compare the bundled snapshot to the target kernel revision before patch review. Line anchors refer to the bundled snapshot, not a moving upstream branch.

How to review one line without losing the execution path

Source fact states only what the selected C statement performs. Framework context explains where ASoC or ALSA connects it to stream lifecycle. Review consideration is explicitly an inference, risk or verification question—not a claim that a bug has been reproduced on hardware.

↳ TRACE A REAL PCM SETUPThese are code-reading stages, not a guarantee of fixed callback order; link setup, DAPM and muting depend on the card and active path.

Snapshot discipline: the bundled code is an educational snapshot, not an assertion that it is today’s upstream master. Always compare the actual source and binding revision used by your hardware.

KERNEL NOISE LABS · ASOC FIELD MANUALIndependent reference / verify against your target tree