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: 10f514bd17 ("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 <broonie@kernel.org>
This commit is contained in:
Joonhoe Kim 2026-10-07 21:39:54 +09:00 committed by Mark Brown
parent 4f173a0fee
commit e7860dc5d8
No known key found for this signature in database
GPG Key ID: 2FEF73B0B3D03889
2 changed files with 7 additions and 4 deletions

View File

@ -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;
}

View File

@ -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;