Disable class-D speaker amplifier when using headphone channels

Hi community,
we are using an DB410c based Myon1 Linux SoM for a communication product in our company. Actually, we have a problem with the class-D speaker amplifier and the headset speaker signals which are embedded on the PM8916’s audio codec:

“DragonBoard 410c Hardware Manual”, page 21
The speaker signals are routed from the PM8916 PMIC built-in Audio CODEC, the two signals are:
-SKPR_DRV_P - Class-D speaker amplifier output+
-SKPR_DRV_M - Class-D speaker amplifier output-

Hardware design facts:
-8 ohm speaker, connected the SKPR_DRV_*
-headset audio jack, connected to HPH_L/R and HPH_REF

Case 1: When I use aplay to play a test wav via speaker, the PMICs codec have to enable the class-D clock signal (300kHz) and generates the audio signal on the speaker as expected. The 300kHz class-D modulation frequency can be measured via scope and can also be sniffed on the speaker wiring via HF sniffer probe and spectrum analyzer (see images).

Case 2: When I use aplay to play a test wav via headset, I do mute the speaker channel first, so audio is only served to the headset. The audio signal plays on the headphone as expected.

The problem: I can hear a quite loud, high frequency signal (approx. 10kHz) on the headphones in this scenario for 5sec. after stopping aplay. The reason is, that the class-D amp gots activated also in this headset scenario and not as expected only when I’m using the speaker. For my understanding, this is because the underlying sound architecture doesn’t take care about the muted speaker output and activates the codecs class-D output stage as soon as a sound output is generated. For clarification: The problem is NOT, that the speaker is playing sound when it is muted (it doesn’t!). The problem is, that the class-D modulates the speaker output to a 0V amplitude since it is muted via alsas “RX3 Digital” control element. Due to a layout problem (I think so) of our baseboard, this modulation frequency is electromagnetically coupled in into the headset channel traces. The result is a high frequency interference on the headset speakers.

A workaround for the first delivered devices would be to force the class-D amp to be deactivated in headset scenario.

Is it possible to deactivate the PM8916’s class-D subsystem at run time?

Thanks for reading, sincerely!
Manuel Del Basso



You seem to have a very strong understanding of what happens.

I don’t know much about this audio part, but looking at pm8916 registers, look like you need to act on CDC_A_SPKR_DRV_CTL register (CLASSD_PA_EN bit). The speaker is controlled by the wcd driver:
https://git.linaro.org/landing-teams/working/qualcomm/kernel.git/tree/sound/soc/codecs/msm8916-wcd-analog.c?h=release/qcomlt-5.7#n647

So maybe you want to add your own code here to undo or disable the speaker on some condition. @srini should know better than me about that.

Alternatively you can check the register value via debugfs:

cat /sys/kernel/debug/regmap/0-01/registers | grep f1b2

And even modify it (for testing purpose) from user space if you build your kernel with REGMAP_ALLOW_WRITE_DEBUGFS (cf Is there a way to read/write PMIC registers from user space?).

Hi Manuel,
Class-D PA should be switched off by default for the first time, if you are not using speaker path. However during run-time its not toggled down during DAPM power down path. Can you try this patch and see if it helps!
https://people.linaro.org/~srinivas.kandagatla/0001-ASoC-msm8916-wcd-analog-disable-Class-D-PA-on-powerd.patch

thanks,
srini

Hi Loic,
thanks for the fast response.
Nice to hear that from you! But understanding the problem is only the first part of solving the problem and for the second part, my knowledge is not as deep as it should be :-/

I have recompiled the kernel with the following change:

0:unixer@lbh:/opt/kernel_5.4.pmic_write2register$ grep -r REGMAP_ALLOW_WRITE_DEBUGFS ./drivers/base/regmap/regmap-debugfs.c
// #undef REGMAP_ALLOW_WRITE_DEBUGFS
#define REGMAP_ALLOW_WRITE_DEBUGFS
#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
#if defined(REGMAP_ALLOW_WRITE_DEBUGFS)

After updating kernel on the target I tried to read out the CDC_A_SPKR_DRV_CTL register before writing to it:

root@kuk-myon-1:~# grep -r 1fb2 /sys/kernel/debug/regmap/0-01/registers
1fb2: 00

This seems not to be the correct value since the speaker on the class-D works with aplay test.wav before I read out 1fb2. Therefor, 1fb2 should return 0b1xxx xxx for my understanding since CLASSD_PA_EN is bit 7?!

It’s f1b2 not 1fb2. But anyway, the patch proposed by @srini should be the proper fix.

Hi guys,
@srini: thank you too for the fast response. I’m recompiling the kernel at this time with your applied patch but with the REGMAP_ALLOW_WRITE_DEBUGFS method (and the correct register address, thank you @Loic :blush:), I could figured out that the interference on the headset channel is NOT indebted by the class-D power amp output switcher bridge… :pensive:

I could disable the class-D output amp successfully when I use aplay to play audio via headset channels by typing:

echo -n "0x0f1b2 0x2f" > /sys/kernel/debug/regmap/0-01/registers 

After that, the earlier shown spectrum peak at 300kHz could not be measured anymore, but the interference on the headset channel is audible nevertheless.

Maybe something goes wrong with the codec generated headphone reference ground, I have to investigate more time and if I found a solution, I will come back to this post.


echo -n "0x0f1b2 0x2f" > /sys/kernel/debug/regmap/0-01/registers

This is a really cool possibility to quick an dirty test things, so I’m very happy that I could learn this method.

Thanks again guys!

1 Like

Hi Manuel,
Can you try this https://people.linaro.org/~srinivas.kandagatla/0001-ASoC-msm8916-wcd-analog-add-delay-before-PA-enable-d.patch hack patch and see if it helps get rid of pop noise that you are seeing on headset. From downstream drivers I can see that HPH PA enable/disable needs an additional delay of 1ms. I did help in some of my tests!

–srini

Hi srini,
I had tested both of your patches, one after the other.

0001-ASoC-msm8916-wcd-analog-disable-Class-D-PA-on-powerd.patch

This patch should resolve the unneccassary activation of the class-D PA in case of using the HEADPHONE_L/R channels, right? With the SPECTRAN sniffer probe, I could see that the class-D PA is still active when playing audio via headphone channels HPH_R/HPH_L.

0001-ASoC-msm8916-wcd-analog-add-delay-before-PA-enable-d.patch

I’m not shure what you mean with pop noise. In fact, I had problems with a high frequency interference (approx 10kHz) on the HPH_R/HPH_L channels.
The high frequency interference problem could be solved after I realized that I did not connect the “virtual GND” HPH_REF to the headphone jack GND in my new schematic… Before I connect HPH_REF to the headphone jack GND, I could hear a pop noise on both HPH_R/HPH_L channels when the codec disables the “virtual GND” HPH_REF.

I can make further tests if you want since my measuring equipment is still set up on my table, please let me know!

Manuel

Just wanted to report the 2 patches from @srini fix an audio issue on 4.14.96 kernel
where switching between audio outputs via Audio Mixer previously corrupted the audio output
while the audio was actively played. The audio output stayed in a corrupted state and switching the
outputs in the Audio Mixer did not restore correct operation once the corruption occured.
Interestinlgy (and possibly why this bug was not detected earlier) the issue does not happen when there is no audio playback in progress. Anyway, those patches fix the issue. Thanks for sharing the patches and creating the topic in the first place.