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

Commit 4e55096e authored by Matt's avatar Matt Committed by Jaroslav Kysela
Browse files

[ALSA] hda: add sigmatel hp detect support



HDA Codec driver
Adds support for detecting hp insertion/removal and enable/disable of
lineouts based on unsolicited events.

Signed-off-by: default avatarMatt <matt@embeddedalley.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 41e2fce4
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -262,6 +262,9 @@ enum {
#define AC_PINCTL_OUT_EN		(1<<6)
#define AC_PINCTL_HP_EN			(1<<7)

/* Unsolicited response - 8bit */
#define AC_USRSP_EN			(1<<7)

/* configuration default - 32bit */
#define AC_DEFCFG_SEQUENCE		(0xf<<0)
#define AC_DEFCFG_DEF_ASSOC		(0xf<<4)
+60 −2
Original line number Diff line number Diff line
@@ -36,6 +36,10 @@

#undef STAC_TEST

#define NUM_CONTROL_ALLOC	32
#define STAC_HP_EVENT		0x37
#define STAC_UNSOL_ENABLE 	(AC_USRSP_EN | STAC_HP_EVENT)

struct sigmatel_spec {
	snd_kcontrol_new_t *mixers[4];
	unsigned int num_mixers;
@@ -507,8 +511,6 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
	return 0;
}

#define NUM_CONTROL_ALLOC	32

enum {
	STAC_CTL_WIDGET_VOL,
	STAC_CTL_WIDGET_MUTE,
@@ -617,10 +619,18 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin
	hda_nid_t pin = cfg->hp_pin;
	hda_nid_t nid;
	int i, err;
	unsigned int wid_caps;

	if (! pin)
		return 0;

	wid_caps = snd_hda_param_read(codec, pin, AC_PAR_AUDIO_WIDGET_CAP);
	if (wid_caps & AC_WCAP_UNSOL_CAP)
		/* Enable unsolicited responses on the HP widget */
		snd_hda_codec_write(codec, pin, 0,
				AC_VERB_SET_UNSOLICITED_ENABLE,
				STAC_UNSOL_ENABLE);

	nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
	for (i = 0; i < cfg->line_outs; i++) {
		if (! spec->multiout.dac_nids[i])
@@ -828,6 +838,53 @@ static void stac92xx_free(struct hda_codec *codec)
	kfree(spec);
}

static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
				unsigned int flag)
{
	unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
			0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
	snd_hda_codec_write(codec, nid, 0,
			AC_VERB_SET_PIN_WIDGET_CONTROL,
			pin_ctl | flag);
}

static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
				  unsigned int flag)
{
	unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
			0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
	snd_hda_codec_write(codec, nid, 0,
			AC_VERB_SET_PIN_WIDGET_CONTROL,
			pin_ctl & ~flag);
}

static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
{
	struct sigmatel_spec *spec = codec->spec;
	struct auto_pin_cfg *cfg = &spec->autocfg;
	int i, presence;

	if ((res >> 26) != STAC_HP_EVENT)
		return;

	presence = snd_hda_codec_read(codec, cfg->hp_pin, 0,
			AC_VERB_GET_PIN_SENSE, 0x00) >> 31;

	if (presence) {
		/* disable lineouts, enable hp */
		for (i = 0; i < cfg->line_outs; i++)
			stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
						AC_PINCTL_OUT_EN);
		stac92xx_set_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN);
	} else {
		/* enable lineouts, disable hp */
		for (i = 0; i < cfg->line_outs; i++)
			stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
						AC_PINCTL_OUT_EN);
		stac92xx_reset_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN);
	}
} 

#ifdef CONFIG_PM
static int stac92xx_resume(struct hda_codec *codec)
{
@@ -851,6 +908,7 @@ static struct hda_codec_ops stac92xx_patch_ops = {
	.build_pcms = stac92xx_build_pcms,
	.init = stac92xx_init,
	.free = stac92xx_free,
	.unsol_event = stac92xx_unsol_event,
#ifdef CONFIG_PM
	.resume = stac92xx_resume,
#endif