ALSA: hda/ca0132: Disable auto-detect on manual output select

Commit 778031e165 ("ALSA: hda/ca0132: Set HP/Speaker
auto-detect default from headphone pin verb") enables HP/Speaker
auto-detect by default when the headphone pin supports presence detect.

With auto-detect enabled, ca0132_select_out() and ca0132_alt_select_out()
choose the output from jack presence instead of the manual HP/Speaker
selection. This means selecting speaker output while headphones are
plugged in updates the control state, but audio still routes to the
headphones.

Treat an explicit manual output selection as a request to leave
auto-detect mode. Clear the HP/Speaker auto-detect switch before applying
the manual selection, and notify userspace so the auto-detect control
state is updated in mixers. Do this for both the normal HP/Speaker
Playback Switch and the alternate Output Select control used by desktop
cards.

This keeps auto-detect enabled by default for devices with jack presence
detection, while preserving the expected behavior that a manual output
choice takes effect immediately.

Fixes: 778031e165 ("ALSA: hda/ca0132: Set HP/Speaker auto-detect default from headphone pin verb")
Signed-off-by: Matt DeVillier <matt.devillier@gmail.com>
Link: https://lore.kernel.org/CAFTm+6AfeXKf=b2frG4xC5yC4jjM9TkD6c8+dOWWFw6BDjDESw@mail.gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
master
Matt DeVillier 2026-05-07 09:58:41 -05:00 committed by Takashi Iwai
parent 7d1051ad68
commit 6fd9f6e870
1 changed files with 31 additions and 13 deletions

View File

@ -5498,6 +5498,30 @@ static int zxr_headphone_gain_set(struct hda_codec *codec, long val)
return 0;
}
/*
* Manual output selection (HP/Speaker Playback Switch or alt Output Select)
* is meaningful only when HP/Speaker auto-detect is disabled, since the
* select_out path always prefers jack presence when auto-detect is on. When
* the user explicitly chooses an output, turn auto-detect off so the manual
* choice actually takes effect, and notify userspace so the auto-detect
* control reflects the new state.
*/
static void ca0132_disable_hp_auto_detect(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
struct snd_kcontrol *kctl;
if (!spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID])
return;
spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID] = 0;
kctl = snd_hda_find_mixer_ctl(codec,
"HP/Speaker Auto Detect Playback Switch");
if (kctl)
snd_ctl_notify(codec->card, SNDRV_CTL_EVENT_MASK_VALUE,
&kctl->id);
}
static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@ -5510,14 +5534,11 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
int auto_jack;
if (nid == VNID_HP_SEL) {
auto_jack =
spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
if (!auto_jack) {
if (ca0132_use_alt_functions(spec))
ca0132_alt_select_out(codec);
else
ca0132_select_out(codec);
}
ca0132_disable_hp_auto_detect(codec);
if (ca0132_use_alt_functions(spec))
ca0132_alt_select_out(codec);
else
ca0132_select_out(codec);
return 1;
}
@ -5978,7 +5999,6 @@ static int ca0132_alt_output_select_put(struct snd_kcontrol *kcontrol,
struct ca0132_spec *spec = codec->spec;
int sel = ucontrol->value.enumerated.item[0];
unsigned int items = NUM_OF_OUTPUTS;
unsigned int auto_jack;
if (sel >= items)
return 0;
@ -5988,10 +6008,8 @@ static int ca0132_alt_output_select_put(struct snd_kcontrol *kcontrol,
spec->out_enum_val = sel;
auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
if (!auto_jack)
ca0132_alt_select_out(codec);
ca0132_disable_hp_auto_detect(codec);
ca0132_alt_select_out(codec);
return 1;
}