Commit 6fd9f6e8 authored by Matt DeVillier's avatar Matt DeVillier Committed by Takashi Iwai
Browse files

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



Commit 778031e1 ("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: 778031e1 ("ALSA: hda/ca0132: Set HP/Speaker auto-detect default from headphone pin verb")
Signed-off-by: default avatarMatt DeVillier <matt.devillier@gmail.com>
Link: https://lore.kernel.org/CAFTm+6AfeXKf=b2frG4xC5yC4jjM9TkD6c8+dOWWFw6BDjDESw@mail.gmail.com


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 7d1051ad
Loading
Loading
Loading
Loading
+31 −13
Original line number Diff line number Diff line
@@ -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) {
		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,9 +6008,7 @@ 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_disable_hp_auto_detect(codec);
	ca0132_alt_select_out(codec);

	return 1;