Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 254f2968 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: hda - Keep EAPD turned on for old Conexant chips



In the old Conexant chips (5045, 5047, 5051 and 5066), a single EAPD
may handle both headphone and speaker outputs while it's assigned only
to one of them.  Turning off dynamically leads to the unexpected silent
output in such a configuration with the auto-mute function.

Since it's difficult to know how the EAPD is handled in the actual h/w
implementation, better to keep EAPD on while running for such codecs.

Cc: <stable@kernel.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 527e4d73
Loading
Loading
Loading
Loading
+22 −21
Original line number Original line Diff line number Diff line
@@ -136,6 +136,7 @@ struct conexant_spec {
	unsigned int thinkpad:1;
	unsigned int thinkpad:1;
	unsigned int hp_laptop:1;
	unsigned int hp_laptop:1;
	unsigned int asus:1;
	unsigned int asus:1;
	unsigned int pin_eapd_ctrls:1;


	unsigned int adc_switching:1;
	unsigned int adc_switching:1;


@@ -3430,11 +3431,13 @@ static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
static void do_automute(struct hda_codec *codec, int num_pins,
static void do_automute(struct hda_codec *codec, int num_pins,
			hda_nid_t *pins, bool on)
			hda_nid_t *pins, bool on)
{
{
	struct conexant_spec *spec = codec->spec;
	int i;
	int i;
	for (i = 0; i < num_pins; i++)
	for (i = 0; i < num_pins; i++)
		snd_hda_codec_write(codec, pins[i], 0,
		snd_hda_codec_write(codec, pins[i], 0,
				    AC_VERB_SET_PIN_WIDGET_CONTROL,
				    AC_VERB_SET_PIN_WIDGET_CONTROL,
				    on ? PIN_OUT : 0);
				    on ? PIN_OUT : 0);
	if (spec->pin_eapd_ctrls)
		cx_auto_turn_eapd(codec, num_pins, pins, on);
		cx_auto_turn_eapd(codec, num_pins, pins, on);
}
}


@@ -3460,9 +3463,12 @@ static void cx_auto_update_speakers(struct hda_codec *codec)
	int on = 1;
	int on = 1;


	/* turn on HP EAPD when HP jacks are present */
	/* turn on HP EAPD when HP jacks are present */
	if (spec->pin_eapd_ctrls) {
		if (spec->auto_mute)
		if (spec->auto_mute)
			on = spec->hp_present;
			on = spec->hp_present;
		cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
		cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
	}

	/* mute speakers in auto-mode if HP or LO jacks are plugged */
	/* mute speakers in auto-mode if HP or LO jacks are plugged */
	if (spec->auto_mute)
	if (spec->auto_mute)
		on = !(spec->hp_present ||
		on = !(spec->hp_present ||
@@ -3889,20 +3895,10 @@ static void cx_auto_parse_beep(struct hda_codec *codec)
#define cx_auto_parse_beep(codec)
#define cx_auto_parse_beep(codec)
#endif
#endif


static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
/* parse EAPDs */
{
	int i;
	for (i = 0; i < nums; i++)
		if (list[i] == nid)
			return true;
	return false;
}

/* parse extra-EAPD that aren't assigned to any pins */
static void cx_auto_parse_eapd(struct hda_codec *codec)
static void cx_auto_parse_eapd(struct hda_codec *codec)
{
{
	struct conexant_spec *spec = codec->spec;
	struct conexant_spec *spec = codec->spec;
	struct auto_pin_cfg *cfg = &spec->autocfg;
	hda_nid_t nid, end_nid;
	hda_nid_t nid, end_nid;


	end_nid = codec->start_nid + codec->num_nodes;
	end_nid = codec->start_nid + codec->num_nodes;
@@ -3911,14 +3907,18 @@ static void cx_auto_parse_eapd(struct hda_codec *codec)
			continue;
			continue;
		if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
		if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
			continue;
			continue;
		if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) ||
		    found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) ||
		    found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs))
			continue;
		spec->eapds[spec->num_eapds++] = nid;
		spec->eapds[spec->num_eapds++] = nid;
		if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
		if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
			break;
			break;
	}
	}

	/* NOTE: below is a wild guess; if we have more than two EAPDs,
	 * it's a new chip, where EAPDs are supposed to be associated to
	 * pins, and we can control EAPD per pin.
	 * OTOH, if only one or two EAPDs are found, it's an old chip,
	 * thus it might control over all pins.
	 */
	spec->pin_eapd_ctrls = spec->num_eapds > 2;
}
}


static int cx_auto_parse_auto_config(struct hda_codec *codec)
static int cx_auto_parse_auto_config(struct hda_codec *codec)
@@ -4024,7 +4024,8 @@ static void cx_auto_init_output(struct hda_codec *codec)
		}
		}
	}
	}
	cx_auto_update_speakers(codec);
	cx_auto_update_speakers(codec);
	/* turn on/off extra EAPDs, too */
	/* turn on all EAPDs if no individual EAPD control is available */
	if (!spec->pin_eapd_ctrls)
		cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
		cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
}
}