From e7860dc5d8d45f6a0e98bfe542c7b776c5ede2a4 Mon Sep 17 00:00:00 2001 From: Joonhoe Kim <26rote@gmail.com> Date: Wed, 7 Oct 2026 21:39:54 +0900 Subject: [PATCH] ASoC: codecs: wcd939x: read the SoundWire port switches per channel The "HPHL/HPHR", "ADCn" and "DMICn" switches are channels of shared SoundWire ports (ADC1-4 are channels 0-3 of the ADC_1_4 port), but wcd939x_get_swr_port() reports a per-port flag. Once one channel of a port is switched on, every switch on that port reads back as on: amixer cset name='ADC1 Switch' on -> ADC1..ADC4 Switch all read "on" Setting one of the others then looks like a no-op to userspace, and "alsactl store" saves all of them as on, so a later "alsactl restore" really enables the unused channels of the port. Read the channel's own bit in the port's channel mask instead, drop the now unused port_enable[] and return 0 from the put handler when the switch does not change, as ALSA expects. Fixes: 10f514bd172a ("ASoC: codecs: Add WCD939x Codec driver") Link: https://lore.kernel.org/all/20251124064850.15419-6-jonathan@marek.ca/ Assisted-by: LLM Signed-off-by: Joonhoe Kim <26rote@gmail.com> Link: https://patch.msgid.link/20261007123954.1709-1-26rote@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 10 +++++++--- sound/soc/codecs/wcd939x.h | 1 - 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 26fe0b6313cd..2d463f062e6d 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -1794,8 +1794,9 @@ static int wcd939x_get_swr_port(struct snd_kcontrol *kcontrol, struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(comp); struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[mixer->shift]; unsigned int portidx = wcd->ch_info[mixer->reg].port_num; + u8 ch_mask = wcd->ch_info[mixer->reg].ch_mask; - ucontrol->value.integer.value[0] = wcd->port_enable[portidx] ? 1 : 0; + ucontrol->value.integer.value[0] = !!(wcd->port_config[portidx - 1].ch_mask & ch_mask); return 0; } @@ -1821,10 +1822,13 @@ static int wcd939x_set_swr_port(struct snd_kcontrol *kcontrol, struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(comp); struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[mixer->shift]; unsigned int portidx = wcd->ch_info[mixer->reg].port_num; + u8 ch_mask = wcd->ch_info[mixer->reg].ch_mask; + bool enable = !!ucontrol->value.integer.value[0]; - wcd->port_enable[portidx] = !!ucontrol->value.integer.value[0]; + if (enable == !!(wcd->port_config[portidx - 1].ch_mask & ch_mask)) + return 0; - wcd939x_connect_port(wcd, portidx, mixer->reg, wcd->port_enable[portidx]); + wcd939x_connect_port(wcd, portidx, mixer->reg, enable); return 1; } diff --git a/sound/soc/codecs/wcd939x.h b/sound/soc/codecs/wcd939x.h index 6bd2366587a8..dab7ef108b48 100644 --- a/sound/soc/codecs/wcd939x.h +++ b/sound/soc/codecs/wcd939x.h @@ -899,7 +899,6 @@ struct wcd939x_sdw_priv { struct sdw_stream_runtime *sruntime; struct sdw_port_config port_config[WCD939X_MAX_SWR_PORTS]; const struct wcd_sdw_ch_info *ch_info; - bool port_enable[WCD939X_MAX_SWR_CH_IDS]; int active_ports; bool is_tx; struct wcd939x_priv *wcd939x;