[ALSA] hda: add sigmatel hp detect support
authorMatt <matt@embeddedalley.com>
Mon, 4 Jul 2005 15:51:39 +0000 (17:51 +0200)
committerJaroslav Kysela <perex@suse.cz>
Thu, 28 Jul 2005 10:21:52 +0000 (12:21 +0200)
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>
sound/pci/hda/hda_codec.h
sound/pci/hda/patch_sigmatel.c

index 59991560d492260b9d407fd00ddb11a5f907de36..dd0d99d2ad2724e937337c4e79720362fab11436 100644 (file)
@@ -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)
index 07d06f7c4390fcad2a036f9c4bcb3468870430a4..9d503da7320db9d21706f7f6717a834af644853c 100644 (file)
 
 #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