[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: Matt <matt@embeddedalley.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
@@ -262,6 +262,9 @@ enum {
|
|||||||
#define AC_PINCTL_OUT_EN (1<<6)
|
#define AC_PINCTL_OUT_EN (1<<6)
|
||||||
#define AC_PINCTL_HP_EN (1<<7)
|
#define AC_PINCTL_HP_EN (1<<7)
|
||||||
|
|
||||||
|
/* Unsolicited response - 8bit */
|
||||||
|
#define AC_USRSP_EN (1<<7)
|
||||||
|
|
||||||
/* configuration default - 32bit */
|
/* configuration default - 32bit */
|
||||||
#define AC_DEFCFG_SEQUENCE (0xf<<0)
|
#define AC_DEFCFG_SEQUENCE (0xf<<0)
|
||||||
#define AC_DEFCFG_DEF_ASSOC (0xf<<4)
|
#define AC_DEFCFG_DEF_ASSOC (0xf<<4)
|
||||||
|
@@ -36,6 +36,10 @@
|
|||||||
|
|
||||||
#undef STAC_TEST
|
#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 {
|
struct sigmatel_spec {
|
||||||
snd_kcontrol_new_t *mixers[4];
|
snd_kcontrol_new_t *mixers[4];
|
||||||
unsigned int num_mixers;
|
unsigned int num_mixers;
|
||||||
@@ -507,8 +511,6 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NUM_CONTROL_ALLOC 32
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
STAC_CTL_WIDGET_VOL,
|
STAC_CTL_WIDGET_VOL,
|
||||||
STAC_CTL_WIDGET_MUTE,
|
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 pin = cfg->hp_pin;
|
||||||
hda_nid_t nid;
|
hda_nid_t nid;
|
||||||
int i, err;
|
int i, err;
|
||||||
|
unsigned int wid_caps;
|
||||||
|
|
||||||
if (! pin)
|
if (! pin)
|
||||||
return 0;
|
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;
|
nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
|
||||||
for (i = 0; i < cfg->line_outs; i++) {
|
for (i = 0; i < cfg->line_outs; i++) {
|
||||||
if (! spec->multiout.dac_nids[i])
|
if (! spec->multiout.dac_nids[i])
|
||||||
@@ -828,6 +838,53 @@ static void stac92xx_free(struct hda_codec *codec)
|
|||||||
kfree(spec);
|
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
|
#ifdef CONFIG_PM
|
||||||
static int stac92xx_resume(struct hda_codec *codec)
|
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,
|
.build_pcms = stac92xx_build_pcms,
|
||||||
.init = stac92xx_init,
|
.init = stac92xx_init,
|
||||||
.free = stac92xx_free,
|
.free = stac92xx_free,
|
||||||
|
.unsol_event = stac92xx_unsol_event,
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
.resume = stac92xx_resume,
|
.resume = stac92xx_resume,
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user