[RFC PATCH 00/23] ASoC: qcom: AudioReach Active speaker protection for WSA884x
From: Srinivas Kandagatla
Date: Fri Oct 23 2026 - 13:18:11 EST
This series adds DSP Active speaker protection (SP) for WSA884x speakers on
Qualcomm AudioReach platforms. It was tested on the Lenovo ThinkPad T14s
Gen 7 (2x WSA8845) and the Glymur CRD (4x WSA8845).
Speaker protection needs the amplifiers' V/I sense capture running
whenever the speakers play. Rather than a separate capture link that
userspace has to keep open, the VI codec DAIs sit on the WSA Playback BE
link, using a new multi_direction codec-codec link flag that makes the core
run .hw_params/.hw_free and stream events for codec DAIs of the other
direction. This core change is the main reason for sending it as RFC,
and feedback on the approach is very welcome.
- ASoC core: default ch_maps for links with more than 8 DAIs, and the
multi_direction_codecs link flag (documented).
- qcom sdw: per-direction stream runtimes on such links.
- wsa884x: VI sense capture DAI, die temperature as a thermal zone.
- AudioReach: control links, VI calibration mode with per-speaker
events, R0/T0 cache and restore in normal mode, static cfg blobs,
and mixer controls for mode, R0/T0, live T0 and calibration state.
- x1e80100: VI feedback on the WSA Playback link, speaker thermal zones.
- DT: VI feedback for glymur-crd and the T14s Gen 7.
A topology with the SP and SP_VI modules is needed to use it.
How it works:
1. The topology puts the speaker protection (SP) module in the playback
graph and the SP_VI module in a VI feedback graph fed by the WSA VI
sense ports, joined by a control link.
2. Starting playback on the WSA Playback link also starts the VI sense
capture (8 kHz, 32-bit, one V/I pair per speaker), so the DSP always
gets feedback while the speakers play.
3. Calibration, once per device with the speakers cold: userspace sets
"Speaker Protection Operation Mode" to Calibration and plays silence;
the DSP makes its own stimulus. The VI module measures each speaker's
resistance (R0), the driver records the amplifier die temperature
(T0) with it, and "Speaker Protection Calibration State" reports the
result.
4. Userspace reads R0/T0 from "Speaker Protection R0T0", switches back
to Normal mode and saves them, e.g. with alsactl store.
5. At boot the saved values are written back (alsactl restore). In
Normal mode the driver sends R0/T0 to the VI module, and the SP
module uses the live V/I feedback to keep each speaker within its
temperature and excursion limits.
How to test (card 0, two speakers; for four, use aplay -c 4):
1. Boot with this series and a topology that has the SP and SP_VI
modules, and select the speakers as the output so the WSA path and
the "VISENSE Switch" controls are on. Stop all playback.
2. Play one second of silence so the amplifiers have been on once and
"Speaker Protection T0" reads a valid temperature, then wait for
DAPM to power them down (about 5 seconds):
aplay -D plughw:0,0 -f S32_LE -c 2 -r 8000 -t raw -d 1 /dev/zero
amixer -c 0 cget name='Speaker Protection T0'
3. With the speakers cold, in a quiet room, start a calibration and
keep the graph running with silence; the DSP makes its own stimulus:
amixer -c 0 cset name='Speaker Protection Operation Mode' Calibration
aplay -D plughw:0,0 -f S32_LE -c 2 -r 8000 -t raw -d 15 /dev/zero &
4. Poll the state until every speaker reports 4 (success); 5 (failed)
or 7 (timed out waiting for V/I) means retry:
amixer -c 0 cget name='Speaker Protection Calibration State'
5. Stop playback, go back to Normal mode, then read and save the
result. R0T0 holds R0 in Q24 ohms and T0 in Q6 degC per speaker:
amixer -c 0 cset name='Speaker Protection Operation Mode' Normal
amixer -c 0 cget name='Speaker Protection R0T0'
alsactl store 0
6. Reboot. alsa-restore writes R0/T0 back and every playback runs with
protection in Normal mode. The kernel log shows the values, e.g.
SP ch0: R0 3.102 ohms, T0 45.000 degC
I have script to do these, I can share it if anyone wants to try it.
Tool use: an LLM coding assistant (Claude Code with Claude Opus) was
used for some of the patches in this series, to debug the bring-up and
to draft the code and commit messages.
Why RFC:
- get some consensus on codec-to-codec which are in different directions
- To avoid duplicate efforts.
- Still 1 or 2 patches cooking to force dsp to program default safe value
- test it on X1E platforms.
Based on next-20261022 with the "ASoC: qcom: AudioReach and WSA88xx
fixes" series applied.
here is my wip kernel tree along with tplg and ucm:
https://github.com/Srinivas-Kandagatla/linux/tree/glymur
https://github.com/Srinivas-Kandagatla/audioreach-topology/tree/glymur
https://github.com/Srinivas-Kandagatla/alsa-ucm-conf/tree/glymur
Ravi Hothi (11):
ASoC: dt-bindings: qcom,wsa8840: allow one sound DAI cell
ASoC: codecs: wsa884x: add VI sense capture DAI
ASoC: qcom: audioreach: run VI module in calibration mode with
per-speaker events
ASoC: qcom: q6apm-dai: add S32_LE format support
ASoC: qcom: audioreach: support up to four speakers in VI feedback
ASoC: qcom: audioreach: cache VI calibration results per speaker
ASoC: qcom: audioreach: make the speaker protection operation mode
configurable
ASoC: qcom: audioreach: send cached R0/T0 to the VI module in normal
mode
ASoC: qcom: audioreach: send static cfg blobs to speaker protection
modules
ASoC: qcom: audioreach: add speaker protection mixer controls
arm64: dts: qcom: glymur-crd: add WSA speaker protection VI feedback
:wSrinivas Kandagatla (12):
ASoC: soc-core: allow default ch_maps on links with more than 8 DAIs
ASoC: soc-pcm: add multi_direction_codecs link flag
ASoC: qcom: sdw: add per-direction stream runtimes for multi_direction
links
ASoC: codecs: wsa884x: register the die temperature as a thermal zone
ASoC: qcom: audioreach: add control link support to graphs
ASoC: qcom: audioreach: pin SPEAKER_PROTECTION_VI media format
ASoC: qcom: audioreach: add live speaker temperature (T0) readback
ASoC: qcom: audioreach: add speaker protection calibration state
control
ASoC: qcom: audioreach: keep the last VI calibration result until the
DSP reports
ASoC: qcom: x1e80100: carry WSA VI feedback on the WSA Playback BE
link
ASoC: qcom: x1e80100: register WSA speaker thermal zones for speaker
protection
arm64: dts: qcom: mahua-t14s: add WSA speaker protection VI feedback
.../bindings/sound/qcom,wsa8840.yaml | 5 +-
Documentation/sound/soc/index.rst | 1 +
.../sound/soc/multi-direction-codecs.rst | 135 +++
arch/arm64/boot/dts/qcom/glymur-crd.dtsi | 29 +-
.../mahua-lenovo-thinkpad-t14s-gen7-lcd.dts | 19 +-
include/sound/soc.h | 7 +
include/uapi/sound/snd_ar_tokens.h | 13 +
sound/soc/codecs/wsa884x.c | 160 +++-
sound/soc/qcom/qdsp6/audioreach.c | 779 +++++++++++++++++-
sound/soc/qcom/qdsp6/audioreach.h | 105 +++
sound/soc/qcom/qdsp6/q6apm-dai.c | 16 +-
sound/soc/qcom/qdsp6/q6apm.c | 42 +-
sound/soc/qcom/qdsp6/q6apm.h | 1 +
sound/soc/qcom/qdsp6/topology.c | 273 ++++++
sound/soc/qcom/sdw.c | 236 ++++--
sound/soc/qcom/x1e80100.c | 81 ++
sound/soc/soc-core.c | 46 +-
sound/soc/soc-pcm.c | 122 ++-
18 files changed, 1924 insertions(+), 146 deletions(-)
create mode 100644 Documentation/sound/soc/multi-direction-codecs.rst
base-commit: bd1ecbb61afefc6a8b876ccbc31e9228b44e9eab