From: mcc45tr Date: Tue, 22 Sep 2026 21:00:00 +0300 Subject: [PATCH] ASoC: qcom: terminate Nabu speaker routes and stop FE before clocks Adapt the Nabu endpoint and FE power-down repair from Kumar-Jy/linux-nabu fe755bd3114037c7f034cffdc70aefbe4b26b3d3. Describe physical speakers in DT using standard widgets, and retain the narrowly matched legacy-DT repair. Do not change the four-channel AFE format, DSP_A framing, channel maps or amplifier gain. New DTs use the common ASoC widget parser; old firmware DTs only have their exact four-speaker feedback cycle repaired. Link: https://github.com/Kumar-Jy/linux-nabu/blob/fe755bd3114037c7f034cffdc70aefbe4b26b3d3/sound/soc/qcom/sm8150.c Signed-off-by: mcc45tr --- diff --git a/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts b/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts index 503da0849..5aedaf63e 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts @@ -991,14 +991,18 @@ &sound { &quat_tdm_sd1_active>; pinctrl-names = "default"; model = "Xiaomi Pad 5"; + widgets = "Speaker", "BR Speaker", + "Speaker", "TR Speaker", + "Speaker", "BL Speaker", + "Speaker", "TL Speaker"; audio-routing = "RX_BIAS", "MCLK", "AMIC1", "MIC BIAS3", "AMIC3", "MIC BIAS4", - "MultiMedia1 Playback", "BR SPK", - "MultiMedia1 Playback", "TR SPK", - "MultiMedia1 Playback", "BL SPK", - "MultiMedia1 Playback", "TL SPK"; + "BR Speaker", "BR SPK", + "TR Speaker", "TR SPK", + "BL Speaker", "BL SPK", + "TL Speaker", "TL SPK"; mm1-dai-link { link-name = "MultiMedia1"; diff --git a/sound/soc/qcom/sm8150.c b/sound/soc/qcom/sm8150.c index 484d540e8..60f09b1d4 100644 --- a/sound/soc/qcom/sm8150.c +++ b/sound/soc/qcom/sm8150.c @@ -424,6 +424,12 @@ static void sm8150_add_be_ops(struct snd_soc_card *card) int i; for_each_card_prelinks(card, i, link) { + /* Power down Nabu's amps before the backend releases its clocks. + * The dummy FE codec otherwise delays DAPM shutdown, preventing + * CS35L41 from reporting PDN_DONE. This does not change TDM framing. + */ + if (of_machine_is_compatible("xiaomi,nabu") && link->dynamic) + link->ignore_pmdown_time = 1; if (link->no_pcm == 1) { link->be_hw_params_fixup = sm8150_be_hw_params_fixup; link->ops = &sm8150_be_ops; @@ -432,6 +438,61 @@ static void sm8150_add_be_ops(struct snd_soc_card *card) } } +static const struct snd_soc_dapm_widget nabu_speaker_widgets[] = { + SND_SOC_DAPM_SPK("BR Speaker", NULL), + SND_SOC_DAPM_SPK("TR Speaker", NULL), + SND_SOC_DAPM_SPK("BL Speaker", NULL), + SND_SOC_DAPM_SPK("TL Speaker", NULL), +}; + +static int sm8150_fix_nabu_speaker_routes(struct snd_soc_card *card) +{ + static const char * const outputs[] = { + "BR SPK", "TR SPK", "BL SPK", "TL SPK", + }; + struct snd_soc_dapm_route *routes; + unsigned int found = 0, j; + int i; + + if (!of_machine_is_compatible("xiaomi,nabu")) + return 0; + + /* Compatibility with old firmware-supplied DTs. New DTs describe + * physical Speaker widgets directly. Only repair the exact legacy + * four-speaker feedback cycle; leave all other routes untouched. + */ + for (i = 0; i < card->num_of_dapm_routes; i++) { + const struct snd_soc_dapm_route *r = &card->of_dapm_routes[i]; + + if (r->control || strcmp(r->sink, "MultiMedia1 Playback")) + continue; + for (j = 0; j < ARRAY_SIZE(outputs); j++) + if (!strcmp(r->source, outputs[j])) + found |= BIT(j); + } + if (found != GENMASK(3, 0)) + return 0; + + routes = devm_kmemdup(card->dev, card->of_dapm_routes, + sizeof(*routes) * card->num_of_dapm_routes, + GFP_KERNEL); + if (!routes) + return -ENOMEM; + + for (i = 0; i < card->num_of_dapm_routes; i++) { + if (routes[i].control || strcmp(routes[i].sink, "MultiMedia1 Playback")) + continue; + for (j = 0; j < ARRAY_SIZE(outputs); j++) + if (!strcmp(routes[i].source, outputs[j])) + routes[i].sink = nabu_speaker_widgets[j].name; + } + card->of_dapm_routes = routes; + card->dapm_widgets = nabu_speaker_widgets; + card->num_dapm_widgets = ARRAY_SIZE(nabu_speaker_widgets); + + return 0; +} + static int sm8150_platform_probe(struct platform_device *pdev) { struct snd_soc_card *card; @@ -453,6 +514,9 @@ static int sm8150_platform_probe(struct platform_device *pdev) card->owner = THIS_MODULE; dev_set_drvdata(dev, card); ret = qcom_snd_parse_of(card); + if (ret) + return ret; + ret = sm8150_fix_nabu_speaker_routes(card); if (ret) return ret; -- 2.51.0