Skip to content

ASoC: wm8962: don't clear a SYSCLK_ENA that DAPM owns in configure_bclk (fixes silent audio on Surface RT / Surface 2) - #142

Open
zefr0g wants to merge 1 commit into
grate-driver:masterfrom
zefr0g:wm8962-sysclk-fix
Open

ASoC: wm8962: don't clear a SYSCLK_ENA that DAPM owns in configure_bclk (fixes silent audio on Surface RT / Surface 2)#142
zefr0g wants to merge 1 commit into
grate-driver:masterfrom
zefr0g:wm8962-sysclk-fix

Conversation

@zefr0g

@zefr0g zefr0g commented Sep 4, 2026

Copy link
Copy Markdown

Fixes #141 and, I expect, the silence reported in #140 too.

The bug

wm8962_configure_bclk() provisionally sets SYSCLK_ENA to read the read-only DSPCLK_DIV, then clears it unconditionally when the bias level is below SND_SOC_BIAS_ON. But that bit is owned by the SYSCLK DAPM supply widget, and wm8962_mic_detect() force-enables that pin. The Tegra machine driver calls wm8962_mic_detect(), so on Surface RT / Surface 2 DAPM writes SYSCLK_ENA = 1 once at card init and never again (the widget never changes power state). The first stream's BIAS_PREPARE runs configure_bclk(), which clears the bit behind DAPM's back. Every stream then plays with SYSCLK off: DACs idle, CP_ENA will not latch, hp_event() logs DC servo timed out, total silence while every DAPM-visible register looks right.

Only boards calling wm8962_mic_detect() are affected, which is exactly the two Surfaces.

Verification

Microsoft Surface 2 (T114, WM8962 rev F), libre-tegra stable 7.0.1 + this patch: DC servo completes on every stream, SYSCLK_ENA/CP_ENA read 1 over I2C during playback, zero wm8962 errors in dmesg, speakers audible. Before the patch, forcing bit 5 of R8 over I2C during a stream produced sound immediately; that is how it was found (regmap cache vs. raw I2C register diff).

Notes

🤖 Generated with Claude Code

wm8962_configure_bclk() provisionally sets SYSCLK_ENA so that the
read-only DSPCLK_DIV field becomes valid, then clears it again whenever
the bias level is below SND_SOC_BIAS_ON. It never checks whether the bit
was already set.

It can be: the "SYSCLK" DAPM supply widget owns that bit, and
wm8962_mic_detect() force-enables the pin. On boards that call it (the
Tegra machine driver, i.e. Microsoft Surface RT and Surface 2) DAPM sets
SYSCLK_ENA once at card init and, because the widget then never changes
power state, never writes it again. The first stream's transition to
SND_SOC_BIAS_PREPARE runs configure_bclk(), which clears the bit behind
DAPM's back. From then on every stream plays with SYSCLK off: the DACs
do not run, CP_ENA refuses to latch, hp_event() reports "DC servo timed
out", and the codec is silent although every register DAPM believes in
looks right.

Remember whether SYSCLK_ENA was set on entry and only undo our own
provisional enable.

Verified on a Microsoft Surface 2 (Tegra 4, WM8962 rev F): with the bit
forced on over I2C during a stream the DC servo completes in ~56 ms and
audio is heard; with this patch applied the DC servo completes on every
stream and there is no more "DC servo timed out".

Fixes: 75704ec ("ASoC: wm8962: Enable SYSCLK provisonally before fetching generated DSPCLK_DIV")
Cc: stable@vger.kernel.org
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Maxime Douailin <maxime.douailin@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Surface 2 / Surface RT: WM8962 silent — the I2S and MCLK pins are never muxed (MUX UNCLAIMED)

1 participant